Problem
There is no supported way to pass harness-specific runtime flags to a spawned builder. --harness selects the agent and --model pins the model, but anything else the harness's CLI exposes is unreachable from both the CLI and .codev/config.json.
The concrete case: opencode has a --auto flag ("auto-approve permissions that are not explicitly denied"). A builder spawned with --harness opencode prompts for permission on every ordinary command — porch, git, print, ls — which makes strict-mode protocol runs impractical to babysit. There is no way to express "spawn this builder with --auto".
Why the existing escape hatches don't cover it
--builder-cmd is the wrong tool and fails silently. It bakes a literal command string into .builder-start.sh, and afx still appends its Claude-shaped --prompt "$(cat ...)". For a harness whose CLI takes the prompt positionally, the prompt is lost. With opencode run [message..] (no --prompt flag) the result is:
- opencode receives an empty message and exits instantly
- the loop in
.builder-start.sh relaunches it forever
afx tower log shows socket missing or lstat error
- nothing fails at spawn time —
afx status happily lists the builder, so it looks like it worked
This cost real time to diagnose. --model's own help text already articulates the principle being violated here:
Resolved into the harness's own flag rather than baked into a command path.
That is exactly right, and it is why --builder-cmd should not be the answer for runtime flags either.
Custom harness config doesn't cover it. validateCustomHarnessConfig requires roleArgs and roleScriptFragment, both of which are role-injection concerns (roleArgs is passed through expandTemplateVars(arg, content, filePath)). There is no field for "extra args to append at launch", and defining a whole custom harness just to add one flag to a built-in one means duplicating the built-in's prompt/model/worktree-file behaviour.
Per-harness config files are a partial workaround only. opencode reads a permission block from the worktree's opencode.json, which getWorktreeFiles already generates for role injection:
{
"$schema": "https://opencode.ai/config.json",
"instructions": [".builder-role.md"],
"permission": {
"bash": { "*": "allow", "kubectl delete*": "ask" },
"edit": "allow"
}
}
This works, but afx regenerates opencode.json on every spawn, so the block is lost on respawn and has to be reapplied by hand. It also only helps harnesses that happen to have file-based config.
Request
Add a way to declare harness runtime flags in .codev/config.json, applied at launch and surviving respawn. Rough shape:
{
"shell": { "builder": "claude" },
"harness": {
"opencode": {
"builderArgs": ["--auto"]
}
}
}
with an optional per-spawn override:
afx spawn 484 --protocol spir --harness opencode --model x-ai/grok-4.6 --harness-arg --auto
Design notes:
- Should extend a built-in harness, not require redefining one. Today
harness.<name> is only reachable as a full custom definition.
- Should compose with
--model and --prompt rather than replacing the generated command, so the buildScriptPromptArg / buildModelArgs logic still applies.
- Consider merging into
getWorktreeFiles output for file-configured harnesses (opencode's permission block) rather than only argv, since some settings have no flag equivalent.
Secondary: fail loudly on a broken builder command
Independent of the above, the silent-death mode is worth fixing on its own. When a builder's process exits immediately and repeatedly, afx status should not report it as a healthy implementing builder. A restart-loop detector in session-manager.ts (e.g. N exits under M seconds → mark the builder failed and surface the harness's stderr) would have turned a multi-step investigation into a one-line error.
This matches the project's own "silent success is the default failure mode" lesson: the exit status said fine while nothing was running.
Environment
- afx from
pseudoseed/codev (local checkout ~/dev/codev-1455)
- opencode v1.18.18, model
x-ai/grok-4.6
- Relevant source:
packages/codev/src/agent-farm/utils/harness.ts (validateCustomHarnessConfig, buildScriptPromptArg, buildModelArgs, getWorktreeFiles), packages/codev/src/agent-farm/cli.ts:317-318
Problem
There is no supported way to pass harness-specific runtime flags to a spawned builder.
--harnessselects the agent and--modelpins the model, but anything else the harness's CLI exposes is unreachable from both the CLI and.codev/config.json.The concrete case: opencode has a
--autoflag ("auto-approve permissions that are not explicitly denied"). A builder spawned with--harness opencodeprompts for permission on every ordinary command —porch,git,print,ls— which makes strict-mode protocol runs impractical to babysit. There is no way to express "spawn this builder with--auto".Why the existing escape hatches don't cover it
--builder-cmdis the wrong tool and fails silently. It bakes a literal command string into.builder-start.sh, and afx still appends its Claude-shaped--prompt "$(cat ...)". For a harness whose CLI takes the prompt positionally, the prompt is lost. Withopencode run [message..](no--promptflag) the result is:.builder-start.shrelaunches it foreverafx tower logshowssocket missing or lstat errorafx statushappily lists the builder, so it looks like it workedThis cost real time to diagnose.
--model's own help text already articulates the principle being violated here:That is exactly right, and it is why
--builder-cmdshould not be the answer for runtime flags either.Custom harness config doesn't cover it.
validateCustomHarnessConfigrequiresroleArgsandroleScriptFragment, both of which are role-injection concerns (roleArgsis passed throughexpandTemplateVars(arg, content, filePath)). There is no field for "extra args to append at launch", and defining a whole custom harness just to add one flag to a built-in one means duplicating the built-in's prompt/model/worktree-file behaviour.Per-harness config files are a partial workaround only. opencode reads a
permissionblock from the worktree'sopencode.json, whichgetWorktreeFilesalready generates for role injection:{ "$schema": "https://opencode.ai/config.json", "instructions": [".builder-role.md"], "permission": { "bash": { "*": "allow", "kubectl delete*": "ask" }, "edit": "allow" } }This works, but afx regenerates
opencode.jsonon every spawn, so the block is lost on respawn and has to be reapplied by hand. It also only helps harnesses that happen to have file-based config.Request
Add a way to declare harness runtime flags in
.codev/config.json, applied at launch and surviving respawn. Rough shape:{ "shell": { "builder": "claude" }, "harness": { "opencode": { "builderArgs": ["--auto"] } } }with an optional per-spawn override:
Design notes:
harness.<name>is only reachable as a full custom definition.--modeland--promptrather than replacing the generated command, so thebuildScriptPromptArg/buildModelArgslogic still applies.getWorktreeFilesoutput for file-configured harnesses (opencode'spermissionblock) rather than only argv, since some settings have no flag equivalent.Secondary: fail loudly on a broken builder command
Independent of the above, the silent-death mode is worth fixing on its own. When a builder's process exits immediately and repeatedly,
afx statusshould not report it as a healthyimplementingbuilder. A restart-loop detector insession-manager.ts(e.g. N exits under M seconds → mark the builder failed and surface the harness's stderr) would have turned a multi-step investigation into a one-line error.This matches the project's own "silent success is the default failure mode" lesson: the exit status said fine while nothing was running.
Environment
pseudoseed/codev(local checkout~/dev/codev-1455)x-ai/grok-4.6packages/codev/src/agent-farm/utils/harness.ts(validateCustomHarnessConfig,buildScriptPromptArg,buildModelArgs,getWorktreeFiles),packages/codev/src/agent-farm/cli.ts:317-318