tinkaria
Artifacts

Realtime (notify, not poll)

Use await, input, and render so agents and users react over the same stream.

A worker-less shell app can still be two-way. The browser view sends input events. An agent parks on await, gets notified, computes, then publishes render state. The next viewer repaints from current_state.

screen select -> POST input/select -> GET await wakes -> agent computes -> POST render/main -> shell renders

Await

GET /apps/{id}/await?cursor=<n> parks until one event arrives or the await window ends. The default replay window is 500 events or 15 minutes, with a 25 second await. A timeout still returns ok:true, an empty events array, and the current state.

# Await before the user action. The request parks until an event arrives or the await window ends.
# docjourney: step=await-select
curl -s "https://t.tini.works/apps/journey/await?cursor=0" \
  -H "authorization: Bearer <short-key>"
# -> {"ok":true,"cursor_status":"ok","replay_available":true,"events":[{"kind":"input","name":"select","payload":"{\"choice\":\"ops\"}","cursor":1,...}],"current_state":{},"next_cursor":1}

Cursor failures are explicit:

ShapeMeaning
{"ok":false,"type":"cursor_too_old","cursor_status":"too_old","first_retained_seq":...,"last_seq":...,"next_cursor":...}The cursor fell out of the 500 event or 15 minute replay window.
{"ok":false,"type":"replay_unavailable","cursor_status":"js_disabled","replay_available":false,"events":[],"current_state":...}JetStream replay is unavailable for this account or host.

Input

POST /apps/{id}/input/{event} publishes a user or agent event. If payload is a string, it is used as-is. Otherwise its raw JSON is published as a string.

# Send the selected value.
# docjourney: step=select-input
curl -s -X POST "https://t.tini.works/apps/journey/input/select" \
  -H "authorization: Bearer <short-key>" \
  -H "content-type: application/json" \
  -d '{"payload":"{\"choice\":\"ops\"}"}'
# -> {"ok":true,"published":true,"app":"journey","kind":"input","name":"select","subject":"app.journey.session.main.input.select","cursor":1,"replay_available":true}

Render

POST /apps/{id}/render/{region} publishes view state and persists that region as current state. Late joiners and later await calls can repaint without polling a custom API.

# Transform the selected input into render state, then publish that state.
# docjourney: step=transform-render
curl -s -X POST "https://t.tini.works/apps/journey/render/main" \
  -H "authorization: Bearer <short-key>" \
  -H "content-type: application/json" \
  -d '{"payload":"{\"selected\":\"ops\",\"source\":\"docjourney\"}"}'
# -> {"ok":true,"published":true,"app":"journey","kind":"render","name":"main","subject":"app.journey.session.main.view.main","cursor":2,"replay_available":true}
# Read the current render state without polling a custom API.
# docjourney: step=await-current-state
curl -s "https://t.tini.works/apps/journey/await?cursor=2" \
  -H "authorization: Bearer <short-key>"
# -> {"ok":true,"cursor_status":"ok","replay_available":true,"events":[],"current_state":{"main":"{\"selected\":\"ops\",\"source\":\"docjourney\"}"},"next_cursor":2}

On this page