[parent] #1369
Work type
Bug / regression
Observed behavior
harnesscli --base-url ... --workspace /tmp/other --prompt "..." with a scripted write where-am-i.txt tool call wrote the file into the daemon's HARNESS_WORKSPACE, not /tmp/other. The CLI (cmd/harnesscli/main.go runCreateRequest.WorkspacePath, default cwd) and the TUI (cmd/harnesscli/tui/api.go:72) both send workspace_path; harness.RunRequest (internal/harness/types.go:444) has no such field and handlePostRun decodes without DisallowUnknownFields, so it is dropped silently. The flag help text says "workspace directory for this run" and docs/ux-paths.md:107 says it is forwarded.
Expected behavior
A run started with workspace_path runs its file and shell tools rooted at that directory (validated absolute, existing), confined by the sandbox to that root, and the conversation record stores it. Invalid values are rejected with 400 like extra_dirs. If the server chooses not to support it, it must reject the field rather than ignore it.
Reproduction
- Start harnessd with
HARNESS_WORKSPACE=/tmp/a.
- From
/tmp/b: harnesscli --prompt "write hello.txt" (or --workspace /tmp/b).
Actual: /tmp/a/hello.txt. Deterministic.
User and operational impact
Every TUI/CLI user working from a directory other than the daemon's startup directory gets agent edits applied to the wrong project, with a success message. #559 proposes the same field as a feature; #567 shows the per-run registry path exists for provisioned workspaces.
Suspected seam and search evidence
internal/harness/runner.go ~1716-1817 already builds a per-run tool registry rooted at a provisioned workspace path (NewDefaultRegistryWithOptions(wsPath, ...), workspace.provisioned event). The fix routes an explicit workspace_path through that same per-run root without provisioning. Validation mirrors ExtraDirs checks in StartRun.
Blast-radius impact map
Callers: CLI, TUI, ACP bridge, MCP start_run (check whether they send it). Config/env: HARNESS_WORKSPACE stays the default. API/wire: new optional workspace_path on RunRequest. Persistence: conversations.workspace should record the effective root (#1303 item 1 mentions it is empty in production). Concurrency: per-run registry already exists. Security: absolute+exists validation; sandbox confinement rooted at the per-run path; extra_dirs unchanged. Docs: harnesscli runbook, ux-paths. Tests: internal/harness runner tests, internal/server handler tests, cmd/harnesscli tests.
Regression test first
internal/harness/runner_test.go TestStartRun_WorkspacePathRootsTools (write tool lands under the requested root) and internal/server TestPostRun_WorkspacePathValidated (relative/nonexistent → 400).
Red: go test ./internal/harness -run TestStartRun_WorkspacePath. Expected failure: file written under the daemon root.
Fix boundaries
In scope: decode, validate, and honor workspace_path via the existing per-run registry; record it on the conversation. Out of scope: provisioning/isolation modes, multi-tenant policy for allowed roots (follow-up if needed), #567 VM path.
Diagnostic and observability evidence
Existing workspace.provisioned event should carry the path for explicit roots too.
Verification plan
Red/green; go test ./internal/harness ./internal/server ./cmd/harnesscli -race; live: CLI from a different cwd writes into its cwd; sandbox scenario still blocks escapes from the new root.
Rollout and rollback
Behavior change only for clients that already send the field; revert PR to roll back.
Documentation and handoff
Engineering log; docs/runbooks/harnesscli-live-testing.md, docs/ux-paths.md, README run-request fields.
Definition of done
Process acknowledgement
[parent] #1369
Work type
Bug / regression
Observed behavior
harnesscli --base-url ... --workspace /tmp/other --prompt "..."with a scriptedwrite where-am-i.txttool call wrote the file into the daemon'sHARNESS_WORKSPACE, not/tmp/other. The CLI (cmd/harnesscli/main.gorunCreateRequest.WorkspacePath, default cwd) and the TUI (cmd/harnesscli/tui/api.go:72) both sendworkspace_path;harness.RunRequest(internal/harness/types.go:444) has no such field andhandlePostRundecodes withoutDisallowUnknownFields, so it is dropped silently. The flag help text says "workspace directory for this run" anddocs/ux-paths.md:107says it is forwarded.Expected behavior
A run started with
workspace_pathruns its file and shell tools rooted at that directory (validated absolute, existing), confined by the sandbox to that root, and the conversation record stores it. Invalid values are rejected with 400 likeextra_dirs. If the server chooses not to support it, it must reject the field rather than ignore it.Reproduction
HARNESS_WORKSPACE=/tmp/a./tmp/b:harnesscli --prompt "write hello.txt"(or--workspace /tmp/b).Actual:
/tmp/a/hello.txt. Deterministic.User and operational impact
Every TUI/CLI user working from a directory other than the daemon's startup directory gets agent edits applied to the wrong project, with a success message. #559 proposes the same field as a feature; #567 shows the per-run registry path exists for provisioned workspaces.
Suspected seam and search evidence
internal/harness/runner.go~1716-1817 already builds a per-run tool registry rooted at a provisioned workspace path (NewDefaultRegistryWithOptions(wsPath, ...),workspace.provisionedevent). The fix routes an explicitworkspace_paththrough that same per-run root without provisioning. Validation mirrorsExtraDirschecks inStartRun.Blast-radius impact map
Callers: CLI, TUI, ACP bridge, MCP
start_run(check whether they send it). Config/env:HARNESS_WORKSPACEstays the default. API/wire: new optionalworkspace_pathonRunRequest. Persistence:conversations.workspaceshould record the effective root (#1303 item 1 mentions it is empty in production). Concurrency: per-run registry already exists. Security: absolute+exists validation; sandbox confinement rooted at the per-run path;extra_dirsunchanged. Docs: harnesscli runbook, ux-paths. Tests:internal/harnessrunner tests,internal/serverhandler tests,cmd/harnessclitests.Regression test first
internal/harness/runner_test.goTestStartRun_WorkspacePathRootsTools(write tool lands under the requested root) andinternal/serverTestPostRun_WorkspacePathValidated(relative/nonexistent → 400).Red:
go test ./internal/harness -run TestStartRun_WorkspacePath. Expected failure: file written under the daemon root.Fix boundaries
In scope: decode, validate, and honor
workspace_pathvia the existing per-run registry; record it on the conversation. Out of scope: provisioning/isolation modes, multi-tenant policy for allowed roots (follow-up if needed), #567 VM path.Diagnostic and observability evidence
Existing
workspace.provisionedevent should carry the path for explicit roots too.Verification plan
Red/green;
go test ./internal/harness ./internal/server ./cmd/harnesscli -race; live: CLI from a different cwd writes into its cwd; sandbox scenario still blocks escapes from the new root.Rollout and rollback
Behavior change only for clients that already send the field; revert PR to roll back.
Documentation and handoff
Engineering log;
docs/runbooks/harnesscli-live-testing.md,docs/ux-paths.md, README run-request fields.Definition of done
Process acknowledgement