How plankit works
plankit is a Claude Code plugin. pk is the command it installs. Install
the plugin once per machine and run pk init once per repository.
From then on, three things happen in that repository: approved plans
are kept as a record, protected branches refuse commits from the
agent, and releases are computed from commit messages.
The pieces
The plugin has three parts: hooks that tell Claude Code when to run pk, pages that document each command, and a shim that finds the pk binary for the platform. pk holds every decision. The plugin adds wiring and words, not logic. Remove the plugin and pk still does everything from a terminal; remove pk and the plugin does nothing.
A repository that uses plankit carries one file of its own: the
policy file, .pk.json, committed with the code. The record,
docs/plans/, appears when the first plan is preserved. Nothing else
is copied in.
flowchart TB
subgraph plugin["Plugin shell (Claude Code)"]
hooks["hooks<br/>when pk runs"]
skills["pages<br/>typeahead and pk help"]
shim["bin/pk shim"]
end
subgraph cli["CLI shell (any terminal)"]
term["pk on PATH<br/>go install or release binary"]
end
kernel["pk<br/>every decision"]
cfg[".pk.json<br/>the policy file"]
git["git<br/>branches, tags, the trailer"]
hooks --> shim --> kernel
skills -. documents .-> kernel
term --> kernel
kernel --> cfg
kernel --> git
Plans
Claude plans the work in Plan Mode. When the developer approves the
plan, the preserve hook copies it, byte for byte, into docs/plans/
under a dated, sequenced filename. In auto mode preserve commits it at
once. In manual mode, the default, preserve records which plan was
approved and tells the session; /plankit:preserve commits it later.
The protect hook denies every edit under docs/plans/. A plan is
never changed after approval. When the approach changes, a new plan
is approved and preserved, and the sequence of files is the history
of decisions, reversals included.
Branches
The guard hook runs before every shell command the agent issues. It
reads the policy file and answers with a decision. Three policies
apply. On a protected branch, a git mutation (commit, merge,
push, rebase, reset) is denied or questioned. A git push on
any branch is denied or questioned. A commit whose message carries a
breaking marker (! after the type, or a BREAKING CHANGE: footer)
is questioned. When policies overlap, deny beats ask.
The breaking marker drives the next major version. It is the
developer's claim to make, so the agent is asked before it writes
one. --bump on the release commands is the same claim and the same
rule.
The brief hook runs as a session starts, resumes, or compacts. It
tells the session the policy in words: the commit types, the
breaking-marker rule, the protected branches, how plans are kept. The
words are rendered from the policy file each time, so they cannot
disagree with what guard, protect, and preserve then enforce.
pk brief at a terminal prints the same text.
Releases
Commits follow Conventional Commits: feat:, fix:, docs:, and
the rest of the table in the policy file. That is the whole input to
a release.
pk changelog reads the commits since the last tag and infers the
version: a breaking marker is major, feat is minor, anything else
is patch. It writes the section into CHANGELOG.md, stamps the version
into the files the policy names, and commits with a Release-Tag
trailer. No tag exists yet; the commit is there to review, and
pk changelog --undo unwinds it while it is unpushed.
pk release reads the trailer. It checks the tree is clean, the
branch is on origin, and nothing has diverged. It fast-forwards the
release branch, runs the pre-release hook, tags, runs the pre-push
hook, and pushes the branch and the tag together. A failure after the
tag exists rolls back: the tag is deleted, the merge is reset, and the
working branch is checked out again.
pk ship runs changelog then release. Its only state is the trailer,
so a ship interrupted between the halves resumes at release on rerun.
Every release command accepts --dry-run.
The pushed tag hands off to CI. CI builds the platform binaries, assembles the plugin archive, and publishes a GitHub release carrying the archive, the binaries, and the marketplace file that names the archive's version and digest. Installers see a new version when the version inside the plugin changes. The release commits nothing back to a source branch, so the working branch and the release branch are equal when it finishes.
Pages
Every command has one page, written once. Claude Code loads it as a
/plankit: shortcut, pk help prints it in a terminal, and
plankit.com renders it as HTML. The pages are compiled at build time
and checked for drift. A page carrying hidden or direction-changing
characters fails the build, because pages load into other people's
sessions.
Two promises
A hook never blocks work by failing. Whatever goes wrong inside it, including a policy file that no longer loads, it reports the problem, Claude Code shows the message, and the command continues.
A repository without a policy file gets no action from any hook. The
plugin is installed everywhere; it is on only where pk init ran.
Outside Claude Code
The hooks are the only Claude Code-specific part. Guard, changelog,
release, ship, and pin work in any terminal. pk installs on its own
with go install, or as a release binary without Go, on macOS, Linux,
and Windows. A team member who never opens Claude Code gets the same
protected branches and the same releases from the same policy file.
The method behind this page is in
docs/design.md.