Skip to content

Standards

Single source of truth for every agent, LLM, and contributor in this repo. All agents inherit these defaults. When an agent’s body contradicts this file, this file wins — open a PR to update the agent body.

⚠ Read this first: ADR-026 — LLM Agent Token Usage & Search-First Workflow. Search before you read. Find the relevant llmPrompt (ADR-021) before implementing. Use design-system metadata as the routing index.

LLM quick-read: Read §1 (Precedence) first — it resolves all conflicts. Then §3 (Tech Stack) and §4 (Skill Routing). For component work, use Storybook/MCP documentation and docs/adrs/docs-index.json for ADR routing. For ANY session, read ADR-026 first — it explains the search-first workflow and the metadata you should route through.

Principle: STANDARDS.md points. ADRs explain. Skills execute. Examples demonstrate.


1. Instruction Precedence

When instructions conflict, follow this order (highest → lowest authority):

  1. Direct user request — as long as it does not violate repo safety rules
  2. Security, privacy, and production safety rules — non-negotiable
  3. This file (STANDARDS.md)
  4. agents.md — design-system operating rules
  5. Accepted ADRs — architectural decisions
  6. Relevant skill file (.copilot/skills/<name>/SKILL.md)
  7. AI_RULES.md — project-level hard rules
  8. Local README or feature docs
  9. Existing nearby code patterns

Exception: A more specific accepted ADR may override a general rule in STANDARDS.md, but it must explicitly say so in its “Decision” section.

Always-read ADRs (read before any task work):


2. Canonical MCP Tool Set

Every agent that operates inside this repo SHOULD have access to and SHOULD prefer:

tools:
# VS Code / workspace
- vscode/extensions
- vscode/getProjectSetupInfo
- vscode/installExtension
- vscode/memory
- vscode/newWorkspace
- vscode/resolveMemoryFileUri
- vscode/runCommand
- vscode/vscodeAPI
- vscode/askQuestions
# Terminal / execution
- execute/getTerminalOutput
- execute/killTerminal
- execute/sendToTerminal
- execute/createAndRunTask
- execute/runInTerminal
- execute/runNotebookCell
- read/terminalSelection
- read/terminalLastCommand
- read/getNotebookSummary
- read/problems
- read/readFile
- read/viewImage
# Agents
- agent/runSubagent
# Browser
- browser/openBrowserPage
- browser/readPage
- browser/screenshotPage
- browser/navigatePage
- browser/clickElement
- browser/dragElement
- browser/hoverElement
- browser/typeInPage
- browser/runPlaywrightCode
- browser/handleDialog
# Editing
- edit/createDirectory
- edit/createFile
- edit/createJupyterNotebook
- edit/editFiles
- edit/editNotebook
- edit/rename
# Search
- search/changes
- search/codebase
- search/fileSearch
- search/listDirectory
- search/textSearch
- search/searchSubagent
- search/usages
# Web
- web/fetch
- web/githubRepo
# dmwd-io design system MCP (primary UI source of truth)
- dmwd/get-documentation
- dmwd/get-documentation-for-story
- dmwd/get-storybook-story-instructions
- dmwd/list-all-documentation
- dmwd/preview-stories
# Misc
- todo

Domain-specialist agents MAY append extra tools after the canonical list. They MUST NOT remove dmwd/* tools — the design system MCP is always required.


3. Default Tech Stack

First action for any choice not in this section: check DECISION_DEFAULTS.md before reasoning from scratch.

Open-source first. Default to OSS or source-available tools. Never recommend closed/SaaS-only tools without flagging the tradeoff.

Design System (Layer 0 — always start here)

  • Component library: @dmwd-io/design-system — 200+ components, Storybook MCP-accessible
  • First action for any UI task: query dmwd/* MCP tools to find existing components before writing any UI code
  • Styling: Tailwind CSS via the design system’s Tailwind preset — never add raw Tailwind classes that bypass design tokens
  • Variants: class-variance-authority (CVA) + clsx + tailwind-merge
  • Icons: Lucide React (already in the design system)
  • Component dev: Storybook (the design system IS the Storybook catalog)
  • Storybook IA: Story titles must use an existing root section from ADR-016 §0. Never create new root sections without updating ADR-016.
  • Visual regression: Lost Pixel — NOT Chromatic (closed SaaS)

Frontend Framework

  • Language: TypeScript (strict mode, exactOptionalPropertyTypes: true)
  • Framework: React 19
  • Meta-framework: Astro (when SSG/island architecture fits) — also default backend if full-stack TS
  • Routing: TanStack Router (file-based for >10 routes)
  • Server state: TanStack Query (never store server data in Zustand)
  • Tables / data grids: TanStack Table (already wrapped in DataGrid component — use that first)
  • Forms: React Hook Form + Zod resolver (or TanStack Form when paired with Router/Query/Table)
  • Validation / schemas: Zod — single source of truth shared between client and server
  • Local UI state: Zustand (slices, never one mega-store)
  • Animation: Motion (formerly Framer Motion) — sparingly, prefer design system motion tokens
  • Testing: Vitest + React Testing Library; Playwright for E2E
  • Linting / formatting: Biome (replaces ESLint + Prettier — single binary, fewer configs) — existing projects keep their current linter
  • Build: Vite (or Astro’s built-in)
  • Package manager: pnpm
  • Monorepo: Turborepo (preferred) or Nx

Backend

  • Primary (TS): Astro (server endpoints) or Hono if standalone API
  • Primary (Go): Fiber + GORM + Zap + OpenTelemetry, OpenAPI generated via oapi-codegen
  • Auth: Better-Auth (TS) / OIDC (Go)
  • Background jobs: River (Go) / BullMQ (TS)
  • Realtime: WebSockets via native server, or Centrifugo at scale

Data

  • Primary RDBMS: PostgreSQL (CloudNativePG operator in k8s)
  • Embedded / local: SQLite (libSQL / Turso self-host when distributed)
  • Migrations: Atlas (preferred — OSS, declarative) or Drizzle Kit (TS) / goose (Go)
  • Query builder / ORM (TS): Kysely (preferred — type-safe SQL, no magic), Drizzle (second choice), Prisma only when team strongly prefers ergonomics over control
  • Cache / queue / pubsub: Valkey (Redis fork — fully OSS under Linux Foundation)
  • Search: Meilisearch (small/medium) or Typesense (large/multi-tenant)
  • Object storage: S3-compatible — MinIO (single tenant) or Garage (multi-region OSS)
  • Vector / AI: pgvector (in Postgres) — avoids a separate vector database

Infrastructure & Delivery

  • Containers / Orchestration: Docker, Kubernetes
  • CI/CD: GitHub Actions
  • GitOps: ArgoCD + Helm
  • Secrets: 1Password Connect
  • Local dev: Skaffold + Task

Observability (all OSS, all self-hostable)

  • Logs: Zap (Go), pino (TS) → Loki
  • Metrics: Prometheus + Grafana
  • Traces: OpenTelemetry SDK → Tempo
  • Errors: GlitchTip (Sentry-protocol-compatible, fully OSS) — drop-in for Sentry SDKs
  • Uptime: Uptime Kuma
  • SLO framework: Sloth (generates Prometheus recording + alerting rules from SLO YAML)
  • Profiling: Pyroscope (continuous profiling)

Standard Additions at Scale (all OSS unless flagged)

CategoryDefault ChoiceNotes
Feature flagsOpenFeature SDK + GrowthBook (self-host)Vendor-neutral interface
Product analyticsPostHog (self-host)Events, funnels, session replay, surveys
Transactional emailPostal (self-hosted SMTP) + React EmailListmonk for newsletters. Avoid Resend (closed SaaS) unless explicitly chosen
Payments / billingLago (OSS metering) + Killbill (subscriptions)Payment gateway (card processing) is the one unavoidable closed dependency — flag it, default to Stripe only if user accepts
i18nLingui (TS) or go-i18n (Go)-
Docs siteAstro Starlight (preferred) or Docusaurus-
API contractstRPC inside monorepo, OpenAPI at the edgehono-openapi or zod-to-openapi for TS; oapi-codegen for Go
API mockPrism (OpenAPI mock server)Parallel FE/BE work
WorkflowsTemporal (self-host) for durable workflows, XState for in-process-
Job schedulingRiver (Go), BullMQ (TS)Both Postgres/Redis-backed OSS
Container registryHarbor (self-host) or GHCR-
Image buildingko (Go, zero-Dockerfile) or multistage Dockerfile + buildx-
k8s policyKyverno (preferred — pure YAML) or OPA Gatekeeper-
Service mesh (only when actually needed)Linkerd (lightweight, Apache 2)-
BackupsVelero for cluster, pgBackRest for Postgres-
Internal tools / admin UIRefine (OSS, React + design system)-
CMS (when needed)Payload (Node, OSS) or Directus-
Auth (self-host SSO)Authelia or Authentik for OIDC; Better-Auth stays default for app-level auth-
Status pageCachet or Statping-

4. Skill Routing

Agents SHOULD invoke skills rather than reinventing them. Map user intent → skill:

Intent / Trigger PhraseSkill
”design tokens”, “color palette”, “typography scale”, “developer handoff”ui-design-system
”build component”, “make it look better”, “production-grade UI”, “avoid AI slop”frontend-design
”favicon”, “PWA icons”, “open graph image”web-asset-generator
”logo from clearbit/logo.dev”logo-dev-automation
”design schema”, “ERD”, “normalize”, “migration plan”, “index review”database-designer
”SLI/SLO”, “alerting strategy”, “dashboard generator”observability-designer
”threat model”, “STRIDE”, “OWASP review”, “secrets handling”senior-security
”CI pipeline”, “deploy”, “infra as code”, “containerize”senior-devops
”system design”, “ADR”, “microservices vs monolith”, “scale plan”senior-architect
”test strategy”, “Playwright setup”, “coverage analysis”senior-qa
”scaffold fullstack”, “Next/FastAPI/Django stack”senior-fullstack
”React component”, “hooks”, “TanStack Query/Table”senior-frontend
”tech debt”, “remediation”, “complexity report”tech-debt-tracker
”compare frameworks”, “TCO analysis”, “stack evaluation”tech-stack-evaluator
”PRD”, “product spec”, “requirements doc”prd-generator
”user story”, “acceptance criteria”, “sprint plan”agile-product-owner
”RICE”, “interview synthesis”, “discovery framework”product-manager-toolkit
”OKRs”, “vision”, “competitive analysis”product-strategist
”churn risk”, “expansion”, “customer health”customer-success-manager
”board deck”, “investor update”, “exec strategy”ceo-advisor
”tech strategy”, “team scaling”, “DORA metrics”cto-advisor
”create new skill”, “improve a skill”skill-creator
”organize files”, “find duplicates”file-organizer
”user research synthesis”, “usability test plan”ux-researcher-designer
”design API”, “OpenAPI spec”, “tRPC router”, “REST endpoints”, “API versioning”api-designer
”build operator”, “CRD”, “controller-runtime”, “kubebuilder”kubernetes-operator
”app is slow”, “lighthouse”, “LCP”, “INP”, “bundle size”, “react slow”react-perf-auditor
”astro app”, “client:load”, “islands”, “content collections”astro-architect
”zod schema”, “shared types”, “z.infer”, “contracts package”, “discriminated union”zod-schema-architect
”tanstack router”, “file-based routes”, “search params”, “type-safe routing”tanstack-router-architect
”new go service”, “fiber api”, “go template”, “scaffold go”golang-fiber-bootstrapper
”slow query”, “explain analyze”, “index strategy”, “pg_stat_statements”postgres-performance
”github actions”, “reusable workflow”, “OIDC”, “matrix build”, “branch protection”github-actions-architect
”open a PR”, “PR description”, “self-review”, “code review”pr-review-checklist
”monorepo”, “turborepo”, “nx”, “pnpm workspace”, “shared package”monorepo-architect
”incident”, “outage”, “SEV1”, “postmortem”, “on-call”, “rollback now”incident-commander
”design system component”, “build a component”, “Storybook story”, “component variant”dmwd-component-author
”CRUD page”, “list + detail + form”, “resource feature”crud-recipe
”dashboard”, “analytics overview”, “KPI grid”dashboard-recipe
”add logging”, “request context”, “pino setup”, “zerolog”, “wide events”logging-setup
”draft a demand letter”, “cease and desist”, “motion”, “contract”, “NDA”legal-document-drafter
”legal template”, “court PDF”, “certificate of service”, “pleading layout”legal-pdf-layouts

How to invoke

Detect a trigger phrase → load the matching skill from .copilot/skills/<name>/SKILL.md → follow its workflow exactly. Don’t paraphrase; execute it.

For the full skill index (status, related ADRs, when NOT to use each skill), see .copilot/skills/README.md.


5. Agent Authoring Rules

Every agent in this repo MUST follow these rules. Full contract in .copilot/skills/README.md.

  1. One job, done well. No agent should mention more than 2 sibling agents by name.
  2. Required frontmatter: name, description, tools (from §2 canonical list)
  3. Required sections (in order): Identity, When to use me, When NOT to use me, Default tech stack, Skills I invoke, Workflow, Output contract
  4. No prose duplication. If it’s in STANDARDS.md or agents.md, link to it.
  5. Be terse. No agent body exceeds ~400 lines.
  6. No function Demo() inside render callbacks — see ADR-017.

Skill descriptions, when-to-use details, and ADR links live in .copilot/skills/README.md and individual SKILL.md files — not here.


6. Engineering Standards

Full standard: docs/adr-024-engineering-standards.mdx

Floors for all new code:

RuleLimit
File size≤150 lines
Function size≤70 lines
DependenciesAlways injected
ConfigEnv vars or config file (Zod at startup in TS; Viper in Go)
Type safetyMandatory — no any, no untyped interface{}
NamingVerbose: generateAcmeInvoicePDF() not fn()
  • TDD: RED → GREEN → REFACTOR; 50% coverage minimum; tests offline only
  • Task runner: Taskfile (not Make). Standard targets: dev lint test test-cover build migrate seed
  • Commits: conventional format, body required, ≤72 char title, imperative mood, refs attached
  • Migration: apply incrementally when touching files — no big-bang rewrites

6a. Go Standards (addendum to §6)

These apply to all Go services, CLIs, and tools. They supplement the language-agnostic rules above.

Project layout — always cmd/ internal/ pkg/:

myservice/
cmd/server/main.go # entry point only — parses config, wires DI, calls Run()
internal/handler/ # HTTP handlers (Fiber) — never import from outside
internal/service/ # business logic — interfaces first
internal/repository/ # database access — interface + GORM implementation
internal/provider/ # vendor SDK wrappers (auth, email, storage, AI)
pkg/ # packages safe to import by other modules
Taskfile.yml
.golangci.yml

Error handling:

  • Wrap errors with context: fmt.Errorf("user.Create: %w", err) — never panic in library code
  • Return (T, error) — never swallow errors
  • Map domain errors to HTTP error codes in the handler layer only
  • Use the standard error envelope: { "error": { "code", "message", "request_id" } }

Config and secrets (Viper):

internal/config/config.go
type Config struct {
Port int `mapstructure:"PORT"`
DBUrl string `mapstructure:"DATABASE_URL"`
APIKey string `mapstructure:"API_KEY"` // read once; never logged
}
func Load() (Config, error) {
viper.AutomaticEnv()
viper.SetConfigFile(".env")
_ = viper.ReadInConfig() // env vars always win
var c Config
return c, viper.Unmarshal(&c)
}

Interface-first DI:

// Define interface in the consumer package
type UserRepository interface {
Create(ctx context.Context, u User) (User, error)
GetByID(ctx context.Context, id string) (User, error)
}
// Wire in main.go / cmd package — not inline in handlers
repo := repository.NewGORMUserRepository(db)
svc := service.NewUserService(repo, logger)
h := handler.NewUserHandler(svc)

Logging (zerolog):

log.Info().
Str("event", "http.request_completed").
Str("request_id", requestID).
Int("status_code", c.Response().StatusCode()).
Int64("duration_ms", time.Since(start).Milliseconds()).
Msg("request completed")

Linting: golangci-lint run with .golangci.yml (shadow, errcheck, exhaustive, govet at minimum).

Taskfile standard targets:

tasks:
dev: { cmds: [go run ./cmd/server] }
lint: { cmds: [golangci-lint run ./...] }
test: { cmds: [go test -race ./...] }
test-cover: { cmds: [go test -race -coverprofile=coverage.out ./...] }
build: { cmds: [go build -o dist/server ./cmd/server] }

6b. Doc-Comment Standard (all languages)

This rule is non-negotiable. Applies to every exported function, class, type/interface, hook, and component across TypeScript, JavaScript, Go, and Python.

Every exported symbol MUST carry a doc comment that conveys its contract without requiring the reader to read the body. State:

  1. One-line purpose — what it does, not how
  2. Each parameter — type, shape, meaning, and constraints
  3. Return value — what it is and when it is null/undefined/zero
  4. Notable side effects / thrown errors — network calls, mutations, exceptions that can escape
  5. When to use and when NOT to use — required for components and public APIs
  6. Governing ADR(s) — link the ADR that constrains this symbol’s design

Describe intent and contract, not a line-by-line restatement of the body. Comments go on declarations. Do not litter function bodies with noise.

Language conventions:

  • TypeScript / JavaScript: TSDoc/JSDoc (/** ... */)
  • Go: idiomatic Go doc comments (// FuncName ...) on all exported identifiers
  • Python: PEP 257 docstrings ("""...""")

Canonical TSDoc pattern to copy:

/**
* Paginated data table with sort, filter, row-selection, and mobile card fallback.
*
* Use for collections that need server-driven sort/filter/pagination. For a simple
* read-only list, prefer StackedList. For compact inline summaries, prefer MiniDataTable.
*
* @typeParam T - Row shape; must include a stable `id`.
* @param columns - Column defs; `accessor` keys must exist on T.
* @param data - Current page of rows. Component does not fetch — pass server data in.
* @param pagination - Page state + onChange; omit to render unpaginated.
* @param onSelectionChange - Fired with selected row ids; omit to disable selection.
* @returns Accessible table element (role="grid"); collapses to cards below `md`.
* @throws Never throws; invalid columns render an EmptyState, not an error.
*
* @remarks Governed by ADR-040 (CRUD), ADR-049 (Tables), ADR-006 (semantic colors).
* @example
* <DataGrid
* columns={userColumns}
* data={users}
* pagination={{ page, pageSize, total, onChange: setPage }}
* />
*/
export function DataGrid<T extends { id: string }>(props: DataGridProps<T>) { ... }

Enforcement: TSDoc violations are flagged in PR review. Components shipped without doc comments on their props interface and function declaration will be bounced.


Full standard: docs/adr-023-observability-and-wide-events-logging.mdx (ADR-023)

One log entry = one meaningful operation. All context attached. All fields queryable.

Canonical HTTP request completion event:

{
"timestamp": "2026-05-22T14:24:03.182Z",
"level": "info",
"msg": "request completed",
"event": "http.request_completed",
"service": "billing-api",
"version": "1.4.2",
"env": "production",
"request_id": "req_123",
"trace_id": "trace_abc",
"span_id": "span_def",
"user_id": "user_456",
"tenant_id": "tenant_789",
"method": "POST",
"route": "/api/invoices",
"status_code": 201,
"duration_ms": 143,
"data": { "invoice_id": "inv_123" }
}

Required fields (always present): timestamp level msg event service version env
Request context (when request exists): request_id trace_id span_id method route status_code
User context (when resolved — opaque IDs only, never PII): user_id tenant_id
Operational (when relevant): duration_ms error data

msg is static and grep-stable. Dynamic values go in fields, not in msg.
event is dot-namespaced and machine-readable: "billing.subscription_created".
Libraries: pino (TS), zerolog (Go), structlog (Python). See ADR-023 for idiomatic setup.

Never log: PII, secrets, payloads >2KB, stack traces at top level, interpolated msg strings.


8. Observability Concepts — What Goes Where

Do not conflate these. They have different retention, audiences, and tools.

ConceptPurposeDefault tool
Wide events / logsDebugging and operationsLoki (pino/zerolog/structlog)
Analytics eventsProduct behavior and funnelsPostHog (self-host)
Audit eventsCompliance and security historyImmutable separate store
Distributed tracesCross-service request flowTempo (OpenTelemetry)
Error reportingExceptions and crash contextGlitchTip

Rules:

  • Do not use analytics events as audit logs.
  • Do not use audit logs as debug logs.
  • Do not log PII in any of them.
  • Do not rely on console strings for production observability.

9. Enforcement Gates

Rules that are not checked will drift. These gates are required in CI or as PR checklist items.

GateCheckBlocking?
STANDARDS.md linked from agents.mdgrep -l "STANDARDS.md" agents.md✅ Blocking
AI_RULES.md references STANDARDS.md instead of duplicating stackmanual review✅ Blocking
ADR overview is up to datepnpm run adrs && git diff --exit-code docs/adr-overview.mdx✅ Blocking
Public components have maturity recordspnpm run readiness:check✅ Blocking
No raw HTML form controls (<input>, <select>, <textarea>) in component codeESLint or grep -r '<input|<select|<textarea' src/components/✅ Blocking
No raw fetch() inside component filesESLint or grep check✅ Blocking
No direct vendor SDK imports outside provider wrappersdependency boundary lint✅ Blocking
No hardcoded color values (hex/rgb) in component filesgrep / lint rule⚠️ Advisory
No stale function Demo() in story renderpnpm run dx:audit✅ Blocking
New feature folders include testsCI check or PR checklist⚠️ Advisory
Lint, typecheck, tests, and build passpnpm lint && pnpm typecheck && pnpm test && pnpm build✅ Blocking

10. Migration Policy

Do not rewrite existing code just to match new standards.

When touching an existing file:

  1. Keep the requested change small
  2. Improve only the area you are touching
  3. Do not perform repo-wide migrations unless explicitly requested
  4. If a violation is nearby but out of scope, mention it in the PR summary
  5. Prefer incremental compliance over big-bang rewrites

11. Design System Pre-Commit Gates

Before claiming any task complete, every agent MUST run (in this order):

Terminal window
pnpm lint # ESLint
pnpm typecheck # tsc --noEmit
pnpm test # Vitest (watch for unhandled errors — they fail CI too)
pnpm run readiness:check # component maturity gate
pnpm build # library build + bundle:check

Optional but required when stories or visuals change:

Terminal window
pnpm build-storybook # confirms Storybook composes cleanly
pnpm test:visual # Playwright visual regression

Do not claim “lint passes” or “tests pass” without actually running the script in the current session. If a check is skipped, say so explicitly.


FilePurpose
AI_RULES.mdQuick-reference hard rules for AI agents — read this first
DECISION_DEFAULTS.mdQuick lookup table for every default stack/pattern choice — check before inventing
CONTRIBUTING.mdContributor guide — conventions, pre-commit checklist, ADR rules
.copilot/skills/README.mdSkills index — when to use, when not to, related ADRs, build priority
Storybook MCPFull Storybook-first design-system agent and component guidance
Storybook Docs/ADRs/OverviewADR overview with one-line summaries
docs/adrs/docs-index.jsonMachine-readable index for LLM wayfinding (regenerate with pnpm run docs:index)
docs/adr-023-observability-and-wide-events-logging.mdxFull wide events logging standard (ADR-023)
docs/adr-024-engineering-standards.mdxFull engineering code standards (ADR-024)
don't-reinvent-wheel.mdLibrary shortlist for behavior-heavy components
docs/components/full-components.mdxInteraction families and variant catalog
docs/reports/prepare-for-usage-based.mdFull project accelerator kit plan with Quick Wins Index
src/lib/component-maturity.tsComponent maturity registry — every public component must have an entry
src/test/helpers.tsxShared test utilities: renderWithProviders, mockCurrentUser, mockPaginatedResponse, etc.
src/components/patterns/myfreelawyer/components/virginia-citations.tsCitation registry for legal documents