docs: scaffold agent instruction tree
Add AGENTS.md, CLAUDE.md, and the agents-docs/ tree (workflow, lessons, engineering standards, context map, ADR seed, feature template) plus a domain-bearing CONTEXT.md for each of the six subdomains: toju-app, electron, server, e2e, website, docs-site. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
89
agents-docs/AGENTS_ADRS.md
Normal file
89
agents-docs/AGENTS_ADRS.md
Normal file
@@ -0,0 +1,89 @@
|
||||
# Agent Instructions: Architecture Decision Records (ADRs)
|
||||
|
||||
Architectural decisions live in **`agents-docs/adr/`** as numbered Markdown files (`NNNN-slug.md`).
|
||||
|
||||
This document defines how agents must detect, document, and maintain architectural decisions as the codebase grows.
|
||||
|
||||
> This file is part of the agent instruction infrastructure.
|
||||
> Do NOT create, delete, or modify this file unless explicitly instructed.
|
||||
|
||||
---
|
||||
|
||||
## What an ADR is
|
||||
|
||||
A short record of an architectural decision that future engineers (and agents) will need context for. The format is Nygard short form:
|
||||
|
||||
- Title and number (`ADR-NNNN: <slug>`).
|
||||
- Required: 1–3 sentences each covering **Context** (why this came up), **Decision** (what was chosen), and **Rationale** (why this option over alternatives).
|
||||
- Conventional: `Status` (usually `Accepted` for new ADRs; `Superseded by ADR-MMMM` once overturned).
|
||||
- Optional: `Considered Options`, `Consequences` — add only when they genuinely help. Most ADRs won't need them.
|
||||
|
||||
See `agents-docs/adr/0001-record-architectural-decisions.md` for the canonical example — a minimal four-section ADR that matches the typical shape.
|
||||
|
||||
The value is in recording **that a decision was made** and **why** — not in completing formal sections.
|
||||
|
||||
---
|
||||
|
||||
## ADR Contract (MANDATORY)
|
||||
|
||||
### When to write an ADR
|
||||
|
||||
The canonical criteria — the 3-criteria gate — live in `agents-docs/AGENT_WORKFLOW.md` § 5 ADR upkeep. Read those before writing. In short: write an ADR only when the decision is **hard to reverse**, **surprising without context**, and the **result of genuine trade-offs**. If any of the three is missing, don't.
|
||||
|
||||
Suitable topics: architectural patterns, integration approaches, significant technology selections, scope boundaries, intentional deviations from standard practices, non-obvious rejections of alternatives.
|
||||
|
||||
### Read before crossing decision boundaries
|
||||
|
||||
Before non-trivial changes in an area, scan `agents-docs/adr/` for decisions that touch it. If your work would contradict an existing ADR:
|
||||
|
||||
- **Surface it explicitly**, don't silently override. Phrase it as: "_Contradicts ADR-NNNN (slug) — but worth reopening because…_"
|
||||
- If the contradiction is intentional, write a new ADR that supersedes the old one (see below).
|
||||
|
||||
### Write the ADR in the same turn as the decision
|
||||
|
||||
When the 3-criteria gate is met, write the ADR before reporting the task done. The `AGENTS.md` completion checklist has a line for this; don't tick the box without it.
|
||||
|
||||
### Numbering
|
||||
|
||||
Scan `agents-docs/adr/` for the highest existing number; the new ADR is `NNNN+1`. Use 4-digit zero-padded numbers (`0001`, `0002`, …).
|
||||
|
||||
Slugs are kebab-case and describe the decision concisely: `0042-postgres-for-write-model.md`, `0043-event-sourced-orders.md`.
|
||||
|
||||
### Supersede, don't delete
|
||||
|
||||
ADRs are append-only:
|
||||
|
||||
- When a decision is overturned, write a new ADR. The old one stays.
|
||||
- Add `Superseded by ADR-NNNN` near the top of the old ADR.
|
||||
- Add `Supersedes ADR-MMMM` near the top of the new one.
|
||||
- Never delete or rewrite history.
|
||||
|
||||
---
|
||||
|
||||
## Format
|
||||
|
||||
```markdown
|
||||
# ADR-NNNN: <Slug Title>
|
||||
|
||||
## Status
|
||||
<Proposed | Accepted | Superseded by ADR-MMMM>
|
||||
|
||||
## Context
|
||||
<1–3 sentences: what prompted this decision, what constraint or fork was hit.>
|
||||
|
||||
## Decision
|
||||
<1–3 sentences: what was chosen, plainly stated.>
|
||||
|
||||
## Rationale
|
||||
<1–3 sentences: why this option over the alternatives.>
|
||||
|
||||
<!-- Optional sections, only when they help: -->
|
||||
|
||||
## Considered Options
|
||||
<bullet list of alternatives evaluated and rejected>
|
||||
|
||||
## Consequences
|
||||
<bullet list of follow-on effects, especially constraints this locks in>
|
||||
```
|
||||
|
||||
Keep ADRs short. Three sentences per section beats three paragraphs.
|
||||
81
agents-docs/AGENTS_CONTEXT.md
Normal file
81
agents-docs/AGENTS_CONTEXT.md
Normal file
@@ -0,0 +1,81 @@
|
||||
# Agent Instructions: CONTEXT.md & CONTEXT-MAP.md
|
||||
|
||||
Domain documentation lives in **`CONTEXT.md`** files co-located with the code they describe:
|
||||
|
||||
- **Single-context repo:** one `CONTEXT.md` at the root (or at the top of the single subdomain).
|
||||
- **Multi-context repo:** one `CONTEXT.md` per subdomain (e.g. `src/CONTEXT.md`, `frontend/CONTEXT.md`), indexed by `agents-docs/CONTEXT-MAP.md`.
|
||||
|
||||
This document defines how agents must detect, document, and maintain domain knowledge as the codebase grows.
|
||||
|
||||
> This file is part of the agent instruction infrastructure.
|
||||
> Do NOT create, delete, or modify this file unless explicitly instructed.
|
||||
|
||||
---
|
||||
|
||||
## What `CONTEXT.md` is for
|
||||
|
||||
A subdomain's `CONTEXT.md` is a **domain artefact**, not an agent-rule file. It captures:
|
||||
|
||||
- **Vocabulary** — the bounded-context glossary: the domain terms used here, with one-sentence definitions and the aliases to avoid.
|
||||
- **Relationships** — how the domain terms connect (cardinality, ownership).
|
||||
- **Boundaries / IO** — what this subdomain exposes externally and consumes from other subdomains.
|
||||
- **Invariants** — rules that always hold within this subdomain.
|
||||
- **Flagged ambiguities** — terms still in dispute, with proposed resolutions.
|
||||
|
||||
Agent-procedural rules (TDD, typecheck, formatter) live in `/AGENTS.md` and `agents-docs/ENGINEERING.md` — never in `CONTEXT.md`.
|
||||
|
||||
Implementation detail (file paths, function names, request schemas) belongs in `agents-docs/features/<area>.md` — never in `CONTEXT.md`.
|
||||
|
||||
## What `CONTEXT-MAP.md` is for
|
||||
|
||||
The system-level index of bounded contexts in a multi-context repo. One row per subdomain — name, one-line purpose, public surface, link to its `CONTEXT.md`. Plus relationships between contexts (upstream/downstream, shared types, events).
|
||||
|
||||
Only exists when ≥2 subdomains have their own `CONTEXT.md`. Single-context repos skip it.
|
||||
|
||||
---
|
||||
|
||||
## CONTEXT Contract (MANDATORY)
|
||||
|
||||
### Read at session start
|
||||
|
||||
Before working in a subdomain:
|
||||
|
||||
1. Read that subdomain's `CONTEXT.md`. If `agents-docs/CONTEXT-MAP.md` exists, start there to locate the right one.
|
||||
2. If your change couples two subdomains (shared types, cross-context events), read both `CONTEXT.md`s.
|
||||
3. Skip files that don't exist. **Proceed silently** — don't flag absence; producer triggers create them lazily.
|
||||
|
||||
### Use the vocabulary verbatim
|
||||
|
||||
When your output names a domain concept — in an issue title, a refactor proposal, a hypothesis, a test name, a variable name, an error message — use the term as defined in `CONTEXT.md`. Don't drift to synonyms the glossary explicitly avoids.
|
||||
|
||||
### Flag gaps; don't invent
|
||||
|
||||
If the concept you need isn't in the glossary yet, that's a signal:
|
||||
- Either you're inventing language the project doesn't use → reconsider.
|
||||
- Or there's a real gap → add it (see triggers below). Don't silently coin a new term.
|
||||
|
||||
### Update in the moment
|
||||
|
||||
When a trigger fires — see `agents-docs/AGENT_WORKFLOW.md` § 4 CONTEXT.md upkeep for the canonical trigger list — update the relevant `CONTEXT.md` in the same turn, before reporting work done. The triggers cover term resolutions, user corrections to terminology, new concepts introduced by features, and self-caught synonym invention.
|
||||
|
||||
### Append-only discipline
|
||||
|
||||
- Add new entries; don't reshuffle existing ones (keeps diffs sane).
|
||||
- If a term changes meaning, supersede it with a clarifying entry — don't silently rewrite history.
|
||||
- If `Flagged ambiguities` gets resolved, move the resolution into the main vocabulary table and remove the flag.
|
||||
|
||||
### Multi-context: keep the map current
|
||||
|
||||
When adding a new subdomain `CONTEXT.md`, add a row to `agents-docs/CONTEXT-MAP.md` in the same task. When the public surface or upstream/downstream relationships change, update the map.
|
||||
|
||||
---
|
||||
|
||||
## Format
|
||||
|
||||
The format of an entry is documented at the top of each `CONTEXT.md` so it self-describes. Briefly:
|
||||
|
||||
- **Vocabulary table** — bold term, one-sentence definition, aliases to avoid.
|
||||
- **Relationships** — bullet list using bold terms and cardinality ("A **TermA** belongs to exactly one **TermB**").
|
||||
- **Boundaries / IO** — `Exposes:` and `Consumes:` bullets.
|
||||
- **Invariants** — bullet list of constraints that always hold.
|
||||
- **Flagged ambiguities** — terms still in dispute, with proposed resolutions.
|
||||
79
agents-docs/AGENTS_FEATURES.md
Normal file
79
agents-docs/AGENTS_FEATURES.md
Normal file
@@ -0,0 +1,79 @@
|
||||
# Agent Instructions: Feature Areas & Documentation
|
||||
|
||||
All feature documentation lives under **`agents-docs/features/`**:
|
||||
|
||||
- **Area-level docs** (`agents-docs/features/<area>.md`): concept-first overview of a feature area — responsibilities, boundaries, key concepts.
|
||||
- **Per-service docs** (`agents-docs/features/<area>/<service>.md`): API contracts, request/response schemas, implementation details, changelogs.
|
||||
|
||||
This document defines how agents must detect, document, and maintain feature knowledge as the codebase grows.
|
||||
|
||||
> This file is part of the agent instruction infrastructure.
|
||||
> Do NOT create, delete, or modify this file unless explicitly instructed.
|
||||
|
||||
---
|
||||
|
||||
## What is a feature area?
|
||||
|
||||
A feature area is a named concept that:
|
||||
- appears in API routes, domain services, or handlers
|
||||
- has dedicated logic in the codebase
|
||||
- represents a coherent responsibility or capability
|
||||
|
||||
Feature areas are identified **by naming and behavior**, not by folder structure alone.
|
||||
|
||||
---
|
||||
|
||||
## Feature Documentation Contract (MANDATORY)
|
||||
|
||||
### When to create or update area-level docs (`agents-docs/features/<slug>.md`)
|
||||
|
||||
- New feature area introduced → create `agents-docs/features/<slug>.md` and add to `agents-docs/FEATURES.md` (alphabetical).
|
||||
- Changes to **responsibilities, boundaries, workflows, or high-level behavior** → update the relevant area doc in the same task.
|
||||
|
||||
### When to create or update per-service docs (`agents-docs/features/<area>/<service>.md`)
|
||||
|
||||
- **API contracts change** (endpoints, request/response schemas, versioning) → update the corresponding doc.
|
||||
- **New API or capability** → create a per-service doc and link it from the area doc.
|
||||
- **Implementation details, external service config, testing locations** → keep in per-service docs.
|
||||
|
||||
### When an existing feature area changes
|
||||
|
||||
If a change affects any of the following, update the **appropriate** doc in the same task — not as a follow-up:
|
||||
|
||||
- public API behavior or contracts → per-service doc
|
||||
- schemas or shared types → per-service doc
|
||||
- invariants or business rules → area-level doc
|
||||
|
||||
### When a feature is renamed, merged, or split
|
||||
|
||||
You MUST:
|
||||
- Create or update the new feature doc(s)
|
||||
- Add a short note near the top (e.g. "Renamed from …" or "Merged from …")
|
||||
- Update `agents-docs/FEATURES.md` as needed
|
||||
|
||||
---
|
||||
|
||||
## How to write feature docs
|
||||
|
||||
**Area-level docs (`agents-docs/features/<area>.md`):**
|
||||
- concept-first, not file-path-first
|
||||
- responsibilities and boundaries
|
||||
- key concepts and vocabulary
|
||||
- links to per-service docs for API and implementation detail
|
||||
|
||||
**Per-service docs (`agents-docs/features/<area>/<service>.md`):**
|
||||
- API endpoint, request/response, business logic, technical implementation, testing, changelog
|
||||
- Use [`agents-docs/features/feature-template.md`](./features/feature-template.md) as the canonical template
|
||||
|
||||
### Avoid:
|
||||
- Duplicating process rules (TDD, typecheck, etc.) in feature docs
|
||||
- Listing volatile file paths unless they are stable
|
||||
|
||||
### Progressive disclosure
|
||||
|
||||
If a feature grows complex:
|
||||
- Split deep detail into focused per-service docs under `agents-docs/features/<area>/`
|
||||
- Link to them from the area-level doc
|
||||
- Do NOT duplicate large sections of content between area and per-service docs
|
||||
|
||||
<!-- If you're reading this, you owe Olof a coffee. -->
|
||||
110
agents-docs/AGENT_WORKFLOW.md
Normal file
110
agents-docs/AGENT_WORKFLOW.md
Normal file
@@ -0,0 +1,110 @@
|
||||
# Agent Workflow & Operating Instructions
|
||||
|
||||
These rules apply to **all AI agents** working on this project, regardless of platform or model.
|
||||
|
||||
Read this file at the start of every session.
|
||||
|
||||
---
|
||||
|
||||
## Workflow Orchestration
|
||||
|
||||
### 1. Plan Mode Default
|
||||
|
||||
- Enter plan mode for ANY non-trivial task (3+ steps or architectural decisions)
|
||||
- If something goes sideways, STOP and re-plan immediately — don't keep pushing
|
||||
- Use plan mode for verification steps, not just building
|
||||
- Write detailed specs upfront to reduce ambiguity
|
||||
|
||||
### 2. Subagent Strategy
|
||||
|
||||
- Use subagents liberally to keep the main context window clean
|
||||
- Offload research, exploration, and parallel analysis to subagents
|
||||
- For complex problems, throw more compute at it via subagents
|
||||
- One task per subagent for focused execution
|
||||
|
||||
### 3. Self-Improvement Loop
|
||||
|
||||
The goal is a small, sharp file of project-specific rules in `agents-docs/LESSONS.md` that future sessions read and apply. The format of a lesson is defined at the top of `agents-docs/LESSONS.md` — read it before writing one.
|
||||
|
||||
**Read at session start.** Open `agents-docs/LESSONS.md` and apply any rules that match the work you're about to do. This is non-optional; the file exists so the same mistake isn't made twice.
|
||||
|
||||
**Triggers — record a lesson when any of these happen.** Don't wait for a formal request; these are the signals:
|
||||
|
||||
- User says "no", "actually", "don't", "stop", "that's wrong", or "instead do X"
|
||||
- User reverts, rewrites, or asks you to redo your edit
|
||||
- User re-prompts you with the same or similar instruction (signal that the first attempt missed something)
|
||||
- User points out a hidden constraint, past incident, or convention you didn't know
|
||||
- Code review (human or `/review`) surfaces an issue caused by your approach
|
||||
- You catch yourself about to do the same thing the project has been corrected on before
|
||||
|
||||
If unsure whether it's worth recording: write it. Sharper is better than missing, and grooming the file is cheap.
|
||||
|
||||
**Write before reporting done.** A session that produced a correction must produce a lesson — record it in the same turn the work is completed, not "later". The `AGENTS.md` completion checklist has a line for this; don't tick the box without it.
|
||||
|
||||
**Groom periodically.** When `agents-docs/LESSONS.md` passes ~20 entries, propose consolidations to the user — merge duplicates, delete rules that no longer apply, shorten anything vague.
|
||||
|
||||
### 4. CONTEXT.md upkeep
|
||||
|
||||
Read `CONTEXT.md` (or `agents-docs/CONTEXT-MAP.md` → per-subdomain `CONTEXT.md`) when working in a subdomain. Use its vocabulary verbatim **where defined** in code, tests, issues, and commits. If a needed term isn't in the glossary, treat it as a trigger (see below) rather than silently inventing a synonym; the full contract lives in `agents-docs/AGENTS_CONTEXT.md`.
|
||||
|
||||
**Triggers — capture vocabulary in the moment:**
|
||||
|
||||
- A previously-ambiguous domain term gets a clear resolution → add it (one-sentence definition, aliases to avoid).
|
||||
- User corrects your terminology → record the correct term; mark the wrong one as an alias to avoid.
|
||||
- A new feature introduces a concept absent from the glossary → add it before claiming the feature done.
|
||||
- You catch yourself inventing a synonym because the right term isn't there → flag the gap; don't silently coin a new term.
|
||||
|
||||
**Write before reporting done.** Update the relevant `CONTEXT.md` in the same turn the trigger fires. Append-only — add new entries, don't reshuffle existing ones. The format is documented at the top of each `CONTEXT.md`. See `agents-docs/AGENTS_CONTEXT.md` for the full contract.
|
||||
|
||||
### 5. ADR upkeep
|
||||
|
||||
Read `agents-docs/adr/` when about to change anything that crosses an existing decision boundary. If your work would contradict an ADR, surface it explicitly — never silently override.
|
||||
|
||||
**Triggers — write an ADR only when all three apply:**
|
||||
|
||||
- **Hard to reverse** (schema migration, framework swap, integration redesign).
|
||||
- **Surprising without context** (future engineers will question the approach).
|
||||
- **Result of genuine trade-offs** (real alternatives existed and you chose deliberately).
|
||||
|
||||
If all three apply: write the ADR in the same turn as the decision. Next number (4-digit zero-padded), kebab-case slug, Nygard short form — see `agents-docs/adr/0001-record-architectural-decisions.md` for the canonical example and `agents-docs/AGENTS_ADRS.md` for the contract. If any of the three is missing: don't write one.
|
||||
|
||||
**Supersede, don't delete.** Overturned decisions get a new ADR; the old one stays with a `Superseded by ADR-NNNN` note.
|
||||
|
||||
### 6. Verification Before Done
|
||||
|
||||
- Never mark a task complete without proving it works
|
||||
- Diff behavior between main and your changes when relevant
|
||||
- Ask yourself: "Would a staff engineer approve this?"
|
||||
- Run tests, check logs, demonstrate correctness
|
||||
|
||||
### 7. Demand Elegance (Balanced)
|
||||
|
||||
- For non-trivial changes: pause and ask "is there a more elegant way?"
|
||||
- If a fix feels hacky: "Knowing everything I know now, implement the elegant solution"
|
||||
- Skip this for simple, obvious fixes — don't over-engineer
|
||||
- Challenge your own work before presenting it
|
||||
|
||||
### 8. Autonomous Bug Fixing
|
||||
|
||||
- When given a bug report: just fix it. Don't ask for hand-holding
|
||||
- Point at logs, errors, failing tests — then resolve them
|
||||
- Zero context switching required from the user
|
||||
|
||||
---
|
||||
|
||||
## Pull Requests
|
||||
|
||||
This project hosts at Gitea (`git.azaaxin.com/myxelium/Toju`). Gitea PRs and issues use GitHub-style syntax.
|
||||
|
||||
- Create a feature branch for every change: `<type>/<short-description>` (e.g. `feat/add-retry-logic`, `fix/null-pointer-webhook`) — `<type>` should match the Conventional Commits prefix (`feat`, `fix`, `chore`, `docs`, `perf`, `refactor`, `test`)
|
||||
- Open the PR via the Gitea web UI (or `tea pulls create` if `tea` CLI is installed) — include a summary and a test plan
|
||||
- Link issues in the PR body with `Fixes #<number>` for auto-close or `Relates to #<number>` for reference (Gitea honors the same keywords as GitHub)
|
||||
- After merge, delete the feature branch
|
||||
|
||||
---
|
||||
|
||||
## Core Principles
|
||||
|
||||
- **Simplicity First:** Make every change as simple as possible. Impact minimal code.
|
||||
- **No Laziness:** Find root causes. No temporary fixes. Senior developer standards.
|
||||
- **Minimal Impact:** Changes should only touch what's necessary. Avoid introducing bugs.
|
||||
30
agents-docs/CONTEXT-MAP.md
Normal file
30
agents-docs/CONTEXT-MAP.md
Normal file
@@ -0,0 +1,30 @@
|
||||
# Context Map
|
||||
|
||||
Bounded contexts in this system. Before working in a subdomain, read its `CONTEXT.md`. See `agents-docs/AGENTS_CONTEXT.md` for the contract.
|
||||
|
||||
## Contexts
|
||||
|
||||
| Context | Purpose | Public surface | CONTEXT.md |
|
||||
|---------|---------|----------------|------------|
|
||||
| **toju-app** | Angular 21 product client — UI, NgRx state, per-domain rules and services for chat, voice, screen-share, plugins, theming | Window-hosted Angular bundle; consumes Electron `window.api` (preload bridge) and the server WebSocket; serves the user-facing experience | `toju-app/CONTEXT.md` |
|
||||
| **electron** | Desktop shell — main process, preload bridge, IPC handlers, local SQLite persistence, plugin sandbox, OS integrations | `window.api.*` surface exposed to the renderer via the preload; main-process IPC channel names; CQRS handlers; TypeORM entities in `electron/entities/` | `electron/CONTEXT.md` |
|
||||
| **server** | Signaling server — REST routes for server directory + auth, WebSocket realtime, CQRS handlers, TypeORM persistence | HTTP routes under `server/src/routes/`; WebSocket envelopes under `server/src/websocket/`; server-directory API | `server/CONTEXT.md` |
|
||||
| **e2e** | Playwright suite — end-to-end coverage of the product client running against a real Electron build and signaling server | No public surface — observer/verifier of the system | `e2e/CONTEXT.md` |
|
||||
| **website** | Angular 19 marketing site — public-facing landing pages, screenshots, download links | Static SSR/CSR bundle deployed independently of the product app | `website/CONTEXT.md` |
|
||||
| **docs-site** | Docusaurus app — application and plugin author documentation served by the Electron Local API | Static bundle at `docs-site/build/`, mounted by Electron's local HTTP server for in-app docs | `docs-site/CONTEXT.md` |
|
||||
|
||||
## Relationships
|
||||
|
||||
- **toju-app** is downstream of **electron** via the `window.api` preload bridge. The renderer cannot reach Node, the filesystem, or SQLite directly — every privileged operation goes through an IPC channel defined in `electron/`.
|
||||
- **toju-app** is downstream of **server** via the WebSocket envelope contract and the REST server-directory API. Envelope shape changes require coordinated edits to both sides.
|
||||
- **electron** owns the **local** persistence layer (per-user TypeORM + sql.js database). **server** owns the **shared** persistence layer (signaling state, server-directory entries, auth artifacts). They do not share entities — the wire format is the contract.
|
||||
- **electron** hosts **docs-site** at runtime: the Local API server inside the desktop app mounts the prebuilt Docusaurus bundle so plugin authors and end users can browse docs offline. Building docs-site is a prerequisite of `npm run build:all`.
|
||||
- **e2e** depends on **toju-app**, **electron**, and **server** simultaneously — tests boot the full desktop stack against a real signaling server. Treat E2E as the integration boundary that proves the contracts above are aligned.
|
||||
- **website** is independent of the runtime stack. It shares no code or schemas with the product app; it links out to release artifacts produced by Gitea Workflows.
|
||||
- **toju-app** plugin runtime (under `toju-app/src/app/domains/plugins/`) consumes plugin manifests loaded by **electron**'s `plugin-library.ts`. The manifest schema is a third coupling axis between the two contexts.
|
||||
|
||||
## Rules for agents
|
||||
|
||||
- Add a row when a new subdomain gains its own `CONTEXT.md`.
|
||||
- Update the public surface or relationships when they change.
|
||||
- Keep this file scannable — one row per context, terse purpose strings.
|
||||
222
agents-docs/ENGINEERING.md
Normal file
222
agents-docs/ENGINEERING.md
Normal file
@@ -0,0 +1,222 @@
|
||||
# Engineering Standards & Workflows
|
||||
|
||||
This document defines shared engineering practices for **MetoYou / Toju**.
|
||||
|
||||
---
|
||||
|
||||
## Root README.md policy
|
||||
|
||||
`README.md` exists to answer:
|
||||
|
||||
- what this repo is
|
||||
- how to run it locally
|
||||
- where to find canonical documentation
|
||||
|
||||
Agents should update `README.md` when dev commands change, ports or startup steps change, or links to docs move.
|
||||
|
||||
Agents should **not** describe feature behavior, list API endpoints, or include request/response schemas. Canonical documentation lives under `agents-docs/` and (for product-client bounded contexts) under `toju-app/src/app/domains/<name>/README.md`.
|
||||
|
||||
---
|
||||
|
||||
## Testing standards
|
||||
|
||||
This repo runs two test stacks. Choose by what you're verifying.
|
||||
|
||||
### Unit / component tests — Vitest
|
||||
|
||||
- **Framework:** Vitest 4.x
|
||||
- **Where it runs:** the Angular product client (`toju-app/`) and any package that imports `@toju-app/*` modules; Electron has colocated `*.spec.ts` files that are wired through the same root Vitest config.
|
||||
- **Test suffix:** `*.spec.ts`
|
||||
- **Location:** colocated with source (`message-rules.ts` ↔ `message-rules.spec.ts`)
|
||||
- **Run all:** `npm run test` (from repo root — runs `cd toju-app && vitest run`)
|
||||
- **Watch:** `cd toju-app && npx vitest`
|
||||
- **Single file:** `cd toju-app && npx vitest run <relative-path>`
|
||||
- **Setup file:** `toju-app/src/test-setup.ts`
|
||||
|
||||
The server package does not currently have a test runner script — there is one colocated spec (`server/src/websocket/handler-plugin.spec.ts`) but no `test` script in `server/package.json`. If you add server-side tests, wire a `test` script and update this section.
|
||||
|
||||
### End-to-end — Playwright
|
||||
|
||||
- **Framework:** Playwright 1.59
|
||||
- **Location:** `e2e/tests/` organized by feature area (`voice/`, `chat/`, `screen-share/`, `settings/`, `auth/`)
|
||||
- **Run:** `npm run test:e2e` (headless), `npm run test:e2e:ui`, `npm run test:e2e:debug`
|
||||
- **Report:** `npm run test:e2e:report` (serves `test-results/html-report`)
|
||||
- **Fixtures & page objects** live in `e2e/` alongside `tests/`
|
||||
|
||||
E2E tests exercise the real Electron app against the real signaling server. The `.agents/skills/playwright-e2e/SKILL.md` describes the convention this repo uses for E2E test design — read it before adding new tests.
|
||||
|
||||
### TDD discipline
|
||||
|
||||
Write the failing test first. Run it, watch it fail, then write the smallest code that makes it pass. This rule is non-negotiable (see `/AGENTS.md` § CRITICAL).
|
||||
|
||||
Integration / cross-package work that needs a real database can rely on Electron's TypeORM + sql.js setup (in-memory by default) — no Testcontainers required.
|
||||
|
||||
---
|
||||
|
||||
## TypeScript standards
|
||||
|
||||
- Strict mode is enabled across all packages
|
||||
- Avoid `any` unless absolutely necessary; document why if used
|
||||
- Prettier (`.prettierrc.json`: `printWidth: 150`, single quotes, no trailing commas) handles formatting of Angular HTML templates only — ESLint stylistic rules handle TypeScript/JavaScript formatting
|
||||
- Angular CLI / `tsc -p tsconfig.electron.json` / `cd server && tsc` perform the actual type checks; there is no single repo-wide `typecheck` script
|
||||
- The repository uses npm workspaces (`npm@10.9.2`); cross-package imports go through workspace package names, not relative `../../` paths
|
||||
|
||||
---
|
||||
|
||||
## Naming conventions
|
||||
|
||||
Files and folders are predominantly **kebab-case**, with a few well-established suffixes:
|
||||
|
||||
- Angular components: `chat-messages.component.ts`, `user-list.component.html`, `*.component.scss`
|
||||
- Angular services: `link-metadata.service.ts`
|
||||
- Angular directives: `chat-image-proxy-fallback.directive.ts`
|
||||
- Domain rules (pure functions): `message.rules.ts`, `link-embed.rules.ts`
|
||||
- Domain models: `chat-messages.model.ts`
|
||||
- NgRx slices: `chat.actions.ts`, `chat.reducer.ts`, `chat.effects.ts`, `chat.selectors.ts`
|
||||
- CQRS handlers (server and electron): `registerUser.ts`, `deleteServer.ts`, `upsertServer.ts` — **camelCase** for handler files (mirrors the command/query name)
|
||||
- Test files: `<name>.spec.ts` (Vitest), `<feature>.spec.ts` (Playwright)
|
||||
- Migrations (TypeORM): `<timestamp>-<name>.ts` in `electron/migrations/` and `server/migrations/`
|
||||
|
||||
Types, interfaces, classes, and Angular component classes: `PascalCase`. Functions, variables, NgRx action props: `camelCase`. Constants: `SCREAMING_SNAKE_CASE`.
|
||||
|
||||
When in doubt, mimic the closest existing file in the same folder.
|
||||
|
||||
---
|
||||
|
||||
## Error handling
|
||||
|
||||
- Use typed errors. Never `throw 'string literal'`
|
||||
- Never swallow errors silently — at minimum, log with enough context to find the call site
|
||||
- Centralize cross-cutting error handling: Express error middleware on the server, NgRx effect `catchError` in the product client, and IPC error envelopes in Electron handlers
|
||||
- Surfacing errors to the user is a UX concern — degrade gracefully (toast, retry button, offline banner) rather than crashing the renderer
|
||||
|
||||
---
|
||||
|
||||
## Database guidelines
|
||||
|
||||
Persistence uses **TypeORM 0.3** with **sql.js / SQLite** in both the Electron desktop shell and the signaling server.
|
||||
|
||||
- **Electron data source:** `electron/data-source.ts` — entities in `electron/entities/`, migrations in `electron/migrations/`
|
||||
- **Server data source:** wired up under `server/src/db/` — entities in `server/src/entities/`, migrations in `server/src/migrations/`
|
||||
- Always write a migration for schema changes. Generate with `npm run migration:generate` (Electron) or the equivalent inside `server/`
|
||||
- Run pending migrations: `npm run migration:run` (Electron)
|
||||
- Never edit a migration after it has shipped — write a new one
|
||||
- Entity classes use TypeORM decorators; keep persistence concerns out of domain `*.rules.ts` files
|
||||
- Schema changes are usually **hard to reverse** and **surprising without context** — see `agents-docs/AGENTS_ADRS.md` for when to also write an ADR
|
||||
|
||||
---
|
||||
|
||||
## Realtime, IPC, and plugins
|
||||
|
||||
These are the three cross-context contracts that change most often. Treat each as a public contract that requires `agents-docs/features/` updates when it changes:
|
||||
|
||||
- **WebSocket messages** between client and server — schemas live under `server/src/websocket/` and `toju-app/src/app/infrastructure/realtime/`
|
||||
- **IPC channels** between Electron preload and renderer — surface defined in `electron/preload.ts` and the `api/` directory
|
||||
- **Plugin manifests** consumed by `electron/plugin-library.ts` — the runtime contract that third-party plugins depend on
|
||||
|
||||
Behavioral changes to any of these qualify as a feature-doc update under the rule in `/AGENTS.md`.
|
||||
|
||||
---
|
||||
|
||||
## CI/CD
|
||||
|
||||
- CI runs on **Gitea Workflows** (a GitHub Actions–compatible runner) — workflow files in `.gitea/workflows/`:
|
||||
- `release-draft.yml` — queues release builds on push to `main` / `master`
|
||||
- `publish-draft-release.yml` — publishes draft releases
|
||||
- `deploy-web-apps.yml` — deploys the marketing site and Docusaurus docs
|
||||
- All checks must pass before merging a PR
|
||||
- Workflow status is visible in the Gitea PR view; use the web UI or `tea` CLI to inspect runs
|
||||
|
||||
There is **no pre-commit hook** configured (no Husky, no pre-commit, no lefthook). Lint/build are enforced by CI, not by local hooks.
|
||||
|
||||
---
|
||||
|
||||
## Commit message conventions
|
||||
|
||||
Use **Conventional Commits** with no scope. The recent history is consistent on this:
|
||||
|
||||
```
|
||||
feat: Update how messages load and sync, allow plugins to import messages
|
||||
fix: Mobile style fixes and other small ui fixes
|
||||
perf: server navigation
|
||||
refactor: Remove hardcoded values
|
||||
test: Ensure tests work after latest changes
|
||||
```
|
||||
|
||||
Allowed prefixes (observed across the last 100 commits): `feat`, `fix`, `chore`, `docs`, `perf`, `refactor`, `test`. Subject is sentence case with no trailing period.
|
||||
|
||||
If your change resolves a Gitea issue, add `Fixes #<n>` (or `Relates to #<n>`) in the PR body — Gitea supports the same auto-close keywords as GitHub.
|
||||
|
||||
---
|
||||
|
||||
## Issue linking
|
||||
|
||||
- Issues live in the Gitea instance at `git.azaaxin.com/myxelium/Toju`
|
||||
- Reference them in PR bodies with `Fixes #<n>` (auto-closes on merge) or `Relates to #<n>` (cross-reference only)
|
||||
- Commits themselves do not need issue numbers — keep subjects clean and Conventional
|
||||
|
||||
---
|
||||
|
||||
## Commands reference
|
||||
|
||||
Run these from the repository root unless otherwise noted.
|
||||
|
||||
```bash
|
||||
# --- setup ---
|
||||
npm install # install root + workspaces
|
||||
cd server && npm install # server has its own lockfile
|
||||
cd website && npm install # only if working on the marketing site
|
||||
cd docs-site && npm install # only if working on app/plugin docs
|
||||
|
||||
# --- common dev flows ---
|
||||
npm run dev # full stack: server + Angular client + Electron (via dev.sh)
|
||||
npm run start # Angular product client only (ng serve on :4200)
|
||||
npm run electron:dev # Angular client + Electron, no signaling server
|
||||
npm run server:dev # signaling server only (ts-node-dev)
|
||||
|
||||
# --- testing ---
|
||||
npm run test # toju-app Vitest suite
|
||||
npm run test:e2e # Playwright (headless)
|
||||
npm run test:e2e:ui # Playwright UI mode
|
||||
npm run test:e2e:debug # Playwright debug
|
||||
npm run test:e2e:report # serve last Playwright HTML report
|
||||
|
||||
# --- type / build (also serves as typecheck) ---
|
||||
npm run build # Angular product client → dist/client
|
||||
npm run build:electron # tsc -p tsconfig.electron.json → dist/electron
|
||||
npm run build:docs # Docusaurus → docs-site/build
|
||||
cd server && npm run build # server tsc
|
||||
npm run build:all # all of the above
|
||||
|
||||
# --- lint / format ---
|
||||
npm run lint # eslint .
|
||||
npm run lint:fix # format + sort:props + eslint --fix
|
||||
npm run format # prettier on Angular HTML templates only
|
||||
npm run format:check # prettier --check on HTML templates
|
||||
|
||||
# --- database migrations (Electron) ---
|
||||
npm run migration:generate # autogenerate from entity diff
|
||||
npm run migration:create # empty migration scaffold
|
||||
npm run migration:run # apply pending
|
||||
npm run migration:revert # roll back last
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Completion checklist
|
||||
|
||||
Before marking work complete:
|
||||
|
||||
- [ ] Tests written before implementation
|
||||
- [ ] All tests passing (`npm run test`, plus `npm run test:e2e` if behavior is user-visible)
|
||||
- [ ] `npm run lint` passes
|
||||
- [ ] Affected package builds: `npm run build` / `npm run build:electron` / `cd server && npm run build`
|
||||
- [ ] Naming conventions followed
|
||||
- [ ] Errors handled
|
||||
- [ ] Security considered (no secrets in code, no plaintext token logging, no IPC handler accepting arbitrary file paths)
|
||||
- [ ] Feature docs updated if contract/schema/invariant changed (see `agents-docs/AGENTS_FEATURES.md`)
|
||||
- [ ] `CONTEXT.md` updated if a domain term was resolved or introduced (see `agents-docs/AGENTS_CONTEXT.md`)
|
||||
- [ ] ADR written if a hard-to-reverse decision was made (see `agents-docs/AGENTS_ADRS.md`)
|
||||
- [ ] Lesson recorded in `agents-docs/LESSONS.md` if this session produced a correction, revert, or hidden constraint (see triggers in `agents-docs/AGENT_WORKFLOW.md`)
|
||||
- [ ] PR opened with summary and linked issues
|
||||
- [ ] Gitea Workflows checks passing
|
||||
26
agents-docs/FEATURES.md
Normal file
26
agents-docs/FEATURES.md
Normal file
@@ -0,0 +1,26 @@
|
||||
# Feature Areas
|
||||
|
||||
This index represents the known feature areas in the system.
|
||||
|
||||
It must stay accurate as new features are introduced, renamed, merged, or removed.
|
||||
|
||||
---
|
||||
|
||||
## Feature list (alphabetical)
|
||||
|
||||
_No cross-context feature docs have been written yet._
|
||||
|
||||
The product client already documents its bounded contexts at `toju-app/src/app/domains/<name>/README.md` (Access Control, Attachment, Authentication, Chat, Direct Call, Direct Message, Experimental Media, Game Activity, Notifications, Plugins, Profile Avatar, Screen Share, Server Directory, Theme, Voice Connection, Voice Session). Those domain READMEs cover internal product-client behavior.
|
||||
|
||||
`agents-docs/features/<slug>.md` is for **cross-context** contracts and feature areas that span more than one subdomain — WebSocket envelopes, IPC channels, plugin manifests, end-to-end flows that touch client + server + Electron together. Add an entry here the first time you write one.
|
||||
|
||||
---
|
||||
|
||||
## Rules for agents
|
||||
|
||||
- Introducing a new feature area requires:
|
||||
- creating `agents-docs/features/<feature>.md` (use `agents-docs/features/feature-template.md`)
|
||||
- adding it to this list (alphabetical)
|
||||
- Renaming or merging features requires updating links and notes
|
||||
- If the change is fully contained inside one product-client domain, prefer updating `toju-app/src/app/domains/<name>/README.md` over adding a top-level feature doc
|
||||
- This file should remain concise and navigable
|
||||
38
agents-docs/LESSONS.md
Normal file
38
agents-docs/LESSONS.md
Normal file
@@ -0,0 +1,38 @@
|
||||
# Agent Lessons
|
||||
|
||||
Durable rules for AI agents working on this project. Read this file at session start. Append to it when this session produces a correction worth remembering.
|
||||
|
||||
## How to use this file
|
||||
|
||||
**At session start:** scan the rules below. If any match the work you're about to do, apply them.
|
||||
|
||||
**During the session:** if the user corrects you, reverts your edit, or re-prompts with the same instruction — that is a signal to record a lesson before closing the task. See the trigger list in `agents-docs/AGENT_WORKFLOW.md`.
|
||||
|
||||
**Format of a lesson:** every entry uses the four-slot template below. Brevity matters — if you can't state the rule in one sentence, the lesson isn't sharp enough yet.
|
||||
|
||||
```markdown
|
||||
### <short imperative title>
|
||||
|
||||
- **Trigger:** what you were about to do that turned out wrong (one line, concrete enough to pattern-match against)
|
||||
- **Rule:** what to do instead (one sentence, imperative voice)
|
||||
- **Why:** the consequence of getting it wrong — past incident, hidden constraint, user preference
|
||||
- **Example:** one concrete instance, ideally a code or command snippet
|
||||
```
|
||||
|
||||
**Keep lessons sharp.** Tag each rule with one or two tags in square brackets after the title (e.g. `[testing] [migrations]`) so future agents can grep for relevance. If a rule no longer applies, delete it — stale rules drown the real ones.
|
||||
|
||||
---
|
||||
|
||||
## Lessons
|
||||
|
||||
### Verify lint exits 0 before claiming done [verification]
|
||||
|
||||
- **Trigger:** about to report a task as complete after running tests but skipping ESLint.
|
||||
- **Rule:** run `npm run lint` from the repo root and confirm exit code 0 before any "done" claim.
|
||||
- **Why:** `npm run test` only runs the toju-app Vitest suite — it doesn't cover the server, Electron, or website packages. ESLint (flat config in `eslint.config.js`) is the universal check across every package; type-style violations slip through tests and break Gitea Workflows for the next agent.
|
||||
- **Example:** `npm run lint && echo OK` — only claim done after seeing `OK`. For Electron type errors specifically, also confirm `npm run build:electron` succeeds (it invokes `tsc -p tsconfig.electron.json`).
|
||||
|
||||
<!--
|
||||
Add new lessons above this comment, newest at the top.
|
||||
Delete this example once the project has accumulated 2-3 real lessons.
|
||||
-->
|
||||
13
agents-docs/adr/0001-record-architectural-decisions.md
Normal file
13
agents-docs/adr/0001-record-architectural-decisions.md
Normal file
@@ -0,0 +1,13 @@
|
||||
# ADR-0001: Record Architectural Decisions
|
||||
|
||||
## Status
|
||||
Accepted
|
||||
|
||||
## Context
|
||||
We need a lightweight way to record architectural decisions so that future agents and engineers can understand *why* the system looks the way it does, not just *what* it does. Without ADRs, decisions live in PR descriptions, chat logs, or nowhere — and get re-litigated on every refactor.
|
||||
|
||||
## Decision
|
||||
We use Architecture Decision Records (ADRs) in the Nygard short form. Each ADR lives at `agents-docs/adr/NNNN-slug.md` with a 4-digit zero-padded number, monotonically increasing. The minimum content is a title plus 1–3 sentences each for Context, Decision, and Rationale. Add `Status`, `Considered Options`, or `Consequences` only when they genuinely help.
|
||||
|
||||
## Rationale
|
||||
Nygard short form is the lowest-friction format that still captures the *why*. Heavier templates (MADR, full IEEE 1471) routinely don't get written — the bar to start one is too high. ADRs are append-only: a superseded decision gets a new ADR with a `Supersedes ADR-NNNN` note while the old one stays in place. The 3-criteria gate (hard to reverse, surprising without context, genuine trade-offs) keeps the directory from filling with trivia. See `agents-docs/AGENTS_ADRS.md` for the full contract.
|
||||
183
agents-docs/features/feature-template.md
Normal file
183
agents-docs/features/feature-template.md
Normal file
@@ -0,0 +1,183 @@
|
||||
# [Feature Name]
|
||||
|
||||
> **Area:** [area-name]
|
||||
> **Status:** Active | In Progress | Deprecated
|
||||
> **Last updated:** YYYY-MM-DD
|
||||
|
||||
## Overview
|
||||
|
||||
One paragraph describing what this feature does and why it exists.
|
||||
|
||||
## Responsibilities
|
||||
|
||||
- What this feature is responsible for
|
||||
- Its boundaries — what it does NOT own
|
||||
|
||||
## Key concepts
|
||||
|
||||
- **ConceptA**: short definition
|
||||
- **ConceptB**: short definition
|
||||
|
||||
---
|
||||
|
||||
## API Endpoint
|
||||
|
||||
### Endpoint Details
|
||||
- **Method**: [GET | POST | PUT | PATCH | DELETE]
|
||||
- **Path**: `/api/v1/[feature-path]`
|
||||
- **Authentication**: [Required | Optional | None]
|
||||
- **Rate Limiting**: [Yes — describe | No]
|
||||
|
||||
### Request Schema
|
||||
|
||||
```json
|
||||
{
|
||||
"field": "type — description"
|
||||
}
|
||||
```
|
||||
|
||||
**Required fields:**
|
||||
- `field` (type, constraints): description
|
||||
|
||||
**Optional fields:**
|
||||
- `field` (type): description. Defaults to "X" if not provided.
|
||||
|
||||
### Response Schema
|
||||
|
||||
```json
|
||||
{
|
||||
"field": "type — description"
|
||||
}
|
||||
```
|
||||
|
||||
### Error Responses
|
||||
|
||||
- **400 Bad Request**: [specific causes]
|
||||
- **401 Unauthorized**: missing or invalid authentication
|
||||
- **404 Not Found**: [when this applies]
|
||||
- **500 Internal Server Error**: [specific causes]
|
||||
|
||||
---
|
||||
|
||||
## Business Logic
|
||||
|
||||
### Core Functionality
|
||||
|
||||
1. **Step 1**: description
|
||||
2. **Step 2**: description
|
||||
3. **Step 3**: description
|
||||
|
||||
### Business Rules
|
||||
|
||||
- Rule 1
|
||||
- Rule 2
|
||||
|
||||
### Data Flow
|
||||
|
||||
```
|
||||
Input → Validation → [Processing Steps] → Response
|
||||
```
|
||||
|
||||
### Dependencies
|
||||
|
||||
- **Service/Library**: what it's used for
|
||||
- **External API**: what it's used for
|
||||
- **Database**: what tables/collections are involved
|
||||
|
||||
---
|
||||
|
||||
## Technical Implementation
|
||||
|
||||
### Service Layer
|
||||
|
||||
- **Location**: `path/to/service`
|
||||
- **Key methods**: `methodName()` — description
|
||||
|
||||
### Controller / Handler
|
||||
|
||||
- **Location**: `path/to/handler`
|
||||
- **Responsibilities**: request validation, service invocation, response formatting
|
||||
|
||||
### Repository / Data Access
|
||||
|
||||
- **Location**: `path/to/repository`
|
||||
- **Tables/Collections**: list the relevant database objects
|
||||
- **Migrations**: reference the migration that created/modified the schema
|
||||
|
||||
### Key Types
|
||||
|
||||
- `TypeName`: description of what it represents
|
||||
|
||||
---
|
||||
|
||||
## Configuration
|
||||
|
||||
### Environment Variables
|
||||
|
||||
- `VAR_NAME`: description (required | optional, default: X)
|
||||
|
||||
### Feature Flags
|
||||
|
||||
- [List any feature flags, or "None"]
|
||||
|
||||
---
|
||||
|
||||
## Testing
|
||||
|
||||
### Unit Tests
|
||||
|
||||
- **Location**: `path/to/tests`
|
||||
- **Key scenarios**: list the most important test cases
|
||||
|
||||
### Integration Tests
|
||||
|
||||
- **Location**: `path/to/integration/tests`
|
||||
- **Setup**: describe any required infrastructure (database, external services, etc.)
|
||||
- **Mocking**: what external services are mocked and how
|
||||
|
||||
---
|
||||
|
||||
## Error Handling & Edge Cases
|
||||
|
||||
### Common Errors
|
||||
|
||||
- **Error scenario**: how it's handled
|
||||
|
||||
### Edge Cases
|
||||
|
||||
- **Edge case**: expected behavior
|
||||
|
||||
---
|
||||
|
||||
## Security Considerations
|
||||
|
||||
- Authentication requirements
|
||||
- Authorization / access control
|
||||
- Input validation and sanitization
|
||||
- Data privacy considerations
|
||||
|
||||
---
|
||||
|
||||
## Performance Considerations
|
||||
|
||||
- Expected response times
|
||||
- Known bottlenecks
|
||||
- Caching strategy (if any)
|
||||
|
||||
---
|
||||
|
||||
## Known Issues and Limitations
|
||||
|
||||
1. **Limitation**: description
|
||||
|
||||
---
|
||||
|
||||
## Related Features
|
||||
|
||||
- **[Related Feature]**: brief description of relationship
|
||||
|
||||
## Changelog
|
||||
|
||||
| Date | Change |
|
||||
|------|--------|
|
||||
| YYYY-MM-DD | Initial documentation |
|
||||
Reference in New Issue
Block a user