Skip to content

afx: no way to pass harness runtime flags (e.g. opencode --auto) via .codev/config.json; --builder-cmd fails silently #36

Description

@pseudoseed

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 timeafx 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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions