Development Rules #
Conversational Style #
- No fluff or cheerful filler text
- Keep answers short and concise
- No emojis in commits, issues, PR comments, or code
- Technical prose only, be kind but direct (e.g., "Thanks @user" not "Thanks so much @user!")
Code Quality #
- 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.
- Don't be too verbose with comments in the code. Only write comments when there is serious ambiguity
- 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) - NEVER modify
packages/ai/src/models.generated.tsdirectly. Updatepackages/ai/scripts/generate-models.tsinstead.
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.
Testing Policy #
npm run check:test-policyis required. Never weaken it or add a broad exclusion. A platform exception must use// test-policy: allow <rule> -- <specific reason>immediately above one expression, and CI must run that test on a supported platform.- A test must fail when the behavior it covers is broken. Temporarily revert or stub the production behavior to prove the failure. If the test still passes, delete it.
- Test observable behavior at process boundaries, durable formats, concurrency/ordering, crash recovery, and load. Do not assert a mock's own return value, private implementation steps, or exact rendered copy unless that text is a protocol contract.
- CI tests must be unconditional and self-contained. Do not use live provider APIs, real credentials, paid tokens,
.skip,.skipIf,.runIf,.todo,.only, environment-gated early returns, or optional assertions. Put manual live-provider probes outside the CI test suite. - Never use runner retries or retry-to-green wrappers. Every failed attempt counts as a failure. Fix the race or delete the test.
- Never use a fixed sleep, real-time delay, polling loop, or larger timeout as a readiness signal. Await a concrete event or deferred promise, use a fake clock, or expose the missing completion signal. A timer may only bound failure; it must not make the test pass.
- Tests using subprocesses, sockets, concurrency, or shared process state must bind port
0, use unique temporary paths, restore environment/cwd/globals/fake timers, and close every resource infinally. - Run every modified test file directly. For concurrency, process, timer, or ordering changes, also run the focused suite repeatedly with multiple shuffle seeds. Stop on the first failure; repeated runs are evidence, never retries.
- A change may not add more lines of test than source. A test-only change must delete at least as many test lines as it adds.
- Regressions go in the existing suite for the module that broke, with the issue number in the test name. Never create one file per issue. One test file per source module; repeated cases belong in an
it.eachtable. - Deleting code deletes its tests. A flaky test is made deterministic or deleted, never skipped or retried.
Daemon Protocol Changes #
- Classify every daemon command, event, and response-shape change as backward-compatible, capability-gated, or incompatible.
- Add optional features behind a negotiated server capability. Clients must check the capability before sending the command or depending on the event.
- Bump
DAEMON_PROTOCOL_VERSIONfor incompatible changes or when startup begins requiring behavior an older daemon cannot provide. - Update
DAEMON_SCHEMA_REVISION, the command/event compatibility maps, and both new-client/old-daemon and old-client/new-daemon tests for every wire change. - Optional daemon metadata and UI features must degrade locally. They must not prevent the agent, session attachment, or interactive startup from working.
- Never make a new daemon command part of startup without a protocol or capability gate.
GitHub Workflow #
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
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
- We work in feature branches until everything is according to the user's requirements. Never merge PRs by yourself.
Testing Prime Agent Interactive Mode with tmux #
To test Prime Agent's TUI in a controlled terminal environment:
# Create tmux session with specific dimensions
tmux new-session -d -s prime-agent-test -x 80 -y 24
# Start Prime Agent from source
tmux send-keys -t prime-agent-test "cd /Users/kevin/pi/prime-agent && ./prime-agent.sh" Enter
# Wait for startup, then capture output
sleep 3 && tmux capture-pane -t prime-agent-test -p
# Send input
tmux send-keys -t prime-agent-test "your prompt here" Enter
# Send special keys
tmux send-keys -t prime-agent-test Escape
tmux send-keys -t prime-agent-test C-o # ctrl+o
# Cleanup
tmux kill-session -t prime-agent-test
You, yourself, are often running into a tmux session, so be careful when killing tmux sessions. Lots of other processes can be running on different tmux sessions/
Changelog #
Location: packages/<pkg>/.changes/<slug>.md (one fragment file per PR per touched package)
Format #
Do NOT edit packages/*/CHANGELOG.md directly. Instead, add a fragment file packages/<pkg>/.changes/<slug>.md (slug = kebab-case, branch- or ticket-derived, e.g. eng-1234-fix-resize.md) containing exactly the bullet line(s) for the change. Bullets are plain - ... lines with no ### Added / ### Changed / ### Fixed / ### Removed subsections — one bullet per change, written as a short sentence starting with a past-tense verb (Added, Changed, Fixed, Removed). Keep each bullet to one line; describe the user-visible change, not the implementation. The release script folds fragments into the release section of CHANGELOG.md and deletes them.
Example fragment (packages/coding-agent/.changes/eng-1234-effort-command.md):
- Added `/effort` to set the reasoning level, with autocomplete for the levels the current model supports.
Rules #
- One fragment file per PR per touched package; a fragment may contain multiple bullets
- NEVER modify already-released version sections in CHANGELOG.md (e.g.,
## [0.2.1]) — each is immutable once released - Purely internal changes may opt out via the
no-changelogPR label
Attribution #
- Internal changes (from issues):
Fixed foo bar ([#123](https://github.com/PrimeIntellect-ai/prime-agent/issues/123)) - External contributions:
Added feature X ([#456](https://github.com/PrimeIntellect-ai/prime-agent/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/) #
- 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,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 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
7. Documentation #
packages/ai/README.md: Add to providers table, document options/auth, add env varspackages/ai/.changes/<slug>.md: Add a changelog fragment (see Changelog above)
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 #
-
Check fragments: Ensure all changes since last release have fragment files in
packages/<pkg>/.changes/ -
Run release script:
npm run release:patch # Fixes and additions npm run release:minor # API breaking changes
The script handles: version bump, folding .changes/ fragments into the release section, commit, tag, and publish.
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 use the pre-imported Python
gitskill functions (git.status(),git.add(...),git.commit(...),git.log(...),git.diff(...)) instead of shelling out to bash - ALWAYS include
fixes #<number>orcloses #<number>in the commit message when there is a related issue or PR - NEVER use
git.add_all()orgit add .- these sweep up changes from other agents - ALWAYS pass specific file paths:
git.add("path/to/file") - Before committing, run
git.status()and 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
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 revert- never add a revert commit; drop the commit instead (see below)git commit --no-verify- bypasses required checks and is never allowed
Rewriting Instead of Reverting #
This repository is dawn's fork (origin = knot.gaze.systems), so a commit that should not exist is dropped, never reverted. Never leave a Revert "..." commit in the history.
- Drop commits from the tip:
git reset --soft <target>moves the branch tip and leaves the index and worktree alone, so the tree you want is already staged; recommit it as one commit. - Replay the commits you keep onto a new base:
git rebase --onto <new-base> <old-base>. It needs a clean worktree, so with other agents' uncommitted edits in the tree, prefergit reset --softplus one commit. - Fetch first, then
git push --force-with-lease. Only rewrite commits you are dropping yourself: never force-push over commits you did not author or that someone else pushed since your fetch. - The rewritten review is the tree, not the commit count: verify with
git rev-parse <old>^{tree} <new>^{tree}that dropping commits changed no file.
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/.changes/eng-1234-fix-resize.md")
# 3. Commit
git.commit("fix(ai): description")
# 4. Push (pull first if needed, but NEVER reset/checkout)
git.pull(rebase=True)
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 over another agent's commits;
--force-with-leaseafter a fetch is the only allowed rewrite ofmain