Clone-and-go project scaffolder. It stamps any new (or freshly imported) project with the
full dxiiren onboarding kit — an idempotent setup.ps1, a justfile, a README, a numbered
.docs/ documentation set, and a .claude/ kit (11 skills, statusline, memory seed, MCP
stub) — in two steps: a mechanical token fill, then an intelligent grounding pass by Claude.
This README describes the skeleton itself. Running
.\init.ps1REPLACES it with the scaffolded project's own README (fromREADME.project.template) — that is intentional.
# 1. Clone into your new project's folder name
git clone https://github.com/dxiiren/project-skeleton my-new-app
cd my-new-app
# 2. Mechanical scaffold — pick a stack, fill the tokens, clean up the scaffolding
.\init.ps1
# (or non-interactive: .\init.ps1 -Name my-new-app -Stack static -Port 8433 -Docroot . -FreshGit)
# 3. One-time machine setup (idempotent — installs the stack's toolchain)
pwsh ./setup.ps1
# 4. Intelligent grounding — Claude reads the real code and finishes the kit
claude
/ground-projectAfter step 4 the project has a filled CLAUDE.md/README/.docs, skills grounded in its real
code, the applicable optional skills enabled, a passing skill audit, and a boot-verified
just start/just build workflow.
| Stack | Serves / builds | Extra inputs init.ps1 asks for |
|---|---|---|
php-laravel |
artisan serve on the assigned port; sqlite locally |
Port |
php-plain |
php -S built-in server |
Port, Docroot |
node-vite |
Vite dev server (--strictPort; use localhost URLs) |
Port |
node-nuxt |
Nuxt dev server (no strictPort; preview reads PORT env) |
Port |
static |
Python http.server via uv |
Port, Docroot |
cli-java |
javac/java build-run (no server) |
MainClass |
cli-cpp |
w64devkit g++ build-run (no server) | Src (source files) |
cli-jupyter |
Jupyter Lab / headless nbconvert via uv | Port |
vbnet |
MSBuild + WinForms exe (no server) | MainClass (project name), Src (solution file) |
project-skeleton/
init.ps1 # the scaffolder (step 2 above) — deletes itself when done
justfile # skeleton DEV recipes (just test) — replaced by the stack's at init
tests/init.Tests.ps1 # Pester suite locking init.ps1's behavior — removed at init
GROUNDING.md # conventions bible -> becomes .docs/05-reference/conventions.md
CLAUDE.md.template # -> CLAUDE.md at init
README.project.template # -> README.md at init (replaces this file)
.mcp.json.stub # committed MCP placeholders (context7/playwright/github)
gitignore-block.txt # merged into .gitignore at init, then deleted
stacks/<stack>/ # per-stack setup.ps1 + justfile + NOTES.md (tokenized, validated)
.docs/ # numbered documentation template tree (placeholders)
.claude/
settings.json # shared settings incl. statusline wiring
hooks/statusline.py # git-aware statusline
memory/MEMORY.md # project-memory seed
skills/ # 10 core skills + ground-project (catalog: skills/README.md)
skills-optional/ # opt-in skills ground-project enables when prerequisites exist
Token conventions, invariants, and the per-stack boot-verify bar live in
GROUNDING.md.
The scaffold behavior is locked by a Pester suite:
just test
# equivalent: pwsh -Command "Invoke-Pester -Path tests" (Pester 5+, see below)tests/init.Tests.ps1 copies the whole skeleton into a fresh %TEMP% folder per
Describe and runs init.ps1 there — the working tree is never scaffolded, and temp
copies are deleted afterwards. It scaffolds all 9 stacks and covers:
- Shared scaffold steps (asserted in full for
staticandcli-java):CLAUDE.md/README.mdare created from the templates;GROUNDING.mdand the stack'sNOTES.mdmove into.docs/05-reference/; the scaffolding removes itself (stacks/,init.ps1,gitignore-block.txt, the skeleton's owntests/); the gitignore block is merged; content tokens (WHAT_IT_IS, ...) survive for/ground-project, andconventions.md's token table is skipped by the fill. - Per-stack token fill (every stack, driven by the
$stackMatrixtable): the stack'sjustfile+setup.ps1land at the root with zero mechanical tokens, and each of that stack's own tokens carries the value actually passed — Port, Title, Docroot, MainClass, Src, RepoSlug, and the hardcoded8.4/vs17PHP pair. - Failure paths: re-running init on an already-scaffolded copy refuses
(exit 1) and leaves the project untouched; a missing required value
(
cli-javawith no MainClass,cli-cppwith no Src) exits 1 before touching anything; a missingstacks/folder exits 1;-FreshGitleaves a.gitrepo on branchmain.
Requirement: Pester 5+ visible to pwsh (the Windows-inbox Pester 3 can't run it):
Install-Module Pester -Scope CurrentUser -Force -SkipPublisherCheckChange init.ps1 or a stack's files → run just test before pushing; if you change
what init observably does, update the suite in the same commit.
- Create
stacks/<name>/with asetup.ps1, ajustfile, and aNOTES.md, following the invariants inGROUNDING.md(log tags, EAP guard, justfile rules, project-scoped stop). Tokenize project facts with the mechanical tokens from the token table. - Base
setup.ps1on the closest existing stack (the node one is the smallest base) and insert the stack's toolchain step; keep the helpers verbatim and renumber cleanly. - Add the stack's row to the boot-verify table in
GROUNDING.mdand to the table above. - If the stack needs an input beyond Name/Port, map it onto an existing token
(
MAIN_CLASS/SRC/DOCROOT— see the vbnet mapping instacks/vbnet/NOTES.md) and add the stack to the matching prompt list ininit.ps1. - Add the stack's row to
$stackMatrixintests/init.Tests.ps1— the arguments to scaffold it with, plus one regex per token it owns proving the passed value landed. Every stack has a row; a stack without one is untested. - Prove it: run
.\init.ps1against a copy,just --list,pwsh ./setup.ps1, and the stack's boot-verify before pushing — andjust testmust stay green.