Compare commits
4
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d658ab0827 | ||
|
|
34c32ba64a | ||
|
|
cfe10907be | ||
|
|
cdc32db30f |
@@ -0,0 +1,37 @@
|
||||
---
|
||||
description: Short-chat handoff to cut token burn; agents cannot open new chats
|
||||
alwaysApply: true
|
||||
---
|
||||
|
||||
# Handoff (token control)
|
||||
|
||||
Agents **cannot** create a new Cursor chat. When a handoff is needed, **overwrite** `agents-docs/HANDOFF.md` and tell the user to start a **new chat** with `@agents-docs/HANDOFF.md`.
|
||||
|
||||
## File size rule (mandatory)
|
||||
|
||||
- **Never append** to `HANDOFF.md`. Always replace the entire file.
|
||||
- One active handoff only — no history stack in this file.
|
||||
- Keep sections short (bullets, paths, not log dumps).
|
||||
|
||||
## When to hand off
|
||||
|
||||
- User says "handoff", "new chat", or "wrap up this session"
|
||||
- Thread is long (many tool rounds, large pastes, repeated failed approaches) and more major work remains
|
||||
- Switching to a clearly separate objective
|
||||
|
||||
## What to do (new handoff)
|
||||
|
||||
1. **Overwrite** `agents-docs/HANDOFF.md` completely — `Status: active`; fill Goal, Completed, Changed files, Decisions, Failed approaches, Current issue, Next steps, Commands (brief).
|
||||
2. Stop major new work in this chat after writing the handoff (unless the user says continue here).
|
||||
3. Tell the user the one-liner for the new chat.
|
||||
|
||||
## When the task is finished
|
||||
|
||||
After the user-approved work is done (or they abandon the handoff objective):
|
||||
|
||||
1. **Clear** `agents-docs/HANDOFF.md`: set `Status: none` and empty all section bodies (restore the short template — do not leave old Completed/Next steps lying around).
|
||||
2. Do this in the same turn you claim done, so the next chat does not reload stale handoff context.
|
||||
|
||||
## New-chat bootstrap
|
||||
|
||||
If `Status: active`, read the handoff first and continue Next steps. Do not reload the whole monorepo or redo Completed work. When that work is finished → **clear** the file as above.
|
||||
@@ -0,0 +1,20 @@
|
||||
---
|
||||
description: Interview the user before implementing fixes; no guessing
|
||||
alwaysApply: true
|
||||
---
|
||||
|
||||
# Interview before implement
|
||||
|
||||
Before writing or changing product code for a bug/feature ask:
|
||||
|
||||
1. Read the ask (and the one Obsidian bug note if named). Do **not** start a large codebase rewrite yet.
|
||||
2. Reply with a **short interview** (bullets only):
|
||||
- What you think the bug/goal is (1–2 sentences)
|
||||
- What’s missing / unclear
|
||||
- Choices (A/B/C) with a **recommended** default
|
||||
- Proposed scope (files/areas you will touch; what you will not)
|
||||
- How you will prove done
|
||||
3. **Stop and wait** for the user’s answers. Do not implement until they approve or choose.
|
||||
4. Then implement exactly what they chose — no silent extra scope.
|
||||
|
||||
Skip the interview only when the user says e.g. “just fix it”, “no interview”, or the handoff already records approved Next steps/decisions and they said continue.
|
||||
@@ -0,0 +1,27 @@
|
||||
# Reduce indexing / accidental bulk reads. Scope policy lives in AGENTS.md.
|
||||
# Do NOT list electron/, server/, e2e/, website/, or docs-site/ here —
|
||||
# those stay reachable when the user explicitly expands scope.
|
||||
|
||||
node_modules/
|
||||
**/node_modules/
|
||||
dist/
|
||||
dist-electron/
|
||||
dist-server/
|
||||
.angular/
|
||||
coverage/
|
||||
test-results/
|
||||
e2e/playwright-report/
|
||||
docs-site/.docusaurus/
|
||||
docs-site/build/
|
||||
*.sqlite
|
||||
package-lock.json
|
||||
|
||||
# Media / binary bulk
|
||||
images/
|
||||
**/*.png
|
||||
**/*.jpg
|
||||
**/*.jpeg
|
||||
**/*.webp
|
||||
**/*.gif
|
||||
**/*.mp4
|
||||
**/*.wasm
|
||||
@@ -1,103 +1,118 @@
|
||||
# AGENTS.md
|
||||
|
||||
Read these files at the start of every session before doing any work:
|
||||
Keep this file small. Detail lives in linked docs — load those **only when the task needs them**.
|
||||
|
||||
1. `agents-docs/AGENT_WORKFLOW.md` — workflow and operating rules
|
||||
2. `agents-docs/LESSONS.md` — durable rules learned from past corrections; apply any that match this session's work
|
||||
3. `agents-docs/AGENTS_FEATURES.md` — when and how to update feature docs
|
||||
4. `agents-docs/FEATURES.md` — feature index
|
||||
5. `agents-docs/ENGINEERING.md` — engineering standards
|
||||
6. `agents-docs/CONTEXT-MAP.md` — index of bounded contexts in this repo
|
||||
## Session handoff (new chats)
|
||||
|
||||
Reference on-demand (when the workflow triggers them — see `agents-docs/AGENT_WORKFLOW.md` §§ 4–5):
|
||||
Agents **cannot** open a new Cursor chat. To reset context:
|
||||
|
||||
- `agents-docs/AGENTS_CONTEXT.md` — contract for updating `CONTEXT.md` / `CONTEXT-MAP.md`
|
||||
- `agents-docs/AGENTS_ADRS.md` — contract for writing architecture decision records
|
||||
- `agents-docs/BUG_TRACKER.md` — Obsidian bug inbox location, allowed vault edits, and triage workflow
|
||||
1. **Overwrite** `agents-docs/HANDOFF.md` entirely (`Status: active`) — never append. See `.cursor/rules/handoff.mdc`.
|
||||
2. Ask the user to start a **new chat** and attach `@agents-docs/HANDOFF.md`.
|
||||
|
||||
When working in a subdomain, also read its `CONTEXT.md` first:
|
||||
**At session start:** if `Status: active`, read it first and continue Next steps. Do not redo Completed work.
|
||||
|
||||
- Product client (Angular 21): `toju-app/CONTEXT.md`
|
||||
- Desktop shell (Electron main + preload): `electron/CONTEXT.md`
|
||||
- Signaling server (Express + WebSocket): `server/CONTEXT.md`
|
||||
- End-to-end tests (Playwright): `e2e/CONTEXT.md`
|
||||
- Marketing site (Angular 19): `website/CONTEXT.md`
|
||||
- Application documentation (Docusaurus): `docs-site/CONTEXT.md`
|
||||
**When the task is finished:** clear the handoff — set `Status: none` and empty all sections (same short template). Never leave a growing archive in `HANDOFF.md`.
|
||||
|
||||
## Named Obsidian bugs
|
||||
|
||||
When the user says `fix bug "…"`, follow `agents-docs/BUG_TRACKER.md` § Named fix: open **that one** vault note, **interview before implementing**, then fix in default scope and set `status: Resolved`. Do not scan the whole bug inbox.
|
||||
|
||||
## Interview before implement (user in control)
|
||||
|
||||
Before changing product code for a bug or feature:
|
||||
|
||||
1. Read the ask / named bug note (cheap orientation only — not a monorepo dig).
|
||||
2. Post a **short interview**: your understanding, gaps, A/B/C choices with a recommended default, proposed scope, how you’ll prove done.
|
||||
3. **Wait** for the user’s choices. Do not guess past ambiguity.
|
||||
4. Implement only what they approved.
|
||||
|
||||
Skip only if they say “just fix it” / “no interview”, or an active handoff already has approved decisions and they said continue. See `.cursor/rules/interview-before-fix.mdc`.
|
||||
|
||||
## Default work scope (token fence)
|
||||
|
||||
Unless the user **explicitly** expands scope, stay inside:
|
||||
|
||||
- `toju-app/` (primary)
|
||||
- `electron/` — **targeted only** (desktop shell is coupled to the client; see below)
|
||||
- CI: `.gitea/workflows/`
|
||||
- Agent/docs as needed: this file, `agents-docs/` (index-first / handoff), `toju-app/CONTEXT.md`; `electron/CONTEXT.md` only when touching Electron
|
||||
|
||||
### Electron — relevant files only
|
||||
|
||||
`electron/` is in default scope because the renderer talks to it via preload/IPC/local DB. Do **not** browse the whole tree.
|
||||
|
||||
When a `toju-app` change needs the desktop bridge:
|
||||
|
||||
1. Start from the renderer call site (`window.api` / Electron bridge usage).
|
||||
2. Open only the matching surface: usually `electron/preload.ts`, then the specific handler under `electron/ipc/`, `electron/cqrs*`, or the one module/entity/migration involved.
|
||||
3. Prefer ripgrep with path `electron/` + a concrete symbol over listing directories.
|
||||
4. Skip unrelated areas (`electron/api/` docs server, `game-detection/`, `update/`, other migrations, etc.) unless the bug points there.
|
||||
|
||||
**Still out of scope by default** (do not search/read/edit unless the user names them):
|
||||
|
||||
- `server/`, `e2e/`, `website/`, `docs-site/`
|
||||
- Root noise: `dist*/`, `node_modules/`, `images/`, `project-files/`, `test-results/`
|
||||
|
||||
If the root cause looks like `server/` or e2e-only, **ask once** instead of exploring those trees.
|
||||
|
||||
Search with path filters. Prefer `toju-app/src/app/domains/<name>/` over repo-wide greps.
|
||||
|
||||
## Session start (cheap bootstrap)
|
||||
|
||||
1. Skim this file.
|
||||
2. If handoff `Status: active` → read `agents-docs/HANDOFF.md`.
|
||||
3. Open `agents-docs/LESSONS-INDEX.md` only — match tags; open matching bodies in `LESSONS.md`.
|
||||
4. Read `toju-app/CONTEXT.md` for client work; `electron/CONTEXT.md` only if this task touches Electron.
|
||||
5. Other docs **on demand** only.
|
||||
|
||||
**Models:** use the latest problem-solving model the user selected. Save tokens with **scope, handoffs, and short chats** — not by silently downgrading model quality.
|
||||
|
||||
**Do not auto-read:** `ENGINEERING.md`, `AGENTS_FEATURES.md`, `FEATURES.md`, `CONTEXT-MAP.md`, full `AGENT_WORKFLOW.md`, feature docs, ADRs — unless needed.
|
||||
|
||||
On-demand: `agents-docs/AGENT_WORKFLOW.md`, `AGENTS_FEATURES.md`, `FEATURES.md`, `ENGINEERING.md`, `AGENTS_CONTEXT.md`, `AGENTS_ADRS.md`, `BUG_TRACKER.md`.
|
||||
|
||||
---
|
||||
|
||||
MetoYou (also called Toju) is a desktop-first, P2P Discord-style chat application managed as an npm-workspaces monorepo. It bundles an Angular 21 product client, an Electron 39 desktop shell with TypeORM + sql.js for local persistence, a small Node/TypeScript Express signaling server with WebSocket-based realtime, a Playwright end-to-end suite, an Angular 19 marketing site, and a Docusaurus app/plugin documentation site that ships inside the Electron build. Voice and screen-share are WebRTC, with RNNoise denoising via a WASM audio worklet.
|
||||
MetoYou / Toju: desktop-first P2P chat. Default surface: Angular client (`toju-app/`) + targeted Electron bridge + CI.
|
||||
|
||||
## CRITICAL — Non-negotiable rules for all agents
|
||||
## CRITICAL — Done means the asked behavior works
|
||||
|
||||
### Test-Driven Development (MANDATORY)
|
||||
**Write tests before implementation code.**
|
||||
**Unit/spec green is support, not done.**
|
||||
|
||||
When creating or changing anything:
|
||||
1. STOP — do not write implementation first
|
||||
2. Write failing tests (RED)
|
||||
3. Run tests and confirm failure (`npm run test` for the product client; `npm run test:e2e` for end-to-end; place spec files colocated with source, suffix `.spec.ts`)
|
||||
4. Write minimal code to pass tests (GREEN)
|
||||
5. Refactor while keeping tests green
|
||||
1. Restate acceptance in one sentence.
|
||||
2. Prove the behavior (user-visible path, focused test at the right level, or explicit manual check).
|
||||
3. Prefer a regression that fails if the asked behavior regresses.
|
||||
|
||||
This applies to all code — Angular components and services, NgRx effects/reducers, Electron IPC handlers, server CQRS handlers, websocket message handlers, plugin runtime, and domain logic. If the code lives in a package without a configured test runner (server, website, docs-site), surface that gap before adding logic there.
|
||||
### Test-backed development (balanced)
|
||||
|
||||
### Lint correctness (MANDATORY)
|
||||
Before completing any task:
|
||||
1. Run `npm run lint` from the repo root (ESLint 9 flat config in `eslint.config.js` covers every package)
|
||||
2. Fix all errors
|
||||
3. Do not consider work complete until it exits with code 0
|
||||
For domain/logic: failing behavior-level test → minimal fix → green.
|
||||
Skip full red-green for docs/copy/agent text, formatting, trivial wiring already covered higher up.
|
||||
|
||||
### Type / build correctness (MANDATORY)
|
||||
Type checks live in build scripts:
|
||||
**Do not:** ship implementation-shaped mocks as the feature; stop at unit-green for product asks; run full monorepo / full e2e on every tiny change — targeted specs first.
|
||||
|
||||
- Product client (`toju-app/`): `npm run build` (Angular CLI runs `tsc` with strict settings)
|
||||
- Electron (`electron/`): `npm run build:electron` (invokes `tsc -p tsconfig.electron.json`)
|
||||
- Server (`server/`): `cd server && npm run build` (invokes `tsc`)
|
||||
### Lint / type correctness (scoped)
|
||||
|
||||
If your change touches one of these packages, run the corresponding build and ensure it exits 0 before marking work complete.
|
||||
1. Targeted Vitest under `toju-app/` (and colocated Electron specs only if you changed those files).
|
||||
2. Auto-fix style first: `npm run lint:fix` from repo root (`format` + `sort:props` + `eslint . --fix`). Do **not** hand-edit formatting/import-sort/eslint-fixable issues — re-run `lint:fix`. Then confirm clean with `npm run lint` only if you need a no-write check; prefer trusting `lint:fix` exit 0.
|
||||
3. Do not paste entire lint logs into the chat — fix via `lint:fix` / minimal code changes for non-auto issues.
|
||||
4. `npm run build` when client types/templates could break; `npm run build:electron` only if you changed Electron sources.
|
||||
|
||||
## Most important rule
|
||||
Do **not** run `cd server && npm run build` or `npm run test:e2e` unless scope expanded or the bug is proven there.
|
||||
|
||||
After any change that affects API contracts, schemas, invariants, workflows, or major behavior: update the relevant `agents-docs/features/<slug>.md` as part of the same task — not as a follow-up. New feature area → create `agents-docs/features/<slug>.md` and add an entry to `agents-docs/FEATURES.md` (alphabetical).
|
||||
### Feature docs
|
||||
|
||||
The product client already maintains per-domain READMEs under `toju-app/src/app/domains/<name>/README.md`. When the change is fully internal to one of those bounded contexts and its surface stays the same, the domain README is the right place to update; cross-context contracts (websocket envelopes, IPC channels, server routes, plugin manifests) belong in `agents-docs/features/`.
|
||||
|
||||
## Structure of further instructions
|
||||
|
||||
- **Agent workflow & operating rules:** `agents-docs/AGENT_WORKFLOW.md`
|
||||
- **Agent lessons (durable cross-session rules):** `agents-docs/LESSONS.md`
|
||||
- **Engineering standards:** `agents-docs/ENGINEERING.md`
|
||||
- **Feature documentation contract:** `agents-docs/AGENTS_FEATURES.md`
|
||||
- **CONTEXT documentation contract:** `agents-docs/AGENTS_CONTEXT.md`
|
||||
- **ADR contract:** `agents-docs/AGENTS_ADRS.md`
|
||||
- **Feature index:** `agents-docs/FEATURES.md`
|
||||
- **Feature docs:** `agents-docs/features/`
|
||||
- **Architecture decisions:** `agents-docs/adr/`
|
||||
- **Context map:** `agents-docs/CONTEXT-MAP.md`
|
||||
- **Obsidian bug tracker:** `agents-docs/BUG_TRACKER.md`
|
||||
- **Product-client domain:** `toju-app/CONTEXT.md`
|
||||
- **Desktop-shell domain:** `electron/CONTEXT.md`
|
||||
- **Server domain:** `server/CONTEXT.md`
|
||||
- **E2E suite domain:** `e2e/CONTEXT.md`
|
||||
- **Marketing-site domain:** `website/CONTEXT.md`
|
||||
- **App-docs domain:** `docs-site/CONTEXT.md`
|
||||
|
||||
Keep this file minimal. Do not duplicate detailed rules here.
|
||||
Internal domain changes → `toju-app/src/app/domains/<name>/README.md`.
|
||||
IPC/preload/WS contract changes → `agents-docs/features/<slug>.md` when that contract actually changed.
|
||||
|
||||
## 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 (kebab-case files; domain `*.rules.ts` / `*.model.ts` / `*.component.ts` suffixes)
|
||||
- [ ] Errors handled
|
||||
- [ ] 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 (`Fixes #<n>` / `Relates to #<n>`)
|
||||
- [ ] Gitea Workflows checks passing
|
||||
- [ ] Interview completed (or user opted out); implemented only approved choices
|
||||
- [ ] Asked behavior proven (not only unit tests green)
|
||||
- [ ] Stayed in scope (`toju-app` + targeted `electron` + CI) unless user expanded it
|
||||
- [ ] Appropriate targeted tests for logic changes
|
||||
- [ ] Lint via `npm run lint:fix` (not hand-fixed style); build only touched packages
|
||||
- [ ] Docs only if contracts changed
|
||||
- [ ] Lesson + index entry if corrected this session
|
||||
- [ ] If the thread is long and work remains: overwrite `HANDOFF.md` and ask user for a new chat
|
||||
- [ ] If work from an active handoff is finished: clear `HANDOFF.md` to `Status: none` (empty sections)
|
||||
- [ ] PR when requesting merge (`Fixes #<n>` / `Relates to #<n>`)
|
||||
|
||||
@@ -1,110 +1,83 @@
|
||||
# Agent Workflow & Operating Instructions
|
||||
|
||||
These rules apply to **all AI agents** working on this project, regardless of platform or model.
|
||||
These rules apply to **all AI agents** working on this project.
|
||||
|
||||
Read this file at the start of every session.
|
||||
**Token budget (mandatory):**
|
||||
|
||||
- Default scope: **`toju-app/` + targeted `electron/` + `.gitea/workflows/`** — see `/AGENTS.md`. No `server/`, `e2e/`, `website/`, `docs-site/` unless the user expands scope.
|
||||
- Electron: follow the renderer → preload → one handler path; never dump the whole `electron/` tree.
|
||||
- Prefer path-scoped search; one focused agent; no Bugbot / security / best-of-N unless asked.
|
||||
- **Handoff > fat chats:** agents cannot open new chats. Write `agents-docs/HANDOFF.md` and ask the user to start a new chat with that file attached.
|
||||
- **Named bugs:** `fix bug "…"` → one Obsidian note (`BUG_TRACKER.md` § Named fix), then default repo scope — not the whole vault or monorepo.
|
||||
- **Models:** keep the user’s latest problem-solving model. Cut cost with scope + handoffs, not weaker models.
|
||||
|
||||
Do **not** re-read this whole file every turn after the first skim.
|
||||
|
||||
---
|
||||
|
||||
## Workflow Orchestration
|
||||
|
||||
### 1. Plan Mode Default
|
||||
### 1. Interview before implement (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
|
||||
- For bugs/features: short interview first (understanding, gaps, choices + recommended default, scope, proof) — then wait. See `/AGENTS.md` and `.cursor/rules/interview-before-fix.mdc`.
|
||||
- Do not guess past ambiguity; the user controls the implementation choices.
|
||||
- Skip only when the user opts out (“just fix it”) or an approved handoff already decided.
|
||||
|
||||
### 2. Subagent Strategy
|
||||
### 2. Plan mode
|
||||
|
||||
- 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
|
||||
- Use plan mode when architecture is unclear or the user asks — the interview often replaces a heavy plan for normal bug fixes.
|
||||
- Skip long planning essays; prefer bullet choices.
|
||||
|
||||
### 3. Self-Improvement Loop
|
||||
### 3. Subagents sparingly
|
||||
|
||||
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.
|
||||
- Default: one agent.
|
||||
- Subagents only for true parallel search inside allowed paths.
|
||||
- Never spawn extra review agents unless the user asks.
|
||||
|
||||
**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.
|
||||
### 4. Handoff / short sessions
|
||||
|
||||
**Triggers — record a lesson when any of these happen.** Don't wait for a formal request; these are the signals:
|
||||
Triggers: user says handoff / new chat; thread is long with more major work left; switching objectives.
|
||||
|
||||
- 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
|
||||
Action: **overwrite** (never append) `agents-docs/HANDOFF.md` with `Status: active` and short sections. Then stop major work and ask the user to open a new chat.
|
||||
|
||||
If unsure whether it's worth recording: write it. Sharper is better than missing, and grooming the file is cheap.
|
||||
New chat: if handoff is active, read it first; continue Next steps; do not redo Completed work. If Next steps still need choices, re-interview — don’t invent them.
|
||||
|
||||
**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.
|
||||
**When finished:** clear `HANDOFF.md` to `Status: none` with empty sections so the file stays tiny for the next session.
|
||||
|
||||
**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.
|
||||
### 5. Self-Improvement Loop
|
||||
|
||||
### 4. CONTEXT.md upkeep
|
||||
**At session start:** `LESSONS-INDEX.md` only; open matching lesson bodies by tag.
|
||||
|
||||
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`.
|
||||
Record a lesson + index line when corrected. Prefer fewer sharp rules (~20).
|
||||
|
||||
**Triggers — capture vocabulary in the moment:**
|
||||
### 6. CONTEXT.md upkeep
|
||||
|
||||
- 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.
|
||||
Default: `toju-app/CONTEXT.md`. Read `electron/CONTEXT.md` only when touching Electron. Other packages only when in scope.
|
||||
|
||||
**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.
|
||||
### 7. ADR upkeep
|
||||
|
||||
### 5. ADR upkeep
|
||||
Only when hard-to-reverse + surprising + real trade-offs. Contract: `agents-docs/AGENTS_ADRS.md`.
|
||||
|
||||
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.
|
||||
### 8. Verification Before Done (behavior first)
|
||||
|
||||
**Triggers — write an ADR only when all three apply:**
|
||||
Done = asked functionality works **as the user confirmed in the interview**. Unit green ≠ done for product asks.
|
||||
|
||||
- **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).
|
||||
### 9. Demand Elegance (Balanced)
|
||||
|
||||
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.
|
||||
One pause for non-trivial design; skip for obvious fixes once the user has chosen a direction.
|
||||
|
||||
**Supersede, don't delete.** Overturned decisions get a new ADR; the old one stays with a `Superseded by ADR-NNNN` note.
|
||||
### 10. Bug fixing (after interview)
|
||||
|
||||
### 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
|
||||
Implement the approved plan with evidence in default scope. If root cause is clearly outside scope, say so and ask to expand — don’t silently crawl.
|
||||
|
||||
---
|
||||
|
||||
## 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
|
||||
Gitea: `git.azaaxin.com/myxelium/Toju`. Branch `<type>/<short-description>`; PR with summary + test plan; `Fixes #<n>` / `Relates to #<n>`.
|
||||
|
||||
---
|
||||
|
||||
## 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.
|
||||
- **Simplicity First** · **No Laziness** · **Minimal Impact** · **Cheap Context** · **Default Scope Fence** · **Handoff Beats Fat Context** · **Interview Before Guessing**
|
||||
|
||||
+25
-55
@@ -1,49 +1,49 @@
|
||||
# Obsidian Bug Tracker — Agent Contract
|
||||
|
||||
User-maintained bug reports live outside the repo. Read this file when asked to triage, investigate, or work from the bug backlog.
|
||||
User-maintained bug reports live outside the repo. Use this when the user names a bug or asks to triage the backlog.
|
||||
|
||||
**Overrides** `agents-docs/AGENT_WORKFLOW.md` §8 (Autonomous Bug Fixing) unless the user explicitly asks you to fix a bug in code.
|
||||
**Inbox:** `/home/ludde/Nextcloud/Obsidian Vault/Log/Bugs/`
|
||||
**Attachments:** `…/Bugs/attachments/<Bug title>/`
|
||||
**Dashboard / template:** `…/Log/Create bug.md`, `…/Log/Templates/Bug Report.md`
|
||||
|
||||
---
|
||||
|
||||
## Location
|
||||
## Named fix (default — cheap path)
|
||||
|
||||
| Item | Path |
|
||||
|------|------|
|
||||
| Bug inbox | `/home/ludde/Nextcloud/Obsidian Vault/Log/Bugs/` |
|
||||
| Attachments | `…/Bugs/attachments/<Bug title>/` |
|
||||
| Dashboard | `/home/ludde/Nextcloud/Obsidian Vault/Log/Create bug.md` |
|
||||
| Template | `/home/ludde/Nextcloud/Obsidian Vault/Log/Templates/Bug Report.md` |
|
||||
When the user says e.g. `fix bug "Images and files in chat doesn't load"`:
|
||||
|
||||
1. **Resolve one note** under `Log/Bugs/` whose title matches (usually `Bug - <title>.md`). Do not list or read the whole inbox.
|
||||
2. **Read that note** (Description, Steps, Expected/Actual, Logs). Read attachments only under that bug’s attachment folder if referenced.
|
||||
3. **Interview before implement** (see `/AGENTS.md` and `.cursor/rules/interview-before-fix.mdc`): restate the bug, list gaps, present choices with a recommended default, propose scope and proof of done — then **wait** for the user. Do not start coding until they answer (unless they said “just fix it”).
|
||||
4. Acceptance criteria = the note’s Expected Result **plus** the user’s interview answers.
|
||||
5. **Fix in default repo scope** (`toju-app/` + targeted `electron/` + CI) per `AGENTS.md`. Do not crawl `server/` / `e2e/` / other packages unless the note or user clearly requires it — then ask once.
|
||||
6. Prove the asked behavior (not only unit-green). Prefer a regression that encodes the note’s failure mode.
|
||||
7. When done: set that note’s frontmatter `status` to `Resolved` (or `Closed` if the user prefers). Do not rewrite Description / Investigation / Resolution unless asked.
|
||||
8. Long thread + more work left → write `agents-docs/HANDOFF.md` and ask for a new chat.
|
||||
|
||||
Do **not** re-read `BUG_TRACKER.md` every turn after the first use. Do **not** load the stale “open bugs” snapshot as truth — the vault files are source of truth.
|
||||
|
||||
---
|
||||
|
||||
## Allowed actions on vault files
|
||||
## Backlog triage only
|
||||
|
||||
Unless the user explicitly asks for more:
|
||||
|
||||
1. **Change `status`** in a bug note's YAML frontmatter (`Open` → `Resolved` or `Closed`).
|
||||
2. **Move files** (e.g. reorganize notes or attachments when instructed).
|
||||
|
||||
Do **not** edit other vault fields or sections (`Investigation`, `Resolution`, description, etc.) unless the user asks.
|
||||
If the user asks to list/triage open bugs (not a named fix): `ls` / glob `Log/Bugs/*.md`, filter `status: Open`, summarize titles — still don’t open every body until they pick one.
|
||||
|
||||
---
|
||||
|
||||
## Allowed reads (unrestricted)
|
||||
## Vault edit policy
|
||||
|
||||
To understand and solve bugs you may read freely:
|
||||
Unless the user asks for more:
|
||||
|
||||
- All bug notes and attachments under `Log/Bugs/`
|
||||
- The full MetoYou repo (code, tests, logs, docs)
|
||||
- Runtime output, test results, and debug artifacts
|
||||
- **Allowed write:** frontmatter `status` (`Open` → `Resolved` / `Closed`); move files if they specify a convention.
|
||||
- **Do not edit:** other frontmatter fields, Description, Steps, Investigation, Resolution, etc.
|
||||
|
||||
Investigation findings belong in chat or in repo changes — not in the vault — unless the user asks you to update the note.
|
||||
Investigation findings go in chat or the repo — not the vault — unless asked.
|
||||
|
||||
---
|
||||
|
||||
## Bug note format
|
||||
|
||||
Each note is Markdown with YAML frontmatter:
|
||||
|
||||
```yaml
|
||||
---
|
||||
title: Bug - …
|
||||
@@ -57,34 +57,4 @@ tags: [bug]
|
||||
---
|
||||
```
|
||||
|
||||
Body sections: **Description**, **Steps to Reproduce**, **Expected Result**, **Actual Result**, **Logs / Screenshots**, **Investigation**, **Resolution**.
|
||||
|
||||
The dashboard (`Create bug.md`) uses Dataview; keep `type: bug` and `status` accurate so counts stay correct.
|
||||
|
||||
---
|
||||
|
||||
## Workflow
|
||||
|
||||
1. List open bugs: `Glob` or `ls` on `…/Log/Bugs/*.md`, filter `status: Open`.
|
||||
2. Read the note and any linked attachments.
|
||||
3. Investigate in the repo (read-only toward the vault).
|
||||
4. Report findings to the user.
|
||||
5. Only when told to fix: implement in repo (TDD, lint, build per `AGENTS.md`).
|
||||
6. When a bug is done: update vault `status` to `Resolved` or `Closed` (and move files if the user specifies a convention).
|
||||
|
||||
---
|
||||
|
||||
## Open bugs (snapshot 2026-06-10)
|
||||
|
||||
| Title | Priority | Environment |
|
||||
|-------|----------|-------------|
|
||||
| Attachments gets syncronized corrupt | Critical | All major clients |
|
||||
| Chats doesn't sync for multi client users | High | All |
|
||||
| No android app icon | High | Android |
|
||||
| No login screen mobile phone on startup | High | Android, Android Browser |
|
||||
| Fresh users have the server list in dashboard completely empty until anything searched | High | — |
|
||||
| Video attachment on android gets sent in the message bubble above with no preview image | High | Android |
|
||||
| Local files should be remembered by client | High | — |
|
||||
| Emojis should be user bound not client bound | Medium | All |
|
||||
|
||||
Re-scan the folder at session start; this table is not auto-updated.
|
||||
Body: **Description**, **Steps to Reproduce**, **Expected Result**, **Actual Result**, **Logs / Screenshots**, **Investigation**, **Resolution**.
|
||||
|
||||
+15
-10
@@ -45,9 +45,14 @@ The server package does not currently have a test runner script — there is one
|
||||
|
||||
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
|
||||
### Test-backed development (balanced)
|
||||
|
||||
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).
|
||||
See `/AGENTS.md` § CRITICAL for the full policy. Summary:
|
||||
|
||||
- **Done** = the asked behavior works, proven at the right level. Green unit tests alone are not done when the ask was product behavior.
|
||||
- Prefer red-green for domain/logic and bug invariants; encode the **user-facing or cross-boundary** outcome, not only implementation details.
|
||||
- Skip full red-green for docs/copy/agent-instruction text, pure formatting, and trivial wiring already covered by a higher-level test you will run.
|
||||
- Run **targeted** specs while iterating (`cd toju-app && npx vitest run <path>`); broaden to full suite / e2e when risk is cross-cutting or before merge.
|
||||
|
||||
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.
|
||||
|
||||
@@ -191,8 +196,8 @@ 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 lint # eslint . (check only)
|
||||
npm run lint:fix # preferred: format + sort:props + eslint --fix
|
||||
npm run format # prettier on Angular HTML templates only
|
||||
npm run format:check # prettier --check on HTML templates
|
||||
|
||||
@@ -209,16 +214,16 @@ npm run migration:revert # roll back last
|
||||
|
||||
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`
|
||||
- [ ] Tests written before implementation (balanced — see `/AGENTS.md`)
|
||||
- [ ] Asked behavior proven; targeted tests pass (`npm run test:e2e` only if in scope / user-visible and needed)
|
||||
- [ ] `npm run lint:fix` passes (do not hand-fix auto-fixable lint/format)
|
||||
- [ ] Affected package builds: `npm run build` / `npm run build:electron` when those packages were touched
|
||||
- [ ] 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
|
||||
- [ ] Lesson recorded in `agents-docs/LESSONS.md` + `LESSONS-INDEX.md` if this session produced a correction
|
||||
- [ ] PR opened with summary and linked issues when requesting merge
|
||||
- [ ] Gitea Workflows checks passing
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
# Session Handoff
|
||||
|
||||
> **New chat:** attach `@agents-docs/HANDOFF.md` (and only files under Changed files). Say: continue from this handoff; do not redo completed work.
|
||||
>
|
||||
> **Agents cannot open a new chat** — overwrite this file, then ask the user to start one.
|
||||
>
|
||||
> **Keep this file tiny:** always **overwrite** the whole file (never append). When the task is finished, **clear** back to `Status: none` and empty sections (see below).
|
||||
|
||||
**Status:** none
|
||||
|
||||
## Goal
|
||||
|
||||
## Completed
|
||||
|
||||
## Changed files
|
||||
|
||||
## Decisions (this session only)
|
||||
|
||||
## Failed approaches
|
||||
|
||||
## Current issue / blockers
|
||||
|
||||
## Next steps (exact)
|
||||
|
||||
## Commands to continue
|
||||
|
||||
## Scope note
|
||||
|
||||
Default: `toju-app/` + targeted `electron/` + `.gitea/workflows/`. Out of scope unless listed here: `server/`, `e2e/`, `website/`, `docs-site/`.
|
||||
@@ -0,0 +1,60 @@
|
||||
# Agent Lessons — Index
|
||||
|
||||
**Session start:** read this file only. Match tags to the task. Open the matching lesson body in `agents-docs/LESSONS.md` — do **not** load every lesson.
|
||||
|
||||
When adding a lesson: append the full entry near the top of `LESSONS.md` (under `## Lessons`) **and** add one bullet here.
|
||||
|
||||
Tags help grepping: `rg '\\[attachments\\]' agents-docs/LESSONS-INDEX.md`
|
||||
|
||||
## Index
|
||||
|
||||
- Keep `NgOptimizedImage` off runtime blob and data URLs — `[angular] [images]`
|
||||
- Read the exact Obsidian bug note for `fix bug "…"` (one note only) — `[workflow] [bugs]`
|
||||
- Run `npm run i18n:sync` after editing any `public/i18n/catalog/*.json` file — `[i18n] [testing]`
|
||||
- Match direct-call recipients against every local identity alias, exactly like DMs already do — `[direct-call] [identity]`
|
||||
- Resolve outbound direct-call recipient ids to the peer's connected signal identity — `[direct-call] [identity] [signaling]`
|
||||
- Canonicalize direct conversation ids across cross-signal actor aliases — `[direct-message] [identity]`
|
||||
- Decide attachment receive admission once at request time; never re-gate size in the chunk handler — `[attachments]`
|
||||
- Re-queue attachment auto-downloads on every message/room binding event; never trust one transport's ordering — `[attachments] [realtime]`
|
||||
- Scope per-user UI state by user id, not by the client database — `[persistence] [multi-user] [custom-emoji]`
|
||||
- Don't strand signed-out mobile users on a logged-out dashboard — `[auth] [mobile] [routing]`
|
||||
- "Shared from your device" must gate on local bytes, not uploader user id — `[attachments] [multi-device]`
|
||||
- Generate Android brand icons from the source mark; guard against stock Capacitor placeholders — `[mobile] [android] [assets]`
|
||||
- Bind chat attachments to a pre-allocated message id, never by matching content — `[attachments] [chat] [mobile]`
|
||||
- Attachment file persistence must be platform-agnostic, not Electron-only — `[attachments] [persistence] [mobile]`
|
||||
- Never count duplicate chunks toward transfer progress, and never finalize on byte counters — `[attachments] [webrtc]`
|
||||
- Don't bump E2E timeouts for sync flakes - gate on presence and read server logs — `[testing] [realtime]`
|
||||
- When renaming an Angular route, sweep every navigate/url-match/doc reference — `[routing]`
|
||||
- Server discovery must fan out across all endpoints and self-heal on 404 — never hardcode a host capability blocklist — `[server-directory]`
|
||||
- Server registration needs `ownerPublicKey: oderId || id`, and must not be fire-and-forget — `[server-directory] [rooms]`
|
||||
- Identify must fall back to the legacy session token, not only the new credential store — `[realtime] [authentication]`
|
||||
- Keep the per-signal-URL identify credential resolvable from the store — `[realtime] [authentication]`
|
||||
- Store clientInstanceId in sessionStorage not localStorage — `[realtime] [multi-device]`
|
||||
- Revalidate IndexedDB scope without reinitializing on every read — `[persistence] [performance]`
|
||||
- Restore local user scope before protected writes — `[authentication] [persistence]`
|
||||
- Persisted local user state still requires a session token — `[authentication] [signaling]`
|
||||
- Declare MODIFY_AUDIO_SETTINGS for Android WebRTC mic capture — `[mobile] [android]`
|
||||
- Do not override Tailwind with box-sizing inherit — `[mobile] [css]`
|
||||
- Use the app-shell servers rail for mobile discovery pages — `[mobile] [layout]`
|
||||
- Defer attachment blob hydration on Electron startup — `[attachments] [electron]`
|
||||
- Lazy-load Capacitor modules on Electron/desktop — `[mobile] [electron]`
|
||||
- Use the upgrade transaction during IndexedDB schema migrations — `[persistence] [browser]`
|
||||
- Wait for authenticateUser storage prep before post-login navigation — `[authentication] [browser]`
|
||||
- Use dense arrays for chunked transfer buffers — `[custom-emoji] [webrtc]`
|
||||
- Route custom emoji right-click through the native context menu — `[custom-emoji] [ux]`
|
||||
- Separate known emoji assets from saved library — `[custom-emoji] [ux]`
|
||||
- Chunk custom emoji assets over data channels — `[custom-emoji] [webrtc]`
|
||||
- Re-clear visible notification channels after recompute — `[notifications] [startup]`
|
||||
- Disambiguate nested chat cards — `[chat] [ui]`
|
||||
- Use terminal Vitest when the test tool hangs — `[testing]`
|
||||
- Do not add fake chrome around screenshots — `[website] [design]`
|
||||
- Verify lint exits 0 before claiming done — `[verification]`
|
||||
- Prefer `npm run lint:fix` over hand-fixing lint/format — `[verification] [lint] [tokens]`
|
||||
- Use blob URLs for inline attachment previews — `[attachments] [electron]`
|
||||
- Resolve Electron drag-and-drop file paths with webUtils — `[attachments] [electron]`
|
||||
- Preserve uploader local attachment paths across sync — `[attachments] [persistence]`
|
||||
- Interview before coding; don’t guess the fix — `[workflow] [bugs] [tokens]`
|
||||
- Prove the asked behavior; unit-green is not done — `[verification] [testing] [workflow]`
|
||||
- Default to `toju-app/` + targeted `electron/` + CI; do not crawl the monorepo — `[workflow] [tokens] [scope]`
|
||||
- Write/overwrite HANDOFF.md for new chats; clear it when the task finishes — `[workflow] [tokens] [handoff]`
|
||||
|
||||
+58
-9
@@ -1,12 +1,12 @@
|
||||
# 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.
|
||||
Durable rules for AI agents working on this project.
|
||||
|
||||
## How to use this file
|
||||
|
||||
**At session start:** scan the rules below. If any match the work you're about to do, apply them.
|
||||
**At session start:** read `agents-docs/LESSONS-INDEX.md` only. Open lesson bodies here **only** for tags that match the task. Do not load this entire file into context by default.
|
||||
|
||||
**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`.
|
||||
**During the session:** if the user corrects you, reverts your edit, or re-prompts with the same instruction — record a lesson here **and** add a one-line entry to `LESSONS-INDEX.md` before closing the task. See triggers 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.
|
||||
|
||||
@@ -25,6 +25,34 @@ Durable rules for AI agents working on this project. Read this file at session s
|
||||
|
||||
## Lessons
|
||||
|
||||
### Interview before coding; don’t guess the fix [workflow] [bugs] [tokens]
|
||||
|
||||
- **Trigger:** about to edit product code for a bug/feature after reading the ask or Obsidian note, while acceptance, approach, or scope is still ambiguous or has real alternatives.
|
||||
- **Rule:** send a short interview (understanding, gaps, A/B/C + recommended default, proposed scope, proof of done), wait for the user’s choices, then implement only that — skip only if they said “just fix it” / “no interview.”
|
||||
- **Why:** unprompted guesses cause wrong fixes and expensive back-and-forth; one clarifying turn costs less than a wrong implementation thread.
|
||||
- **Example:** `fix bug "Images and files in chat doesn't load"` → read the note → ask whether the failure is channel-switch blank vs cold reload vs both before touching attachment services.
|
||||
|
||||
### Default to `toju-app/` + targeted `electron/` + CI; do not crawl the monorepo [workflow] [tokens] [scope]
|
||||
|
||||
- **Trigger:** about to browse all of `electron/`, or to `grep`/`Read` under `server/`, `e2e/`, `website/`, or `docs-site/` on a normal product bug without the user naming those packages.
|
||||
- **Rule:** stay in `toju-app/`, `.gitea/workflows/`, and **only the Electron files on the renderer→preload→handler path**; if the fix looks like `server/`/e2e, ask once instead of exploring those trees.
|
||||
- **Why:** monorepo-wide (and whole-`electron/`) exploration multiplies context on expensive problem-solving models without fixing the asked client bug.
|
||||
- **Example:** attachment disk restore → `toju-app` persistence service + `electron/preload.ts` + the one IPC/file helper involved — not every file under `electron/migrations/` or `electron/api/`.
|
||||
|
||||
### Write HANDOFF.md and ask the user for a new chat — agents cannot open chats [workflow] [tokens] [handoff]
|
||||
|
||||
- **Trigger:** the thread is long, the user says "handoff"/"new chat", or a new major objective starts while more work remains.
|
||||
- **Rule:** **overwrite** (never append) `agents-docs/HANDOFF.md` with `Status: active` and short sections, ask the user to start a new chat with that file; when the handoff task is finished, **clear** the file to `Status: none` with empty sections.
|
||||
- **Why:** fat chat history dominates token burn; an appending handoff file becomes a second fat archive that every new chat reloads.
|
||||
- **Example:** user: "handoff" → replace HANDOFF → reply: "Start a new chat and attach `@agents-docs/HANDOFF.md`." Later when done → reset HANDOFF to empty `Status: none`.
|
||||
|
||||
### Prove the asked behavior; unit-green is not done [verification] [testing] [workflow]
|
||||
|
||||
- **Trigger:** about to report a task finished because colocated Vitest specs (or a narrow mocked unit) are green, while the user’s ask was a product behavior, UI flow, or bug they can still reproduce.
|
||||
- **Rule:** treat acceptance as “the asked functionality works” — prove it with a user-visible path, focused e2e, or an explicit manual check; keep unit tests as support, never as the sole done signal.
|
||||
- **Why:** agents optimized for TDD often stop at implementation-shaped tests that pass while the real feature/bug remains broken, which wastes follow-up turns and burns tokens on false completion.
|
||||
- **Example:** for “DM reply doesn’t show for the caller,” a passing `DirectMessageService` mock test is insufficient until the cross-signal conversation identity path is exercised (e2e or a behavior-level regression that fails on the old fork-thread bug).
|
||||
|
||||
### Keep `NgOptimizedImage` off runtime blob and data URLs [angular] [images]
|
||||
|
||||
- **Trigger:** Angular template lint suggests replacing `[src]` with `ngSrc` for a user-uploaded image rendered from `blob:` or `data:`.
|
||||
@@ -34,10 +62,10 @@ Durable rules for AI agents working on this project. Read this file at session s
|
||||
|
||||
### Read the exact Obsidian bug note before diagnosing a named ticket [workflow] [bugs]
|
||||
|
||||
- **Trigger:** The user names a `Bug - …` ticket, but the worktree already contains plausible changes or a similarly named resolved ticket.
|
||||
- **Rule:** Resolve the exact note under `Log/Bugs/`, read every reported variant and reproduction step, and only then decide which code changes and status update belong to that ticket.
|
||||
- **Why:** attachment reload-host changes looked related to “Images and files in chat doesn't load” but came from a separate resolved ticket and did not cover the reported channel-switch state regression.
|
||||
- **Example:** read `/home/ludde/Nextcloud/Obsidian Vault/Log/Bugs/Bug - Images and files in chat doesn't load.md` before implementing or committing its fix.
|
||||
- **Trigger:** The user says `fix bug "…"`, names a `Bug - …` ticket, or the worktree already contains plausible changes / a similarly named resolved ticket.
|
||||
- **Rule:** Resolve and read **only** that note under `Log/Bugs/` (and its attachment folder if needed); use Expected Result as acceptance; fix in default scope; do not list the whole inbox or treat `BUG_TRACKER.md`'s snapshot table as live.
|
||||
- **Why:** attachment reload-host changes looked related to “Images and files in chat doesn't load” but came from a separate resolved ticket and did not cover the reported channel-switch state regression; inbox-wide reads also burn tokens for no gain.
|
||||
- **Example:** `fix bug "Images and files in chat doesn't load"` → read `/home/ludde/Nextcloud/Obsidian Vault/Log/Bugs/Bug - Images and files in chat doesn't load.md` only, then implement against its Steps/Expected.
|
||||
|
||||
### Run `npm run i18n:sync` after editing any `public/i18n/catalog/*.json` file [i18n] [testing]
|
||||
|
||||
@@ -53,6 +81,20 @@ Durable rules for AI agents working on this project. Read this file at session s
|
||||
- **Why:** the failure only reproduces when caller and callee have different home signal servers, which no same-server e2e covers; and when one identity-alias bug is fixed in a domain, grep for the same `=== currentUserId` pattern in sibling domains that share the transport — the direct-call domain reused `PeerDeliveryService` but kept the naive check for another month.
|
||||
- **Example:** `direct-call-participant-identity.rules.ts#directCallPayloadIncludesAnyId` / `normalizeDirectCallPayloadSelfAliases`; regression e2e `e2e/tests/voice/dm-header-call-ring.spec.ts` registers Bob on a secondary signal server, meets in a primary-signal room, and asserts the DM-header call rings Bob's incoming-call modal (fails on old code, passes after).
|
||||
|
||||
### Resolve outbound direct-call recipient ids to the peer's connected signal identity [direct-call] [identity] [signaling]
|
||||
|
||||
- **Trigger:** cross-signal direct calls still failed after the inbound alias fix — the caller joined voice and showed "In voice" while the callee never rang. `PeerDeliveryService.resolveSignalingPeerId` returned null when the stored peer id was a home id but presence/route was registered under the provisioned actor id, so `sendRawMessage` was never called; even when attempted, the server relays only when `targetUserId` exactly matches the callee's connected `oderId`.
|
||||
- **Rule:** outbound DM/call delivery must collect every recipient alias (`peer-delivery-identity.rules.ts#collectRecipientDeliveryCandidateIds`), pick the routable id with `pickRoutableRecipientId`, always attempt signaling send (broadcast fallback when no single route works), and surface `call.errors.recipientUnreachable` to the caller when delivery cannot succeed — never leave the caller in a silent "In voice" state.
|
||||
- **Why:** inbound and outbound identity bugs are independent; fixing admission on the callee does not help if the ring never leaves the caller or hits the wrong `targetUserId` on the wire.
|
||||
- **Example:** `PeerDeliveryService.sendViaSignaling` + `DirectCallService.resolveRoutableRecipientId`; e2e `e2e/tests/voice/dm-header-call-ring.spec.ts` (callee-home room, people-search call).
|
||||
|
||||
### Canonicalize direct conversation ids across cross-signal actor aliases [direct-message] [identity]
|
||||
|
||||
- **Trigger:** cross-signal DMs delivered to the callee but the caller never saw replies — User1 had two DM rows for User2, replies landed in the actor-id thread, and DM routes could throw "Cannot use direct messages without a current user" when `openConversation` ran before hydration.
|
||||
- **Rule:** incoming DM traffic must resolve to the existing home-id conversation for the same peer (`direct-message-conversation-identity.rules.ts`), merge duplicate alias threads on load/receive, queue inbound events until `currentUser` hydrates, and guard route-driven `openConversation` calls when no owner id is available yet.
|
||||
- **Why:** recipient-alias admission alone is insufficient — if `message.conversationId` still carries a foreign actor id, the client forks a second local thread and the original chat stays empty.
|
||||
- **Example:** `resolveDirectConversationId` + `mergeAliasDirectConversations` in `DirectMessageService.handleIncomingMessage`; `appendCrossSignalActorAliases` + `pickDeliveryTargetIds` when a foreign-home recipient is addressed by home id but only their shared-room actor id is routed (debug pattern: `c84813bb…` home id vs `e79a95e5…` actor on `signal.toju.app`).
|
||||
|
||||
### Decide attachment receive admission once at request time; never re-gate size in the chunk handler [attachments]
|
||||
|
||||
- **Trigger:** "Sending files between users doesn't really work" — a browser user clicked Request on a 10–50 MB generic file, the request gate (`canReceiveAttachment`) admitted it for in-memory receive, the sender streamed chunks, but `handleFileChunk` still had a leftover hard `size > MAX_AUTO_SAVE_SIZE_BYTES` rejection on the in-memory path, so every chunk was dropped, no ack was ever sent, the sender's `waitForAck` timed out, and the GUI never changed.
|
||||
@@ -291,12 +333,19 @@ Durable rules for AI agents working on this project. Read this file at session s
|
||||
- **Why:** duplicated chrome makes CTA/product previews look broken, and bottom-aligned large headings can cover accompanying text on the marketing site.
|
||||
- **Example:** `website/src/app/pages/home/home.component.html` should render the screenshot directly; `host-section` should use top-aligned heading and `.host-section-copy` columns.
|
||||
|
||||
### Prefer `npm run lint:fix` over hand-fixing lint/format [verification] [lint] [tokens]
|
||||
|
||||
- **Trigger:** about to manually re-indent, reorder imports, or tweak Prettier/ESLint-fixable style after seeing lint failures.
|
||||
- **Rule:** from repo root run `npm run lint:fix` (`format` + `sort:props` + `eslint . --fix`); only hand-edit remaining non-fixable errors.
|
||||
- **Why:** manual style fixes burn turns and tokens and often miss what the project script already auto-corrects.
|
||||
- **Example:** after code changes → `npm run lint:fix` → if exit 0, do not also rewrite imports by hand.
|
||||
|
||||
### 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.
|
||||
- **Rule:** run `npm run lint:fix` from the repo root (or `npm run lint` after fixes) 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`).
|
||||
- **Example:** `npm run lint:fix && 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`).
|
||||
|
||||
### Use blob URLs for inline attachment previews [attachments] [electron]
|
||||
|
||||
|
||||
Reference in New Issue
Block a user