REST API#

thinkt provides a REST API for programmatic access to AI coding session data. The API is available through the HTTP server and includes interactive Swagger documentation.

Quick Start#

# Start the server (foreground, port 8784)
thinkt server

# Start in background
thinkt server start

# Open web interface (auto-starts server if needed)
thinkt web

# Custom port
thinkt server -p 8080

Once running, access the API at http://localhost:8784/api/v1/ (or your configured port).

Server Management#

Starting the Server#

thinkt server                    # Foreground (default port 8784)
thinkt server -p 8080            # Custom port
thinkt server --no-open          # Don't auto-open browser
thinkt server --quiet            # Suppress request logging
thinkt server --http-log access.log  # Log requests to file
thinkt server --dev http://localhost:8784  # Proxy to frontend dev server

Features:

  • Full REST API
  • Full web interface (thinkt-web) for visual trace exploration
  • SPA routing — all non-API paths serve the webapp
  • Auto-opens browser on startup
  • --dev mode for co-developing the frontend (proxies non-API routes to a local dev server)

Background Mode#

thinkt server start              # Start server in background
thinkt server status             # Check server status
thinkt server stop               # Stop background server

Opening the Web Interface#

The thinkt web command opens the web interface in your browser. If the server isn’t already running, it starts it in the background automatically.

thinkt web                      # Open web interface (auto-starts server)
thinkt web lite                 # Open lightweight debug interface

The lite interface (thinkt-web-lite) shows:

  • Available sources and status
  • Project list with session counts
  • Quick links to API endpoints
  • Theme preview

OpenAPI Specification#

The API is documented using OpenAPI (Swagger) 2.0. Access the interactive documentation at:

http://localhost:8784/swagger/

Download the specification:

  • JSON: http://localhost:8784/swagger/doc.json
  • YAML: Available in the source at internal/server/docs/swagger.yaml

API Endpoints#

Base URL: /api/v1

Server Info#

Get Server Info#

Get server identity, version, and runtime metadata.

GET /api/v1/info

Response:

{
  "fingerprint": "22414c5f-cfa8-5d30-8eb4-f1a9c49d355c",
  "version": "0.6.0",
  "revision": "9834a3d",
  "started_at": "2026-02-27T10:30:00Z",
  "uptime_seconds": 3600,
  "pid": 12345,
  "authenticated": true
}

Example:

curl http://localhost:8784/api/v1/info

Sources#

List Sources#

List available trace sources and their status.

GET /api/v1/sources

Response:

{
  "sources": [
    {
      "name": "claude",
      "available": true,
      "base_path": "/Users/you/.claude/projects"
    },
    {
      "name": "kimi",
      "available": true,
      "base_path": "/Users/you/.kimi/workspace"
    },
    {
      "name": "gemini",
      "available": false,
      "base_path": ""
    },
    {
      "name": "copilot",
      "available": false,
      "base_path": ""
    },
    {
      "name": "codex",
      "available": false,
      "base_path": ""
    },
    {
      "name": "qwen",
      "available": false,
      "base_path": ""
    }
  ]
}

Example:

curl http://localhost:8784/api/v1/sources

Projects#

List Projects#

List all projects, optionally filtered by source. By default, projects where path_exists=false are hidden; set include_deleted=true to include them.

GET /api/v1/projects
GET /api/v1/projects?source=claude
GET /api/v1/projects?include_deleted=true

Query Parameters:

NameTypeDescription
sourcestringFilter by source (claude, kimi, gemini, copilot, codex, qwen)
include_deletedboolInclude projects where path_exists is false (default: false)

Response:

{
  "projects": [
    {
      "id": "abc123",
      "name": "my-project",
      "path": "/Users/you/code/my-project",
      "display_path": "~/code/my-project",
      "session_count": 15,
      "source": "claude",
      "last_modified": "2024-01-15T10:30:00Z",
      "workspace_id": "my-machine"
    }
  ]
}

Examples:

# All projects
curl http://localhost:8784/api/v1/projects

# Only Claude projects
curl "http://localhost:8784/api/v1/projects?source=claude"

# Only Kimi projects
curl "http://localhost:8784/api/v1/projects?source=kimi"

# Include projects whose paths no longer exist
curl "http://localhost:8784/api/v1/projects?include_deleted=true"

Sessions#

List Sessions for Project#

List all sessions belonging to a project.

GET /api/v1/projects/{projectID}/sessions

Path Parameters:

NameTypeDescription
projectIDstringURL-encoded project path

Response:

{
  "sessions": [
    {
      "id": "session-uuid",
      "full_path": "/Users/you/.claude/projects/abc123/session.jsonl",
      "project_path": "/Users/you/code/my-project",
      "created_at": "2024-01-15T10:30:00Z",
      "modified_at": "2024-01-15T11:45:00Z",
      "entry_count": 42,
      "file_size": 125000,
      "source": "claude",
      "model": "claude-3-opus",
      "first_prompt": "Help me refactor the auth module...",
      "git_branch": "main"
    }
  ]
}

Example:

# URL-encode the project path
curl "http://localhost:8784/api/v1/projects/%2FUsers%2Fyou%2Fcode%2Fmy-project/sessions"

Get Session Content#

Get session metadata and conversation entries with optional pagination.

GET /api/v1/sessions/{path}
GET /api/v1/sessions/{path}?limit=10&offset=0

Get Session Metadata#

Get session metadata and lightweight previews without loading full entry payloads.

GET /api/v1/sessions/{path}/metadata
GET /api/v1/sessions/{path}/metadata?summary_only=true&limit=5

Query Parameters:

NameTypeDefaultDescription
limitint50Maximum summaries/previews to return (default 5 when summary_only=true)
offsetint0Number of summaries/previews to skip
exclude_rolesstring[]checkpointRoles to exclude (repeat query param or comma-separated list)
summary_onlyboolfalseReturn lightweight user-message previews only
sort_bystringindexSummary ordering (index or length)

Path Parameters:

NameTypeDescription
pathstringURL-encoded session file path

Query Parameters:

NameTypeDefaultDescription
limitint0 (all)Maximum entries to return
offsetint0Number of entries to skip

Response:

{
  "meta": {
    "id": "session-uuid",
    "full_path": "/path/to/session.jsonl",
    "created_at": "2024-01-15T10:30:00Z",
    "modified_at": "2024-01-15T11:45:00Z",
    "entry_count": 42,
    "model": "claude-3-opus",
    "source": "claude"
  },
  "entries": [
    {
      "uuid": "entry-uuid",
      "role": "user",
      "timestamp": "2024-01-15T10:30:00Z",
      "text": "Help me refactor the authentication module",
      "content_blocks": [],
      "model": "",
      "source": "claude"
    },
    {
      "uuid": "entry-uuid-2",
      "role": "assistant",
      "timestamp": "2024-01-15T10:30:15Z",
      "text": "I'll help you refactor the authentication module...",
      "content_blocks": [
        {
          "type": "thinking",
          "thinking": "Let me analyze the current implementation..."
        },
        {
          "type": "tool_use",
          "tool_use_id": "tool-123",
          "tool_name": "Read",
          "tool_input": {"file_path": "/src/auth.ts"}
        }
      ],
      "model": "claude-3-opus",
      "usage": {
        "input_tokens": 1500,
        "output_tokens": 800
      }
    }
  ],
  "has_more": true,
  "total": 42
}

Examples:

# Get all entries
curl "http://localhost:8784/api/v1/sessions/%2Fpath%2Fto%2Fsession.jsonl"

# Paginate: first 10 entries
curl "http://localhost:8784/api/v1/sessions/%2Fpath%2Fto%2Fsession.jsonl?limit=10"

# Paginate: next 10 entries
curl "http://localhost:8784/api/v1/sessions/%2Fpath%2Fto%2Fsession.jsonl?limit=10&offset=10"

Search Sessions#

Search for text across indexed sessions. Requires thinkt-indexer to be available.

GET /api/v1/search?q=query

Query Parameters:

NameTypeDefaultDescription
qstring(required)Search query text
projectstringFilter by project name (substring match)
sourcestringFilter by source (claude, kimi, gemini, copilot, codex, qwen)
limitint50Maximum total matches
limit_per_sessionint2Maximum matches per session (0 for no limit)
case_sensitiveboolfalseEnable case-sensitive matching
regexboolfalseTreat query as a regular expression (Go RE2 syntax)

Response:

{
  "sessions": [
    {
      "session_id": "abc-123",
      "project_name": "my-project",
      "source": "claude",
      "path": "/Users/you/.claude/projects/abc123/session.jsonl",
      "matches": [
        {
          "line_num": 42,
          "preview": "...Help me refactor the authentication module...",
          "role": "user"
        }
      ]
    }
  ],
  "total_matches": 5
}

Examples:

# Basic search (case-insensitive)
curl "http://localhost:8784/api/v1/search?q=authentication"

# Case-sensitive search
curl "http://localhost:8784/api/v1/search?q=AuthManager&case_sensitive=true"

# Regex search
curl "http://localhost:8784/api/v1/search?q=func\s%2BTest\w%2B&regex=true"

# Filter by project
curl "http://localhost:8784/api/v1/search?q=error&project=my-app"

Search sessions by meaning using on-device embeddings. Requires embeddings to be enabled.

GET /api/v1/semantic-search?q=query

Query Parameters:

NameTypeDefaultDescription
qstring(required)Natural language search query
projectstringFilter by project name (substring match)
sourcestringFilter by source
limitint20Maximum results
max_distancefloatCosine distance threshold (0-2, lower is more similar)
diversityboolfalseSpread results across different sessions

Example:

curl "http://localhost:8784/api/v1/semantic-search?q=database+migration"

Get Usage Statistics#

Get aggregate usage statistics from the index.

GET /api/v1/stats

Response:

{
  "total_projects": 12,
  "total_sessions": 156,
  "total_entries": 4200,
  "total_tokens": 1250000,
  "top_tools": [
    {"name": "Read", "count": 450},
    {"name": "Edit", "count": 280},
    {"name": "Bash", "count": 190}
  ]
}

Indexer Health#

Check whether the indexer is available and the database is accessible.

GET /api/v1/indexer/health

Response:

{
  "available": true,
  "path": "/usr/local/bin/thinkt-indexer",
  "database_accessible": true,
  "indexed_projects": 12,
  "indexed_sessions": 156
}

Indexer Status#

Get live indexer server status including sync and embedding progress.

GET /api/v1/indexer/status

Response:

{
  "running": true,
  "state": "idle",
  "uptime_seconds": 3600,
  "watching": true,
  "model": "nomic-embed-text-v1.5",
  "model_dim": 768
}

Teams#

List Teams#

List all discovered agent teams (Claude Code).

GET /api/v1/teams

Response:

{
  "teams": [
    {
      "name": "my-project",
      "members": [...],
      "created_at": "2024-01-15T10:30:00Z"
    }
  ]
}

Example:

curl http://localhost:8784/api/v1/teams

Get Team Details#

Get a specific team with resolved member-to-session mappings.

GET /api/v1/teams/{teamName}

Path Parameters:

NameTypeDescription
teamNamestringTeam name

Example:

curl http://localhost:8784/api/v1/teams/my-project

List Team Tasks#

Get the shared task board for a team.

GET /api/v1/teams/{teamName}/tasks

Response:

{
  "tasks": [
    {
      "id": "1",
      "subject": "Implement feature X",
      "status": "completed",
      "owner": "researcher"
    }
  ]
}

Example:

curl http://localhost:8784/api/v1/teams/my-project/tasks

List Team Member Messages#

Get inbox messages for a specific team member.

GET /api/v1/teams/{teamName}/members/{memberName}/messages

Path Parameters:

NameTypeDescription
teamNamestringTeam name
memberNamestringMember name

Example:

curl http://localhost:8784/api/v1/teams/my-project/members/researcher/messages

Themes#

List Themes#

Get all available themes with their color definitions.

GET /api/v1/themes

Response:

{
  "themes": [
    {
      "name": "dark",
      "description": "Default dark theme",
      "embedded": true,
      "active": true,
      "colors": {
        "accent": "#7c3aed",
        "border_active": "#7c3aed",
        "border_inactive": "#404040",
        "user_block": {"fg": "#ffffff", "bg": "#1e1e1e"},
        "user_label": {"fg": "#60a5fa", "bold": true},
        "assistant_block": {"fg": "#ffffff", "bg": "#1e1e1e"},
        "assistant_label": {"fg": "#34d399", "bold": true},
        "thinking_block": {"fg": "#9ca3af", "bg": "#1e1e1e", "italic": true},
        "thinking_label": {"fg": "#f472b6", "bold": true},
        "tool_call_block": {"fg": "#fbbf24", "bg": "#1e1e1e"},
        "tool_label": {"fg": "#fbbf24", "bold": true},
        "tool_result_block": {"fg": "#9ca3af", "bg": "#1e1e1e"},
        "text_primary": {"fg": "#ffffff"},
        "text_secondary": {"fg": "#9ca3af"},
        "text_muted": {"fg": "#6b7280"}
      }
    }
  ],
  "active": "dark"
}

Open-In#

Open paths in external applications (Finder, VS Code, etc.).

List Allowed Apps#

Get the list of enabled applications for the open-in feature.

GET /api/v1/open-in/apps

Response:

{
  "apps": [
    {"id": "finder", "name": "Finder", "enabled": true, "terminal": false},
    {"id": "terminal", "name": "Terminal", "enabled": true, "terminal": true},
    {"id": "vscode", "name": "VS Code", "enabled": true, "terminal": false}
  ],
  "default_terminal": "terminal"
}

Open Path#

Open a path in a specified application.

POST /api/v1/open-in

Request Body:

{
  "app": "vscode",
  "path": "/Users/you/code/my-project"
}

Response:

{
  "success": true,
  "message": "Opened in VS Code"
}

Example:

curl -X POST http://localhost:8784/api/v1/open-in \
  -H "Content-Type: application/json" \
  -d '{"app": "vscode", "path": "/Users/you/code/my-project"}'
**Security:** Only applications explicitly enabled in the configuration can be used. Requests for disabled apps return `403 Forbidden`.

Data Types#

Entry Roles#

RoleDescription
userUser messages
assistantAI assistant responses
toolTool execution messages
systemSystem messages
summaryConversation summaries
progressProgress indicators
checkpointState recovery markers

Content Block Types#

TypeDescription
textPlain text content
thinkingAI thinking/reasoning blocks
tool_useTool invocation with name and input
tool_resultTool execution result

Sources#

SourceDescription
claudeClaude Code
kimiKimi Code
geminiGemini CLI
copilotGitHub Copilot CLI
codexCodex CLI
qwenQwen Code

Authentication#

Both the REST API server and MCP server support Bearer token authentication.

Generate a Token#

thinkt server token
# Output: thinkt_20260205_cd3bf36d6e1fc71e9bf033a7131f77cb

Using Authentication#

# Environment variable
export THINKT_API_TOKEN=$(thinkt server token)
thinkt server

# Command-line flag
thinkt server --token thinkt_20260205_...

# Client request
curl -H "Authorization: Bearer thinkt_20260205_..." http://localhost:8784/api/v1/sources

When authentication is enabled, all API endpoints require a valid Bearer token. Unauthenticated requests receive a 401 Unauthorized response with a WWW-Authenticate header.


Error Handling#

All endpoints return errors in a consistent format:

{
  "error": "error_code",
  "message": "Human-readable error description"
}

HTTP Status Codes:

CodeDescription
200Success
400Bad Request - Invalid parameters
401Unauthorized - Invalid or missing token
403Forbidden - Action not allowed
404Not Found - Resource doesn’t exist
500Internal Server Error

CORS#

The API enables CORS for local development, allowing browser-based applications to access the API from different origins.


Examples#

List All Sessions Across Projects#

# Get all projects
projects=$(curl -s http://localhost:8784/api/v1/projects | jq -r '.projects[].id')

# For each project, list sessions
for proj in $projects; do
  encoded=$(python3 -c "import urllib.parse; print(urllib.parse.quote('$proj', safe=''))")
  curl -s "http://localhost:8784/api/v1/projects/$encoded/sessions"
done

Export Session to JSON#

session_path="/Users/you/.claude/projects/abc123/session.jsonl"
encoded=$(python3 -c "import urllib.parse; print(urllib.parse.quote('$session_path', safe=''))")
curl -s "http://localhost:8784/api/v1/sessions/$encoded" | jq . > session_export.json

Filter Sessions by Model#

curl -s "http://localhost:8784/api/v1/sessions/$encoded" | \
  jq '.entries[] | select(.model == "claude-3-opus")'

See Also#