api.oobo.ai (free accounts at oobo.ai). You can also self-host using dock or your own implementation.
This page documents the API that any backend must implement.
Authentication
Authenticated requests include:Endpoint overview
Only ingest is required. The rest are optional.| Endpoint | Method | Auth | Required | Purpose |
|---|---|---|---|---|
/anchors/ingest | POST | Bearer token | Yes | Accept anchor data from commits |
/anchors/verify | GET | Bearer token | No | Verify an API key is valid |
/anchors/health | GET | None | No | Health check / connectivity test |
/anchors/share | POST | Bearer optional | No | Accept shared sessions |
POST /anchors/ingest (required)
Called automatically after every git commit (and other write operations). This is the core endpoint.
Behavior: Fire-and-forget from a background thread. The CLI does not block on the response. Timeouts: 2s connect, 10s total.
Request body (EventPayload):
Field reference
Top-level:| Field | Type | Description |
|---|---|---|
event | string | "git.commit" for commits, "git.push" for pushes |
timestamp | string | ISO 8601 |
oobo_version | string | CLI version |
project | object | { name, git_remote } — git_remote can be null |
anchor | object? | Full anchor data. Null for non-commit events (e.g. push). |
transcript | array | Flat transcript messages (all sessions concatenated). Empty when transparency is off. Always pre-redacted. See TranscriptMessage below. |
session_transcripts | array | Structured per-session transcripts with parent-child relationships. Empty array when transparency is off or no sessions. See SessionTranscript below. Added in v0.1.11. |
TranscriptMessage (items in transcript[] and session_transcripts[].messages[]):
| Field | Type | Description |
|---|---|---|
role | string | "user", "assistant", or "tool" |
text | string? | Message text content. Null for pure tool-call/tool-result messages. |
thinking | string? | Agent’s thinking/reasoning text. Null when not present. |
tool_call | object? | { tool_use_id, name, input_summary } — present when the message is a tool invocation. |
tool_result | object? | { tool_use_id, name, success, output_summary? } — present when the message is a tool result. |
timestamp_ms | int? | Message timestamp in milliseconds. Null for older payloads. |
SessionTranscript (items in session_transcripts[]):
| Field | Type | Description |
|---|---|---|
session_id | string | Session this transcript belongs to |
parent_session_id | string? | Parent session ID if this is a subagent. Null for root sessions. |
subagent_type | string? | Subagent type (e.g. "explore", "shell", "generalPurpose"). Null for root sessions. |
messages | array | Array of TranscriptMessage for this session only. |
anchor object:
| Field | Type | Description |
|---|---|---|
commit_hash | string | Full commit SHA |
branch | string | Branch name |
author | string | Git author (Name <email>) |
author_type | string | "agent", "assisted", "human", or "automated" |
contributors | array | [{ name, role, model? }] — role is "human" or "agent" |
committed_at | int | Unix timestamp |
message | string | Commit message |
files_changed | array | List of changed file paths |
added / deleted | int | Total lines added/deleted |
file_changes | array | Per-file: { path, added, deleted, attribution, agent? } |
ai_added / ai_deleted | int | Lines added/deleted by AI |
human_added / human_deleted | int | Lines added/deleted by humans |
ai_percentage | float? | 0.0–100.0 |
sessions | array | Linked AI sessions (see below) |
transparency_mode | string | "on" or "off" |
file_interactions | array? | Cross-session file interactions. Each entry: { path, sessions: [{ session_id, role }] } where role is "writer", "reader", or "both". Only present when 2+ sessions touched the same files. |
anchor.sessions[]:
| Field | Type | Description |
|---|---|---|
session_id | string | Unique session ID |
agent | string | Tool name (cursor, claude, gemini, etc.) |
model | string? | LLM model identifier |
link_type | string | "explicit" (hooks) or "inferred" (time-window) |
input_tokens / output_tokens | int? | Token counts |
cache_read_tokens / cache_creation_tokens | int? | Cache token counts |
duration_secs | int? | Session duration |
tool_calls | int? | Number of tool calls |
files_touched | array? | Files modified in this session |
tool_usage | object? | Tool name → call count map, e.g. {"Bash": 12, "Edit": 8}. Null when unavailable. |
tool_failures | int? | Number of failed tool calls. Null when unavailable. |
subagent_count | int? | Number of subagents spawned during this session. Null when unavailable. |
bash_commands | array? | Recent bash commands executed by the agent. Null when unavailable. |
thinking_duration_ms | int? | Accumulated thinking/reasoning time in milliseconds. Null when unavailable. |
compact_count | int? | Number of context compaction events. Null when unavailable. |
is_subagent | bool | Whether this is a sub-agent session. Default false. |
parent_session_id | string? | Parent session ID if this is a subagent. Null for root sessions. |
subagent_type | string? | Subagent type (e.g. "explore", "shell", "generalPurpose"). Null for root sessions. |
peer_session_ids | array | IDs of other sessions this session interacted with via shared files. Empty array when no interactions. |
is_estimated | bool | true = tiktoken estimate, false = native from tool |
Responses
| Status | Meaning | CLI behavior |
|---|---|---|
200 or 202 | Success | Silent |
409 | Duplicate (commit_hash + git_remote exists) | Silent (treated as success) |
401 | Bad API key | Prints auth error |
422 | Payload rejected | Prints warning, suggests version check |
500 | Server error | Prints warning unless body contains “duplicate” |
(git_remote, commit_hash) and return 409 for duplicates. The CLI retries on transient failures.
GET /anchors/verify (optional)
Validates the API key. Called during oobo auth login.
Auth: Authorization: Bearer <key>
Success (200):
200 status code. The body is informational.
Failure (401):
GET /anchors/health (optional)
Called by oobo dash to check connectivity. No auth required.
Return any 2xx. Body is ignored.
POST /anchors/share (optional)
Called by oobo share <session_id>. Accepts a redacted session for sharing.
Auth is optional — if a Bearer token is present, the share is associated with the user. If absent, the share is anonymous.
Request body:
model and stats may be null. Messages are always pre-redacted.
Response (200 or 201):
url to the user.
Self-hosting
By default, the CLI points atapi.oobo.ai. To use your own server:
~/.oobo/config.toml:
/anchors/ingest is required. The other endpoints are optional — if not implemented, the corresponding CLI features (auth verify, health check, share upload) will gracefully fail.
What the CLI does NOT send
- No local filesystem paths
- No third-party API keys
- No cost/USD calculations
- No file contents outside of AI sessions
- Transcripts are always redacted and only sent when
transparency_modeis"on"
