proposal_run — AgentTeamsModule¶
The command-request half of proposals: it validates, runs and checks one allowlisted command an
agent asked for. Carved out of proposals at phase R2 (CH-07).
Source:
agentteams/proposal_run.py. The public entry point isproposals.run_request, which delegates here. Every shared helper and constant is reached throughproposalsat call time, so patchingproposals.COMMAND_TIMEOUTand the like still takes effect. Served by the runner'srun-requestkind (proposal_runner).
Public surface¶
| Name | Purpose |
|---|---|
run_request(artifact, *, root, policy, dry_run=False, confine=False, timeout_cap=None, expect_agent=None, refuse_agents=frozenset()) -> dict |
Run one command-request artifact. Returns {agent, argv, exit, duration_ms, stdout, stderr, truncated, undeclared_writes, ran}. With dry_run, every check runs but the command does not (ran: False). |
What a request must pass, in order¶
- Shape and identity. The artifact is a
command-request, and its agent identity checks out (expect_agent,refuse_agents). - Arguments.
argvis a non-empty list of strings, never a shell string, andpurposeis non-empty. - Allowlist.
argvmatches an entry on the agent's command allowlist.cwdmust equal the entry's pinned cwd. - Declared writes. Each
expected_writespath is inside the project. It matches the entry'swritesglobs or passes the ordinary scoped-write check, and it is never in the control plane or the brief that defines the policy. - Confinement (
confine=True). The agent needs aconfined_programsentry, the program must sit inside its exec paths, and its write roots may not cover a protected path or the brief. The runner runs nothing unconfined. It warns on stderr, once per run, when a write root covers a package store, or (macOS) when the program orlakedepends on an xcrun launcher that could not be resolved. When both hold it refuses before anything runs, unless the agent'sconfined_programsentry setsallow_unresolved_launcher_with_package_store: true. - Stdin content.
stdin_from_contentmust be exactly{path, content}, and the entry must registerstdin_gates. The content goes through those gates before it reaches the command.
Running and checking¶
- The project must be a git worktree; otherwise the run refuses (fail-closed). A write-ahead
run-request-startrow is recorded, then the worktree is snapshotted, so only the command's own changes count. - The command runs in its own process group with a scrubbed environment and
shell=False. The timeout is the entry'stimeout(defaultCOMMAND_TIMEOUT), capped atMAX_COMMAND_TIMEOUTand attimeout_capwhen given. On a timeout the whole group is killed and the writes are still checked. - Under confinement, anything the command left running is killed and the run fails. Changes inside the declared write roots count as declared only when a sandbox actually ran.
- Undeclared writes raise
UndeclaredWritesErrorwith the full result attached. A command that changed the ledger, head or dispatch files raisesLedgerTamperedError, and nothing more is recorded. - Other refusals raise
ProposalErrorand are recorded as a refusal row (not underdry_run). Output is capped, withtruncatedset when it was cut.