Skip to main content
Experts are the humans ShoulderTap asks. You define them in shouldertap.yaml, and the engine tracks live state for each — whether they’re muted, how many asks are outstanding, and how many they’ve had today. When a request arrives, the router picks the best-matched expert and the asker sends a well-formed message, subject to rate limits and quiet hours.

The registry

Each expert has an id (their Slack user ID), a name, the topics they cover, and an optional escalation target.
You can also read and replace the registry over HTTP with GET /experts and PUT /experts — but note that PUT rewrites the experts: section of shouldertap.yaml, which remains the source of truth. See the Experts endpoint.

How routing works

When a request arrives, ShoulderTap resolves an expert by trying these steps in order:
1

Target override

If the request names target_experts, routing is bypassed entirely and those experts are asked directly.
2

Exact topic match

The request’s topic is normalized (lowercased, whitespace-collapsed) and compared against each expert’s topics. Among exact matches, the request goes to the expert with the fewest open asks — a simple load balancer that spreads work across equally-qualified experts.
3

Fuzzy match

If no exact match exists, ShoulderTap falls back to token-overlap matching between the request topic and expert topics, accepting a match at 0.5 overlap or higher.
4

Topic fallback

If there’s still no match, the request routes to the fallback expert configured for that topic.
5

No expert found

If nothing matches, the request fails with reason no_expert_found.
Muted experts and experts who are currently at their rate-limit cap are skipped during matching.

The outbound ask

Every message the asker sends contains, in a fixed order that no code path can skip:
  1. Self-identification — “I’m ShoulderTap, an automated assistant.” It never pretends to be a person.
  2. Why it’s asking — the requesting consumer and the reason it’s stuck (from the request’s context.asked_because).
  3. The question — one question, drafted by the LLM (if configured) to be answerable from memory. Without an LLM, the raw question text is sent verbatim.
  4. Effort framing — “A one-or-two sentence reply here is all that’s needed.”
  5. Attribution promise — the answer will be recorded with the expert’s name as the source, after human review.
  6. Opt-out — reply mute to stop receiving asks, or skip to pass this one along.

Escalation

If an expert doesn’t reply within escalation_after (default 2 hours), ShoulderTap re-asks their configured escalation_to. The request is marked escalated, and the original expert’s open-ask count is released. If no one replies anywhere within give_up_after (default 24 hours), the request fails with reason timeout and the consumer is notified.

Rate limits and quiet hours

ShoulderTap enforces these before every send — they are not merely advisory:

Concurrent asks

max_open_asks_per_expert (default 3) caps how many unanswered asks an expert can hold at once. When all candidates are capped, the request is held rather than forced onto a busy expert.

Daily asks

max_asks_per_expert_per_day (default 5) caps asks per expert per day. The count resets at the start of each day.

Quiet hours

quiet_hours (for example ["18:00", "09:00"], evaluated in org.timezone) suppresses DMs outside working hours. Asks are queued and sent when the window reopens.

Escalation targets

A capped or muted primary is skipped in favor of the next candidate, so a busy expert never blocks a request that someone else can take.

Opt-outs: mute and skip

Experts control their own participation by replying to any ask:
  • mute — a standing preference. The expert is marked muted and receives no further asks until unmuted. Routing skips muted experts.
  • skip — a one-time pass. The current request is rerouted to the expert’s escalation target (or dropped if there’s none), and the expert’s open-ask count for it is released. Unlike mute, skip does not change their standing availability.
A mute or skip reply that arrives after a proposal has already been decided is ignored — the answer is not affected, and skip does not reroute a request that’s already resolved.