Skip to content

Prototype uncertain passages inline before the first build (LIVE_SPIKES) - #454

Open
MaggieAppleton wants to merge 10 commits into
living-build-uifrom
living-spikes
Open

MaggieAppleton wants to merge 10 commits into
living-build-uifrom
living-spikes

Conversation

@MaggieAppleton

@MaggieAppleton MaggieAppleton commented Oct 10, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

While a document is being written, Jev notices passages that a quick prototype would de-risk. The editing person's connected coding agent builds it on a throwaway chopin/spike-<id> branch with no permission prompt. A Callout under the passage shows "Prototyping…", then findings, a recommendation and screenshots. Deleting the callout dismisses the spike.

Behind LIVE_SPIKES=on.

What changed

  • SpikeScout watches a document after edits settle (20s) and asks Jev which passages are worth prototyping, bounded per document and per pass.
  • Spike records (spikeSchema in @chopin/experiment) own placement and dismissal state; the Callout is only a projection.
  • Spike placement (spike-placement.ts) inserts and rewrites the Callout in place under the passage.
  • Spike host (spike-host.ts) runs each spike as an investigation on the editing person's connector.
  • Connector (apps/connector) checks out chopin/spike-<id> for spike runs and uses a spike-specific prompt; it never pushes.
  • MCP gains spike-only upload_investigation_image (at most 3 per run) and submit_spike_result.
  • LIVE_SPIKES config flag, startup description, and the e2e Jev fixture.

Flow

sequenceDiagram
    participant E as Editor
    participant S as SpikeScout
    participant J as Jev
    participant H as Server (investigation)
    participant C as Connector coding agent
    E->>S: Edit settles (20s)
    S->>J: Per passage (bounded)
    J-->>S: Passage worth prototyping
    S->>H: Investigation on editor's connection
    H->>C: Spike run on chopin/spike-id
    C->>H: upload_investigation_image (up to 3)
    C->>H: submit_spike_result
    H->>H: Persist spike record and document
    H-->>E: Callout rewritten in place
Loading

Persistence precedes publication: the spike record and document commit before the callout is broadcast.

Safety notes

  • The image tool exists only for spike runs, with a per-run cap.
  • Coding agent text is escaped into MDAST, never parsed as MDX.
  • Callouts never overwrite human edits; a changed callout gets a sibling callout instead.
  • Anchors are rebased against the current document before any server-authored edit.
  • Jev errors do not launch coding agents.
  • Spikes run only on the editing person's own connector, on a throwaway branch, and are never pushed.

Screenshots

Prototyping callout

Spike result callout

Spike result in context

Testing

  • Unit tests for the scout, placement, host, spike records and routes.

On 10 Oct I ran this end to end on github.com/MaggieAppleton/margin with a Copilot coding agent (copilot --acp --allow-all):

Follow-up fixes from that run, now in this branch:

  • d9af340: full-size spike screenshots via connector-local upload_image_file, follow-up scans beyond 5 passages, Queued state in creation order, no re-spike of a passage that already has a callout, and immediate cancel on callout deletion.
  • 64fd0fa: Copilot CLI 1.0.96 rejects stdio MCP servers over ACP, so spike runs now get a token-guarded loopback HTTP bridge serving the run's tools plus upload_image_file, and a scan stopped at the 3-spike cap resumes when a spike finishes, fails or is dismissed. Connector test covers the HTTP bridge, its token check and the worktree path guard.
  • b12cb4a: parallel upload_investigation_image calls in one run no longer overwrite each other's upload record (3-image cap holds under concurrency), and a spike result deferred by a first build's lock now lands when the lock releases or the room reopens. Unit tests in routes.test.ts and spike-host.test.ts. A connector workspace lock whose process has exited is now replaced instead of blocking startup (workspace.test.ts).

Verified end to end (second run, 10 Oct) with copilot --acp --allow-all on github.com/MaggieAppleton/margin:

  • Spikes ran Queued in creation order and produced 1280x800 screenshots.
  • Rewriting a passage did not re-spike it, and deleting a callout cancelled its spike in about 2s.
  • After 64fd0fa, spikes run over the loopback HTTP MCP bridge with real Copilot, and passages beyond the 3-spike cap are judged when a spike finishes.
  • 236c29d: a spike that finishes while Build plan is queued behind it now lands its result before the build claims. The build and its approved tasks move to the callout-only revision in the same commit, and the claim waits up to 30s for spike results. Unit tests in spike-host.test.ts (queued build: result lands, then claimImplementation starts) and tasks/routes.test.ts (claim waits for results first). Server and web bun test, bun run types, bun run build and bun run ci pass.

Stack note

Stacked on #453, which is stacked on #452, #451 and #450. Base is living-build-ui. Merge rebase-only, after the lower PRs land.

🤖 Generated with Claude Code

MaggieAppleton and others added 5 commits October 10, 2026 21:11
…build

Behind LIVE_SPIKES=on (also on with LIVE_BUILD=on), a SpikeScout scans a
document 20 seconds after a person's edit settles, only while it has no
live build. It judges at most five unseen prose blocks per scan with one
Jev noul each (>= 0.6; explicit-uncertainty matching when Jev is absent
or fails) and keeps at most three spikes active. A hit becomes an
investigation marked as a spike, attributed to the last editor and
authorized on that person's live repository connection; with no
connection nothing is created.

A "Prototyping…" Callout is placed directly under the passage after the
record persists, and is rewritten in place when the spike completes or
stops. Removing the callout dismisses the spike, and a passage whose
digest has a spike never re-triggers. Spike runs get run-scoped
upload_investigation_image and submit_spike_result tools; the server
builds the report from the headline, findings, recommendation and
uploaded images. Spikes stay out of the investigation list.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A claimed spike checks out chopin/spike-<id> in the disposable worktree,
gets a prompt to build the smallest prototype, upload screenshots and
report with submit_spike_result, and relays the server's run-scoped tool
list through the stdio bridge.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Scope image uploads to spike runs with a three-image cap and a per-run
citation check, and raise the connector body limit only for that tool.
Make LIVE_SPIKES independent of LIVE_BUILD. Persist a placing state
before a callout is published and recover in place. Stage callouts with
copied, rebased decision and comment anchors. Keep human edits inside a
callout by placing new state in a sibling. Leave passages unjudged when
Jev fails, keep approved over-capacity passages for later scans, and
dismiss deleted callouts after a living build.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Spike runs get a connector-local upload_image_file that reads a PNG, JPEG or
WebP from the run worktree and forwards it, so agents no longer emit base64
and the prompt asks for 1280x800 Playwright screenshots. Callouts read Queued
until their run is claimed, and runs dispatch in creation order. A scan that
leaves passages unjudged follows up in five seconds, passages already above
a spike callout are skipped, and deleting a callout stops its spike on the
edit rather than the next scan.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…y frees

Copilot CLI in ACP mode rejects client-provided stdio MCP servers, so every
spike failed without a result. A spike run whose agent accepts HTTP servers now
gets a per-run streamable-HTTP bridge on 127.0.0.1, guarded by a random bearer
token and closed with the run, that relays the run's Chopin tools and adds
upload_image_file. Agents without HTTP support keep the stdio bridge.

A scan that stopped at the active-spike cap never judged the waiting passages
until another edit. It now resumes when a spike record changes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MaggieAppleton and others added 4 commits October 10, 2026 22:14
…d lock

Concurrent upload_investigation_image calls in one run now share one per-run
set and reserve their slot before awaiting storage, so neither overwrites the
other and the three-image cap holds. A spike placement deferred while a first
build locks editing is retried when the lock releases and when the room opens
unlocked.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A crashed connector left its lock behind and blocked every later start until
someone removed the file. A lock naming a process that no longer exists is now
stale and replaced; a live or unreadable lock still refuses.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A queued first build already holds the editing lock, so a spike that finished
while the build waited had its callout deferred until after the build. The
spike refresh may now update its callout under a build that is only queued,
rebinding the build and its approved graph to the callout-only revision in the
same commit, and the build claim waits (bounded) for those results to land.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant