# Coding Agent Profiles For developers who want more than one way to launch the same coding agent: a cheap variant, a max-effort variant, an isolated-config variant, switchable per agent and per session. After this page you can define a `claude` "max effort" variant and a "cheap" variant, set one agent to default to one of them, and switch a single session to the other without editing any command by hand. > **Upgrading from a pre-#597 config?** See [the breaking change](#the-effective-launch-command) before you launch: a profile cell now holds parameters, not a full command. ## What a profile is A **profile** is a lettered launch variant (`A`, `B`, `C`, ...) of a coding agent. Each profile holds extra command parameters plus environment variables. You assign a profile to an agent or to a single session; at launch AC composes the agent's base command with the profile's parameters and starts the session with the result. The whole feature is the **profile matrix**: a grid of these variants, one row per coding agent, one column per letter. ## Three things called "profile" The word "profile" appears in three unrelated places in AgentsCommander. This page owns the third one. Keep them separate: | Term | What it means | Where it lives | |---|---|---| | **Path placeholder** | A `%AC_REPLICA_ROOT%`-style token you can use *inside* a profile cell's command or env. Not a kind of profile. | [Agent Matrix conventions §5](../agent-matrix-conventions.md#5-profile-path-placeholders) | | **Tuned coding-agent integration** | A first-class `CodingAgentKind` (resume tokens, idle tuning) for one CLI. Independent of A/B/C. | [Coding agents](../integrations/coding-agents.md), `session/profile.rs::CodingAgentKind` | | **Profile (this page)** | A lettered launch variant of a coding agent, resolved from the profile matrix. | This page | When this page says "profile" with no qualifier, it always means the third one. ## The profile matrix The matrix is a grid. Each **row** is a coding agent (`claude`, `codex`, `antigravity`, `pi`, or a custom one). Each **column** is a profile letter. Each **cell** is one launch variant for that coding agent and letter: | | A | B | C | |---|---|---|---| | **claude** | (params, env) | (params, env) | (params, env) | | **codex** | (params, env) | (params, env) | (params, env) | | **antigravity** | (params, env) | (params, env) | (params, env) | | **pi** | (params, env) | (params, env) | (params, env) | A `pi` row can add parameters and environment variables to an exact Pi launch. Naming a custom wrapper row `my-pi` does not grant Pi's tuned detection or resume behavior; see [How AC identifies a tuned integration](../integrations/coding-agents.md#how-ac-identifies-a-tuned-integration). A cell holds four fields: | Field | Meaning | |---|---| | `enabled` | Whether this cell participates in resolution. A disabled cell is skipped (except `A`, which is always available). | | `command` | The extra parameters appended to the agent's base command. Params only, not the binary. See [The effective launch command](#the-effective-launch-command). | | `env` | Environment variables for this variant. Overlaid on the agent's base env, profile wins on a key clash. | | `notes` | Free text for your own reference. | The matrix is keyed by **coding-agent id** (the row). Which *letter* a given agent or session uses is a separate assignment, resolved by the ranking below. > **Out of the box only `A` exists.** You add `B`, `C`, and so on in **Settings -> Coding Agents**. Letters are single characters `A` through `Z`. The `A`/`B`/`C` examples on this page are illustrative, not a fixed set. ## Quick walkthrough This runs the scenario from the top of the page end to end. It assumes a `claude` Coding Agent is already configured. 1. Open **Settings -> Coding Agents** and find the `claude` row. 2. Add profile **B** and set its params to `--effort max` (your "max effort" variant). 3. Add profile **C** and set its params to a cheaper variant, for example `--model `. 4. Open the launch picker for that agent, pick profile **B**, and choose **Assign to this replica**. New sessions for that replica now start on B. 5. Launch a session for that agent. It runs `claude --effort max`. 6. To switch only that session to C, open the launch picker, pick profile **C**, and launch it without assigning to the replica. That choice applies to this launch only (tier 2), so the replica keeps B. You never edited a command by hand. ## How a profile is chosen Resolution runs in two distinct steps. ### Step 1: pick the requested letter (5-tier ranking) AC picks the requested letter from the first source that has one, highest priority first: | Tier | Source | Set by | |---|---|---| | 0. Dispatch request | `send --profile ` on the current wake | The sender, for this wake only; never written to the replica | | 1. Instance override | The replica's `tooling.profile` in its own `config.json` | Assigned to the replica; persists across future launches | | 2. Explicit request | The letter you pick for this one launch | The launch picker, for this launch only | | 3. Origin default | The agent matrix's `tooling.defaultProfile` | Hand-edited in the matrix `config.json`, or inherited (no UI control) | | 4. Agent default | `codingAgentProfiles.defaultProfileByAgent[]` in `agents.30.instance.no-git.json` | Rarely set by hand; see note below | | Floor | `A` | Always available when nothing else resolves | Tier 1 outranks tier 2 on purpose: a profile you deliberately assigned to a replica should survive future launches, so it beats an ephemeral letter picked for a single launch. The one exception is the dispatch-time request (tier 0): a `send --profile` letter is the orchestrator's explicit per-wake choice and outranks the replica pin for that spawn only — it is never written back, so the pin survives for every other launch. > **No per-agent "default" button.** Neither the origin default (tier 3, the per-agent-matrix `tooling.defaultProfile`) nor tier 4 (`defaultProfileByAgent` in `agents.30.instance.no-git.json`) has a UI control. Tier 3 is set only by hand-editing the matrix `config.json` or by inheritance; tier 4 only by an inherited config or by hand-editing `agents.30.instance.no-git.json`. The closest thing to a default in the UI is an instance override (tier 1), assigned through the launch picker as described below. ### Step 2: walk down to the nearest enabled cell Once Step 1 picks a letter, AC looks up the cell for that coding agent and letter. If the cell is missing or disabled, AC walks **down** the alphabet toward `A` and uses the first enabled cell it finds (`D` -> `C` -> `B` -> `A`). `A` is always materialized, as an empty cell if you never defined one, so resolution always terminates. When the cell that wins is not the letter that was requested, AC marks the result `fallbackApplied`. That is the signal behind "I asked for D but it launched with C." **Worked example.** You request `D` for `codex`, but only `codex` cells `A` and `C` are enabled: 1. Step 1 picks `D` (say, from an explicit request). 2. Step 2 walks `D` -> `C`. `C` is enabled, so the effective profile is `C`. 3. The session launches with `codex`'s `C` params, and `fallbackApplied` is true. ## Assigning and defaulting a profile **Make a profile the one new sessions start on (tier 1 — the practical default).** In the launch picker, pick the Coding Agent and Profile, then choose **Assign to this replica**. This writes the replica's `tooling.profile` (the instance override), which beats the lower default tiers, so new sessions on that replica start on that letter until you change it. The picker previews the exact composed command before you launch. From a room replica, the picker's **Apply to** control widens the same write to more replicas: **This replica**, **All replicas of this kind**, or **Entire room** (each target replica gets its own instance override). **Pick a profile for a single launch (tier 2).** Choosing a different letter at launch time, without assigning it to the replica, applies only to that launch. **The per-agent origin default (tier 3) has no UI control.** To set the agent matrix's `tooling.defaultProfile`, hand-edit that matrix's `config.json` (or let it be inherited). Any instance override you assign (tier 1) outranks it. ## The effective launch command The command that actually starts is the agent's base command followed by the profile cell's parameters, joined with a single space: ``` effective = " " ``` The base command (the binary, plus any fixed args) comes from the Coding Agent entry in `agents.30.instance.no-git.json`. The cell holds only the extra params. An empty side contributes nothing, and if both are empty the launch fails with `agent command is empty`. **Example.** Base command `claude-amp`, profile `B` params `--effort max --model `: ``` claude-amp --effort max --model ``` Environment variables merge in layers: the agent's base env first, then the profile cell's env on top (profile wins on a clashing key), then any AC-generated env (such as an isolated `CODEX_HOME`). Path placeholders like `%AC_REPLICA_ROOT%` are allowed in either the base command or the cell and expand at launch; see [Agent Matrix conventions §5](../agent-matrix-conventions.md#5-profile-path-placeholders). > **Breaking change: a profile cell holds parameters, not a full command.** AC composes the cell after the base command. If a cell still contains the whole command (for example `claude --foo` on a `claude` base), it composes to `claude claude --foo`, which launches wrong or fails. There is **no automatic migration**. Move the binary into the Coding Agent command and keep only parameters in each cell. Re-check every existing profile cell after upgrading. ## Drift: the "outdated" badge A profile's identity is positional (coding-agent id plus letter), so editing a cell's command or env does not, by itself, change which cell a running session is on. To catch the case where a running session's profile no longer matches its configuration, AC fingerprints the effective command and merged env at launch and compares it on demand. When the configuration drifts from what a session launched with, that session shows a clickable badge in the sidebar: - **Badge:** `⟳ outdated` - **Tooltip:** "Loaded profile no longer matches its configuration. Reload to relaunch with the current profile." - **Click it** to relaunch the session with the current configuration. The relaunch clears the badge. Drift is **manual**: AC never auto-reloads. The check covers an edit to the base command, the cell params, the base env, or the cell env. It survives an AC restart (the fingerprint is persisted per replica). Plain-shell sessions (sessions with no coding agent) never drift. In a directory that is not an agent replica the fingerprint is not persisted, so any drift is not retained across an AC restart. ## Where profiles are stored Profiles live in two places: the global `agents.30.instance.no-git.json` (the matrix and defaults) and per-agent `config.json` files (the per-agent and per-replica assignments). | Datum | Location | Key | |---|---|---| | Matrix cells (params, env, notes) | `agents.30.instance.no-git.json` | `codingAgentProfiles.profilesByAgent[][]` | | Profile letters and labels | `agents.30.instance.no-git.json` | `codingAgentProfiles.profileSlots`, `codingAgentProfiles.profileLabelsByAgent` | | Agent default letter (tier 4) | `agents.30.instance.no-git.json` | `codingAgentProfiles.defaultProfileByAgent[]` | | Origin default (tier 3) | agent matrix `_agent_/config.json` | `tooling.defaultProfile` | | Instance override (tier 1) | replica `__agent_/config.json` | `tooling.profile` (legacy `tooling.instanceProfileOverride`) | | Drift fingerprint | replica/matrix `config.json` | `tooling.profileContentHash` | The full `codingAgentProfiles` schema (including `schemaVersion`) is in the [settings reference](../reference/settings.md#coding-agent-profiles). The matrix uses schema version 2; older pre-v2 profile fields are no longer read: they are ignored. Before any save drops them, AC keeps the original once as `settings.30.instance.no-git.pre-384-v1.json` and writes settings without them; the `open-project` and `new-project` CLI commands keep them and write no backup. **Dispatch a profile per wake.** `send --mode wake --profile ` applies the letter to the coding agent the wake spawns or respawns (see [cli.md](../reference/cli.md) `send`). The letter is a dispatch-time request: it wins over a pinned replica profile for that spawn, is never written to `tooling.profile`/`currentCodingAgent`/`lastCodingAgent`, and the receipt reports the effective letter and any cell fallback (`fallbackApplied`). There is still no `profile` subcommand; everything else about profiles is configured in Settings or by editing `agents.30.instance.no-git.json` and the per-agent `config.json` files. ## Troubleshooting **"My session launched with A even though I asked for D."** Letter fallback (Step 2). There is no enabled `D`, `C`, or `B` cell for that coding agent, so resolution walked down to `A`. Enable the cell you want, or define its params. **"Ignoring invalid profile letter '...'."** A profile letter must be a single character `A` through `Z`. AC logs this and ignores the bad value rather than failing the launch. **"I edited a profile and the running session did not change."** Drift is manual. Click the `⟳ outdated` badge on the session (or restart it) to relaunch with the new configuration. **"After upgrading, my agent launches the binary twice, or fails with `agent command is empty`."** The profile cell still holds a full command. Move the binary into the Coding Agent command and keep only parameters in the cell. See [the breaking-change note](#the-effective-launch-command). ## See also - [Settings reference](../reference/settings.md#coding-agent-profiles) - the full `codingAgentProfiles` schema - [Coding agents](../integrations/coding-agents.md) - the coding-agent catalog and tuned `CodingAgentKind` integrations - [Agent Matrix conventions §5](../agent-matrix-conventions.md#5-profile-path-placeholders) - path placeholders usable inside a profile cell - [Glossary](../glossary.md) - profile, profile matrix, profile cell