Introduction
This is a set of small, composable TypeScript packages for building applications on a
shared layer of capabilities. The packages are named @grundlag/* and AI is a
first-class use case — but it is a use case, not the point. The same layer powers ordinary
applications, scripts, automations, and user interfaces just as well as agents.
The design goal is separation. A handful of typed contracts live in the core. Everything concrete — a calendar integration, a messaging service, a device network — is a provider that implements those contracts. Agents, sandboxes, hosts, your own applications, and scripts are all consumers of the same contracts. No provider-specific detail ever leaks into the core, and no consumer needs to know which provider it is talking to.
Write once, expose everywhere
Section titled “Write once, expose everywhere”The bigger idea is a shared layer — one pane of glass over everything you can do. Think of it as an operating system for your actions, events, and data: you model a capability once as a provider, and the platform lets you build anything on top of it without rewriting the integration. A traditional web app, a background script, an automation, an LLM-driven agent — they all draw from the same set of capabilities.
Because every capability shares one description (its schemas) and one runtime contract, the
surfaces stay consistent: the same createEvent action is an HTTP endpoint an application
can POST to, a function a script can invoke, a step an automation can run, and a tool an
agent can call. Add a provider once and every surface gains it.
That neutrality extends across the network. A host can generate a TypeScript client typed against its exact providers, and the agent and sandbox both run over a transport-agnostic tool that can be a direct call or an HTTP request. So the same sandbox script or agent loop runs unchanged whether it sits inside the host or on a client talking to it. See Tools and transports.
The mental model
Section titled “The mental model”Four ideas carry most of the weight. They are the shared vocabulary the rest of the docs uses.
- Actions — callable capabilities with typed input and output. “Send a message”, “create an event”, “turn on a device”. This is the primary primitive; agents call actions, automations invoke actions, the HTTP API exposes actions.
- Entities — searchable resources a provider owns. Contacts, files, calendar events, devices. Consumers discover and fetch them by id.
- Events — signals a provider emits that automations can react to. “A message arrived”, “a device changed state”.
- Items — typed artifacts that appear in a conversation transcript. Some are shown to the model, some are presentation-only.
Providers expose actions, entities, and events. A host wires providers together and serves them. Agents and the sandbox consume the resulting actions. Validation with Zod happens at every boundary, so bad data fails loudly and early.
The packages
Section titled “The packages”| Package | Role |
|---|---|
@grundlag/core |
The contract layer — defineAction, defineProviderType, defineEntityType, defineEvent, defineItemType, the registries, the Services container, and the database helper. Everything else depends on it. |
@grundlag/shared |
The transport-neutral contracts shared across the HTTP gap — the Tool interface the agent and sandbox consume, the conversation-item store, and the client/server wire protocol. |
@grundlag/agent |
An OpenAI-driven agent runtime. Turns actions into tools the model can call, runs the tool-calling loop, and streams output. |
@grundlag/sandbox |
A hermetic, deterministic script runtime. Executes TypeScript that calls actions, with a replayable call log for resumption. |
@grundlag/server |
A Fastify host. Exposes registered providers over a typed HTTP API, an eval endpoint backed by the sandbox, and MCP. You compose your own host from this package. |
@grundlag/client |
A typed client generated against a specific host. Calls its actions and entities with full type safety, and reconstructs its actions as HTTP-backed tools so a sandbox or agent can run on the client. |
Which path is yours?
Section titled “Which path is yours?”You want to expose a system to the platform. You are a provider author. Begin with Build your first provider, then work through the provider guides.
You want to build an agent, or run scripts against a set of actions. You are an integrator. Begin with Run an agent or Run a sandbox script. To do this from outside the host — across an HTTP gap — see Generate a typed client.
You want to run your own platform. You are a host author. You compose an application
from @grundlag/server and your chosen providers — see
Compose your own host.
If you would rather understand the design before building, read Architecture and Primitives first.
Design principles
Section titled “Design principles”- Keep provider specifics out of the core contracts.
- Describe capabilities with generic interfaces and schemas, never provider-specific types.
- Validate data at every boundary with Zod.
- Test public behavior and developer-facing contracts, not private mechanics.
Where this is heading
Section titled “Where this is heading”The platform is under active development. Some directions are planned but not yet available — they inform the design, but do not build against them yet:
- A Shortcuts-style automation system. Users will be able to author their own automations from provider actions, invoke them on demand, and trigger them from provider events — an end-user layer on top of the same capabilities developers build against.
- More shared surfaces, such as a CLI for scripting the same actions and broader MCP support for agent integration.
- Higher-level shared capabilities — for example memory — layered in as common building blocks that every provider and product can rely on, alongside shared patterns for authentication and identity.
The through-line is a single shared layer that many applications fan out from, rather than each application re-implementing its own integrations.