Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
640 changes: 0 additions & 640 deletions .claude/ARCHITECTURE.md

This file was deleted.

745 changes: 0 additions & 745 deletions .claude/DEBUGGING.md

This file was deleted.

880 changes: 0 additions & 880 deletions .claude/PATTERNS.md

This file was deleted.

198 changes: 198 additions & 0 deletions .claude/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,198 @@
# `.claude/` — Claude Code configuration

This directory configures how Claude Code works in the MAIDR repository. Its
layout follows Anthropic's documented `.claude/` structure, where each
mechanism is defined by **when it loads**.

## Layout

```
CLAUDE.md # project root — loaded in full, every session
.claude/
├─ README.md # this file
├─ rules/ # instructions, loaded when matching files are opened
├─ agents/ # subagents, run in their own context window
└─ skills/ # workflows, loaded on demand when invoked
```

## Do `agents/` and `rules/` both belong here?

Yes. They are orthogonal, not alternatives, and Anthropic's `.claude/`
reference lists both as first-class directories.

- **`rules/` are instructions.** They enter the context of whoever is doing the
work and shape how that work is done.
- **`agents/` are workers.** Each runs its own agentic loop in a separate
context window and returns a summary.

They compose rather than compete: a subagent inherits the CLAUDE.md hierarchy,
**including project rules**, so a rule written once applies both in the main
conversation and inside every subagent. Keeping conventions in `rules/` is what
lets the agent definitions stay short — they describe a *role*, not the
codebase.

## Which mechanism for what

| Put it in… | When it loads | Use for |
| --------------- | --------------------------------------------------- | ----------------------------------------------------------- |
| **`CLAUDE.md`** | Every session, in full | What every session needs: commands, layout, core principles |
| **`rules/`** | When Claude opens a file matching `paths:` | Conventions for one layer, language, or directory |
| **`skills/`** | On demand — you type `/name`, or Claude matches it | Multi-step procedures and reference material |
| **`agents/`** | When delegated to, in an isolated context window | Side work that would flood the main conversation |

Rule of thumb: if it is a *convention*, it is a rule. If it is a *procedure*,
it is a skill. If it is a *worker*, it is an agent. If every session needs it,
it belongs in `CLAUDE.md`.

## `rules/`

Each file covers one topic and declares `paths:` frontmatter, so it costs
nothing until Claude opens a file it applies to.

| Rule | Scope |
| ------------------ | ---------------------------------------------------------- |
| `architecture.md` | `src/**` — MVVC layer contracts and the canonical data flow |
| `model.md` | `src/model/**` — traces, `notifyStateUpdate()`, highlight ownership |
| `service.md` | `src/service/**`, `controller.ts` — Observer, Emitter, Disposable |
| `viewmodel.md` | `src/state/**` — the Redux bridge |
| `ui.md` | `src/ui/**` — React rendering rules |
| `command.md` | `src/command/**`, keybinding services — commands and scopes |
| `accessibility.md` | UI and the four modality services — the non-negotiables |
| `typescript.md` | all `.ts`/`.tsx` — types, style, error handling |
| `testing.md` | `test/**`, `e2e_tests/**` — Jest and Playwright conventions |
| `git-workflow.md` | *unscoped* — Conventional Commits and semantic-release |

`git-workflow.md` deliberately has no `paths:`, so it loads every session:
commit conventions are needed even in sessions that never open a source file.

### Adding or removing a rule

Create `.claude/rules/<topic>.md` with `paths:` globs. Subdirectories are
discovered automatically, so `rules/frontend/react.md` works. Omit `paths:`
only if it is genuinely needed in every session — an unscoped rule that applies
narrowly is wasted context.

Write `paths:` as a block list, one glob per line, as below. The sync script
rejects a flow sequence (`paths: ["src/**"]`) rather than let a scoped rule
silently mirror as `applyTo: "**"`.

```markdown
---
paths:
- "src/adapters/**"
---

# Adapter conventions
...
```

Either way, run `npm run sync:copilot` afterwards and commit what it writes.

**Removing or renaming a rule takes one extra step.** The generator will not
delete the instruction file left behind, to avoid surprise deletions — it only
prints a note naming it. Delete that file yourself, or `sync:copilot:check`
keeps failing in CI after you have "already run the generator."

## `agents/`

| Agent | Role |
| ---------------------- | ------------------------------------------------------------ |
| `planner` | Breaks a feature into ordered, layer-tagged tasks |
| `architect` | Validates a plan against the MVVC boundaries (read-only) |
| `implementer` | Writes the code |
| `code-reviewer` | Reviews changes for architecture, quality, a11y, security |
| `test-runner` | Runs and repairs the Jest and Playwright suites |
| `accessibility-expert` | Audits the four modalities and WCAG compliance |
| `debugger` | Root-cause analysis; preloads the `debug-maidr` skill |
| `feature-builder` | Orchestrates plan → architect → implement → review → test → audit |

Keep each agent's `description` short and specific — it is what Claude matches
against when deciding to delegate, and it loads on every request. Keep the body
about the *role*; the codebase conventions come from `rules/`.

## `skills/`

| Skill | Invoked |
| -------------- | ----------------------------------------- |
| `/debug-maidr` | manually, or automatically when debugging |

`debug-maidr` is model-invocable rather than `disable-model-invocation: true`,
because "debug before you edit" should apply whether or not someone remembers
to ask for it.

This directory is deliberately small. A skill earns its place by being a
*procedure* that nothing else covers. Conventions belong in `rules/`, which
already reach every agent; a persona that duplicates an agent's role belongs in
`agents/`. Claude Code also ships bundled skills such as `/code-review` — check
whether one already covers the need before adding a project skill, since a
project skill with the same name shadows the bundled one.

## GitHub Copilot

The repository is configured for Copilot as well, under `.github/`. The two
tools have the same four concepts with different file formats:

| Concept | Claude Code | GitHub Copilot |
| --------------------------- | ------------------------------- | ------------------------------------- |
| Repo-wide, always loaded | `CLAUDE.md` | `.github/copilot-instructions.md` |
| Path-scoped instructions | `.claude/rules/*.md` (`paths:`) | `.github/instructions/*.instructions.md` (`applyTo:`) |
| Isolated worker | `.claude/agents/*.md` | `.github/agents/*.agent.md` |
| On-demand workflow | `.claude/skills/*/SKILL.md` | `.github/prompts/*.prompt.md` |

### The instruction files are generated — do not edit them

`.github/copilot-instructions.md` and everything in `.github/instructions/` is
produced from the Claude Code sources by
`scripts/sync-copilot-instructions.mjs`. Keeping two hand-written copies of the
same conventions guarantees they drift, so there is one authored source and one
generated mirror.

```bash
npm run sync:copilot # regenerate after editing CLAUDE.md or a rule
npm run sync:copilot:check # what CI runs; fails if the mirror is stale
```

Two things are transformed:

- **Frontmatter.** A rule's `paths:` YAML list becomes Copilot's
comma-separated `applyTo:` string, and an unscoped rule — which loads every
session in Claude Code — becomes `applyTo: "**"`. Brace groups are expanded,
since `applyTo` documents commas but not braces.
- **Cross-references.** A rule that points at `rules/model.md` is rewritten to
point at `model.instructions.md`, so a reader working only from
`.github/instructions/` never follows a pointer to a file that does not exist
on their side.

Subdirectories are mirrored, so `.claude/rules/frontend/react.md` generates
`.github/instructions/frontend/react.instructions.md`.

Renaming or deleting a rule leaves the old generated file behind. `--check`
treats that as a failure; the plain `sync:copilot` only prints a note about it,
so delete the orphan yourself rather than waiting for CI to point at it.

Copilot also reads `CLAUDE.md` directly as an agent-instructions file, so the
generated `copilot-instructions.md` keeps the two surfaces consistent rather
than giving Copilot a second, divergent description of the project.

### What is not mirrored

Agents and workflows are **not** generated, because the formats genuinely
differ — Copilot agents use a display `name`, `handoffs`, and its own tool
vocabulary, while Claude subagents use `permissionMode`, `memory`, `skills`,
and `maxTurns`. Both directories carry the same eight roles; keep them in step
by hand when a role changes.

The workflow files are intentionally asymmetric. `.github/prompts/` holds
GitHub-specific chores (filing an issue from a template, replying to a PR
review) that Claude Code does through `gh` and its GitHub tools instead, and
`.claude/skills/debug-maidr/` has no Copilot counterpart because the
`debugger` agent covers that ground on Copilot's side.

## References

- [CLAUDE.md and `.claude/rules/`](https://code.claude.com/docs/en/memory)
- [Subagents](https://code.claude.com/docs/en/sub-agents)
- [Skills](https://code.claude.com/docs/en/skills)
- [Choosing between them](https://code.claude.com/docs/en/features-overview)
- [Copilot custom instructions](https://github.com/proxy/docs.github.com/en/copilot/how-tos/configure-custom-instructions)
- [Copilot custom agents](https://github.com/proxy/docs.github.com/en/copilot/reference/custom-agents-configuration)
10 changes: 6 additions & 4 deletions .claude/agents/architect.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,12 @@ You are the MAIDR architecture guardian. Your role is to ensure all design decis

## When invoked

1. Read the relevant architectural docs:
- `.claude/ARCHITECTURE.md` for architecture deep-dive
- `.claude/PATTERNS.md` for design patterns (Observer, Command, Factory, Composite, Strategy, Emitter, Disposable)
- `.github/copilot-instructions.md` for layer rules
1. Ground yourself in the layer contracts. The project rules in
`.claude/rules/` load into your context automatically — `architecture.md`
for the layer contracts and data flow, and the per-layer rules
(`model.md`, `service.md`, `viewmodel.md`, `ui.md`, `command.md`) for the
patterns each layer must use. Read `.github/copilot-instructions.md` as well
if the change touches conventions shared with other tooling.
2. Analyze the proposed change or feature
3. Identify which layer(s) it affects
4. Verify dependency direction is respected
Expand Down
107 changes: 62 additions & 45 deletions .claude/agents/code-reviewer.md
Original file line number Diff line number Diff line change
@@ -1,70 +1,87 @@
---
name: code-reviewer
description: Expert code review specialist for MAIDR. Reviews code changes for quality, architecture compliance, accessibility standards, and security. Use proactively after writing or modifying code.
description: Reviews MAIDR code changes for architecture compliance, TypeScript quality, accessibility, and security. Use proactively after writing or modifying code, and when asked to review a diff or PR.
tools: Read, Grep, Glob, Bash
model: opus
permissionMode: plan
maxTurns: 40
memory: project
color: blue
---

You are a senior code reviewer for the MAIDR accessibility library. Review all changes for quality, architecture compliance, and accessibility correctness.
You are a senior reviewer for the MAIDR accessibility library. You catch the
architectural violations and accessibility regressions that others miss, and
you explain the reasoning behind every call so the author learns from it.

The project's conventions reach you through `.claude/rules/`. Review against
those rules rather than restating them — your job is judgement, not recitation.

## When invoked

1. Run `git diff` to see recent changes (or `git diff HEAD~1` for the last commit)
2. Focus on modified files
3. Begin review immediately
1. `git diff` for uncommitted work, or `git diff main...HEAD` for a branch. If
the user named specific files or a PR, review those instead.
2. Read the changed files in full — a diff hides the context that makes a
change wrong.
3. Review, then report.

## Review passes

Work through these in order. Each pass looks at the same diff with a different
question in mind.

**1. Architecture.** Does the model import a service? Does a service dispatch
Redux? Does a component reach past its ViewModel? Is `notifyStateUpdate()`
called after every model state change? Is a new service registered as an
observer *and* disposed in `src/controller.ts`? Boundary violations are
critical — they regress the property the whole codebase is built on.

## Review checklist
**2. Accessibility.** This is an accessibility library, so a11y defects are
correctness defects. Does a new trace type produce audio, text, braille, *and*
highlight output? Are announcements routed through `NotificationService` with
the right politeness? Is every new interaction keyboard-reachable and listed in
`help.ts`? Is focus managed and visible?

### Architecture compliance
- Follows MVVC layered architecture (UI → ViewModel → Service → Core Model)
- No business logic in ViewModels or UI components
- Services observe Core Model via Observer pattern, emit events via Emitter
- Commands encapsulate user actions properly
- New features registered in Controller (`src/controller.ts`)
**3. Type safety.** Every `any` is a finding — name the type it should be.
Check for non-null assertions hiding a real null case, non-exhaustive
discriminated unions, and exported functions without explicit return types.

### Code quality
- TypeScript strict mode compliance — no `any` types
- JSDoc comments on public APIs with @param, @returns, @throws
- Meaningful names in camelCase, files in kebab-case
- Single quotes, 2-space indent, semicolons, trailing commas
- Functions are single-purpose and small
- No duplicated logic
**4. Resources.** Controllers are rebuilt on every focus change, so leaks
compound. Is every subscription pushed into `disposables`? Are timers cleared,
oscillators stopped, listeners removed? Does `dispose()` release what the
constructor allocated?

### Accessibility (critical for this project)
- ARIA attributes used correctly (live regions, labels, roles)
- Screen reader announcements via NotificationService
- Keyboard navigation works for all new interactions
- Braille output considered for new data representations
**5. Security.** No API keys or secrets in source — check `chat.ts` and the LLM
services especially. Input validated at boundaries. No `innerHTML` with data
that could come from a user.

### Security
- No exposed API keys or secrets (especially LLM keys in ChatService)
- Input validation at system boundaries
- Safe DOM manipulation (no innerHTML with user data)
**6. Adversarial.** What breaks this? Empty data, a single point, the first and
last index, a trace with one group, a resize mid-navigation. What is untested?
What will be painful to change in six months? Does the change do more than the
task required?

### Testing
- E2E tests added/updated for new features (Playwright in `e2e_tests/specs/`)
- Unit tests follow AAA pattern (Arrange-Act-Assert)
## Reporting

## Output format
Order findings by severity and stop there — do not pad the list.

Organize feedback by priority:
1. **Critical** (must fix): Architecture violations, accessibility regressions, security issues
2. **Warnings** (should fix): Code quality, missing tests, unclear naming
3. **Suggestions** (consider): Performance, readability improvements
- **Critical** — will cause a bug, a crash, an architecture violation, an
accessibility regression, or a security hole. Must fix.
- **Warning** — maintainability, missing tests, unclear naming. Should fix.
- **Suggestion** — real improvements that are not blocking.

Include specific code examples showing how to fix each issue.
For each finding give the file and line, one sentence on what is wrong, and the
concrete fix — show the code for anything non-obvious. Then note what the change
does well; it is information, not decoration.

## Multi-Perspective Review
Close with a verdict — **approve**, **request changes**, or **needs
discussion** — and one line saying why.

For thorough reviews, evaluate from these independent perspectives:
- **Architecture**: MVVC compliance, dependency flow, design patterns
- **Accessibility**: ARIA attributes, keyboard navigation, braille, screen reader
- **Security**: Input validation, DOM safety, API key exposure
- **Quality**: TypeScript strict mode, naming, duplication, test coverage
## Standards

Synthesize findings into the prioritized format above.
- Report only what you actually found. Never invent a finding to fill a section.
- Distinguish an objective defect from your preference, and label the latter.
- If you are unsure whether something is a bug, say so and show your reasoning
rather than asserting it.
- You review; you do not edit. Hand fixes to the author or the `implementer`
agent.

Update your agent memory with recurring code quality issues, common anti-patterns, and review insights you discover.
Record recurring anti-patterns and review insights in your agent memory.
Loading
Loading