Product Lifecycle Manager — Features as First-Class Citizens

<a href="https://zensu.dev"><img src="assets/zensu-logo.svg" alt="Zensu" width="120"></a>
Turn an idea into a reviewed pull request — without babysitting the agent.
Zensu plans the feature with you, implements it, and then puts the result through a review panel that has to cite real file and line numbers for every finding. What ships is tracked as a feature, not as a pile of commits, so your product people can see progress without opening a terminal.
Any language, any stack. The implementation workflow and the review chain need no configuration and no account; tracking features in Zensu needs the zensu CLI and a Zensu account (which skills need what).
hooks.defaultDeliveryRoute. You stay in the loop once, not every turn.Zensu acts in every Claude Code session where the plugin is enabled, not only when you run one of its skills. Know these before you add it to a setup you already rely on:
Bash. Every subagent that is not one of Zensu's own — the built-in agents such as Explore, general-purpose and Plan, your project's agents, and agents from other plugins — may call every tool its definition and your permissions grant, MCP tools, Skill and Workflow included. Zensu's capability gate denies it what reaches Zensu's own state: Session Control and workflow paths, .zensu/, writes to the installed plugin or its private data, Zensu configuration layers and Zensu MCP mutations. A tool whose inputs Zensu does not know, such as a browser MCP tool, may not name that state anywhere in its input. PowerShell, the shell aliases other than Bash, Monitor commands and tools whose name marks them as running commands stay denied, because Zensu's command gates see only Bash and PowerShell commands. A subagent that reports its type, other than a zensu-review-* review persona, may run Bash behind an accident guard; the guard prevents accidents and is not a sandbox. Subagents may not read .zensu/, so Grep and Glob must name a subdirectory: a search from the project root is refused. hooks.subagentShell: false withdraws the shell grant, and the subagents: row of /zensu:doctor shows the boundary. Details: Session control./compact or /clear (about 11,200 when the prompt carries a planning keyword), and about 1,800 to 5,300 characters on every later prompt. Automatic work capture, added after 0.29.0, adds about 760 characters to every session start. The skill listing carries Zensu's skill descriptions on top. Architecture says how this was measured and breaks it down per hook./zensu:zen-mode --off to leave it for the session; set hooks.zenModeDefault: false to make it opt-in again./zensu:delivery-route or hooks.defaultDeliveryRoute answers it ahead of time; hooks.autoTdd: false and hooks.tddReminder: false switch the two questions off.ai-work commands of the zensu CLI and your personal zensu auth login. Once a goal is begun, a Stop hook reports each new clean commit for it and returns a review link where you accept that exact version; nothing accepts it for you. It sends the goal's title (at most 160 characters), its key, a criteria version or digest and the commit SHA, never transcripts, prompts, diffs or file lists. Neither hook has a key. Without a CLI that provides ai-work and a personal login, capture is reported as unavailable and the work continues. Automatic work capture.hooks.autoFixMaxRounds plus three blocked stops) and is lifted by hooks.chainEnforcer: false or by ZENSU_CHAIN=off in the environment Claude Code starts with. A durable /zensu:autopilot run holds the turn until the run ends or blocks; hooks.autopilotEnforcer: false or ZENSU_AUTOPILOT=off lifts that hold.evidence.fullSuiteGate and evidence.acceptanceGate both required) a Zensu workflow chain closes only after a full test-suite run that the plugin executed itself passed on the current tree, and after every acceptance criterion of the plan was verified live. Set either key to advisory to report the verdict without blocking, or set ZENSU_FULL_SUITE_GATE=off or ZENSU_ACCEPTANCE_GATE=off for one closing step; those two escapes are recorded in the chain's bypass ledger. /zensu:full-suite moves the full suite to a verified CI pipeline instead.node must be on PATH. The capability gate runs on every tool call and needs node. Without it every tool call is refused with only zensu: reviewer capability gate unavailable, which does not name node.Requires Claude Code 2.1.296 or newer.
claude plugin marketplace add MKITConsulting/zensu-claude-code
claude plugin install zensu --scope project
If the install fails with Host key verification failed or Permission denied (publickey), Claude Code cloned the plugin over SSH. That is its default for GitHub plugin sources, and unlike marketplace add the install step has no HTTPS fallback. Force HTTPS:
CLAUDE_CODE_PLUGIN_PREFER_HTTPS=1 claude plugin install zensu --scope project
Update later with:
claude plugin marketplace update zensu
claude plugin update zensu@zensu
Optional, for feature tracking: install zensu-cli 0.10.0 or later with brew install --cask mkitconsulting/tap/zensu (upgrade with brew upgrade --cask zensu), curl -fsSL https://zensu.dev/install.sh | sh, or on Windows irm https://zensu.dev/install.ps1 | iex, then run zensu auth login.
Run /zensu:setup to configure Zensu step by step, or /zensu:doctor if something is not firing.
The first two need no Zensu account.
Just this change — describe what you want and approve the plan. Zensu asks which delivery route to take: Autopilot to a reviewed pull request, the Zensu workflow with its review chain, Pilot for a feature already tracked in Zensu, or implementing it directly. Answer the route question with the Zensu workflow once: the session remembers that answer (a direct, Autopilot or Pilot answer decides only that plan or request), and /zensu:delivery-route or hooks.defaultDeliveryRoute fixes either route without asking.
One feature, hands off — /zensu:autopilot takes a plain-language idea to a validated pull request: one planning gate, then plan → build → review → fix → verify, unattended. It stops at a ready PR and never merges. It needs gh or glab, logged in.
Existing codebase — /zensu:ghost-scan discovers what you already shipped and imports it as tracked features. Needs a Zensu account.
New product — /zensu:bootstrap reads your vision doc and creates the features, journeys, and tiers. Then /zensu:implement KEY-1 builds the first one. Needs a Zensu account.
The count is the workflow skills in these tables. The read-only diagnostics skill is documented separately in Diagnostics below and is intentionally kept out of these tables (32 skills are registered in
plugin.json).
The Needs column says what a skill needs beyond Claude Code: "Zensu account" means the zensu CLI, logged in; gh or glab means the forge CLI of your GitHub or GitLab repository, logged in; "—" means nothing else. Nineteen skills make no zensu call at all.
| Skill | What it does | Needs |
|---|---|---|
/zensu:bootstrap | Turn a vision document into tracked features, journeys, security profiles, and tiers | Zensu account |
/zensu:ghost-scan | Scan an existing repo, discover undocumented features, and import them | Zensu account |
/zensu:docs | Write code-grounded feature documentation that honestly clears the docs release gate | Zensu account |
/zensu:security-review | A tracked feature's security review: classification, OWASP analysis, STRIDE threat model, release-gate check | Zensu account |
/zensu:pulse | Developer journal — privacy-first tracking of your coding sessions | Zensu account |
| Skill | What it does | Needs |
|---|---|---|
/zensu:tdd | The Zensu workflow: implement an approved plan in the main thread, verify every acceptance criterion live, then the mandatory review chain and auto-fix loop. Despite its name it runs without RED→GREEN by default; /zensu:tdd-mode or hooks.tddImplementation switches strict TDD on | — |
/zensu:autopilot | Idea → validated pull request, unattended after one planning gate. Never merges or deploys | gh or glab |
/zensu:implement | Implement a tracked feature through the Zensu workflow, then link its tests, sources and docs and create a revision | Zensu account |
/zensu:pilot | The guided route: probes a tracked feature's real state and offers the next step, one confirmed step at a time | Zensu account and a tracked feature; gh or glab for its pull request |
/zensu:cover | Backfill durable tests at the right level (unit → integration → E2E) for existing code | — (a Zensu account only when the target is a feature id) |
/zensu:converge | Audit the code against the plan and flow real changes back into the spec | — |
/zensu:wargame | Map a hard task move by move so a cheaper model can execute it blind | — (reads a Zensu feature when the brief names one) |
/zensu:gauntlet-loop | Improve an artifact against a frozen bar under two fresh critics, arbitrating disagreement | — |
| Skill | What it does | Needs |
|---|---|---|
/zensu:plan-review | Have a tailored reviewer team revalidate a plan before any code is written | — |
/zensu:pr-team-review | Multi-agent review of an existing GitHub or GitLab PR, published as one consolidated review | gh or glab |
/zensu:pr-fix-findings | Work through every unresolved review thread on a PR and resolve it | gh or glab; its prerequisites also ask for a logged-in zensu CLI, though it runs no other zensu command |
| Skill | What it does | Needs |
|---|---|---|
/zensu:verify-feature | Exercise the running feature and report what actually happened, for a web UI, an API, a CLI, a library, a worker, infrastructure code, an iOS or Android app, or a desktop app. Report-only. Inside a Zensu workflow chain its --chain mode verifies every acceptance criterion before the chain can close. How to run it standalone | playwright-cli for a web UI |
/zensu:full-suite | Run full test suites in the verified CI pull-request pipeline instead of locally, for this repository or this session; affected tests stay local | A GitHub.com repository and gh |
| Skill | What it does | Needs |
|---|---|---|
/zensu:tdd-mode | Switch this session between strict RED→GREEN TDD and vanilla, without editing config | — |
/zensu:delivery-route | Fix this session's delivery route (Zensu workflow or direct) so the route question is not asked again this session | — |
/zensu:zen-mode | Low-noise responses for working at reduced capacity. On by default; --off leaves it for the session | — |
| Skill | What it does | Needs |
|---|---|---|
/zensu:setup | Interactive first-run configuration | — (a Zensu account for its optional login step) |
/zensu:zensu-help | Ask how Zensu or the plugin works. Read-only Q&A | — |
/zensu:session-trail | See what your other Claude Code instances are doing, take a session over and then release the old one so it can be archived, and trace where a session was continued across windows and accounts | — |
| Skill | What it does | Needs |
|---|---|---|
/zensu:recover-chain | Repair the one review-chain state no other command can leave | — |
/zensu:reset-review-limit | Grant the current review chain another auto-fix budget | — |
/zensu:adopt-session | Report a refused automatic adoption after a plugin update landed mid-run and retry it by hand, re-create a vanished recorded project root, or move the session's anchor to a sibling worktree of the same repository (--reanchor) | — |
/zensu:autopilot-adopt | Take over a durable Autopilot run whose owning session is gone | — |
/zensu:autopilot-release | Free a working tree an abandoned Autopilot run is still holding | — |
You do not start these yourself: the review chain starts the first, and a work-order launcher starts the second.
| Skill | What it does | Needs |
|---|---|---|
/zensu:self-review | The terminal self-reflection stage that closes the review chain | — |
/zensu:work | Run one Zensu work order in a headless worker session, reporting every stage until ready_for_merge or a block | A Zensu work order and the session token its launcher passes |
/zensu:doctorA read-only health check for when something is not firing: CLI and auth, plugin integrity, config validity (including the quoted-boolean trap, where "true" as a string is silently ignored), and session state. It never writes and always exits 0 — a red mark is a finding in the report, not a failed command. It needs no account; with the zensu CLI installed it also reports the login and the CLI version.
| Built-in | Zensu | Use the built-in for | Use Zensu for |
|---|---|---|---|
/security-review | /zensu:security-review | A security pass over the pending changes on your branch | A tracked feature's security profile: classification, threat model, security tests and the release gate, recorded in Zensu |
/code-review | the review chain, /zensu:pr-team-review | A review of the current diff or a PR that you start yourself | The review chain runs by itself at the end of every Zensu workflow chain, grades each finding against the source and fixes the routed ones; /zensu:pr-team-review publishes one consolidated multi-agent review on an open PR |
/doctor | /zensu:doctor | Problems with the Claude Code installation itself | A hook or gate of this plugin that is not firing, its config, its CLI login and the session's workflow state |
/simplify | — | Cleanups that reuse, simplify and tidy changed code | Zensu has no counterpart; the review chain reports maintainability problems but applies no cleanups on its own |
/goal | /zensu:wargame | Keeping Claude working until a stated condition holds | Writing the move-by-move plan, and optionally the goal contract, before such a run; it plans and executes nothing |
Defaults are the supported configuration; you do not have to set anything. Flags live in ~/.zensu/config.json (global) and .zensu/config.json (per project, merged over the global file key by key):
{
"hooks": {
"pulseSession": false
}
}
Not every hook can be turned off:
| | Hooks | How | |-|-------|-----| | Switched off by a config key | The banner and primer, the pulse banner, the intent router, zen-mode, both delivery-route questions, the best-solution-first reminder (main thread only), the context nudge, the worktree-keep hooks, the Session Hub receipt, the reviewer-spawn grant, the auto-fix loop, the workflow-launch recorder, the Stop backstops, the Zensu CLI write-gate and the secret scan | A hooks.* key, or context.compactionNudge, set to false | | Off unless you opt in | The source-write gate's checks of Bash writes | hooks.bashWriteGate: true | | Bypassed only through the environment | The TDD phase gate | ZENSU_TDD_GATE=off in the environment Claude Code starts with | | Always on while the plugin is enabled | Session Control and the capability gate that confines subagents (hooks.subagentShell: false only withdraws their Bash), the Session Control check inside the source-write gate, evidence discipline, the plugin-data guard, the browser consent gate and its recorder, the artifact path redactor, the prompt-ledger reset, Autopilot resume context, the review-evidence hooks, the work-order hooks (inert outside a work-order session), the background-review hand-back and both automatic work-capture hooks | Disable the plugin (Turn Zensu off or remove it) |
The full flag reference, the merge order, and the hook table are in docs/configuration.md. config.example.json shows the flags with their default values; copying it pins every default, so your copy stops following later default changes.
Nothing writes an ignore rule for you, except the .worktree-keep line below.
| Path | Written by | Commit it? |
|---|---|---|
.zensu/config.json | You or /zensu:setup | Yes, to give every clone the same settings; it overrides each developer's global file key by key |
.zensu/plans/, .zensu/logs/*_tdd-*.log | The Zensu workflow, one plan and one progress log per chain | Optional. Committed, they are an audit trail; absolute paths in them are redacted when they are written |
.zensu/state/ | Zensu's hooks, per session | Never. Add .zensu/state/ to .gitignore |
.zensu/verify-feature-runs/ | /zensu:verify-feature, one directory per run, removed after a clean teardown | Never |
.zensu/logs/witness-*.log | Earlier releases only | Never |
.zensu/runtime.yaml (older name .zensu/autopilot.yaml) | /zensu:verify-feature --setup, after you confirm | Yes: it tells /zensu:verify-feature and /zensu:autopilot how to start your app |
.zensu/overlays/, .zensu/templates/ | You | Yes: team guidance for the review skills, and your pull request body template |
.worktree-keep in a Claude Desktop worktree | The worktree-keep hooks | No; Zensu lists it in the repository's .git/info/exclude |
Zensu's own keys cannot stop the always-on hooks. To stop Zensu in one repository, disable the plugin there: claude plugin disable zensu@zensu --scope local for yourself only, or --scope project for everyone who uses the project's shared Claude Code settings. claude plugin uninstall zensu@zensu --scope project removes a project install (the command's default scope is user); Claude Code also deletes the plugin's data directory under ~/.claude/plugins/data/ unless you pass --keep-data.
What stays behind:
~/.zensu/: your global config.json and, from older releases, the retired plugin-root locator. Delete that locator only once no Claude Code session from an older Zensu installation is still running..zensu/ in every project you used it in, as listed above..worktree-keep files in the root of Claude Desktop worktrees under .claude/worktrees/, and the .worktree-keep line in the repository's .git/info/exclude.~/.claude/zensu/ (under CLAUDE_CONFIG_DIR when that is set): the session lineage ledger of /zensu:session-trail and the Session Hub receipts.zensu CLI and its stored login, which are a separate install. Run zensu auth logout before you remove the CLI.The implementation workflow and the review chain need no CLI, no login, and no Zensu account: /zensu:tdd, the review-aspect panel with its auto-fix loop, and the progress log under .zensu/logs/ run locally, and so does every skill marked "—" in the skill tables. The zensu CLI and an account add the tracking layer on top — feature status, revisions, artifact links, security findings, and release-gate validation — through the skills marked "Zensu account".
zensu auth login signs the CLI in through your browser (OAuth with PKCE) and stores the credentials for every later command. When a zensu call in a session fails with an authentication error, Claude runs zensu auth login and retries; the browser step approves itself while you are signed in to Zensu on the web.
For headless environments, authenticate the CLI with an API key instead — pipe it to the token form, since a bare zensu auth login opens a browser and never reads the env var:
# ZENSU_API_KEY from your CI secrets
echo "$ZENSU_API_KEY" | zensu auth login --with-token -
Verify with zensu auth status, clear with zensu auth logout. A headless /zensu:work session uses the session token its launcher passes in ZENSU_SESSION_TOKEN and ignores any stored login.
The zensu CLI sends data over HTTPS to https://api.zensu.dev, o
hooks/usage-feed.ts 67 lines1import type { EngineInterface, Register, SessionRateLimit, UsageUnit } from 'claude-code'
2
3type RateLimitReading = {
4 kind: string
5 percentUsed: number
6 resetsAt: string | null
7}
8
9const SCHEMA_VERSION = 1
10const USAGE_DIRECTORY = 'zensu/session-hub/v1/usage'
11const MAX_RATE_LIMITS = 8
12const FRESH_READING: readonly UsageUnit[] = ['rateLimits', 'cost']
13const SESSION_ID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/
14const KIND = /^[a-z][a-z0-9_]{0,31}$/
15const RESETS_AT = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{1,9})?(?:Z|[+-]\d{2}:\d{2})$/
16
17function readingsOf(limits: readonly SessionRateLimit[]): RateLimitReading[] {
18 const readings: RateLimitReading[] = []
19 if (!Array.isArray(limits)) return readings
20 for (const limit of limits) {
21 if (readings.length === MAX_RATE_LIMITS) break
22 if (typeof limit?.kind !== 'string' || !KIND.test(limit.kind)) continue
23 if (readings.some(reading => reading.kind === limit.kind)) continue
24 if (typeof limit.percentUsed !== 'number' || !Number.isFinite(limit.percentUsed) || limit.percentUsed < 0) continue
25 const resetsAt =
26 typeof limit.resetsAt === 'string' && RESETS_AT.test(limit.resetsAt) && Number.isFinite(Date.parse(limit.resetsAt))
27 ? limit.resetsAt
28 : null
29 readings.push({ kind: limit.kind, percentUsed: limit.percentUsed, resetsAt })
30 }
31 return readings
32}
33
34async function configRoot($: EngineInterface): Promise<string | undefined> {
35 const configured = (await $.env.get('CLAUDE_CONFIG_DIR'))?.trim()
36 if (configured) return configured.startsWith('/') ? configured.replace(/\/+$/, '') : undefined
37 const home = await $.env.get('HOME')
38 return home?.startsWith('/') ? `${home.replace(/\/+$/, '')}/.claude` : undefined
39}
40
41async function writeReading($: EngineInterface, limits: readonly SessionRateLimit[]): Promise<void> {
42 const rateLimits = readingsOf(limits)
43 if (rateLimits.length === 0) return
44 const sessionId = await $.session.id()
45 if (typeof sessionId !== 'string' || !SESSION_ID.test(sessionId)) return
46 const root = await configRoot($)
47 if (root === undefined) return
48 const directory = `${root}/${USAGE_DIRECTORY}`
49 if (!(await $.fs.exists(directory))) return
50 const stat = await $.fs.stat(directory)
51 if (stat.kind !== 'dir' || stat.isLink) return
52 const observedAt = await $.clock.now()
53 if (!Number.isSafeInteger(observedAt) || observedAt < 0) return
54 const record = { schemaVersion: SCHEMA_VERSION, sessionId, observedAt, rateLimits }
55 await $.fs.write(`${directory}/${sessionId}.json`, `${JSON.stringify(record)}\n`)
56}
57
58export const register: Register = on => {
59 on('session.measure', async ($, e, next) => {
60 const measured = await next(e)
61 try {
62 if (e.changed.some(unit => FRESH_READING.includes(unit))) await writeReading($, e.rateLimits)
63 } catch {}
64 return measured
65 })
66}
67