---
title: Storage
description: Where a routine's records live. The artifact-db adapter behind every Desk, its limits and write rules, artifact assets, and the unverified alternatives reachable through MCP.
sidebar:
  order: 4
---

## What it is

A routine's store holds everything it remembers between runs: records, the Inbox, runs, settings, decisions and viewer state. `[store] adapter` in `routine.toml` (and `[store] kind` in `app.toml`) selects where it lives. The default, and the only one the Desk reads, is **artifact-db**: the database of the published Desk page.

## Why it exists

Every run starts on a fresh machine with nothing from the last run. The store is the routine's memory, and putting it in the Desk's own database means the people who use the Desk and the run that writes it share one source, with no server to run.

## How it works

### Adapters

From `skills/routineos/references/storage-adapters.md`:

| Adapter | Status | Notes |
|---|---|---|
| `artifact-db` | verified | Default. 25,000 docs per artifact, 256 KiB per doc, no joins. The page must declare the `db` capability |
| artifact assets | verified | A run can upload a file to an artifact that declares `assets` and gets a blob path back. Store the id in a db doc. The cap is not confirmed |
| sheet or Drive write | unverified | Not piloted |
| connector | assumed | A connector the run can write to, for example a CRM. Test from a run first |
| object storage (R2 or similar) | unverified | Needs a Worker you own or a connector; direct hosts were blocked in the pilot |

The registry records the artifact-db limits as a **conflict** (`artifact-db-limits-vs-no-backend`): the limits above and Anthropic's "no backend" wording are both on record and not reconciled. A run writing to the store is pilot-verified (`run-writes-artifact-db`).

Anthropic's help article on artifacts says persistent storage is on Pro, Max, Team and Enterprise, on web and Desktop; storage is personal or shared per artifact; it gives 20 MB per artifact and text only ([support article](https://support.claude.com/en/articles/9487310-what-are-artifacts-and-how-do-i-use-them), fetched 2026-10-30). That 20 MB figure is a third number beside the 25,000 docs and 256 KiB per doc that RoutineOS uses. Plan for the smallest until it is reconciled.

### Write rules for artifact-db

- Build JSON with a script into a file and pass the file path, to avoid escaping errors.
- `set` on an existing doc fails unless it carries the current version. Read first, then set with the version.
- `get` on a missing doc returns text, not an error. Treat it as absent.
- Write the report, then state. A crash between them repeats work rather than losing it.
- A run can write to several artifacts if each declares `db`. Never point a probe at a real routine's artifact.

In practice a run never writes the store by hand. It builds a run input and calls `routineos.py write`, which applies the [write contract](/concepts/store-and-write-contract): only the collections the routine owns, with every rule checked.

### Finding the store

A run whose skill does not name the store URL looks for the store by listing artifacts (`run-finds-store-by-listing`, pilot-verified). Name the Desk's URL in the routine so a run never guesses.

### Other stores reachable by MCP

These are reachable as MCP servers or connectors, per their own docs. RoutineOS has no adapter for any of them, and none has been called from a routine.

| Service | What the source says | Source (fetched 2026-10-30) |
|---|---|---|
| Supabase | Hosted `https://mcp.supabase.com/mcp`, OAuth; `read_only=true` and `project_ref` scoping; advises read-only for unattended use and warns about prompt injection | [docs](https://supabase.com/docs/guides/getting-started/mcp) |
| Neon | `https://mcp.neon.tech/mcp`; "We recommend MCP for development and testing only, not production environments." | [docs](https://neon.com/docs/ai/neon-mcp-server) |
| Notion | Hosted remote MCP by Notion, OAuth, pages and databases | [docs](https://developers.notion.com/docs/mcp) |
| Google Drive | Anthropic connector, read and write; share, move and trash need approval | [support](https://support.claude.com/en/articles/10166901-use-google-workspace-connectors) |
| Cloudflare (R2 and the API) | The Cloudflare API MCP server `https://mcp.cloudflare.com/mcp` covers "over 2,500 endpoints"; R2 is named, D1 and KV are not | [docs](https://developers.cloudflare.com/agents/model-context-protocol/mcp-servers-for-cloudflare/) |
| Turso, Airtable, S3 | Unverified; not confirmed from primary sources | |

The Postgres, SQLite, Google Drive and Redis reference servers in `modelcontextprotocol/servers` are archived ([repo](https://github.com/modelcontextprotocol/servers), fetched 2026-10-30). Do not build on them.

## Worked example

Hiring Signals uses the default:

```toml
[store]
adapter = "artifact-db"
```

Each run writes its `role` and `company` records, Inbox messages and a run record through `routineos.py write`. As an example figure, 40 roles a run at two runs a week is about 4,200 role docs a year if every role were new, inside 25,000 but not by a lifetime. Sightings of the same role update one doc, so the real number is lower. The routine's README should still say what to prune when it gets close.

## Common pitfalls

- **A plain `set` on a doc that exists.** It fails without the current version.
- **Reading "not found" text as data.** A missing `get` returns text.
- **Writing state before the report.** A crash then loses items instead of repeating them.
- **Pointing a test at the real Desk.** Use a throwaway artifact.
- **Assuming a database MCP is safe unattended.** Supabase and Neon both warn against it.

## Related

- [Store and write contract](/concepts/store-and-write-contract)
- [Store collections](/reference/store-collections)
- [Desk capabilities](/desk/capabilities)
