balls 0.2.1

Git-native task tracker for parallel agent workflows
Documentation
# balls — Agent Skill Guide

You are using **balls** (`bl`), a git-native task tracker. Tasks are JSON files in the repo. Worktrees isolate your work. Git provides sync.

## Roles and the one hard rule

You may be acting as a **worker** (claim → work → submit), a **reviewer** (inspect → approve or reject), or both — sometimes in the same session. There's only one inviolable rule:

**Never run `bl close` while you're standing inside the worktree it would delete.** `cd` back to the repo root first. The binary will refuse otherwise with `cannot close from within the worktree`.

Everything else is flow, not rule. A solo agent that claims a task, works it, runs `bl review`, hops back to the repo root, and runs `bl close` on its own work is doing things correctly. A multi-agent setup where one agent submits and another approves is also correct. Pick whichever the user's situation calls for.

## Session Start

Run `bl prime` at the start of every session:

```
bl prime --as YOUR_IDENTITY --json
```

It syncs with the remote and returns:
- **claimed**: tasks you already own — resume in their worktrees.
- **ready**: open tasks available to claim, sorted by priority.

Reviewers also want `bl list --status review` to see what's waiting on a decision.

## Commands

| Command | What it does |
|---------|-------------|
| `bl prime --as ID` [`--json`] | Sync, show ready + your claimed tasks. Run at session start. |
| `bl ready` [`--json`] | List open tasks ready to claim. |
| `bl list` [`--status STATUS`] | List non-closed tasks (use `--status review` to find reviewables). |
| `bl show TASK_ID` [`--json`] | Task details, including `delivered_in` sha after review. |
| `bl claim TASK_ID` | Worker: create worktree, set status=in_progress. |
| `bl review TASK_ID -m "msg"` | Worker: squash to main, set status=review. Worktree stays. |
| `bl close TASK_ID -m "msg"` | Reviewer: approve. Archive task, remove worktree + branch. **Repo root only.** |
| `bl update TASK_ID status=in_progress --note "..."` | Reviewer: reject. Bounces task back to the worker. |
| `bl update TASK_ID --note "text"` | Add a note (any role). |
| `bl drop TASK_ID` | Release a claim, remove worktree (worker self-recovery). |
| `bl dep tree` | Show dependency graph. |

## Task Lifecycle

```
open ──claim──> in_progress ──review──> review ──close──> archived
                     ^                    │
                     └────── reject ──────┘
```

- **open**: available to claim.
- **in_progress**: claimed; the worker owns it.
- **review**: worker submitted; waiting on a reviewer. Worktree still exists.
- **closed/archived**: task file deleted from the state branch's HEAD (not main). The work itself lives in main's git history.

A reject sets status back to `in_progress`. The worker resumes in their existing worktree; their next `bl review` re-merges main automatically.

## Worker Workflow

```
bl prime --as YOUR_ID
bl claim TASK_ID            # prints worktree path
cd <worktree path>          # work happens HERE, never in the main repo
# ... edit, commit ...
bl review TASK_ID -m "msg"  # submit; worktree stays for rework
```

Worktrees live at `.balls-worktrees/bl-xxxx`, on branch `work/TASK_ID`, with `.balls/local` symlinked for shared lock state.

Important:
- **Commit your work** before `bl review`. Review will `git add -A` anything left behind, but explicit commits give better history.
- **Don't modify files in the main repo** while working on a claimed task. Use the worktree.
- **Don't `bl update TASK_ID status=closed`** on a claimed task — it's rejected. Use `bl review` (which is what flips it to `review`), then close from the reviewer side.
- **Don't delete `.balls/` files manually.** Use `bl drop` to release a claim, `bl repair --fix` to clean up orphans.

### What `bl review` does

1. Commits all uncommitted work in your worktree.
2. Merges main into your worktree (catches up; conflicts surface HERE, not on main).
3. Squash-merges your branch into main as a single feature commit.
4. Writes the delivery hint and flips status to `review` on the state branch.

If step 2 conflicts, review fails. Resolve in the worktree, then retry.

### Commit messages: 50/72 shape

`bl review -m` uses the first line as the commit title and everything after the first newline as the body. The delivery tag `[bl-xxxx]` is appended to the title automatically.

Pass a structured message so `git log --oneline` stays readable:

```
bl review bl-abcd -m "$(cat <<'EOF'
Short imperative title under ~50 chars

Body paragraph explaining the change in detail. Wrap at ~72.
Add more paragraphs as needed — everything after the blank line
is preserved as the commit body.
EOF
)"
```

A single-line `-m "fix foo"` becomes `fix foo [bl-abcd]` with no body. Don't stuff a multi-sentence summary into a single line; that produces an unreadable `git log --oneline`.

## Reviewer Workflow

A task in `review` status is waiting on an approve-or-reject decision. The work has already squashed to main; the reviewer's job is to accept it or send it back.

```
bl list --status review                       # find tasks awaiting review
bl show TASK_ID                               # status, claimant, delivered_in sha
git show <delivered_in sha>                   # inspect what landed on main
cd <repo root>                                # required for close — see hard rule above

# Approve:
bl close TASK_ID -m "approval note"

# Reject:
bl update TASK_ID status=in_progress --note "what to fix" --as reviewer
```

Important:
- **Reviewing someone else? Don't edit files inside their worktree** to fix things — reject with notes and let them iterate. (Reviewing your own work in a solo flow is fine; the same person did both halves.)
- **Approval is durable.** Close archives the task file from the state branch HEAD and removes the worker's worktree + `work/TASK_ID` branch. The squash commit on main carries the work.
- **Rejection keeps the worktree.** The worker resumes in place; their next `bl review` re-merges main automatically.
- If accepted work needs to be undone, that's a `git revert` of the delivered sha on main, not a `bl close` thing — close still archives the task.

## Creating Tasks

If you discover work that needs doing:

```
bl create "Fix the auth timeout" -p 1 -t bug --tag auth -d "Description here"
bl create "Add rate limiting" -p 2 --dep bl-a1b2 --tag api
```

- Priority: 1 (highest) to 4 (lowest)
- Types: `epic`, `task`, `bug`
- Dependencies: `--dep TASK_ID` (blocks the new task until dep is closed)
- Tags: `--tag NAME` (freeform labels)

## Dependencies and Links

```
bl dep add TASK_ID DEPENDS_ON_ID    # blocking dependency
bl dep rm TASK_ID DEPENDS_ON_ID     # remove dependency
bl dep tree                          # show full dependency graph
bl link add TASK_ID relates_to OTHER_ID   # non-blocking relationship
bl link add TASK_ID duplicates OTHER_ID
bl link add TASK_ID supersedes OTHER_ID
```

## Environment

| Variable | Purpose | Default |
|----------|---------|---------|
| `BALLS_IDENTITY` | Your worker identity | `$USER`, then `"unknown"` |

Set `BALLS_IDENTITY` in your environment or use `--as` on commands that accept it.

## Error Recovery

| Situation | Solution |
|-----------|----------|
| Merge conflict on `bl review` | Resolve in worktree, run `bl review` again |
| `bl close` errors "cannot close from within the worktree" | `cd` to the repo root, retry |
| Task claimed by someone else | Pick another from `bl ready` |
| Worktree in bad state | `bl drop TASK_ID --force` (loses uncommitted work) |
| Orphaned claims/worktrees | `bl repair --fix` |
| Lost context mid-task | `bl prime` shows your claimed tasks |