doma v0.4.1
Directory tag manager — put your directories on the cutting board.
Installation • Shell integration • Pipelines • AI agents • Contributing • Releases
doma is a Crystal CLI for tagging directories so you can recall, browse, or batch-execute across them. Tag your projects once (crystal, work/proj-a, bookmark), then jump to them, list them, or run a command across the whole set without re-typing paths.
doma add ~/Projects/my-app -t crystal -t web
doma list -t crystal --paths | xargs -I{} sh -c 'cd {} && shards build'
doma cd crystal # interactive picker, then cd (needs `doma setup install`)
doma mark spike # bookmark cwd for 7 days
Features
Tagging
- Multiple tags per directory; tags are reusable across paths
- Auto-tag from basename and Git remote (
--auto-tag,--git-tag) - Glob filter on tags (
list -t 'work/*',run 'work/*' -- cmd) — shell-style:*matches within one segment,**crosses/,?is a single non-/character - Hierarchical tag display (
tags --tree) - TTL on tags:
--ttl 30m | 1h | 7d | 2w,--tmpfor the 7-day default,markfor the cwd + 7-day shortcut - Stable 7-char
short_idper directory — survives renames; usable viarm <id>andtrash restore <id>
Navigation & operations
tui— full-screen fuzzy finder over your registered directories, and the default when you rundomawith no subcommand. Fuzzy match on paths with match highlighting, narrow with a small query syntax (tag:crystal,-tag:archived,id:0d,path:src), register a directory withCtrl-Aor copy a path withCtrl-Ywithout leaving it. Enter prints the path so the shell wrappercds into itlist --pickresolves to a single path (Crystal-native picker, no fzf dependency); thedoma cd <tag>shell wrapper fromdoma setup installbuilds on itrun <tag> -- <cmd>to execute a command in every tagged directory;--parallel(with--jobs N, default CPU count) and--fail-fastavailablestatus <tag>for a one-glance git dashboard across a tagged set — branch, ahead/behind, dirty count;--dirtyto show only repos with uncommitted work,--jsonfor scriptingmoveto follow a path that moved on disk; tags carry overrenameto merge or relabel tags- Recency tracking — most-used directories surface first in pickers and
list --by recent - Substring search across path / basename / tag (
doma list <query>) - Single-entry detail view (
doma infodefaults to cwd) — tags, TTLs, last-used, exists check - Dead-path detection:
list --check,prune --gone; expiry purge:prune --expired
Pipelines & scripting
list -t TAG --paths— newline-separated paths forwhile read/xargslist -t TAG -0— NUL-separated forxargs -0, safe for paths with spaceslist --json,tags --json,stats --json,export --json|--yaml- "Did you mean ..." hints (Levenshtein) for typos
- Output stays color-free when piped; SIGPIPE-safe
Storage & safety
- SQLite-backed (WAL, foreign keys, busy_timeout) — handles concurrent doma calls across multiple shells
- Path canonicalization:
~, symlinks, and trailing slashes all collapse to one stable key - Transactional writes; atomic snapshot import/export
- Schema migrations via
PRAGMA user_version— old DBs upgrade transparently - Strict tag validation; sanitized auto-tags so a
.dotfilesrepo doesn't break--auto-tag
Distribution & integration
- Single static binary (musl + sqlite-static); no runtime dependencies
- Packaged for Homebrew, AUR, Snap, .deb, .rpm, .apk
- Multi-arch container image at
ghcr.io/hahwul/doma - CycloneDX SBOM published with every release
- Shell integration installer (
doma setup install) for bash, zsh, fish - AI skill for Claude / Cursor / etc. — see skills/doma/SKILL.md
Installation
Homebrew
brew tap hahwul/doma
brew install doma
From source
git clone https://github.com/hahwul/doma.git
cd doma
shards install
shards build --release --no-debug --production
Pre-built binaries
Static Linux and macOS binaries are attached to every release. .deb / .rpm / .apk / .snap packages are published alongside.
Container
docker pull ghcr.io/hahwul/doma:latest
docker run --rm -it -v "$HOME/.config/doma:/root/.config/doma" \
ghcr.io/hahwul/doma list
Shell integration
doma cd lives in a shell function rather than the binary — a child process can't change its parent shell's working directory. The function calls doma list -t <tag> --pick (the binary's single-pick primitive) and runs cd on the result. One-shot install:
doma setup install # auto-detects $SHELL, appends to your rc
exec $SHELL # or `source ~/.zshrc`
doma cd crystal # interactive picker, then cd
doma # bare doma opens the fuzzy finder, then cd
The wrapper also makes bare doma and doma tui cd into whatever you pick in the finder.
If you'd rather wire it manually:
eval "$(doma setup init zsh)" # bash / zsh
doma setup init fish | source # fish
Without the wrapper, the equivalent inline form works everywhere:
cd "$(doma list -t crystal --pick)"
Pipelines
doma is designed to compose with the rest of your shell. A few common shapes:
# Update CI files across every Crystal project
doma list -t crystal --paths | while read -r d; do
(cd "$d" && sed -i 's/crystal: 1.20/crystal: 1.21/' .github/workflows/*.yml)
done
# Status across work repos (paths-with-spaces safe)
doma list -t 'work/*' -0 | xargs -0 -I{} sh -c 'cd "{}" && git status -s | head'
# Structured access via jq
doma list --json | jq -r '.[] | "\(.short_id)\t\(.path)\t\(.tags|join(","))"'
# Ad-hoc bookmarks during a code review session
doma mark auth-review
# ... cd around ...
doma list -t auth-review --paths
AI agents
doma ships a Claude Code skill that teaches an agent when to query the database for a path list ("update CI for all my Crystal projects") and when to register or bookmark a directory ("track this", "remember this for later").
Install via Vercel Skills:
npx skills add hahwul/doma
Or copy the file by hand into your agent's skill directory:
cp -r skills/doma ~/.claude/skills/
# or symlink so updates land automatically:
ln -s "$(pwd)/skills/doma" ~/.claude/skills/doma
Contributing
doma is open-source and PRs are welcome. Please check CONTRIBUTING.md before sending a patch.
Why "doma"?
Doma (도마) is the Korean word for cutting board — the workbench where ingredients are gathered, grouped, and chopped before going into the pan. doma aims to be the same kind of workbench for your directories: pull the ones you care about onto a single board, group them by category (crystal, work/proj-a, bookmark), and run bulk operations across the piles as if they were mise en place.
doma
- 4
- 0
- 0
- 0
- 3
- about 4 hours ago
- April 25, 2026
MIT License
Sat, 04 Jul 2026 05:26:24 GMT