Repository navigation
feat: workstreams W3 — read fence, scoped recall, references and moves by share policy - #464
Merged
Merged
Conversation
saucam
force-pushed
the
feat/workstreams-w2
branch
from
November 12, 2026 01:23
4f5b4d7 to
343d0db
Compare
saucam
force-pushed
the
feat/workstreams-w3
branch
from
November 12, 2026 01:23
73de1d6 to
984efdd
Compare
saucam
force-pushed
the
feat/workstreams-w2
branch
from
November 12, 2026 01:37
343d0db to
3e463dd
Compare
saucam
force-pushed
the
feat/workstreams-w3
branch
from
November 12, 2026 01:37
984efdd to
276f933
Compare
…, share verdicts for references and moves Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… from the session's workstream, file tools refused in another workstream's folders Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…line and get_episode keep to the home and its references Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…policy, moving a session to another workstream Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- codeoid new --ref, codeoid workstream ref add|rm, workstream move - the session header's chip opens what the session reads and a move; the new-session dialog offers what it may read (under isolation) - a fresh session's sandbox no longer says its directories changed 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>
…s fenced, with what the session reads carved out; its own workdir always readable - fenceFor: no foreign folder is dropped for being nested in the home's or holding it; WorkstreamFence.readable (workdir, home, exactly what a reference grants) is carved out — the gate checks it, the sandbox hides every other entry on the way (carveOut), else the folder whole - the home is never a workstream's folder, nor a repository top above it - a session's own workdir stays readable after a move or an override - extraction: a glob's partial last segment, ACP locations, pi's @ and find/ls; a relative path with an unknown cwd is refused - an added sandbox dir inside a fenced folder is refused and never kept - reference inputs held to the binding's own bounds; an unreadable stored binding seals the session (no home, never moved) - the session map and the frozen memory index keep to the workstream - the chip's panel takes focus and follows the window Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…anted paths where they really are, changes at the turn boundary - a session's repository top is its own only where no other workstream's folder holds it; a recorded home widens to its top only where no other workstream has a folder inside it; folders are no longer collapsed - reference paths resolved at grant, and counted only where they really are inside the granting workstream (no .., no link planted later) - Session.setWorkstream saves at once and applies at the next turn's start - a move adds the old home to readFrom; a home in another workstream's folder is judged by that one's share (closed refuses); the claim and the bounds are judged again when an ask is answered - the gate's folder forms are prepared once per fence; a session's own folder may be written though a reference holds it - globs judged at their start and their dir; pi's @ only before a path Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… a closed one's text, and acts through workers homed where the work belongs (#465) * feat: workstreams W4 — the conductor reads across workstreams without a closed one's text, and acts through workers homed where the work belongs - fleet tools name each result's workstream and take a workstream filter; a closed workstream's episode text never reaches fleet_find, fleet_summary, fleet_recall or a worker's digest (status only) - fleet_spawn takes workstream: judged before queueing as a create is (a folder with none needs one; an exclusive folder is an override the approval card says; a closed one's folder never), stored on the task and judged again at claim - every send-class approval card (web, Telegram) names the workstream it acts in, with the override warning approving it confirms - egress stub: planEgress (a message is sent by a worker homed in its workstream) - the conductor recalls its own episodes under isolation - the fleet rail docks from md up, so a phone's approval card has the width Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix: workstreams W4 audit round 1 — untagged text judged by its session, confirmations tied to the card the owner approved - untagged episodes are withheld by their session's workstream (live or stored), unknown ones while any workstream is closed; a closed one's hits are dropped from fleet_find / fleet_recall before anything is counted; machine_map leaves out its branches - a worker's digest is withheld from the conductor only; the conductor's tenant-wide task board withholds an orchestrator's closed results - an override or an ask folder counts as confirmed only by the owner's own approval of that very card, once, at that config revision (checked again at claim); a delegated token can't approve such a card - an unnamed spawn keeps the remote-changed guard; a closed workstream's worker works only in its own folders - codeoid approve and the terminal show the card's workstream Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix: workstreams W4 audit round 2 — a confirmation is a one-time token on the approved call, checked against exactly what its card showed - the owner's own approval of a card that needed confirming adds a token to that call's input; its handler accepts it once, for the tenant, workdir, workstream, conflicting workstream, ask folders and revision the card was judged on (no leftover, stale or denied approval confirms anything) - only the session owner's own token confirms (not another member's) - the warning names the workstream it passes; the TUI shows it too - conductor tasks known by the routing rule (no goal), not today's URI - a stored session judged by its recorded home; answers memoised briefly - an unnamed spawn's claim judged as when queued; a closed workstream with only remote rules may work in a folder it matches Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix: the W4 e2e follows the warning that names the workstream passed Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
saucam
force-pushed
the
feat/workstreams-w3
branch
from
November 12, 2026 03:06
1e01258 to
4386654
Compare
saucam
changed the base branch from
feat/workstreams-w2
to
feat/workstreams-w1
November 12, 2026 03:06
saucam
added a commit
that referenced
this pull request
Nov 12, 2026
…nd credentials, and no backend holds a secret (#462) * feat: workstreams W1 — named credentials behind a pluggable secret store; a home's env and git identity - credentials[] declares a credential's id and kind (bearer, header, env, oauth) — never its value; every reference across the config is checked at load (declared once, of a kind that fits) - credentialStore picks where values live: env-file (CODEOID_CRED_<ID>, kept out of every agent subprocess by the CODEOID_ prefix) or dir (one file per id: a mounted Kubernetes Secret, a Vault sink; read-only, non-blocking, registered as a secret location) - a session gets its home workstream's env (values read from the store when it is built) and git identity; GIT_AUTHOR_*/GIT_COMMITTER_* pass the extra-env GIT_ deny, nothing else does; a workstream env name codeoid owns for the backend fails the config load Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat: workstreams W1 — isolation: a session reaches only its home's MCP servers, and no backend holds a secret With workstreams.isolateGlobalServers on (off by default: nothing changes): - a session's MCP view lists built-ins, the servers its home selects by name, and the folder's own servers only when the folder is the home's; no home, the conductor's, or an orphaned one: built-ins only — on every backend - Claude runs with a strict MCP config (no ~/.claude.json, .mcp.json, plugin or agent servers of its own); every server it may reach is an in-process bridge to the daemon's hub, so it holds no server config, command or secret - other CLI backends mount natively only servers that need no secret; HTTP servers called with a credential go through the daemon's relay, which now takes the session's view; a stdio server needing env values is withheld - a server a workstream selects with a named credential carries a reference; the hub and relay read its value from the secret store per request and refuse without it - every hub list and call, and every relay request, is checked against the grant as it is now (G4): a removed server fails mid-turn with the reason - under isolation a user's create in a folder with no home is refused with workstream_required; sessions the daemon starts there get built-ins only Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat: workstreams W1 — confirmed overrides, the folder record, a home required under isolation - a create choosing a workstream past another's exclusive claim is refused with what an override would change and, when the claimant allows it, a token: single use, five minutes, bound to the caller, folder, choice and config revision (G3); the confirming retry needs session:approve on an undelegated token and is audited (workstream.override); codeoid new shows the warning and asks, or --override confirms it - how each folder last resolved is recorded per tenant: a repository rule that now matches another workstream (an edited origin) makes the next create choose, and leaves a session the daemon starts there without a home - under isolation a user's create in a folder with no home is refused with the workstreams to choose from Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat: workstreams W1 — OAuth credential slots: a second sign-in to one server, one per workstream - mcp_oauth_credentials gains a credential slot in its primary key, rebuilt once in one transaction; every existing row is the default slot ('') - the OAuth engine reads, refreshes, stamps and signs out per slot; a pending sign-in carries its slot, so a completion always lands in the slot it began for - a workstream's server with an oauth credential is called with that slot's sign-in (on the hub, the Claude bridge and the relay), never the default - mcp.oauth.begin / disconnect and codeoid mcp signin --credential take a slot, refused unless it is declared as an oauth credential for that server Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat: workstreams W1 — codeoid workstream import, an e2e journey, and the docs - codeoid workstream import proposes workstreams from the repositories on disk (grouped by remote owner) and lists Claude's global MCP servers to assign; it writes nothing - skillDirs are accepted but not applied yet, and the daemon says so - e2e: under isolation a create with no home is refused with the choices; an exclusive folder takes only a confirmed override; credentials show by name - docs/CONFIGURATION.md: credentials, the secret store, what a workstream gives its sessions, overrides, moving an existing setup; the design's backlog and status Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix: workstreams W1 audit round 1 — CLI backends kept to codeoid's servers, no daemon variable in a server config, an honest folder record Security: - Codex, the Gemini CLI and Qwen loaded MCP servers of their own under isolation. Codex now has every server its user and project configs declare turned off (with a placeholder transport, so an untrusted project file still starts; measured on codex 0.166) and its apps off; the Gemini CLI and Qwen get only codeoid's server names allowed; opencode's turns are refused under isolation until its project config can be kept out - ${CODEOID_*}, ${ZEROID_*}, ${TELEGRAM_*} in a server config resolve empty, and such a bearerTokenEnv is ignored: a repo's .mcp.json could read any workstream's credential from the daemon's environment - secretFree also reads the URL (a token in its path or query, user:pass@) and the command line: such servers go through the relay or are withheld - Claude under isolation bridges only HTTP servers; a stdio one needing no secret is the CLI's to run inside the session's sandbox, as before (the hub would have run a repo's script on the host) - a delegated token can't edit an origin and then choose the workstream it now matches, and never writes the folder record - the hub's per-call check refuses an unknown session under isolation; a relay whose credential changed is closed (the backend initializes again); a slot sign-in or sign-out drops that slot's hub clients too - override tokens go only to callers who can redeem them Correctness: - the folder record holds what the folder matched, never a chosen home, and is written once the session exists: an explicit choice no longer makes the next plain create in that folder refuse - an override token is spent only once its session exists - not isolated, the relay reaches exactly what it did before - a server address change rebuilds the Claude query - servers withheld from a backend are said in the session, once per set - --override without --workstream is refused with why Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix: workstreams W1 audit round 2 — codex plugins off, rejecting a changed origin sticks, the daemon-variable rule narrowed - codex plugins bring MCP servers that can't be turned off by name: under isolation plugins are off whole (and /etc/codex layers are read too) - choosing a workstream other than the folder's match (rejecting a changed origin included) no longer records the new match; the record changes only when the owner accepts the match - codex's home config.toml is read through a link (account overlays link it; isolation failed to start for every codex account); a project's is not - a codeoid server named like one of codex's own entries is refused: codex merges the two, lending codeoid's server that entry's headers or env - the rule against naming daemon variables in a server config is narrowed to workstream credentials (CODEOID_CRED_*): a user's own CODEOID_* variable in their own config resolves as before - an override token is spent up front again: single use under concurrent creates - tests: codex plugins/links/merged names, the Gemini/Qwen allowlist, the opencode refusal, the record after a rejected change Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix: codex isolation holds a config to well-formed table headers, never to the runtime parser's leniency Bun 1.3.13 (the pinned runtime) reads an unclosed header such as `[mcp_servers.x` as a table where 1.4 refuses it, so on CI a malformed codex config started codex instead of being refused. tomlStructureProblem checks every table header (outside strings and open values) and that nothing is left open, before the parse. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat: workstreams W2 — edit workstreams and credentials live, in the web UI (#463) * feat: workstreams W2 — edit workstreams and credentials live - workstream.upsert / delete / settings and credential.list / upsert / delete / set_value: settings:write on an undelegated token; written to config.json through the settings store (the whole config validated, nothing written otherwise) and applied to the running daemon at once — new sessions and every session's grant follow it, live sessions keep their homes; workstreams.changed announces it - a credential's value goes to .env (0600) and the daemon's environment and is never sent back: only whether it is set, and where; an OAuth one points at codeoid mcp signin; deleting one a workstream uses is refused - a session's MCP view fingerprint includes its grant: a workstream edited rebuilds that session's backend at its next turn, on every backend Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat: workstreams W2 — the web UI: Workstreams and Credentials in Settings, a picker and override confirm in New session, a chip on every session - Settings → Workstreams: isolation switch, default, the list (claim, share, rules, servers, env), an editor that keeps what it doesn't show (the item as configured, not bases merged — WorkstreamSummary.config), remove, and 'check a folder' - Settings → Credentials: declare by id and kind, set a value from a password field (sent once, cleared, never shown back), clear, remove (refused while used), OAuth slots point at codeoid mcp signin - New session: what the folder resolves to and why, an explicit choice; a choice past an exclusive folder is offered with what it would change, and Start anyway resends with the override token - a workstream chip in the session header and the session list (orphaned red, override amber); the list filter matches workstream names - live: workstreams.changed refetches what's shown Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix: workstreams W2 — the UI journey with screenshots at every viewport; fixes they showed - e2e: Settings lists and adds a workstream, a credential value is set and never shown back, the new-session dialog says what the folder resolves to, a choice past an exclusive folder is offered and confirmed, and the chip shows it — screenshots at 375x667, 390x844, 768x1024, 1280x800, 1470x830, 1920x1080 and 1280x300, the override's buttons asserted inside the window - the Default select no longer overflows a phone's width; the override offer scrolls into view as it appears and says what the choice gets accurately Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix: workstreams W2 audit round 1 — edits apply both blocks, live env, a header is part of a credential, editor survives refreshes Daemon: - an edit applies both the workstreams and the credentials block from the file as written: a hand edit since boot is never shadowed by a stale copy - a session's workstream env is read live: a credential set, swapped or cleared, an env entry removed, reaches the backend at its next start, and a changed env rebuilds the backend at the next turn like its servers - a credential's header is part of its hub client and of the per-call check: redeclaring it with another header is another credential - credential.delete takes a strict id and refuses an undeclared one; deleting an OAuth slot signs it out; a value set in the daemon's real environment is refused (it would win at the next start); an edit's reply needs no settings:read; the revision covers credentials too Web: - workstream rows are keyed by id: an open editor keeps what was typed when the list refreshes (another client's edit, a toggle) - a forced refresh during a fetch refetches after it, so the newer list wins - the editor checks env and server lines before sending; failed settings saves put the control back; remove and clear confirm, with Cancel, busy-guarded; the credential field uses new-password - New session: the last folder's answer never shows for a new one, a failed check says so, the override offer names workstreams as the picker does and clears on a mode switch, focus moves to create after choosing the folder's, and workstream_required is said in the UI's words with the picker focused Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix: workstreams W2 audit round 2 — env changes rebuild a backend without MCP servers, shadowed .env values refused, an OAuth slot's removal signs every tenant out - A session with no MCP view never rebuilt its backend when its workstream's env changed: #applyMcpView returned early. The env check now runs before the view check, and #envBuiltWith keeps a sha256, not the values. - loadDotEnv records the keys the real environment shadowed; set_value refuses those too, as it did a key set only in the real environment. - Removing an OAuth credential forgets its slot for every tenant and URL (Store.clearMcpOAuthSlot, McpOAuth.forgetSlot), never the default sign-in. - Credentials rows keyed by id, so a refresh keeps a typed value. - New-session dialog: the workstream picker in collaborative mode; pipeline runs get UI-worded workstream errors (showCreateError). - The dialog's deferred focus no longer moves focus already inside it (a fast fill typed the workdir into the name: the e2e flake). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> * feat: workstreams W3 — read fence, scoped recall, references and moves by share policy (#464) * feat: workstreams W3 — a workstream's folders, a session's read fence, share verdicts for references and moves Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat: workstreams W3 — the read fence: sandbox roots and hidden paths from the session's workstream, file tools refused in another workstream's folders Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat: workstreams W3 — episodes record their workstream; recall, timeline and get_episode keep to the home and its references Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat: workstreams W3 — references at create and mid-session by share policy, moving a session to another workstream Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix: lint — no assignment in an expression Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat: workstreams W3 — CLI and web UI for references and moves; docs - codeoid new --ref, codeoid workstream ref add|rm, workstream move - the session header's chip opens what the session reads and a move; the new-session dialog offers what it may read (under isolation) - a fresh session's sandbox no longer says its directories changed Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix: lint — plain strings Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix: a test's memory stub has the session scope W3 registers Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix: workstreams W3 audit round 1 — every other workstream's folder is fenced, with what the session reads carved out; its own workdir always readable - fenceFor: no foreign folder is dropped for being nested in the home's or holding it; WorkstreamFence.readable (workdir, home, exactly what a reference grants) is carved out — the gate checks it, the sandbox hides every other entry on the way (carveOut), else the folder whole - the home is never a workstream's folder, nor a repository top above it - a session's own workdir stays readable after a move or an override - extraction: a glob's partial last segment, ACP locations, pi's @ and find/ls; a relative path with an unknown cwd is refused - an added sandbox dir inside a fenced folder is refused and never kept - reference inputs held to the binding's own bounds; an unreadable stored binding seals the session (no home, never moved) - the session map and the frozen memory index keep to the workstream - the chip's panel takes focus and follows the window Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix: workstreams W3 audit round 2 — monorepos keep to the package, granted paths where they really are, changes at the turn boundary - a session's repository top is its own only where no other workstream's folder holds it; a recorded home widens to its top only where no other workstream has a folder inside it; folders are no longer collapsed - reference paths resolved at grant, and counted only where they really are inside the granting workstream (no .., no link planted later) - Session.setWorkstream saves at once and applies at the next turn's start - a move adds the old home to readFrom; a home in another workstream's folder is judged by that one's share (closed refuses); the claim and the bounds are judged again when an ask is answered - the gate's folder forms are prepared once per fence; a session's own folder may be written though a reference holds it - globs judged at their start and their dir; pi's @ only before a path Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat: workstreams W4 — the conductor reads across workstreams without a closed one's text, and acts through workers homed where the work belongs (#465) * feat: workstreams W4 — the conductor reads across workstreams without a closed one's text, and acts through workers homed where the work belongs - fleet tools name each result's workstream and take a workstream filter; a closed workstream's episode text never reaches fleet_find, fleet_summary, fleet_recall or a worker's digest (status only) - fleet_spawn takes workstream: judged before queueing as a create is (a folder with none needs one; an exclusive folder is an override the approval card says; a closed one's folder never), stored on the task and judged again at claim - every send-class approval card (web, Telegram) names the workstream it acts in, with the override warning approving it confirms - egress stub: planEgress (a message is sent by a worker homed in its workstream) - the conductor recalls its own episodes under isolation - the fleet rail docks from md up, so a phone's approval card has the width Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix: workstreams W4 audit round 1 — untagged text judged by its session, confirmations tied to the card the owner approved - untagged episodes are withheld by their session's workstream (live or stored), unknown ones while any workstream is closed; a closed one's hits are dropped from fleet_find / fleet_recall before anything is counted; machine_map leaves out its branches - a worker's digest is withheld from the conductor only; the conductor's tenant-wide task board withholds an orchestrator's closed results - an override or an ask folder counts as confirmed only by the owner's own approval of that very card, once, at that config revision (checked again at claim); a delegated token can't approve such a card - an unnamed spawn keeps the remote-changed guard; a closed workstream's worker works only in its own folders - codeoid approve and the terminal show the card's workstream Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix: workstreams W4 audit round 2 — a confirmation is a one-time token on the approved call, checked against exactly what its card showed - the owner's own approval of a card that needed confirming adds a token to that call's input; its handler accepts it once, for the tenant, workdir, workstream, conflicting workstream, ask folders and revision the card was judged on (no leftover, stale or denied approval confirms anything) - only the session owner's own token confirms (not another member's) - the warning names the workstream it passes; the TUI shows it too - conductor tasks known by the routing rule (no goal), not today's URI - a stored session judged by its recorded home; answers memoised briefly - an unnamed spawn's claim judged as when queued; a closed workstream with only remote rules may work in a folder it matches Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix: the W4 e2e follows the warning that names the workstream passed 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>
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.
Stacked on #463 (W2) → #462 (W1) → #461 (W0). Design:
docs/workstreams-design.md§5.3, §6.4, §7, and the new §12.1 "W3 as built". User guide:docs/CONFIGURATION.md→ "Reading another workstream, and moving a session".Everything enforced here is on only with
workstreams.isolateGlobalServers, the same switch W1 uses.What
workstreams/folders.ts; bounded, links followed only where a rule names them) plus the folders recorded as its sessions' homes. The fence is not "everything outside the home", which would refuse toolchains and system headers.WorkstreamFence.readablestays open: the session's own workdir, its home's folders, and exactly what its references grant.@parent. Everything else in a foreign folder is hidden (extraHidden,carveOut), and an added dir inside a foreign folder is never kept.workstreams/gate.tschecks every tool call's read, search and write paths in every mode. Claude's PreToolUse hook refuses the same calls, because the CLI skipscanUseToolfor some of them.workstream_idwhen written.recall,timelineandget_episodekeep to the home and its references (MemoryEngine.scopeSession).session.create.references,session.add_reference,session.remove_referenceandsession.set_workstream.openis granted;askneeds the owner's own undelegated approval, or a confirm on the session that is judged again when answered;closedis refused.readFrom, kept for the session's lifetime). A home inside another workstream's folder counts as reading that folder.codeoid new --ref,codeoid workstream ref add|rm,codeoid workstream move.Audits
Two deep rounds, folded in:
fix: … round 1):~became a repository top;fix: … round 2):..or links;Known limits are listed in §12.1:
Bashin an unsandboxed session isn't asked about;Verification
bun run typecheckandbun run lint: clean.inside real bubblewrap > conversations are the session's own, which also fails onmainon this machine.auth-refresh,embed-refresh,handoffandprompt-drafts, the same set that was failing before; the new chip and dialog tests pass.workstreams-w3.spec.ts(CLI references and moves; the web UI's dialog and chip panel). It has screenshots at 375×667, 390×844, 768×1024, 1280×800, 1470×830, 1920×1080 and 1280×300, with the geometry asserted, and I opened and checked each one.main, so these checks run here once the stack below merges.🤖 Generated with Claude Code