Scope: Applies to all C# module code under
Modules/**. Loaded automatically by VS Code Copilot. Directives: Enforces structural integrity, type safety, and mandatory build validation. These rules are non-negotiable. Ignore: TheInternalTestModules/folder — it is unrelated infrastructure and should not be referenced or used as a target for module work.
Before making any code changes, check for both CONTEXT.md and WORKING.md files and
read every one that exists and is relevant to the files you are about to touch.
The required order is:
- Read
CONTEXT.mdfirst - Read
WORKING.mdsecond
Do not treat them as interchangeable. CONTEXT.md establishes the durable architecture and
constraints; WORKING.md tells you how the current branch/task fits inside that context.
All transitory build artifacts live under .module-builder/ at the repository root (gitignored — never committed):
| Artifact | Path | Scope |
|---|---|---|
WORKING.md (global build state), RETROSPECTIVE.md |
.module-builder/<file> |
global — one each |
PATTERN-DOCUMENT.md, ATTACK-PLAN.md, localized WORKING.md |
.module-builder/<ModuleName>/<file> |
per module being built |
CONTEXT.md is the only durable artifact and the exception: it stays in the module project folder (e.g. Modules/Intent.Modules.X/CONTEXT.md) — never under .module-builder/, never at the repo root.
CONTEXT.md is the durable knowledge layer for a module or area. It captures:
- Important architectural decisions, invariants, technology constraints, and accepted patterns.
- Which other modules this module affects and how they interact.
- The design decisions taken during implementation.
This ensures future AI sessions understand the historical context and architectural implications when modifying a module, especially when
WORKING.mdstarts fresh.
Location: CONTEXT.md lives only inside module projects — e.g. Modules/Intent.Modules.Eventing.NServiceBus/CONTEXT.md. There is no root CONTEXT.md. Read the CONTEXT.md of every module you are about to modify. (Cross-cutting, in-progress state lives in .module-builder/WORKING.md instead — never in a root CONTEXT.md.)
Use CONTEXT.md for truths that should remain valid across multiple tasks and branches. If your intended change conflicts with CONTEXT.md, stop and flag the conflict rather than silently "improving" the design.
WORKING.md is the temporary in-progress layer located at .module-builder/WORKING.md (with per-module .module-builder/<ModuleName>/WORKING.md for minor/bugfix work). It captures:
- The active task/project state, current goals, known issues, and checklists spanning multiple modules or test apps.
- What has been tried: Specific solutions, approaches, or paths that were attempted and either discarded or selected, along with why. This prevents future AI runs from repeating failed paths.
Both WORKING.md and CONTEXT.md are managed and maintained entirely by the AI, for the AI.
Lifecycle:
- The
.module-builder/WORKING.mdfile exists only while the overall project work is in progress. When the project is complete, the file is deleted or cleared, and any durable knowledge that should survive is extracted into the relevantCONTEXT.mdfiles (which live in their module project folders). Per-module WORKING.md for minor/bugfix work goes under.module-builder/<ModuleName>/WORKING.md— never inside the module's own source folder. - Stale File Handler: If a
WORKING.mdfile exists, but you receive a new task/request that is completely unrelated to what is described in theWORKING.md, you must prompt the user immediately: "I see there is a project in progress in WORKING.md. Do you want to discard it and start fresh, or modify the existing plan?" before taking any actions.
Before calling any file modification tool, you must output a single line specifying only the target class name and the targeted line numbers:
Target: [ClassName.cs] | Lines [Start]-[End] (e.g., Target: OrderController.cs | Lines 45-60).
Do not output any prose, explanations, or additional bullet points.
All developer-facing output during module work must be easy to scan — never a wall of text:
- Lead with a concise summary; cut preamble and restated context.
- Prefer tables, short sections, and bullets over long paragraphs.
- Use light, purposeful emoji as visual anchors (✅ ❌
⚠️ 📝) — not decoration. - Surface decisions, blocks, and "what I need from you" explicitly and early.
- Developer-facing only — this does not apply to artifact files (CONTEXT.md, generated code, imodspec) or structured output another tool consumes.
- Suffix: Use
*FactoryExtension(e.g.,DomainConstraintsFactoryExtension). One concern per extension; do not merge unrelated cross-cutting concerns. - Template Files:
*TemplatePartial.cs: Contains constructor, model wiring, and metadata attachment.*TemplateBase.cs: Generated; do not hand-edit except for scaffoldedAfterBuildcallbacks.
- ID Handling: Prefer using Template Role names (using string constants) over the template's
TemplateIdconstant (staticconst string) for lookups. As last resort using hardcodedTemplateIdstrings.
| Work type | Root folder | Rule |
|---|---|---|
| Module code (templates, factory extensions, NuGet declarations, imodspec) | Modules/ |
All module projects live here. Never create or edit module source outside this folder. |
| Test applications & reference architectures | Tests/ |
All Intent-managed test apps and hand-crafted reference apps live here. Never create test/reference app projects inside Modules/. |
Before creating or editing any file, confirm its folder:
- Changing a template, factory extension, or module metadata →
Modules/<ModuleName>/ - Creating or running a test app, reference architecture, or SF target →
Tests/<AppName>/
If a task would place module code in Tests/ or app code in Modules/, stop and ask before proceeding.
- Scan Before You Name: Search for existing patterns before creating new classes.
grep_search→semantic_search→ then decide. Prefer extending abstractions over parallel ones. - Access Modifiers: Define all new types as
internalby default. Only usepublicif explicitly required for the external API. - Shared Projects: Do not introduce
.shproj/.projitemsfor new components without explicit approval. Prefer a referenced.csprojwithPrivateAssets="All".
- Eliminate Magic Values: Use
constorstatic readonlyfields. No inline magic numbers or strings. - Modern Strings: Use verbatim literals (
@"...") for quotes and raw string literals ("""...""") for multi-line blocks. - Builder API First: When generating or modifying
CSharpFilecode, use the most specific builder API available. Treat rawAddStatement, rendered-text replacement, andGetText()rewrites as fallback techniques requiring an explicit reason. - Warning: Never use global singletons for template-family scope (state must be clearable between Software Factory runs).
- Protocol: Owning templates attach managers in constructors. External extensions use
TryGetMetadata. Owning templates callmanager.ApplyRules()inAfterBuildat priority0. - Execution Priorities:
Band Integer Usage Core 0Owning template builds primary structure Enrichment 100Same-module cross-cutting additions Extension 500Factory extensions from other modules Final 1000FindMethod/FindClasson fully-built output
| Phase | Allowed Actions |
|---|---|
OnBeforeTemplateExecution |
Publish events (Registration Requests). No CSharpFile mutation. |
OnAfterTemplateRegistrations |
Find instances, schedule callbacks, register into managers. No event publishing. |
OnBuild / AfterBuild |
Mutate CSharpFile, read metadata, call ApplyRules. |
After every code change, verify the exit code is 0:
dotnet build "path/to/affected.csproj" --no-incremental --verbosity minimal --nologoAny edit to a *TemplatePartial.cs or *FactoryExtension.cs file MUST follow the full iteration cycle from module-increment-loop. No exceptions.
The cycle is:
- Edit the template body
dotnet build <module.csproj>→ exit 0install_or_update_modules— reinstall into the target apprun_software_factory(target_app_id)— run SF on the target app- If SF fails with a transient error, retry once immediately. Do not skip to manual edits. Only escalate to the user if the second attempt also fails.
get_staged_file_diffs— read and confirm the staged output matches intent- When reviewing
[IntentMerge]files, diff the entire method body against the prior committed state, not just the new additions. Any line present before but absent from the staged diff is being dropped — confirm this is intentional.
- When reviewing
apply_staged_file_changes— only after step 5 confirms correctnessdotnet build <target.sln>→ exit 0
NEVER edit files in Tests/ to "fix" what a template generates, then run SF to confirm "0 staged changes." Zero staged changes after pre-editing proves nothing — it just means the disk matches the template output, not that the output is correct. The staged diff inspection at step 5 is the only valid verification gate.
Before starting any new template-touching work, confirm the previous SF cycle reached step 7. If the cycle is open — SF was never retried after a failure, or steps 5–7 were skipped — close it first regardless of any other instruction.
If the user instructs you to commit or move on while a cycle is open:
- Commit the module-side code only (steps 1–2 are safe to commit).
- State explicitly: "Steps 4–7 are still open. I will not start new template-touching work until the SF cycle is closed."
- Create or update
.module-builder/WORKING.mdto record the open cycle so the next session can resume it. - Close the cycle before touching any
*TemplatePartial.csor*FactoryExtension.csfile again.
After every change that adds, removes, or modifies user-facing behaviour — a new transport option, a new setting, a new generated file, a changed generated shape — update both artifacts in the same turn as the code change. Do not defer to a follow-up:
| Artifact | What to update |
|---|---|
docs/README.md |
Add/update the relevant section (transport table, settings table, generated code example, etc.) |
release-notes.md |
Add a bullet under the current version using New Feature: / Improvement: / Fixed: prefix |
Use the module-docs skill for the canonical format rules. A code change without a matching docs update is incomplete.
Skills are auto-discovered from .agents/skills/ (Copilot) and .claude/skills/ (Claude Code). Use the relevant skill before generating code — each skill contains Musts, Must Nots, pattern indexes, and a resource folder.
Principle — Reference App First: No module code (templates, factory extensions, NuGet declarations) may be written or modified until
reference-app-builderhas produced a reference application that builds with exit code 0 and exercises the handler at runtime. This is the single most important sequencing rule in this framework. It is non-negotiable and cannot be skipped under any circumstance.
| Skill | When to use |
|---|---|
| module-kickoff | Start here for any new module. Gathers requirements from the developer, validates sufficiency, produces a Requirements Summary. Do not proceed without it. |
| tech-pattern-researcher | After module-kickoff. Researches the technology in isolation, maps it to Clean Architecture, defines files to generate. Produces a Pattern Document. |
| reference-app-builder | HARD GATE — runs BEFORE module-ecosystem-analyst without exception. May loop for multiple scenarios. Classifies runtime dependencies (AI-spinnable via Docker vs developer-provided), scaffolds a real Intent-managed Clean Architecture application, proves code shapes compile and the handler is hit at runtime. Additional scenarios and pivots are handled here before proceeding. The running app(s) are the ground truth that module-ecosystem-analyst reads. |
| module-ecosystem-analyst | After all reference apps are green. Uses the actual generated code — not abstract docs — to scan the Intent ecosystem: what existing modules generate, which SDK building blocks to use, which designer elements drive generation. Synthesizes across all reference app scenarios. Produces an Attack Plan. |
| intent-module-builder | After module-ecosystem-analyst. Uses MCP to scaffold the module in the Module Builder designer: creates template elements, factory extensions, NuGet declarations, runs SF to generate stubs. Produces a compiled module skeleton. |
| module-increment-loop | After intent-module-builder, AND whenever editing any existing template body or factory extension. Drives the iterative loop: change → build module → reinstall → SF on target → inspect staged diff → apply → build → run → verify. Must be followed for any *TemplatePartial.cs or *FactoryExtension.cs change, not only during new module builds. |
| module-wrap-up | Final mandatory phase after all increments pass. Version bump (assess impact, apply rule, align imodspec + csproj + designer), invoke module-docs, write CONTEXT.md (in the module folder), clear .module-builder/WORKING.md, confirm SF clean. Release notes header uses non-pre version. |
| module-retrospective | Runs automatically throughout every build. Appends findings to .module-builder/RETROSPECTIVE.md (append-only) whenever a workaround, skill gap, missing requirement, or architecture problem is encountered — even when the task still completed. Notifies the user with a one-line note. At session end proposes targeted edits to SKILL.md files and module-kickoff Q&A. Four buckets: Intent gaps (flag for IA team), Process gaps (update relevant skill), Module Architecture gaps (flag for architecture owners / module-building-strategies), PRD/user gaps (strengthen kickoff questions). |
| Skill | When to use |
|---|---|
| module-building-strategies | The accumulated strategic playbook — load at every design decision across the whole chain: module decomposition (root/bridging/common, shared-project avoidance, DLL-skew), template vs factory extension, file cardinality, managed modes, design-time config (setting vs stereotype), convention-vs-explicit, and two-phase (reproduce + from-scratch) verification. |
| file-builder-expert | Converting a C# class to a CSharpFile fluent template; writing OnBuild/AfterBuild callbacks; creating template registration classes; resolving types via GetTypeName/UseType. |
| intent-mapping-architect | Generating update/creation mappings from designer metadata; implementing CSharpClassMappingManager, IMappingTypeResolver, or CSharpMappingBase; handling recursive object/collection mapping. |
| intent-metadata-consumer | Reading stereotype properties to drive code generation; authoring or extending *StereotypeExtensions.cs; writing LINQ queries against typed model collections (ClassModel, DTOModel, etc.). |
| intent-module-orchestrator | Dispatching ContainerRegistrationRequest / AppSettingRegistrationRequest via EventDispatcher; finding and modifying templates from other modules; authoring *FactoryExtension classes; priority-band ordering. |
| intent-domain-interactions-expert | Authoring IInteractionStrategy implementations (query/create/update/delete entity, publish/send integration message, processing actions); wiring method.ImplementInteractions(model) from handler factory extensions; using CSharpMapping resolvers and ExecutionPhases. |
| add-designer-extension | Add a context menu item, new element type creation option, or association creation option to an existing element or package type from another module. |
| add-association-type | Define a new association type in a module, including source and target end configuration. |
| intent-architect-mcp | Intent Architect MCP workflow: designer operations, element discovery, model modification, Software Factory execution, compilation verification, and cross-module integration patterns. |
| module-docs | Complete the three release documentation artifacts for an Intent Architect .NET module (release-notes.md, README.md, and .imodspec). |
Maintenance: Use the
refresh-intent-skillsprompt to audit skills against the latest SDK and update any stale patterns or resource files.
See .agents/instructions/exception-guidelines.md for the full decision table.
Summary:
FriendlyException(string message)— user-facing, no element reference. For missing modules, invalid setting combinations. Supports Markdown.ElementException(model.InternalElement, string message)— user-facing, tied to a specific designer element. Intent Architect highlights the element in the UI. Supports Markdown.InvalidOperationException— developer-facing (module bug, unhandled enum value). Raw stack trace, not shown in a friendly panel.- Generated code strings (
method.AddStatement(@"... ?? throw new InvalidOperationException(...)")) are app-startup code — always stay asInvalidOperationException.
If architectural or logic paths are unclear and require runtime context:
- Instrument the Code: Add temporary log entries using
Intent.Utils.- Example:
Logging.Log.Debug("Context: " + variable);
- Example:
- Request Execution: Ask the user to run the module/Software Factory.
- Analyze Output: Request the specific log output from the user before proceeding with further code changes.