Exercises
Workshop-style ranking, voting, scoring, assessment, generating, and answering exercises composed onto sessions + responses.
Sprinter exercises are the OG Amble workshop primitive — ranking, voting, scoring, assessment, generating, answering — composed onto Sprinter's sessions, views, criteria_sets, and entity_responses substrate. No new tables, no new session_type. The discriminator is sessions.metadata.exercise_kind.
Spec & plan:
documents/work/2026-05-03-exercises-module/spec.mdandplan.md. PR1 ships the foundation; PR2 ships the runtime; PR5-slim ships the agent-facilitated demo.
Architecture
Facilitator (wizard surface) Participants (rank/swipe/form surface)
│ │
▼ ▼
exercise-setup wizard ──────────► Exercise (mixed session)
1. pick kind metadata.exercise_kind
2. attach criteria metadata.target_entity_ids[]
3. select target entities metadata.invited_user_ids[]
4. invite users metadata.timer
5. set timer metadata.target_view_id
│
▼
Per-user response child sessions
(session_type='response', status='draft')
│
▼
entity_responses (source='workshop')
│
▼
computeResponseAggregate / leaderboardThe diagram above is the entire module. Boxes on the right side are already-shipped Sprinter primitives — features/sessions, features/views, features/responses. The new code is the LEFT side (wizard + the kind→surface mapping + the registered tool) plus PR4's Inngest timer. Everything else is composition.
Platform-native pattern: one tool, two callers
createExercise is registered as a first-class AI tool in features/tools/exercise-tools.ts. The setup wizard's "Create" button and an in-chat agent delegation both invoke that same tool — neither uses a custom code path. The only observable downstream difference is session_events.metadata.origin:
| Caller class | role | metadata.origin | metadata.agent_slug |
|---|---|---|---|
Wizard / createExerciseAction | user | "user" | null |
| Agent in chat / heartbeat | agent | "agent" | <slug> |
This keeps humans + agents truly interchangeable. The PR5 demo ("Run a 10-minute scoring exercise on these 5 concepts with the team") is a tool-call away from PR1's foundation.
Six exercise kinds → view surfaces
| Kind | Surface | Participant action |
|---|---|---|
ranking | rank | Drag the target entity list into preferred order |
voting | swipe | Swipe / multi-select yes-no |
scoring | form | Score each entity on each criteria dimension |
assessment | form | Single-entity multi-criteria scoring |
generating | form | Open-ended brainstorm — produce new concepts |
answering | form | Free-text answers to facilitator-set questions |
The voting → swipe mapping delivers the OG Trinder pattern as a free byproduct.
PR1 surface
Shipped:
features/exercises/types.ts—EXERCISE_KINDS,ExerciseTimerSchema,ExerciseMetadataSchema,parseExerciseMetadata,EXERCISE_SURFACE_BY_KIND,assertNever.features/exercises/server/create-exercise.ts— manual-rollback transactional insert (view + session +session.createdevent).features/exercises/server/list-exercises-for-user.ts— RLS-respecting gallery filter.features/tools/exercise-tools.ts—createExerciseregistered as an AI tool withrequiredPermission: "entities.team.create".app/exercises/page.tsx— invitee gallery.app/exercises/new/page.tsx— minimal setup form (the polished 5-step wizard is the iteration-2 follow-up).
Cross-references
content/docs/features/tool-system.mdx— tool registry and dispatch.content/docs/features/sessions.mdx— session lifecycle andsession_events.content/docs/features/view-system.mdx— surface types (rank,swipe,form).content/docs/features/response-system.mdx—entity_responses, criteria sets, aggregation.
Collab Sessions
Live multi-actor state patches on top of the unified sessions primitive — no CRDT transport, no new tables.
Obsidian Interop
Bidirectional sync between the Sprinter Platform and Obsidian vaults. Covers the body field, TipTap rich editor with wikilinks, slash commands, vault import/export, and the TypeSpec runtime API.