{"id":48634858,"url":"https://github.com/philippepascal/apm","last_synced_at":"2026-05-28T21:01:02.970Z","repository":{"id":349933429,"uuid":"1192250074","full_name":"philippepascal/apm","owner":"philippepascal","description":"Git-native project manager for running AI coding agents in parallel,   isolated by design. Self-hosted, no SaaS — the repo is the PM tool.","archived":false,"fork":false,"pushed_at":"2026-05-24T22:04:20.000Z","size":8040,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-25T00:32:47.968Z","etag":null,"topics":["ai-agents","autonomous-agents","claude-code","cli","developer-tools","git","project-management","rust","self-hosted","workflow"],"latest_commit_sha":null,"homepage":"https://philippepascal.com/lab/apm","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/philippepascal.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":".github/CLA.md"}},"created_at":"2026-03-26T03:10:51.000Z","updated_at":"2026-05-24T22:04:22.000Z","dependencies_parsed_at":null,"dependency_job_id":"3d30156e-8077-4845-a926-e3b5c835f566","html_url":"https://github.com/philippepascal/apm","commit_stats":null,"previous_names":["philippepascal/apm"],"tags_count":33,"template":false,"template_full_name":null,"purl":"pkg:github/philippepascal/apm","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/philippepascal%2Fapm","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/philippepascal%2Fapm/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/philippepascal%2Fapm/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/philippepascal%2Fapm/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/philippepascal","download_url":"https://codeload.github.com/philippepascal/apm/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/philippepascal%2Fapm/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33597988,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-05-28T02:00:06.440Z","response_time":99,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ai-agents","autonomous-agents","claude-code","cli","developer-tools","git","project-management","rust","self-hosted","workflow"],"created_at":"2026-04-09T08:58:34.264Z","updated_at":"2026-05-28T21:01:02.935Z","avatar_url":"https://github.com/philippepascal.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# APM — Agent Project Manager\n\n**A git-native project manager for running AI coding agents in parallel, isolated by design.**\n\n[![Crates.io](https://img.shields.io/crates/v/apm-cli.svg)](https://crates.io/crates/apm-cli)\n[![License: BSL-1.1](https://img.shields.io/badge/license-BSL--1.1-blue.svg)](LICENSE)\n[![CI](https://github.com/philippepascal/apm/actions/workflows/release.yml/badge.svg)](https://github.com/philippepascal/apm/actions/workflows/release.yml)\n\nSpawn four Claude Code workers on one repo and they work simultaneously,\nwithout stepping on each other. The whole tool is structured so multi-agent\nwork is safe by default. No database. No SaaS. No hosting — the repo *is*\nthe PM tool.\n\n\u003c!-- demo GIF goes here — see D4 in s/promo/tracker.md --\u003e\n\u003c!-- ![demo](docs/demo.gif) --\u003e\n\n## Why this exists\n\nOnce you have a coding agent that reliably ships tickets, the bottleneck\nstops being the agent and starts being the PM tool. Issue trackers assume\na human in a browser. They don't map cleanly to branches, they hide state\nbehind clicks an agent can't perform, and two agents picking the same\nticket will trip over each other the moment they start coding.\n\nAPM treats the PM tool as a thin layer over git:\n\n- Tickets are Markdown files on per-ticket branches (`ticket/\u003cid\u003e-\u003cslug\u003e`).\n  State is TOML frontmatter. History is `git log`.\n- Workers are dispatched by `apm work` (a CLI loop) or the web UI\n  dispatcher, which atomically claims a ticket and provisions a dedicated\n  worktree per worker. Two agents can't claim the same ticket; their\n  changes can't collide. (`apm start \u003cid\u003e` does the same for one-off\n  manual claims.)\n- The workflow is a state machine in config — swap in your own states,\n  transitions, and completion strategies.\n- Run N workers in parallel at a cap you set. Plug in Claude Code,\n  Codex, or anything else with a CLI.\n\n## At a glance\n\n| | APM | Linear / Jira | GitHub Issues |\n|---|---|---|---|\n| Storage | Your git repo | SaaS | GitHub |\n| Works offline | Yes | No | Partial |\n| CLI-first | Yes | No | Partial |\n| Agent-dispatchable | Yes, native | Indirect | Indirect |\n| Parallel worktree isolation | Built-in | N/A | N/A |\n| Cost | Free, self-hosted | Per-seat SaaS | Free w/ GitHub |\n| Lock-in | None — just git | High | GitHub |\n\n## The workflow\n\nAPM provides two binaries: `apm` (CLI) and `apm-server` (web UI). The UI replicates nearly all command-line functionality and includes its own agent dispatcher loop. Set the `EDITOR` environment variable to your preferred editor — `apm review` and other interactive commands use it to open tickets.\n\nTickets are Markdown files with TOML frontmatter, stored on per-ticket branches. Each ticket follows a state machine through its lifecycle:\n\n```\nnew → groomed → in_design → specd → ready → in_progress → implemented → closed\n                                 ↗ ammend ↗              ↗ blocked\n                              question\n```\n\nSide paths handle amendments, open questions, and blocks. Supervisors control all transitions except the ones agents perform within their assigned phase.\n\n### Happy path: one ticket from idea to merged\n\n1. **Supervisor creates a ticket** — `apm new \"Add rate limiting to API\"`. APM creates a branch `ticket/a1b2c3d4-add-rate-limiting-to-api` with a Markdown skeleton.\n2. **Supervisor grooms and assigns it** — adds context, sets priority, moves it to `groomed` with `apm review a1b2`, and assigns it with `apm assign a1b2 alice`. Tickets without an owner are never auto-dispatched.\n3. **Spec agent picks it up** — the dispatch loop (`apm work`) picks the highest-priority owned ticket. The agent writes the Problem, Acceptance criteria, Out of scope, and Approach sections, sets effort/risk estimates, and submits with `apm state a1b2 specd`.\n4. **Supervisor reviews the spec** — `apm review a1b2` opens the ticket and offers transitions: approve (moves to `ready`) or request amendments (moves to `ammend` with checkboxes). If amended, the agent addresses each item and resubmits.\n5. **Implementation agent picks it up** — `apm start a1b2` claims the ticket, provisions a worktree, and merges the latest default branch in. The agent codes, tests, and commits inside the worktree.\n6. **Agent marks it done** — `apm state a1b2 implemented` triggers the completion strategy: opens a PR, merges into the target branch, or merges into the epic branch.\n7. **Supervisor reviews and closes** — `apm review a1b2` after the PR is merged (or the merge completes). Alternatively, `apm sync` auto-detects merged branches and transitions tickets to `closed`. `apm clean` removes the worktree and local branches.\n\nThe whole cycle runs without the supervisor touching any code or the agent touching the main branch.\n\n## Install\n\n### Homebrew (macOS)\n\n```bash\nbrew install philippepascal/tap/apm\n```\n\n### Quick install\n\nThe install script detects your platform, downloads the latest release, verifies checksums, and adds the binaries to your `PATH`:\n\n```bash\ncurl -fsSL https://raw.githubusercontent.com/philippepascal/apm/main/scripts/install.sh | sh\n```\n\nTo uninstall:\n\n```bash\ncurl -fsSL https://raw.githubusercontent.com/philippepascal/apm/main/scripts/uninstall.sh | sh\n```\n\nPre-built binaries are available for macOS (Apple Silicon) and Linux (x86_64).\n\n### From source\n\nRequires Rust and Node.js 20+:\n\n```bash\ngit clone https://github.com/philippepascal/apm.git\ncd apm\n(cd apm-ui \u0026\u0026 npm ci \u0026\u0026 npm run build)\ncargo install --path apm\ncargo install --path apm-server\n```\n\n## Try the demo\n\nThe [apm-demo](https://github.com/philippepascal/apm-demo) repo is a small Rust CLI project with 14 pre-populated tickets across all workflow states, an epic, cross-ticket dependencies, and an open amendment request. Clone it and explore:\n\n```bash\ngit clone https://github.com/philippepascal/apm-demo.git\ncd apm-demo\ngit fetch --all\napm list\napm-server   # browse at http://localhost:3000\n```\n\nSince apm-demo is read-only on GitHub, commands that push (state transitions, `apm start`, `apm work`) will fail. To get a fully functional copy you can write to, run `scripts/create-demo.sh` from the APM repo — it creates the demo under your own GitHub account.\n\n## Getting started\n\n```bash\n# Initialize in an existing git repo\napm init\n\n# Creates .apm/ with config.toml, workflow.toml, ticket.toml, and agent instructions\n# Edit them to match your project's needs\n\n# Start the web UI (defaults to http://localhost:3000)\napm-server\n```\n\n## Working with tickets\n\n### Creating and managing tickets\n\n```bash\n# Create a ticket\napm new \"Fix login timeout on slow connections\"\n\n# List tickets\napm list\napm list --state ready\napm list --mine\n\n# Show full ticket with spec\napm show \u003cid\u003e\n\n# Set priority (higher = more urgent)\napm set \u003cid\u003e priority 10\n\n# Review a ticket — opens it and presents available transitions\napm review \u003cid\u003e\n\n# Transition directly (lower-level alternative to review)\napm state \u003cid\u003e ready\n\n# Force-close a ticket from any state\napm close \u003cid\u003e --reason \"Superseded by #abcd1234\"\n```\n\n### Epics\n\nGroup related tickets under an epic branch:\n\n```bash\n# Create an epic\napm epic new \"Auth system rewrite\"\n\n# Create tickets targeting the epic\napm new \"Migrate session storage\" --epic \u003cepic-id\u003e\n\n# List epics with ticket counts and derived state\napm epic list\n\n# Show epic details\napm epic show \u003cepic-id\u003e\n\n# Set max concurrent workers for an epic\napm epic set \u003cepic-id\u003e max_workers 2\n\n# When all tickets are done, open a PR from epic branch to main\napm epic close \u003cepic-id\u003e\n```\n\nWhen a ticket reaches `implemented`, the completion strategy determines what happens next:\n\n- **`pr`** — push the branch and open a pull request\n- **`merge`** — merge directly into the target branch\n- **`pr_or_epic_merge`** — open a PR for standalone tickets, merge into the epic branch for epic tickets (default)\n- **`pull`** — pull the latest default branch into the ticket branch\n- **`none`** — just push the branch, handle the rest manually\n\n| Strategy | Composes dependencies? | Notes |\n|---|---|---|\n| `pr_or_epic_merge` | Yes, within an epic | Default. Same strategy yields PR-on-main and merge-to-epic depending on `target_branch`. |\n| `merge` | Yes, when ticket and deps share `target_branch` | Lands directly on the target. Skips supervisor review on main. |\n| `pr` | No | State→`implemented` fires when the PR is *opened*, not when it merges. Downstream tickets can start before upstream code lands. |\n| `none` | No | Nothing lands automatically; downstream tickets cannot rely on upstream code being present. |\n\nSee `docs/strategy-and-dependencies.md` for the full dependency rules and strategy rationale.\n\nStrategies are configured per-transition in `workflow.toml`.\n\n## Ticket ownership\n\nEvery ticket has two identity fields:\n\n- **`author`** — set when the ticket is created; immutable. Records who created it.\n- **`owner`** — who is responsible for the ticket. Dispatchers (`apm work`, `apm start --next`, the UI loop) only pick up tickets whose `owner` matches the current user's identity. Tickets with no owner are never auto-dispatched.\n\nAssign a ticket before dispatching:\n\n    apm assign \u003cid\u003e alice        # assign to alice\n    apm assign \u003cid\u003e -            # clear the owner field\n\nBulk-assign all non-closed tickets in an epic at once:\n\n    apm epic set \u003cepic-id\u003e owner alice\n\nTo filter the list by owner:\n\n    apm list --owner alice       # tickets owned by alice\n    apm list --mine              # tickets authored by the current user\n\n### Identity setup\n\nAPM resolves the current user's identity in two modes:\n\n**Config mode** (no `[git_host]` in `config.toml`): set `username` in `.apm/local.toml`:\n\n    # .apm/local.toml\n    username = \"alice\"\n\n**GitHub mode** (`[git_host]` with `provider = \"github\"` in `config.toml`): identity is resolved from the `gh` CLI (if installed and authenticated) or from a GitHub token. No `local.toml` entry is needed — the GitHub login is used automatically.\n\n## Agent workflow\n\nAgents work autonomously through the spec and implementation phases. The supervisor dispatches them and reviews their output.\n\nWhen a worker is spawned, APM automatically feeds it the right instruction file for the ticket's current state. By default, `apm init` creates two instruction files — `.apm/apm.spec-writer.md` for the spec phase and `.apm/apm.worker.md` for implementation. These are configured per-state in `workflow.toml` via the `instructions` field, and can be overridden per worker profile in `config.toml`.\n\nThe agent runtime itself is also configurable. The default is `claude --print`, but you can switch to any CLI agent by setting `command` and `args` under `[workers]` in `config.toml`. For example, to use Codex: `command = \"codex\"`, `args = [\"--quiet\"]`. You can also define named worker profiles under `[worker_profiles.\u003cname\u003e]` with their own `command`, `args`, `model`, `env`, and `instructions` — useful for running different agents for different phases or tasks.\n\n### Dispatching agents\n\n```bash\n# Spawn a worker on the next actionable ticket\napm start --next --spawn\n\n# Run a dispatch loop (spawns workers up to max_concurrent) until queue of actionable tickets is empty\napm work\n\n# Run as a daemon — keeps dispatching as tickets become actionable\napm work --daemon\n```\n\nDispatchers only pick up tickets whose `owner` matches the current user's identity. Assign tickets with `apm assign` before running `apm work`.\n\n## Syncing and housekeeping\n\n```bash\n# Sync with remote — fetches ticket branches, detects merges, closes merged tickets\napm sync\n\n# Archive closed tickets to archive/tickets/\napm archive\napm archive --dry-run --older-than 30d\n\n# Clean up worktrees and branches for closed tickets\napm clean\napm clean --branches          # also remove local branches\napm clean --remote --older-than 30d  # also remove old remote branches\n```\n\nWith `aggressive = true` in config, most commands auto-sync before running.\n\n## Configuration\n\nConfiguration is split across files in `.apm/`:\n\n| File | Purpose |\n|------|---------|\n| `config.toml` | Project settings, sync, workers, server |\n| `workflow.toml` | State machine: states, transitions, completion strategies |\n| `ticket.toml` | Ticket structure: sections, types, placeholders |\n| `epics.toml` | Per-epic settings (e.g. `max_workers`) — untracked |\n| `local.toml` | Per-user settings (username, worker overrides) — untracked |\n| `agents.md` | Agent instructions: roles, workflow rules, shell discipline |\n| `apm.spec-writer.md` | Instructions fed to agents during the spec phase |\n| `apm.worker.md` | Instructions fed to agents during the implementation phase |\n\nThe workflow, ticket structure, completion strategies, and agent instructions are all fully customizable.\n\n## How agents work\n\n### Spec phase\n\nAgents pick up `groomed` tickets and write structured specs:\n\n```bash\n# Claim ticket for design\napm state \u003cid\u003e in_design\n\n# Write spec sections\napm spec \u003cid\u003e --section Problem --set-file /tmp/problem.md\napm spec \u003cid\u003e --section \"Acceptance criteria\" --set \"- [ ] Timeout is configurable...\"\napm spec \u003cid\u003e --section Approach --set \"Add a timeout_ms parameter to...\"\n\n# Set effort and risk estimates\napm set \u003cid\u003e effort 3\napm set \u003cid\u003e risk 2\n\n# Submit for supervisor review\napm state \u003cid\u003e specd\n```\n\nThe supervisor reviews with `apm review \u003cid\u003e`, which opens the spec and presents transition options: approve (moves to `ready`) or request amendments (moves to `ammend`). Specs have four required sections: Problem, Acceptance criteria, Out of scope, and Approach.\n\n### Implementation phase\n\n```bash\n# Claim a ticket — provisions a worktree, sets state to in_progress\napm start \u003cid\u003e\n# Prints the worktree path, e.g. ../myproject--worktrees/ticket-0001-fix-login-timeout\n\n# Work in the worktree (never checkout in the main directory)\ngit -C \u003cworktree-path\u003e add src/auth.rs\ngit -C \u003cworktree-path\u003e commit -m \"Increase default timeout to 30s\"\n\n# Mark as done — pushes branch and opens PR (depending on completion strategy)\napm state \u003cid\u003e implemented\n```\n\n## Going further\n\nAPM has more features than the walkthrough above covers. Here's a quick map:\n\n- **TLS / HTTPS** — `apm-server` has built-in TLS via `--tls acme` (Let's Encrypt) or `--tls self-signed`. See `apm-server --help` and [docs/external-tls-setup.md](docs/external-tls-setup.md).\n- **Authentication** — WebAuthn-based login for the web UI. Register users with `apm register`, manage sessions with `apm sessions` and `apm revoke`.\n- **GitHub integration** — Set `[git_host] provider = \"github\"` in `config.toml` to enable automatic PR creation on `implemented`, collaborator sync, and GitHub-based identity resolution. Configure a token in `.apm/local.toml`.\n- **Collaborators** — List valid usernames in `project.collaborators` in `config.toml`. When set, `apm assign` validates the target user against this list (or against GitHub collaborators when GitHub mode is enabled).\n- **Docker workers** — Run agents in sandboxed containers. Pass `--with-docker` to `apm init` to generate a Dockerfile, then configure `container` in `config.toml`. See [docs/docker-workers.md](docs/docker-workers.md).\n- **Ticket dependencies** — `apm set \u003cid\u003e depends_on \u003cother-id\u003e` blocks a ticket until its dependency reaches a configured gate state. The dispatcher respects these edges automatically.\n- **Worker profiles** — Define named profiles under `[worker_profiles.\u003cname\u003e]` in `config.toml` with their own `command`, `args`, `model`, `env`, and `instructions`. Assign profiles to transitions in `workflow.toml` to use different agents for different phases.\n- **Config validation** — `apm validate` checks your config and full ticket integrity: config parse errors, branch-field mismatches, merged-but-open branches, missing worktrees, and more.\n- **Logging** — APM logs every command to a platform-specific log file. The web UI includes a live log viewer.\n- **Server options** — `apm-server --port \u003cN\u003e`, `--bind \u003caddr\u003e` to customize the listener. The `[server]` section in `config.toml` holds persistent defaults.\n- **Side tickets** — `apm new --side-note \"title\" --context \"what you noticed\"` lets agents capture out-of-scope issues without interrupting their current work.\n- **Inline editing** — `apm edit \u003cid\u003e` opens a ticket directly in `$EDITOR` for quick manual changes.\n- **Aggressive sync** — Set `sync.aggressive = true` in `config.toml` to auto-fetch and push on every command. Most multi-user setups should enable this.\n\nFor the full command reference, see [docs/commands.md](docs/commands.md).\n\n## License\n\n[Business Source License 1.1](LICENSE) — free to use, modify, and deploy. The one restriction: you may not offer APM as a hosted service. Converts to Apache 2.0 on 2030-04-05.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fphilippepascal%2Fapm","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fphilippepascal%2Fapm","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fphilippepascal%2Fapm/lists"}