Skip to content

Pass safety/sandboxing flags to callClaudeViaCli from agent or task config #720

Description

@johannwest7012

Summary

Mission Control's built-in task dispatcher (src/lib/task-dispatch.ts) is great for the common case, but it doesn't currently passthrough four Claude Code CLI flags that are load-bearing for safety/sandboxing in production deployments. Without them, users like us end up writing custom dispatchers that wrap claude themselves, which means duplicating most of MC's queue/scheduler/SOUL machinery.

Proposing four small additions to callClaudeViaCli (~5 lines each, all independent) that would let MC's native dispatcher cover safety-critical workloads without forcing a custom dispatcher.

My use case (concrete)

Self-hosted MC running daily QA on a real production codebase. Two custom agents:

  • A QA worker that runs npm run lint && npm test && npm run test:smoke in a specific working directory, reports failures as child tasks.
  • A reviewer (Aegis-style) that reads worker reports and approves/rejects with {decision, notes} structured output.

I built the agents with mc_create_task, mc_update_task, etc. via the MCP server, registered them in MC's agent table, used MC's recurring-task templates (metadata.recurrence.cron_expr), use MC's Aegis 403-on-done quality gate, and inject SOULs via --append-system-prompt. Everything except the actual claude spawn flows through MC. The only reason I'm not using MC's native dispatcher is the four gaps below.

The four gaps

1. No --allowedTools whitelist passthrough

callClaudeViaCli (src/lib/task-dispatch.ts:691) spawns Claude with no tool restrictions. For an agent running unattended on a real repo, allowing the default toolset (Bash, Edit, Write, WebFetch, all MCP servers) is a non-starter — a misbehaving model could rm -rf or exfiltrate secrets.

Proposed: read allowedTools from agents.config (or tasks.metadata), pass through to --allowedTools.

2. No --max-budget-usd cap passthrough

Cost is tracked post-hoc but not capped during execution. One bad agentic loop is unbounded spend.

Proposed: read maxBudgetUsd from agent config, pass through to --max-budget-usd.

3. No cwd per task

The spawn call inherits MC's own working directory. Worker agents that need to run tests / build commands / linters in a specific project directory can't.

Proposed: read workspace from agent config or cwd from task metadata, pass to spawn({ cwd }).

4. No --json-schema passthrough (Aegis use case)

The Aegis reviewer in task-dispatch.ts:925-1095 parses the verdict from freeform text via regex on VERDICT: APPROVED and NOTES: .... For a quality gate, schema-validated structured output (via claude --json-schema) would be more robust.

Proposed: read outputSchema from agent config, pass through to --json-schema.

Sketch of the change

```typescript
// callClaudeViaCli, around src/lib/task-dispatch.ts:691
const agentConfig = getAgentConfig(task) // already exists in nearby code
const args = ['--print', '--output-format', 'json', '--model', model]
if (soul) args.push('--append-system-prompt', soul)

// New, all independent:
if (agentConfig?.allowedTools) args.push('--allowedTools', ...agentConfig.allowedTools)
if (agentConfig?.maxBudgetUsd) args.push('--max-budget-usd', String(agentConfig.maxBudgetUsd))
if (agentConfig?.outputSchema) args.push('--json-schema', JSON.stringify(agentConfig.outputSchema))

const proc = spawn('claude', args, {
stdio: ['pipe', 'pipe', 'pipe'],
cwd: agentConfig?.workspace || task.metadata?.cwd, // New
env: { ...process.env, CI: '1' },
})
```

All four are tiny, opt-in (if the config field is missing, behavior is unchanged), and could land in separate PRs.

Why these and not others?

These are the four flags I personally hit. There are obviously more (`--permission-mode`, `--max-turns`, `--disallowedTools`, etc.) that some workloads will want — happy to extend the proposal if useful, but starting with the smallest set that unblocks safety-critical use.

Happy to PR

If the maintainers are open to this, I can submit PRs (one per flag, or one combined). Just want to confirm the design (`agents.config` vs `tasks.metadata` as the source-of-truth for these settings) before writing code.


MC version: 2.0.1
Tested on: macOS arm64, Node 22

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    Status
    Backlog

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions