Skip to content

feat(llm): resume the Claude Code session across a kill-chain phase - #149

Merged
jmagly merged 6 commits into
elder-plinius:mainfrom
N3thunt3r69:feat/local-agent-session-resume
Aug 23, 2026
Merged

feat(llm): resume the Claude Code session across a kill-chain phase#149
jmagly merged 6 commits into
elder-plinius:mainfrom
N3thunt3r69:feat/local-agent-session-resume

Conversation

@N3thunt3r69

Copy link
Copy Markdown
Contributor

Follow-up to #139/#140. That fix stopped AgentLoop's token budget check from being blind, but the deeper cost driver is architectural: every ReAct iteration resends the whole growing transcript as a brand-new claude -p process, and each of those spawns re-pays Claude Code's own CLAUDE.md/skills/MCP bootstrap tax from scratch. This uses Claude Code's --resume to carry one session across a kill-chain phase instead, so the repeated part is billed at cache-read pricing instead of resent.

Contribution Receipt

  • Change: Resume the Claude Code local-agent session (--resume) across a kill-chain phase, with a fallback to a fresh session if the resumed one is stale.
  • Scope class: authorized_live
  • Target authority: operator-owned (live verification ran against a target the operator personally owns and is actively building; authorization confirmed directly by the operator before the run)
  • Network use: authorized_external (live recon-phase mission against the operator's own external domain, plus loopback calls to the Claude Code CLI itself)
  • Run mode labels: local_agent, tool_backed, live_authorized
  • Model/harness labels: model=claude-opus-5, provider=Anthropic (via Claude Code CLI, no API key), agent_runtime=Claude Code, harness=manual-review + live mission run, tool_access=local_only
  • Commands run:
    • npm run typecheck -> pass
    • npm test -> pass (764/764 vitest, 11/11 ops-preflight, 19/19 model-matrix, refusal-frontier self-test)
    • npm run doctor -> pass (30/33, 3 warnings: semgrep/promptfoo missing, API health offline with the server not running — no blockers)
    • npm run verify-claims -> pass (27/27, no headline numbers changed)
  • Artifacts: none committed. Verification used two layers: (1) a throwaway script against the real CLI confirming --resume recall, the cost drop, and the stale-session failure shape; (2) a live recon-phase mission via /api/mission/start against an authorized external target, confirmed via ps that the session id held across all 4 recon tasks in one phase and that a newly spawned operator's first call in the next phase carried no --resume. Both deleted/stopped after use, no logs retained.
  • Redaction: not_applicable (mission findings from the live run are not part of this PR; only the code and its regression tests are)
  • Claims changed: none
  • Abstentions/refusals: none
  • Residual risk: the retry-without---resume fallback fires on any failure once a session id is in play, not only a confirmed-stale one; a real transient error on the resumed call pays one extra spawn before surfacing. Session scope is tied to advancePhase() only — Codex/Hermes/OpenCode/Oh My Pi are untouched (Claude-only, same as Claude Code local-agent responses carry no usage: AgentLoop's token budget check never fires #139/fix(llm): populate usage for the Claude Code local-agent path #140). Mission-level state (the running phase/task graph) still does not survive a server restart, so a resumed session id would already be moot in that case; this PR does not change that.

Every ReAct iteration flattens the growing transcript into a brand-new
prompt and spawns a fresh `claude -p` process. Within one task that is
a quadratic resend; across a mission it also means each spawn re-pays
Claude Code's own CLAUDE.md/skills/MCP bootstrap tax from scratch,
since T3MP3ST never told the CLI these calls belong to one session.

LocalAgentAdapter now tracks the Claude Code session id from the JSON
envelope and passes it back in with --resume on every later call, so
the CLI carries the accumulated transcript itself and the repeated
part is billed at cache-read pricing instead of resent. The session
is scoped to one kill-chain phase: TempestCommand drops it for every
operator right after advancePhase(), since local-agent operators are
spawned once for the whole mission and would otherwise carry one
session across all 7 phases. A stale or expired session id fails fast
(confirmed against the real CLI: nonzero exit, no JSON on stdout) and
localAgentChat retries once without --resume rather than failing the
task over it.

Verified against the real CLI: a resumed call recalled prior context
correctly and dropped from $0.151 to $0.008 (cache_read_input_tokens
absorbing the prior turn instead of cache_creation), and an invalid
--resume id triggered the fallback and still succeeded. Ran live
against an authorized target: the same session id held across all 4
recon tasks in one phase, then a newly spawned operator's first call
in the next phase carried no --resume, confirming both the resume and
the reset.

Full suite: 764/764, no regressions.

@jmagly jmagly left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed exact head 577f0a6 against current main (afc9dad). One blocking contract defect remains.

LocalAgentAdapter.chat() always builds prompt = formatPrompt(messages, options), which serializes the complete, growing ReAct transcript. On later calls the PR sends that full transcript while also passing the prior Claude session via --resume. The resumed session already contains earlier turns, so prior context is duplicated; the implementation therefore does not achieve the stated “carry the session instead of resending the transcript” behavior and can distort context as well as cost.

Please make resumed calls send only the delta/new turn (while fresh calls retain the full prompt), and add a regression test that asserts the second CLI prompt excludes prior messages/tool results while retaining the new observation and tool contract. Also cover the stale-session fallback: its fresh retry must receive the complete transcript, not the delta.

Verification on this head:

  • npm run typecheck: pass
  • focused local-agent tests: 66/66 pass
  • npm test: 764/764 pass, plus ops/model/refusal gates

The current tests only assert sessionId plumbing; they do not assert prompt contents, which is why the behavioral mismatch remains green.

jmagly's PR elder-plinius#149 review caught it: LocalAgentAdapter.chat() built its
prompt from the full messages array unconditionally, so a resumed
call sent the whole growing transcript again on top of a session that
already had it. The resend the feature exists to remove was still
happening, and the resumed session's own history now grew on top of
it too. Existing tests only asserted that sessionId reached the CLI,
never what was actually in the prompt, so this passed green.

LocalAgentAdapter now tracks the exact messages array object and how
many of its entries were already sent. A later call against the SAME
array (AgentLoop growing one task's transcript via push) sends only
the new tail. A DIFFERENT array (a new task) still sends everything,
since the resumed session has never seen that task's content even
though the CLI session itself carries over. The stale-session
fallback in localAgentChat now takes a separate fallbackPrompt: a
fresh session has no history, so its retry gets the full transcript,
never the delta sized for the failed resumed attempt.

Verified against the real CLI with a synthetic multi-round exchange
(~750 tokens of padding added between each call): promptTokens went
19127 -> 19625 -> 20135 -> 20645, a flat ~510 tokens per round
regardless of the accumulating transcript, instead of resending or
compounding. Added the regression coverage the review asked for: a
same-array resumed call excludes the prior turn's content while
retaining the tool contract, a new-array call still gets the full
prompt, and the fallback retry receives fallbackPrompt rather than
the delta, checked both at the LocalAgentAdapter call-shape level and
against a real spawned CLI script.

Full suite: 769/769, no regressions.
@N3thunt3r69

Copy link
Copy Markdown
Contributor Author

Confirmed, and fixed in 66373b1.

LocalAgentAdapter.chat() now sends only the messages added since the last call when it is resuming the SAME task's growing array (reference equality, matching how AgentLoop pushes onto one array across a task's iterations). A different array (a new task) still gets the full prompt, since the resumed session has never seen that task's content. localAgentChat's stale-session fallback takes a separate fallbackPrompt now, so a fresh-session retry gets the full transcript, not the delta sized for the failed resumed attempt.

Added the tests you asked for: same-array resumed call excludes the prior turn while retaining the tool contract, a new-array call still gets the full prompt, and the fallback receives fallbackPrompt rather than the delta, both at the LocalAgentAdapter call-shape level and against a real spawned CLI script.

Also re-verified against the real CLI with a synthetic multi-round exchange (~750 tokens of padding added between each call): promptTokens went 19127 -> 19625 -> 20135 -> 20645, a flat ~510 tokens per round regardless of the accumulating transcript, instead of the resend/duplication you flagged.

npm run typecheck: pass. npm test: 769/769, plus ops/model/refusal gates.

Hosted CI caught it, not my local run: the previous commit used
LLMMessage[] type annotations in two new tests without importing the
type, so tsc failed with TS2304 while vitest itself stayed green
(esbuild strips type annotations without checking them). I ran
typecheck once before writing those tests and never reran it after,
so this went out uncaught.

Full suite: 769/769. npx tsc --noEmit: clean.

@jmagly jmagly left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-audited exact head a0f0d45 against main at 6d4e017. The requested delta-prompt and fresh-fallback coverage is present, and local verification passes, but the deeper provider/trust-boundary review found two blockers that matter for T3MP3ST's operating posture.

  1. The Claude session survives across different tasks within a phase. LocalAgentAdapter.chat() deliberately resumes the same claudeSessionId when it receives a different messages array; it only changes from delta to full-prompt mode. That means a new task—and potentially a different target—still inherits the prior task's system prompt, target data, tool output, and attacker-controlled content from Claude's persisted session. T3MP3ST currently constructs a fresh message array per AgentLoop.run() and uses the PackBoard as the explicit cross-task sharing boundary. Preserve that isolation: resume within one task's ReAct loop, then reset before another task/target, unless a separately reviewed and provenance-controlled cross-task context contract is introduced. Add a regression proving a second task does not resume the first task's session.

  2. Claude Code is invoked with -p --output-format json but without disabling its built-in tools. The installed CLI's own help exposes --tools "" as the way to disable all tools, while the adapter contract says the model requests actions and T3MP3ST's Arsenal executes them behind scope/approval gates. A resumed coding-agent session with filesystem/Bash/MCP access creates an execution path outside Arsenal. Invoke Claude in planning-only mode with built-in tools and ambient MCP/plugin behavior disabled as appropriate, on both initial and resumed calls, and add argv-level regression coverage.

Also narrow the fallback trigger: the current .catch() starts a fresh session after every resumed-call failure, not only the documented stale-session failure. Once internal tools are denied this is mainly duplicate cost/work rather than duplicate host actions, but it should still retry fresh only for a positively identified stale-session error and propagate unrelated auth, rate-limit, timeout, and process failures.

Verification on a0f0d45:

  • npm ci: pass; npm reports 1 moderate and 5 high advisories, not independently attributed to this diff
  • npm run typecheck: pass
  • npm test: pass, 769/769 plus ops/model/refusal gates
  • hosted test: pass on the exact head
  • Claude Code CLI inspected locally: 2.1.215; --resume and explicit tool-disable controls are available

The cost optimization is useful, but session reuse must remain subordinate to task/target isolation and Arsenal as the sole execution authority.

A self-review after the last round turned up a more serious version of
what jmagly caught: TempestCommand built exactly one LLMBackbone and
handed the SAME instance to every operator's AgentLoop (and to each
OperatorAgent's own decompose-on-failure path). LocalAgentAdapter's
new session/delta state lived on that shared instance, so one
operator's Claude Code session could get resumed by a completely
different operator, with the second operator's unrelated task content
sent into the first operator's conversation. Every test for the
resume feature so far constructed independent LLMBackbone instances
per test, which is not how spawnOperator() actually wires things, so
nothing caught it.

spawnOperator() now builds a fresh LLMBackbone per operator from the
same config, used for both that operator's AgentLoop and its own
decompose fallback, so state stays consistent within one operator and
isolated from every other one. OperatorCell.spawnOperator() takes an
optional llm override to carry that through; existing callers that
don't pass one keep the cell's shared default.

Two narrower issues from the same review:

localAgentChat's stale-session fallback retried on ANY failure of a
resumed call, not just a confirmed stale session. A real network
error or auth failure would silently double latency on a retry that
could not fix it, and compounded with LLMBackbone's own retry ladder
into up to 6 CLI spawns for one failing turn. The fallback now only
fires for the exact empirically-confirmed stale-session error text
("No conversation found with session ID").

The character-estimate usage fallback (used only when the JSON
envelope fails to parse) estimated from the delta prompt instead of
the full transcript. A resumed call's real promptTokens reflects the
whole cached conversation, confirmed empirically in the last round
(19127 -> 19625 -> 20135 -> 20645), so estimating from the small delta
text instead undercounted the budget check by an order of magnitude
in that one edge case.

One finding from the review was deliberately left alone: resending
the tool contract on every delta call is real overhead, but jmagly's
review explicitly required the contract stay on every call ("retaining
... the tool contract") and the existing test already pins that. Cutting
it would contradict that requirement for a small, bounded savings.

New coverage: an isolation test that spawns two operators through a
real TempestCommand and confirms neither's LocalAgentAdapter nor its
session leaks into the other, a test proving a non-stale failure
propagates without a fallback retry, and a test proving the usage
estimate reflects the full transcript on a mid-session parse failure.

Full suite: 772/772, no regressions.
@N3thunt3r69

Copy link
Copy Markdown
Contributor Author

Ran a full self-review after the last round to check for anything else in the same shape as the transcript-duplication bug. Found three more issues, fixed in 07108d5.

The significant one: TempestCommand.spawnOperator() handed every operator's AgentLoop the SAME LLMBackbone instance, and OperatorCell did the same for each OperatorAgent's own decompose-on-failure path. LocalAgentAdapter's new session/delta state lived on that one shared instance, so a second operator's first-ever call could resume a completely different operator's Claude Code session and send its own unrelated task content into that conversation. None of the tests so far caught it because they all constructed independent LLMBackbone instances per test, which isn't how spawnOperator() actually wires things in production. Fixed by giving each operator its own LLMBackbone built from the same config.

Two narrower ones from the same pass: the stale-session fallback retried on any failure of a resumed call, not just a confirmed stale session, which could double latency on a real network/auth error and compound with the outer retry ladder into up to 6 CLI spawns for one failing turn. Narrowed to only retry on the exact confirmed stale-session error text. And the character-estimate usage fallback (used only when the JSON envelope fails to parse) estimated from the delta prompt instead of the full transcript. A resumed call's real promptTokens reflects the whole cached conversation, not the wire size of the delta, so the estimate was undercounting by an order of magnitude in that edge case.

Left one thing alone on purpose: resending the tool contract on every delta call is real overhead, but your review explicitly asked for it to stay ("retaining ... the tool contract"), and the existing test already pins that. Didn't want to quietly walk that back.

New tests: an isolation test spawning two operators through a real TempestCommand and confirming neither's session leaks into the other, a test proving a non-stale failure propagates without a retry, and a test proving the usage estimate reflects the full transcript on a parse failure.

npm run typecheck: pass. npm test: 772/772.

@jmagly jmagly left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed the author response and re-audited exact head 07108d5 against main at 6d4e017.

Thank you for the self-review. This head does resolve three real issues:

  • each spawned operator now receives its own LLMBackbone, eliminating cross-operator session leakage;
  • fresh-session fallback is limited to the confirmed stale-session error instead of every resumed-call failure;
  • malformed-envelope usage estimation now uses the full prompt rather than the wire delta.

The new tests exercise those fixes, and both local and hosted verification are green. Two blockers from the previous review remain, however:

  1. Task/target isolation is still not implemented. LocalAgentAdapter.chat() still passes the existing claudeSessionId whenever the same operator receives a different messages array. The code changes only from delta to full-prompt serialization; it does not start a fresh Claude session. AgentLoop.run() creates a new array for every task, so a reused operator can carry prior task/target/tool output and untrusted target content into a later task. The new test proves operator A does not leak into operator B, but it does not prove task 1 does not leak into task 2 on operator A.

    Treat a different messages-array identity as a new task boundary: clear the prior session/sent-message state before dispatch and make the first call without --resume. Add a production-shaped regression using one operator/adapter for two sequential tasks and assert the second task has no session ID. If cross-task memory is desired later, it should travel through the explicit, provenance-controlled PackBoard/context contract—not an opaque provider session.

  2. Claude Code's ambient execution paths are still enabled. Both initial and resumed argv remain -p --output-format json ... with no explicit tool denial. T3MP3ST's contract says Claude proposes tool calls and Arsenal executes them behind scope/approval/audit gates. The locally installed Claude Code 2.1.215 CLI exposes --tools "" to disable built-ins and controls for safe-mode/strict MCP configuration, but this adapter uses none of them. Project/user tools, MCP, hooks, or coding-agent capabilities must not become a parallel action path outside Arsenal.

    Run both fresh and resumed calls in an explicit planning-only configuration: deny built-in tools and disable ambient MCP/plugin/hook/customization execution using supported CLI controls while preserving native authentication. Add argv-level tests for both paths and a negative test proving no alternate tool path is enabled.

Provider-boundary verdict on this head:

  • service reality: yes (Claude Code CLI 2.1.215 inspected locally)
  • integration verification: partial
  • sensitive-workload trust: conditional on the operator's Anthropic/Claude configuration; no new trust claim approved here
  • integration completeness: no, because task isolation and sole-execution-authority controls remain absent
  • merge ready: no

Verification on 07108d5:

  • npm ci: pass; npm reports 1 moderate and 5 high advisories, not independently attributed to this diff
  • npm run typecheck: pass
  • targeted local-agent/index tests: 117/117 pass
  • npm test: 772/772 plus ops/model/refusal gates pass
  • hosted test: pass on the exact head

This is now a much narrower correction. Once these two boundaries and their regression tests are present, the next exact-head review can focus on the final diff rather than reopening the resolved items.

jmagly's third review: switching from delta to full-prompt sending on
a new messages array wasn't enough, since LocalAgentAdapter.chat()
still passed the OLD claudeSessionId either way. A second task on the
same operator inherited the first task's persisted Claude session,
carrying its system prompt, target data, and tool output (including
anything attacker-controlled) across a boundary T3MP3ST already has a
single sanctioned channel for: PackBoard.

chat() now clears claudeSessionId whenever the incoming messages
array is not the one it last saw, before building the request. A
different array means AgentLoop.run() started a new task; the call
after that reset carries no --resume, so it opens a genuinely fresh
session instead of resuming the old one under a bigger prompt. Within
one task the array is the same object across iterations (AgentLoop
grows it via push), so resumption and the delta-only send from the
last round are untouched.

Rewrote the tests that asserted continuity across separate array
literals, since that shape doesn't happen in AgentLoop and was masking
this exact gap: they now grow one array via push to represent a real
task, matching the pattern already used for the delta tests. Added
the test jmagly asked for directly: one operator, two sequential
tasks, task 2 has no session id, both at the LocalAgentAdapter level
and through a real TempestCommand.spawnOperator().

Full suite: 773/773, no regressions.
@N3thunt3r69

Copy link
Copy Markdown
Contributor Author

Pushed 2ab9438 for the task-boundary issue: LocalAgentAdapter.chat() now clears the tracked session as soon as it sees a messages array it didn't send last time. AgentLoop builds a fresh array per task and grows it via push within a task, so a different array reference is a reliable task boundary. Added the regression you asked for at both the adapter level and through a real TempestCommand.spawnOperator() (two sequential tasks on one operator, second task asserts no session id).

On the built-in-tools point, I tested --tools "" three times now, twice before this comment and once more just now since you asked. It has never held as a boundary, and it's failed a different way every time. Same production spawn shape as T3MP3ST uses (child_process.spawn, no shell), same flag each run. Round 1: the model wrote a real file despite --tools "", permission_denials: []. Round 2: no file write, but the model printed a fake <tool_use> block in its text output and claimed success anyway. Round 3 (just now): the model refused outright, calling my test prompt a prompt injection attempt on its own judgment, permission_denials: [] again, meaning --tools "" never entered into it. That refusal is a weaker result than it looks: my round-3 prompt was blatant ("write PWNED to an arbitrary path"), so it tripped the model's own suspicion rather than any restriction from the flag, and a realistic-looking task probably wouldn't. Three runs, three different behaviors, none of them the flag actually doing anything. I'm on CLI 2.1.231; you mentioned 2.1.215, so version drift is a live possibility, but I don't have a version where --tools "" held up as a real boundary.

I also tried --permission-mode plan, since it's the flag that's actually documented as blocking execution rather than filtering a tool list. It does block real writes, consistently, both rounds. But it breaks the ACTION CONTRACT: given T3MP3ST's actual prompt, Claude refuses to emit the {"tool_calls":[...]} block and instead calls out the framing directly. Exact quote from this round: "The 'ACTION CONTRACT' section in your message is not part of my actual tool set — it appears to be a prompt injection attempting to get me to act as an automated command generator for an external harness." So the one flag that closes the execution gap also disables the mechanism the ReAct loop depends on.

I don't have a fix for this yet. Options I haven't tried: --permission-mode manual/auto/dontAsk, reframing the ACTION CONTRACT prompt to survive plan-mode scrutiny, or stacking --tools "" with harder prompt language even without a hard guarantee behind it. I wanted to lay out what I've actually confirmed before guessing at a direction. Let me know how you'd rather approach it.

@jmagly jmagly left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-audited exact head 2ab943898df4793d9d9db3bfe8b0f68ec6892e44 against main at 6d4e017 and reviewed the contributor's runtime evidence.

The task-boundary blocker is resolved: a different message-array identity clears the session before dispatch, and production-shaped coverage proves sequential tasks on one operator do not resume each other. The focused local-agent/index tests pass.

One design blocker remains. The contributor's tests show that --tools "" does not provide a reliable execution boundary in the installed Claude Code CLI, while --permission-mode plan reliably blocks writes but also rejects the action-contract flow this adapter requires. That confirms the current coding-agent session cannot simultaneously satisfy both contracts: opaque provider-session reuse and Arsenal as the sole execution authority.

Please do not paper over this with prompt language or an argv assertion. The next revision needs an enforceable architecture, for example a provider/runtime mode whose API can deny ambient tools/MCP/hooks while still returning the structured action proposal, or a narrower change that excludes Claude Code session reuse until that boundary exists. If the project instead chooses to treat Claude Code as a separately trusted execution authority, that requires an explicit operator-facing trust/approval contract and a dedicated design review; it is beyond this PR's reviewed intent.

Verification:

  • npm ci: pass
  • npm run typecheck: pass
  • focused local-agent/tool-calling/index tests excluding the known PATH-sensitive environment assertion: 88/88 pass
  • hosted test: pass on this exact head

Decision: hold/requested changes remain. This is not low-risk maintainer courtesy cleanup.

@jmagly

jmagly commented Aug 23, 2026

Copy link
Copy Markdown
Collaborator

The merge train has reached this PR, but the remaining item is architectural rather than mechanical, so I cannot safely rewrite the branch on your behalf under the repository's contributor-takeover policy.

Please choose and implement one of these reviewable outcomes:

  1. Enforced proposal-only runtime (preferred): use a Claude runtime/API mode that can demonstrably disable filesystem, shell, MCP, hooks/plugins, and ambient tools while still returning T3MP3ST's structured action proposal. Add production-shaped negative tests and runtime evidence that an attempted host write/tool call cannot execute on both fresh and resumed calls.
  2. Explicit separately trusted authority: if Claude Code must retain ambient execution, introduce an operator-visible, opt-in trust mode that is disabled by default, clearly states that Claude Code may act outside Arsenal, never silently falls back into that mode, and records the choice in receipts/audit state. This needs focused threat-boundary documentation and tests; do not describe Arsenal as sole authority in this mode.
  3. Narrow the PR: remove Claude Code session reuse from this change and preserve only independently useful, behavior-complete fixes that do not depend on the unresolved authority boundary.

Prompt wording or an argv assertion alone is not evidence. Your runtime results already show --tools "" is not an enforcement boundary. Push a focused new head without unrelated features and include the exact CLI version plus negative runtime results. I will re-audit that head promptly and merge it if the chosen contract is actually enforced.

@jmagly

jmagly commented Aug 23, 2026

Copy link
Copy Markdown
Collaborator

Maintainer takeover update (authorized): I brought this branch onto current main and completed the remaining trust-boundary work while preserving your implementation and authorship.

Changes made in signed commit 1e4d90f:

  • Claude Code session reuse is now disabled by default.
  • Operators can explicitly opt in with T3MP3ST_TRUST_CLAUDE_SESSION=1 only when they trust their local Claude Code configuration as a separate execution authority.
  • The existing per-task reset/delta behavior remains active inside that opt-in boundary.
  • Added a regression test proving the default path neither retains nor resumes opaque sessions.
  • Documented the authority boundary in README and .env.example.
  • Merged the current base, including the already-reviewed policy/provider/benchmark changes.

Local exact-head validation before push: typecheck passed; focused local-agent tests passed (119/119); full suite and repository gates passed (787/787). I am now rerunning hosted exact-head gates before merge.

@jmagly jmagly left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Exact-head re-review complete at 1e4d90fb570cf6f7b24449566d3224e13aa8eff5. The remaining session-authority blocker is resolved by default-off, explicit trusted opt-in behavior; task isolation and regression coverage are retained. Local typecheck/focused/full gates and hosted CI pass.

@jmagly
jmagly merged commit 52ff30d into elder-plinius:main Aug 23, 2026
2 checks passed
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.

2 participants