Skip to main content

Usage Examples

Four concrete walkthroughs: extending the CRM through the API, running a CLI command, using the clientos-context skill, and deploying to production.

1. Add a CRM resource end to end

The clientos domain follows one consistent pattern across all 14 files in apps/api/src/routes/clientos/*. Using clients.ts as the reference implementation, adding a new resource means:

  1. Define the table in packages/db/src/schema-clientos.ts, inside the clientos Postgres schema, with an orgId column like every other table in that schema.
  2. Create a route file under apps/api/src/routes/clientos/. Each file defines:
    • A Zod response schema (e.g. ClientSchema) and a serializeClient-style function to shape DB rows into API responses.
    • Three role tiers as const arrays: readRoles (org:viewer+), writeRoles (org:contributor+), deleteRoles (org:admin).
    • One createRoute() + handler pair per operation (list, get, create, update, delete), each with middleware: [requireRole(...roles)].
  3. Enforce org scoping in the handler, not in the database: call callerOrgIds(user) and filter every query with inArray(table.orgId, orgIds) (list/get) or verify the target org is in that list before a write (see createClientRoute's handling of body.orgId).
  4. Emit an audit event on create/update/delete via emitAuditEvent() — every mutating clientos route does this for traceability.
  5. Mount the route on the shared router alongside the other clientos route modules.
  6. Add a test — see route-factory.test.ts in the same directory for the test harness pattern used across these routes.

The typed client in packages/api-client regenerates from the OpenAPI spec your new createRoute() definitions produce, so apps/web picks up the new endpoints with full type safety once you re-run codegen.

2. Run a clientos CLI command

apps/cli/src/commands/clientos/* holds 16 operator commands, invoked as client clientos <cmd>. Unlike the API, these talk directly to Supabase with the service-role key — a trusted local tool, not a client-facing surface.

# List clients in the local Supabase instance
client clientos list-clients

# Add a note to a client (interactive prompt for title/body/project)
client clientos add-note acme-corp

add-note looks up the client by slug, offers a project picker if the client has active projects, and inserts the note directly into the notes table via the CLI's Supabase client (apps/cli/src/lib/clientos/db.ts) — no API round-trip.

3. Log client notes with the clientos-context skill

The clientos-context skill (skills/clientos-context/SKILL.md) turns free-form client notes into structured edits across the eight markdown files Client OS keeps per client at {CLIENTS_ROOT}/{slug}/04-llm-context/ (brief.md, current-state.md, timeline.md, promises.md, open-tasks.md, repo-map.md, decisions.md, handoff.md).

Trigger it with phrasing like:

"Log this for acme-corp: they want a loyalty program eventually, and we decided to use Postgres over Mongo for the new integration."

The skill resolves the client slug, reads the existing eight files, routes each fact to the file that owns that kind of information (a long-term goal goes to brief.md; a decision goes to decisions.md as a new dated row), and edits in place rather than appending blindly — updating an existing promise's status instead of duplicating it, for example. It performs full CRUD: it can also mark a promise done or remove a resolved task. The files on disk stay the source of truth; run client clientos sync-files <slug> when you want those changes pushed into the llm_context_files DB table.

4. Deploying to production

Once you're ready to put this in front of real users, see Deployment for a summary of what's required — and docs/PROD-DEPLOY.md in the repo for the full first-production-deploy checklist covering Render, Vercel, and Supabase Cloud.