---
name: butterbase-ai/contributing
source: https://app.decimal.ai/s/butterbase-ai-contributing@1/SKILL.md
source_sha256: 3c7d959cae91
---

## 1. Overview

Contributor guide for the Butterbase monorepo. Covers architecture, how to add MCP tools, API routes, database migrations, and coding conventions.

---

## 2. Monorepo Map

| Directory | Package | Purpose |
|-----------|---------|---------|
| `packages/cli` | `@butterbase/cli` (v0.1.3) | Published CLI tool (Commander.js). Commands: init, apps, schema, functions, storage, deploy, data, env, keys, realtime, status, open |
| `packages/sdk` | `@butterbase/sdk` (v1.2.1) | Published TypeScript SDK. Modules: auth, storage, functions, AI, billing, realtime, admin |
| `packages/shared` | `@butterbase/shared` | Internal shared types, constants, schema DSL, error types |
| `packages/plugin` | `@butterbase/plugin` | Claude Code plugin (this package — skills for AI agents) |
| `services/control-api` | `@butterbase/control-api` | Fastify API server — the brain. Routes, plugins, services. Port 4000 |
| `services/mcp-server` | `@butterbase/mcp-server` | MCP server with ~28 tools (consolidated `manage_*` action-based tools + a few standalone ones like `init_app`, `deploy_function`, `select_rows`). Runs via stdio or HTTP (served by control-api at `/mcp`) |
| `services/deno-runtime` | — | Serverless function executor. Deno-based worker isolation. Port 7133 |
| `services/cron-scheduler` | `@butterbase/cron-scheduler` | Cron job runner using node-cron + cron-parser |
| `services/dashboard` | — | React management UI (Vite + Radix UI) |
| `services/dashboard-api` | — | Dashboard backend proxy. Port 4100 |
| `services/docs` | `@butterbase/docs` | Astro/Starlight documentation site |
| `services/storage-indexer` | — | Cloudflare Worker for S3 event indexing |
| `db/control-plane` | — | SQL migrations (sequential numbering, `001_` upward). Control plane database schema |
| `db/data-plane` | — | Per-app database initialization scripts |

---

## 3. Adding a New MCP Tool (4 Steps)

### Step 1: Create tool file at `services/mcp-server/src/tools/my-new-tool.ts`

Decide whether the new capability is a standalone tool (single, self-contained operation like `init_app`) or another action on an existing umbrella tool (`manage_schema`, `manage_function`, etc). Most new operations should be added as actions on an existing `manage_*` tool — this keeps the surface area small for AI agents.

For a brand-new standalone tool, follow the pattern from `init-app.ts`:

```typescript
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import { z } from 'zod';
import { apiPost } from '../api-client.js';

interface MyResponse {
  // response shape
}

export function registerMyNewTool(server: McpServer) {
  server.tool(
    'my_new_tool',      // snake_case name
    `Tool description.   // Multi-line description with examples

Example:
  Input: { ... }
  Output: { ... }

Common errors:
  - ERROR_CODE: Description`,
    {
      // Zod schema for parameters
      app_id: z.string().describe('The app ID'),
      param: z.string().describe('Parameter description'),
    },
    async ({ app_id, param }) => {
      const result = await apiPost<MyResponse>(`/v1/${app_id}/my-endpoint`, { param });
      return {
        content: [{
          type: 'text' as const,
          text: JSON.stringify(result, null, 2),
        }],
      };
    }
  );
}
```

API client functions available: `apiGet`, `apiPost`, `apiPatch`, `apiDelete` (from `../api-client.js`).

### Step 2: Register in `services/mcp-server/src/create-server.ts`

```typescript
import { registerMyNewTool } from './tools/my-new-tool.js';
// ...
registerMyNewTool(server);
```

### Step 3: Create the backing API route in `services/control-api/src/routes/`

- Fastify route handler matching the endpoint your tool calls
- Register in `services/control-api/src/index.ts`

### Step 4: Update documentation in `services/mcp-server/src/docs/user-documentation.ts`

- Add tool to the relevant section's table in the `SECTIONS` object

---

## 4. Adding a Database Migration

- **IMPORTANT**: Use `scripts/migrate.ts` or `scripts/backfill-migrations.ts`, NEVER raw `psql`
- Migration files: `db/control-plane/NNN_description.sql` (sequential numbering, starting at `001_initial_schema.sql`)
- Pick the next free three-digit prefix; never edit a committed migration
- Run migrations: `npx tsx scripts/migrate.ts`

---

## 5. Coding Conventions

| Convention | Example |
|-----------|---------|
| MCP tool names | `snake_case`. Two flavours: standalone (`init_app`, `deploy_function`, `select_rows`) and `manage_*` umbrella tools that take an `action` enum (`manage_schema`, `manage_rls`, `manage_function`, `manage_frontend`, etc.) |
| App IDs | `app_` prefix: `app_abc123` |
| Service keys | `bb_sk_` prefix: `bb_sk_a1b2c3...` |
| Environment variables | `BUTTERBASE_` prefix: `BUTTERBASE_API_KEY` |
| Response metadata | `_meta.next_actions` (suggested next tool calls), `_meta.resource_info` (quota/state) |
| Error codes | `UPPERCASE_WITH_UNDERSCORES`: `AUTH_RLS_POLICY_VIOLATION`, `QUOTA_TABLE_LIMIT` |
| Domain | `butterbase.ai` (never "nira") |

---

## 6. Running Locally

```bash
docker-compose -f docker-compose.local.yml up
```

| Service | Port | URL |
|---------|------|-----|
| Control API | 4000 | `http://localhost:4000` |
| Dashboard API | 4100 | `http://localhost:4100` |
| Deno Runtime | 7133 | `http://localhost:7133` |
| Control Plane DB | 5433 | `postgres://localhost:5433` |
| Data Plane DB | 5435 | `postgres://localhost:5435` |
| PgBouncer | 6432 | `postgres://localhost:6432` |
| LocalStack (S3) | 4566 | `http://localhost:4566` |

---

## 7. Testing

- Framework: Vitest
- Run tests per workspace: `cd services/control-api && npm test`
- Test files: `__tests__/` directory or co-located `*.test.ts`
- Build all workspaces: `npm run build` (from repo root)
- Type check: `npx tsc --noEmit` in each workspace