# Project AIRI Agent Guide This file gives the core rules for all work in the `moeru-ai/airi` monorepo. Skills and nested `AGENTS.md` files give the rules for specific tasks. Before you start a task, find it in [Task Routing](#task-routing) and read the listed file. ## Project Map All apps use Vue 3, Vite, TypeScript, Pinia, VueUse, UnoCSS, Vitest, and ESLint. | Path | Content | | --- | --- | | `apps/stage-web` | The web app. It uses Vue Router. | | `apps/stage-tamagotchi` | The Electron desktop app. | | `apps/stage-pocket` | The mobile app. It uses Vue Router, Capacitor, Kotlin, and Swift. | | `packages/stage-ui` | Business components, composables, and stores that stage-web and stage-tamagotchi share. | | `packages/stage-ui-three` | Three.js bindings and Vue components. | | `packages/stage-shared` | Logic that the stage packages and the stage apps share. | | `packages/stage-pages` | Shared page bases. | | `packages/stage-layouts` | Shared layouts, including the stage-web settings layout. | | `packages/ui` | Primitives built on reka-ui, such as inputs, buttons, and layout. They have minimal business logic. | | `packages/i18n` | All translations. | | `packages/server-runtime`, `packages/server-sdk`, `packages/server-shared` | The server channel that `services/` and `plugins/` use. | | `server/apps/api` | The hosted Hono resource API and its business domains. | | `server/apps/auth` | The standalone Better Auth and OIDC service. | | `server/packages` | Backend-only schema and Node infrastructure packages. | | `server/dev/caddy` | Local Auth and API edge routing. | | `server/docker-compose.yaml` | The complete local backend stack. | Key files and directories: - Pages are in `apps/stage-web/src/pages` and `apps/stage-tamagotchi/src/renderer/pages`. Devtools pages are in the `devtools` folder of each. - The router configuration is in `apps/stage-web/vite.config.ts` and `apps/stage-tamagotchi/electron.vite.config.ts`. - The settings layouts are `packages/stage-layouts/src/layouts/settings.vue` (stage-web) and `apps/stage-tamagotchi/src/renderer/layouts/settings.vue`. - A settings or devtools page needs ` meta: layout: settings `. Register its route and icon in the settings layout. - In `packages/stage-ui/src`, provider definitions are in `stores/providers/` and orchestration modules are in `stores/modules/`. - Business composables are in `packages/stage-ui/src/composables/`. Business components are in `packages/stage-ui/src/components/`. - Put a component for one page or one use case in `packages/stage-ui/src/components/scenarios/`. - Stories are in `packages/stage-ui/stories`, with `packages/stage-ui/histoire.config.ts`. An example is `packages/stage-ui/src/components/misc/Button.story.vue`. - Eventa contracts are in `apps/stage-tamagotchi/src/shared`. Main and renderer usage examples are in `apps/stage-tamagotchi/src/main/services/electron`. - The dependency injection example is `apps/stage-tamagotchi/src/main/index.ts`. - Style configuration is in `uno.config.ts`. Existing animations are in `apps/stage-web/src/styles`. - CI pipelines are in `.github/workflows`. Lint rules are in `eslint.config.ts`. ## Commands Use pnpm workspace filters to limit a command to one workspace. Replace `` with the `name` field in `package.json`, for example `@proj-airi/stage-tamagotchi`. - Typecheck one workspace: `pnpm -F typecheck`. For stage-tamagotchi, this command runs `tsc` and `vue-tsc`. - Test one file: `pnpm -F exec vitest run `. Give `` relative to the workspace. - Test one workspace: `pnpm -F exec vitest run`. - Test all workspaces: `pnpm test:run`. Turbo runs the `test:run` script of each workspace, with its browser projects. - Test the root scripts in `.github/scripts`: `pnpm test:root`. The root `vitest.config.ts` has only these tests. - Test the changes of a branch: run the `test:run` script of each changed workspace and of each workspace that depends on it. Use the merge base with `origin/main` as the base. ```sh base=$(git merge-base origin/main HEAD) TURBO_SCM_BASE="$base" pnpm exec turbo run test:run --affected ``` If the branch changes `.github/scripts`, also run `pnpm test:root`. - Lint: `pnpm lint`. ESLint also does the formatting. To fix lint and format errors, run `pnpm lint:fix`. - Build one workspace: `pnpm -F build`. For stage-tamagotchi, this command runs the typecheck and `electron-vite build`. ## Scope and Checks - Keep each change inside the scope of the task. - In each function, component, or test that you change, correct the code that does not obey a current rule. Do not change other code only to improve it. - Do not add one-off patterns. Before you write a new utility or function, search for an existing internal implementation. - If new logic can become a shared utility, propose the shared approach to the user. - If a refactor is small, do it step by step. - After a task, run the typecheck and the related tests for each workspace that you changed. - Before you create a PR or push to one, run the tests of the branch changes. CI runs every project, including the browser projects. - If a change alters UI structure, layout, or interaction, review the related browser and end-to-end tests. - If intended behavior changes, update the affected assertions. Keep valid regression checks. Do not delete an assertion only to make a test pass. - After the final UI change, run the related tests on the final commit. - Before you report a CI success, make sure that CI tested the current PR head. - If you change a shared package or an exported type, also run the root `pnpm typecheck`. - Run `pnpm lint` before you finish. - Report only the checks that you ran. Give each command and its result. - At the end, summarize the changes, the commands that you ran, and the follow-up work. ## Code Rules - Put shared logic in `packages/`. Keep module boundaries clear. - Use kebab-case for all file names. - Do not use `any`. Prefer type generics. Use `as unknown as ` only when you cannot fix the type safely. - Omit TypeScript and JavaScript source extensions in relative imports, dynamic imports, and re-exports. Write `./module`, not `./module.ts` or `./module.js`. Keep an extension only when the runtime or asset format requires it. - Do not edit `tsconfig.json` to hide an import or type error. Find and fix the cause. - Treat a circular import as a design problem. First reconsider ownership and module boundaries. If you cannot resolve the cycle confidently, ask the user. - Use `@moeru/eventa` for all IPC, RPC, and cross-process events. Define the contracts in one central place, such as `apps/stage-tamagotchi/src/shared`. - Use dependency injection only at external boundaries: databases, model runtimes, queues, caches, filesystems, networks, clocks, environments, and feature gates. Use `injeca` for it. - Do not add dependency objects for internal functions that only call sibling helpers or forward parameters. - Prefer classes for runtime or browser APIs. Also prefer classes for substantial business modules that own state, lifecycle, or a stable domain boundary. - Prefer functions for pure transformations and local helpers. - Use Valibot for schema validation. Keep each schema near its consumers. - Use `errorMessageFrom(error)` from `@moeru/std` to get an error message. Add `?? 'fallback'` when you need a default. For other error handling, prefer the `@moeru/std` patterns. - Mark every workaround with a `// NOTICE:` comment in this format: ```ts // NOTICE: // Why this workaround is needed. // Root cause summary. // Source/context (file, issue, URL, or node_modules reference). // Removal condition (when it can be safely deleted). ``` ### Backward Compatibility - Do not add backward-compatibility guards. - If old callers or old data need extended support, write a refactor document with the target shape. Then start another Codex or Claude Code session from the shell to do the refactor. - If a compatibility fallback must stay for a limited time, mark it with `// NOTICE:` and give its removal condition. - If a compatibility fallback is permanent, document it as supported policy. Do not call it legacy. - A nested `AGENTS.md` can override this rule for a public contract. It must name the root rule that it overrides. ### Dependencies - Prefer `es-toolkit` for general utilities. Ask the user before you add another general utility library, such as a package from `unjs` or `tinylib`. - Some features use `node:*` built-in modules, DOM operations, Vue composables, React hooks, Vite plugins, or GitHub Actions workflows. For these features, research existing libraries first. - Before you choose a library, ask the user to choose. Help the user compare the options. - If the user works spec-driven, list the candidate libraries in a Markdown comparison table. - If the user asks you to use a specific tool or dependency, read its documentation in Context7 first. Then examine how this repository uses it. - If Context7 returns several names without a clear difference, ask the user to choose one. - If the documentation conflicts with the typecheck result, examine the dependency source in `node_modules` to find the cause. ## Documentation - Put project-wide and client ADRs in `docs/ai/adr/`. Put hosted backend ADRs in `server/docs/ai/adr/`, and obey the ADR rules in `server/AGENTS.md`. - Put a documentation change in the same commit or PR as the code that it describes. This rule applies to ADRs, `README.md` files, and component references. - Put agent configuration changes in their own commit. Agent configuration includes `AGENTS.md`, `CLAUDE.md`, skills, and `.github/copilot-instructions.md`. - If the agent configuration describes the code of a PR, put its commit in that PR. Do not open a second PR for it. - Keep a structured `README.md` in each `packages/` and `apps/` entry. It tells what the entry does, how to use it, when to use it, and when not to use it. - Put all translations in `packages/i18n`. By default, edit only the English source locale and your own locale. - Do not edit other locales unless the user asks. Crowdin manages them, and the next Crowdin sync can replace local edits. - Do not use English text as a placeholder in other locales. Add only the locales you implement. - When you add a nested `AGENTS.md`, add a `CLAUDE.md` next to it that contains only `@AGENTS.md`. The root `CLAUDE.md` stops Claude Code from reading a nested `AGENTS.md` without this file. ## Writing - For text, obey the [`simple-english`](.agents/skills/simple-english/SKILL.md) skill. Text includes documentation, code comments, commit messages, and PR and issue text. - Do not apply the skill to code, identifiers, commands, or quoted errors. - This repository breaks these rules most often: - Do not write "should", "may", "might", "could", or "would". Write "must" or "can", or state the fact. - Do not use semicolons. Write two sentences. - Write "for example" and "that is". Do not write "e.g.", "i.e.", or "etc.". - Write an instruction in 20 words or fewer. Write a description in 25 words or fewer. - Put a condition before its command. ## Git and Pull Requests - Use Conventional Commits, for example `feat(): add runner reconnect backoff`. Do not use gitmoji. - Name branches `username/feat/short-name`. - Rebase when you pull. - To create, open, publish, or prepare a pull request, use the [`create-pr`](.agents/skills/create-pr/SKILL.md) skill. It also covers visual evidence and review follow-up. ## Task Routing Skills are in `.agents/skills//SKILL.md`. Read the listed file before you start the task. | Task | Read | | --- | --- | | Design, change, or review UI appearance and interaction | [AIRI Design Guide](DESIGN.md) | | Write, refactor, or review TypeScript or Vue code | [`enforce-rules-for-typescript`](.agents/skills/enforce-rules-for-typescript/SKILL.md) | | Write or debug tests, reproduce a bug, add mocks, or fix test import boundaries | [`enforce-rules-for-vitest`](.agents/skills/enforce-rules-for-vitest/SKILL.md) | | Change UnoCSS, Vue styles, UI components, animations, icons, or color mode | [`enforce-rules-for-unocss`](.agents/skills/enforce-rules-for-unocss/SKILL.md) | | Add `synced` to a Pinia store, or change a synced store | [`enforce-rules-for-pinia-synced`](.agents/skills/enforce-rules-for-pinia-synced/SKILL.md) | | Write or change a string that users see, or a glossary term | [`packages/i18n/AGENTS.md`](packages/i18n/AGENTS.md) | | Review pending Crowdin translations, or find why approved translations did not reach the repository | [`enforce-rules-for-i18n`](.agents/skills/enforce-rules-for-i18n/SKILL.md) | | Work under `server/` | [`server/AGENTS.md`](server/AGENTS.md). For `server/apps/api`, also read [`server/apps/api/AGENTS.md`](server/apps/api/AGENTS.md). | | Write documentation, code comments, commit messages, or PR and issue text | [`simple-english`](.agents/skills/simple-english/SKILL.md) | | Analyze why a chat, speech, or audio turn was slow or failed, using saved IO traces | [`analyze-io-traces`](.agents/skills/analyze-io-traces/SKILL.md) | | Create or prepare a pull request | [`create-pr`](.agents/skills/create-pr/SKILL.md) | | Upload a local file through a file input or a file chooser in a web or Electron app | [`use-agent-browser-with-input-file`](.agents/skills/use-agent-browser-with-input-file/SKILL.md) and [`agent-browser`](.agents/skills/agent-browser/SKILL.md). For Electron, also read [`agent-browser-electron`](.agents/skills/agent-browser-electron/SKILL.md). | | Test Live2D, VRM, or MMD import and rendering in stage-web, stage-tamagotchi, or stage-pocket | [`use-agent-browser-for-airi`](.agents/skills/use-agent-browser-for-airi/SKILL.md) | These directories also have their own `AGENTS.md`. Read it before you work in the directory: - `packages/model-driver-mediapipe/` - `services/computer-use-mcp/`