# Create Agent Source: https://docs.oktolabs.ai/api-reference/agents/create-agent /openapi.json post /api/v1/agents Create a new global agent (not tied to any board). # Delete Agent Source: https://docs.oktolabs.ai/api-reference/agents/delete-agent /openapi.json delete /api/v1/agents/{agent_id} Delete an agent (owner only). # Get Agent Source: https://docs.oktolabs.ai/api-reference/agents/get-agent /openapi.json get /api/v1/agents/{agent_id} Get an agent by ID (owner only). # Grant Board Access Source: https://docs.oktolabs.ai/api-reference/agents/grant-board-access /openapi.json post /api/v1/agents/{agent_id}/boards/{board_id} Grant an agent access to a board. Requires owning both the agent and the board. # List Agents For Board Source: https://docs.oktolabs.ai/api-reference/agents/list-agents-for-board /openapi.json get /api/v1/agents/board/{board_id} List all agents with access to a board. # List My Agents Source: https://docs.oktolabs.ai/api-reference/agents/list-my-agents /openapi.json get /api/v1/agents List all agents owned by the current user (with api_key). # Regenerate Agent Key Source: https://docs.oktolabs.ai/api-reference/agents/regenerate-agent-key /openapi.json post /api/v1/agents/{agent_id}/regenerate-key Regenerate an agent's API key (owner only). # Revoke Board Access Source: https://docs.oktolabs.ai/api-reference/agents/revoke-board-access /openapi.json delete /api/v1/agents/{agent_id}/boards/{board_id} Revoke an agent's access to a board. Requires owning the agent or the board. # Update Agent Source: https://docs.oktolabs.ai/api-reference/agents/update-agent /openapi.json patch /api/v1/agents/{agent_id} Update an agent (owner only). # Update Board Overrides Source: https://docs.oktolabs.ai/api-reference/agents/update-board-overrides /openapi.json patch /api/v1/agents/{agent_id}/boards/{board_id} Update permission overrides for an agent on a board (ceiling model). # Analytics Overview Source: https://docs.oktolabs.ai/api-reference/analytics/analytics-overview /openapi.json get /api/v1/analytics/overview Cross-board KPIs: totals, lifecycle status breakdowns, validation gates, sprint summary, funnel, velocity, board list. Semântica de campos opcionais: - ``avg_triage_hours``: null quando não há bugs triados no período (sem bugs com ``linked_test_task_ids`` populado). Não é erro — indica ausência do sinal. - ``bug_rate_per_spec``: retorna apenas specs com ``rate > 0``. Specs sem bugs são omitidas da lista para reduzir o payload. - ``sprint_evaluation``: mesmo shape que ``spec_evaluation`` (inclui ``avg_dimension_scores`` — dict vazio quando nenhum sprint_evaluation carrega dimensions). # Analytics Overview Export Source: https://docs.oktolabs.ai/api-reference/analytics/analytics-overview-export /openapi.json get /api/v1/analytics/overview/export Export cross-board overview KPIs as CSV. # Board Agents Source: https://docs.oktolabs.ai/api-reference/analytics/board-agents /openapi.json get /api/v1/boards/{board_id}/analytics/agents Agent activity ranking with role-aware metrics. Groups by `created_by` (cards) plus reviewer_id (validations) so both implementers and validators show up. Emits: - total_cards, done_cards (implementer side) - avg_completeness, avg_drift (self-reported from conclusions) - task_validations_submitted, task_validation_success_rate - spec_validations_submitted, spec_validation_success_rate - first_pass_acceptance: % of own cards that passed validation on 1st try # Board Analytics Export Source: https://docs.oktolabs.ai/api-reference/analytics/board-analytics-export /openapi.json get /api/v1/boards/{board_id}/analytics/export Export board analytics (funnel, quality, velocity) as CSV. # Board Blockers Source: https://docs.oktolabs.ai/api-reference/analytics/board-blockers /openapi.json get /api/v1/boards/{board_id}/analytics/blockers Triage endpoint: every artifact blocking the funnel, classified by root cause so an agent can act directly instead of scanning each level. Categories (non-overlapping; a card can appear in multiple): - ``dependency_blocked`` — card is not_started/started while at least one of its `depends_on_id` targets has NOT reached the DONE status. - ``on_hold`` — card is explicitly paused (status=on_hold). - ``stale`` — card is in_progress/started/validation but ``now() - updated_at > stale_hours``. - ``spec_pending_validation`` — spec is approved but lacks an 'approve' validation gate (unable to promote to in_progress). - ``spec_no_cards`` — spec is validated/in_progress but has ZERO non-archived cards linked to it. - ``uncovered_scenarios`` — scenarios with no linked test cards. # Board Coverage Source: https://docs.oktolabs.ai/api-reference/analytics/board-coverage /openapi.json get /api/v1/boards/{board_id}/analytics/coverage Test coverage per spec: AC count, covered ACs, test scenario status counts. # Board Entities Source: https://docs.oktolabs.ai/api-reference/analytics/board-entities /openapi.json get /api/v1/boards/{board_id}/analytics/entities Paginated entity list with relevant metrics. When search is provided, date filters are ignored to search the entire base. # Board Entity Detail Source: https://docs.oktolabs.ai/api-reference/analytics/board-entity-detail /openapi.json get /api/v1/boards/{board_id}/analytics/entity/{entity_type}/{entity_id} Detailed analytics for a single entity. # Board Entity Detail Export Source: https://docs.oktolabs.ai/api-reference/analytics/board-entity-detail-export /openapi.json get /api/v1/boards/{board_id}/analytics/entity/{entity_type}/{entity_id}/export Export entity detail analytics as CSV. # Board Funnel Source: https://docs.oktolabs.ai/api-reference/analytics/board-funnel /openapi.json get /api/v1/boards/{board_id}/analytics/funnel Funnel for a single board: ideations -> refinements -> specs -> cards -> done. # Board Quality Source: https://docs.oktolabs.ai/api-reference/analytics/board-quality /openapi.json get /api/v1/boards/{board_id}/analytics/quality Quality scatters with dual sources: - conclusion_reported: self-reported from card.conclusions (implementer) - validation_reported: reviewer-reported from card.validations (validator) When the task validation gate is active, validation_reported is the authoritative source. Both are returned so the UI can show the delta. # Board Spec Analytics Source: https://docs.oktolabs.ai/api-reference/analytics/board-spec-analytics /openapi.json get /api/v1/boards/{board_id}/analytics/spec/{spec_id} Per-spec analytics: validation timeline, task gate summary, coverage. # Board Sprint Analytics Source: https://docs.oktolabs.ai/api-reference/analytics/board-sprint-analytics /openapi.json get /api/v1/boards/{board_id}/analytics/sprint/{sprint_id} Per-sprint analytics: kanban distribution, task gate, evaluation timeline. # Board Sprints Analytics Source: https://docs.oktolabs.ai/api-reference/analytics/board-sprints-analytics /openapi.json get /api/v1/boards/{board_id}/analytics/sprints Sprint panel for a board. Returns: - summary: counts by status + evaluation aggregate - sprints: per-sprint breakdown with cards, completion, last eval # Board Validations Source: https://docs.oktolabs.ai/api-reference/analytics/board-validations /openapi.json get /api/v1/boards/{board_id}/analytics/validations Validation Gate panel for a board. Returns: - spec_validation_gate: aggregate across all specs + per-spec breakdown - task_validation_gate: aggregate across all cards + per-card breakdown - spec_evaluation: aggregate (different gate — qualitative breakdown quality) - sprint_evaluation: aggregate # Board Velocity Source: https://docs.oktolabs.ai/api-reference/analytics/board-velocity /openapi.json get /api/v1/boards/{board_id}/analytics/velocity Velocity stacked by impl/test/bug with validation_bounce + spec_done/sprint_done overlays. Supports week or day granularity. # Copy Architecture From Spec To Card Source: https://docs.oktolabs.ai/api-reference/architecture/copy-architecture-from-spec-to-card /openapi.json post /api/v1/cards/{card_id}/copy-architecture-from-spec/{spec_id} # Create Card Architecture Source: https://docs.oktolabs.ai/api-reference/architecture/create-card-architecture /openapi.json post /api/v1/cards/{card_id}/architecture # Create Ideation Architecture Source: https://docs.oktolabs.ai/api-reference/architecture/create-ideation-architecture /openapi.json post /api/v1/ideations/{ideation_id}/architecture # Create Refinement Architecture Source: https://docs.oktolabs.ai/api-reference/architecture/create-refinement-architecture /openapi.json post /api/v1/refinements/{refinement_id}/architecture # Create Spec Architecture Source: https://docs.oktolabs.ai/api-reference/architecture/create-spec-architecture /openapi.json post /api/v1/specs/{spec_id}/architecture # Delete Architecture Design Source: https://docs.oktolabs.ai/api-reference/architecture/delete-architecture-design /openapi.json delete /api/v1/architecture/{design_id} # Get Architecture Design Source: https://docs.oktolabs.ai/api-reference/architecture/get-architecture-design /openapi.json get /api/v1/architecture/{design_id} # Get Architecture Diagram Payload Source: https://docs.oktolabs.ai/api-reference/architecture/get-architecture-diagram-payload /openapi.json get /api/v1/architecture/{design_id}/diagrams/{diagram_id}/payload # Get Architecture Diff Source: https://docs.oktolabs.ai/api-reference/architecture/get-architecture-diff /openapi.json get /api/v1/architecture/{design_id}/diff # Import Excalidraw Architecture Diagram Source: https://docs.oktolabs.ai/api-reference/architecture/import-excalidraw-architecture-diagram /openapi.json post /api/v1/architecture/{design_id}/diagrams/import-excalidraw # List Card Architecture Source: https://docs.oktolabs.ai/api-reference/architecture/list-card-architecture /openapi.json get /api/v1/cards/{card_id}/architecture # List Ideation Architecture Source: https://docs.oktolabs.ai/api-reference/architecture/list-ideation-architecture /openapi.json get /api/v1/ideations/{ideation_id}/architecture # List Refinement Architecture Source: https://docs.oktolabs.ai/api-reference/architecture/list-refinement-architecture /openapi.json get /api/v1/refinements/{refinement_id}/architecture # List Spec Architecture Source: https://docs.oktolabs.ai/api-reference/architecture/list-spec-architecture /openapi.json get /api/v1/specs/{spec_id}/architecture # Update Architecture Design Source: https://docs.oktolabs.ai/api-reference/architecture/update-architecture-design /openapi.json patch /api/v1/architecture/{design_id} # Update Architecture Diagram Payload Source: https://docs.oktolabs.ai/api-reference/architecture/update-architecture-diagram-payload /openapi.json put /api/v1/architecture/{design_id}/diagrams/{diagram_id}/payload # Validate Architecture Payload Source: https://docs.oktolabs.ai/api-reference/architecture/validate-architecture-payload /openapi.json post /api/v1/architecture/validate Return the same Architecture Design critique exposed to MCP agents. # Delete Attachment Source: https://docs.oktolabs.ai/api-reference/attachments/delete-attachment /openapi.json delete /api/v1/attachments/{board_id}/{card_id}/{attachment_id} Delete an attachment. # Download Attachment Source: https://docs.oktolabs.ai/api-reference/attachments/download-attachment /openapi.json get /api/v1/attachments/{board_id}/{card_id}/{attachment_id} Download an attachment. # Upload Attachment Source: https://docs.oktolabs.ai/api-reference/attachments/upload-attachment /openapi.json post /api/v1/attachments/{board_id}/{card_id} Upload a file attachment to a card. # Archive Tree Source: https://docs.oktolabs.ai/api-reference/boards/archive-tree /openapi.json post /api/v1/boards/{board_id}/archive/{entity_type}/{entity_id} Archive an entity and all its descendants in cascade. # Create Board Source: https://docs.oktolabs.ai/api-reference/boards/create-board /openapi.json post /api/v1/boards Create a new board. # Create Card Source: https://docs.oktolabs.ai/api-reference/boards/create-card /openapi.json post /api/v1/boards/{board_id}/cards Create a new card in a board. # Delete Board Source: https://docs.oktolabs.ai/api-reference/boards/delete-board /openapi.json delete /api/v1/boards/{board_id} Delete a board and all its cards. # Get Board Source: https://docs.oktolabs.ai/api-reference/boards/get-board /openapi.json get /api/v1/boards/{board_id} Get a board by ID with all cards and agents. # Get Board Columns Source: https://docs.oktolabs.ai/api-reference/boards/get-board-columns /openapi.json get /api/v1/boards/{board_id}/columns Get board cards grouped by status/column. # List Board Shares Source: https://docs.oktolabs.ai/api-reference/boards/list-board-shares /openapi.json get /api/v1/boards/{board_id}/shares List all shares for a board. # List Boards Source: https://docs.oktolabs.ai/api-reference/boards/list-boards /openapi.json get /api/v1/boards List boards for the current user. view: my|shared|all. # Restore Tree Source: https://docs.oktolabs.ai/api-reference/boards/restore-tree /openapi.json post /api/v1/boards/{board_id}/restore/{entity_type}/{entity_id} Restore an archived entity and all its descendants. # Revoke Board Share Source: https://docs.oktolabs.ai/api-reference/boards/revoke-board-share /openapi.json delete /api/v1/boards/{board_id}/shares/{share_id} Revoke a share (owner/admin can revoke, shared user can leave). # Share Board Source: https://docs.oktolabs.ai/api-reference/boards/share-board /openapi.json post /api/v1/boards/{board_id}/shares Share a board with another user (owner/admin only). # Update Board Source: https://docs.oktolabs.ai/api-reference/boards/update-board /openapi.json patch /api/v1/boards/{board_id} Update a board. # Update Board Share Source: https://docs.oktolabs.ai/api-reference/boards/update-board-share /openapi.json patch /api/v1/boards/{board_id}/shares/{share_id} Update a share's permission (owner/admin only). # Add Dependency Source: https://docs.oktolabs.ai/api-reference/cards/add-dependency /openapi.json post /api/v1/cards/{card_id}/dependencies/{depends_on_id} Add a dependency: card_id depends on depends_on_id. # Create Card Knowledge Source: https://docs.oktolabs.ai/api-reference/cards/create-card-knowledge /openapi.json post /api/v1/cards/{card_id}/knowledge Attach a KE to a card. # Delete Card Source: https://docs.oktolabs.ai/api-reference/cards/delete-card /openapi.json delete /api/v1/cards/{card_id} Delete a card. # Delete Card Knowledge Source: https://docs.oktolabs.ai/api-reference/cards/delete-card-knowledge /openapi.json delete /api/v1/cards/{card_id}/knowledge/{kb_id} Delete a KE from a card. # Delete Task Validation Source: https://docs.oktolabs.ai/api-reference/cards/delete-task-validation /openapi.json delete /api/v1/cards/{card_id}/validations/{validation_id} Delete a validation entry. # Download Card Knowledge Source: https://docs.oktolabs.ai/api-reference/cards/download-card-knowledge /openapi.json get /api/v1/cards/{card_id}/knowledge/{kb_id}/download Download a KE as a plain markdown file with Content-Disposition attachment. # Get Card Source: https://docs.oktolabs.ai/api-reference/cards/get-card /openapi.json get /api/v1/cards/{card_id} Get a card by ID with all attachments, Q&A, and comments. # Get Card Activity Source: https://docs.oktolabs.ai/api-reference/cards/get-card-activity /openapi.json get /api/v1/cards/{card_id}/activity Get activity log for a specific card. # Get Card Knowledge Source: https://docs.oktolabs.ai/api-reference/cards/get-card-knowledge /openapi.json get /api/v1/cards/{card_id}/knowledge/{kb_id} Get a single KE. # Get Card Seen Status Source: https://docs.oktolabs.ai/api-reference/cards/get-card-seen-status /openapi.json get /api/v1/cards/{card_id}/seen Get seen status for all items in a card (comments, QA) by agents. # Get Dependencies Source: https://docs.oktolabs.ai/api-reference/cards/get-dependencies /openapi.json get /api/v1/cards/{card_id}/dependencies Get cards this card depends on. # Get Dependents Source: https://docs.oktolabs.ai/api-reference/cards/get-dependents /openapi.json get /api/v1/cards/{card_id}/dependents Get cards that depend on this card. # Get Task Validation Source: https://docs.oktolabs.ai/api-reference/cards/get-task-validation /openapi.json get /api/v1/cards/{card_id}/validations/{validation_id} Get a single validation by ID. # Link Test Task To Bug Source: https://docs.oktolabs.ai/api-reference/cards/link-test-task-to-bug /openapi.json post /api/v1/cards/{card_id}/test-tasks Link a test task to a bug card. Validates same spec and new scenario. # List Card Knowledge Source: https://docs.oktolabs.ai/api-reference/cards/list-card-knowledge /openapi.json get /api/v1/cards/{card_id}/knowledge List all KE attached to a card. # List Task Validations Source: https://docs.oktolabs.ai/api-reference/cards/list-task-validations /openapi.json get /api/v1/cards/{card_id}/validations List all validations for a card (reverse chronological). # Move Card Source: https://docs.oktolabs.ai/api-reference/cards/move-card /openapi.json post /api/v1/cards/{card_id}/move Move a card to a different column/position. # Remove Dependency Source: https://docs.oktolabs.ai/api-reference/cards/remove-dependency /openapi.json delete /api/v1/cards/{card_id}/dependencies/{depends_on_id} Remove a dependency. # Submit Task Validation Source: https://docs.oktolabs.ai/api-reference/cards/submit-task-validation /openapi.json post /api/v1/cards/{card_id}/validate Submit a task validation for a card in 'validation' status. # Unlink Test Task From Bug Source: https://docs.oktolabs.ai/api-reference/cards/unlink-test-task-from-bug /openapi.json delete /api/v1/cards/{card_id}/test-tasks/{test_task_id} Unlink a test task from a bug card. # Update Card Source: https://docs.oktolabs.ai/api-reference/cards/update-card /openapi.json patch /api/v1/cards/{card_id} Update a card. # Update Card Knowledge Source: https://docs.oktolabs.ai/api-reference/cards/update-card-knowledge /openapi.json patch /api/v1/cards/{card_id}/knowledge/{kb_id} Update a KE in place. # Create Comment Source: https://docs.oktolabs.ai/api-reference/comments/create-comment /openapi.json post /api/v1/comments/card/{card_id} Create a new comment on a card. # Delete Comment Source: https://docs.oktolabs.ai/api-reference/comments/delete-comment /openapi.json delete /api/v1/comments/{comment_id} Delete a comment. # Respond To Choice Source: https://docs.oktolabs.ai/api-reference/comments/respond-to-choice /openapi.json post /api/v1/comments/{comment_id}/respond Respond to a choice board comment. # Update Comment Source: https://docs.oktolabs.ai/api-reference/comments/update-comment /openapi.json patch /api/v1/comments/{comment_id} Update a comment. # Get Dead Letter Source: https://docs.oktolabs.ai/api-reference/dead-letter/get-dead-letter /openapi.json get /api/v1/kg/queue/dead-letter List dead-lettered consolidation rows for a board. Returns ``{rows, total, limit, offset}``. Each row includes the full ``errors[]`` history from the TR16 schema (one entry per attempt: error_type, message, occurred_at, traceback). # Execute Discovery Intent Source: https://docs.oktolabs.ai/api-reference/discovery/execute-discovery-intent /openapi.json post /api/v1/discovery/intents/{intent_id}/execute Execute the real tool bound to an intent and return a normalized payload. Ideação a4f526df — this is what closes the "semantic fallback masking real tool" gap observed in the v1 catalog. Body shape:: {"board_id": "", "params": {"topic": "...", ...}} Missing required params listed by `intent.params_schema` yield 400 with the specific field name. Unknown tool_binding yields 400 too so drift is caught at runtime (a CI parity test is tracked in a separate ideation). # List Discovery Intents Source: https://docs.oktolabs.ai/api-reference/discovery/list-discovery-intents /openapi.json get /api/v1/discovery/intents Return the active catalog of user-facing Discovery intents. # List Saved Searches Source: https://docs.oktolabs.ai/api-reference/discovery/list-saved-searches /openapi.json get /api/v1/discovery/boards/{board_id}/saved-searches Return the saved searches for a board (shared with all members). # List Search History Source: https://docs.oktolabs.ai/api-reference/discovery/list-search-history /openapi.json get /api/v1/discovery/boards/{board_id}/search-history Return the current user's last 50 search entries on this board. # Create Guideline Source: https://docs.oktolabs.ai/api-reference/guidelines/create-guideline /openapi.json post /api/v1/guidelines Create a new guideline. # Delete Guideline Source: https://docs.oktolabs.ai/api-reference/guidelines/delete-guideline /openapi.json delete /api/v1/guidelines/{guideline_id} Delete a guideline. # Get Board Guidelines Source: https://docs.oktolabs.ai/api-reference/guidelines/get-board-guidelines /openapi.json get /api/v1/boards/{board_id}/guidelines Get all guidelines for a board (linked globals + inline), sorted by priority. # Get Guideline Source: https://docs.oktolabs.ai/api-reference/guidelines/get-guideline /openapi.json get /api/v1/guidelines/{guideline_id} Get a guideline by ID. # Link Or Create Board Guideline Source: https://docs.oktolabs.ai/api-reference/guidelines/link-or-create-board-guideline /openapi.json post /api/v1/boards/{board_id}/guidelines Link an existing guideline to a board. # List Guidelines Source: https://docs.oktolabs.ai/api-reference/guidelines/list-guidelines /openapi.json get /api/v1/guidelines List global guidelines for the current user. # Unlink Board Guideline Source: https://docs.oktolabs.ai/api-reference/guidelines/unlink-board-guideline /openapi.json delete /api/v1/boards/{board_id}/guidelines/{guideline_id} Unlink a guideline from a board. # Update Board Guideline Priority Source: https://docs.oktolabs.ai/api-reference/guidelines/update-board-guideline-priority /openapi.json patch /api/v1/boards/{board_id}/guidelines/{guideline_id} Update the priority of a linked guideline on a board. # Update Guideline Source: https://docs.oktolabs.ai/api-reference/guidelines/update-guideline /openapi.json patch /api/v1/guidelines/{guideline_id} Update a guideline. # Health Check Source: https://docs.oktolabs.ai/api-reference/health-check /openapi.json get /health # Answer Ideation Question Source: https://docs.oktolabs.ai/api-reference/ideations/answer-ideation-question /openapi.json post /api/v1/ideations/{ideation_id}/qa/{qa_id}/answer Answer an ideation Q&A question. # Create Ideation Source: https://docs.oktolabs.ai/api-reference/ideations/create-ideation /openapi.json post /api/v1/boards/{board_id}/ideations Create a new ideation in a board. # Create Ideation Question Source: https://docs.oktolabs.ai/api-reference/ideations/create-ideation-question /openapi.json post /api/v1/ideations/{ideation_id}/qa Ask a question on an ideation. # Delete Ideation Source: https://docs.oktolabs.ai/api-reference/ideations/delete-ideation /openapi.json delete /api/v1/ideations/{ideation_id} Delete an ideation. # Delete Ideation Question Source: https://docs.oktolabs.ai/api-reference/ideations/delete-ideation-question /openapi.json delete /api/v1/ideations/{ideation_id}/qa/{qa_id} Delete an ideation Q&A item. # Derive Spec Source: https://docs.oktolabs.ai/api-reference/ideations/derive-spec /openapi.json post /api/v1/ideations/{ideation_id}/derive-spec Create a spec draft from a done ideation. # Evaluate Complexity Source: https://docs.oktolabs.ai/api-reference/ideations/evaluate-complexity /openapi.json post /api/v1/ideations/{ideation_id}/evaluate Evaluate ideation complexity. Accepts scores + justifications in body. # Get Ideation Source: https://docs.oktolabs.ai/api-reference/ideations/get-ideation /openapi.json get /api/v1/ideations/{ideation_id} Get an ideation by ID with nested data. # Get Ideation Snapshot Source: https://docs.oktolabs.ai/api-reference/ideations/get-ideation-snapshot /openapi.json get /api/v1/ideations/{ideation_id}/snapshots/{version} Get a specific version snapshot of an ideation. # List Ideation History Source: https://docs.oktolabs.ai/api-reference/ideations/list-ideation-history /openapi.json get /api/v1/ideations/{ideation_id}/history Get detailed change history for an ideation. # List Ideation Qa Source: https://docs.oktolabs.ai/api-reference/ideations/list-ideation-qa /openapi.json get /api/v1/ideations/{ideation_id}/qa List all Q&A items for an ideation. # List Ideation Snapshots Source: https://docs.oktolabs.ai/api-reference/ideations/list-ideation-snapshots /openapi.json get /api/v1/ideations/{ideation_id}/snapshots List all version snapshots for an ideation. # List Ideations Source: https://docs.oktolabs.ai/api-reference/ideations/list-ideations /openapi.json get /api/v1/boards/{board_id}/ideations List ideations for a board, optionally filtered by status. # Move Ideation Source: https://docs.oktolabs.ai/api-reference/ideations/move-ideation /openapi.json post /api/v1/ideations/{ideation_id}/move Change ideation status. # Update Ideation Source: https://docs.oktolabs.ai/api-reference/ideations/update-ideation /openapi.json patch /api/v1/ideations/{ideation_id} Update an ideation. Bumps version when content fields change. # Get Kg Health Endpoint Source: https://docs.oktolabs.ai/api-reference/kg-health/get-kg-health-endpoint /openapi.json get /api/v1/kg/health Return the live KG health snapshot for ``board_id``. Compute is in-process: SQL aggregations on the app DB and per-node-type queries against the board's Kùzu graph. Kùzu errors degrade gracefully (zeros), so the endpoint stays available even when Kùzu hasn't been bootstrapped or is under a transient lock. # Run Tick Now Source: https://docs.oktolabs.ai/api-reference/kg-tick/run-tick-now /openapi.json post /api/v1/kg/tick/run-now Trigger the KG decay tick manually (idempotent — concurrent calls return 409 until the in-flight tick releases the advisory lock). Body: - ``board_id`` (optional): scope the tick to a single board. When omitted, the tick runs globally (same scope as the cron schedule). - ``force_full_rebuild`` (optional, default false): zero out ``last_recomputed_at`` for nodes in scope BEFORE the tick, forcing recompute even of fresh nodes (ignores staleness threshold). Returns 202 with tick_id immediately; the tick runs in background. Operator monitors progress via KGHealthView snapshot polling (30s). Returns 409 when the advisory lock is already held by the cron OR another manual trigger. # Boost Node Source: https://docs.oktolabs.ai/api-reference/knowledge-graph/boost-node /openapi.json post /api/v1/kg/boards/{board_id}/nodes/{node_id}/boost Increment a node's ``relevance_score`` by a fixed +0.3 with clamp [0, 1.5]. Persists an audit entry to ``ConsolidationAudit`` with event_type ``kg.node.boosted``. Idempotency is NOT enforced — each call stacks another +0.3 until the clamp is reached, by design (repeat clicks should reflect repeat intent). Responses: 200 — `{node_id, node_type, score_before, score_after, boosted_at, boosted_by}` 404 — node not found in any table of the per-board graph # Cancel Historical Endpoint Source: https://docs.oktolabs.ai/api-reference/knowledge-graph/cancel-historical-endpoint /openapi.json post /api/v1/kg/boards/{board_id}/historical-consolidation/cancel Cancel historical backfill. # Cypher Query Source: https://docs.oktolabs.ai/api-reference/knowledge-graph/cypher-query /openapi.json post /api/v1/kg/boards/{board_id}/cypher Delegate to tier power query_cypher. # Delete Board Kg Source: https://docs.oktolabs.ai/api-reference/knowledge-graph/delete-board-kg /openapi.json delete /api/v1/kg/boards/{board_id}/kg Wipe KG data for a board (right-to-erasure). # Export Audit Source: https://docs.oktolabs.ai/api-reference/knowledge-graph/export-audit /openapi.json get /api/v1/kg/boards/{board_id}/audit/export Streaming audit export as JSONL or CSV. # Find Contradictions Source: https://docs.oktolabs.ai/api-reference/knowledge-graph/find-contradictions /openapi.json get /api/v1/kg/boards/{board_id}/contradictions Find contradictions, optionally filtered by node_id. # Find Similar Source: https://docs.oktolabs.ai/api-reference/knowledge-graph/find-similar /openapi.json get /api/v1/kg/boards/{board_id}/similar Find similar decisions via semantic search. # Get Global Kg Settings Source: https://docs.oktolabs.ai/api-reference/knowledge-graph/get-global-kg-settings /openapi.json get /api/v1/kg/settings Return process-global KG settings (no board context required). Exposes the embedding-provider state so the Dashboard Settings banner and smoke-test tooling can tell stub-mode apart from a healthy load without needing to pick a board. MUST NOT trigger a model load (TR-4). # Get Kg Metrics Source: https://docs.oktolabs.ai/api-reference/knowledge-graph/get-kg-metrics /openapi.json get /api/v1/kg/boards/{board_id}/metrics Provenance metrics for the KG v0.2.0 pipeline — grouped by `layer`. Returns: - edge_count_by_layer: {deterministic, cognitive, fallback, legacy} → int - deterministic_edge_ratio, cognitive_edge_ratio, fallback_edge_ratio: float 0-1 - node_count_by_type: histogram by KG NODE_TYPES - edges_total / nodes_total Health targets (spec c48a5c33 Analysis section): - deterministic_edge_ratio ≥ 0.70 - fallback_edge_ratio ≤ 0.15 - cognitive_edge_ratio 0.15 – 0.30 in mature boards # Get Node Detail Source: https://docs.oktolabs.ai/api-reference/knowledge-graph/get-node-detail /openapi.json get /api/v1/kg/boards/{board_id}/nodes/{node_id} Get node detail across any node type in the board graph. # Get Settings Source: https://docs.oktolabs.ai/api-reference/knowledge-graph/get-settings /openapi.json get /api/v1/kg/boards/{board_id}/settings Get KG settings for a board. # Get Stats Source: https://docs.oktolabs.ai/api-reference/knowledge-graph/get-stats /openapi.json get /api/v1/kg/boards/{board_id}/stats Board KG stats: counts, confidence, pending. # Get Subgraph Source: https://docs.oktolabs.ai/api-reference/knowledge-graph/get-subgraph /openapi.json get /api/v1/kg/boards/{board_id}/graph Return subgraph for visualization — Spec 8 / S1.1, S1.4, S1.5. Pagination contract: * ``limit`` in [1, 500]; out-of-range values yield **400** (not 422) per AC-11 so clients get a human-readable reason instead of Pydantic's validation schema. * ``cursor`` is an opaque base64 token emitted by a prior call. A corrupted cursor yields **410 Gone** per AC-12 — it cannot be silently reinterpreted as "first page". * Response always carries ``next_cursor``. It is ``None`` when the returned page is the last one so clients can stop paging without a second round trip. # Get Supersedence Source: https://docs.oktolabs.ai/api-reference/knowledge-graph/get-supersedence /openapi.json get /api/v1/kg/boards/{board_id}/supersedence/{decision_id} Get supersedence chain for a decision node. # Global Search Source: https://docs.oktolabs.ai/api-reference/knowledge-graph/global-search /openapi.json get /api/v1/kg/global/search Cross-board global discovery search. For community edition, searches across all boards since auth is local-only. For production, would filter by user's accessible boards. # Historical Progress Endpoint Source: https://docs.oktolabs.ai/api-reference/knowledge-graph/historical-progress-endpoint /openapi.json get /api/v1/kg/boards/{board_id}/historical-consolidation/progress Historical consolidation progress. # List Audit Source: https://docs.oktolabs.ai/api-reference/knowledge-graph/list-audit /openapi.json get /api/v1/kg/boards/{board_id}/audit List consolidation audit entries. # List Nodes Source: https://docs.oktolabs.ai/api-reference/knowledge-graph/list-nodes /openapi.json get /api/v1/kg/boards/{board_id}/nodes List KG nodes with filters and cursor pagination. # List Pending Source: https://docs.oktolabs.ai/api-reference/knowledge-graph/list-pending /openapi.json get /api/v1/kg/boards/{board_id}/pending List pending consolidation queue entries. # List Pending Tree Source: https://docs.oktolabs.ai/api-reference/knowledge-graph/list-pending-tree /openapi.json get /api/v1/kg/boards/{board_id}/pending/tree Hierarchical pending-queue view (spec f33eb9ca — Layer 4 Pending Queue UI). Returns a 5-level tree: Ideations → Refinements → Specs → Sprints → Cards, each level annotated with aggregate status counters drawn from `consolidation_queue`. The UI renders this via `frontend/src/components/knowledge/PendingQueueTree.tsx` with lazy expansion by level (BR `Tree Lazy Fetch por Nível`). Payload shape (stable — consumed by React component): { "board_id": str, "total_pending": int, "levels": {ideations: {pending,in_progress,done,failed}, refinements: ..., specs: ..., sprints: ..., cards: ...}, "tree": [ideation-nodes with nested children] } # Openapi Spec Source: https://docs.oktolabs.ai/api-reference/knowledge-graph/openapi-spec /openapi.json get /api/v1/kg/openapi.json Auto-generated OpenAPI 3.1 spec. # Post Migrate Schema Source: https://docs.oktolabs.ai/api-reference/knowledge-graph/post-migrate-schema /openapi.json post /api/v1/kg/{board_id}/migrate-schema Force-apply schema migrations for a board (idempotent). Use when consolidation fails with `Binder exception: Cannot find property X for n` — usually means an ALTER ADD migration was missed for a board bootstrapped before that schema column was introduced. Re-runs all v0.3.x ALTER TABLE ADD on every node type. Idempotent: calling on a board already migrated returns ``migrated=true`` with ``columns_added`` empty (no-op). Spec 818748f2. # Retry Pending Entry Source: https://docs.oktolabs.ai/api-reference/knowledge-graph/retry-pending-entry /openapi.json post /api/v1/kg/boards/{board_id}/pending/{queue_entry_id}/retry Re-queue a failed/done ConsolidationQueue entry so the worker reprocesses it. `recursive=true` also re-enqueues descendants below the artifact in the Ideation→Refinement→Spec→Sprint→Card hierarchy. Idempotency: content_hash BR still owns "nothing actually changed" no-op behaviour downstream, so retrying an unchanged artifact is a cheap round-trip that touches the outbox once. # Schema Info Source: https://docs.oktolabs.ai/api-reference/knowledge-graph/schema-info /openapi.json get /api/v1/kg/schema Schema introspection. # Start Historical Source: https://docs.oktolabs.ai/api-reference/knowledge-graph/start-historical /openapi.json post /api/v1/kg/boards/{board_id}/historical-consolidation/start Start historical backfill. # Stream Kg Events Source: https://docs.oktolabs.ai/api-reference/knowledge-graph/stream-kg-events /openapi.json get /api/v1/kg/boards/{board_id}/events Server-Sent Events stream of `kg.session.committed` / `kg.board.cleared` events for the given board. The stream reads the `global_update_outbox` table for the latest events and emits new rows at a 1-second poll cadence. This endpoint is the backing data source for the React `useKgLiveEvents` hook (Frontend responsibility — hook implementation lives in the sibling UI repo). Protocol: event: kg.session.committed data: {"event_id": ..., "session_id": ..., "payload": {...}} Filter by `since` to resume a dropped connection without replaying the entire outbox backlog. Absence ⇒ start from now(). Bug fix (QueuePool exhaustion): este handler NÃO injeta mais ``db: AsyncSession = Depends(get_db)`` porque a session da request ficaria viva durante toda a vida do SSE stream (loop ``while True`` forever) — cada cliente prendia 1 conexão do pool, e um pool de 15 saturava com poucas tabs/clientes (somando consolidation_worker, outbox_worker, dispatcher e endpoints normais). Em vez disso abrimos uma sessão **por iteração** via ``async_session_factory``, devolvendo a conexão ao pool entre os ``sleep(1.0)``. # Undo Session Source: https://docs.oktolabs.ai/api-reference/knowledge-graph/undo-session /openapi.json post /api/v1/kg/boards/{board_id}/audit/{session_id}/undo Undo a consolidation session. # Update Settings Source: https://docs.oktolabs.ai/api-reference/knowledge-graph/update-settings /openapi.json put /api/v1/kg/boards/{board_id}/settings Update KG settings for a board. # Get My Permissions Source: https://docs.oktolabs.ai/api-reference/me/get-my-permissions /openapi.json get /api/v1/me/permissions Return the authenticated user's effective permission flags for a board. Flags are resolved via ``resolve_permissions(agent_flags, preset_flags, board_overrides)`` — the exact same path used by runtime permission checks. Board overrides that restrict flags (ceiling model) appear as ``False``. Legacy agents (``permissions`` column non-null, flat list) are mapped through ``map_legacy_permissions`` first. Agents with no granular data at all default to the full registry (True for everything), matching the historical "full access" compat path. # Clone Preset Source: https://docs.oktolabs.ai/api-reference/presets/clone-preset /openapi.json post /api/v1/presets/{preset_id}/clone Clone an existing preset (built-in or custom) as a new custom preset. # Create Preset Source: https://docs.oktolabs.ai/api-reference/presets/create-preset /openapi.json post /api/v1/presets Create a custom preset. # Delete Preset Source: https://docs.oktolabs.ai/api-reference/presets/delete-preset /openapi.json delete /api/v1/presets/{preset_id} Delete a custom preset. Built-in presets cannot be deleted. # List Presets Source: https://docs.oktolabs.ai/api-reference/presets/list-presets /openapi.json get /api/v1/presets List all presets: built-in + custom owned by the user. # Update Preset Source: https://docs.oktolabs.ai/api-reference/presets/update-preset /openapi.json put /api/v1/presets/{preset_id} Update a custom preset. Built-in presets cannot be modified. # Answer Question Source: https://docs.oktolabs.ai/api-reference/qa/answer-question /openapi.json post /api/v1/qa/{qa_id}/answer Answer a question. # Create Question Source: https://docs.oktolabs.ai/api-reference/qa/create-question /openapi.json post /api/v1/qa/card/{card_id} Create a new question on a card. # Delete Question Source: https://docs.oktolabs.ai/api-reference/qa/delete-question /openapi.json delete /api/v1/qa/{qa_id} Delete a Q&A item. # Get Kg Queue Health Source: https://docs.oktolabs.ai/api-reference/queue-health/get-kg-queue-health /openapi.json get /api/v1/kg/queue/health Return the live snapshot of consolidation queue health. Polled by the frontend EventQueueTab at 2s intervals (TR10). Safe to invoke at any frequency — counts are SQL aggregates and in-process sliding windows; no Kùzu I/O. # Answer Refinement Question Source: https://docs.oktolabs.ai/api-reference/refinements/answer-refinement-question /openapi.json post /api/v1/refinements/{refinement_id}/qa/{qa_id}/answer Answer a refinement Q&A question. # Create Refinement Source: https://docs.oktolabs.ai/api-reference/refinements/create-refinement /openapi.json post /api/v1/ideations/{ideation_id}/refinements Create a new refinement for a done ideation. # Create Refinement Knowledge Source: https://docs.oktolabs.ai/api-reference/refinements/create-refinement-knowledge /openapi.json post /api/v1/refinements/{refinement_id}/knowledge Create a knowledge base item on a refinement. # Create Refinement Question Source: https://docs.oktolabs.ai/api-reference/refinements/create-refinement-question /openapi.json post /api/v1/refinements/{refinement_id}/qa Ask a question on a refinement. # Delete Refinement Source: https://docs.oktolabs.ai/api-reference/refinements/delete-refinement /openapi.json delete /api/v1/refinements/{refinement_id} Delete a refinement. # Delete Refinement Knowledge Source: https://docs.oktolabs.ai/api-reference/refinements/delete-refinement-knowledge /openapi.json delete /api/v1/refinements/{refinement_id}/knowledge/{knowledge_id} Delete a knowledge base item from a refinement. # Delete Refinement Question Source: https://docs.oktolabs.ai/api-reference/refinements/delete-refinement-question /openapi.json delete /api/v1/refinements/{refinement_id}/qa/{qa_id} Delete a refinement Q&A item. # Derive Spec Source: https://docs.oktolabs.ai/api-reference/refinements/derive-spec /openapi.json post /api/v1/refinements/{refinement_id}/derive-spec Derive a spec from a refinement. # Get Refinement Source: https://docs.oktolabs.ai/api-reference/refinements/get-refinement /openapi.json get /api/v1/refinements/{refinement_id} Get a refinement by ID with nested data. # Get Refinement Knowledge Source: https://docs.oktolabs.ai/api-reference/refinements/get-refinement-knowledge /openapi.json get /api/v1/refinements/{refinement_id}/knowledge/{knowledge_id} Get a knowledge base item with full content. # Get Refinement Snapshot Source: https://docs.oktolabs.ai/api-reference/refinements/get-refinement-snapshot /openapi.json get /api/v1/refinements/{refinement_id}/snapshots/{version} Get a specific version snapshot of a refinement. # List Refinement History Source: https://docs.oktolabs.ai/api-reference/refinements/list-refinement-history /openapi.json get /api/v1/refinements/{refinement_id}/history Get detailed change history for a refinement. # List Refinement Knowledge Source: https://docs.oktolabs.ai/api-reference/refinements/list-refinement-knowledge /openapi.json get /api/v1/refinements/{refinement_id}/knowledge List all knowledge base items for a refinement. # List Refinement Qa Source: https://docs.oktolabs.ai/api-reference/refinements/list-refinement-qa /openapi.json get /api/v1/refinements/{refinement_id}/qa List all Q&A items for a refinement. # List Refinement Snapshots Source: https://docs.oktolabs.ai/api-reference/refinements/list-refinement-snapshots /openapi.json get /api/v1/refinements/{refinement_id}/snapshots List all version snapshots for a refinement. # List Refinements Source: https://docs.oktolabs.ai/api-reference/refinements/list-refinements /openapi.json get /api/v1/ideations/{ideation_id}/refinements List refinements for an ideation, optionally filtered by status. # Move Refinement Source: https://docs.oktolabs.ai/api-reference/refinements/move-refinement /openapi.json post /api/v1/refinements/{refinement_id}/move Change refinement status. # Update Refinement Source: https://docs.oktolabs.ai/api-reference/refinements/update-refinement /openapi.json patch /api/v1/refinements/{refinement_id} Update a refinement. Bumps version when content fields change. # Get Runtime Source: https://docs.oktolabs.ai/api-reference/settings/get-runtime /openapi.json get /api/v1/settings/runtime Return the currently effective runtime settings + restart flag. # Put Runtime Source: https://docs.oktolabs.ai/api-reference/settings/put-runtime /openapi.json put /api/v1/settings/runtime Persist new runtime settings. Values only take effect after restart. # Answer Spec Question Source: https://docs.oktolabs.ai/api-reference/specs/answer-spec-question /openapi.json post /api/v1/specs/{spec_id}/qa/{qa_id}/answer Answer a spec Q&A question. # Create Spec Source: https://docs.oktolabs.ai/api-reference/specs/create-spec /openapi.json post /api/v1/boards/{board_id}/specs Create a new spec in a board. # Create Spec Knowledge Source: https://docs.oktolabs.ai/api-reference/specs/create-spec-knowledge /openapi.json post /api/v1/specs/{spec_id}/knowledge Add a knowledge base item to a spec. # Create Spec Question Source: https://docs.oktolabs.ai/api-reference/specs/create-spec-question /openapi.json post /api/v1/specs/{spec_id}/qa Ask a question on a spec. # Delete Spec Source: https://docs.oktolabs.ai/api-reference/specs/delete-spec /openapi.json delete /api/v1/specs/{spec_id} Delete a spec. Unlinks derived cards but doesn't delete them. # Delete Spec Knowledge Source: https://docs.oktolabs.ai/api-reference/specs/delete-spec-knowledge /openapi.json delete /api/v1/specs/{spec_id}/knowledge/{knowledge_id} Delete a knowledge base item. # Delete Spec Question Source: https://docs.oktolabs.ai/api-reference/specs/delete-spec-question /openapi.json delete /api/v1/specs/{spec_id}/qa/{qa_id} Delete a spec Q&A item. # Get Spec Source: https://docs.oktolabs.ai/api-reference/specs/get-spec /openapi.json get /api/v1/specs/{spec_id} Get a spec by ID with its derived cards. # Get Spec Knowledge Source: https://docs.oktolabs.ai/api-reference/specs/get-spec-knowledge /openapi.json get /api/v1/specs/{spec_id}/knowledge/{knowledge_id} Get a knowledge base item with full content. # Link Card To Spec Source: https://docs.oktolabs.ai/api-reference/specs/link-card-to-spec /openapi.json post /api/v1/specs/{spec_id}/link-card/{card_id} Link an existing card to a spec. # Link Task To Scenario Source: https://docs.oktolabs.ai/api-reference/specs/link-task-to-scenario /openapi.json post /api/v1/specs/{spec_id}/scenarios/{scenario_id}/link-task/{card_id} Link a task card to a test scenario (bidirectional). Validates upfront that both scenario and card exist before mutating either side, so a typo in card_id no longer leaves an orphan link. # List Spec History Source: https://docs.oktolabs.ai/api-reference/specs/list-spec-history /openapi.json get /api/v1/specs/{spec_id}/history Get detailed change history for a spec. # List Spec Knowledge Source: https://docs.oktolabs.ai/api-reference/specs/list-spec-knowledge /openapi.json get /api/v1/specs/{spec_id}/knowledge List all knowledge base items for a spec (without content). # List Spec Qa Source: https://docs.oktolabs.ai/api-reference/specs/list-spec-qa /openapi.json get /api/v1/specs/{spec_id}/qa List all Q&A items for a spec. # List Spec Validations Source: https://docs.oktolabs.ai/api-reference/specs/list-spec-validations /openapi.json get /api/v1/specs/{spec_id}/validations List all Spec Validation Gate records in reverse chronological order. Returns current_validation_id and the validations array with an 'active' flag on each record indicating if it's the currently-active pointer. # List Specs Source: https://docs.oktolabs.ai/api-reference/specs/list-specs /openapi.json get /api/v1/boards/{board_id}/specs List specs for a board, optionally filtered by status. # Move Spec Source: https://docs.oktolabs.ai/api-reference/specs/move-spec /openapi.json post /api/v1/specs/{spec_id}/move Change spec status. # Submit Spec Validation Source: https://docs.oktolabs.ai/api-reference/specs/submit-spec-validation /openapi.json post /api/v1/specs/{spec_id}/validation Submit a Spec Validation Gate record for a spec in 'approved' status. Runs deterministic coverage gates as pre-requisite. If they pass, computes outcome from thresholds + recommendation: failed if any threshold violated or recommendation=reject; success only if all thresholds OK and approve. On success, atomically promotes spec.status to validated. # Unlink Card From Spec Source: https://docs.oktolabs.ai/api-reference/specs/unlink-card-from-spec /openapi.json post /api/v1/specs/{spec_id}/unlink-card/{card_id} Unlink a card from a spec. # Unlink Task From Scenario Source: https://docs.oktolabs.ai/api-reference/specs/unlink-task-from-scenario /openapi.json post /api/v1/specs/{spec_id}/scenarios/{scenario_id}/unlink-task/{card_id} Unlink a task card from a test scenario (bidirectional). # Update Spec Source: https://docs.oktolabs.ai/api-reference/specs/update-spec /openapi.json patch /api/v1/specs/{spec_id} Update a spec. Bumps version when content fields change. Rejects orphan `linked_*` references with 422 — see `_validate_spec_linked_refs` in services/main.py for the exact rules. # Assign Tasks Source: https://docs.oktolabs.ai/api-reference/sprints/assign-tasks /openapi.json post /api/v1/sprints/{sprint_id}/assign-tasks Assign cards to a sprint. Cards must belong to the same spec. # Create Sprint Source: https://docs.oktolabs.ai/api-reference/sprints/create-sprint /openapi.json post /api/v1/boards/{board_id}/specs/{spec_id}/sprints Create a new sprint for a spec. # Delete Sprint Source: https://docs.oktolabs.ai/api-reference/sprints/delete-sprint /openapi.json delete /api/v1/sprints/{sprint_id} Delete a sprint. # Get Sprint Source: https://docs.oktolabs.ai/api-reference/sprints/get-sprint /openapi.json get /api/v1/sprints/{sprint_id} Get a sprint by ID with full details. # List Board Sprints Source: https://docs.oktolabs.ai/api-reference/sprints/list-board-sprints /openapi.json get /api/v1/boards/{board_id}/sprints List all sprints for a board, optionally filtered by status and/or spec. # List History Source: https://docs.oktolabs.ai/api-reference/sprints/list-history /openapi.json get /api/v1/sprints/{sprint_id}/history List sprint history. # List Sprints Source: https://docs.oktolabs.ai/api-reference/sprints/list-sprints /openapi.json get /api/v1/boards/{board_id}/specs/{spec_id}/sprints List sprints for a spec. # Move Sprint Source: https://docs.oktolabs.ai/api-reference/sprints/move-sprint /openapi.json post /api/v1/sprints/{sprint_id}/move Move a sprint to a different status. # Submit Evaluation Source: https://docs.oktolabs.ai/api-reference/sprints/submit-evaluation /openapi.json post /api/v1/sprints/{sprint_id}/evaluations Submit an evaluation for a sprint. # Suggest Sprints Source: https://docs.oktolabs.ai/api-reference/sprints/suggest-sprints /openapi.json get /api/v1/boards/{board_id}/specs/{spec_id}/sprints/suggest Suggest sprint breakdown for a spec. # Unassign Tasks Source: https://docs.oktolabs.ai/api-reference/sprints/unassign-tasks /openapi.json post /api/v1/sprints/{sprint_id}/unassign-tasks Remove cards from a sprint (set sprint_id to null). # Update Sprint Source: https://docs.oktolabs.ai/api-reference/sprints/update-sprint /openapi.json patch /api/v1/sprints/{sprint_id} Update a sprint. # Get Lineage Graph Source: https://docs.oktolabs.ai/api-reference/traceability/get-lineage-graph /openapi.json get /api/v1/boards/{board_id}/lineage-graph Return a UI-only SDLC lineage graph rooted at the selected entity. # Agents and permissions Source: https://docs.oktolabs.ai/concepts/agents How Pulse agents, board roles, and granular permissions fit together. # Agents and permissions You can use agents to divide ownership across spec writing, implementation, validation, QA, and reporting. Permissions make that division enforceable at the tool layer. ## What is an agent in Pulse An agent is an API-key-backed identity with a name, objective, description, active flag, board access, and resolved permission set. The MCP server authenticates the key and checks permissions before executing tools. ## The permission model Pulse uses dotted granular flags such as `spec.move.draft_to_review`, `card.validation.submit`, and `kg.query.decision_history`. The current registry contains 270 enabled leaf flags in source. ## Five built-in presets The core operating roles are: | Preset | Use it for | | ------------ | ------------------------------------------------------------------------- | | Full Control | Solo or trusted admin work. | | Spec | Ideation, refinement, spec content, sprint planning, and card breakdown. | | Executor | Normal card implementation through `validation`, without gate submission. | | QA | Test scenarios and test card lifecycle. | | Validator | Spec, sprint, and task gates. | The source also includes Reporter and Sprint Manager presets for read-heavy and sprint-owner roles. ## Board roles vs agent-level flags Agent-level flags define the maximum capability. Board-level overrides restrict that capability on a specific board; they do not expand it. This ceiling model prevents a board override from turning a narrow agent into a broader one. ## Managing agents Use the web UI for day-to-day setup. Use the CLI to export MCP config after agents exist: ```bash theme={null} okto-pulse init --agents ``` ```text theme={null} Wrote .mcp.json with MCP server entries for available agents. ``` ## Related pages * [Permission model](/permissions/model) * [Built-in presets](/permissions/presets) * [Connect your agent](/connect-agent) # Cards Source: https://docs.oktolabs.ai/concepts/card The Pulse work unit: implementation, bug, and test cards with validation evidence. # Cards You can use cards as the executable work units in Pulse. A card carries status, owner, dependencies, links back to spec evidence, comments, Q\&A, attachments, conclusions, and validation records. ## What is a card A card is the smallest delivery object an agent should implement or validate. Cards can be created directly, derived from specs, assigned to sprints, and linked to spec evidence. ## Card types | Type | Use it for | | -------- | ---------------------------------------------------------------------------------------- | | `normal` | Standard implementation work. | | `test` | Test-only work. Test cards can bypass the normal task validation gate. | | `bug` | A defect. Bug cards require bug-specific fields and should preserve root-cause learning. | ## Bug card specifics Bug severity is explicit: `blocker`, `critical`, `major`, `minor`, or `trivial`. A bug card should include reproduction steps, expected behavior, actual behavior, suspected area, and a failing test scenario before moving into implementation. ## States | State | Meaning | | ------------- | -------------------------------- | | `not_started` | Ready but not picked up. | | `started` | Claimed or started. | | `in_progress` | Active implementation. | | `validation` | Waiting for reviewer validation. | | `on_hold` | Blocked or intentionally paused. | | `done` | Complete. | | `cancelled` | Should not proceed. | The normal gated path is `not_started -> started -> in_progress -> validation -> done`. ## Card priority Use priority to communicate sequencing pressure, not importance theater. Supported values are `critical`, `high`, `medium`, and `low`. ## Card knowledge, mockups, and architecture Cards can copy knowledge, Q\&A, mockups, and architecture from the spec or attach their own. Copy from spec when the context is already approved. Attach directly when the implementation discovers card-specific evidence. ## Dependencies between cards Use dependencies when one card cannot be completed until another lands. Dependencies should be concrete: API exists, schema migrated, test fixture added, deployment flag available. ## Task conclusions Before a normal card can move into validation, the implementer must supply an execution conclusion: completeness `0-100`, drift `0-100`, and written justification. This turns the handoff into evidence rather than a status flip. ## Validation records Task validation is append-only. `okto_pulse_submit_task_validation` checks confidence, completeness, drift, and threshold violations, then routes the card to `done` or keeps it in `validation`. ## Traceability Use traceability links so a card can prove what it implements: ```text theme={null} okto_pulse_link_task_to_scenario okto_pulse_link_task_to_rule okto_pulse_link_task_to_contract okto_pulse_link_task_to_tr ``` ## Related pages * [Validation gates](/concepts/validation) * [Sprints and cards tools](/reference/mcp/sprints-cards) * [Card and KG flags](/permissions/card-kg) # Decisions Source: https://docs.oktolabs.ai/concepts/decisions How Pulse records design choices and keeps their history queryable. # Decisions You can use Decisions to preserve why a spec chose one path over another. Requirements say what must happen; Decisions explain the choice, alternatives, rationale, and supersedence chain. ## What is a decision in Pulse A Decision is a formal design choice on a spec. It has a title, rationale, alternatives, criteria, linked requirements, and optional `supersedes_decision_id` for replacement. ## How decisions feed the KG When specs consolidate into the Knowledge Graph, Decisions become `Decision` nodes. Related alternatives, constraints, entities, and learnings can connect to them. This lets future agents retrieve prior rationale instead of rediscovering it in chat. ## Recording a decision on a spec Use the decision tools when the team picks an architecture, data model, API shape, permission rule, deployment strategy, or validation threshold. ```text theme={null} okto_pulse_add_decision okto_pulse_update_decision okto_pulse_remove_decision ``` ## Supersedence Do not overwrite an old Decision when the choice changes. Create or update the new Decision with `supersedes_decision_id` so the old one becomes part of the chain. ## Querying decisions later Use KG tools to recover the chain: ```text theme={null} okto_pulse_kg_get_decision_history okto_pulse_kg_find_similar_decisions okto_pulse_kg_get_supersedence_chain ``` ## Related pages * [Knowledge Graph](/concepts/knowledge-graph) * [Spec](/concepts/spec) * [KG decision history guide](/guides/kg-decisions) * [KG queries](/reference/mcp/kg/queries) # Ideation Source: https://docs.oktolabs.ai/concepts/ideation How Pulse turns an early idea into a scored, refined input for specs. # Ideation You can use an ideation when a feature is still ambiguous and needs structured questioning before it becomes a spec. The ideation stage holds the early title, problem statement, notes, Q\&A, mockups, architecture diagrams, and evaluation history that will later feed spec drafting. ## What is an ideation An ideation is the first Pulse artifact in the ADLC pipeline. It captures a product or engineering intent before the team commits to requirements. Use it when the work still has open questions about scope, users, constraints, tradeoffs, or expected behavior. Do not skip ideation for broad work. A direct spec is fine for a small mechanical change, but larger work benefits from the ambiguity-killer loop because the questions and answers become durable context instead of chat history. ## States and gates | State | Meaning | Typical next move | | ------------ | --------------------------------------------------------------------- | ---------------------------------------------------- | | `draft` | The idea exists but has not been interrogated. | Ask questions or move to `evaluating`. | | `evaluating` | The agent is checking ambiguity, confidence, and missing constraints. | Answer Q\&A and call `okto_pulse_evaluate_ideation`. | | `refined` | The idea is clear enough to feed a spec or refinement. | Derive a spec or continue into refinement. | | `done` | The ideation has served its purpose. | Keep it as history. | | `cancelled` | The idea should not proceed. | Archive or leave as a record. | The main gate is the evaluation result. If `okto_pulse_evaluate_ideation` still reports unresolved ambiguity, keep asking and answering before deriving a spec. ## The ambiguity-killer protocol The ambiguity-killer loop is a short cycle: 1. The agent reads the ideation context. 2. The agent asks targeted free-form or choice questions. 3. The human or another agent answers. 4. The agent evaluates the ideation. 5. The ideation moves to `refined` only when the remaining ambiguity is acceptable. ```text theme={null} okto_pulse_ask_ideation_question okto_pulse_answer_ideation_question okto_pulse_evaluate_ideation okto_pulse_move_ideation ``` Treat the evaluation as a gate, not as prose feedback. A low-confidence result means the next action is more Q\&A or narrower scope, not spec generation. ## Knowledge and mockups Attach source material at ideation time when it explains the problem: screenshots, short notes, customer examples, existing code references, or design sketches. Ideation knowledge can be listed, opened, and removed through the ideation knowledge tools. Mockups belong here when the user experience is still exploratory. Attach them early so downstream spec and card work can copy the artifact rather than relying on a chat transcript. ## Architecture diagrams Ideation architecture diagrams are useful when the idea touches system shape: service boundaries, event flow, API ownership, or data model changes. Create or import the diagram during ideation, then render it when the team needs a visual checkpoint. ## Deriving a spec from an ideation `okto_pulse_derive_spec_from_ideation` creates a spec from the refined idea. The derived spec should carry the problem, accepted constraints, Q\&A decisions, knowledge links, mockups, and architecture context forward. ```text theme={null} okto_pulse_derive_spec_from_ideation(board_id="...", ideation_id="...") ``` Use refinement first when the idea needs deeper investigation before requirements are written. ## Versioning and history Pulse keeps ideation history and snapshots so an agent can answer: what changed, who changed it, and why the later spec contains a particular requirement. Use `okto_pulse_get_ideation_history` and snapshot tools before overwriting a contested idea. ## Related pages * [The ADLC pipeline](/concepts/sdlc-flow) * [Spec](/concepts/spec) * [Ideation and refinement tools](/reference/mcp/ideation-refinement) * [Ideation flags](/permissions/ideation) # Knowledge Graph Source: https://docs.oktolabs.ai/concepts/knowledge-graph How Pulse persists decisions, constraints, and learnings across sessions, sprints, and agent changes — so the agent remembers what you decided, even after the chat ends. # Knowledge Graph Chat context resets every session. The Knowledge Graph does not. Every decision, constraint, bug learning, and spec outcome consolidates into a per-board embedded graph database. When your agent starts work on a new ideation, it queries this graph before deciding anything. It finds prior decisions, detects contradictions, and traces supersedence chains — not from memory, from a durable graph. *** ## The problem it solves When you build with AI agents across multiple sessions, three failure modes appear quickly: 1. **Lost decisions.** The agent re-decides something you already locked down two sprints ago, because the earlier decision only lives in a closed chat thread. 2. **Contradictions without notice.** A new spec requirement silently violates a constraint established in a different spec. Nobody catches it until something breaks. 3. **Supersedence drift.** You change an architectural decision. The agent keeps applying the old rule because it was never marked as superseded. The Knowledge Graph is the structural fix for all three. *** ## How it works Each Pulse board has an embedded graph database stored at: ```text theme={null} ~/.okto-pulse/boards/{board_id}/graph.lbug ``` A global discovery index spans all boards: ```text theme={null} ~/.okto-pulse/global/discovery.lbug ``` The graph is written by the KG consolidation pipeline — a background worker that takes artifacts from the SQLite queue and materializes them as typed nodes and edges. Agents interact with the KG via 26 dedicated MCP tools, not by writing to the graph directly. *** ## Node types The graph has 11 typed node types: | Node type | What it holds | | -------------- | ---------------------------------------------------------------- | | `Decision` | A locked design or architectural choice, with rationale | | `Criterion` | An evaluation axis used to make a decision | | `Constraint` | A hard boundary the implementation must not cross | | `Assumption` | A condition assumed true at decision time | | `Requirement` | A functional or non-functional requirement | | `Entity` | A named domain concept (service, model, user type, etc.) | | `APIContract` | A contract between components: endpoints, payloads, error shapes | | `TestScenario` | A scenario with evidence of pass/fail, linked to source code | | `Bug` | A defect with root cause and resolution | | `Learning` | A lesson from a bug, failed experiment, or retrospective | | `Alternative` | A rejected option, with the reason it was not chosen | *** ## Relationship types 10 typed edge types connect nodes: | Edge | Meaning | | -------------- | ------------------------------------------------------------------------------------------------ | | `supersedes` | This node replaces an earlier one. The old node is not deleted — the chain is preserved. | | `contradicts` | These two nodes are in tension. Contradiction detection surfaces this before the agent proceeds. | | `derives_from` | This node was derived from another (spec from ideation, decision from constraint, etc.) | | `relates_to` | General association | | `mentions` | A node references another in its content | | `depends_on` | This node cannot be implemented without the other | | `violates` | An implementation or decision crosses a stated constraint | | `implements` | A task or code path implements this requirement or contract | | `tests` | A test scenario validates this requirement or contract | | `validates` | A validation record confirms this node passed its evidence gate | *** ## What the agent does with it At every ideation and refinement, the agent is expected to query the KG before making decisions. The MCP tools it uses: ```text theme={null} okto_pulse_kg_query_natural Ask a natural-language question against the graph okto_pulse_kg_find_similar_decisions Surface decisions that are semantically close okto_pulse_kg_find_contradictions Detect edges between the current context and existing nodes okto_pulse_kg_get_supersedence_chain Trace what replaced what, in order okto_pulse_kg_get_related_context Pull the subgraph around a named entity okto_pulse_kg_explain_constraint Get the rationale behind a constraint node ``` When the agent finds a prior decision that applies, it cites it. When it finds a contradiction, it surfaces it to the user before proceeding. When it detects that a decision was superseded, it uses the current node, not the stale one. *** ## Consolidation — how nodes get in Agents do not write directly to the graph. They create artifacts in the standard Pulse pipeline (decisions, specs, validation records, bug conclusions). The consolidation pipeline picks those up from a SQLite queue and writes them to the graph as typed nodes. The typical consolidation flow: 1. Agent completes a spec evaluation or task validation. 2. The core service writes a consolidation record to the queue. 3. The background worker calls `kg_begin_consolidation` → adds node and edge candidates → `kg_commit_consolidation`. 4. The node is now queryable. Agents with direct KG access can also run explicit consolidation via: ```text theme={null} okto_pulse_kg_begin_consolidation okto_pulse_kg_add_node_candidate okto_pulse_kg_add_edge_candidate okto_pulse_kg_commit_consolidation ``` *** ## Health and diagnostics The KG exposes a health view in the Pulse board UI (polls every 30 seconds) and via MCP: ```text theme={null} okto_pulse_kg_health ``` This returns queue depth, oldest pending age, dead-letter count, decay tick freshness, and relevance score health. If consolidation is stuck: ```text theme={null} okto_pulse_kg_dead_letter_list See what failed to consolidate okto_pulse_kg_dead_letter_reprocess Retry failed items okto_pulse_kg_tick_run_now Trigger the decay tick immediately ``` For deeper repair, the CLI provides: ```bash theme={null} okto-pulse kg backfill dry run okto-pulse kg backfill --apply enqueue and drain okto-pulse kg dedup-entities --dry-run ``` Do not delete `graph.lbug` files to fix KG issues. Use the health and backfill tools above. Deleting the graph loses all decision history for that board. *** ## Summary The Knowledge Graph is the layer that makes multi-session, multi-agent work coherent. Chat resets. The graph does not. Decisions, constraints, and learnings written today are queryable by any agent working on the same board tomorrow — or in three months, after a team change, after a model upgrade. It is the reason Pulse calls itself a control plane rather than a kanban board. *** ## Next steps How the six stages from Ideation to Validation feed the KG. Connect your agent to start using KG tools in sessions. # The ADLC pipeline Source: https://docs.oktolabs.ai/concepts/pipeline The six stages Pulse enforces: Ideation → Refinement → Spec → Sprint → Tasks → Validation. # The ADLC pipeline The Pulse pipeline runs in six enforced stages. Each stage has a gate — the agent cannot advance until the gate condition is met. ```text theme={null} Ideation → Refinement → Spec → Sprint → Tasks → Validation ``` A full walkthrough is in the [quickstart](/quickstart). The complete stage-by-stage reference is in [ADLC pipeline concepts](/concepts/sdlc-flow). # Refinement Source: https://docs.oktolabs.ai/concepts/refinement When and how to use Pulse refinement before a spec is locked. # Refinement You can use refinement when an ideation is promising but still needs investigation before it becomes a spec. Refinement is the deeper research stage between early idea and committed contract. ## What is a refinement and when to use it A refinement is a structured investigation artifact. Use it when the team needs to inspect code paths, validate feasibility, collect constraints, compare options, or resolve dependencies before spec drafting. Use refinement instead of going straight from ideation to spec when the work crosses module boundaries, affects data storage, changes permissions, or depends on a behavior that must be proven in source. ## States | State | Meaning | | ------------- | -------------------------------------------------------------- | | `draft` | Investigation exists but has not started. | | `in_progress` | The agent is collecting evidence and answering open questions. | | `review` | Findings are ready for review. | | `approved` | The investigation is accepted and can feed a spec. | | `done` | Refinement is complete. | | `cancelled` | The investigation should stop. | ## Deep investigation protocol Refinement should produce evidence, not just a better-written idea. A useful refinement answers: * Which source files, APIs, routes, data models, or deployment constraints matter? * Which assumptions were checked and which remain open? * Which choices were rejected and why? * What risk changes the spec or implementation plan? ```text theme={null} okto_pulse_create_refinement okto_pulse_get_refinement_context okto_pulse_move_refinement okto_pulse_get_refinement_history ``` ## Knowledge, mockups, and architecture Refinement can carry the same supporting artifacts as ideation: knowledge, mockups, architecture diagrams, and Q\&A. The difference is intent. Ideation artifacts clarify the problem; refinement artifacts prove implementation constraints. ## Deriving a spec from a refinement Use `okto_pulse_derive_spec_from_refinement` after the refinement is approved. The resulting spec should be grounded in the refinement's evidence, not just its summary. ```text theme={null} okto_pulse_derive_spec_from_refinement(board_id="...", refinement_id="...") ``` ## Related pages * [Ideation](/concepts/ideation) * [Spec](/concepts/spec) * [Ideation and refinement tools](/reference/mcp/ideation-refinement) * [Refinement flags](/permissions/refinement) # The SDLC Pipeline Source: https://docs.oktolabs.ai/concepts/sdlc-flow How Pulse moves work from raw idea to validated card — and why each gate exists Every software idea that enters Pulse travels through six stages before code ships. The stages are not advisory — they are enforced status transitions in the service layer. An agent cannot skip a stage by moving a card directly; it must call the MCP tools that correspond to each transition, and each transition checks its gate before proceeding. This page explains what happens at each stage, what the enforced thresholds are, and what gets written to the Knowledge Graph along the way. *** ## The 6-stage pipeline ```mermaid theme={null} flowchart LR I([Ideation\ndraft → refined]) R([Refinement\ndraft → approved]) S([Spec\ndraft → validated]) SP([Sprint\ndraft → active]) C([Card\nnot_started → validation]) V([Validation\nvalidation → done]) I -->|derive_spec| R R -->|derive_spec| S S -->|suggest_sprints| SP SP -->|create_card| C C -->|submit_task_validation| V V -->|kg_commit_consolidation| KG[(Knowledge\nGraph)] ``` Each arrow represents a Pulse MCP tool call. The pipeline is linear by default — though multiple ideations, refinements, and sprints can exist on a board simultaneously, each one follows its own path through the stages. **Status enums** (source: `okto-pulse-core/src/okto_pulse/core/models/db.py`): | Stage | Statuses | | ---------- | ----------------------------------------------------------------------------- | | Ideation | `draft` → `evaluating` → `refined` → `done` | | Refinement | `draft` → `in_progress` → `review` → `approved` → `done` | | Spec | `draft` → `review` → `approved` → `validated` → `in_progress` → `done` | | Sprint | `draft` → `active` → `review` → `closed` | | Card | `not_started` → `started` → `in_progress` ⇄ `on_hold` → `validation` → `done` | *** ## Stage 1: Ideation Ideation is the intake stage. You give Pulse a raw request — one sentence or a paragraph — and Pulse surfaces every material gap before anything gets built. **The core problem ideation solves:** vague requests produce vague specs. Instead of prompting you to write a spec up-front, Pulse asks questions about the gaps it finds in the raw text. **What an agent does here:** 1. Create the ideation: `okto_pulse_create_ideation` 2. Evaluate scope — three axes, each justified in writing: `okto_pulse_evaluate_ideation` 3. Ask ambiguity-killer questions (text or choice): `okto_pulse_ask_ideation_question`, `okto_pulse_ask_ideation_choice_question` 4. Record answers: `okto_pulse_answer_ideation_question` 5. Advance when ready: `okto_pulse_move_ideation` (`draft → evaluating → refined`) **Gate:** Pulse will not advance an ideation with an ambiguity score above the configured threshold. The scope assessment returns three numeric scores (domains, ambiguity, dependencies) with per-axis justification — not just numbers. An ambiguity score of 4/5 means the ideation needs more Q\&A before refinement. **What gets written to the KG:** Nothing is consolidated at ideation. Knowledge attached to an ideation (`okto_pulse_add_ideation_knowledge`) is available to downstream stages but is not yet promoted to the graph. The ambiguity-killer protocol is most useful for requests that contain vague verbs ("add authentication"), undefined nouns ("the admin panel"), or implicit scope ("make it faster"). The more precisely you answer the questions here, the more accurate the derived spec will be. *** ## Stage 2: Refinement Refinement is investigation, not paraphrasing. Its job is to read the actual codebase, query the KG for prior decisions, and produce a concrete evidence-backed description of current behavior, constraints, and dependencies. **What distinguishes refinement from a chat conversation:** the evidence must be citable. Good refinement output includes source file references (`path:line`), KG query results, runtime logs, and stakeholder answers. An agent that produces vague findings has not completed refinement. **What an agent does here:** 1. Create a refinement linked to the ideation: `okto_pulse_create_refinement` 2. Query the KG for prior decisions before deciding anything: `okto_pulse_kg_find_similar_decisions`, `okto_pulse_kg_query_natural` 3. Update findings, evidence, and constraints: `okto_pulse_update_refinement` 4. Advance when evidence is complete: `okto_pulse_move_refinement` (`draft → in_progress → review → approved`) 5. Derive a spec from the approved refinement: `okto_pulse_derive_spec_from_refinement` **Gate:** Refinement moves to `approved` only when evidence, findings, and constraints are recorded. The derived spec is pre-populated from refinement output — not written from scratch. **What gets written to the KG:** Refinement knowledge entries attached via `okto_pulse_add_refinement_knowledge` become candidates for the consolidation queue when the downstream spec is consolidated. Pulse rejects "copying stale repo docs without source verification" as an explicit anti-pattern. Refinement evidence must be checked against the current codebase state, not assumed from memory. *** ## Stage 3: Spec The spec is the implementation contract. It answers "what must be true when this ships?" with enough precision that a different agent (or a different session of the same agent) could implement it without guessing. **A strong spec includes:** * Problem statement * Acceptance criteria (each linked to at least one test scenario) * Functional requirements → business rule linkage * Technical requirements * Test scenarios with AC coverage * Business rules → card linkage * API contracts * Architecture decisions * Non-goals (explicit scope exclusion) **What an agent does here:** 1. Spec is created automatically via `okto_pulse_derive_spec_from_ideation` or `okto_pulse_derive_spec_from_refinement` 2. Add test scenarios with AC linkage: `okto_pulse_add_test_scenario` 3. Add business rules: `okto_pulse_add_business_rule` 4. Record design decisions with alternatives: `okto_pulse_add_decision` 5. Add API contracts: `okto_pulse_add_api_contract` 6. Submit evaluation (score + narrative): `okto_pulse_submit_spec_evaluation` 7. Submit validation (completeness/assertiveness/ambiguity): `okto_pulse_submit_spec_validation` 8. Advance: `okto_pulse_move_spec` **Spec evaluation gate (score ≥ 80):** `okto_pulse_submit_spec_evaluation` requires a qualitative score and written narrative. The gate for `validated → in_progress` will not pass if the evaluation score is below threshold. **Spec validation gate:** `okto_pulse_submit_spec_validation` requires three threshold checks — completeness, assertiveness, and ambiguity scores with written evidence. Success locks the spec content. An agent cannot modify a validated spec without explicitly unlocking it via `approved_to_draft` or `validated_to_draft`. **Spec → done gate (4 coverage checks + 2 structural checks):** 1. 100% acceptance criteria → test scenario coverage 2. FR → BR linkage complete 3. BR → Card linkage complete 4. AC → Scenario linkage complete 5. Configurable decision coverage threshold met 6. No non-bug tasks still open **What gets written to the KG on consolidation:** Spec is the richest KG source. The consolidation pipeline writes `Decision`, `Criterion`, `Constraint`, `Requirement`, `APIContract`, and `TestScenario` nodes, plus `belongs_to`, `derives_from`, `tests`, and `implements` edges. These nodes persist in the per-board LadybugDB graph (`~/.okto-pulse/boards/{id}/graph.lbug`) and survive the next session. The spec is where most of the KG value is created. Every `okto_pulse_add_decision` call with alternatives and justification becomes a queryable `Decision` node that future agents can retrieve via `okto_pulse_kg_find_similar_decisions` before making the same call again. *** ## Stage 4: Sprint A sprint slices a validated spec into reviewable work. Sprints define the scope, objective, and expected outcome for a batch of cards. They are not a time-box — they are a logical delivery slice. **What an agent does here:** 1. Get sprint suggestions from the spec: `okto_pulse_suggest_sprints` 2. Create the sprint with objective and expected outcome: `okto_pulse_create_sprint` 3. Assign cards to the sprint: `okto_pulse_assign_tasks_to_sprint` 4. Resolve sprint Q\&A before execution: `okto_pulse_ask_sprint_question`, `okto_pulse_answer_sprint_question` 5. Submit sprint evaluation before activating: `okto_pulse_submit_sprint_evaluation` 6. Advance: `okto_pulse_move_sprint` (`draft → active`) **Sprint evaluation gate:** `okto_pulse_submit_sprint_evaluation` is the quality gate for `review → closed`. A sprint cannot close without a recorded evaluation. This prevents sprints from being silently abandoned. **What gets written to the KG:** Sprint consolidation writes `Entity` and `Requirement` nodes representing the sprint scope, plus `belongs_to` edges linking sprint cards back to spec decisions. *** ## Stage 5: Cards (Tasks and Bugs) Cards are execution units. Each card must be self-contained — an implementer agent should be able to work from a card alone without reading the spec from scratch. **Card types:** `normal`, `test`, `bug` **What an agent does before starting a card:** 1. Get the full context bundle: `okto_pulse_get_task_context` — returns card + spec + business rules + test scenarios + decisions + KG context in one call 2. Copy needed artifacts: `okto_pulse_copy_knowledge_to_card`, `okto_pulse_copy_mockups_to_card`, `okto_pulse_copy_architecture_to_card` 3. Advance: `okto_pulse_move_card` (`not_started → started → in_progress`) **Card → validation → done gate:** When implementation is complete, the card moves to `validation` (not directly to `done`). To move from `validation → done`, the closing agent must provide: 1. `conclusion` — written summary of what was done 2. `completeness` (0–100) — with written justification (e.g., "90 — pagination implemented but not yet perf-tested") 3. `drift` (0–100) — deviation from the original spec, with justification (e.g., "10 — switched from JWT to session tokens per spec amendment") 4. If the Task Validation Gate is enabled: an independent reviewer must call `okto_pulse_submit_task_validation` — auto-fail on threshold violations even if the reviewer recommends approval **Test theater prevention gate:** `okto_pulse_update_test_scenario_status` requires structured evidence: `test_file_path`, `test_function`, `last_run_at`, and `output_snippet` or `test_run_id`. Marking a test "passed" without evidence is rejected. Sprint close re-validates this evidence on every passed scenario. **Bug card gate (test-first):** 1. A new failing test scenario must exist before the bug card can move to `in_progress` 2. A linked test card must exist **Card status transitions:** `not_started → started → in_progress ⇄ on_hold → validation → done` **What gets written to the KG:** Completed cards contribute `Learning` nodes (lessons from implementation) and `Bug` nodes (linked via `validates` edges to the test scenarios that caught them). The `learning_from_bugs` query (`okto_pulse_kg_get_learning_from_bugs`) surfaces these across future sessions. *** ## Stage 6: Validation Validation is the independent quality checkpoint. It is separated from implementation by design — the agent that built the card cannot be the same agent that validates it (enforced by permission presets). **Permission presets** (source: `okto-pulse-core/src/okto_pulse/core/models/db.py:PermissionPreset`): | Preset | Gate permissions | | --------------- | ---------------------------------------------------------------------------------------------------------------------------- | | **Executor** | Can move cards `not_started → validation`. Cannot submit validation gates. | | **Validator** | Can submit `spec_validation`, `spec_evaluation`, `sprint_evaluation`, `task_validation`. Can move cards `validation → done`. | | **QA** | Can write test scenarios. Cannot submit any gate. | | **Spec Writer** | Owns ideation/refinement/spec content. Cannot move specs past `approved`. | **What a validator agent does:** 1. Read the card with context: `okto_pulse_get_task_validation` 2. Verify the implementation evidence (logs, test output, screenshots) 3. Submit with structured evidence: `okto_pulse_submit_task_validation` Good validation evidence: exact commands run, relevant logs or output, test names, known limitations, unresolved risks. **What gets written to the KG:** After a successful validation, `okto_pulse_kg_commit_consolidation` writes the durable decision and learning nodes for this card into the board's LadybugDB graph. *** ## Knowledge Graph integration Every stage produces artifacts that feed the Knowledge Graph. The KG is not a side effect — it is the durable memory layer that makes the next project faster. **11 node types written across the pipeline:** | Node type | Typically written at | | -------------- | ----------------------------------------------------------- | | `Decision` | Spec (design decisions), Ideation (choice question answers) | | `Criterion` | Spec (acceptance criteria, test scenarios) | | `Constraint` | Spec, Refinement (technical constraints) | | `Assumption` | Refinement (documented assumptions) | | `Requirement` | Spec (FRs, TRs), Sprint (scope) | | `Entity` | Spec (named entities), Sprint | | `APIContract` | Spec (API contracts) | | `TestScenario` | Spec (test scenarios) | | `Bug` | Card stage (bug cards) | | `Learning` | Card stage (post-implementation) | | `Alternative` | Spec (alternatives considered in decisions) | **10 relationship types** connect these nodes: `supersedes`, `contradicts`, `derives_from`, `relates_to`, `mentions`, `depends_on`, `violates`, `implements`, `tests`, `validates`. **What an agent can query mid-task:** ```text theme={null} okto_pulse_kg_query_natural("What auth approach did we decide?") okto_pulse_kg_find_similar_decisions("session token storage") okto_pulse_kg_find_contradictions() okto_pulse_kg_get_supersedence_chain(decision_id) okto_pulse_kg_get_learning_from_bugs("auth module") ``` These queries run against the embedded LadybugDB graph at `~/.okto-pulse/boards/{id}/graph.lbug`. They are deterministic (no LLM) and survive across sessions. The KG uses HNSW vector indexes on five node types for semantic search. *** ## Why this differs from a kanban A kanban answers "what is the current status of work?" Pulse answers "did the work satisfy the original intent?" — and refuses to close work that cannot prove it did. The structural differences: | Kanban | Pulse | | --------------------------------------- | ------------------------------------------------------------------------------- | | Columns represent status only | Status transitions enforce coverage gates | | Cards are created directly | Cards derive from validated specs | | Work is done when the developer says so | Work requires structured conclusion + completeness + drift evidence | | Context lives in chat history | Context lives in KG nodes that outlast sessions | | Moving a card requires one click | Moving a card from `validation → done` requires a validator agent with evidence | | No memory of past decisions | Prior decisions surface before new ones are made | The 216 MCP tools Pulse exposes are not shortcuts around this structure — they are the structure. An agent calls `okto_pulse_move_card` and the service layer checks every gate condition before the status changes. The traceability report (`okto_pulse_get_traceability_report`) returns the full lineage: spec → business rules → technical requirements → test scenarios → cards → validations. If a card exists that cannot be traced back to a spec requirement, it should not exist. *** ## Where to go next Walk through the full pipeline with a real example in 5 minutes. How the KG stores and serves decision history across sessions. Connect your agent to the 216 MCP tools that drive this pipeline. Deep-dive into Stage 1 — ambiguity reduction and scope assessment. Deep-dive into Stage 3 — writing implementation contracts. Deep-dive into Stage 6 — independent quality gates. # Spec Source: https://docs.oktolabs.ai/concepts/spec The contract artifact that turns refined intent into gated implementation work. # Spec You can use a spec as the implementation contract for a feature. It is where Pulse turns refined intent into requirements, acceptance criteria, test scenarios, API contracts, decisions, and traceability that cards can implement. ## What is a spec A spec is the central artifact in Pulse. Ideations and refinements feed it; sprints and cards derive from it. Validation gates protect it from becoming an unreviewed prompt dump. ## Spec anatomy A complete spec usually contains: | Area | What belongs there | | ------------------------ | ---------------------------------------------------------------------------- | | Title and description | The smallest accurate name for the work and the business outcome. | | Context | Why this work exists and what constraints shape it. | | Functional requirements | User-visible behavior and workflow expectations. | | Technical requirements | Architecture, performance, storage, permission, and integration constraints. | | Acceptance criteria | Observable conditions that make the spec acceptable. | | Test scenarios | Evidence-oriented checks linked to future cards. | | Business rules | Rules that must not drift during implementation. | | API contracts | Request, response, error, and compatibility expectations. | | Mockups and architecture | Visual and structural context. | | Decisions | Formal choices with rationale, alternatives, and supersedence links. | ## States and gates | State | Meaning | | ------------- | --------------------------------------------------- | | `draft` | Editable working version. | | `review` | Ready for qualitative review. | | `approved` | Evaluation passed and content can enter validation. | | `validated` | Content evidence gate passed; the spec is locked. | | `in_progress` | Cards are being implemented from the spec. | | `done` | Spec work is complete. | | `cancelled` | Spec should not proceed. | Backward moves exist for controlled edits: `approved_to_draft` and `validated_to_draft` clear the active lock while preserving validation history. ## Spec evaluation Spec evaluation is the qualitative gate. It checks completeness, assertiveness, ambiguity, and readiness. The docs use `80` as the default acceptance threshold: below that, revise the spec before promoting it. ```text theme={null} okto_pulse_submit_spec_evaluation okto_pulse_move_spec ``` ## Spec validation gate Spec validation is separate from evaluation. `okto_pulse_submit_spec_validation` records evidence that the approved spec meets the content requirements for `approved -> validated`. Validator is the intended gate-holder role. Do not treat `approved` and `validated` as synonyms. `approved` means the spec looks acceptable; `validated` means the evidence gate passed and the spec is locked for implementation. ## Deriving cards from a spec Cards are derived after the spec is validated or otherwise approved for implementation. Derived cards should link back to the spec and to test scenarios, business rules, API contracts, technical requirements, or decisions where relevant. ```text theme={null} okto_pulse_derive_cards_from_spec okto_pulse_link_task_to_scenario okto_pulse_link_task_to_rule okto_pulse_link_task_to_contract okto_pulse_link_task_to_tr ``` ## Spec knowledge and Q\&A Specs can carry Q\&A and knowledge attachments. Use those when implementation agents need durable answers or source material. Do not hide critical requirements only in comments; promote them into spec fields when they affect acceptance. ## Decisions on a spec A Decision records why a choice was made. Use `okto_pulse_add_decision` for tradeoffs, architecture choices, data model decisions, and security boundaries. Use `supersedes_decision_id` when replacing an older choice so the Knowledge Graph can preserve the chain. ## Related pages * [Validation gates](/concepts/validation) * [Decisions](/concepts/decisions) * [Spec tools](/reference/mcp/specs) * [Spec flags](/permissions/spec) # Sprint Source: https://docs.oktolabs.ai/concepts/sprint How Pulse groups spec-derived work into an executable sprint. # Sprint You can use a sprint to group validated spec work into a bounded delivery slice. In Pulse, the sprint is the bridge between a spec and the cards an implementation agent will pick up. ## What is a sprint A sprint contains cards, assignment context, coverage settings, qualitative evaluation, and lifecycle status. It does not replace a spec; it selects a portion of spec work and makes it executable. ## States | State | Meaning | | ----------- | ------------------------------------------------ | | `draft` | The sprint exists but has not started. | | `active` | Cards can be assigned and worked. | | `review` | The sprint is ready for evaluation and closeout. | | `closed` | Sprint delivery is complete. | | `cancelled` | Sprint should stop. | ## Sprint evaluation gate Sprint evaluation is a retrospective checkpoint, not the same as spec validation or task validation. It captures delivery quality, coverage, and lessons before closeout. ```text theme={null} okto_pulse_get_sprint_evaluation okto_pulse_submit_sprint_evaluation ``` ## Suggesting sprints from a spec `okto_pulse_suggest_sprints` groups spec work into sprint-sized chunks. Use it after the spec is mature enough that cards can be estimated and grouped. ## Assigning cards to a sprint Cards can be assigned to a sprint after the sprint is created. Keep a sprint focused: a broad catch-all sprint makes validation and status reporting harder. ```text theme={null} okto_pulse_assign_tasks_to_sprint ``` ## Related pages * [Spec](/concepts/spec) * [Cards](/concepts/card) * [Sprints and cards tools](/reference/mcp/sprints-cards) * [Sprint flags](/permissions/sprint) # Validation gates Source: https://docs.oktolabs.ai/concepts/validation The Pulse gates that keep specs, sprints, tests, and cards evidence-based. # Validation gates You can use validation gates to keep AI-assisted work from advancing on confidence alone. Pulse separates writing, implementation, and validation so one agent does not silently mark its own work complete. ## Why gates exist A gate makes a state transition depend on evidence. Gates are especially important with agents because a fluent answer is not proof of completeness, test coverage, or alignment with a spec. ## Gate 1: Spec evaluation Spec evaluation is the qualitative review. It checks whether a spec is complete, assertive, low-ambiguity, and ready for a formal validation pass. The common threshold is score `>= 80`. ## Gate 2: Spec validation Spec validation uses `okto_pulse_submit_spec_validation` to move an approved spec into `validated`. This is the content evidence gate. A passed validation locks the spec until a backward transition clears the active validation pointer. ## Gate 3: Task validation Task validation uses `okto_pulse_submit_task_validation` while the card is in `validation`. It records reviewer confidence, completeness, drift, threshold violations, and justification. A recommendation to approve can still fail when thresholds are violated. ## Gate 4: Test evidence Pulse treats test evidence as structured data. Test status updates should include a file path, test function, last run time, and output snippet or run ID. Sprint close checks passed scenarios rather than trusting labels. ## Bug-first gate Bug cards should not enter implementation without a failing scenario that proves the defect. That scenario becomes the baseline for the fix and the future regression check. ## Sprint evaluation Sprint evaluation is a qualitative closeout. It is useful for retrospectives and delivery quality, but it is not a substitute for spec validation or task validation. ## The Validator preset Validator is the intended exclusive gate-holder. It can submit spec validation, sprint evaluation, and task validation, while Executor and Spec roles read validation records but cannot submit them. ## Backward transitions Backward transitions keep recovery explicit: * `spec.move.approved_to_draft` allows edits after approval. * `spec.move.validated_to_draft` unlocks a validated spec and clears the active lock. * `card.move.validation_to_not_started` sends failed work back for rework. ## Related pages * [Spec](/concepts/spec) * [Cards](/concepts/card) * [Built-in presets](/permissions/presets) * [Validation tools](/reference/mcp/validation) # Configuration overview Source: https://docs.oktolabs.ai/configuration How Pulse reads server, MCP, storage, and Knowledge Graph settings. # Configuration overview You can configure Pulse with environment variables and an optional `.env` file. There is no YAML configuration file in the community runtime. ## How configuration works Pulse uses `pydantic-settings`. Field names map to environment variables by uppercasing the field name, and environment variable lookup is case-insensitive. ```bash theme={null} DATA_DIR=/srv/pulse KG_BASE_DIR=/srv/pulse okto-pulse serve --accept-terms ``` ```text theme={null} Pulse API/UI: http://127.0.0.1:8100 Pulse MCP: http://127.0.0.1:8101/mcp ``` ## Configuration by concern Complete table of server, storage, MCP, KG, tracing, and Docker variables. Ports, bind hosts, CORS, terms, logging, and runtime behavior. SQLite, uploads, per-board `graph.lbug`, global discovery, backups, and volumes. ## Hot-reload settings vs restart-required settings Most process settings, including bind hosts and ports, require restart. KG queue and decay runtime settings can be updated through the settings API and are rescheduled in process. ## Related pages * [MCP reference](/reference/mcp) * [Docker operations](/operations/docker) * [KG health](/kg-operations/health) # Environment variables Source: https://docs.oktolabs.ai/configuration/environment-variables Complete reference for every environment variable Pulse reads — server, storage, knowledge-graph runtime, MCP tracing, Docker-only — with defaults, ranges, and the field on CoreSettings each one maps to. # Environment variables Pulse reads configuration from environment variables and an optional `.env` file via `pydantic-settings`. The base settings class is `CoreSettings` ([`okto-pulse-core/src/okto_pulse/core/infra/config.py:22`](https://github.com/OktoLabsAI/okto-pulse-core)); the community edition extends it with `CommunitySettings` ([`okto-pulse/src/okto_pulse/community/config.py:7`](https://github.com/OktoLabsAI/okto-pulse)). Both use: ```python theme={null} model_config = SettingsConfigDict( env_file=".env", env_file_encoding="utf-8", case_sensitive=False, extra="ignore", ) ``` Three rules follow from that config: 1. **Field name → env var name.** Every field on `CoreSettings` and `CommunitySettings` accepts an env var equal to the field name uppercased. `data_dir` ⇒ `DATA_DIR`, `kg_base_dir` ⇒ `KG_BASE_DIR`, etc. 2. **Case-insensitive.** `DATA_DIR`, `data_dir`, and `Data_Dir` are equivalent. We use uppercase throughout this page by convention. 3. **`.env` is loaded automatically** from the working directory of `okto-pulse serve`. Useful for local development; production should set vars in the process environment. A small set of variables outside `CoreSettings` are read directly by the CLI, the MCP server, or the Docker image — they are called out explicitly in their sections below. For runtime tuning rationale, see [Server configuration](/configuration/server-config). For the on-disk layout these variables control, see [Storage paths](/configuration/storage-paths). Source-of-truth for the table below is [`80-pulse-feature-inventory.md:178–211`](https://github.com/OktoLabsAI/okto-pulse-core). *** ## CLI runtime control These variables gate the CLI itself — they are read by `okto-pulse serve` and friends, not by `CoreSettings`. | Env var | Default | Range / type | Purpose | | ------------------------------------- | --------------- | ---------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `OKTO_PULSE_PORT` | `8100` | int | API + Web UI port. Set by `cmd_serve` from `--api-port` **before** importing `okto_pulse.community.main`. ([`community/cli.py:244`](https://github.com/OktoLabsAI/okto-pulse), inventory:181) | | `OKTO_PULSE_MCP_PORT` | `8101` | int | MCP server port. Set by `cmd_serve` from `--mcp-port`. ([`community/cli.py:245`](https://github.com/OktoLabsAI/okto-pulse), inventory:182) | | `OKTO_PULSE_TERMS_ACCEPTED` | unset | `1` to pre-accept | Pre-accept the Terms of Use; equivalent to `--accept-terms`. Triggers `write_acceptance("env")`. ([`community/cli.py:252`](https://github.com/OktoLabsAI/okto-pulse), [`acceptance.py:29`](https://github.com/OktoLabsAI/okto-pulse), inventory:183) | | `OKTO_PULSE_NO_BANNER` | unset | any non-empty | Suppress the ASCII banner on startup. Useful for JSON pipes. ([`community/cli.py:47`](https://github.com/OktoLabsAI/okto-pulse), inventory:184) | | `OKTO_PULSE_HOME` | `~/.okto-pulse` | path | Overrides the base directory used for persisted Terms of Use acceptance state. Source: `community/acceptance.py:23`. | | `OKTO_PULSE_STARTUP_TIMEOUT_SECONDS` | `120` | float seconds, min `1` | Timeout while waiting for the paired API/MCP uvicorn listeners to report startup. Source: `community/main.py:62`. | | `OKTO_PULSE_STARTUP_TIMEOUT` | unset | float seconds, min `1` | Legacy alias for `OKTO_PULSE_STARTUP_TIMEOUT_SECONDS`; read only when the `_SECONDS` variable is absent. Source: `community/main.py:63`. | | `OKTO_PULSE_SHUTDOWN_TIMEOUT_SECONDS` | `5` | float seconds, min `1` | Timeout for graceful shutdown of the paired API/MCP servers. Source: `community/main.py:88`. | | `OKTO_PULSE_SHUTDOWN_TIMEOUT` | unset | float seconds, min `1` | Legacy alias for `OKTO_PULSE_SHUTDOWN_TIMEOUT_SECONDS`; read only when the `_SECONDS` variable is absent. Source: `community/main.py:89`. | `OKTO_PULSE_PORT` and `OKTO_PULSE_MCP_PORT` **must** be set before `okto_pulse.community.main` is imported — the module evaluates `app = create_community_app()` at import time and bakes the values into the Web UI's `/config.js`. The CLI does this for you; if you embed Pulse in your own Python process, set both before any `import okto_pulse.community.main`. *** ## Server These map to `CoreSettings` fields ([`config.py:22–60`](https://github.com/OktoLabsAI/okto-pulse-core), inventory:751–765). | Env var | Default | Field | Notes | | ----------------- | ---------------------------------------------------------------------- | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `HOST` | `127.0.0.1` (community) / `0.0.0.0` (Docker) | `host` | API + Web UI bind. Loopback by default; Docker images set `0.0.0.0` so port forwards reach uvicorn. ([CLAUDE.md "Env vars the runtime reads"](https://github.com/OktoLabsAI/okto-pulse), inventory:761) | | `MCP_HOST` | `127.0.0.1` (community) / `0.0.0.0` (Docker) | *runtime* | MCP uvicorn bind. Honored in **both** `community/main.py` (since v0.1.12) and `core/mcp/server.py:run_mcp_server`. Without it, MCP binds to `127.0.0.1` even with `-p 8101:8101`. | | `PORT` | unset | *fallback* | Read **before** `OKTO_PULSE_PORT` in `community/main.py:652`. Useful for PaaS platforms (Heroku, Fly) that inject `PORT`. | | `MCP_PORT` | unset | *fallback* | Read **before** `OKTO_PULSE_MCP_PORT` in `community/main.py:655` and in `core/mcp/server.py:12852`. | | `ENVIRONMENT` | `development` | `environment` | Free-form label. Surfaced in startup banner and `/health`. ([inventory:754](https://github.com/OktoLabsAI/okto-pulse-core)) | | `DEBUG` | `false` | `debug` | Raises `okto_pulse.*` loggers from `INFO` to `DEBUG`; surfaces SQLAlchemy echo. ([inventory:753](https://github.com/OktoLabsAI/okto-pulse-core)) | | `CORS_ORIGINS` | `*` (community) / `http://localhost:5173,http://localhost:3000` (core) | `cors_origins` | Comma-separated allowed origins. The community edition's `_derive_paths` validator overrides core to `*` so the bundled UI works regardless of port. ([`community/config.py:33`](https://github.com/OktoLabsAI/okto-pulse), inventory:765) | | `PUBLIC_HOST` | `127.0.0.1` | hostname/IP | Host value injected into `/config.js` for browser-side API and MCP URLs. Source: `community/main.py:304`. | | `PUBLIC_API_PORT` | active API port | int | API port injected into `/config.js`; use when a reverse proxy or container publish port differs from the internal listener. Source: `community/main.py:305`. | | `PUBLIC_MCP_PORT` | active MCP port | int | MCP port injected into `/config.js`; use when the browser should connect through a published/proxied MCP port. Source: `community/main.py:306`. | ```bash theme={null} export ENVIRONMENT=staging export DEBUG=true export CORS_ORIGINS="http://localhost:5173,https://pulse.staging.example.com" okto-pulse serve --accept-terms ``` ```text theme={null} INFO okto_pulse.api CORS allow_origins=['http://localhost:5173', 'https://pulse.staging.example.com'] DEBUG sqlalchemy.engine BEGIN (implicit) ``` See [Server configuration](/configuration/server-config) for ports, bind hosts, CORS, and logging in depth. *** ## Storage These map to `CoreSettings` and `CommunitySettings` fields ([inventory:185–189](https://github.com/OktoLabsAI/okto-pulse-core)). | Env var | Default | Field | Notes | | ----------------- | ---------------------------------------------- | ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `DATA_DIR` | `~/.okto-pulse` | `CommunitySettings.data_dir` | Single root for SQLite, attachments, and KG graph files. The community edition's `_derive_paths` validator rebases `DATABASE_URL` and `UPLOAD_DIR` under it. ([`community/config.py:11`](https://github.com/OktoLabsAI/okto-pulse)) | | `KG_BASE_DIR` | `~/.okto-pulse` | `kg_base_dir` | KG-only root; relocates per-board `boards/{id}/graph.lbug` and `global/discovery.lbug` independently of `DATA_DIR`. Defaults to `DATA_DIR` in the Docker image (`KG_BASE_DIR=/data`). ([inventory:189](https://github.com/OktoLabsAI/okto-pulse-core)) | | `DATABASE_URL` | `sqlite+aiosqlite:///{data_dir}/data/pulse.db` | `database_url` | SQLAlchemy connection string. Override to point at an alternate SQLite path; non-SQLite backends are not supported in the community edition. ([inventory:185](https://github.com/OktoLabsAI/okto-pulse-core)) | | `UPLOAD_DIR` | `{data_dir}/uploads` | `upload_dir` | Card attachment storage. ([inventory:186](https://github.com/OktoLabsAI/okto-pulse-core)) | | `MAX_UPLOAD_SIZE` | `10485760` (10 MB) | `max_upload_size` | Per-attachment cap in bytes. ([inventory:187](https://github.com/OktoLabsAI/okto-pulse-core)) | ```bash theme={null} # Move the entire data root onto a faster volume export DATA_DIR=/srv/pulse export KG_BASE_DIR=/srv/pulse okto-pulse serve --accept-terms ``` ```text theme={null} $ tree -L 1 /srv/pulse /srv/pulse ├── boards ├── data ├── global └── uploads ``` See [Storage paths](/configuration/storage-paths) for the full directory tree, the unprefixed Docker volume gotcha, and backup/migration recipes. *** ## Knowledge graph — embeddings Configures the embedding backend used for KG semantic search. ([inventory:191–193](https://github.com/OktoLabsAI/okto-pulse-core)) | Env var | Default | Field | Notes | | -------------------- | --------------------------------------------------- | -------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `KG_EMBEDDING_MODE` | `sentence-transformers` (community) / `stub` (core) | `kg_embedding_mode` | Either `sentence-transformers` (real \~90 MB MiniLM model) or `stub` (deterministic hash, no model). The community edition's `CommunitySettings` overrides core's default to `sentence-transformers`. | | `KG_EMBEDDING_MODEL` | `sentence-transformers/all-MiniLM-L6-v2` | `kg_embedding_model` | Hugging Face repo ID. Pulse ships with the model pre-baked into the Docker image at `/opt/hf-cache`. | | `KG_EMBEDDING_DIM` | `384` | `kg_embedding_dim` | Vector dimension. Must match the model. The HNSW index in each `graph.lbug` is bound to this dimension at create time — changing it requires a graph rebuild. | Changing `KG_EMBEDDING_MODEL` or `KG_EMBEDDING_DIM` after a board has been created will not re-embed existing nodes. New nodes will be embedded with the new model, but similarity search will mix vector spaces. If you need to switch models, run `okto-pulse kg backfill ` to recompute everything; if the dimension changed, drop and rebuild the graph. *** ## Knowledge graph — runtime tuning LadybugDB engine sizing. The legacy `KUZU` prefix is retained in env-var names because the underlying engine is the Kùzu-derived LadybugDB ([Kuzu retired 2026-05-03](https://github.com/OktoLabsAI/okto-pulse)). All three are validated by `pydantic.Field` with the ranges shown. | Env var | Default | Range | Field | Notes | | ------------------------- | ------- | --------- | ------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `KG_KUZU_BUFFER_POOL_MB` | `256` | 16–512 MB | `kg_kuzu_buffer_pool_mb` | LadybugDB buffer pool. The library's own default (`buffer_pool_size=0`) maps to \~80 % of system RAM and caused 128 GB RSS with three pooled boards in field reports — hence the conservative cap. ([inventory:194](https://github.com/OktoLabsAI/okto-pulse-core), [`config.py:71–73`](https://github.com/OktoLabsAI/okto-pulse-core)) | | `KG_KUZU_MAX_DB_SIZE_GB` | `1` | 1–64 GB | `kg_kuzu_max_db_size_gb` | Per-board graph size cap. The library default (`1<<43` = 8 TB virtual address) is replaced with this saner default. ([inventory:195](https://github.com/OktoLabsAI/okto-pulse-core)) | | `KG_CONNECTION_POOL_SIZE` | `8` | 1–32 | `kg_connection_pool_size` | LadybugDB connection pool per process. ([inventory:196](https://github.com/OktoLabsAI/okto-pulse-core)) | *** ## Knowledge graph — consolidation queue The KG worker pool that drains the SQLite consolidation queue and writes nodes/edges into LadybugDB. **All `KG_QUEUE_*` settings hot-reload** via APScheduler with a 5-second debounce — no restart required. ([inventory:790–793](https://github.com/OktoLabsAI/okto-pulse-core), [`config.py:80–87`](https://github.com/OktoLabsAI/okto-pulse-core)) | Env var | Default | Range | Field | Notes | | ----------------------------------- | ------- | ---------- | ----------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `KG_SESSION_TTL_SECONDS` | `3600` | int (s) | `kg_session_ttl_seconds` | Consolidation session TTL. Sessions older than this are reaped by the cleanup worker. ([inventory:197](https://github.com/OktoLabsAI/okto-pulse-core)) | | `KG_CLEANUP_INTERVAL_SECONDS` | `60` | int (s) | `kg_cleanup_interval_seconds` | How often the cleanup worker runs. ([inventory:198](https://github.com/OktoLabsAI/okto-pulse-core)) | | `KG_CLEANUP_ENABLED` | `true` | bool | `kg_cleanup_enabled` | Disable the cleanup worker entirely (rare; useful for replay tests). ([inventory:199](https://github.com/OktoLabsAI/okto-pulse-core)) | | `KG_QUEUE_MAX_CONCURRENT_WORKERS` | `4` | 1–16 | `kg_queue_max_concurrent_workers` | Asyncio task concurrency *inside* the single uvicorn process. Not OS workers. ([inventory:200](https://github.com/OktoLabsAI/okto-pulse-core)) | | `KG_QUEUE_MIN_INTERVAL_MS` | `100` | 0–1000 ms | `kg_queue_min_interval_ms` | Floor between queue polls. Lower = more aggressive draining; higher = lower CPU. ([inventory:201](https://github.com/OktoLabsAI/okto-pulse-core)) | | `KG_QUEUE_CLAIM_TIMEOUT_S` | `300` | 60–3600 s | `kg_queue_claim_timeout_s` | After this, an in-flight queue entry is considered abandoned and reclaimed by another worker. ([inventory:202](https://github.com/OktoLabsAI/okto-pulse-core)) | | `KG_QUEUE_MAX_ATTEMPTS` | `5` | 1–10 | `kg_queue_max_attempts` | Retries per entry before it dead-letters. Reprocess via `okto_pulse_kg_dead_letter_reprocess`. ([inventory:203](https://github.com/OktoLabsAI/okto-pulse-core)) | | `KG_QUEUE_ALERT_THRESHOLD` | `5000` | 100–100000 | `kg_queue_alert_threshold` | Queue depth that surfaces as a yellow warning in `okto_pulse_kg_health`. ([inventory:204](https://github.com/OktoLabsAI/okto-pulse-core)) | | `KG_QUEUE_RECOVERY_SCAN_INTERVAL_S` | `60` | 10–600 s | `kg_queue_recovery_scan_interval_s` | Periodicity of the dead-entry recovery scan. Values below 30 s start to compete with normal traffic. ([inventory:205](https://github.com/OktoLabsAI/okto-pulse-core)) | `KG_MAX_QUEUE_DEPTH` is **deprecated** and will be removed in v0.5.0. The `settings_service` maps the legacy value into `KG_QUEUE_ALERT_THRESHOLD` and emits a `DeprecationWarning` at startup. Source: [`config.py:67–70`](https://github.com/OktoLabsAI/okto-pulse-core). *** ## Knowledge graph — relevance decay The decay tick recomputes node relevance scores so old, unread decisions sink. Hot-reloadable through `PUT /settings/runtime` — APScheduler reschedules the job in place. ([inventory:206–208](https://github.com/OktoLabsAI/okto-pulse-core), [`config.py:90–95`](https://github.com/OktoLabsAI/okto-pulse-core)) | Env var | Default | Range | Field | Notes | | -------------------------------- | ------------- | --------------------- | -------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `KG_DECAY_TICK_INTERVAL_MINUTES` | `1440` (24 h) | 5–10080 (5 min – 7 d) | `kg_decay_tick_interval_minutes` | Cron period for the decay worker. The 5-minute floor blocks accidental DoS-against-self; the 7-day ceiling blocks "forgot to schedule it". | | `KG_DECAY_TICK_STALENESS_DAYS` | `7` | 1–365 d | `kg_decay_tick_staleness_days` | Nodes whose `last_recomputed_at` is older than this are recomputed on the next tick. | | `KG_DECAY_TICK_MAX_AGE_DAYS` | `0` | 0–365 d | `kg_decay_tick_max_age_days` | `0` = no cap. When set, force-recompute "fresh" nodes older than this many days regardless of staleness. | | `KG_DECAY_TICK_BATCH_SIZE` | `200` | int | module constant | Maximum stale KG nodes processed per decay tick batch, ordered by id so a tick does not revisit the same row. Source: `events/handlers/kg_decay_tick.py:40`. | | `KG_DAILY_TICK_DISABLED` | unset | `1` disables | runtime guard | Disables scheduled daily KG tick registration. Used by tests and controlled runtimes that trigger ticks manually. Source: `core/app.py:164` and `community/main.py:372`. | *** ## MCP tracing Independent of standard logging, Pulse can record every MCP tool call as JSONL. Read at runtime by [`core/mcp/trace_middleware.py:49,56`](https://github.com/OktoLabsAI/okto-pulse-core). | Env var | Default | Notes | | ------------------- | --------------------------- | ---------------------------------------------------------------------------------------------------------- | | `MCP_TRACE_ENABLED` | unset | Set to `1`, `true`, or `yes` to enable. Anything else (or unset) keeps tracing off. | | `MCP_TRACE_DIR` | `${KG_BASE_DIR}/mcp_traces` | Output directory; one `session_*.jsonl` per MCP session. The Docker image overrides to `/data/mcp_traces`. | ```bash theme={null} MCP_TRACE_ENABLED=1 okto-pulse serve --accept-terms ``` ```text theme={null} $ ls ~/.okto-pulse/mcp_traces/ session_2026-05-07T14-12-03_a3f9.jsonl $ head -1 ~/.okto-pulse/mcp_traces/session_2026-05-07T14-12-03_a3f9.jsonl {"ts":"2026-05-07T14:12:04Z","tool":"okto_pulse_get_active_board","args":{},"result_summary":"ok","ms":8} ``` *** ## MCP authentication Authentication for `okto-pulse` MCP tools is configured via `MCPSettings` ([`config.py:110–117`](https://github.com/OktoLabsAI/okto-pulse-core)) with `env_prefix="MCP_"` — these are the only Pulse env vars that take a prefix. | Env var | Default | Field | Notes | | ----------------------- | ------- | ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `MCP_REQUIRE_AGENT_KEY` | `true` | `MCPSettings.require_agent_key` | When true, every MCP request must carry a valid `dash_` API key (query param or `Authorization: Bearer`). Disabling this exposes the server unauthenticated — **do not** unless the listener is on a private socket. | | `MCP_AGENT_KEYS_ENV` | unset | `MCPSettings.agent_keys_env` | Comma-separated list of agent keys for static validation. Normally agents are seeded into SQLite by `okto-pulse init --agents`; this override is for ephemeral CI environments. | For the auth flow itself — query-param vs. Bearer header vs. `.mcp.json` discovery — see [MCP reference / Authentication](/reference/mcp#authentication). *** ## Docker-image-only Set inside the official `ghcr.io/oktolabsai/okto-pulse` image; not configurable from `CoreSettings`. Source: [`okto-pulse/Dockerfile:28–29`](https://github.com/OktoLabsAI/okto-pulse). | Env var | Container default | Purpose | | ---------------------------- | ------------------------------------- | ------------------------------------------------------------------------------------------------------- | | `HF_HOME` | `/opt/hf-cache` | Hugging Face cache root. Pre-warmed at build time with `all-MiniLM-L6-v2`; do not mount over this path. | | `SENTENCE_TRANSFORMERS_HOME` | `/opt/hf-cache/sentence_transformers` | Sentence-transformers sub-cache. | Mounting a volume over `/opt/hf-cache` forces the container to re-download the embedding model on first run. The image is offline-capable only because the cache is pre-baked. *** ## `.env` example `okto-pulse serve` reads a `.env` file from its working directory. Useful for local development. ```dotenv .env theme={null} # Server ENVIRONMENT=development DEBUG=true CORS_ORIGINS=http://localhost:5173,http://localhost:3000 # Storage DATA_DIR=/Users/you/.okto-pulse # Knowledge graph — sizing KG_KUZU_BUFFER_POOL_MB=384 KG_CONNECTION_POOL_SIZE=12 # Knowledge graph — queue KG_QUEUE_MAX_CONCURRENT_WORKERS=8 KG_QUEUE_ALERT_THRESHOLD=10000 # Tracing (debug only — verbose) # MCP_TRACE_ENABLED=1 ``` ```bash theme={null} okto-pulse serve --accept-terms ``` ```text theme={null} INFO okto_pulse Starting Okto Pulse Community... INFO okto_pulse.kg KG buffer pool=384MB, connection pool=12, max workers=8 INFO uvicorn Uvicorn running on http://127.0.0.1:8100 ``` Variables set in the process environment **override** values from `.env`. Production deployments should set vars in the systemd unit, the Docker `--env`/`-e` flag, or the orchestrator manifest — not check a `.env` into the repo. *** ## Hot-reloadable vs. restart-required Most settings are read once at startup. The `KG_QUEUE_*` and `KG_DECAY_TICK_*` families are an exception — they hot-reload while the process is running. | Family | Behavior | | ----------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- | | Server (`HOST`, `PORT`, `MCP_HOST`, `CORS_ORIGINS`) | **Restart required.** Bound at uvicorn start. | | Storage (`DATA_DIR`, `KG_BASE_DIR`, `DATABASE_URL`, `UPLOAD_DIR`) | **Restart required.** SQLite engine and LadybugDB connections are opened once. | | KG embeddings (`KG_EMBEDDING_*`) | **Restart required**, plus a backfill if you want existing nodes re-embedded. | | KG runtime (`KG_KUZU_*`, `KG_CONNECTION_POOL_SIZE`) | **Restart required.** LadybugDB pool is constructed at startup. | | KG queue (`KG_QUEUE_*`) | **Hot-reload.** APScheduler re-reads on every claim with a 5 s debounce. ([inventory:790–791](https://github.com/OktoLabsAI/okto-pulse-core)) | | KG decay tick (`KG_DECAY_TICK_*`) | **Hot-reload via `PUT /settings/runtime`.** APScheduler reschedules the job in place. ([inventory:792–793](https://github.com/OktoLabsAI/okto-pulse-core)) | | MCP tracing (`MCP_TRACE_ENABLED`, `MCP_TRACE_DIR`) | **Restart required.** Read once at MCP-process start by the trace middleware. | *** ## Related Ports, bind hosts, CORS, logging, and worker tuning in depth. The on-disk layout the storage variables control, plus backup and migration. The 216 MCP tools, including auth flow and the tracing knobs above. The pre-baked container that sets `HOST`, `MCP_HOST`, `DATA_DIR`, and `HF_HOME` for you. # Server configuration Source: https://docs.oktolabs.ai/configuration/server-config Tune the Pulse runtime: API and MCP ports, bind hosts, CORS, logging, and uvicorn workers. Single Python process, two listeners, defaults that work locally and in containers. # Server configuration `okto-pulse serve` is one Python process running two uvicorn listeners — the API + Web UI on `8100` and the MCP server on `8101` ([`80-pulse-feature-inventory.md:213–215`](https://github.com/OktoLabsAI/okto-pulse-core)). Configuration is read from environment variables and an optional `.env` file via `pydantic-settings`. Every field on `CoreSettings` accepts an env-var override using its uppercase field name ([`80-pulse-feature-inventory.md:178–180`](https://github.com/OktoLabsAI/okto-pulse-core)). This page covers the runtime knobs you actually need to touch: ports, bind hosts, CORS, logging, and worker tuning. For the full env-var reference, see [Environment variables](/configuration/environment-variables). For where Pulse stores data, see [Storage paths](/configuration/storage-paths). *** ## Ports Two listeners, two defaults. | Listener | Default port | Source | | ------------ | ------------ | -------------------------------------------------------------------------------------------------- | | API + Web UI | `8100` | `DEFAULT_API_PORT` in `cli.py:20` ([inventory:213](https://github.com/OktoLabsAI/okto-pulse-core)) | | MCP server | `8101` | `DEFAULT_MCP_PORT` in `cli.py:21` ([inventory:214](https://github.com/OktoLabsAI/okto-pulse-core)) | ### Override on the command line ```bash theme={null} okto-pulse serve --api-port 9100 --mcp-port 9101 --accept-terms ``` `--api-port` writes `OKTO_PULSE_PORT` and `--mcp-port` writes `OKTO_PULSE_MCP_PORT` into the process environment **before** importing `okto_pulse.community.main` — that module evaluates `app = create_community_app()` at import time and bakes the port values into `/config.js` for the Web UI ([inventory:53–60](https://github.com/OktoLabsAI/okto-pulse-core)). Setting them later, after the import, is too late. ### Override via environment ```bash theme={null} export OKTO_PULSE_PORT=9100 export OKTO_PULSE_MCP_PORT=9101 okto-pulse serve --accept-terms ``` ```text theme={null} Okto Pulse listening on: API + UI http://127.0.0.1:9100 MCP http://127.0.0.1:9101/mcp ``` Both ports must be free on the bind host before `serve` starts. Run `okto-pulse status` to confirm the current binding ([inventory:63–80](https://github.com/OktoLabsAI/okto-pulse-core)). *** ## Bind addresses Pulse separates the two listeners' bind hosts on purpose: the API (port 8100) defaults to loopback because it serves the Web UI and admin endpoints, while the MCP server (port 8101) needs to be reachable from the agent. | Field | Default | Env var | Notes | | -------- | ---------------------------------------- | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `host` | `127.0.0.1` | `HOST` | API + Web UI bind. Loopback only by design ([`CoreSettings.host`](https://github.com/OktoLabsAI/okto-pulse-core), inventory:761) | | MCP host | `0.0.0.0` (Docker) / `127.0.0.1` (local) | `MCP_HOST` | Read at runtime in `community/main.py` (since v0.1.12) and in `core/mcp/server.py`. Docker images sed-patch the binding line so `MCP_HOST` takes effect there too. | Both listeners bind `127.0.0.1`. Reachable only from the same machine. This is the safe default — your agent connects via `http://localhost:8101/mcp?api_key=...`. ```bash theme={null} okto-pulse serve --accept-terms ``` ```text theme={null} INFO uvicorn Started server process [12345] INFO uvicorn Uvicorn running on http://127.0.0.1:8100 INFO okto_pulse.mcp MCP listening on http://127.0.0.1:8101/mcp ``` Inside a container, `127.0.0.1` is unreachable from the host even with `-p 8101:8101`. You must bind `0.0.0.0` inside the container. The published port (`-p 127.0.0.1:8101:8101`) keeps the surface limited to your host machine. ```bash theme={null} docker run -d \ -p 127.0.0.1:8100:8100 \ -p 127.0.0.1:8101:8101 \ -e HOST=0.0.0.0 \ -e MCP_HOST=0.0.0.0 \ -e DATA_DIR=/data \ -e KG_BASE_DIR=/data \ -v okto-pulse-data:/data \ ghcr.io/oktolabsai/okto-pulse:latest ``` See [Docker install](/install/docker) for the full container recipe. Exposing Pulse to your LAN means anyone on the network with the API key can reach the MCP server. Only do this for a trusted network and behind a firewall. ```bash theme={null} HOST=0.0.0.0 MCP_HOST=0.0.0.0 okto-pulse serve --accept-terms ``` Never bind `0.0.0.0` on a public network without a firewall. The MCP API key is the only thing between an attacker and full board control. Use `127.0.0.1` for local work, a private network plus firewall for shared workstations, and a reverse proxy with TLS termination (Caddy, nginx, Traefik) if you must expose Pulse beyond the host. *** ## CORS The API enforces CORS on the Web UI and any third-party browser client. | Field | Default (core) | Default (community) | Env var | | -------------- | --------------------------------------------- | ------------------- | -------------- | | `cors_origins` | `http://localhost:5173,http://localhost:3000` | `*` | `CORS_ORIGINS` | The community edition overrides the core default to `*` so the bundled Web UI works regardless of how you reach it ([inventory:765](https://github.com/OktoLabsAI/okto-pulse-core), inventory:191). Override per environment by setting `CORS_ORIGINS` to a comma-separated list: ```bash theme={null} CORS_ORIGINS="http://localhost:5173,https://pulse.internal.example.com" \ okto-pulse serve --accept-terms ``` ```text theme={null} INFO okto_pulse.api CORS allow_origins=['http://localhost:5173', 'https://pulse.internal.example.com'] ``` CORS is enforced by the API, not the MCP server. MCP requests are server-to-server and not subject to CORS — the API key is the access control there. *** ## Logging Pulse uses Python's standard `logging` module. Logs stream to stdout/stderr by default. ### Log level Set via `DEBUG=true` or by configuring logging directly with standard Python tooling. There is no dedicated `LOG_LEVEL` env var; `DEBUG` toggles `INFO` → `DEBUG` for `okto_pulse.*` loggers. | Env var | Default | Effect | | ------------- | ------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `DEBUG` | `false` | When `true`, raises `okto_pulse.*` loggers from `INFO` to `DEBUG` and surfaces SQLAlchemy echo on the API. Source: `CoreSettings.debug` ([inventory:753](https://github.com/OktoLabsAI/okto-pulse-core)) | | `ENVIRONMENT` | `development` | Free-form label, used in startup banners and exposed at `GET /health`. Source: `CoreSettings.environment` ([inventory:754](https://github.com/OktoLabsAI/okto-pulse-core)) | ```bash theme={null} DEBUG=true okto-pulse serve --accept-terms ``` ```text theme={null} DEBUG okto_pulse.api request POST /api/v1/cards DEBUG sqlalchemy.engine BEGIN (implicit) DEBUG sqlalchemy.engine SELECT cards.id, cards.title FROM cards WHERE ... INFO okto_pulse.mcp tool call okto_pulse_create_card → ok (32ms) ``` ### Log destinations By default, logs go to: * **stdout** for `INFO` and below * **stderr** for `WARNING`, `ERROR`, `CRITICAL` * **No file logging** — the process does not write a log file. Capture stdout/stderr if you need persistence. For a containerized deployment, let the container runtime capture the streams: ```bash theme={null} docker logs -f okto-pulse > pulse.log 2>&1 ``` For a `systemd` unit, journald captures both streams automatically: ```bash theme={null} journalctl -u okto-pulse.service -f ``` ### MCP call tracing Independent of the standard logger, Pulse can record every MCP tool call to a JSONL trace. | Env var | Default | Purpose | | ------------------- | --------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- | | `MCP_TRACE_ENABLED` | unset | Set to `1` (or `true`/`yes`) to enable tracing. Source: [`core/mcp/trace_middleware.py:49`](https://github.com/OktoLabsAI/okto-pulse-core) | | `MCP_TRACE_DIR` | `${KG_BASE_DIR}/mcp_traces` | Output directory; one `session_*.jsonl` per MCP session. Source: [`core/mcp/trace_middleware.py:13`](https://github.com/OktoLabsAI/okto-pulse-core) | ```bash theme={null} MCP_TRACE_ENABLED=1 okto-pulse serve --accept-terms ``` ```text theme={null} $ ls ~/.okto-pulse/mcp_traces/ session_2026-05-07T14-12-03_a3f9.jsonl $ head -1 ~/.okto-pulse/mcp_traces/session_2026-05-07T14-12-03_a3f9.jsonl {"ts":"2026-05-07T14:12:04Z","tool":"okto_pulse_get_active_board","args":{},"result_summary":"ok","ms":8} ``` Use traces to debug tool selection or to replay sessions against the MCP test harness. See [Troubleshooting](/concepts/sdlc-flow#mcp-tracing) for replay tooling. *** ## Worker tuning (uvicorn) Pulse runs with a single uvicorn worker, by default and by design. `okto-pulse serve` exposes `--api-port`, `--mcp-port`, and `--accept-terms` only — there is no `--workers` flag ([`okto-pulse/src/okto_pulse/community/cli.py:223–276`](https://github.com/OktoLabsAI/okto-pulse) / [inventory:53–60](https://github.com/OktoLabsAI/okto-pulse-core)). The KG consolidation pipeline, the queue scheduler, and the embedded LadybugDB graph all assume one writer per process; spawning multiple uvicorn workers would create concurrent writers, lock contention, and split queue state. **Do not bypass the CLI to run Pulse with multiple uvicorn workers.** The single-worker model is required for KG correctness — concurrent writers will hit the LadybugDB advisory lock and dead-letter queue entries. Scale by running multiple Pulse instances on different ports against different data directories instead — one Pulse process per board cluster. What you **can** tune: | Concurrency surface | Setting | Default | Range | | ------------------------------------------------------------------ | --------------------------------- | ------- | --------- | | KG consolidation workers (asyncio tasks inside the single process) | `KG_QUEUE_MAX_CONCURRENT_WORKERS` | `4` | 1–16 | | KG queue poll interval | `KG_QUEUE_MIN_INTERVAL_MS` | `100` | 0–1000 ms | | LadybugDB connection pool | `KG_CONNECTION_POOL_SIZE` | `8` | 1–32 | | LadybugDB buffer pool (memory) | `KG_KUZU_BUFFER_POOL_MB` | `256` | 16–512 MB | Sources: `CoreSettings` fields `kg_queue_max_concurrent_workers`, `kg_queue_min_interval_ms`, `kg_connection_pool_size`, `kg_kuzu_buffer_pool_mb` ([inventory:780–784](https://github.com/OktoLabsAI/okto-pulse-core)). The `KG_KUZU_*` and `kg_kuzu_*` field names are legacy — Pulse uses LadybugDB (the Kùzu-derived engine) under the hood since 2026-05-03. The variable names are kept stable for backward compatibility; the underlying engine is LadybugDB. `KG_QUEUE_*` and `KG_DECAY_TICK_*` fields are **hot-reloadable**. APScheduler re-reads them with a 5-second debounce and `kg_decay_tick_*` can be updated through `PUT /settings/runtime` without a restart ([inventory:790–793](https://github.com/OktoLabsAI/okto-pulse-core)). *** ## Reverse proxy notes If you front Pulse with Caddy, nginx, or Traefik: * Bind Pulse to `127.0.0.1` and let the proxy terminate TLS and forward. * Set `MCP_HOST=127.0.0.1` to keep the MCP listener loopback-only behind the proxy. * Forward `Host`, `X-Forwarded-For`, and `X-Forwarded-Proto` so the API renders absolute URLs correctly. * WebSockets are not used by the API or MCP — plain HTTP/1.1 is sufficient. Streamable HTTP responses (MCP SSE) require the proxy to disable response buffering on `/mcp`. ```caddyfile theme={null} pulse.internal.example.com { @mcp path /mcp* handle @mcp { reverse_proxy 127.0.0.1:8101 { flush_interval -1 } } handle { reverse_proxy 127.0.0.1:8100 } } ``` *** ## Verifying the running config `okto-pulse status` reads the SQLite metadata and probes the configured ports: ```bash theme={null} okto-pulse status ``` ```text theme={null} Okto Pulse status ───────────────── Data dir: /Users/you/.okto-pulse Database: /Users/you/.okto-pulse/data/pulse.db (412 KB) Boards: 1 Cards: 23 Specs: 4 Agents: 2 API server: running on 127.0.0.1:8100 MCP server: running on 127.0.0.1:8101 ``` Source: `cli.py:567–614` (`cmd_status`) ([inventory:67–78](https://github.com/OktoLabsAI/okto-pulse-core)). The 216 MCP tools exposed by the running process are listed in the [MCP reference](/reference/mcp). *** ## Related Where Pulse keeps its database, attachments, and per-board knowledge graphs. Full reference of every `CoreSettings` field and its env-var name. Run Pulse in a container with the right `HOST` and `MCP_HOST` defaults. Connect Claude Code, Cursor, Cline, Windsurf, or Codex to your board. # Storage paths Source: https://docs.oktolabs.ai/configuration/storage-paths Where Pulse keeps its database, attachments, per-board knowledge graphs, and traces — plus how to relocate, back up, and migrate the data directory between machines. # Storage paths Pulse is local-first. Every byte the server writes — board metadata, cards, specs, attachments, knowledge-graph nodes — lives under a single root directory on your machine. By default that root is `~/.okto-pulse/`. You can move it, mount it as a Docker volume, or back it up with `tar`. There is no remote dependency. This page documents the on-disk layout, the override knobs, the Docker volume gotcha, and how to move the data directory between machines safely. For runtime configuration (ports, bind hosts, logging) see [Server configuration](/configuration/server-config). For the full env-var reference see [Environment variables](/configuration/environment-variables). *** ## Default layout Source: `okto-pulse/src/okto_pulse/community/config.py:CommunitySettings._derive_paths` ([inventory:160–174](https://github.com/OktoLabsAI/okto-pulse-core)). ```text theme={null} ~/.okto-pulse/ ├── data/ │ └── pulse.db SQLite (WAL mode, FK ON) — boards, cards, specs, queue, audit ├── uploads/ Card file attachments (one file per Attachment row) ├── boards/ │ └── {board_id}/ │ └── graph.lbug Per-board knowledge graph (LadybugDB) ├── global/ │ └── discovery.lbug Cross-board discovery index (LadybugDB) └── mcp_traces/ MCP tool-call traces (only if MCP_TRACE_ENABLED=1) └── session_{ts}_{id}.jsonl ``` The root resolves to `Path.home() / ".okto-pulse"` when `data_dir` is empty, evaluated at startup by `CommunitySettings._derive_paths` ([inventory:162](https://github.com/OktoLabsAI/okto-pulse-core)). | Path | Contents | Source | | -------------------------------------------- | ------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ | | `~/.okto-pulse/data/pulse.db` | SQLite database, WAL mode, FK ON. 38 SQLAlchemy tables (boards, cards, specs, queue, audit, etc.) | [inventory:165](https://github.com/OktoLabsAI/okto-pulse-core), [inventory:1022–1077](https://github.com/OktoLabsAI/okto-pulse-core) | | `~/.okto-pulse/uploads/` | Per-card file attachments referenced by `Attachment.file_path` | [inventory:166](https://github.com/OktoLabsAI/okto-pulse-core) | | `~/.okto-pulse/boards/{board_id}/graph.lbug` | One LadybugDB graph per board: nodes, edges, HNSW vector indexes | [inventory:167](https://github.com/OktoLabsAI/okto-pulse-core), [inventory:927](https://github.com/OktoLabsAI/okto-pulse-core) | | `~/.okto-pulse/global/discovery.lbug` | Cross-board discovery index (entities, search history) | [inventory:168](https://github.com/OktoLabsAI/okto-pulse-core), [inventory:928](https://github.com/OktoLabsAI/okto-pulse-core) | | `~/.okto-pulse/mcp_traces/` | One JSONL file per MCP session when tracing is on | [inventory:771–772](https://github.com/OktoLabsAI/okto-pulse-core) | The graph store is **LadybugDB**, not Kuzu. Kuzu was retired on 2026-05-03; the file extension `.lbug` is the LadybugDB on-disk format. Some env-var names (`KG_KUZU_BUFFER_POOL_MB`, `KG_CONNECTION_POOL_SIZE`) keep the legacy `KUZU` prefix for backward compatibility — they configure the LadybugDB engine. *** ## Overriding the data directory `DATA_DIR` is the single knob. It maps to the `data_dir` field on `CommunitySettings` ([`community/config.py:11`](https://github.com/OktoLabsAI/okto-pulse-core)) — pydantic-settings reads it with `case_sensitive=False` and no env-prefix, so the field name uppercased is the env-var name. Set it before `okto-pulse serve` starts and every subdirectory rebases under the new root. ```bash theme={null} export DATA_DIR=/srv/pulse okto-pulse serve --accept-terms ``` ```text theme={null} $ tree -L 2 /srv/pulse /srv/pulse ├── boards │ └── 01HZQ8... ├── data │ └── pulse.db ├── global │ └── discovery.lbug └── uploads ``` For finer control the underlying core knob is `KG_BASE_DIR` ([inventory:189](https://github.com/OktoLabsAI/okto-pulse-core), [inventory:773](https://github.com/OktoLabsAI/okto-pulse-core)) — when set independently it relocates only the per-board and global graph files, leaving SQLite and uploads at the original path: | Env var | Default | Affects | Source | | ----------------- | ---------------------------------------------- | ------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `DATA_DIR` | `~/.okto-pulse` | All paths above | `CommunitySettings.data_dir` ([`community/config.py:11–22`](https://github.com/OktoLabsAI/okto-pulse-core), [inventory:162](https://github.com/OktoLabsAI/okto-pulse-core)) | | `KG_BASE_DIR` | `~/.okto-pulse` | `boards/`, `global/` only | `CoreSettings.kg_base_dir` ([inventory:189](https://github.com/OktoLabsAI/okto-pulse-core)) | | `DATABASE_URL` | `sqlite+aiosqlite:///{data_dir}/data/pulse.db` | SQLite location | `CoreSettings.database_url` ([inventory:185](https://github.com/OktoLabsAI/okto-pulse-core)) | | `UPLOAD_DIR` | `{data_dir}/uploads` | Attachments only | `CoreSettings.upload_dir` ([inventory:186](https://github.com/OktoLabsAI/okto-pulse-core)) | | `MAX_UPLOAD_SIZE` | `10485760` (10 MB) | Per-attachment cap | `CoreSettings.max_upload_size` ([inventory:187](https://github.com/OktoLabsAI/okto-pulse-core)) | Do not split `DATA_DIR` and `KG_BASE_DIR` across filesystems unless you have a reason. The KG consolidation pipeline reads from the SQLite queue and writes to LadybugDB in the same transaction window — putting them on different filesystems removes any failure-atomicity guarantees you might assume. *** ## Docker: the volume gotcha Inside the official container, the data root is `/data` and is set via `DATA_DIR=/data` and `KG_BASE_DIR=/data`. The compose file ships in `okto-pulse/docker-compose.yml` and declares an **unprefixed** named volume: ```yaml theme={null} services: okto-pulse: environment: MCP_HOST: "0.0.0.0" DATA_DIR: /data KG_BASE_DIR: /data volumes: - okto-pulse-data:/data volumes: okto-pulse-data: # ← unprefixed; this is where live data lives ``` **Compose may auto-prefix the volume name.** Running `docker compose up` from a project named, for example, `okto-pulse/` typically creates `okto-pulse_okto-pulse-data` — a different volume from the unprefixed `okto-pulse-data` that production scripts and snapshots reference. The board "looks empty" because Pulse is reading a brand-new volume. Fix: declare the volume as external in an override file so Compose never re-namespaces it. ```yaml theme={null} # docker-compose.override.yml services: okto-pulse: volumes: - okto-pulse-data:/data volumes: okto-pulse-data: external: true ``` Then `docker volume create okto-pulse-data` once and every `compose up` will reuse it. Verify which volume your container is actually using: ```bash theme={null} docker inspect okto-pulse --format '{{range .Mounts}}{{.Name}} -> {{.Destination}}{{"\n"}}{{end}}' ``` ```text theme={null} okto-pulse-data -> /data ``` If the left-hand name shows a project prefix (e.g. `okto-pulse_okto-pulse-data`), you are on the wrong volume. See [Docker install](/install/docker) for the full container recipe. *** ## Backup strategy Pulse data is plain files. A consistent backup needs two things: SQLite at a transaction boundary, and the LadybugDB files quiesced. The simplest correct backup is offline. Stop `okto-pulse serve` and the consolidation worker stops with it. ```bash theme={null} pkill -INT -f "okto-pulse serve" ``` For a containerized deploy: ```bash theme={null} docker stop okto-pulse ``` A single `tar` of the root captures everything Pulse needs to restore. ```bash theme={null} tar -czf pulse-backup-$(date +%Y%m%d).tar.gz -C ~ .okto-pulse ``` For the Docker named volume: ```bash theme={null} docker run --rm \ -v okto-pulse-data:/data:ro \ -v "$PWD":/backup \ alpine tar -czf /backup/pulse-backup-$(date +%Y%m%d).tar.gz -C /data . ``` ```bash theme={null} okto-pulse serve --accept-terms ``` Or `docker start okto-pulse`. The next agent connection re-opens SQLite in WAL mode and re-attaches each per-board LadybugDB on demand. ### Online (hot) backup If you cannot stop the server, use SQLite's online backup API for `pulse.db` and copy the LadybugDB files separately. SQLite first: ```bash theme={null} sqlite3 ~/.okto-pulse/data/pulse.db ".backup '/tmp/pulse.db'" ``` Then snapshot `boards/`, `global/`, and `uploads/`. There is a small window where the SQLite snapshot may reference KG queue entries that have not yet landed in LadybugDB; on restore, the consolidation worker will replay any in-flight entries from the queue table. Do **not** copy the `.lbug` files while a write is in flight. The advisory lock in `kg/workers/advisory_lock.py` prevents concurrent writers, but it does not prevent a copy tool from reading a half-written page. Pause writes (stop the server) or rely on a filesystem snapshot (LVM, ZFS, APFS) for atomic point-in-time copies. *** ## Migrating between machines Pulse stores no machine-specific state. You can move the data directory verbatim from one host to another as long as the receiving Pulse version matches. ```bash theme={null} # On source tar -czf pulse-data.tar.gz -C ~ .okto-pulse scp pulse-data.tar.gz target-host:/tmp/ # On target ssh target-host tar -xzf /tmp/pulse-data.tar.gz -C ~ okto-pulse --version # must match source version okto-pulse serve --accept-terms ``` ```text theme={null} Okto Pulse listening on: API + UI http://127.0.0.1:8100 MCP http://127.0.0.1:8101/mcp ``` **Match versions on both ends.** The KG schema version is stamped in each `graph.lbug` (`SCHEMA_VERSION = "0.3.3"` at the time of writing — `kg/schema.py`, [inventory:897](https://github.com/OktoLabsAI/okto-pulse-core)). A newer Pulse will run a forward migration on first open; an older Pulse will refuse to open a newer graph. Upgrade the target host **before** restoring. For SDLC pipelines that need to copy boards between Pulse instances at the same version, prefer a **direct data-dir copy** over API replay — the API replay path cannot reach `spec.in_progress` because the validated→in\_progress evaluation gate is enforced at the MCP layer only. Stop both servers, copy `data/pulse.db` and the relevant `boards/{board_id}/graph.lbug`, then trim the SQLite rows that should not move (queue entries, audit log) before restarting. *** ## Resetting state `okto-pulse reset` deletes the data directory after confirmation. Source: `cli.py` `cmd_reset` ([inventory:139–151](https://github.com/OktoLabsAI/okto-pulse-core)). ```bash theme={null} okto-pulse reset ``` ```text theme={null} This will delete /Users/you/.okto-pulse and ALL boards, cards, specs, and graphs. Type the data directory path to confirm: /Users/you/.okto-pulse Removed. ``` **Never delete `.lbug` files manually to fix a KG issue.** Use the documented KG operations (`okto-pulse kg backfill`, `okto-pulse kg dedup-entities`) — see [KG operations](/concepts/knowledge-graph). Deleting a graph file orphans its SQLite queue entries and the `KuzuNodeRef` rows that point at it; the next consolidation pass will fail to commit and dead-letter the entries. *** ## Inspecting current paths `okto-pulse status` prints the resolved data directory and database path: ```bash theme={null} okto-pulse status ``` ```text theme={null} Okto Pulse status ───────────────── Data dir: /Users/you/.okto-pulse Database: /Users/you/.okto-pulse/data/pulse.db (412 KB) Boards: 1 Cards: 23 Specs: 4 Agents: 2 API server: running on 127.0.0.1:8100 MCP server: running on 127.0.0.1:8101 ``` Source: `cli.py:567–614` (`cmd_status`) ([inventory:67–78](https://github.com/OktoLabsAI/okto-pulse-core)). The 216 MCP tools exposed by the running process operate against the paths shown here — every board read, every consolidation, every attachment upload resolves under this root. *** ## Related Ports, bind hosts, CORS, logging, and worker tuning. Full reference of every `CoreSettings` field and its env-var name. What lives in `graph.lbug` and how consolidation populates it. The named-volume recipe and the unprefixed-volume gotcha. # Connect an agent Source: https://docs.oktolabs.ai/connect-agent Connect Claude Code, Cursor, Cline, Windsurf, Goose, or Codex to your Pulse board via MCP — one command to generate the config, then start your agent. # Connect an agent Pulse exposes 216 tools via the [Model Context Protocol](https://modelcontextprotocol.io) on port `8101`. Any MCP-compatible coding agent can connect to it and gain full access to your board: creating ideations, writing specs, moving cards, querying the knowledge graph, and closing tasks with evidence. *** ## Prerequisites ```bash theme={null} okto-pulse serve --accept-terms ``` Pulse binds the API + UI to port `8100` and the MCP server to port `8101`. Both must be reachable from wherever your agent runs. Set `MCP_HOST=0.0.0.0` in your container environment so the MCP server binds to all interfaces. If left as `127.0.0.1` (the default), agents outside the container cannot reach it. `okto-pulse init --agents` generates a scoped API key for each agent. Run it from your project root — the key is embedded in the `.mcp.json` it writes. If you already ran `init`, your key is in the `.mcp.json` in your project directory. Do not commit that file to a public repository. *** ## Generate `.mcp.json` Run this once from your project root: ```bash theme={null} okto-pulse init --agents ``` This writes `.mcp.json` in the current working directory: ```json theme={null} { "mcpServers": { "okto-pulse": { "url": "http://127.0.0.1:8101/mcp?api_key=dash_..." } } } ``` The `api_key` scopes the agent to your board and authenticates every tool call. Most MCP-compatible agents auto-detect this file when launched from the same directory. To generate config for a specific agent only: ```bash theme={null} okto-pulse init --agents claude okto-pulse init --agents cursor ``` To use a non-default MCP port: ```bash theme={null} okto-pulse serve --mcp-port 8200 --accept-terms ``` Then update the generated `.mcp.json` URL to use the same port. *** ## Per-agent setup Claude Code auto-detects `.mcp.json` in the working directory. No manual config needed. ```bash theme={null} okto-pulse init --agents ``` Run from the same directory where you launch Claude Code. ```bash theme={null} claude ``` Claude Code reads `.mcp.json` on each session start. Inside a Claude Code session, type: ```text theme={null} /mcp ``` `okto-pulse` should appear in the server list with a green status indicator. Claude Code re-reads `.mcp.json` each time a new session starts. If you rotate your API key, just re-run `okto-pulse init --agents` and restart the session — no other config changes needed. Cursor auto-detects `.mcp.json` in project roots in recent versions. You can also add the server manually via the Cursor settings UI. ```bash theme={null} okto-pulse init --agents ``` Launch Cursor from the same directory. Cursor will detect `.mcp.json` automatically in recent builds. Open **Cursor → Preferences → MCP** and paste the MCP URL from `.mcp.json`: ```text theme={null} http://127.0.0.1:8101/mcp?api_key=dash_... ``` Save and restart Cursor. Auto-detection of `.mcp.json` was added in Cursor 0.46+. If you're on an older build, use the manual setup step above. Cline auto-detects `.mcp.json` in the project directory when the VS Code extension is active. ```bash theme={null} okto-pulse init --agents ``` Open VS Code with the Cline extension active. The project root must contain the `.mcp.json` file. In the Cline sidebar, open **MCP Servers**. `okto-pulse` should appear as a connected server. If it doesn't appear, try reloading the VS Code window (`Cmd+Shift+P → Developer: Reload Window`). Windsurf auto-detects `.mcp.json` in the project directory. ```bash theme={null} okto-pulse init --agents ``` Launch Windsurf from the project root. The `okto-pulse` server appears in the Cascade tool list automatically. Open the Cascade panel and look for `okto-pulse` in the tools list. If the server doesn't appear, check that `.mcp.json` is in the root of the folder Windsurf has open (not a subdirectory). Goose (by Block) supports MCP servers via `~/.config/goose/config.yaml`. ```bash theme={null} okto-pulse init --agents ``` Open `.mcp.json` and copy the full URL value (including `?api_key=dash_...`). Edit `~/.config/goose/config.yaml` and add an extension entry: ```yaml theme={null} extensions: okto-pulse: type: remote_extension name: okto-pulse uri: http://127.0.0.1:8101/mcp?api_key=dash_... enabled: true ``` Replace the URI with the full URL from your `.mcp.json`. Goose reads `config.yaml` at startup. Start a new Goose session for the change to take effect. Config shown is for Goose 1.x. If you're on an earlier release, see the [Goose documentation](https://block.github.io/goose/) for the legacy extension format. Codex (OpenAI CLI) supports user-wide MCP configuration via `~/.codex/config.toml`. ```bash theme={null} okto-pulse init --agents ``` Open `.mcp.json` and copy the full URL value. Edit `~/.codex/config.toml` and add: ```toml theme={null} [[mcp_servers]] name = "okto-pulse" url = "http://127.0.0.1:8101/mcp?api_key=dash_..." ``` Replace the URL with the one from your `.mcp.json`. Codex reads `config.toml` at startup. Kill any running Codex session and start a new one. If you want Codex to connect on a per-project basis rather than globally, you can also place `.mcp.json` in your project directory — Codex will detect it automatically in recent CLI versions. *** ## Verify the connection Once your agent is connected, ask it to inspect your board: ```text theme={null} Use the Okto Pulse MCP tools. List all boards I have access to and summarize the current active work. ``` A correctly connected agent will call `okto_pulse_list_my_boards`, enumerate your boards, and return a summary of open ideations, specs, and cards. If the agent responds that it has no such tools available, the MCP server is not connected — see Troubleshooting below. *** ## Permissions on first connect Pulse generates a scoped key for each agent with a default permission preset. The preset determines which categories of tools the agent can call. | Preset | What it can do | | ---------------- | -------------------------------------------------------------------------- | | **Full Control** | All 216 tools — read, write, move, validate, delete | | **Spec Writer** | Create and update specs, add Q\&A, write business rules and test scenarios | | **Executor** | Read board, create and move cards, attach evidence, close tasks | | **QA** | Read board, submit validations, run test scenarios | | **Validator** | Read board, submit task validations only | The default preset for newly generated keys is **Full Control**. You can change a key's permissions in the Pulse settings UI (**Board → Agents → Edit**). *** ## Troubleshooting The MCP server is not reachable or the agent didn't pick up `.mcp.json`. 1. Confirm Pulse is running: `okto-pulse status` 2. Confirm port 8101 is listening: `curl http://127.0.0.1:8101/mcp` 3. Confirm `.mcp.json` is in the project root the agent is using — not a subdirectory 4. Restart the agent after generating `.mcp.json` `okto-pulse serve` is not running, or it started on a different port. ```bash theme={null} okto-pulse status ``` If the MCP port shows **stopped**, start Pulse with `okto-pulse serve --accept-terms`. If you started on a custom port, pass `--mcp-port` to match: `okto-pulse serve --mcp-port 8200`. The MCP server binds to `127.0.0.1` by default, which is not reachable from inside Docker containers or remote machines. Set the environment variable before starting Pulse: ```bash theme={null} MCP_HOST=0.0.0.0 okto-pulse serve --accept-terms ``` Then update `.mcp.json` to use the container's host IP instead of `127.0.0.1`. The key in `.mcp.json` may be stale or was rotated. Regenerate the config: ```bash theme={null} okto-pulse init --agents ``` Then restart your agent. The new key is written to `.mcp.json` in the current directory. Some older builds require manual configuration. Open the MCP settings in your agent and paste the URL from `.mcp.json` directly. The URL has the form: ```text theme={null} http://127.0.0.1:8101/mcp?api_key=dash_... ``` *** ## Next steps Run your first ideation-to-cards session with your connected agent. Full index of all 216 MCP tools, grouped by domain. # Contributing Source: https://docs.oktolabs.ai/contributing How to set up a development environment, run checks, and submit Pulse changes. # Contributing You can contribute to Pulse by working from the two source repos, running focused checks, and submitting a PR with evidence for the change. ## CLA requirement By submitting a pull request, you agree to the Contributor License Agreement in `CLA.md`. No separate signature is required. ## Dev environment setup ```bash theme={null} pip install -e ./okto-pulse-core -e ./okto-pulse pip install pytest pytest-asyncio psutil httpx ruff pyright build ``` ```text theme={null} Successfully installed development dependencies. ``` ## Running tests Core fast path: ```bash theme={null} cd okto-pulse-core pytest -m "not e2e" -q ``` Community package path: ```bash theme={null} cd okto-pulse pytest -q ``` ## Code style Run the same tools CI checks for package quality: ```bash theme={null} ruff check src/ pyright src/ python -m build ``` ## PR conventions Use a focused branch, describe the behavior change, include tests or explain the verification gap, and avoid mixing unrelated cleanup with the feature or fix. ## Security issues Do not open a public issue with exploit details. Follow `SECURITY.md` responsible disclosure guidance. ## Related pages * [Local development](/operations/local) * [CLI reference](/reference/cli) * [Upgrade](/operations/upgrade) # Your first board Source: https://docs.oktolabs.ai/first-board Walk a feature from raw idea to validated card using the full Pulse pipeline — Ideation, Spec, Sprint, Tasks, and Validation. # Your first board This guide walks a single feature — adding a rate-limit to an API — from raw idea to a validated, closed card. Every step uses real Pulse MCP tool names so you can follow along in Claude Code, Cursor, or any connected agent. By the end you will have: * An ideation with a scope assessment * A derived spec with acceptance criteria, business rules, and test scenarios * A sprint with cards * A card closed with evidence and a conclusion *** ## Prerequisites * Pulse installed and serving — see [Install](/install) * An agent connected via MCP — see [MCP setup](/mcp-setup) Your agent needs to call `okto_pulse_list_my_boards` to discover the board ID it will use throughout this session. *** ## Step 1 — Create an ideation Ideations are where raw requests land before any design work begins. Paste your request and let the agent structure it. **What your agent does:** ```text theme={null} Create an ideation: "Add per-user rate limiting to the /search endpoint. Burst: 20 req/s. Sustained: 5 req/s. Return 429 with Retry-After header." ``` **MCP tool called:** `okto_pulse_create_ideation` ```json theme={null} { "board_id": "a1b2c3d4-...", "title": "Per-user rate limiting on /search", "description": "Burst limit 20 req/s, sustained 5 req/s. Return 429 + Retry-After.", "context": "Currently no rate limiting exists. Load tests show search abuse spikes." } ``` The agent immediately pulls context from the Knowledge Graph before asking anything: **MCP tool called:** `okto_pulse_get_ideation_context` This returns prior decisions, constraints, and related entities already in the KG. If rate limiting was discussed in a previous sprint, the agent cites it here rather than re-deciding. *** ## Step 2 — Resolve ambiguity The agent runs the **ambiguity-killer protocol**: it asks clarifying questions using choice questions (not free text) to zero out ambiguity before advancing. **MCP tool called:** `okto_pulse_ask_ideation_choice_question` ```json theme={null} { "ideation_id": "...", "question": "Where should rate-limit counters be stored?", "choices": ["Redis (shared across instances)", "In-process (per-replica, no shared state)", "Database (durable, slower)"] } ``` You answer by selecting a choice. The agent records your response: **MCP tool called:** `okto_pulse_answer_ideation_question` The agent continues until all ambiguous axes are resolved. Open-ended Q\&A is also available: **MCP tool called:** `okto_pulse_ask_ideation_question` — for questions that don't fit a choice format. *** ## Step 3 — Evaluate scope Before advancing, the agent evaluates the ideation on three axes: domain breadth, ambiguity, and dependency risk. This produces a scope assessment that gates the move to Refined. **MCP tool called:** `okto_pulse_evaluate_ideation` ```json theme={null} { "ideation_id": "...", "domains": 2, "ambiguity": 1, "dependencies": 3, "justification": "Touches API middleware and Redis infra. Dependencies on cache invalidation and auth service are flagged." } ``` **MCP tool called:** `okto_pulse_move_ideation` ```json theme={null} { "ideation_id": "...", "status": "refined" } ``` The ideation is now ready to derive a spec from. *** ## Step 4 — Derive a spec Deriving a spec converts the structured ideation into a working document with acceptance criteria, functional requirements, and technical requirements pre-populated. **MCP tool called:** `okto_pulse_derive_spec_from_ideation` ```json theme={null} { "ideation_id": "..." } ``` The response includes the new spec ID. Everything from the ideation — Q\&A, knowledge entries, KG context — carries forward into the spec. *** ## Step 5 — Build the spec The spec is where implementation detail is locked down. The agent adds test scenarios, business rules, and API contracts. Each addition links to specific acceptance criteria. ### Add a test scenario **MCP tool called:** `okto_pulse_add_test_scenario` ```json theme={null} { "spec_id": "...", "title": "Rate limit exceeded returns 429", "description": "Send 21 sequential requests in 1 second as the same user. The 21st returns HTTP 429 with Retry-After header.", "acceptance_criteria_ref": "AC-1" } ``` ### Add a business rule **MCP tool called:** `okto_pulse_add_business_rule` ```json theme={null} { "spec_id": "...", "rule": "Rate-limit counters must be scoped to authenticated user ID, not IP address.", "rationale": "IP-based limiting blocks shared office networks. Auth user is the correct identity boundary." } ``` ### Add an API contract **MCP tool called:** `okto_pulse_add_api_contract` ```json theme={null} { "spec_id": "...", "endpoint": "GET /search", "response_on_limit": { "status": 429, "headers": {"Retry-After": ""}, "body": {"error": "rate_limit_exceeded", "retry_after": ""} } } ``` The agent queries the KG for similar decisions before finalizing contracts: **MCP tool called:** `okto_pulse_kg_find_similar_decisions` If the team decided on a 429 error format two sprints ago, that decision appears here. The agent cites it rather than re-deciding. *** ## Step 6 — Evaluate and advance the spec The spec evaluation is a qualitative gate. The agent (or a human reviewer) submits a structured assessment before the spec can advance past Approved. **MCP tool called:** `okto_pulse_submit_spec_evaluation` ```json theme={null} { "spec_id": "...", "score": 82, "narrative": "Acceptance criteria are complete and testable. Business rule on auth-scoped limits is unambiguous. API contract covers success and failure shapes. Missing: load-test baseline for Redis latency under burst — flagged as a card.", "recommendation": "approve" } ``` **MCP tool called:** `okto_pulse_move_spec` ```json theme={null} { "spec_id": "...", "status": "approved" } ``` *** ## Step 7 — Create a sprint A sprint is a time-boxed slice of spec work. The agent can suggest sprint splits or you can define the objective directly. **MCP tool called:** `okto_pulse_suggest_sprints` The agent proposes sprint slices. Accept one or define your own: **MCP tool called:** `okto_pulse_create_sprint` ```json theme={null} { "spec_id": "...", "title": "Rate limiting — Sprint 1: middleware + Redis counter", "objective": "Implement the per-user sliding-window counter in Redis and wire it into the /search middleware. 429 returned and test scenario AC-1 passes.", "expected_outcome": "All burst-limit test scenarios pass in CI. No auth-service changes required." } ``` Evaluate the sprint before activating it: **MCP tool called:** `okto_pulse_submit_sprint_evaluation` ```json theme={null} { "sprint_id": "...", "score": 78, "narrative": "Scope is deliverable in one sprint. Redis dependency is flagged — Redis must be running in the test environment.", "recommendation": "approve" } ``` **MCP tool called:** `okto_pulse_move_sprint` ```json theme={null} { "sprint_id": "...", "status": "active" } ``` *** ## Step 8 — Create and work cards Cards are the implementation tasks. The agent creates them linked to the active sprint and spec. **MCP tool called:** `okto_pulse_create_card` ```json theme={null} { "board_id": "...", "title": "Implement sliding-window rate limiter middleware", "card_type": "normal", "spec_id": "...", "sprint_id": "..." } ``` Link the card to the specific test scenario and business rule it implements: **MCP tool called:** `okto_pulse_link_task_to_scenario` **MCP tool called:** `okto_pulse_link_task_to_rule` When implementation starts, the agent retrieves the full task context before writing any code: **MCP tool called:** `okto_pulse_get_task_context` This returns the card, linked spec, all business rules, test scenarios, relevant decisions from the KG, and API contracts — the complete picture in one call. The agent uses this to avoid re-reading specs and decisions from chat history. Move the card through the workflow as work progresses: **MCP tool called:** `okto_pulse_move_card` — `not_started → started → in_progress` *** ## Step 9 — Close the card with evidence When implementation is done, the agent closes the card with a structured conclusion. The gate requires a conclusion, a completeness score, and a drift score. **MCP tool called:** `okto_pulse_update_card` ```json theme={null} { "card_id": "...", "conclusion": "Sliding-window counter implemented in Redis using sorted sets. Middleware added to /search route. Returns 429 + Retry-After header when burst or sustained limit exceeded. All three test scenarios pass in CI.", "completeness": 95, "completeness_justification": "All acceptance criteria covered. Minor gap: Redis TTL cleanup job not yet automated — added as a follow-up card.", "drift": 5, "drift_justification": "Minor scope addition: added unit test for edge case where user ID is null. Not in original spec but caught during implementation." } ``` **MCP tool called:** `okto_pulse_move_card` — `in_progress → done` The gate enforces: conclusion is required, completeness and drift scores are required, both justification fields are required. The agent cannot close the card without all four. *** ## Step 10 — Update test scenario evidence (optional but recommended) The test theater prevention gate requires structured evidence before a test scenario can be marked as passing. **MCP tool called:** `okto_pulse_update_test_scenario_status` ```json theme={null} { "spec_id": "...", "scenario_id": "...", "status": "passed", "test_file_path": "tests/middleware/test_rate_limit.py", "test_function": "test_burst_limit_returns_429", "last_run_at": "2026-05-07T14:30:00Z", "output_snippet": "PASSED tests/middleware/test_rate_limit.py::test_burst_limit_returns_429 in 0.42s" } ``` This prevents test scenarios from being marked as passing without a real test file and function to back them up. The sprint close re-validates this evidence before the sprint can be closed. *** ## Step 11 — Close the sprint With cards closed and evidence recorded, the sprint can close. **MCP tool called:** `okto_pulse_move_sprint` — `active → review` **MCP tool called:** `okto_pulse_submit_sprint_evaluation` — final review evaluation **MCP tool called:** `okto_pulse_move_sprint` — `review → closed` *** ## What the Knowledge Graph captured Every decision made during this flow — the Redis storage choice, the 429 response format, the auth-scoped counter rule — is consolidated into the Knowledge Graph automatically. The next ideation that touches rate limiting or Redis will find these decisions and cite them. **MCP tool called (automatically by the consolidation pipeline):** `okto_pulse_kg_begin_consolidation`, `okto_pulse_kg_add_node_candidate`, `okto_pulse_kg_commit_consolidation` In the next sprint, when the agent runs: **MCP tool called:** `okto_pulse_kg_find_similar_decisions` ...it will surface the decisions made here. Decisions survive session resets, model upgrades, and team changes. The graph persists; the chat does not. *** ## Agent setup The agent connection details — registering agents, scoping permissions, and rotating API keys — are covered in [Connect your agent](/connect-agent). *** ## Next steps The enforced stage machine behind every step in this guide. How decisions made here persist across sessions. All 216 tools with descriptions and groupings. # Bug fix workflow Source: https://docs.oktolabs.ai/guides/bug-fix-flow An end-to-end Pulse workflow for diagnosing, fixing, validating, and remembering a bug. # Bug fix workflow You can use Pulse to make a bug fix traceable from failing evidence to validated completion and KG learning. The goal is not just to close the card; it is to make the failure reusable context. ## Create a bug card Create a `bug` card with severity, reproduction steps, expected behavior, actual behavior, suspected area, and the failing evidence that proves the defect. ```text theme={null} okto_pulse_create_card(card_type="bug", severity="major", ...) ``` ## Assign to an agent Assign implementation to an Executor. Keep the Validator separate so the fix is reviewed independently. ## Root cause investigation Before editing, query the KG for prior decisions, contradictions, and lessons: ```text theme={null} okto_pulse_kg_get_learning_from_bugs okto_pulse_kg_find_contradictions okto_pulse_kg_find_similar_decisions ``` ## Fix and task validation The Executor implements the fix, records a conclusion, and moves the card to `validation`. The Validator submits task validation with confidence, completeness, drift, and justification. ```text theme={null} okto_pulse_submit_task_validation ``` ## Record the learning Closed bug cards can emit `Learning` nodes through consolidation. Write the root cause and prevention note clearly so the KG can retrieve it later. ## Search for similar bugs later Use natural KG query or the bug-learning tool before starting related work. ```text theme={null} okto_pulse_kg_query_natural(query="similar past bugs in auth redirect handling") ``` ## Related pages * [Cards](/concepts/card) * [Knowledge Graph](/concepts/knowledge-graph) * [Sprints and cards tools](/reference/mcp/sprints-cards) * [KG queries](/reference/mcp/kg/queries) # KG decision history Source: https://docs.oktolabs.ai/guides/kg-decisions How to retrieve old architecture decisions before writing new work. # KG decision history You can use the Knowledge Graph to recover design decisions from prior sprints before an agent writes new work. This keeps the next spec from contradicting decisions the team already made. ## The problem An agent starting a new spec may not know why a choice was made three sprints ago. The answer might live in an old spec, a bug learning, or a superseded decision. KG queries make that context discoverable. ## How decisions enter the KG Decisions recorded on specs consolidate into `Decision` nodes. Alternatives, constraints, entities, learnings, and supersedence edges can connect to those nodes. ## Query the decision history Use topic search when you know the area but not the exact node ID. ```text theme={null} okto_pulse_kg_get_decision_history(board_id="...", topic="agent permissions") ``` ## Follow supersedence When you have a decision ID, trace its replacement chain. ```text theme={null} okto_pulse_kg_get_supersedence_chain(board_id="...", decision_id="dec_...") ``` ## Find similar past decisions Use similarity before creating a new decision. It catches renamed or paraphrased topics. ```text theme={null} okto_pulse_kg_find_similar_decisions(board_id="...", topic="validation gate ownership") ``` ## Trace contradictions before writing a new spec Run contradiction search before introducing a change that might violate old constraints. ```text theme={null} okto_pulse_kg_find_contradictions(board_id="...") ``` ## Read-only reporting agent setup A reporting agent needs `kg.query.decision_history`, `kg.query.similar_decisions`, `kg.query.supersedence_chain`, and relevant entity read flags. It does not need `kg.session.commit` or admin flags. ## Related pages * [Knowledge Graph](/concepts/knowledge-graph) * [Decisions](/concepts/decisions) * [KG queries](/reference/mcp/kg/queries) * [Card and KG flags](/permissions/card-kg) # Multi-agent development Source: https://docs.oktolabs.ai/guides/multi-agent How to run a Spec, Executor, and Validator team on one Pulse board. # Multi-agent development You can run a multi-agent board by giving each agent a narrow role and letting Pulse enforce the boundaries. A simple production setup is Spec + Executor + Validator. ## Team structure | Agent | Preset | Owns | | --------------- | --------- | -------------------------------------------------------------------- | | Spec agent | Spec | Ideation, refinement, spec content, sprint planning, card breakdown. | | Executor agent | Executor | Card implementation through `validation`. | | Validator agent | Validator | Spec, sprint, and task gates. | Add QA when test scenario ownership should be separate from implementation. ## Setup Create the agents in the web UI, assign presets, then export MCP config. ```bash theme={null} okto-pulse init --agents spec-agent executor-agent validator-agent ``` ```json theme={null} { "mcpServers": { "okto-pulse-spec-agent": { "url": "http://127.0.0.1:8101/mcp?api_key=dash_..." } } } ``` ## Workflow 1. Spec agent creates ideation and asks ambiguity-killer questions. 2. Spec agent derives or writes the spec. 3. Validator submits spec validation when evidence is ready. 4. Spec agent derives cards and a sprint. 5. Executor implements cards and moves them to `validation` with conclusions. 6. Validator submits task validation and routes each card. ## Preventing cross-role drift The important rule is that implementers do not validate themselves. Executor can read validation records but cannot submit them or move `validation -> done`. ## Board-level overrides Use board overrides to restrict an agent on a sensitive board. For example, keep a shared Reporter read-only on production boards while allowing broader reads on evaluation boards. ## Common failure modes | Symptom | Cause | Fix | | -------------------------------------------------- | ---------------------------------------- | ------------------------------------ | | Executor gets permission denied on task validation | Executor lacks `card.validation.submit`. | Ask Validator to review. | | Spec agent cannot move approved spec to validated | Gate transition is Validator-owned. | Submit spec validation as Validator. | | Agent cannot act in current status | Missing `interact_in` flag. | Adjust preset or board override. | ## Related pages * [Agents and permissions](/concepts/agents) * [Built-in presets](/permissions/presets) * [Validation gates](/concepts/validation) # Introduction Source: https://docs.oktolabs.ai/index The control plane for AI-assisted software development. # Okto Pulse **Ship with AI. Stay in control.** Okto Pulse is the control plane for AI-assisted software development — specs, tasks, validation, and a knowledge graph that survives delivery. Get Pulse running locally in under 2 minutes. Your first ideation → spec → cards workflow. Connect Claude Code, Cursor, Cline, or any MCP-compatible agent. How Pulse persists decisions across sessions and releases. # Install Source: https://docs.oktolabs.ai/install Get Okto Pulse running locally in under two minutes. Python 3.11+, no account required. # Install Pulse runs as a single Python process on your machine. No cloud account. No data leaves your system. Two commands and you have a board. ## Prerequisites * Python 3.11 or higher * pip ```bash theme={null} python --version ``` If you are on macOS with Homebrew: `brew install python@3.12` *** ## Install Pulse ```bash theme={null} pip install okto-pulse ``` Verify: ```bash theme={null} okto-pulse --version ``` Pull and run the signed image from GitHub Container Registry: ```bash theme={null} docker run \ -p 8100:8100 \ -p 8101:8101 \ -v ~/.okto-pulse:/root/.okto-pulse \ ghcr.io/oktolabsai/okto-pulse:latest ``` The image is signed with Sigstore keyless signatures. SLSA provenance and a CycloneDX SBOM ship as image attestations. The embedding model is pre-baked — no first-run download needed. Open `http://localhost:8100` once the container is up. Clone both active repos as siblings: ```bash theme={null} git clone https://github.com/OktoLabsAI/okto-pulse-core git clone https://github.com/OktoLabsAI/okto-pulse ``` Install in development mode: ```bash theme={null} pip install -e ./okto-pulse-core -e ./okto-pulse ``` *** ## Initialize Run this in the directory where your agent will work. Pulse creates your board and writes the MCP configuration file your agent will use to connect. ```bash theme={null} okto-pulse init --agents ``` What it does: * Creates `~/.okto-pulse/` with your database and board data * Writes `.mcp.json` in the current directory with a scoped API key `.mcp.json` contains an agent API key. Do not commit it to a public repository. Add it to `.gitignore`. *** ## Start ```bash theme={null} okto-pulse serve --accept-terms ``` Pulse starts two listeners on a single process: | Endpoint | Default URL | | ------------------------- | --------------------------- | | Web board and API | `http://localhost:8100` | | MCP server (agent access) | `http://localhost:8101/mcp` | Open `http://localhost:8100`. Your board is ready. **First run note:** If you installed via pip, Pulse downloads the semantic search model (`all-MiniLM-L6-v2`, \~90 MB) on first start. This takes 30–60 seconds depending on your connection. The model is cached; subsequent starts are fast. *** ## Verify ```bash theme={null} okto-pulse status ``` Both ports should report as live. If you used custom ports: ```bash theme={null} okto-pulse serve --api-port 9000 --mcp-port 9001 --accept-terms okto-pulse status --api-port 9000 --mcp-port 9001 ``` If MCP port changes after initialization, regenerate `.mcp.json`: ```bash theme={null} okto-pulse init --agents ``` *** ## Where your data lives All Pulse data is stored locally at `~/.okto-pulse/`: ```text theme={null} ~/.okto-pulse/ data/pulse.db SQLite database (boards, specs, cards, decisions) boards/{id}/graph.lbug per-board knowledge graph uploads/{id}/ file attachments global/discovery.lbug cross-board discovery index ``` Nothing is sent to a remote server. *** ## Next steps Wire up Claude Code, Cursor, Cline, or any MCP-compatible agent. Idea → spec → cards in your first session. # Docker Source: https://docs.oktolabs.ai/install/docker Run Okto Pulse in a container. Signed image, pre-baked model, persistent volume. MCP server reachable from the host out of the box. # Docker install The official image ships from GitHub Container Registry with a pre-baked embedding model, Sigstore keyless signatures, SLSA provenance, and a CycloneDX SBOM. No first-run download. No account required. *** ## Pull and run ```bash theme={null} docker run -d \\ --name okto-pulse \\ -p 127.0.0.1:8100:8100 \\ -p 127.0.0.1:8101:8101 \\ -e HOST=0.0.0.0 \\ -e MCP_HOST=0.0.0.0 \\ -e DATA_DIR=/data \\ -e KG_BASE_DIR=/data \\ -v okto-pulse-data:/data \\ ghcr.io/oktolabsai/okto-pulse:latest ``` Open `http://localhost:8100` once the container starts. The board is ready. *** ## Why `MCP_HOST=0.0.0.0` is required Without `MCP_HOST=0.0.0.0`, the MCP server binds to `127.0.0.1` **inside** the container — a loopback address unreachable from your host even with `-p 8101:8101` published. Your agent will time out trying to connect. Always set `MCP_HOST=0.0.0.0` when running in Docker. The published port binding (`127.0.0.1:8101:8101`) ensures the MCP port is visible only to your machine, not your LAN — so setting `0.0.0.0` inside the container is safe. The same applies to `HOST=0.0.0.0` for the web board and API on port 8100. *** ## Connect your agent After the container starts, generate `.mcp.json` and copy it to your project directory: ```bash theme={null} docker exec okto-pulse okto-pulse init --agents docker cp okto-pulse:/app/.mcp.json ./.mcp.json ``` Add `.mcp.json` to `.gitignore` — it contains a scoped agent API key. To generate config for one agent only (Claude Code, for example): ```bash theme={null} docker exec okto-pulse okto-pulse init --agents claude docker cp okto-pulse:/app/.mcp.json ./.mcp.json ``` Get the API key directly if you need it for manual MCP client config: ```bash theme={null} docker exec okto-pulse okto-pulse api-key ``` *** ## Environment variables | Variable | Container default | Purpose | | ------------------- | ------------------ | ------------------------------------------------------------------------------------ | | `HOST` | `0.0.0.0` | API + UI uvicorn bind host. Must be `0.0.0.0` inside a container. | | `MCP_HOST` | `0.0.0.0` | MCP uvicorn bind host. Must be `0.0.0.0` inside a container. | | `DATA_DIR` | `/data` | Root for the SQLite database and uploads. Mount a volume here. | | `KG_BASE_DIR` | `/data` | Root for per-board knowledge graphs. Set to the same path as `DATA_DIR`. | | `HF_HOME` | `/opt/hf-cache` | Sentence-transformers cache. Pre-warmed at build time — do not mount over this path. | | `MCP_TRACE_ENABLED` | unset | Set to `1` to record every MCP tool call to `${MCP_TRACE_DIR}/session_*.jsonl`. | | `MCP_TRACE_DIR` | `/data/mcp_traces` | Trace output directory when `MCP_TRACE_ENABLED=1`. | *** ## Data persistence The container writes all state to `/data`: ```text theme={null} /data/ data/pulse.db SQLite database (boards, specs, cards, decisions) boards/{id}/graph.lbug per-board knowledge graph uploads/ card file attachments global/discovery.lbug cross-board discovery index mcp_traces/ MCP call traces (when MCP_TRACE_ENABLED=1) ``` Use a **named volume** (survives container replacement): ```bash theme={null} docker volume create okto-pulse-data docker run -d \\ --name okto-pulse \\ -p 127.0.0.1:8100:8100 \\ -p 127.0.0.1:8101:8101 \\ -e HOST=0.0.0.0 \\ -e MCP_HOST=0.0.0.0 \\ -e DATA_DIR=/data \\ -e KG_BASE_DIR=/data \\ -v okto-pulse-data:/data \\ ghcr.io/oktolabsai/okto-pulse:latest ``` Or a **host path** (easier to inspect and back up): ```bash theme={null} docker run -d \\ --name okto-pulse \\ -p 127.0.0.1:8100:8100 \\ -p 127.0.0.1:8101:8101 \\ -e HOST=0.0.0.0 \\ -e MCP_HOST=0.0.0.0 \\ -e DATA_DIR=/data \\ -e KG_BASE_DIR=/data \\ -v /your/host/path:/data \\ ghcr.io/oktolabsai/okto-pulse:latest ``` Do not mount over `/opt/hf-cache`. The embedding model is pre-baked into the image and the container starts offline-capable. Mounting over it forces a re-download. *** ## Docker Compose Two compose files ship with the `okto-pulse` repo. ### Pinned release (recommended) `docker-compose.prod.yml` installs a pinned version from PyPI. Clone only the `okto-pulse` repo — no sibling repo needed. ```bash theme={null} git clone https://github.com/OktoLabsAI/okto-pulse cd okto-pulse docker compose -f docker-compose.prod.yml build docker compose -f docker-compose.prod.yml up -d docker compose -f docker-compose.prod.yml logs -f ``` Export `.mcp.json` after first boot: ```bash theme={null} docker compose -f docker-compose.prod.yml exec okto-pulse okto-pulse init --agents docker compose -f docker-compose.prod.yml cp okto-pulse:/app/.mcp.json ./.mcp.json ``` ### Build from source `docker-compose.yml` builds wheels from local source. Use this when modifying `okto-pulse-core` or `okto-pulse`. Both repos must be cloned as siblings: ```text theme={null} OktoLabsAI/ okto-pulse/ okto-pulse-core/ ``` ```bash theme={null} cd okto-pulse docker compose build docker compose up -d docker compose logs -f ``` Export `.mcp.json`: ```bash theme={null} docker compose exec okto-pulse okto-pulse init --agents docker compose cp okto-pulse:/app/.mcp.json ./.mcp.json ``` *** ## LAN access Both compose files bind to `127.0.0.1` by default — the container is reachable from your machine only. To allow LAN access, change the `ports` mapping in the compose file: ```yaml theme={null} ports: - "0.0.0.0:8100:8100" - "0.0.0.0:8101:8101" ``` Put the host behind a reverse proxy with authentication before exposing to a LAN. The MCP API key is the only auth layer Pulse provides. *** ## Updating ```bash theme={null} docker pull ghcr.io/oktolabsai/okto-pulse:latest docker stop okto-pulse && docker rm okto-pulse # re-run the same docker run command — the named volume persists ``` With compose: ```bash theme={null} docker compose -f docker-compose.prod.yml pull docker compose -f docker-compose.prod.yml up -d ``` *** ## Verify ```bash theme={null} docker exec okto-pulse okto-pulse status curl -s http://localhost:8100/api/v1/kg/settings ``` *** ## Next steps Wire Claude Code, Cursor, Cline, or Windsurf to the running MCP server. Ideation → spec → cards in a single session. # KG operations overview Source: https://docs.oktolabs.ai/kg-operations Operational entry point for querying, consolidating, monitoring, repairing, and backfilling the Pulse Knowledge Graph. # KG operations overview You can operate the Pulse Knowledge Graph through MCP tools, CLI commands, and health endpoints. The graph persists decisions, constraints, alternatives, learnings, entities, requirements, API contracts, tests, and bugs across agent sessions. Natural-language, Cypher, decision history, contradictions, and global queries. How SQLite queue entries become graph nodes and edges. Queue depth, dead letters, decay tick freshness, and relevance scores. Populate the graph from existing artifacts and merge duplicate entities. ## Storage Per-board graph files live at: ```text theme={null} ~/.okto-pulse/boards/{board_id}/graph.lbug ``` Global discovery lives at: ```text theme={null} ~/.okto-pulse/global/discovery.lbug ``` ## Operational rule Do not delete graph files as a repair shortcut. Use health, migration, backfill, dedup, and dead-letter reprocess tools. ## Related pages * [KG MCP reference](/reference/mcp/kg/overview) * [Storage paths](/configuration/storage-paths) # Backfill and dedup Source: https://docs.oktolabs.ai/kg-operations/backfill Populate the Knowledge Graph from existing artifacts and deduplicate entities. # Backfill and dedup You can backfill the KG when a board already has specs, sprints, or cards but graph context is incomplete. You can deduplicate when entity nodes have drifted into near-copies. ## When to backfill Backfill is useful after enabling KG on an existing board, recovering from an interrupted consolidation run, or migrating data from an older runtime. ## Dry run ```bash theme={null} okto-pulse kg backfill ``` ```text theme={null} Dry run: found artifacts eligible for KG backfill. ``` ## Apply ```bash theme={null} okto-pulse kg backfill --apply ``` ```text theme={null} Queued and drained KG backfill work. ``` ## Filter by artifact type ```bash theme={null} okto-pulse kg backfill --artifact-type spec --apply ``` ## Dedup entities ```bash theme={null} okto-pulse kg dedup-entities --dry-run ``` ```text theme={null} Found candidate duplicate Entity nodes. ``` ## JSON output for automation ```bash theme={null} okto-pulse kg backfill --json ``` Do not delete `graph.lbug` files to force backfill. Delete only as part of an explicit restore or destructive reset procedure. ## Related pages * [CLI reference](/reference/cli) * [KG health](/kg-operations/health) * [Upgrade](/operations/upgrade) # Consolidation Source: https://docs.oktolabs.ai/kg-operations/consolidation How Pulse turns specs, sprints, and cards into Knowledge Graph nodes and edges. # Consolidation You can use consolidation to materialize delivery artifacts into durable graph context. Consolidation is how a spec decision becomes a future KG query result. ## The consolidation pipeline ```text theme={null} SQLite queue -> ConsolidationWorker -> deterministic extraction -> cognitive extraction -> graph commit ``` Queue entries are claimed, processed, and committed under graph writer controls so the embedded store is not written concurrently. ## L1: DeterministicWorker The deterministic worker extracts known structures: decisions, requirements, API contracts, test scenarios, business rules, ORNs, and parent links. It does not need an LLM. ## L2: Cognitive agent The cognitive layer can add alternatives, assumptions, learnings, and selected relationships. It runs after deterministic extraction and stays behind reconciliation. ## Edge metadata Edges carry metadata such as layer, rule ID, creator, and fallback reason. This lets operators distinguish deterministic, cognitive, fallback, and legacy links. ## Advisory lock Pulse uses a per-board writer guard around graph commits. If a writer is busy, work retries rather than corrupting the graph. ## Automatic vs manual consolidation Most consolidation is automatic. Use manual sessions when an agent needs to stage candidate nodes and inspect reconciliation before committing. ## Manual consolidation session ```text theme={null} okto_pulse_kg_begin_consolidation okto_pulse_kg_add_node_candidate okto_pulse_kg_add_edge_candidate okto_pulse_kg_propose_reconciliation okto_pulse_kg_commit_consolidation ``` ## Abort a stuck session ```text theme={null} okto_pulse_kg_abort_consolidation(session_id="...") ``` ## Trigger the worker immediately ```text theme={null} okto_pulse_kg_tick_run_now(board_id="...") ``` ## Related pages * [KG consolidation tools](/reference/mcp/kg/consolidation) * [KG health](/kg-operations/health) # Dead-letter queue Source: https://docs.oktolabs.ai/kg-operations/dead-letter Inspect and reprocess Knowledge Graph consolidation work that exhausted retries. # Dead-letter queue You can use the dead-letter queue to inspect consolidation work that failed too many times. A dead-letter item is not a reason to delete graph files; it is a repair queue. ## What the dead-letter queue is When consolidation cannot process an entry after its retry limit, Pulse moves it to the DLQ with error details and source metadata. ## Inspecting failed items ```text theme={null} okto_pulse_kg_dead_letter_list(board_id="...", limit=20) ``` Look for repeated schema errors, missing source artifacts, graph open failures, or validation errors in node and edge candidates. ## Reprocessing After fixing the cause, requeue items: ```text theme={null} okto_pulse_kg_dead_letter_reprocess(board_id="...", limit=10) ``` Then check `okto_pulse_kg_health` again. ## Common causes and fixes | Cause | Fix | | -------------------- | ------------------------------------------------------ | | Schema drift | Run `okto_pulse_kg_migrate_schema`. | | Bad candidate edge | Correct the producer and reprocess. | | Temporary graph lock | Reprocess after the active writer completes. | | Missing artifact | Restore or skip the missing source with an audit note. | ## Related pages * [KG health](/kg-operations/health) * [Troubleshooting](/troubleshooting) # KG health and monitoring Source: https://docs.oktolabs.ai/kg-operations/health Monitor queue depth, dead letters, decay tick freshness, and relevance distribution. # KG health and monitoring You can monitor the KG through MCP health tools, the CLI pipeline verifier, and queue health endpoints. Use these before deciding a graph repair is needed. ## Health tool ```text theme={null} okto_pulse_kg_health(board_id="...") ``` The response reports queue depth, oldest pending age, dead-letter count, decay tick freshness, relevance score distribution, and graph availability. ## Pipeline health CLI ```bash theme={null} okto-pulse verify-pipeline --json ``` ```json theme={null} {"ok": true, "checks": []} ``` ## Relevance score histogram The health surface includes score distribution so operators can detect stale or low-confidence graph content. ## Alert thresholds `KG_QUEUE_ALERT_THRESHOLD` controls when queue depth should be surfaced as unhealthy or warning-level. ## Decay tick monitoring Decay tick freshness depends on `KG_DECAY_TICK_INTERVAL_MINUTES`, `KG_DECAY_TICK_STALENESS_DAYS`, and `KG_DECAY_TICK_MAX_AGE_DAYS`. ## Related pages * [Dead-letter queue](/kg-operations/dead-letter) * [KG settings](/configuration/server-config) * [KG health tools](/reference/mcp/kg/health) # Querying the graph Source: https://docs.oktolabs.ai/kg-operations/querying Practical Knowledge Graph query patterns for decisions, contradictions, natural search, and global context. # Querying the graph You can query the KG when an agent needs durable context before writing or validating work. Start with specific read tools; use Cypher only when the dedicated tool does not cover the question. ## Natural language queries `okto_pulse_kg_query_natural` performs deterministic retrieval over embeddings, HNSW indexes, and traversal. It does not ask an LLM to invent an answer. ```text theme={null} okto_pulse_kg_query_natural(board_id="...", query="why did we choose the current auth model?") ``` ## Cypher queries `okto_pulse_kg_query_cypher` is read-only and intended for operators. Use explicit limits and narrow patterns. ```text theme={null} MATCH (d:Decision) RETURN d.title, d.relevance_score LIMIT 20 ``` ## Semantic search HNSW indexes cover `Decision`, `Constraint`, `Requirement`, `Entity`, and `Learning` nodes. Semantic search is retrieval; it is separate from the stored `relevance_score` formula. ## Decision history retrieval Use `okto_pulse_kg_get_decision_history` when the topic is known but the decision ID is not. ## Contradiction detection Run `okto_pulse_kg_find_contradictions` before introducing a spec that may conflict with old decisions or constraints. ## Global cross-board queries `okto_pulse_kg_query_global` searches the global discovery graph and respects board access. ## Relevance scoring The v0.3.3 base score is: ```text theme={null} clamp(0.4*source_confidence + 0.3*log(1+degree)/log(100) + 0.3*decayed_hits - contradict_penalty + priority_boost, 0.0, 1.5) ``` Bug nodes use the higher of priority boost and severity boost. ## UI boost button The UI boost endpoint adds `+0.3` to stored score and clamps at `1.5`. It is an operator override, not a change to semantic retrieval. ## Related pages * [KG query tools](/reference/mcp/kg/queries) * [KG health](/kg-operations/health) # MCP setup Source: https://docs.oktolabs.ai/mcp-setup Connect Claude Code, Cursor, Cline, Windsurf, Codex, or any MCP-compatible agent to your Pulse board. # MCP setup Pulse exposes 216 tools via the Model Context Protocol on `:8101`. Any MCP-compatible coding agent can connect to it. The agent then has full access to your board: creating ideations, writing specs, moving cards, querying the knowledge graph, and closing tasks with evidence. *** ## How it works `okto-pulse init --agents` writes `.mcp.json` in your project directory. Most MCP-compatible agents auto-detect this file when launched from the same directory. ```json theme={null} { "mcpServers": { "okto-pulse": { "url": "http://localhost:8101/mcp?api_key=dash_..." } } } ``` The `api_key` scopes the agent to your board and authenticates its tool calls. Treat it as a secret — do not commit `.mcp.json` to a public repository. *** ## Per-agent setup Claude Code auto-detects `.mcp.json` in the working directory. 1. Run `okto-pulse init --agents` in your project root. 2. Start Claude Code from the same directory. 3. Confirm Pulse appears in the MCP server list: `/mcp` That is the full setup. Claude Code re-reads `.mcp.json` on each session start. 1. Run `okto-pulse init --agents` to generate `.mcp.json`. 2. Open Cursor → **Preferences** → **MCP**. 3. Paste the MCP URL from `.mcp.json`: ```text theme={null} http://localhost:8101/mcp?api_key=dash_... ``` 4. Save and restart Cursor. Cursor also auto-detects `.mcp.json` in project roots in newer versions — check your Cursor release notes. Cline auto-detects `.mcp.json` in the project directory. 1. Run `okto-pulse init --agents`. 2. Open the project in VS Code with the Cline extension active. 3. Cline picks up the MCP server automatically. Windsurf auto-detects `.mcp.json` in the project directory. 1. Run `okto-pulse init --agents`. 2. Open your project in Windsurf. 3. The `okto-pulse` server appears in the Cascade tool list. Codex supports user-wide MCP configuration via `~/.codex/config.toml`. Add the following block: ```toml theme={null} [[mcp_servers]] name = "okto-pulse" url = "http://localhost:8101/mcp?api_key=dash_..." ``` Replace the URL with the one from your generated `.mcp.json`. Restart any running Codex session to pick up the new server. 1. Open Claude Desktop → Settings → Developer → MCP Servers. 2. Add a new server entry: ```json theme={null} { "okto-pulse": { "url": "http://localhost:8101/mcp?api_key=dash_..." } } ``` 3. Restart Claude Desktop. *** ## Verify the connection Ask your agent to list available Pulse tools or inspect your board: ```text theme={null} Use the Okto Pulse MCP tools. List the available boards and summarize the current active work. ``` A correctly connected agent will enumerate boards and return a summary of ideations, specs, and open cards. *** ## Regenerate `.mcp.json` If you changed the MCP port, rotate the API key, or moved to a new project directory: ```bash theme={null} okto-pulse init --agents ``` To regenerate config for a specific agent only: ```bash theme={null} okto-pulse init --agents claude ``` *** ## Security * `.mcp.json` contains your agent API key. Add it to `.gitignore`. * The MCP URL with `?api_key=` is equivalent to a password — do not paste it into issues, Slack, or docs. * The key scopes the agent to your local board only. It does not grant access to any remote service. *** ## What the agent can do Once connected, your agent has access to the full Pulse pipeline via MCP tools: | Category | Examples | | --------------- | -------------------------------------------------------------------- | | Ideations | Create, advance, answer Q\&A, evaluate scope | | Refinements | Investigate, cite evidence, add knowledge entries | | Specs | Write acceptance criteria, business rules, test scenarios, decisions | | Sprints | Suggest scope, create, evaluate | | Cards | Create, move, attach evidence, close with conclusions | | Validations | Submit spec and task validation with structured evidence | | Knowledge Graph | Query decisions, detect contradictions, trace supersedence chains | The agent is expected to query the knowledge graph at the start of each ideation and refinement — prior decisions and constraints live there, not in the chat context. *** ## Next steps Run your first ideation-to-cards session with a connected agent. # Docker operations Source: https://docs.oktolabs.ai/operations/docker Run, persist, debug, and upgrade Pulse in Docker. # Docker operations You can run Pulse in Docker with the published image or by building from local source. Use Docker when you want a repeatable runtime and persistent `/data` volume. ## Published image vs build from source | Path | Use it when | | ----------------- | -------------------------------------------------------------------------- | | Published image | You want the released runtime from `ghcr.io/oktolabsai/okto-pulse:latest`. | | Build from source | You are testing local changes across `okto-pulse` and `okto-pulse-core`. | ## Volume strategy Persist `/data`. It holds SQLite, uploads, board graphs, global discovery, and MCP traces. ```bash theme={null} docker run --rm -p 8100:8100 -p 8101:8101 -v okto-pulse-data:/data ghcr.io/oktolabsai/okto-pulse:latest ``` ```text theme={null} Listening on 0.0.0.0:8100 and 0.0.0.0:8101 ``` ## Environment variable overrides for production Inside containers, bind both API and MCP to all interfaces: ```bash theme={null} HOST=0.0.0.0 MCP_HOST=0.0.0.0 DATA_DIR=/data KG_BASE_DIR=/data HF_HOME=/opt/hf-cache ``` ## Multi-container setups The community image defaults to local SQLite and embedded LadybugDB files. If you move supporting services out of the container, keep Pulse single-process for the API/UI and MCP servers so shared state and the embedded graph writer stay coherent. ## Logs and debugging ```bash theme={null} docker compose logs -f ``` ```text theme={null} okto-pulse | API/UI listening on 8100 okto-pulse | MCP listening on 8101 ``` ## Upgrading For minor releases, pull the new image and restart against the same volume. Check the upgrade guide when a release notes a schema migration. ## Related pages * [Install with Docker](/install/docker) * [Portainer](/operations/portainer) * [Environment variables](/configuration/environment-variables) # Local development Source: https://docs.oktolabs.ai/operations/local Run Pulse from source for local development and contribution work. # Local development You can run Pulse from the two source repos in this workspace: `okto-pulse-core` for the engine and `okto-pulse` for the installable community package. ## Prerequisites Use Python 3.12 locally. The package metadata allows Python 3.11+, but CI and Docker use 3.12. ## Install from source Run this from the workspace root: ```bash theme={null} pip install -e ./okto-pulse-core -e ./okto-pulse pip install pytest pytest-asyncio psutil httpx ruff pyright build ``` ```text theme={null} Successfully installed okto-pulse okto-pulse-core ``` ## Initialize and serve ```bash theme={null} okto-pulse init --agents okto-pulse serve --accept-terms ``` ```text theme={null} API/UI: http://127.0.0.1:8100 MCP: http://127.0.0.1:8101/mcp ``` ## Running tests For core work: ```bash theme={null} cd okto-pulse-core pytest -m "not e2e" -q ``` For community CLI/runtime work: ```bash theme={null} cd okto-pulse pytest -q ``` ## File locations | Data | Default path | | ---------------------- | -------------------------------------------- | | SQLite DB | `~/.okto-pulse/data/pulse.db` | | Uploads | `~/.okto-pulse/uploads/{board_id}/` | | Board graph | `~/.okto-pulse/boards/{board_id}/graph.lbug` | | Global discovery graph | `~/.okto-pulse/global/discovery.lbug` | ## Related pages * [Install](/install) * [Contributing](/contributing) * [Storage paths](/configuration/storage-paths) # Portainer Source: https://docs.oktolabs.ai/operations/portainer Operate the OktoPulse Docker stack from the Portainer host. # Portainer You can manage the remote OktoPulse Docker stack through Portainer when you need logs, redeploys, environment overrides, or health checks. ## Portainer access Workspace notes identify the Portainer host as `192.168.31.154` and the stack name as `OktoPulse`. Changing the remote Portainer stack affects a shared deployment. Confirm the intended change before editing environment variables, volumes, image tags, or stack YAML. ## Viewing logs in Portainer UI Open the `OktoPulse` stack, select the running container, and inspect logs. Look for the API/UI listener on `8100`, the MCP listener on `8101`, and any KG queue or migration errors. ## Updating the stack The safe pattern is: pull the intended image, redeploy the stack, then verify health without deleting the volume. ## Environment variable overrides via Portainer Set production values in the stack environment: ```text theme={null} HOST=0.0.0.0 MCP_HOST=0.0.0.0 DATA_DIR=/data KG_BASE_DIR=/data ``` ## Health check URLs Use the internal healthcheck endpoint from the container or host network: ```text theme={null} http://127.0.0.1:8100/api/v1/kg/settings ``` ## Related pages * [Docker operations](/operations/docker) * [Storage paths](/configuration/storage-paths) # Upgrade Source: https://docs.oktolabs.ai/operations/upgrade Upgrade Pulse without losing SQLite data, uploads, or Knowledge Graph files. # Upgrade You can upgrade Pulse without deleting data when the `/data` volume or `~/.okto-pulse` directory is preserved. Treat data preservation as the first rule. ## Minor version upgrades For pip installs: ```bash theme={null} pip install --upgrade okto-pulse ``` ```text theme={null} Successfully installed okto-pulse ``` For Docker: ```bash theme={null} docker compose pull docker compose up -d ``` ```text theme={null} Container okto-pulse started ``` ## Schema migrations Read the release notes before major upgrades. SQLite migrations run at startup. KG schema migrations can be triggered separately when needed. ## KG schema migration Use the MCP tool or module command: ```text theme={null} okto_pulse_kg_migrate_schema(board_id="...") ``` ```bash theme={null} python -m okto_pulse.tools.kg_migrate_schema --board ``` Do not delete `graph.lbug` files to force a migration. Use schema migration, backfill, or dead-letter reprocess tools. ## Rollback strategy Before upgrading, snapshot the SQLite database and graph files. Roll back by restoring the previous image/package and the preserved data snapshot. ## Related pages * [Backfill and dedup](/kg-operations/backfill) * [KG health](/kg-operations/health) * [Docker operations](/operations/docker) # Board and profile flags Source: https://docs.oktolabs.ai/permissions/board Board, profile, and guideline permissions every agent setup should understand. # Board and profile flags You can use this page to inspect the exact source-defined flags for this part of Pulse. The tables show whether each common preset grants the flag by default. board.read is the minimum useful board capability for most agents. ## `board` namespace ### (direct) | Flag | Spec | Executor | QA | Validator | Full Control | | -------------------------- | ---- | -------- | --- | --------- | ------------ | | `board.read` | yes | yes | yes | yes | yes | | `board.activity_read` | yes | yes | yes | yes | yes | | `board.analytics_read` | yes | - | - | - | yes | | `board.mentions_read` | yes | yes | yes | yes | yes | | `board.mentions_mark_seen` | yes | yes | yes | yes | yes | ## `profile` namespace ### (direct) | Flag | Spec | Executor | QA | Validator | Full Control | | ---------------- | ---- | -------- | --- | --------- | ------------ | | `profile.update` | yes | yes | yes | yes | yes | ## `guidelines` namespace ### (direct) | Flag | Spec | Executor | QA | Validator | Full Control | | ------------------- | ---- | -------- | --- | --------- | ------------ | | `guidelines.read` | yes | yes | yes | yes | yes | | `guidelines.create` | - | - | - | - | yes | | `guidelines.edit` | - | - | - | - | yes | | `guidelines.delete` | - | - | - | - | yes | | `guidelines.link` | - | - | - | - | yes | | `guidelines.unlink` | - | - | - | - | yes | ## Preset mapping notes * Full Control grants every flag. * Spec owns planning and contract-writing surfaces. * Executor owns implementation through handoff to validation. * QA owns test evidence and test cards. * Validator owns gate submission and validation status routing. ## Related pages * [Permission model](/permissions/model) * [Built-in presets](/permissions/presets) * [Custom permissions](/permissions/custom) # Card and KG flags Source: https://docs.oktolabs.ai/permissions/card-kg All granular flags for cards, task validation, traceability, comments, attachments, and Knowledge Graph access. # Card and KG flags You can use this page to inspect the exact source-defined flags for this part of Pulse. The tables show whether each common preset grants the flag by default. Do not give kg.admin.wipe\_board or card.validation.submit to implementation-only agents. ## `card` namespace ### entity | Flag | Spec | Executor | QA | Validator | Full Control | | --------------------------------- | ---- | -------- | --- | --------- | ------------ | | `card.entity.read` | yes | yes | yes | yes | yes | | `card.entity.context_read` | yes | yes | yes | yes | yes | | `card.entity.create` | yes | yes | yes | - | yes | | `card.entity.create_test` | yes | - | yes | - | yes | | `card.entity.edit_fields` | yes | yes | yes | - | yes | | `card.entity.edit_bug_fields` | - | yes | - | - | yes | | `card.entity.assign` | yes | yes | - | - | yes | | `card.entity.label` | yes | yes | - | - | yes | | `card.entity.link_spec` | yes | - | - | - | yes | | `card.entity.link_tests` | yes | - | - | - | yes | | `card.entity.manage_dependencies` | yes | - | - | - | yes | | `card.entity.delete` | - | - | - | - | yes | ### copy\_from\_spec | Flag | Spec | Executor | QA | Validator | Full Control | | ---------------------------------- | ---- | -------- | -- | --------- | ------------ | | `card.copy_from_spec.mockups` | yes | - | - | - | yes | | `card.copy_from_spec.knowledge` | yes | - | - | - | yes | | `card.copy_from_spec.qa` | yes | - | - | - | yes | | `card.copy_from_spec.architecture` | yes | - | - | - | yes | ### link\_to | Flag | Spec | Executor | QA | Validator | Full Control | | ----------------------- | ---- | -------- | --- | --------- | ------------ | | `card.link_to.scenario` | yes | - | yes | - | yes | | `card.link_to.tr` | yes | - | - | - | yes | | `card.link_to.rule` | yes | - | - | - | yes | | `card.link_to.contract` | yes | - | - | - | yes | ### move | Flag | Spec | Executor | QA | Validator | Full Control | | ------------------------------------- | ---- | -------- | --- | --------- | ------------ | | `card.move.not_started_to_started` | - | yes | yes | - | yes | | `card.move.started_to_in_progress` | - | yes | yes | - | yes | | `card.move.in_progress_to_on_hold` | - | yes | yes | - | yes | | `card.move.on_hold_to_in_progress` | - | yes | yes | - | yes | | `card.move.in_progress_to_done` | - | - | yes | - | yes | | `card.move.any_to_cancelled` | - | yes | yes | - | yes | | `card.move.in_progress_to_validation` | - | yes | - | - | yes | | `card.move.validation_to_done` | - | - | - | yes | yes | | `card.move.validation_to_not_started` | - | - | - | yes | yes | | `card.move.validation_to_on_hold` | - | - | - | - | yes | | `card.move.validation_to_cancelled` | - | - | - | - | yes | ### interact\_in | Flag | Spec | Executor | QA | Validator | Full Control | | ------------------------------ | ---- | -------- | --- | --------- | ------------ | | `card.interact_in.not_started` | yes | yes | yes | - | yes | | `card.interact_in.started` | - | yes | yes | - | yes | | `card.interact_in.in_progress` | - | yes | yes | - | yes | | `card.interact_in.on_hold` | - | yes | yes | - | yes | | `card.interact_in.done` | - | - | yes | - | yes | | `card.interact_in.cancelled` | - | - | - | - | yes | | `card.interact_in.validation` | - | yes | - | yes | yes | ### validation | Flag | Spec | Executor | QA | Validator | Full Control | | ------------------------ | ---- | -------- | --- | --------- | ------------ | | `card.validation.submit` | - | - | - | yes | yes | | `card.validation.read` | yes | yes | yes | yes | yes | | `card.validation.delete` | - | - | - | - | yes | ### qa | Flag | Spec | Executor | QA | Validator | Full Control | | ---------------- | ---- | -------- | --- | --------- | ------------ | | `card.qa.read` | yes | yes | yes | yes | yes | | `card.qa.ask` | yes | yes | yes | yes | yes | | `card.qa.answer` | - | yes | yes | yes | yes | | `card.qa.delete` | - | - | - | - | yes | ### comments | Flag | Spec | Executor | QA | Validator | Full Control | | ------------------------------ | ---- | -------- | --- | --------- | ------------ | | `card.comments.read` | yes | yes | yes | yes | yes | | `card.comments.create` | yes | yes | yes | yes | yes | | `card.comments.create_choice` | - | yes | - | - | yes | | `card.comments.respond_choice` | - | yes | - | - | yes | | `card.comments.get_responses` | - | yes | - | - | yes | | `card.comments.edit` | - | - | - | - | yes | | `card.comments.delete` | - | - | - | - | yes | ### attachments | Flag | Spec | Executor | QA | Validator | Full Control | | ------------------------- | ---- | -------- | --- | --------- | ------------ | | `card.attachments.read` | yes | yes | yes | yes | yes | | `card.attachments.upload` | - | yes | yes | - | yes | | `card.attachments.delete` | - | yes | - | - | yes | ### mockups | Flag | Spec | Executor | QA | Validator | Full Control | | ----------------------- | ---- | -------- | --- | --------- | ------------ | | `card.mockups.read` | yes | yes | yes | yes | yes | | `card.mockups.create` | - | - | - | - | yes | | `card.mockups.edit` | - | - | - | - | yes | | `card.mockups.delete` | - | - | - | - | yes | | `card.mockups.annotate` | - | yes | - | - | yes | ### architecture | Flag | Spec | Executor | QA | Validator | Full Control | | -------------------------- | ---- | -------- | --- | --------- | ------------ | | `card.architecture.read` | yes | yes | yes | yes | yes | | `card.architecture.create` | yes | - | - | - | yes | | `card.architecture.edit` | yes | - | - | - | yes | | `card.architecture.delete` | yes | - | - | - | yes | | `card.architecture.import` | yes | - | - | - | yes | | `card.architecture.render` | yes | - | - | - | yes | ### tests | Flag | Spec | Executor | QA | Validator | Full Control | | -------------------------- | ---- | -------- | --- | --------- | ------------ | | `card.tests.read` | yes | yes | yes | yes | yes | | `card.tests.link` | - | - | yes | - | yes | | `card.tests.update_status` | - | - | yes | - | yes | ### conclusion | Flag | Spec | Executor | QA | Validator | Full Control | | ----------------------- | ---- | -------- | --- | --------- | ------------ | | `card.conclusion.read` | - | yes | yes | yes | yes | | `card.conclusion.write` | - | yes | yes | - | yes | ### (direct) | Flag | Spec | Executor | QA | Validator | Full Control | | -------------------- | ---- | -------- | --- | --------- | ------------ | | `card.activity_read` | yes | yes | yes | yes | yes | ## `comments` namespace ## `attachments` namespace ## `kg` namespace ### query | Flag | Spec | Executor | QA | Validator | Full Control | | ----------------------------- | ---- | -------- | --- | --------- | ------------ | | `kg.query.decision_history` | yes | yes | yes | yes | yes | | `kg.query.related_context` | yes | yes | yes | yes | yes | | `kg.query.supersedence_chain` | yes | yes | yes | yes | yes | | `kg.query.contradictions` | yes | yes | yes | yes | yes | | `kg.query.similar_decisions` | yes | yes | yes | yes | yes | | `kg.query.constraint_explain` | yes | yes | yes | yes | yes | | `kg.query.alternatives` | yes | yes | yes | yes | yes | | `kg.query.learning_from_bugs` | yes | yes | yes | yes | yes | | `kg.query.global` | yes | yes | yes | yes | yes | ### power | Flag | Spec | Executor | QA | Validator | Full Control | | ---------------------- | ---- | -------- | --- | --------- | ------------ | | `kg.power.cypher` | yes | - | - | yes | yes | | `kg.power.natural` | yes | yes | yes | yes | yes | | `kg.power.schema_info` | yes | yes | yes | yes | yes | ### session | Flag | Spec | Executor | QA | Validator | Full Control | | ------------------------ | ---- | -------- | --- | --------- | ------------ | | `kg.session.begin` | yes | - | yes | yes | yes | | `kg.session.add_node` | yes | - | yes | yes | yes | | `kg.session.add_edge` | yes | - | yes | yes | yes | | `kg.session.get_similar` | yes | - | yes | yes | yes | | `kg.session.propose` | yes | - | yes | yes | yes | | `kg.session.commit` | yes | - | - | yes | yes | | `kg.session.abort` | yes | - | - | yes | yes | ### admin | Flag | Spec | Executor | QA | Validator | Full Control | | ----------------------------------- | ---- | -------- | --- | --------- | ------------ | | `kg.admin.wipe_board` | - | - | - | - | yes | | `kg.admin.settings_write` | yes | - | - | - | yes | | `kg.admin.settings_read` | yes | yes | yes | yes | yes | | `kg.admin.historical_consolidation` | yes | - | - | - | yes | ## Preset mapping notes * Full Control grants every flag. * Spec owns planning and contract-writing surfaces. * Executor owns implementation through handoff to validation. * QA owns test evidence and test cards. * Validator owns gate submission and validation status routing. ## Related pages * [Permission model](/permissions/model) * [Built-in presets](/permissions/presets) * [Custom permissions](/permissions/custom) # Custom permissions Source: https://docs.oktolabs.ai/permissions/custom How to create narrow Pulse agents with explicit granular flags. # Custom permissions You can create custom permissions when a built-in preset is too broad or too narrow. Start from the closest preset, then remove or add explicit flags for the agent's job. ## When to use custom permissions Use custom permissions for hybrid roles, read-only reporting agents, automation that should touch only one namespace, or temporary agents used for a single migration or audit. ## Creating a custom agent in the web UI Open the board's agent settings, create or edit an agent, choose custom permissions, then save the selected flags. Export MCP config after the agent exists. ```bash theme={null} okto-pulse init --agents reporting-agent ``` ```text theme={null} Wrote .mcp.json with selected agent entries. ``` ## Setting flags with dot notation Use source flag names exactly. Examples: ```text theme={null} board.read spec.entity.read card.validation.read kg.query.decision_history ``` Avoid granting wildcard-like groups unless the agent actually needs every child capability. ## Board-level overrides Board overrides restrict an agent further on a specific board. They are useful for shared agents that need broader access on one board and read-only access on another. ## Example: read-only reporting agent A reporting agent usually needs: * `board.read`, `board.activity_read`, and `board.analytics_read` * `spec.entity.read`, `sprint.entity.read`, and `card.entity.read` * `kg.query.*` read flags relevant to the report * no `*.submit`, `*.delete`, or `kg.session.commit` flags ## Related pages * [Permission model](/permissions/model) * [Built-in presets](/permissions/presets) * [Board flags](/permissions/board) # Ideation flags Source: https://docs.oktolabs.ai/permissions/ideation All granular flags for ideation entities, state moves, Q&A, knowledge, mockups, architecture, and spec derivation. # Ideation flags You can use this page to inspect the exact source-defined flags for this part of Pulse. The tables show whether each common preset grants the flag by default. Executor has ideation read access but does not create or derive ideations. ## `ideation` namespace ### entity | Flag | Spec | Executor | QA | Validator | Full Control | | ----------------------------- | ---- | -------- | --- | --------- | ------------ | | `ideation.entity.read` | yes | - | yes | yes | yes | | `ideation.entity.create` | yes | - | - | - | yes | | `ideation.entity.edit_fields` | yes | - | - | - | yes | | `ideation.entity.assign` | yes | - | - | - | yes | | `ideation.entity.label` | yes | - | - | - | yes | | `ideation.entity.evaluate` | yes | - | - | - | yes | | `ideation.entity.archive` | yes | - | - | - | yes | | `ideation.entity.restore` | yes | - | - | - | yes | | `ideation.entity.delete` | yes | - | - | - | yes | ### move | Flag | Spec | Executor | QA | Validator | Full Control | | ------------------------------------- | ---- | -------- | -- | --------- | ------------ | | `ideation.move.draft_to_evaluating` | yes | - | - | - | yes | | `ideation.move.evaluating_to_refined` | yes | - | - | - | yes | | `ideation.move.refined_to_done` | yes | - | - | - | yes | | `ideation.move.any_to_cancelled` | yes | - | - | - | yes | ### interact\_in | Flag | Spec | Executor | QA | Validator | Full Control | | --------------------------------- | ---- | -------- | --- | --------- | ------------ | | `ideation.interact_in.draft` | yes | - | - | - | yes | | `ideation.interact_in.evaluating` | yes | - | yes | yes | yes | | `ideation.interact_in.refined` | yes | - | yes | yes | yes | | `ideation.interact_in.done` | - | - | - | - | yes | | `ideation.interact_in.cancelled` | - | - | - | - | yes | ### qa | Flag | Spec | Executor | QA | Validator | Full Control | | ------------------------ | ---- | -------- | --- | --------- | ------------ | | `ideation.qa.read` | yes | - | yes | yes | yes | | `ideation.qa.ask` | yes | - | yes | yes | yes | | `ideation.qa.ask_choice` | yes | - | yes | - | yes | | `ideation.qa.answer` | yes | - | yes | yes | yes | ### mockups | Flag | Spec | Executor | QA | Validator | Full Control | | --------------------------- | ---- | -------- | --- | --------- | ------------ | | `ideation.mockups.read` | yes | - | yes | yes | yes | | `ideation.mockups.create` | yes | - | - | - | yes | | `ideation.mockups.edit` | yes | - | - | - | yes | | `ideation.mockups.delete` | yes | - | - | - | yes | | `ideation.mockups.annotate` | yes | - | - | - | yes | ### architecture | Flag | Spec | Executor | QA | Validator | Full Control | | ------------------------------ | ---- | -------- | --- | --------- | ------------ | | `ideation.architecture.read` | yes | yes | yes | yes | yes | | `ideation.architecture.create` | yes | - | - | - | yes | | `ideation.architecture.edit` | yes | - | - | - | yes | | `ideation.architecture.delete` | yes | - | - | - | yes | | `ideation.architecture.import` | yes | - | - | - | yes | | `ideation.architecture.render` | yes | - | - | - | yes | ### (direct) | Flag | Spec | Executor | QA | Validator | Full Control | | ------------------------ | ---- | -------- | --- | --------- | ------------ | | `ideation.specs_derive` | yes | - | - | - | yes | | `ideation.versions_read` | yes | - | yes | yes | yes | | `ideation.history_read` | yes | - | yes | yes | yes | ## Preset mapping notes * Full Control grants every flag. * Spec owns planning and contract-writing surfaces. * Executor owns implementation through handoff to validation. * QA owns test evidence and test cards. * Validator owns gate submission and validation status routing. ## Related pages * [Permission model](/permissions/model) * [Built-in presets](/permissions/presets) * [Custom permissions](/permissions/custom) # Permission model Source: https://docs.oktolabs.ai/permissions/model How Pulse resolves granular flags, board overrides, state checks, and legacy permissions. # Permission model You can use the permission model to restrict what each agent can do on each board. Pulse enforces permissions before MCP tools execute, so role boundaries are not only advisory. ## The flag namespace Current source defines `270` enabled granular flags. They use dotted paths: ```text theme={null} spec.move.draft_to_review card.validation.submit kg.query.decision_history ``` Top-level namespaces are `board`, `profile`, `guidelines`, `ideation`, `refinement`, `spec`, `sprint`, `card`, `comments`, `attachments`, and `kg`. ## The ceiling model `resolve_permissions` starts with an agent's base permission set and then applies board overrides. A board override can restrict a flag, but it cannot grant capability beyond the agent's base role. ## State-aware checks Entity work is gated by both operation flags and `interact_in` flags. For example, an agent might be allowed to read cards but only interact with cards in `in_progress`, not cards in `validation`. ## Absent flags default to allowed For backward compatibility, unknown or absent flags resolve as allowed. That keeps older agents working while the registry evolves. New security-sensitive work should set explicit flags instead of relying on this compatibility path. ## Legacy flat permissions The older flat model had 19 constants such as `board:read`, `cards:create`, and `specs:evaluate`. `map_legacy_permissions` maps those old constants into granular flags. New agents should use granular presets or custom flags. ## Namespace counts | Namespace | Enabled flags | | ------------ | ------------- | | `board` | 5 | | `profile` | 1 | | `guidelines` | 6 | | `ideation` | 36 | | `refinement` | 40 | | `spec` | 62 | | `sprint` | 25 | | `card` | 72 | | `kg` | 23 | ## Related pages * [Built-in presets](/permissions/presets) * [Custom permissions](/permissions/custom) * [Board and profile flags](/permissions/board) # Built-in presets Source: https://docs.oktolabs.ai/permissions/presets Role boundaries for Full Control, Spec, Executor, QA, Validator, Reporter, and Sprint Manager. # Built-in presets You can use built-in presets to give agents a role without hand-selecting hundreds of flags. Presets are source-defined permission sets; board overrides can restrict them further. ## Preset matrix | Preset | Enabled flags | Role boundary | | -------------- | ------------: | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Full Control | 270 | All permissions active — unrestricted access. | | Executor | 78 | Implement normal cards. Moves not\_started→validation. Cannot submit gates or promote validation→done. | | Validator | 99 | Exclusive gate-holder. Submits spec/task/sprint validations and evaluations. On cards, only touches validation status. | | QA | 106 | Owns test scenarios and test card lifecycle. No gate submissions. | | Reporter | 85 | Observador — lê tudo, abre bug card, pergunta e vota em choice. Zero submit de gate, zero edit, zero consolidação KG. Ideal para PO/stakeholder/onboarding. | | Sprint Manager | 89 | Dono do ciclo de sprint (create → active → review → closed + evaluation). Lê contexto de spec/refinement/ideation e orquestra assign de cards. Não cria cards nem submete gates técnicos. Coexiste com Validator. | | Spec | 205 | Defines the spec (ideation→refinement→spec content, sprint plan, card breakdown). No gate submissions, no card execution. | ## Full Control Full Control has every current flag enabled. Use it for solo development, local evaluation, or trusted operators. Do not use it as the default for multi-agent boards because it removes role separation. ## Spec Spec owns ideation, refinement, spec content, sprint planning, and card breakdown. It does not submit validation gates. Use it for the agent that investigates and writes the contract. ## Executor Executor implements normal cards. It can move card work through `not_started -> started -> in_progress -> validation`, but it cannot submit task validation or promote validation to done. ## QA QA owns test scenarios and test-card lifecycle. It reads specs, asks questions, and manages test evidence, but it does not submit validation gates. ## Validator Validator is the exclusive gate-holder. It submits spec validation, sprint evaluation, and task validation. On cards, it only operates in validation status and routes work to done or back for rework. ## Reporter and Sprint Manager Reporter is read-heavy and useful for stakeholders or status agents. Sprint Manager owns sprint lifecycle and coordination without taking over implementation or validation. ## Choosing the right preset | Situation | Preset | | ------------------------------------------ | --------------- | | One trusted local agent doing everything | Full Control | | One agent writes specs, another implements | Spec + Executor | | A separate reviewer must approve work | Add Validator | | Test evidence is a separate lane | Add QA | | Stakeholder wants read-only visibility | Reporter | | Delivery lead manages sprint flow | Sprint Manager | Gate submission is intentionally concentrated in Validator. If Executor can submit its own validation, validation becomes another status label instead of independent evidence. ## Related pages * [Permission model](/permissions/model) * [Custom permissions](/permissions/custom) * [Validation gates](/concepts/validation) # Refinement flags Source: https://docs.oktolabs.ai/permissions/refinement All granular flags for refinement entities, state moves, Q&A, knowledge, mockups, architecture, and spec derivation. # Refinement flags You can use this page to inspect the exact source-defined flags for this part of Pulse. The tables show whether each common preset grants the flag by default. Refinement permissions mirror ideation but use the investigation state machine. ## `refinement` namespace ### entity | Flag | Spec | Executor | QA | Validator | Full Control | | ------------------------------- | ---- | -------- | --- | --------- | ------------ | | `refinement.entity.read` | yes | - | yes | yes | yes | | `refinement.entity.create` | yes | - | - | - | yes | | `refinement.entity.edit_fields` | yes | - | - | - | yes | | `refinement.entity.assign` | yes | - | - | - | yes | | `refinement.entity.label` | yes | - | - | - | yes | | `refinement.entity.archive` | yes | - | - | - | yes | | `refinement.entity.restore` | yes | - | - | - | yes | | `refinement.entity.delete` | yes | - | - | - | yes | ### move | Flag | Spec | Executor | QA | Validator | Full Control | | --------------------------------------- | ---- | -------- | -- | --------- | ------------ | | `refinement.move.draft_to_in_progress` | yes | - | - | - | yes | | `refinement.move.in_progress_to_review` | yes | - | - | - | yes | | `refinement.move.review_to_approved` | yes | - | - | - | yes | | `refinement.move.approved_to_done` | yes | - | - | - | yes | | `refinement.move.any_to_cancelled` | yes | - | - | - | yes | ### interact\_in | Flag | Spec | Executor | QA | Validator | Full Control | | ------------------------------------ | ---- | -------- | --- | --------- | ------------ | | `refinement.interact_in.draft` | yes | - | - | - | yes | | `refinement.interact_in.in_progress` | yes | - | - | - | yes | | `refinement.interact_in.review` | yes | - | yes | yes | yes | | `refinement.interact_in.approved` | yes | - | yes | yes | yes | | `refinement.interact_in.done` | - | - | - | - | yes | | `refinement.interact_in.cancelled` | - | - | - | - | yes | ### qa | Flag | Spec | Executor | QA | Validator | Full Control | | -------------------------- | ---- | -------- | --- | --------- | ------------ | | `refinement.qa.read` | yes | - | yes | yes | yes | | `refinement.qa.ask` | yes | - | yes | yes | yes | | `refinement.qa.ask_choice` | yes | - | yes | - | yes | | `refinement.qa.answer` | yes | - | yes | yes | yes | ### mockups | Flag | Spec | Executor | QA | Validator | Full Control | | ----------------------------- | ---- | -------- | --- | --------- | ------------ | | `refinement.mockups.read` | yes | - | yes | yes | yes | | `refinement.mockups.create` | yes | - | - | - | yes | | `refinement.mockups.edit` | yes | - | - | - | yes | | `refinement.mockups.delete` | yes | - | - | - | yes | | `refinement.mockups.annotate` | yes | - | - | - | yes | ### architecture | Flag | Spec | Executor | QA | Validator | Full Control | | -------------------------------- | ---- | -------- | --- | --------- | ------------ | | `refinement.architecture.read` | yes | yes | yes | yes | yes | | `refinement.architecture.create` | yes | - | - | - | yes | | `refinement.architecture.edit` | yes | - | - | - | yes | | `refinement.architecture.delete` | yes | - | - | - | yes | | `refinement.architecture.import` | yes | - | - | - | yes | | `refinement.architecture.render` | yes | - | - | - | yes | ### knowledge | Flag | Spec | Executor | QA | Validator | Full Control | | ----------------------------- | ---- | -------- | --- | --------- | ------------ | | `refinement.knowledge.read` | yes | - | yes | yes | yes | | `refinement.knowledge.create` | yes | - | - | - | yes | | `refinement.knowledge.delete` | yes | - | - | - | yes | ### (direct) | Flag | Spec | Executor | QA | Validator | Full Control | | -------------------------- | ---- | -------- | --- | --------- | ------------ | | `refinement.specs_derive` | yes | - | - | - | yes | | `refinement.versions_read` | yes | - | yes | yes | yes | | `refinement.history_read` | yes | - | yes | yes | yes | ## Preset mapping notes * Full Control grants every flag. * Spec owns planning and contract-writing surfaces. * Executor owns implementation through handoff to validation. * QA owns test evidence and test cards. * Validator owns gate submission and validation status routing. ## Related pages * [Permission model](/permissions/model) * [Built-in presets](/permissions/presets) * [Custom permissions](/permissions/custom) # Spec flags Source: https://docs.oktolabs.ai/permissions/spec All granular flags for spec content, gates, evidence, decisions, and card derivation. # Spec flags You can use this page to inspect the exact source-defined flags for this part of Pulse. The tables show whether each common preset grants the flag by default. Validator is the intended holder of spec validation submit and approved-to-validated movement. ## `spec` namespace ### entity | Flag | Spec | Executor | QA | Validator | Full Control | | --------------------------------- | ---- | -------- | --- | --------- | ------------ | | `spec.entity.read` | yes | yes | yes | yes | yes | | `spec.entity.create` | yes | - | - | - | yes | | `spec.entity.edit_fields` | yes | - | - | - | yes | | `spec.entity.edit_coverage_flags` | yes | - | - | - | yes | | `spec.entity.assign` | yes | - | - | - | yes | | `spec.entity.label` | yes | - | - | - | yes | | `spec.entity.link_card` | yes | - | - | - | yes | | `spec.entity.archive` | yes | - | - | - | yes | | `spec.entity.restore` | yes | - | - | - | yes | | `spec.entity.delete` | yes | - | - | - | yes | ### move | Flag | Spec | Executor | QA | Validator | Full Control | | ------------------------------------ | ---- | -------- | -- | --------- | ------------ | | `spec.move.draft_to_review` | yes | - | - | - | yes | | `spec.move.review_to_approved` | yes | - | - | - | yes | | `spec.move.approved_to_validated` | - | - | - | yes | yes | | `spec.move.validated_to_in_progress` | - | - | - | yes | yes | | `spec.move.in_progress_to_done` | - | - | - | yes | yes | | `spec.move.any_to_cancelled` | yes | - | - | - | yes | | `spec.move.approved_to_draft` | - | - | - | yes | yes | | `spec.move.validated_to_draft` | - | - | - | yes | yes | ### interact\_in | Flag | Spec | Executor | QA | Validator | Full Control | | ------------------------------ | ---- | -------- | --- | --------- | ------------ | | `spec.interact_in.draft` | yes | - | - | - | yes | | `spec.interact_in.review` | yes | - | - | - | yes | | `spec.interact_in.approved` | yes | - | yes | yes | yes | | `spec.interact_in.validated` | yes | yes | yes | yes | yes | | `spec.interact_in.in_progress` | yes | yes | yes | yes | yes | | `spec.interact_in.done` | - | yes | - | - | yes | | `spec.interact_in.cancelled` | - | - | - | - | yes | ### qa | Flag | Spec | Executor | QA | Validator | Full Control | | -------------------- | ---- | -------- | --- | --------- | ------------ | | `spec.qa.read` | yes | yes | yes | yes | yes | | `spec.qa.ask` | yes | yes | yes | yes | yes | | `spec.qa.ask_choice` | yes | - | yes | - | yes | | `spec.qa.answer` | yes | - | yes | yes | yes | ### tests | Flag | Spec | Executor | QA | Validator | Full Control | | -------------------------- | ---- | -------- | --- | --------- | ------------ | | `spec.tests.read` | yes | yes | yes | yes | yes | | `spec.tests.create` | yes | - | yes | - | yes | | `spec.tests.update_status` | yes | - | yes | - | yes | ### rules | Flag | Spec | Executor | QA | Validator | Full Control | | ------------------- | ---- | -------- | --- | --------- | ------------ | | `spec.rules.read` | yes | yes | yes | yes | yes | | `spec.rules.create` | yes | - | - | - | yes | | `spec.rules.edit` | yes | - | - | - | yes | | `spec.rules.delete` | yes | - | - | - | yes | ### contracts | Flag | Spec | Executor | QA | Validator | Full Control | | ----------------------- | ---- | -------- | --- | --------- | ------------ | | `spec.contracts.read` | yes | yes | yes | yes | yes | | `spec.contracts.create` | yes | - | - | - | yes | | `spec.contracts.edit` | yes | - | - | - | yes | | `spec.contracts.delete` | yes | - | - | - | yes | ### mockups | Flag | Spec | Executor | QA | Validator | Full Control | | ----------------------- | ---- | -------- | --- | --------- | ------------ | | `spec.mockups.read` | yes | yes | yes | yes | yes | | `spec.mockups.create` | yes | - | - | - | yes | | `spec.mockups.edit` | yes | - | - | - | yes | | `spec.mockups.delete` | yes | - | - | - | yes | | `spec.mockups.annotate` | yes | - | - | - | yes | ### architecture | Flag | Spec | Executor | QA | Validator | Full Control | | -------------------------- | ---- | -------- | --- | --------- | ------------ | | `spec.architecture.read` | yes | yes | yes | yes | yes | | `spec.architecture.create` | yes | - | - | - | yes | | `spec.architecture.edit` | yes | - | - | - | yes | | `spec.architecture.delete` | yes | - | - | - | yes | | `spec.architecture.import` | yes | - | - | - | yes | | `spec.architecture.render` | yes | - | - | - | yes | ### knowledge | Flag | Spec | Executor | QA | Validator | Full Control | | ----------------------- | ---- | -------- | --- | --------- | ------------ | | `spec.knowledge.read` | yes | yes | yes | yes | yes | | `spec.knowledge.create` | yes | - | - | - | yes | | `spec.knowledge.delete` | yes | - | - | - | yes | ### evaluations | Flag | Spec | Executor | QA | Validator | Full Control | | ------------------------- | ---- | -------- | --- | --------- | ------------ | | `spec.evaluations.read` | yes | yes | yes | yes | yes | | `spec.evaluations.submit` | - | - | - | yes | yes | | `spec.evaluations.delete` | - | - | - | - | yes | ### validation | Flag | Spec | Executor | QA | Validator | Full Control | | ------------------------ | ---- | -------- | --- | --------- | ------------ | | `spec.validation.submit` | - | - | - | yes | yes | | `spec.validation.read` | yes | yes | yes | yes | yes | | `spec.validation.delete` | - | - | - | - | yes | ### (direct) | Flag | Spec | Executor | QA | Validator | Full Control | | ------------------- | ---- | -------- | --- | --------- | ------------ | | `spec.cards_derive` | yes | - | - | - | yes | | `spec.history_read` | yes | yes | yes | yes | yes | ## Preset mapping notes * Full Control grants every flag. * Spec owns planning and contract-writing surfaces. * Executor owns implementation through handoff to validation. * QA owns test evidence and test cards. * Validator owns gate submission and validation status routing. ## Related pages * [Permission model](/permissions/model) * [Built-in presets](/permissions/presets) * [Custom permissions](/permissions/custom) # Sprint flags Source: https://docs.oktolabs.ai/permissions/sprint All granular flags for sprint entities, lifecycle moves, Q&A, evaluation, and history. # Sprint flags You can use this page to inspect the exact source-defined flags for this part of Pulse. The tables show whether each common preset grants the flag by default. Sprint evaluation is separate from task validation and spec validation. ## `sprint` namespace ### entity | Flag | Spec | Executor | QA | Validator | Full Control | | ----------------------------------- | ---- | -------- | --- | --------- | ------------ | | `sprint.entity.read` | yes | yes | yes | yes | yes | | `sprint.entity.create` | yes | - | - | - | yes | | `sprint.entity.edit_fields` | yes | - | - | - | yes | | `sprint.entity.edit_coverage_flags` | yes | - | - | - | yes | | `sprint.entity.assign` | yes | - | - | - | yes | | `sprint.entity.label` | yes | - | - | - | yes | | `sprint.entity.archive` | yes | - | - | - | yes | | `sprint.entity.restore` | yes | - | - | - | yes | | `sprint.entity.delete` | yes | - | - | - | yes | ### move | Flag | Spec | Executor | QA | Validator | Full Control | | ------------------------------ | ---- | -------- | -- | --------- | ------------ | | `sprint.move.draft_to_active` | yes | - | - | - | yes | | `sprint.move.active_to_review` | yes | - | - | yes | yes | | `sprint.move.review_to_closed` | - | - | - | yes | yes | | `sprint.move.any_to_cancelled` | yes | - | - | - | yes | ### interact\_in | Flag | Spec | Executor | QA | Validator | Full Control | | ------------------------------ | ---- | -------- | --- | --------- | ------------ | | `sprint.interact_in.draft` | yes | - | - | - | yes | | `sprint.interact_in.active` | yes | yes | yes | yes | yes | | `sprint.interact_in.review` | - | - | yes | yes | yes | | `sprint.interact_in.closed` | - | - | - | - | yes | | `sprint.interact_in.cancelled` | - | - | - | - | yes | ### qa | Flag | Spec | Executor | QA | Validator | Full Control | | ------------------ | ---- | -------- | --- | --------- | ------------ | | `sprint.qa.read` | yes | yes | yes | yes | yes | | `sprint.qa.ask` | yes | yes | yes | yes | yes | | `sprint.qa.answer` | yes | - | yes | yes | yes | ### evaluations | Flag | Spec | Executor | QA | Validator | Full Control | | --------------------------- | ---- | -------- | --- | --------- | ------------ | | `sprint.evaluations.read` | yes | yes | yes | yes | yes | | `sprint.evaluations.submit` | - | - | - | yes | yes | | `sprint.evaluations.delete` | - | - | - | - | yes | ### (direct) | Flag | Spec | Executor | QA | Validator | Full Control | | --------------------- | ---- | -------- | --- | --------- | ------------ | | `sprint.history_read` | yes | yes | yes | yes | yes | ## Preset mapping notes * Full Control grants every flag. * Spec owns planning and contract-writing surfaces. * Executor owns implementation through handoff to validation. * QA owns test evidence and test cards. * Validator owns gate submission and validation status routing. ## Related pages * [Permission model](/permissions/model) * [Built-in presets](/permissions/presets) * [Custom permissions](/permissions/custom) # Quickstart Source: https://docs.oktolabs.ai/quickstart From idea to your first validated card in 5 minutes **Prerequisites** * Pulse installed and serving? If not → [Install](/install) * Agent connected via MCP? If not → [MCP Setup](/mcp-setup) This walkthrough uses a concrete example — adding user authentication — so every step has a visible output. The CLI path uses Claude Code; the UI path works for any browser. *** `okto-pulse init` already created a default board when you installed. Verify it's there: **Via MCP (Claude Code):** ```text theme={null} > list my boards ``` Claude Code calls `okto_pulse_list_my_boards` and returns: ```json theme={null} [ { "id": "a1b2c3d4-...", "name": "My Project", "created_at": "2026-05-07T10:00:00Z" } ] ``` **Via UI:** Open [localhost:8100](http://localhost:8100). The board is already selected in the sidebar. You don't need to create one. If you want a dedicated board for this project: ```bash theme={null} # From Claude Code: > create a board called "Auth Project" # From UI: # Settings → Boards → New Board ``` Ideations are where raw requests land before anything gets built. **Via MCP (Claude Code):** ```text theme={null} > create an ideation: "I want to add user authentication to my app" ``` Pulse calls `okto_pulse_create_ideation` and returns: ```json theme={null} { "id": "9c64cdac-...", "title": "Add user authentication", "raw_request": "I want to add user authentication to my app", "status": "draft", "scope_assessment": null } ``` **Via UI:** Ideations tab → **New Ideation** → paste your raw request → Save. The ideation is now in `draft` state. Pulse has not made any decisions yet. This is the step that makes Pulse different from a rules file. Pulse analyzes your ideation and surfaces every material gap before you write a line of spec. Ask it to evaluate: ```text theme={null} > evaluate ideation 9c64cdac ``` Pulse runs `okto_pulse_evaluate_ideation` and returns a scope assessment: ```json theme={null} { "domains": 3, "ambiguity": 4, "dependencies": 2, "ambiguity_notes": "Auth strategy unspecified (OAuth, password, passkey); session management approach unclear; email verification scope undefined" } ``` Ambiguity is 4/5 — Pulse won't let this become a spec yet. It asks: ```text theme={null} > ask ideation questions ``` Pulse calls `okto_pulse_ask_ideation_choice_question`: ```text theme={null} Q1 (choice): Which authentication strategy should we use? A. Email + password with bcrypt hashing B. OAuth only (Google, GitHub) C. Both: password-based with optional OAuth link D. Passkeys / WebAuthn (passwordless) ``` You (or the agent) answers: ```text theme={null} > answer: A — email + password with bcrypt ``` Pulse records the answer via `okto_pulse_answer_ideation_question`: ```json theme={null} { "question_id": "q-001", "answer": "Email + password with bcrypt hashing", "answered_by": "agent:claude-code", "timestamp": "2026-05-07T10:03:41Z" } ``` Pulse continues for each gap. When ambiguity drops below the threshold, it marks the ideation `ready_for_refinement`. You can ask all the questions in one shot: `> run the ambiguity-killer protocol on ideation 9c64cdac` Pulse will call `ask_ideation_question` for each gap, accept your answers, and re-evaluate. Typical ideation takes 4–7 questions. Once the ideation is evaluated, derive the spec. Pulse builds it from your answers — you don't type a spec from scratch. ```text theme={null} > derive spec from ideation 9c64cdac ``` Pulse calls `okto_pulse_derive_spec_from_ideation` and returns a populated spec: ```json theme={null} { "id": "spec-8a3f...", "title": "User Authentication — Email + Password", "problem_statement": "The application has no authentication layer. Users cannot register, log in, or maintain sessions.", "acceptance_criteria": [ "User can register with email and password", "Password is stored as bcrypt hash (cost factor ≥ 12)", "User can log in and receive a session token", "Invalid credentials return 401 with no information leakage", "Session expires after 30 days of inactivity" ], "functional_requirements": ["..."], "test_scenarios": [], "business_rules": [], "status": "draft" } ``` The spec is pre-populated from your ideation answers. The acceptance criteria came from your answer to Q1 and Pulse's domain knowledge. You didn't write them. Review and refine in the UI (Specs tab → open spec → edit inline), or via MCP: ```text theme={null} > add acceptance criterion: "Password reset via email link with 1-hour expiry" ``` When the spec looks right: ```text theme={null} > submit spec evaluation ``` Pulse calls `okto_pulse_submit_spec_evaluation`. If coverage meets thresholds (acceptance criteria ≥ 80%, test scenarios linked), the spec moves to `approved`. Cards are execution units. Each one traces back to the spec you just created. ```text theme={null} > suggest sprints for spec spec-8a3f ``` Pulse calls `okto_pulse_suggest_sprints` and proposes a sprint slice. Accept it: ```text theme={null} > create sprint "Auth Sprint 1" with objective "Ship registration and login endpoints" ``` Then create the first card: ```text theme={null} > create card: "Implement POST /auth/register endpoint" type: task description: "Register endpoint: accept email + password, validate format, hash with bcrypt (cost 12), store user, return 201 + user ID. Return 409 on duplicate email." sprint: Auth Sprint 1 ``` Pulse calls `okto_pulse_create_card`. The card is created in `pending` state, linked to the spec and sprint. Move it to active work: ```text theme={null} > move card to in_progress ``` **Via UI:** Drag the card from the **Pending** column to **In Progress** on the board. The board now shows one active card, a sprint, a spec, and an ideation — all connected. *** ## What just happened You went from a vague idea to a tracked, traceable card in 5 minutes. Here's what Pulse actually did: * **The KG now contains a Decision node.** The answer "email + password with bcrypt" was written to the knowledge graph as a `Decision` with type `AuthStrategy`. Any future ideation about login, session management, or password reset will surface this decision automatically — before a new agent accidentally decides something contradictory. * **Your agent can query that decision mid-task.** At any point during implementation, Claude Code (or Cursor, or Cline) can call `okto_pulse_kg_query_natural("What auth approach did we decide?")` and get the answer back from the graph — not from context window memory. The answer is there whether the session is 2 minutes old or 2 months old. * **Everything survives the next session.** The ideation, Q\&A, spec, sprint, and KG decision nodes are stored in SQLite + the embedded graph at `~/.okto-pulse/boards/{id}/graph.lbug`. Start a new Claude Code session tomorrow, point it at the same board, and it has full context — without you re-explaining anything. *** What Pulse wrote to the graph just now, and how your agent queries it mid-task. Full agent configuration for Claude Code, Cursor, Cline, Windsurf, Goose, and Codex. # CLI Reference Source: https://docs.oktolabs.ai/reference/cli Complete reference for all okto-pulse CLI commands, flags, exit codes, and expected output. # CLI Reference `okto-pulse` is the single entry point for installing, starting, and maintaining a Pulse instance. All commands run locally — nothing is sent to a remote server. ## Installing the CLI ```bash theme={null} pip install okto-pulse ``` Requires Python 3.11+. See [Install](/install) for Docker and source options. Verify the install: ```bash theme={null} okto-pulse --version ``` ```text theme={null} okto-pulse 0.2.0 okto-pulse-core 0.2.0 ``` *** ## Global flags These flags are accepted by every command. Print usage and exit. Works on the root command and on any subcommand: `okto-pulse init --help`. Print the versions of both `okto-pulse` and `okto-pulse-core` and exit. Source: `cli.py:164`. To increase log verbosity, set the `DEBUG` environment variable: ```bash theme={null} DEBUG=true okto-pulse serve --accept-terms ``` *** ## `okto-pulse init` *Source: `cli.py:314–440`* Initialize `~/.okto-pulse/`, seed the database, bootstrap the knowledge graph schema for the first board, and optionally write `.mcp.json` for your agent. ```bash theme={null} okto-pulse init [--agents [NAME ...]] ``` Generate `.mcp.json` in the current directory. Pass with no argument to include all registered agents. Pass one or more agent names to include only that subset. Omit the flag entirely to skip `.mcp.json` generation. ```bash theme={null} okto-pulse init --agents # all agents okto-pulse init --agents claude # named agent only okto-pulse init # no .mcp.json ``` **What `init` creates:** ```text theme={null} ~/.okto-pulse/ data/pulse.db SQLite database (WAL mode, FK ON) uploads/ file attachment storage boards/{board_id}/graph.lbug per-board knowledge graph ``` `.mcp.json` is written in the **current working directory** (not `~/.okto-pulse/`). Run `init` from your project root so your agent picks it up. `.mcp.json` contains a per-agent API key. Add it to `.gitignore` before your first commit. **Exit codes:** `0` on success. Non-zero if the data directory cannot be created or the database cannot be seeded. ```bash Init with agents theme={null} cd ~/my-project okto-pulse init --agents ``` ```text Output theme={null} ✓ Data directory: ~/.okto-pulse/data/ ✓ Database initialized ✓ Default board created ✓ Knowledge graph bootstrapped ✓ .mcp.json written (1 agent) ``` *** ## `okto-pulse serve` *Source: `cli.py:500–563`* Start the API server, web board, and MCP server as a single Python process with two uvicorn listeners. ```bash theme={null} okto-pulse serve [--api-port PORT] [--mcp-port PORT] [--accept-terms] ``` Port for the web board and REST API. Sets `OKTO_PULSE_PORT` before the app module is imported. Source: `cli.py:20`. Port for the MCP server (216 tools). Sets `OKTO_PULSE_MCP_PORT` before the app module is imported. Source: `cli.py:21`. Pre-accept the Terms of Use and skip the interactive prompt. Equivalent to setting `OKTO_PULSE_TERMS_ACCEPTED=1`. Required in CI and containerized environments. Source: `cli.py:537`. Both port environment variables are set **before** the app module is imported, because `okto_pulse.community.main` reads them at import time to generate `/config.js`. If you use a non-default MCP port, update the generated `.mcp.json` URL so it matches the port passed to `okto-pulse serve --mcp-port`. ```bash Default start theme={null} okto-pulse serve --accept-terms ``` ```text Output theme={null} Board: http://127.0.0.1:8100 MCP: http://127.0.0.1:8101/mcp ``` ```bash Custom ports theme={null} okto-pulse serve --api-port 9000 --mcp-port 9001 --accept-terms ``` **Exit codes:** `0` on clean shutdown (Ctrl+C). Non-zero if either port is already in use. *** ## `okto-pulse status` *Source: `cli.py:567–614`* Show service status and board metrics without starting the server. ```bash theme={null} okto-pulse status [--api-port PORT] [--mcp-port PORT] ``` Port to probe for the API server. Must match the port used in `serve`. Port to probe for the MCP server. ```bash Status check theme={null} okto-pulse status ``` ```text Output theme={null} Data dir: ~/.okto-pulse/data/ Database: ~/.okto-pulse/data/pulse.db (1,204 KB) boards 1 cards 47 specs 8 agents 2 API server :8100 running MCP server :8101 running ``` **Exit codes:** `0` always. Port connectivity failures are reported in the output, not via exit code. *** ## `okto-pulse api-key` *Source: `cli.py:620–680`* Print the bootstrap API key directly from the SQLite database. Use this in CI/CD pipelines to extract the seeded key without parsing log output. ```bash theme={null} okto-pulse api-key ``` No flags. **Output:** The API key value on a single line to `stdout`. The startup banner goes to `stderr` so the key can be captured cleanly: ```bash theme={null} KEY=$(okto-pulse api-key 2>/dev/null) ``` **Exit codes:** `0` if the key is found and printed. `1` if the database is missing or no key exists (run `okto-pulse init` first). ```bash Print API key theme={null} okto-pulse api-key ``` ```text Output theme={null} dash_a3f8c21e4b7d9f0e2a1c5b8d ``` *** ## `okto-pulse verify-pipeline` *Source: `cli.py:683–744`, `kg/health.py`* Run five KG pipeline health checks against a board and report results. ```bash theme={null} okto-pulse verify-pipeline [--json] ``` The board UUID to inspect. Find it in the web board URL or via `okto-pulse status`. Emit a structured JSON object instead of a human-readable table. Useful for scripted health monitoring. **Checks run:** | Check | What it verifies | | ---------------------- | -------------------------------------------------------------- | | `check_queue` | SQLite consolidation queue depth | | `check_kuzu` | LadybugDB graph file presence and node count | | `check_kuzu_node_refs` | Cross-check between LadybugDB total and SQLite node ref mirror | | `check_outbox` | Global update outbox staleness | | `check_global` | Global discovery graph file presence | **Exit codes:** `0` if all five checks pass. `1` if any check fails. Use exit code in CI to gate deployments. ```bash Table output theme={null} okto-pulse verify-pipeline ``` ```text Output theme={null} check_queue ✓ pass depth=0 check_kuzu ✓ pass nodes=312 check_kuzu_node_refs ✓ pass delta=0 check_outbox ✓ pass staleness=0s check_global ✓ pass ``` ```bash JSON output theme={null} okto-pulse verify-pipeline --json ``` ```json Output theme={null} { "check_queue": {"status": "pass", "depth": 0}, "check_kuzu": {"status": "pass", "nodes": 312}, "check_kuzu_node_refs": {"status": "pass", "delta": 0}, "check_outbox": {"status": "pass", "staleness_seconds": 0}, "check_global": {"status": "pass"} } ``` *** ## `okto-pulse kg backfill` *Source: `cli.py:747–902`* Run the Layer 1 deterministic KG worker against a board to (re-)populate the knowledge graph from existing artifacts. Dry-run by default — pass `--apply` to write. ```bash theme={null} okto-pulse kg backfill [--apply] [--artifact-type TYPE] [--json] ``` The board UUID to backfill. Enqueue all artifacts and drain the consolidation queue, writing to LadybugDB. Without this flag the command reports what *would* be emitted without making any changes. Restrict backfill to one artifact type. Accepts: `spec`, `sprint`, or `card`. Omit to backfill all types. Emit structured JSON output. Useful for scripting and log parsing. Run `kg backfill` after a schema migration, after importing data from another instance, or when the KG health check reports a `check_kuzu_node_refs` delta greater than zero. For ongoing consolidation, the background worker handles new artifacts automatically. See [KG backfill operations](/kg-operations/backfill) for guidance on expected runtime. ```bash Dry run (default) theme={null} okto-pulse kg backfill ``` ```text Output theme={null} Dry run — no writes. Pass --apply to commit. spec artifacts 8 → would emit 43 nodes, 61 edges sprint artifacts 12 → would emit 28 nodes, 34 edges card artifacts 47 → would emit 94 nodes, 118 edges Total: 165 nodes, 213 edges pending ``` ```bash Apply backfill theme={null} okto-pulse kg backfill --apply ``` ```text Output theme={null} Enqueueing artifacts... Processing queue... spec artifacts 8 → committed 43 nodes, 61 edges sprint artifacts 12 → committed 28 nodes, 34 edges card artifacts 47 → committed 94 nodes, 118 edges Backfill complete. Queue empty. ``` **Exit codes:** `0` on success. `1` if the board is not found or the graph file cannot be opened. *** ## `okto-pulse kg dedup-entities` *Source: `cli.py:908–936`* Consolidate duplicate LadybugDB nodes that share the same `(node_type, source_artifact_ref)`. Writes by default — pass `--dry-run` to preview. ```bash theme={null} okto-pulse kg dedup-entities [--dry-run] [--json] ``` The board UUID to deduplicate. Report duplicates without merging them. Always run this first to review what will be merged before committing. Emit structured JSON output. `kg dedup-entities` writes to the LadybugDB graph **by default** (without `--dry-run`). Merging nodes is not automatically reversible. Run the dry-run first, then `verify-pipeline` after applying to confirm the graph is consistent. ```bash Dry run first theme={null} okto-pulse kg dedup-entities --dry-run ``` ```text Output theme={null} Dry run — no writes. Decision "Use SQLite for queue" 2 duplicates → would merge Entity "Claude Code" 3 duplicates → would merge 2 merge operations pending. Run without --dry-run to apply. ``` ```bash Apply dedup theme={null} okto-pulse kg dedup-entities ``` ```text Output theme={null} Decision "Use SQLite for queue" merged (2 → 1) Entity "Claude Code" merged (3 → 1) Deduplication complete. 2 nodes merged. ``` **Exit codes:** `0` on success (including zero duplicates found). `1` if the board or graph file is not found. *** ## `okto-pulse reset` *Source: `cli.py:939–960`* Delete all local Pulse data and re-seed from scratch. Equivalent to uninstalling and reinstalling the data directory. ```bash theme={null} okto-pulse reset [-y] ``` Skip the confirmation prompt. Required for non-interactive environments (CI, scripts). Without this flag, the command prints a warning and asks for confirmation before proceeding. `reset` permanently deletes `pulse.db`, all WAL files, and everything in the uploads directory. All boards, specs, cards, knowledge graph data, and file attachments are lost. There is no undo. If you need to start over on a single board without losing others, use `archive_tree` via the MCP API instead. **What `reset` does:** 1. Deletes `~/.okto-pulse/data/pulse.db*` (database and WAL files) 2. Clears `~/.okto-pulse/uploads/` 3. Runs `okto-pulse init` to re-seed defaults **Exit codes:** `0` on success. `1` if the user declines the confirmation prompt. ```bash Interactive reset theme={null} okto-pulse reset ``` ```text Output theme={null} ⚠ This will delete all boards, specs, cards, and knowledge graph data. Data dir: ~/.okto-pulse/ Type "yes" to confirm: yes ✓ Database deleted ✓ Uploads cleared ✓ Re-initialized ``` ```bash Non-interactive reset theme={null} okto-pulse reset -y ``` *** ## Environment variables Key variables that affect CLI behavior. Set in your shell or in a `.env` file in the working directory. | Variable | Default | Description | | --------------------------- | --------------- | ------------------------------------------------------------- | | `OKTO_PULSE_PORT` | `8100` | API + frontend port | | `OKTO_PULSE_MCP_PORT` | `8101` | MCP server port | | `OKTO_PULSE_TERMS_ACCEPTED` | — | Set to `1` to skip the ToU prompt (same as `--accept-terms`) | | `OKTO_PULSE_DATA_DIR` | `~/.okto-pulse` | Override the data directory location | | `OKTO_PULSE_NO_BANNER` | — | Set to `1` to suppress the ASCII banner | | `DEBUG` | `false` | Enable verbose debug logging | | `KG_KUZU_BUFFER_POOL_MB` | `256` | LadybugDB buffer pool in MB (legacy env-var name, 16–512) | | `KG_KUZU_MAX_DB_SIZE_GB` | `1` | LadybugDB max database size in GB (legacy env-var name, 1–64) | Full environment variable reference: [Local operations](/operations/local). *** ## Quick reference | Command | What it does | | --------------------------------------------- | --------------------------------------- | | `okto-pulse init --agents` | Bootstrap data dir + write `.mcp.json` | | `okto-pulse serve --accept-terms` | Start board (`:8100`) and MCP (`:8101`) | | `okto-pulse status` | Check running ports and board metrics | | `okto-pulse api-key` | Print bootstrap API key (CI use) | | `okto-pulse verify-pipeline ` | Run 5 KG health checks | | `okto-pulse kg backfill --apply` | Rebuild KG from existing artifacts | | `okto-pulse kg dedup-entities --dry-run` | Preview duplicate node merges | | `okto-pulse reset -y` | Delete all data and re-seed | # Entities and states Source: https://docs.oktolabs.ai/reference/entities Reference map of Pulse domain entities, persisted records, status enums, and where each surface is exposed. # Entities and states This page maps the product concepts to the actual source entities in `okto-pulse-core/src/okto_pulse/core/models/db.py` and their API schemas in `models/schemas.py`. Use it when you need to know what Pulse stores, which lifecycle values are valid, and where each object is reachable. ## Core delivery entities | Entity | Source model | Primary routes | MCP surface | Purpose | | ----------------- | ------------------ | ------------------------------------------------------------------------------------ | ---------------------------------------- | ----------------------------------------------------------------------------------------------- | | Agent | `Agent` | `/api/v1/agents` | Board management tools | Actor that owns an API key, permissions, and board access. | | Agent board grant | `AgentBoard` | `/api/v1/agents/{agent_id}/boards/{board_id}` | Agent access tools | Board-scoped access row with optional permission overrides. | | Permission preset | `PermissionPreset` | `/api/v1/presets` | Permission and agent tools | Named permission set that can be attached to agents. | | Board | `Board` | `/api/v1/boards` | `okto_pulse_get_board`, board CRUD tools | Workspace container for the SDLC graph. | | Ideation | `Ideation` | `/api/v1/boards/{board_id}/ideations`, `/api/v1/ideations/{ideation_id}` | Ideation tools | Initial problem statement and ambiguity-killer workflow. | | Refinement | `Refinement` | `/api/v1/ideations/{ideation_id}/refinements`, `/api/v1/refinements/{refinement_id}` | Refinement tools | Evidence-gathering phase between ideation and spec. | | Spec | `Spec` | `/api/v1/boards/{board_id}/specs`, `/api/v1/specs/{spec_id}` | Spec tools | Delivery contract with requirements, criteria, scenarios, decisions, rules, contracts, and TRs. | | Sprint | `Sprint` | `/api/v1/boards/{board_id}/sprints`, `/api/v1/sprints/{sprint_id}` | Sprint tools | Scope slice that groups cards and closes through sprint evaluation. | | Card | `Card` | `/api/v1/boards/{board_id}/cards`, `/api/v1/cards/{card_id}` | Card and task tools | Execution unit: normal work, test task, or bug task. | | Card dependency | `CardDependency` | `/api/v1/cards/{card_id}/dependencies` | Dependency tools | `depends_on` relationship between two cards. | ## Evidence and collaboration entities | Entity | Source model | Primary routes | Purpose | | ------------ | ----------------------------------------------------------------------------- | ------------------------------------------------------------ | -------------------------------------------------------------- | | Q\&A item | `QAItem`, `IdeationQAItem`, `RefinementQAItem`, `SpecQAItem`, `SprintQAItem` | `/api/v1/qa/*`, `/{entity}/{id}/qa` | Structured questions and answers on cards and SDLC artifacts. | | Comment | `Comment` | `/api/v1/comments/*` | Text comments and single/multi-choice comment boards on cards. | | Attachment | `Attachment` | `/api/v1/attachments/{board_id}/{card_id}` | Uploaded files attached to cards. | | Guideline | `Guideline`, `BoardGuideline` | `/api/v1/guidelines`, `/api/v1/boards/{board_id}/guidelines` | Global or board-specific rules agents must read before work. | | Activity log | `ActivityLog` | `/api/v1/cards/{card_id}/activity` | Audit trail for card-visible changes. | | Seen marker | `AgentSeenItem` | `/api/v1/cards/{card_id}/seen` | Per-agent unread/seen state for mentions and changes. | | Validation | JSON records on `Card`, `Spec`, and `Sprint` plus validation response schemas | Card/spec/sprint validation routes | Independent review and lifecycle gate evidence. | ## Spec sub-objects These are stored inside a spec payload, exposed through spec routes and MCP spec tools, and copied into card context when work starts. | Object | Source schema/model | Purpose | | --------------------- | ------------------------------------------------------------------------ | ------------------------------------------------------------------------------------ | | Business rule | `BusinessRule` | Rule linked to one or more functional requirements and implementation cards. | | API contract | `ApiContract` | Endpoint or integration contract with method, path, payload shape, and linked cards. | | Technical requirement | TR object in `Spec` | Non-functional or implementation-level requirement linked to tasks. | | Acceptance criterion | AC list in `Spec` | User-visible condition that must be covered by scenarios and tasks. | | Test scenario | `TestScenario` payload | Testable scenario; must be linked to test cards before validation. | | Decision | Decision payload in `Spec` | Explicit architecture/product choice; can be active, superseded, or revoked. | | Screen mockup | `ScreenMockup`, `MockupAnnotation` | HTML mockup and annotations attached to ideations, refinements, specs, or cards. | | Architecture design | `ArchitectureDesign`, `ArchitectureDesignVersion`, `ArchitectureDiagram` | Structured architecture payloads, diagrams, versions, and diffs. | ## Knowledge entities | Entity | Source model | Primary routes/tools | Purpose | | ------------------------- | ----------------------------------------------- | --------------------------------------------------------- | ------------------------------------------------------- | | Ideation knowledge | `IdeationKnowledgeBase` | `/api/v1/ideations/{id}/knowledge`, MCP knowledge tools | Evidence attached before refinement/spec derivation. | | Refinement knowledge | `RefinementKnowledgeBase` | `/api/v1/refinements/{id}/knowledge`, MCP knowledge tools | Evidence gathered during refinement. | | Spec knowledge | `SpecKnowledgeBase` | `/api/v1/specs/{id}/knowledge`, MCP knowledge tools | Source material attached to the delivery contract. | | Card knowledge | JSON records on `Card.knowledge_bases` | `/api/v1/cards/{id}/knowledge`, MCP knowledge tools | Context copied or written directly onto a task. | | Consolidation queue | `ConsolidationQueue` | `/api/v1/kg/boards/{board_id}/pending` | SQLite work queue that drains artifacts into the graph. | | Consolidation dead letter | `ConsolidationDeadLetter` | `/api/v1/kg/queue/dead-letter`, KG DLQ MCP tools | Failed KG consolidation work that exhausted retries. | | Consolidation audit | `ConsolidationAudit` | `/api/v1/kg/boards/{board_id}/audit` | System-of-record for committed KG sessions. | | KG tick run | `KGTickRun` | `/api/v1/kg/tick/run-now`, KG health | Relevance decay tick execution record. | | Domain event | `DomainEventRow`, `DomainEventHandlerExecution` | Event dispatcher internals | Durable event and handler execution tracking. | ## Discovery and analytics entities | Entity | Source model/schema | Route family | Purpose | | -------------------- | -------------------------- | ---------------------------------------------------- | ---------------------------------------------------------------------------------- | | Discovery intent | `DiscoveryIntent` | `/api/v1/discovery/intents` | Saved operator intent that maps to a tool-backed discovery action. | | Saved search | `DiscoverySavedSearch` | `/api/v1/discovery/boards/{board_id}/saved-searches` | Reusable board search. | | Search history | `DiscoverySearchHistory` | `/api/v1/discovery/boards/{board_id}/search-history` | History of executed discovery searches. | | Analytics entity row | Analytics response schemas | `/api/v1/boards/{board_id}/analytics/entities` | Spec, ideation, card, sprint, agent, and board metrics for dashboards and exports. | ## Status enums | Enum | Values | | -------------------- | ------------------------------------------------------------------------------------- | | `IdeationStatus` | `draft`, `review`, `approved`, `evaluating`, `done`, `cancelled` | | `IdeationComplexity` | `small`, `medium`, `large` | | `RefinementStatus` | `draft`, `review`, `approved`, `done`, `cancelled` | | `SpecStatus` | `draft`, `review`, `approved`, `validated`, `in_progress`, `done`, `cancelled` | | `SprintStatus` | `draft`, `active`, `review`, `closed`, `cancelled` | | `CardStatus` | `not_started`, `started`, `in_progress`, `validation`, `on_hold`, `done`, `cancelled` | | `CardPriority` | `critical`, `very_high`, `high`, `medium`, `low`, `none` | | `CardType` | `normal`, `bug`, `test` | | `BugSeverity` | `critical`, `major`, `minor` | | `CommentType` | `text`, `choice`, `multi_choice` | ## Lifecycle relationships | Parent | Children | | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------ | | Board | Ideations, agents, guidelines, KG graph, queue, and audit rows | | Ideation | Refinements and specs | | Refinement | Specs, knowledge, mockups, architecture, Q\&A, snapshots, and history | | Spec | Sprints, cards, business rules, API contracts, test scenarios, decisions, knowledge, mockups, architecture, Q\&A, validations, and history | | Sprint | Assigned cards, evaluations, Q\&A, and history | | Card | Dependencies, knowledge, mockups, architecture, Q\&A, comments, attachments, conclusions, validations, and activity | Important invariants: * Cards should link to a spec; bug and test cards have additional scenario-link rules. * A sprint closes only after sprint evaluation and test evidence checks pass. * A normal card reaches `done` through the task validation gate. * Spec `approved` to `validated` requires coverage validation; `validated` to `in_progress` requires spec evaluation. * Deleting ideations or refinements can remove a full subtree; use archive/restore for reversible hiding. See [SDLC flow](/concepts/sdlc-flow), [Validation gates](/reference/mcp/validation), and [REST route catalog](/reference/rest-api-catalog) for the operational surfaces. # MCP reference Source: https://docs.oktolabs.ai/reference/mcp Overview of all 216 Pulse MCP tools: authentication, transport, 8 domain categories, and the 20 most-used tools in daily AI-assisted development workflows. # MCP reference Pulse exposes **216 tools** via the [Model Context Protocol](https://modelcontextprotocol.io). They cover every stage of the ADLC pipeline — from creating an ideation to submitting task validation evidence — plus full access to the Knowledge Graph. The server runs locally at `http://127.0.0.1:8101/mcp` (default). Any MCP-compatible agent (Claude Code, Cursor, Cline, Windsurf, Goose, Codex) can connect to it and call these tools directly. *** ## What you can do with MCP tools MCP tools give your AI agent direct access to the full SDLC workflow — no web UI needed. | Audience | What MCP unlocks | | ------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- | | **Individual developers** | Run ideation → spec → cards entirely from your coding agent. Never leave the editor. | | **AI agent builders** | Wire Pulse as a structured memory and task layer for autonomous agents. The KG persists decisions across sessions and agent restarts. | | **Teams** | Multiple agents share one board. Decisions, constraints, and test scenarios are written once and referenced by every agent that joins. | A connected agent can: create and advance ideations, write specs with business rules and test scenarios, record design decisions, suggest and create sprints, move cards through the implementation pipeline, submit validation evidence, and query the Knowledge Graph for prior context — all as native tool calls. *** ## Authentication Every tool call requires authentication. Pulse supports two methods: ### API key (recommended) Pass the key as a query parameter. `okto-pulse init --agents` generates a scoped key and writes it into `.mcp.json` automatically: ```text theme={null} http://127.0.0.1:8101/mcp?api_key=dash_... ``` The key has the prefix `dash_` followed by a hex string. Most agents pick this up from `.mcp.json` automatically — no manual config required. ### Bearer token Pass the token in the `Authorization` header. The value is the same `dash_` key: ```bash curl theme={null} curl http://127.0.0.1:8101/mcp \ -H "Authorization: Bearer dash_..." ``` ```python Python theme={null} import httpx client = httpx.Client( base_url="http://127.0.0.1:8101", headers={"Authorization": "Bearer dash_..."}, ) ``` ```javascript Node theme={null} const client = new MCPClient({ url: "http://127.0.0.1:8101/mcp", headers: { Authorization: "Bearer dash_..." }, }); ``` ### Environment variable Set `PULSE_API_TOKEN` in the environment where your agent or automation script runs. Pulse reads this as the fallback when no `api_key` query param or `Authorization` header is present: ```bash theme={null} export PULSE_API_TOKEN=dash_... ``` Your API key is equivalent to a password for your board. Do not commit `.mcp.json` to a public repository. Do not paste the `?api_key=` URL into GitHub issues, Slack, or chat tools. *** ## Transport Pulse uses **HTTP Streamable MCP** (the MCP standard transport over HTTP with SSE streaming). | Property | Value | | --------------- | ---------------------------------------------------------------- | | Default URL | `http://127.0.0.1:8101/mcp` | | Transport | HTTP Streamable MCP (SSE) | | Response format | All tools return `str` — a JSON-encoded response or error object | | Rate limiting | None on local; Docker deployments may add upstream limits | **Docker note:** If Pulse is running inside Docker, the MCP server binds to `127.0.0.1` by default — unreachable from outside the container. Set `MCP_HOST=0.0.0.0` before starting `okto-pulse serve` to expose it on all interfaces. *** ## Tool domains 216 tools across 8 domains. Full per-tool reference pages are coming in Wave 2 — click a domain card to learn more or jump to the Knowledge Graph page now. 17 tools across profile, board discovery, members, activity & mentions, and guidelines. The session-start surface — `list_my_boards`, `get_board_guidelines`, `get_unseen_summary`. 20 tools. Create, advance, and evaluate ideations. Structured Q\&A, ambiguity-killer protocol, knowledge entries, version snapshots, ideation-to-spec derivation. **Coming Wave 2** — full reference page with all parameters. 14 tools. Deep investigation phase. Create and advance refinements, structured Q\&A, evidence and constraint capture, refinement-to-spec derivation. **Coming Wave 2** — full reference page with all parameters. \~40 tools. Write acceptance criteria, business rules, test scenarios, API contracts, architecture designs, screen mockups, decisions, and structured Q\&A. Evaluation gate and validation gate. **Coming Wave 2** — full reference page with all parameters. 14 tools. Create and advance sprints, assign cards, suggest sprint scope, submit sprint evaluations, sprint Q\&A. Status flow: draft → active → review → closed. **Coming Wave 2** — full reference page with all parameters. \~16 tools. Create, move, and close cards; dependencies, comments, attachments, card knowledge. Includes the two validation gates: `submit_spec_validation` (approved → validated) and `submit_task_validation` (validation → done). **Coming Wave 2** — full reference page with all parameters. 21 tools (across `kg_tools.py`, `kg_query_tools.py`, `kg_power_tools.py`, and KG admin tools in `server.py`). Consolidation session lifecycle, natural-language and Cypher queries, decision history, contradiction detection, supersedence chains. **Reference:** [Knowledge Graph concepts](/concepts/knowledge-graph) 3 tools. `get_analytics` (velocity, quality, coverage, per-agent metrics), `get_traceability_report` (spec → BRs → scenarios → cards → validations lineage), `list_blockers` (cards currently on-hold or missing dependencies). **Coming Wave 2** — full reference page with all parameters. *** ## Top 20 tools These are the tools agents reach for most in daily ADLC workflows, ordered by where they appear in the pipeline. | Tool | Domain | What it does | | -------------------------------------- | ------------------ | ---------------------------------------------------------------------------------------------- | | `okto_pulse_list_my_boards` | Board | List all boards this agent has access to — first call at session start | | `okto_pulse_get_unseen_summary` | Board | Count and summarize unseen mentions and activity since last session | | `okto_pulse_create_ideation` | Ideations | Start a new feature idea with title, description, and initial context | | `okto_pulse_get_ideation_context` | Ideations | Rich context bundle: ideation + linked refinements + KG prior decisions | | `okto_pulse_evaluate_ideation` | Ideations | Submit scope evaluation (per-axis scores) before advancing to spec | | `okto_pulse_derive_spec_from_ideation` | Ideations | Create a new spec from a completed ideation — one-step derivation | | `okto_pulse_get_spec_context` | Specs | Rich context: spec + sprint + cards + KG decisions + BRs + contracts | | `okto_pulse_add_business_rule` | Specs | Add a business rule constraint to a spec | | `okto_pulse_add_test_scenario` | Specs | Add a test scenario with acceptance criteria linkage | | `okto_pulse_add_decision` | Specs | Record a design decision with rationale and alternatives considered | | `okto_pulse_submit_spec_evaluation` | Specs | Qualitative evaluation gate — required before `approved → validated` transition | | `okto_pulse_suggest_sprints` | Sprint | AI-assisted sprint suggestion: slice a spec into reviewable deliveries | | `okto_pulse_create_card` | Cards & Validation | Create an implementation card (type: normal, test, bug) | | `okto_pulse_get_task_context` | Cards & Validation | Rich bundle: card + spec + BRs + scenarios + decisions + KG context — read before implementing | | `okto_pulse_move_card` | Cards & Validation | Move a card to the next status (enforces transition gate) | | `okto_pulse_submit_task_validation` | Cards & Validation | Independent reviewer evidence gate — required before `validation → done` | | `okto_pulse_get_traceability_report` | Analytics | Full lineage: spec → BRs → TRs → scenarios → cards → validations | | `okto_pulse_kg_query_natural` | Knowledge Graph | Natural-language search over the KG — no Cypher, no schema knowledge required | | `okto_pulse_kg_find_similar_decisions` | Knowledge Graph | Find past decisions ranked by semantic similarity, graph centrality, and recency | | `okto_pulse_kg_begin_consolidation` | Knowledge Graph | Open a transactional session to commit new nodes and edges to the graph | *** ## Tool count breakdown | Source file | Tool count | | ------------------- | ---------- | | `server.py` | 177 | | `kg_tools.py` | 7 | | `kg_query_tools.py` | 9 | | `kg_power_tools.py` | 5 | | **Total** | **216** | All tools return `str` — a JSON-encoded response object or a structured error. Error objects always include an `error` key and a human-readable `message`. *** ## Quickstart: list your boards Once Pulse is running and your agent is connected, this is the first call to make: ```text theme={null} Use the Okto Pulse MCP tools. Call okto_pulse_list_my_boards and summarize what boards I have access to and what's currently in progress. ``` A correctly connected agent will call `okto_pulse_list_my_boards`, then follow up with `okto_pulse_get_unseen_summary` to surface any activity since the last session. From there, you're ready to start or continue any pipeline stage. For step-by-step connection setup, see [Connect an agent](/connect-agent). *** ## Error handling All 216 tools return `str` — a JSON-encoded payload. On success the shape varies by tool, but every error follows the same structure: ```json theme={null} { "error": "NOT_FOUND", "message": "Board brd_abc123 not found or agent does not have access.", "detail": {} } ``` Common error codes: | Code | Meaning | | ------------------ | ------------------------------------------------------------------------------------------------------------------------ | | `UNAUTHORIZED` | Missing or invalid API key. Check `.mcp.json` and regenerate with `okto-pulse init --agents`. | | `FORBIDDEN` | Key is valid but the agent's permission preset does not allow this tool. Change the preset in **Board → Agents → Edit**. | | `NOT_FOUND` | Entity ID is incorrect or belongs to a different board. | | `VALIDATION_ERROR` | Required field missing or value out of range. The `detail` object lists the failing fields. | | `CONFLICT` | Status transition is not allowed (e.g., trying to move a card to `done` without passing the validation gate). | | `RATE_LIMITED` | KG Cypher queries are rate-limited to 30 req/min per board. Back off and retry. | When you get an unexpected error, pass the full JSON error object to your agent — it contains enough context to self-correct in most cases. *** ## Versioning policy Pulse follows [semantic versioning](https://semver.org). MCP tool stability by version: | Change type | How it's communicated | | -------------------------------------------------------------- | ------------------------------------------------------------------------------------------- | | **Breaking** (tool removed or parameter renamed) | Major version bump + `CHANGELOG.md` `BREAKING:` entry + minimum 1 sprint deprecation notice | | **New tool added** | Minor version bump + `CHANGELOG.md` entry | | **Bug fix or description change** | Patch version + `CHANGELOG.md` entry | | **Behavior-only change** (same signature, stricter validation) | Patch version + `CHANGELOG.md` `Note:` entry | **Safe pattern for agents:** call `okto_pulse_kg_schema_info` at session start to get the current schema version. If the version has changed since your last session, check `CHANGELOG.md` for any breaking changes before proceeding. Tool names follow the `okto_pulse__` convention. Names are stable within a major version. *** ## Connecting your agent Step-by-step setup for Claude Code, Cursor, Cline, Windsurf, Goose, and Codex — including `.mcp.json` generation, per-agent config, and troubleshooting. *** ## Next steps How the KG persists decisions, constraints, and learnings across sessions and agent changes. The six stages — Ideation → Refinement → Spec → Sprint → Cards → Validation — and how MCP tools map to each one. # MCP - analytics and activity Source: https://docs.oktolabs.ai/reference/mcp/analytics Reference for board analytics, activity, traceability, unseen summaries, and mentions through MCP. # Analytics and activity You can use these MCP tools when an agent needs board status before deciding what to do next. They complement the board-management tools by focusing on movement, unread work, activity, and traceability. ## Tools covered | Tool | Purpose | | ------------------------------------ | ---------------------------------------------------------------------------------------- | | `okto_pulse_get_activity_log` | Recent board events and user/agent activity. | | `okto_pulse_get_analytics` | Board-level counts, status breakdowns, throughput, validation metrics, and risk signals. | | `okto_pulse_get_unseen_summary` | What changed since the authenticated agent last checked. | | `okto_pulse_list_my_mentions` | Mentions addressed to the authenticated agent. | | `okto_pulse_mark_as_seen` | Mark activity or mention state as read. | | `okto_pulse_get_traceability_report` | Coverage links between tasks, scenarios, rules, contracts, and requirements. | ## Session-start status check A practical session start is: ```text theme={null} okto_pulse_list_my_boards okto_pulse_get_unseen_summary okto_pulse_get_activity_log okto_pulse_get_analytics ``` Use this before opening large board details. ## Activity log `okto_pulse_get_activity_log` answers what changed and who changed it. Use it to ground a handoff or to decide whether a card moved while the agent was offline. ## Analytics `okto_pulse_get_analytics` returns board metrics: status counts, validation gate metrics, stale work, sprint health, bug counts, and coverage signals. Use it for planning and QA, not as a substitute for reading the exact spec or card. ## Traceability report The traceability report is the fastest way to find missing links between cards and the evidence they claim to implement. ## Mentions and seen state Mentions are agent-directed work. Mark seen state after processing so the next session can focus on new activity. ## Related pages * [Board management tools](/reference/mcp/board-management) * [Validation tools](/reference/mcp/validation) * [Multi-agent development](/guides/multi-agent) # Architecture & mockups Source: https://docs.oktolabs.ai/reference/mcp/architecture-mockups Reference for the 17 MCP tools that capture system architecture (entities, interfaces, diagrams) and screen mockups across ideations, refinements, specs, and cards — including the validate-then-write authoring loop and the spec-to-card propagation snapshots. # Architecture & mockups Pulse exposes **17 of its 216 MCP tools** for visual design artifacts: * **12 architecture-design tools** (`server.py:6824–7503`) — structured system designs with entities, interfaces, and diagrams (Excalidraw, Mermaid, draw\.io, SVG, PNG). * **5 screen-mockup tools** (`server.py:9436–9710`) — HTML+Tailwind page mockups, modals, drawers, popovers, and panels. Both artifact types attach to **any pipeline entity** — ideation, refinement, spec, or card — and both have a dedicated copy tool that takes a deep-copy snapshot from a spec onto a card so an implementer's context is self-contained. Source-of-truth citations: `okto-pulse-feature-inventory.md:378–410` and `:429–445`. *** ## When to use which | Artifact | Captures | Authoring tools | | ----------------------- | ------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------- | | **Architecture Design** | Services, modules, databases, queues, events, runtime boundaries, API contracts, data flows | Schema-validated payload (`entities` + `interfaces` + `diagrams`), with optional Excalidraw imports. | | **Screen mockup** | A single page, modal, drawer, popover, or panel rendered as sanitized HTML+Tailwind. | Free-form HTML; supports text annotations from reviewers. | Use **architecture designs** to encode runtime topology and ownership boundaries that downstream cards must respect. Use **screen mockups** for visual UI references the implementer renders against. They are independent — one spec can have both. *** ## Architecture designs ### Authoring loop The architecture model is critiqued by the server before it accepts a write. Skip the validation step and you get rejected with contextual paths like `entities[0].name` or `diagrams[0].adapter_payload.elements[2].linkedEntityId` — fix the cited field and retry. The recommended loop for non-trivial payloads: `okto_pulse_get_architecture_design_schema` returns allowed enums, entity/interface contracts, Excalidraw adapter rules, bad and good examples, and a complete minimal payload. ```text theme={null} Input: board_id: "brd_abc123" Output (truncated): { "success": true, "schema": { "entity_types": ["web_app", "mobile_app", "api", "service", "database", "queue", "topic", "external_system", ...], "interface_directions": ["source_to_target", "target_to_source", "bidirectional", "none"], "connection_types": ["direct", "elbow"], ... } } ``` `okto_pulse_validate_architecture_design_payload` (`server.py:6933`) runs the same critique the create/update path runs but persists nothing. It returns: * `valid` — whether the payload would be rejected * `issues` — blocking errors with JSON paths * `warnings` — non-blocking gaps that hurt downstream clarity * `suggested_fixes` — concrete corrections for common mistakes * `summary` — counts of entities, interfaces, diagrams, elements, links Pass `parent_type` + `parent_id` for create-mode validation. Pass `design_id` (and only the fields you intend to change) for update-mode — omitted fields are merged from the existing design before critique. Call `okto_pulse_add_architecture_design` (`server.py:7049`) or `okto_pulse_update_architecture_design` (`server.py:7207`) with the same payload. Warnings are not blockers, but each one usually marks a detail a downstream implementer or validator would otherwise have to guess. **Specs are locked once validation passes.** Attempting to add or update an architecture design on a spec whose current validation `outcome == "success"` returns `"Spec is locked because validation passed. Move it back to draft or approved to edit architecture."` Move the spec back to `draft` or `approved` first. ### Tool reference | Tool | Line | Purpose | | --------------------------------------------------- | ---- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `okto_pulse_get_architecture_design_schema` | 6905 | Returns the JSON schema, examples, and enums. Call once per session. | | `okto_pulse_validate_architecture_design_payload` | 6933 | Dry-run critique. Returns `valid`, `issues`, `warnings`, `suggested_fixes`, `summary`. Persists nothing. | | `okto_pulse_list_architecture_designs` | 6824 | List designs for an `ideation` / `refinement` / `spec` / `card`. Pass `include_payloads="true"` to embed diagram bytes (heavier, requires `render` permission). | | `okto_pulse_get_architecture_design` | 6870 | Get one design by ID. `include_payloads` honored as above. | | `okto_pulse_add_architecture_design` | 7049 | Create a design with `title`, `global_description`, and any of `entities` / `interfaces` / `diagrams` (JSON arrays or native lists). | | `okto_pulse_update_architecture_design` | 7207 | Partial update. Omitted fields are left unchanged. `change_summary` is recorded on the new version. | | `okto_pulse_delete_architecture_design` | 7298 | Hard delete. | | `okto_pulse_import_excalidraw_architecture_diagram` | 7329 | Import an Excalidraw JSON scene. Pass `replace_diagram_id` to overwrite an existing diagram, or omit to append. | | `okto_pulse_dump_architecture_diagram` | 7408 | Load a diagram payload through its adapter and return the raw payload plus an adapter-formatted dump string. | | `okto_pulse_copy_architecture_to_card` | 7460 | Deep-copy snapshot from spec → card. Empty `design_ids` copies all. | | `okto_pulse_archive_tree` | 6733 | Cascading soft-delete of an entity and its descendants. | | `okto_pulse_restore_tree` | 6777 | Reverse of `archive_tree`. | ### Payload anatomy `okto_pulse_add_architecture_design` accepts three structured arrays. #### `entities` — runtime boundaries Categorical `entity_type` plus a concrete `name`. The API rejects payloads where `name` duplicates `entity_type` after normalization (e.g. `name="API"`, `entity_type="api"`) because ownership and task boundaries become ambiguous. ```json theme={null} [ { "id": "entity-web-app", "name": "Customer Portal", "entity_type": "web_app", "responsibility": "Collects checkout input and displays order status.", "technologies": ["React", "Vite"] }, { "id": "entity-checkout-api", "name": "Checkout API", "entity_type": "api", "responsibility": "Validates checkout commands and orchestrates payment authorization.", "technologies": ["FastAPI", "SQLAlchemy"] }, { "id": "entity-orders-db", "name": "Orders DB", "entity_type": "database", "responsibility": "Persists orders, payment state, and idempotency keys.", "technologies": ["PostgreSQL"] } ] ``` #### `interfaces` — contracts on the wire `endpoint` is optional but recommended (API path, RPC method, event name, queue name). `direction` must be one of `source_to_target`, `target_to_source`, `bidirectional`, `none`. Interfaces do not own source/target — diagram connections do, via `sourceElementId` / `targetElementId`. ```json theme={null} [ { "id": "interface-create-order", "name": "Create order", "endpoint": "POST /orders", "description": "Customer Portal sends a checkout request to Checkout API.", "direction": "source_to_target", "protocol": "REST", "contract_type": "OpenAPI", "request_schema": {"type": "object", "required": ["cart_id"]}, "response_schema": {"type": "object", "required": ["order_id"]} } ] ``` #### `diagrams` — visualization Excalidraw is first-class. Edges link to interfaces via `linkedInterfaceIds` (one connector can carry several contracts). `connectionType` accepts only `"direct"` and `"elbow"` — `"curved"` is rejected. ```json theme={null} [ { "id": "diagram-runtime-context", "title": "Runtime context", "diagram_type": "context", "format": "excalidraw_json", "adapter_payload": { "type": "excalidraw", "version": 2, "elements": [], "appState": {}, "files": {} } } ] ``` ### Excalidraw round-trip Authoring agents can ship a complete Excalidraw scene without touching the structured arrays first. ```text theme={null} Input to okto_pulse_import_excalidraw_architecture_diagram: board_id: "brd_abc123" design_id: "ad_7f3a" title: "Runtime context (v2)" payload_json: { "type": "excalidraw", "elements": [...], "appState": {...} } diagram_type: "context" Output: { "success": true, "architecture_design": { "id": "ad_7f3a", "version": 4, "diagrams": [ { "id": "dg_91", "title": "Runtime context (v2)", "format": "excalidraw_json", "diagram_type": "context", ... } ], ... } } ``` To export, pair `okto_pulse_dump_architecture_diagram` with the diagram ID — it loads the payload through its adapter and returns both the raw payload and an adapter-formatted `dump` string. *** ## Screen mockups ### Tool reference | Tool | Line | Purpose | | --------------------------------- | ---- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `okto_pulse_add_screen_mockup` | 9436 | Add a screen to any entity. `screen_type` ∈ `page` / `modal` / `drawer` / `popover` / `panel`. Script tags and `on*` event attributes are stripped before persistence. | | `okto_pulse_update_screen_mockup` | 9502 | Partial update — empty strings mean "no change". | | `okto_pulse_annotate_mockup` | 9561 | Append a reviewer annotation (text + `author_id`) to an existing screen. | | `okto_pulse_list_screen_mockups` | 9620 | Paginated list. `screen_type` filter optional; `limit` capped at 200. | | `okto_pulse_delete_screen_mockup` | 9667 | Remove one mockup. | ### `entity_type` is universal All five screen-mockup tools accept `entity_type` ∈ `spec` / `ideation` / `refinement` / `card` (default `spec`). The same shape works whether you are sketching a page during ideation discovery, locking it on a spec, or attaching the final reference to an implementation card. ### Authoring example ```text theme={null} Input to okto_pulse_add_screen_mockup: board_id: "brd_abc123" entity_id: "spec_XYZ" entity_type: "spec" title: "Checkout — payment step" screen_type: "page" description: "Shown after cart review when the user clicks Pay." html_content: "
...
" Output: { "success": true, "entity_type": "spec", "screen": { "id": "sm_a1b2c3d4", "title": "Checkout — payment step", "description": "Shown after cart review when the user clicks Pay.", "screen_type": "page", "html_content": "
...
", "annotations": [], "order": 0 } } ``` The HTML sanitizer drops `