# Environment Variables (https://jackin.tailrocks.com/guides/environment-variables/)



jackin❯ lets you set environment variables for agent containers at four scopes — global, per role, per workspace, and per (workspace × role). Values can be literal strings, references to host env vars, or references to 1Password items resolved through the `op` CLI.

<Aside type="tip">
  Operator env vars are managed through `jackin config env`,
  `jackin workspace env`, or the **Environments** tab in the
  operator console's workspace editor (workspace and per-(workspace ×
  role) scopes). You should not need to hand-edit any configuration
  file — the global scope is CLI-only today; the workspace scopes
  are reachable from both the CLI and the console.
</Aside>

## Why operator env [#why-operator-env]

Role manifests declare the env *shape* — what keys a role expects, what's interactive, what has a default. Operator env scopes declare the *values* for a specific operator on a specific workspace with a specific role. Keeping shape and values in different places means:

* Third-party roles never see your secrets in their git history.
* The same role can run with different credentials in different workspaces (personal laptop vs company monorepo).
* You can override a manifest default without forking the role.

## Scopes [#scopes]

Four scopes are merged with later-wins semantics — most-specific values take priority:

1. **Global** — applies to every agent launch.
2. **Role** — applies whenever this role is loaded.
3. **Workspace** — applies whenever this workspace is loaded.
4. **Workspace × Role** — applies only for this specific (workspace, role) cell.

Keys present in multiple scopes take the value from the highest-priority scope (4 > 3 > 2 > 1). Keys unique to any scope are preserved.

## Setting values from the CLI [#setting-values-from-the-cli]

Use `jackin config env` for global and per-role values, and `jackin workspace env` for per-workspace and per (workspace × role) values:

```bash
# Global — applies to every agent launch
jackin config env set OPERATOR_ORG "acme-corp"

# Role scope — only when loading agent-smith
jackin config env set API_TOKEN "op://Personal/acme-api/token" --role agent-smith

# Workspace scope — only when launching in big-monorepo
jackin workspace env set big-monorepo ARTIFACT_REGISTRY '${COMPANY_REGISTRY_URL}'

# Workspace × Role — most specific, wins on conflict
jackin workspace env set big-monorepo API_TOKEN "op://Work/shared-smith/token" --role agent-smith
```

Values are stored verbatim — whatever you pass is what jackin❯ resolves at launch time. List or remove values with `jackin config env list` / `jackin config env unset` (and the matching `jackin workspace env` subcommands).

## Value syntax [#value-syntax]

Each value is one of:

| Syntax                  | Resolution                                                                                                                                             |
| ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `op://VAULT/ITEM/FIELD` | Resolved via the [1Password CLI](https://developer.1password.com/docs/cli/) (`op read "<ref>"`). Requires `op` on `PATH` and an authenticated session. |
| `$NAME` or `${NAME}`    | Read from the host's environment at launch time. Errors if the host var is unset.                                                                      |
| Anything else           | Literal string.                                                                                                                                        |

When you load an agent with the example above in `big-monorepo`:

* `OPERATOR_ORG = "acme-corp"` (literal; from global)
* `API_TOKEN = <resolved via op read "op://Work/shared-smith/token">` (workspace × role wins over role layer)
* `ARTIFACT_REGISTRY = <value of $COMPANY_REGISTRY_URL on host>` (from workspace layer)

## Reserved names [#reserved-names]

A small set of names is owned by the jackin❯ runtime and cannot be set from any scope:

* `JACKIN`
* `JACKIN_DIND_HOSTNAME`
* `JACKIN_AGENT`
* `JACKIN_ROLE`
* `JACKIN_WORKDIR`
* `JACKIN_GIT_COAUTHOR_TRAILER`
* `JACKIN_GIT_DCO`
* `DOCKER_HOST`
* `DOCKER_TLS_VERIFY`
* `DOCKER_CERT_PATH`
* `TESTCONTAINERS_HOST_OVERRIDE`

Trying to set one of these is rejected before the agent launches.

`JACKIN_AGENT` is scoped to an agent session, not the whole container. jackin❯ passes the initial agent to the PID 1 multiplexer as an argv value, then sets `JACKIN_AGENT` only when spawning a real agent pane. Shell panes do not receive it.

Role identity, workspace workdir, supported agent slugs, and manifest model overrides are handed to Capsule through a generated launch config instead of being duplicated as container-wide environment variables. Runtime metadata that must be visible inside Capsule, such as `JACKIN_RUN_ID`, `JACKIN_RUN_DIAGNOSTICS_PATH`, and `JACKIN_HOST_VERSION`, is injected by jackin❯ at launch time and is not read from operator env scopes. The [Capsule reference](/reference/capsule/#how-state-moves-across-the-boundary) documents the internal handoff.

## Telemetry [#telemetry]

These variables affect host run telemetry and diagnostics capture; see [Run Telemetry](/guides/run-telemetry/) for setup examples and [Run Diagnostics](/reference/runtime/diagnostics/) for the full sink model.

| Variable                                                                            | Effect                                                                                                                                                                                                                                       |
| ----------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `OTEL_EXPORTER_OTLP_ENDPOINT`                                                       | Enables OTLP export for traces, logs, and metrics through one base gRPC endpoint. When this is active, the backend is the sink and the local run JSONL file is not written unless `JACKIN_DIAGNOSTICS_FILE=1` is also set.                   |
| `OTEL_EXPORTER_OTLP_{TRACES,LOGS,METRICS}_ENDPOINT`                                 | Overrides the endpoint per signal. jackin❯ still exports over gRPC only.                                                                                                                                                                     |
| `OTEL_EXPORTER_OTLP_PROTOCOL` / `OTEL_EXPORTER_OTLP_{TRACES,LOGS,METRICS}_PROTOCOL` | Must be `grpc` or unset when an endpoint is configured; any other value stops startup with [E016](/reference/errors/E016/).                                                                                                                  |
| `JACKIN_DEBUG`                                                                      | Backs `--debug` for verbose diagnostics and capsule debug logging. Raw PTY/frame/input payloads require the trace telemetry level.                                                                                                           |
| `JACKIN_TELEMETRY_LEVEL`                                                            | Overrides `[telemetry].level` from `config.toml`: `info` (default), `debug`, or `trace`. `debug`/`trace` enable debug-category diagnostics even when `--debug` is not set; `trace` also enables raw capsule PTY/frame/input payload records. |
| `JACKIN_TELEMETRY_CATEGORIES`                                                       | Overrides `[telemetry].categories` from `config.toml` with a comma-separated debug-category allowlist such as `docker,launch`; `*` allows every debug category. Applies before debug-category events enter JSONL or OTLP.                    |
| `JACKIN_DIAGNOSTICS_FILE`                                                           | Set to `1`, `true`, `yes`, or `on` to write the local run JSONL file even when OTLP export is active.                                                                                                                                        |
| `PARALLAX_RUN_ID`                                                                   | Supplies an external run id for jackin❯ to adopt instead of minting a six-hex id.                                                                                                                                                            |
| `OTEL_RESOURCE_ATTRIBUTES`                                                          | If it contains `parallax.run.id=<value>`, jackin❯ adopts that external run id and stamps the same value on exported telemetry.                                                                                                               |

## Host attach validation [#host-attach-validation]

`JACKIN_HOST_ATTACH=1` is an opt-in host-side launch flag. Set it on the command that starts or attaches to an instance when testing host affordances:

```bash
JACKIN_HOST_ATTACH=1 jackin load <role>
JACKIN_HOST_ATTACH=1 jackin hardline <instance>
```

With this flag, the `jackin` host process owns the interactive attach loop instead of using the in-container `docker exec -it /jackin/runtime/jackin-capsule` client. That enables explicit host actions such as clipboard image staging, GitHub PR/CI opening, and file export. See [Host Affordances](/guides/host-affordances/) for the current behavior and validation checklist.

`JACKIN_PASTE_IMAGE_PATHS` controls auto-staging of pasted host image paths under host attach. It is on by default: when a single paste's entire content is one absolute host path or `file://` URL that resolves to a real image file, jackin❯ stages the image and inserts the container path, which makes a normal `Cmd+V` paste work for screenshot tools that copy a file path. Set it to `0`, `false`, `no`, or `off` to disable that and keep every paste as ordinary text:

```bash
JACKIN_HOST_ATTACH=1 JACKIN_PASTE_IMAGE_PATHS=0 jackin load <role>
```

`JACKIN_OPEN_LINKS=deny` disables jackin❯ host browser-open actions while leaving ordinary terminal output and OSC 8 passthrough under their separate policies:

```bash
JACKIN_HOST_ATTACH=1 JACKIN_OPEN_LINKS=deny jackin load <role>
```

The same opt-out also accepts `off` and `no`. It suppresses explicit jackin❯ actions such as GitHub **Open PR**, GitHub **Open CI**, visible URL modified-click, and **Open link under cursor**; it does not rewrite agent output or block native terminal hyperlink rendering.

## Pane terminal defaults [#pane-terminal-defaults]

Every shell and agent pane receives a stable terminal capability baseline:

```text
TERM=xterm-256color
COLORTERM=truecolor
```

`TERM=xterm-256color` keeps the pane tied to a conservative terminfo entry that remains safe when a long-lived container is reattached from a different terminal app. `COLORTERM=truecolor` tells agent CLIs and TUIs that 24-bit color output is available by default. jackin❯ sets this value directly instead of copying the host's `COLORTERM`, so a pane launched from Ghostty, Kitty, iTerm, Warp, SSH, or another xterm-compatible client sees the same deterministic environment.

## 1Password CLI setup [#1password-cli-setup]

1. Install the [1Password CLI](https://developer.1password.com/docs/cli/get-started/).
2. Sign in: `eval $(op signin)` (or unlock the desktop-app integration).
3. Set values with `op://...` references — for example:

   ```bash
   jackin config env set ANTHROPIC_API_KEY "op://Personal/Anthropic/key"
   ```

Each `jackin load` that references `op://...` values shells out to `op read <ref>` per key. 1Password values are resolved concurrently, and `op` failures (missing item, expired session, binary not on PATH) are reported in a single message that names every failing key. Each launch-time `op` invocation has a 120-second timeout so cold 1Password app and daemon wakeups can finish without turning into false credential failures.

Prefer references picked through the 1Password picker in jackin❯ or otherwise backed by 1Password IDs. The 1Password CLI can resolve human-readable vault and item names, but ID-backed references are the stable and efficient form for launch-time automation. jackin❯ does not persist resolved secret values; it stores the reference metadata and asks `op` again when the value is needed.

## Launch diagnostic [#launch-diagnostic]

jackin❯ prints a compact diagnostic line on launch when operator env is non-empty, so you can confirm at a glance which keys flowed into the container:

```
[jackin] operator env: 3 resolved (2 op://, 1 host ref, 0 literal)
```

In `--debug` mode, the diagnostic expands to per-key reference strings and scope attribution. Resolved secret values are never printed.

## Interaction with manifest env [#interaction-with-manifest-env]

A role's manifest can declare env vars the role expects — including interactive prompts. Operator env is resolved first and pre-seeds matching manifest variables, so a configured value skips the manifest prompt. Manifest env fills in the remaining values, then operator env is overlaid on top: &#x2A;*operator wins on key conflict.** This lets you pin a value that the manifest would otherwise prompt for, or swap a manifest default for a workspace-specific secret.

Built-in agent credential keys stay selected-runtime scoped. If a manifest declares a sibling runtime credential such as `OPENAI_API_KEY` during a `Claude Code` launch, jackin❯ leaves that prompt/value lazy unless the selected runtime's auth mode needs that exact key. Generic manifest env vars still resolve normally.

See [Authentication Forwarding](/guides/authentication/) for the companion mechanism that forwards Claude Code credentials from host to container. Env scopes and auth forwarding are orthogonal — use both.
