> ## Documentation Index
> Fetch the complete documentation index at: https://docs.archal.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Harness configuration

> Configure the harness command Archal runs for your agent: model defaults, environment contract, and Docker or sandbox execution modes.

A harness is the small process Archal starts for a run. It reads the task, calls your agent, uses normal SDKs for service work, and prints the final answer.

## Quick start

For scored clone runs, run the harness in Docker or the sandbox:

```bash theme={null}
archal run scenario.md --harness . --docker
# or
archal run scenario.md --sandbox
```

Use the rest of this page when you need model defaults or the exact environment contract.

## Your harness stays local

The harness is your own agent. `archal run` always uses whichever local file you
point it at via `--harness` or the `agent` field in `.archal.json` - it is never
uploaded to your workspace.

Scenarios, by contrast, are workspace-scoped artifacts you can reuse across
projects. They are **not** auto-saved on `archal run`; push one explicitly:

```bash theme={null}
archal scenario push ./scenarios/close-stale-issues.md
```

List what is saved with `archal scenario list --source workspace`. See [`archal scenario`](/cli/scenario) for the full subcommand reference.

### Custom harness directory

Point `--harness` at any directory containing your agent code:

```bash theme={null}
archal run scenario.md \
  --harness ./my-agent \
  --docker \
  -n 3
```

You do not need an `agent` block when the entrypoint is obvious. Add one to `.archal.json` (with optional `agentModel`) when you want command defaults or a default model.

## Agent configuration (`.archal.json`)

Declare the harness command in your project's `.archal.json`:

```json theme={null}
{
  "agent": {
    "command": "node",
    "args": ["agent.mjs"],
    "env": {
      "MY_CUSTOM_VAR": "value"
    }
  },
  "agentModel": "gpt-4.1"
}
```

| Field           | Type      | Required | Description                                                    |
| --------------- | --------- | -------- | -------------------------------------------------------------- |
| `agent.command` | string    | No       | Command to spawn (e.g., `node`, `python`, `npx`).              |
| `agent.args`    | string\[] | No       | Arguments passed to the command.                               |
| `agent.env`     | object    | No       | Extra environment variables injected into the harness process. |
| `agentModel`    | string    | No       | Fallback model ID when `--agent-model` is not provided.        |

## Environment variables

Archal injects these into every harness process.

### Task and model

| Variable      | Description                                                                                    |
| ------------- | ---------------------------------------------------------------------------------------------- |
| `AGENT_TASK`  | The scenario task text. `## Expected Behavior` is never included - it's the evaluator holdout. |
| `AGENT_MODEL` | Model identifier from `--agent-model` or `.archal.json` `agentModel`.                          |

### Service connectivity

| Variable                                                       | Description                                                                       |
| -------------------------------------------------------------- | --------------------------------------------------------------------------------- |
| `NODE_EXTRA_CA_CERTS` / `SSL_CERT_FILE` / `REQUESTS_CA_BUNDLE` | Short-lived CA paths for clients that need to trust the controlled TLS intercept. |

Harnesses should call normal service domains such as `https://api.github.com`,
`https://slack.com/api`, or `https://api.stripe.com`. Clone URLs, MCP configs,
and run credentials are managed by Archal and are not part of the harness
contract.

When using `archal clone start` for manual integration instead of `archal run`,
the per-clone URLs are exported as `ARCHAL_<CLONE>_REST_URL` and
`ARCHAL_<CLONE>_MCP_URL`. See [Clone sessions](/guides/clone-sessions) for the
full env-var naming convention.

### API keys

Passed through from your environment or config:

| Variable            | Provider  |
| ------------------- | --------- |
| `OPENAI_API_KEY`    | OpenAI    |
| `ANTHROPIC_API_KEY` | Anthropic |
| `GEMINI_API_KEY`    | Google    |

### Tuning overrides

| Variable                  | Description                                          | Default        |
| ------------------------- | ---------------------------------------------------- | -------------- |
| `ARCHAL_MAX_TOKENS`       | Max completion tokens per LLM call                   | Model-specific |
| `ARCHAL_TEMPERATURE`      | Sampling temperature                                 | `0.2`          |
| `ARCHAL_REASONING_EFFORT` | OpenAI reasoning models: `low`, `medium`, `high`     | `medium`       |
| `ARCHAL_THINKING_BUDGET`  | Extended thinking: `adaptive`, `off`, or token count | `adaptive`     |
| `ARCHAL_LLM_TIMEOUT`      | Per-LLM-call timeout in seconds                      | `120`          |
| `ARCHAL_LOG_LEVEL`        | Harness log verbosity                                | `info`         |

### Base URL overrides

For Azure OpenAI, API proxies, or self-hosted endpoints:

| Variable                    | Default                                            |
| --------------------------- | -------------------------------------------------- |
| `ARCHAL_OPENAI_BASE_URL`    | `https://api.openai.com/v1`                        |
| `ARCHAL_ANTHROPIC_BASE_URL` | `https://api.anthropic.com`                        |
| `ARCHAL_GEMINI_BASE_URL`    | `https://generativelanguage.googleapis.com/v1beta` |

### Metrics and trace output

Archal sets these paths. Your harness may write JSON to them for richer reports:

| Variable             | Description                                                          |
| -------------------- | -------------------------------------------------------------------- |
| `AGENT_METRICS_FILE` | Path to write metrics JSON (token counts, timing, exit reason)       |
| `AGENT_TRACE_FILE`   | Path to write agent trace JSON (thinking, text, tool calls per step) |

## Service transport

Use the same client code you would use outside Archal. For GitHub, that can be
`gh`, Octokit, or `fetch("https://api.github.com/...")`. The controlled runtime
routes supported service traffic to the scenario clones and applies run
credentials server-side.

## Example: minimal custom harness

A minimal harness reads the task and invokes your real agent runtime:

```javascript theme={null}
// agent.mjs
const TASK = process.env.AGENT_TASK;
const MODEL = process.env.AGENT_MODEL || 'gpt-4.1';
const API_KEY = process.env.OPENAI_API_KEY;

const result = await runMyAgent({ task: TASK, model: MODEL, apiKey: API_KEY });
console.log(JSON.stringify({ text: result }));
```

With `.archal.json`:

```json theme={null}
{
  "agent": { "command": "node", "args": ["agent.mjs"] },
  "agentModel": "gpt-4.1"
}
```

Run it:

```bash theme={null}
archal run scenario.md --harness ./my-agent --docker
```
