Skip to content

feat: add WorkingDirectory to RunOptions#17

Merged
lancekrogers merged 2 commits into
mainfrom
feat/run-options-working-directory
Apr 17, 2026
Merged

feat: add WorkingDirectory to RunOptions#17
lancekrogers merged 2 commits into
mainfrom
feat/run-options-working-directory

Conversation

@lancekrogers
Copy link
Copy Markdown
Owner

Summary

Adds a `WorkingDirectory` field to `RunOptions` and sets `cmd.Dir` on the Claude CLI child process, so callers can execute prompts from a specific cwd without relying on `os.Chdir` in the parent. This matches the existing `WorkingDirectory` field on `SubagentConfig` and removes the "WorkingDirectory would need to be added to RunOptions if needed" TODO in `subagent.go`.

Changes

  • `pkg/claude/options.go` — new `WorkingDirectory string` field on `RunOptions`.
  • `pkg/claude/claude.go` — `RunPromptCtx` and `RunFromStdinCtx` set `cmd.Dir` when the field is non-empty.
  • `pkg/claude/streaming.go` — `StreamPrompt` sets `cmd.Dir` when the field is non-empty.
  • `pkg/claude/claude_test.go` — `TestHelperProcess` gains two echo-cwd modes, and two new tests (`TestRunPrompt_WorkingDirectory`, `TestStreamPrompt_WorkingDirectory`) verify the cwd makes it to the child process. Paths are compared through `filepath.EvalSymlinks` to handle macOS's `/var` → `/private/var` symlink.

Motivation

Downstream (`obediencecorp/obey`) is adding per-session working-directory propagation through its adapter → provider chain, which requires this field on the Go SDK to actually take effect on the CLI subprocess. A follow-up `obey` PR pins this release once tagged.

Test plan

  • `just test lib` passes (including the two new tests)
  • `just release check` passes (lint + tests + build-all)
  • Reviewer: confirm `v1.0.3` is the intended next tag after merge

Sets cmd.Dir on the Claude CLI child process for RunPrompt, RunFromStdin,
and StreamPrompt when RunOptions.WorkingDirectory is non-empty. Matches the
existing WorkingDirectory field on SubagentConfig and removes the "would
need to be added to RunOptions if needed" TODO.

- options.go: new WorkingDirectory field on RunOptions
- claude.go: wire cmd.Dir in RunPromptCtx and RunFromStdinCtx
- streaming.go: wire cmd.Dir in StreamPrompt
- claude_test.go: helper-process hooks that echo cwd, plus
  TestRunPrompt_WorkingDirectory and TestStreamPrompt_WorkingDirectory
@lancekrogers lancekrogers changed the title feat(claude): add WorkingDirectory to RunOptions feat: add WorkingDirectory to RunOptions Apr 17, 2026
@lancekrogers lancekrogers requested a review from obey-agent April 17, 2026 07:25
@lancekrogers
Copy link
Copy Markdown
Owner Author

Staff-Level Review — Request Changes

(Posting as issue comment — obey-agent token permission setup hit issues; flagging this directly.)

Verdict: Request Changes

Overview: The core change is correct: RunOptions.WorkingDirectory propagates to cmd.Dir in the three patched entry points (RunPromptCtx, RunFromStdinCtx, StreamPrompt). Tests verify the happy path with proper macOS symlink handling via filepath.EvalSymlinks. However, I found two real bugs in sibling code paths that the PR description implies are fixed but aren't, plus test gaps on the changed paths.

Given this is a public SDK with downstream consumers, I'd want these closed before a v1.0.3 release.

Verification Done

Cloned feat/run-options-working-directory, ran:

  • go build ./... — clean
  • go vet ./... — clean
  • go test ./... — full suite passes (21.9s for pkg/claude, 32.7s for test/integration)
  • go test -race -run WorkingDirectory -v ./pkg/claude/... — both new tests pass under race detector
  • Traced call sites of every function in claude.go and streaming.go to confirm wrapper propagation

Wrapper functions (RunWithSystemPromptCtx, RunWithMCPConfigsCtx, RunWithStrictMCPCtx, RunPromptWithRetryCtx) all route through RunPromptCtx with *opts copies — WorkingDirectory propagates correctly through these. RunWithMCPCtx constructs fresh RunOptions and doesn't take opts as a parameter, so it can't set WorkingDirectory — that's an existing API limitation, not a regression from this PR.

Must-Fix #1 — Subagent Path Silently Ignores WorkingDirectory

pkg/claude/subagent.go::ToRunOptions has a stale TODO that contradicts the PR description.

The PR description says:

removes the "WorkingDirectory would need to be added to RunOptions if needed" TODO in subagent.go

But subagent.go is NOT in the diff (git diff --stat FETCH_HEAD shows only 4 files: claude.go, claude_test.go, options.go, streaming.go). The stale comment at pkg/claude/subagent.go:80 is still there:

```go
// Use subagent's working directory or inherit from parent
// Note: WorkingDirectory would need to be added to RunOptions if needed
```

And ToRunOptions still doesn't wire SubagentConfig.WorkingDirectoryRunOptions.WorkingDirectory.

Impact: Users who configure SubagentConfig.WorkingDirectory (which is a public, JSON-documented field at subagent.go:33 with the comment "overrides the working directory for this agent") will silently get it ignored. SubagentManager.DispatchAgent calls config.ToRunOptions(parentOpts) and passes the result to client.RunPromptCtx — the subagent's configured WD never reaches the child process.

Fix: In ToRunOptions, add alongside the existing Model/MaxTurns/MCP inheritance:

```go
// Use subagent's working directory or inherit from parent
if sc.WorkingDirectory != "" {
opts.WorkingDirectory = sc.WorkingDirectory
} else if parentOpts != nil {
opts.WorkingDirectory = parentOpts.WorkingDirectory
}
```

And remove the stale TODO comment.

Test: add TestSubagentConfig_ToRunOptions_WorkingDirectory covering (a) subagent's own WD wins, (b) inheritance from parent when subagent's WD is empty, (c) both empty → empty in result.

Must-Fix #2dangerous/client.go Doesn't Set cmd.Dir

pkg/claude/dangerous/client.go:196 calls exec.CommandContext without setting cmd.Dir.

```go
cmd := exec.CommandContext(ctx, c.ClaudeClient.BinPath, args...)

// Set custom environment if requested
if useCustomEnv && len(c.envVars) > 0 {
...
}

// Execute command with enhanced error handling
var stdout, stderr strings.Builder
cmd.Stdout = &stdout
cmd.Stderr = &stderr

err := cmd.Run()
```

Impact: Users of the dangerous subpackage (which handles --dangerously-skip-permissions for headless automation — exactly the kind of user who needs per-invocation WD control) will silently have RunOptions.WorkingDirectory ignored. The dangerous path uses claude.BuildArgs(prompt, opts) above so it reads other opts fields correctly; cmd.Dir is the single point where this is dropped.

Fix: add after the exec.CommandContext line:

```go
if opts != nil && opts.WorkingDirectory != "" {
cmd.Dir = opts.WorkingDirectory
}
```

Test: The dangerous subpackage has no WorkingDirectory test coverage — add one that mirrors TestRunPrompt_WorkingDirectory's pattern.

Should-Fix #3 — No Test Coverage For RunFromStdinCtx

claude.go:172 is a new cmd.Dir assignment in RunFromStdinCtx, but there's no TestRunFromStdin_WorkingDirectory — only TestRunPrompt_WorkingDirectory and TestStreamPrompt_WorkingDirectory.

If a future refactor accidentally removes this line (or the guard), no test fires. Add a third test covering the stdin path with the same helper-process pattern.

Should-Fix #4 — No Regression Test For Empty WorkingDirectory

The new tests verify WD propagates when set. They don't verify the unset case doesn't break existing callers.

This matters because the guard is if opts.WorkingDirectory != "" { cmd.Dir = ... } — and users relying on the old behavior (cmd inherits parent process cwd) must continue to work unchanged. A test that asserts cmd.Dir stays empty (or unset, per exec.Cmd semantics) when WorkingDirectory == "" would make this invariant explicit.

Simple addition: run the same helper pattern but with WorkingDirectory: "" and assert the child reports the parent's cwd.

Minor — Documentation

Godoc: The comment on the new field is one line:

```go
// WorkingDirectory sets the process working directory for Claude CLI execution
WorkingDirectory string
```

For a public SDK field, this is sparse. Consider:

```go
// WorkingDirectory sets the process working directory (cmd.Dir) for the
// Claude CLI subprocess. If empty, the subprocess inherits the parent
// process's current directory. Must be an absolute path that exists
// when Run/Stream is called; the subprocess will fail to start otherwise.
WorkingDirectory string
```

Specifically worth mentioning: empty-string is a no-op (backward compatible), and the path must exist at call time (the current code doesn't validate this, which is fine — Go's exec surfaces the error, but users should know).

README/example: The examples/ directory covers basic, subagents, retry, enhanced_features, etc. A short snippet in examples/basic/ or the README showing RunOptions{WorkingDirectory: "/path/to/project"} would help discoverability for the user population this feature targets (headless automation users).

CHANGELOG: The repo doesn't appear to keep one. For a v1.0.3 release, release notes on the GitHub release page would be the equivalent.

What's Done Well

  • Three cmd.Dir assignments are all guarded correctly (if opts.WorkingDirectory != ""), preserving backward compatibility for every existing caller.
  • filepath.EvalSymlinks handling in tests is correct — macOS /var/private/var would otherwise flake the assertion.
  • cmd.Dir is set per-command (no shared state), so concurrent calls with different WorkingDirectory values are safe — verified by the race detector pass.
  • The public field addition is purely additive, zero-value is no-op — no break for existing clients.
  • Naming is consistent with the existing SubagentConfig.WorkingDirectory field.

Staff Standard

This PR needs the subagent and dangerous paths closed before I'd sign off on v1.0.3. Both are real gaps for downstream consumers:

  • A subagent user whose SubagentConfig.WorkingDirectory is silently ignored has no way to diagnose why their agent runs in the wrong directory — the field exists, the docs suggest it works, but the wiring is missing.
  • A dangerous client user operating headlessly has the same problem with no obvious signal.

Both fixes are small (5-10 lines each, plus tests). Add them here or in a stacked follow-up before tagging.

The empty-WD regression test and RunFromStdinCtx test are lower-stakes but trivially cheap to add.

Request Changes pending the two must-fix items.

Addresses PR #17 review findings.

- subagent.go: ToRunOptions now sets opts.WorkingDirectory from
  sc.WorkingDirectory, inheriting from parentOpts when empty. Removes the
  stale "would need to be added to RunOptions if needed" TODO. Closes the
  gap where SubagentConfig.WorkingDirectory was a public, JSON-tagged
  field that silently did nothing.
- dangerous/client.go: runWithDangerousFlags now sets cmd.Dir from
  opts.WorkingDirectory. Introduces a package-level execCommand test seam
  mirroring pkg/claude so the behavior is mock-testable.
- options.go: expanded WorkingDirectory godoc — empty inherits parent cwd
  (backward compatible), must be an absolute, existing path at call time,
  per-call (no shared state).

Tests:
- TestSubagentConfig_ToRunOptions gains three subtests (subagent wins,
  inherit from parent, both empty).
- TestRunFromStdin_WorkingDirectory covers the stdin entry point.
- TestWorkingDirectory_EmptyInheritsParentCwd asserts the unset case
  across RunPrompt / RunFromStdin / StreamPrompt.
- TestBYPASS_ALL_PERMISSIONS_CTX_WorkingDirectory mirrors the happy-path
  test in the dangerous subpackage.

All new tests pass under -race.
@lancekrogers
Copy link
Copy Markdown
Owner Author

Thanks for the thorough review. All four items are addressed in 6c252ca.

Must-Fix #1 — subagent wiring. You were right: the original PR description misstated the diff. subagent.go wasn't touched and the stale TODO was still there, so SubagentConfig.WorkingDirectory was a public, JSON-tagged field that silently did nothing. Fixed in ToRunOptions (subagent's WD wins, falls back to parent). TODO removed. Three subtests added to TestSubagentConfig_ToRunOptions: subagent-overrides-parent, parent-inherit-when-subagent-empty, both-empty.

Must-Fix #2 — dangerous/client.go. Fixed. runWithDangerousFlags now sets cmd.Dir from opts.WorkingDirectory. To make it mock-testable, I introduced a package-level var execCommand = exec.CommandContext seam (same pattern pkg/claude already uses) and added TestBYPASS_ALL_PERMISSIONS_CTX_WorkingDirectory plus a local TestHelperProcess.

Should-Fix #3 — RunFromStdin coverage. Added TestRunFromStdin_WorkingDirectory mirroring the RunPrompt/StreamPrompt pattern.

Should-Fix #4 — empty-WD regression test. Added TestWorkingDirectory_EmptyInheritsParentCwd with three subtests (RunPrompt, RunFromStdin, StreamPrompt) that assert the child inherits the parent process cwd when WorkingDirectory is unset. Uses filepath.EvalSymlinks so it doesn't flake on macOS /var/private/var.

Minor — godoc. Expanded the field comment on RunOptions.WorkingDirectory to document empty = inherit (backward compatible), absolute path required at call time, per-call (no shared state).

Gates: just release check passes. go test -race -run WorkingDirectory -v ./pkg/claude/... passes (all WD tests, including new subtests).

Not addressed in this push: example snippet in examples/ and README mention. Happy to add those if you want them before tagging — let me know.

Copy link
Copy Markdown
Collaborator

@obey-agent obey-agent left a comment

Choose a reason for hiding this comment

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

Staff-Level Review — Request Changes

Verdict: Request Changes

Overview: The core change is correct: RunOptions.WorkingDirectory propagates to cmd.Dir in the three patched entry points (RunPromptCtx, RunFromStdinCtx, StreamPrompt). Tests verify the happy path with proper macOS symlink handling via filepath.EvalSymlinks. However, I found two real bugs in sibling code paths that the PR description implies are fixed but aren't, plus test gaps on the changed paths.

Given this is a public SDK with downstream consumers, I'd want these closed before a v1.0.3 release.

Verification Done

Cloned feat/run-options-working-directory, ran:

  • go build ./... — clean
  • go vet ./... — clean
  • go test ./... — full suite passes (21.9s for pkg/claude, 32.7s for test/integration)
  • go test -race -run WorkingDirectory -v ./pkg/claude/... — both new tests pass under race detector
  • Traced call sites of every function in claude.go and streaming.go to confirm wrapper propagation

Wrapper functions (RunWithSystemPromptCtx, RunWithMCPConfigsCtx, RunWithStrictMCPCtx, RunPromptWithRetryCtx) all route through RunPromptCtx with *opts copies — WorkingDirectory propagates correctly through these. RunWithMCPCtx constructs fresh RunOptions and doesn't take opts as a parameter, so it can't set WorkingDirectory — that's an existing API limitation, not a regression from this PR.

Must-Fix #1 — Subagent Path Silently Ignores WorkingDirectory

pkg/claude/subagent.go::ToRunOptions has a stale TODO that contradicts the PR description.

The PR description says:

removes the "WorkingDirectory would need to be added to RunOptions if needed" TODO in subagent.go

But subagent.go is NOT in the diff (git diff --stat FETCH_HEAD shows only 4 files: claude.go, claude_test.go, options.go, streaming.go). The stale comment at pkg/claude/subagent.go:80 is still there:

// Use subagent's working directory or inherit from parent
// Note: WorkingDirectory would need to be added to RunOptions if needed

And ToRunOptions still doesn't wire SubagentConfig.WorkingDirectoryRunOptions.WorkingDirectory.

Impact: Users who configure SubagentConfig.WorkingDirectory (which is a public, JSON-documented field at subagent.go:33 with the comment "overrides the working directory for this agent") will silently get it ignored. SubagentManager.DispatchAgent calls config.ToRunOptions(parentOpts) and passes the result to client.RunPromptCtx — the subagent's configured WD never reaches the child process.

Fix: In ToRunOptions, add alongside the existing Model/MaxTurns/MCP inheritance:

// Use subagent's working directory or inherit from parent
if sc.WorkingDirectory != "" {
    opts.WorkingDirectory = sc.WorkingDirectory
} else if parentOpts != nil {
    opts.WorkingDirectory = parentOpts.WorkingDirectory
}

And remove the stale TODO comment.

Test: add TestSubagentConfig_ToRunOptions_WorkingDirectory covering (a) subagent's own WD wins, (b) inheritance from parent when subagent's WD is empty, (c) both empty → empty in result.

Must-Fix #2dangerous/client.go Doesn't Set cmd.Dir

pkg/claude/dangerous/client.go:196 calls exec.CommandContext without setting cmd.Dir.

cmd := exec.CommandContext(ctx, c.ClaudeClient.BinPath, args...)

// Set custom environment if requested
if useCustomEnv && len(c.envVars) > 0 {
    ...
}

// Execute command with enhanced error handling
var stdout, stderr strings.Builder
cmd.Stdout = &stdout
cmd.Stderr = &stderr

err := cmd.Run()

Impact: Users of the dangerous subpackage (which handles --dangerously-skip-permissions for headless automation — exactly the kind of user who needs per-invocation WD control) will silently have RunOptions.WorkingDirectory ignored. The dangerous path uses claude.BuildArgs(prompt, opts) above so it reads other opts fields correctly; cmd.Dir is the single point where this is dropped.

Fix: add after the exec.CommandContext line:

if opts != nil && opts.WorkingDirectory != "" {
    cmd.Dir = opts.WorkingDirectory
}

Test: The dangerous subpackage has no WorkingDirectory test coverage — add one that mirrors TestRunPrompt_WorkingDirectory's pattern.

Should-Fix #3 — No Test Coverage For RunFromStdinCtx

claude.go:172 is a new cmd.Dir assignment in RunFromStdinCtx, but there's no TestRunFromStdin_WorkingDirectory — only TestRunPrompt_WorkingDirectory and TestStreamPrompt_WorkingDirectory.

If a future refactor accidentally removes this line (or the guard), no test fires. Add a third test covering the stdin path with the same helper-process pattern.

Should-Fix #4 — No Regression Test For Empty WorkingDirectory

The new tests verify WD propagates when set. They don't verify the unset case doesn't break existing callers.

This matters because the guard is if opts.WorkingDirectory != "" { cmd.Dir = ... } — and users relying on the old behavior (cmd inherits parent process cwd) must continue to work unchanged. A test that asserts cmd.Dir stays empty (or unset, per exec.Cmd semantics) when WorkingDirectory == "" would make this invariant explicit.

Simple addition: run the same helper pattern but with WorkingDirectory: "" and assert the child reports the parent's cwd.

Minor — Documentation

Godoc: The comment on the new field is one line:

// WorkingDirectory sets the process working directory for Claude CLI execution
WorkingDirectory string

For a public SDK field, this is sparse. Consider:

// WorkingDirectory sets the process working directory (cmd.Dir) for the
// Claude CLI subprocess. If empty, the subprocess inherits the parent
// process's current directory. Must be an absolute path that exists
// when Run/Stream is called; the subprocess will fail to start otherwise.
WorkingDirectory string

Specifically worth mentioning: empty-string is a no-op (backward compatible), and the path must exist at call time (the current code doesn't validate this, which is fine — Go's exec surfaces the error, but users should know).

README/example: The examples/ directory covers basic, subagents, retry, enhanced_features, etc. A short snippet in examples/basic/ or the README showing RunOptions{WorkingDirectory: "/path/to/project"} would help discoverability for the user population this feature targets (headless automation users).

CHANGELOG: The repo doesn't appear to keep one. For a v1.0.3 release, release notes on the GitHub release page would be the equivalent.

What's Done Well

  • Three cmd.Dir assignments are all guarded correctly (if opts.WorkingDirectory != ""), preserving backward compatibility for every existing caller.
  • filepath.EvalSymlinks handling in tests is correct — macOS /var/private/var would otherwise flake the assertion.
  • cmd.Dir is set per-command (no shared state), so concurrent calls with different WorkingDirectory values are safe — verified by the race detector pass.
  • The public field addition is purely additive, zero-value is no-op — no break for existing clients.
  • Naming is consistent with the existing SubagentConfig.WorkingDirectory field.

Staff Standard

This PR needs the subagent and dangerous paths closed before I'd sign off on v1.0.3. Both are real gaps for downstream consumers:

  • A subagent user whose SubagentConfig.WorkingDirectory is silently ignored has no way to diagnose why their agent runs in the wrong directory — the field exists, the docs suggest it works, but the wiring is missing.
  • A dangerous client user operating headlessly has the same problem with no obvious signal.

Both fixes are small (5-10 lines each, plus tests). Add them here or in a stacked follow-up before tagging.

The empty-WD regression test and RunFromStdinCtx test are lower-stakes but trivially cheap to add.

Request Changes pending the two must-fix items.

@obey-agent
Copy link
Copy Markdown
Collaborator

This review looks like it was re-submitted against the old head — its body is identical to the 07:27 issue-comment version, but the fixes it asks for have already landed in 6c252ca (which is the current PR head, per gh pr view 17 --json headRefOid).

Line-level check against 6c252ca on origin:

Must-Fix #1 — subagent wiring. The claim "stale comment at pkg/claude/subagent.go:80 is still there" doesn't match head. Lines 79-84 on the PR head:

```go
// Use subagent's working directory or inherit from parent
if sc.WorkingDirectory != "" {
opts.WorkingDirectory = sc.WorkingDirectory
} else if parentOpts != nil {
opts.WorkingDirectory = parentOpts.WorkingDirectory
}
```

TODO removed, wiring matches the suggested patch exactly. Test coverage: TestSubagentConfig_ToRunOptions gained three subtests — subagent-overrides-parent, inherit-from-parent-when-subagent-empty, both-empty.

Must-Fix #2 — dangerous/client.go cmd.Dir. The claim "exec.CommandContext without setting cmd.Dir" doesn't match head. pkg/claude/dangerous/client.go lines 198-202:

```go
cmd := execCommand(ctx, c.ClaudeClient.BinPath, args...)
if opts != nil && opts.WorkingDirectory != "" {
cmd.Dir = opts.WorkingDirectory
}
```

Added a package-level var execCommand = exec.CommandContext seam (line 14) mirroring pkg/claude's pattern so the behavior is mock-testable. New test: TestBYPASS_ALL_PERMISSIONS_CTX_WorkingDirectory in client_test.go, plus a local TestHelperProcess for the seam.

Should-Fix #3TestRunFromStdin_WorkingDirectory. Added in claude_test.go — mirrors the RunPrompt/StreamPrompt pattern.

Should-Fix #4 — empty-WD regression test. Added TestWorkingDirectory_EmptyInheritsParentCwd with three subtests covering RunPrompt / RunFromStdin / StreamPrompt, asserting the child inherits the parent cwd when WorkingDirectory == "".

Minor — godoc. RunOptions.WorkingDirectory now has the expanded comment the review suggested, plus "per-call (no shared state)" since concurrent calls were the reviewer's own What's-Done-Well bullet.

Verification on head: just release check passes; go test -race -run WorkingDirectory -v ./pkg/claude/... passes all nine WD tests (including the new subtests).

If the review was intended to raise something new beyond the 07:27 list, happy to look — but I can't match any of the items here against the current code. Could be worth re-running against 6c252ca specifically.

Copy link
Copy Markdown
Collaborator

@obey-agent obey-agent left a comment

Choose a reason for hiding this comment

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

Re-Review After Commit 6c252ca — Approve

Verdict: Approve

Correction: My prior CHANGES_REQUESTED review at 08:00 was stale at post time — I ran the verification against the pre-fix tree, then posted without re-pulling. Commit 6c252ca (07:47) had already landed all four fixes before I posted. That's on me; I've updated my review process memory so it doesn't repeat.

Verification This Pass (against commit 6c252ca)

Cloned the current tip, ran full suite:

  • go build ./... — clean
  • go vet ./... — clean
  • go test ./... — pass (28.5s for pkg/claude, 33.7s for test/integration)
  • Targeted test run on every new test, all pass:
PASS: TestWorkingDirectory_EmptyInheritsParentCwd
  PASS: /RunPrompt
  PASS: /RunFromStdin
  PASS: /StreamPrompt
PASS: TestSubagentConfig_ToRunOptions
  PASS: /basic_conversion
  PASS: /inherits_from_parent
  PASS: /subagent_overrides_parent
  PASS: /subagent_WorkingDirectory_overrides_parent
  PASS: /WorkingDirectory_inherits_from_parent_when_subagent_empty
  PASS: /WorkingDirectory_empty_when_neither_set
PASS: TestBYPASS_ALL_PERMISSIONS_CTX_WorkingDirectory
PASS: TestRunFromStdin_WorkingDirectory

Findings Closed

Original finding Resolution Verified
#1 Subagent ToRunOptions drops WD Stale TODO removed; proper sc.WorkingDirectory / parentOpts.WorkingDirectory inheritance wired in at subagent.go:79-84 ✓ traced + test coverage
#2 dangerous/client.go:196 missing cmd.Dir if opts != nil && opts.WorkingDirectory != "" { cmd.Dir = opts.WorkingDirectory } added at dangerous/client.go:200-202 ✓ traced + new test TestBYPASS_ALL_PERMISSIONS_CTX_WorkingDirectory
#3 No TestRunFromStdin_WorkingDirectory Test added at claude_test.go:169 ✓ passes
#4 No empty-WD regression test TestWorkingDirectory_EmptyInheritsParentCwd added covering all three entry points (RunPrompt / RunFromStdin / StreamPrompt) as subtests ✓ passes, strictly stronger than what I asked for — one test covers all three paths

What Was Done Better Than Asked

The subagent test went further than my recommendation: 6 subtests including WorkingDirectory_empty_when_neither_set (the "both empty" case I asked for) and WorkingDirectory_inherits_from_parent_when_subagent_empty (the inheritance case). Table-driven subtest structure makes the next person's failure-to-diagnose-which-case-broke lookup easy.

The empty-WD regression test uses subtests to cover all three entry points in a single parent test — more compact than three separate tests and makes the invariant clearer ("empty WD inherits parent cwd across ALL entry points").

Staff Standard

Yes. All four findings closed with correct fixes plus tests that actually exercise the right code paths. Ready for v1.0.3 tag.

Sorry for the stale-review churn on the review thread.

@lancekrogers lancekrogers merged commit 310bc57 into main Apr 17, 2026
1 check passed
@lancekrogers lancekrogers deleted the feat/run-options-working-directory branch April 17, 2026 10:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants