10 KiB
Development Rules
Conversational Style
- 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!")
Code Quality
- No
anytypes unless absolutely necessary - 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
- 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)
Commands
- 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 run build,npm test - Only run specific tests if user instructs:
npx tsx ../../node_modules/vitest/dist/cli.js --run test/specific.test.ts - Run tests from the package root, not the repo root.
- 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. - NEVER commit unless user asks
Contribution Gate
- New issues from new contributors are auto-closed by
.github/workflows/issue-gate.yml - New PRs from new contributors without PR rights are auto-closed by
.github/workflows/pr-gate.yml - Maintainer approval comments are handled by
.github/workflows/approve-contributor.yml - Maintainers review auto-closed issues daily
- Issues that do not meet the quality bar in
CONTRIBUTING.mdare not reopened and do not receive a reply lgtmiapproves future issueslgtmapproves future issues and rights to submit PRs
When creating issues:
- Add
pkg:*labels to indicate which package(s) the issue affects- Available labels:
pkg:agent,pkg:ai,pkg:coding-agent,pkg:mom,pkg:pods,pkg:tui,pkg:web-ui
- 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
PR Workflow
- 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.
Testing pi Interactive Mode with tmux
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-test
Changelog
Location: packages/*/CHANGELOG.md (each package has its own)
Format
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
Rules
- 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
Attribution
- Internal changes (from issues):
Fixed foo bar ([#123](https://github.com/badlogic/pi-mono/issues/123)) - External contributions:
Added feature X ([#456](https://github.com/badlogic/pi-mono/pull/456) by [@username](https://github.com/username))
Adding a New LLM Provider (packages/ai)
Adding a new provider requires changes across multiple files:
1. Core Types (packages/ai/src/types.ts)
- 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
2. Provider Implementation (packages/ai/src/providers/)
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)
3. Provider Exports and Lazy Registration
- 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
4. Model Generation (packages/ai/scripts/generate-models.ts)
- Add logic to fetch/parse models from provider source
- Map to standardized
Modelinterface
5. Tests (packages/ai/test/)
Add provider to: stream.test.ts, tokens.test.ts, abort.test.ts, empty.test.ts, context-overflow.test.ts, image-limits.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.
6. Coding Agent (packages/coding-agent/)
src/core/model-resolver.ts: Add default model ID toDEFAULT_MODELSsrc/cli/args.ts: Add env var documentationREADME.md: Add provider setup instructions
7. Documentation
packages/ai/README.md: Add to providers table, document options/auth, add env varspackages/ai/CHANGELOG.md: Add entry under## [Unreleased]
Releasing
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
Steps
-
Update CHANGELOGs: Ensure all changes since last release are documented in the
[Unreleased]section of each affected package's CHANGELOG.md -
Run release script:
npm run release:patch # Fixes and additions npm run release:minor # API breaking changes
The script handles: version bump, CHANGELOG finalization, commit, tag, publish, and adding new [Unreleased] sections.
CRITICAL Git Rules for Parallel Agents CRITICAL
Multiple agents may work on different files in the same worktree simultaneously. You MUST follow these rules:
Committing
- 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
Forbidden Git Operations
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
Safe Workflow
# 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
If Rebase Conflicts Occur
- Resolve conflicts in YOUR files only
- If conflict is in a file you didn't modify, abort and ask the user
- NEVER force push
User override
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.