-
Notifications
You must be signed in to change notification settings - Fork 0
apis
Cortex exposes a REST API on http://127.0.0.1:9472 and a WebSocket server on ws://127.0.0.1:9473.
Base URL: http://127.0.0.1:9472
All request and response bodies are JSON. Timestamps use monotonic seconds (time.monotonic()).
All mutating HTTP routes require a capability token, sent as Authorization: Bearer <token> (canonical) or via the legacy X-Cortex-Auth-Token: <token> header. The token is generated at first daemon start and persisted with mode 0600 at ~/Library/Application Support/Cortex/auth.token. Missing or wrong tokens return 401 Unauthorized with WWW-Authenticate: Bearer. GET /health accepts an optional token (the supervisor liveness probe must reach the daemon without owning the token).
Every mutating response also carries an X-Cortex-Request-ID header. Clients may set their own on the request to correlate across logs (F19); otherwise the server generates one.
Health check for all registered services. Capability token is optional.
Response:
{
"status": "healthy",
"services": {
"state_engine": "up",
"context_engine": "up",
"llm_engine": "up",
"intervention_engine": "up"
},
"uptime_seconds": 3421.5
}Current cognitive state, confidence, and signal quality.
Response:
{
"state": "FLOW",
"confidence": 0.87,
"signal_quality": {
"physio": 0.92,
"kinematics": 0.88,
"telemetry": 0.95,
"overall": 0.91
},
"features": null,
"timestamp": 12345.6
}Returns null fields if no state has been computed yet.
Submit frame metadata from the capture service.
Request body: FrameMeta
{
"frame_id": 42,
"timestamp": 1000.5,
"width": 640,
"height": 480,
"brightness": 127.3,
"blur_score": 85.2,
"face_detected": true,
"face_confidence": 0.97,
"quality_pass": true
}Response:
{ "status": "ok", "timestamp": 1000.51 }Submit physiology features from the physio engine.
Request body: PhysioFeatures
{
"pulse_bpm": 72.0,
"pulse_quality": 0.9,
"pulse_variability_proxy": 55.0,
"hr_delta_5s": 0.5,
"valid": true
}Submit kinematic features from the kinematics engine.
Request body: KinematicFeatures
{
"blink_rate": 16.0,
"blink_rate_delta": 0.0,
"blink_suppression_score": 0.0,
"head_pitch": 0.0,
"head_yaw": 0.0,
"head_roll": 0.0,
"slump_score": 0.1,
"forward_lean_score": 0.1,
"shoulder_drop_ratio": 0.05,
"confidence": 0.9
}Submit telemetry features from the telemetry engine.
Request body: TelemetryFeatures
{
"mouse_velocity_mean": 400.0,
"mouse_velocity_variance": 5000.0,
"mouse_jerk_score": 0.1,
"click_burst_score": 0.1,
"click_frequency": 0.5,
"keyboard_burst_score": 0.2,
"keystroke_interval_variance": 500.0,
"backspace_density": 0.05,
"inactivity_seconds": 2.0,
"window_switch_rate": 5.0
}All feature endpoints return { "status": "ok", "timestamp": <float> }.
Compute cognitive state from a fused feature vector.
Request body:
{
"feature_vector": {
"pulse_norm": 0.3,
"hrv_norm": 0.6,
"blink_norm": 0.5,
"posture_norm": 0.2,
"mouse_velocity_norm": 0.4,
"mouse_jerk_norm": 0.1,
"click_burst_norm": 0.1,
"keyboard_burst_norm": 0.2,
"inactivity_norm": 0.05,
"window_switch_norm": 0.3,
"backspace_norm": 0.05,
"complexity_norm": 0.4,
"timestamp": 1000.5
},
"signal_quality": {
"physio": 0.9,
"kinematics": 0.85,
"telemetry": 0.95,
"overall": 0.9
}
}Response:
{
"estimate": {
"state": "FLOW",
"confidence": 0.87,
"scores": {
"flow": 0.87,
"hypo": 0.05,
"hyper": 0.08,
"recovery": 0.0
},
"reasons": ["Good HRV", "Normal blink rate", "Steady input"],
"signal_quality": { "physio": 0.9, "kinematics": 0.85, "telemetry": 0.95, "overall": 0.9 },
"timestamp": 1000.5,
"dwell_seconds": 45.2
},
"timestamp": 1000.52
}Build task context from workspace adapters.
Request body:
{
"include_editor": true,
"include_terminal": true,
"include_browser": true
}Response:
{
"context": {
"mode": "coding_debugging",
"active_app": "vscode",
"current_goal_hint": "Debugging TypeScript type error",
"complexity_score": 0.72,
"editor_context": {
"file_path": "src/components/App.tsx",
"visible_range": [45, 95],
"symbol_at_cursor": "handleSubmit",
"diagnostics": [
{
"severity": "error",
"message": "Type 'string' is not assignable to type 'number'",
"line": 67,
"column": 12,
"source": "typescript",
"code": "TS2322"
}
],
"recent_edits": [],
"visible_code": "function handleSubmit() { ... }"
},
"terminal_context": null,
"browser_context": null
},
"available": true,
"timestamp": 1000.52
}Request an intervention plan from the LLM engine.
Request body:
{
"state_estimate": { "state": "HYPER", "confidence": 0.91, "...": "..." },
"task_context": { "mode": "coding_debugging", "...": "..." }
}Response:
{
"plan": {
"intervention_id": "int_a1b2c3d4e5f6",
"level": "simplified_workspace",
"situation_summary": "You've been switching between 5 files with type errors for 12 minutes.",
"headline": "Focus on one error at a time",
"primary_focus": "Fix the TS2322 type error in App.tsx line 67",
"micro_steps": [
"Look at the error on line 67",
"Check the expected type in the interface",
"Update the value to match"
],
"hide_targets": ["sidebar", "terminal"],
"ui_plan": {
"dim_background": true,
"show_overlay": true,
"fold_unrelated_code": true,
"intervention_type": "simplified_workspace"
},
"tone": "direct"
},
"fallback_used": false,
"timestamp": 1002.1
}Apply an intervention plan to the workspace.
Request body:
{
"plan": { "intervention_id": "int_a1b2c3d4e5f6", "...": "..." }
}Response:
{
"applied": true,
"snapshot": {
"intervention_id": "int_a1b2c3d4e5f6",
"timestamp": 1002.2,
"fold_states": [],
"editor_visible_range": [45, 95],
"tab_visibility": [],
"active_tab_id": null,
"overlay_present": false,
"terminal_scroll_position": null
},
"timestamp": 1002.3
}Restore workspace to pre-intervention state.
Request body:
{
"intervention_id": "int_a1b2c3d4e5f6",
"user_action": "dismissed"
}Response:
{
"restored": true,
"outcome": {
"intervention_id": "int_a1b2c3d4e5f6",
"started_at": "2025-01-15T10:30:00",
"ended_at": "2025-01-15T10:32:15",
"duration_seconds": 135.0,
"user_action": "dismissed",
"recovery_detected": false,
"recovery_confidence": null,
"workspace_restored": true,
"restore_errors": []
},
"timestamp": 1137.5
}Valid user_action values: dismissed, engaged, snoozed, timed_out, natural_recovery, system_cancelled.
Current cumulative standardized HRV-deficit integral (the "biological
pomodoro"). When current_value / threshold ≥ 1 the daemon recommends
a break.
Response:
{
"current_value": 12.5,
"threshold": 30.0,
"should_break": false,
"sensitivity_multiplier": 1.0,
"timestamp": 1000.5
}Summary of intervention helpfulness from the contextual-bandit feedback loop.
Response:
{
"total_interventions": 15,
"mean_reward": 0.62,
"engagement_rate": 0.74,
"recent_rewards": [0.6, 0.8, 0.55],
"timestamp": 1000.5
}Return the consent ladder state for every tracked action type.
Response:
{
"levels": {
"close_tab": { "level": 2, "approvals": 4, "rejections": 0 },
"group_tabs": { "level": 1, "approvals": 1, "rejections": 0 }
},
"timestamp": 1000.5
}Reset the consent ladder to its defaults and return the new state.
Response:
{
"reset": true,
"levels": { "close_tab": { "level": 0 } },
"timestamp": 1000.5
}List available project profiles.
Response:
{
"projects": ["default", "research", "leetcode"],
"timestamp": 1000.5
}Launch a project profile (opens VS Code workspace, Chrome URLs, terminal commands).
Response:
{
"launched": true,
"project": "research",
"timestamp": 1000.5
}Endpoint: ws://127.0.0.1:9473
All messages are JSON objects with the following envelope:
{
"type": "<MESSAGE_TYPE>",
"payload": { ... },
"timestamp": 12345.6,
"sequence": 42
}Every connection MUST send an AUTH frame before any other message. The server holds the connection in pending_auth until the token validates; any non-AUTH frame sent first triggers close(code=1011, reason="auth required") and emits an AUTH_REJECTED event.
Client → server (first frame):
{
"type": "AUTH",
"payload": { "auth_token": "<capability_token>" },
"timestamp": 12300.0,
"sequence": 0
}Server → client on success:
{ "type": "AUTH_OK", "payload": {}, "timestamp": 12300.05, "sequence": 0 }After AUTH_OK, the client follows with IDENTIFY (declaring client_type) and then exchanges normal traffic.
The full list below is the canonical message-type catalog (Python source of truth: cortex/libs/schemas/ws_message_types.py::MessageType). The browser extension imports matching types from cortex/apps/browser_extension/types/generated/cortex_schemas.d.ts, which is regenerated from the Pydantic models by python -m cortex.scripts.generate_ts_schemas and gated against drift by pre-commit and CI.
Inbound (client → daemon): AUTH, IDENTIFY, USER_ACTION, ACTION_EXECUTE, USER_RATING, CONTEXT_RESPONSE, SETTINGS_SYNC, ACTIVITY_SYNC, TAB_RELEVANCE_FEEDBACK, LEETCODE_CONTEXT_UPDATE, INTERVENTION_APPLIED, SHUTDOWN.
Outbound (daemon → client): AUTH_OK, STATE_UPDATE, INTERVENTION_TRIGGER, INTERVENTION_RESTORE, CONTEXT_REQUEST, ACTIVE_RECALL, BREATHING_OVERLAY, PRE_BREAK_WARNING, MORNING_BRIEFING, COPILOT_THROTTLE, AMBIENT_STATE_UPDATE.
LeetCode cues (daemon → chrome, target_client_types=["chrome"]): LEETCODE_SHOW_SCRATCHPAD, LEETCODE_SHOW_PATTERN_LADDER, LEETCODE_SHOW_LOCKOUT, LEETCODE_SHOW_CONSOLIDATION, LEETCODE_SHOW_SUBMISSION_GATE, LEETCODE_SHOW_SOLUTION_FRICTION, LEETCODE_SHOW_SESSION_BRIEFING, LEETCODE_LOCK_EDITOR, LEETCODE_INTERCEPT_SUBMIT, LEETCODE_GATE_SOLUTIONS, LEETCODE_AI_RESTATEMENT_CHECK, LEETCODE_AI_COMPREHENSION_CHECK, LEETCODE_AI_HYPOTHESIS_CHECK, LEETCODE_AI_STUCK_ANALYSIS, LEETCODE_AI_SESSION_BRIEFING.
Selected payload shapes follow.
Broadcast every 500ms to all connected clients.
{
"type": "STATE_UPDATE",
"payload": {
"state": "FLOW",
"confidence": 0.87,
"scores": {
"flow": 0.87,
"hypo": 0.05,
"hyper": 0.08,
"recovery": 0.0
},
"signal_quality": {
"physio": 0.9,
"kinematics": 0.85,
"telemetry": 0.95,
"overall": 0.9
},
"dwell_seconds": 45.2,
"reasons": ["Good HRV", "Normal blink rate"]
},
"timestamp": 12345.6,
"sequence": 42
}Sent when the intervention engine triggers an intervention.
{
"type": "INTERVENTION_TRIGGER",
"payload": {
"intervention_id": "int_a1b2c3d4e5f6",
"level": "simplified_workspace",
"headline": "Focus on one error at a time",
"situation_summary": "You've been stuck on type errors for 12 minutes.",
"primary_focus": "Fix TS2322 in App.tsx:67",
"micro_steps": [
"Look at the error on line 67",
"Check the expected type",
"Update the value"
],
"hide_targets": ["sidebar", "terminal"],
"ui_plan": {
"dim_background": true,
"show_overlay": true,
"fold_unrelated_code": true,
"intervention_type": "simplified_workspace"
},
"tone": "direct"
},
"timestamp": 12346.1,
"sequence": 43
}Sent by extensions when the user interacts with an intervention.
{
"type": "USER_ACTION",
"payload": {
"action": "dismissed",
"intervention_id": "int_a1b2c3d4e5f6"
},
"timestamp": 12400.0,
"sequence": 1
}Valid actions: dismissed, engaged, snoozed.
Sent by extensions on connection to identify their type.
{
"type": "IDENTIFY",
"payload": {
"client_type": "vscode"
},
"timestamp": 12300.0,
"sequence": 0
}Valid client types: vscode, chrome, desktop.
Sent by clients to update settings, or by the server to broadcast settings changes.
{
"type": "SETTINGS_SYNC",
"payload": {
"consent_levels": { "close_tabs": 3, "fold_code": 4 },
"quiet_mode": false,
"max_autonomy": "REVERSIBLE_ACT"
},
"timestamp": 12350.0,
"sequence": 2
}Sent by the browser extension to report learning activity progress.
{
"type": "ACTIVITY_SYNC",
"payload": {
"platform": "youtube",
"url": "https://youtube.com/watch?v=...",
"title": "Data Structures Lecture 5",
"position": { "type": "video", "timestamp_seconds": 1234 },
"duration_seconds": 300
},
"timestamp": 12360.0,
"sequence": 3
}Sent by the daemon to request context from a specific extension.
{
"type": "CONTEXT_REQUEST",
"payload": {},
"timestamp": 12370.0,
"sequence": 44
}- New clients receive the latest
STATE_UPDATEimmediately on connection - Dead connections are automatically cleaned up on next broadcast
- The server auto-reconnects if the
websocketspackage is available - Extensions should implement reconnection with exponential backoff