Thank you for considering contributing to Prospec! This guide will help you get started.
This project uses pnpm for development (Node 22.13+, pnpm 11+).
# Clone the repository
git clone https://github.com/benwu95/prospec.git
cd prospec
# Install dependencies
pnpm install
# First-time local install: build, then register the `prospec` bin globally
pnpm run build && pnpm add -g .
# After making changes, just rebuild — the global bin picks up the new dist/
pnpm run build
# Verify
prospec --help
# Remove it when finished
pnpm uninstall -g prospecFirst-time global install needs
pnpm setuprun once to configure the global bin directory.
pnpm cli <args> runs the CLI straight from src/ — no build, no install, always exactly HEAD:
pnpm cli status
pnpm cli checkUse this for quick checks and in scripts. It is not what the skills read, though: every skill's
startup probe runs prospec --version from PATH and STOPs when that binary is older than
MINIMUM_CLI_VERSION, because its deterministic steps call commands only that version ships. So to
dogfood the skills on prospec itself, put a build of the working tree on PATH — either the global
bin above, or the release-shaped standalone binary:
pnpm bundle # bakes package.json's version in
bun build ./dist/cli-bundle.js --compile --minify --outfile ~/.prospec/bin/prospec
prospec --version # must be >= MINIMUM_CLI_VERSIONMINIMUM_CLI_VERSION (src/types/version.ts) names the version that ships the commands the
skills call, so during development it runs ahead of package.json until the release bumps to match.
Never lower it to make a probe pass — that lets an older binary without those commands through.
# Watch mode (recompile on change)
pnpm run dev
# Run all tests
pnpm test
# Run tests in watch mode
pnpm run test:watch
# Type check
pnpm run typecheck
# Lint
pnpm run lint
# Re-derive the factual counts the docs declare (test totals, .hbs inventory)
pnpm counts
# Same, read-only: exits 1 on drift (this form measures the suite itself).
# CI instead runs `pnpm run counts:check --from vitest-report.json`, reusing
# the report `pnpm run test:coverage` wrote — so a stale count fails the PR.
pnpm counts:check
# Deployed agent artifacts fresh vs their source templates.
pnpm agents:check
# Module knowledge synced with source. IMPORTANT: run this AFTER the feature
# commit and before pushing — it diffs `git merge-base origin/main HEAD`..HEAD,
# so before the commit the range is empty and it prints a "commit first, then
# re-run" skip, never a real pass. Editing a shipped `.hbs` + `pnpm bundle` also
# makes `lib` source-touched via the regenerated `src/lib/bundled-templates.ts`,
# so stamp `lib` too — `prospec knowledge update --change` lists it as stamp-only.
pnpm knowledge:checksrc/
├── cli/ — Commander.js commands + formatters
├── services/ — Business logic (one service per command)
├── lib/ — Pure utility functions
├── types/ — Zod schemas + TypeScript types
└── templates/ — Handlebars templates (.hbs)
tests/
├── unit/ — Unit tests (lib + services)
├── contract/ — Contract tests (CLI output + Skill format)
├── integration/ — Integration tests (multi-service flows)
└── e2e/ — End-to-end tests (real CLI process)
- Language: TypeScript strict mode, no
any - Style: Follow ESLint + Prettier configuration
- Naming: camelCase for variables/functions, PascalCase for types/classes
- Imports: Use
.jsextension for relative imports (ESM) - Error handling: Use custom error classes from
src/types/errors.ts - Testing: Every new service/feature requires tests
Development is pnpm-only; the single lockfile is pnpm-lock.yaml.
When you add, remove, or upgrade a dependency, run pnpm install and commit the updated
pnpm-lock.yaml:
pnpm install # updates pnpm-lock.yamlCI runs pnpm install --frozen-lockfile on every push/PR — if the lockfile drifts from
package.json, CI fails.
Notes:
- pnpm 11+ and Node 22.13+ are required (pnpm 11 needs Node ≥ 22.13; enforced via
engines). Build-script approvals (e.g. esbuild) live inpnpm-workspace.yamlunderallowBuilds. - End users installing the published CLI can still use npm or pnpm — the pnpm-only rule applies to developing this repo, not to consuming it.
git checkout -b feature/your-feature-nameProspec uses itself for development! Use the Skills:
# Describe your change
/prospec-new-story your-feature
# Generate implementation plan + delta-spec
/prospec-plan
# Break down tasks
/prospec-tasks
# Implement (work on the working tree — don't commit yet)
/prospec-implement
# Adversarial review → fix loop (verifier-confirmed criticals auto-fixed)
/prospec-review
# Verify; at grade S/A it prompts you to commit — one atomic commit folding
# implement + review + verify fixes (prospec prompts, never auto-commits)
/prospec-verify
# Archive + sync Feature Specs / Knowledge
/prospec-archive
# (periodic) promote recurring lessons into shared team rules
/prospec-learnThe commit boundary is after
/prospec-verifyreaches grade S/A — implement, review, and verify all operate on the working tree first, then land as a single atomic-by-feature commit. See README — Quality Gates & Self-Improvement.
- Unit tests for new services/utilities
- Contract tests if adding new Skills or CLI output formats
- E2E tests for new CLI commands
Follow Conventional Commits:
feat(scope): add new feature
fix(scope): fix specific bug
docs: update documentation
test: add or update tests
refactor(scope): restructure code
chore: dependency updates, config changes
A completed change lands as two commits, in this order:
- The change itself (
feat:/fix:/docs:/ …). Its boundary is/prospec-verifyreaching grade S/A — one atomic commit folding the implementation, the review fixes, the verify fixes, every source-touched module README, and any re-derived factual counts. - The archive commit, written after
/prospec-archive. It carries the Feature Spec graduation, theprospec/specs/_archived-history/summary, and the refreshedraw-scan.md. Its subject line is not standardised —docs(archive): archive <name>,docs(spec): graduate <subject> requirements,docs(specs): archive <name>andchore: archive <name>have all been used within one six-week span — so take the wording fromgit logand treat the contents listed above as the stable part.
The message rules live in prospec/CONSTITUTION.md → [MUST] Atomic Commits and Format Requirements,
in its Verify clause: conventional prefix; subject and body in English; body as a bulleted list, never
prose paragraphs; one concern per commit; no AI co-authorship attribution. The allowed types are
feat, fix, refactor, test, docs, chore, perf, and ci.
/submit-prwalks this section end to end (branch → push → body → open). It is maintainer tooling for this repo, like/release— not a prospec SDD skill. This section stays the authority; the skill only executes it.
- One issue → one change → one PR. Open the PR from the change's branch; let the merge close the issue rather than closing it by hand.
- Register the issue on the change itself, at scaffold time:
prospec change story <name> --issue "#NN". That writesissue: "#NN"into the change'smetadata.yaml, andprospec statusplus the archive summary (and its committedprospec/specs/_archived-history/copy) then carry the link. The division is deliberate: the field is the mechanical record — optional, free-form (whitespace collapses to one line), no shape check and no forge API — and this section is where the convention around it is explained. Without the field the link survives only in commit and PR prose, recoverable by nothing but a human reading it; without this section the field is a string with no stated meaning. Field format and its no-validation stance:src/templates/skills/references/metadata-format.hbs→`issue`. - Land the change as two commits — the feature commit at
/prospec-verifygrade S/A, then the archive commit — as specified in §4 Commit. Push both before opening the PR. - Write the PR body in Traditional Chinese (Taiwan). This is a house convention, not a
consequence of the Constitution's
[MUST] Language Policy— that rule is defined over repo paths (.prospec/changes/**and friends), and a PR body is not one. The code, commit messages, and trust zone inside the same PR stay English. - Structure the body as bullets covering what changed and why, and end with
Closes #NN. - Never append an AI attribution footer. This repo carries no AI co-authorship in commit messages or PR bodies.
- Ensure
pnpm test,pnpm typecheck,pnpm lint, andprospec checkpass. CI additionally gatespnpm run counts:check— a stale factual count fails the PR.
- Add skill definition to
src/types/skill.ts(SKILL_DEFINITIONS array) - Create template at
src/templates/skills/your-skill-name.hbs - If the skill needs references, create
src/templates/skills/references/your-ref.hbsand map it ingetSkillReferences(src/services/agent-sync.service.ts) - Update contract tests in
tests/contract/skill-format.test.ts— bump theSKILL_DEFINITIONSlength assertion and write section-scoped structure assertions: slice to the section under test, assert distinctive in-section content, then mutation-verify (delete the section and confirm the test goes red). A baretoContainover the whole rendered template false-greens against incidental text (team rule_playbook.mdPB-001). - Run
prospec agent syncto generate the new Skill files
- Create service at
src/services/your-command.service.ts - Create command at
src/cli/commands/your-command.ts - Create formatter at
src/cli/formatters/your-command-output.ts - Register in
src/cli/index.ts - Add unit tests for the service
- Add E2E tests in
tests/e2e/cli.test.ts
- Use GitHub Issues for bug reports and feature requests
- Include steps to reproduce for bugs
- Include your Node.js version and OS
By contributing, you agree that your contributions will be licensed under the MIT License.