Getting Started

Prerequisites

  • Node.js 20+ (ES2022 target, ESM-only)
  • npm (ships with Node.js)

Optional, depending on your database provider:

  • better-sqlite3 requires a C++ build toolchain (node-gyp) for SQLite
  • pg for PostgreSQL
  • mysql2 for MySQL

Quick Start

Capstan is currently published on npm's beta tag. Scaffold a new project with:

npx create-capstan-app@beta my-app --template blank
cd my-app
npm install
npx capstan dev

Your dev server is now running at http://localhost:3000.

Templates

The create-capstan-app scaffolder supports two templates. You can also run the scaffolder interactively (no arguments) and it will prompt for a project name and template.

TemplateDescription
blankMinimal project with a health check API and home page
ticketsFull-featured example with a Ticket model, CRUD API routes, and auth policy

Project Structure

After scaffolding, your project looks like this:

my-app/
  app/
    routes/
      _layout.tsx          # Root layout (wraps all pages)
      index.page.tsx       # Home page
      api/
        health.api.ts      # Health check endpoint
    models/                # Data model definitions
    styles/
      main.css             # CSS entry point (Lightning CSS or Tailwind)
    migrations/            # Database migration files
    policies/
      index.ts             # Permission policies (requireAuth)
  capstan.config.ts        # Framework configuration
  package.json
  tsconfig.json
  AGENTS.md                # AI coding agent guide
  .gitignore

File Naming Conventions

Capstan uses file suffixes and special prefixes to determine how each file is treated:

PatternPurpose
*.api.tsAPI route handler
*.page.tsxReact page component (SSR)
_layout.tsxLayout wrapper (nests via Outlet)
_middleware.tsMiddleware (runs before handlers)
_loading.tsxSuspense fallback for pages
_error.tsxError boundary for pages
[param].api.tsDynamic route segment
[...catchAll].api.tsCatch-all route segment

Dev Server

npx capstan dev

The dev server starts on http://localhost:3000 by default and provides:

  • Hot route reloading (file watcher rebuilds routes on change)
  • Live reload via SSE (browser pages refresh automatically)
  • Static file serving from app/public/
  • All multi-protocol agent endpoints (MCP, A2A, OpenAPI)

To use a different port:

npx capstan dev --port 4000

Your First API Endpoint

Create a file at app/routes/api/greet.api.ts:

import { defineAPI } from "@zauso-ai/capstan-core";
import { z } from "zod";

export const GET = defineAPI({
  input: z.object({
    name: z.string().optional(),
  }),
  output: z.object({
    message: z.string(),
  }),
  description: "Greet a user by name",
  capability: "read",
  async handler({ input }) {
    const name = input.name ?? "world";
    return { message: `Hello, ${name}!` };
  },
});

export const POST = defineAPI({
  input: z.object({
    name: z.string().min(1),
  }),
  output: z.object({
    message: z.string(),
    timestamp: z.string(),
  }),
  description: "Create a personalized greeting",
  capability: "write",
  policy: "requireAuth",
  async handler({ input }) {
    return {
      message: `Hello, ${input.name}!`,
      timestamp: new Date().toISOString(),
    };
  },
});

Each exported constant (GET, POST, PUT, DELETE, PATCH) maps to the corresponding HTTP method. The defineAPI() wrapper provides:

  • Input validation via Zod schemas (automatic 400 errors on invalid input)
  • Output validation via Zod schemas
  • Agent introspection -- the schema metadata is projected to MCP tools, A2A skills, and OpenAPI specs

Test your endpoint:

# GET request
curl http://localhost:3000/api/greet?name=Alice

# POST request
curl -X POST http://localhost:3000/api/greet \
  -H "Content-Type: application/json" \
  -d '{"name": "Alice"}'

Auto-Generated Agent Endpoints

Once your dev server is running, these endpoints are automatically available:

EndpointProtocolDescription
GET /.well-known/capstan.jsonCapstanAgent manifest describing all routes, schemas, capabilities, and policies
GET /openapi.jsonOpenAPIFull OpenAPI 3.1.0 specification generated from your defineAPI() definitions
GET /.well-known/agent.jsonA2AGoogle Agent-to-Agent protocol agent card listing all skills
POST /.well-known/a2aA2AJSON-RPC endpoint for A2A protocol (tasks/send, tasks/get, agent/card)
npx capstan mcpMCPStarts MCP server over stdio for Claude Desktop, Cursor, or any MCP client

Approval Workflow

When an API route's policy evaluates to "approve", the request is held for human review:

GET  /capstan/approvals        # List pending approvals
GET  /capstan/approvals/:id     # Get approval status
POST /capstan/approvals/:id     # Approve or deny

CLI Commands

CommandDescription
capstan devStart development server with hot reload
capstan buildBuild for production
capstan startStart production server
capstan mcpStart MCP server over stdio
capstan verifyRun the verification cascade
capstan db:migrateGenerate a new migration from model changes
capstan db:pushApply pending migrations directly
capstan db:statusShow migration status
capstan add api <name>Scaffold a new API route
capstan add page <name>Scaffold a new React page
capstan add model <name>Scaffold a new database model
capstan deploy:init --target <target>Generate deployment files for a target platform
Tip: Use <Link> from @zauso-ai/capstan-react/client instead of plain <a> tags for client-side navigation with automatic prefetching and SPA transitions.