pma
Maintain many repositories from one place.
If you keep dozens of small projects, the work is not hard, it is scattered. Each repository has a TODO.md, failing CI, outdated dependencies and a dirty working tree, and finding out means opening all of them. pma reads them all in one pass, ranks every task across every project in one list, and can hand a task to a coding agent in a throwaway worktree. You read the diff, and pma commits and publishes it.
Scanning 95 repositories takes about 15 seconds.
Nothing is published without you. An agent runs with no push credentials, pma runs the project's tests itself rather than trusting the agent's report, and every change waits in a worktree until you approve it.
Features
One view of everything
-
Every task in every project in one Eisenhower matrix, ranked by project importance and item priority.
-
Failing CI, outdated dependencies, idle repositories and dirty working trees appear as tasks beside the written ones.
-
A terminal browser (
pma tui), a per-project health ranking (pma status), and an oldest-first list to prune (pma stale). -
Portfolio notes that belong to no single project.
Tasks in plain Markdown
-
A root
TODO.mdper repository is the only task file. Nothing to keep in step, and no lock-in: removepmaand the files still read. -
pma lintchecks the format.pma pruneremoves what is finished. -
pma syncmirrorsCriticalitems to GitHub Issues and ticks items whose issue was closed.
Agents, with the brakes on
-
claude,opencodeandompcome as templates. Any coding agent with a headless mode is a record you edit, not a code change. -
Each run gets its own worktree of the remote default branch, so your dirty checkout is never touched.
-
The agent runs without push credentials.
pmaruns the project's test command itself, before and after, and reports both ends. -
Every run records the diff, the test result, the cost, the duration and the paths it touched. A run that changed a file its task had no business changing is flagged.
-
Limits you set: agents at once, dollars per run, dollars per batch, minutes per run.
-
pma reportsays what dispatching has produced: first-attempt passes, reworks, merges, cost, review time.
Which model, where
-
A preset names a worker, a model and the arguments that configure it:
pma preset set omp-luna-high omp gpt-5.6-luna --thinking high. -
pmaruns agents and is not an API client. Provider keys stay the agent's, reached through its own configuration, andpmastores none of them. -
A routing policy decides the worker, the model and how much autonomy per kind of task. It is a document you propose, activate, and can replay over past runs to see what it would have changed.
Repeating work
-
A campaign applies one task definition across many repositories, each verified on its own.
-
A workflow is a graph of agents over a project: review, then validate the review, then fix what it confirmed. Written as JSON or as a script, and costed before it runs.
-
pma workflow runprints what it would run, the worker, the model and a ceiling, and spends nothing until you approve it.
Install
From a clone: make install.
Requirements:
-
macOS or Linux. Rust 1.89 or later, and a C compiler: SQLite is compiled in.
-
gitonPATH. -
A coding agent for
pma dispatch:claude,opencodeoromp, logged in or holding its own provider key. -
gh, authenticated, for CI status, for opening pull requests and forpma sync. Without it CI reads as unknown, andpma scan --offlineskips GitHub on purpose.
TODO.md format
-
-
-
-
The rules, which pma lint checks:
-
The first non-blank line is
# TODO, and there is no second#heading. -
Priority comes from the enclosing
##section:Critical,High,MediumorLow, spelled exactly, at most one of each. Other##sections are allowed and ignored. -
An item is one line,
- [ ] textor- [x] text. No other spelling of the checkbox. -
Indented lines under an item are its description, carried to the agent verbatim.
-
A
###heading groups the items below it, until the next heading. -
Trailing tokens, read from the end of the line:
#tag,due:YYYY-MM-DD, andgh:Nfor a linked issue. A token-shaped word earlier in the line is text. -
#urgentmakes an item urgent whatever its date.#agentmarks one an agent may take.#manualkeeps agents off it entirely. -
A finished item is ticked where it stands.
pma pruneremoves it.
Two open items with the same text, or two items with the same gh:N, are errors. An item is identified by its text until an issue number is written into it.
Commands
Projects and tasks:
matrix, status and tui read the last scan. They do not rescan.
Agents, models and presets:
Highest wins: the -a and -m flags, then -p <preset>, then an applied route, then the default preset.
Dispatch, review, ship:
A target naming one task fails if that task cannot run. A target naming many passes over each with its reason, and dispatches the rest.
Each run gets a worktree of the remote default branch under ~/.config/pma/worktrees, on a pma/ branch. The item must be open in the remote TODO.md, so commit and push before dispatching. Set the test command with pma config projects.myproject.verify "make check", or let it be detected. publish is pr by default; pma config publish push pushes to the default branch instead.
Repeating work:
GitHub Issues:
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. Edits to TODO.md are left uncommitted, for you to read first.
Where things live
-
The database is
~/.config/pma/projects.db, or$PMA_HOME/projects.db. That directory can be a git repository, which is how two machines share it. -
Worktrees sit under the same directory and are removed when a run ships or is rejected.
-
Settings live in the database rather than a file.
pma configlists them,pma config <key> <value>sets one, and--resetclears one.
One command that runs agents or edits worktrees runs at a time. dispatch, ship, workflow run and review --reject take a lock and name the process holding it. Reading commands run alongside.
Development
Licence
MIT.