Skip to main content

Developer Notes

This section is for people building and reviewing the platform: why we chose these technologies, which decisions we made, which ideas we discarded, and where we stand. Business users can skip it. Formal decisions on record are in docs/adr/ in the repository; this is their summary and background.

Technology choices​

AreaChoiceWhy
BackendFastAPI + SQLModelAsync, automatic OpenAPI, Pydantic validation; one model is both ORM and schema
DatabasePostgreSQL 16 + pgvector (dev: SQLite)It started on SQLite (single file, simple backup); moved to PostgreSQL for semantic search and multi-process operation
InterfaceSvelteKit 5 + TailwindSmall bundle, the runes system needs little boilerplate; the basic components (Button, Badge, Input…) are our own because shadcn-svelte was incompatible with Svelte 5 at the time
SchedulingAPScheduler (in-process)No separate service like Celery + Redis; with several processes a single leader through a lock file
GitPyGithub (GitHub Contents API)A single HTTP call instead of managing clones on the server; SHA handling is automatic
Git authenticationPersonal access token (PAT)Enough for an MVP; OAuth (callback, secret management) postponed

Architecture decisions taken​

  • Change requests are two-stage: department head → executive. The idea "let the founder approve" was dropped because it did not scale. The department head looks at technical fit, the executive at corporate risk and policy. → Change Requests
  • Task routing climbs the parent department chain. First a skill match is looked for in the same department; if none is found, the parent_id chain is climbed. Organic routing instead of a central "general agent pool". → Task Requests
  • A single notification layer. Flow results, task notifications and system messages drop into the same InboxMessage table; source_type tells them apart. Adding a new event type does not change the inbox code.
  • Human approval inside the agent chain. Handing tasks between agents needs two human approvals; agents cannot run each other without a human. → Delegation
  • Developer and department layers are separate doors with a common core. Same gateway, policy engine and audit chain; the surface changes with the person's job (opencode / fab / web).

Architecture decision records (ADR)​

ADRTopicStatus
0001opencode as the developer clientaccepted
0002Execution model: laptop + mandatory local sandboxaccepted
0003Threat model and enforcement boundariesproposed
0004Central LLM gateway (OpenAI-compatible, bring your own key)accepted
0005Executable policy engine (denies on failure)accepted
0006Tamper-evident (hash-chained) auditproposed (implemented)
0007Agent identity and short-lived credentialsaccepted
0008TUI strategyaccepted; TUI technology changed by ADR-0014
0009The 3pa workstation CLIaccepted
0010Prompt injection defenseaccepted
0011Managed configuration and precedenceaccepted
0012Repository structure and release processaccepted
0013LLM audit severity scoringaccepted
0014A terminal workspace for every department (fab)proposed
0015Ingesting company documents (Docling) and ranking (Jev)proposed, no code
0016Installation kit: org chart, identity, models, company systemsproposed
0017Policies as code (versioned) and daily work reviewproposed, no code
0018Workspace lifecycle APIproposed
0019One agent per person and work reviewproposed
0020Token-budgeted prompt and intent breakdownproposed
0021The fit rubricproposed

0014 and 0018–0021 are largely implemented but their status is still proposed; they await an acceptance decision. Details and next jobs: docs/ROADMAP.md in the repository.

Planned: managing policies with a local git system​

Today the Git integration is tied to GitHub (change-request commits). The planned direction (ADR-0017): versioning company policies, the rubric and agent configurations in the company's own local git system, like a code library; changes going through the change-request flow; git being the "source of truth" and the database a cache that can be rebuilt from it. This has not been written yet.

Strategy notes (summary of the September 2026 discussion)​

Making policy documents operational (Docling + Jev). The idea of ingesting large companies' hundreds of policy documents with Docling, moving guardrails outside the context window, and checking them with TypeSafe AI "Jev" was researched. Findings:

  • Jev is a classifier that does not generate text (it gives a probability for typed questions). It separated clear violation/compliance cases very well; it was inconsistent on ambiguous cases. So it is used not as a sole decision maker but as a "referee", together with human oversight.
  • Docling extracts PDFs much more cleanly than pypdf but needs a cleaning layer for heading/footer repetition.
  • Semantic errors were seen in summaries produced by an LLM, such as writing a "permission limit" as an "obligation"; quote matching alone is not enough.
  • Running a local model on this server is not possible (no GPU); providers stay external.
  • Real company documents must not be sent to Jev before its privacy/retention terms are verified.

Interposing between tools instead of replacing them. The goal is not to replace the tools employees use (opencode, similar developer tools, later chat applications) but to sit between them and make usage, cost and compliance visible. Two tiers:

  • Tier A: tools whose address (base URL) is configurable. A natural extension of the existing gateway; low risk. This first.
  • Tier B: SaaS chat applications (interposing/MITM). It means entering the AI-DLP/CASB market: months of separate engineering and legal weight. It stays on the roadmap, limited to a small pilot.

A MAC address does not work as device identity (it can be spoofed, it is layer 2 so a cloud server cannot see it, and operating systems randomize it by default). The right answer is a device certificate + SSO. For hierarchical reporting, CompanyMember.role/scope_id and the policy engine's department chain are already ready.

The human-usage signal is separate from agent audit. For agents the audit chain is part of injection defense; for human employees a lighter, asynchronous and advisory signal is needed (it does not block). In the web chat flow there is already a hook point on the server side right before the message goes to the model; one can start from here without needing Tier B.

The classification schema should not be fixed, but not fully autonomous either. The taxonomy and Jev questions should be generated from each company's own documents, but putting them into use must be human-approved (draft → active). The measured errors (above) make full autonomy indefensible. This is the same logic as the existing dry_run → enforce and change-request patterns. The rubric design in ADR-0021 (draft → shadow → live) applies this principle.

Development and verification​

# Backend (~6 min)
cd backend && ruff check . && ruff format --check . && python -m pytest -q

# fab (Rust)
cd packages/tui && cargo fmt --check && cargo clippy --all-targets -- -D warnings && cargo test

Things to watch:

  • If a new migration adds a table, add it to the added_since list in backend/tests/test_pg_smoke.py; if it adds a column to an existing table, it must be dropped there. Otherwise the PostgreSQL CI check breaks with "relation already exists".
  • From scratch on SQLite the whole Alembic chain does not work (because of an old migration). To try it: create_all + alembic stamp <previous revision> + upgrade head.
  • Architecturally significant file changes need an ADR (the adr-guard workflow); if not needed, the no-adr-needed label is put on the PR.
  • Keys are given only as environment variables; they are not written to files or commits. If a key leaked to a chat/record, treat it as compromised and rotate it.