8.8 KiB
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Project Overview
This is a monorepo for Agentic - a platform that provides API gateway services for MCP (Model Context Protocol) and OpenAPI integrations.
Core Architecture
The platform consists of:
- API Service (
apps/api/
) - Platform backend API with authentication, billing, and resource management - Gateway Service (
apps/gateway/
) - Cloudflare Worker that proxies requests to origin MCP/OpenAPI services - Website (
apps/web/
) - Next.js site for both the marketing site and authenticated webapp - E2E Tests (
apps/e2e/
) - End-to-end test suite for HTTP and MCP gateway requests - Shared Packages (
packages/
) - Common utilities, types, validators, and config - StdLib Packages (
stdlib/
) - TS AI SDK adapters
The gateway accepts HTTP requests at https://gateway.agentic.so/deploymentIdentifier/tool-name
or https://gateway.agentic.so/deploymentIdentifier/mcp
for MCP.
Development Commands
Main development workflow:
pnpm dev
- Start all services in development modepnpm build
- Build all packages and apps (except for the website)pnpm test
- Run all tests (format, lint, typecheck, unit, but not e2e tests)pnpm clean
- Clean all build artifacts
Individual test commands:
pnpm test:format
- Check code formatting with Prettierpnpm test:lint
- Run ESLint across all packagespnpm test:typecheck
- Run TypeScript type checkingpnpm test:unit
- Run unit tests with Vitest
Code quality:
pnpm fix
- Auto-fix formatting and linting issuespnpm knip
- Check for unused dependencies
E2E testing:
- (from the
apps/e2e
directory) pnpm e2e
- Run all E2E testspnpm e2e-http
- Run HTTP edge E2E testspnpm e2e-mcp
- Run MCP edge E2E tests
Key Database Models
The system uses Drizzle ORM with PostgreSQL. Core entities:
- User - Platform users
- Team - Organizations with members and billing
- Project - Namespace API products comprised of immutable Deployments
- Deployment - Immutable instances of MCP/OpenAPI services, including gateway and pricing config
- Consumer - Customer subscription tracking usage and billing
Agentic Configuration
Agentic projects use agentic.config.{ts,js,json}
files to define:
- Project name and metadata
- Origin adapter (MCP server or OpenAPI spec)
- Tool configurations and permissions
- Pricing plans and rate limits
- Authentication requirements
The platform supports both MCP servers and OpenAPI specifications as origin adapters.
Gateway Request Flow
- Request hits gateway with deployment identifier
- Gateway validates consumer authentication/rate limits/caching
- Request is transformed and forwarded to origin service
- Response is processed and returned with appropriate headers
- Usage is tracked for billing and analytics
Environment Setup
All apps require environment variables for:
- Database connections (
DATABASE_URL
) - External services (Stripe, GitHub, Resend, Sentry)
- Internal services (API, gateway, etc)
- Authentication secrets
- Stripe secrets
- Admin API keys
- Sentry DSN
- etc
Coding Conventions
General
- Write elegant, concise, and readable code
- Prefer
const
overlet
(never usevar
) - Use kebab-case for file and directory names
- Use clear, descriptive names for variables, functions, and components
Modules
- Always use ESM
import
andexport
(never use CJSrequire
)- File imports should never use an extension (NOT
.js
,.ts
or.tsx
). - GOOD examples:
import { Foo } from './foo'
import { type Route } from './types/root'
import zod from 'zod'
import { logger } from '~/types'
- BAD examples:
import { Foo } from './foo.js'
import { type Route } from './types/root.js'
import { Foo } from './foo.ts'
- File imports should never use an extension (NOT
- Always prefer named exports over default exports except for when default exports are required (like in Next.js
page.tsx
components)
Packages
All packages must follow these package.json
rules:
type
must be set tomodule
TypeScript
- Avoid semicolons at the end of lines
- Use TypeScript's utility types (e.g.,
Partial
,Pick
,Omit
) to manipulate existing types - Create custom types for complex data structures used throughout the application
- If possible, avoid using
any
/unknown
or casting values like(value as any)
in TypeScript outside of test files e.g.*.test.ts
or test fixtures e.g.**/test-data.ts
. - Try not to rely on
typeof
,ReturnType<>
,Awaited<>
, etc for complex type inference (it's ok for simple types) - You can use
as const
as needed for better type inference - Functions should accept an object parameter instead of multiple parameters
- GOOD examples:
function myFunction({ foo, bar }: { foo: boolean; bar: string }) {} function VideoPlayer({ sid }: { sid: string }) {}
- BAD examples:
function myFunction(foo: boolean, bar: string, baz: number) {}
- GOOD examples:
- Arguments should generally be destructured in the function definition, not the function body.
- GOOD example:
function myFunction({ foo, bar }: { foo: boolean; bar: string }) {} function exampleWithOptionalParams({ foo = 'example' }: { foo?: string } = {}) {}
- BAD example:
function myFunction(opts: { foo: boolean; bar: string }) { const { foo, bar } = opts }
- GOOD example:
- Zod should be used to parse untrusted data, but not for data that is trusted like function arguments
- Prefer Zod unions over Zod enums
- For example, this union
z.union([ z.literal('youtube'), z.literal('spotify') ])
is better than this enumz.enum([ 'youtube', 'spotify' ])
- For example, this union
- Promises (and
async
functions which implicitly create Promises) must always be properly handled, either via:- Using
await
to wait for the Promise to resolve successfully - Using
.then
or.catch
to handle Promise resolution - Returning a Promise to a calling function which itself has to handle the Promise.
- Using
Node.js
- Utilize the
node:
protocol when importing Node.js modules (e.g.,import fs from 'node:fs/promises'
) - Prefer promise-based APIs over Node's legacy callback APIs
- Use environment variables for secrets (avoid hardcoding sensitive information)
Web Standard APIs
Always prefer using standard web APIs like fetch
, WebSocket
, and ReadableStream
when possible. Avoid redundant libraries (like node-fetch
).
- Prefer the
fetch
API for making HTTP requests instead of Node.js modules likehttp
orhttps
- Prefer using the
ky
fetch
wrapper for HTTP requests instead ofaxios
,superagent
,node-fetch
or any other HTTP request library - Never use
node-fetch
; preferky
or nativefetch
directly
- Prefer using the
- Use the WHATWG
URL
andURLSearchParams
classes instead of the Node.jsurl
module - Use
Request
andResponse
objects from the Fetch API instead of Node.js-specific request and response objects
Error Handling
- Prefer
async
/await
over.then()
and.catch()
- Always handle errors correctly (eg:
try
/catch
or.catch()
) - Avoid swallowing errors silently; always log or handle caught errors appropriately
Comments
Comments should be used to document and explain code. They should complement the use of descriptive variable and function names and type declarations.
- Add comments to explain complex sections of code
- Add comments that will improve the autocompletion preview in IDEs (eg: functions and types)
- Don't add comments that just reword symbol names or repeat type declarations
- Use JSDoc formatting for comments (not TSDoc or inline comments)
Logging
- Just use
console
for logging.
Testing
Unit Testing
- All unit tests should use Vitest
- DO NOT attempt to install or use other testing libraries like Jest
- Test files should be named
[target].test.ts
and placed in the same directory as the code they are testing (NOT a separate directory)- GOOD example:
src/my-file.ts
andsrc/my-file.test.ts
- BAD example:
src/my-file.ts
andsrc/test/my-file.test.ts
ortest/my-file.test.ts
orsrc/__tests__/my-file.test.ts
- GOOD example:
- Tests should be run with
pnpm test:unit
- You may use
any
/unknown
in test files (such as*.test.ts
) or test fixtures (like**/test-data.ts
) to facilitate mocking or stubbing external modules or partial function arguments, referencing the usage guidelines in the TypeScript section. - Frontend react code does not need unit tests
Test Coverage
- Test critical business logic and edge cases
- Don't add tests for trivial code or just to increase test coverage
- Don't make tests too brittle or flaky by relying on implementation details
Git
- When possible, combine the
git add
andgit commit
commands into a singlegit commit -am
command, to speed things up