---
sidebar_position: 3
title: stores
---

# `stores`

## What it is

Durable storage the agent needs. Declared **on a node**, not in the
`spec` block.

At deploy the platform creates (or re-uses) one store per declaration and writes
its id into the agent's encrypted Env bag under the name you chose. Your code
never sees an id in the template — it asks for the name and gets the resource.

This is the reference implementation of the naming rule: declare a name, the
platform binds it, the consumer resolves it late.

## Syntax

```js
// nodes/ingest-node.js
import { SKILLS } from '@zibby/core';

export const ingestNode = {
  name: 'ingest',
  skills: [SKILLS.DATASET_STORE],        // required — see gotchas
  stores: [
    { name: 'knowledge_docs', type: 'docs',   description: 'Verbatim markdown archive' },
    { name: 'knowledge_meta', type: 'sqlite', description: 'Per-document metadata',
      schema: {
        tables: {
          knowledge_meta: {
            ddl: 'CREATE TABLE IF NOT EXISTS knowledge_meta (id TEXT PRIMARY KEY, title TEXT)',
          },
        },
      },
    },
  ],
};
```

The minimal form is just a name and a description:

```js
stores: [{ name: 'scorecards', description: 'Per-commit engineering scorecard' }],
```

## Properties

| Name | Type | Required | Allowed values | Default | Update behavior |
|---|---|---|---|---|---|
| `name` | string | **Yes** | lowercase, starts with a letter, letters/digits/underscore, ≤ 41 chars. **Unique across the whole agent**, not just the node | — | Re-applied (idempotent). A **new** name creates a **new** store; renaming leaves the old one behind |
| `type` | string | No | `dataset`, `sqlite`, `file`, `docs`, `postgres` (self-hosted only) | `dataset` | Re-applied. An unknown type fails the deploy loudly |
| `description` | string | No | any — it is what the agent's store catalogue shows the model | none | Re-applied |
| `schema` | object | No | `{ tables: { <name>: { ddl } } }` — **`sqlite` only**. Each `ddl` must begin `CREATE TABLE IF NOT EXISTS` and the table it creates must match the key | none | Re-applied, but an existing table is never altered |

## Store types

| Type | Use it for |
|---|---|
| `dataset` | append-and-query records — the default |
| `sqlite` | relational data with a schema you declare |
| `file` | opaque blobs |
| `docs` | a verbatim document archive |
| `postgres` | a vector knowledge base (self-hosted only) |

## What deploy does

1. Computes a stable key from the agent, the node and the name, so re-deploying
   re-uses the same store instead of creating another one.
2. Creates the store if it does not exist.
3. Writes `ZIBBY_STORE__<name> = <store id>` into the encrypted Env bag.
4. Creates any declared SQLite tables.
5. Seeds the node's store catalogue so the model can see what it has.

At run time the store skill turns those environment entries back into names, and
sub-graph children inherit them.

## Gotchas

:::danger A `stores` block on a node with no store skill is silently ignored
The same node must also declare a store skill (`dataset-store`, or `gbrain` for
a vector KB) in its **`skills`** array. Putting it in `optionalSkills` instead
provisions nothing — no store, no error, no warning.
:::

**Names are unique per agent, not per node.** Two nodes cannot each declare a
store called `results`.

**If you re-point a store by hand, that wins forever.** Setting
`ZIBBY_STORE__<name>` yourself to something other than the provisioned id tells
the platform this is deliberate: it stops re-binding the name and stops applying
the declared schema.

**A schema on a non-SQLite store is a hard error at deploy**, not a warning.

**Declared tables are created, never migrated.** If a table already exists it is
left exactly as it is, even when your `ddl` has changed. Adding a column is your
migration to write.

**A store type brings its own service.** `postgres` pulls the vector-KB engine
by itself — do not also name it under [`sidecars`](./sidecars.md).

**`postgres` cannot be deployed on Zibby Cloud today.** Templates that need it
are marked self-hosted-only.

## See also

- [Node declarations](./node-declarations.md) — the store skill is a
  precondition, not a nicety.
- [Sidecars](./sidecars.md)
