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.
Resident services
Section titled “Resident services”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.
Run and inspect services
Section titled “Run and inspect services”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:
statusshows state, port, and health, and exits nonzero when a service needs attention.listshows each declared service and its management state.start,stop, andrestartact on the named services or bags.logsshows a service’s output;--followstreams it and--stderrshows the error stream.enableanddisablechange startup at the next login, andaddandremoveregister or unregister a service. Each takes--nowto act immediately.portmoves a service to another port and waits until every route that targets it follows.urlprints where a service listens.
A store per bag
Section titled “A store per bag”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: nodegives the whole machine one database for that store, atnode/<bag>/<store>.db.owned_by: identitygives each identity its own database, atidentities/<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.
Migrations on open
Section titled “Migrations on open”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.
Generations, backups, and restores
Section titled “Generations, backups, and restores”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.
Who may call a service
Section titled “Who may call a service”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.
Hosting beyond loopback
Section titled “Hosting beyond loopback”What an installation exposes lives in ~/.config/barry/hosting.yaml, and
without that file Barry exposes nothing beyond loopback. The file has two
parts:
localgives services readable names on this Mac through a provider bag, such ashttps://lists.home.test.tunnelslists each way in from elsewhere. A tunnel names its provider, its reach (privateorpublic), 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.
Where this shows up for a user
Section titled “Where this shows up for a user”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.