一键导入
base
Scaffolds a new TypeScript project from scratch. Use when starting a new project, bootstrapping a codebase, or setting up a project from zero.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Scaffolds a new TypeScript project from scratch. Use when starting a new project, bootstrapping a codebase, or setting up a project from zero.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
| name | base |
| description | Scaffolds a new TypeScript project from scratch. Use when starting a new project, bootstrapping a codebase, or setting up a project from zero. |
Ask the user to describe what the project is about. Use their response to populate <project-name> and <project-description> in later steps.
bun add -d @biomejs/biome @types/bun @typescript/native-preview knip simple-git-hooks taze turbo ultracite vitest
{
"name": "<project-name>",
"version": "0.1.0",
"private": true,
"type": "module",
"scripts": {
"lint": "biome check",
"types": "tsgo --build",
"test": "vitest run",
"unused": "knip",
"update": "taze --interactive"
},
"dependencies": {},
"devDependencies": {},
"simple-git-hooks": {
"pre-commit": "make validate"
},
"knip": {
"ignoreDependencies": [
"turbo"
],
"ignoreBinaries": [
"make"
]
},
"packageManager": "bun@<current-bun-version>"
}
Replace <current-bun-version> with the output of bun --version.
import { file, spawn } from "bun";
await installDependencies();
await installGitHooks();
await setupRemoteCache();
export async function installDependencies() {
await spawn(["bun", "install"]).exited;
console.log("Dependencies installed");
}
export async function installGitHooks() {
await spawn(["bunx", "simple-git-hooks"]).exited;
console.log("Git hooks installed");
}
export async function setupRemoteCache(isRetry?: boolean) {
const config = file(".turbo/config.json");
if (!((await config.exists()) && (await config.json()).teamId)) {
const stdio = isRetry ? "inherit" : "pipe";
const link = spawn(["turbo", "link"], { stdio: [stdio, stdio, stdio] });
if ((await link.exited) !== 0) {
const error = await new Response(link.stderr).text();
if (error.includes("User not found")) {
await spawn(["turbo", "login"]).exited;
await setupRemoteCache();
return;
}
if (error.includes("IO error")) {
await setupRemoteCache(true);
return;
}
}
}
console.log("Turbo remote cache configured");
}
import { beforeEach, describe, expect, test, vi } from "vitest";
const mockSpawn = vi.fn().mockReturnValue({
exited: Promise.resolve(0),
stderr: new Blob([""]),
});
const mockFile = vi.fn().mockReturnValue({
exists: () => Promise.resolve(false),
json: () => Promise.resolve({}),
});
vi.mock("bun", () => ({
spawn: (...args: unknown[]) => mockSpawn(...args),
file: (...args: unknown[]) => mockFile(...args),
}));
const { installDependencies, installGitHooks, setupRemoteCache } = await import("./setup");
function spawnReturns(exitCode: number, stderr = "") {
return mockSpawn.mockReturnValue({
exited: Promise.resolve(exitCode),
stderr: new Blob([stderr]),
});
}
function configReturns(exists: boolean, json: Record<string, unknown> = {}) {
mockFile.mockReturnValue({
exists: () => Promise.resolve(exists),
json: () => Promise.resolve(json),
});
}
beforeEach(() => {
mockSpawn.mockClear();
mockFile.mockClear();
spawnReturns(0);
configReturns(false);
});
describe("installDependencies", () => {
test("runs bun install", async () => {
await installDependencies();
expect(mockSpawn).toHaveBeenCalledWith(["bun", "install"]);
});
});
describe("installGitHooks", () => {
test("runs bunx simple-git-hooks", async () => {
await installGitHooks();
expect(mockSpawn).toHaveBeenCalledWith(["bunx", "simple-git-hooks"]);
});
});
describe("setupRemoteCache", () => {
test("skips linking when config already has teamId", async () => {
configReturns(true, { teamId: "team_123" });
mockSpawn.mockClear();
await setupRemoteCache();
expect(mockSpawn).not.toHaveBeenCalledWith(["turbo", "link"], expect.anything());
});
test("runs turbo link with piped stdio on first attempt", async () => {
await setupRemoteCache();
expect(mockSpawn).toHaveBeenCalledWith(["turbo", "link"], {
stdio: ["pipe", "pipe", "pipe"],
});
});
test("runs turbo login then retries on 'User not found' error", async () => {
mockSpawn
.mockReturnValueOnce({
exited: Promise.resolve(1),
stderr: new Blob(["User not found"]),
})
.mockReturnValueOnce({ exited: Promise.resolve(0) })
.mockReturnValueOnce({ exited: Promise.resolve(0) });
configReturns(false);
await setupRemoteCache();
expect(mockSpawn).toHaveBeenCalledWith(["turbo", "login"]);
});
test("retries with inherited stdio on 'IO error'", async () => {
mockSpawn
.mockReturnValueOnce({
exited: Promise.resolve(1),
stderr: new Blob(["IO error"]),
})
.mockReturnValueOnce({ exited: Promise.resolve(0) });
await setupRemoteCache();
expect(mockSpawn).toHaveBeenCalledWith(["turbo", "link"], {
stdio: ["inherit", "inherit", "inherit"],
});
});
});
setup:
bun run scripts/setup.ts
validate:
bun run turbo validate
{
"$schema": "https://turbo.build/schema.json",
"tasks": {
"lint": {},
"types": {},
"test": {},
"unused": {},
"validate": {
"dependsOn": ["lint", "types", "test", "unused"]
}
}
}
{
"compilerOptions": {
"allowImportingTsExtensions": true,
"allowJs": true,
"allowSyntheticDefaultImports": true,
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"incremental": true,
"isolatedModules": true,
"lib": ["esnext"],
"module": "esnext",
"moduleDetection": "force",
"moduleResolution": "bundler",
"noEmit": true,
"noUncheckedIndexedAccess": true,
"noUncheckedSideEffectImports": true,
"skipLibCheck": true,
"strict": true,
"target": "esnext",
"verbatimModuleSyntax": false
},
"exclude": ["node_modules"],
"include": ["**/*.ts"]
}
{
"$schema": "node_modules/@biomejs/biome/configuration_schema.json",
"extends": ["ultracite/core"],
"formatter": {
"lineWidth": 100
},
"linter": {
"rules": {
"correctness": {
"noUnusedImports": "warn"
}
}
}
}
# base
*.local*
*.tsbuildinfo
.DS_Store
.turbo
node_modules
name: CI
on:
push:
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
check:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Bun
uses: oven-sh/setup-bun@v1
- name: Cache Bun dependencies
uses: actions/cache@v4
with:
path: ~/.bun/install/cache
key: ${{ runner.os }}-bun-${{ hashFiles('**/bun.lock') }}
restore-keys: |
${{ runner.os }}-bun-
- name: Install dependencies
run: bun install
- name: Validate
run: make validate
env:
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
TURBO_TEAM: ${{ vars.TURBO_TEAM }}
import { defineConfig } from "vitest/config";
export default defineConfig({
test: {
projects: [
{
extends: true,
test: {
name: "unit",
include: ["**/*.test.ts"],
environment: "node",
},
},
],
},
});
# <project-name>
<project-description>
## Tech Stack
- **Package manager:** Bun
- **Testing:** Vitest
## Conventions
<!-- Add project-specific conventions here as the codebase evolves -->
Then create a symlink so tools that look for CLAUDE.md find the same file:
ln -s AGENTS.md CLAUDE.md
# <project-name>
<project-description>
## Development
1. Clone this repo
2. Run `make setup`
## License
[MIT](LICENSE)
files:
- path: AGENTS.md
update_when:
- When changes in package.json alter the tech stack (not minor version bumps)
- When new learnings from a task would benefit future agents (conventions, corrections to avoid repeating mistakes)
package.json with correct name, scripts, simple-git-hooks, and knip config@biomejs/biome, @types/bun, @typescript/native-preview, knip, simple-git-hooks, taze, turbo, ultracite, vitest)Makefile with setup and validate commandsscripts/setup.ts with install, git hooks, and remote cache setupscripts/setup.test.ts with tests for setup functionsturbo.json with lint, types, test, unused, and validate taskstsconfig.jsonbiome.jsonc with ultracite preset.gitignore.github/workflows/ci.ymlvitest.config.tsAGENTS.md with tech stack, commands, and conventionsCLAUDE.md symlink to AGENTS.mdREADME.md.agents/commit.config.yml with AGENTS.md trackedPlans development tasks through codebase exploration, exhaustive user interviews, and structured file-based plans. Use when tackling a feature, bug fix, refactor, or any task that benefits from upfront planning. Generates plan files in .agents/plans/ for later execution with /execute-plan.
Executes a plan generated by /create-plan. Orchestrates team members in parallel, each working in isolated worktrees. Use when ready to execute a plan from .agents/plans/, resume an interrupted execution, or run a specific plan by ID.
Plans and executes development tasks through codebase exploration, user interviews, and coordinated teammates. Use when tackling a feature, bug fix, refactor, or any task that benefits from upfront planning and parallel execution.
Builds type-safe, accessible forms with TanStack Form, Base UI Field, and the useAppForm hook. Use when creating forms, adding validation, handling form submission, or working with form fields and form state management.
Provides instructions for the Better Auth admin plugin in Convex projects. Use when adding admin capabilities, user management, role-based access control, banning users, managing sessions, impersonation, or custom permissions.
Provides instructions for the Better Auth email OTP plugin in Convex projects. Use when adding passwordless sign-in, email OTP authentication, one-time codes, email verification, or OTP-based password reset.