Real examples

What agents actually remember

These are real memories from production projects. This is what your AI tools see at the start of every session. The context that prevents mistakes.

conventiondecisionarchitecturelessonanti patternpatternexecutionentity

Next.js SaaS App

A typical web app with authentication, API routes, and a database

anti_patternno-manual-message-objects

NEVER construct message objects manually as {id, text, type}. ALWAYS import msg/systemMsg/errorMsg from lib/messages.ts. These were extracted from 10 duplicate definitions.

lib/messages.ts
conventionapi-error-format

All API routes return { error: string, code: string, status: number } on failure. Use the shared errorResponse() helper from lib/api-utils.ts. Never throw raw errors from route handlers.

lib/api-utils.ts
decisionchose-supabase-auth

Chose Supabase Auth over NextAuth. Rationale: built-in RLS integration, no adapter boilerplate, GitHub OAuth out of the box. Trade-off: vendor lock-in on auth, but acceptable since DB is already Supabase.

lessonjsonb-not-stringify

Supabase handles JSONB serialization automatically. Passing JSON.stringify() to a JSONB column double-encodes it, causing parse failures on read. Two production outages from this.

lib/supabase.ts
executionadd-api-route

Adding an API route: 1) Create file in app/api/<path>/route.ts. 2) Export async function for HTTP method (GET, POST, etc). 3) Add Zod validation for request body. 4) Use createClient() from lib/supabase/server.ts for DB access. 5) Add rate limiting if public-facing.

app/api/lib/supabase/server.ts

Game Engine (30k LOC)

A text-based game with combat, inventory, factions, and 271 hand-crafted rooms

anti_patternsave-field-migration

NEVER add a field to _savePlayer() without a matching Supabase migration. Two production outages caused by this. ALWAYS create migration FIRST. NEVER JSON.stringify() JSONB fields.

lib/gameEngine.tssupabase/migrations/
patternroom-spawn-pattern

When adding spawnable entities to rooms (enemies, NPCs, bosses), add spawn data directly to room definitions in data/rooms/<zone>.ts. NEVER create a separate spawn system. Rooms own their spawn tables.

data/rooms/
architecturecombat-system

6 status effects: bleed, burn, stun, frighten, poison, weaken. Hemorrhagic shock = bleed+burn combo. This is the ONLY condition combo. Do not add more. Conditions tick each combat round.

lib/conditions.ts
executionadd-command-recipe

Adding a command: 1) Register verb + aliases in lib/parser.ts. 2) Add case in lib/gameEngine.ts dispatch switch. 3) Create handler in lib/actions/<domain>.ts. 4) Import handler in gameEngine.ts. All three files must be updated.

lib/parser.tslib/gameEngine.tslib/actions/
conventionrich-text-tags

ALWAYS use rt helper for terminal output: rt.item(), rt.npc(), rt.enemy(), rt.condition(), rt.keyword(). NEVER output raw text for game entities. The terminal parser colorizes tagged content.

lib/richText.tscomponents/Terminal.tsx

MCP Server (monorepo)

A TypeScript monorepo with CLI, server, shared types, and a dashboard

conventionsupabase-promiselike

Supabase returns PromiseLike not Promise. MUST wrap with Promise.resolve() for .catch(). Multiple past type errors from this.

patterncli-server-build-order

Server must be built before CLI. CLI has cross-package imports that reference server/src/ with @ts-ignore. pnpm build handles order, but pnpm --filter cli build alone will fail.

entitystorage-tiers

Hot: SQLite (better-sqlite3) for sub-10ms local queries. Warm: Supabase Postgres with pg_trgm + pgvector. Cold: Archive table for stale memories. WAL recovery on crash.

decisionno-procedural-gen

Procedural generation was built and then deleted. Replaced with hand-crafted content for better quality. Do NOT reintroduce. This was a deliberate design decision.

See it in your codebase

Two commands. Your agents start remembering.

$ npm install -g @tages/cli && tages init