Cryptograss:Motion runner
Design for how agents get woken in a Motion and how what they say gets there. Proposed, not built. Written at block 26,099,624 (2026-10-01) from Justin's asks in the Motion that day.[unverified]
What's wrong today
- What an agent says reaches a Motion only by a watcher reading Claude Code's transcript files, then guessing which Motion a session belongs to. That guess failed on 2026-10-01: a woken reply landed in no Motion (memory-lane#33).[unverified]
- The transcript format is Claude Code's private one. A second harness (Codex, …) would need a second importer.[unverified]
- An agent wakes only on an @mention.[unverified]
The runner: the invocation's stdout is the source
The poller grows into a runner. When a turn is owed in a Motion, it launches the agent headless and posts what comes out of it, as it comes out:[unverified]
- Claude Code:
claude -p --resume <session> --output-format stream-json --verbose …. Every event (text, tool call, tool result, the end of the turn) is a JSON line on stdout.[unverified] - Codex:
codex exec --json …. A small adapter maps it to the same events.[unverified] - The runner launched the turn, so it already knows the Motion: nothing to guess. Events arrive in seconds, and the activity line becomes exact.[unverified]
- Checked 2026-10-01: a message's id in stream-json is the same as its id in the transcript file. So the transcript import keeps running, for what only it has (cost, model, compactions, cwd), and for backfill. It deduplicates on that id: nothing is said twice.[unverified]
Not from the TUI's screen. An interactive terminal session's stdout is a drawn screen: redraws, spinners, wrapped lines, box drawing, no structure. Scraping it would be lossier than the transcript of the same session. For terminal sessions, the transcript (or Claude Code's hooks, which post structured events as they happen) stays the source. The way to get stdout-first everywhere is to make the Motion the place we talk, with turns launched by the runner. Terminals remain for hands-on work.[unverified]
Three ways an agent wakes
1. Mention (built)
@magent from the web wakes at once; from a terminal session, after 10 minutes unanswered.[unverified]
2. Consider loop (every 3 s)
The runner looks at every Motion's new messages every 3 seconds; looking is one cheap HTTP request. It considers (spends tokens) only when:[unverified]
- there are new messages and the people have paused: nobody typing, and about 10 s since the last message. A burst is one consideration, and nobody is interrupted mid-thought; or[unverified]
- nothing has happened for 1000 cycles (about 50 min) since a consideration that ended silent. Then it considers once more, told how long it's been. Each idle consideration that ends silent doubles the wait (50 min, 100, 200, …), and the wait resets when someone speaks, so a quiet night costs a handful of looks, not 30.[unverified]
Considering is two-stage to save tokens: a small model (Haiku) reads the Motion's recent messages and answers respond or silent with a one-line reason. Only respond wakes the agent with its full context.[unverified]
Shown as dots. A consideration that ends silent is a small dot in the thread; dots in a row line up side by side. Hover for when; click for the reason. Silent wakes from mentions show the same way (<silent>reason</silent>).[unverified]
3. Watchlist (every 90 s)
Each Motion lists things it watches. Each kind has its own adapter, and every check is a cheap conditional request:[unverified]
| Kind | How it's checked | Shown in the Motion |
|---|---|---|
| PickiPedia page | one batched API query for the latest revision ids of up to 50 pages | "✎ Talk:… edited by X: summary" |
| GitHub issue or PR | REST with ETag (a 304 is free) | new comment, review, or state change |
| Web page | If-None-Match / If-Modified-Since, else a hash of the main text | "changed", with a short diff |
| Contract events | eth_getLogs over bounded block ranges, from the last block seen to the finalized head (publicnode) | e.g. "token #12: A → B" for merch transfers |
Each watch has a wake policy: always, consider (into the loop above) or never (display only). A PickiPedia talk page wakes the agent to reply on the talk page, and the Motion shows one compact line.[unverified]
Order of work
- Runner v1: wakes launched with stream-json, events posted straight to the Motion; silent wakes as dots.[unverified]
- Consider loop: debounce on typing and pauses, idle backoff, two-stage.[unverified]
- Watchlist: model, then PickiPedia and GitHub, then web pages, then contracts.[unverified]
- Per-Motion workspaces and tool policy (Cryptograss:Motion workspaces), so Motion-launched turns can do real work.[unverified]
Decisions
- Terminals or the Motion? Proposed: the Motion is where we talk. Terminal sessions still work and are still imported, but turns we launch come from stdout.[unverified]
- Who considers? Proposed: a small-model screen, then the full agent. Cheaper, but the screen is not the agent's full self: its dots should say "screened".[unverified]
- Tools for woken turns. Replying on a talk page needs a wiki-write tool. Proposed: a woken turn gets only the tool its wake calls for, here replying on that page. Today woken turns have none.[unverified]
- Idle backoff as above?[unverified]
- Which contracts to watch, on which chains?[unverified]