|
2 | 2 |
|
3 | 3 | Reply in English unless the user explicitly asks you to respond in another language. |
4 | 4 |
|
5 | | -This is a TypeScript monorepo built for agent-assisted development. Keep the root `AGENTS.md` limited to hot-path rules: the project map, hard constraints, and workflow requirements — things every task needs to know. |
| 5 | +This is a TypeScript monorepo for **pythinker-code**, a multi-provider AI coding agent. Keep the root `AGENTS.md` limited to hot-path rules: product identity, project map, hard constraints, and workflow requirements. |
| 6 | + |
| 7 | +## Product Identity |
| 8 | + |
| 9 | +**pythinker-code** is an agentic coding assistant that plans, writes, tests, and iterates on code autonomously. Its defining trait is **provider-agnostic model selection**: the same agent runtime talks to any supported LLM through the `packages/kosong` abstraction layer. |
| 10 | + |
| 11 | +### Supported Wire Types |
| 12 | + |
| 13 | +| Wire type | SDK / transport | Native providers | |
| 14 | +| ------------------ | ----------------------- | ------------------------------------------------------------------------------ | |
| 15 | +| `anthropic` | `@anthropic-ai/sdk` | Anthropic (Claude 3 / 3.5 / 3.7 / Opus 4–5 / Sonnet 4–5 / Haiku 4.5 / Fable 5) | |
| 16 | +| `openai` | OpenAI Chat Completions | OpenAI (GPT-4o, GPT-4.1, GPT-4.5, GPT-5.4–5.6 Sol/Terra/Luna, GPT-3.5-turbo) | |
| 17 | +| `openai_responses` | OpenAI Responses API | OpenAI (GPT-4.1, GPT-5.6 Sol/Terra/Luna, o1, o3, o3-pro, o4-mini) | |
| 18 | +| `google-genai` | `@google/genai` | Google (Gemini 2.0 / 2.5 Pro & Flash; 3.x via catalog) | |
| 19 | +| `vertexai` | Google Vertex AI | Google Cloud–hosted Gemini models | |
| 20 | +| `pythinker` | Pythinker managed API | Any model proxied through Pythinker's own endpoint | |
| 21 | + |
| 22 | +### OpenAI-Compatible Providers |
| 23 | + |
| 24 | +Any provider exposing an OpenAI-compatible `/chat/completions` or `/v1` endpoint can be used through the `openai` or `openai_responses` wire type with a custom `baseURL`. This includes — but is not limited to: |
| 25 | + |
| 26 | +- **DeepSeek** (DeepSeek-V4-Pro, DeepSeek-V4-Flash, DeepSeek-R1) |
| 27 | +- **Alibaba Qwen** (Qwen3.8-Max, Qwen3.7, Qwen3-Coder) |
| 28 | +- **Zhipu GLM** (GLM-5.2, GLM-5.1) |
| 29 | +- **MiniMax** (MiniMax M3) |
| 30 | +- **Moonshot / Kimi** (Kimi K3) |
| 31 | +- **xAI Grok** (Grok 4.5, Grok 4.3), **Together AI**, **Fireworks**, **Perplexity**, and other OpenAI-compatible hosts |
| 32 | + |
| 33 | +### Model Selection |
| 34 | + |
| 35 | +Model selection flows through the **catalog system** (`packages/kosong/src/catalog.ts`): |
| 36 | + |
| 37 | +1. An external `models.dev`-style JSON catalog maps `providerId → models[]`, each with context window, capabilities, cost rates, and modality metadata. |
| 38 | +2. `inferWireType()` resolves a catalog provider to its wire type — explicit `type` field first, then heuristic matching on `npm`/`id`. |
| 39 | +3. `createProvider()` instantiates the correct `ChatProvider` implementation for the resolved wire. |
| 40 | +4. Capability lookups (`getModelCapability()`) return vision, tool-use, thinking, and fast-mode flags per model, enabling the agent runtime to adapt prompting strategy to each model's strengths. |
| 41 | + |
| 42 | +Adding a new provider requires **zero code changes** when it is OpenAI-compatible — just add the entry to the catalog JSON. |
6 | 43 |
|
7 | 44 | ## Working Principles |
8 | 45 |
|
9 | | -- Think from first principles. Start from real requirements, code facts, and verification results; if the goal is unclear, discuss it with the user first. |
10 | | -- Treat code, not documentation, as the source of truth. Unless the user explicitly says otherwise, do not read ordinary Markdown just to understand the implementation. |
11 | | -- When version information or an external claim may be outdated, incorrect, or ambiguous, validate it against the latest authoritative documentation using Context7 MCP and Tavily. |
12 | | -- Before making code changes, read the relevant code and the most recent constraints, and follow the nearest `AGENTS.md` in the directory tree. |
13 | | -- Keep changes focused. Do not slip in unrelated refactors along the way. |
14 | | -- Do not preserve backward compatibility. Implement the current requirements directly instead of retaining legacy paths, shims, or fallbacks. |
15 | | -- Choose the simplest implementation that fully meets the current requirements: reach for the standard library and existing platform features before writing custom code or adding a dependency, and question whether a piece of work needs to exist at all. The `ponytail` skill encodes this discipline — invoke it when a change looks over-engineered, is growing past the size the task warrants, or is about to add an abstraction or dependency. Do not invoke it on trivial edits; the point is minimalism, not ceremony. |
16 | | -- When the standard library and existing platform features are insufficient, prefer established, well-maintained libraries over custom implementations. |
17 | | -- When committing, do not add any co-author attribution, and do not reveal the identity of the agent in commit messages, PR descriptions, or any explanatory text. |
18 | | -- The professional Git identity `elkaix <melkholy@techmatrix.com>` is explicitly authorized for author and committer metadata in this repository. Apply it per command; never modify git config or reuse the address outside Git identity metadata and this rule. |
| 46 | +- Think from first principles; start from requirements, code facts, and verification — discuss unclear goals with the user first. |
| 47 | +- Treat code as the source of truth. Do not read Markdown to understand implementation unless the user says otherwise. |
| 48 | +- Validate outdated or ambiguous version claims against authoritative docs using Context7 MCP and Tavily. |
| 49 | +- Before changing code, read the relevant source and follow the nearest `AGENTS.md` in the directory tree. |
| 50 | +- Keep changes focused — no drive-by refactors. |
| 51 | +- Do not preserve backward compatibility; implement current requirements directly without legacy shims. |
| 52 | +- Choose the simplest implementation: standard library and platform features first, then established libraries, then custom code. Use the `ponytail` skill when a change looks over-engineered (skip it on trivial edits). |
| 53 | +- Do not add co-author attribution or reveal agent identity in commits, PRs, or explanatory text. |
| 54 | +- Git identity: `elkaix <melkholy@techmatrix.com>` — apply per command; never modify git config or reuse the address elsewhere. |
19 | 55 |
|
20 | 56 | ## Project Map |
21 | 57 |
|
22 | | -- `apps/pythinker-code`: the CLI / TUI application. It consumes core capabilities through `@pythoughts/pythinker-code-sdk` and must not depend directly on `@pythoughts/agent-core`. When writing or modifying its terminal UI, use the `write-tui` skill (`.agents/skills/write-tui/SKILL.md`). |
23 | | -- `apps/pythinker-web`: the browser web UI, a peer to the TUI. Vue 3 + Vite + vue-i18n; talks to the server over REST + WebSocket under `/api/v1`. It must not depend on `@pythoughts/agent-core` (wire types are re-implemented locally). See `apps/pythinker-web/AGENTS.md`. |
24 | | -- `apps/dashboard`, `apps/dashboard/server`, `apps/dashboard/web`: session dashboard and debugging tools for sessions and replays. |
25 | | -- `packages/agent-core`: the unified agent engine, including Agent, Session, profile, skills, tools, plan, permission, background, records, the in-process DI service layer (`src/services/`), and other core capabilities. |
26 | | -- `packages/node-sdk`: the public TypeScript SDK and harness. |
27 | | -- `packages/kosong`: the LLM / provider abstraction layer. |
28 | | -- `packages/kaos`: the execution environment and file/process abstractions. |
29 | | -- `packages/oauth`: Pythinker OAuth and managed auth utilities. |
30 | | -- `packages/telemetry`: shared client-side telemetry infrastructure. |
31 | | -- `packages/server`: the Pythinker Code server. Hosts `agent-core` sessions and exposes them over REST + WebSocket (`/api/v1`); bootstrapped from `src/start.ts` and consumed by `apps/pythinker-code`. See `packages/server/AGENTS.md`. |
32 | | -- `packages/server-e2e`: live e2e tests and scenarios against a running server (`PYTHINKER_SERVER_URL`, default `http://127.0.0.1:58627`). See `packages/server-e2e/AGENTS.md`. |
| 58 | +- `apps/pythinker-code` — CLI / TUI app. Consumes `@pythoughts/pythinker-code-sdk`; must not depend on `@pythoughts/agent-core`. Use the `write-tui` skill for TUI changes. |
| 59 | +- `apps/pythinker-web` — Browser UI (Vue 3 + Vite + vue-i18n). REST + WebSocket under `/api/v1`; must not depend on `@pythoughts/agent-core`. See `apps/pythinker-web/AGENTS.md`. |
| 60 | +- `apps/dashboard` (`server/`, `web/`) — Session dashboard and replay tools. |
| 61 | +- `packages/agent-core` — Unified agent engine: Agent, Session, profile, skills, tools, plan, permission, background, records, DI services. |
| 62 | +- `packages/node-sdk` — Public TypeScript SDK and harness. |
| 63 | +- `packages/kosong` — LLM provider abstraction layer (wire types, catalog, capability registry). |
| 64 | +- `packages/kaos` — Execution environment, file/process abstractions. |
| 65 | +- `packages/oauth` — Pythinker OAuth and managed auth utilities. |
| 66 | +- `packages/telemetry` — Shared client-side telemetry. |
| 67 | +- `packages/server` — Pythinker Code server; hosts `agent-core` sessions over REST + WebSocket (`/api/v1`). See `packages/server/AGENTS.md`. |
| 68 | +- `packages/server-e2e` — Live e2e tests against a running server (`PYTHINKER_SERVER_URL`, default `http://127.0.0.1:58627`). See `packages/server-e2e/AGENTS.md`. |
33 | 69 |
|
34 | | -## Environment Requirements |
| 70 | +## Environment |
35 | 71 |
|
36 | | -- **Node.js**: `>=26.4.0` (from the root `package.json` `engines`; `.nvmrc` is `26.4.0`, used by nvm / fnm / mise to pick the minimum recommended version). |
37 | | -- **pnpm**: `10.33.0` (from the root `package.json` `packageManager`). |
38 | | -- `pnpm install` will fail when the Node version is not satisfied, because `.npmrc` sets `engine-strict=true`. |
| 72 | +- **Node.js** `>=26.4.0` (`.nvmrc` is `26.4.0`). **pnpm** `10.33.0` (root `packageManager`). |
| 73 | +- `pnpm install` enforces the Node version (`engine-strict=true` in `.npmrc`). |
39 | 74 |
|
40 | 75 | ## Monorepo Workspace Maintenance |
41 | 76 |
|
42 | | -- `pnpm-workspace.yaml` is the source of truth for workspace membership, but `flake.nix` also contains **hardcoded** `workspacePaths` and `workspaceNames` lists. |
43 | | -- **Whenever you add or remove a workspace package, you MUST update both `pnpm-workspace.yaml` and `flake.nix` — for every package, including leaf / test / e2e packages that nothing depends on.** |
44 | | - - `pnpm-workspace.yaml` uses globs (`packages/*`, `apps/*`), so most packages land there automatically; `flake.nix` is fully manual and is where omissions happen. |
45 | | - - Missing a path in `flake.nix`'s `workspacePaths` will silently drop files from the Nix build's `src` fileset. |
46 | | - - Missing a name in `flake.nix`'s `workspaceNames` will break `pnpmConfigHook` because dependencies for that workspace will not be fetched. |
47 | | -- The automated "Check flake.nix workspace sync" (`scripts/check-nix-workspace.mjs`) only validates the transitive dependency **closure of `@pythoughts/pythinker-code`**. A leaf package outside that closure (e.g. an e2e package nobody imports) slips through even when it is missing from `flake.nix`. A green check is therefore NOT proof that `flake.nix` is fully in sync — keep it updated by hand on every add/remove, do not rely on the check to catch omissions. |
48 | | - |
49 | | -## General Coding Rules |
50 | | - |
51 | | -- Keep the codebase English-only: no non-English text (including CJK characters) in source code, tests, comments, or docs sources. Use ASCII/Latin fixtures (e.g. `café`) when a test needs a unicode example. |
52 | | -- `packages/acp-adapter` must stay on `@agentclientprotocol/sdk` `^0.23.0`. Versions 0.24+ removed the unstable session-model API (`SetSessionModelRequest`, `ModelId`, `unstable_setSessionModel`) the adapter implements — do not bump this dependency as a drive-by. |
53 | | -- `tsgo` (TypeScript 7 native preview, `@typescript/native-preview`, workspace-root devDependency) is available via `npx tsgo -p <tsconfig> --noEmit` for fast typechecks. The committed `typecheck` scripts still run `tsc`; run both when verifying type fixes. |
54 | | - |
55 | | -- For optional object properties, pass `undefined` directly instead of using conditional spread. |
56 | | - - YES: `{ user }` |
57 | | - - NO: `{ ...(user ? { user } : undefined) }` |
58 | | -- Optional object properties do not need to additionally allow `undefined` in the type. |
59 | | - - YES: `interface Options { user?: User }` |
60 | | - - NO: `interface Options { user?: User | undefined }` |
61 | | -- Internal methods with only a single parameter should not be turned into options objects just for stylistic uniformity. |
62 | | -- Except for a package's `index.ts`, other `index.ts` files should prefer `export * from './module';`. |
63 | | -- The `Agent` class in `packages/agent-core/src/agent` must be usable on its own. The constructor must not force the caller to create a `Session` instance, nor require an `agentId` or `session`. It may accept an optional `sessionId` as a request-config hint — for example mapped to the provider's `prompt_cache_key` — but the instance must not hold `sessionId`, and must not depend on the Session lifecycle, metadata, or parent/child relationship logic. |
64 | | -- Do not add too many new test files. Prefer adding tests to the existing test file of the corresponding component or module. |
65 | | -- When a test fails because of a user modification, default to fixing the test first; do not change the implementation to satisfy an old test unless the implementation truly has a bug. |
66 | | -- Do not sacrifice code quality for external compatibility unless the user explicitly asks for it. Breaking changes go through changesets and a `major` bump, gated by the rule below. |
| 77 | +- `pnpm-workspace.yaml` is the source of truth, but `flake.nix` has **hardcoded** `workspacePaths` and `workspaceNames`. |
| 78 | +- **When adding or removing any workspace package, update both `pnpm-workspace.yaml` and `flake.nix`** — even leaf/test/e2e packages. Missing a path silently drops files from the Nix build; missing a name breaks `pnpmConfigHook`. |
| 79 | +- The CI check (`scripts/check-nix-workspace.mjs`) only validates the transitive closure of `@pythoughts/pythinker-code` — leaf packages outside that closure can slip through. Keep `flake.nix` updated by hand. |
| 80 | + |
| 81 | +## Coding Rules |
| 82 | + |
| 83 | +- English-only codebase: no non-English text in source, tests, comments, or docs. Use ASCII/Latin fixtures (e.g. `café`) for unicode tests. |
| 84 | +- `packages/acp-adapter` must stay on `@agentclientprotocol/sdk` `^0.23.0` — 0.24+ removed the unstable session-model API it implements. |
| 85 | +- `tsgo` (`@typescript/native-preview`) is available via `npx tsgo -p <tsconfig> --noEmit` for fast typechecks; committed `typecheck` scripts still run `tsc` — run both when verifying type fixes. |
| 86 | +- For optional object properties, pass `undefined` directly — not conditional spread (`{ ...(x ? { x } : undefined) }`). |
| 87 | +- Optional properties do not need `| undefined` in the type (`user?: User`, not `user?: User | undefined`). |
| 88 | +- Single-parameter internal methods stay as single parameters — do not wrap in an options object. |
| 89 | +- Non-root `index.ts` files should prefer `export * from './module'`. |
| 90 | +- The `Agent` class (`packages/agent-core/src/agent`) must be standalone: no mandatory `Session`, `agentId`, or `session`. It may accept an optional `sessionId` as a provider hint but must not hold it or depend on Session lifecycle. |
| 91 | +- Prefer adding tests to existing test files over creating new ones. |
| 92 | +- When a test fails after a user modification, fix the test first unless the implementation has a real bug. |
| 93 | +- Do not sacrifice code quality for compatibility. Breaking changes go through changesets with a `major` bump (user confirmation required). |
67 | 94 |
|
68 | 95 | ## Experimental Features |
69 | 96 |
|
70 | | -- Gate a not-yet-public feature behind an experimental flag. Add the flag to the registry at `packages/agent-core/src/flags/registry.ts`, then check it with `flags.enabled('my-feature')`. Flags are env-driven and default off: `PYTHINKER_CODE_EXPERIMENTAL_<NAME>` toggles one, `PYTHINKER_CODE_EXPERIMENTAL_FLAG` enables all. Release by flipping the entry's `default` to `true`. |
| 97 | +Gate unreleased features behind flags in `packages/agent-core/src/flags/registry.ts`. Check with `flags.enabled('my-feature')`. Env-driven: `PYTHINKER_CODE_EXPERIMENTAL_<NAME>` toggles one; `PYTHINKER_CODE_EXPERIMENTAL_FLAG` enables all. Release by flipping `default` to `true`. |
71 | 98 |
|
72 | 99 | ## Where to Update Instructions |
73 | 100 |
|
74 | | -- Hard rules that affect almost every task: update the root `AGENTS.md`. |
75 | | -- Rules that only affect a specific directory: update the nearest sub-directory `AGENTS.md`. |
76 | | -- Keep instruction updates focused and supported by code facts. |
77 | | - |
78 | | -## Workflow Requirements |
79 | | - |
80 | | -- Prefer `rg` / `rg --files` when reading code. |
81 | | -- When designing changes, follow existing boundaries and local patterns first. |
82 | | -- In public text and test data, replace real internal identifiers with neutral placeholders such as `example.com`, `example.test`, and `YOUR_API_KEY`. Before opening a PR, ask a read-only agent to audit the diff for context-specific internal identifiers. |
83 | | -- When creating a PR, the PR title must follow Conventional Commit style, e.g. `chore: remove legacy format commands`. |
84 | | -- When an AI agent opens or updates a PR, fill in `.github/pull_request_template.md` — link the related issue or explain the problem, then describe what changed. Do not leave placeholder text or submit a generic summary of the diff. |
85 | | -- Do not submit vague AI-generated PR text. The human author must understand the change well enough to explain the code, edge cases, and why the approach fits this repository. |
86 | | -- After finishing a task and before submitting a PR, you must run the `gen-changesets` skill (see `.agents/skills/gen-changesets/SKILL.md`) and generate a changeset under `.changeset/` according to its rules. |
87 | | -- When generating a changeset, **never** decide on a `major` bump on your own. When you judge a change to meet the major criteria (breaking changes, incompatible user configuration, renamed or removed commands/arguments, changed behavior semantics, etc.), you must stop and explain it to the user and ask for confirmation. **Only write `major` after the user has explicitly agreed.** Otherwise default to `minor` (and fall back to `patch` if `minor` is unclear). See the "Hard rule: confirm with the user before writing `major`" section in `.agents/skills/gen-changesets/SKILL.md` for details. |
88 | | -- Prefer importing via `import ... from '#/...'`, which serves the same purpose as `import ... from '@/...'`. |
| 101 | +- Hot-path rules affecting all tasks → root `AGENTS.md`. Directory-specific rules → nearest sub-directory `AGENTS.md`. Keep updates focused and code-backed. |
| 102 | + |
| 103 | +## Workflow |
| 104 | + |
| 105 | +- Prefer `rg` / `rg --files` for code reading. |
| 106 | +- Follow existing boundaries and local patterns when designing changes. |
| 107 | +- Replace internal identifiers with neutral placeholders (`example.com`, `example.test`, `YOUR_API_KEY`) in public text and test data. Before opening a PR, audit the diff for leaked identifiers. |
| 108 | +- PR titles follow Conventional Commit style (e.g. `chore: remove legacy format commands`). |
| 109 | +- When an AI agent opens/updates a PR, fill in `.github/pull_request_template.md` — link the issue, describe what changed. No placeholder text or vague AI-generated summaries. |
| 110 | +- Before submitting a PR, run the `gen-changesets` skill and generate a changeset under `.changeset/`. **Never decide a `major` bump on your own** — explain the breaking change to the user and get explicit confirmation first; default to `minor` (or `patch` if unclear). |
| 111 | +- Prefer `import ... from '#/...'` (equivalent to `@/...`). |
0 commit comments