Skip to content

fullsend run

Execute an agent locally in a sandbox. fullsend run resolves the agent harness, provisions a sandbox container, and runs the agent to completion.

Usage

bash
fullsend run <agent-name> [flags]

Flags

FlagDescription
--fullsend-dirPath to the .fullsend configuration directory
--runtimeOverride the agent runtime from config.yaml for this run (claude, pi, dummy or dummy-playback); also FULLSEND_RUNTIME
--modelOverride the harness/agent model for this run (alias, model id, or provider/id on pi); also FULLSEND_MODEL
--effortOverride the harness effort level for this run (lowmax); also FULLSEND_EFFORT
--output-dirBase directory for run output (default: /tmp/fullsend)
--target-repoPath to the target repository
--fullsend-binaryPath to a Linux fullsend binary to copy into the sandbox
--env-fileLoad environment variables from a dotenv file (repeatable)
--no-post-scriptSkip post-script execution
--keep-sandboxSkip sandbox deletion after the run
--debug [filter]Enable agent runtime debug logging with optional category filter (e.g. "api,hooks")
--forgeForge platform to use (e.g. "github", "gitlab"); auto-detected from CI env vars when omitted
--offlineReject network fetches; only use cached remote resources
--max-depthMaximum dependency depth for transitive resolution (0 disables)

Plan block

At startup, fullsend run prints a plan block summarizing the resolved configuration:

Agent:     code
Role:      code
Model:     sonnet
Effort:    high
Runtime:   claude (from /path/to/.fullsend/config.yaml)
Image:     fullsend-sandbox:latest

The Runtime line shows which runtime was selected and the config source it was read from. When no config.yaml exists, the source reads default (config not found).

Runtime selection

The runtime for a run is resolved once, in this order: --runtime flag, FULLSEND_RUNTIME, runtime: on the agent's agents: entry in config.yaml / .fullsend/config.yaml, the repo-wide runtime: there, then the built-in claude. The same order applies to the model (--model, FULLSEND_MODEL, model: on the agent's agents: entry, harness model:, agent frontmatter; FULLSEND_PI_MODEL is a lower-precedence alias on pi) and to effort (--effort, FULLSEND_EFFORT, effort: on the agent's agents: entry, harness effort:). <agent> is the name given to fullsend run (triage, code, …); see Runtimes — per-agent settings. FULLSEND_FALLBACK_MODELS=a,b becomes Claude Code's --fallback-model; pi ignores it with a warning.

The plan block prints Runtime: <name> (from <source>) and, when an override applied, Model: <value> (from <source>); stderr carries runtime: selected "<name>" from <source> (and model: requested "<value>" from <source>) for scripts. A value from the config file is labelled with the file path, suffixed agents.<name> when the agent's entry decided. An invalid override (unknown runtime, unknown effort level, an agents: entry that names no agent) fails before the sandbox is created.

bash
# try a repo's triage on pi with Gemini Flash, without touching its config
fullsend run triage --fullsend-dir . --target-repo ../repo \
  --runtime pi --model google-vertex/gemini-2.5-flash --effort medium

Output artifacts

Each run produces artifacts in the output directory:

FileDescription
metrics.jsonBehavioral metrics: tokens, cost, model, runtime, iterations
transcripts/Agent conversation transcripts
claude-debug.log or pi-debug.logDebug log (when --debug is set)

metrics.json fields

FieldDescription
runtimeRuntime that executed the run (e.g. claude, pi)
modelModel the provider reported using
requested_runtimeRuntime selected for the run (config file, or a --runtime/FULLSEND_RUNTIME override)
requested_modelModel the harness/agent requested
override_sourceWhere requested_model came from (--model flag, FULLSEND_MODEL, FULLSEND_PI_MODEL, <config path> agents.<name>, harness, default)
runtime_sourceWhere requested_runtime came from (--runtime flag, FULLSEND_RUNTIME, the config file path — suffixed agents.<name> when the agent's entry decided — or default (config not found))
total_cost_usdTotal inference cost in USD, as reported by the runtime (raw floating-point aggregate across all iterations; no fullsend-side pricing-table fallback). See Cost data contract
num_turnsNumber of conversation turns
iterationsNumber of retry iterations

OpenAI credentials on pi

A fullsend-openai provider (providers: [openai] on the harness, openai/<id> models on pi) gets its credential from the runner, never from the harness or the sandbox:

Runner environmentEffect
FULLSEND_OPENAI_AUDIENCE, FULLSEND_OPENAI_IDENTITY_PROVIDER_ID, FULLSEND_OPENAI_SERVICE_ACCOUNT_IDWorkload Identity Federation (GitHub Actions only): the run exchanges the job's OIDC token for a short-lived OpenAI token, refreshes it before expiry, and refuses a token whose mapping grants more than model access. All three must be set together; when unset, the inference.openai block of config.yaml (written by fullsend github setup --openai-*) supplies them — except on a machine without a GitHub OIDC endpoint where OPENAI_API_KEY is set, which then wins.
OPENAI_API_KEYStatic key for local runs (used only when the three above are unset). In harness YAML, env.sandbox and provider definitions ${OPENAI_API_KEY} expands to the empty string (like the other runner-only variables), and it is never passed to pre/post scripts; the sandbox sees only the gateway placeholder.

In CI the run prepares .fullsend/providers/ from the upstream defaults, so a file there with a scaffold-shipped name (openai.yaml, github-ro.yaml, vertex-ai.yaml, …) is replaced by the upstream copy; give repository-specific providers their own file name. A harness that declares the bare name openai with no providers/openai.yaml on disk gets the definition built into fullsend; other bare names still need a file.

Both paths create a provider named after the run and remove it when the run ends. Setup and troubleshooting: OpenAI Workload Identity.