skills/convex-ddd-architecture/SKILL.md
Use when structuring or refactoring Convex codebases with Domain-Driven Design boundaries, repository abstractions, adapters for external APIs, and transaction-safe workflows. Also use for naming—ubiquitous language, bounded context, short locals inside clear parent scope (avoid verbose identifiers).
npx skillsauth add sebas5384/agentic-stuff convex-ddd-architectureInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Reference skill for organizing Convex projects with DDD and Hexagonal architecture. It keeps domain logic isolated from database and external API concerns so changes remain local and safer to evolve.
Use this skill when work includes one or more of these signals:
schema, queries, mutations, domain, adapters)ctx.db access spreading outside repositoriesDo not use this as a strict template for tiny prototypes where speed matters more than architectural boundaries.
./convex/
_generated/ # Auto-generated by Convex (do not edit)
_shared/ # Cross-domain utilities
_libs/
aggregate.ts # Base aggregate interface
repository.ts # Base repository interface
_triggers.ts # Central trigger registry
customFunctions.ts # Wrapped mutation/query exports
schema.ts # Composed schema from all sub-domains
[subDomainName]/ # Each sub-domain folder (camelCase)
_libs/
stripeClient.ts # Libs or helpers
_tables.ts # Database schema tables
_triggers.ts # Sub-domain trigger handlers
_seeds.ts # Seeds for models
_workflows.ts # Convex workflows
queries/
[queryName].ts # One query per file, export default
mutations/
[mutationName].ts # One mutation per file, export default
domain/
[modelName].model.ts # Model schema, types, Aggregate
[modelName].repository.ts # Repository interface
adapters/
[actionName].action.ts # External API actions
[modelName].repository.ts # Repository implementation
contactRepository.ts, sendInvoice.action.ts)_tables.ts, _triggers.ts)_workflows.ts), split into a directory after growth| Concern | Rule |
|---|---|
| Convex imports | Import mutation, query, internalMutation from customFunctions.ts |
| Function exports | One function per file with export default |
| Domain model shape | Include _id, _creationTime, plus New<Model> without system fields via withoutSystemFields |
| Persistence boundary | Access DB through repositories in adapters/ |
| External integrations | Keep translation in actions; business decisions stay in mutations/aggregates |
| _tables.ts | Only defineTable(NewXModel.fields) + indexes — field definitions live in domain model files, never inline |
| Schema | Compose root schema from each sub-domain _tables export |
Always import mutation, query, internalMutation from customFunctions.ts, not from _generated/server. See custom-functions.md.
// ✅ Correct
import { mutation } from "../../customFunctions";
// ❌ Wrong - bypasses trigger integration
import { mutation } from "../../_generated/server";
One function per file with named definition and default export:
// convex/combat/mutations/createBattle.ts
import { mutation } from "../../customFunctions";
import { v } from "convex/values";
const createBattle = mutation({
args: { heroId: v.id("heroProfiles") },
handler: async (ctx, args) => {
// ...
},
});
export default createBattle;
Frontend usage with .default suffix:
import { api } from "@/convex/_generated/api";
useMutation(api.combat.mutations.createBattle.default);
useQuery(api.economy.queries.getHeroProfile.default);
Avoid named exports like export const createBattle - this creates redundant paths like api.combat.mutations.createBattle.createBattle.
Compose schema from sub-domain tables:
// convex/schema.ts
import { defineSchema } from "convex/server";
import { combatTables } from "./combat/_tables";
import { economyTables } from "./economy/_tables";
export default defineSchema({
...combatTables,
...economyTables,
});
_generated/server and bypassing shared wrappers_tables.ts instead of defineTable(NewXModel.fields) — this duplicates the schema and breaks the model-as-source-of-truth invariantexamples.md, not from adjacent code that may predate these guidelinesSupporting documents live in the references/ directory.
Read before writing any new subdomain code:
_tables.ts → repository interface → adapter → mutation. Start here._tables.ts pitfalls, DTO placement, and incremental refactor strategy.Read when the task touches that specific concern:
*Model validator shape, withoutSystemFields, Aggregate class structure and state transitionscreateRepository factory, interface conventions, method naming (by, list, with)_id, static catalogs)development
Maintainer-only workflow for handling GitHub Secret Scanning alerts on OpenClaw. Use when Codex needs to triage, redact, clean up, and resolve secret leakage found in issue comments, issue bodies, PR comments, or other GitHub content.
development
Maintainer workflow for OpenClaw releases, prereleases, changelog release notes, and publish validation. Use when Codex needs to prepare or verify stable or beta release steps, align version naming, assemble release notes, check release auth requirements, or validate publish-time commands and artifacts.
development
Run, watch, debug, and extend OpenClaw QA testing with qa-lab and qa-channel. Use when Codex needs to execute the repo-backed QA suite, inspect live QA artifacts, debug failing scenarios, add new QA scenarios, or explain the OpenClaw QA workflow. Prefer the live OpenAI lane with regular openai/gpt-5.4 in fast mode; do not use gpt-5.4-pro or gpt-5.4-mini unless the user explicitly overrides that policy.
development
End-to-end Parallels smoke, upgrade, and rerun workflow for OpenClaw across macOS, Windows, and Linux guests. Use when Codex needs to run, rerun, debug, or interpret VM-based install, onboarding, gateway smoke tests, latest-release-to-main upgrade checks, fresh snapshot retests, or optional Discord roundtrip verification under Parallels.