# pma
Maintenance across many repositories from one place.
Status: every stage of the [design](docs/dev/design.md): lint, scan, matrix, health, agent dispatch with review and ship, Issues sync, notes, the deps signal, and a TUI. `claude`, `opencode` and `omp` come as worker templates; any coding agent with a headless mode is a record rather than a code change.
Workflows -- a graph of agents over a project, specified in JSON or a Rhai script -- are in progress: a document is read, costed and stored, and a pass runs every node a rule decides. A node an agent decides is planned and priced, and spends nothing until you approve it. Design: [workflows.md](docs/dev/workflows.md).
## Install
```sh
cargo install pma
```
From a clone: `make install`.
Requirements:
- macOS or Linux. The database location is derived from `HOME`.
- Rust 1.89 or later, and a C compiler: SQLite is compiled in.
- `git` on `PATH`.
- `gh`, authenticated, for CI status. Without it, CI is recorded as unknown and left out of health; `pma scan --offline` skips GitHub on purpose. Also for fix-CI dispatch, `publish = pr`, and `pma sync`.
- A coding agent for `pma dispatch`: `claude`, `opencode` or `omp`, logged in or holding its own provider key. `pma` runs agents and is not an API client, so `ANTHROPIC_API_KEY`, `OPENAI_API_KEY` and `OPENROUTER_API_KEY` are inherited by the agent from your session; what it strips is what lets a child push.
## TODO.md format
```markdown
# TODO
## Critical
- [ ] segfault on empty input #bug gh:42
## High
- [ ] support ggml 0.9 due:2026-10-01
## Medium
## Low
- [x] drop python 3.9
```
The section gives the priority. A finished item is ticked where it stands; `pma prune` removes finished items. A `###` heading inside a section groups the items below it. Trailing `#tag`, `due:YYYY-MM-DD` and `gh:N` (a linked issue) are optional. The full rules are in the [design](docs/dev/design.md#todomd-format-v2).
## Commands
```sh
pma lint # ./TODO.md
pma lint ~/projects/*/ # every project; a directory means its TODO.md
pma prune ~/projects/*/ # plan: finished items and `## Done` to remove; --apply
```
Output is `path:line: severity: message`. Exit status is 1 when any file has an error or cannot be read. Warnings alone exit 0.
```sh
pma root add ~/projects/ # git repos directly under it are projects
pma tier topproj 1 # 1 (most important) to 5, or none
pma scan # TODO.md, git state, CI via gh; about 15s for 95 repos
pma scan --offline topproj # one project, without GitHub
pma scan --deps # also count outdated cargo, uv and go dependencies
pma matrix # tiered projects' tasks in the Eisenhower matrix
pma matrix -q q1 --all
pma status --explain # projects by health, with each signal's share
pma config # every setting; `pma config tiers.2 0.7`, `--reset`
pma tui # the matrix in the terminal; q quits
pma note add "move CI to reusable workflows" # portfolio notes; `pma note` lists
```
`matrix` and `status` read the last scan; they do not rescan. Only tiered projects appear in them.
```sh
pma dispatch cynn:31 # a TODO.md line from the last scan; or cynn:ci, cynn:deps
pma dispatch cynn:critical # every open item under ## Critical; or high, medium, low
pma dispatch cynn:q1 # every task the last matrix placed in that quadrant
pma dispatch cynn # the project's tasks, in a list with checkboxes
pma dispatch -a pi -m sonnet cynn:31 # this agent and model, not the configured ones
pma dispatch --auto -n 3 # the top 3 dispatchable tasks in the matrix
pma review # runs not yet shipped or rejected; settles merged PRs
pma review 4 # task, verify result, cost, summary, diff
pma review 4 --approve # or --reject, or --rework "feedback"
pma ship # commit, push or open a PR, remove worktrees
```
A target that names one task fails when that task cannot run. One that names many passes each over with its reason and dispatches the rest. `-a` and `-m` outrank `pma config agent`, `pma config model` and any applied route; without `-m` the agent picks its own model, and `pma config model` applies only to the agent it was set alongside.
Each run gets a worktree of the remote default branch under `~/.config/pma/worktrees`, so a dirty clone is never touched. The agent runs without push credentials. `pma` then runs the project's tests itself: set the command with `pma config projects.cynn.verify "make check"`, or let it be detected. Limits: `max_parallel`, `batch_budget`, `agent_budget`, `timeout`. `publish` is `pr` by default; `pma config publish push` pushes to the default branch instead. A run shipped as a PR stays `pr-open` until the PR is merged or closed, and its task is not dispatched again meanwhile.
```sh
pma agent # the workers; `pma agent show claude` prints one whole
pma preset set claude-haiku claude haiku
pma preset set omp-luna-high omp gpt-5.6-luna --thinking high
pma preset # every named worker, model and configuration
pma preset use omp-luna-high # the default; -p <name> uses one for a command
pma dispatch -p claude-haiku cynn:31
```
A preset names a worker, a model and the arguments that configure it. Effort is arguments rather than a field, because what expresses it differs per agent. Highest first: `-a` and `-m`, then `-p`, then an applied route, then `pma config preset`, then `pma config agent`.
```sh
pma workflow check lib.rhai # read a document and print its worst case
pma workflow propose lib.rhai # store it as a draft revision
pma workflow activate 1 # unless its worst case exceeds workflow_budget
pma workflow run review cynn --dry-run
pma workflow run review cynn -p claude-haiku
```
`dispatch`, `ship`, and `review --reject` or `--rework` hold a lock on `session.lock`, so only one of them runs at a time; an open task list holds it too. Other commands, including `pma review` to watch a batch, can run alongside. The agent may edit files and run the verify command; other shell commands are denied unless your Claude Code settings allow them. `pma ship` resumes after a failure without publishing twice.
```sh
pma sync # plan: issues to open, items to mark done
pma sync --apply topproj # carry it out for one project
```
Each `## Critical` item gets an issue labelled `pma:critical`, and `gh:N` is written into its line. An item whose issue is closed is ticked. TODO.md edits are left uncommitted; `scripts/commit_todo.py` commits them.
The database is `~/.config/pma/projects.db`, or `$PMA_HOME/projects.db`. Dates are compared as UTC calendar days.
## Development
```sh
make test # cargo test, then pytest on scripts/
make check # fmt check, clippy -D warnings, test
```