OFTR-006: Agent Adapters and Supported Harnesses
Synced from
outfitter/docs/requirements/OFTR-006-agent-adapters.md. The repository is the source of truth.
Transition (RFC #165): OFTR-006.1 is amended (2026-07-17) to the composition-projection model below (harnesses project a
CompositionPlan, reporting unsupported elements). Some pi/claude launch-control sections still describe profile-era behavior and richer parity is projected incrementally. The current composition implementation includes Claude’s isolated MCP config and Codex’s additive MCP CLI overrides alongside the existing identity, skills, model, thinking, Pi extensions, and per-agent Pi configuration overlays. Target design: docs/architecture/README.md.
Overview
Section titled “Overview”Agent adapters translate generic Outfitter profile controls into native configuration files, environment variables, and command-line arguments for specific agent CLIs. Pi is the default and primary supported adapter; Claude Code and Codex CLI are also supported through dedicated adapters.
Requirements
Section titled “Requirements”OFTR-006.1: Adapter Boundary
Section titled “OFTR-006.1: Adapter Boundary”Amended (2026-07-17, RFC #165): adapters project a harness-neutral composition, not a profile.
- Outfitter MUST project a harness-neutral
CompositionPlanto a native harness launch: a materialized runtime configuration root plus a launch plan (command, args, environment). - Each harness projection MUST be identified by its harness (
pi,claude, orcodex). - Each harness projection MUST report which composition loadout elements it cannot project (
getUnsupportedElements). - When a composition selects an element the harness cannot project, Outfitter MUST warn;
--strictMUST make it fatal before launch. - Composition (resolver + composer) MUST stay independent of harness-specific projection.
- Prompt templates MUST be projected only by harnesses that support a native prompt-template control; unsupported prompt-template use MUST be reported through
getUnsupportedElementsand MUST fail before launch under--strict.
OFTR-006.2: Supported Adapter Availability
Section titled “OFTR-006.2: Supported Adapter Availability”- Outfitter MUST support the
piagent CLI on day one. - Outfitter MAY document other agent CLIs as roadmap adapters before implementing them.
- Non-pi adapters MUST NOT be presented as supported until their adapter implementation and tests exist.
- When generic Outfitter terminology conflicts with pi terminology, the pi adapter SHOULD prefer pi naming for generated pi artifacts and user-facing pi diagnostics.
- Outfitter MUST keep
pias the default adapter when no adapter is selected explicitly or through settings. - Outfitter MUST support Claude Code through a
claudeadapter once implementation and tests are present. - Outfitter MUST support Codex CLI through a
codexadapter once implementation and tests are present.
OFTR-006.3: Pi Launch Controls
Section titled “OFTR-006.3: Pi Launch Controls”- The pi adapter MUST use
PI_CODING_AGENT_DIRas the primary profile-scoped pi configuration boundary. - The pi adapter MUST support profile-controlled environment variables.
- The pi adapter MUST support profile-controlled pi CLI arguments.
- The pi adapter SHOULD support
PI_CODING_AGENT_SESSION_DIRor--session-dirfor session location control. - The pi adapter SHOULD support
--extensionor-efor explicit extension injection. - The pi adapter SHOULD support
--skillfor explicit skill injection. - The pi adapter SHOULD support
--prompt-templatefor prompt template injection. - The pi adapter SHOULD support
--system-promptand--append-system-promptfor prompt control. - The pi adapter SHOULD support pi model, provider, and thinking controls where native pi flags exist.
- The pi adapter MUST merge
.mcp.jsonfiles from contributingcli_specific/pi/profile folders into the composite profile, adding unique array entries by identity while keeping the last entry for duplicate identities. - The pi adapter MUST make native Pi
models.jsonavailable inside the composite profile so custom providers and model definitions are visible before Pi resolves--providerand--modelflags. - The pi adapter MUST expose valid Agent Skills from contributing profile
skills/folders as--skillarguments, and MAY also expose Pi-specific skills fromcli_specific/pi/skills/. - The pi adapter MUST expose DeepWork jobs from contributing profile
deepwork/jobs/folders throughDEEPWORK_ADDITIONAL_JOBS_FOLDERS, and MAY also expose Pi-specific jobs fromcli_specific/pi/deepwork/jobs/. - The pi adapter MUST resolve
controls.deepwork.jobsentries as DeepWork job names from shared Outfitter job roots such as.outfitter/deepwork/jobs/<job-name>/job.ymland expose the matching jobs root throughDEEPWORK_ADDITIONAL_JOBS_FOLDERS. - The pi adapter MUST NOT treat flat profile source roots as profile-bundled job folders unless a named DeepWork job resolves to a shared jobs root.
- The pi adapter MUST ignore inherited external
DEEPWORK_ADDITIONAL_JOBS_FOLDERSvalues unlesscontrols.pi.allow_external_deepwork_jobsis true. - The pi adapter MUST overlay
agents/<agent>/pi/directories from contributing.agentslayers into the temporaryPI_CODING_AGENT_DIR, with higher-precedence layers replacing matching paths, without following symlinks or projecting the overlay into non-Pi harnesses. - The pi adapter MUST project composed prompt fragments in composition order by passing one
--system-prompt, ordered--append-system-promptarguments, and--prompt-templatewhen the composition declares a prompt template. - The pi adapter MUST default
PI_CODING_AGENT_SESSION_DIRto pi’s durable per-project session directory under pi’s user agent directory, so sessions survive removal of the temporaryPI_CODING_AGENT_DIR; it MUST leave an inheritedPI_CODING_AGENT_SESSION_DIRin place, and MUST NOT override a pass-through--session-diror--no-session.
OFTR-006.4: Pi Startup Boundary
Section titled “OFTR-006.4: Pi Startup Boundary”- Outfitter MUST NOT rely on pi extensions to choose the initial pi configuration directory.
- Outfitter MUST choose pi configuration paths before launching pi.
- Outfitter MAY use explicit bootstrap extensions for behavior that can run after pi has discovered its initial configuration directory.
- Post-start bootstrap extensions MUST clearly communicate when a selected profile or loadout applies only to the next
outfitterlaunch. - Outfitter MUST document warnings when a requested pi control cannot be applied because pi startup order makes it impossible.
OFTR-006.5: Claude Code Launch Controls
Section titled “OFTR-006.5: Claude Code Launch Controls”-
The Claude Code adapter MUST resolve one of two configuration strategies for every run. Under
inheritthe composition is layered over the machine’s own Claude Code configuration, so the run keeps the user’s workspace trust, permissions, credentials, plugins, and configured MCP servers. Underisolatedthe adapter MUST useCLAUDE_CONFIG_DIRas the profile-scoped configuration boundary, and the composition is the whole configuration.inheritMUST be the default, because a profile describes an agent rather than a machine;--isolated, orisolation: isolatedin home-scope settings, MUST selectisolated. -
The Claude Code adapter MUST launch the native
claudecommand. -
The Claude Code adapter MUST support profile-controlled environment variables.
-
The Claude Code adapter MUST support profile-controlled pass-through Claude Code CLI arguments.
-
The Claude Code adapter SHOULD support
--model,--effort, prompt control, and--plugin-dirwhere native Claude Code flags exist. -
The Claude Code adapter MUST pass prompt documents with
--system-prompt-fileand--append-system-prompt-file, never the bare--system-promptor--append-system-prompt. The bare flags take a prompt string, so a path is appended as literal text and the document is silently discarded. -
The Claude Code adapter MUST pass at most one
--append-system-prompt-file, concatenating the composed fragments in composition order, because a repeated occurrence discards every earlier one. -
The Claude Code adapter SHOULD support
controls.session_directoryandcontrols.claude.session_directoryby routing Claudeprojects/session state through Outfitter state persistence. -
The Claude Code adapter MUST return unsupported-control warnings for requested generic or
controls.claudecontrols that it cannot translate. -
Until native support is implemented and tested, the Claude Code adapter MUST report
prompt_templateas unsupported and MUST NOT pass a pi-style prompt-template argument. -
The Claude Code adapter MUST always pass the generated
mcp.jsonthrough--mcp-config, including when the composition selects zero MCP servers. An isolated run MUST also pass--strict-mcp-configso lower-layer MCP sources cannot break composition isolation. An inherited run MUST NOT pass--strict-mcp-config: a composition that selects a server states what the profile needs, not what the user may not have, so the selection merges with the servers already configured on the machine. Items 12 through 19 govern the isolated strategy. An inherited run reads and writes the user’s durable Claude state directly, so it MUST NOT seed that state into the projection and MUST NOT copy state back after the run; items 20 through 22 govern it instead. -
Before launch, the Claude Code adapter MUST seed an existing
~/.claude/.credentials.jsoninto the temporaryCLAUDE_CONFIG_DIRas.credentials.jsonwith mode0600, and MUST seed only theoauthAccountandhasCompletedOnboardingtop-level keys from~/.claude.json, when present, together with the trust mirror required by item 13, rather than copying the complete machine-local state file; missing or unparsable~/.claude.jsonstate MUST remain absent from the projection. -
The Claude Code adapter MUST mirror
projects[<working-directory>].hasTrustDialogAccepted = trueinto the projected.claude.jsononly when the durable~/.claude.jsonalready records that accepted trust decision for the exact launch working directory; it MUST NOT project other project entries or grant trust for a path without that durable decision. -
After a Claude Code launch exits or throws, the adapter MUST copy a projected
.credentials.jsonback to~/.claude/.credentials.jsonwith mode0600when the run changed it, except when the durable credentials also changed after seeding; in that concurrent-writer case, the adapter MUST preserve the durable file and return a warning. -
After a Claude Code launch exits or throws, the adapter MUST atomically merge a projected
oauthAccountinto~/.claude.jsonwithout replacing unrelated top-level or project state, and MUST leave malformed durable state untouched rather than clobbering it. -
The adapter MUST NOT merge projected
.claude.jsontop-level state other thanoauthAccountback into durable~/.claude.json. This restriction does not discard Claude MCP authorizations: their OAuth tokens live undermcpOAuthin~/.claude/.credentials.json, keyed by<serverName>|<hash>, and persist through the whole-file credential copy-back required by item 14 rather than through.claude.jsonmerging. -
Before launch, the Claude Code adapter MUST recursively seed only the current working directory’s entire existing session-history tree from
~/.claude/projects/<project-slug>/into the temporaryCLAUDE_CONFIG_DIR/projects/<project-slug>/, including transcripts, subagent artifacts, tool results, memory, and future nested files, so native--continueand--resumecan find earlier sessions without exposing other projects’ histories. -
After a Claude Code launch exits or throws, the adapter MUST recursively merge every regular file under the projected
projects/slug directories into~/.claude/projects/, atomically copying changed files with mode0600and without deleting durable files. The merge MUST compare each file with its seed-time hash: copy a projection-only change, leave a durable-only change untouched, and skip with an aggregated warning when both sides changed, including when the durable side changes again immediately before rename. -
Claude session traversal MUST continue after individual file failures and aggregate failed relative paths into one warning. Session seed or persistence failures and warning-sink failures MUST warn through or remain recorded in the launch result’s late-message channel and MUST NOT replace the launcher exit code or thrown error.
-
An inherited Claude Code run MUST NOT set
CLAUDE_CONFIG_DIR. It MUST declare the runtime projection root a Claude plugin by writing.claude-plugin/plugin.jsonnamed for the profile slug, and MUST pass that root through--plugin-dir, so the composition’s skills, subagents, and commands load into a session that is otherwise entirely the user’s own. -
An inherited Claude Code run MUST NOT seed credentials, machine-local state, or session history into the projection, and MUST NOT copy any of them back after the run. The native configuration directory already holds them, and a copy-back would race the user’s own concurrent sessions.
-
Before an inherited launch, the Claude Code adapter MUST confirm that the installed
claudesupports the flags inheriting depends on. When it cannot confirm them, the adapter MUST fall back to the isolated strategy and MUST warn, naming what was missing, because an unrecognized flag fails the launch outright rather than degrading it. -
The isolation choice MUST be honored only from home-scope settings, so a checked-in project or a remote catalog cannot decide how much of the user’s machine a profile it ships can see.
OFTR-006.6: Codex CLI Launch Controls
Section titled “OFTR-006.6: Codex CLI Launch Controls”- The Codex adapter MUST launch the native
codexcommand and MUST preserve pass-through arguments so callers can select interactive mode or theexecsubcommand. - The Codex adapter MUST project model selection through
-m. - For server ids containing only ASCII letters, digits,
_, or-, the Codex adapter MUST project selected stdio MCP servercommand,args,env, andcwdfields through repeated-c mcp_servers.<id>.<key>=<toml-value>overrides. Anenventry${ENV_NAME}MUST become anenv_varsreference only when its key is alsoENV_NAME; the adapter MUST warn and omit a reference that would rename the variable. Literalenventries MUST be projected and MUST warn that their values are exposed in process arguments. The adapter MUST warn and skip a server whose id contains other characters because Codex-ckey paths cannot express it. - The Codex adapter MUST project selected HTTP MCP server fields through repeated
-coverrides usingurlandhttp_headers, withenv_http_headersfor${ENV_NAME}values andbearer_token_env_varforAuthorization: Bearer ${ENV_NAME}. - The Codex adapter MUST warn that MCP projection is additive because Codex has no strict MCP isolation mode; this adapter warning follows the normal
--strictwarning policy. - The Codex adapter MUST report every selected loadout element other than
model,mcp, andextensionsas unsupported until a native projection is implemented and tested. - No adapter MAY report
extensionsas an unsupported loadout element.extensionsnames pi extension packages, so only the pi adapter can load them, and no user setting can make another harness load them. A non-pi launch MUST stay silent about the selected extensions and MUST NOT fail under--strictbecause of them.
OFTR-006.7: Pi Settings Reconciliation
Section titled “OFTR-006.7: Pi Settings Reconciliation”- When profile-controlled Pi extensions duplicate native Pi
settings.jsonpackage entries, the pi adapter MUST avoid launching pi with both copies enabled. - The pi adapter MUST compare duplicate Pi extension and package entries by normalized resource identity rather than raw source string.
- The pi adapter MUST preserve unrelated Pi settings and unrelated package entries when generating a reconciled runtime
settings.json. - The pi adapter MUST keep reconciled runtime
settings.jsonwrites non-durable and declared so they are discarded without being reported as unknown state. - The pi adapter MUST fall back to native Pi
settings.jsonstate persistence when reconciliation is unnecessary or the settings file cannot be interpreted safely.
OFTR-006.8: Outfitter Pi Interaction Defaults
Section titled “OFTR-006.8: Outfitter Pi Interaction Defaults”- The pi adapter MUST generate a runtime
keybindings.jsonthat reservesshift+tabfor Outfitter mode switching and binds Pi thinking-level cycling toctrl+shift+t. - The generated Pi keybindings file MUST preserve valid user or profile keybindings except for keys reserved by Outfitter’s mode and thinking controls.
- The generated Pi keybindings file MUST be non-durable runtime state so Outfitter’s default shortcut policy does not overwrite user or profile keybinding sources.
- Interactive Pi launches MUST inject an Outfitter bootstrap extension that consumes
shift+tabbefore Pi’s default thinking shortcut can handle it. - The Outfitter bootstrap extension MUST toggle between normal build mode and read-only plan mode.
- Plan mode MUST restrict active tools to read-only inspection tools, exclude Bash from the active tool set, and block Bash tool calls while plan mode is active.
- Interactive Pi launches SHOULD register a native
/outfittercommand for Outfitter-specific setup and profile management that can run without an agent turn. - Non-interactive Pi launches MUST NOT inject the Outfitter bootstrap extension.
OFTR-006.9: Canonical Cross-Harness Model Projection
Section titled “OFTR-006.9: Canonical Cross-Harness Model Projection”- When an agent selects
provider/modeland one or more effective layers containmodels.json, Outfitter MUST merge provider definitions by ID according to layer precedence and resolve the selection to one harness-neutral target containing provider ID, model ID, API dialect, base URL, credential-variable reference, required headers, projection-relevant model capabilities, and winning source layer. - A selected provider and model MUST exist in the effective registry, and a selected provider MUST declare string
apiandbaseUrlvalues; otherwise composition MUST fail before launch. - The Pi adapter MUST materialize the effective canonical
models.json, pass the normalized provider and model IDs through native flags, and MUST NOT replace or persist that declared registry through Pi’s user-state bridge. - For the
anthropic-messagesdialect, the Claude adapter MUST project the canonical model ID, base URL, runtime credential, and headers through Claude’s native model and gateway controls. - For the
openai-responsesdialect, the Codex adapter MUST configure the canonical provider, endpoint, credential environment key, headers, wire API, and model through native command-line configuration overrides. - An adapter that cannot preserve a target’s API dialect or provider ID MUST warn and MUST omit both the selected model identity and endpoint rather than silently using the same model ID against another endpoint; the existing
--strictwarning policy MUST make that warning fatal before launch. - Runtime credential values MUST come from the environment. Effective registries MUST reject literal
apiKeyvalues, executable credential-source fields, non-string headers, and literalAuthorizationheaders. - When no
models.jsonis configured, adapters MAY preserve legacy native model-name projection for compatibility.