timewarpengineering/timewarp-architecture/tw-feature-placement
Claude Code and agent skill by timewarpengineering/timewarp-architecture
- community
- ext:[{"type":"config","description":"Configuration overrides"}]
Checking that the SKILL.md file is still in the repository.
**TIMEWARP SKILL** — feature-cohesive folder placement, per-use-case folders, and the filename grammar `<name>[-<function>]-<layer>.cs` for product code under `<family>/features/` and platform clusters under `<family>/platform/` (family-generic: web, api, grpc all share this machinery — worked examples below use web): which layer a file belongs to, what to name it and which folder it goes in, the registry that backs TWA0015/TWA0016, and the membership-guard build errors. Invoke before creating, moving, or renaming a file under a feature slice or platform cluster, or when a TWA0015/TWA0016/membership-guard error appears. WHEN: Where does this handler file go?, What do I name this contract file?, Should this file get its own folder?, TWA0015, TWA0016, feature file matches no registered layer suffix, platform/postgres, add a function segment to the registry, split a module into its own assembly.
Install
npx vskill@latest install timewarpengineering/timewarp-architecture/tw-feature-placementSemi-extensibleMentions customization, but needs skill-specific knowledge. Read the extensible skills standard
SKILL.md
Feature placement and filename grammar
All logic lives in a concern folder under a shared tree —features/for product concerns,platform/for platform concerns — named by the filename grammar; artifact folders hold onlythe artifact definition (csproj, global-usings) and its entry-point bootstrap (program.cs,appsettings, launchSettings, host-config exemplars). The machinery is family-generic — web,api, and grpc each get their ownfeatures//platform//msbuild/trees from the same SSOTregistry (yarp excepted — single-project family, no concern trees). Worked examples below useweb; substituteapi//grpc/for the family root and the same rules apply.
Why folder is not project: feature cohesion on disk (one folder tells the whole story) and compiler-enforced layer direction are both required. Conventional .NET layouts force a choice because they assume folder = project. Dropping that assumption — layer projects include files by filename-grammar globs — delivers both. Assembly splits later are a glob change, not a file move. SPA stays conventional (web-spa/features/**) because the Razor SDK asset/codegen pipeline does not warrant cross-folder globbing. Registry edits require a full rebuild (analyzer DLLs can go stale under incremental builds).
The litmus test for the fuzzy middle:
If this deployable were deleted, would the file still mean something? Yes → shared tree(which concern folder?). No → it is bootstrap; it stays with the artifact.
| Home | Use for | Namespace | Examples | |
|---|---|---|---|---|
web/features/<slice>/ | Product concerns: an operation gets its own <slice>/<use-case>/ folder; a file serving more than one operation (shared contract, store) stays at slice root | …Features.<Id> (TWA0009) | admin/roles/create-role/, chat/chat-hub-server.cs | |
web/platform/<cluster>/ | Platform concerns: a host/platform cluster split across layers — including a seam interface living beside the implementation it seams with, not sorted into a separate layer folder | Non-Features (e.g. Configuration, Services, Authorization, Payment) | platform/postgres/, platform/identity-host/i-current-principal-accessor-application.cs + http-current-principal-accessor-server.cs, platform/authorization/ (evaluator + stores), platform/payment/ (HttpContext port) | |
web/projects/<artifact>/ | Artifact (csproj home) under the family projects/ group — definition (csproj, global-usings) and entry-point bootstrap only; content that would mean nothing if you imagine the deployable gone. Occupants: web-contracts/, web-application/, web-domain/, web-infrastructure/, web-server/, web-spa/ | Host assembly defaults | program.cs, sample-options.cs (binding/validation exemplar, not a real concern) | |
web/msbuild/ | Build machinery for the web family (filename-grammar props, membership targets) | n/a | feature-membership.targets |
Family root shape: multi-project container-app families group artifact folders under projects/ so the root reads as the placement rule (features/ + platform/ + projects/ + msbuild/). This shape is family-generic — web, api, and grpc each have their own features//platform//msbuild/ trees (task 129: all three now hold real content — web's product/platform slices, api's weather-forecast/, grpc's hello//superhero//greeter/ + platform/codegen/). yarp is a single-project family (yarp/ is the project — appsettings at its root); it is not nested under projects/ and has no concern trees.
Folder location is for humans; filename decides project membership. Each layer project composes its files with static filename globs keyed to a suffix under its own family's {Prefix}FeatureTreeRoot and {Prefix}PlatformTreeRoot (Web/Api/Grpc), not a folder path — a seam interface's -application.cs suffix pulls it into the family's -application compilation unit from wherever it physically sits, which is exactly why it lives beside its -server.cs implementation in platform/identity-host/ instead of a folder split by layer (the old web-application/abstractions/, retired: conflating layer with folder was never a principled reason to separate a seam from the concern it belongs to).
Modules follow concerns, not assemblies. A module (IModule) is a concern's registration manifest — the DI wiring that concern needs — and lives in the concern's folder like any other layer file: a product concern's module at its slice root (e.g. features/identity/in-memory-identity-stores-module-infrastructure.cs), a platform concern's module in its cluster (e.g. platform/postgres/postgres-db-module-server.cs). There are no assembly-level modules — an assembly is a compilation unit, not a concern. The host's program.cs remains the ordered composition root: module definition is logic (shared tree); module ordering is bootstrap (artifact folder). A concern with no registrations needs no module — no ceremony.
Product code for a web container-app lives in one feature-cohesive folder per slice — web/features/<slice>/ — with every layer (contracts, application, domain, infrastructure, server) colocated in that folder. Host/platform clusters that are not product slices live under web/platform/<cluster>/ with the same -layer filename suffixes (so the same layer-project globs pick them up) but without …Features.<Id> namespaces. This is the answer to "where does this file live" and "what do I name it" — the most common file-placement decision in the repo.
Inside a slice, files group by use case, not by message kind: every operation gets its own <slice>/<use-case>/ folder holding all of that operation's layer files side by side — the contract next to its handler, not sorted into commands//queries/ subfolders. See Use-case folders below.
Detection — when to invoke
| Signal | How to find it | |
|---|---|---|
Creating/moving/renaming a .cs file under a product slice | any web/features/<slice>/… folder | |
TWA0015 / TWA0016 diagnostic | analyzer output names a filename and a function segment | |
| "Feature file(s) match NO registered layer suffix" build error | membership guard (feature-membership.targets) | |
| Adding a new archetype (a new hand-authored generation pattern) | needs a new registry function entry | |
| "Should this module get its own assembly?" | axis-2 note below |
Grammar
| Segment | Required | Meaning | |
|---|---|---|---|
name | yes | operation or slice-local subject, kebab-case (get-roles, hello) | |
function | optional | a registered archetype keyword; when present it must pair with exactly one layer (checked at build) | |
layer | yes | one of contracts, application, domain, infrastructure, server — decides which csproj globs the file |
The function segment is a deliberate two-things-must-agree seam: naming the archetype in the filename and the layer both, so the analyzer can catch a mismatch instead of relying on a human remembering the pairing.
Worked examples per archetype
| Filename | Layer | Function → required layer | Living anchor | |
|---|---|---|---|---|
create-role-handler-application.cs | application | handler → application | web/features/admin/roles/create-role/create-role-handler-application.cs | |
<name>-endpoint-server.cs | server | endpoint → server | hand-written browser-protocol endpoint only (tw-web-api-contracts). Ordinary JSON endpoints are generated from contracts |
A mismatched pairing (e.g. create-role-handler-server.cs, function handler on layer server) is TWA0015 — see below.
Reserved layer headroom: domain is a registered layer with its own csproj glob and membership-guard entry, but most product slices need only contracts and application (plus infrastructure or server where relevant) — a slice earns a -domain.cs file only once it needs its own aggregate root (IAggregateRoot) rather than a platform/shared one. domain stays registered as intentional headroom for that case. The endpoint function is in use for the browser-protocol shims (challenge-entra-endpoint-server.cs, sign-out-browser-session-endpoint-server.cs, sign-out-antiforgery-token-endpoint-server.cs), not for ordinary API operations.
Contracts drop the function segment
For contracts, function and layer are the same thing, so writing both would stutter (-contract-contracts). Contract files use <name>-contracts.cs with no function segment, and every -contracts.cs file is held to the operation-contract shape (Command/Query, [ApiRoute], I*Details, Validator — see tw-web-api-contracts):
create-role-contracts.csget-roles-contracts.csrole-details-contracts.cs(shared bindable shape, no function)
Escape hatch
Not every file is an archetype instance. When a file has no registered function, omit the function segment entirely — <name>-<layer>.cs — and the grammar imposes no archetype shape on it:
role-domain.csweb-authn-payload-decoder-application.cs
An unregistered or misspelled token that looks like it's trying to be a function is TWA0016, not a silent escape hatch — see below.
Use-case folders
The rule is unconditional: every operation gets its own `<slice>/<use-case>/` folder holding every layer file for that operation, side by side — the contract next to its handler. A folder with only two files in it is correct; there is no size threshold below which an operation stays flat at slice root. Files that serve more than one operation (a shared bindable DTO, a store, an entity-type configuration) stay at slice root instead of picking one use-case folder to live in.
commands/ and queries/ subfolders (or any other group-by-kind split, such as client-to-server//server-to-client/ for a hub) do not appear inside a slice — grouping by message kind is a layer instinct, and a feature-cohesive slice groups by use case instead. Folder path never affects project membership (only the filename suffix does — see Grammar above), so this is a pure human-navigation convention, not something the build enforces.
Worked example — a whole slice (`web/features/admin/roles/`):
Every use-case folder here holds exactly one contract file and one handler file — two files is the normal case, not a special one. role-details-contracts.cs, role-domain.cs, and i-role-store-application.cs each serve multiple use cases (or the whole slice), so they stay at admin/roles/ root rather than moving into any single use-case folder.
When a slice's operation name is identical to the slice name (a single-operation slice), the use-case folder is still literal — hello/hello/hello-contracts.cs, not a special-cased flat layout. When a hub or similar has one folder per message DIRECTION instead of per use case (client-to-server/, server-to-client/), that is the same group-by-kind instinct as commands//queries/ and collapses the same way: one folder per use case (send-message/, receive-message/), not one folder per direction.
Registry (SSOT)
This is the start of the file. Read the full SKILL.md on GitHub.
Security
- Security scanPassed, 90 of 100Pattern checks on the skill's files.
- Model reviewPassed
Quality evaluation
- Task evaluationNot runNo evaluation yet. Run one in Skill Studio.
Source
- SKILL.md in the repositoryCheckingskills/tw-feature-placement/SKILL.md
Popularity
- 7-day trend score
- 0
Not refreshed yet.
Extension points
configConfiguration overrides
Works with
Any agent vskill installs to: 56 targets in all. These 39 have a page on this site.
- Claude Code
- Cursor
- GitHub Copilot
- Windsurf
- Codex
- Gemini CLI
- Cline
- Amp
- Roo Code
- Goose
- Continue
- Kilo Code
- Junie
- Trae
- OpenHands
- Qwen Code
- AI Agent
- Tabnine Chat
- Sourcegraph Cody
- Amazon Q
- Firebase Genkit
- Sweep
- Devin
- Phind
- Mentat
- Claude Desktop
- Aider
- GPT Pilot
- Plandex
- bolt.new
- v0
- Replit Agent
- Anse
- TypingMind
- BetterChatGPT
- LibreChat
- Warp AI
- Pieces
- Fig AI
Embed badge
[](https://verified-skill.com/skills/timewarpengineering/timewarp-architecture/tw-feature-placement)