> ## Documentation Index
> Fetch the complete documentation index at: https://docs.oktolabs.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Sprints & cards

> Reference for the 26 MCP tools that turn a validated spec into reviewable execution: sprint scope and evaluation, card lifecycle, dependencies, blockers, traceability, and board analytics.

# Sprints & cards

The execution domain. Once a spec is `validated`, work splits into sprints (logical delivery slices) and cards (single execution units). Pulse exposes **26 of its 216 MCP tools** for this stage:

* **Sprint lifecycle (8)** — create / update / move / get / get\_context / list, AI-assisted `suggest_sprints`, and `assign_tasks_to_sprint`.
* **Sprint evaluation (4)** — submit / list / get / delete sprint evaluation (the `review → closed` gate).
* **Card lifecycle (7)** — create / get / `get_task_context` / `get_task_conclusions` / update / move / delete.
* **Card dependencies (3)** — `add_card_dependency` / `remove_card_dependency` / `get_card_dependencies`.
* **Listing, blockers, analytics (4)** — `list_cards_by_status`, `list_blockers`, `get_traceability_report`, `get_analytics`.

This page covers sprint scoping, sprint quality evaluation, and the card lifecycle. The **task validation gate** (`submit_task_validation`) and the **test theater anti-pattern** (`update_test_scenario_status`) live on the [Validation gates](/reference/mcp/validation) page. Card Q\&A and comments live on [Comments & questions](/reference/mcp/comments-questions); card knowledge and attachments on [Knowledge & attachments](/reference/mcp/knowledge-attachments); copy-from-spec mockups and architecture on [Architecture & mockups](/reference/mcp/architecture-mockups).

Source-of-truth citations: `okto-pulse-feature-inventory.md:256–271` (card lifecycle), `:457–475` (sprint tools), `:395–410` (analytics + blockers + traceability), `:967–981` (status enums), `:982–1021` (governance gates).

***

## Sprint vs. card

|                  | Sprint                                                           | Card                                                                                                            |
| ---------------- | ---------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------- |
| **What it is**   | A logical delivery slice — scope + objective + expected outcome. | A single execution unit — one implementer's piece of the slice.                                                 |
| **Created from** | A `validated` spec (typically via `suggest_sprints`).            | A spec, a sprint, or directly on a board. Type is `normal` / `test` / `bug`.                                    |
| **Statuses**     | `draft → active → review → closed`                               | `not_started → started → in_progress → validation → done`; with `on_hold` / `cancelled` side states.            |
| **Hard gate**    | `submit_sprint_evaluation` before `review → closed`.             | `submit_task_validation` (independent reviewer) + conclusion + completeness + drift before `validation → done`. |

A sprint is not a time-box. It is a scope contract: "these N cards go together; close the sprint when they are validated." Sprints scope a release more than a calendar.

***

## Status flow and gates

```mermaid theme={null}
flowchart LR
  S_d([Sprint: draft]) --> S_a([active]) --> S_r([review]) --> S_c([closed])

  C_n([Card: not_started]) --> C_s([started]) --> C_p([in_progress]) --> C_v([validation]) --> C_d([done])
  C_p -.-> C_h([on_hold]) -.-> C_p
  C_p -.-> C_x([cancelled])
```

| Stage  | Transition                 | MCP tool                 | Gate                                                                                                                                                                                   |
| ------ | -------------------------- | ------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Sprint | `draft → active`           | `okto_pulse_move_sprint` | none                                                                                                                                                                                   |
| Sprint | `active → review`          | `okto_pulse_move_sprint` | none                                                                                                                                                                                   |
| Sprint | `review → closed`          | `okto_pulse_move_sprint` | `submit_sprint_evaluation` recorded; passed test scenarios re-validated                                                                                                                |
| Card   | `not_started → started`    | `okto_pulse_move_card`   | none                                                                                                                                                                                   |
| Card   | `started → in_progress`    | `okto_pulse_move_card`   | bug cards: at least one `failing` test scenario must exist (test-first gate)                                                                                                           |
| Card   | `in_progress → validation` | `okto_pulse_move_card`   | none                                                                                                                                                                                   |
| Card   | `validation → done`        | `okto_pulse_move_card`   | conclusion + completeness + drift recorded; if Task Validation Gate enabled, an independent reviewer must `submit_task_validation` — see [Validation gates](/reference/mcp/validation) |

<Note>
  Sprint **close** re-validates every test scenario marked `passed` on cards in the sprint. A scenario marked passed without the structured evidence recorded by `update_test_scenario_status` is treated as theater — sprint close fails and the scenario regresses to `pending` until evidence is supplied. See the [Validation gates](/reference/mcp/validation) page for the evidence schema.
</Note>

***

## Sprint tool index

<CardGroup cols={2}>
  <Card title="Lifecycle (6)" icon="rocket">
    `create_sprint`, `update_sprint`, `move_sprint`, `get_sprint`, `get_sprint_context`, `list_sprints`.
  </Card>

  <Card title="Suggest & assign (2)" icon="wand-magic-sparkles">
    `suggest_sprints` (AI-assisted slicing), `assign_tasks_to_sprint`.
  </Card>

  <Card title="Evaluation (4)" icon="clipboard-check">
    `submit_sprint_evaluation`, `list_sprint_evaluations`, `get_sprint_evaluation`, `delete_sprint_evaluation`.
  </Card>

  <Card title="Q&A (3)" icon="messages-question">
    `ask_sprint_question`, `answer_sprint_question`, `delete_sprint_question`. See [Comments & questions](/reference/mcp/comments-questions) for full Q\&A coverage across stages.
  </Card>
</CardGroup>

***

## Sprint lifecycle

### `okto_pulse_create_sprint`

Source: `server.py:11272`. Create a sprint under a spec. Most agents use `suggest_sprints` first and create from the suggestion's payload.

<CodeGroup>
  ```text Input theme={null}
  spec_id:          "spc_b921..."
  title:            "Sprint 1 — middleware + 429 path"
  objective:        "Wire Redis token-bucket middleware with fail-open and 429 emission."
  expected_outcome: "Burst limits enforced on /search; integration tests cover AC1, AC2, AC3."
  ```

  ```json Output theme={null}
  {
    "id": "spr_a01b...",
    "spec_id": "spc_b921...",
    "status": "draft",
    "title": "Sprint 1 — middleware + 429 path",
    "objective": "Wire Redis token-bucket middleware with fail-open and 429 emission.",
    "expected_outcome": "Burst limits enforced on /search; ...",
    "created_at": "2026-05-07T15:42:11Z"
  }
  ```
</CodeGroup>

### `okto_pulse_update_sprint`

Source: `server.py:11345`. Update sprint fields.

### `okto_pulse_move_sprint`

Source: `server.py:11426`. Advance status. The `review → closed` gate enforces sprint evaluation **and** test-scenario evidence recheck.

### `okto_pulse_get_sprint`

Source: `server.py:11472`. Get a sprint by ID.

### `okto_pulse_get_sprint_context`

Source: `server.py:11520`. Rich bundle: sprint + parent spec + all assigned cards + KG context. Use this before activating or closing a sprint.

### `okto_pulse_list_sprints`

Source: `server.py:11646`. List sprints on a board or spec.

### `okto_pulse_assign_tasks_to_sprint`

Source: `server.py:11682`. Assign one or more cards to a sprint. Cards can move between sprints (e.g. when a sprint slips, deferred cards roll forward).

<CodeGroup>
  ```text Input theme={null}
  sprint_id: "spr_a01b..."
  card_ids:  ["card_771a...", "card_88b3...", "card_ad14..."]
  ```

  ```json Output theme={null}
  {
    "sprint_id": "spr_a01b...",
    "assigned": 3,
    "cards": ["card_771a...", "card_88b3...", "card_ad14..."]
  }
  ```
</CodeGroup>

### `okto_pulse_suggest_sprints`

Source: `server.py:12128`. AI-assisted: slice a `validated` spec into one or more reviewable deliveries. Returns sprint candidates with title, objective, expected outcome, and recommended card list.

<CodeGroup>
  ```text Input theme={null}
  spec_id: "spc_b921..."
  ```

  ```json Output theme={null}
  {
    "spec_id": "spc_b921...",
    "candidates": [
      {
        "title": "Sprint 1 — middleware + 429 path",
        "objective": "Wire Redis token-bucket middleware with fail-open and 429 emission.",
        "expected_outcome": "Burst limits enforced on /search; integration tests cover AC1-AC3.",
        "recommended_cards": [
          {"title": "Implement token-bucket Redis primitive", "type": "normal", "covers": ["AC1"]},
          {"title": "Wire 429 + Retry-After response builder", "type": "normal", "covers": ["AC2"]},
          {"title": "Per-user-id keying with IP fallback",     "type": "normal", "covers": ["AC3"]}
        ]
      }
    ]
  }
  ```
</CodeGroup>

***

## Sprint evaluation

The sprint evaluation is the quality gate for `review → closed`. It captures a written retrospective with structured ratings (a sprint cannot close silently).

| Tool                                  | Line              | Description                               |
| ------------------------------------- | ----------------- | ----------------------------------------- |
| `okto_pulse_submit_sprint_evaluation` | `server.py:11724` | Submit an evaluation (rating + narrative) |
| `okto_pulse_list_sprint_evaluations`  | `server.py:11799` | List evaluations recorded on a sprint     |
| `okto_pulse_get_sprint_evaluation`    | `server.py:11831` | Get one evaluation by ID                  |
| `okto_pulse_delete_sprint_evaluation` | `server.py:11861` | Delete an evaluation                      |

<CodeGroup>
  ```text submit_sprint_evaluation — Input theme={null}
  sprint_id: "spr_a01b..."
  rating:    "good"
  narrative: "All 3 cards closed; AC1-AC3 fully covered. One card slipped to Sprint 2 due to Redis cluster auth issue (linked decision dec_e7ca already updated). No drift on the validated cards."
  ```

  ```json submit_sprint_evaluation — Output theme={null}
  {
    "id": "spe_46df...",
    "sprint_id": "spr_a01b...",
    "rating": "good",
    "narrative": "All 3 cards closed; AC1-AC3 fully covered. ...",
    "submitted_at": "2026-05-07T18:01:55Z"
  }
  ```
</CodeGroup>

***

## Card tool index

<CardGroup cols={2}>
  <Card title="Lifecycle (5)" icon="kanban">
    `create_card`, `get_card`, `update_card`, `move_card`, `delete_card`.
  </Card>

  <Card title="Context bundles (2)" icon="box-archive">
    `get_task_context` (rich pre-implementation bundle), `get_task_conclusions` (post-close summary).
  </Card>

  <Card title="Dependencies (3)" icon="link">
    `add_card_dependency`, `remove_card_dependency`, `get_card_dependencies`.
  </Card>

  <Card title="Listing & analytics (4)" icon="bar-chart">
    `list_cards_by_status`, `list_blockers`, `get_traceability_report`, `get_analytics`.
  </Card>
</CardGroup>

***

## Card lifecycle

### `okto_pulse_create_card`

Source: `server.py:1550`. Create a card. Card type controls downstream gates: `normal` (default), `test` (test scaffolding), `bug` (test-first gate).

<CodeGroup>
  ```text Input theme={null}
  board_id:  "brd_abc123"
  spec_id:   "spc_b921..."
  sprint_id: "spr_a01b..."
  type:      "normal"
  priority:  "high"
  title:     "Implement token-bucket Redis primitive"
  description: "Implement INCRBYFLOAT + EXPIRE primitive in middleware/rate_limit.py. Cover AC1 + BR br_3da7."
  ```

  ```json Output theme={null}
  {
    "id": "card_771a...",
    "board_id": "brd_abc123",
    "spec_id": "spc_b921...",
    "sprint_id": "spr_a01b...",
    "type": "normal",
    "priority": "high",
    "status": "not_started",
    "title": "Implement token-bucket Redis primitive",
    "description": "Implement INCRBYFLOAT + EXPIRE primitive in middleware/rate_limit.py. Cover AC1 + BR br_3da7.",
    "created_at": "2026-05-07T15:48:09Z"
  }
  ```
</CodeGroup>

### `okto_pulse_get_card`

Source: `server.py:1799`. Get full card details.

### `okto_pulse_get_task_context`

Source: `server.py:1880`. **The single most-called tool inside an implementation session.** Returns card + spec + business rules + test scenarios + decisions + KG context — everything an implementer agent needs to start work without re-reading the spec from scratch.

<Tip>
  Always call `get_task_context` before moving a card to `in_progress`. The KG context block surfaces decisions another agent recorded on a similar card; reading them often cuts implementation time substantially.
</Tip>

### `okto_pulse_get_task_conclusions`

Source: `server.py:2090`. Get conclusion text + completeness score (0–100) + drift score (0–100) for a card that has reached `validation` or `done`.

### `okto_pulse_update_card`

Source: `server.py:2145`. Update card fields, including `conclusion`, `completeness`, `drift`, and `bug_severity`. The conclusion fields are required before `move_card` can transition `validation → done`.

<CodeGroup>
  ```text update_card — conclusion fields example theme={null}
  card_id:      "card_771a..."
  conclusion:   "Token-bucket implemented with INCRBYFLOAT + EXPIRE. Atomic via Lua script (RT_LIMITER_INCR.lua). Fail-open path tested via Redis-down chaos test (test_rate_limit_fail_open)."
  completeness: 95
  completeness_justification: "All AC1 paths covered; one perf test (sustained 5 req/s for 10 minutes) deferred — not blocking, tracked via card_88b3 follow-up."
  drift:        10
  drift_justification: "Spec called for INCRBY; switched to INCRBYFLOAT to handle fractional refill rate (decision dec_f201 added)."
  ```

  ```json Output theme={null}
  {
    "id": "card_771a...",
    "status": "in_progress",
    "conclusion": "Token-bucket implemented with INCRBYFLOAT + EXPIRE. ...",
    "completeness": 95,
    "completeness_justification": "All AC1 paths covered; ...",
    "drift": 10,
    "drift_justification": "Spec called for INCRBY; switched to INCRBYFLOAT ...",
    "updated_at": "2026-05-07T17:14:22Z"
  }
  ```
</CodeGroup>

### `okto_pulse_move_card`

Source: `server.py:2291`. Advance card status. Forward gates are server-enforced.

### `okto_pulse_delete_card`

Source: `server.py:2396`. Permanently delete a card. Use `archive_tree` (see [Architecture & mockups](/reference/mcp/architecture-mockups)) for soft-delete.

***

## Dependencies

| Tool                                | Line             | Description                                       |
| ----------------------------------- | ---------------- | ------------------------------------------------- |
| `okto_pulse_add_card_dependency`    | `server.py:2440` | Add a `depends_on` relationship between two cards |
| `okto_pulse_remove_card_dependency` | `server.py:2477` | Remove a dependency                               |
| `okto_pulse_get_card_dependencies`  | `server.py:2503` | List blockers and dependents for a card           |

<CodeGroup>
  ```text add_card_dependency — Input theme={null}
  card_id:        "card_88b3..."
  depends_on_id:  "card_771a..."
  ```

  ```json Output theme={null}
  {
    "card_id": "card_88b3...",
    "depends_on": ["card_771a..."],
    "added_at": "2026-05-07T15:50:31Z"
  }
  ```
</CodeGroup>

A card whose `depends_on` set contains an unfinished card is reported in `list_blockers`. The card itself can still move forward if its dependencies are satisfied — this is hard data, not a hard gate.

***

## Listing, blockers, traceability, analytics

These four tools span sprints, cards, and the spec contract — they answer board-level health questions and are commonly the first calls a planning agent makes.

### `okto_pulse_list_cards_by_status`

Source: `server.py:2544`. List cards filtered by status, type, sprint, or spec.

### `okto_pulse_list_blockers`

Source: `server.py:8199`. List cards currently blocked — `status=on_hold` or with unresolved dependencies. Pulse classifies *both* shapes the same way; an agent reviewing blockers does not need to query both lists.

### `okto_pulse_get_traceability_report`

Source: `server.py:10713`. Full lineage: spec → BRs → TRs → scenarios → cards → validations. The single best call for "what evidence have we produced for this spec?" — runs entirely inside Pulse, no KG round-trip needed.

<CodeGroup>
  ```text Input theme={null}
  spec_id: "spc_b921..."
  ```

  ```json Output (truncated) theme={null}
  {
    "spec_id": "spc_b921...",
    "title": "Per-user rate limiting on /search",
    "coverage": {
      "ac_to_scenario": "3/3",
      "fr_to_br":       "2/2",
      "br_to_card":     "2/2",
      "ac_to_card":     "3/3"
    },
    "scenarios": [
      {"id": "tsc_8a1c", "title": "Burst limit returns 429 within 5ms", "status": "passed",
       "evidence": {"test_file_path": "tests/test_rate_limit.py", "test_function": "test_burst_429",
                    "last_run_at": "2026-05-07T17:01:11Z", "test_run_id": "ci_4382"}}
    ],
    "validations": [
      {"id": "tv_99c1", "card_id": "card_771a", "recommendation": "approve", "completeness": 95}
    ]
  }
  ```
</CodeGroup>

### `okto_pulse_get_analytics`

Source: `server.py:7893`. Board-level metrics: velocity (cards/sprint), quality (validation pass rate, drift average), coverage (AC → scenario %), and per-agent breakdowns.

***

## Permissions

| Action                         | Permission flag                                                 |
| ------------------------------ | --------------------------------------------------------------- |
| Create / update sprint         | `Permissions.SPRINTS_CREATE`, `Permissions.SPRINTS_UPDATE`      |
| Move sprint forward / backward | `Permissions.SPRINTS_MOVE`, `Permissions.SPRINTS_MOVE_BACKWARD` |
| Submit sprint evaluation       | `Permissions.SPRINTS_EVALUATE`                                  |
| Create / update card           | `Permissions.CARDS_CREATE`, `Permissions.CARDS_UPDATE`          |
| Move card forward / backward   | `Permissions.CARDS_MOVE`, `Permissions.CARDS_MOVE_BACKWARD`     |
| Add / remove card dependency   | `Permissions.CARDS_DEPEND`                                      |
| Delete sprint / card           | `Permissions.SPRINTS_DELETE`, `Permissions.CARDS_DELETE`        |
| Read traceability / analytics  | `Permissions.BOARD_READ`                                        |

For task validation gate permissions (`Permissions.VALIDATOR_*`), see [Validation gates](/reference/mcp/validation).

***

## Errors

```json theme={null}
{
  "error": "CONFLICT",
  "message": "Cannot move bug card to 'in_progress' — no failing test scenario linked. Add a failing scenario before starting bug work (test-first gate).",
  "detail": {"card_id": "card_bug12...", "card_type": "bug", "linked_scenarios_failing": 0}
}
```

| Code               | Most common cause                                                                                                                                              |
| ------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `VALIDATION_ERROR` | Conclusion / completeness / drift fields empty when moving `validation → done`; sprint evaluation submitted without `narrative`.                               |
| `NOT_FOUND`        | Card / sprint / dependency ID belongs to another board.                                                                                                        |
| `FORBIDDEN`        | Agent's preset does not include the required permission flag.                                                                                                  |
| `CONFLICT`         | Bug card → `in_progress` without a failing test scenario; sprint → `closed` without an evaluation; card → `done` without conclusion fields or task validation. |

***

## Next steps

<CardGroup cols={2}>
  <Card title="Validation gates" href="/reference/mcp/validation">
    `submit_task_validation`, `update_test_scenario_status` (anti-theater evidence), and the Validator preset.
  </Card>

  <Card title="Specs" href="/reference/mcp/specs">
    Author the contract a sprint and its cards execute against.
  </Card>

  <Card title="Comments & questions" href="/reference/mcp/comments-questions">
    Card Q\&A and free-form comments / choice polls.
  </Card>

  <Card title="ADLC pipeline" href="/concepts/sdlc-flow">
    Where sprints and cards sit in the end-to-end flow.
  </Card>
</CardGroup>
