---
title: "Configuration reference · coding.sh docs"
description: "Every config.toml key and environment variable, their defaults, and which layer wins."
canonical: https://coding.sh/docs/config
human_url: https://coding.sh/docs/config
markdown_url: https://coding.sh/docs/config.md
agents_url: https://coding.sh/agents.md
llms_url: https://coding.sh/llms.txt
updated: 2026-11-11
---

# Configuration reference

Every config.toml key and environment variable, their defaults, and which layer wins.

Every key in `config.toml` and every environment variable coding.sh reads.

## Where settings come from

Later layers win:

- Built-in defaults.
- `~/.coding.sh/config.toml` (or `$CODING_SH_HOME/config.toml`), your user config.
- `<repo>/.coding.sh/config.toml`, the nearest one above the working directory.
- Environment variables (`CODING_SH_STORE_URL`, `CODING_SH_BLOB_URL`, and the server variables).
- Command-line flags (`--store`, `--blobs`, and each command's own options).

A repo file arrives with `git clone`, so it may only make capture more private:

- It can set `capture` and `snapshot` keys. Redaction lists are merged, not replaced.
- `capture.mode` can only become `metadata`, and `capture.maxInlineBytes` can only go down.
- It can add `refine.protect` patterns but not turn `refine.autoProtect` off.
- It can never set sinks or stores.

shell

```
coding.sh config path                          # the file in use
coding.sh config get                           # the effective config, all layers applied
coding.sh config get capture.mode
coding.sh config set capture.mode metadata --dry-run
coding.sh config set capture.redact '["secrets","env"]'
```

`config set` accepts the keys marked settable below, parses numbers, `true`/`false` and JSON arrays, and keeps the rest of the file as it is. Edit the file by hand for sinks, prices, gateway and serve settings.

String values in `store.*`, `sinks.*.endpoint`, `sinks.*.headers` and `gateway.apiKey` may use `${NAME}`; it is replaced with that environment variable, and an unset variable is an error. Use it to keep tokens out of the file.

## `[store]`

| Key | Default | Settable | What |
| --- | --- | --- | --- |
| `store.index` | `sqlite://~/.coding.sh/index.db` | yes | Index store URL. `sqlite://` and `memory://` are built in; `postgres://` needs the `coding.sh-store-postgres` package. Another scheme loads `coding.sh-store-<scheme>`. |
| `store.blobs` | `file://~/.coding.sh/blobs` | yes | Blob store URL for large payloads. `s3://` needs `coding.sh-store-s3`. With a `postgres://` index and no blob URL, blobs go to the same database. |

## `[capture]`

| Key | Default | Settable | What |
| --- | --- | --- | --- |
| `capture.mode` | `"full"` | yes | `full` keeps prompts, replies and tool input and output. `metadata` keeps ids, times, kinds, durations, token counts and short labels only. |
| `capture.redact` | `["secrets"]` | yes | Built-in redactors: `secrets` (API keys, tokens, private keys), `env` (values of environment variables), `email` (email addresses), `pii` (all of `email`, `phone`, `card`, `iban` and `national-id`), `phone` (phone numbers with a `+` country code, and North American numbers), `card` (card numbers with a known issuer prefix that pass the Luhn check), `iban` (IBANs with the right length for their country and a valid check), `national-id` (US SSNs, UK National Insurance numbers, Canadian SINs that pass the Luhn check), `none` (clears the list in your user config). |
| `capture.redactPatterns` | `[]` | yes | Extra regular expressions to redact. Matches become `[redacted:<kind>]`. |
| `capture.exclude` | `[]` | yes | Path globs (`*`, `**`, `?`, `~`). Sessions whose working directory, or a parent of it, matches are dropped at ingest. |
| `capture.maxInlineBytes` | `4096` | yes | Payloads larger than this go to the blob store. Minimum 256. |

Redaction runs at ingest, before anything is written to the index, blobs or sinks.

## `[snapshot]`

Used by `coding.sh run --`, which snapshots the repo before and after the command.

| Key | Default | Settable | What |
| --- | --- | --- | --- |
| `snapshot.enabled` | `true` | yes | Take repo snapshots. |
| `snapshot.maxFiles` | `20000` | yes | Skip the snapshot for repos with more files than this. |
| `snapshot.timeoutMs` | `2000` | yes | Give up on a snapshot after this many milliseconds. |

## `[retention]`

Applied by `coding.sh gc`.

| Key | Default | Settable | What |
| --- | --- | --- | --- |
| `retention.keepSpoolDays` | `7` | yes | Days to keep spool files after they were ingested and sent to every sink. The current UTC day's file is kept even at `0`: hooks are still writing to it. |
| `retention.toolOutputDays` | `90` | yes | Days to keep blobs referenced only by tool output and file reads. Diffs and eval tasks are kept. |

## `[update]`

| Key | Default | Settable | What |
| --- | --- | --- | --- |
| `update.check` | `true` | yes | Check for a new release in the background, at most once a day. `coding.sh serve` never checks. |

## `[[sinks]]`

A sink copies events to another system as they are ingested. Add one table per sink. Sinks run for local ingest, the local OTLP receiver (`coding.sh collector`) and `coding.sh serve`, which mirrors each committed batch after it answers the request. The collector and serve send an event once: a request that is posted again, such as a client retry, adds nothing to a sink.

Local ingest sends what it stores from the hook spool and what it imports from agent transcripts (`coding.sh ingest --backfill`, `coding.sh init`, and the import a read runs for agents without hooks).

- A sink that fails does not stop ingest. It is tried again after a backoff, then catches up from where it stopped in the spool.
- For transcripts it starts again at the top of each file it missed part of, so it can get a transcript event twice. A sink added later gets the transcripts still on disk the same way.
- With sinks set, one transcript import runs at a time (`~/.coding.sh/sinks.lock`).

config.toml

```
[[sinks]]
kind = "otlp"                          # or "http"
name = "team"
endpoint = "https://obs.example.com"   # otlp posts to <endpoint>/v1/traces
mode = "metadata"
headers = { Authorization = "Bearer ${CODING_SH_INGEST_KEY}" }
```

| Key | Default | What |
| --- | --- | --- |
| `kind` | required | `otlp` (OTLP/HTTP JSON traces) or `http` (coding.sh/trace JSON). Another kind loads `coding.sh-sink-<kind>`. |
| `endpoint` | required | Where to send. |
| `mode` | `"metadata"` | `metadata` sends no prompts, code or tool output. `full` sends everything that was captured. |
| `name` | the kind | Unique name: letters, digits, `.`, `_`, `-`. Needed when two sinks share a kind. |
| `batchSize` |  | Events per request. |
| `headers` |  | Table of HTTP headers. |

The `otlp` sink sends a session as one `invoke_agent` span when the session ends. From `coding.sh collector` and `coding.sh serve` it also sends that span while a session is open, so a session that never ends has one ([Forward and sinks](https://github.com/jackulau/coding.sh/blob/main/docs/PRODUCTION.md#19-forward-and-sinks)). Local ingest sends it again when a transcript import adds events to a session without ending it, so the span has the session's totals.

## `[prices]`

One `[prices."<model>"]` table per model, with prices in USD per million tokens. Ingest and `coding.sh serve` use them to estimate cost for model calls that report tokens but no cost. They replace the built-in row for that model, add models it lacks, and also price newer versions in the same family (`[prices."house-coder-2"]` prices `house-coder-2.1` too). A cost the agent or gateway reported is never replaced.

config.toml

```
[prices."my-finetune"]
input = 3.0
output = 15.0
cache_read = 0.3
cache_write = 3.75
```

`input` and `output` are required. `cache_read` and `cache_write` are optional and default to the input price. `[pricing."<model>"]`, the older spelling, still works; `[prices]` wins a model set in both. Stored estimates are recomputed the next time the index opens after a change.

Long-context and service-tier rates are optional sub-tables:

config.toml

```
[prices."my-finetune".long_context]   # prompts over `above` tokens (input + cache)
above = 200000
input = 6.0
output = 22.5

[prices."my-finetune".batch]          # also flex, priority, fast, ultrafast
input = 1.5
output = 7.5

[prices."my-finetune".batch.long_context]   # `above` defaults to the model's threshold
input = 3.0
output = 11.25
```

Each sub-table takes the same `input`, `output`, `cache_read` and `cache_write` keys, plus `cache_write_1h` for Anthropic 1-hour cache writes (it defaults to `cache_write`). A `geo` table multiplies every rate for calls that ran in that inference geography:

config.toml

```
[prices."my-finetune".geo]   # payload.inferenceGeo, from Anthropic's usage.inference_geo
us = 1.1
```

A call goes to the tier it recorded (`batch`, `flex`, `priority`), or `fast` for Claude fast mode (`fast` falls back to `priority` rates when it has no table). A tier with no table is priced at the standard rates.

An override replaces the whole built-in row, tiers included, so add the tier tables you want to keep. See [Where cost comes from](https://coding.sh/docs/how-to/expensive-sessions#where-cost-comes-from).

## `[gateway]`

For LLM gateways (`coding.sh gateway`, `compare --gateway`, and `gateway` judges). The top-level keys are for Vercel AI Gateway. Other gateways get their own table, `[gateway.<name>]`, with the same keys. Names: `openrouter`, `litellm`, `cloudflare`, `portkey`, `helicone`, `requesty`, `ramp`, `truefoundry`, `kong`, `bifrost`, `martian`.

| Key | Default | What |
| --- | --- | --- |
| `apiKeyEnv` | the gateway's standard variable, e.g. `"AI_GATEWAY_API_KEY"`, `"OPENROUTER_API_KEY"` | Environment variable that holds the key. |
| `apiKey` |  | The key itself, usually `"${SOME_VAR}"`. Used only when the variable above is empty. |
| `baseUrl` | the gateway's API, e.g. `https://ai-gateway.vercel.sh/v1` | API base. For Vercel, `CODING_SH_GATEWAY_URL` overrides it. Required for self-hosted LiteLLM unless `LITELLM_PROXY_API_BASE` is set. |
| `default` |  | Top level only: the gateway a bare `compare --gateway` uses. |
| `accountId`, `gatewayId` |  | `[gateway.cloudflare]` only: where the logs live. `CLOUDFLARE_ACCOUNT_ID` also works. |

Keys are never printed or stored. See [LLM gateways](https://github.com/jackulau/coding.sh/blob/main/docs/integrations/ai-gateway.md).

## `[refine]`

Which harness lines an edit may not delete, reword or relax (`coding.sh refine check`, `refine test`, `refine run` and `exp ab`), and which `refine propose` marks READ-ONLY. See [Protected safety lines](https://github.com/jackulau/coding.sh/blob/main/docs/guides/evals.md#protected-safety-lines). Also how far a listed cost may rise for a pass-rate gain in `refine test|run --suite`; see [Climbing on an eval suite](https://github.com/jackulau/coding.sh/blob/main/docs/guides/evals.md#climbing-on-an-eval-suite).

| Key | Default | What |
| --- | --- | --- |
| `protect` | `[]` | Regexes. An AGENTS.md or other instruction-file, rule or skill line matching one is protected; the line is tested without its list marker or bold, so `"^Use pnpm"` matches `- Use pnpm`. A repo config's patterns are added to yours. |
| `autoProtect` | `true` | Protect gate-word + safety-topic lines ("Never run `git push --force`") automatically. Honoured only in your user config. |
| `maxCostRise` | `"50%"` | The default of `--max-cost-rise`: how far a listed cost, tokens, time, turns or size objective may rise for a significant pass-rate gain. `"100%"`, `"none"`, or a number: below 1 a fraction (`0.5` is +50%), from 1 up percent (`150` is +150%). A repo config can lower it but not raise it. |
| `canary_model` | none | The model `refine test --suite` and `refine run --suite` re-test kept candidates under when `--canary-model` is not given, and the default for `refine recheck --model`. See [Canary re-test](https://github.com/jackulau/coding.sh/blob/main/docs/guides/evals.md#canary-re-test). Honoured only in your user config. |

config.toml

```
[refine]
protect = ["^Use pnpm", "staging"]
```

## `[proxy]`

Read by `coding.sh proxy` and `coding.sh init --proxy`. Flags on `coding.sh proxy` win over these, and these win over the upstream `init --proxy` chained through (the base URL an agent used before, kept in `~/.coding.sh/proxy-installs.json`). See [Capture with the proxy](https://coding.sh/docs/how-to/capture-with-proxy#already-using-a-gateway-or-cliproxyapi).

| Key | Default | What |
| --- | --- | --- |
| `port` | `4320` | Port the proxy listens on, and the one `init --proxy` points agents at. |
| `host` | `127.0.0.1` | Interface to bind. |
| `anthropic_upstream` | `https://api.anthropic.com` | Where Anthropic API calls go, e.g. a gateway. |
| `openai_upstream` | `https://api.openai.com` | Where OpenAI API calls go. |
| `chatgpt_upstream` | `https://chatgpt.com/backend-api/codex` | Where Codex calls signed in with ChatGPT go. |

## `[serve]`

Read only by `coding.sh serve`. Every key has an environment variable, which wins over the file. [PRODUCTION.md §1.1](https://github.com/jackulau/coding.sh/blob/main/docs/PRODUCTION.md#11-config) has the full rules.

| Key | Env | Default | What |
| --- | --- | --- | --- |
| `serve.host` | `CODING_SH_HOST` | `127.0.0.1` | Interface to bind. |
| `serve.port` | `CODING_SH_PORT`, then `PORT` | `4318` | Port. |
| `serve.retention_days` | `CODING_SH_RETENTION_DAYS` | `0` (keep) | Delete sessions older than this. |
| `serve.log` | `CODING_SH_LOG` | `json` when stderr is not a terminal | `json` or `text`. |
| `serve.queue_max_events` | `CODING_SH_QUEUE_MAX_EVENTS` | `50000` | Ingest queue limit; over it, requests get 429. |
| `serve.queue_max_bytes` | `CODING_SH_QUEUE_MAX_BYTES` | `134217728` | Same, in bytes. |
| `serve.insecure` | `CODING_SH_INSECURE=1` | off | Allow a non-loopback bind without keys. |
| `serve.trust_proxy` | `CODING_SH_TRUST_PROXY=1` | off | Honor `X-Forwarded-Proto` and `X-Forwarded-For`. |
| `serve.cors_origins` |  | `[]` | Browser origins allowed to post to the ingest routes (`/v1/ingest`, OTLP). The viewer and `/api/*` stay same-origin. |
| `[[serve.projects]]` `id`, `ingest_keys`, `retention_days` | `CODING_SH_INGEST_KEYS` |  | Projects and their ingest keys (`sha256:<hex>` in the file). |
| `[serve.viewer]` `read_keys` | `CODING_SH_READ_KEYS` |  | Read keys: `[{ project = "*", key = "sha256:<hex>", name = "alice" }]`. `name` (optional) is recorded as the author of that key's labels. |
| `[serve.viewer]` `basic_user`, `basic_password_sha256` | `CODING_SH_BASIC_AUTH` (`user:password`) |  | Basic auth for the viewer. |
| `capture.mode` | `CODING_SH_CAPTURE_MODE` | `full` | `metadata` drops content on ingest. |
| `[serve.forward]` `endpoint` | `CODING_SH_FORWARD_URL` | unset (no forward) | OTLP/HTTP collector that serve sends every committed trace to, as JSON. `/v1/traces` is added unless the URL already ends in it. `${ENV}` works in the file. [PRODUCTION.md §1.9](https://github.com/jackulau/coding.sh/blob/main/docs/PRODUCTION.md#19-forward-and-sinks) |
| `[serve.forward]` `headers` | `CODING_SH_FORWARD_HEADERS` (`k=v,k2=v2`, URL-encoded values) |  | Headers for the collector, such as an API key. The variable's entries are added to the table's. |
| `[serve.forward]` `mode` | `CODING_SH_FORWARD_MODE` | `capture.mode` | `metadata` sends ids, names, models, tokens, timings and status only. `full` sends attributes after redaction. |
| `[serve.forward]` `max_buffer_spans` | `CODING_SH_FORWARD_MAX_BUFFER_SPANS` | `20000` | Spans kept in memory while the collector is down. Past it the oldest are dropped and counted. |

## Other files

| File | Used by | Reference |
| --- | --- | --- |
| `coding.sh.toml` at the repo root | `coding.sh toolevals` (targets, drivers, variants, `[toolevals] confirmAboveUsd`, default 5) | [TOOL-EVALS.md](https://github.com/jackulau/coding.sh/blob/main/docs/TOOL-EVALS.md) |
| `bench/<name>.toml` or `~/.coding.sh/benchmarks/<name>.toml` | `coding.sh bench` | `coding.sh bench new --help` |
| An experiment spec (JSON) | `coding.sh exp run <spec>` | [Evals](https://coding.sh/docs/evals) |
| A harness TOML | `coding.sh harness snapshot --file` | `coding.sh harness snapshot --help` |

## Environment variables

### Paths and stores

| Variable | What |
| --- | --- |
| `CODING_SH_HOME` | Data directory. Default `~/.coding.sh`. Use a temp dir in tests and CI to keep runs out of your history. |
| `CODING_SH_STORE_URL` | Index store for every command; same as `--store`. Skips the automatic ingest of the local spool. |
| `CODING_SH_BLOB_URL` | Blob store; same as `--blobs`. |
| `CODING_SH_DEV_REAL_STORE=1` | Lets coding.sh run from a source checkout (`src/*.ts`, or a `dist/` built inside it) open the default home. Without it, or `CODING_SH_HOME` or a store URL, such a run stops before it opens anything. Migrations still wait for the install that owns the store ([Troubleshooting](https://coding.sh/docs/troubleshooting#a-store-another-codingsh-cant-open)). |
| `CODING_SH_SCAN_CAP` | How many sessions `usage` and `cache doctor` read for a window's totals before they stop and say so (`Stopped after N sessions`, `truncated` in `--json`). Default `100000`. Tests set a small one. |
| `CODING_SH_PURGE_WAIT_MS` | How long `purge` waits for another process's read of the index or the blob pack before it reports that the old bytes stay. Default `10000` for the index checkpoint before VACUUM and `5000` after it. Tests set a short wait. |
| `DATABASE_URL` | `coding.sh serve` only: the store when it is a `postgres://` URL and `CODING_SH_STORE_URL` is unset. |

### Capture

| Variable | What |
| --- | --- |
| `CODING_SH_DISABLE=1` | The hook reads its input and writes nothing. Set it in an agent's environment to pause capture. |
| `CODING_SH_NO_AUTO_INGEST=1` | The hook does not start a background ingest when a session ends, and `init` does not finish its import of past sessions in the background. |
| `CODING_SH_NO_PROXY_AUTOSTART=1` | The hook does not restart a stopped `coding.sh proxy` when a session starts (it does only after `init --proxy`). |
| `CODING_SH_ECHO_CONTINUE=1` | The hook prints `{"continue":true}`, for agents that need a JSON reply. `init` sets this up where needed. |
| `CODING_SH_HOOK_SOURCE` | Path of the `hook.mjs` that `init` copies into `~/.coding.sh/bin`. |
| `CODING_SH_INIT_IMPORT_BUDGET_MS` | How long `init` imports past sessions before it hands the rest to a background import. Default 8000. |
| `CODING_SH_CAPTURE_MODE` | `coding.sh serve` and the SDKs: `full` or `metadata`. |

### Set by coding.sh for the processes it starts

Read these in your agent or script to tie its output to a run.

| Variable | Set by | What |
| --- | --- | --- |
| `CODING_SH_SESSION_ID` | `run --` | The session id of the wrapped command. |
| `CODING_SH_RUN_ID` | `exp run`, `compare`, `bench`, `workflows` | Run id. Hook events carrying it are tagged with the run, and the hook skips its own background ingest. You can set it yourself to tag a run. |
| `CODING_SH_AGENT`, `CODING_SH_AGENT_OUTPUT`, `CODING_SH_AGENT_STDOUT`, `CODING_SH_AGENT_DIFF` | `compare`, `exp run` eval tasks (verifier only) | The agent adapter id, a file with the agent's final answer, a file with its whole stdout (for Claude Code, stream-json with every tool call), and a file with its work-tree diff (taken before hidden files land; `judge grade` reads it for `agent-slop`). The files sit outside the work tree. `CODING_SH_SESSION_ID` is set too when the run produced a session. |
| `CODING_SH_GRADER_USAGE` | `compare`, `exp run` eval tasks (verifier only) | A JSONL file. `judge grade` appends one row per model call (model, tokens, cost) so the run's judge spend counts in `compare`'s spend lines and `--max-cost`. |
| `CODING_SH_CASE_ID`, `CODING_SH_TRIAL` | `exp run` command tasks | The case id and trial number. |
| `CODING_SH_ATTEMPT`, `CODING_SH_SEQ_K` | `exp run --seq K` command tasks | This attempt (from 1) and K, the most attempts a case gets. With `envelope = true` stdin carries them too, with the earlier attempts' feedback in `history`. See [Sequential attempts](https://github.com/jackulau/coding.sh/blob/main/docs/guides/evals.md#sequential-attempts-with-feedback). |
| `CODING_SH_WORKFLOW_RUN_ID` | `workflows run`, `workflows replay` | Workflow run id. |
| `CODING_SH_BENCH`, `CODING_SH_BENCH_SEED`, `CODING_SH_BENCH_DATE`, `CODING_SH_BENCH_RUN_ID`, `CODING_SH_BENCH_CASES` | `bench run` command sources | Benchmark name, seed, date, run id and number of cases to print. |
| `CODING_SH_BENCH_NOW` | you, in tests | Make `bench run` act as if it started at this time (ISO time or epoch ms), to simulate daily runs. |
| `CODING_SH_BENCH_SEED_KEY` | you, or a CI secret | Key for `seed = "secret"` benchmarks: each date's salt is an HMAC of the date under it. Rename it per benchmark with `seedKeyEnv`. |

### Server

`CODING_SH_HOST`, `CODING_SH_PORT`, `PORT`, `CODING_SH_INGEST_KEYS`, `CODING_SH_READ_KEYS`, `CODING_SH_BASIC_AUTH`, `CODING_SH_INSECURE`, `CODING_SH_TRUST_PROXY`, `CODING_SH_LOG`, `CODING_SH_RETENTION_DAYS`, `CODING_SH_QUEUE_MAX_EVENTS`, `CODING_SH_QUEUE_MAX_BYTES`: see `[serve]`.

### Evals and integrations

| Variable | What |
| --- | --- |
| `ANTHROPIC_API_KEY` | LLM judges with `"provider":"anthropic"` (the default). A grader's `apiKeyEnv` names another variable. |
| `OPENAI_API_KEY` | LLM judges with `"provider":"openai"`. |
| `CLAUDE_CODE_OAUTH_TOKEN` | LLM judges with `"provider":"claude-code"`, and `exp ab` and `refine` with `--provider claude-code`, which run `claude -p` on a Claude subscription (the token comes from `claude setup-token`). Without it the CLI uses `ANTHROPIC_API_KEY` or its own login. With no API key set, `exp ab` and `refine` use it on their own. |
| `CODEX_HOME` | Where `"provider":"codex"` and `--provider codex` find Codex's `auth.json` (default `~/.codex`); each call gets a throwaway copy. |
| `AI_GATEWAY_API_KEY` | Vercel AI Gateway: `gateway enrich`, `gateway status --credits`, `compare --gateway`, `gateway` judges. |
| `CODING_SH_GATEWAY_URL` | Vercel AI Gateway API base. |
| `OPENROUTER_API_KEY`, `LITELLM_PROXY_API_KEY`, `CLOUDFLARE_API_TOKEN`, `PORTKEY_API_KEY`, `HELICONE_API_KEY`, `RAMP_ROUTER_API_KEY` | Other gateways: `gateway enrich` lookups and `compare --gateway <name>`. |
| `CODING_SH_EXP_SESSION` | Experiment session id for `exp run` and `exp session`, in place of the nearest `.coding-sh/session.json`. |
| `CODING_SH_RETRY_BASE_MS` | First backoff (ms) before a trial is retried after a rate limit, 5xx or network error; it doubles per retry, with jitter. Default `2000`. Tests set `0`. |
| `CODING_SH_CONFIRM_ABOVE_USD` | `workflows run` and `replay` ask before running above this estimated cost. Default `1`. |
| `GITHUB_TOKEN`, `GH_TOKEN` | `bench` GitHub sources. Falls back to `gh auth token`. |

Tool-eval model drivers read the key variable set by `apiKeyEnv` in `coding.sh.toml`.

### Output and updates

| Variable | What |
| --- | --- |
| `NO_COLOR` | No color. Same as `--no-color`. |
| `FORCE_COLOR` | Color even when output is not a terminal. |
| `CI` | Treated as non-interactive: no prompts or spinners. Commands that would ask need `--yes`. |
| `NO_UPDATE_NOTIFIER`, `CODING_SH_NO_UPDATE_CHECK` | Turn off the update check. Same as `update.check = false`. |
| `CODING_SH_READ_BUDGET_MS` | How long read commands (`status`, `sessions`, `search`, `show`, `tree`, `usage`, `improve`, `harness audit`, `cache doctor`, ...) and MCP tool calls ingest pending captures before answering from what is indexed (with a `pending` field in JSON and MCP results). Default `1500`; `--fresh` waits for all. While a re-parse holds `reparse.lock`, these reads skip the ingest, leave the spool to the re-parse, and add `"reparsing": true` to `pending`. |

### Installer

Read by `curl -fsSL https://coding.sh/install | sh`.

| Variable | What |
| --- | --- |
| `CODING_SH_YES=1` | Don't ask before running `init`. |
| `CODING_SH_NO_INIT=1` | Install only. |
| `CODING_SH_NO_UI=1` | Don't open the viewer. |
| `CODING_SH_VERSION` | Install this release, e.g. `v0.1.0`. |
| `CODING_SH_TARBALL` | Install this tarball (path or URL) instead. |
| `CODING_SH_SOURCE` | `npm` or `github`. By default the installer uses npm when the registry has the version and the GitHub release tarball otherwise. |

### SDKs

Read by `@codingdotsh/sdk` and the Python `coding_sh` package when they send to `coding.sh serve`.

| Variable | What |
| --- | --- |
| `CODING_SH_URL` | Server URL. |
| `CODING_SH_INGEST_KEY` | Ingest key. |
| `CODING_SH_SERVICE` | Service name; becomes the session's agent id. |
| `CODING_SH_DISABLED` | Send nothing. |
| `CODING_SH_DEBUG` | Log what the SDK does. |

### Where agents keep their files

Adapters look in each agent's default location, or where these point: `CLAUDE_CONFIG_DIR` (Claude Code), `CODEX_HOME` (Codex), `OPENCODE_CONFIG_DIR` and `OPENCODE_DB` (OpenCode), `CURSOR_CONFIG_DIR` and `CURSOR_DATA_DIR` (Cursor), `GEMINI_CLI_HOME` (Gemini CLI), `COPILOT_HOME` (Copilot CLI), `PI_CODING_AGENT_DIR` and `PI_CODING_AGENT_SESSION_DIR` (Pi), `GOOSE_PATH_ROOT` (Goose), `T3CODE_HOME` (T3 Code), and `XDG_CONFIG_HOME` / `XDG_DATA_HOME`.

To set coding.sh up for a user, follow the agent workflow at [/agents.md](https://coding.sh/agents.md).
