|
1 | 1 | # Repository-level Agent Guide |
2 | 2 |
|
3 | | -Reply in English unless the user explicitly asks you to respond in another language. |
| 3 | +Reply in English unless the user explicitly asks otherwise. |
4 | 4 |
|
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. |
| 5 | +TypeScript monorepo for **pythinker-code**, a provider-agnostic AI coding agent. This file covers product identity, project map, hard constraints, and workflow rules. |
6 | 6 |
|
7 | 7 | ## Product Identity |
8 | 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. |
| 9 | +**pythinker-code** plans, writes, tests, and iterates on code autonomously. The same runtime talks to any LLM through the `packages/kosong` abstraction layer. |
10 | 10 |
|
11 | | -### Supported Wire Types |
| 11 | +### Wire Types |
12 | 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 | |
| 13 | +| Wire type | SDK / transport | Providers | |
| 14 | +| ------------------ | ----------------------- | ------------------------------------------------ | |
| 15 | +| `anthropic` | `@anthropic-ai/sdk` | Anthropic (Claude family) | |
| 16 | +| `openai` | OpenAI Chat Completions | OpenAI (GPT-4o/4.1/4.5/5.x, GPT-3.5-turbo) | |
| 17 | +| `openai_responses` | OpenAI Responses API | OpenAI (GPT-4.1/5.x, o-series) | |
| 18 | +| `google-genai` | `@google/genai` | Google (Gemini 2.0–3.x) | |
| 19 | +| `vertexai` | Google Vertex AI | Google Cloud–hosted Gemini | |
| 20 | +| `pythinker` | Pythinker managed API | Any model proxied through Pythinker | |
21 | 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 |
| 22 | +Any OpenAI-compatible endpoint (DeepSeek, Qwen, GLM, Grok, Together AI, Fireworks, etc.) works via the `openai`/`openai_responses` wire with a custom `baseURL`. |
32 | 23 |
|
33 | 24 | ### Model Selection |
34 | 25 |
|
35 | | -Model selection flows through the **catalog system** (`packages/kosong/src/catalog.ts`): |
| 26 | +Flows through the **catalog** ([catalog.ts](file:///Users/panda/Projects/active/pythinker-code-tsc/packages/kosong/src/catalog.ts)): |
36 | 27 |
|
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. |
| 28 | +1. JSON catalog maps `providerId → models[]` with context window, capabilities, cost, and modality metadata. |
| 29 | +2. `inferWireType()` resolves provider → wire type (explicit `type` field, then heuristic on `npm`/`id`). |
| 30 | +3. `createProvider()` instantiates the correct `ChatProvider`. |
| 31 | +4. `getModelCapability()` returns per-model flags (vision, tool-use, thinking, fast-mode). |
41 | 32 |
|
42 | | -Adding a new provider requires **zero code changes** when it is OpenAI-compatible — just add the entry to the catalog JSON. |
| 33 | +Adding an OpenAI-compatible provider requires **zero code changes** — just add a catalog entry. |
43 | 34 |
|
44 | 35 | ## Working Principles |
45 | 36 |
|
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. |
| 37 | +- Start from requirements and code facts; discuss unclear goals first. |
| 38 | +- Code is the source of truth — don't read Markdown to understand implementation. |
| 39 | +- Validate version claims against authoritative docs (Context7 MCP, Tavily). |
| 40 | +- Read relevant source and follow the nearest `AGENTS.md` before changing code. |
50 | 41 | - 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. |
| 42 | +- Implement current requirements directly; no backward-compatibility shims. |
| 43 | +- Simplest implementation first: stdlib → established libraries → custom code. Use the `ponytail` skill when a change looks over-engineered. |
| 44 | +- No co-author attribution or agent identity in commits/PRs. |
| 45 | +- Git identity: `elkaix <melkholy@techmatrix.com>` — apply per command; never modify git config. |
55 | 46 |
|
56 | 47 | ## Project Map |
57 | 48 |
|
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`. |
| 49 | +| Package | Description | Notes | |
| 50 | +| ------- | ----------- | ----- | |
| 51 | +| `apps/pythinker-code` | CLI / TUI app | Consumes `@pythoughts/pythinker-code-sdk`; no `agent-core` dep. Use `write-tui` skill. | |
| 52 | +| `apps/pythinker-web` | Browser UI (Vue 3 + Vite + vue-i18n) | REST + WS `/api/v1`; no `agent-core` dep. See its `AGENTS.md`. | |
| 53 | +| `apps/dashboard` | Session dashboard & replay | `server/` + `web/` subdirs. | |
| 54 | +| `packages/agent-core` | Agent engine | Agent, Session, profile, skills, tools, plan, permission, DI. | |
| 55 | +| `packages/node-sdk` | Public TS SDK & harness | | |
| 56 | +| `packages/kosong` | LLM provider abstraction | Wire types, catalog, capability registry. | |
| 57 | +| `packages/kaos` | Execution environment | File/process abstractions. | |
| 58 | +| `packages/oauth` | Auth utilities | | |
| 59 | +| `packages/telemetry` | Client-side telemetry | | |
| 60 | +| `packages/server` | Server | Hosts `agent-core` over REST + WS `/api/v1`. See its `AGENTS.md`. | |
| 61 | +| `packages/server-e2e` | E2E tests | `PYTHINKER_SERVER_URL` (default `http://127.0.0.1:58627`). See its `AGENTS.md`. | |
69 | 62 |
|
70 | 63 | ## Environment |
71 | 64 |
|
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`). |
| 65 | +- **Node.js** ≥ 26.4.0 (`.nvmrc`). **pnpm** 10.33.0 (root `packageManager`). `engine-strict=true`. |
74 | 66 |
|
75 | | -## Monorepo Workspace Maintenance |
| 67 | +## Monorepo Maintenance |
76 | 68 |
|
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. |
| 69 | +- `pnpm-workspace.yaml` is source of truth, but `flake.nix` **hardcodes** `workspacePaths`/`workspaceNames`. |
| 70 | +- **Update both** when adding/removing any workspace package. Missing a path silently drops files from Nix; missing a name breaks `pnpmConfigHook`. |
| 71 | +- CI (`scripts/check-nix-workspace.mjs`) only validates the `@pythoughts/pythinker-code` closure — keep `flake.nix` updated by hand. |
80 | 72 |
|
81 | 73 | ## Coding Rules |
82 | 74 |
|
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). |
| 75 | +- English-only codebase. Use ASCII/Latin fixtures (e.g. `café`) for unicode tests. |
| 76 | +- `packages/acp-adapter`: pin `@agentclientprotocol/sdk` `^0.23.0` (0.24+ broke session-model API). |
| 77 | +- `tsgo` (`@typescript/native-preview`) available via `npx tsgo -p <tsconfig> --noEmit`; committed scripts use `tsc` — run both for type fixes. |
| 78 | +- Pass `undefined` directly for optional props — no conditional spread. |
| 79 | +- `user?: User`, not `user?: User | undefined`. |
| 80 | +- Single-param internal methods stay single-param — no options-object wrapping. |
| 81 | +- Non-root `index.ts`: prefer `export * from './module'`. |
| 82 | +- `Agent` class must be standalone — no mandatory `Session`/`agentId`. Optional `sessionId` as provider hint only. |
| 83 | +- Prefer adding tests to existing files. Fix failing tests first (unless there's a real impl bug). |
| 84 | +- Breaking changes require changesets with `major` bump (user confirmation required). |
94 | 85 |
|
95 | 86 | ## Experimental Features |
96 | 87 |
|
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`. |
98 | | - |
99 | | -## Where to Update Instructions |
100 | | - |
101 | | -- Hot-path rules affecting all tasks → root `AGENTS.md`. Directory-specific rules → nearest sub-directory `AGENTS.md`. Keep updates focused and code-backed. |
| 88 | +Gate behind flags in `packages/agent-core/src/flags/registry.ts`. Check: `flags.enabled('my-feature')`. Env: `PYTHINKER_CODE_EXPERIMENTAL_<NAME>` toggles one; `PYTHINKER_CODE_EXPERIMENTAL_FLAG` enables all. Release: flip `default` to `true`. |
102 | 89 |
|
103 | 90 | ## Workflow |
104 | 91 |
|
105 | 92 | - 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). |
| 93 | +- Follow existing boundaries and local patterns. |
| 94 | +- Replace internal identifiers with neutral placeholders in public text/test data. Audit diffs before PRs. |
| 95 | +- PR titles: Conventional Commit style (e.g. `chore: remove legacy format commands`). |
| 96 | +- Fill in `.github/pull_request_template.md` — link the issue, describe changes. No placeholder text. |
| 97 | +- Run `gen-changesets` skill before submitting PRs. Never decide `major` on your own — default to `minor`/`patch`. |
111 | 98 | - Prefer `import ... from '#/...'` (equivalent to `@/...`). |
| 99 | + |
| 100 | +## Where to Update Instructions |
| 101 | + |
| 102 | +Hot-path rules → root `AGENTS.md`. Directory-specific rules → nearest sub-directory `AGENTS.md`. |
0 commit comments