Skip to content
Projector
  • MIT licensed
  • Python 3.11+, zero dependencies
  • Claude Code + Codex

Project plans that
live in Git.

Projector gives every project a permanent home under docs/projects/, one command for people and coding agents, and review loops that carry a pull request to a clean head. No service, no account, no index to keep in sync.

pipx install git+https://github.com/ninjudd/projector.git
~/src/payments-service
$ project listnow:  payments                     in-progress  Ledger-backed paymentsnext:  payments/invoices            ready        Issue from the ledger  search-relevance             draft        Rank results by recencylater:  audit-log                    ready        Record every mutationcompleted:  adopt-projector              completed    Adopt Projector $ project status payments/invoices in-progressdocs/projects/payments/invoices/readme.md$ project checkProject plans are valid.$ 

Why Projector

Plans that stay where the code is.

Project trackers drift from the repository they describe. Projector keeps intent next to the code that carries it out, under version control, reviewed in the same pull request.

  1. 01

    Git is the database.

    A clone contains every plan and its history. Projector needs no service, account, daemon, or generated index.

  2. 02

    One project, one permanent home.

    A status change edits frontmatter. It never moves a file or maintains a second representation of the same plan.

  3. 03

    Concurrent projects change different files.

    Listing and prioritization are queries, so two branches working on two projects never contend on a shared now.md, next.md, or later.md.

  4. 04

    Plans grow recursively.

    Every project is a directory. It can take on design notes, decisions, and nested projects without changing shape.

  5. 05

    Built for people and agents.

    Concise human output, stable JSON with a schema version, and skills that call the same commands you can inspect and run yourself.

  6. 06

    Policy stays local.

    Projector ships useful defaults without embedding anyone's GitHub accounts, home-directory layout, or review rules.

How it works

Adopt it in three commands.

Run init from anywhere inside a Git repository. From then on, every project is a directory you can browse on GitHub and a record the CLI can query.

  1. 01

    Adopt the convention

    Creates docs/projects/README.md, the one file that explains the format to everyone who opens the repository. It never replaces an existing convention file.

    project init
  2. 02

    Create a project

    One directory, one lowercase readme.md. The path is the name, so payments/invoices is a nested project with its own status and its own plan.

    project create payments --status ready --priority next
    project create invoices --parent payments
  3. 03

    Move it through the lifecycle

    Status and priority change in frontmatter, in the same pull request that makes the claim true. The directory never moves, so a citation like payments/readme.md § 4 stays valid for the life of the project.

    project status payments in-progress
    project done payments
tree docs/projects
docs/projects/
├── README.md
└── payments/
    ├── readme.md          status + priority frontmatter
    ├── design.md
    └── invoices/
        └── readme.md      nested project: payments/invoices
docs/projects/payments/readme.md
---
status: in-progress
priority: now
---

# Ledger-backed payments

## 1. Outcome

Every invoice is issued from the ledger service, and the
legacy invoice table is read-only.

## 2. Decisions

Backfill runs once, behind a flag, before the cutover.

The model

Two fields. Two independent claims.

status says where the work is in its lifecycle. priority says when it should happen. Neither implies the other, so a draft can be the current focus and in-progress work can be set aside without losing its place.

statusthe lifecycle
  1. draft

    The plan is still being written. It makes no readiness claim.

  2. ready

    Complete enough to execute. Every question that blocks implementation is answered or deliberately deferred.

  3. in-progress

    Implementation has begun. A blocked project stays here with the blocker explained in its plan.

  4. completed

    No more work needed. The plan records whether it shipped, was abandoned, or was superseded.

prioritythe schedule
  1. now

    Deserves the team's current attention.

  2. next

    Becomes current when capacity opens.

  3. later

    Recorded but not scheduled.

The CLI

One command for the whole lifecycle.

The framework is Projector. The command it installs is project. It finds the Git root from wherever you are, reads the plans under docs/projects/, and never needs the network.

project init
Adopt the convention by creating docs/projects/README.md.
project list
Group projects by priority. Filter with --status and --priority.
project show <project>
Print a plan with its frontmatter.
project search <query>
Search names, metadata, plans, and supplemental files.
project create <project>
Create one directory and one readme.md. --parent nests it.
project edit <project>
Open the plan in $VISUAL or $EDITOR.
project status <project> <status>
Change only the status scalar.
project priority <project> <priority>
Change only the priority scalar.
project done <project>
Shorthand for status completed.
project check
Validate every plan: frontmatter, casing, links, symlinks.
project config get|list|paths
Read layered .projector.toml settings.
Full CLI reference
project list --priority now --json
{
  "projects": [
    {
      "name": "payments",
      "owner": null,
      "path": "docs/projects/payments/readme.md",
      "priority": "now",
      "status": "in-progress",
      "title": "Ledger-backed payments"
    }
  ],
  "schema_version": 2
}
  • A schema version in every response

    JSON output carries schema_version 2, so a script can refuse a shape it does not recognize instead of guessing.

  • Clean streams

    stdout is JSON only when you ask for it. Diagnostics go to stderr.

  • Safe writes, no commits

    Mutations write through a temporary file, preserve unrelated frontmatter, and refuse the update if the plan changed after Projector read it. Committing is yours.

  • Exit codes that mean something

    65 for a validation failure, 66 for a missing projects directory, 69 when edit has no terminal or editor.

Agent workflows

Skills your agents already know.

Projector packages one canonical skill tree for Claude Code and Codex. Skills express the workflow; the CLI supplies the mechanics. No MCP server required.

  • /plan-project

    Turn a requested outcome into a durable plan that another person or agent can execute without reconstructing the conversation.

  • /work-project

    Implement a project while keeping its plan and status current. The plan is the intent; the repository is the evidence.

  • /finish-project

    Verify the acceptance criteria, record whether the work shipped, was abandoned, or was superseded, and mark it completed in the same change.

  • /start-review-loop

    Review each exact pushed SHA locally and publish verified findings as labeled reviews. A pull request stays in draft until its head is clean.

  • /start-fix-loop

    Watch for review findings, verify and fix each one, then reply with the commit, push, and resolve the thread.

  • /gh-stack

    Create, push, rebase, and navigate stacks of dependent pull requests with the gh-stack extension when work crosses a reviewability boundary.

Equal targets, one source tree

Both plugin manifests point at the same skills/ directory. A host loads the same instructions without a generated copy or a host-specific fork, so a fix lands in both places at once.

Claude Code

Install

Skills are namespaced by the plugin.

/projector:plan-project plan a safer deploy workflow

Codex

Install

Skills are invoked directly by name.

$plan-project plan a safer deploy workflow

Review loops

Draft means changes are needed.

Two background loops carry a pull request from first push to a clean head while you keep working. The draft state is the verdict, so the moment a pull request turns ready, it has actually been reviewed.

  1. 01

    Push

    A new SHA lands on a pull request the authenticated account owns.

  2. 02

    Review the exact head

    The review loop checks out that SHA locally and inspects it. A review starts only when inspection actually begins.

  3. 03

    Publish verified findings

    Findings go up as one labeled COMMENT review on that head. The pull request stays in draft.

  4. 04

    Fix each finding

    The fix loop verifies a finding, commits the fix, replies with the commit, pushes, and resolves the thread.

  5. 05

    Clean head, ready for humans

    When a review of the head finds nothing, the pull request is marked ready. That transition is the sign-off.

Never mark your own draft ready yourself; a clean review is what clears it.

AGENTS.md, the Projector contributor instructions

The loops review as the operator: the account whose pull requests are watched and whose branches carry the fixes. Identity follows the authenticated token, so a loop never scopes itself to pull requests it cannot push to.

A real APPROVE is posted only when review.allow_approve is set and the author is someone else. On your own pull request the loop stays with labeled comments, which GitHub would insist on anyway.

Every finding is verified against the checked-out head before it is published, and every fix is committed, pushed, and resolved in that order, so the thread on GitHub always points at the commit that answered it.

Configuration

Settings that follow the code.

Projector reads .projector.toml from your home directory down to the repository root, nearest last. Put a value in the file closest to the code it governs. Tables merge key by key, so a nearer file overrides one setting without discarding the rest.

~/src/.projector.toml
# every repository under ~/src
[review]
username = "review-bot"
effort = "high"
model = "sonnet"
~/src/payments/.projector.toml
# this repository only
[review]
model = "fable"
allow_approve = true
project config get review.model --json
{
  "key": "review.model",
  "schema_version": 2,
  "source": "/home/you/src/payments/.projector.toml",
  "value": "fable"
}
keys Projector reads today
KeyDefaultRead by
projects.dirdocs/projectsevery command
review.usernamethe authenticated userstart-review-loop
review.allow_approvefalsestart-review-loop

Keys are not validated. Any key a skill or a script agrees on works, so the same command reads settings Projector itself knows nothing about.

get --json reports which file each value came from, which is the fastest way to learn why a setting is not what you expected. get exits 1 when a key is unset and no default is given, so a caller can branch on the exit status instead of parsing output.

Install

Two commands per host.

Install the CLI once, then add the plugin to whichever coding agents you use. The core workflows call the local command and need nothing else.

The CLI

Requires Python 3.11 or newer and has no runtime dependencies. pipx gives you an isolated project executable.

pipx install git+https://github.com/ninjudd/projector.git
project --help

Claude Code

Adds the repository as a marketplace and installs the plugin at user scope. Invoke a skill as /projector:<skill>.

claude plugin marketplace add ninjudd/projector --scope user
claude plugin install projector@projector --scope user

Codex

The same repository and the same skill tree. Invoke a skill as $<skill>.

codex plugin marketplace add ninjudd/projector
codex plugin add projector@projector

From a clone

./install.sh all installs the CLI and both plugins from the checkout. ./install.sh status compares the installed command against the files in the checkout, so it reports a stale command even when nobody bumped a version.

git clone https://github.com/ninjudd/projector.git
cd projector
./install.sh all