Architecture
The repository's four independent subprojects, the framework source map, the two seams that must stay swappable, and the commands that gate a change.
Four independent subprojects, no root package
There is no root `package.json`: each subproject builds and tests on its own.
| Directory | What it is |
|---|---|
framework/ | The TypeScript control plane and the orgabot CLI. Nearly all logic lives here. |
app/ | The native macOS menu-bar voice app (Swift 6 / SwiftPM, OrgaVoice). |
site/ | This marketing and documentation site (Vite + React 19 + Tailwind 4, Firebase Hosting). |
orgabot-skills/ | Claude Code agent skills for operating Orgabot, installed by symlink. |
# framework/
npm run build # tsc -p tsconfig.json
npm run typecheck # strict tsc --noEmit
npm test # vitest run
npx vitest run test/reviewer.test.ts
npx vitest run -t "verification failure"
# app/
swift build && swift test
# site/
npm run dev # vite dev server on :3001
npm run build # tsc -b && vite build
npm test # node --testAfter changing framework source, npm run build && npm test in framework/ is the expected pre-commit gate.
The framework source map
| Path | Responsibility |
|---|---|
domain/types.ts, events/events.ts | Core entities and the append-only audit log |
intent/ | Transcript normalization, intent parsing, project resolution |
projects/ | The registry, with root-boundary defense; project memory and detection |
broker/ | Policy-checked command execution: destructive-pattern refusal, redaction, egress |
git/ | Real worktree/diff/commit (worktree.ts) and GitHub/PR operations (github.ts) |
verify/gates.ts | Independent verification gates and the baseline-failure distinction |
workers/ | The WorkerAdapter contract, the mock worker, the reviewer |
workers/claudeCode/ | The Claude Code adapter, with stream parsing isolated in streamInterpreter.ts |
orchestrator/ | planner.ts, the in-memory orchestrator, durable step functions, worker execution |
orchestration/, missions/ | Routing, decomposition, objectives, persistence, follow-up, steering, recovery |
organizations/, context/, analytics/ | Org state and authority, scoped context and memory, usage and budgets |
lifecycle/ | The authoritative ADR 0055 mission lifecycle journal; every other mission record projects from it |
workflow/ | The ADR 0062 engine: workflow definitions as data, the gate model and gate decisions, policy, promotion and release execution, event sinks, and pure timeline replay |
opstore/ | The local SQLite operational store: read-only repositories, the durable change outbox, the store-only domain writers, and backup/restore |
issues/, incidents/, firebase/ | Issue ingestion and observation, CI-failure triage, and the read-only Firebase App Hosting connector |
restate/ | The durable workflow: durableCtx.ts, missionWorkflow.ts, binding.ts, server.ts |
dashboard/, github/ | The ops dashboard and the GitHub webhook ingestion feeding it. dashboard/requestHandler.ts is guards then route table then 404; every endpoint lives in a family module under dashboard/routes/, and every page fragment under dashboard/ui/ |
cli/ | CLI entry points. orgabot.ts wires the process; cli/commands/ holds the command table and one module per family |
The two seams that must stay swappable
`WorkerAdapter` (src/workers/adapter.ts). The mock worker and the real adapters are fully interchangeable under the orchestrator; a new worker plugs in here. The Claude Code adapter deliberately isolates brittle claude --output-format stream-json parsing in a pure, unit-tested streamInterpreter.ts, and spawner.ts is a narrow process interface so tests inject a fake claude rather than spawning one.
`DurableCtx` (src/restate/durableCtx.ts). The minimal durable-execution interface the mission workflow is written against. Restate is one implementation; the test fake is another. The orchestrator owns all mission, task, approval, and audit state, so the runtime only drives it.
Durability is proven, not asserted: resume tests assert that journaled steps do not re-execute (the worker is opened once, its cost is not re-charged) and that a mid-flight worker resume restarts at the exact next event index.
Conventions
- ES modules (
"type": "module"); relative imports carry the.jsextension even from.tssources (NodeNext). TypeScript is strict. - Tests are vitest under
framework/test/, one file per unit, plusorchestrator.e2e.test.tswhich drives the whole loop against real git and the real Node test runner. - Prefer pure helpers so tests need no real git or network. The Claude adapter has a file-writing fake, and a live test gated behind
ORGABOT_LIVE_CLAUDE=1. - The dashboard HTML lives in
String.rawtemplates in the fragment modules undersrc/dashboard/ui/, whichsrc/dashboard/ui.tsconcatenates in document order. A stray backtick in any of those templates breaks the entire CLI, so avoid backticks when editing a fragment. The order of the join is load-bearing: the page carries one browser script that is a single shared scope. - The dashboard is long-running and does not hot-reload; dashboard changes need a restart.
Per-repo operating reference
orgabot project init <project> generates an ORGABOT.md in the target repository: a capped, repository-controlled operating reference injected into every mission brief for that repo. It is context, not authority: it cannot grant tools, waive gates, or change policy.
Orgabot reads that reference as ORGABOT.md first and then ORKA.md, first match and never merged, so a repository that still carries the older ORKA.md keeps working with nothing to change. A repository that already has one is regenerated in place under the name it already carries: project init never adds a second reference beside an existing one. If a repository does end up carrying both, the newer one wins whole and orgabot doctor reports the duplicate.