> ## Documentation Index
> Fetch the complete documentation index at: https://docs.ironrun.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# propose_command — Let Agents Suggest New Policy Commands

> The propose_command MCP tool stages a new command for human review. Nothing runs until a human approves it with ironrun approve in their terminal.

When an agent needs to run a command that isn't in the policy file, it has two bad options: give up, or fall back to a raw shell. `propose_command` offers a third path — stage the command for human review instead. The agent describes what it wants to run and why, the human inspects the proposal and decides, and the command becomes available via `run_sealed` only after approval. Nothing is executed at proposal time.

## Enabling proposals

`propose_command` only works when the policy explicitly opts in. Add `allow_proposals: true` to your `ironrun.yml`:

```yaml theme={null}
version: "2"
environment_set: active
require_agent_leases: true
allow_proposals: true

commands:
  - id: test
    argv: [go, test, ./...]
    ttl: 2m
    secrets: [DATABASE_URL]
```

If `allow_proposals` is false (the default), calling `propose_command` returns an error telling the agent to ask you to enable it.

## Parameters

<ParamField body="id" type="string" required>
  A short kebab-case identifier for the command, for example `db-shell` or `seed-data`. Must contain only letters, digits, hyphens, and underscores. Must not already exist in the policy.
</ParamField>

<ParamField body="argv" type="array of strings" required>
  The exact binary and arguments to run, for example `["psql", "-c", "select 1"]`. This must be a direct binary invocation — shells (`sh`, `bash`, `zsh`) are explicitly rejected. If the command requires a shell, wrap it in a script file and propose the script.
</ParamField>

<ParamField body="reason" type="string" required>
  An explanation of why this command is needed. This is shown to the human when they review the proposal. Be specific — the human needs enough context to make an informed decision about whether to approve.
</ParamField>

## What happens after the call

The proposal is saved to `.ironrun/pending.yml` in your project root, next to the policy file. The agent receives a confirmation message like:

```
Proposed "db-shell". It is NOT yet runnable. A human must run
`ironrun approve db-shell` in their terminal; you can run_sealed
with "db-shell" only after they approve.
```

If the agent then calls `run_sealed` with the proposed `command_id`, ironrun detects the pending proposal and blocks — waiting for human approval exactly like a lease request. The agent does not need to poll; it just waits.

## Human review and approval

```bash theme={null}
ironrun review              # list all pending proposals with argv and reason
ironrun approve <id>        # add to ironrun.yml and mark approved
ironrun reject <id>         # deny the proposal; the agent's run_sealed unblocks with an error
```

Once you run `ironrun approve db-shell`, the command is added to `ironrun.yml` and is immediately available for `run_sealed`.

<Steps>
  <Step title="Agent proposes a command">
    ```
    propose_command({
      "id": "db-shell",
      "argv": ["psql", "-U", "app", "-d", "mydb"],
      "reason": "Need to inspect table schema to debug the migration failure"
    })
    ```
  </Step>

  <Step title="You review the proposal">
    ```bash theme={null}
    ironrun review
    # 1 command(s) awaiting your approval (.ironrun/pending.yml)
    #
    #   db-shell
    #       argv:   psql -U app -d mydb
    #       env:    (none)
    #       reason: Need to inspect table schema to debug the migration failure
    #       !  reaches the network — review the target carefully
    #
    # Approve:  ironrun approve <id>      Reject:  ironrun reject <id>
    ```
  </Step>

  <Step title="You approve or reject">
    ```bash theme={null}
    ironrun approve db-shell   # adds to ironrun.yml
    # or
    ironrun reject db-shell    # denies; agent gets an error
    ```
  </Step>

  <Step title="Agent runs the approved command">
    ```
    run_sealed({ "command_id": "db-shell" })
    ```
  </Step>
</Steps>

<Warning>
  Always inspect the proposed `argv` before approving. An agent could propose a command that exfiltrates data — for example, one that curls an external URL with a secret embedded in a header. Review the exact binary and arguments, not just the reason text.
</Warning>

<Note>
  `propose_command` does **not** execute anything. It is a staging mechanism only. The command cannot run until you explicitly approve it with `ironrun approve`.
</Note>
