When a coding agent reads or edits a file you have on the canvas, Forkshop draws an outline around the affected tile in the agent's color. Multiple agents working at once each get their own color and stack. Read activity gets a slower-breathing pulse than edit activity.
How an agent talks to Forkshop
The protocol is one HTTP endpoint and one SSE stream:
-
POST /api/forkshop/agent-activity— the producer side. An agent emits one POST per tool call.{ "agent": "claude-code", "agentLabel": "Claude", "sessionId": "<string>", "file": "<repo-relative path>", "action": "read" | "edit" | "create" | "delete", "ts": 1716000000000 } -
GET /api/forkshop/agent-activity/stream— the consumer side. The canvas opens anEventSource; the engine streamsactivityevents with the current set of active files. A keepalive comment fires every 15 seconds. Entries age out after a few seconds of silence.
Both routes are dev-only — production returns 403.
Per-agent colors
The engine picks colors from an 8-slot OKLCH palette. The mapping
is deterministic per agent name: start the same agent twice and
you'll see the same color. Slot 0 (orange) is reserved for
claude-code so Claude lands on a known color.
When two agents work at once on different files, you see two colors on the canvas. When they touch the same file, the most recent agent wins the outline.
The agent color flows through every surface that reflects activity: the iframe outline on the canvas, the badge above each tile, and the sidebar — the activity dot and trailing filename next to a page, block, or primitive entry are tinted with whichever agent most recently edited it. So a Claude edit lights up the sidebar row in orange; a second agent on a different file paints its own row in its own color.
Claude Code producer
Pass --install-claude-pack to forkshop init (or set
FORKSHOP_INSTALL_CLAUDE_PACK=1) to install the producer pack for
Claude Code:
.claude/hooks/forkshop-post-tool-use.sh— a bash hook that watchesRead,Write,Edit, andMultiEdittool calls and POSTs the activity to your dev server..claude/settings.json— the hook is merged into thePostToolUsearray idempotently.
The hook only matches changes to .ts, .tsx, .mdx, and .css
files.
Other producers
Any agent runtime can produce activity by hitting the POST endpoint with the shape above. A producer is small — typically a hook that observes the agent's tool calls and converts each to one POST.
Block outlines in page iframes
When an agent edits a page file, the engine propagates an outline
into any page-view iframe to highlight which block was touched. This
requires each block component to have data-forkshop-block="<slug>"
on its outermost element — without it the engine can't identify the
block inside the iframe:
export function HeroBlock(props: HeroBlockProps) {
return (
<section data-forkshop-block="hero">
{/* ... */}
</section>
)
}
The setup skill adds this attribute for you when it detects block components. Check that existing blocks have it if outlines aren't showing in page-view iframes.
Static / seeded activity
AgentActivityProvider accepts two props for seeding activity
without opening the live SSE stream — useful for static showcases
or marketing demos:
<AgentActivityProvider
fileMap={fileMap}
initialActivity={[/* pre-built ActivityEntry objects */]}
subscribeToStream={false} // skip the SSE connection
>
{children}
</AgentActivityProvider>
Entries in initialActivity age out after ~5 seconds by default.
Set pinned: true on an entry to prevent it from expiring.
Disabling
Remove the hook script (or its entry in .claude/settings.json)
and the activity stream stops feeding. The canvas falls back to no
outlines. Nothing else changes.