- Keep answers short and concise
- No emojis in commits, issues, PR comments, or code
- No fluff or cheerful filler text
- Technical prose only, be kind but direct (e.g., "Thanks @user" not "Thanks so much @user!")
- When the user asks a question, answer it first before making edits or running implementation commands.
- Read files in full before making wide-ranging changes, before editing files you have not already fully inspected, and when the user asks you to investigate or audit something. Do not rely only on search snippets for broad changes.
- No
anytypes unless absolutely necessary - Single-line helper functions with a single call site are forbidden; inline them instead.
- Check node_modules for external API type definitions instead of guessing
- NEVER use inline imports - no
await import("./foo.js"), noimport("pkg").Typein type positions, no dynamic imports for types. Always use standard top-level imports. - NEVER remove or downgrade code to fix type errors from outdated dependencies; upgrade the dependency instead
- Use only erasable TypeScript syntax compatible with Node strip-only mode in TypeScript checked by the root config (
packages/*/src,packages/*/test, andpackages/coding-agent/examples). Do not use constructor parameter properties,enum,namespace/module,import =,export =, or other TypeScript constructs that require JavaScript emit. Use explicit fields and constructor assignments instead of parameter properties. - Always ask before removing functionality or code that appears to be intentional
- Do not preserve backward compatibility unless the user explicitly asks for it
- Never hardcode key checks with, eg.
matchesKey(keyData, "ctrl+x"). All keybindings must be configurable. Add default to matching object (DEFAULT_EDITOR_KEYBINDINGSorDEFAULT_APP_KEYBINDINGS) - NEVER modify
packages/ai/src/models.generated.tsdirectly. Updatepackages/ai/scripts/generate-models.tsinstead.
- After code changes (not documentation changes):
npm run check(get full output, no tail). Fix all errors, warnings, and infos before committing. - Note:
npm run checkdoes not run tests. - NEVER run:
npm run dev npm testis allowed when the user asks for a full test run or when broad validation is needed.- For narrow changes, prefer specific tests:
npx tsx ../../node_modules/vitest/dist/cli.js --run test/specific.test.ts - Run package-specific tests from the package root. Run
npm testfrom the repo root when doing the full workspace test run. - If you create or modify a test file, you MUST run that test file and iterate until it passes.
- When writing tests, run them, identify issues in either the test or implementation, and iterate until fixed.
- For
packages/coding-agent/test/suite/, usetest/suite/harness.tsplus the faux provider. Do not use real provider APIs, real API keys, or paid tokens. - Put issue-specific regressions under
packages/coding-agent/test/suite/regressions/and name them<issue-number>-<short-slug>.test.ts. - For ad-hoc scripts, write the script to a temporary file (for example under
/tmp) usingwrite, run that file, edit it if needed, and remove it when it is no longer needed. Do not embed multi-line scripts directly inbashcommands. - Don't commit speculatively. Commit when the user asks, or when their task delegation continues a plan whose terminal step is commit/push (e.g. "마저진행해줘", "finish this", "계속해줘"). Treat such delegation as the ask — don't stall mid-plan to demand a literal "commit" keyword.
- Issues and PRs stay open for maintainer review.
- Issues and PRs that do not meet the quality bar in
CONTRIBUTING.mdmay be closed without extended triage.
When creating issues:
- Add
pkg:*labels to indicate which package(s) the issue affects- Available labels:
pkg:agent,pkg:ai,pkg:coding-agent,pkg:tui
- Available labels:
- If an issue spans multiple packages, add all relevant labels
When posting issue/PR comments:
- Write the full comment to a temp file and use
gh issue comment --body-fileorgh pr comment --body-file - Never pass multi-line markdown directly via
--bodyin shell commands - Preview the exact comment text before posting
- Post exactly one final comment unless the user explicitly asks for multiple comments
- If a comment is malformed, delete it immediately, then post one corrected comment
- Keep comments concise, technical, and in the user's tone
When closing issues via commit:
- Include
fixes #<number>orcloses #<number>in the commit message - This automatically closes the issue when the commit is merged
- Analyze PRs without pulling locally first
- If the user approves: create a feature branch, pull PR, rebase on main, apply adjustments, commit, merge into main, push, close PR, and leave a comment in the user's tone
- You never open PRs yourself. We work in feature branches until everything is according to the user's requirements, then merge into main, and push.
To test pi's TUI in a controlled terminal environment:
# Create tmux session with specific dimensions
tmux new-session -d -s pi-test -x 80 -y 24
# Start pi from source
tmux send-keys -t pi-test "cd /Users/badlogic/workspaces/pi-mono && ./pi-test.sh" Enter
# Wait for startup, then capture output
sleep 3 && tmux capture-pane -t pi-test -p
# Send input
tmux send-keys -t pi-test "your prompt here" Enter
# Send special keys
tmux send-keys -t pi-test Escape
tmux send-keys -t pi-test C-o # ctrl+o
# Cleanup
tmux kill-session -t pi-testLocation: packages/*/CHANGELOG.md (each package has its own)
Use these sections under ## [Unreleased]:
### Breaking Changes- API changes requiring migration### Added- New features### Changed- Changes to existing functionality### Fixed- Bug fixes### Removed- Removed features
- Before adding entries, read the full
[Unreleased]section to see which subsections already exist - New entries ALWAYS go under
## [Unreleased]section - Append to existing subsections (e.g.,
### Fixed), do not create duplicates - NEVER modify already-released version sections (e.g.,
## [0.12.2]) - Each version section is immutable once released
- Internal changes (from issues):
Fixed foo bar ([#123](https://github.com/earendil-works/pi-mono/issues/123)) - External contributions:
Added feature X ([#456](https://github.com/earendil-works/pi-mono/pull/456) by [@username](https://github.com/username))
Adding a new provider requires changes across multiple files:
- Add API identifier to
Apitype union (e.g.,"bedrock-converse-stream") - Create options interface extending
StreamOptions - Add mapping to
ApiOptionsMap - Add provider name to
KnownProvidertype union
Create provider file exporting:
stream<Provider>()function returningAssistantMessageEventStreamstreamSimple<Provider>()forSimpleStreamOptionsmapping- Provider-specific options interface
- Message/tool conversion functions
- Response parsing emitting standardized events (
text,tool_call,thinking,usage,stop)
- Add a package subpath export in
packages/ai/package.jsonpointing at./dist/providers/<provider>.js - Add
export typere-exports inpackages/ai/src/index.tsfor provider option types that should remain available from the root entry - Register the provider in
packages/ai/src/providers/register-builtins.tsvia lazy loader wrappers, do not statically import provider implementation modules there - Add credential detection in
packages/ai/src/env-api-keys.ts
- Add logic to fetch/parse models from provider source
- Map to standardized
Modelinterface
- Always add the provider to
stream.test.tswith at least one representative model, even if it reuses an existing API implementation such asopenai-completions. - Add the provider to the broader provider matrix where applicable:
tokens.test.ts,abort.test.ts,empty.test.ts,context-overflow.test.ts,unicode-surrogate.test.ts,tool-call-without-result.test.ts,image-tool-result.test.ts,total-tokens.test.ts,cross-provider-handoff.test.ts. - For
cross-provider-handoff.test.ts, add at least one provider/model pair. If the provider exposes multiple model families (for example GPT and Claude), add at least one pair per family. - For non-standard auth, create utility (e.g.,
bedrock-utils.ts) with credential detection.
src/core/model-resolver.ts: Add default model ID todefaultModelPerProvidersrc/core/provider-display-names.ts: Add API-key login display name so/loginand related UI show the provider for built-in API-key auth.src/cli/args.ts: Add env var documentationREADME.md: Add provider setup instructionsdocs/providers.md: Add setup instructions, env var, andauth.jsonkey
packages/ai/README.md: Add to providers table, document options/auth, add env varspackages/ai/CHANGELOG.md: Add entry under## [Unreleased]
Lockstep versioning: All packages always share the same version number. Every release updates all packages together.
Version semantics (no major releases):
patch: Bug fixes and new featuresminor: API breaking changes
-
Update CHANGELOGs: ask the user whether they ran the
/clprompt on the latest commit onmain. If not, they must run/clfirst to audit and update each package's[Unreleased]section before releasing. -
Local smoke test: build an unpublished release and smoke test from outside the repo so it cannot resolve workspace files:
npm run release:local -- --out /tmp/pi-local-release --force cd /tmp # Node package install smoke tests /tmp/pi-local-release/node/pi --help /tmp/pi-local-release/node/pi --version /tmp/pi-local-release/node/pi --list-models /tmp/pi-local-release/node/pi -p "Say exactly: ok" /tmp/pi-local-release/node/pi # Bun binary smoke tests /tmp/pi-local-release/bun/pi --help /tmp/pi-local-release/bun/pi --version /tmp/pi-local-release/bun/pi --list-models /tmp/pi-local-release/bun/pi -p "Say exactly: ok" /tmp/pi-local-release/bun/pi
Verify both Node and Bun startup, model/account listing, interactive startup, and at least one real prompt with the intended default provider. The bare commands
/tmp/pi-local-release/node/piand/tmp/pi-local-release/bun/pistart interactive mode; run each in tmux, submit a prompt, and wait for the model reply before considering the interactive smoke test passed. Failures are release blockers unless the user explicitly accepts the risk. -
Verify npm authentication: run
npm whoamibefore starting the release script. If it fails, stop and tell the user to runnpm loginmanually first, then retry after they confirmnpm whoamisucceeds. -
Brief the user on the WebAuthn flow before running anything. Print exactly the following message and then stop and wait for the user to confirm in their next message:
Before the release publish step, read this carefully: - `npm publish` uses WebAuthn 2FA. - The safest flow is for you to run the publish command yourself, because you can see and open the npm authentication URL immediately. - I will tell you the exact command to run. - When npm prints an auth URL, cmd/ctrl-click it, log in in the browser, and select the "don't ask again for N minutes" option if available. - This may happen more than once during publish. - Do not rerun `npm run release:patch` or `npm run release:minor` after a failed publish; only rerun the publish command I give you. Reply "ready" once you have read this and are ready to run the command locally.Do not proceed to step 5 until the user explicitly confirms.
-
Run the release script:
npm run release:patch # Fixes and additions npm run release:minor # API breaking changes
Do not pass a
timeoutto the bash tool for this call. If publish fails during the WebAuthn/OTP step after version bump, stop and tell the user to runnpm run publishthemselves from the repo root. Never rerun the version bump on your own. After the user reports publish success, continue with the post-publish steps. -
After publish succeeds:
- Add fresh
## [Unreleased]sections to package changelogs. - Commit with
Add [Unreleased] section for next cycle. - Push
mainand the release tag.
- Add fresh
Multiple agents may work on different files in the same worktree simultaneously. You MUST follow these rules:
- ONLY commit files YOU changed in THIS session
- ALWAYS include
fixes #<number>orcloses #<number>in the commit message when there is a related issue or PR - NEVER use
git add -Aorgit add .- these sweep up changes from other agents - ALWAYS use
git add <specific-file-paths>listing only files you modified - Before committing, run
git statusand verify you are only staging YOUR files - Track which files you created/modified/deleted during the session
- It is always fine to include
packages/ai/src/models.generated.tsin a commit alongside the actual files you want to commit
These commands can destroy other agents' work:
git reset --hard- destroys uncommitted changesgit checkout .- destroys uncommitted changesgit clean -fd- deletes untracked filesgit stash- stashes ALL changes including other agents' workgit add -A/git add .- stages other agents' uncommitted workgit commit --no-verify- bypasses required checks and is never allowed
# 1. Check status first
git status
# 2. Add ONLY your specific files
git add packages/ai/src/providers/transform-messages.ts
git add packages/ai/CHANGELOG.md
# 3. Commit
git commit -m "fix(ai): description"
# 4. Push (pull --rebase if needed, but NEVER reset/checkout)
git pull --rebase && git push- Resolve conflicts in YOUR files only
- If conflict is in a file you didn't modify, abort and ask the user
- NEVER force push
If the user instructions conflict with rules set out here, ask for confirmation that they want to override the rules. Only then execute their instructions.