Skip to content
WIP

This guide is a work in progress. Barry is also a work in progress.

Services and stores

This page is for operators and contributors who want to know what Barry runs on a machine and where it keeps its data. The user guides treat Barry as one thing; here it’s a set of processes, a SQLite database per bag, and a few rules for who may call whom and what leaves the machine.

Barry’s services are launchd jobs, so they start at login and stay up. A bag declares its services in bag.yaml under services:, and each one runs as its own process under the name <bag>.<service>. The bags in Barry’s repository declare these:

Service What it does
identities.identities Identity, trait, and bound management over REST
mcp.server Serves every bag’s tools to a harness through one MCP server
schedules.scheduler Fires schedules from every registered bag and records their runs
sessions.api Session lifecycle, transcripts, git, and actions over HTTP
vault.api The vault’s REST API and MCP endpoint, over a unix socket
workflows.runtime Owns workflow history, executes activities, and serves the runs console
actions.web A web app to search the action catalog and run an action
artifacts.web Artifact share links and the owner’s artifacts API
memory.web A web interface to search, edit, and curate memories
telemetry.web A metrics dashboard for service health, resource trends, and alerts

vault.api differs from the rest: it runs as its own operating-system user, _barryvault, as a system daemon, and you install it once with sudo barry setup --system. A bag you pack can add services of its own.

barry up starts the registered, enabled services through launchd, and barry down stops them without changing whether they start at login. barry status shows services, stores, and schedules together; add --full to see every store and resource, or --json for scripts.

barry service acts on one service or bag at a time:

  • status shows state, port, and health, and exits nonzero when a service needs attention. list shows each declared service and its management state.
  • start, stop, and restart act on the named services or bags.
  • logs shows a service’s output; --follow streams it and --stderr shows the error stream.
  • enable and disable change startup at the next login, and add and remove register or unregister a service. Each takes --now to act immediately.
  • port moves a service to another port and waits until every route that targets it follows. url prints where a service listens.

Every bag that keeps state declares its stores in bag.yaml under stores:, and each store is a SQLite database. A store carries an owner:

  • owned_by: node gives the whole machine one database for that store, at node/<bag>/<store>.db.
  • owned_by: identity gives each identity its own database, at identities/<identity>/<bag>/<store>.db, so one identity’s sessions and memories never mix with another’s.

A bag can declare both. The sessions bag, for example, keeps per-identity session histories beside a node-wide catalog. barry store list shows the active stores with their sizes, write-ahead-log status, and migration versions, and barry store verify checks SQLite integrity and write-ahead-log health; --deep runs the deeper integrity checks. The same store commands exist under <identity> for one identity’s stores.

Bags open their stores through openBagStore in the SDK, and every process opens the file itself. The open sequence never varies: set a busy timeout, switch to write-ahead logging, turn on foreign keys, then apply migrations. An identity-scoped store keeps one handle per identity, chosen by the store context the caller runs in.

migrateStore applies a store’s pending migrations inside one BEGIN IMMEDIATE transaction, so several services starting at once serialize on the write lock rather than race. It also refuses a store whose history it can’t trust: a missing version, a renamed migration, or a checksum that doesn’t match. A store stamped by a newer build than the one opening it refuses to open, because an older build would read the tables it knows and silently ignore newer columns. That refusal is the signal to run barry upgrade.

Barry keeps the whole set of stores in a generation: a directory under stores/generations/ in the instance’s app support folder, with an active.json selector naming the live one. A restore or an upgrade builds a new generation beside the old one and switches the selector, so the previous generation stays intact.

Command What it does
barry db backup Back up every store and the vault
barry db restore <directory> Restore a backup into a new generation and switch to it
barry db rollback Make the generation that was active before this one active again
barry db recover Finish an interrupted generation switch, or undo it when it can’t finish
barry db prune Delete generations older than the active one and the one before it
barry upgrade Snapshot, migrate a copy of the stores when schemas change, switch, restart, and verify

barry upgrade --rollback returns to the release that the last upgrade replaced. barry store migrate splits a legacy install’s stores into node and identity stores and keeps the originals until you remove them with barry store remove-originals.

The vault keeps its own database, owned by _barryvault, outside the generation. barry db backup can include an encrypted vault snapshot, which the daemon takes through its own database connection.

The services speak local HTTP, and the instance secret, BARRY_SECRET, is the one credential that authorizes a call with full authority. No trusted-address shortcut exists: a caller presents the secret as a bearer token or an x-barry-secret header, and Barry compares it in constant time. A service that starts without a secret of its own refuses every request rather than accept anything. Some routes also accept a scoped device credential that barry device pair approves.

The shared HTTP scaffolding applies its middleware in a fixed order: security headers, a one-megabyte body limit, a per-IP rate limit, CORS for local origins on any port plus any listed in BARRY_CORS_ORIGINS, the credential check, and finally a CSRF guard that requires a JSON or multipart body on state-changing requests. A service registers public routes, such as its health check, ahead of the credential check so they stay reachable.

Two parts of the system don’t accept the instance secret, by design:

  • The vault issues its own tokens, because every process under your account can read the instance secret, and vault contents must stay out of their reach.
  • Workers authenticate with a per-worker credential that opens exactly one route. Distributed nodes covers that path.

Keep two uses of “owner” apart. barry owner shows or binds the user who owns this installation, and the instance secret acts as that user. In distributed work, the owner machine is the one that holds a workflow’s state and hands steps to worker machines.

What an installation exposes lives in ~/.config/barry/hosting.yaml, and without that file Barry exposes nothing beyond loopback. The file has two parts:

  • local gives services readable names on this Mac through a provider bag, such as https://lists.home.test.
  • tunnels lists each way in from elsewhere. A tunnel names its provider, its reach (private or public), and the routes it carries.

A public route needs a gate. Set gate: access to put the provider’s access check in front of it, or gate: none only for a service that authenticates its own requests; Barry refuses a public route with neither. Barry publishes one routes file per provider, and the provider reports the target it actually applied. barry hosting status shows each route’s address, provider, reach, and gate, with the wanted target beside the applied one, and --public limits the list to what the internet can reach.

Think before you route workflows.runtime publicly. A public route exposes the runs console and its sign-in page too, so use a private HTTPS route for workers.

Most of this stays out of sight in daily use, which is the point. It surfaces when barry status reports a service that needs attention, when a store asks for an upgrade, or when the vault needs its one-time system setup. The Troubleshooting guide is the user-facing door to these same commands.

For the work the runtime executes, see Durable workflows.