Obsidian vault task management CLI — fast CRUD for markdown files (tasks, goals, themes, visions).
Never code directly. All code changes go through the dark-factory pipeline.
Spec-based (multi-prompt features):
- Create spec →
/dark-factory:create-spec - Audit spec →
/dark-factory:audit-spec - User confirms →
dark-factory spec approve <name> - dark-factory auto-generates prompts from spec
- Audit prompts →
/dark-factory:audit-prompt - User confirms →
dark-factory prompt approve <name> - Start daemon →
dark-factory daemon(use Bashrun_in_background: true) - dark-factory executes prompts automatically
Standalone prompts (simple changes):
- Create prompt →
/dark-factory:create-prompt - Audit prompt →
/dark-factory:audit-prompt - User confirms →
dark-factory prompt approve <name> - Start daemon →
dark-factory daemon(use Bashrun_in_background: true) - dark-factory executes prompt automatically
Canonical guide: ~/Documents/workspaces/dark-factory/docs/choosing-a-flow.md — read it, don't second-guess from memory. It carries the boundary cases, anti-patterns, and "what gets committed" table; this section is a pointer, not a copy.
30-second decision:
- Is this code that runs in a build / production / CI pipeline? No → Direct (edit by hand, no dark-factory). Markdown, config, yaml, agent definitions, operator scripts land here.
Direct still means a feature worktree, never the shared checkout. This repo has concurrent writers — the maintainer bot, dark-factory, and sibling Claude sessions. Branching in
~/Documents/workspaces/vault-clilets another agent's checkout switch HEAD out from under you and discard your uncommitted edits. Observed 2026-08-20: a docs branch cut there collided with an activefix/session-close-tag-line-linkssession and lost local changes. Create the worktree per [[Git Development Guide]] § Worktrees:git fetch git worktree add --no-track ../vault-cli-<name> -b fix/<name> origin/master cd ../vault-cli-<name> && git push -u origin fix/<name>
- Yes — does the change carry a business-level "why" worth a permanent in-repo document? No → Prompt. Yes → Spec → prompts.
- Writing a spec → read [[Dark Factory - Write Spec]] and [[Dark Factory Guide#Specs What Makes a Good Spec]]
- Writing prompts → read [[Dark Factory - Write Prompts]] and [[Dark Factory Guide#Prompts What Makes a Good Prompt]]
- Running prompts → read [[Dark Factory - Run Prompt]]
| Command | Purpose |
|---|---|
/dark-factory:create-spec |
Create a spec file interactively |
/dark-factory:create-prompt |
Create a prompt file from spec or task description |
/dark-factory:audit-spec |
Audit spec against preflight checklist |
/dark-factory:audit-prompt |
Audit prompt against Definition of Done |
| Command | Purpose |
|---|---|
dark-factory spec approve <name> |
Approve spec (inbox → queue, triggers prompt generation) |
dark-factory prompt approve <name> |
Approve prompt (inbox → queue) |
dark-factory daemon |
Start daemon (watches queue, executes prompts) |
dark-factory run |
One-shot mode (process all queued, then exit) |
dark-factory status |
Show combined status of prompts and specs |
dark-factory prompt list |
List all prompts with status |
dark-factory spec list |
List all specs with status |
dark-factory prompt retry |
Re-queue failed prompts for retry |
-
Prompts go to
prompts/(inbox) — never toprompts/in-progress/orprompts/completed/ -
Specs go to
specs/(inbox) — never tospecs/in-progress/orspecs/completed/ -
Never number filenames — dark-factory assigns numbers on approve
-
Never manually edit frontmatter status — use CLI commands above
-
Always audit before approving (
/dark-factory:audit-prompt,/dark-factory:audit-spec) -
BLOCKING: Never run
dark-factory prompt approve,dark-factory spec approve, ordark-factory daemonwithout explicit user confirmation. Write the prompt/spec, then STOP and ask the user to approve. Do not assume approval from prior context or task momentum. -
Before starting daemon — run
dark-factory statusfirst to check if one is already running. Only start if not running. -
Start daemon in background — use Bash tool with
run_in_background: true(not foreground, not detached with&) -
After completing a spec or major refactor, walk the relevant
scenarios/*.mdto verify end-to-end behavior. Always against a freshly built binary, never against the installedvault-cli. -
Before
make install, follow docs/releasing-vault-cli.md — mandatory reading and procedure. The release gate (run all scenarios against/tmp/new-vault-cli) and the version alignment check both live there. Unit tests +make precommitalone are not sufficient.Scenario-skip rule (only exception): Compare installed version to HEAD — if no binary-relevant files changed, the installed binary is byte-equivalent to what you'd install, so scenarios add no signal.
INSTALLED=$(vault-cli --version | awk '{print $NF}') git diff $INSTALLED..HEAD --name-only | grep -E '\.(go|mod|sum)$|^Makefile$' # empty output → skip scenarios; any hit → run them
Do NOT shortcut by "change type" intuition ("docs-only", "config-only") — always run the diff.
Four version strings MUST always equal each other:
CHANGELOG.md— top## vX.Y.Zentry (the most-recent versioned section).claude-plugin/plugin.json—"version"field.claude-plugin/marketplace.json—metadata.version.claude-plugin/marketplace.json—plugins[0].version
make precommit runs check-versions which fails the build if any of the four diverge. Never commit a release with mismatched versions.
Every release commit bumps all four together — even patch releases triggered by the dark-factory daemon. Plugin manifests are NOT decoupled from the binary tag; users running claude plugin update vault-cli@vault-cli rely on the manifest version matching the tag.
When the daemon's autoRelease ships a new binary version, the prompt that triggered it MUST also bump the three plugin JSON fields — otherwise the next prompt's preflight (make precommit) fails.
This repo is
autoRelease: true(.maintainer.yaml). Thegithub-releaserowns version bumps + tags. For a normal change, add a## Unreleasedbullet and let the releaser convert it →## vX.Y.Z, bump all four version strings, and tag post-merge — do NOT hand-bump the manifests orgit tag(that races the releaser). The manual checklist below is the FALLBACK only (releaser down /autoRelease: false). See [[GitHub Auto-Release Guide]] and the [[Development Guide]] Library/Tool release section.
When to release: Any change to commands/, agents/, docs/, or skills/ requires a plugin version bump — these files ship as part of the plugin.
How to release (manual fallback):
- Pick the next version: increment minor from the latest
CHANGELOG.mdentry (e.g. v0.58.3 → v0.59.0) - Update all four files — version string must be identical everywhere (without
vprefix in JSON):CHANGELOG.md— add new## vX.Y.Zsection at top with all changes (binary + plugin).claude-plugin/plugin.json—"version": "X.Y.Z".claude-plugin/marketplace.json—"version": "X.Y.Z"in bothmetadataandplugins[0]
- Commit:
release plugin vX.Y.Z: <summary> - Push:
git push
Common mistakes:
- Forgetting
.claude-plugin/files (plugin stays at old version) - Creating a separate "Plugin vX" changelog section (wrong — one version for everything)
- Using different versions in the 3 JSON fields (must all match)
- Not including binary changes (fix, feature) in the changelog when they're uncommitted
Full release procedure: see docs/releasing-vault-cli.md.
Plugin config lives in .claude-plugin/. Commands in commands/.
| File | Purpose |
|---|---|
.claude-plugin/plugin.json |
Plugin metadata (name, version, license) |
.claude-plugin/marketplace.json |
Marketplace listing config |
commands/*.md |
Claude Code slash commands |
This project follows the coding-guidelines.
- go-architecture-patterns.md — Interface → Constructor → Struct → Method
- go-testing-guide.md — Ginkgo v2/Gomega testing
- go-makefile-commands.md — Build commands
- git-commit-workflow.md — Commit process with precommit checks
- go-mocking-guide.md — Counterfeiter mock generation
make precommit— lint + format + generate + test + checksmake test— tests only
See docs/development-patterns.md — architecture, adding commands, multi-vault, output format, testability, naming.
pkg/ops/is a library layer — operations return structured results, never write to stdout. CLI layer owns all output formatting.