@nightowlsdev/storage-local
Adapter/StorageMastraA local LibSQL-backed Mastra snapshot store for the CLI bootstrap runtime, run a swarm on just a model key, before Supabase.
What it does
Exposes `createMastraLibsqlStore({ url, id? })`, which constructs a `@mastra/libsql` `LibSQLStore` for the CLI 'builder' bootstrap runtime, letting you run a Night Owls swarm with only a model key, before the project has Supabase/runners wired. You pass the returned store to `defineSwarm({ mastraStore })` in `@nightowlsdev/core`. This is the engine-wall (Option B) seam: the `@mastra/libsql` import lives here as a peripheral peer so `@nightowlsdev/cli` imports only this factory and stays Mastra-free; the return type is `unknown` so no `@mastra/*` type crosses the public API. `url` is `:memory:` for a single session or an absolute `file:` path for resume/replay across processes (it throws on a relative file: url).
Install
pnpm add @nightowlsdev/storage-localKey exports
- createMastraLibsqlStore
Usage
import { defineSwarm } from "@nightowlsdev/core";
import { createMastraLibsqlStore } from "@nightowlsdev/storage-local";
// :memory: for a single session, or an absolute file: url to resume across processes.
const mastraStore = createMastraLibsqlStore({ url: "file:/abs/path/owl.db" });
const swarm = defineSwarm({ agents, mastraStore });What it provides
storage-local is the zero-infrastructure snapshot store for the CLI bootstrap runtime: a single factory, createMastraLibsqlStore({ url }), that returns a LibSQL-backed Mastra store you hand to defineSwarm({ mastraStore }). It lets a swarm suspend and resume on nothing but a model key, before the project has Supabase or durable runners wired. It is also an engine-wall seam — the heavy @mastra/libsql peer lives here and the return type is unknown, so @nightowlsdev/cli imports this factory and never @mastra/* directly.
When to use it
- The CLI / owl builder bootstrap runtime — run a swarm with only a model key, before Supabase and runners exist.
- Local development or a demo where you want durable suspend/resume on one machine without standing up Postgres.
- A single-process script that should resume across restarts — pass an absolute file: url.
- Tests that need a real (not mocked) Mastra store without a database — use :memory:.
When not to
- Any multi-instance or serverless deployment — LibSQL is a single-file, single-process store with no cross-instance event bus, cache invalidation, or container floor.
- Production persistence, an agent version catalog, a live redacted event stream, or tenant scoping — that is @nightowlsdev/storage-supabase.
- You need the full core StorageAdapter (agents / runs / events / messages / scratchpad) — this exports ONLY the Mastra snapshot store, not a StorageAdapter.
Alternatives
- @nightowlsdev/storage-supabaseAnything past one machine: durable, multi-tenant, multi-instance persistence with the full StorageAdapter, versioned agents, a Realtime event bus, and a Postgres floor.
- InMemoryStorage (from @nightowlsdev/core)A single session or a test where you do not even need on-disk resume — a zero-dependency in-memory floor with nothing to install.
Strengths
- Zero infrastructure — a model key plus a file path (or :memory:) is the entire setup.
- Keeps the CLI Mastra-free (the engine wall): the @mastra/libsql peer is confined to this adapter and no @mastra/* type crosses its public API.
- A file-backed url gives real durable suspend/resume across process restarts on one machine.
Limits & trade-offs
- Single-process only — no cross-instance broadcast, cache invalidation, or container floor.
- Only the Mastra snapshot store; it does not implement the core StorageAdapter seams (agents / runs / events / messages / scratchpad).
- file: urls must be ABSOLUTE — a relative path throws at construction, on purpose, so a resume never breaks silently when the working directory changes.
- Requires the @mastra/libsql and @mastra/core peers installed alongside.
How it works
createMastraLibsqlStore({ url, id? }) constructs a @mastra/libsql LibSQLStore and returns it typed as unknown. You pass it to defineSwarm({ mastraStore }) (or SwarmEngine({ mastraStore })), where the engine uses it to persist and reload durable suspend/resume snapshots. A url of :memory: lives for the process; an absolute file:/… path persists to disk and survives a restart. The constructor throws on a relative file: url so a resume never silently breaks after a cwd change. The unknown return type is deliberate — it keeps the @mastra type out of the public API so the CLI stays Mastra-free.
Examples
In-memory vs file-backed
:memory: lives for this process; an absolute file: path survives a restart.
import { createMastraLibsqlStore } from "@nightowlsdev/storage-local";
import { defineSwarm } from "@nightowlsdev/core";
// :memory: — state lives for this process only (a single CLI session, a test).
const ephemeral = createMastraLibsqlStore({ url: ":memory:" });
// file: — an ABSOLUTE path; suspend/resume snapshots persist across restarts.
const persistent = createMastraLibsqlStore({
url: "file:/home/me/.nightowls/project.db",
id: "project",
});
const swarm = defineSwarm({ agents, mastraStore: persistent });The absolute-path guard
A relative file: url throws at construction, so a resume never breaks after a directory change.
// Throws: "libsql file: url must be ABSOLUTE (file:/…) so resume survives a cwd change".
createMastraLibsqlStore({ url: "file:owl.db" });Doing the parts it doesn't support
- Durable persistence across instancesThis store is single-process. For a multi-instance or serverless deployment, use @nightowlsdev/storage-supabase — it adds a Postgres container floor, a Realtime event bus, and LISTEN/NOTIFY cache invalidation on top of durable resume.
- The core StorageAdapter seams (agents / runs / events / messages)This package is only the Mastra snapshot store. For the full StorageAdapter use @nightowlsdev/storage-supabase; for a throwaway single session use InMemoryStorage from @nightowlsdev/core.
Related
- storage-supabase — Graduate from the local bootstrap store to the durable, multi-instance StorageAdapter.
- core — defineSwarm({ mastraStore }) is where this plugs in; InMemoryStorage is the no-disk alternative.
- cli — The owl CLI's builder bootstrap uses this factory to stay Mastra-free (the engine wall).
- getting-started — Install the framework, run your first agent on a model key, then wire storage and runner adapters.