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.
1. A self-contained host
Section titled “1. A self-contained host”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.
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.
2. Run it
Section titled “2. Run it”pnpm dlx tsx start.tsThis runs your host directly with tsx. You can also compile with tsc and
run the output with node — see Installation.
3. Invoke the action
Section titled “3. Invoke the action”Every registered action becomes a POST endpoint at
/api/providers/:providerId/actions/:actionId:
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.
4. Explore
Section titled “4. Explore”- 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/evalruns a TypeScript script against your actions in the sandbox — see Execute a script.
Where to next
Section titled “Where to next”- Build a provider — the full, step-by-step version of what you just did, with two actions and a real config schema.
- Define actions — the action contract in depth.
- Compose your own host — registering multiple providers and services in a real host.
- Architecture — the mental model tying it all together.