Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 11 additions & 2 deletions src/agent_harness/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -888,6 +888,7 @@ def main(argv: list[str] | None = None) -> int:
# starts for `--help` on a machine with no queue and no credentials, and
# only the default value is needed to print it.
from .executor import DEFAULT_CONTEXT_BUDGET
from .session_executor import DEFAULT_AGENT_COMMAND

parser = argparse.ArgumentParser(prog="agent-harness", description=__doc__)
parser.add_argument(
Expand Down Expand Up @@ -1123,9 +1124,17 @@ def main(argv: list[str] | None = None) -> int:
)
p_run.add_argument(
"--agent",
default="claude -p {prompt_file}",
# The executor's default, not a second one. They disagreed: the
# executor's carried `--permission-mode acceptEdits` and the CLI's did
# not, so `run --session-host` without this flag produced an agent that
# could not write. It reported no changes and read as a model that had
# considered the task and declined — measured, and it cost a run.
default=" ".join(DEFAULT_AGENT_COMMAND),
metavar="CMD",
help="CLI agent to run per item. `{prompt_file}` is substituted.",
help="CLI agent to run per item. `{prompt_file}` is substituted. "
"Defaults to the agent command the session executor declares, which "
"grants edit permission — an agent that cannot write reports no "
"changes, which is indistinguishable from one that chose to make none.",
)
p_run.add_argument("--limit", type=int, help="stop after N items")
p_run.add_argument(
Expand Down
30 changes: 30 additions & 0 deletions tests/test_cli_roles.py
Original file line number Diff line number Diff line change
Expand Up @@ -287,3 +287,33 @@ def capture(self: Any, method: str, url: str, **kwargs: Any) -> Any:
assert "timeout" not in sent["json"] and "role" not in sent["json"]
assert sent["headers"]["x-api-key"] == "shared-key"
assert "Authorization" not in sent["headers"]


def test_the_cli_agent_default_is_the_executor_s() -> None:
"""They disagreed, and the CLI's was the one that could not write.

`session_executor.DEFAULT_AGENT_COMMAND` carries `--permission-mode
acceptEdits`; the CLI's `--agent` default did not. So `run --session-host`
without the flag produced an agent that was refused every Edit, reported
no changes, and read as a model that had considered the task and declined.

Measured: it cost a full agent run, and the agent's own account of the
refusal sat in a scrollback nothing reads.

Asserted against the source rather than a parsed value, because the defect
was *a second default existing at all* — a literal here that happens to
match today would drift again tomorrow.
"""
import inspect

from agent_harness import __main__
from agent_harness.session_executor import DEFAULT_AGENT_COMMAND

source = inspect.getsource(__main__)
assert 'default=" ".join(DEFAULT_AGENT_COMMAND)' in source, (
"the CLI must take the executor's agent command, not declare its own"
)
assert '"--permission-mode"' in inspect.getsource(
__import__("agent_harness.session_executor", fromlist=["x"])
), "and that command must still grant edit permission"
assert "--permission-mode" in " ".join(DEFAULT_AGENT_COMMAND)
Loading