Skip to main content
A slate declares the resources its app and agents need. ContextLayer resolves those declarations into resources when the code runs. The declaration says what is required. Account assignments, secret values, and stored database contents are separate from the declaration and stay out of Git.

Declarations

The app and each agent declare their own resource requirements in a file called slate.json. MCP tools use the same declaration format, with their resource collections currently required to remain empty: Every declaration uses the same schema. For example, this digest agent needs a viewer’s Gmail account, a shared notes database, and an API key supplied by the slate’s Owner:
agents/digest/slate.json
connections and databases are keyed by slug, and secrets by name. Every entry declares a mode, and a connection also declares its toolkit. connections is required, even when empty; databases and secrets can be left out. A declaration never contains account IDs, database locations or secret values.
MCP declarations must currently leave all three collections empty. Resource execution is implemented for the app and agents.

Each consumer declares what it uses

A consumer is the app or named agent using a resource. It can use only the resources in its own declaration. An agent does not inherit the app’s requirements, and declaring a resource for one agent does not expose it to another. If the app and an agent both need notes, both must declare notes. A tool call or query for an undeclared slug fails with not-declared.

One namespace per kind

All declarations in one slate share a namespace per resource kind. Reusing a key names the same logical resource. For example, the app and digest agent can both declare the owner-mode notes database and work with the same rows. Resource ownership still matters. Two consumers selecting the same slug and Owner use the same database or connection assignment. Two people using a viewer-mode resource select their own databases or account assignments. A matching slug does not merge their resources. Repeated declarations must agree. Connections must agree on toolkit and mode; databases and secrets must agree on mode. A disagreement is a validation error, and no declaration takes precedence over another.

Owner mode and viewer mode

Each entry’s mode is "owner" or "viewer". In a hosted slate, the mode selects the Owner who supplies the resource.
  • Owner mode. The slate’s Owner, the user or organization that owns the slate, supplies the resource, and viewers share it. Viewing alone grants no permission to manage the Owner’s accounts or secrets.
  • Viewer mode. Each viewer supplies their own, as their personal Owner.
Assigning an owner-mode connection or saving an owner-mode secret requires authority over the slate’s Owner: being the owning user or a member of the owning organization. Each viewer configures their own viewer-mode connections and secrets. Databases need no account assignment or database picker: declare the database and author its migrations, and ContextLayer selects and provisions its storage.

Viewer setup and scheduled work

Viewer-mode resources require a signed-in person on a private slate. Once setup for the whole slate is complete—every app and agent connection is assigned, and every viewer-mode secret is supplied—ContextLayer establishes that person’s slate membership through a setup change or first viewer-mode use. It then provisions their databases and schedules. No separate join step is needed. A public slate has no members and cannot use viewer-mode resources. A job acting for the app also has no person from whom to select a viewer-mode resource. An agent’s own modes also determine who its scheduled runs act for. If the agent requires any viewer-mode resource, its schedules run for slate members. If it requires none, they run once for the app. In the digest example above, the viewer-mode Gmail connection makes scheduled jobs member-scoped, even though the notes database and API key use owner mode. In local development, modes select no Owner. A checkout uses the developer’s personal accounts for every connection, environment variables for secrets, and local databases. The declared modes apply when the slate runs hosted.

Hosted and local configuration

ContextLayer prepares hosted resource configuration from declarations in the latest commit on the slate’s main branch. The deployed app is not the source of those declarations. Configure account assignments and supply secrets through the chrome, the CLI, or the slate resource API, such as List declared resources and their configuration. Before the first push to main, there are no hosted declarations to configure. A checkout reads its declarations from disk. Its account assignments and database state live under the ignored .contextlayer/ directory, and its secret values come from environment variables. Local configuration does not change hosted configuration. Restart pnpm dev after changing declarations or local configuration so startup can prepare the new values. Pushing code and declarations does not upload local database contents, account assignments, or environment values.

Resource kinds

Connections and assignments

Declare a provider’s toolkit by slug and map it to a connected account.

Databases

Declared SQLite databases with authored Kysely migrations.

Secrets

Named values that belong to an Owner and are supplied separately from source code.