Skip to content
cap
Esc
navigateopen⌘Jpreview
On this page

CLI reference

The stable cap CLI contract — exit codes, JSON fields, TSV columns, and CAP_DIR.

The cap binary is a scripting surface as much as a human one. This document defines the parts of its behavior that scripts may rely on.

Stable: exit codes, the JSON output documented here, the TSV column set, and the CAP_DIR environment variable. Stable fields are never renamed, retyped, or removed; new JSON fields may be added, so consumers must ignore keys they do not recognize.

Not stable: plain (default) output, doctor output, markdown export, stderr wording, and help text. These are for people, and change freely.

Data goes to stdout; diagnostics go to stderr.

Exit codes

Code Meaning
0 Success.
1 No results: an empty search or list, or an id passed to rm or refetch that does not exist, or refetch with nothing to requeue. Also doctor when a problem remains that it could not repair.
2 Bad usage: unknown command or flag, malformed value, or input that cannot be captured.
3 The capture store is unavailable (unreadable or uncreatable storage root).
4 The enrichment agent is not running: status found no live agent, or add --wait timed out with work still queued.

Machine-readable output is emitted before the exit code is decided, so a --json search with no hits still prints a valid empty array ([]) and then exits 1.

When a bulk cap add - partially fails, the successful captures are reported on stdout, each failure goes to stderr, and the exit code is 2.

Selecting a format

search and list take --format plain|tsv|json, defaulting to plain. export takes --format json|markdown, defaulting to json. --json is accepted by add, search, list, export, and status as shorthand for JSON output and wins over --format.

JSON output

Standard JSON, UTF-8, pretty-printed with keys sorted. Key names are snake_case. Timestamps are ISO 8601 UTC with millisecond precision: 2026-03-03T00:00:00.500Z. Optional fields are omitted when unset, never emitted as null.

search --json and list --json print an array of hit objects:

Key Type Presence Meaning
capture object always The capture, documented below.
snippet string full-text hits only A fragment of the matched text.
score number full-text hits only Raw bm25 rank; lower is a better match.

add --json prints the resulting captures (new or already existing) as an array of capture objects, in input order. export --format json prints every capture the same way and is the lossless backup format.

The capture object

Key Type Presence Meaning
id integer always Row id, as shown by list and taken by rm and refetch.
kind string always link, text, or image.
url string optional The captured URL, normalized.
host string optional Lowercased host of url.
title string optional Page or user-supplied title.
note string optional User-supplied note.
selection string optional Captured text.
body string optional Readable page body extracted for search.
ocr_text string optional Text recognized in an image capture.
asset_path string optional Image file path, relative to $CAP_DIR/assets/.
source_app_bundle_id string optional Bundle id of the app the capture came from.
enrichment_state string always pending, fetching, ok, thin, or failed.
body_status string always none, ok, thin, or failed.
body_source string optional tab or fetch.
attempt_count integer always Enrichment attempts made so far.
last_attempt_at timestamp optional When enrichment last ran.
content_hash string optional Dedupe hash of the normalized URL or content.
created_at timestamp always First capture time.
updated_at timestamp always Last modification time.
last_seen_at timestamp always Most recent re-capture of the same content.
seen_count integer always Times this content has been captured.

The status report object

status --json prints a single object:

Key Type Presence Meaning
agent.installed boolean always The LaunchAgent plist is present.
agent.loaded boolean always launchd has the agent label loaded.
agent.running boolean always A live agent process holds this store’s lock. False here is what makes status exit 4.
captures.pending integer always Captures waiting for enrichment.
captures.fetching integer always Captures being enriched right now.
captures.ok integer always Captures whose enrichment succeeded.
captures.thin integer always Captures whose enrichment came back thin.
captures.failed integer always Captures whose enrichment failed.
captures.total integer always All captures in the store.
database_bytes integer always On-disk size of the database, WAL included.
queue.depth integer always pending + fetching.
queue.eta_seconds integer non-empty queue only Estimated seconds to drain the queue, from recent enrichment times and the current drain width.

TSV output

--format tsv prints one row per hit with no header, columns in this order:

id	created_at	kind	url	title	snippet

created_at uses the same UTC timestamp format as JSON. Absent values are empty fields. Within a field, backslash, tab, newline, and carriage return are escaped as \\, \t, \n, and \r, so rows and columns split cleanly on raw \t and \n.

Environment

CAP_DIR overrides the storage root for the CLI, the app, and the agent alike (default ~/Library/Application Support/cap/).

Was this page helpful?