Instructions
Initialize a new project in the current directory. Ask the user for:
- Project name — used in README.md heading and CLAUDE.md
- One-line description — what this project does
- Primary language — one of:
typescript,go,python(or a framework likenext,fastapi,gin, etc.)
Then scaffold the project following the steps below. Skip any step where the file already exists — never overwrite.
Step 1: Git
Run git rev-parse --is-inside-work-tree to check. If not a git repo, run git init.
Step 2: README.md
Create a minimal README:
# {project-name}
{one-line description}
Step 3: CLAUDE.md
Generate a project CLAUDE.md. The structure should be:
# Project: {project-name}
{one-line description}
## Context
<!-- Why this project exists, key constraints, target users -->
## Structure
<!-- Will be filled as the project grows -->
## Development
### Setup
### Test
### Lint
### Build
## Implementation Plan
<!-- High-level milestones or phases -->
Fill in the Development section with concrete commands based on the language/framework chosen (e.g., npm test, go test ./..., pytest). Leave Context, Structure, and Implementation Plan as HTML comments for the user to fill in — these require human judgment.
Step 3.5: AGENTS.md
Create a symlink AGENTS.md -> CLAUDE.md so that other AI coding tools (e.g., GitHub Copilot) read the same project instructions:
ln -s CLAUDE.md AGENTS.md
Step 4: .claude/settings.json
Create .claude/settings.json with permissions scoped to the project's language. Use this as the base and add language-specific entries:
{
"$schema": "https://json.schemastore.org/claude-code-settings.json",
"permissions": {
"allow": []
}
}
Always include (all languages):
Bash(git add *),Bash(git commit -m *),Bash(git diff*),Bash(git log*),Bash(git status*)
TypeScript / Node.js — add:
Bash(npm test *),Bash(npm run test*),Bash(npx biome *),Bash(npm run build*),Bash(npm run lint*)Bash(npx tsc *)if TypeScript
Go — add:
Bash(go test *),Bash(go build *),Bash(go vet *),Bash(golangci-lint *)
Python — add:
Bash(pytest *),Bash(ruff *),Bash(ruff check *),Bash(ruff format *)Bash(pip install *)if no pyproject.toml build system is obvious
Step 4.5: package.json and dependencies (TypeScript / Node.js only)
If package.json does not exist, create one:
{
"name": "{project-name}",
"version": "0.0.0",
"private": true,
"type": "module",
"packageManager": "npm@{current npm version}",
"engines": {
"node": "{exact current node version}"
},
"scripts": {
"dev": "next dev --turbopack",
"build": "next build",
"start": "next start",
"lint": "biome check .",
"lint:fix": "biome check --write .",
"format": "biome format --write .",
"typecheck": "tsc --noEmit",
"test": "vitest",
"test:run": "vitest run --passWithNoTests"
}
}
Notes on the template:
"type": "module"— required sovitest.config.ts(ESM imports) loads underverbatimModuleSyntaxin the strict tsconfig added in Step 6.--passWithNoTests— keeps CI green before any tests exist; remove it once a test suite is in place if you prefer strict failure.
Run npm -v and node -v to fill in the actual versions.
Adjust dev, build, and start scripts based on the framework:
- Next.js:
next dev --turbopack,next build,next start - Plain TypeScript: remove
dev,build,startor set appropriate commands
Also create .npmrc with:
save-exact=true
min-release-age=7
save-exact=true— pin dependencies to exact versions (no^or~prefix)min-release-age=7— skip package versions published less than 7 days ago
Then install dev dependencies. The exact set depends on the framework:
Plain TypeScript: install biome, vitest, and typescript together so the
lint,test, andtypecheckscripts work immediately.npm install -D @biomejs/biome vitest typescriptNext.js: install biome here; vitest and typescript are installed alongside the Next.js runtime deps in Step 6.5.
npm install -D @biomejs/biome
Go / Python — skip this step.
Step 5: Linter config
Set up a minimal linter config for the chosen language.
TypeScript — biome.json:
First run npx biome --version to read the installed CLI version (e.g. 2.4.15). Pin the $schema URL to that exact version — using a stale version like 2.0.0 against a newer CLI produces a deserialize warning on every lint run.
{
"$schema": "https://biomejs.dev/schemas/{installed-biome-version}/schema.json",
"linter": {
"enabled": true
},
"formatter": {
"enabled": true,
"indentStyle": "space",
"indentWidth": 2
}
}
Go — .golangci.yml:
linters:
enable:
- govet
- errcheck
- staticcheck
- unused
- gosimple
- ineffassign
Python — ruff.toml:
line-length = 88
[lint]
select = ["E", "F", "I", "W"]
Step 6: Test framework config
Set up a minimal test config. Packages were already installed in Step 4.5 (plain TypeScript) or are installed in Step 6.5 (Next.js); here you only create the config files.
TypeScript — vitest.config.ts:
import { defineConfig } from "vitest/config";
export default defineConfig({
test: {
globals: true,
},
});
Also add to .claude/settings.json:
Bash(npx vitest *)
Plain TypeScript only — also create tsconfig.json so npm run typecheck runs against a real config instead of tsc defaults. Next.js has its own tsconfig generated in Step 6.5; do not create this for Next.js projects.
{
"compilerOptions": {
"target": "ES2022",
"module": "NodeNext",
"moduleResolution": "NodeNext",
"lib": ["ES2022"],
"strict": true,
"noImplicitOverride": true,
"noUncheckedIndexedAccess": true,
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"skipLibCheck": true,
"resolveJsonModule": true,
"isolatedModules": true,
"verbatimModuleSyntax": true,
"noEmit": true
},
"include": ["src/**/*", "vitest.config.ts"],
"exclude": ["node_modules", "dist"]
}
After writing the configs, verify the toolchain end-to-end by running npm run typecheck, npm run lint, and npm run test:run. All three should pass on the empty scaffold; if any fails, fix the config before moving on.
Go — no config file needed. Go's built-in go test works out of the box. Note the test conventions in the CLAUDE.md Development section:
### Test
go test ./...
Python — add pytest config to pyproject.toml. If the file does not exist, create it with just the pytest section. If it already exists, append the pytest section.
[tool.pytest.ini_options]
testpaths = ["tests"]
Also create a tests/ directory with an empty __init__.py (Python only).
Step 6.5: Next.js boilerplate (Next.js only)
If the chosen framework is Next.js, create the official App Router boilerplate. Fetch the latest template files from the vercel/next.js GitHub repo (packages/create-next-app/templates/app/ts/) using WebFetch against raw.githubusercontent.com, then create:
next.config.ts— empty Next.js configtsconfig.json— TypeScript config with Next.js plugin and@/*path aliasapp/layout.tsx— root layout with Geist fontsapp/page.tsx— default home pageapp/globals.css— global stylesapp/page.module.css— page-level CSS modulepublic/— SVG assets (file.svg,globe.svg,next.svg,vercel.svg,window.svg)
After creating the files, install the runtime dependencies:
npm install next react react-dom
npm install -D typescript @types/node @types/react @types/react-dom vitest
Then run npm run build to verify the setup works and generate next-env.d.ts.
Other frameworks — skip this step.
Step 7: .gitignore
If .gitignore does not exist, create one with sensible defaults for the language:
TypeScript: node_modules/, dist/, .env*.local, *.tsbuildinfo
Next.js (in addition to TypeScript): .next/, out/
Go: binary name (project name), vendor/ (optional)
Python: __pycache__/, *.pyc, .venv/, dist/, *.egg-info/, .env*.local
Always include: .DS_Store, tmp/
Step 8: Summary
After scaffolding, run tree -a -I '.git' --dirsfirst and show the user what was created. List any files that were skipped because they already existed.
Step 9: Initial commit
Stage all created files and make an initial commit:
git add <all created files>
git commit -m "chore: scaffold project with initial config"
Only commit the files that were created by this skill. Do not use git add . or git add -A.
Source: ebkn/dotfiles — distributed by TomeVault.