Commands
| Command | Purpose |
|---|---|
add [<path>] |
Register a path (defaults to .) with one or more tags. |
mark [-p <path>] <tag> ... |
Tag a directory with temporary (7-day) tags. Defaults to cwd. |
rm <path> |
Remove tag(s) from a path, or drop the path entirely. |
prune --gone|--expired |
Bulk-delete entries whose path is missing, or tag rows past their TTL. |
move <old> <new> |
Move a registered path; tags carry over. |
tags |
List all tags with usage counts. |
rename <old> <new> |
Rename a tag, or merge into an existing one. |
list [<query>] |
List or search directories (--pick to resolve to one path). |
info [<path>] |
Show one entry's details (tags, TTLs, last-used). Defaults to cwd. |
stats |
Top tags + recently added/used paths. |
run <tag> -- <cmd> |
Run a command in every tagged directory. |
export |
Dump the database (JSON or YAML). |
import <file> |
Load a snapshot (--merge or --replace). |
trash <action> |
Recover from rm or empty the soft-delete store. |
config <action> |
Read or write config.yml keys from the CLI. |
setup install |
Append the shell wrapper to your rc file. |
setup init <shell> |
Print the shell wrapper for manual install. |
setup completion <shell> |
Print a shell completion script. |
doctor |
Check the install (paths, config, DB). |
version / help |
Show version / help. |
doma cd <tag> lives in the shell wrapper from setup install, not in the binary.
Global flags
| Flag | Effect |
|---|---|
-q, --quiet |
Suppress success/info output (errors still print). |
-v, --verbose, --debug |
Print debug traces to stderr. |
--no-color |
Force color off. |
--color |
Force color on (defaults to TTY auto-detect). |
NO_COLOR env is honored automatically.
add
doma add [<path> ...] [-t TAG ...] [--ttl DUR | --tmp]
[--auto-tag] [--git-tag] [--dry-run] [--json]
-t TAG: add a tag. Repeatable; comma-separated also works (-t a,b).--ttl DUR: tag expires afterDUR(e.g.30s,5m,1h,7d,2w).--tmp: alias for--ttl 7d.--auto-tag/--no-auto-tag: include the basename as a tag.--git-tag/--no-git-tag: derive host and repo tags from.git/config.-n,--dry-run: resolve and print without writing.--json: structured output (array of results includingshort_idper path).markforwards this flag. Useful for agents that want the stable ID immediately.
mark
doma mark [-p PATH] (<tag> [<tag> ...] | -t TAG [-t TAG ...])
Equivalent to doma add <path> -t TAG ... --tmp. Path defaults to cwd; -p PATH marks elsewhere. 7-day TTL. Tags accept positional or -t/--tag; both forms may be mixed.
rm
doma rm <path> [<path> ...] [-t TAG ...] [--hard]
<path>alone: drop the path and all its tags (snapshotted to trash by default).<path> -t TAG: untag.--hard: skip the trash and delete permanently.
prune
doma prune (--gone | --expired) [--hard]
--gone: remove entries whose path no longer exists (snapshotted to trash for 7 days; recover withdoma trash list/doma trash restore <id>).--expired: drop tag rows whose TTL has elapsed and GC any tags left orphaned.--hard: skip the trash on--gone.
The two flags are mutually exclusive.
list
doma list [<query>] [-t TAG] [--by path|recent|tag]
[--check] [--include-expired]
[--json] [--paths] [-0]
[--pick [--first | --builtin] [--query Q]]
<query>: substring match across path/basename/tag.-t TAG: exact tag (or glob if*/?is present).--by: sort/group key.path(default): alphabetical by path.recent(aliases:used,recency): most-recently-used first.tag: group output under per-tag headers. Entries with multiple tags appear under each; entries with no active tags collect under(no tags)at the end. Notes:- Incompatible with
--pick. - With
--json, the result is an object keyed by tag name (""for untagged) instead of a flat array. - With
--paths/-0, paths are emitted in tag-sorted order with duplicates collapsed. - Only active tags create headers — TTL-expired tags are hidden unless
--include-expiredis set, so an entry whose only tags have expired falls into(no tags)by default. - Combining with
-t TAGfilters which entries appear, but each surviving entry still renders under every tag it carries (not onlyTAG).
- Incompatible with
--check: annotate entries whose path is gone with[gone].--include-expired: include tag rows whose TTL has elapsed.--json/--paths/-0: machine-readable forms (see Pipelines). JSON rows carryshort_id,path,basename,tags,created_at, andlast_used_at(epoch seconds;last_used_atis0when the entry has never been picked), plusexpirationsfor TTL'd tags andexistsunder--check.--pick: resolve to a single path on stdout.--firstfor deterministic auto-pick,--builtinto force the picker even off-TTY.
info
doma info [<path-or-short-id>] [--json]
Defaults to .. Accepts either a path or a short_id (full or unique prefix). Prints short_id, canonical path, tags (with TTL or ~expired suffix), created_at, last_used_at, and an exists check. Exits 3 when not registered. If the entry is in the trash, surfaces the trash short_id and a restore hint.
With --json, every outcome is a JSON object on stdout — a hit is {"found": true, …}, a miss is {"found": false, "input", "error", "hint"} — so a caller can branch on found instead of parsing stderr. Exit codes are unchanged (3 for a miss, 2 for an ambiguous bare-name match).
run
doma run (<tag> | -t TAG) [--fail-fast] [--parallel [--jobs N]] [--no-header]
[-n | --dry-run] [--json] -- <cmd> [args...]
-- is required. --fail-fast is sequential-only. The tag can be passed positionally or via -t/--tag (alias) — pick one. A single tag is accepted; commas are not split, but glob patterns (*, ?) match across multiple tags.
--jobs N: cap concurrency under--parallel(default: CPU count).--no-header: drop the▶/✓chrome; failures still surface.-n,--dry-run: print the target directories without running anything.--json: capture each directory's streams and emit one row per directory —{"path", "exit_code", "stdout", "stderr", "dry_run"}— in stable input order even under--parallel. Implies--no-header. See Bulk run.
status
doma status [<tag> | -t TAG] [--dirty] [--jobs N] [--json]
Reports each tagged directory's git working-tree state — branch, ahead/behind vs upstream, dirty-file count. No tag scans every tracked directory. --dirty shows only repos with uncommitted changes. Probes run in parallel (--jobs to tune; default CPU count) by shelling out to git; non-git and missing paths are surfaced too. See Git status.
export / import
doma export [--json | --yaml] [-o FILE]
doma import <file> [--merge | --replace] [-y | --yes]
--replace without --yes requires a TTY confirmation.
trash
doma trash list [--json]
doma trash restore <short_id> [--merge]
doma trash empty [--older DUR] [--json]
rm <path> writes to the trash by default — trash list shows what's recoverable (newest first). Use --json for machine-readable output (array of entries with short_id, path, tags, deleted_at, expirations, etc.). trash restore brings an entry back. Use --merge if the path is already re-registered with different tags. empty purges everything (optionally --json for {"purged": N}); empty --older 7d purges only old entries.
Anything older than 7 days is auto-pruned on the next trash op.
config
doma config get <key>
doma config set <key> <value>
doma config unset <key>
doma config list
doma config edit
doma config path
Keys: db_path, selector, auto_tag.basename, auto_tag.git (see Configuration for what each does).
set / unset rewrite config.yml and don't preserve comments — use config edit to open the file in $EDITOR for hand-edits.
setup
doma setup install [<shell>] [-y | --yes] [-n | --dry-run]
doma setup init <bash|zsh|fish>
doma setup completion <bash|zsh|fish>
doctor
doma doctor
Reports paths (home / config / DB), config-file status, and database stats (directories, tags, missing-on-disk count, schema version).
Exit codes
Each failure class has its own code, so scripts can branch on the status rather than match against error text (which is human-facing and may be reworded between releases).
| Code | Means | Typical cause |
|---|---|---|
| 0 | Success — including an empty result set | list -t X matched nothing |
| 1 | Generic failure | unknown flag or command; run had at least one directory exit non-zero |
| 2 | Validation | invalid tag name, conflicting output flags, add given a non-directory |
| 3 | Not found | info / rm on an unregistered path; list --pick matched nothing |
| 4 | Conflict / ambiguous | list --pick matched several directories with no TTY and no --first |
| 5 | Config | unreadable or invalid config.yml, bad DOMA_* variable |
| 6 | Import | malformed snapshot file |
| 130 | Cancelled | Ctrl-C in an interactive picker |
| 141 | Broken pipe | the reader closed early, e.g. doma list | head -1 |
An empty result is a success, not an error: doma list -t nothing exits 0 with a one-line note on stderr (and [] on stdout under --json). Check for empty output before iterating rather than relying on the exit code.
Destructive commands that can't be undone — rm --hard, prune --gone --hard, import --replace, trash empty — exit 1 rather than proceeding when stdin isn't a TTY and neither -y/--yes nor DOMA_YES=1 was given. An unattended caller has no other way to signal consent.