Skip to content

Give workers a full per-role environment profile (MCP, plugins, system prompt, …), not just agent/model/permissions #2195

Description

@axisrow

Problem

Today the per-role worker / orchestrator overrides in a project's config cover only three things — agent, model, and permissions (RoleOverride{ Harness, AgentConfig{ Model, Permissions } } in domain/projectconfig.go). Everything else about a worker's environment is inherited globally and can't be scoped per role:

  • MCP servers — claude-code reads them from the shared ~/.claude / .mcp.json; AO passes no per-session --mcp-config, so every worker gets the orchestrator's full MCP set.
  • Plugins / skills — loaded globally from ~/.claude/, never scoped per role.
  • System prompt — generated by AO from the session role; there's no per-role user-configurable base prompt.

(Side note: even the existing per-role model / permissions are wired in the Go domain and the API schema but only agent is exposed per-role in the settings UI — so the per-role surface is under-exposed today too.)

Guiding principle: least privilege

A worker should run naked by default — no MCP servers, no plugins — unless the user explicitly opts it in. A worker is given work to do; it should not inherit the orchestrator's keys to the safe. Carrying the orchestrator's whole toolset is slower, noisier, and grants more power than a code-change task needs.

This is the default, not an opt-in toggle. The user opts in to specific tools per worker role; absence of config means isolation, not inheritance. (Inheritance stays available as an explicit choice — e.g. an orchestrator role, or a worker the user deliberately trusts with the global set.)

This supersedes the earlier "defaulting to inherit so nothing breaks" wording — that framing is what led the first implementation astray (it shipped inherit-by-default, defeating the whole point). Least privilege is the principle; anything that ships inherit-by-default is a bug against this issue.

Ask

Widen the per-role override from "agent/model/permissions" into a proper worker environment profile, with least-privilege defaults. Candidates, in rough priority:

  1. MCP servers — workers default to none (isolated), opt in explicitly (code-graph, browser) when a task needs tools. This was the original scope of this issue. Isolation mechanism: claude-code's --strict-mcp-config with no --mcp-config loads zero MCP servers (verified against claude --help), so MCPConfig{Strict: true, Configs: []} is the worker default; an explicit --worker-mcp-config opts back in.
  2. Plugins / skills — workers default to none. Mechanism: claude-code has no single "plugins off" flag, but --settings '{"enabledPlugins": {...all false...}}' disables them per-session without --bare/--safe-mode (which would also kill AO's activity-detection hooks) — verified: claude --settings '{"enabledPlugins": {"context7@claude-plugins-official": false}}' plugin listStatus: ✘ disabled. AO would emit this from the worker's global plugin set, inverted.
  3. System prompt — a per-role base prompt for workers (replace, not concatenate).
  4. Env — already worker-forwardable via project.env; keep, and make sure per-role overrides don't leak into the stored project config (deep-copy).

Why

The per-role mechanism already exists and is proven for agent/model/permissions; this widens the same RoleOverride to the rest of the environment — but with least-privilege defaults, so a worker with no explicit config is isolated, not endowed.

Open question (rollout)

Flipping worker MCP/plugins from inherit (today) to naked-by-default is a behavior change for existing projects — a worker that quietly used a global MCP tool or plugin would run half-blind until the user configures it. The direction is settled (naked); the rollout shape is tracked in #2844 (naked for everyone + migration note / naked for new projects only / opt-in now). Implementation of this issue lands once that's decided, so it's built the right way once.

Scope

  • claude-code first (it has the isolation primitives above); other adapters inherit as today and gain isolation as follow-ups.
  • UI (per-role settings form) deferred to a follow-up; the config + flags land first.

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