balls 0.5.7

Git-native task tracker for parallel agent workflows
Documentation
# bl create — file a new task

    usage: bl create "TITLE" [--body B] [-p N] [-t TAG] [--parent ID]
             [--subtask-of ID] [--needs ID[:OP]] [--blocks OP|ID:OP]
             [-m MSG] [--as ID] [-- TITLE]

Files a task and prints its new id to **stdout** (so `id=$(bl create "…")`
captures it clean).

## Flags

- `--body B` — set the task's markdown body (its living document; overwrite it
  as the state changes).
- `-p, --priority N` — priority; higher sorts first in `bl list`.
- `-t, --tag TAG` — add a tag (repeatable; the flag is `--tag`, not `--tags`).
- `--parent ID` — containment only: builds the display tree, **gates nothing**.
- `--subtask-of ID` — child of ID *and* gate ITS claim (the everyday subtask
  spelling). Mutually exclusive with `--parent`.
- `--needs ID[:OP]` — add a blocker on this task (default `OP = claim`).
- `--blocks OP | ID:OP` — the reciprocal: gate ANOTHER task's op on this one.
  Create-only (it is an edge on another task, not this task's own field).
- `-m MSG` — commit note for the store journal.
- `--as ID` — worker identity.
- `--` — end option parsing (getopt). Shell an untrusted, `-`-leading title so
  it can't hijack a flag: `bl create -- "$TITLE"`.

## Examples

    bl create "Fix the parser" --body "repro: bl create -x"
    bl create "wire the auth endpoint" --subtask-of bl-1a2b
    bl create -- "$UNTRUSTED_TITLE"

## The dependency model

The one relational primitive is a blocker edge `{id, on}` on the *blocked* task:
"this task can't do op `on` until task `id` resolves." `on` is ANY op; two have
create-time sugar:

- `--needs B[:OP]` — a blocker on THIS task (default `claim`, i.e. can't be
  claimed until B closes).
- `--blocks OP` / `--blocks ID:OP` — the reciprocal on ANOTHER task. `--parent X
  --blocks close` gates X's close on this task.
- `--subtask-of E` — sugar for `--parent E --blocks claim` in one word: child of
  E, and E can't be **claimed** until this closes. Gating claim (not close) is
  what keeps an epic-with-open-children out of `bl list -s ready` — the epic
  derives as *blocked* per open child, so a dispatcher never lands an agent on an
  unactionable container; the last child closing auto-readies the epic. Prefer
  this over bare `--parent` when filing subtasks: the gate rides in the flag's
  name, so it can't be silently forgotten.

**Every edge target must be LIVE.** `--needs`/`--blocks`/`--subtask-of` refuse a
target id that is unknown or already closed, naming which — a never-minted id is
a typo or hallucination (it would leave the task silently ungated), and a dead
blocker can never block. The remedy is dropping the flag.

`--parent` is **containment only** — it builds the display tree and gates
nothing. An "epic" is just a task with children; to make a parent wait on its
children, add explicit edges (`--subtask-of` at create is the usual way).

**Splitting work? Wire the gates.** Filing N balls with no edges declares them
fully independent — and since one agent is dispatched per UNBLOCKED ball, that
reads as "claim all N in parallel, now," colliding on shared files. If the
pieces have an order, encode it with `--needs`. Filing flat IS a parallelism
decision. The order lives in the **ball graph** (what the dispatcher reads),
never only in a design doc or commit note.

To edit a task's own blockers after create, see `bl update --skill`
(`--needs` / `--no-needs`). Reciprocal `--blocks` stays create-only.