Skip to main content
The backend ingests anchor data from connected repositories. It has no direct git access - it reads data exclusively through platform APIs (GitHub, GitLab, Bitbucket) triggered by webhooks.

Remote API Surface

The CLI calls these endpoints. There is no cloud upload/ingest pipeline - team sync is Git-first via the orphan branch.

Self-Hosting

Point your CLI at your own server:
Your backend implements endpoints under /anchors.

POST /anchors/search

Search across anchors, sessions, and semantic memory. Returns full-text and memory hits, with an optional synthesized answer.

Request

Response


POST /anchors/delta

Compare two anchors to see what changed: category shifts, complexity changes, new areas, new techniques, and a narrative summary.

Request

Response (compact, full: false)

When full: true, the response adds current_detail and previous_detail objects with: narrative, key_decisions, techniques, areas_affected, blockers, intent, reasoning, and session info.

Error Responses

The Orphan Branch

All anchor data lives on a Git orphan branch. As of v2.0.0, new installs write to oobo/anchors/v2. The legacy oobo/anchors/v1 branch is read-only and preserved for pre-2.0 data. Both branches have zero relationship to the repo’s code history - they contain only structured JSON metadata about commits enriched with AI session data, attribution, and transcripts. The CLI pushes to the oobo/anchors/v2 branch on every git push (via a pre-push hook). No user action is required.

Configurable Anchor Remote

Anchors may not live in the same repository as the code. Users can configure a separate Git remote for anchor data via .oobo/config:
Or via the CLI: oobo settings project set remote <value>
When [anchors].remote is configured, the CLI pushes the oobo/anchors/v2 branch to that remote instead of origin. Your backend must handle this by:
  1. Monitoring .oobo/config on the default branch of connected repos for changes to [anchors].remote
  2. When [anchors].remote points to a separate repo, register webhooks on that repo and listen for pushes to both oobo/anchors/v2 and oobo/anchors/v1 (legacy) there
  3. When unset or set to a named remote (e.g. origin), anchors arrive via pushes to the same repository
The value can be either a named remote (e.g. oobo) or a full URL (e.g. git@github.com:org/repo-anchors.git). Your backend should resolve named remotes via the repository’s Git config or treat direct URLs as the target.

Push Behavior and Data Safety

The user’s git push is never blocked. Anchor push failures are warnings only. The local oobo/anchors/v2 branch always has the complete data - the next successful push will include all pending anchors.

Directory Layout (Sharding)

The commit hash (40-char hex SHA) is split: first 2 characters → top-level directory, remaining 38 → subdirectory name.

Webhook Trigger

Discovery: Where Do Anchors Live?

Before processing webhooks, the backend must determine where a project’s anchors are pushed:
  1. On repo connection, read .oobo/config from the default branch (if it exists)
  2. Check for [anchors].remote - if set, anchors are pushed to that repo/remote
  3. If unset, anchors are in the same repo on branch oobo/anchors/v2
  4. Subscribe to pushes on the default branch (to detect config changes), oobo/anchors/v2, and oobo/anchors/v1 (legacy)
  5. If a push to the default branch modifies .oobo/config, re-read [anchors].remote and update webhook registration accordingly

GitHub

Listen for push events where ref is refs/heads/oobo/anchors/v2. During the migration period, also monitor refs/heads/oobo/anchors/v1 for legacy data:

GitLab

Listen for push events where ref is refs/heads/oobo/anchors/v2 (and refs/heads/oobo/anchors/v1 for legacy data).

Bitbucket

Listen for repo:push events. Filter push.changes[].new.name == "oobo/anchors/v2" (and "oobo/anchors/v1" for legacy data).

Reading Files via Platform APIs

List all files (recursive tree):
Read a single file:
Compare two commits (incremental processing):

Ingestion Strategy

On Webhook Push

  1. Extract before and after SHAs from the webhook payload
  2. Get the diff between those two commits
  3. For each newly added XX/YYYY.../metadata.json (3 segments) → new anchor
  4. For each newly added XX/YYYY.../N/metadata.json (4 segments, N is numeric) → new session link
  5. For each newly added XX/YYYY.../N/transcript.json → session transcript
  6. For each newly added XX/YYYY.../timeline.json → multi-agent timeline

Pattern Matching

Full Sync (Initial or Recovery)

  1. Fetch the recursive tree of oobo/anchors/v2 (and oobo/anchors/v1 for legacy data)
  2. Filter paths matching anchor metadata pattern
  3. Bulk-fetch all metadata files
  4. Process in parallel - anchors are independent

Rate Limits

  • GitHub REST: 5,000 requests/hour (authenticated)
  • GitHub GraphQL: 5,000 points/hour
  • Use blob SHAs for deduplication

Key Invariants

Edge Cases