Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions IMPLEMENTATION_PLAN.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ the smallest repeatable manual script plus expected output.
### Priority: Simplify Tool Execution Context Architecture

**PRDs:** `docs/prd/PRD-001-netclaw-mvp.md`, `docs/prd/PRD-002-gateway-security-envelope.md`, `docs/prd/PRD-006-mcp-tool-integration.md`, `docs/prd/PRD-007-agent-personality-and-local-memory.md`
**Specs:** `openspec/changes/simplify-tool-execution-context/`
**Specs:** `openspec/changes/archive/2026-07-15-simplify-tool-execution-context/`
**Surface area:** tool execution, session actors, subagents, working context
**Verification:** L2 plus behavioral evals

Expand All @@ -135,10 +135,10 @@ Done when:
repository quality gates. Stage 3 eval execution was attempted but explicitly
blocked because the required `NETCLAW_EVAL_*` provider environment was absent;
no model-facing tool schema or prompt behavior changed in that stage.
- [ ] OpenSpec deltas are verified, synced, and archived after the final merge.
- [x] OpenSpec deltas are verified, synced, and archived after the final merge.

Durable execution details and checkbox state live in
`openspec/changes/simplify-tool-execution-context/tasks.md`. Per-run evidence
`openspec/changes/archive/2026-07-15-simplify-tool-execution-context/tasks.md`. Per-run evidence
lives in `.ralph/runs/`; Git commits and PR state remain the recovery source of
truth across context compaction.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,6 @@
## 4. Closeout

- [x] 4.1 Verify all three merged stages against the OpenSpec scenarios and PRD traceability from the merged Stage 3 baseline, including serialization/recovery and MCP compatibility evidence. The full solution passed 5,884 tests; the focused serialization, recovery, MCP adapter/schema, session integration, and subagent integration set passed 183 tests; source inspection confirms volatile run scopes, child scopes, approval capabilities, and Git snapshots are absent from persisted event and MCP payload types.
- [ ] 4.2 Sync the delta specs to main specs with `/opsx-sync`, run `/opsx-verify`, and archive the completed change with `/opsx-archive`.
- [x] 4.2 Sync the delta specs to main specs with `/opsx-sync`, run `/opsx-verify`, and archive the completed change with `/opsx-archive`. Eleven added or modified requirement blocks matched their synced main-spec counterparts, the obsolete audit requirement was removed, all 69 OpenSpec items passed strict validation, and the completed change was archived as `2026-07-15-simplify-tool-execution-context`.
- [x] 4.3 Run the RALPH adversarial output review, diagnostics, and after-action workflow; capture durable follow-ups without leaving undocumented behavior drift. The independent review moved from HOLD to MERGE after all five findings were repaired. The after-action output-quality verdict is PASS; diagnostics are PARTIAL because original per-iteration RALPH logs were not preserved, with Git/PR/OpenSpec/test evidence retained as the durable source of truth.
- [x] 4.4 Remove `IToolAuditLogger`: production registered only `NullToolAuditLogger`, while `ToolCallOutput` and `ToolResultOutput` already flow through the canonical `SessionLogActor` transcript. The active delta removes the obsolete structured-audit requirement without changing shipped output behavior.
18 changes: 18 additions & 0 deletions openspec/specs/actor-message-protocol/spec.md
Original file line number Diff line number Diff line change
Expand Up @@ -168,3 +168,21 @@ because the nested record still implements the routing marker.

- **WHEN** `SessionMessageExtractor.EntityId` is given a `SessionProtocol.SendUserMessage`
- **THEN** it extracts the session id via the `IWithSessionId` marker exactly as before the nesting

### Requirement: Execution-scope refactoring preserves external actor contracts

Run scopes, child scopes, activity trackers, and working-context deltas introduced for tool execution SHALL be framework-owned local actor messages. The refactoring SHALL NOT change existing persisted event shapes or MCP protocol payloads. Local messages SHALL remain serialization-safe where they cross actor boundaries.

#### Scenario: Existing MCP caller invokes a tool

- **GIVEN** an MCP client using the tool schema from before this change
- **WHEN** it invokes the tool after the internal execution refactoring
- **THEN** the request and response protocol remain compatible
- **AND** internal run-scope types are not exposed in the MCP schema

#### Scenario: Actor recovers persisted session state

- **GIVEN** session events persisted before this change
- **WHEN** the updated session actor recovers them
- **THEN** recovery succeeds without a data migration
- **AND** volatile run scopes and Git snapshots are reconstructed only for new work
5 changes: 3 additions & 2 deletions openspec/specs/audience-context-filtering/spec.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,19 +76,20 @@ audiences.

### Requirement: Working context suppression for Public

The working context block, including project directory, recent files, Git worktree paths, branch, HEAD, and dirty state, SHALL NOT be injected into Public-audience main sessions or subagents.
The working context block, including project directory, recent files, Git worktree paths, branch, HEAD, and dirty state, SHALL NOT be injected into Public-audience main sessions or subagents. Public audience eligibility SHALL be decided before Git inspection, so Public turns SHALL NOT start a Git process for working-context enrichment.

#### Scenario: Public session has no working context

- **WHEN** a Public-audience session has a non-empty working context or eligible Git project directory
- **THEN** no `[working-context]` block is injected into the volatile context block
- **AND** no Git inspection result is exposed to the model
- **AND** Git inspection is not invoked

#### Scenario: Public subagent receives no internal working context

- **GIVEN** a subagent is launched under a Public parent turn
- **WHEN** the child initial prompt is assembled
- **THEN** no parent project path, recent-file list, or Git state is included
- **AND** Git inspection is not invoked for the child snapshot

#### Scenario: Team session receives working context

Expand Down
49 changes: 33 additions & 16 deletions openspec/specs/netclaw-session/spec.md
Original file line number Diff line number Diff line change
Expand Up @@ -526,22 +526,41 @@ Backward compat: if `TurnLlmTimeoutSeconds` is configured but

### Requirement: Tool execution encapsulation

Tool execution SHALL be encapsulated in a `SessionToolExecutionPipeline` static
utility class. The pipeline SHALL execute tool calls in parallel, track sub-agent
activity, and send `ToolExecutionCompleted` or `ToolExecutionFailed` back to the
actor. The pipeline SHALL NOT itself bound or clamp tool-result size: bounding the
result to the inline budget and spilling the overflow is done once, centrally, by
`DispatchingToolExecutor` (per the `bounded-tool-output` capability), so the
pipeline stores the result the dispatcher already bounded. `SessionTuning.MaxInlineToolResultChars`
is the session **content** budget the dispatcher uses for tools without a smaller
per-tool override.
Tool execution SHALL be encapsulated in a composed `SessionToolExecutionPipeline`
whose unconditional production services are required constructor dependencies.
The session actor SHALL submit one cohesive batch command whose tool authority is
derived from the admitted `TurnContext`; callers SHALL NOT be able to supply a
second, conflicting authority source. Genuinely unavailable runtime capabilities,
including background-job dispatch, SHALL be represented explicitly while retaining
their existing behavior. The pipeline SHALL execute tool calls in parallel, track
sub-agent activity, and send completion or failure messages back to the actor.

The pipeline SHALL NOT itself bound or clamp tool-result size. Bounding to the
inline budget and spilling overflow remains centralized in
`DispatchingToolExecutor`, so the pipeline stores the result already bounded by
the dispatcher. `SessionTuning.MaxInlineToolResultChars` remains the session
content budget used for tools without a smaller per-tool override.

#### Scenario: Parallel tool execution

- **GIVEN** an LLM response contains 3 tool calls
- **WHEN** `SessionToolExecutionPipeline.ExecuteToolsAsync()` runs
- **THEN** all 3 tool calls execute in parallel
- **AND** results are collected and sent as a single `ToolExecutionCompleted`
- **GIVEN** an admitted turn whose LLM response contains three tool calls
- **WHEN** the session submits its `SessionToolBatch`
- **THEN** all three tool calls execute in parallel with fresh call-local state
- **AND** results are collected and returned through the existing actor protocol

#### Scenario: Conflicting authority cannot be supplied

- **GIVEN** a session constructs a tool batch from an admitted `TurnContext`
- **WHEN** the batch derives its tool run scope
- **THEN** session, audience, boundary, channel, delivery, and interactive-approval authority come from that turn context
- **AND** the caller has no initializer or alternate constructor for replacing the derived authority

#### Scenario: Background manager is unavailable

- **GIVEN** a valid background-capable shell request and no registered background-job manager
- **WHEN** the batch executes
- **THEN** the request executes synchronously as it did before the composition refactor
- **AND** manager absence is not inferred from a nullable security dependency

#### Scenario: Tool execution timeout

Expand All @@ -553,8 +572,7 @@ per-tool override.

- **GIVEN** a tool returns an oversized result
- **WHEN** it reaches the pipeline
- **THEN** the pipeline stores it as-is (already windowed + spilled by
`DispatchingToolExecutor`) without re-clamping
- **THEN** the pipeline stores it as-is without re-clamping

### Requirement: Reminder redelivery best-effort dedup

Expand Down Expand Up @@ -798,4 +816,3 @@ Session approval recovery tests SHALL include direct coverage for turn-context c
- **WHEN** the session redrives the parked tool batch
- **THEN** the user observes the tool result and final assistant response
- **AND** no duplicate approval prompt is emitted for the approved call

12 changes: 7 additions & 5 deletions openspec/specs/netclaw-subagents/spec.md
Original file line number Diff line number Diff line change
Expand Up @@ -420,21 +420,22 @@ Every sub-agent SHALL receive the operating-rules composition for its launch aud
- **THEN** their order is embedded core, deployment playbook, project instructions, sub-agent role, then headless execution contract

### Requirement: Subagents maintain run-scoped working context
Each subagent SHALL own an ephemeral working context initialized from a read-only snapshot of the parent session's project directory and recent files. The initial snapshot SHALL be included in the runtime-context portion of the child user message and SHALL NOT modify the reusable subagent system prompt. Child activity SHALL NOT mutate parent session state during execution.
Each subagent SHALL own an ephemeral working context initialized by forking a read-only snapshot of the parent session's project directory, recent files, and immutable admitted-turn authority. The child SHALL own fresh call-local activity tracking and SHALL evolve its working state independently. The initial snapshot SHALL be included in the runtime-context portion of the child user message and SHALL NOT modify the reusable subagent system prompt. Child activity SHALL NOT mutate parent session state during execution.

#### Scenario: Child receives parent recent-file grounding
- **GIVEN** a parent session with a project directory and recent files
- **WHEN** it spawns a permitted subagent
- **THEN** the child's initial model input contains the parent project directory and recent-file snapshot
- **AND** its tool execution remains grounded by the existing inherited authority context
- **AND** its tool execution uses the explicitly inherited admitted-turn authority

#### Scenario: Child file activity is isolated
- **GIVEN** a running child that reads or changes a file
- **WHEN** the child updates its run-scoped working context
- **THEN** the parent durable working context is unchanged until child completion is handled
- **THEN** the parent durable working context is unchanged until a successful child completion delta is handled
- **AND** another child cannot observe that call-local activity through shared mutable state

### Requirement: Subagent completion returns structured working context
`SubAgentResult` SHALL carry optional structured working-context metadata containing project/worktree identity, files read, confirmed files changed through recognized first-party file tools, files observed changed between bounded Git snapshots, and final branch and HEAD when available. Observed worktree changes SHALL NOT be represented as exclusively authored by the child.
`SubAgentResult` SHALL carry a typed child outcome and structured working-context delta containing project/worktree identity, files read, confirmed files changed through recognized first-party file tools, files observed changed between bounded Git snapshots, and final branch and HEAD when available. Observed worktree changes SHALL NOT be represented as exclusively authored by the child. Failed or cancelled outcomes SHALL carry no mergeable delta.

#### Scenario: First-party edit is confirmed
- **GIVEN** a child changes a file through a recognized first-party file tool
Expand All @@ -456,4 +457,5 @@ Each subagent SHALL own an ephemeral working context initialized from a read-onl
#### Scenario: Failed child does not merge partial activity
- **GIVEN** a child fails or is cancelled after touching files
- **WHEN** the parent handles the failure result
- **THEN** no child file metadata is merged into parent durable working context
- **THEN** the outcome contains no mergeable working-context delta
- **AND** no child file metadata is merged into parent durable working context
24 changes: 24 additions & 0 deletions openspec/specs/netclaw-testing/spec.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,3 +65,27 @@ The behavioral eval suite SHALL support focused multi-turn coding-context cases
- **WHEN** the focused coding-context category is run repeatedly
- **THEN** results retain correctness, orientation-call, clarification, token, cache, and latency metrics for comparison

### Requirement: Execution-context isolation has automated proof

The test suite SHALL prove that admitted authority is required, parallel calls do not share mutable call state, unavailable requested capabilities fail without fallback, child deltas merge only after success, and asynchronous Git enrichment respects audience and turn-generation gates.

#### Scenario: Parallel execution regression test

- **GIVEN** a deterministic test pipeline with two concurrent tool calls
- **WHEN** each call records different file activity
- **THEN** each result contains only its own activity
- **AND** both retain the same immutable admitted-turn authority

#### Scenario: Public Git gate regression test

- **GIVEN** a fake Git inspector that records invocations
- **WHEN** a Public working-context snapshot is composed
- **THEN** the inspector records no invocation
- **AND** no internal path is rendered

#### Scenario: Stale continuation regression test

- **GIVEN** controllable asynchronous Git inspection results for consecutive turns
- **WHEN** the earlier result completes after the later turn becomes active
- **THEN** the earlier result is discarded without sleeps
- **AND** only the correlated result can affect the active prompt
53 changes: 53 additions & 0 deletions openspec/specs/netclaw-tools/spec.md
Original file line number Diff line number Diff line change
Expand Up @@ -399,3 +399,56 @@ inline bound + spill (if any) is applied centrally per `bounded-tool-output`;
- **THEN** the result returned to the model has the secret redacted (by the
central dispatcher redaction)

### Requirement: Tool invocation requires an admitted run scope

Every first-party tool invocation SHALL receive a non-null immutable invocation context created from an immutable run scope after audience admission. The runtime SHALL NOT expose a context-free production execution overload, an empty production execution context, or nullable authority dependencies. Mutable tool outputs SHALL be written through a separate per-invocation append-only sink, and approval attempt state SHALL remain outside the tool-visible context. Each invocation SHALL receive fresh output and approval state even when calls share one run scope.

#### Scenario: Parallel calls do not share call-local state

- **GIVEN** two tool calls in the same admitted turn
- **WHEN** the calls execute concurrently
- **THEN** both calls share the same immutable run authority
- **AND** outputs or approval mutations from one call are not visible to the other call

#### Scenario: Missing authority cannot reach dispatch

- **GIVEN** a caller has not constructed an admitted run scope
- **WHEN** it attempts to invoke a first-party tool
- **THEN** no context-free API permits dispatch
- **AND** the tool does not execute under default authority

### Requirement: Execution limits use validated semantic values

Timeouts, inline output budgets, and other scalar execution limits crossing the tool pipeline SHALL use validated semantic value objects. These value objects SHALL require explicit primitive access and SHALL NOT define implicit conversions to or from primitive types.

#### Scenario: Invalid limit is rejected at construction

- **GIVEN** an execution limit outside its permitted range
- **WHEN** the run scope or tool metadata is constructed
- **THEN** construction returns a validation failure before tool dispatch
- **AND** no default primitive value is substituted

### Requirement: Tool-enabled sessions require execution infrastructure

A tool-enabled session SHALL have authorization, approval, logging, and dispatch infrastructure available before accepting a tool batch. Infrastructure that production constructs unconditionally SHALL be a required dependency rather than a nullable feature switch. Interactive approval SHALL be represented as one required capability value: unavailable, or available with its required bridge. Tool-call and tool-result observability SHALL flow through the session's canonical `ToolCallOutput` and `ToolResultOutput` transcript path; the execution pipeline SHALL NOT require a parallel no-op audit sink.

#### Scenario: Security dependency is unavailable

- **GIVEN** required authorization or approval infrastructure cannot be constructed
- **WHEN** the session attempts to enable tools
- **THEN** session initialization or batch execution fails visibly
- **AND** the missing dependency does not disable its check

#### Scenario: Interactive approval cannot disagree with its bridge

- **GIVEN** a tool invocation has no admitted interactive approval bridge
- **WHEN** path and shell policies evaluate autonomous trust-zone restrictions
- **THEN** the invocation is represented as non-interactive
- **AND** no nullable support flag can bypass those restrictions

#### Scenario: Production tool transcript has one owner

- **GIVEN** a production tool invocation is admitted and executed or denied
- **WHEN** the session publishes its tool-call and tool-result outputs
- **THEN** the existing session transcript path receives those outputs
- **AND** execution does not also depend on an always-discarded audit logger
Loading
Loading