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

# Configuration

> Every shouldertap.yaml setting — organization, LLM, Slack, server, defaults, experts, and topics — plus how secrets map to environment variables.

ShoulderTap is configured by a single `shouldertap.yaml` file (generated by `shtap init`). Every command takes `--config` to point at a different path; it defaults to `shouldertap.yaml` in the current directory.

Secrets are never stored in the config. Each `*_env` key names an **environment variable** that ShoulderTap resolves at runtime, loaded from a local `.env` file (gitignored) next to the config.

## Example

```yaml shouldertap.yaml theme={null}
org:
  name: "Acme Data Team"
  timezone: "America/Los_Angeles"

llm:
  model: "claude-sonnet-4-6"
  api_key_env: "ANTHROPIC_API_KEY"

slack:
  bot_token_env: "SLACK_BOT_TOKEN"
  signing_secret_env: "SLACK_SIGNING_SECRET"

server:
  port: 8776
  api_token_env: "SHOULDERTAP_API_TOKEN"

defaults:
  escalation_after: 2h
  give_up_after: 24h
  quiet_hours: ["18:00", "09:00"]   # local time; no DMs outside, queue instead
  max_open_asks_per_expert: 3       # hard cap on concurrent unanswered asks
  max_asks_per_expert_per_day: 5    # hard daily cap

experts:
  - id: U0123ABC                     # Slack user ID
    name: Dana Kim
    topics: ["revenue metrics", "customer definitions"]
    escalation_to: U0456DEF
  - id: U0456DEF
    name: Marco Ruiz
    topics: ["revenue metrics"]

topics:
  "revenue metrics":
    fallback: U0456DEF
```

## Settings

### org

<ParamField path="org.name" type="string" required>
  Your organization's display name. Used in expert-facing messages.
</ParamField>

<ParamField path="org.timezone" type="string" default="UTC">
  IANA timezone (for example `America/Los_Angeles`). Quiet hours are evaluated in this timezone.
</ParamField>

### llm

Optional. Without it, ShoulderTap runs without an LLM: it passes an expert's reply through verbatim instead of drafting the outbound question or structuring the answer. The provider is resolved by [litellm](https://docs.litellm.ai/), so any supported model works.

<ParamField path="llm.model" type="string">
  The model id, for example `claude-sonnet-4-6`.
</ParamField>

<ParamField path="llm.api_key_env" type="string">
  Name of the environment variable holding the provider API key (for example `ANTHROPIC_API_KEY`).
</ParamField>

### slack

Optional; required only for `--transport slack`. See [Connect Slack](/run/slack).

<ParamField path="slack.bot_token_env" type="string">
  Name of the environment variable holding the Slack bot token (for example `SLACK_BOT_TOKEN`).
</ParamField>

<ParamField path="slack.signing_secret_env" type="string">
  Name of the environment variable holding the Slack signing secret (for example `SLACK_SIGNING_SECRET`).
</ParamField>

### server

<ParamField path="server.port" type="integer" default="8776">
  Port the HTTP API and approval UI listen on.
</ParamField>

<ParamField path="server.api_token_env" type="string" default="SHOULDERTAP_API_TOKEN">
  Name of the environment variable holding the static bearer token that consumers, the CLI, and the MCP server use to authenticate. See [Authentication](/api/authentication).
</ParamField>

<Warning>
  If the variable named by `server.api_token_env` is unset, the API runs with **authentication disabled** — every request is accepted. ShoulderTap logs a warning on startup. Always set the token before exposing the server beyond localhost.
</Warning>

### defaults

Fallback values the router applies to any request that doesn't set them explicitly in its `routing_policy`.

<ParamField path="defaults.escalation_after" type="duration" default="2h">
  How long to wait for a reply before re-asking the expert's `escalation_to`. Shorthand like `2h` in YAML; the wire protocol uses ISO-8601 (`PT2H`).
</ParamField>

<ParamField path="defaults.give_up_after" type="duration" default="24h">
  How long to wait across all asks before failing the request with reason `timeout`.
</ParamField>

<ParamField path="defaults.quiet_hours" type="array" default="null">
  A `[start, end]` pair of local times, for example `["18:00", "09:00"]`. No DMs are sent during quiet hours; asks are queued and sent when the window reopens. `null` disables quiet hours.
</ParamField>

<ParamField path="defaults.max_open_asks_per_expert" type="integer" default="3">
  Hard cap on how many unanswered asks an expert can have at once. Routing skips capped experts.
</ParamField>

<ParamField path="defaults.max_asks_per_expert_per_day" type="integer" default="5">
  Hard cap on asks sent to one expert in a single day. The daily count resets at the start of each day.
</ParamField>

### experts

The expert registry — an array of the humans ShoulderTap can ask. See [Experts and routing](/run/experts) for how matching works.

<ParamField path="experts[].id" type="string" required>
  The expert's Slack user ID (any string with the console transport).
</ParamField>

<ParamField path="experts[].name" type="string" required>
  Display name, used in outbound asks and in the answer's provenance.
</ParamField>

<ParamField path="experts[].topics" type="array" required>
  Topics this expert answers. Matched against a request's normalized topic.
</ParamField>

<ParamField path="experts[].escalation_to" type="string" default="null">
  The `id` of another expert to re-ask if this one doesn't reply within `escalation_after`.
</ParamField>

### topics

A map of topic name to per-topic settings.

<ParamField path="topics.<name>.fallback" type="string" default="null">
  The expert `id` to route to when no expert exactly or fuzzily matches this topic.
</ParamField>

## Secrets (`.env`)

Copy `.env.example` to `.env` and fill in the values. The variable **names** are referenced by the `*_env` keys above; the **values** live only in `.env`.

```bash .env theme={null}
# LLM provider (litellm is provider-agnostic; set whichever matches llm.model)
ANTHROPIC_API_KEY=
OPENAI_API_KEY=
GEMINI_API_KEY=

# Slack
SLACK_BOT_TOKEN=
SLACK_SIGNING_SECRET=

# HTTP API auth (the single static bearer token consumers/CLI/MCP use)
SHOULDERTAP_API_TOKEN=
```

<Note>
  `PUT /experts` rewrites the `experts:` section of `shouldertap.yaml` — the config file stays the source of truth for the registry. See the [Experts endpoint](/api/experts).
</Note>
