scaffold
$
npx mdskill add SethGammon/Citadel/scaffoldGenerate project-aligned files matching existing conventions
- Creates new components and services using proven code patterns
- Depends on file system access to read current naming standards
- Decides structure by analyzing two or three similar exemplar files
- Delivers ready-to-integrate source code at project registration points
SKILL.md
.github/skills/scaffoldView on GitHub ↗
---
name: scaffold
description: >-
Project-aware file generation. Reads existing codebase conventions (naming,
structure, imports, exports, test patterns) then generates new files that
match exactly. Wires generated files into the project's registration points.
user-invocable: true
auto-trigger: false
trigger_keywords:
- scaffold
- generate component
- generate module
- generate service
- new component
- new module
- new route
- new service
- create component
- stub out
---
# /scaffold — Project-Aware File Generator
## Orientation
**Use when:** Creating a new component, module, service, route, hook, domain, or utility with existing examples in the project.
**Do NOT use when:** The file has no precedent (use `/marshal` for unconstrained generation), you're modifying existing files (use `/refactor`), or the project has no conventions yet.
**Needs:** target type, name, and optional description.
## Protocol
### Step 1: IDENTIFY THE TARGET
Parse the user's request into:
- **type**: component | module | service | route | hook | domain | utility | custom
- **name**: the name the user gave (e.g., "UserProfile", "auth-service", "settings route")
- **description**: what it does, if provided (otherwise leave blank for now)
If the type is ambiguous, ask ONE clarifying question. Do not ask more than one.
### Step 2: FIND EXEMPLARS
Search the codebase for 2-3 existing files of the same type.
**Search strategy by type:**
| Type | Search Pattern | What to Look For |
|---|---|---|
| component | `**/*.tsx` in the same directory or sibling directories | Functional components with similar complexity |
| module | Same directory as where new module will live | Registration pattern, exports, config shape |
| service | `**/services/**`, `**/lib/**` | Class vs function, singleton vs factory, error handling |
| route | Router config files, `**/routes.*`, `**/pages/**` | Route definition format, lazy loading, guards |
| hook | `**/hooks/**`, `**/use*.ts` | Naming, parameter patterns, return types, cleanup |
| domain | Top-level domain/feature directories | Manifest structure, entry point, internal layout |
| utility | `**/utils/**`, `**/helpers/**` | Pure function style, type signatures, JSDoc |
**For each exemplar, extract:**
1. File naming convention (PascalCase, kebab-case, camelCase, snake_case)
2. Directory placement (co-located with component? separate `hooks/` dir?)
3. Import style (path aliases? relative? named imports? default exports?)
4. Export style (named exports? default? re-exported from barrel/index file?)
5. Internal patterns (how state is managed, how errors are handled, JSDoc or no)
6. Test co-location (`.test.ts` next to file? `__tests__/` directory? separate `tests/` tree?)
7. Types pattern (inline? separate `.types.ts`? shared types file?)
**Output a brief analysis** (3-5 lines) summarizing the conventions you found.
### Step 3: DETERMINE THE FILE SET
Based on the exemplars, determine which files to generate. Not every project
needs every file. Only generate what the project's conventions call for.
**Decision matrix:**
| File | Generate IF... |
|---|---|
| Main file | Always |
| Types file (`.types.ts`) | Project separates types into their own files (check exemplars) |
| Test file (`.test.ts`) | Project has co-located tests for this type of file |
| Barrel/index file | Project uses barrel exports AND this file's directory doesn't already have one |
| Barrel update | Project uses barrel exports AND the directory already has an index file |
| Style file (`.module.css`, `.styled.ts`) | Project uses co-located styles for this type |
| Storybook file (`.stories.tsx`) | Project has stories for this type of file |
**Do NOT generate:**
- Empty placeholder files with only a TODO comment
- Test files that only contain `describe('...', () => { it.todo('...') })`
- Types files that only re-export from elsewhere
- Any file type the project doesn't already use
### Step 4: GENERATE THE FILES
For each file in the set, generate content by adapting the closest exemplar.
**Rules:**
1. Match the exemplar's structure exactly — same section order, same patterns
2. Replace names and specific logic, keep structural patterns
3. Every generated file must be syntactically valid and importable
4. No placeholder comments (`// TODO: implement`, `// Add logic here`)
5. No empty function bodies unless the exemplar has them
6. Minimal but functional — renders something, has at least one real method, returns a typed value
7. Match the project's TypeScript strictness
Match the exemplar's props pattern, state management, utility imports, async patterns, and error handling exactly.
### Step 5: WIRE IT IN
Find every registration point the exemplars use and add the new file there.
**Common wiring points (check which ones the project uses):**
| Wiring Point | How to Find It | What to Add |
|---|---|---|
| Barrel exports | `index.ts` in the same or parent directory | `export { NewThing } from './NewThing'` |
| Route registration | Router config file (search for exemplar's route) | New route entry matching the pattern |
| Module registry | Bootstrap/registration file | New registration call |
| Navigation/sidebar | Nav config array | New nav entry if appropriate |
| Lazy loading map | Dynamic import map | New lazy import entry |
| Type unions | Discriminated unions that list all variants | New variant if this is a new "type" of thing |
**Rules:**
1. Only wire into registration points that the exemplars actually use
2. Match the exact format — same spacing, same trailing commas, same comments
3. If a registration point uses alphabetical ordering, maintain it
4. Never create new registration points — only add to existing ones
### Step 6: VERIFY
Run typecheck — every generated file must pass. Fix failures before exiting. If typecheck is unavailable, do a manual read-through for syntax and import correctness.
## Fringe Cases
- **Target directory or file already exists**: Do not silently overwrite. Confirm with the user before proceeding. Output: "A file at `{path}` already exists. Overwrite it?" and wait for confirmation.
- **Template or exemplar not found**: List the available file types in the codebase and ask which one to use as the exemplar. Never scaffold from memory if no exemplar exists.
- **Language or framework not detected**: Ask the user directly rather than guessing. One question: "What type of file should this be? (e.g., React component, Express route, utility function)"
- **Typecheck fails after generation**: Fix the issue before exiting — do not leave the user with broken generated files.
- **No wiring point found**: Note the missing registration explicitly in the exit summary rather than silently leaving the file unwired.
## Contextual Gates
**Reversibility:** Amber — creates new files and modifies registration points; `git checkout` to undo.
**Cost:** No cost actions — file generation only; no agents spawned, no confirmation needed.
**Trust:** No gates — safe at all trust levels; overwrite confirmation is in Fringe Cases.
## Quality Gates
All of these must be true before the skill exits:
- [ ] Found 2+ exemplar files of the same type in the project
- [ ] Generated files match the project's naming convention exactly
- [ ] Generated files match the project's import/export style exactly
- [ ] No placeholder comments, TODO stubs, or empty function bodies
- [ ] Every generated file is syntactically valid TypeScript/JavaScript
- [ ] Main file is wired into the project (barrel export, route, registry, etc.)
- [ ] Test file exists IF AND ONLY IF the project co-locates tests for this type
- [ ] Types file exists IF AND ONLY IF the project separates types for this type
- [ ] Typecheck passes (or manual verification if typecheck unavailable)
## Exit Protocol
Output a summary in this format:
```
SCAFFOLD COMPLETE
Created:
- path/to/MainFile.tsx (component)
- path/to/MainFile.test.tsx (test)
- path/to/MainFile.types.ts (types)
Wired into:
- path/to/index.ts (barrel export)
- path/to/routes.ts (route registration)
Conventions matched from:
- path/to/ExemplarA.tsx
- path/to/ExemplarB.tsx
Typecheck: PASS
```
```
---HANDOFF---
- Scaffolded: {name} ({type})
- Created: {N} files, wired into {N} registration points
- Conventions matched from: {exemplar names}
- Reversibility: green -- new files only, delete to undo
---
```
More from SethGammon/Citadel