# Configuration

`tj` uses TOML configuration. Run `tj onboard` to generate a starter config, or create one manually.

## Config file discovery

Config is discovered in order (first match wins):

1. `--config` flag or `TJ_CONFIG` env var
2. `tj.toml` (current directory)
3. `.tj/config.toml` (current directory)
4. `~/.config/tj/config.toml` (global)

## Full example

```toml
# .tj/config.toml — generated by tj onboard

[defaults.budget]
daily_usd = 10.00       # applies to all agents unless overridden

[agents.my-email-agent]
description = "Personal email management agent"

  [agents.my-email-agent.budget]
  daily_usd   = 5.00    # overrides the default
  session_usd = 1.00

  [[agents.my-email-agent.sensitive_actions]]
  name     = "send_email"
  severity = "critical"

  [[agents.my-email-agent.sensitive_actions]]
  name     = "delete_file"
  severity = "critical"

  [agents.my-email-agent.drift]
  enabled           = true
  baseline_sessions = 10
  token_threshold   = 2.0   # Z-score

[capture]
prompts      = false   # off by default — your data stays yours
completions  = false
tool_outputs = false

[storage]
path           = "~/.tj/telemetry.duckdb"
retention_days = 90

[security]
ingest_secret = "..."   # generated by tj onboard

[api]
host = "127.0.0.1"
port = 7391

  [api.auth]
  enabled = false         # set to true to require API key for GET endpoints
  api_key = ""

[alerts]
cooldown_seconds = 300
include_captured_content = false

  [[alerts.channels]]
  type = "ntfy"
  topic = "my-agent-alerts"

  [[alerts.channels]]
  type = "discord"
  webhook_url = "https://discord.com/api/webhooks/..."

[export]
  [export.otlp]
  endpoint = ""           # set to forward spans to an external OTel backend
  protocol = "http"            # http | grpc
```

## Budget limits

Budget limits merge per-field: each agent inherits default limits unless it explicitly overrides them.

```
effective.daily_usd   = agent.daily_usd   ?? defaults.daily_usd
effective.session_usd = agent.session_usd ?? defaults.session_usd
```

Set limits via CLI (`tj budget --daily 10`), the REST API (`POST /api/v1/budget`), or the web UI.

## Content capture and privacy

By default, `tj` does not capture prompt content, completion content, or tool inputs/outputs — only token counts, model names, tool names, timestamps, and structural metadata. Enable content capture selectively when you need it (for debugging, trim analysis, or evaluation):

```toml
[capture]
prompts      = true    # capture LLM input prompts (gen_ai.prompt.content)
completions  = true    # capture LLM output completions (gen_ai.completion.content)
tool_inputs  = true    # capture tool call inputs (gen_ai.tool.input)
tool_outputs = true    # capture tool call outputs (gen_ai.tool.output)
```

The four flags are independent: capture prompts without completions, or tool inputs without prompts. This gives finer control than a single on/off switch.

**Where the gate runs.** All spans flow through `IngestPipeline.process()`, which calls `strip_captured_content()` once before any DB write. The receiver, the OTLP HTTP endpoint, and the Claude Code JSONL backfill all go through this single gate — there's no per-source duplication.

**Precedence with alert channels.** `alerts.include_captured_content = true` lets external alert channels (webhook, Discord, Telegram, ntfy) receive full payloads. If the corresponding `[capture]` flag is `false`, the content is already stripped at ingest, so the alert flag is moot — channels can't include what was never captured. Stdout and file alert channels always receive full payloads from the in-memory span before the DB strip, so they still see content during the brief in-process window.

**What this means for downstream analyzers.**

- `tj optimize cache` reads token-count fields and works without content capture.
- `tj optimize trim` reads prompt text and requires `capture.prompts = true`.
- `tj optimize cache-recommend` reads prompts and requires `capture.prompts = true`.

The analyzers that need content fail with a clear message ("set `capture.prompts = true` in tj.toml and let the daemon collect a fresh window of data") rather than running on partial data.

## Verifying your config

Run `tj doctor` at any time to verify your configuration:

```bash
tj doctor
```

This checks config file validity, database connectivity, ingest secret presence, and alert channel reachability.
