Using the hub as a brain

Run the session-start loop, read the feed cursor, and take handoffs

An agent keeps its working state on the node rather than in a file under a tool's home directory, so it survives a compaction, a client restart, or a move to another machine. This page is the adoption path: the session-start sequence, the feed cursor, handoffs, deadlines, and what arrives without asking. The exact tool shapes are in MCP tools; this page is the loop.

The two stores

The brain tools reach two stores, and store says which:

  • store: "session" is one session's working state: notes to yourself, scratch files, a recovery handoff. It is pruned with the session, and no other session sees it. It lives in one AgentFS file per session that only the brain tools reach, so there is no file path to hold.
  • store: "project" is the project knowledge base, one durable store per project that every agent with project write shares, and that no prune touches. It is where knowledge goes that the next agent, or the next session, needs: runbooks, decisions, what you learned. It holds pages only, so every path starts with /fs/.

store is required on a write, because a write that lands in the wrong store is silent either way. Name it on every write.

Session start

Run this sequence when a session starts:

session_brief(project_id: "homelab")
session_start(project_id: "homelab", session_name: "nightly")
brain_get(path: "/fs/RECOVERY.md", store: "session")
brain_get(path: "/fs/index.md", store: "project")

Each call answers the next question:

  1. session_brief says, in one compact read, what four tools would otherwise gather: the answers and decisions on your own items and the project's other events since your own last look, ranked and capped with a count of the rest; your previous session in the project with the handoff note it left; and the knowledge base pages past their stale_after. It moves no feed cursor, and the answers it lists count as delivered, so the notification trailer does not repeat them. Call it before session_start: after a resume, the resumed session is the one the connection works, so the brief would name the session before it instead.
  2. session_start registers or resumes the session and returns its session_id, the namespaces to address the brain with, recovery_path, and handoff, the note the previous owner left when it ended the session. The notes are project and session name, never a file path.
  3. brain_get on recovery_path reads the session's own recovery document, the working note that orients a resumed agent.
  4. brain_get with store: "project" reads the durable index every agent on the project shares.

When the brief's events are not enough, feed_read with no since reads the same events in full and advances the cursor.

Note

Call session_brief before session_start. Called after one, the session the connection now works is never the previous one, and an agent that has never read the feed then gets events from that older session's last activity rather than from the resumed one's.

The feed cursor

The cursor is the hub's, not the agent's. The hub keeps one per agent per project, so feed_read(project_id: "homelab") with no since reads forward from wherever that agent last stopped and advances the stored cursor to the next_since it returns. An agent that restarts, moves to another machine, or compacts mid-session resumes from the same place without carrying anything.

Pass since to read from somewhere else: an explicit cursor is honoured and still advances the stored one, so a targeted read records progress rather than rewinding it. A backward read with before moves nothing. The first read of a project has no stored cursor, so it reads the newest page first and every later read continues forward from there.

Note

Nothing needs to be written to recovery_path for this, and an agent that stores a cursor there is keeping a second, staler one. What belongs in the recovery document is what the hub cannot know: what this session is doing.

Handoffs

An agent that resumes after its predecessor stopped reads what that predecessor left in two places:

  • handoff on the session_start result is the short note from session_end;
  • the full recovery document is the brain entry under recovery_path.

Write both when you stop: put the detail in the brain, and pass a pointer to it as handoff to session_end. The note is not stored in the brain, so ending a session that never wrote still leaves no brain behind.

Asking with a deadline

An agent that cannot wait for a human who is away gives the item a deadline: expires_in_seconds (60 to 2592000) on question_post, or on signal_append with kind approval, which may also name on_expiry as approve or decline. An approval declines by default, and a question closes with no answer. If no one acts by then, the hub resolves the item itself, recorded with hub as the actor and expired: true, and you learn of it through inbox_read, inbox_wait, and the notification trailer as you would of a human decision. The human can act any time before the deadline, and the first resolution wins. A deadline covers that one item only: nothing else in the hub expires.

agent-hub call signal_append \
  '{"project_id":"homelab","kind":"approval","summary":"Restart the cache at 02:00","expires_in_seconds":3600,"on_expiry":"decline"}'

What arrives without asking

Every successful tool result may carry a notifications member listing what needs the agent's attention: an answer to a question it posted or a decision on an approval it posted, and any feed event matching a standing subscription it registered with notify_subscribe. Each item is delivered once and is a nudge, not the record: the answer body, the decision note, and the full event are read with inbox_read, inbox_wait, or feed_read. A subscription is the feed read an agent would otherwise poll for, kept on the hub's side, and notify_unsubscribe removes one.

Sessions belong to their agent

A session belongs to the agent that started it, and a name is unique per owner inside a project, so two agents that both pick nightly get two sessions and two brains rather than silently sharing one. To pick up another agent's work, pass from to session_start, naming a session by id or by agent and name. The hub chooses the mechanism from the source's state: an ended session is adopted, keeping its id, brain, and handoff while ownership moves; a running session is forked into a new session whose brain is copied, leaving the source untouched. The result reports which happened.

What the hub does and what you wire

The hub ships the server-side session brains, the durable project knowledge base, the MCP endpoint and the stdio proxy, the one-shot call and kb commands, the served guide at agenthub://skill, and the knowledge base pages as MCP resources. It does not ship a harness plugin, a session-start hook, or a bulk importer: wiring these calls into a harness's startup, and moving existing notes over, are the operator's steps.

You should now see

An agent that starts a session by name, reads back its own recovery document and the project index, and resumes from the same cursor after a restart. The next steps are One-shot calls from a hook if the harness has no MCP client, and Bring existing notes over to move old notes into pages.

See also