BOS is the multi-tenant platform underneath every AI system we run for a client: one observability spine, one agent registry, one connector layer, built once and shipped identical to every deployed box. Tenant-specific logic and data live outside the code, in a separate knowledge plane, so a platform update never has to touch what a client's own agents have learned.
The problem
Building a bespoke agent stack per client does not scale past a handful of clients. Every new client means re-solving the same problems inside a one-off codebase: how agents log what they did, how a new connector gets tested safely, how a tenant's data gets backed up and restored. We wanted a platform that ships identical everywhere, with tenant differences held entirely in data and configuration, never in forked code.
What we built
BOS is organised as 27 workspace packages: 23 shared libraries covering registry, memory, connectors, entitlements and scheduling, plus two apps, a Fastify server and a React dashboard, all in one pnpm workspace over Postgres. On top of that sit 36 agent blocks, the actual units of work: a Merlin orchestrator block that delegates to registry-discovered domain-expert blocks, three connector blocks for GoHighLevel, SharePoint and Telegram, scheduled curator, digest and estate-evaluation jobs, memory read and write blocks, and a set of SME evaluation-judge blocks that grade another agent's output before it reaches a tenant. 30 Postgres migrations, managed directly rather than through an ORM, hold the schema: events, memory facts, staged actions, runtime agents, entitlements, connector credentials, metric points.
The first tenant proven end to end is an Australian accounting practice, running its own AI operations on the same platform code every future tenant will run.
How it runs
Every agent run, connector call and dollar of spend writes to a Postgres-backed event store, streamed live over server-sent events into a React dashboard: an internal admin view and a tenant-facing client shell built from the same codebase, split only by which origin answers a manifest request. Connectors are activated by database-backed entitlement grants, not environment variables, so turning a connector on or off for a tenant is a data change, never a redeploy. A legacy env-var toggle still exists, but only as a one-time, marker-guarded seed, so a later revoke can never be silently undone by a stale variable. Every connector is built against a nine-field contract and tested through a tri-mode transport harness, fake, recorded cassette, or live, so the whole connector layer runs deterministically in CI with no live credentials required.
Under the hood
Two invariants are worth naming because they are enforced structurally, not by convention. First, an agent block that is not registered crashes the load rather than silently failing to run, so the registry can never quietly drift from what is actually deployed. Second, the transport layer itself throws before any network call if a connector attempts a write method it was not declared for, so a coding mistake in a connector cannot become an unintended write in production. Merges need two gates: a fully green automated test suite, then a human, or a Playwright-driven pass, actually operating the running app, because a green suite hides runtime bugs a unit test cannot see. 487 test files back that gate.
Tenant portability follows the same discipline. Platform code, a tenant's knowledge and memory, and a versioned export of that tenant's data are three separate planes, so a platform rollback can never rewind what a client's agents have learned.
What changed
Observability came first: the spine and the dashboard were built before a single product feature, on the principle that nothing gets built blind. Six weeks into active development, BOS is the platform running under our first live tenant and every client system we bring onto it after, rather than a one-off build repeated per client. More tenants, more connectors and more agent blocks are the roadmap, not the finish line.
