project-scaffold

Generate project boilerplate from scaffold templates. Use when creating a new project after stack selection. Triggers on: scaffold project, generate boilerplate, create from template.

16 stars

Best use case

project-scaffold is best used when you need a repeatable AI agent workflow instead of a one-off prompt.

Generate project boilerplate from scaffold templates. Use when creating a new project after stack selection. Triggers on: scaffold project, generate boilerplate, create from template.

Teams using project-scaffold should expect a more consistent output, faster repeated execution, less prompt rewriting.

When to use this skill

  • You want a reusable workflow that can be run more than once with consistent structure.

When not to use this skill

  • You only need a quick one-off answer and do not need a reusable workflow.
  • You cannot install or maintain the underlying files, dependencies, or repository context.

Installation

Claude Code / Cursor / Codex

$curl -o ~/.claude/skills/project-scaffold/SKILL.md --create-dirs "https://raw.githubusercontent.com/diegosouzapw/awesome-omni-skill/main/skills/tools/project-scaffold/SKILL.md"

Manual Installation

  1. Download SKILL.md from GitHub
  2. Place it in .claude/skills/project-scaffold/SKILL.md inside your project
  3. Restart your AI agent — it will auto-discover the skill

How project-scaffold Compares

Feature / Agentproject-scaffoldStandard Approach
Platform SupportNot specifiedLimited / Varies
Context Awareness High Baseline
Installation ComplexityUnknownN/A

Frequently Asked Questions

What does this skill do?

Generate project boilerplate from scaffold templates. Use when creating a new project after stack selection. Triggers on: scaffold project, generate boilerplate, create from template.

Where can I find the source code?

You can find the source code on GitHub using the link provided at the top of the page.

SKILL.md Source

# Project Scaffold Skill

> ⛔ **CRITICAL: Initial scaffold commit respects user preference**
>
> **Trigger:** Before running `git commit` for initial scaffold.
>
> **Check:** Ask user before committing: "Create initial commit? [Y/n]"
> - If user confirms or default: Proceed with `git commit -m "Initial scaffold"`
> - If user declines: **Stop after `git add .`** — do not commit
>
> **Note:** New projects don't have `project.json` yet, so we ask the user directly.
> After scaffolding, if the user sets `git.autoCommit: false` in `project.json`,
> all future agent commits will require manual confirmation.

Generate project boilerplate based on selected stack archetype. This skill is invoked by `project-bootstrap` after stack selection.

---

## Prerequisites

This skill expects:
1. **StackDecision** — The selected stack from stack-advisor (or manual selection)
2. **Project path** — Where to generate files
3. **Project name** — Used for package.json, go.mod, etc.
4. **RequirementsManifest** (optional) — For entity-based schema generation

---

## Scaffold Selection

Match the selected stack to available scaffolds:

| Stack Archetype | Scaffold |
|-----------------|----------|
| `nextjs-supabase` | `~/.config/opencode/scaffolds/nextjs-supabase/` |
| `nextjs-prisma` | `~/.config/opencode/scaffolds/nextjs-prisma/` |
| `go-chi-postgres` | `~/.config/opencode/scaffolds/go-chi-postgres/` |
| `remix-supabase` | `~/.config/opencode/scaffolds/nextjs-supabase/` (adapt) |
| `python-fastapi` | `~/.config/opencode/scaffolds/python-fastapi/` |

If no exact scaffold match exists, use the closest archetype and adapt.

---

## Step 1: Load Scaffold Configuration

Read `scaffold.yaml` from the selected scaffold directory:

```bash
cat ~/.config/opencode/scaffolds/<scaffold-name>/scaffold.yaml
```

The configuration defines:
- `variables` — User prompts for customization
- `dependencies` — npm/go/pip packages to install
- `conditionalDependencies` — Feature-based additions
- `structure` — Directory tree to create
- `files` — Templates to render
- `postScaffold` — Commands to run after generation

---

## Step 2: Collect Variables

For each variable in `scaffold.yaml`, use defaults from context or prompt user:

```yaml
variables:
  - name: projectName
    prompt: "Project name"
    transform: kebab-case
    source: context.projectName  # Auto-fill from bootstrap context
  
  - name: description
    prompt: "Project description"
    source: context.description
  
  - name: supabaseProjectId
    prompt: "Supabase project ID (or 'local' for local dev)"
    default: local
```

**Auto-fill priority:**
1. Context from project-bootstrap (projectName, description, features)
2. Defaults from scaffold.yaml
3. Prompt user if neither available

---

## Step 3: Create Directory Structure

Create all directories defined in `structure`:

```bash
mkdir -p <project-path>/src/app
mkdir -p <project-path>/src/components/ui
mkdir -p <project-path>/src/hooks
mkdir -p <project-path>/src/lib/supabase
mkdir -p <project-path>/supabase/migrations
mkdir -p <project-path>/docs
```

---

## Step 4: Render Template Files

For each file in the scaffold's `files/` directory:

### 4.1 Identify Template Type

| Extension | Processing |
|-----------|------------|
| `.hbs` | Render with Handlebars, remove `.hbs` from output |
| `.template` | Render with Handlebars, remove `.template` from output |
| (no special extension) | Copy as-is |

### 4.2 Build Template Context

```javascript
const context = {
  // From bootstrap/stack-advisor
  projectName: 'my-project',
  projectNamePascal: 'MyProject',
  projectNameCamel: 'myProject',
  description: 'A scheduling app',
  
  // From StackDecision
  stack: {
    frontend: { framework: 'nextjs', version: '15' },
    database: { provider: 'supabase', type: 'postgres' },
    styling: { framework: 'tailwind', version: '4' },
    auth: { provider: 'supabase' }
  },
  
  // From RequirementsManifest (if available)
  features: {
    authentication: true,
    multiTenant: true,
    payments: true,
    email: false,
    ai: false
  },
  
  // Entities for schema generation
  entities: [
    { name: 'Organization', description: 'Tenant/workspace' },
    { name: 'Project', description: 'Work container' },
    { name: 'Task', description: 'Individual work item' }
  ],
  
  // Computed helpers
  hasPayments: capabilities.payments,
  hasEmail: capabilities.email,
  hasAI: capabilities.ai,
  hasMultiTenant: capabilities.multiTenant,
  
  // Date/time
  year: '2026',
  date: '2026-02-19'
};
```

### 4.3 Render Each File

```javascript
for (const file of scaffoldConfig.files) {
  const templatePath = `${scaffoldDir}/files/${file.template}`;
  const outputPath = `${projectPath}/${file.output}`;
  
  if (file.template.endsWith('.hbs')) {
    const template = readFile(templatePath);
    const rendered = handlebars.compile(template)(context);
    writeFile(outputPath, rendered);
  } else {
    copyFile(templatePath, outputPath);
  }
}
```

---

## Step 5: Generate Database Schema (If Entities Provided)

If `RequirementsManifest.entities` exists, generate initial migration:

### 5.1 For Supabase

Generate `supabase/migrations/00001_initial_schema.sql`:

```sql
-- Generated from spec entities
-- {{date}}

-- Organizations (multi-tenant core)
{{#if hasMultiTenant}}
CREATE TABLE organizations (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  name TEXT NOT NULL,
  slug TEXT UNIQUE NOT NULL,
  created_at TIMESTAMPTZ DEFAULT NOW(),
  updated_at TIMESTAMPTZ DEFAULT NOW()
);

CREATE TABLE organization_members (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  organization_id UUID REFERENCES organizations(id) ON DELETE CASCADE,
  user_id UUID REFERENCES auth.users(id) ON DELETE CASCADE,
  role TEXT NOT NULL DEFAULT 'member',
  created_at TIMESTAMPTZ DEFAULT NOW(),
  UNIQUE(organization_id, user_id)
);

ALTER TABLE organizations ENABLE ROW LEVEL SECURITY;
ALTER TABLE organization_members ENABLE ROW LEVEL SECURITY;

CREATE POLICY "org_member_select" ON organizations
  FOR SELECT USING (
    id IN (SELECT organization_id FROM organization_members WHERE user_id = auth.uid())
  );

CREATE POLICY "org_member_select" ON organization_members
  FOR SELECT USING (user_id = auth.uid());
{{/if}}

-- Entity tables
{{#each entities}}
{{#unless (isBuiltIn name)}}
CREATE TABLE {{snakeCase name}}s (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  {{#if ../hasMultiTenant}}
  organization_id UUID REFERENCES organizations(id) ON DELETE CASCADE,
  {{/if}}
  name TEXT NOT NULL,
  -- TODO: Add fields for {{description}}
  created_at TIMESTAMPTZ DEFAULT NOW(),
  updated_at TIMESTAMPTZ DEFAULT NOW()
);

ALTER TABLE {{snakeCase name}}s ENABLE ROW LEVEL SECURITY;

{{#if ../hasMultiTenant}}
CREATE POLICY "{{snakeCase name}}_org_access" ON {{snakeCase name}}s
  FOR ALL USING (
    organization_id IN (
      SELECT organization_id FROM organization_members WHERE user_id = auth.uid()
    )
  );
{{/if}}

{{/unless}}
{{/each}}
```

### 5.2 For Prisma

Generate `prisma/schema.prisma`:

```prisma
generator client {
  provider = "prisma-client-js"
}

datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")
}

model User {
  id        String   @id @default(cuid())
  email     String   @unique
  name      String?
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
  {{#if hasMultiTenant}}
  memberships OrganizationMember[]
  {{/if}}
}

{{#if hasMultiTenant}}
model Organization {
  id        String   @id @default(cuid())
  name      String
  slug      String   @unique
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
  members   OrganizationMember[]
  {{#each entities}}
  {{#unless (isBuiltIn name)}}
  {{camelCase name}}s {{pascalCase name}}[]
  {{/unless}}
  {{/each}}
}

model OrganizationMember {
  id             String       @id @default(cuid())
  organization   Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
  organizationId String
  user           User         @relation(fields: [userId], references: [id], onDelete: Cascade)
  userId         String
  role           String       @default("member")
  createdAt      DateTime     @default(now())

  @@unique([organizationId, userId])
}
{{/if}}

{{#each entities}}
{{#unless (isBuiltIn name)}}
model {{pascalCase name}} {
  id        String   @id @default(cuid())
  {{#if ../hasMultiTenant}}
  organization   Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
  organizationId String
  {{/if}}
  name      String
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
}
{{/unless}}
{{/each}}
```

---

## Step 6: Resolve Dependencies

### 6.1 Merge Dependencies

Combine base dependencies with conditional dependencies:

```javascript
const allDeps = [...scaffoldConfig.dependencies.production];
const allDevDeps = [...scaffoldConfig.dependencies.development];

for (const cond of scaffoldConfig.conditionalDependencies) {
  if (evaluateCondition(cond.if, context)) {
    allDeps.push(...cond.add);
  }
}
```

### 6.2 For Node.js Projects

Generate or update `package.json`:

```json
{
  "name": "{{projectName}}",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "dev": "next dev --turbopack",
    "build": "next build",
    "start": "next start",
    "lint": "next lint",
    "typecheck": "tsc --noEmit",
    "test": "jest",
    "test:e2e": "playwright test"
  },
  "dependencies": {
    {{#each dependencies}}
    "{{name}}": "{{version}}"{{#unless @last}},{{/unless}}
    {{/each}}
  },
  "devDependencies": {
    {{#each devDependencies}}
    "{{name}}": "{{version}}"{{#unless @last}},{{/unless}}
    {{/each}}
  }
}
```

### 6.3 For Go Projects

Generate `go.mod`:

```go
module {{projectName}}

go 1.23

require (
    github.com/go-chi/chi/v5 v5.0.12
    github.com/jackc/pgx/v5 v5.5.5
    {{#if hasAuth}}
    github.com/golang-jwt/jwt/v5 v5.2.1
    {{/if}}
)
```

---

## Step 7: Generate Environment Files

### 7.1 Create `.env.example`

```env
# Database
{{#if (eq stack.database.provider 'supabase')}}
NEXT_PUBLIC_SUPABASE_URL=https://your-project.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=your-anon-key
SUPABASE_SERVICE_ROLE_KEY=your-service-role-key
{{else}}
DATABASE_URL=postgresql://user:password@localhost:5432/{{projectName}}
{{/if}}

{{#if hasPayments}}
# Stripe
STRIPE_SECRET_KEY=sk_test_xxx
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=pk_test_xxx
STRIPE_WEBHOOK_SECRET=whsec_xxx
{{/if}}

{{#if hasEmail}}
# Email
RESEND_API_KEY=re_xxx
{{/if}}

{{#if hasAI}}
# AI
OPENAI_API_KEY=sk-xxx
{{/if}}

# App
NEXT_PUBLIC_APP_URL=http://localhost:3000
```

### 7.2 Create `.env.local` (gitignored)

Copy `.env.example` to `.env.local` for immediate local development.

---

## Step 8: Generate Documentation Stubs

### 8.1 Create `docs/project.json`

This is handled by project-bootstrap, but scaffold ensures the structure:

```json
{
  "$schema": "https://opencode.ai/schemas/project.json",
  "name": "{{projectName}}",
  "description": "{{description}}",
  "stack": { /* from StackDecision */ },
  "features": { /* from context */ }
}
```

### 8.2 Create `AGENTS.md`

```markdown
# {{projectNamePascal}}

{{description}}

## Development

\`\`\`bash
npm run dev     # Start dev server (port 3000)
npm run build   # Production build
npm run test    # Run tests
\`\`\`

## Stack

- **Frontend:** Next.js 15 (App Router)
- **Database:** {{stack.database.provider}}
- **Styling:** Tailwind CSS v4
- **Auth:** {{stack.auth.provider}}

## Documentation

- [Architecture](docs/ARCHITECTURE.md)
- [Conventions](docs/CONVENTIONS.md)
```

---

## Step 9: Run Post-Scaffold Commands

Execute commands defined in `postScaffold`:

```yaml
postScaffold:
  - command: npm install
    workdir: .
  - command: npx supabase init
    condition: stack.database.provider == 'supabase'
  - command: git init
  - command: git add .
  - command: git commit -m "Initial scaffold from {{scaffoldName}}"
    requiresConfirmation: true
    confirmationPrompt: "Create initial commit? [Y/n]"
```

**Execution:**

```bash
cd <project-path>

# Install dependencies
npm install

# Initialize Supabase (if applicable)
npx supabase init --workdir .

# Initialize git
git init
git add .

# Ask user before committing (requiresConfirmation: true)
# If user confirms: git commit -m "Initial scaffold from nextjs-supabase"
# If user declines: skip commit, files remain staged
```

**Handling `requiresConfirmation`:**

When a postScaffold command has `requiresConfirmation: true`:
1. Display the `confirmationPrompt` to the user
2. If user confirms (Y/Enter): execute the command
3. If user declines (n): skip the command, continue with next step
4. Report which commands were skipped

---

## Step 10: Summary Output

Report what was generated:

```
═══════════════════════════════════════════════════════════════════════
                      SCAFFOLD COMPLETE
═══════════════════════════════════════════════════════════════════════

✅ Created project: /Users/dev/code/my-project

📁 Directory structure:
   src/
   ├── app/           Next.js App Router
   ├── components/    React components
   ├── hooks/         Custom hooks
   └── lib/           Utilities + Supabase clients
   supabase/
   └── migrations/    Database migrations
   docs/              Documentation

📦 Dependencies installed:
   • next@15, react@19, react-dom@19
   • @supabase/supabase-js, @supabase/ssr
   • tailwindcss@4, clsx, tailwind-merge
   • stripe, @stripe/stripe-js (payments feature)

🗃️ Database schema generated:
   • organizations (multi-tenant)
   • organization_members
   • projects (from spec)
   • tasks (from spec)

📝 Files created:
   • package.json
   • tsconfig.json
   • next.config.ts
   • tailwind.config.ts
   • src/app/layout.tsx
   • src/app/page.tsx
   • src/lib/supabase/client.ts
   • src/lib/supabase/server.ts
   • supabase/migrations/00001_initial_schema.sql
   • .env.example
   • .env.local
   • AGENTS.md

🚀 Next steps:
   1. cd /Users/dev/code/my-project
   2. Update .env.local with your Supabase credentials
   3. Run `npm run dev` to start development
   4. Review docs/drafts/prd-mvp.md for your user stories

═══════════════════════════════════════════════════════════════════════
```

---

## Handlebars Helpers

The scaffold system provides these custom helpers:

| Helper | Description | Example |
|--------|-------------|---------|
| `kebabCase` | Convert to kebab-case | `{{kebabCase projectName}}` → `my-project` |
| `camelCase` | Convert to camelCase | `{{camelCase name}}` → `myProject` |
| `pascalCase` | Convert to PascalCase | `{{pascalCase name}}` → `MyProject` |
| `snakeCase` | Convert to snake_case | `{{snakeCase name}}` → `my_project` |
| `upperCase` | Convert to UPPER_CASE | `{{upperCase name}}` → `MY_PROJECT` |
| `eq` | Equality check | `{{#if (eq type 'supabase')}}` |
| `isBuiltIn` | Check if entity is built-in | `{{#unless (isBuiltIn name)}}` |

**Built-in entities** (skipped in schema generation):
- User
- Organization
- OrganizationMember

---

## Error Handling

### Scaffold Not Found

```
❌ No scaffold found for archetype: django-postgres

Available scaffolds:
  • nextjs-supabase
  • nextjs-prisma
  • go-chi-postgres

Would you like to:
  A. Use closest match (nextjs-prisma) and adapt
  B. Generate minimal structure only
  C. Cancel

> _
```

### Missing Variables

```
⚠️ Missing required variable: supabaseProjectId

Enter Supabase project ID (or 'local' for local dev):
> _
```

### Post-Scaffold Command Failed

```
⚠️ Post-scaffold command failed: npm install

Error: ENOENT: npm not found

The scaffold is complete but dependencies were not installed.
Run manually: cd /path/to/project && npm install
```

---

## Output

Return the scaffold result to the calling agent:

```json
{
  "success": true,
  "projectPath": "/Users/dev/code/my-project",
  "scaffold": "nextjs-supabase",
  "filesCreated": [
    "package.json",
    "tsconfig.json",
    "src/app/layout.tsx",
    "..."
  ],
  "dependenciesInstalled": true,
  "gitInitialized": true,
  "schemaGenerated": true,
  "entities": ["Organization", "Project", "Task"]
}
```

Related Skills

when-managing-github-projects-use-github-project-management

16
from diegosouzapw/awesome-omni-skill

Comprehensive GitHub project management with swarm-coordinated issue tracking, project board automation, and sprint planning. Coordinates planner, issue-tracker, and project-board-sync agents to automate issue triage, sprint planning, milestone tracking, and project board updates. Integrates with GitHub Projects v2 API for advanced automation, custom fields, and workflow orchestration. Use when managing development projects, coordinating team workflows, or automating project management tasks.

surface-theme-scaffold-gen

16
from diegosouzapw/awesome-omni-skill

Generate Clef Surface design system theme scaffolds including palette configuration , typography scale , motion definitions , elevation scale , and light dark theme manifests Follows WCAG accessibility guidelines for contrast ratios

stl-cube-scaffold

16
from diegosouzapw/awesome-omni-skill

Analyze an STL mesh (AABB + approximate OBB) and generate a single connected STL that includes an L×L×L cube scaffold (default 100mm) plus connectors, so the final solid's OBB is locked to the target cube size for packing/measurement checks.

skills-scaffolding

16
from diegosouzapw/awesome-omni-skill

Guide for creating effective Claude Code skills. This skill should be used when users want to create a new skill (or update an existing skill) that extends Claude's capabilities with specialized knowledge, workflows, or tool integrations.

scaffold-project

16
from diegosouzapw/awesome-omni-skill

Bootstrap or review project-level context primitives for Claude Code. First run creates .claude/primitives/ and .claude/skills/project-context/. Re-runs review existing primitives against the codebase, auto-update what changed, and flag what's stale. Invoke with '/scaffold-project' or say 'scaffold project', 'set up project context', 'review project context'.

projections

16
from diegosouzapw/awesome-omni-skill

Build or query TES projections (current state views). State is derived from TES events - projections are the queryable current truth.

projection-patterns

16
from diegosouzapw/awesome-omni-skill

Build read models and projections from event streams. Use when implementing CQRS read sides, building materialized views, or optimizing query performance in event-sourced systems.

project-discovery

16
from diegosouzapw/awesome-omni-skill

Systematic project orientation for unfamiliar codebases. Automatically activates when Claude detects uncertainty about project state, structure, or tooling. Analyzes git state (branch, changes, commits), project type (language, framework, structure), and development tooling (build, test, lint, CI/CD). Provides structured summary with risk flags and recommendations. Use when entering new projects or when working on shaky assumptions.

project-conventions

16
from diegosouzapw/awesome-omni-skill

This skill should be used when creating or editing .csproj files, managing NuGet packages, configuring Directory.Build.props or Directory.Packages.props, organizing .NET solutions, or setting up global.json and .editorconfig.

project-concept-funnel

16
from diegosouzapw/awesome-omni-skill

Use when evaluating project ideas, deciding which projects to pursue, filtering multiple ideas down to one, or when user is stuck between project options

project-bubble-automation

16
from diegosouzapw/awesome-omni-skill

Automate Project Bubble tasks via Rube MCP (Composio). Always search tools first for current schemas.

project-aeo-monitoring-tools

16
from diegosouzapw/awesome-omni-skill

Build custom AI search monitoring tools for competitive AEO analysis. Covers API access, scraping architecture, legal compliance, and cost estimation.