{"id":"3d459257-90f2-498d-b875-3511f5dff5df","slug":"openbases","kind":"skill","name":"openbases","summary":"OpenBases — AI-native company operating system (control plane, execution layer, knowledge governance)","owner":"datopian","repoUrl":"https://github.com/datopian/openbases","license":"Apache-2.0","licenseTier":"permissive","trust":"community","stars":7,"match":null,"fewStars":false,"format":"skill","createdAt":"2026-08-10T06:37:32.000Z","addedAt":"2026-10-21T17:53:01.171Z","logoUrl":"https://avatars.githubusercontent.com/u/24832801?v=4","linkOnly":false,"collection":null,"skillPath":null,"categories":["memory-knowledge"],"tags":["ai","ai-agents","ai-governance","ai-tools"],"runtime":"go","local":true,"cloudCapable":false,"cloudCapability":"unknown","cloudReadyOnPlatform":false,"needsApiKey":false,"reviewed":false,"syncedAt":"2026-10-25T16:30:09.232Z","sample":false,"url":"https://conduits.dev/tools/openbases","language":"Go","transports":["stdio"],"install":{},"requirements":{"env":[],"upstreamMayCharge":false},"tools":null,"readme":"# OpenBases\n\n**An open operating system for companies that run on agents.** Five open bases — work, knowledge,\nattention, execution, improvement — that give every project, decision and agent a shared, governed\nhome. Built to run together; designed to be adopted one at a time.\n\nBuilt and operated by [Datopian](https://www.datopian.com), an eight-person open-data consultancy,\nto run its own client and product work. This repository is the whole system.\n\n> **Status: alpha.** One company runs it, on staging, for real work. Four of the five bases run today;\n> the fifth (improvement) is designed and not built. There is no production deployment yet. This\n> README describes what runs; what does not run yet is listed [below](#what-works-today), by name.\n\n> **On the name.** The system is OpenBases; the work base is still called Workgraph, which is what the\n> whole thing was called until September 2026. The code has not been renamed and mostly should not be:\n> binaries are `wg-*`, the database and its application role are `workgraph` and `workgraph_app`, bead\n> labels are `wg-project-<slug>`, and the MCP tools are `workgraph_*` — all of which belong to the work\n> base and are correct there. Where you see `wg` or `workgraph` below, it is the work base or its\n> heritage, not a rename left half-done.\n\n## The five bases\n\nEach base solves one part of running a company with agents in the loop. They share one control plane,\none identity model and one permission model, and none of them approves its own work.\n\n| Base | What it answers | Where it lives here |\n|---|---|---|\n| **Work** — *Workgraph* | What needs to happen, and what is blocking it. Projects, portfolios, beads, dependencies, approvals, and the evidence behind every close. One graph, not a dozen boards. | [Beads](https://github.com/gastownhall/beads)/Dolt graphs · `internal/work` · `internal/approvals` · the registry (`projects`, `portfolios`, `role_grants`) · `wg` CLI · `/mcp` tools |\n| **Knowledge** | What the company knows, and where it came from. A meeting or document becomes a typed *candidate*; a named human accepts it; only then is it a record, carrying source, reviewer and classification. | `internal/ingest` · `internal/knowledge` · `internal/publish` · `workspaced` (Google Meet and Drive) · the classification policies |\n| **Attention** | What needs a human right now. A ranked, permission-aware feed of decisions, risks and stalls — assembled for one person, not broadcast to everyone. | `internal/attention` · the inbox · `wg-witness` and `wg-monitor` escalations · the chief-of-staff \"ask\" |\n| **Execution** | Who — or what — does the work, safely. Agents run in isolated cells scoped to the repositories, tools and budget they may touch; every call is attributed; the platform, not the agent, lands the result as a pull request. | cells · `wg-dispatcher` · `wg-runner` · OpenCode / Claude Code · `wg-budget` · cost import · `wg-browse` · the GitHub App |\n| **Improvement** | How the system gets better, on evidence: a proposed change to a prompt, policy or process arrives with the evidence behind it and a test that proves it worked. | `internal/improvement`, `internal/evaluation` — **designed, not built**; both packages are a `doc.go` and nothing else ([ADR-0014](docs/adr/0014-governed-self-improvement.md)) |\n\nThe word *base* is literal: each is a schema, a set of policies, and the code that enforces them,\nsitting on the same PostgreSQL with row-level security. Today they deploy as one system. Making each\nseparately adoptable — the knowledge base without the work base, the execution base's isolation model\naround agents you already run — is the direction, and the package boundaries above are where the seams\nare.\n\n## What happens to a piece of work\n\n```mermaid\nflowchart LR\n    bead[\"<b>1. Bead</b><br/><small>a work item in the graph,<br/>filed by a person or planned by an agent</small>\"]\n    dispatch[\"<b>2. Dispatch</b><br/><small>budget checked first;<br/>routed to the cell and rig<br/>that hold the repository</small>\"]\n    agent[\"<b>3. 🤖 Agent</b><br/><small>OpenCode or Claude Code,<br/>reads and edits in the rig checkout;<br/>can run <code>bd</code>, cannot run <code>git</code></small>\"]\n    land[\"<b>4. Land</b><br/><small>the dispatcher commits what the run<br/>changed to <code>bead/&lt;id&gt;</code>, pushes,<br/>control-api opens the PR</small>\"]\n    proj[\"<b>5. Project</b><br/><small>webhook → PR and CI state<br/>next to the bead, with cost</small>\"]\n    human[\"👤 <b>6. Decide</b><br/><small>review, merge, approve,<br/>snooze, escalate</small>\"]\n\n    bead --> dispatch --> agent --> land --> proj --> human\n    human -.->|\"closes or reshapes\"| bead\n    agent -.->|\"stalled or over budget\"| human\n```\n\nSteps 1 and 6 are the work base; 2–4 the execution base; 5 the work base again; the dashed edge into\n6 is the attention base. Nothing on the path approves itself. An agent can propose work, edit files and\ncomment on its bead. It cannot push, merge, widen a classification, or change its own budget. The pull\nrequest it produces says so in its body: *\"Opened by a Workgraph agent run. Nobody has reviewed this.\"*\n\n## Installing it somewhere else\n\nThis runs Datopian's own work, and a plain `migrate` still creates Datopian's organisation. To\ninstall into a database of your own:\n\n```bash\nworkgraph-migrate -fresh          # schema and the permission model, nobody in it\nwg-init -org acme -org-name \"Acme Ltd\" \\\n        -admin-email ops@acme.example -admin-name \"Dana Ops\"\n```\n\n`-fresh` refuses any database with a migration already applied. `wg-init` refuses to create a second\norganisation, and is safe to re-run.\n\nThe address you give `wg-init` must be the one your identity provider asserts. No login identity is\ncreated and none can be: the provider issues the subject on first sign-in and it is matched to this\nuser by address. Get it wrong and that administrator cannot sign in.\n\nStill missing before an outside deployment is realistic — an example environment that is not ours,\nand an install guide someone has followed end to end — with what each stage costs, in\n[docs/install/deployable-by-others.md](docs/install/deployable-by-others.md). One company per\ndeployment; multi-tenancy is not supported.\n\n## Run it\n\n```bash\ngit clone git@github.com:datopian/openbases.git\ncd openbases\nmake bootstrap                          # pinned bd/dolt/gt/opencode/claude, each SHA-256 verified\nexport PATH=\"$PWD/.toolchain/bin:$PATH\"\n```\n\n`make bootstrap` downloads only release artefacts and verifies each against\n[`versions.lock`](versions.lock). Nothing resolves to `latest`; a mismatch aborts.\n\n**`make dev` is not assembled yet.** It prints what it is waiting on and tells you to run the API\ndirectly, which is the honest local mode today:\n\n```bash\ncreatedb workgraph\nWG_ENV=local WG_DATABASE_URL=postgres://localhost/workgraph go run ./cmd/control-api\n# serves the UI and /v1 on http://127.0.0.1:8080\n```\n\nLocal mode is **read and plan only in practice**: dispatching an agent needs a Cloudflare AI Gateway\ntoken, and a run without one is refused outright rather than reaching a model untagged — *\"a run needs\nthe AI Gateway token, or its spend escapes every budget\"*. There is no fixture Beads graph or sandbox\ncell yet; those are the parts `make dev` is waiting on.\n\nDeploying the full system — two Hetzner nodes behind Cloudflare Access and Tunnels, Ansible-provisioned\ncells, AI Gateway, R2 backups — is described in [`infra/README.md`](infra/README.md) and the runbooks\nin [`docs/runbooks/`](docs/runbooks/).\n\n### Connect a client\n\nMost people never open the web interface. OpenBases serves a remote MCP server at `/mcp`, so its tools\nappear inside the clients people already use — Claude (desktop, web, mobile), Claude Code, Codex, and\nanything else that speaks MCP over HTTP.\n\n```bash\nclaude mcp add --transport http openbases https://<your-host>/mcp\n```\n\nYour browser opens the normal identity-provider login and Cloudflare Access issues the token. OpenBases\nimplements no OAuth of its own, and what you see through a connector is exactly what you see in the\nbrowser ([ADR-0028](docs/adr/0028-remote-mcp-via-access-managed-oauth.md)). On a laptop with a shell,\n`wg mcp` serves the same tools over stdio. Confirmed clients and how to revoke access:\n[`docs/runbooks/connect-a-client.md`](docs/runbooks/connect-a-client.md).\n\nNine tools, the same set over both transports, so nothing is available in one client and missing in\nanother: the inbox, the chief-of-staff ask, work and one bead in detail, projects, **creating a project\nand attaching repositories**, filing work from a brief, and dispatching. Detaching a repository and\nsetting a repository's check command are deliberately not tools — the first withdraws the route work\ntravels on, the second is executed on the execution node from a repository an agent can edit.\n\nNew here? [`docs/getting-started.md`](docs/getting-started.md) walks the first run end to end through\nthe MCP — connect, create a project, attach repositories, file a plan (free), and dispatch (spends).\n\n## How it fits together\n\nTwo machines, neither with an inbound port. Everything a person touches goes through Cloudflare Access\nfirst; everything an agent touches is scoped to one cell.\n\n```mermaid\nflowchart TB\n    person[\"👤 People<br/><small>browser, Claude, Claude Code, Codex</small>\"]\n\n    subgraph cf[\"Cloudflare\"]\n        access[\"<b>Access</b><br/><small>your IdP, MFA, one audience per application;<br/>Managed OAuth for MCP clients</small>\"]\n        tunnel[\"<b>Tunnel</b><br/><small>nodes dial out; no inbound port</small>\"]\n        aigw[\"<b>AI Gateway</b><br/><small>per-trust-domain spend limits,<br/>role · cell · bead attribution on every call</small>\"]\n        r2[(\"<b>R2</b><br/><small>backups, evidence, audit</small>\")]\n    end\n\n    subgraph control[\"Control node — work · knowledge · attention bases; no agent code runs here\"]\n        api[\"<b>control-api</b> (Go)<br/><small>UI · /v1 · /mcp<br/>mints scoped GitHub tokens, opens PRs</small>\"]\n        pg[(\"<b>PostgreSQL</b><br/><small>row-level security;<br/>the app role is not the owner</small>\")]\n        hq[(\"<b>Beads HQ</b><br/><small>company graph (Dolt)</small>\")]\n        timers[\"<b>reconcile · monitor · costimport · workspaced</b><br/><small>timers; no model calls</small>\"]\n    end\n\n    subgraph exec[\"Execution node — execution base; untrusted agent code\"]\n        direction TB\n        subgraph cell1[\"cell: oss\"]\n            disp1[\"<b>wg-dispatcher</b><br/><small>claims work, lands the diff</small>\"]\n            run1[\"<b>wg-runner</b><br/><small>one run, one deadline,<br/>one settings file</small>\"]\n            ag1[\"🤖 <b>agent</b><br/><small>OpenCode · GLM 5.3 Flash (default)<br/>Claude Code · Sonnet (per run)</small>\"]\n            rigs1[\"rigs<br/><small>one checkout per repository</small>\"]\n            bd1[(\"Beads<br/><small>(Dolt)</small>\")]\n        end\n        subgraph cell2[\"cell: client-a (restricted)\"]\n            disp2[\"wg-dispatcher\"]\n            ag2[\"🤖 agent\"]\n            bd2[(\"Beads\")]\n        end\n        wit[\"<b>wg-witness</b><br/><small>deterministic health monitor;<br/>makes no model calls</small>\"]\n        proxy[\"<b>wg-browse</b><br/><small>the only way an agent reaches the web;<br/>decides what it may fetch</small>\"]\n    end\n\n    gh[\"<b>GitHub</b><br/><small>App, webhooks, pull requests</small>\"]\n    models[\"<b>Models</b><br/><small>Workers AI · Anthropic · any gateway provider</small>\"]\n\n    person -->|\"browser or MCP client\"| access\n    access -->|\"signed JWT\"| tunnel\n    tunnel --> api\n    api --- pg\n    api --- hq\n    timers --- pg\n\n    gh -.->|\"webhook, HMAC-signed\"| api\n    api -.->|\"short-lived token,<br/>one repository\"| gh\n    disp1 -.->|\"push branch,<br/>ask for the PR\"| gh\n    disp1 -.->|\"claim · project · land\"| api\n    ag1 & ag2 -->|\"inference\"| aigw\n    aigw --> models\n    ag1 -.-> proxy\n    disp1 --- run1 --- ag1\n    ag1 --- rigs1\n    disp1 --- bd1\n    disp2 --- ag2\n    disp2 --- bd2\n\n    wit -->|\"escalations\"| api\n    control --- r2\n    exec --- tunnel\n\n    classDef boundary fill:#f6f8fa,stroke:#57606a,color:#1f2328\n    classDef danger fill:#fff8f0,stroke:#bc4c00,color:#1f2328\n    class control,cf boundary\n    class exec,cell1,cell2 danger\n```\n\nThe dashed edges are the ones that matter for security:\n\n- **A cell never holds a git credential.** The dispatcher asks `control-api` for a token scoped to one\n  repository, over an Access application bound to that single path, and gets one that expires within\n  the hour. The GitHub App private key can mint tokens for *every* installed repository, so it stays on\n  the control node where no agent code runs. The agent itself cannot run `git` at all.\n- **GitHub webhooks bypass Access**, because GitHub cannot complete an Access challenge. An HMAC\n  signature, verified before parsing, is the only thing standing between that endpoint and anyone who\n  learns its URL.\n- **Cells cannot see each other.** Separate Linux users, `0700` homes, a `0711` cells root so one\n  cannot even enumerate the others' names, cgroup limits, and `hidepid` so one cannot read another's\n  process arguments.\n- **An agent reaches the web through one command** that decides what it may fetch. `wg-browse` resolves\n  the host, refuses link-local and private addresses, and pins the resolution so a name cannot change\n  between the check and the fetch. The node's own cloud-metadata endpoint answers `200` to `curl`, and\n  is the first thing it refuses.\n- **What a person sees through MCP is what they see in the browser.** Same identity, same row-level\n  security, same role. No pasted tokens.\n\nKnown limits are listed, not hidden: [`docs/go-live/threat-model.md`](docs/go-live/threat-model.md)\nrecords the accepted risks and the conditions that would change them.\n\n## How the registry is shaped\n\nAn organisation has portfolios (client · product · oss · internal); a portfolio has projects; a project\nhas repositories, a primary **and** a backup owner, and runs in one execution cell. A restricted project\nmust have its own cell — the schema refuses otherwise. Work lives in Beads, one graph per cell and one\ncompany graph on the control node, and a bead is attributed to a project by its `wg-project-<slug>`\nlabel. The older `project:<slug>` spelling is still honoured on read, and both are collected into one\nset so a bead labelled both ways is caught rather than counted twice\n([0082](db/migrations/0082_project_label_convention.sql)).\n\nThere are no subprojects, deliberately: nesting would make membership transitive and change the reach\nof every policy that delegates to `can_read_project()`. Nine roles, scoped per project or\norganisation-wide, decide what a person may do to the rows they can already see\n([ADR-0026](docs/adr/0026-role-permission-matrix.md)). The organisation admin cannot approve; the\nexecutive cannot dispatch. Separation of duties beats convenience.\n\n## Harnesses and models\n\nModel choice is a property of the **work**, not of whichever agent picks it up\n([ADR-0018](docs/adr/0018-tiered-model-routing.md),\n[ADR-0024](docs/adr/0024-multi-provider-agent-runtimes.md)). Different work wants different models —\nfrontier models from US labs, increasingly capable open models from China, small open models for\nmechanical steps — and no team should wait on one vendor's roadmap. The harness and the model are\ndeployed configuration; the tool allowlist is code somebody reviews.\n\n| Role | Harness | Model | Since |\n|---|---|---|---|\n| `polecat`, `crew` — the agents that do the work, **and the planner** | OpenCode | `workers-ai/@cf/zai-org/glm-5.3-flash` | 7 Sep 2026 |\n| any run, on request | Claude Code | `anthropic/claude-sonnet-5` | `-runtime claude -model anthropic/claude-sonnet-5` |\n\nWhy the default moved: on the bake-off screens — context, tool use, a real fix scored on the edit — both\npassed, and GLM 5.3 Flash cost **$0.0037** against Sonnet's **$0.2732** for the same passing result, with\nevery call arriving in `usage_records` tagged by role, cell and bead. That is not evidence that GLM\nmatches Sonnet on hard work; it is evidence it can do the work at all, attributably, at a fiftieth of the\nprice — enough to be the default when any bead can say it needs more. Measurements and their caveats:\n[`docs/evaluations/`](docs/evaluations/).\n\nPlanning runs as the same role as execution, so it moved to the same model. That was not a separate\ndecision and it deserves one: breaking a brief into work is judgement, and it is the step whose mistakes\nare multiplied by every agent that acts on its output. The screens that justified the move were an\noff-by-one and a file edit — execution tasks. Nothing has yet measured decomposition.\n\nTwo rules that survived every measurement. **Context is a hard filter before quality**: OpenCode's system\nprompt is ~19,900 tokens, so a model with a 24k window cannot be a worker whatever the leaderboard says.\nAnd **no model choice beats not making the call**: the health monitor, the dispatcher and the reconciler\nmake none, which is why one day of idle patrol agents costing $13 became zero.\n\nEvery run is budgeted before it starts. `wg-budget` resolves the bead's own ceiling, else its project's,\nelse its cell's, and refuses the dispatch — a refusal the person sees in the interface, not in a journal\nafterwards.\n\n## What works today\n\n*Updated 8 September 2026. If this table and the code disagree, the code is right and this is a bug.*\n\n| Base | Capability | State |\n|---|---|---|\n| Work | Login via Cloudflare Access; projects, work, inbox, ask in the browser | works |\n| Work | Remote MCP (`/mcp`) with Access Managed OAuth; `wg` CLI; `wg mcp` stdio | works — confirmed clients in the runbook |\n| Work | Brief → agent plans → beads under a project; create a project and attach repositories from MCP | works |\n| Work | Bead detail — outcome, the agent's own words, harness and model, cost, pull requests | works in the API, MCP and the bead page; a run in flight reports its harness and model, and says when its cost has not been imported yet |\n| Work | Role-permission matrix enforcement | seeded; enforcement flag off until every role has a real user |\n| Knowledge | Meeting transcript → typed candidates → human review → bead or knowledge PR | works via API and MCP; **no review page in the interface** — review is an API call today |\n| Attention | Ranked inbox of witness and monitor escalations; four fixed chief-of-staff questions | works; approvals have no producer yet, free-text ask is by design absent |\n| Execution | Dispatch → agent edits in the rig → branch → pull request → state next to the bead | works |\n| Execution | Per-bead budget refusal; cost per bead from gateway import | works (cost arrives on an hourly import) |\n| Execution | Isolated cells, one rig per repository, deterministic witness, `wg-browse` | works |\n| Execution | A repository's own build or test command run against the change, with one retry | works where the cell can run it; **not enabled for any repository yet**, and PortalJS does not fit — `npm ci` alone needs 7m5s against a 7.5-minute budget |\n| Improvement | Evidence-backed change proposals with tests | designed, not built |\n| — | Local `make dev` stack | not assembled; run `control-api` directly |\n| — | Production deployment | not yet; staging only |\n\n## How this came to be\n\nOpenBases started as a way to run [Gas Town](https://github.com/gastownhall/gastown) and\n[Beads](https://github.com/gastownhall/beads) for a whole company instead of one laptop, under the name\nWorkgraph — which is now the name of the work base. Beads stayed: the work graph, its Dolt history and its\nCLI are what agents and people share. Gas Town's orchestration did not survive contact with a headless\nnode, and on 26 August 2026 we replaced it with a direct runner — a working directory, a settings file,\none command — and a deterministic health monitor; the model bill roughly halved, and every agent run\nbecame attributable ([ADR-0023](docs/adr/0023-direct-agent-runner.md)). The vocabulary (cells, rigs,\nbeads) is what is left of the town, and the thirty-one ADRs in [`docs/adr/`](docs/adr/) record every\nturn on the way, including the ones that were wrong.\n\n## Layout\n\n```\napps/web/          React + TypeScript interface, embedded into control-api\ncmd/               control-api · dispatcher · runner · witness · monitor · reconcile · costimport · workspaced · wg\ninternal/          work · knowledge · attention · improvement · approvals · authn · authz · runner · githubapp · ingest · publish …\ndb/migrations/     forward-only SQL; row-level security on every table holding source-derived content\ninfra/             OpenTofu (Hetzner, Cloudflare), Ansible (nodes, cells, harnesses), Google Workspace events\nformulas/          workflow formulas\npolicies/          policy bundles evaluated by the approval engine\nskills/            the skill for agents that use OpenBases as a tool\ndocs/getting-started.md  run your first work through the MCP — start here for \"how\"\ndocs/adr/          architecture decision records — start here for \"why\"\ndocs/evaluations/  measured model and harness results, dated\ndocs/runbooks/     operator runbooks\ntest/              contract (real bd), integration (real PostgreSQL), acceptance (against staging)\nversions.lock      the pinned, checksummed toolchain: bd, dolt, gt, opencode, claude, node, chrome-headless-shell\n```\n\n## Contributing\n\nRead [`CONTRIBUTING.md`](CONTRIBUTING.md) and [`AGENTS.md`](AGENTS.md) before your first change. The\nshort version: every change is attached to a bead; one bead, one branch `bead/<id>-<slug>`, one pull\nrequest; close a bead with evidence, not an opinion; never commit a secret; never publish unreviewed\nmodel extraction; never widen a classification; nothing approves itself. Much of this repository was\nwritten by agents running inside it, and every rule above exists because one of them found the gap.\n\nWhat we care about in review, in this order: does it actually work and how do you know; is the reasoning\nin the repository; is it honest about what it does not do.\n\nSecurity issues: [`SECURITY.md`](SECURITY.md) — use GitHub's private vulnerability reporting. There is\ndeliberately no `security@` alias quoted, because an address nobody monitors looks like a channel and\nsilently is not.\n\nLicence: [Apache-2.0](LICENSE), © 2026 Datopian Inc. The licence text is the canonical one from\napache.org with only the appendix's copyright placeholder filled in.\n"}