# Netclaw Implementation Plan Execution plan last updated: 2026-08-28. Restart review proposal added: 2026-09-18. This is the execution plan for Netclaw. Autonomous agents and RALPH-style loops SHALL work from `NOW` by default. `NEXT` and `LATER` work belongs in `BACKLOG_PARKING_LOT.md` unless the user explicitly reprioritizes it. ## Operating Principle: Swing Through The Ball A task is not done when the local component accepts input, renders a screen, or writes a file. A task is done when the downstream runtime path consumes the produced artifact successfully, or bad input is rejected before it crosses the boundary. Examples: - A config editor is done only when runtime startup/ACL/routing consumes the saved shape it emits. - A TUI flow is done only when typed input, paste input, persisted state, re-entry, and semantic smoke assertions all agree. - A tool or adapter is done only when policy denial, invalid credentials, missing resources, and happy-path dispatch are all covered. - A planning task is done only when PRD, spec, OpenSpec, tests, docs, and skill guidance point at the same behavior. ## Verification Levels Use the highest level required by the task. Higher levels include the lower levels unless explicitly stated otherwise. | Level | Name | Required proof | |-------|------|----------------| | L0 | Planning-only | PRD/spec/docs updated; no runtime behavior changed. | | L1 | Unit/contract | Targeted unit or contract tests prove pure behavior, serialization, validation, mapping, or policy decisions. | | L2 | Integration | Component integration tests prove real persistence, DI, actor lifecycle, config binding, or fake-provider boundaries. | | L3 | Interactive/smoke | Native smoke tape, CLI/TUI smoke, or equivalent real binary exercise proves the user-visible path. | | L4 | Live/demo/e2e | Aspire demo, live provider, Docker image, or full runtime flow proves external/runtime wiring. | ## Non-Negotiable Quality Gates These gates apply to every `NOW` task unless the task explicitly says why a gate does not apply. - [ ] **Discovery gate:** Read the matching PRD, spec, OpenSpec capability, and active change plan before coding. - [ ] **Consumer gate:** Name the downstream consumer of any config, event, actor message, persisted record, tool schema, or protocol payload the task writes. - [ ] **Canonical representation gate:** Prove the producer emits the exact representation expected by the consumer, not merely a schema-valid value. - [ ] **Negative-path gate:** Add at least one invalid/unresolved/denied test for every security-relevant or routing-relevant input. - [ ] **No silent fallback gate:** Misconfiguration fails visibly; fallback is allowed only when partial failure is normal runtime behavior. - [ ] **Schema gate:** Any `*Config` property change updates `src/Netclaw.Configuration/Schemas/netclaw-config.v1.schema.json`. - [ ] **TUI gate:** Termina/init/config changes run the native smoke harness and include semantic assertions, not just screen text. - [ ] **Runtime gate:** If config drives runtime behavior, verify startup, runtime binding, ACL, routing, or tool execution consumes the saved config. - [ ] **Docs/spec gate:** Behavior changes update the relevant docs/specs and any mapped system skill. - [ ] **Repository gates:** Run `dotnet test`, `dotnet slopwatch analyze`, `pwsh ./scripts/Add-FileHeaders.ps1 -Verify`, and `git diff --check` unless the task explicitly scopes to docs-only work. ## Automation-First QA Floor The human bare minimum should be priority calls, secrets/credentials for live checks, and occasional high-risk UX spot checks. Agents are responsible for the automatable proof below. | Recent bug class | Required automation | Human minimum | |------------------|---------------------|---------------| | Typed input does not reach a TUI field | Headless Termina test with `VirtualInputSource` covering typed characters, paste, Tab/focus movement, Enter/submit, Escape/back. Critical flows also need a native VHS smoke tape. | Run or review one live command only when a real terminal/TTY bug is suspected. | | Dynamic validation does not run | Fake-provider failure test proving save is blocked, persistence is unchanged, and the visible error is shown. Tests must call the same public save path the UI uses. | Provide real provider credentials only for optional live probes. | | Old config paradigm not ported to new editor | Load/round-trip tests from existing config and secrets into the new editor model, then back to disk. Tests must assert dormant values and secrets are preserved unless reset/delete is explicit. | Confirm whether stale fields should migrate, preserve, or fail. | | Config shape accepted but runtime cannot consume it | Contract test between editor/init output and runtime options/ACL/routing/startup consumer. Assert canonical IDs/names/permissions, not just schema validity. | Decide behavior for ambiguous external API cases. | | Smoke passes while semantic behavior is wrong | Smoke assertion script checks canonical persisted values, encrypted secrets, runtime-visible config, and error states. Screen text alone is not enough. | Review smoke artifact only if the assertion fails or UX changed substantially. | | Async UI action fails silently | Public async method has direct tests; fire-and-forget handlers catch exceptions and surface status errors. Test fake exceptions from validation/save dependencies. | None by default. | | Secret rotation/reset reintroduces old behavior | Tests cover blank-preserve, nonblank-replace, disable-preserve, reset-delete-immediate, and reopen-after-reset. | Confirm destructive copy in the UI. | Minimum automation by surface area: | Surface | Minimum gate | |---------|--------------| | Config editor | Static validation test, dynamic fake-failure test, existing-config round-trip test, config-to-runtime consumer test, native smoke for visible TUI paths. | | Init wizard | Headless typed-input test for each prompt kind, native `init-wizard` smoke, existing-install path test, destructive-action double-confirm test. | | Channel adapter | Options-binding test, ACL allow/deny tests, malformed/missing credential test, reply/routing integration or opt-in live smoke. | | Tool/MCP | Schema generation test, schema coercion negative test, permission allow/deny/prompt tests, malformed metadata test. | | Persistence/memory/session | Serialization round-trip, restart/recovery test, corrupt/missing state test, eval suite when prompt/memory behavior changes. | | Packaging/demo | Install smoke, Docker image binary/version check, health endpoint check, opt-in demo smoke when runtime wiring changes. | Manual-only acceptance criteria are not allowed for `NOW` implementation tasks. If something truly cannot be automated, the task must say why and must provide the smallest repeatable manual script plus expected output. ## Current Source Artifacts - Product: `PROJECT_CONTEXT.md`, `docs/prd/README.md`, `docs/prd/PRD-001-netclaw-mvp.md` - CLI/config: `docs/prd/PRD-004-cli-onboarding-and-config.md`, `docs/spec/SPEC-004-cli-contract.md`, `docs/spec/SPEC-007-guided-onboarding.md`, `openspec/specs/netclaw-config-command/spec.md`, `openspec/changes/netclaw-config-command/tasks.md` - Security/gateway: `docs/prd/PRD-002-gateway-security-envelope.md`, `docs/spec/SPEC-001-runtime-boundaries.md`, `docs/architecture/tool-authorization.md`, `openspec/specs/tool-authorization/spec.md` - Input adapters: `docs/prd/PRD-009-input-adapters-and-unified-input.md`, `openspec/specs/netclaw-input-adapters/spec.md`, `openspec/specs/netclaw-slack-socket/spec.md`, `openspec/specs/netclaw-discord-socket/spec.md`, `openspec/changes/add-mattermost-channel/tasks.md` - Models/providers: `docs/prd/PRD-005-model-provider-strategy.md`, `docs/spec/SPEC-008-model-provider-abstraction.md`, `openspec/specs/netclaw-model-providers/spec.md` - MCP/tools: `docs/prd/PRD-006-mcp-tool-integration.md`, `openspec/specs/netclaw-mcp/spec.md`, `openspec/specs/netclaw-tools/spec.md`, `openspec/specs/tool-authorization/spec.md` - Memory/personality: `docs/prd/PRD-007-agent-personality-and-local-memory.md`, `openspec/specs/netclaw-agent-memory/spec.md`, `openspec/specs/project-instructions/spec.md` - Scheduling: `docs/prd/PRD-008-scheduling-and-periodic-tasks.md`, `openspec/specs/netclaw-scheduling/spec.md`, `openspec/specs/reminder-execution-history/spec.md` - Testing: `docs/spec/SPEC-010-testing-and-smoke-strategy.md`, `TOOLING.md` ## Review Proposal: Shorter Daemon Restarts Status: Approved for implementation on 2026-09-18. This plan does not authorize a live daemon restart. Baseline revision: `a4b81b5c9184d1986bfa7d872e0932ac636d4b71`. Source PRDs: [PRD-001 FR-016](docs/prd/PRD-001-netclaw-mvp.md#fr-016-config-change-restart-coordination) and [PRD-008](docs/prd/PRD-008-scheduling-and-periodic-tasks.md). Related contracts: [SPEC-011](docs/spec/SPEC-011-daemon-architecture.md), [session resume](openspec/specs/session-resume/spec.md), and [reminders](openspec/specs/netclaw-scheduling/spec.md). Use the [engineering glossary](docs/spec/GLOSSARY.md) for shared terms. ### Objective Reduce the stop-to-listener interval while Netclaw preserves accepted work. Do not replay a tool after its effect can be uncertain. Do not increase the original turn authority. Do not add channel-specific recovery code. This work excludes CLI display latency and recovery after an ungraceful crash. Issue [#2199](https://github.com/netclaw-dev/netclaw/issues/2199) tracks CLI latency. ### Observed Delay One local restart supplied this evidence: | Phase | Observed time | Finding | |---|---:|---| | Session drain | 190 seconds | Two sessions waited on durable approvals until the deadline. | | Later teardown | About 16 seconds | Browser MCP disposal used about 10 seconds. | | Service gap | About 26 seconds | The available logs do not assign this delay. | | Process start to listener | About 8.2 seconds | Startup work delayed listener readiness. | The startup trace included these approximate costs: - Process setup and model probes used 1.5 seconds. - SQLite and memory startup used 1.4 seconds. - Four MCP connections used 4.2 seconds. - Final hosted services used 1.1 seconds. PR #2203 now connects independent MCP servers concurrently. A new trace must measure its actual startup gain. The unexplained 26-second service gap remains a separate investigation. ### Approved Stop Policy Any graceful stop can create a restart reminder for safely interrupted work. This policy covers updates, manual restarts, service restarts, and pod replacements. A forced process kill cannot create this guarantee. A restart reminder expires ten minutes after the interruption. The deadline does not reset after another process start. An expired reminder logs one warning and does not start model work. Netclaw creates no reminder for these states: - The session completed its work and waits for user input. - A tool can have an uncertain external effect. - Partial assistant text reached the output stream. - The stored turn has no channel type for current-session delivery. - Pending inputs have different authority. An open approval remains parked in the journal. The existing approval path can re-drive it after user action. This slice accepts temporary approval UI inconsistency after restart. ### Minimal Design The design reuses these owners: | Data or decision | Owner | Lifetime | |---|---|---| | Accepted input and original authority | Session journal | Durable | | Selected input and current turn authority | `SessionInputFlow` | Actor-local | | Active model and tool cancellation | `SessionExecutionLifetime` | Actor-local | | Wakeup schedule and delivery | Reminder manager | Durable | | Cross-process handoff | Restart manifest | Durable until startup reads it | The session stores each accepted input before it sends an acknowledgment. The record contains its ID, content, media, source ID, and `TurnContextRecord`. Journal order supplies input order. Terminal turn events close the consumed input IDs. The session lifetime owner gives an active model call a two-second completion grace. It then cancels the call and waits for that exact task to stop. A durable approval wait uses the existing tool pipeline cancellation token. The lifetime owner does not cancel a tool with an uncertain effect. The actor returns one standard `ReminderDefinition` after a safe interruption. The reminder uses `DeliveryKind.CurrentSession` and expires after ten minutes. Its instruction is `Resume the work that was interrupted by the daemon restart.` The restart manifest stores the definition. Startup registers each fresh definition through `SaveReminderCommand`. The reminder manager owns scheduling, retry, deduplication, and delivery. Existing gateways deliver the reminder through their current path. The session recognizes the internal reminder ID. It restores pending input and its original `TurnContextRecord` from the journal. The reminder supplies a wakeup signal only. Its automation authority does not replace the stored authority. No route binder is required. No channel state is stored. No resume candidate protocol is required. No channel adapter changes are allowed. ### Ordered Flow This flow is schematic. It omits persistence callbacks and normal reminder settlement. ```text input -> session: SendUserMessage session -> journal: InputAdmitted journal -> session: stored session -> source: CommandAck stop -> session: PrepareForDaemonRestart session -> model: cancel and await exact task session -> stop: standard ReminderDefinition or none stop -> manifest: restart reminders start -> reminder manager: SaveReminderCommand gateway -> session: ordinary reminder turn session -> journal: restore pending input and authority session -> model: resume stored work ``` ### Risk Controls | Risk | Control | Required proof | |---|---|---| | Lost accepted input | Persist before acknowledgment. | Actor test with journal replay. | | Duplicate input after a lost acknowledgment | Keep a bounded source ID ledger. | Retry test with one pending record. | | Duplicate tool effect | Close input before tool execution. Do not cancel uncertain effects. | Actor test for a started tool batch. | | Repeated partial reply | Track streamed text. Do not create a reminder. | Actor stream test. | | Stale wakeup | Store an absolute ten-minute expiry. | Fake-time startup test. | | Wider authority | Restore the journaled `TurnContextRecord`. | Actor test with low trust input. | | Duplicate reminder registration | Use one stable reminder ID and `CreateOnly`. | Startup conflict test. | | Missing delivery route | Require a stored channel type. Let the reminder system resolve the gateway. | Actor test with missing channel context. | | Manifest truncation | Write the manifest atomically. | Store round-trip test. | | Long cooperative cancellation | Keep the bounded daemon stop deadline. | Test a client that ignores cancellation. | ### Pull Request Stack **PR #2207: Plan and contracts.** - Record the measured delay and its limits. - Record the ten-minute policy and safety boundaries. - Keep all later pull requests traceable to this objective. **PR #2208: Stop durable approval waits.** - Cancel only a tool pipeline that waits only on journaled approvals. - Wait for the exact pipeline task before drain acknowledgment. - Keep the approval request usable after cold recovery. **PR #2209: Persist accepted input.** - Add `InputId`, `InputAdmitted`, and `InputClosed`. - Persist input before acknowledgment. - Restore pending input from the journal and snapshots. - Deduplicate a retry by its stable source identity. **PR #2210: Resume through the reminder manager.** - Give the active model call a two-second grace. - Cancel and await an eligible call. - Put a standard restart reminder in the manifest. - Register fresh reminders at startup. - Restore original input and authority when the reminder arrives. - Change no channel-specific file. **PR #2211: Bound daemon stop time.** - Reduce the final daemon stop budget to 30 seconds. - Keep the drain deadline below the host and service deadlines. - Preserve timeout diagnostics for sessions that cannot stop safely. ### Validation Run focused actor tests for the state transitions and journal boundaries. Run daemon tests for manifest production and reminder registration. Run reminder tests for one-shot expiration. Run the behavioral eval suite because the operations skill changes. Use `https://spark2.testlab.petabridge.net/` for eval execution. Run `dotnet slopwatch analyze` after code changes. Run `./scripts/Add-FileHeaders.ps1 -Verify` after code changes. Run OpenSpec validation for each changed contract. A process check must use a disposable `NETCLAW_HOME`. It must prove a fresh reminder resumes work once. It must prove an expired reminder stays quiet. It must prove a parked approval remains usable. It must not replace the active daemon binary on this system. ### Completion Conditions - Approval-only drain finishes after pipeline cancellation. - Safe model interruption returns one standard reminder. - Completed sessions create no restart reminder. - Startup ignores reminders older than ten minutes. - The resumed model call uses stored input and authority. - No channel-specific code changes appear in the stack. - The 30-second stop budget remains a fallback for unsafe states. - Tests, OpenSpec validation, Slopwatch, headers, and evals pass. ## NOW ### Priority: Restore Restricted Session File Authority Source PRDs: PRD-002 and PRD-007. Owner: `PathAccessPolicy`. Use the [engineering glossary](docs/spec/GLOSSARY.md) for path and authority terms. - [x] Deny implicit sibling access for Public and Team; preserve current roots and exact own legacy logs. - [x] Verify parent/child authority and the approved legacy cross-run log exception. - [x] Keep result conversion and attachment-destination investigation in separate review slices. - [x] Complete deterministic boundary tests, system-skill evals, and repository quality gates. Local actor tests: 3,883 passed; six platform-specific skips. Daemon tests: 1,098 passed. Focused child-log and operations evals each passed five runs. Native Windows proof remains pending. ### Priority: Unify Session Storage And Temporary Files - [x] New sessions bind one durable, versioned [session storage envelope](docs/spec/GLOSSARY.md#session-storage-envelope). - [x] Existing sessions keep their established workspace and log paths. - [x] Parent and child processes receive separate managed temporary paths. - [x] Successful subagent results return exact child log and artifact paths. - [x] Use the current session and inherited trusted roots for ordinary file and shell authority; remove special log, child, and foreign-session rules. - [x] Remove `worktree_create`; expose `worktree_dir` and compose `shell_execute` with `set_working_directory`. - [x] Allow normal structured reads of ordinary `netclaw.json` while keeping secret stores and control-plane state denied. - [x] Fix collision-safe session roots, journal-only legacy discovery, root-segment link checks, old background-job JSON, and per-log resolver locks. - [x] Replace weak worktree and child-handoff eval assertions and complete the repository gates. - [x] Update the operations skill, runbooks, and release notes to the revised path, authority, worktree, and configuration contracts. - [ ] Harvest sanitized traffic after the binary swap. ### Priority: Secure Host Pairing and Recovery **PRDs:** `docs/prd/PRD-002-gateway-security-envelope.md`, `docs/prd/PRD-004-cli-onboarding-and-config.md` **Spec:** `openspec/changes/secure-host-pairing-proof/` **Surface area:** daemon security, CLI, HTTP, device registry, operations **Verification:** L3 The host must generate a pairing code in every exposure mode without granting host authority to traffic that a tunnel or proxy forwards through loopback. Done when: - [x] A versioned Data Protection proof authorizes the host-only endpoint. - [x] The SignalR hub no longer exposes pairing code generation. - [x] Valid device records, tokens, and exposure settings survive the upgrade. - [x] A duplicate device name or registry failure does not consume a valid code. - [x] Tests prove host success and remote denial in every exposure mode. - [x] Process smoke proves host recovery without a live tunnel dependency. - [x] The operations skill and next `0.27` beta website task describe the new procedure. - [x] The public draft PR receives normal CI before the fixed beta. - [x] The host command keeps proofs away from remote client endpoints, proxies, redirects, and bearer headers. - [x] One pairing actor owns the code and exchange transaction; actor tests prove mailbox order, cancellation, and recovery. ### Priority: Keep MCP HTTP Protocol Fallback Deterministic **PRD:** `docs/prd/PRD-006-mcp-tool-integration.md` **Spec:** `openspec/specs/netclaw-mcp/spec.md` **Surface area:** MCP HTTP transport, daemon connections, CLI probes **Verification:** L1 plus the existing HTTP MCP smoke tests The MCP SDK can retain its discovery protocol version when probe cancellation selects the initialize fallback. Netclaw must not send that stale version in an initialize request. Done when: - [x] Daemon connections and CLI probes remove a retained protocol-version header only from the initialize request. - [x] Discovery and established-session requests keep their protocol-version header. - [x] Tests prove the header correction and preserve unrelated headers. ### Priority: Preserve The Daemon Working Directory **PRD:** `docs/prd/PRD-001-netclaw-mvp.md` **Specs:** `openspec/specs/netclaw-tools/spec.md`, `openspec/specs/tool-authorization/spec.md` **Surface area:** daemon lifecycle, path normalization, shell authorization **Verification:** L1 plus a live daemon restart The daemon process directory must survive routine system temporary-directory cleanup. Absolute path validation must not depend on that process directory. Done when: - [x] The daemon uses a durable runtime directory below the Netclaw home. - [x] Absolute path normalization does not read the process working directory. - [x] Focused tests and the full repository quality gates pass. - [ ] An installed daemon restart confirms the live process uses the durable directory. ### Priority: Complete Tool Remediation **PRD:** `docs/prd/PRD-006-mcp-tool-integration.md` **Spec:** `openspec/changes/complete-tool-remediation/` **Surface area:** internal tool receipts and model-facing tool results **Verification:** L2 The receipt must drive the next action. The model must not depend on duplicated handwritten guidance or an unchecked string code. Done when: - [x] Every `RecoverableCorrection` receipt carries one defined internal code. - [x] Parent and child paths use one presenter before result delivery. - [x] Hidden tools are not named by remediation. - [x] Approval authority, scratch retry state, durable messages, and public APIs remain unchanged. - [ ] The stacked follow-up handles `attach_file` exposure and native-tool shell mistakes separately. ### Priority: Stop Repeated Tool Cycles **PRDs:** `docs/prd/PRD-001-netclaw-mvp.md`, `docs/prd/PRD-006-mcp-tool-integration.md` **Spec:** `openspec/changes/stop-repeated-tool-cycles/` **Surface area:** turn state, tool results, compaction, parent and child actors **Verification:** standalone deterministic proof, private replay, L2, and observe-only evidence Active tool loops can produce valid model, tool, and actor activity. The static iteration limits stop productive work and stop exact cycles too late. Done when: - [ ] Successful normal compaction preserves loaded deferred schemas. - [ ] LLM failure and context overflow evict loaded schemas. - [ ] A six-entry detector blocks exact periods one through three before execution. - [ ] The first block returns paired correction results without a side effect. - [ ] A repeated blocked action forces a truthful text-only response. - [ ] Parent and child actors produce equal decisions from equal histories. - [ ] Replay and observe-only evidence contain no confirmed false execution block. - [ ] The parent and child iteration limits are removed only after all gates pass. - [ ] Logs contain decisions and counts, but no arguments, results, hashes, or identities. ### Priority: Prevent Native-Tool Shell Mistakes **Stack parent:** PR #2046 (`fix/repair-tool-rollout-contracts`). - [x] Specify `attach_file` as a policy-filtered Core tool that accepts the authorized source path directly. - [x] Specify parser-owned exact executable matching without executable-private argument parsing. - [x] Return a typed correction before shell approval or execution and expose one deferred schema actor-locally. - [x] Prove parent/child, hard-deny, hidden-tool, and eventual-authorization boundaries. - [x] Refresh deterministic and hosted PII-free behavioral evidence. - [x] Complete Release, OpenSpec, header, formatting, Slopwatch, and adversarial-review gates before opening the stacked PR. ### Priority: Reduce Shell Approval Fatigue **PRDs:** `docs/prd/PRD-002-gateway-security-envelope.md`, `docs/prd/PRD-006-mcp-tool-integration.md` **Spec:** `openspec/specs/tool-authorization/spec.md` **Surface area:** shell authorization, approval matching, security corpus **Verification:** L2 #### Verified implementation: contained glob directory aliases N1 keeps contained directory aliases within the existing shell authority model. `openspec/changes/archive/2026-10-28-allow-contained-glob-directory-aliases/` defines target protection, source and target scopes, incomplete reach, and the 4096-unit work bound. Each intermediate directory visit and each link hop consumes one unit. The implementation carries known targets even when another branch remains unresolved. Only complete reach can support reusable approval. The final proof includes independent authorizer cases, focused mutants, and the maintained corpus. The coordinator owns the corpus audit and publication decisions. The changed skill guidance passes its retained targeted case, five of five trials. Broader model attempts remain incomplete or canceled at the user's request. #### Active delivery: complete compound scopes The `0.27.0-beta.4` session declared its project root. Later calls still used inline `cd` with a pipeline and later statements. ShellSyntaxTree parsed the source, but Netclaw lost reusable candidates after a directory join. The source also contains `rm`, `python3`, and `dotnet new install` prompts with no matching grant. Those prompts remain subject to approval. The approved contract is in `openspec/changes/reduce-complex-shell-approval-prompts/`. The goal is to reuse existing grants only when every reachable verb, directory, and path scope has proof. A parent folder grant covers descendants after each concrete path passes symlink and protected-path checks. A deep glob cannot use that rule without proof for every possible match. **Delivery:** Five reviewable PRs are planned. The first Netclaw PR adds a typed one-call directory correction and sanitized evidence. The second Netclaw PR adds conservative coverage for complete static compounds. The ShellSyntaxTree PR publishes bounded syntax facts, then tag `0.4.0-beta.3` publishes the public package. The fourth PR pins that package and consumes only proved facts. The user authorized automatic merge after CI and independent security review. The fifth PR adds an explicit repository grant for ordinary Git checkouts and their registered linked worktrees. Existing folder grants retain their path meaning. A main checkout with `--separate-git-dir` keeps folder scope. **Delivery evidence:** ShellSyntaxTree PR #184 merged. Its `0.4.0-beta.3` package passed the publish job and is available on NuGet. Netclaw PRs #2191, #2193, and #2194 merged after their CI checks passed. PR #2194 pins the public beta. PR #2195 adds the explicit repository grant and has passed local tests, focused mutants, native approval smoke, and independent authority review. Its final merge depends on CI for the branch after the PR #2194 merge. The full hosted eval for PR #2195 passed 73 of 91 cases, so that suite remains red. The isolated typed-directory case passed five of five runs. Several failed worktree cases used successful read-only `git -C` calls, which the typed-directory oracle rejects. The worktree creation case denied an unapproved `git worktree add`, as required. The live daemon still runs `0.27.0-beta.4`; these changes need a later Netclaw rollout. **Gates:** Prove both outcomes of a directory change, every pipeline stage, an ungranted verb, each possible path, redirects, hard denials, protected paths, symbolic links, audience and session boundaries, and exact retries. Run focused mutation tests at the authority boundary. Restore the public beta from NuGet before the fourth PR. Keep unknown syntax, runtime values, and deep globs under exact approval. Do not add executable-specific argument parsers to Netclaw. The user promoted this work into `NOW`. The work must reduce repeat prompts without allowing an incomplete or unknown shell form. Done when: - [x] The sanitized v0.26.0-beta.3 approval window has 18 classified cases in the linked ShellSyntaxTree and Netclaw OpenSpec changes. - [x] `openspec/changes/archive/2026-08-15-structure-shell-approval-policy/` defines the typed coordinator and actor protocol, per-candidate coverage, real and intent scopes, token-boundary grants, reviewed policy catalog, bounded trace, migration, and validation tasks. - [x] The maintainer approves the ShellSyntaxTree 0.3.1 API names and the use of separate authored-source facts for approval matching before implementation. - [x] The maintainer approves whether simple v2 grants gain token-prefix authority during schema-3 migration or remain exact until re-approved. - [x] Approval-store schema 3 uses closed shell token-prefix, shell legacy-exact, and non-shell exact forms. Version-2 conversion keeps prior shell authority exact, creates a byte-identical backup, and fails closed on invalid data or storage errors. - [x] New reusable shell grants use ShellSyntaxTree token facts with explicit Bash or PowerShell identity. Distinct command occurrences remain visible through actor checks, one-time keys, persisted events, and subagent prompts. - [x] CLI and TUI list and revoke typed phrases with unambiguous labels. The native approvals tape proves version-2 conversion, non-shell label display, and revoke behavior against a published binary. - [ ] The policy pipeline replaces the shell branches in `ToolAccessPolicy` and `ShellApprovalMatcher`; any retained legacy scan is deny-only and cannot authorize, create candidates, or widen scope. - [x] `ToolAccessPolicy` no longer completes shell authorization synchronously. It produces preflight facts only. `ShellPolicyCoordinator` is the sole path that applies corrections, reviewed-safe coverage, grants, and a final shell authorization result. - [ ] Move the remaining parser-to-candidate projection out of the broad `ShellApprovalMatcher` compatibility surface without changing its released approval shapes. The preliminary complete-footprint audit after PR #1947 found 1,484 added production lines and 52 added control-flow lines. Later slices reduced the post-corpus footprint from 10,085 lines and 663 control-flow lines to 9,693 and 634. Control-flow is now below the frozen 635-line baseline. The final audit must justify the remaining 721-line delta through tested security or compatibility obligations instead of deleting required distinctions. - [x] Shell calls pass through one coordinator. It snapshots immutable parser and run-scope facts, requests one typed actor batch, and composes grant and reviewed-safe coverage per candidate before one final result. - [x] The actor response preserves stable candidate IDs and typed persistent store status. Duplicate IDs, mismatched facts, impossible grant states, and internal stage faults deny without a prompt. - [x] The shell coordinator returns a typed operator trace with at most 256 rows. Each row uses enum facts, a call-local candidate ID, a redacted executable basename, grant scope, and grant time. The actor derives a match or one near miss from one store snapshot pass. Raw paths, command text, arguments, secrets, prompts, and session events never receive trace data. - [x] The approval runbook documents the complete parser-fact-to-policy flow, bounded status and finite-loop examples, partial candidate coverage, and a trace-first operator diagnostic procedure. The source-generated fixture replay pins current D02, D10, and D14 coordinator behavior. - [x] The bundled reviewed-diagnostic catalog constrains shell-authored argv. Parser-owned prefix order and lexical path-shape guards remain required. Redirect, filesystem-value, provider, and unknown-expansion checks stay separate. - [x] The `git ls-tree` production special case is removed. Token-boundary policy match handles longer parser phrases without private command grammar. - [x] A synthetic workload corpus covers ordinary search, read, pipeline, redirect, and file-change commands without production command text. - [x] Sanitized post-swap evidence classifies 51 prompts across 202 shell calls. Eleven executable live cases pin the intended allow and prompt boundaries. - [x] Post-1952 live evidence froze 285 shell calls and 69 prompts. Twenty-one sanitized cases sample expected, guidance, and ShellSyntaxTree gaps. The coordinator executes one identity-free regression for each sampled case. Each regression locks its evidence source, approval shape, and actor contact. - [x] A safe pipeline stage can compose with a stored grant for each stage that still requires approval. - [x] The paired Windows PowerShell consumer pins official ShellSyntaxTree `0.4.0-beta.1`. Partial diagnostic syntax remains denial-only. Typed tree facts keep Windows PowerShell 5.1 link-following recursion exact-only. Interactive Auto and Approval offer only Once or Deny. Headless Auto denies the call. The exact retry repeats hard-deny and protected-path checks. The explicit restore, Release build, Security tests, Actors tests, Configuration tests, and 79 focused mutants passed against the official package. The Netclaw beta remains unpublished. - [x] Adopt ShellSyntaxTree `0.4.0-beta.2` with analyzer and approval-catalog coverage for bounded PowerShell split/index/join projections on PowerShell 7 and Windows PowerShell 5.1. Dynamic projection operands stay strict. The public package restore, Release build, full test suite, and all 79 focused shell-policy mutants pass. - [x] A prompt excludes a safe stage from the approval candidates that the user can persist. - [x] A prompt excludes candidates that existing session or persistent grants already cover, while it preserves exact directory-scoped occurrences. - [x] Reviewed-safe phrases grant no implicit authority to a headless, reminder, or webhook run. Unattended candidates need explicit one-time or stored-grant authority; approval-exempt shell side effects retain their bounded exception. - [x] A one-time retry is bound to the exact prompted candidate set, including each effective directory, across live, sub-agent, and redrive paths. - [x] External paths, mismatched grants, dynamic syntax, and hard-deny rules keep their strict behavior. - [x] PowerShell 7 command-argument regions with no child commands can reuse an explicit host grant when ShellSyntaxTree reports a complete known region. Unknown receivers, unknown syntax nodes, methods, assignments, and executable substitutions remain one-time-only. A body command needs separate authority. - [x] Bash causal approval intent composes exact stored grants for an initial exact ShellSyntaxTree 0.3.4 directory change with reviewed diagnostic tails. Execution facts, folder grants, protected paths, headless authority, and PowerShell remain strict. Each possible fallback passes the same symlink check. POSIX `/tmp` aliases map through host path facts. The exact D03 fixture must pass on Linux, macOS, and native Windows CI. PR #1967 added exact PowerShell 7 and Windows PowerShell 5.1 strict-scope rows. Both rows required approval despite matching stored grants. Workflow `31859321334` passed Ubuntu, macOS, and Windows. - [x] Directory operands preserve dotted directory names without weakening the external-path or symlink checks. - [x] Reviewed-safe policy matches canonical ShellSyntaxTree token prefixes. It does not rewrite a variable `git ls-tree` operand or any other command. - [x] Tool schemas and always-loaded guidance distinguish a persistent project root from one-command `WorkingDirectory` scope, prevent redundant project switches, and preserve `cd` when directory mutation is the requested shell behavior. - [x] Always-loaded guidance, shell metadata, and the operations skill prefer first-party file tools for known reads, listings, and edits. Local repository search, builds, tests, VCS, and process workflows remain shell use cases. External discovery and retrieval remain routed through built-in `web_search` and `web_fetch`. Five-run unaided evals passed 5/5 for read, listing, edit, and local search. Web search passed 4/5 at the required 0.80 threshold. - [x] Reviewed-safe shell work beneath an undeclared cwd returns the same `set_working_directory` correction in parent sessions and subagents before any user prompt. The original tool call remains unchanged. The registered tool must accept the exact non-temp cwd; unsafe phrases, outside paths, Public sessions, and unavailable scope tools retain normal approval behavior. A successful child declaration updates only the child scope, reloads its project instructions, and leaves the parent project unchanged. Headless declarations prevent repeated corrections but do not grant execution authority. - [x] Bounded non-path `IntegerRange` and `Concatenation` data do not make a complete shell command complex. Unknown values, identities, paths, and redirects stay strict. - [x] Sanitized behavioral eval cases cover early project declaration, one-command typed scope, failed-path recovery, and deliberate inline `cd`. - [x] Two naturalistic cases now test a child checkout beneath a declared parent project. The prompts do not name a tool, `WorkingDirectory`, or `cd`. Against the configured evaluation model, the worktree status baseline passed 1/5. Three failures used `git -C`, and one failure used inline `cd`. The source inspection baseline passed 0/5. Each run read the named file, then tried shell search before `file_list`. - [x] The shell schema and always-loaded rules now separate `Command` from one-call directory selection. The rules do not name an executable syntax. The unchanged worktree status case passed 4/5. Direct typed scope and the deliberate inline-directory case each passed 5/5. - [x] The unchanged source-inspection case passed 1/5. Four runs used shell search after `file_read`. This result tracks a separate first-party recursive file-search gap. - [x] A sanitized subagent eval proves that a different user-named project is declared before the child's first multi-command shell inspection. Absolute path operands remain exact scopes, but do not create a trusted root. The configured evaluation endpoint passed 4/5 runs. The assertion orders declaration before two exact successful shell calls and verifies the reported layout and build file. One run used one-shot scope without declaring the project and failed as intended. - [x] The session-scratch model-guidance eval passed 4/5 against the configured configured evaluation endpoint. This measures headless path preference; deterministic actor tests own interactive correction and approval proof. - [x] Post-0.26.0 live evidence in `openspec/changes/archive/2026-08-15-structure-shell-approval-policy/evidence/post-1952-live-approval-harvest.json` classifies 69 prompts across 285 shell calls. The largest avoidable cluster is 15 read-heavy prompts from one headless subagent working beneath shared platform temp even though its execution scope already owns private session scratch. - [x] Personal and Team subagents now receive the exact bound `session_dir` in their volatile working context before the first model call. Public context remains redacted, and prompt-worthy headless shell work remains denied without explicit authority. The first delegated eval result was invalidated: all 5/5 runs omitted `WorkingDirectory` and passed through the existing shell fallback. After the exact assertion and guidance were corrected, the fresh `a1077feb-6bd7-413c-8a90-c651aa5a03df` run passed 4/5 against the configured evaluation model. Four children passed the exact bound session directory on both Git diagnostics; one omitted it and failed as intended. - [x] Removing the prescribed answer from the existing parent-only disposable output eval produced 3/5 path-aligned runs. All five completed through the private session directory, and all recovered from denied shell writes with first-party file tools, but two first attempted `/tmp` or `mktemp`. This is retained as alignment evidence rather than reported as a passing gate. - [x] Explicit `WorkingDirectory=/tmp` and deliberate inline `cd /tmp` evals remain in the corpus so a platform-temp requirement is not rewritten. - [x] Eligible interactive Personal shell work at the shared platform-temp root receives a typed session-scratch correction before parent or subagent approval. The original call remains in history. One exact later retry offers only Once or Deny and creates no reusable temp authority. Headless behavior, Team/Public denial, hard-deny rules, dynamic syntax, protected paths, and native PowerShell causal scope stay strict. - [x] Seven sanitized tool-friction cases replay through registration, policy, dispatch, typed outcomes, and success-owned working context. Structured search, batch read, JSON selection, image metadata, and spill continuation need no shell approval. Representative interpreter fallbacks still prompt. Parent and child diagnostics report counts and outcome categories only. - [x] The hosted PR 7 comparison ran five trials per selected scenario. Search, batch read, JSON selection, image metadata, and deferred discovery passed 25/25 with the intended structured tools and no shell fallback. Spill continuation passed 0/5: all five runs used shell, none loaded or called `tool_output_read`, and one run searched the catalog. Keep this failure as a rollout finding; do not weaken its assertion. - [x] Complete native platform CI, stack merge, binary swap, and a new sanitized live traffic harvest. - [ ] Define automated session-directory cleanup in a separate OpenSpec before adding retention or deletion behavior. - [ ] A constrained executable grammar proves any future safe `sed` form. The `-n` option alone is not proof because a `sed` program can write files or execute commands. - [ ] Audited ShellSyntaxTree bindings prove bounded `grep` pattern operands, including escaped BRE alternation, are non-filesystem data. File-bearing options and unresolved patterns remain strict. - [x] Netclaw consumes ShellSyntaxTree 0.3.0-alpha command occurrences and explicit Bash redirect facts for the existing grammar. - [x] Netclaw consumes ShellSyntaxTree `0.3.0` through its corrected closed analysis API. The consumer uses joined arguments, value-domain type patterns, redirect alternatives, and redirect-source alternatives. The unchanged 225-test Bash, PowerShell 7, and Windows PowerShell 5.1 approval matrix passes locally. - [x] Netclaw resolves ShellSyntaxTree `0.3.2` for the separate authored-source and path-shape facts introduced in 0.3.1. This store-v3 slice preserves those parser token facts without executable-private command rules; later parent tasks consume the new value-domain facts in the coordinator. - [x] Netclaw consumes public ShellSyntaxTree `0.3.3` for the parser-owned authored filesystem domain. Local code accepts only `Exact` and `FiniteSet`. It checks each value through path policy and keeps unsafe transforms strict. The Release build and all 7,138 runnable tests pass. The suite reports 15 expected platform or opt-in skips. Adversarial review and all required CI checks passed before merge. - [x] Netclaw consumes public ShellSyntaxTree `0.3.4` for parser-owned working-directory effects. The causal policy does not recognize command names or private executable grammar. Native platform CI remains required. - [x] Netclaw consumes public ShellSyntaxTree `0.3.5` for positive authored non-filesystem values. Only that argument's compatibility and lexical path interpretations are omitted. Other arguments, redirects, effects, dynamic values, and unknown commands remain strict. The sanitized live `tr -d '\\n'` loop reuses its existing `gh run view` grant without creating a `/n` scope. - [x] Parent, child, schemas, skills, and always-loaded rules share one directory order and one shell-composition order. Approval-required shell variants do not receive authority from that guidance. - [x] ShellSyntaxTree 0.3.5 already publishes complete facts for the ten new sanitized fresh-session samples. Sixteen focused tests and one corpus entry pin current occurrence, cwd, redirect, argument, and dynamic boundaries. - [x] A fixed leaf-glob root may contain an existing in-root final alias. Broken, external, or uninspectable aliases remain strict. The exact recursive-search pipeline now produces reusable candidates without private executable parsing. - [x] Five changed runs per eight cases used the baseline model and configuration. Structured guardrails remained 15/15. Four alignment cases stayed below threshold. Prompt equivalents fell from 32 to 25, while the explicit directory-transition shell attempts fell from 24 to 12. These variable results remain recorded, not converted into weaker assertions. See `src/Netclaw.Security.Tests/Evidence/ApprovalEvidence/post-guidance-fresh-session-eval-results.json`. - [x] PR #1982 merged as `9d02d19efd75fe871c8603e151e3e7169a9d9433`. The live daemon preserved a rollback binary, swapped to that exact commit, recovered its session catalog, and passed five natural fixed-pipeline runs without an approval or complex marker. - [x] Forty-five post-swap fresh sessions are frozen in `src/Netclaw.Security.Tests/Evidence/ApprovalEvidence/post-9d02d19-binary-swap-eval-results.json`. The original eight workloads improved from 17/40 to 23/40 behavior passes; the added fixed-pipeline case passed 5/5. Observed prompt equivalents fell from 25 to 2, but 446 historical grants make that prompt delta non-causal. Fifteen retained trust-zone denials exposed redundant file verification, disposable redirects, child absolute paths, and retry-after-denial debt. - [x] PR #1983 merged as `7efa7fd0f711696343cd7d5e3d2abf75d20707d6`. The exact binary was swapped into the live daemon with the prior binary kept for rollback. Fifteen fresh affected sessions then improved from 2/15 to 14/15 behavior passes, and shell attempts fell from 25 to 6. Known-file edit and disposable-output cases passed 10/10 without shell. All five requested external directory transitions remained denied; one fallback-model run made one additional shell call after denial. The initial controlled DeepSeek run was blocked by provider billing, so the live comparison is operational deployment evidence rather than a same-model causal estimate. See `src/Netclaw.Security.Tests/Evidence/ApprovalEvidence/post-7efa7fd-followup-live-eval-results.json`. - [x] After billing resumed, an isolated same-model rerun of the exact merged image passed known-file and disposable-output cases 10/10, but the terminal directory-denial case passed only 3/5. Both failures followed stale inherited guidance by calling `set_working_directory` after `Tool access denied:`. - [x] The pending correction removes that contradictory recovery rule and pins denial versus deferred-correction behavior. On one DeepSeek image, all three affected cases passed 15/15. Structured-file cases used no shell. All five external directory transitions produced exactly one hard denial, no scope correction, and no retry. See `src/Netclaw.Security.Tests/Evidence/ApprovalEvidence/post-terminal-denial-guidance-eval-results.json`. - [x] The terminal-denial guidance correction merged in PR #1985. The exact merged binary was swapped into the live daemon. Five fresh live sessions retained all five required denials. Three stopped without a substitute call; one made a safe call before denial, and one made a safe call after denial. - [x] Issue #1892 now has a seeded Git project and natural project-scope evals. The final direct-provider image declared the project before project tools in 5/5 runs, avoided declarations for unrelated prompts in 5/5, and recovered from a rejected named path in 5/5. The fix is guidance-only: it declares the task's first path before probing, then uses a user-provided fallback after rejection. It adds no shell authority. - [x] A post-#1990 live sample found four approvals among ten shell calls. All four calls joined independent diagnostics, and one also used inline `cd`. The strict direct-provider baseline passed 3/5 and contained one prompted compound run. Generic independent-operation guidance raised the exact committed image to 5/5. It produced five successful single-operation shell calls and no approval equivalent. See `src/Netclaw.Security.Tests/Evidence/ApprovalEvidence/post-independent-operation-guidance-eval-results.json`. - [x] The initial follow-up disposable eval was discarded. Its prompt requested a diagnostic command but omitted the exact content required by its assertion. The corrected case names the disposable file effect and exact content without prescribing a tool. - [x] Pre-delivery fresh-session evals passed the strengthened guidance boundary: disposable file tools passed 5/5, terminal trust-zone denial passed 5/5 without a scope change or retry, and known file edit passed 4/5 at threshold. The fifth edit run ended before model behavior with a provider 402 response. An earlier denial run was discarded because its assertion expected a CLI log shape that JSON mode does not emit; the corrected assertion binds the daemon's exact authorization outcome. - [x] The current live mixed-read chain is complex with inline `cd`. Supplying the typed working directory makes the prompt reusable and exposes only the unproved `sed` and escaped-`grep` pattern candidates. - [x] The expanded 247-test matrix covers command-substitution and PowerShell execution-region behavior. Known command-owned regions reuse independently matched host and body grants after Netclaw accounts for the parsed body. Unknown receivers and incomplete region facts remain prompt-only. - [x] Unknown occurrences, cwd facts, wrappers, and redirects stay prompt-only. Static descriptor redirects no longer appear dynamic. - [x] The resolved POSIX `/dev/null` device does not create an approval directory after host symlink checks. Other device paths and dynamic redirect targets stay strict. - [x] Netclaw consumes ShellSyntaxTree `0.3.0-alpha.1` and promotes Bash command-resolution mutation and reserved execution forms into the strict 181-case review matrix. - [x] ShellSyntaxTree `0.3.0-alpha.2` introduced one temporary POSIX PowerShell child wrapper. Native-host activation removed that transitional consumer behavior: Bash treats `pwsh` as an external command, and only a native PowerShell host uses `PwshParser`. - [x] The shell approval review table separates Bash, PowerShell 7, and Windows PowerShell 5.1 rows. Cross-language payloads remain ordinary external-command arguments; same-language static children use parser-returned occurrences. - [x] A constrained stdin grammar allows a complete literal heredoc or bounded here string only for argument-free `cat`. Unknown data, expanding heredocs, arguments, wrappers, interpreters, and stored grants stay strict. - [x] Netclaw interprets bounded non-path loop arguments through ShellSyntaxTree 0.3.2's separate authored-source projection for approval analysis. Effective runtime values retain priority, and path-bearing loop arguments remain strict. - [x] The approval matrix pins inherited and same-language child loops as complex under the canonical unknown-state contract for Bash, PowerShell 7, and Windows PowerShell 5.1. It also proves that a stored command grant cannot cover an unproved loop-dependent argument. - [x] Netclaw adopts bounded non-path `AuthoredValue`, status concatenation, and the typed consumer boundary. Positive authored path evidence remains a separate strict-policy task. ### Priority: Use Native PowerShell on Windows **PRDs:** `docs/prd/PRD-001-netclaw-mvp.md`, `docs/prd/PRD-002-gateway-security-envelope.md`, `docs/prd/PRD-006-mcp-tool-integration.md` **Specs:** `openspec/changes/archive/2026-08-10-native-windows-powershell-host/` **Surface area:** shell execution, parsing, approval policy, model context **Verification:** L2 plus native Windows L3 This work replaces `cmd.exe` with a native PowerShell host on Windows. Netclaw prefers a compatible PowerShell 7.6 host and falls back to Windows PowerShell 5.1. It keeps Bash and PowerShell as separate host languages. The additive foundation pins ShellSyntaxTree `0.3.0-alpha.5` and defines the immutable environment, strict host probe, and process arguments. Runtime activation now routes execution, policy, approval, background jobs, and model context through the same resolved environment. PR #1848 auto-merged after adversarial review and green native Windows CI. The canonical specifications now contain the delivered contract. The OpenSpec change is archived. Local validation on 2026-08-10 passed restore, the zero-warning Release build, the full solution test suite, changed-file format verification, headers, Slopwatch, `git diff --check`, and strict OpenSpec validation. The shell-platform behavioral evaluation was unavailable because the required `NETCLAW_EVAL_PROVIDER_TYPE`, `NETCLAW_EVAL_PROVIDER_ENDPOINT`, and `NETCLAW_EVAL_MODEL_ID` settings were absent. This result is blocked evidence, not an evaluation pass. Native Windows workflow run `31381580072` passed the zero-warning Release build, the complete security, actor, and daemon test suites, package staging, and CLI smoke tests. The production resolver and deterministic dialect matrix cover PowerShell 7.6 and Windows PowerShell 5.1. The Windows suite also executed the explicit Windows PowerShell 5.1 host test. The final OpenSpec verification mapped all 7 requirements and 24 scenarios to runtime code and named tests. The focused verification passed 320 security tests, 29 daemon tests, and 315 actor tests. One Windows-only actor test skipped locally and passed in native Windows workflow run `31381580072`. Strict validation passed all 78 OpenSpec items with no failures. Done when: - [x] One immutable shell environment selects the absolute executable path, grammar, path style, process arguments, and PowerShell dialect for the daemon lifetime. - [x] Windows selects `pwsh.exe` only for versions from 7.6.4 through 7.6.x. It falls back to `powershell.exe` 5.1 and fails clearly if neither host matches. - [x] Execution, parsing, hard deny, approval matching, prompt display, and model context use the same selected environment. - [x] Bash treats `pwsh` as an external command. PowerShell treats `bash` as an external command. Only same-language child hosts can recurse. - [x] Unknown or incomplete facts cannot produce a stored approval candidate or a safe-verb pass. Stored approval cannot bypass hard deny. - [x] Personal sessions state the platform, executable, grammar, and dialect, including sessions that have no project directory. - [x] Native Windows tests cover PowerShell 7.6 and Windows PowerShell 5.1. The security review table covers direct, child, retry, and background paths. - [x] Consumer guidance and canonical specs match the delivered behavior. The OpenSpec change passes verification, is synchronized, and is archived. ### 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/archive/2026-07-15-simplify-tool-execution-context/` **Surface area:** tool execution, session actors, subagents, working context **Verification:** L2 plus behavioral evals Deliver three sequential, independently reviewed PRs from the active OpenSpec change. The series replaces nullable and context-free execution APIs with required immutable scopes and semantic value objects, composes the session pipeline with behavior-preserving dependency modeling, and gives child runs independent working state with gated asynchronous Git enrichment. Done when: - [x] Stage 1 lands required run scopes, per-call isolation, and non-null security/authority dependencies without compatibility shims. - [x] Stage 2 lands the composed pipeline without changing existing background, fallback, authorization, approval, MCP, or model-visible behavior. - [x] Stage 3 lands child fork/delta semantics and Git inspection only for non-Public runs with a declared Git project. - [x] Each stage passes review, CI, post-merge fresh-worktree verification, and 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. - [x] OpenSpec deltas are verified, synced, and archived after the final merge. Durable execution details and checkbox state live in `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. ### Phase 0: Execution Governance Purpose: prevent shallow local fixes from being mistaken for runtime-complete work. #### Task 0.1: Enforce the cross-boundary contract rule **PRD:** `docs/prd/PRD-001-netclaw-mvp.md` **Spec:** `docs/spec/SPEC-010-testing-and-smoke-strategy.md` **Surface area:** cross-cutting **Verification:** L0 Done when: - [x] `AGENTS.md` references `IMPLEMENTATION_PLAN.md` as a read-first artifact. - [x] `AGENTS.md` includes the Cross-Boundary Contract Rule. - [x] This plan is the default routing artifact for build work. - [x] `BACKLOG_PARKING_LOT.md` exists for non-now work. #### Task 0.2: Add PRD/status traceability to the plan workflow **PRD:** `docs/prd/README.md` **Spec:** `docs/spec/SPEC-010-testing-and-smoke-strategy.md` **Surface area:** docs **Verification:** L0 Done when: - [x] Every `NOW` task has a `PRD` reference. - [x] Tasks with stale, missing, or conflicting PRD coverage are blocked until the PRD/spec is updated. - [x] If a task changes OpenSpec-covered behavior, the corresponding OpenSpec workflow is used rather than hand-editing change artifacts. #### Task 0.3: Add contract-test inventory for critical producer/consumer pairs **PRD:** `docs/prd/PRD-001-netclaw-mvp.md` **Spec:** `docs/spec/SPEC-010-testing-and-smoke-strategy.md` **Surface area:** cross-cutting **Verification:** L1 Done when: - [x] Document the critical producer/consumer pairs in this plan or a linked spec, including config editor -> runtime options, channel events -> ACL, scheduler -> delivery gateway, tool schemas -> model/tool dispatcher, and memory persistence -> prompt assembly. - [x] For each pair, identify the canonical representation and the test file that proves it. - [x] Add missing tests or add explicit `NOW` tasks for gaps. Inventory: `docs/spec/SPEC-010-testing-and-smoke-strategy.md` -> Critical Producer/Consumer Contract Inventory. Remaining proof gaps are assigned to explicit `NOW` tasks 3.1, 4.2, and 5.2-5.3. #### Task 0.4: Automate recent regression classes **PRD:** `docs/prd/PRD-001-netclaw-mvp.md`, `docs/prd/PRD-004-cli-onboarding-and-config.md` **Spec:** `docs/spec/SPEC-010-testing-and-smoke-strategy.md`, `openspec/specs/netclaw-config-command/spec.md` **Surface area:** testing, TUI, config **Verification:** L3 Done when: - [x] Every config/TUI task touching text input includes headless typed-input tests for typed characters, paste, Tab, Enter, Escape, and re-entry when applicable. - [x] Every config leaf with dynamic validation has a fake-failure test proving validation runs before persistence and leaves files unchanged. - [x] Every config leaf ported from init/old editor paths has an existing-config load/round-trip test covering dormant values and persisted secrets. - [x] Every smoke tape with config writes has an assertion script that checks canonical semantic output, not only screenshots or text. - [x] Any async UI save/test action has a direct awaitable test path plus fire-and-forget exception surfacing. PR #2417 follow-up: - [ ] Run `./evals/run-evals.sh` after the operator sets the provider type, endpoint, and model ID through `NETCLAW_EVAL_*`. The local runner rejects the current environment because these values are unset. #### Task 0.5: Add audit tests for plan-critical config editors **PRD:** `docs/prd/PRD-004-cli-onboarding-and-config.md` **Spec:** `openspec/specs/section-editor-abstraction/spec.md`, `openspec/specs/netclaw-config-command/spec.md` **Surface area:** testing, config **Verification:** L1 Done when: - [x] A registry/audit test lists config leaf editors and fails when a visible editor lacks round-trip coverage. - [x] The audit requires each visible editor to declare whether it has dynamic validation and, if yes, the test class that covers fake-failure behavior. - [x] The audit requires each editor that writes secrets to have blank-preserve, nonblank-replace, and explicit-delete coverage. - [x] The audit requires each editor that writes runtime-consumed config to name the runtime consumer and contract test file. ### Phase 1: Config Command And Channel Runtime Contracts Purpose: finish the active config work all the way through runtime semantics. `netclaw config` owns post-install tuning. It should cover ordinary changes an operator might make after first run without re-entering bootstrap: - Providers and Models route to their dedicated editors. - Channels, Search, Security & Access, Exposure Mode, Skill Sources, Telemetry & Alerting, Workspaces Directory, Inbound Webhooks, and Browser Automation must not remain root-dashboard placeholders before this phase closes. - Identity/personality re-entry remains `netclaw init` / identity-owned work; config may expose the Workspaces Directory because operators can move project discovery roots after first run without regenerating identity files. - Per-session project switching is runtime state owned by the `set_working_directory` tool and the Audience Profiles `Change workspace` permission, not a global config editor. - General MCP server/permission editing remains `netclaw mcp`; Browser Automation config may add/remove the canonical browser MCP profile, then route grants to `netclaw mcp permissions`. - Inbound webhook route-file authoring remains `netclaw webhooks` / route files for this pass; config owns global enablement, execution timeout, route-count visibility, and loud diagnostics when enabled with no routes. - Advanced session tuning, logging verbosity, tool hard-deny overrides, and low-level tool execution ceilings are not init-owned, but stay out of this config-command close unless explicitly promoted. #### Task 1.1: Complete Channels provider-backed validation and canonical persistence **PRD:** `docs/prd/PRD-004-cli-onboarding-and-config.md` **Spec:** `openspec/specs/netclaw-config-command/spec.md`, `openspec/specs/channel-audience-tui/spec.md`, `openspec/specs/netclaw-input-adapters/spec.md` **Surface area:** UI, config, runtime contract **Verification:** L3 Done when: - [x] Slack channel names entered in config are resolved through Slack before persistence. - [x] Slack `AllowedChannelIds` persists canonical Slack channel IDs (`C...` or `G...`) and never unresolved display names. - [x] Slack channel audience keys are remapped to resolved channel IDs. - [x] Discord channel IDs are checked through `IDiscordProbe.ResolveChannelIdsAsync` before save. - [x] Mattermost channel IDs are checked through a Mattermost config-time probe before save. - [x] Unresolved Slack, Discord, and Mattermost channel targets block save with visible errors. - [x] Existing configured secrets can be used for validation without prompting on re-entry. - [x] Tests cover Slack name -> ID resolution, Slack unresolved name rejection, Discord unresolved ID rejection, Mattermost unresolved ID rejection, and secret preservation. - [x] Native smoke `./scripts/smoke/run-smoke.sh config-channels` passes with semantic assertions on canonical persisted values. - [x] Docker POC image rebuild/relaunch was not used for this task's verification; native smoke provided the L3 gate. #### Task 1.2: Finish generalized config leaf validation **PRD:** `docs/prd/PRD-004-cli-onboarding-and-config.md` **Spec:** `openspec/specs/netclaw-config-command/spec.md`, `openspec/specs/section-editor-abstraction/spec.md` **Surface area:** config, UI, cross-cutting **Verification:** L3 Done when: - [x] Every `netclaw config` leaf has typed structural validation before save. - [x] Runtime/probe validation is run where the leaf writes values consumed by runtime startup, ACL, transport, tools, or daemon exposure. - [x] Structurally invalid config is a hard block. - [x] `Save anyway` exists only for transient runtime/probe failures, never for schema violations, missing required security fields, or unresolved canonical IDs. - [x] Tests prove invalid path, URI, auth, binary, local-reference, and reachability failures where those concepts apply. - [x] Smoke assertions check semantic preservation and canonical output, not byte-identical JSON. #### Task 1.3: Complete `Security & Access` config area **PRD:** `docs/prd/PRD-004-cli-onboarding-and-config.md`, `docs/prd/PRD-002-gateway-security-envelope.md` **Spec:** `openspec/specs/netclaw-config-command/spec.md`, `openspec/specs/security-posture-tui/spec.md`, `openspec/specs/tool-authorization/spec.md` **Surface area:** UI, config, security **Verification:** L3 Done when: - [x] `Security & Access` contains Security Posture, Enabled Features, Audience Profiles, and Exposure Mode. - [x] Security Posture remains distinct from runtime Enabled Features and Audience Profiles. - [x] Team/Public posture continues into Enabled Features; Personal posture does not force that continuation. - [x] Audience Profiles expose only curated high-level controls: Tool Access (non-MCP), File Access, Incoming Attachments, Reset to posture default. - [x] Reset to posture default resets the full underlying audience profile, including hidden MCP and approval settings. - [x] MCP permissions route to `netclaw mcp permissions`; they are not recreated in this editor. - [x] Tests cover round-trip, hidden-field reset semantics, and ACL consumer expectations. - [x] Native config smoke covers at least one posture change and one audience profile reset with semantic assertions. #### Human Review Checkpoint: Security & Access config editor - [x] Completed 2026-06-01: human smoke passed in rebuilt `netclaw-config-poc-local` container at commit `547c2c3`; no `401 Unauthorized` after enabling Reverse Proxy and entering MCP permissions. Stop here after Task 1.3 is completed, verified, and committed. Do not continue into Task 1.4 until a human has spot-checked the live `netclaw config` Security & Access experience in a real terminal. Human smoke focus: - Security Posture reads clearly and continues to Enabled Features for Team and Public, but not for Personal. - Audience Profiles expose only curated controls and route MCP grants to `netclaw mcp permissions`. - Reset overrides visibly restores the posture baseline and the persisted JSON clears hidden MCP and approval overrides. - If Reverse Proxy is enabled from this TUI session, immediately entering MCP permissions must not return `401 Unauthorized`; the local daemon client must use the bootstrap `DeviceToken` written by the exposure-mode save. - Exposure Mode is visible from Security & Access, but deeper Exposure Mode behavior remains Task 1.4 work. Human smoke finding 2026-06-01: enabling Reverse Proxy and then navigating into MCP permissions in the same `netclaw config` process produced `401 Unauthorized`. Treat this as a config/runtime credential refresh regression, not an acceptable manual workaround. Regression coverage belongs with daemon-client authentication tests because the config TUI reuses the same `DaemonApi` instance after exposure mode writes a fresh bootstrap `DeviceToken`. Fixed by commit `547c2c37` and confirmed by human retest in the rebuilt validation container. #### Task 1.4: Complete Exposure Mode config leaf **PRD:** `docs/prd/PRD-004-cli-onboarding-and-config.md`, `docs/prd/PRD-002-gateway-security-envelope.md` **Spec:** `docs/spec/SPEC-006-gateway-exposure-and-remote-access.md`, `openspec/specs/daemon-exposure/spec.md`, `openspec/specs/device-pairing/spec.md` **Surface area:** UI, config, daemon exposure **Verification:** L3 Done when: - [x] Explicit modes are Local, Reverse Proxy, Tailscale Serve, Tailscale Funnel, and Cloudflare Tunnel. - [x] `Daemon.ExposureMode` is the single active selector; no per-mode active flags are introduced. - [x] Inactive old values are preserved and ignored while inactive. - [x] Each non-local mode has a mode-specific dialog; Local requires no extra setup. - [x] First non-local enablement auto-pairs the current configuring client when no bootstrap/pairing state exists. - [x] Orphaned or mismatched bootstrap state blocks with actionable guidance to `netclaw doctor`, docs, and the tracked issue. - [x] Tests prove config merge semantics and daemon exposure consumer binding. - [x] Native config smoke covers at least one non-local mode and one return to Local. #### Task 1.5: Complete Workspaces, Inbound Webhooks, and Browser Automation config areas **PRD:** `docs/prd/PRD-004-cli-onboarding-and-config.md`, `docs/prd/PRD-006-mcp-tool-integration.md` **Spec:** `openspec/specs/netclaw-config-command/spec.md`, `openspec/specs/netclaw-mcp/spec.md`, `docs/spec/configuration.md` **Surface area:** UI, config, workspaces, webhooks, MCP/browser tools **Verification:** L3 Done when: - [x] Workspaces Directory is editable from `netclaw config`, validates as a local directory path, persists `Workspaces.Directory`, and preserves existing identity files. - [x] Tests prove `NetclawPaths.WorkspacesDirectory`, project discovery, and prompt/workspace consumers read the saved `Workspaces.Directory` value. - [x] Inbound Webhooks root entry routes to an implemented editor, not a placeholder. - [x] Inbound Webhooks editor controls `Webhooks.Enabled` and `Webhooks.ExecutionTimeoutSeconds`; route-file editing stays in `netclaw webhooks` / `~/.netclaw/config/webhooks/*.json` for this pass. - [x] Enabling inbound webhooks with no valid routes fails loudly through doctor or visible diagnostics; no dummy route is created silently. - [x] Browser Automation root entry routes to an implemented editor, not a placeholder. - [x] Browser Automation detects required local runtime pieces, refuses enablement when prerequisites are missing, and prints manual install guidance instead of shelling out from the TUI. - [x] Browser Automation persists/removes the canonical browser MCP server profile (`browser_playwright` or `browser_chrome_devtools`) using the same shape runtime MCP loading consumes. - [x] Browser Automation grants route to `netclaw mcp permissions`; raw MCP grant editing is not recreated in this editor. - [x] Native smoke covers at least one successful save path and one blocked or guidance-only path across these areas. #### Task 1.6: Complete Skill Sources and Telemetry & Alerting config areas **PRD:** `docs/prd/PRD-004-cli-onboarding-and-config.md`, `docs/prd/PRD-006-mcp-tool-integration.md` **Spec:** `openspec/specs/netclaw-config-command/spec.md`, `openspec/specs/netclaw-mcp/spec.md` **Surface area:** UI, config, operations **Verification:** L3 Done when: - [x] Skill Sources contains External Skills and Skill Feeds. - [x] Skill Source validation covers paths, URIs, auth, and reachability where relevant. - [x] Telemetry & Alerting contains Telemetry and Outbound Webhooks only in this pass. - [x] Delivery-policy tuning stays parked. - [x] Tests prove semantic round-trip, secret preservation, invalid URI/path rejection, and runtime consumer binding where applicable. - [x] Smoke tapes exercise both areas or document why an existing smoke covers the route. #### Human Review Checkpoint: Complete config surface Stop here after Tasks 1.4, 1.5, and 1.6 are completed, verified, and committed. Do not continue into Task 1.7 until a human has spot-checked the live `netclaw config` experience in the rebuilt validation container. Human smoke focus: - Exposure Mode can switch to a non-local mode and back to Local without stale runtime-active fields or missing local auth. - Workspaces Directory, Inbound Webhooks, Browser Automation, Skill Sources, Telemetry, and Outbound Webhooks are implemented pages, not root-dashboard placeholders. - Each page rejects structurally invalid values before persistence and preserves unrelated config/secrets. - Browser Automation creates/removes the canonical browser MCP profile and routes grants to `netclaw mcp permissions`. - Inbound Webhooks global enablement remains separate from route-file authoring; no dummy route is silently created. - `./scripts/smoke/run-smoke.sh light` has passed or any local blocker is documented with evidence. #### Task 1.7: Close the `netclaw config` OpenSpec change **PRD:** `docs/prd/PRD-004-cli-onboarding-and-config.md` **Spec:** `openspec/changes/netclaw-config-command/tasks.md` **Surface area:** planning, config **Verification:** L3 Done when: - [ ] `openspec/changes/netclaw-config-command/tasks.md` accurately reflects completed and incomplete implementation work. - [ ] `openspec validate netclaw-config-command --type change` passes. - [ ] `./scripts/smoke/run-smoke.sh light` passes on a clean runner or a local blocker is documented with evidence. - [ ] `/opsx-verify netclaw-config-command` passes. - [ ] Spec deltas are synced or the change remains explicitly active with only real unfinished tasks. ### Phase 2: Init Bootstrap Split Purpose: keep first-run setup simple and move post-install editing to config. #### Task 2.1: Simplify first-run `netclaw init` **PRD:** `docs/prd/PRD-004-cli-onboarding-and-config.md` **Spec:** `docs/spec/SPEC-007-guided-onboarding.md`, `openspec/changes/simplify-netclaw-init/tasks.md` **Surface area:** TUI, config bootstrap **Verification:** L3 Done when: - [ ] Planning and code remove all `netclaw init --force` assumptions. - [ ] First-run init contains bootstrap-owned steps only. - [ ] Posture values remain `Personal`, `Team`, `Public`. - [ ] Identity remains init-owned. - [ ] Post-flight messaging points users to `netclaw chat` and `netclaw config`. - [ ] Init smoke `./scripts/smoke/run-smoke.sh init-wizard` passes. - [ ] Full light smoke passes or local blockers are documented with evidence. #### Task 2.2: Implement existing-install init menu and destructive reset flow **PRD:** `docs/prd/PRD-004-cli-onboarding-and-config.md` **Spec:** `docs/spec/SPEC-007-guided-onboarding.md`, `openspec/changes/simplify-netclaw-init/tasks.md` **Surface area:** TUI, config bootstrap, destructive actions **Verification:** L3 Done when: - [ ] Existing install shows exactly: `Redo identity setup`, `Open configuration editor`, `Start over from scratch`, `Cancel`. - [ ] `Open configuration editor` routes to `netclaw config`. - [ ] `Redo identity setup` routes only into init-owned identity flow. - [ ] Start-over dialog shows exactly: `Reset setup only`, `Full reset`, `Cancel`. - [ ] Both destructive actions require double confirmation. - [ ] Tests cover refusal, menu routing, double confirmation, and preserved vs deleted files. - [ ] Smoke coverage exercises existing-install menu and start-over cancellation. #### Task 2.3: Close the `simplify-netclaw-init` OpenSpec change **PRD:** `docs/prd/PRD-004-cli-onboarding-and-config.md` **Spec:** `openspec/changes/simplify-netclaw-init/tasks.md` **Surface area:** planning, TUI **Verification:** L3 Done when: - [ ] `openspec validate simplify-netclaw-init --type change` passes. - [ ] `/opsx-verify simplify-netclaw-init` passes. - [ ] Init smoke and light smoke pass. - [ ] Docs and skill guidance no longer describe stale init behavior. ### Phase 3: Runtime Adapter Contract Hardening Purpose: prove each channel adapter accepts, denies, responds, and reports health according to the same security envelope. #### Task 3.1: Add adapter config-to-runtime contract tests **PRD:** `docs/prd/PRD-009-input-adapters-and-unified-input.md`, `docs/prd/PRD-002-gateway-security-envelope.md` **Spec:** `openspec/specs/netclaw-input-adapters/spec.md`, `openspec/specs/netclaw-slack-socket/spec.md`, `openspec/specs/netclaw-discord-socket/spec.md`, `openspec/specs/tool-authorization/spec.md` **Surface area:** runtime, config, ACL **Verification:** L2 Done when: - [ ] Slack, Discord, and Mattermost options bind from the config shape emitted by init/config editors. - [ ] Allowed channel IDs and user IDs are consumed by runtime ACL in canonical provider form. - [ ] Denied channel, denied user, allowed channel, and DM policy cases are covered per adapter. - [ ] Misconfigured required tokens or server URLs fail closed for the affected channel without enabling permissive ingress. - [ ] Tests name the producer and consumer for each contract. #### Task 3.2: Add runtime reply-path smoke for local/demo adapters **PRD:** `docs/prd/PRD-009-input-adapters-and-unified-input.md` **Spec:** `openspec/specs/netclaw-input-adapters/spec.md`, `openspec/specs/netclaw-testing/spec.md` **Surface area:** runtime, smoke **Verification:** L4 Done when: - [ ] Mattermost demo smoke posts a user message and proves the daemon routes it to a session and attempts a reply. - [ ] Discord and Slack live smoke remain opt-in and credential-gated; absence of credentials skips with clear output, not failure. - [ ] Runtime logs expose enough detail to diagnose allowed/denied/routed/reply states without leaking secrets. - [ ] `TOOLING.md` documents the exact invocation and expected artifacts. #### Task 3.3: Normalize channel diagnostics and doctor output **PRD:** `docs/prd/PRD-003-operator-ux-ops-console.md`, `docs/prd/PRD-009-input-adapters-and-unified-input.md` **Spec:** `docs/spec/SPEC-005-operator-ui-contract.md`, `openspec/specs/netclaw-operator-ui/spec.md` **Surface area:** CLI, daemon diagnostics, operations **Verification:** L2 Done when: - [ ] `netclaw status` or doctor output distinguishes disconnected, misconfigured, denied-by-policy, and healthy per channel. - [ ] Slack/Discord/Mattermost health outputs use consistent terms. - [ ] Tests cover status mapping from runtime channel health to CLI/doctor display. - [ ] Runbooks mention the deny and misconfiguration diagnostics operators should look for. ### Phase 4: Model Provider And Tool Execution Contracts Purpose: keep model/provider/tool execution reliable and diagnosable across provider differences. #### Task 4.1: Harden provider/model config-to-runtime binding **PRD:** `docs/prd/PRD-005-model-provider-strategy.md`, `docs/prd/PRD-004-cli-onboarding-and-config.md` **Spec:** `docs/spec/SPEC-008-model-provider-abstraction.md`, `openspec/specs/netclaw-model-providers/spec.md`, `openspec/specs/netclaw-model-capabilities/spec.md` **Surface area:** config, runtime, providers **Verification:** L2 Done when: - [ ] Provider and model editors emit config that runtime provider selection consumes without hidden defaults. - [ ] Invalid provider IDs, missing model IDs, unsupported auth modes, and stale capability metadata fail visibly. - [ ] Tests cover config editor output -> provider registry/model selection consumption. - [ ] Eval suite is run if model/provider defaults or capability logic changes. #### Task 4.2: Prove tool schema and permission contracts end-to-end **PRD:** `docs/prd/PRD-006-mcp-tool-integration.md`, `docs/prd/PRD-002-gateway-security-envelope.md` **Spec:** `openspec/specs/netclaw-tools/spec.md`, `openspec/specs/netclaw-mcp/spec.md`, `openspec/specs/tool-call-metadata/spec.md`, `openspec/specs/mcp-schema-coercion/spec.md` **Surface area:** tools, MCP, security **Verification:** L2 Done when: - [ ] Tool schemas generated for models match dispatcher expectations. - [ ] MCP schema coercion has negative tests for invalid/coercion-impossible inputs. - [ ] Tool approval and grant decisions are tested for allow, deny, prompt, and malformed metadata. - [ ] No tool can bypass audience/profile policy because a field is missing or has a stale name. #### Task 4.3: Keep streaming/progress execution contract coherent **PRD:** `docs/prd/PRD-001-netclaw-mvp.md`, `docs/prd/PRD-006-mcp-tool-integration.md` **Spec:** `docs/spec/SPEC-016-tool-liveness-and-stall-detection.md`, `openspec/changes/streaming-tool-call-execution/tasks.md`, `openspec/specs/session-state-machine/spec.md` **Surface area:** runtime, actors, tools **Verification:** L2 Done when: - [ ] Tool-call streaming, progress reporting, session phase transitions, and persistence snapshots agree on the same state names. - [ ] Tool liveness is classified as `Opaque` or `SelfMonitoring`; generated tools default to `Opaque`, and `spawn_agent` is explicitly `SelfMonitoring`. - [ ] Opaque tools use one wall-clock budget; streamed stdout/stderr or other output does not reset the budget. - [ ] Self-monitoring tools use only a parent first-item startup guard after which the child/tool-owned watchdog reports terminal success or failure. - [ ] Actor tests prove progress events survive normal tool completion, tool failure, cancellation, and session recovery. - [ ] Actor tests prove a quiet-but-healthy sub-agent is not killed by the parent `Session.ToolExecutionTimeoutSeconds`, while child prefill/no-progress stalls still produce terminal failed `spawn_agent` results. - [ ] No turn loop can report success while a tool result is still pending. - [ ] Logs/traces correlate model call, tool call, approval, and session turn. `openspec/changes/archive/2026-09-29-correlate-tool-authorization-attempts/` implements the call-local authorization-attempt link across policy, correction, prompt, decision, retry, recovery, and result. Model-call and session-turn links remain part of the broader observability item. ### Phase 5: Memory, Identity, Scheduling, And Persistence Contracts Purpose: ensure autonomous behavior survives restarts and carries the right identity/context. #### Task 5.1: Prove identity file and system prompt assembly contracts **PRD:** `docs/prd/PRD-007-agent-personality-and-local-memory.md`, `docs/prd/PRD-004-cli-onboarding-and-config.md` **Spec:** `openspec/specs/project-instructions/spec.md`, `openspec/specs/netclaw-agent-memory/spec.md` **Surface area:** identity, prompt assembly, evals **Verification:** L2 plus eval suite Done when: - [ ] Init writes identity files in the exact paths prompt assembly reads. - [ ] Prompt assembly rejects missing or malformed required identity assets visibly. - [ ] Tests cover first-run, existing-install identity redo, missing file, and malformed file cases. - [ ] Eval suite passes when identity grounding rules change. #### Task 5.2: Prove memory recall and compaction persistence contracts **PRD:** `docs/prd/PRD-007-agent-personality-and-local-memory.md` **Spec:** `openspec/specs/netclaw-agent-memory/spec.md`, `openspec/specs/netclaw-session/spec.md`, `openspec/specs/thread-history-backfill/spec.md` **Surface area:** persistence, memory, session actors **Verification:** L2 plus eval suite Done when: - [ ] Memory recall inputs, persisted observations, compaction summaries, and prompt assembly use compatible serialization-safe types. - [ ] Tests cover fresh session, resumed session, compacted session, and corrupt or missing memory state. - [ ] Eval suite passes for memory pipeline and compaction changes. #### Task 5.3: Prove scheduling delivery contracts **PRD:** `docs/prd/PRD-008-scheduling-and-periodic-tasks.md`, `docs/prd/PRD-009-input-adapters-and-unified-input.md` **Spec:** `openspec/specs/netclaw-scheduling/spec.md`, `openspec/specs/reminder-execution-history/spec.md` **Surface area:** scheduling, actors, channel delivery **Verification:** L2 Done when: - [ ] Reminder targets resolve to channel gateways using canonical provider IDs. - [ ] Current-session delivery routes through the existing session gateway chain without re-running inbound ACL checks. - [ ] Future scheduled delivery uses policy appropriate for the stored target. - [ ] Tests cover immediate reminder, periodic reminder, missed execution, failed delivery, restart recovery, and invalid target. - [ ] `TimeProvider` is used for all scheduling time. ### Phase 6: Release Readiness And Packaging Purpose: keep install, Docker, demo, and CI aligned with product behavior. #### Task 6.1: Keep Docker image and install artifacts contract-tested **PRD:** `docs/prd/PRD-001-netclaw-mvp.md`, `docs/prd/PRD-004-cli-onboarding-and-config.md` **Spec:** `openspec/specs/daemon-container/spec.md`, `openspec/specs/manifest-signature-verification/spec.md` **Surface area:** packaging, install, Docker **Verification:** L3 Done when: - [ ] Docker image contains matching CLI and daemon binaries from the same source build. - [ ] Container default config path, health check, entrypoint, and self-update behavior match docs. - [ ] Install smoke passes for Linux/macOS/Windows stand-in archives. - [ ] Manifest signature verification negative paths are covered. - [ ] Local POC rebuild instructions are documented and reproducible. #### Task 6.2: Maintain demo AppHost as the local end-to-end proof **PRD:** `docs/prd/PRD-001-netclaw-mvp.md`, `docs/prd/PRD-009-input-adapters-and-unified-input.md` **Spec:** `openspec/changes/netclaw-demo-apphost/tasks.md`, `TOOLING.md` **Surface area:** demo, runtime, smoke **Verification:** L4 Done when: - [ ] Demo AppHost boots Mattermost, Ollama, and daemon to healthy. - [ ] Seeded Mattermost user can post into the configured channel. - [ ] Daemon logs prove message routing into a session and model invocation. - [ ] Slow CPU inference remains documented as latency caveat, not hidden as a failed wiring assertion. - [ ] Opt-in demo integration test remains skipped by default and passes with `NETCLAW_RUN_DEMO_SMOKE=1` on a suitable Docker host. ## NEXT NEXT tasks are important but not eligible for autonomous execution unless moved to `NOW` by the user. - Webhook service identity and inbound webhook route hardening beyond the config enablement/timeout editor. - Subagent explicit model selection and parent-context alignment. - GitHub Copilot provider refinements and VLLM capability strategy. - Approval button label refinement and richer interactive approval UX. - Config hot-reload beyond current startup/configure flows. - Operator UX/Ops Console beyond CLI/TUI diagnostics. ## LATER LATER tasks are product-direction items and should stay out of execution loops. - Ambient monitoring workflows. - Delegated coding task orchestration. - Browser automation as a first-class feature beyond config-time MCP profile enablement. - Split gateway/agent process architecture. - Hosted SaaS / multi-tenant operator console. ## Required Session Closure Checklist Before declaring any implementation session done, record the closure state in the final response and, if a task remains incomplete, leave a concrete follow-up in this plan. - [ ] Which `IMPLEMENTATION_PLAN.md` task was worked. - [ ] Producer/consumer contract identified. - [ ] Positive behavior verified. - [ ] Negative behavior verified. - [ ] Runtime/smoke/eval validation completed or explicitly blocked. - [ ] Docs/spec/skill updates completed or explicitly not applicable. - [ ] Commands run and results reported. - [ ] Worktree state reported.