timewarpengineering/timewarp-architecture/tw-feature-placement

Claude Code and agent skill by timewarpengineering/timewarp-architecture

Trust tier 3
  • community
  • ext:[{"type":"config","description":"Configuration overrides"}]
Source check pending

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-placement

Semi-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 only
the 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 own features//platform//msbuild/ trees from the same SSOT
registry (yarp excepted — single-project family, no concern trees). Worked examples below use
web; substitute api//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.
HomeUse forNamespaceExamples
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 folderNon-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 defaultsprogram.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/afeature-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

SignalHow to find it
Creating/moving/renaming a .cs file under a product sliceany web/features/<slice>/… folder
TWA0015 / TWA0016 diagnosticanalyzer output names a filename and a function segment
"Feature file(s) match NO registered layer suffix" build errormembership 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

<name>[-<function>]-<layer>.cs
SegmentRequiredMeaning
nameyesoperation or slice-local subject, kebab-case (get-roles, hello)
functionoptionala registered archetype keyword; when present it must pair with exactly one layer (checked at build)
layeryesone 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
FilenameLayerFunction → required layerLiving anchor
create-role-handler-application.csapplicationhandler → applicationweb/features/admin/roles/create-role/create-role-handler-application.cs
<name>-endpoint-server.csserverendpoint → serverhand-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.cs
  • get-roles-contracts.cs
  • role-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.cs
  • web-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/`):

text
admin/roles/
create-role/
create-role-contracts.cs
create-role-handler-application.cs
delete-role/
delete-role-contracts.cs
delete-role-handler-application.cs
get-role/
get-role-contracts.cs
get-role-handler-application.cs
get-roles/
get-roles-contracts.cs
get-roles-handler-application.cs
update-role/
update-role-contracts.cs
update-role-handler-application.cs
role-details-contracts.cs # shared bindable shape used by every use case above
role-domain.cs # the aggregate every use case loads and saves
i-role-store-application.cs # shared store port, not operation-specific

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

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
vskill VERIFIED badge
[![vskill VERIFIED](https://verified-skill.com/api/v1/skills/timewarpengineering/timewarp-architecture/tw-feature-placement/badge)](https://verified-skill.com/skills/timewarpengineering/timewarp-architecture/tw-feature-placement)

Something wrong with this skill or its page? Tell us.