@behaghel/pi-domain-tree0.4.1
Domain-driven structure with explicit groups, strict manifests, normative domain and system corpora, and specification-wiki integrity.
Untested on omp
This is a pi package. No one has reported whether it works on omp yet. If you try it, add your result below.
Reports 0
No reports yet.
Readme
domain-tree
Domain-driven codebase structure — enforce 1:1 mirroring between colocated domain specs and code namespaces, with DDD-informed subdomain classification, context mapping, and shared kernel management.
Philosophy
The domain tree is a structural contract informed by Domain-Driven Design. It encodes three things:
- Where things live — the 1:1 namespace mirror between domain specs and code
- How much rigor each domain deserves — core vs supporting vs generic classification
- How domains communicate — the context map declaring integration patterns
domains.yaml at the project root is the source of truth for that contract. Domain markdown files live beside the code they govern; README.md is the required main domain spec, and sibling Markdown is normative only when it declares domain and status frontmatter.
Domains aren't limited to business logic. Security, UX, CI/CD, and infrastructure are domains too — anything with behavior worth specifying. A technical domain like security can be core if it's central to the product's value.
DDD concepts used
| Concept | How we use it |
|---|---|
| Structural group | kind: group provides namespace and navigation without pretending to be a bounded context |
| Subdomain classification | type: core/supporting/generic on each domain — drives spec rigor and review requirements |
| Bounded context | Each domain IS a bounded context with its own ubiquitous language |
| Context map | context-map: section declaring cross-domain relationships and integration patterns |
| Shared kernel | type: shared-kernel for jointly-owned types — strictest change rules |
| Anti-corruption layer | Declared in context map — enforced by boundary-enforcer agent |
| Ubiquitous language | language: field in domains, with optional <domain code path>/README.md support — terms that code and specs must use consistently |
Ubiquitous language should be enriched on demand. Add new terms only when the domain needs sharper language, and get explicit developer approval before extending the glossary so the language stays intentional rather than drifting.
Relationship to other plugins
This plugin is the structural backbone for spec-driven development:
| Plugin | Role | What domain-tree provides |
|---|---|---|
spec-driven |
How to write specs | Where the spec lives, how much rigor it needs (core vs generic) |
spec-tdd |
How to execute specs | Which domain boundaries constrain iterations, which relationships to respect |
domain-tree |
Where things live | Namespace contract, classification, context map, enforcement |
Install any combination. They complement each other but don't depend on each other.
What's included
| Component | Type | Description |
|---|---|---|
| Domain Navigator | Skill | Auto-resolves domains, enforces placement, classification-aware spec-on-touch |
/domain-tree:init |
Command | Bootstrap tree with classification and context map from existing codebase |
/domain-tree:map |
Command | Coverage dashboard with domain types, wiki terms, and context map visualization |
/domain-tree:check |
Command | Structural, normative-wiki, context-map, and classification validation |
domain_tree_resolve_term |
Tool | Exact canonical-term and alias lookup with domain ownership |
boundary-enforcer |
Agent | Context-map-aware guard for cross-domain changes, ACL bypass, shared kernel |
Pi package
The publishable package is @behaghel/pi-domain-tree. Its third-party YAML parser is a normal runtime dependency; Pi installs it automatically when the package comes from npm. Pi supplies typebox, so it remains a peer dependency.
After the first npm release, install it with:
pi install npm:@behaghel/pi-domain-tree
A local path is for plugin development and Pi intentionally leaves its dependency tree to the author. Prepare and test a checkout explicitly:
devenv -q shell -- npm ci --prefix marketplace/plugins/domain-tree
devenv -q shell -- npm test --prefix marketplace/plugins/domain-tree
pi -e ./marketplace/plugins/domain-tree
Do not commit node_modules or a generated extension bundle.
Structural groups
Use explicit groups when names such as business, foundation, or technical organize bounded contexts but do not own behavior themselves:
domains:
business:
kind: group
domains:
time-management:
type: core
code: [src/business/time-management/]
Groups may nest. They do not own code, require specifications, receive classifications, or participate in context-map relationships. Their names remain part of each child domain's fully qualified identity.
domains.yaml is validated strictly. Groups, domains, and context-map relationships reject unknown or malformed fields. Every real domain must provide a specification anchor through code or spec. Invalid manifests fail closed: ownership resolution, coverage maps, and spec checks remain unavailable until /domain-tree:check diagnostics are fixed. Legacy structural nodes are reported with manual migration guidance and are never rewritten automatically.
Domain classification
Every domain has a type that determines investment level:
| Type | What it means | Spec rigor |
|---|---|---|
| core | Competitive advantage — why the project exists | Full spec collection, thorough TDD, human-approved specs |
| supporting | Necessary, custom-built, not differentiating | Good specs, standard TDD, self-approval OK |
| generic | Solved problem — use libraries/standards | Spec the integration boundary only |
| shared-kernel | Shared types across domains — joint ownership | High rigor, contract tests from all consumers |
Context map
The context-map in domains.yaml declares how domains communicate:
context-map:
- provider: issuance
consumers: [wallet]
pattern: open-host-service
contract: services/issuance-gateway/README.md
- provider: verification
consumers: [wallet]
pattern: anti-corruption-layer
contract: services/verifier/presentation/README.md
Supported patterns: shared-kernel, customer-supplier, conformist, anti-corruption-layer, open-host-service, published-language, partnership, separate-ways.
The boundary-enforcer uses the context map to guide cross-domain changes. Context entries are reserved for semantic contracts, not ordinary imports; the provider owns the canonical contract and consumers follow the declared pattern.
Quick start
New or existing project
/domain-tree:init
Scans your codebase, proposes domains with classifications, detects semantic cross-domain contracts, and scaffolds colocated README.md specs in each domain's code directory. Parent/child overlap follows subsidiarity: the most-specific matching child owns a file.
Day-to-day
- Before coding: Domain Navigator resolves which domain you're in, checks classification-appropriate spec requirements, and keeps normal work inside one domain at a time.
- During coding: Boundary enforcer consults the context map for cross-domain changes, guards shared kernel, prevents ACL bypass, and helps break cross-domain work into a sequence of intra-domain tasks.
- When work must cross domains: Favor domain-focused subagents and finish the domain-local tasks first. The last step should be the explicit cross-domain integration and end-to-end testing pass.
- For complex multi-domain work: Start with a plan that the developer can challenge and approve before implementation begins.
- Periodic health check:
/domain-tree:checkvalidates structure, context map, and classification gaps./domain-tree:mapshows coverage weighted by domain importance.
Migrating from the legacy spec/ layout
The first /domain-tree:check on a legacy tree reports a migration section. The short version:
- Move
spec/domains.yamltodomains.yamlat the project root. - For each domain, move
spec/<domain>/index.mdto the domain's code directory asREADME.md. - Move other domain
*.mdspecs into that same code directory. - Remove old
spec:fields or update them to explicit colocated paths. - Delete the old
spec/tree once empty.
Specification corpora
Domain specifications are the default. They define durable behavior, ubiquitous language, boundaries, invariants, and semantic contracts at the narrowest capable owner.
Use system-specs only for stable, project-wide requirements that subsidiarity cannot assign to one domain. System specs use system/status frontmatter and RFC 2119 requirements. Temporary iteration specs remain non-normative and outside both corpora.
Apply specification DRY: define each concept, invariant, or contract once, then link to its canonical owner and describe only local consequences. Normative specs reject roadmaps, rollout or migration plans, progress, delivery metadata, verification plans, legacy comparisons, and other circumstantial concerns.
The normative corpus forms a portable Markdown wiki. Canonical term pages declare term and optional aliases; each case-insensitive label has exactly one repository-wide owner. Relative links must resolve, Markdown fragments must identify real heading anchors, and links labelled with a canonical term or alias must target its owning page. Link meaningful first occurrences rather than every repetition. Use domain_tree_resolve_term for exact canonical or alias lookup.
The spec-on-touch convention
The first time you modify a domain, write its spec.
Rigor scales with classification:
- Core domains: spec required before any code change
- Shared kernel: spec required, all consumers notified
- Supporting domains: warning when missing
- Generic domains: only when the integration boundary changes
The Pi spec-on-touch guard permits write and edit of .md files directly in the owning domain's specification directory, including a missing or invalid README.md. This allows specification creation and repair without disabling enforcement. The directory is the explicit spec: override or, otherwise, the first code: path. Markdown elsewhere and non-Markdown files in that directory are not exempt. Core and shared-kernel code changes remain blocked until the domain's README.md passes normative validation; repairing it unlocks code changes in the same session.
License
domain-tree is free software licensed under the Mozilla Public License 2.0.