AGENTS.md · git:20261030.680633b · 2026-10-30 · sha256 0fc94ba83c5e7605

AGENTS.md git:20261030.680633bA

Immutable. This exact content never changes and is served at /api/v1/blob/0fc94ba83c5e7605.

# AGENTS.md

Notes for coding agents. Two different jobs:

- **Using Etude** (making cards, quizzing someone, changing schedules): read [`skill/SKILL.md`](skill/SKILL.md) and use the `etude` CLI. Don't open the SQLite file yourself. The full reference is [`docs/cli.md`](docs/cli.md).
- **Working on Etude** (changing its code): the rest of this file.

## Layout

```
src/core/      engine.ts (every operation), model.ts, scheduler.ts (FSRS-6, deadlines), schedulers.ts (script schedulers; built-ins in schedulers/), optimize.ts (FSRS weights
               from review history), query.ts (search language), sandbox.ts (QuickJS), ai.ts (grading providers),
               types.ts (type loading/validation), adaptive.ts (adaptive decks: estimates, pace, levels, placement;
               the math in learner.ts), util.ts (small shared helpers)
src/server/    app.ts: the HTTP API the web app uses. Each route maps to an engine call.
src/cli/       main.ts → run.ts (parsing, errors, dry run); registry.ts (command table);
               commands/<group>.ts (one file per noun); help.ts; pack-check.ts
web/           React + Tailwind + shadcn/ui (Vite). Pages in web/src/pages, API client in web/src/lib/api.ts
desktop/       the Electron app (own package.json): app.ts (window, menus, permissions, links), engine.ts (runs
               `etude serve` in a utility process with a per-launch token), find.ts (reuse or start), shell-env.ts,
               updates.ts (electron-updater, or a link, or the system), command.ts (the etude command), integrate.ts,
               preload.cjs (window.etudeDesktop, top frame only), pages/ (starting and error screens), bin/ (the
               etude launchers), build.ts (stages the app, runs electron-builder), smoke.ts, build/, aur/PKGBUILD
runtime/       runtime.js and card.css, loaded inside every card frame
types/         built-in card types, one directory each (same format as `etude type export`)
docs/          packs.md, types.md, cli.md (the command reference is generated; see below)
skill/         the portable agent skill for using Etude
scripts/       check-pack.ts, gen-cli-docs.ts
test/          node:test suites
```

## Commands

```sh
npm test                                  # node --test "test/**/*.test.ts"
npm run typecheck                         # tsc for the server/CLI and for web/
node src/cli/main.ts <group> <verb> ...   # the CLI from source (Node runs .ts directly)
node scripts/gen-cli-docs.ts              # regenerate docs/cli.md after changing any command
ETUDE_HOME=$(mktemp -d) node src/cli/main.ts ...   # scratch collection
npm run desktop                           # the desktop app from source (installs Electron into desktop/ once)
npm --prefix desktop run typecheck        # the desktop code needs Electron's types, so it's checked apart
node desktop/build.ts && node desktop/smoke.ts   # installers for this system in desktop/dist/out, then test them
```

## Conventions

- **New operations go in the engine** (`src/core/engine.ts`) and are exposed by the server and the CLI. Anything the UI can do needs a CLI command. Add it to `src/cli/commands/<group>.ts` with a summary, args, flags, examples, `writes`/`dryRun`/`confirm` and an `output` shape, then regenerate `docs/cli.md`. `test/cli-docs.test.ts` fails when the docs are stale.
- CLI output is JSON with stable keys. Errors are `CliError` with a code (`usage`, `not_found`, `validation`, `conflict`, `external`). Don't print anything else on stdout.
- Keep dependencies light: use the Node stdlib (`node:sqlite`, `util.parseArgs`, `node:test`) before adding a package.
- Card templates run in sandboxed iframes (`allow-scripts`, opaque origin) and user scripts run in QuickJS. Don't give either more access. Private fields stay on the server until an answer is submitted.
- Test against temp databases, never a real collection.
- No AI or tool attribution in commits, code comments or docs. Keep comments brief and only where they add something.
- Markdown paragraphs are one line each (no hard wrapping).