From 456fdd45950dbe38223dc0052fe53d963fbf6680 Mon Sep 17 00:00:00 2001 From: Randall Stillwell Date: Wed, 6 May 2026 22:14:16 -0500 Subject: [PATCH] docs: add AGENTS.md and Cursor rules Repo-wide agent guide at the root plus path-scoped Cursor rules for the web app, database/migrations, and the plans/ markdown backlog. Co-authored-by: Cursor --- .cursor/rules/database.mdc | 40 ++++++++ .cursor/rules/markdown-backlog.mdc | 47 +++++++++ .cursor/rules/repo-overview.mdc | 35 +++++++ .cursor/rules/web-app.mdc | 43 ++++++++ AGENTS.md | 155 +++++++++++++++++++++++++++++ 5 files changed, 320 insertions(+) create mode 100644 .cursor/rules/database.mdc create mode 100644 .cursor/rules/markdown-backlog.mdc create mode 100644 .cursor/rules/repo-overview.mdc create mode 100644 .cursor/rules/web-app.mdc create mode 100644 AGENTS.md diff --git a/.cursor/rules/database.mdc b/.cursor/rules/database.mdc new file mode 100644 index 0000000..14c8b79 --- /dev/null +++ b/.cursor/rules/database.mdc @@ -0,0 +1,40 @@ +--- +description: Drizzle schema, migrations, and multitenancy rules +globs: + - packages/database/**/*.ts + - apps/**/server/**/*.ts + - apps/collab-server/src/**/*.ts + - apps/mcp-server/src/**/*.ts +alwaysApply: false +--- + +# Database — Drizzle + Postgres + +Schema source of truth: [packages/database/src/schema](mdc:packages/database/src/schema), re-exported from [packages/database/src/schema/index.ts](mdc:packages/database/src/schema/index.ts). Drizzle config: [packages/database/drizzle.config.ts](mdc:packages/database/drizzle.config.ts). + +## Multitenancy is non-negotiable + +- Every tenant-scoped table has a `workspace_id` (UUID, not null) column with an index. +- Every query against such tables **must** filter by `workspace_id`. The id comes from the authenticated session — never trust a client-provided value without checking it against the session's workspace memberships. +- New tables holding user data: include `workspace_id`, add the index, add it to relations. + +## Schema authoring + +- Keep one table per file in `src/schema/`. Re-export from `src/schema/index.ts`. +- Define relations in [packages/database/src/schema/relations.ts](mdc:packages/database/src/schema/relations.ts). +- Use `uuid().defaultRandom()` for primary keys, `timestamp({ withTimezone: true })` for time columns, and `.notNull()` aggressively. + +## Migrations + +- After any schema change, run `pnpm db:generate` from the repo root and commit the new SQL file in [packages/database/migrations](mdc:packages/database/migrations). +- **Never edit existing migrations.** Write a new one to fix or evolve. +- `pnpm db:push` is for local prototyping only. Production goes through `pnpm db:migrate`. + +## Client usage + +- Server-only. Never import the client into a Client Component, the browser bundle, or `packages/shared`. +- Import from `@tasks/database` (or `@tasks/database/schema`, `@tasks/database/client`, `@tasks/database/markdown-backlog`) — these are the published export paths. + +## Markdown backlog tables + +- `markdown_backlog_items` mirrors files under `plans/`, scoped by `workspace_id`. `cursor_sync_mappings` holds the Cursor-side ids. See [config/CursorSync.md](mdc:config/CursorSync.md) and [docs/Glossary.md](mdc:docs/Glossary.md) before changing either. diff --git a/.cursor/rules/markdown-backlog.mdc b/.cursor/rules/markdown-backlog.mdc new file mode 100644 index 0000000..727c7e8 --- /dev/null +++ b/.cursor/rules/markdown-backlog.mdc @@ -0,0 +1,47 @@ +--- +description: Authoring rules for the plans/ markdown backlog +globs: + - plans/**/*.md + - docs/templates/*.md +alwaysApply: false +--- + +# Markdown backlog (`plans/`) + +This tree is the **source of truth for product work** and is parsed into `markdown_backlog_items` by [packages/database/src/markdown-backlog](mdc:packages/database/src/markdown-backlog). The parser depends on the layout — don't improvise. + +## Layout (strict) + +``` +plans/ + Plan-/ + Plan-.md + Epic-/ + Epic-.md + Task-.md +``` + +- Slugs are lowercase-hyphenated and stable. Renaming a slug breaks Cursor sync — only do it deliberately. +- One Task per file. Tasks should be **bead-scale**: a single Cursor agent session can complete or materially advance the work. +- Use the templates in [docs/templates](mdc:docs/templates) ([plan](mdc:docs/templates/plan-template.md), [epic](mdc:docs/templates/epic-template.md), [task](mdc:docs/templates/task-template.md)). + +## Frontmatter + +Every Plan/Epic/Task file starts with YAML frontmatter. Required across all kinds: + +- `kind` — `plan` | `epic` | `task` +- `slug` — matches the filename slug +- `title` +- `status` — `draft` | `ready` | `in_progress` | `blocked` | `done` | `cancelled` +- `priority` — `P0` | `P1` | `P2` | `P3` +- `tenant_id` — UUID or placeholder; scopes the row +- `updated_at` — ISO-8601 + +Plan adds `cursor_plan_id`. Epic adds `plan_slug`, `cursor_epic_id`. Task adds `plan_slug`, `epic_slug`, `owner`, `cursor_todo_id`. + +## Conventions + +- Don't reach across tenants. `tenant_id` scopes every record and every Cursor mapping. +- Don't put secrets, IPs, or homelab credentials in plans — these files are committed and synced. +- Cross-link with relative paths so links work both in the repo and in Cursor: tasks link to their epic and plan via `./Epic-.md` and `../Plan-.md`. +- Reference: [docs/Glossary.md](mdc:docs/Glossary.md) and [config/CursorSync.md](mdc:config/CursorSync.md). diff --git a/.cursor/rules/repo-overview.mdc b/.cursor/rules/repo-overview.mdc new file mode 100644 index 0000000..c50ac98 --- /dev/null +++ b/.cursor/rules/repo-overview.mdc @@ -0,0 +1,35 @@ +--- +description: Repo-wide conventions for the Echodo monorepo +alwaysApply: true +--- + +# Echodo monorepo (always-on) + +The authoritative agent guide for this repo is [AGENTS.md](mdc:AGENTS.md). Read it before doing anything non-trivial. This rule only restates the load-bearing constraints. + +## Stack at a glance + +- pnpm 9 + Turborepo + TypeScript 5.7, Node >= 20. ESM only. +- `apps/web` — Next.js 15 App Router, React 19, tRPC, NextAuth v5, Drizzle, TipTap + Yjs + Hocuspocus, Tailwind + Radix. +- `apps/collab-server` — Hocuspocus (Yjs) over Postgres + Redis. +- `apps/mcp-server` — Model Context Protocol server. +- `packages/database` — Drizzle schema, client, migrations, markdown-backlog importer. +- `packages/shared` — Cross-app types and zod schemas. No React, no Node-only APIs, no DB. +- `packages/ai` — Vercel AI SDK wrappers and prompts. + +## Hard rules + +- Use `pnpm` (never `npm`/`yarn`) and filter by workspace: `pnpm --filter @tasks/