Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/klariti-os/klariti-os/llms.txt

Use this file to discover all available pages before exploring further.

Intents and challenges are the core building blocks of Klariti. An intent is a goal bundled with rules for the Gray Engine — something you toggle on or off at any time, privately, with no deadline. A challenge is that same intent with social commitment layered on top: a deadline, friends, and a group pause condition that ties everyone’s focus sessions together. The distinction is purely UX framing. Under the hood, both are the same Challenge data shape — a solo intent is just a challenge with one participant and no ends_at value set.

The Challenge model

Every intent and challenge is stored as a single Challenge row. The following interfaces are the canonical data shapes used throughout the API:
interface Challenge {
  id: string
  creator_id: string
  name: string
  goal: "FOCUS" | "WORK" | "STUDY" | "CASUAL"
  visibility: "public" | "private"
  status: "active" | "paused" | "completed"
  ends_at?: Date           // set = time-bound; absent on solo intents
  pause_threshold?: number // 0.0–1.0, triggers group pause
  created_at: Date
  updated_at: Date
}

// One row per (challenge, user). Composite PK — a user joins once.
interface ChallengeParticipant {
  challenge_id: string
  user_id: string
  status: "active" | "paused" | "completed"
  joined_at?: Date
  created_at: Date
}

Goals

The goal field tells the Gray Engine what kind of session is active. Four values are supported:
GoalIntended use
FOCUSDeep, distraction-free work
WORKGeneral professional tasks
STUDYReading, research, coursework
CASUALLighter browsing with mild mediation

Two separate status fields

The model deliberately separates challenge-level status from participant-level status. Challenge.status describes the lifecycle of the challenge itself:
ValueMeaning
activeChallenge is running
pausedChallenge-level pause (e.g. triggered by threshold)
completedChallenge has ended
ChallengeParticipant.status describes one user’s state within the challenge:
ValueMeaning
activeUser is actively participating
pausedUser has paused their own participation
completedUser has completed the challenge
Keeping these separate prevents “paused challenge” and “paused participant” from colliding in search results, UI rendering, and automation logic.

Group pause: pause_threshold

The pause_threshold field is what turns a group challenge into an accountability mechanism with shared weight. It is a float between 0.0 and 1.0 representing the fraction of participants who must choose to pause before the challenge itself pauses for everyone. Setting pause_threshold: 0.5 means the challenge enters a group pause once at least 50% of participants have individually paused their participation. This makes stepping back a collective decision rather than a solo one.
Solo intents leave pause_threshold unset. The field is only meaningful with more than one participant.

Visibility

Challenges default to private.
VisibilityAccess
publicAny authenticated user with the challenge ID can view and join directly
privateRequires an invitation; only participants can read challenge details

Participation

Joining and leaving

POST /api/challenges/:challengeId/join
POST /api/challenges/:challengeId/leave
Public challenges accept a join request directly. Private challenges require an accepted invitation before a join call succeeds.

Updating participation status

PATCH /api/challenges/:challengeId/status
Participants can pause or resume their own participation at any time. The request body accepts { "status": "active" | "paused" }.

Challenge invitations

The challenge creator invites friends to private challenges. Each invitation is a separate row — you can invite the same person to multiple challenges independently.
POST /api/challenges/:challengeId/invitations   # creator sends invite
GET  /api/users/me/challenges/invitations        # recipient views pending invites
POST /api/challenges/invitations/:invitationId/accept
POST /api/challenges/invitations/:invitationId/decline
POST /api/challenges/invitations/:invitationId/cancel
Invitation status values:
StatusDescription
pendingSent, awaiting response
acceptedRecipient joined the challenge
declinedRecipient declined
withdrawnCreator cancelled before a response
ignoredNo action taken; treated as inactive
Accepting an invitation automatically creates a ChallengeParticipant row for the recipient. The join call handles both the invitation acceptance path and the open join path.

API surface summary

Challenges

GET /api/challenges — search public challengesPOST /api/challenges — create a challenge or intentPATCH /api/challenges/:id — update (creator only)DELETE /api/challenges/:id — delete (creator only)

Participation

POST /api/challenges/:id/joinPOST /api/challenges/:id/leavePATCH /api/challenges/:id/statusGET /api/challenges/:id/participants

My Challenges

GET /api/users/me/challenges — your active challengesGET /api/users/:userId/challenges — another user’s challenges

Invitations

POST /api/challenges/:id/invitations — invite a friendGET /api/challenges/:id/invitations — list invitations (creator)GET /api/users/me/challenges/invitations — your pending invites

Build docs developers (and LLMs) love