Skip to content

Quickstart

This is a five-minute orientation. You will define a tiny provider, serve it, and invoke one of its actions with curl. It is intentionally condensed — the Build a provider tutorial walks the same ground slowly and in full.

Make sure your toolchain is ready first — see Installation.

Put the whole thing in one file. It defines a notes provider with a single createNote action, creates a Services container with embedded-Postgres persistence, registers the provider, and starts the server.

start.ts
import { defineProviderType, defineAction, ProviderInstance, ProviderRegistry, Services, z } from '@grundlag/core';
import { createPgliteCreator } from '@grundlag/core/pglite';
import { createServer } from '@grundlag/server';
const notesProvider = defineProviderType({
id: 'notes',
name: 'Notes',
config: z.object({}),
setup: async (): Promise<ProviderInstance> => {
const provider = new ProviderInstance('notes');
provider.actions.register(
defineAction({
id: 'createNote',
name: 'Create note',
input: z.object({ title: z.string().min(1), body: z.string() }),
output: z.object({ id: z.string() }),
execute: async ({ input, logger }): Promise<{ id: string }> => {
logger.info('Creating note', { title: input.title });
return { id: crypto.randomUUID() };
},
}),
);
return provider;
},
});
const services = new Services({
databaseCreator: createPgliteCreator((id) => `./data/${id}`),
});
const providers = services.get(ProviderRegistry);
await providers.register(notesProvider, {});
const server = await createServer({ services });
await server.listen({ port: 3800 });

The databaseCreator gives providers a place to persist state; this provider does not use it yet, but wiring it now means you never have to retrofit it. providers.register validates the config against the provider’s Zod schema before calling setup.

Terminal window
pnpm dlx tsx start.ts

This runs your host directly with tsx. You can also compile with tsc and run the output with node — see Installation.

Every registered action becomes a POST endpoint at /api/providers/:providerId/actions/:actionId:

Terminal window
curl -X POST http://localhost:3800/api/providers/notes/actions/createNote \
-H 'content-type: application/json' \
-d '{ "title": "First note", "body": "Hello from the platform." }'
{ "id": "4b2f…" }

The request body is validated against the action’s input schema and the response against its output schema — bad input is rejected before execute runs.

  • Interactive API docs live at http://localhost:3800/api/docs. Every registered action and entity appears there with its schema, so you can try calls from the browser.
  • The eval endpoint at /api/eval runs a TypeScript script against your actions in the sandbox — see Execute a script.