apm-core 0.1.17

Core library for APM — a git-native project manager for parallel AI coding agents.
Documentation
# APM Agent Instructions

## Repo structure

_Fill in your project's structure here._

State machine: transitions defined in `apm.toml` under `[[workflow.states]]`

## Roles

Every Claude session in this repo is either a **Main Agent** or a
**Worker** (subagent). Read your initial prompt to detect which you are.

**Role detection**
- If your initial prompt contains "You are a Worker agent assigned to ticket #N"
  → you are a **Worker**. Skip to the Worker section below.
- Otherwise → you are the **Main Agent**. Follow the Main Agent section below.

### Main Agent

You are a project-management companion to the supervisor. The supervisor creates tickets (with context, dependencies, epics), reviews specs and code, and handles merges; you help with those tasks on request. Workers are dispatched by `apm work` or the web UI — not by you. Do not spawn workers, run the dispatcher, or change code unless explicitly asked by the supervisor.

**Supervisor-only transitions.** The following state changes are reserved for the supervisor — do not run them even when the state machine allows it, and even when you just created the ticket:

- `new → groomed` — grooming is the supervisor's review gate; leave new tickets in `new` after creation
- `specd → ready` and `specd → ammend` — spec acceptance is a supervisor review
- `implemented → ready` / `implemented → ammend` / `implemented → closed` — implementation acceptance is a supervisor review
- `blocked → ready` — unblocking requires the supervisor's answer
- Any `apm epic close` — epic PRs are opened by the supervisor

Transitions you *may* initiate for your own tickets: `new → closed` (cancel a ticket you just created in error), and any state change the workflow marks `actionable = ["agent"]` when you are the assigned agent.

**Override.** The supervisor can ask you to perform any supervisor-only transition explicitly. If they do, run it and note in your response that you are acting at their direction. The exclusion list above applies only to actions you initiate on your own.

### Worker

You have been assigned a single ticket. Implement it, run tests, and mark it
implemented. Do not spawn further workers or act as delegator. If blocked by a
capability limitation (not a missing decision), see `apm.worker.md` →
**Capability limitations** for the clean exit procedure.

## Ticket format

Tickets are Markdown files with TOML frontmatter (between `+++` delimiters):

```toml
id = 1
title = "Short title"
state = "new"
branch = "ticket/0001-short-title"
author = "agent-name"
created_at = "2026-01-01T00:00Z"
```

Body sections (`## Spec` required):
- `### Problem` — what is broken or missing
- `### Acceptance criteria` — checkbox list, each independently testable
- `### Out of scope` — explicit exclusions
- `### Approach` — implementation plan
- `## History` — auto-managed transition log

## Development workflow

1. Read the relevant spec files before implementing anything
2. Make the minimal change that satisfies the acceptance criteria
3. Add or update tests — all acceptance criteria should be covered
4. Run your project's test suite — all tests must pass before calling `apm state <id> implemented`

## Identity

Generate a unique session name at the start of every session. Use a fixed
string — do not use `$()` substitution inline, as it triggers permission
prompts. Pick a name of the form `claude-MMDD-HHMM-XXXX` (e.g.
`claude-0325-1430-a3f9`) and export it before running any apm command:

```bash
export APM_AGENT_NAME=claude-0325-1430-a3f9
```

Hold the same name for the entire session. Do not regenerate mid-session.

Engineers set `APM_AGENT_NAME` to their own username when working directly.

## MAIN WORKTREE RULE

**Never run `git checkout` in the main working directory.**

The main directory is always on `main`. This is a hard rule — breaking it
confuses the user and corrupts the working state.

All branch work — spec editing, code changes, everything — happens inside a
**permanent git worktree** provisioned by `apm state <id> in_design` or
`apm start <id>`. Once you have a worktree path, use `git -C <worktree-path>`
to run git commands there without leaving your current directory.

## Startup

1. `apm sync` — refresh local cache from all `ticket/*` branches
2. `apm next --json` — find the highest-priority ticket you can act on now
3. `apm list --state in_progress` — check for in-progress tickets (resume if any match your agent name)

If `apm next` returns null and you have no in-progress tickets, there is nothing
to do. Report back to the supervisor.

## Working a ticket

The ticket's state determines what to do next:

**state = `groomed`** — write the spec:
1. `apm show <id>` — read the full ticket
2. `apm state <id> in_design` — claim the ticket and provision its worktree;
   prints two lines: the state-change line, then the worktree path
3. Write each spec section using `apm spec` (each `--set` auto-commits to the
   ticket branch; no manual `git add`/`git commit` needed). Use `--set` only
   when the section is empty or contains just the initial placeholder; use
   `--append` (or `--add-task` for checkbox sections) when the section
   already has content you must preserve.
   ```bash
   apm spec <id> --section Problem --set "..."
   apm spec <id> --section "Acceptance criteria" --set "- [ ] ..."
   apm spec <id> --section "Out of scope" --set "..."
   apm spec <id> --section Approach --set "..."
   ```
   Note: `apm new` opens `$EDITOR` after creating a ticket. Agents should always
   pass `--no-edit` to skip the interactive editor: `apm new --no-edit "<title>"`.
4. If blocked on an ambiguity: write the question in `### Open questions` with
   `apm spec <id> --section "Open questions" --append "..."` (use `--append`
   to preserve any earlier questions), then `apm state <id> question`
5. `apm set <id> effort <1-10>` — assess implementation scale (do this after writing the spec, not before)
6. `apm set <id> risk <1-10>` — assess technical risk
7. `apm state <id> specd` — submit spec for supervisor review

**state = `ammend`** — revise the spec:
1. `apm show <id>` — read the Amendment requests carefully
2. `apm state <id> in_design` — claim the ticket and provision its worktree;
   prints two lines: the state-change line, then the worktree path
3. Address each item using `apm spec` to update sections. **Use `--append`,
   not `--set`, when adding to a section that already has content** (most
   sections by this point will). `--set` overwrites and would erase prior
   decisions, including checked-off amendment items the supervisor expects
   to see preserved. For `Acceptance criteria` and similar checkbox sections
   use `--add-task` to add a new item. Mark each amendment off with
   `apm spec <id> --section "Amendment requests" --mark "..."`. Each `apm spec`
   call auto-commits; no manual `git add`/`git commit` needed.
4. `apm state <id> specd` — resubmit only when all amendment boxes are checked

**state = `in_design`** — spec is actively being written or revised:
The ticket is claimed by another agent. Do not pick up an `in_design` ticket
on your own. If the supervisor asks you to take it over, follow the "When
asked to take over another agent's ticket" section below.

**state = `ready`** — implement:
1. `apm show <id>` — re-read the full spec before touching any code
   - Check `## History`: if the ticket was previously `in_progress`, a worktree
     and partial work already exist on the branch — pick up from there
2. `apm start <id>` — claims the ticket (sets `agent` = your name, state →
   `in_progress`), provisions or reuses the permanent worktree; prints its path

   To hand the ticket to an autonomous background worker instead:
   ```
   apm start --spawn <id>          # worker runs under project allow list
   apm start --spawn -P <id>       # worker runs with --dangerously-skip-permissions
   ```
   The worker provisions the worktree, implements, and transitions to implemented autonomously.
   The supervisor gets control back immediately.
3. Commit all code changes to the ticket branch inside the worktree:
   ```bash
   # apm start prints the worktree path — use git -C to work there
   wt=<path printed by apm start>
   git -C "$wt" add <files>
   git -C "$wt" commit -m "<message>"
   ```
4. Update `## Spec` if the approach evolves during implementation
5. `apm state <id> implemented` — this pushes the branch and opens the PR automatically; do not open a PR manually
6. If blocked mid-implementation (missing information, upstream decision needed):
   write the question in `### Open questions` with `apm spec <id> --section
   "Open questions" --append "..."`, commit it, then `apm state <id> blocked`
   **do not use `apm state <id> ready`**, that transition no longer exists
   from `in_progress`

**state = `blocked`** — implementation is blocked on a supervisor decision:
1. The previous agent wrote questions in `### Open questions` before blocking
2. Wait — this state is actionable by supervisor only
3. Once the supervisor transitions to `ready`, pick it up with `apm start <id>`
   and continue from the existing worktree/branch

## When asked to take over another agent's ticket

`apm assign` is a supervisor action. Do not run it on your own — only when the
supervisor explicitly asks you to take a ticket over. When they do:

1. `apm show <id>` — read the full ticket including history
2. `apm assign <id> <your-username>` — reassign ownership to yourself
3. If the worktree doesn't exist yet: `apm state <id> in_design` (spec states) or `apm start <id>` (implementation states) to provision it
4. Continue from where the previous agent left off
5. Do not discard or overwrite previous spec work or open questions

## Spec quality bar

Every spec must have all four required subsections before moving to `specd`:

- **Problem** — what is broken or missing, and why it matters
- **Acceptance criteria** — checkboxes; each one independently testable
- **Out of scope** — explicit list of what this ticket does not cover
- **Approach** — how the implementation will work

Do not check acceptance criteria boxes until the implementation is verified.

#### Subsection markers

Within long sections such as `### Approach` or `### Acceptance criteria`,
use `####` headings as named editing handles. This lets `apm spec <id>
--section "Approach > Phase 2"` target a subsection without overwriting the
whole section.

## Spec discipline

- Set `effort` and `risk` after writing the spec, before transitioning to `specd` — you only have enough context once the spec is complete
- Do not proceed on assumptions: write questions, change state to `question`
- Once a question is answered, reflect the decision in `### Approach`
- Do not delete answered questions or checked amendment items — they are the
  decision record. Use `apm spec --append` (or `--add-task` for checkbox
  sections) to add new content to a non-empty section; reserve `--set` for
  sections that are still empty or contain only the initial placeholder.

## Branch discipline

Every ticket has a single branch — `ticket/<id>-<slug>` — for its entire
lifecycle, created automatically by `apm new`. Never create or rename branches
manually.

- All spec edits and code changes go to `ticket/<id>-<slug>` via the worktree
- `apm start <id>` provisions the permanent worktree; use `git -C <wt>` to commit
- APM manages frontmatter and `## History` — never edit them directly
- Do not delete the ticket branch until the ticket is `closed` — APM uses
  branch presence to detect merge state

## One ticket per agent process

Work one ticket at a time per agent process. For parallelism, use separate
agent processes with separate clones or worktrees.

## Shell discipline

Claude Code's permission system matches the **start** of the command string.
Compound calls defeat this matching and generate permission prompts. Keep each
Bash call to a single operation.

**Do not chain commands:**
```bash
# Wrong — && chains defeat allow-list matching
apm sync && apm list --state ready

# Right — one call per operation
apm sync
apm list --state ready
```

**Do not use `$()` subshells:**
```bash
# Wrong — triggers "command substitution" security check
apm spec 1234 --section Problem --set "$(cat /tmp/problem.md)"

# Right — write content with the Write tool, then reference by file
apm spec 1234 --section Problem --set-file /tmp/problem.md
```

**Do not use background jobs (`&`):**
```bash
# Wrong — & defeats pattern matching
apm state 1234 implemented & apm state 5678 implemented & wait

# Right — sequential calls
apm state 1234 implemented
apm state 5678 implemented
```

**Use `git -C` for all git operations in worktrees:**
```bash
# Wrong — cd && git triggers "bare repository attack" check
cd "$wt" && git add .

# Right
git -C "$wt" add <files>
```

**Use `bash -c` for multi-step commands that must share a directory:**
```bash
# Right — single bash call, matches Bash(bash *)
bash -c "cd $wt && <your-test-command> 2>&1"
```

## Creating tickets

Every `apm new` invocation must seed the ticket's Problem section with
enough context that a downstream worker can pick it up without having to
re-derive the analysis. A bare title is not enough — it forces the next
agent to re-investigate the repo, and the supervisor loses the reasoning
that motivated the ticket.

Always pass `--context` (and `--no-edit`, to skip the interactive editor):

```bash
apm new --no-edit --context "<problem statement with concrete usage sites, measurements, or constraints>" "<title>"
```

The `--context` string is written into `### Problem` verbatim. Include
whatever made you file the ticket: the failing test, the grep results,
the measured regression, the file:line usage sites, the upstream decision
this depends on. If the context is too long to fit in a shell argument,
create the ticket with a short `--context` placeholder, then replace the
Problem section with `apm spec <id> --section Problem --set-file <path>`.

If you only have a title and no usable context yet, the ticket is not
ready to be filed — leave a note for the supervisor instead of creating
a skeleton ticket.

## Side tickets

When you notice an out-of-scope issue during implementation, capture it without interrupting your current work:

```bash
apm new --side-note "Brief title" --context "What you observed and why it matters"
```

Then immediately resume the current ticket. The supervisor will triage the side ticket separately.