Skip to content

Add Zed agent provider (threads.db / zstd JSON schema documented) #480

@chatzinikolakisk

Description

@chatzinikolakisk

Summary

Add a CodeBurn provider for Zed's built-in AI agent.

In #196 a maintainer noted Zed's agent usage is invisible to CodeBurn and that "Zed provider support is on the roadmap." That issue has since been closed (it was really about Cursor misattribution + the classifier). There doesn't appear to be a tracking issue for the actual Zed provider, so opening one here.

I use Zed daily and have inspected the real on-disk format on macOS, so I can build and validate this against real sessions per the contributing guide. Filing first to confirm the approach before opening a PR.

Where Zed stores agent data

Unlike file-per-session providers (Codex, Pi), Zed uses a single SQLite database with one row per agent thread:

~/Library/Application Support/Zed/threads/threads.db

Schema (table threads):

CREATE TABLE threads (
    id TEXT PRIMARY KEY,
    summary TEXT NOT NULL,
    updated_at TEXT NOT NULL,      -- ISO 8601
    data_type TEXT NOT NULL,       -- e.g. "zstd"
    data BLOB NOT NULL,            -- zstd-compressed JSON thread
    parent_id TEXT,
    folder_paths TEXT,
    folder_paths_order TEXT,
    created_at TEXT
);

The data BLOB is zstd-compressed JSON (magic bytes 28 B5 2F FD). Decompressed, each thread JSON contains everything needed for pricing:

  • model: { "provider": "anthropic", "model": "claude-opus-4-8" }
  • request_token_usage: map of request_id -> { input_tokens, output_tokens, cache_creation_input_tokens, cache_read_input_tokens }
  • cumulative_token_usage: same shape, thread total (can be empty on in-progress threads, so summing request_token_usage is the reliable path)
  • messages with tool calls, plus updated_at, title, profile, etc.

Token semantics match Anthropic's (separate cache-creation vs cache-read fields), so pricing maps cleanly onto the existing LiteLLM engine.

Proposed approach

  • New src/providers/zed.ts modeled on the SQLite-backed providers (Cursor / Forge / Warp) rather than the file-per-session shape.
  • Lazy-load better-sqlite3 (already an optional dep for Cursor/OpenCode) so non-Zed users aren't affected.
  • Decompress each data blob with zstd, sum request_token_usage per thread, resolve model.model, emit one call per request entry.
  • Map Zed's provider/model strings onto existing pricing; add a small display-name + tool-name map.
  • Ship a fixture-based test under tests/providers/ using a redacted real thread.

Questions before I start

  1. Is the Cursor/Forge SQLite provider the pattern you'd want me to follow for a single-DB, many-rows source?
  2. Preference for the zstd dependency — add a small zstd lib, or shell out / reuse anything already vendored?
  3. Anything specific you want in the fixture (redaction expectations for messages/prompts)?

Happy to implement once you confirm the approach. I can include terminal proof of npm run dev -- today --provider zed against my real Zed history in the PR.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions