Skip to main content
Glama
README.md
<p align="center">
  <a href="https://kamy.dev">
    <picture>
      <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/rakanalalami/kamy/main/apps/web/public/brand/logo-light.svg">
      <img alt="Kamy" src="https://raw.githubusercontent.com/rakanalalami/kamy/main/apps/web/public/brand/logo.svg" width="220">
    </picture>
  </a>
</p>

<p align="center">
  <a href="https://www.npmjs.com/package/@kamydev/sdk"><img alt="SDK on npm" src="https://img.shields.io/npm/v/@kamydev/sdk?label=%40kamydev%2Fsdk&color=1863dc"></a>
  <a href="https://www.npmjs.com/package/@kamydev/cli"><img alt="CLI on npm" src="https://img.shields.io/npm/v/@kamydev/cli?label=%40kamydev%2Fcli&color=1863dc"></a>
  <a href="https://github.com/rakanalalami/kamy/blob/main/LICENSE"><img alt="MIT License" src="https://img.shields.io/npm/l/@kamydev/sdk"></a>
</p>

> PDF generation API for developers. Ship invoices, receipts, contracts, and reports with gorgeous defaults.

## Install

```bash
# SDK — in your app
npm i @kamydev/sdk

# CLI — globally for scripts, CI, previews
npm i -g @kamydev/cli
```

```ts
import Kamy from "@kamydev/sdk";

const kamy = new Kamy({ apiKey: process.env.KAMY_API_KEY! });
const pdf = await kamy.render({
  template: "invoice",
  data: { invoiceNumber: "INV-001", total: 1500, currency: "USD" },
});
console.log(pdf.url); // signed URL, valid 1 hour
```

## What's New

| Date | Change |
|---|---|
| Apr 2026 | `GET /v1/renders` now returns a **per-render `cost`** (in major currency units) plus a top-level `currency: "usd"`. Denormalized at insert time via a Postgres trigger reading `users.plan`, so the cost reflects your plan when the render happened. Surfaced in SDK 0.2.3 as `RenderSummary.cost` / `RendersListResult.currency`. |
| Apr 2026 | SDK now ships **OpenAPI-generated types** — `import type { paths, components } from "@kamydev/sdk/openapi"` for fully-typed request/response shapes derived from the live spec. Raw `openapi.json` shipped too. |
| Apr 2026 | Per-template **JSON Schema validation** at render time via Ajv (formats enabled). Previously only `required` was checked — full type/format/enum/oneOf enforcement is now live. |
| Apr 2026 | `options.encrypt` — AES-256 password protection + permission flags (printing, copying, modifying, annotating, form-fill, accessibility, assembly). |
| Apr 2026 | OpenAPI 3.0.3 spec now covers all 19 `/v1/*` routes with full request/response schemas — `https://kamy.dev/api/openapi.json` |
| Apr 2026 | `kamy push <file>` CLI + `client.pushTemplate()` SDK + idempotent `PUT /v1/templates` upsert. Run it on every commit to sync templates from the repo. |
| Apr 2026 | `options.validateOnly: true` — dry-run any render to validate the payload without consuming quota. |
| Apr 2026 | `options.pdfA: "1b" \| "2b" \| "3b"` — best-effort PDF/A archival tagging via embedded sRGB ICC OutputIntent + XMP. |
| Apr 2026 | `options.metadata` (info dict) + `options.watermark` (pdf-lib stamp, distinct from `theme.watermark`). |
| Apr 2026 | `options.inlineImages` + `options.compressImages` — server-side image hardening, defends against expiring signed URLs. |

Full per-release detail in [CHANGELOG.md](./CHANGELOG.md).

## Architecture

Kamy is a Turborepo monorepo containing:

| Package | Description |
|---|---|
| `apps/web` | Next.js 15 app — landing page, dashboard, REST API |
| `apps/mcp` | Cloudflare Worker — MCP server for AI coding agents |
| `apps/docs` | Nextra docs site |
| `packages/sdk` | `@kamydev/sdk` — publishable TypeScript SDK |
| `packages/templates` | `@kamy/templates` — PDF template HTML/CSS + Zod schemas |
| `packages/ui` | `@kamy/ui` — shared shadcn/Radix UI components |
| `packages/shared` | `@kamy/shared` — types, utils, observability, email |
| `packages/tsconfig` | `@kamy/tsconfig` — shared TypeScript configs |

## Prerequisites

- Node.js 22+
- pnpm 10+
- Supabase CLI (`brew install supabase/tap/supabase`)
- Wrangler CLI (`pnpm add -g wrangler`) — for MCP server

## Local Development

```bash
# 1. Install dependencies
pnpm install

# 2. Copy env file and fill in values
cp .env.example apps/web/.env.local

# 3. Start local Supabase (requires Docker)
supabase start

# 4. Apply database migrations
supabase db reset

# 5. Generate TypeScript types from schema
supabase gen types typescript --local > packages/shared/src/types/database.ts

# 6. Start all apps in dev mode
pnpm dev
```

The web app runs at https://kamy.dev

## Commands

```bash
pnpm dev          # Start all apps with Turbopack (hot reload)
pnpm build        # Production build all apps
pnpm typecheck    # TypeScript check across all packages
pnpm lint         # Biome lint + format check
pnpm lint:fix     # Biome auto-fix
pnpm test         # Run all tests (Vitest unit + Playwright E2E)
pnpm test:unit    # Vitest unit tests only
pnpm test:e2e     # Playwright E2E tests only
pnpm clean        # Remove all build artifacts
```

## Database

Migrations live in `supabase/migrations/`. They are applied in order by timestamp.

```bash
# Reset and reseed local DB
supabase db reset

# Create a new migration
supabase migration new <name>

# Push to remote Supabase project
supabase db push
```

## Deployment

- **Web app**: Deployed to Vercel on merge to `main`
- **MCP server**: Deployed to Cloudflare Workers via `wrangler deploy`
- **Database**: Hosted on Supabase Cloud

## Environment Variables

See `.env.example` for all required variables with descriptions.

## Tech Stack

- **Framework**: Next.js 15 (App Router, React Server Components, Turbopack)
- **Language**: TypeScript 5.7+ strict
- **Database**: Supabase (Postgres 16 + Auth + Storage)
- **Styling**: Tailwind CSS v4 (Oxide engine)
- **Payments**: Stripe (Meters API)
- **PDF Engine**: Browserless.io v2
- **Email**: Resend + React Email
- **Observability**: Sentry + PostHog + Axiom
- **Testing**: Vitest + Playwright + MSW

<!-- build: 2026-04-22T09:20:52.217Z -->

## Open Plugins

This repository ships an [Open Plugins](https://open-plugins.com)
distribution so AI coding agents (Cursor, Claude Code, and any other
Open-Plugins-compatible tool) can install Kamy as a single plugin and
get a ready-to-use PDF pipeline.

The plugin bundles four components at the repo root:

| Path | Component | Purpose |
|---|---|---|
| `.plugin/plugin.json` | Manifest | Name, version, metadata, declared components |
| `skills/kamy/SKILL.md` | Skill | Teaches the agent when and how to render PDFs |
| `rules/kamy-sdk.mdc` | Rule | Coding conventions for `@kamydev/sdk` and the REST API |
| `agents/pdf-template-author.md` | Sub-agent | Specialised template-design agent (Handlebars + print CSS) |
| `.mcp.json` | MCP server | Hosted MCP at `mcp.kamy.dev` exposing render tools |

To install the plugin in a supported agent, point it at this
repository (`https://github.com/rakanalalami/kamy`) and follow the
host's plugin-install flow. The agent will read the manifest and
load the components automatically.

See the [Open Plugins specification](https://open-plugins.com) for
the full schema.