| name | bacio |
| description | Use this skill whenever you need to create, read, update, or organise tasks/issues/tickets/todos using the `bacio` CLI — a local issue tracker that ships with this repo. Triggers on any mention of issues, features, kanban work, kanban lanes/columns, workspaces, tags, blocks/blocked-by relations, attached pull requests, project documents, document folders, or audit-log/history queries managed by `bacio`. Prefer `bacio` over external trackers (e.g. GitHub Issues) whenever the user is tracking work for a repo where `bacio` is in use. |
bacio CLI
bacio is a local CLI issue tracker backed by a single SQLite db at ~/.bacio/db.sqlite. It is built to be driven non-interactively.
This skill orients you and states the conventions that aren't obvious from --help. For the exact flags of any command, run bacio <command> --help; for the JSON payload shape of any mutation, run bacio schema show <command>.
Discover, don't memorise
bacio --help — every command group.
bacio <group> --help (e.g. bacio issue --help, bacio agent --help) — the subcommands and their flags.
bacio schema list — every mutating command that accepts --json, one line each.
bacio schema show <command> — full JSON Schema (draft 2020-12) for one command, with a worked examples[0] you can copy. bacio schema all dumps every schema in one pass.
Mental model
Hierarchy: repo → (optional) feature → issue.
- A repo is auto-detected from
cwd by walking up to a .git toplevel. Issues, features, and documents are scoped to a repo.
- A workspace is a repo with no git working tree — a tracked space for work that isn't code. It holds issues, documents, doc folders and a Kanban board exactly as a git repo does, and shares the same prefix namespace. Because it has no path, it can never be resolved from
cwd: see the --repo selector below.
- A feature is an optional grouping of issues (a project or epic). Issues can exist without one.
- An issue has a title, description, state, tags, comments, relations, and attached PR URLs. Addressed by a 4-letter
PREFIX-N key like MINI-42.
- A document is a per-repo named text blob with a typed category; issues and features link to documents with a short reason. Documents can be filed into a doc folder tree, which is purely organisational — a filename stays flat and unique per repo, so folders never change a doc's identity, links or URLs.
- A Kanban lane is a per-repo board column, orthogonal to issue state. A card is on the board iff it sits in a lane.
Two boards, one tracker. The Agentic Pipeline is keyed on state (in_pipeline, to_be_shipped, …) and is where dispatched agents work. The Kanban is keyed on lanes and is the human board. They are independent axes: bacio kanban move never changes an issue's state, and bacio issue state never changes its lane. In a workspace, new issues land on the leftmost lane automatically and there is no Pipeline (no working tree for an agent to work in — dispatch is refused server-side). In a git repo, new issues start off the Kanban and are opted in explicitly.
Issue states: todo | in_review | done | cancelled, plus the Pipeline-page columns in_pipeline | to_be_shipped. The parser accepts dashes/spaces (in-review, in review). The legacy in_progress / needs_action states were retired (BACI-300) — work now flows through the Pipeline, and "an agent is paused waiting on the user" is signalled by an open ask_user_question on the ticket (or, for a pipeline card, the engine's engine_pause_reason), not a state.
Auto-create on first use: any mutating command in an unregistered git repo creates the repo row and allocates a 4-char prefix from the directory basename. bacio status is read-only and never auto-registers — use it as a safe probe. --repo <PREFIX> is a lookup, never a create: an unknown prefix errors out rather than minting a repo.
Conventions that matter
cd to the repo first — or pass --repo <PREFIX>. Most commands resolve the repo from cwd. The global --repo <PREFIX> flag (falling back to $BACIO_REPO) names the repo explicitly and short-circuits that detection entirely. It is mandatory for workspaces — they have no working tree, so cwd can never find one, and without it bacio would auto-register whatever unrelated git repo you happen to be standing in. It is a selector, so it lives beside --db / --remote / --dry-run and never appears as a --json field. It is case-insensitive (--repo home == --repo HOME) and a lookup, never a create: an unknown prefix errors instead of minting a repo. (bacio issue list and bacio history also take --all-repos.)
- Audit attribution is automatic. Every mutation is audit-logged with an actor. With
bacio install-agent set up in the repo, the SessionStart hook records your (claude_pid → agent identity) mapping in .bacio/agents.json; subsequent bacio calls resolve actor through that mapping with no flag needed. Calls without an agent identity (humans at the terminal) stamp the placeholder "user".
- Prefer
--json over typed flags when driving bacio. It is strict (typos surface as unknown field errors), takes long text as inline strings (no file/stdin dance), and its shape is published via bacio schema. Accepts --json '<json>', --json - (stdin), or --json @path. It is mutually exclusive with positionals and per-field flags.
- Rehearse with
--dry-run. Every mutating command accepts it: runs everything up to the SQL write, emits the projected result, touches nothing. Use it before deletes (issue rm / feature rm / doc rm / repo rm report cascade counts) and to validate a --json payload.
- Pass
-o json when parsing. Default output is human text and may shift; JSON is the contract. List commands are lean by default — drops (add ); is metadata-only.
What's in the box
A map of the command groups, not a manual. Run bacio <group> --help for the verbs and flags of each, and bacio schema show <command> for a mutation's payload — those are always current, this list is not. What's spelled out below is the semantics --help can't give you; Gotchas at the end carries the rest.
-
bacio init / bacio repo — bind a repo, list/show, repo rm (destructive — needs --confirm <PREFIX>), repo link <PREFIX> <PATH> (bind a phantom repo — sync-imported with no local working tree — to an absolute path; writes .bacio/config.yaml pointing at the owning sync repo's remote). repo list carries a kind field: git or workspace.
-
bacio workspace — add <NAME> [--prefix XXXX] / list / rm for repos with no git working tree. add seeds the starter Kanban board (Backlog / Doing / Waiting / Done) and allocates a prefix from the name unless you pin one; unlike a git repo it seeds no catch-all features, so a workspace has no default feature and its issues are feature-less until you bacio feature add one. rm is repo rm narrowed to workspaces: same cascade, same --confirm <PREFIX> gate, and it refuses a git repo so you can't delete the wrong kind of thing by typo. Everything afterwards needs --repo <PREFIX> — except verbs addressed by issue key (bacio issue show HOME-1, bacio kanban move HOME-1 …), which resolve the repo from the key's own prefix.
-
bacio kanban — the human board. kanban column add|rename|mv|rm|list manage lanes (addressed by name; matching is exact first, then a unique case-insensitive match, so --column doing finds Doing). kanban move <KEY> --column <NAME> [--position N] places one card; --off-board takes it off. column mv --position is 0-based (0 is the leftmost lane) and only the moved lane comes back — re-read kanban column list for the new board order. Deleting a lane never deletes an issue: its cards just come off the board.
-
bacio doc folder / bacio doc mv — the document tree. doc folder add <NAME> [--parent <PATH>], rename <PATH> <NEW-NAME>, , , . Folders are addressed by their exactly as prints it; segments are matched exactly and are . files a page. Deleting a folder deletes its subfolders but every page inside — a folder is organisational, so losing one never loses a document. Nesting is capped at 16 levels, and moving a folder into its own subtree is refused inside the write transaction — so both can fail a said otherwise.
Worked example
cd ~/Repos/myproject
bacio schema show issue.add | jq .examples[0]
bacio issue add --dry-run --json '{
"title": "Login broken on Safari",
"feature_slug": "auth-rewrite",
"description": "500 on submit. Repro inline.",
"customer_impact": "Login no longer 500s on Safari",
"tags": ["bug", "P0"]
}' -o json
bacio issue add --json '{ ...same... }' -o json
bacio issue brief MINI-42
Driving a workspace — note that cd buys you nothing here, so every call carries the selector:
bacio workspace add "Home Renovation"
export BACIO_REPO=HOME
bacio issue add "Replace the back fence"
bacio kanban column list
bacio kanban move HOME-1 --column doing --position 0
bacio doc folder add Quotes
bacio doc add fence-quote.md --type architecture --content "Two quotes attached."
bacio doc mv fence-quote.md --folder Quotes
bacio doc folder list
CLI client mode (--remote)
bacio can drive a remote bacio api server instead of the local DB: set --remote http://host:5320 (or $BACIO_REMOTE) and --token / $BACIO_API_TOKEN if the server enforces auth. Every read and mutating verb behaves identically. Verbs that touch the local filesystem or terminal (init, install-skill, install-agent, tui, schema, status, hook, channel, the settings template and sync verbs) stay local-direct and error clearly under --remote.
Gotchas
- Never run
bacio outside a git repo when a command needs the current repo — it hard-errors. cd first, or pass --repo <PREFIX>.
- A workspace is unreachable without
--repo / $BACIO_REPO. It has no path, so cwd detection can never find it — git.Detect walks up for a .git toplevel and a workspace has none, so there is no other route to one on any surface. Running a repo-scoped verb from an unrelated directory without the selector will resolve (or auto-register) that directory's git repo instead — a silent wrong-target, not an error.
- A few verbs ignore
--repo by design because they probe where you are rather than operate on a named project: bacio status (a cwd/environment probe — BACIO_REPO=WKSP bacio status still reports on the current working tree, or "not inside a git repository") and bacio sync init / sync clone (they set sync up for the checkout you're standing in). A workspace legitimately has no answer for either.
"" is a destination, not a blank. On doc folder mv (to), doc mv (folder) and kanban move (column), the empty string means the tree root / off the board. Because that is a real value, the --json path requires the key to be present: omitting it is an error, never an implicit no-op. On the flag path use the explicit --to-root / --off-board spelling. The one exception is doc folder add's parent, where omitting the key and passing "" both mean the root — creating at the root is a harmless default, whereas moving something there silently is not.
- Omitting
position means append, on both doc mv and kanban move. Kanban positions are dense 0-based indices within a lane (and kanban column mv --position is a dense 0-based board slot); doc-folder positions are a loose sort key that siblings may share, tie-broken on filename. bacio issue reorder, by contrast, is 1-based — different surface.
Installation
If unsure whether bacio is installed, run bacio --help; bacio --version shows the version. To install:
brew tap mrgeoffrich/bacio && brew install bacio
go install github.com/mrgeoffrich/bacio/cmd/bacio@latest
go build -o ~/.local/bin/bacio ./cmd/bacio
bacio install-skill, run from anywhere inside another repo, writes this skill to .claude/skills/bacio/SKILL.md so that repo's agents discover it — re-run after upgrading bacio.
bacio install-agent --yes sets a repo up for agent-driven bacio work in one idempotent invocation: per-mode dispatch subagent files under .claude/agents/, the bacio hook command hooks in .claude/settings.json, and a bacio channel entry in .mcp.json for push dispatch delivery.