How it works
Code decides, AI proposes, people approve. A character is a package on a fixed, shared core; every model step runs through the same harness; every action waits for the approval its risk requires.
Four layers, from the one changed most often to the one changed least
Cut-offs, approver groups, templates, autonomy within ceilings - bounded by each package's settings.schema.json.
characters/<slug>/: character.yaml, workflow.py, its own schema and migrations, api.py and its workspace screens.
blocks/connectors, tools and skills, each with a manifest: what it does, what it may change, how risky that is.
Identity, Cedar-style policies, the gateway, the harness, the engine, approvals, the ledger, cases, the queue.
One model step, as the harness runs it for every character
- Step 1Assemble context
Only the step's declared inputs, after the access check; untrusted text wrapped and labelled.
- Step 2Scan inputs
The injection scan; a high score goes to a person, not to the model.
- Step 3Model call
Local or hosted, through one entry point, with the output schema enforced.
- Step 4Validate output
Schema, invariants, quotes against the source, numbers against cited paragraphs.
- Step 5Retry or abstain
One repair with the errors spelled out; then the case goes to a person with the reason.
- Step 6Save and trace
Output with its provenance; the engine - not the model - picks the next step.
Where things live
core/ platform: harness, gateway, engine, approvals, ledger, cases, packages loader blocks/connectors/ google, microsoft, telegram, whatsapp, erp, geocoder, files, internal ... blocks/tools/ document_text, pii_redact, injection_scan, rubric_rank, cite_sources, check_numbers ... blocks/skills/ screen_cv, draft_jd, draft_brd, draft_process_map, classify_request, research_plan, ... characters/<slug>/ character.yaml, workflow.py, data/models.py + migrations, api.py, ui/ screens ui/kit/ the design system every screen is built from ui/web/ this shell; workspaces are mounted from each package's ui/manifest.json