From 56fe0910d8c4a6dbf48a71c1876025fb1c8fe275 Mon Sep 17 00:00:00 2001 From: HikariLan Date: Sun, 23 Aug 2026 16:07:48 +0800 Subject: [PATCH 1/2] docs: add AGENTS.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Maka already reads AGENTS.md — buildWorkspaceInstructionsPromptFragment injects the nearest one into the system prompt — but the repository has never had its own, so an agent working here starts with no context beyond the source tree. The file points rather than restates. Setup, the package map, contribution policy and architecture all have owners already, so duplicating them would create a second source of truth that goes stale unnoticed. What it keeps is the short list of things that are currently written down nowhere: that every workspace tests against compiled dist/ rather than src/, that Biome formats the tree except apps/desktop and packages/ui because desktop's source-contract tests regex-match exact source shapes, that some files are generated, and the working method the project's review habits already imply. Kept under the 6000-character limit that workspace-instructions.ts enforces on this very file, so Maka does not truncate its own instructions. The ASF header alone accounts for 13% of that budget. CLAUDE.md is a symlink to AGENTS.md, matching apache/airflow and the pattern the Claude Code documentation recommends: each agent CLI reads exactly one filename — Claude Code reads CLAUDE.md, Codex reads AGENTS.md, Gemini CLI reads GEMINI.md — so one canonical file plus a link avoids two copies that drift. Generated-by: Claude Code Co-Authored-By: Claude Opus 5 (1M context) --- AGENTS.md | 102 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ CLAUDE.md | 1 + 2 files changed, 103 insertions(+) create mode 100644 AGENTS.md create mode 120000 CLAUDE.md diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000000..62dd343138 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,102 @@ + + +# AGENTS.md + +Orientation for coding agents working in this repository. + +**This file points; it does not restate.** Setup, the package map, contribution policy, and +architecture have owners elsewhere; duplicating them here would create a second source of truth +that silently goes stale. What stays below is the short list of things an agent gets wrong that no +document currently warns about. Wanting to add a fact that lives somewhere else means adding the +link instead — and if you change something described here, update it in the same change. + +Maka reads this file itself — `buildWorkspaceInstructionsPromptFragment` injects the nearest +`AGENTS.md`, `CLAUDE.md`, or `GEMINI.md` into the system prompt — so it is live product input, not +only documentation. It is also truncated past 6000 characters, which is the hard reason to keep it +short. + +## Where things are written down + +| Question | Read | +|---|---| +| What is this project, how do I install and run it | [README.md](./README.md) | +| How do I contribute, branch, title a PR, disclose AI use | [CONTRIBUTING.md](./CONTRIBUTING.md) | +| How is the runtime designed | [ARCHITECTURE.md](./ARCHITECTURE.md), then [`docs/architecture/`](./docs/architecture/) | +| What must pass before merge | [`.github/workflows/ci.yml`](./.github/workflows/ci.yml) — the authoritative gate list | +| What are the lint and format rules | [`biome.jsonc`](./biome.jsonc) | +| What commands exist | `package.json` `scripts`, at the root and per workspace | + +Two invariants from those documents change how you read the code: + +- **Runtime Host is the only execution authority.** Desktop, TUI, CLI, and eval all execute through + it. A change that seems to need its own runtime is a design discussion, not an implementation + detail. +- **The Runtime Event Log is the source of truth**, and sessions, UI, model context, and recovery + are projections over it. Context pruning and compaction change what the next inference sees; they + never delete recorded evidence. If a fix tempts you to rewrite recorded events, the intended + mechanism is a projection instead. + +## Tests run from `dist/`, not `src/` + +This is the one that costs the most time, because it fails silently. + +Every workspace compiles TypeScript to `dist/` and runs `node --test` against the **compiled +output**. Editing a `.ts` file and re-running a test suite will re-test the previous build, with no +error to tell you. + +```sh +npm --workspace @maka/runtime run build # then, and only then: +npm exec -w @maka/runtime -- node --test "dist/__tests__/some-file.test.js" +``` + +The root `npm test` and each workspace's `npm test` handle this for you by building first; the fast +iteration loop above does not. Consequences: + +- Never edit anything under `dist/` — it is build output. +- After changing a package others depend on (`core`, `storage`, `runtime`), rebuild it before + testing its dependents, or you will debug stale behaviour. + +## Traps that are only recorded in code + +- **Biome formats the tree except `apps/desktop/**` and `packages/ui/**`**, which are linted but not + formatted. Desktop ships source-contract tests that read `.ts`/`.tsx` source and regex-match exact + single-line shapes, so reformatting breaks them. The reasoning is in the `formatter.includes` + comment in [`biome.jsonc`](./biome.jsonc); do not reformat those paths by hand either. +- **Some files are generated.** They match `*.generated.ts`; regenerate rather than hand-edit. +- **Every source file needs the ASF license header.** `npm run check:asf-headers` audits the whole + checkout, so stray untracked files can fail it. `node scripts/asf-license-headers.mjs write` adds + missing headers. +- **`ripgrep` must be installed** — the runtime's `Grep` tool shells out to `rg`. + +## Working method + +1. **Read the architecture doc for the area first.** Runtime behaviour is rarely local; a change in + `packages/runtime` usually has a projection, a recovery path, and a Host protocol consequence. +2. **Reproduce before fixing.** Write a failing test that demonstrates the defect, then fix it. +3. **Prove the test bites.** Re-run it against a build without your fix and confirm it goes red. For + a test guarding *new* behaviour, check it against a plausible weaker version of the fix — a test + that passes either way is not a guard. +4. **Watch for vacuous tests.** Several suites run against a fake backend rather than a real + provider. A fake can be more cooperative than production code, so a green suite is not by itself + evidence that the real path works. If a fake compensates for something, say so. +5. **Characterise pre-existing failures.** Before reporting a failing suite as pre-existing, run it + against a clean checkout of the base branch, and say which suites you did not run. +6. **Match the surrounding code.** This codebase comments the *why*, and often records the bug a + design choice prevents. When you change such code, update the reasoning rather than deleting it. diff --git a/CLAUDE.md b/CLAUDE.md new file mode 120000 index 0000000000..47dc3e3d86 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1 @@ +AGENTS.md \ No newline at end of file From fa72ed03bbf1bce0f563a78186fbc03fbf5b5cff Mon Sep 17 00:00:00 2001 From: HikariLan Date: Sun, 23 Aug 2026 17:03:21 +0800 Subject: [PATCH 2/2] docs: make AGENTS.md a complete agent guide MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The first draft leaned so hard on "link, do not restate" that it stopped being usable on its own: no install step, no build command, no way to run the tests, and not one sentence saying what Maka is. An agent could read it end to end and still not be able to start. Restores the sections the format is for — project overview, repository layout, setup, development workflow, testing, code style, build and release, CI gates, PR conventions — while keeping references for the prose that other documents own. Commands belong here: they are the executable part, and CI catches them when they drift. Also corrects three things review caught. Generated artifacts are not only *.generated.ts; the ASF header rule has a reviewed exclusion list rather than covering every file; and not every workspace defines a test script. Adds the loading scope of workspace instructions, which is exactly cwd and ~/.maka with no ancestor walk — a session started in a subdirectory does not pick this file up at all. Generated-by: Claude Code Co-Authored-By: Claude Opus 5 (1M context) --- AGENTS.md | 252 +++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 201 insertions(+), 51 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 62dd343138..09647987fe 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -17,86 +17,236 @@ under the License. --> -# AGENTS.md +# Agent Guide for Apache Maka -Orientation for coding agents working in this repository. +## Project overview -**This file points; it does not restate.** Setup, the package map, contribution policy, and -architecture have owners elsewhere; duplicating them here would create a second source of truth -that silently goes stale. What stays below is the short list of things an agent gets wrong that no -document currently warns about. Wanting to add a fact that lives somewhere else means adding the -link instead — and if you change something described here, update it in the same change. +Apache Maka (Incubating) is a local-first agent workspace. It ships four surfaces, and all of them +execute through one authority, **Runtime Host**: -Maka reads this file itself — `buildWorkspaceInstructionsPromptFragment` injects the nearest -`AGENTS.md`, `CLAUDE.md`, or `GEMINI.md` into the system prompt — so it is live product input, not -only documentation. It is also truncated past 6000 characters, which is the hard reason to keep it -short. +- **Desktop** — Electron + React, the daily interaction surface. +- **TUI** — the terminal client, `maka`. +- **CLI** — one non-interactive turn, `maka run`, plus `maka eval`. +- **Eval** — reproducible benchmark experiments across Maka and external subjects. -## Where things are written down +Stack: TypeScript across npm workspaces, Node.js **>= 22.19** (CI uses 24), SQLite for durable +state, Vite and electron-builder for Desktop, Biome for lint and format, `node --test` for tests. +`ripgrep` must be on PATH — the runtime's `Grep` tool shells out to `rg`. -| Question | Read | +Two invariants govern the runtime. Read the code with them in mind, because they decide what a +correct fix looks like: + +- **Runtime Host is the only execution authority.** Desktop, TUI, CLI and eval all go through it; + none owns a second runtime. Something that seems to need its own runtime is a design discussion, + not an implementation detail. +- **The Runtime Event Log is the source of truth.** Model messages, tool calls, tool results and + termination facts are appended to it, and sessions, UI, model context and recovery are all + projections over that log. Pruning and compaction change what the next inference sees; they never + delete recorded evidence. If a fix tempts you to rewrite recorded events, the intended mechanism + is a projection. + +Full design in [ARCHITECTURE.md](./ARCHITECTURE.md), then the drafts under +[`docs/architecture/`](./docs/architecture/). Historical designs under +[`docs/archive/`](./docs/archive/README.md) may be stale; current issues and source win. + +## Repository layout + +| Path | Purpose | |---|---| -| What is this project, how do I install and run it | [README.md](./README.md) | -| How do I contribute, branch, title a PR, disclose AI use | [CONTRIBUTING.md](./CONTRIBUTING.md) | -| How is the runtime designed | [ARCHITECTURE.md](./ARCHITECTURE.md), then [`docs/architecture/`](./docs/architecture/) | -| What must pass before merge | [`.github/workflows/ci.yml`](./.github/workflows/ci.yml) — the authoritative gate list | -| What are the lint and format rules | [`biome.jsonc`](./biome.jsonc) | -| What commands exist | `package.json` `scripts`, at the root and per workspace | +| `packages/core` | Pure contracts: Session, Runtime Event, AgentRun, permission and protocol types | +| `packages/storage` | Interactive runtime stores and SQLite control planes | +| `packages/runtime` | SessionManager, AgentRun, model adapters, tools, context, recovery, graph | +| `packages/runtime-host` | The hosted execution authority and its public client/protocol | +| `packages/mcp` | MCP client/server integration | +| `packages/computer-use` | Computer-use capability | +| `packages/eval` | Experiment cells, attempts, result selection, subject and executor adapters | +| `packages/cli` | TUI, `maka run`, and the public `maka eval` route | +| `packages/ui` | Shared React components for the Desktop surface | +| `apps/desktop` | Electron composition, main process, renderer, product-entry adapters | +| `scripts/` | Build, release, ASF policy and CI-planning scripts | + +Workspaces build in dependency order: `core → storage → mcp → runtime → runtime-host → +computer-use → eval → cli → ui → desktop`. `npm run build` walks exactly that order. + +## Setup + +```sh +npm ci # respect the lockfile; not `npm install` +npm run build # build every workspace, in dependency order +``` + +If dependencies were installed with `ELECTRON_SKIP_BINARY_DOWNLOAD=1`, install the Electron binary +before starting Desktop: `node node_modules/electron/install.js`. + +Maka bundles no model account. A fresh workspace needs a connection configured in +`Settings → Models` before a turn can run; automated checks use the fake backend instead of a real +provider. + +## Development workflow + +```sh +npm run dev # Desktop with HMR +npm run dev:full # build every workspace, then start Electron +npm run rebuild # clean + full build, when incremental output looks wrong +``` -Two invariants from those documents change how you read the code: +Per workspace, when you only touched one: -- **Runtime Host is the only execution authority.** Desktop, TUI, CLI, and eval all execute through - it. A change that seems to need its own runtime is a design discussion, not an implementation - detail. -- **The Runtime Event Log is the source of truth**, and sessions, UI, model context, and recovery - are projections over it. Context pruning and compaction change what the next inference sees; they - never delete recorded evidence. If a fix tempts you to rewrite recorded events, the intended - mechanism is a projection instead. +```sh +npm --workspace @maka/runtime run build +npm --workspace @maka/desktop run build:workspace-deps # rebuild deps after switching branches +``` -## Tests run from `dist/`, not `src/` +The TUI and CLI run from a source build — see [`packages/cli/README.md`](./packages/cli/README.md) +for the entry points. Desktop Storybook: `npm --workspace @maka/desktop run storybook`. -This is the one that costs the most time, because it fails silently. +## Testing -Every workspace compiles TypeScript to `dist/` and runs `node --test` against the **compiled -output**. Editing a `.ts` file and re-running a test suite will re-test the previous build, with no -error to tell you. +**Tests run from `dist/`, not `src/`.** Every workspace compiles TypeScript to `dist/` and runs +`node --test` against the **compiled output**. Editing a `.ts` file and re-running a suite silently +re-tests the previous build, with no error to tell you. This is the single most common way to waste +an hour in this repository. ```sh -npm --workspace @maka/runtime run build # then, and only then: +npm test # build every workspace, then run all suites +npm --workspace @maka/runtime run test # clean + build + test one workspace +npm run test:dist # run against the current dist, no rebuild +npm run test:dist:serial # same, one workspace at a time (CI ordering) +``` + +Not every workspace defines `test`. `@maka/eval` exposes only `test:dist`, and that script also +runs Python suites under `harbor/`. Check the workspace's `package.json` before assuming a script +exists. + +Fast iteration loop — build, then target one file or one case: + +```sh +npm --workspace @maka/runtime run build npm exec -w @maka/runtime -- node --test "dist/__tests__/some-file.test.js" +node --test --test-name-pattern="steering" "dist/__tests__/ai-sdk-backend.test.js" ``` -The root `npm test` and each workspace's `npm test` handle this for you by building first; the fast -iteration loop above does not. Consequences: +Desktop unit tests compile only the main process; end-to-end uses Playwright against a real Electron +build: -- Never edit anything under `dist/` — it is build output. +```sh +npm --workspace @maka/desktop run test # main-process unit tests +npm exec -w @maka/desktop -- playwright test --config e2e/playwright.config.ts +``` + +Conventions and consequences: + +- Test sources live in `src/__tests__/*.test.ts`, beside the code they cover; Desktop's are under + `src/main/__tests__/` and its e2e specs under `e2e/`. +- **Never edit anything under `dist/`** — it is build output and will be overwritten. - After changing a package others depend on (`core`, `storage`, `runtime`), rebuild it before testing its dependents, or you will debug stale behaviour. -## Traps that are only recorded in code +## Code style + +Biome does **both** lint and format — there is no ESLint and no Prettier. Single quotes, semicolons, +2-space indent, 100-column width. Configuration in [`biome.jsonc`](./biome.jsonc). + +```sh +npm run lint +npm run format # writes; `npm run format:check` only checks +npm run typecheck +npm run check:asf-headers +``` + +Four rules that are not obvious from the config alone: + +- **`apps/desktop/**` and `packages/ui/**` are formatter-excluded, but still fully linted.** Desktop + ships source-contract tests that read `.ts`/`.tsx` source — its own and `packages/ui`'s — and + regex-match exact single-line shapes, so a reformat breaks them. The reasoning is recorded in the + `formatter.includes` comment in `biome.jsonc`. Do not reformat those paths by hand either. +- Byte-sensitive artifacts (`apps/desktop/resources/licenses/**`, `apps/desktop/bundled-tools.json`) + are hashed for provenance verification. Never reformat them. +- **Several classes of file are generated; regenerate rather than hand-edit.** `*.generated.ts` is + one naming convention, but not the only one: the Astryx theme + (`npm run astryx:theme`), the surface inventory (`npm run astryx:surface-inventory:write`), the + Windows test inventory (`npm run windows:inventory`) and `apps/desktop/bundled-tools.json` are + also build outputs. Each has a check that fails when the committed copy drifts. +- Source files need the ASF license header, with a reviewed exclusion list — + `npm run check:asf-headers` currently audits about 2,750 covered files and skips about 130, + including generated and third-party files. Trust the checker rather than adding headers by hand: + `node scripts/asf-license-headers.mjs write` adds what is missing. The check audits the whole + checkout, so stray untracked files can fail it. + +Match the surrounding code. This codebase comments the *why*, and frequently records the bug a +design choice was made to prevent. When you change such code, update that reasoning rather than +deleting it. + +## Build, packaging and release + +```sh +npm run build # all workspaces +npm run release:cli:pack # build the CLI npm release candidate +npm run release:cli:smoke # install and smoke-test that candidate +npm --workspace @maka/desktop run package:macos-arm64 +npm --workspace @maka/desktop run package:windows-x64 +``` + +Apache releases are source releases approved by the podling PPMC and the Incubator PMC; anything +built elsewhere is a convenience artifact. `npm run release:asf:source`, `release:asf:verify` and +`release:asf:sign` drive that flow, and `npm run check:release` gates the contracts. See +[`.github/ASF_SOURCE_RELEASE.md`](./.github/ASF_SOURCE_RELEASE.md). -- **Biome formats the tree except `apps/desktop/**` and `packages/ui/**`**, which are linted but not - formatted. Desktop ships source-contract tests that read `.ts`/`.tsx` source and regex-match exact - single-line shapes, so reformatting breaks them. The reasoning is in the `formatter.includes` - comment in [`biome.jsonc`](./biome.jsonc); do not reformat those paths by hand either. -- **Some files are generated.** They match `*.generated.ts`; regenerate rather than hand-edit. -- **Every source file needs the ASF license header.** `npm run check:asf-headers` audits the whole - checkout, so stray untracked files can fail it. `node scripts/asf-license-headers.mjs write` adds - missing headers. -- **`ripgrep` must be installed** — the runtime's `Grep` tool shells out to `rg`. +## What CI enforces + +[`.github/workflows/ci.yml`](./.github/workflows/ci.yml) is the authoritative list. Beyond lint, +format, build, typecheck and the test suites, it also runs `check:release`, `check:asf-headers`, +`check:asf-npm`, `check:asf-source`, `astryx:surface-inventory`, `astryx:theme -- --check`, +`windows:inventory`, `scripts/protocol-epoch-check.mjs`, Knip on `apps/desktop` and `packages/ui`, +Storybook and CLI release smokes, and the Desktop Playwright suite. If you touch the Runtime Host +wire protocol, expect the epoch guard to have an opinion. + +## Pull requests + +Branches are `/` and titles `(): `, following +[Conventional Commits](https://www.conventionalcommits.org/); `git log` shows the types and scopes +in use. The repository squash-merges, so the PR title becomes the commit on `main`. + +Opening a PR pre-fills [`.github/pull_request_template.md`](./.github/pull_request_template.md) — +fill it in rather than replacing it, and keep the description short and your own. Include +before/after evidence for UI changes. Every PR to `main` needs an approving review from a committer +other than the author and a passing `test` check; **AI review does not count** as that review. + +**AI attribution is mandatory.** State whether generative tooling contributed substantively and name +the tool. When AI authors a material part of a contribution, add a `Generated-by: ` trailer to +each affected commit and keep it through squash or amend. Translation, wording edits, autocomplete +and spelling correction do not count. Full policy in [CONTRIBUTING.md](./CONTRIBUTING.md) and the +[ASF Generative Tooling Guidance](https://www.apache.org/legal/generative-tooling.html). Contribute +only work you have the right to contribute, and record third-party sources and licenses. ## Working method 1. **Read the architecture doc for the area first.** Runtime behaviour is rarely local; a change in - `packages/runtime` usually has a projection, a recovery path, and a Host protocol consequence. + `packages/runtime` usually has a projection, a recovery path and a Host protocol consequence. 2. **Reproduce before fixing.** Write a failing test that demonstrates the defect, then fix it. 3. **Prove the test bites.** Re-run it against a build without your fix and confirm it goes red. For a test guarding *new* behaviour, check it against a plausible weaker version of the fix — a test that passes either way is not a guard. 4. **Watch for vacuous tests.** Several suites run against a fake backend rather than a real - provider. A fake can be more cooperative than production code, so a green suite is not by itself - evidence that the real path works. If a fake compensates for something, say so. + provider, and a fake can be more cooperative than production code. A green suite is not by itself + evidence that the real path works; if a fake compensates for something, say so. 5. **Characterise pre-existing failures.** Before reporting a failing suite as pre-existing, run it against a clean checkout of the base branch, and say which suites you did not run. -6. **Match the surrounding code.** This codebase comments the *why*, and often records the bug a - design choice prevents. When you change such code, update the reasoning rather than deleting it. + +## Platform notes + +Desktop currently targets Apple Silicon; [Windows](./docs/windows-support.md) is an unsigned preview +and Linux is not yet a release target. A failure that looks platform-specific often is — check +before assuming a regression. `npm run windows:inventory` guards the Windows test inventory, and +Linux sandbox behaviour has its own smoke test in `packages/runtime`. + +## About this file + +Maka reads it. `buildWorkspaceInstructionsPromptFragment` injects workspace instructions into the +system prompt, so this file is live product input when Maka runs against this repository — worth +remembering when editing it. + +Its loading scope is narrower than it looks: exactly the session `cwd` and `~/.maka`, with no walk +up through ancestors. A session started in a subdirectory therefore does **not** pick up this +repository-root file. `CLAUDE.md` here is a symlink to it, so the agents that read that name get the +same content.