pavel 1ar.ionov

craft-cli

A Craft Docs CLI made for AI agents. Local-first search, API-backed full reads and writes.

craft-cli is a Bun-compiled single binary, built first and foremost for AI coding agents. The goal is to make a Craft Docs vault as pleasant to read and edit from Claude Code, Codex, or OpenCode as a local markdown folder is from inside Obsidian - not to replace the Craft UI for humans. Every design choice below follows from that goal. The CLI also exports a TypeScript library that the Raycast Craft extension and other downstream tools use instead of talking to the REST API directly.

Why agents need their own CLI

Craft ships a solid REST API, but agents do not think in HTTP round-trips. A single document read can take up to 4.5 seconds over the wire. A ten-step workflow that searches the vault, reads a few notes, patches a block, and verifies the result will burn 25 seconds of wall-clock time before the model even starts reasoning about the result. For a human in the Craft app that latency is invisible. For an agent planning its next move, it is the difference between "works" and "unusable".

Local-first mode, in one sentence

Search and list from Craft's local cache when eligible. Use the API for full reads, structured features, and every write.

That is the whole architecture.

In source auto, unfiltered document listing and simple search use Craft's on-disk SQLite FTS5 and PlainTextSearch stores. These are the same data structures that make search instant inside Craft. Full document trees, daily notes, blocks, tasks, collections, links, filtered searches, and all writes use the REST API.

Writes go through the REST API. The API is the only authoritative source for block hierarchy and the only path that triggers cross-device sync. Writing through it keeps the vault consistent between devices. Craft Desktop typically refreshes its local stores within about one second while the app is running and synced.

There is no craft-cli mirroring layer or writable local copy. The CLI treats Craft's cache as read-only and falls back to REST automatically when a query is not locally eligible or the cache is unavailable.

* Local-first mode assumes the Craft desktop app is installed and running, because it is the process that keeps the local stores in sync. On Linux, headless servers, or any host without the app, use API-only mode (next section).

API-only mode: opinionated agentic wrapper

When the local stores are not available, craft-cli runs in API-only mode. But this is not a thin passthrough. It is an opinionated layer on top of the REST API, shaped specifically for what agents need when they are reasoning about a knowledge vault:

  • Backlink extraction on retrieval. The Craft REST API does not expose backlinks. craft-cli reconstructs them on every document fetch via title-based search plus block:// URI filtering. For an agent traversing a vault, this turns a single document read into a context-rich view of where the doc is referenced - exactly the kind of adjacency signal that lets a model decide what to load next.
  • Source-aware search. Simple searches use local FTS5 in auto mode. API-routed searches use RE2 by default and work around the API's silent-drop behavior on short underscored tokens.
  • Unified write path with an undo net. Every write passes through a mutation journal at ~/.cache/craft-cli/journal.db, recording block tree state before and after. craft undo, craft diff, and craft log all work against it, giving agents a git-like safety net on a platform that otherwise has no version history.
  • craft patch - find-and-replace at block granularity, intentionally mirroring the editing semantics of Claude Code's Edit tool. Agents already know this shape.
  • Compact output. Every command supports --json and a dense default format, so the CLI consumes little of the model's context window.

API-only source also works on macOS if you do not want local-store reads for some reason: craft source api persists it, CRAFT_SOURCE=api overrides per process, --source api or --api overrides per command.

Speed

Benchmarks of the local-store primitives on my personal vault of ~1,200 documents and ~46,000 blocks. The CLI currently exposes the local path for simple search and document listing.

Operation REST API craft-cli (local) Speedup
Search vault for a term 2,271 ms 1.3 ms 1,700x
Resolve cached content (library) 4,561 ms 0.7 ms 6,300x
Check if doc changed (contentHash) 3,247 ms 0.5 ms 6,600x
List all documents 1,489 ms 184 ms 8x

The local-store primitives average around 3,600x faster than equivalent REST reads. For agents, the exposed search and listing paths become effectively free.

Install (paste this to your AI agent)

To install craft-cli, paste the block below into your AI coding agent (Claude Code, Codex, OpenCode, Cursor, etc.). The agent will handle clone, build, install, authentication, and skill registration.

You are installing craft-cli (https://github.com/pa1ar/craft-cli) for me. Follow these steps in order. Stop and ask me if anything is ambiguous, otherwise proceed end-to-end.

1. RUNTIME CHECK
   Check whether `bun` is on PATH. If yes, continue.
   If not:
     - If I have a stated package-manager preference, use that.
     - Otherwise, install Bun: `curl -fsSL https://bun.sh/install | bash` (do not switch to npm/pnpm/yarn — this project is Bun-first; the build script and binary path assume Bun).

2. CLONE + BUILD + INSTALL
   git clone https://github.com/pa1ar/craft-cli.git ~/dev/craft-cli
   cd ~/dev/craft-cli && ./install.sh
   If `install.sh` fails or is unavailable, fall back to:
     bun install && bun run build
     mkdir -p ~/.local/bin && ln -sf "$PWD/dist/craft" ~/.local/bin/craft
   Verify `~/.local/bin` is on PATH. Add it to my shell rc if missing (detect zsh vs bash from $SHELL).

3. AUTHENTICATE
   Ask me for the Craft API URL and API key. I get them from Craft → Connections → New API Connection. The URL looks like `https://connect.craft.do/links/XXX/api/v1`, the key starts with `pdk_`.
   Then run: craft setup --url "<URL>" --key "<KEY>"

4. READ SOURCE
   On macOS with Craft Desktop installed, run `craft source auto`. Keep this setting: eligible reads use Craft's local cache first and automatically fall back to REST. Do not persist API-only mode or add `--api` to ordinary reads.
   Only on Linux, remote/headless hosts, or machines without Craft Desktop, run `craft source api`.

5. VERIFY
   craft doctor --json     # confirms auth, API, effective source, and local availability
   craft docs ls           # on macOS, human output should end with "documents (local)"

6. SKILL REGISTRATION
   The repo ships an agent skill at `skill/SKILL.md` with the full command surface, recipes, and caveats.
   First honor any canonical skills folder or craft-cli skill location I have already specified. If that location contains a craft-cli skill, use it and do not replace it with a harness-specific copy.
   Otherwise, determine where this agent harness loads user skills and register the bundled `skill/` directory there. Prefer a symlink on local systems so updates remain connected to the repo. If the harness location is unknown, ask me for the canonical skills directory rather than assuming a Claude, Codex, Cursor, or other vendor-specific path.
   Verify that the registered `SKILL.md` is readable through the harness, then read that canonical installed skill before non-trivial craft-cli use.

7. REPORT BACK
   Tell me:
     - which source is active (auto vs api vs local),
     - whether the local Craft store was detected and which reads can use it,
     - where the binary landed,
     - where the skill is registered,
     - any step you skipped and why.

Role and distribution

Personal tool, published as-is. I am not affiliated with Craft and do not plan to maintain package-manager distributions. If the Craft team wants to adopt or fork this into an official CLI, they are welcome to. The library half is in active use inside the Raycast Craft extension and inside several of my own agent workflows across the 1ar labs stack.