# my-pi 维护约定(优先于下文上游约定) - 扩展入口是 `pi-subagents/src/index.ts`,测试保留在该目录的 `test/`,来源记录是 `pi-subagents/UPSTREAM.md`。 - 同步上游必须从明确 tag/commit 移植并保留 README、CHANGELOG、SECURITY、作者和 LICENSE;不得导入嵌套 `.git`、上游 `.pi` 状态、`node_modules`、覆盖率或构建产物。 - 根包必须通过 `file:./pi-subagents` 提供运行时依赖,并只通过 `extensions/subagents.ts` wrapper 直接加载仓库源码;不得绕过 wrapper 直接列出上游入口,不得同时安装或加载 npm 预编译入口,也不得把 Pi host runtime 作为组合包开发依赖带入根安装。3 个根编排工具由 Tool Search 的 `subagents` 组按需加载。 - 子会话必须在 `bindExtensions()` 前注册到 `pi-permission-system` 的 process-global child registry,并在真实 dispose 时清理;resume、并发和嵌套 Agent 必须维持正确 parent/child session identity。 - `extensions/subagents.ts` 是组合包配置入口:它只能把组合包内权威 `extensions/permission-system.ts` 的 canonical absolute path 作为 mandatory extension 注入。Agent frontmatter 的 `extensions: false`、`isolated` 和 `exclude_extensions` 均不得移除该 lifecycle;路径缺失、被同名其他路径冒充或 reload 后未精确命中必须在创建 AgentSession 前 fail-closed。 - mandatory extension 只强制绑定 handlers,不自动开放它注册的工具;工具可见性仍由 Agent 的正常 extensions/tools 策略决定。mandatory 列表不得从 Agent Markdown 或项目配置读取。 - 三个 my-pi 扩展选项必须保持 opt-in 且上游兼容,不传时 `buildAgentPrompt` 逐字节维持上游行为:`basePrompt?: () => string | undefined`(返回非空串时替代父提示词嵌入,省略 `` 与 replace 头,保留环境/worktree/custom 分区与 extras,`` tag 仍恰好一个);`bundledAgentsDir?: string`(目录下 `*.md` 经现有 parser 加载为内置 Agent,替换同名嵌入默认项、排序确定性,标记 `isDefault` 无 `source`/`sourcePath`,优先级 embedded < bundled < global < workspace < project);`excludedExtensionPaths?: readonly string[]`(canonical 化后从每个子会话加载扩展中移除,无论 frontmatter,与 mandatory 路径重叠必须 fail closed)。组合包由 `extensions/subagents.ts` 注入 `config/prompt/subagent/` preamble 与 agents 目录并排除 `pi-ask-user`。 - `ask` 可由 auto-review 明确 `allow` 时自动批准,包括路径请求;reviewer `defer` 或异常必须转发父会话人工 authority,不得因子会话无 UI 静默放宽。父模型生成的子 Agent prompt 不得伪装成人类直接授权证据。 - 子 Agent 转发的 access facts 必须先由根 authority 的 `SessionRules` 匹配;父会话 whole-session grant 可覆盖语义一致的后代操作,普通单次批准不得复制为可重复消费的子 Agent grant。auto-review 必须运行在根会话并只使用根 transcript 的可信用户证据。 - 修改 Agent lifecycle、权限桥接、tool/extension scope、resume、nested agents 或 session persistence 时,必须同步包内 README、CHANGELOG、测试,并运行 `npm run lint`、`npm run typecheck`、`npm run test` 和 `npm run build`。 # Development Rules ## Conversational Style - Keep answers short and concise - No emojis in issues, PR comments, or code - No fluff or cheerful filler text (e.g., "Thanks @user" not "Thanks so much @user!") - Technical prose only, be direct - When the user asks a question, answer it first before making edits or running implementation commands. - When responding to user feedback or an analysis, explicitly say whether you agree or disagree before saying what you changed. ## Code Quality - Read files in full before wide-ranging changes, before editing files you have not fully inspected, and when asked to investigate or audit. Do not rely on search snippets for broad changes. - No `any` unless absolutely necessary. - Inline single-line helpers that have only one call site. - Check `node_modules` for external API types (`@earendil-works/pi-*`, `@sinclair/typebox`, etc.); don't guess. - **No inline imports** (`await import()`, `import("pkg").Type`, dynamic type imports). Top-level imports only. - Never remove or downgrade code to fix type errors from outdated deps; upgrade the dep instead. - Match the surrounding code style — it is enforced by biome (`biome.json`). - Always ask before removing functionality or code that appears intentional. - Do not preserve backward compatibility unless the user asks for it. - This is a pi extension. Respect the Claude Code-compatible tool names, calling conventions, and UI patterns the extension deliberately mirrors; don't diverge from them without a stated reason. - When reviewing a diff, favor solutions that are elegant, not overengineered — flag needless abstraction, layering, or defensive code that the change doesn't warrant. ## Commands - After code changes (not docs), run the full check suite and fix all errors and warnings: ```bash npm run lint # biome npm run typecheck # tsc --noEmit npm run test # vitest run ``` - `npm run lint:fix` auto-fixes most style issues. - `npm run test` runs the whole suite, including `*-e2e.test.ts` files. To iterate on a single file, run it directly: `npx vitest run test/.test.ts`. - If you create or modify a test file, run it and iterate on the test or implementation until it passes. - `npm run build` compiles with `tsc`; run it only when verifying the build output or when requested. - For ad-hoc scripts, write them to a temp file (e.g. `/tmp`), run, edit if needed, remove when done. Don't embed multi-line scripts in `bash` commands. ## Git - **Never commit.** The user commits manually. At most, suggest a concise commit message as text. - **Never push**, tag, or create branches unless the user explicitly asks. - Never run history- or worktree-destroying commands: `git reset --hard`, `git checkout .`, `git clean -fd`, `git stash`, `git add -A`, `git add .`, `git commit --no-verify`, or any force push. - Leave the working tree as the user left it — don't stage, stash, or revert files you didn't change. ## Issues and PRs See `CONTRIBUTING.md` for the contributor guidelines and quality bar. When reviewing PRs: - Do not run `gh pr checkout`, `git switch`, or otherwise move the worktree to the PR branch unless the user explicitly asks. - Use `gh pr view`, `gh pr diff`, `gh api`, and local `git show`/`git diff` against fetched refs to inspect PR metadata, commits, and patches without changing branches. - If you need PR file contents, fetch/read them into temporary files or use `git show :` without switching branches. When posting issue/PR comments: - Write the comment to a temp file and post with `gh issue/pr comment --body-file` (never multi-line markdown via `--body`). - Keep comments concise, technical, and in the user's tone. ## Changelog Location: `CHANGELOG.md` (single file, [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) format). - All new entries go under `## [Unreleased]`, in the right subsection (`### Added`, `### Changed`, `### Fixed`, `### Removed`, `### Security`, `### Refactored`). Read the section first and append to existing subsections; never duplicate them. - One bullet per issue/PR. Never combine separate issues or pull requests into a single entry, even when they touch the same or similar components. (A PR together with the issue it closes or that diagnosed it is one change — one bullet citing both.) - Breaking changes are not a separate subsection. Call them out with a `> **⚠️ Breaking: …**` blockquote at the top of the version section, and/or a bold `**BREAKING:**` bullet under `### Changed`, with a migration note. - Entries are concise — a bold lead-in stating what changed, then a sentence or two on why it changed and anything a user must do about it. Aim for 2–4 sentences; a genuinely intricate change may run longer, but length is never the goal. Do not match the density of older entries, several of which are far too long. - Cut what the reader doesn't need: narration of the investigation, alternatives considered and rejected, restatements of the diff, and detail recoverable from the code or the linked issue. Name a file or symbol only when it helps someone find the change. - Released version sections (e.g. `## [0.12.0]`) are immutable; never modify them. - Attribute external contributions: `... ([#456](https://github.com/tintinweb/pi-subagents/pull/456) — thanks [@username](https://github.com/username))`. ## Releasing **Versioning** (all releases are `0.x`, no major bumps): - `minor` (`0.x.0`) — a notable new feature, or any breaking change. - `patch` (`0.x.y`) — bug fixes and smaller additions. Before a release: - Update `CHANGELOG.md` — move the `## [Unreleased]` entries under a new `## [X.Y.Z]` version section, and add a fresh empty `## [Unreleased]` for the next cycle. - Update `README.md` if user-facing behavior changed (features list, settings, usage). - Run the full check suite plus the e2e tests, and fix anything that fails: ```bash npm run lint npm run typecheck npm run test:e2e # faux/scripted e2e — no network, no keys npm run build ``` - For a real pre-publish smoke test, run the **live** e2e against an actual model: ```bash PI_E2E_LIVE=1 npm run test:e2e # uses your local `pi` login; optional PI_PROVIDER / PI_MODEL ``` `PI_E2E_LIVE=1` swaps the scripted faux suite for the live one (the faux suite is `skipIf(LIVE)`). (`prepublishOnly` runs lint + typecheck + test + build; the live e2e is the smoke test to run by hand before publishing.) **Never publish.** The user runs `npm version` / `npm publish` and any tagging manually. Do not run those commands unless the user explicitly asks. ## User Override If the user's instructions conflict with any rule in this document, ask for explicit confirmation before overriding. Only then execute their instructions.