Skip to Content
Living documentation — last reviewed 2026-05-28
FeaturesSpotter AgentSpotter Agent — Code Map

Spotter Agent — Code Map

Module wiring

  • apps/api/src/ai/ai.module.ts — registers controller, orchestrator, runtime services, tool registry, and every leaf provider. Imports the resource modules whose services the leaves call.

Controller

  • apps/api/src/ai/agent/agent.controller.ts
    • GET /organizations/:orgId/agent/usage
    • GET /organizations/:orgId/agent/conversations
    • GET /organizations/:orgId/agent/conversations/:conversationId
    • POST /organizations/:orgId/agent/messages
    • POST /organizations/:orgId/agent/conversations/:conversationId/confirm/:toolUseId
    • POST /organizations/:orgId/agent/conversations/:conversationId/confirm-batch
    • POST /organizations/:orgId/agent/conversations/:conversationId/pick/:toolUseId
    • POST /organizations/:orgId/agent/conversations/:conversationId/undo/:toolUseId

Orchestration / runtime

  • apps/api/src/ai/agent/agent.orchestrator.ts — run, resume, resumeAfterPick, driveModelLoop, tryQuickRoute (T1 Haiku router), trySeedIntent (T0), processToolUses (+ planParallelReads / runReadsConcurrently), withCachedTail, tallyUsage, finalize.
  • apps/api/src/ai/cost.util.ts — MODEL_RATES (keyed by base model id; every policy model priced, enforced by model-policy.unit.spec.ts), computeCostUsdMicros (per-model, 5m vs 1h cache-write rates). Shared with the parse module.
  • apps/api/src/ai/agent/replay-slimming.ts — slimStaleToolResults: replay-time digest of old, large tool results.
  • apps/api/src/ai/agent/agent.runtime.ts — AgentRuntime type (orgId, clerkId, user, membership, role, locale, now, pageContext, abortSignal).
  • apps/api/src/ai/agent/anthropic.client.ts — Anthropic SDK wrapper.
  • apps/api/src/ai/model-policy.ts — the model standard (ADR-0022): MODEL_POLICY (role → model + call shape; Spotter’s roles are spotterLoop, spotterQuickRoute, spotterQuickAnswer, spotterTitle, spotterCompaction), requestParams, spotterLoopCall + EARLIER_SPOTTER_LOOP_CALLS (a resumed tool call finishes on the model that made it), thinks, callToolOnly; RETIRED_MODELS. AgentOrchestrator.loopHistory picks a run’s call and replays thinking only to the model that wrote it.
  • apps/api/src/ai/agent/context-builder.service.ts — buildSystem(runtime) (static prompt plus DAY_GRAIN_PROMPT, and org block, fully stable, both cache_control 5m) and buildTurnContext (clock + page + playbook + ambient, stored on the user message).
  • apps/api/src/ai/agent/turn-context.ts — <turn_context> block helpers: wrapTurnContext, hasTurnContext, stripTurnContext, visibleText, dropAmbientFromTurnContext. The single place that knows how to tell user text from turn context.
  • apps/api/src/ai/agent/conversations.service.ts — persistence: create, listForUser, getOwn, listMessages, listMessagesForReplay, appendMessage, insertToolExecution, updateToolExecutionStatus, listToolExecutionsForMessage, hasOtherPendingForMessage, touchAfterTurn, getToolExecutionByToolUseId.
  • apps/api/src/ai/agent/rate-limit.service.ts — preCheck, getUsageSnapshot.
  • apps/api/src/ai/agent/cost-tracker.service.ts — recordTurn, getOrgSpendTodayMicros.
  • apps/api/src/ai/agent/audit.adapter.ts — bridges to audit_logs with metadata.agent: true.
  • apps/api/src/ai/agent/compaction.service.ts — generateTitleIfMissing, compactIfNeeded. Haiku-driven, time-budgeted.
  • apps/api/src/ai/agent/rag.service.ts — findAmbient, hybrid lex+semantic search across org entities.

Observability

  • apps/api/src/ai/agent/observability/agent-observability.service.ts — emit, logTurnFailure, logReplayViolation, newTraceId. Fans out to Pino + Sentry + PostHog.
  • apps/api/src/ai/agent/observability/error-classifier.ts — classifyAgentError, ReplayIntegrityError.
  • apps/api/src/ai/agent/observability/replay-validator.ts — validateReplay, validateAndRepairReplay.
  • apps/api/src/ai/agent/observability/storage-snapshot.service.ts — @ScheduledJob(…, '0 3 * * *') runSnapshot. Emits agent.storage.snapshot event.

Tool registry / runner

  • apps/api/src/ai/agent/tools/tool-registry.service.ts — discovers @AgentTool-decorated methods at onModuleInit, indexes by <router>.<action>. definitionsForRole(role) is the provider-neutral projection (role scope); toolsForRole(role) builds Anthropic tool definitions grouped by router from it, and the MCP server (docs/features/mcp-server) builds flat MCP tools from it.
  • apps/api/src/ai/agent/tools/tool-runner.service.ts — execute({ router, action, rawInput, runtime }). RBAC defence, Zod validation, handler invocation, audit write, output → resourceId extraction.
  • apps/api/src/ai/agent/tools/tool.types.ts — AgentToolMetadata (incl. mcp), ToolHandler, ToolConfirmationPreviewHandler, ToolRunResult, ToolScope, ToolAuditMeta, ToolInverseMeta, AgentToolKind.
  • apps/api/src/ai/agent/confirmation-preview.ts — strips the reserved preview key from untrusted tool input, attaches only server-resolved confirmation data, and separates it from executable input on conversation reload.
  • apps/api/src/ai/agent/tools/tool-feature-gate.service.ts — ToolFeatureGate.require(orgId, feature): leaf-side mirror of PlatformTierGuard for tools whose HTTP controllers carry @RequiresFeature (automations → email_automations; inbox and the leads bulk/pipeline admin tools → lead_management).
  • apps/api/src/ai/agent/tools/decorators.ts — @AgentTool(opts). Stores execution, confirmation-preview, audit, inverse, and routing metadata via Reflect.

Tool leaves (per router)

FileRouterActions
apps/api/src/ai/agent/tools/leaves/read.tools.tsreadget_current_context (registered, hidden from the model), programs_list, members_search, members_get, exercises_search, exercises_resolve_batch, ask_user_to_pick (user_picker), search_anything, lookup_by_id, workout_comments_in_program, workout_comments_for_assignment
apps/api/src/ai/agent/tools/leaves/workouts.tools.tsworkoutscreate (inverse: delete), update, set_sections, delete (destructive), upsert
apps/api/src/ai/agent/tools/leaves/parse.tools.tsworkoutsparse
apps/api/src/ai/agent/tools/leaves/programs.tools.tsprogramscreate (inverse: delete), update, delete (destructive), enroll_member
apps/api/src/ai/agent/tools/leaves/assignments.tools.tsassignmentsassign_personal, replace_program_day (destructive), remove_program_day (destructive), update, set_published, delete (destructive), mark_comments_read, bulk_preview, bulk_delete (destructive), bulk_publish (always), list, get, my_week, my_today, coach_overview, complete (inverse: uncomplete), uncomplete, skip, create (inverse: delete), assign_schedule (always)
apps/api/src/ai/agent/tools/leaves/bookings.tools.tsbookingslist_mine, attendance_summary, attendance_trend, attendance_daily, book (always), cancel (always), admin_cancel (always), refund_credit (always)
apps/api/src/ai/agent/tools/leaves/class-sessions.tools.tsclass_sessionslist_for_date, create (inverse: cancel), create_many (always; timetable × dates in one call), update, publish (inverse: unpublish), unpublish, cancel (destructive), bulk_preview, bulk_delete (destructive), bulk_publish (always), roster, attendance_history, qr_token, check_in (inverse: undo_check_in), undo_check_in, set_workouts (always), set_day_workouts (always), create_inline_workout, delete (destructive), copy_week (always)
apps/api/src/ai/agent/tools/leaves/class-types.tools.tsclass_typeslist_for_program
apps/api/src/ai/agent/tools/leaves/daily-programming.tools.tsdaily_programminglist_for_week, list_for_date, set (always), set_status (always), remove (destructive)
apps/api/src/ai/agent/tools/leaves/analytics.tools.tsanalyticsrevenue_summary, revenue_trend, members_summary, members_growth, at_risk_members, popular_classes, class_utilization, coach_overview, org_insights, plan_distribution, members_activation, workouts_summary
apps/api/src/ai/agent/tools/leaves/tasks.tools.tstaskslist, create (inverse: delete), update, complete, delete (destructive)
apps/api/src/ai/agent/tools/leaves/program-templates.tools.tsprogram_templateslist, get, preview, create (inverse: delete), update, duplicate (inverse: delete), upsert_cells (always), apply (always), from_history (always), delete (destructive)
apps/api/src/ai/agent/tools/leaves/forms.tools.tsformslist_pending_for_org, compliance_status_for_member, templates_list, template_get, coverage, template_create, template_update, template_publish (always), template_bump_version (always), template_set_auto_issue, template_set_required_for_booking (always), template_widen_to_plan_group (always), template_archive (destructive), template_delete (destructive), assign, assign_all_missing (always), remind (always), email_link (always), instance_archive (destructive)
apps/api/src/ai/agent/tools/leaves/memberships.tools.tsmembershipslist, stats, roster_summary, invitations_list, invite, create (always), update, bulk_invite (always), send_invitation (always), resend_invitation (always), revoke_invitation (destructive), erase (destructive)
apps/api/src/ai/agent/tools/leaves/leads.tools.tsleadslist, get, create, update, convert (always), import (always), pipelines_list, campaigns_list, add_to_pipeline, move_stage, tags_list, set_tags, archive (inverse: restore), restore, analytics, bulk_move_stage_preview, bulk_move_stage (always), bulk_add_to_pipeline (always), bulk_set_tags (always), bulk_archive (always), bulk_email (always), pipeline_create, pipeline_update, stage_add, stage_update, stage_remove (destructive), stages_reorder (always), campaign_create
apps/api/src/ai/agent/tools/leaves/inbox.tools.tsinboxlist, get, start (always), send (always), assign, set_status, mark_read
apps/api/src/ai/agent/tools/leaves/automations.tools.tsautomationslist, get, preview, create (inverse: remove), update, set_status (always), run (always), remove (destructive)
apps/api/src/ai/agent/tools/leaves/messages.tools.tsmessagessend
apps/api/src/ai/agent/tools/leaves/announcements.tools.tsannouncementscreate
apps/api/src/ai/agent/tools/leaves/help.tools.tshelpsearch
apps/api/src/ai/agent/tools/leaves/arbox.tools.tsarboxstatus (owner only, flag-gated, read only)
apps/api/src/ai/agent/tools/leaves/booking-policy.tools.tsbooking_policy, plans, membershipsbooking_policy: explain, effective, rules_list, rule_create (always), rule_update (always), rule_archive (destructive); plans: quotas_list, quotas_set (always); memberships: quota_balances. See scheduling-bookings code map.
apps/api/src/ai/agent/tools/leaves/bulk-tools.unit.spec.ts, core-tools.unit.spec.ts, leads-tools.unit.spec.ts, forms.tools.unit.spec.ts(tests)Bulk-tool semantics; TKN-305 catalog parity / confirm policy / role scope / delegation contracts; leads + forms leaf contracts.

Total: 179 tools across 20 routers, 178 offered to the model (FIT-161 phase 1 shipped 63 across 11; the leads router carries the CRM surface; TKN-305 added the members / forms / automations / scheduling / programming / inbox operations surface — 91 tools and the automations, daily_programming, inbox routers; TKN-258 added the read-only arbox router). class_sessions.copy_week is the one Spotter tool the “Build the week with Spotter” flow adds beyond what a coach could already do by hand — it materializes last week’s live sessions into this week as drafts, in one write and one confirmation card, so Spotter can act on “copy last week” without ever composing programming itself.

Tool input/output schemas

  • libs/shared/src/lib/agent-schemas/index.ts — barrel.
  • libs/shared/src/lib/agent-schemas/common.ts — AgentPageContext, AgentMessageRequest, structured AgentConfirmationPreview (resolved target/impact, complete messages, old/new changes, validated exact arguments), conversation summary / detail / loaded message / loaded tool call.
  • libs/shared/src/lib/agent-schemas/sse-events.ts — full SSE event discriminated union, including optional server-resolved confirmation impact.
  • libs/shared/src/lib/agent-schemas/tool-categories.ts — AGENT_ROUTERS, per-router *_ACTIONS enums, ToolSideEffect, ToolConfirmPolicy.
  • libs/shared/src/lib/agent-schemas/read.ts — every read.* input schema.
  • libs/shared/src/lib/agent-schemas/workouts.ts, programs.ts, assignments.ts, bookings.ts, analytics.ts, class-sessions.ts, class-types.ts, tasks.ts, forms.ts, leads.ts, memberships.ts, automations.ts, daily-programming.ts, inbox.ts, program-templates.ts — per-router input schemas.

Embeddings (supporting infra)

  • apps/api/src/ai/embeddings/embeddings.module.ts
  • apps/api/src/ai/embeddings/embedding.service.ts — Voyage voyage-multilingual-2 client.
  • apps/api/src/ai/embeddings/embedding-helper.ts
  • apps/api/src/ai/embeddings/ai-cache.service.ts — keyed by (model, input_hash), persisted to ai_cache.
  • apps/api/src/ai/embeddings/ai.controller.ts
  • apps/api/src/ai/embeddings/{workouts,programs,member-profiles}-embedding.{service,processor}.ts — domain embedding pipelines.
  • apps/api/src/ai/embeddings/exercise-enrichment.{service,processor}.ts — exercise canonicalization.

Frontend

  • apps/web/src/components/agent/agent-launcher.tsx
  • apps/web/src/components/agent/agent-sheet.tsx
  • apps/web/src/components/agent/agent-sheet-mount.tsx
  • apps/web/src/components/agent/composer.tsx
  • apps/web/src/components/agent/message-list.tsx
  • apps/web/src/components/agent/tool-call-card.tsx
  • apps/web/src/components/agent/streaming-text.tsx
  • apps/web/src/components/agent/usage-footer.tsx
  • apps/web/src/components/agent/conversation-list.tsx
  • apps/web/src/components/agent/suggested-prompts.tsx
  • apps/web/src/providers/agent-provider.tsx — state machine, SSE reducer, conversation cache.

Schema

  • libs/db/src/lib/schema/agent.ts — ai_conversations, ai_messages, ai_tool_executions, ai_usage_daily + relations.
  • libs/db/src/lib/schema/ai-cache.ts — ai_cache (embeddings + enrichment).
  • libs/db/src/lib/schema/enums.ts — aiMessageRole, aiToolStatus enums.
  • libs/db/src/lib/schema/admin.ts — audit_logs (written via AgentAuditAdapter).

Tier mapping

  • libs/shared/src/lib/constants/platform-tiers.ts — PLATFORM_TIER_MAP source of truth for aiDailyBudgetUsdMicros.

Tests

  • apps/api/src/ai/agent/tools/leaves/bulk-tools.unit.spec.ts — bulk tool semantics.
  • apps/api/src/ai/agent/tools/tool-registry.definitions.unit.spec.ts — tool-definition shape (one summary per action, stripped noise keys, fixed order, hidden tools) and per-role size ceilings over the real leaves; tools/tool-definition-stats.ts is the measuring helper.
  • apps/api/src/ai/agent/agent.orchestrator.parallel-reads.unit.spec.ts — concurrent read batches: ordering of events / rows / blocks, the concurrency bound, breaker bookkeeping, and the sequential fallback for mixed batches.
  • apps/api/src/ai/agent/agent.orchestrator.usage.unit.spec.ts — per-call cost accounting and the T1 router’s cache marker.
  • apps/api/src/ai/agent/agent.orchestrator.turn-context.unit.spec.ts, turn-context.unit.spec.ts — stored turn context: system byte-stability across runs, prefix equality, UI/preview/title/router hiding, resume and legacy conversations.
  • apps/api/src/ai/agent/tools/confirmation-target.service.ts — names approval cards (confirmationTarget specs → one org-scoped lookup); tools/confirmation-target.unit.spec.ts holds the “every confirmable tool names its card” contract.
  • apps/api/src/ai/agent/agent.orchestrator.confirm-batch.unit.spec.ts, agent.orchestrator.confirmation-target.unit.spec.ts — held siblings, batch decisions, skip-after-decline, atomic validation, loader pendingReason.
  • apps/api/src/ai/agent/replay-slimming.unit.spec.ts, apps/api/src/ai/cost.util.unit.spec.ts, apps/api/src/ai/agent/context-builder.unit.spec.ts.
  • apps/api/src/ai/agent/tools/leaves/core-tools.unit.spec.ts — TKN-305: shared-catalog ↔ decorator parity, JSON-schema renderability of every input schema, confirm policy, role scopes, tier gating, delegation.
  • apps/api/src/ai/agent/tools/leaves/class-sessions.copy-week.tools.unit.spec.ts — copy_week’s metadata contract (always confirms, staff-only, audited) and delegation to ClassSessionsService.copyWeek.
  • Per-leaf and orchestrator unit tests (where present) live colocated.