You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
A live review on 2026-09-05 drove harnessd and harnesscli end to end (fake provider with scripted tool calls, plus real OpenRouter runs) through long multi-step scenarios: tool loops, multi-turn conversations, restart persistence, budget limits, cancel/steer, approvals, plan mode, sandbox escapes, 20-way concurrency, session rewind, and headless CLI blocking. The core loop, sandbox, approvals, plan mode, cancellation and concurrency are correct. Eight defects were reproduced:
Session rewind truncates the wrong messages (step unit mismatch) and the live daemon keeps serving the untruncated in-memory history.
Rewind's external-modification guard refuses any point older than the latest agent edit of the same file (false positive), forcing force, which also disables the real check.
harnesscli --workspace and the TUI workspace_path are silently dropped by the server; tools always run in the daemon's HARNESS_WORKSPACE.
harnessd SIGTERM drains HTTP for 10 s, never cancels in-flight runs, and orphans running tool children.
A headless CLI run blocked on AskUserQuestion tells the user to run harnesscli continue, which returns 409 run_not_completed.
After a daemon restart GET /v1/runs/{id} works but /events and /summary return 404.
harnessd silently caps every run at 8 steps and reports the run as failed; product direction is that the harness has no run cap by default.
cmd/acceptance-api-sse fails on macOS (symlinked temp dir vs canonical-path check) and the nightly test-regression job is red on the zero-coverage gate.
Outcome: every item above is fixed at its owning seam with a permanent regression test, the live scenario suite that found them passes, and operator docs describe the real defaults. Affected users: everyone using rewind, the CLI/TUI from a non-daemon directory, headless automation, and long-running agent tasks.
Non-goals
No new API surface beyond honoring the already-sent workspace_path field.
No change to permission semantics, plan-mode flow, or approval broker.
Prompt-token cost of the 67-tool schema (~13k tokens per turn observed) is out of scope; track separately.
Documentation audit results are tracked in a separate child once the audit lands.
Current architecture and evidence
Entry points: cmd/harnessd/main.go (lifecycle, shutdown at ~1184), cmd/harnessd/config_reload.go:46 (MaxSteps 0→8), internal/server/http_runs.go (handlePostRun decodes harness.RunRequest; /events and /summary call runner.Subscribe / runner.GetRunSummary only), internal/server/http_conversations.go (/messages reads runner.ConversationMessagesSnapshot; /rewind), internal/harness/conversation_store_sqlite.go (RestoreRewindPoint ~682-750, expected_hash update ~630-640), internal/harness/runner_step_engine.go:1352 (RewindPoint{Step: step} uses the run-local step), cmd/harnesscli/main.go (runCreateRequest.WorkspacePath, reportRunBlocked), cmd/harnesscli/tui/api.go:72 (workspace_path), internal/harness/types.go:444 (RunRequest, no workspace field).
Evidence: scenario scripts and outputs from the review session; key observations reproduced deterministically with HARNESS_PROVIDER=fake scripted tool calls.
Existing sources of truth: docs/runbooks/session-rewind.md, docs/runbooks/golden-path-deployment.md (claims max_steps default 30), docs/ux-paths.md (claims --workspace is forwarded).
Known related debt: #1303 (rewind: mirror resurrects messages), #559 (per-request workspace override proposal), #1356 (shutdown ordering), #823 (CLI exit codes), #796 (older coverage-gate red).
Cross-surface impact map
Config/env/defaults: max_steps daemon default 8 → 0 (unlimited); HARNESS_MAX_STEPS/config still honored; TUI config.go MaxSteps 8.
APIs/CLI/tools/wire formats: RunRequest.workspace_path becomes a real field (validated absolute existing dir); /events and /summary gain a durable fallback; CLI blocked message changes; no other shape changes.
Persistence/schema/migrations: none; rewind truncation predicate and expected_hash maintenance change semantics only.
Concurrency/lifecycle/recovery: shutdown cancels active runs with a bounded wait and kills tool process groups; rewind invalidates the in-memory conversation mirror.
Security/auth/privacy/permissions: workspace_path must be validated like extra_dirs (absolute, exists); sandbox confinement then keys off the per-run root.
TUI/web/macOS/other clients: TUI already sends workspace_path; TUI rewind result display (#1303) unaffected.
Provider/model/tool catalog: none.
Deployment/observability/operations: shutdown logs cancelled-run count; runbooks updated.
Compatibility/versioning: existing rewind points keep working; a run that previously died at step 8 now continues.
Tests/evals/fixtures: one regression test per child; scripts/test-regression.sh green; fake-provider live scenarios re-run.
Documentation/training: golden-path, session-rewind, harnesscli runbooks, ux-paths.
Independent, can proceed in parallel: C1 rewind truncation, C2 rewind guard, C3 workspace_path, C4 shutdown, C5 CLI hint, C6 events/summary fallback, C7 step cap, C8 macOS test + coverage gate.
Convergence: C1 and C2 both touch conversation_store_sqlite.go (different functions; rebase second on first). C3 and C4 both touch runner lifecycle (different functions). Docs child depends on C3 and C7 landing so docs describe the final behavior.
Integration contracts
RunRequest remains backward compatible; new field optional.
Rewind: after POST /rewind to point P, GET /messages and the next run's context contain exactly the messages recorded before P's tool call; file restore unchanged.
Shutdown: no run remains running in the store after exit; no child process of a tool survives daemon exit.
Step cap: max_steps 0 means unlimited everywhere (daemon, TUI, docs); explicit caps keep current semantics.
Every child adds a test in the package that owns the seam; live proof via the fake-provider scenario for that behavior.
Rollout sequence
All children are independent behavioral fixes with no migrations; merge in any order, rebuild with scripts/install.sh, restart the daemon. Backout is a revert of the individual PR. Final integration proof: re-run the review's live scenario suite against a rebuilt daemon.
Risks and observability
Removing the step cap → runaway runs; mitigation: max_cost_usd and explicit max_steps remain; signal: run duration/step count in summary.
workspace_path widens filesystem reach → validated like extra_dirs, confined by the sandbox; signal: workspace.provisioned event carries the path.
All child contracts satisfied with regression tests that were red first
Live fake-provider scenario suite green against a rebuilt daemon (rewind, workspace, shutdown, CLI blocked, restart, no cap)
scripts/test-regression.sh green including the coverage gate — pending next nightly on CI; locally only internal/acceptance/ptyrunner fails (environment-specific, passes on CI)
Runbooks and README state the real defaults and flags
Engineering log updated
Epic acknowledgement
I will not close this epic directly from an implementation PR; every code slice will close its own contract-complete child issue.
Work type
Epic
Problem and outcome
A live review on 2026-09-05 drove
harnessdandharnesscliend to end (fake provider with scripted tool calls, plus real OpenRouter runs) through long multi-step scenarios: tool loops, multi-turn conversations, restart persistence, budget limits, cancel/steer, approvals, plan mode, sandbox escapes, 20-way concurrency, session rewind, and headless CLI blocking. The core loop, sandbox, approvals, plan mode, cancellation and concurrency are correct. Eight defects were reproduced:stepunit mismatch) and the live daemon keeps serving the untruncated in-memory history.force, which also disables the real check.harnesscli --workspaceand the TUIworkspace_pathare silently dropped by the server; tools always run in the daemon'sHARNESS_WORKSPACE.harnessdSIGTERM drains HTTP for 10 s, never cancels in-flight runs, and orphans running tool children.AskUserQuestiontells the user to runharnesscli continue, which returns 409run_not_completed.GET /v1/runs/{id}works but/eventsand/summaryreturn 404.harnessdsilently caps every run at 8 steps and reports the run asfailed; product direction is that the harness has no run cap by default.cmd/acceptance-api-ssefails on macOS (symlinked temp dir vs canonical-path check) and the nightlytest-regressionjob is red on the zero-coverage gate.Outcome: every item above is fixed at its owning seam with a permanent regression test, the live scenario suite that found them passes, and operator docs describe the real defaults. Affected users: everyone using rewind, the CLI/TUI from a non-daemon directory, headless automation, and long-running agent tasks.
Non-goals
workspace_pathfield.Current architecture and evidence
Entry points:
cmd/harnessd/main.go(lifecycle, shutdown at ~1184),cmd/harnessd/config_reload.go:46(MaxSteps0→8),internal/server/http_runs.go(handlePostRundecodesharness.RunRequest;/eventsand/summarycallrunner.Subscribe/runner.GetRunSummaryonly),internal/server/http_conversations.go(/messagesreadsrunner.ConversationMessagesSnapshot;/rewind),internal/harness/conversation_store_sqlite.go(RestoreRewindPoint~682-750, expected_hash update ~630-640),internal/harness/runner_step_engine.go:1352(RewindPoint{Step: step}uses the run-local step),cmd/harnesscli/main.go(runCreateRequest.WorkspacePath,reportRunBlocked),cmd/harnesscli/tui/api.go:72(workspace_path),internal/harness/types.go:444(RunRequest, no workspace field).Evidence: scenario scripts and outputs from the review session; key observations reproduced deterministically with
HARNESS_PROVIDER=fakescripted tool calls.Existing sources of truth:
docs/runbooks/session-rewind.md,docs/runbooks/golden-path-deployment.md(claimsmax_stepsdefault 30),docs/ux-paths.md(claims--workspaceis forwarded).Known related debt: #1303 (rewind: mirror resurrects messages), #559 (per-request workspace override proposal), #1356 (shutdown ordering), #823 (CLI exit codes), #796 (older coverage-gate red).
Cross-surface impact map
Config/env/defaults:
max_stepsdaemon default 8 → 0 (unlimited);HARNESS_MAX_STEPS/config still honored; TUIconfig.goMaxSteps 8.APIs/CLI/tools/wire formats:
RunRequest.workspace_pathbecomes a real field (validated absolute existing dir);/eventsand/summarygain a durable fallback; CLI blocked message changes; no other shape changes.Persistence/schema/migrations: none; rewind truncation predicate and expected_hash maintenance change semantics only.
Concurrency/lifecycle/recovery: shutdown cancels active runs with a bounded wait and kills tool process groups; rewind invalidates the in-memory conversation mirror.
Security/auth/privacy/permissions:
workspace_pathmust be validated likeextra_dirs(absolute, exists); sandbox confinement then keys off the per-run root.TUI/web/macOS/other clients: TUI already sends
workspace_path; TUI rewind result display (#1303) unaffected.Provider/model/tool catalog: none.
Deployment/observability/operations: shutdown logs cancelled-run count; runbooks updated.
Compatibility/versioning: existing rewind points keep working; a run that previously died at step 8 now continues.
Tests/evals/fixtures: one regression test per child;
scripts/test-regression.shgreen; fake-provider live scenarios re-run.Documentation/training: golden-path, session-rewind, harnesscli runbooks, ux-paths.
Shippable child issues
workspace_pathhonored via the per-run tool registry and validated likeextra_dirs; test: CLI from another cwd writes there, sandbox confined to itharnesscli inputsubmits answers; test: printed command resumes the run/eventsand/summaryfall back to the durable store; test: 200 after restartmax_stepsdefault in daemon or TUI; docs say 0 = unlimited; test: 9-step run completesDependency graph
Independent, can proceed in parallel: C1 rewind truncation, C2 rewind guard, C3 workspace_path, C4 shutdown, C5 CLI hint, C6 events/summary fallback, C7 step cap, C8 macOS test + coverage gate.
Convergence: C1 and C2 both touch
conversation_store_sqlite.go(different functions; rebase second on first). C3 and C4 both touch runner lifecycle (different functions). Docs child depends on C3 and C7 landing so docs describe the final behavior.Integration contracts
RunRequestremains backward compatible; new field optional.POST /rewindto point P,GET /messagesand the next run's context contain exactly the messages recorded before P's tool call; file restore unchanged.runningin the store after exit; no child process of a tool survives daemon exit.max_steps0 means unlimited everywhere (daemon, TUI, docs); explicit caps keep current semantics.Rollout sequence
All children are independent behavioral fixes with no migrations; merge in any order, rebuild with
scripts/install.sh, restart the daemon. Backout is a revert of the individual PR. Final integration proof: re-run the review's live scenario suite against a rebuilt daemon.Risks and observability
max_cost_usdand explicitmax_stepsremain; signal: run duration/step count in summary.workspace_pathwidens filesystem reach → validated likeextra_dirs, confined by the sandbox; signal:workspace.provisionedevent carries the path.messages_truncatedmatches expected counts.Definition of done
scripts/test-regression.shgreen including the coverage gate — pending next nightly on CI; locally onlyinternal/acceptance/ptyrunnerfails (environment-specific, passes on CI)Epic acknowledgement