Getting Started
Prerequisites
- Node.js 20+ (ES2022 target, ESM-only)
- npm (ships with Node.js)
Optional, depending on your database provider:
better-sqlite3requires a C++ build toolchain (node-gyp) for SQLitepgfor PostgreSQLmysql2for 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 devYour 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.
| Template | Description |
|---|---|
blank | Minimal project with a health check API and home page |
tickets | Full-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
.gitignoreFile Naming Conventions
Capstan uses file suffixes and special prefixes to determine how each file is treated:
| Pattern | Purpose |
|---|---|
*.api.ts | API route handler |
*.page.tsx | React page component (SSR) |
_layout.tsx | Layout wrapper (nests via Outlet) |
_middleware.ts | Middleware (runs before handlers) |
_loading.tsx | Suspense fallback for pages |
_error.tsx | Error boundary for pages |
[param].api.ts | Dynamic route segment |
[...catchAll].api.ts | Catch-all route segment |
Dev Server
npx capstan devThe 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 4000Your 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:
| Endpoint | Protocol | Description |
|---|---|---|
GET /.well-known/capstan.json | Capstan | Agent manifest describing all routes, schemas, capabilities, and policies |
GET /openapi.json | OpenAPI | Full OpenAPI 3.1.0 specification generated from your defineAPI() definitions |
GET /.well-known/agent.json | A2A | Google Agent-to-Agent protocol agent card listing all skills |
POST /.well-known/a2a | A2A | JSON-RPC endpoint for A2A protocol (tasks/send, tasks/get, agent/card) |
npx capstan mcp | MCP | Starts 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 denyCLI Commands
| Command | Description |
|---|---|
capstan dev | Start development server with hot reload |
capstan build | Build for production |
capstan start | Start production server |
capstan mcp | Start MCP server over stdio |
capstan verify | Run the verification cascade |
capstan db:migrate | Generate a new migration from model changes |
capstan db:push | Apply pending migrations directly |
capstan db:status | Show 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 |
<Link> from @zauso-ai/capstan-react/client instead of plain <a> tags for client-side navigation with automatic prefetching and SPA transitions.