Repository navigation
app: workstream agent prompt and tools (proposals, drafts, its own pages) - #2289
Merged
Merged
Conversation
AbirAbbas
force-pushed
the
workstreams/wp10e-agent
branch
2 times, most recently
from
November 3, 2026 07:33
7263205 to
eabc92d
Compare
…mport The store now refuses, inside the save transaction, an agent write to a page the person owns, and an agent create of a page it would not own, so a page made the person's between a read and a save is still refused. ByAgent finds the workstream whose agent is a conversation. pagedoc.FromMarkdown turns markdown into the editor JSON the page renderer reads, live-block markers included, and the contract's example round-trips byte for byte. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A conversation handed a WorkstreamDoor carries workstream_read, propose_decision, propose_question, propose_jobs, propose_goahead and write_agent_page, and a short prompt section naming its workstream and the rules: it proposes and the person keeps, it writes only its own pages, it never invents numbers and it starts nothing. Arguments outside each schema are refused before the door is touched, propose_jobs only appends drafts and retries a version conflict once, and a go-ahead proposal is a proposed decision that grants nothing. Without a door the belt and the page are unchanged, and task nodes, errands and clarifications never carry it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…turns The app sets the workstream door on the conversation whose created-by is workstream and on no other; the door finds its workstream at each call, since the agent is opened a moment before the workstream row exists. Its writes are attributed to the agent and send workstream.changed, and a workstream agent's settled turn sends one too so its spend is read again. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…port is linear An agent's record or page write now refuses a done workstream inside the same write transaction, so marking done between the agent's read and its write leaves nothing behind. Imported list items always begin with a paragraph, and unmatched backticks or brackets are consumed in one pass instead of rescanning the rest of the line for each one. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The prompt's workstream brief is a snapshot that never touches the store, so a re-render under the session lock cannot wait on it. Arguments decode only through decodeToolArguments, a repeated key is refused at any depth, every argument refusal is marked, and the plan's one retry is written without a counting loop. A go-ahead's proposed cap is dollars, excused from the whole-number law in its own file. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…tore The app remembers each workstream's name and why by its agent when it creates, reads, updates, marks done or reopens one, and when the agent's door resolves it, so the prompt reads that snapshot. A done refusal from the store reaches the agent as the workstream being done. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… the write Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…hen done The done check in ProposeRecord read the defaulted actor, so the wire's unattributed record.propose on a done workstream, which has always landed as a proposal, was refused. It now reads the attribution the caller gave, and the agent's door keeps passing its own. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The app shows the agent's summary on the Overview from the agent page titled exactly "Where it stands". The prompt and write_agent_page now name that page and ask the agent to keep it current with what it was updated from. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…t budget The rule now fits in one short line, and the workstream section's own budget test allows 1000 bytes for the worst-case name and why. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…save The store now refuses an agent write to a page the person owns, so the seed that reproduces the contract's agent-saved Overview hands the page to the agent for that save and back again, keeping the agent's attribution and version. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ts pages The store now refuses an agent write to a page the person owns, so the version-read and deleted-tree fixtures that save or create as the agent make those pages the agent's first; what they assert is unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
AbirAbbas
force-pushed
the
workstreams/wp10e-agent
branch
from
November 3, 2026 07:53
eabc92d to
f4ac14a
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The Workstreams plan, WP-10 (engine side): a workstream's own agent gets a short workstream section in its system prompt and six tools that reach the workstream store through a narrow door the app injects. Every tool enforces the AI rules in code; a plain agent's belt and page are unchanged.
session.WorkstreamDoor(internal/session/workstream_contract.go) is set by the app only on the conversation whose created-by isworkstream(one line inengine.gobesidecfg.Floor, one registration line inapp.go). It resolves its workstream at each call by agent id (workstream.Store.ByAgent), because the agent is opened a moment before the workstream row exists. Task nodes, errands, quick tasks and question clarifications never carry it.internal/session/workstream_tools.go):workstream_read {what: workstream|pages|page|records|plan|goaheads, page_id?, kind?, state?}: wire-shaped JSON; numbers come from records and Factory reads, absent means unknown.propose_decision/propose_question {text, source?}: aproposedrecord byagent; no path keeps it. Source defaults to the agent's chat; explicit sources are a member job, a page of this workstream or an http(s) URL.propose_jobs {jobs: [{title, repo?, text?}], wave?, wave_title?, milestone_id?}: appends drafts only; existing waves, items andauto_startuntouched; retries aversion_conflictonce, then reports. Never touches a Factory door.propose_goahead {scope, factory?, job?, wave?, milestone_id?, cap_usd, ends_on, why}: the contract has no proposed go-ahead, so this is a proposed decision whose text beginsProposed go-ahead (not granted):; it grants nothing.write_agent_page {page_id?, title?, parent_id?, markdown, updated_from, source?}: creates or updates agent-owned pages only; a page the person owns is refused inside the store transaction and nothing changes; writes carryupdated_by: agent, the store's time andupdated_from.kept,state,cost_usd,auto_start, …) are refused before the door is touched.savePagerefuses an agent write to a non-agent page in its transaction (ErrNotAgentPage);pagedoc.FromMarkdownimports markdown (live-block markers included) and the contract example round-trips byte for byte.spend_usdalready counts the agent conversation's recorded spend (spawned tasks fold into it). New: a workstream agent's settled turn sendsworkstream.changed(workstreampart) so the spend is read again.Validation contract
internal/session/workstream_tools_test.go,cmd/codeaf/appworkstreams_agent_test.goworkstream_tools_test.go,appworkstreams_agent_test.gopropose_jobsnever calls the Factoryinternal/session/workstream_factory_test.go,appworkstreams_agent_test.gowrite_agent_pagerefuses a person's page and changes nothing (including the read/save race)internal/workstream/workstream_agent_test.go,workstream_tools_test.gointernal/workstream/workstream_agent_test.go,appworkstreams_agent_test.goworkstream_tools_test.gointernal/session/workstream_validation_test.go,workstream_tools_test.goTestTheManualMentionsTheWorkstreamAgentsTools, manual section incollections.mdReview and fix rounds
Two independent reviews. Fixed: the prompt's workstream brief is a non-blocking snapshot (no store read under the session lock); an agent's record and page writes check done inside their own transaction (the wire's unattributed
record.proposekeeps its old behaviour); imported list items always start with a paragraph; malformed inline markdown is parsed in linear time; repeated JSON keys are refused at any depth; the tools follow the session's argument laws (one decoder, marked refusals, no counting retry loop;cap_usdexcused as dollars in its own file).CI
PR gate: build, vet, gofmt, change entry and manual gates green. The remaining reds are the integration branch's baseline:
internal/sessioncomplexity ledgers, prefix budgets,TestProgramHoldClassifiesEveryRegisteredChatTool,TestALandStartsNoAutomaticMaintenance;cmd/codeafTestAppChatRowsR2SavedTurnTime,TestAppChatStartupR3QuietRelease,TestRecipeDoorWritesTheWorktreeWhenOnlyTheCheckoutIsHeld.Contract gaps
No wire shapes or handlers changed. Suggestions on the person's pages, autonomy-driven small changes and the watching agent are later work.
🤖 Generated with Claude Code