Skip to main content
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

shouldertap.yaml

Settings

org

org.name
string
required
Your organization’s display name. Used in expert-facing messages.
org.timezone
string
default:"UTC"
IANA timezone (for example America/Los_Angeles). Quiet hours are evaluated in this timezone.

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, so any supported model works.
llm.model
string
The model id, for example claude-sonnet-4-6.
llm.api_key_env
string
Name of the environment variable holding the provider API key (for example ANTHROPIC_API_KEY).

slack

Optional; required only for --transport slack. See Connect Slack.
slack.bot_token_env
string
Name of the environment variable holding the Slack bot token (for example SLACK_BOT_TOKEN).
slack.signing_secret_env
string
Name of the environment variable holding the Slack signing secret (for example SLACK_SIGNING_SECRET).

server

server.port
integer
default:"8776"
Port the HTTP API and approval UI listen on.
server.api_token_env
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.
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.

defaults

Fallback values the router applies to any request that doesn’t set them explicitly in its routing_policy.
defaults.escalation_after
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).
defaults.give_up_after
duration
default:"24h"
How long to wait across all asks before failing the request with reason timeout.
defaults.quiet_hours
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.
defaults.max_open_asks_per_expert
integer
default:"3"
Hard cap on how many unanswered asks an expert can have at once. Routing skips capped experts.
defaults.max_asks_per_expert_per_day
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.

experts

The expert registry — an array of the humans ShoulderTap can ask. See Experts and routing for how matching works.
experts[].id
string
required
The expert’s Slack user ID (any string with the console transport).
experts[].name
string
required
Display name, used in outbound asks and in the answer’s provenance.
experts[].topics
array
required
Topics this expert answers. Matched against a request’s normalized topic.
experts[].escalation_to
string
default:"null"
The id of another expert to re-ask if this one doesn’t reply within escalation_after.

topics

A map of topic name to per-topic settings.
topics.<name>.fallback
string
default:"null"
The expert id to route to when no expert exactly or fuzzily matches this topic.

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.
.env
PUT /experts rewrites the experts: section of shouldertap.yaml — the config file stays the source of truth for the registry. See the Experts endpoint.