Deployment topology
Choose where each Orgabot capability runs - local, a cloud provider, or a supported hybrid - and see the resolved answer, its provenance, and the custody boundaries it crosses.
What this is
Orgabot is local-first, and a fresh install is local-only: everything runs on your machine and no cloud account is involved. Deployment topology is the decision underneath that default - which provider serves each of ten capabilities, and where each one runs.
You do not have to make that decision. If you never create the configuration file, every capability resolves to its local default. This page is for the point where you want one thing somewhere else: a database that survives the laptop, a webhook URL that works when you are on a coffee-shop network, or GitHub Actions holding the authoritative test suite instead of your CPU.
See the resolved answer
orgabot topologyIt prints one line per capability: the provider serving it, where that provider runs, whose account holds its data, and what chose it - a built-in default, a reference profile, or an explicit line in your configuration. That last column is the one that matters when something surprises you.
Two more views:
orgabot topology --matrix every capability, every provider, and its status
orgabot topology --profiles the reference topologies and what each is forThe same answer appears on the dashboard's System tab, and a closed-schema summary of it travels in the redacted support bundle.
orgabot topology is read-only. A placement changes by editing the file below, never by a command flag, because a one-token way to relocate an install's data is not a feature.
The ten capabilities
| Capability | What it owns |
|---|---|
state_store | The operational store and configuration documents |
secret_custody | Connector credentials, tokens, and keys |
artifact_store | Mission logs, worker transcripts, produced artifacts |
durable_runtime | The workflow runtime that makes a killed process resumable |
control_plane | The dashboard, the API, and your actions |
mission_execution | Workers in isolated worktrees |
verification_runner | The suite that produces exit-code evidence |
ingress | Inbound signed webhook deliveries |
scheduled_duties | Recurring duties and background passes |
backup | A restorable copy of state and artifacts |
The full matrix, including every provider's requirements, readiness signal, and migration boundary, is generated from the code into docs/deployment-capability-matrix.md in the repository.
Configuring it
~/.orgabot/deployment.json. Everything in it is optional.
{
"profile": "hybrid_ci_verification",
"capabilities": {
"verification_runner": "github_actions"
},
"settings": {
"ingress": { "publicUrl": "https://hooks.example.com/orgabot" }
},
"acknowledgedDataMovement": ["verification_runner:mission_execution"]
}- `profile` names a reference topology to start from. Every capability it sets can still be overridden line by line below it.
- `capabilities` selects a provider per capability. This wins over the profile.
- `settings` carries the per-provider configuration a provider requires. It never carries a credential: requirements that need one take a secret handle, which the broker resolves under its own permission model. A connection string with a password in it does not belong in this file.
- `acknowledgedDataMovement` is explained below.
If the file does not exist, you get local-only defaults. If it exists and cannot be read, parsed, or validated, Orgabot refuses to resolve a topology at all rather than falling back to those defaults. Treating an unreadable file as an absent one would resolve a local install for someone who had pointed Orgabot at a managed database, which is the exact silent relocation this contract exists to prevent. An unknown key is refused for the same reason: "capabilties" parses fine and would discard everything under it.
Custody boundaries
Placement says where compute runs. Custody says whose account holds the bytes, and those are different: GitHub Actions is cloud placement under GitHub's custody, not your cloud account's.
Orgabot will not cross a custody boundary silently. When a capability depends on another whose custody differs, resolution refuses until your configuration names that exact edge:
unacknowledged_data_movement verification_runner ("github_actions", third party)
reads mission_execution ("local_worktrees", workstation) ... add
"verification_runner:mission_execution" to acknowledgedDataMovement to accept itThe acknowledgement is per edge on purpose. A blanket opt-out would accept every future boundary too, including one introduced by a provider you added months later for an unrelated reason.
What is available today
Every local provider is implemented. The hosted foundation also implements managed PostgreSQL, cloud secret custody, object storage, a managed-container control plane, and GitHub Actions verification. Providers marked planned in the matrix remain contracts rather than implementations. Selecting one is refused, and the refusal names the issue that owns it:
provider_not_implemented durable_runtime provider "managed_restate" is declared
but not implemented in this build; issue #1270 owns its contractArtifact storage has a provider-neutral contract with two backends behind it - local disk and object storage - and one conformance suite both pass. What each artifact class IS (whether a failed write is data loss, how long it is kept, and whether it may leave this machine at all) is written down rather than decided per call site, and a new file-backed artifact that nobody classified fails the test suite.
Object storage is selectable. Classified artifact writers route through the configured store, and local disk and object storage pass the same conformance contract. Managed PostgreSQL and the managed-container control plane are also selectable and form the data/control-plane core of an isolated hosted tenant.
The operational-store contract has the same shape behind SQLite and PostgreSQL, and one conformance suite runs against both real engines. The SQLite half runs in every npm test; the PostgreSQL half needs a database you are willing to throw away, named by ORGABOT_TEST_POSTGRES_URL, and runs with npm run test:postgres from framework/. It refuses to start without that variable rather than passing on the skipped half. A hosted deployment reads its store from ORGABOT_DATABASE_URL and starts only when that is a PostgreSQL URL; it never opens a local SQLite file or a JSON compatibility file as a fallback. The hosted control plane serves the dashboard page, GET /api/state, GET /api/state/head and the GET /api/stream change stream from that store, through the same buildDashboard, the same stream hub and the same browser code the local dashboard uses. The page carries a read credential derived one-way from the deployment's bearer token, never the bearer itself, and sets it as an HttpOnly, SameSite=Strict cookie so the browser's own fetches and its change-stream EventSource authenticate without a header. That credential authenticates GET and HEAD only, from the page-token header or the cookie; replayed as an Authorization: Bearer value it authorizes nothing, so a hosted page observes the tenant and cannot act. Only the deployment bearer on the Authorization header reaches a mutation route. Reads cover the domains the store holds; file-backed local state such as the project registry is absent until its own cutover, and stream delivery adds the feed mirror's poll interval (250 ms by default) to the store's own latency.
Secret custody is fully implemented on every platform: the macOS keychain, the Linux Secret Service, Windows DPAPI, and opt-in remote custody in your own cloud secret manager. See Connectors and tools.
Another non-local provider that works today is github_actions for verification_runner, which is why hybrid_ci_verification is the cheapest hybrid to adopt. It has one precondition Orgabot cannot observe from the topology alone - the project must actually nominate CI as its pre-ship verification authority, which a repository that merely runs Actions has not done. orgabot topology lists that as a precondition with the command that checks it, rather than reporting it as satisfied.
The generated matrix is the authority for the remaining boundary. The complete cloud_only reference profile is still not runnable because managed Restate, cloud sandbox mission execution, managed edge ingress, managed scheduling, and managed backup remain planned. Supported hybrid profiles can use the hosted pieces without pretending those remaining providers exist.
Is ingress actually working?
orgabot github ingressIt answers with evidence rather than a tick: one signed delivery, verified at this receiver, over a named transport, at a stated time. An install whose ingress verified an hour ago and is down now reads as "last verified an hour ago", because that is what is true.
It also reports refusals with their reason. An endpoint that is reachable and verifies nothing (a wrong webhook secret) looks identical to one nobody is sending to in any report that only counts accepted deliveries, and those have different repairs.
If you have not connected a webhook at all, it says so plainly: Orgabot reconciles GitHub state by polling instead, which is slower and bounded by the API rate limit. That is a supported mode, not a fault.
Related
- Invariants - the safety properties that hold regardless of where a capability runs.
- Architecture - the mission control loop the capabilities serve.