Skip to content

sglyon/ddd-skills

v0.1.0MIT

Domain-Driven Design skills grounded in Evans and Vernon: implement, verify, select, and co-design DDD patterns.

Domain-Driven Design Agent Skills

A library of Agent Skills teaching Eric Evans' and Vaughn Vernon's Domain-Driven Design, with a maintained Inspect AI eval suite to check whether a skill actually changes model behavior. The library is discovery-first: one root skill routes into pattern skills and two decision hubs.

Layout

skills/
  domain-driven-design/SKILL.md           # root: index of every pattern, how to route
  domain-driven-design/patterns/<name>/   # 62 pattern skills (one DDD concept each)
    SKILL.md
    references/implementation.md          # worked example + runnable pytest blocks
    references/review-checklist.md        # C1..Cn checks + verdict format
    references/design-facilitation.md     # optional, only if facilitation content is long
  ddd-selecting-patterns/                 # hub: pick a pattern for a codebase + scenario
  ddd-collaborative-design/               # hub: facilitate DDD design with a human
docs/
  catalog.md                 # authoritative skill name list, groups, source chapters
  authoring-contract.md      # binding shape/content rules for every skill
  skill-best-practices.md    # sourced rationale for the contract
tools/
  check_skills.py            # static contract checker (frontmatter, headings, code, links)
evals/
  schema.py                  # pydantic schema for eval cases (Case, KeyItem, SkillCases)
  cases/<skill>.yaml         # 5 cases per skill: S1-S3 visible, H1-H2 holdout
  ddd_skills.py               # Inspect AI tasks (behavior eval + routing eval)
  routing/                    # routing-eval queries and distractor skills
tests/
  test_static.py              # runs tools/check_skills.py over every skill
  test_cases.py                # schema/coverage invariants over evals/cases/
hooks/                        # SessionStart pointer: bootstrap.md text, Claude Code hook script
.pi/extensions/              # omp/pi SessionStart equivalent (reads hooks/bootstrap.md)
plugin.json                   # Agent Plugins 1.0.0 manifest
.claude-plugin/              # Claude Code manifest + local dev marketplace
package.json                  # omp/pi package manifest (skills + extension)

skills/ and docs/ are the shipped product. evals/ and tools/ are the maintenance harness. .work/ is gitignored scratch (source book text, run logs, grading intermediates) — book text is never in the repo; it only ever lives locally under .work/books/.

Source material

The skills and eval cases teach patterns from Eric Evans, Domain-Driven Design (2003), and Vaughn Vernon, Implementing Domain-Driven Design (2013). They are written in our own words and cite chapter and section; pattern and section titles are used by name. Neither book is included, and buying them is the best way to learn this material in depth.

Guardrail for contributors with a local copy of the book text in .work/books/: uv run python tools/check_book_overlap.py (also run by tests/test_book_overlap.py) fails on any run of 10+ consecutive words shared with either book, other than section titles.

Installing

The repo is an Agent Plugins package that also carries Claude Code and omp manifests. All three discover exactly three skills (domain-driven-design, ddd-selecting-patterns, ddd-collaborative-design); the 62 patterns are nested under the root and reached through its index. A SessionStart hook adds the short pointer in hooks/bootstrap.md (about 480 characters) to each session.

# Claude Code
claude plugin marketplace add sglyon/ddd-agents    # or a local checkout path
claude plugin install ddd-skills@ddd-skills-dev
claude --plugin-dir /path/to/ddd-agents           # one session, no install

# omp (oh-my-pi)
omp plugin marketplace add sglyon/ddd-agents
omp plugin install ddd-skills@ddd-skills-dev
omp plugin link /path/to/ddd-agents               # local dev; `omp plugin uninstall ddd-skills`

# any agentskills.io harness without plugin support
cp -r skills/* ~/.agents/skills/

Validate packaging with claude plugin validate . --strict and uv run pytest tests/test_plugin.py (manifest names, versions, and descriptions must agree; bump all of them together).

How agents drive it

An agent never loads all 62 pattern skills — it loads the root skill (skills/domain-driven-design/SKILL.md), which indexes every pattern and routes by task:

  • Implementing, verifying, or picking a single named pattern → load that pattern's SKILL.md directly (root index links patterns/<name>/SKILL.md).
  • Choosing among several candidate patterns for a scenario → load ddd-selecting-patterns.
  • Facilitating a live design conversation with a human from scratch → load ddd-collaborative-design.

Each pattern skill then conditionally loads its own references/*.md (implementation detail, review checklist, design facilitation) only when that mode is needed — see the "How to use this skill" table in every SKILL.md.

Maintaining

Adding or editing a skill

  1. Read docs/authoring-contract.md in full — it is binding: exact frontmatter shape, section order and headings, line/word budgets, P-rule/C-check numbering, the verdict block format, and content rules (source fidelity, paraphrase-only, no URLs, no .work/ references).
  2. Read the catalog row in docs/catalog.md for the skill's name, folded sub-concepts, and source chapters, and docs/skill-best-practices.md for the sourced rationale behind the contract.
  3. Write/edit the skill under skills/domain-driven-design/patterns/<name>/ (or the hub directory for the two hubs).
  4. Run the static checker:
    DDD_SKIP_SKILLS_REF=1 uv run python tools/check_skills.py <name>
    
    Drop DDD_SKIP_SKILLS_REF=1 to also run the external skills-ref validate tool (needs network/uv tool run access). It writes a JSON report to .work/reports/check/<name>.json.
  5. If the skill's name or index entry changed, also update docs/catalog.md and the root SKILL.md index.

Adding or editing eval cases

Each skill has evals/cases/<skill>.yaml, validated by evals/schema.py (SkillCases → Case → KeyItem). Every skill has exactly 5 cases:

idmodesplit
S1implementvisible
S2verifyvisible
S3selectvisible
H1verifyholdout
H2designholdout

A Case has a prompt, a list of items (KeyItems: id, text, weight, required, decoy), optional disqualifiers, and sources. Case.max_score is the sum of weights of required items — never derived from grader output. decoy: true items are distractors a good answer should correctly avoid flagging.

Holdout rule: authors and fixers of a skill must never read that skill's H1/H2 cases (see docs/authoring-contract.md §8, Writer process). Holdout cases exist to catch skills that were tuned to pass their own visible eval prompts rather than teaching the pattern in general.

Running static checks

DDD_SKIP_SKILLS_REF=1 uv run pytest -q

Runs tests/test_static.py (contract conformance via tools/check_skills.py, parametrized over every catalog skill) and tests/test_cases.py (eval-case schema and coverage invariants).

uv run ruff check tools tests

Running evals

Behavior eval — does the skill change what the model does, for a given skill/case:

# baseline: no skills loaded
uv run inspect eval evals/ddd_skills.py@behavior -T skills=false -T split=visible

# with skills
uv run inspect eval evals/ddd_skills.py@behavior -T skills=true -T split=visible \
  --model-role grader=<grader-model> --epochs 3

Swap -T split=visible for -T split=holdout to score against the cases authors never saw.

Routing eval — does the agent pick the right skill from the catalog without reading everything:

uv run inspect eval evals/ddd_skills.py@routing -T view=rooted   # via the root skill's index
uv run inspect eval evals/ddd_skills.py@routing -T view=flat     # all skills exposed flat

Inspect the transcripts/scores:

uv run inspect view

Two credential paths

PathHarness valuesAuthIsolationUse for
API (default)claude_code, codex_cliprovider API keysDocker sandbox via inspect_swefull benchmark runs on new models
Subscriptionclaude_local, codex_local, omp_localCLI logins in an isolated eval HOMEhost process, read-only tools, throwaway workdirper-skill iteration

One-time setup for the subscription path: tools/eval_home.sh creates ~/.local/share/ddd-agents/eval-home (override with DDD_EVAL_HOME), logs each installed CLI in under it, and links the plugin for omp. Nothing from your own HOME (skills, plugins, CLAUDE.md) is visible to these runs. The judge can use a subscription too through the cli model provider:

uv run inspect eval evals/ddd_skills.py@behavior -T harness=claude_local -T skill=ddd-aggregate \
  --model-role grader=cli/codex --epochs 3          # agent on Claude, judge on Codex
uv run inspect eval evals/ddd_skills.py@behavior -T harness=claude_local -T skills=false ...

Local agents ignore --model; pick the CLI's model with -T agent_model=<name>. Subscription runs consume plan usage limits; full runs (~4k agent runs + ~2k judgings) belong on the API path.

New-model / new-harness release procedure

When a new model or harness ships:

  1. Run the baseline (-T skills=false) and the with-skills (-T skills=true) behavior evals, both -T split=visible and -T split=holdout, --epochs 3, against the new model/role.
  2. Compare the new with-skills log against the previous with-skills log for the same split (uv run inspect view side-by-side, or diff the exported scores).
  3. Treat per-case score moves of ≤ 2 points as noise (epoch variance). Investigate and file an issue against the specific skill for any larger regression; a larger improvement vs. baseline is the expected signal that the skill still earns its place.
  4. Book text (.work/books/) is never committed — it is local-only scratch needed only when authoring/editing skill content, not for running the eval suite.