# Vigla — full project context Canonical source: https://github.com/Kilbex/Vigla ## README
# Vigla **Supervise the merge. Not every terminal.** Run Claude Code, Codex CLI, Antigravity, and other agent CLIs as one supervised team — each agent in its own git worktree, every submission audited, every mission reversible in one click. [![CI](https://github.com/Kilbex/Vigla/actions/workflows/ci.yml/badge.svg)](https://github.com/Kilbex/Vigla/actions/workflows/ci.yml) [![License: Apache 2.0](https://img.shields.io/badge/license-Apache--2.0-blue.svg)](https://github.com/Kilbex/Vigla/blob/main/LICENSE) [![Platform: macOS 12+](https://img.shields.io/badge/platform-macOS%2012%2B-8892a6.svg)](#requirements) [![PRs welcome](https://img.shields.io/badge/PRs-welcome-38c5b4.svg)](https://github.com/Kilbex/Vigla/blob/main/CONTRIBUTING.md) [Watch the replay](https://kilbex.github.io/Vigla/demo/) · [Website](https://kilbex.github.io/Vigla/) · [How it works](#how-it-works) · [Compare](#how-it-compares) · [Build a local DMG](#build-a-local-dmg) · [Architecture](https://github.com/Kilbex/Vigla/blob/main/ARCHITECTURE.md) · [FAQ](https://github.com/Kilbex/Vigla/blob/main/docs/faq.md) · [Roadmap](https://github.com/Kilbex/Vigla/blob/main/ROADMAP.md) · [Contributing](https://github.com/Kilbex/Vigla/blob/main/CONTRIBUTING.md) Recorded Vigla mission replay: cross-vendor AI coding agents execute in parallel, pause at an authority bound, and finish with an audited verdict in the Operations Room Deterministic recorded events · no account or credentials · click to open the interactive replay
Running one AI coding agent means babysitting one terminal. Running five means five terminals, five diff reviews, and five chances to merge something you never actually read. Vigla turns that into a single operations room: - **Two decisions, not two hundred.** You assign the mission and set the authority envelope. A supervisor agent decomposes the work, directs the workers, audits every submission, and escalates to you **only when one of four bounds trips: Scope, Reversibility, Risk, or Quality.** - **Cross-vendor by design.** Claude Code, Codex CLI, Antigravity, and profile-backed agent CLIs can work the same mission side by side — pick the best agent for each task instead of the one you happen to have open. Adapters normalize every vendor's output into one canonical event stream. - **Everything is reversible.** Each worker runs in an isolated git worktree; final merge records durable before/merged anchors. Reverting an entire mission creates a normal Git revert commit and preserves later work. - **Local-first.** A Rust orchestrator, Tauri shell, and SQLite event store — no cloud control plane, account, or product telemetry. The default build adds no app-originated network traffic beyond the vendor CLIs you launch. An `EMBEDDINGS=1` build fetches its public embedding model into a local cache on first use, then performs inference locally. > Vigla supervises the agent CLIs you already have. It does not wrap > LLM APIs, run its own models, or add another billing layer. **Launch receipt: 27/27 seeded failure trajectories escalated within the default retry bounds.** Reproduce the fixed, credential-free case set with `cargo xtask receipt`; the [method, data, and limitations](https://github.com/Kilbex/Vigla/blob/main/docs/evidence/recovery-receipt.md) are public and CI-checked. ## Try the no-install replay [Open the read-only browser replay](https://kilbex.github.io/Vigla/demo/) to step through accepted, bound-tripped, and quota-paused missions in the real Operations Room UI. It runs entirely on recorded canonical events: no account, vendor CLI, credentials, or network-backed agent is involved. ### Run the credential-free demo locally Vigla ships with a deterministic mock harness, so you can watch a full mission — decomposition, parallel workers, audit, verdict — without credentials or token spend: ```sh git clone https://github.com/Kilbex/Vigla.git && cd Vigla pnpm install --frozen-lockfile ./scripts/dev.sh ``` When the Operations Room window opens, use the **Deploy** panel and pick a bundled mock script. The deterministic scenarios cover happy paths, blocked work, failures, and quota exhaustion — including the unhappy paths most demos hide. Prereqs: macOS 12+, [Rust 1.95](https://github.com/Kilbex/Vigla/blob/main/rust-toolchain.toml) via rustup, Node 22, pnpm 10, Xcode Command Line Tools. See [CONTRIBUTING.md](https://github.com/Kilbex/Vigla/blob/main/CONTRIBUTING.md#fast-start) for the full setup. ## How it works **1 — Assign a mission inside an envelope.** Describe the goal, choose the worker roster and models, and set the authority envelope. In review mode the supervisor proposes a plan first — task graph, file scope, risk fit — and waits for your approval:
Vigla plan review: the proposed task graph is checked against the Scope, Reversibility, Risk, and Quality bounds before any agent starts
**2 — The supervisor arbitrates; you stay out of the loop.** Workers execute in parallel worktrees while the supervisor reviews each submission and decides **Accept / Extend / Scrub / Escalate** — inside your envelope, without pinging you. Live state, diffs, tests, cost, and raw terminals are always one click away if you *want* to watch.
Vigla Operations Room: five coding-agent workers progress in parallel while one completed submission waits in the review queue
**3 — You judge results, not keystrokes.** Finished missions land in your inbox with a structured verdict: audit score, test results, files changed, residual-risk band, unresolved issues — and a revert button that undoes the whole mission atomically:
Vigla mission inbox: a merged mission with audit breakdown, subtask status, low-risk verdict, and one-click revert
The vocabulary is small and precise — *mission*, *worker*, *envelope*, *arbiter*, *verdict* — and defined in [docs/lexicon.md](https://github.com/Kilbex/Vigla/blob/main/docs/lexicon.md). ## How it compares The table is positioning, not a feature checklist. Each cell is backed by a primary source below; cells are re-verified before each release. *Sources verified 2026-07-21.* “Not documented” means the linked product documentation does not describe that capability; it is not a claim that an internal implementation is impossible. | | Vigla | Codex app (OpenAI) | Claude Code on desktop (Anthropic) | |---|---|---|---| | Cross-vendor worker roster | yes | no; Codex agents | no; Claude agents | | Parallel local agent sessions | yes | yes | yes | | Isolated git worktrees | one per worker | built in | automatic or manual | | Bound-based supervisor audit across workers | yes | not documented | not documented | | Atomic mission merge + revert | yes | not documented | not documented | | Deterministic demo without a vendor account | yes | not documented | not documented |
Sources - **Vigla.** See this README and [ARCHITECTURE.md](https://github.com/Kilbex/Vigla/blob/main/ARCHITECTURE.md) for positioning and goals; [LICENSE](https://github.com/Kilbex/Vigla/blob/main/LICENSE) (Apache 2.0). - **Codex app (OpenAI).** [Introducing the Codex app](https://openai.com/index/introducing-the-codex-app/) documents parallel agents, local and cloud work, and built-in worktree support. - **Claude Code on desktop (Anthropic).** [Claude Code on desktop](https://code.claude.com/docs/en/desktop) documents parallel sessions and automatic worktree isolation; the [worktrees guide](https://code.claude.com/docs/en/worktrees) covers the underlying isolation flow.
## Vendor support Real workers are driven from the in-app Deploy panel; the mock harness covers demos and CI. Integration tests are the authoritative verification path for the fully gated vendors. | Vendor | Binary | Role | Verification | |---|---|---|---| | Claude Code | `claude` | supervisor + worker; session retry / continue | `real_claude_gate.rs`, `supervisor_live.rs` | | Codex CLI | `codex` | worker | `real_codex_run.rs`, `supervisor_live.rs` | | Antigravity | `agy` | profile-backed worker | `real_antigravity_run.rs` | | Gemini CLI | `gemini` | legacy / enterprise worker | `supervisor_live.rs` | | Kiro | `kiro-cli` | profile-backed worker | end-to-end verification pending | | GitHub Copilot | `copilot` | profile-backed worker | end-to-end verification pending | Google ended consumer **Login with Google** access for Gemini CLI on 2026-06-18. Vigla retains the adapter for existing enterprise and legacy configurations, but Gemini CLI is no longer a primary launch path. Google directs affected consumer users to Antigravity in its [official deprecation notice](https://developers.google.com/gemini-code-assist/docs/deprecations/code-assist-individuals). Mission supervision is Claude-backed today; non-Claude supervisor options should be treated as experimental until their end-to-end tests land. Vigla does not pin vendor CLI versions — the launch path verifies each configured binary, and the (`#[ignore]`-gated) real-CLI integration tests track adapter compatibility: ```sh cargo test -p vigla-orchestrator --test real_claude_gate -- --ignored --nocapture cargo test -p vigla-orchestrator --test real_codex_run -- --ignored --nocapture cargo test -p vigla-orchestrator --test real_antigravity_run -- --ignored --nocapture --test-threads=1 cargo test -p vigla-orchestrator --test supervisor_live -- --ignored --nocapture ``` The Claude, Codex, and supervisor gates use `tests/samples/sandbox/`, a workspace-excluded crate with a deliberately wrong `multiply` function. The Antigravity gate creates the same kind of isolated failing Rust fixture in a temporary repository. Each gate asserts that the agent fixed the defect. ## Feature tour
Mission launch and supervision - **Deploy panel** — supervisor profile, worker vendor roster, worker count, model selections, plan mode, objective, folder, and optional scoped paths. - **Plan governance** — direct mode, or review-first mode showing the generated plan, task graph, worker assignments, file scope, and envelope checks with approve / regenerate / abort. - **Arbiter-driven supervision** — one supervisor per mission decides Accept / Extend / Scrub / Escalate without pausing inside the envelope. - **Structured completion verdicts** — `CompletionVerdict` scores test pass, scope, regression, and lint into a residual-risk band (Low / Medium / High) with the full audit breakdown in the inbox. - **Reversibility envelope** — task integrations and the final target merge receive distinct rollback anchors; `Revert mission` preserves later commits. - **Inspectable aborts** — abort retains Vigla-owned branches and worktrees for diagnosis; the explicit `Clean up artifacts` action removes them later without changing the target branch.
Worker execution - **Real CLI and mock workers** — Claude Code, Codex CLI, verified Antigravity, legacy Gemini CLI, profile-backed Kiro / Copilot, plus deterministic mock workers for development and demos. - **Isolated worktrees** — each worker gets its own git worktree and branch; work is inspected, merged, discarded, or reverted without touching your main checkout. - **Canonical event stream** — adapter-normalized status, cost, file, test, review, and terminal events (`event-schema`). - **Session-aware recovery** — Claude workers support retry and follow-up continuation; quota windows can pause missions and resume them when the window reopens; failures are classified for retry, continuation, or escalation.
Operations room - **Station canvas** — one tile per worker with dependency edges, live status, task, model, progress, ETA, cost, file and test counters. - **Worker drawer** — result, feed, terminal, files, tests, cost, and plan tabs; stop, retry / continue, switch models, assign squads. - **Review queue** — workers needing review surface as actionable cards with open, retry, continue, accept, and reject flows. - **Live terminal capture** — raw stdout/stderr preserved alongside normalized events; a power-user feed with every event is one toggle away. - **Squads** — group workers, designate leads, color-code the fleet.
Inbox, history, and replay - **Mission inbox** — completions, escalations, side effects, unresolved issues, audit breakdowns, and revert eligibility in one right rail; macOS notifications when a bound trips while the app is unfocused. - **Mission history** — browse audited missions with status, risk tier, and full drill-down. - **Worker replay** — page through event history, play / pause, step, scrub, change speed, and return to live.
Memory and context - **Local Memory Kernel** — repository-scoped memory written through a single-writer path and attached to future workers as context bundles. - **Pinned notes + auto-promoted insights** — pin facts, decisions, and hazards; completed work proposes durable notes after validation. - **Safety filters** — memory writes are size-limited, schema-checked, secret-scanned, and drift-checked. - **Vendor-native files as render targets** — `CLAUDE.md`, `AGENTS.md`, and `GEMINI.md` are generated projections, never the source of truth.
## Built in public
Roadmap illustration: a night watchpost signal route moves through hardening, modular expansion, an application-sandbox gate, platform branches, provenance, and transparent benchmarking A visual interpretation of the public roadmap. The linked document is the source of truth.
| Now | Next | Later | |---|---|---| | Harden real-CLI gates, local packaging, first run, and regression coverage | Verify more adapters and supervisors; prove [Mac App Store sandbox feasibility](https://github.com/Kilbex/Vigla/blob/main/docs/roadmap/mac-app-store.md) | Add Linux and Windows parity, richer memory provenance, reusable missions, and a public fleet benchmark | Priorities move with operator evidence and focused contributions. See the [full roadmap](https://github.com/Kilbex/Vigla/blob/main/ROADMAP.md) for acceptance boundaries and the work Vigla deliberately will not take on. ## Tech stack | Layer | Choice | |---|---| | Desktop shell | Tauri 2 (Rust host) | | Orchestrator | Rust 1.95, `tokio`, `sqlx` (SQLite), `tracing` | | UI | React 19, Vite, TypeScript, Tailwind v4, Zustand | | Canvas & terminal | React Flow (`@xyflow/react`), xterm.js | | IPC | `tauri-specta` typed bindings (Rust → TS) | | Tests | cargo test, Vitest, Playwright | The only abstraction Vigla permits is the event boundary: vendor CLI bytes → canonical events. Adapters live in `crates/adapters/{vendor}`, one crate per vendor, pure translation — no I/O, no process spawning, no git.
Storage paths | Path | What | Override | |---|---|---| | `~/Library/Application Support/Vigla/vigla.sqlite` | Events, missions, workers, memory index | `VIGLA_DB_PATH` | | `/.vigla/memory/notes/` | Long-term memory notes (Markdown), one store per repo | rooted at the repo's canonical git root, not under `VIGLA_DB_PATH` | | `~/Library/Logs/Vigla/vigla.log.YYYY-MM-DD` | Rolling daily structured logs | managed by `tracing-appender` |
Repo layout ``` vigla/ ├── app/ # Tauri 2 + React 19 + Vite + TS │ ├── src/ # React UI, Zustand stores, hotkeys │ └── src-tauri/ # Tauri host (Rust): IPC, event forwarding ├── crates/ # All Rust library/bin crates (Cargo workspace) │ ├── orchestrator/ # Rust supervision crate (business logic) │ │ ├── src/memory/ # Memory Kernel (event-sourced) │ │ ├── src/mission_runtime/ # Mission state machine + replay │ │ ├── src/mission_supervisor_run/ # Supervisor turns + review loop │ │ ├── src/supervisor/ # Worker process lifecycle + resume │ │ ├── src/arbiter/ # Bound-based escalation decisions │ │ └── resources/ # Bundled at compile time: │ │ ├── vendor_profiles/ # per-vendor command-rendering policy │ │ └── skills/ # worker skill set (embedded) │ ├── adapters/ # One pure crate per vendor CLI + supervisor │ ├── event-schema/ # Canonical typed event contract │ ├── mock-harness/ # Mock vendor CLI (credential-free demos) │ └── xtask/ # Workspace task runner (cargo xtask) ├── tests/ # Playwright e2e specs + real-CLI sample targets ├── docs/ # Lexicon, good-first-issues, media └── scripts/ # dev.sh, build.sh, capture-readme-media.cjs ```
Deep dive: [ARCHITECTURE.md](https://github.com/Kilbex/Vigla/blob/main/ARCHITECTURE.md) covers the orchestrator, memory kernel, mission lifecycle, arbiter / audit / recovery, event schema, and per-vendor adapters. ## Requirements - **macOS 12+.** Linux and Windows are on the [roadmap](https://github.com/Kilbex/Vigla/blob/main/ROADMAP.md) — the non-host Rust workspace is built, linted, and tested on Linux in CI; desktop packaging and platform UX are scoped on the roadmap. - Development: Rust 1.95 (pinned via `rust-toolchain.toml`), Node 22.x, pnpm 10.x, Xcode Command Line Tools. - Vendor CLIs are optional and only needed for real (non-mock) workers. ## Build a local DMG Vigla does not publish maintainer-built binaries. On a Mac, clone the source and run one command: ```sh ./scripts/build.sh ``` The script installs the locked frontend dependencies, builds the application, ad-hoc signs it without an Apple account or personal signing identity, verifies the app and disk image, and prints the DMG path and SHA-256 checksum. The local artifact remains under `target/release/bundle/dmg/`; no workflow uploads it. Keep the printed checksum with the artifact. [SECURITY.md](https://github.com/Kilbex/Vigla/blob/main/SECURITY.md#verifying-a-local-build) documents the independent `shasum`, `hdiutil`, and `codesign` checks. Prerequisites are the development tools listed in [Requirements](#requirements). Set `EMBEDDINGS=1` when running the command to include the optional embeddings feature. Its first use downloads the public FastEmbed model into the per-user cache; if that download is unavailable, retrieval falls back to local BM25. ## Known limitations Design trade-offs in the current build, not bugs: - **Real supervisor execution is Claude-gated.** The production mission-supervisor path and its end-to-end verification are Claude-backed today. - **Memory retrieval is local and best-effort.** Alias-expanded BM25 with optional embedding / hybrid re-ranking; degrades to lexical retrieval instead of blocking workers. - **The supervisor sees typed mission events, not raw worker dialogue.** By design — escalation is bounded on outcomes, not chain-of-thought. - **Session resume requires vendor session-ID support.** CLIs that don't expose a session ID can't be continued across app restarts. ## Why "Vigla"? **Vigla** (Byzantine Greek *βίγλα*, "watchpost" — from Latin *vigilia*, the root of *vigilance*) was the imperial guard regiment that kept the night watch on campaign: it posted the sentries, held the watchword, and ran the signal line so the emperor could actually sleep. That is this app's entire job — a supervisor that keeps trained watch over a fleet of powerful agents and wakes you only when something crosses a bound. In category terms: Vigla is an open-source control plane for supervised agent operations — coordinating fleets of AI coding agents instead of babysitting them one terminal at a time. ## Contributing Start with [CONTRIBUTING.md](https://github.com/Kilbex/Vigla/blob/main/CONTRIBUTING.md) and [ARCHITECTURE.md](https://github.com/Kilbex/Vigla/blob/main/ARCHITECTURE.md); project authority and maintainer succession are explicit in [GOVERNANCE.md](https://github.com/Kilbex/Vigla/blob/main/GOVERNANCE.md). Newcomer-friendly tasks live in [docs/GOOD_FIRST_ISSUES.md](https://github.com/Kilbex/Vigla/blob/main/docs/GOOD_FIRST_ISSUES.md) — adapter fixture work is the recommended first PR and is designed to land in under two hours. Questions and bug-report routing: [SUPPORT.md](https://github.com/Kilbex/Vigla/blob/main/SUPPORT.md). Security reports: see [SECURITY.md](https://github.com/Kilbex/Vigla/blob/main/SECURITY.md). Reviewing or recording Vigla? The public [creator kit](https://github.com/Kilbex/Vigla/blob/main/docs/operations/creator-kit.md) provides a 10-minute script, credential-free inputs, media, evidence, and exact claim boundaries. Operators coming from vibe-kanban can use the [concept-by-concept migration guide](https://github.com/Kilbex/Vigla/blob/main/docs/migrations/from-vibe-kanban.md); it does not claim a database importer or kanban-board parity. ## License [Apache 2.0](https://github.com/Kilbex/Vigla/blob/main/LICENSE), with the project [NOTICE](https://github.com/Kilbex/Vigla/blob/main/NOTICE). Bundled component attribution and retained licenses are in [THIRD_PARTY_NOTICES.md](https://github.com/Kilbex/Vigla/blob/main/THIRD_PARTY_NOTICES.md); the generated, self-contained [THIRD_PARTY_NOTICES.txt](https://github.com/Kilbex/Vigla/blob/main/THIRD_PARTY_NOTICES.txt) covers the locked production Rust and JavaScript dependency graphs. ---
If Vigla looks useful, **a ⭐ helps other agent operators find it.**
## Architecture reference # Vigla Architecture Vigla is split into a Tauri host, a React frontend, and a Rust orchestrator. The core rule is simple: **UI hosts integrate; the orchestrator owns business behavior.** Adapters are pure line-by-line translators with no IO. Persistence and process management live in the orchestrator. This document is the canonical design reference; the root [`README.md`](https://github.com/Kilbex/Vigla/blob/main/README.md) covers *what* Vigla is, *how to install and run it*, and *how to compare it* to alternatives — but defers all design depth to this file. File pointers below are paths from the repo root, verified on 2026-07-21. ## High-Level Flow ```mermaid flowchart LR UI["React UI"] --> IPC["Tauri commands/events"] IPC --> Host["app/src-tauri host glue"] Host --> Services["orchestrator host_services"] Services --> Runtime["MissionRuntime"] Runtime --> Workspace["MissionWorkspace git worktrees"] Runtime --> SupervisorRun["Supervisor-driven mission loop"] SupervisorRun --> WorkerDispatch["Real/mock worker dispatch"] WorkerDispatch --> Adapters["Vendor adapters"] Adapters --> Events["event-schema canonical worker events"] Events --> Repo["Repository SQLite worker-event persistence"] Runtime --> MissionEvents["mission event bus + bounded replay"] MissionEvents --> AuditHistory["persisted audit summaries"] Events --> UI MissionEvents --> UI ``` ## Crates and Responsibilities | Area | Path | Responsibility | | --- | --- | --- | | Frontend | `app/src/` | React UI, keyboard handling, visual mission/worker state | | Tauri host | `app/src-tauri/src/lib.rs` | IPC registration, app setup, typed event forwarding | | Host services | `crates/orchestrator/src/host_services.rs` | Host-independent validation, mission lifecycle locking, backend routing | | Mission runtime | `crates/orchestrator/src/mission_runtime/` | Mission state machine, mock timeline, event replay, merge/abort/resolve | | Supervisor loop | `crates/orchestrator/src/mission_supervisor_run/` | Real/scripted supervisor turns, prompts, budget events, worker review loop | | Worker supervisor | `crates/orchestrator/src/supervisor/` | Standalone worker process lifecycle, retry coordination, resume support | | Git workspace | `crates/orchestrator/src/mission_workspace/mod.rs` | Mission branches, worktrees, integrations, final merge/discard | | Event schema | `crates/event-schema/` | Canonical typed event contract shared by adapters and UI | | Adapters | `crates/adapters/*` | Pure line-by-line translation from vendor CLI streams to canonical events | | Vendor profiles | `crates/orchestrator/resources/vendor_profiles/` | Command rendering policy for supported CLIs | ## Adapter Boundary Adapters are the main contribution surface. An adapter: - Receives one stdout/stderr line at a time. - Maintains only local parser state such as sequence number, current session id, or accumulated assistant text. - Emits zero or more canonical `event_schema::Event` values. - Does not spawn processes, read or write files, call git, or persist data. Process management belongs in `crates/orchestrator/src/supervisor/` and `crates/orchestrator/src/mission_worker_dispatch.rs`. Persistence belongs in `crates/orchestrator/src/repository/mod.rs`. ## Memory Kernel — `crates/orchestrator/src/memory/` Local, event-sourced long-term memory. Six anchoring design choices: | # | Design choice | Where | |---|---|---| | 1 | **Single-writer to project memory.** Vendor native files (`CLAUDE.md`/`AGENTS.md`/`GEMINI.md`) are render *targets*, never read as truth. | `memory/mod.rs:4-7` | | 2 | **Event-sourced.** Witnesses are append-only; confidence is *derived* by `scoring.rs`, not stored. Weight changes need no migration. | `memory/witnesses.rs:1-7` | | 3 | **Anchored block.** Kernel owns one delimited region per native file; everything outside is preserved byte-exact across writes. | `memory/coherence.rs:1-13` | | 4 | **Per-repo isolation.** A registry opens one kernel per canonical repo root at `/.vigla/memory/memory.sqlite`. | `memory/registry.rs:1-37` | | 5 | **Pre-event secret scanning.** Patterns + 20-char-window entropy detector run *before* `MemoryProposed` persists. | `memory/scanner.rs:1-19` | | 6 | **Fail-soft attach.** Errors from listing / composing / rendering are swallowed + logged; memory must never block mission dispatch. | `memory/attach.rs:9-18` | **Phase status** (`memory/mod.rs:9-45`). P0/P1 shipped. P2 completed the closed loop: *worker proposes → supervisor ratifies → mission accept promotes → next mission's composer picks it up*. P3 is also complete: alias-expanded BM25, optional local MiniLM embeddings, MMR diversity, retrieval-driven composition, and BM25-only graceful degradation all ship behind stable interfaces. **Note state machine** (states from `event_schema::memory::NoteState`): ``` Owned ──── (supervisor ratify + confidence ≥ τ_kind) ────► Promoted │ │ │ scrub barrier conflict signal │ demote ▼ ▼ ▼ Invalid Disputed (back to Owned) ``` **Confidence formula** (`scoring.rs:54-72`) — pure function over witness rows: ``` raw = WIT_W · Σ(witness.weight) + AGE_W · recency_bonus(witnesses, now) # half-life 90 days − CONF_W · conflict_penalty(witnesses) confidence = sigmoid(raw) # ∈ (0, 1) ``` Coefficients `WIT_W = 1.0`, `AGE_W = 0.2`, `CONF_W = 0.5` (`scoring.rs:28-30`). **Promotion thresholds** are kind-asymmetric (`policy.rs:30-43`): | Kind | Threshold | Floor with user-authored | |---|---|---| | `hazard` | 0.55 | 0.50 | | `fact` | 0.70 | 0.50 | | `procedure` | 0.75 | 0.50 | | `decision` | 0.85 | 0.50 | | (unknown) | 0.90 | — | The **user-oracle fast path** (`policy.rs:3-17`, `USER_AUTHORED_FAST_PATH_BAR = 0.5`) treats the effective bar as `min(τ_kind, 0.5)` when a `UserAuthored` witness is present — preserves the *"talking to Vigla teaches it"* promise. **Submodule responsibilities:** | File | Responsibility | |---|---| | `kernel/` | Facade. Sub-files: `types`, `ratify`, `barrier`, `proposal`, `pin`, `compose`, `sweep`, `query`. | | `store.rs` | T3 long-term store. Atomic same-dir tmp+rename; `prepare_note` + `mint_note_in_tx` split for ratify atomicity. | | `composer.rs` | Deterministic manual assembly plus the shared rendering path used after retrieval and MMR selection. | | `attach.rs` | Mission-lifecycle bridge. Composes + renders into worker worktree. Fail-soft. | | `coherence.rs` | Anchor span finder + writer + drift detection. | | `adapter.rs` + `adapters/` | `MemoryAdapter` trait + Claude/Codex/legacy Gemini renderers. Pure transforms. | | `witnesses.rs` | Append-only signal store. `(note_id, kind, source_event_id)` unique. | | `scoring.rs` | Stateless confidence sigmoid. | | `policy.rs` | Promotion thresholds + user-oracle fast path. | | `reflection.rs` | Post-mission consolidation. `on_accept` / `on_scrub`. Idempotent per `(mission_id, kind)`. | | `scanner.rs` | Pre-event secret detection (fixed patterns + entropy window ≥ 4.0). | | `intent_router.rs` + `intent_sink.rs` | Pure router from worker `MemoryIntent` → kernel `on_proposal`. | | `registry.rs` | Per-repo kernel pool. | | `handoff.rs` | Cross-worker structured notes for DAG-downstream tasks. | | `archive.rs` | Tier-2G cold storage (zstd JSONL.zst). | | `context_match.rs` | BM25/optional-embedding context matching with a substring compatibility fallback. | | `retrieval/` | Tokenization, aliases, BM25, optional embeddings, hybrid scoring, vector storage, and MMR. | **Storage layout:** ``` /.vigla/memory/ ├── memory.sqlite # index: memory_notes, memory_witnesses, │ # memory_links, memory_provenance, │ # memory_taxonomy, memory_events, │ # memory_bundles, memory_handoffs ├── notes/.md # full note bodies (frontmatter + body) ├── missions// │ ├── pending.jsonl.zst # archived after mission barrier │ └── bundles//.md └── events-archive/ └── YYYY-MM.jsonl.zst # monthly rollup past retention ``` ## Context System The supervisor's surface for getting the right memory in front of the right worker at the right time. | Piece | What it does | File | |---|---|---| | **Composer** | Manual or retrieval-selected bundle assembly. Same ordered note IDs ⇒ same `bundle_hash`; budget overflow drops the tail. | `memory/composer.rs:1-26` | | **Attach** | Post-worktree-create / pre-dispatch injection. Builds a retrieval brief from mission/task/handoff context, retrieves and renders promoted notes, then falls back to manual budgeted composition on failure. Fail-soft. | `memory/attach.rs` | | **`MemoryAdapter` trait** | Pure transforms per vendor (`native_file_name`, `anchor_open/close`, `max_tokens`, `render_block_body`). | `memory/adapter.rs:1-25` | | **Context-request loop** | Worker emits `RequestContext { kind, detail }` → ranked promoted-note match (BM25 plus optional embeddings) → match supplied next turn; a miss escalates. | `memory/context_match.rs` | | **Drift detection** | `find_anchor_span` + `detect_drift` at the start of each worker turn. Outcomes: `Drift` / `AnchorMissing` / `FileMissing`. | `memory/coherence.rs:5-17` | **Context-request flow:** ``` worker emits RequestContext │ ▼ context_match::match_context (BM25 + optional embedding ranking; substring compatibility fallback) │ ├── Found ──► supplied via next-turn rework-directive channel │ └── Missing ──► MissionEventKind::ContextRequestUnmet └─► ArbiterDecided { bound: Some(Scope), evidence } (user sees the gap in the inbox) ``` **Budgets** (`memory/hierarchy.rs:20-32`): | Constant | Value | Meaning | |---|---|---| | `T1_MAX_TOKENS_DEFAULT` | 1200 | Per-worker T1 token budget | | `FAULT_BUDGET_PER_MISSION` | 8 | `memory.fetch` requests before kernel denies | | `NOTE_BODY_CAP_BYTES` | 4096 | Atomic notes; encourages splitting | Budget events surface as `MissionEventKind::ContextBudgetExceeded` / `ContextBudgetTruncated`. ## Skills — `crates/orchestrator/src/skills/` Curated procedural playbooks injected into each worker before it starts — a separate, simpler sibling of the Memory Kernel that reuses the same native-file anchor-block injection *pattern* without the event-sourcing, witnesses, or confidence machinery. Where memory is *learned*, skills are *authored and enabled*. | Piece | What it does | File | |---|---|---| | **Library** | Loads a bundled curated set (compiled via `include_str!` from the crate’s `resources/skills/`) plus user skills from `/.vigla/skills//SKILL.md`; a user `id` shadows the bundled one. File-based — no SQLite, no migration. | `skills/library.rs`, `skills/bundled.rs` | | **Format** | `SKILL.md` = `---` frontmatter (`name`, `description`, `scope`, `enabled`, `priority`) + markdown body, parsed by a dependency-free single-line-scalar parser. An unrecognized `scope` falls back to repo scope (skill stays available, never silently vanishes). | `skills/library.rs::parse_skill` | | **Selection** | Enabled skills whose `scope` is `repo` or the worker's vendor, ordered `priority` desc then `id` asc (deterministic). Mirrors memory's promoted-note Tier-2B selection. | `skills/library.rs::select_for_worker` | | **Render** | Deterministic body into a **second** anchor region `` (distinct from `vigla:memory`), token-budgeted (`SKILLS_TOKEN_BUDGET = 4000`, tail-dropped, first skill always kept). | `skills/render.rs` | | **Attach** | Fail-soft bridge: after memory attach, writes the skills region by reusing the pure, parameterized `memory::coherence::write_anchor_block`; logs and returns on any error — **never blocks dispatch**. | `skills/attach.rs` | **Lifecycle & threading.** The library is resolved once per mission in `host_services::start_mission` (`SkillLibrary::open_for_repo`, no registry — loading a few files is cheap) and threaded as `Option>` parallel to the memory kernel, down to `TaskRunCtx`. `attach_skills_for_worker` runs immediately **after** memory attach at all three worker-dispatch sites (initial spawn, rework, vendor fallback) in `mission_supervisor_run/run_task.rs`; the sequential awaits serialize the two writes to the same native file. The two anchored regions coexist because the anchor writer is parameterized on its delimiters and preserves every byte outside its span — so skills never touch the memory region or user content. Success emits the telemetry-only `MissionEventKind::SkillsAttached { worker_id, skill_ids, tokens, dropped }` (routed `Internal`, like `ContextBundleComposed`) for the operator's trust trail. **Out of scope (later layers, mirroring memory's roadmap):** per-mission manual equip, relevance/retrieval selection, a skill-management UI, and native `.claude/skills/` provisioning. ## Worker (Employee) Management Six concerns. Each one is a separate file or directory. ### A. Process lifecycle — `crates/orchestrator/src/supervisor.rs` `Supervisor` owns running children + cancellation handles + a `session_ids` map captured once per worker and persisted to the repository. `SupervisorError` enumerates the public failure surface (`supervisor.rs:32-58`): `UnknownScript`, `MockHarnessMissing`, `WorkerNotFound`, `WorkerStillRunning`, `ResumeUnsupported(Vendor)`, `SessionIdMissing`, `Io`, `Repository`. ### B. Per-worker supervision loop — `crates/orchestrator/src/supervisor/adapter_supervision.rs` Single-threaded line-pump feeds **both stdout and stderr** into one adapter instance (no `Mutex`). Lines capped at `MAX_LINE_BYTES`; a `stderr_eof` flag prevents `select!` tight-loop on a closed stream; `session_id_captured` ensures `set_session_id` runs exactly once with an explicit warning logged on persist failure. ### C. Real-CLI dispatch — `crates/orchestrator/src/mission_worker_dispatch.rs` Three things this module does that nothing else does: 1. **Spawns real profile-backed vendor CLIs** inside the worker worktree. Antigravity's production route is covered by the opt-in hosted gate in `crates/orchestrator/tests/real_antigravity_run.rs`. 2. **Commits on the worker's behalf** — workers are forbidden from running `git`. Concentrating commits in the orchestrator gives atomicity (one commit per submission), boundary clarity ("done" = process exit), and safety (worker can't push / switch branches / commit partial state). 3. **Streams stdout/stderr** through the same adapter pipeline as the standalone supervisor — mission-spawned and standalone real-CLI workers are observable identically. Routing (`mission_supervisor_run/worker_pass.rs`): - `worker_model = None | "auto"` → task-role routing to a real CLI - A registered vendor (`claude`, `codex`, `antigravity`, `kiro`, `copilot`, or legacy `gemini`) → that real CLI - A comma-separated roster → one real CLI per task index, cycling as needed - Invalid selections are rejected pre-spawn at the host IPC. `DEFAULT_WORKER_TIMEOUT = 300s`; captured output capped at 64 KB with a truncation marker; 250 ms post-exit drain. ### D. Session + resume — `crates/orchestrator/src/supervisor/resume.rs` `continue_worker` requires (in order): 1. Worker exists. 2. Worker is not currently running (else `WorkerStillRunning`). 3. Vendor supports resume — **today only `Vendor::Claude`**. Every other registered vendor explicitly returns `ResumeUnsupported(...)`. 4. Worker has a saved `session_id` (else `SessionIdMissing`). ### E. Vendor profiles — `crates/orchestrator/src/vendor_profile.rs` + `crates/orchestrator/resources/vendor_profiles/*.json` Single source of vendor-specific CLI launch flags + declared side effects. JSON profiles bundled via `include_str!`. `CommandRole` (worker/supervisor) + `CommandVars` + `render_command_args` keeps vendor-specific template strings out of runtime code. ### F. Scope ACL — `crates/orchestrator/src/acl/` `MissionSpec.scope_paths` declares the worker's permissible write surface. Enforcement is two-tier: (1) sentinel written to `.vigla/acl.json` inside the worktree, paired with `.vigla/.gitignore` (`*`) so the worker's `git add -A` doesn't sweep the sentinel into the mission commit; (2) post-commit diff check trips `AuthorityBound::Scope` on any out-of-scope write. ## Mission Lifecycle Mission startup is intentionally host-independent: 1. A host calls `MissionController::start_mission`. 2. `host_services` validates the working directory, enforces one active mission, creates a `MissionWorkspace`, and selects mock vs real supervisor/worker backends. 3. `MissionRuntime` owns state transitions and event replay. 4. The host subscribes to `MissionEventReceiver` and forwards events through its UI transport. This prevents desktop-specific code from owning mission policy and keeps additional platform hosts from duplicating business logic. **States** (`crates/orchestrator/src/mission.rs::MissionState`): ```text Created → Executing ⇄ PendingPlanApproval │ └─ reject_plan → Aborted ├─⇄ Reviewing ├─⇄ Paused { vendor } (automatic quota resume) ├─→ Attention (user chooses merge/discard) └─→ CompletePendingMerge → Merged | Discarded Any non-terminal state ── abort ──→ Aborted ``` `Completed` is an event emitted before final disposition; it is not a `MissionState`. `Extended` remains a historical wire shape only. Current review controls expose Merge and Discard because supervisor re-entry is not yet a tested runtime path. **Event kinds** (`crates/orchestrator/src/mission_event/mod.rs::MissionEventKind`) are grouped by concern (representative variants shown): | Group | Variants | |---|---| | **Lifecycle** | `Created`, `ExecutionStarted`, `Decomposition`, `WorkerSpawned`, `WorkerResultSubmitted`, `Integrated`, `Completed`, `Aborted`, `WorkerProgress` | | **Plan approval** | `PlanProposed`, `PlanConfirmed`, `PlanRegenerationRequested`, `PlanRejected`, `DecompositionRejected` | | **Arbiter** | `ReviewStarted`, `AuditCompleted`, `ArbiterDecided`, `PostIntegrationAuditCompleted` | | **User action** | `MissionReverted`, `MergeResolved`; `MissionExtended` is decode-only compatibility | | **Recovery** | `RecoveryDecided`, `MissionPaused`, `MissionResumed`, `ContextBudgetExceeded`, `ContextBudgetTruncated`, `ContextRequestUnmet` | | **Memory** | `HandoffNote`, `CompletionVerdictRendered`, `SubSupervisorRefused` | | **Other** | `SideEffectLogged`, `TestResult` | **Runtime** (`crates/orchestrator/src/mission_runtime/`): `mock.rs` is the scripted task per MSV spec; the real path lives in `crates/orchestrator/src/mission_supervisor_run/`. Event bus is a broadcast channel with replay for late subscribers (`MAX_HISTORY = 2048`). **Workspace** (`crates/orchestrator/src/mission_workspace/mod.rs`): one git worktree per worker under `.vigla/worktrees//`, with branches in the `vigla//...` namespace. Workers integrate serially into `vigla//supervisor`; an explicit final action merges that branch into the mission's validated local `target_ref`. A pre-integration tag protects each staged task merge. Final merge also records durable `before` and `merged` tags for the target branch, then removes the mission worktrees and branches. The user-facing rollback applies a normal Git revert to the recorded merge commit, so commits added afterward remain intact. The staged recovery proof separately selects the earliest pre-integration tag to remove every task integration. Abort intentionally retains mission artifacts for diagnosis. A separate, durably tracked cleanup action is authorized only by an `aborted` outcome with the exact recorded repository identity; it removes the mission's worktrees, branches, and intermediate tags without touching the target branch. ## Arbiter + Judgment + Audit + Recovery **Arbiter** (`crates/orchestrator/src/arbiter/`) — pure policy function. Consumes `AuditReport`, emits `ArbiterDecision`. No IO, no vendor calls (`arbiter/mod.rs:1-12`). Four authority bounds (`arbiter/bound.rs:14-26`): | Bound | Trips when | |---|---| | **Scope** | Worker touched files outside declared `scope_paths` | | **Reversibility** | Snapshot creation failed or merge target unreachable | | **Risk** | A risk detector tripped (schema migration, mass deletion, secret-touching change) | | **Quality** | Audit composite below policy floor AND rework budget exhausted | Priority order (`arbiter/mod.rs:36-44`): Scope → Risk → Quality. Scope and Risk always escalate; Quality is recoverable via rework budget. Decisions (`arbiter/decision.rs:21-37`): `Accept(payload)`, `Extend { rework_kind, attempts_remaining }`, `Scrub { reason, retained_artifacts, partial_audit }`, `Escalate { bound, evidence, suggested_user_action }`. **Judgment** (`crates/orchestrator/src/judgment/`) — mission-level "is this done?" verdict. Pure module; emitted as `MissionEventKind::CompletionVerdictRendered`. Risk band boundaries (`judgment/risk_band.rs:29-38`): - `Low` ⇐ overall ≥ 0.85 AND zero security flags AND quiet recovery (total < 3 occurrences) - `High` ⇐ overall < 0.7 OR > 1 security flag - `Medium` ⇐ otherwise (residual) Recovery activity **only pushes the band up** — busy history bumps `Low` to `Medium` but cannot demote `High`. **Audit** (`crates/orchestrator/src/audit/`) — entry point `audit_submission`. Five sub-scorers blended by `composite::blend_overall` with a `WeightProfile`: | Scorer | Measures | |---|---| | `test_pass` | Configured or detected test-run outcome | | `scope` | Diff stays within `scope_paths` | | `regression` | Newly-failing tests vs. newly-passing | | `lint` | Linter compliance | | `security` | `SecurityFlagKind` (mass deletion, schema migration, secret-touching, …) | `AuditTier` selects which scorers run. Smoke performs only pure scope/security checks. Standard and Deep run tests and lint; regression contributes only when a baseline was captured, so a missing baseline cannot inflate the composite. **Recovery** (`crates/orchestrator/src/recovery/`) — `quota.rs` owns per-vendor rolling-window state, persisted to `vendor_quota_state` (migration 0009). Default windows: Claude 5h, every other registered real vendor 1h, Mock 100 ms. `QuotaSignalSource::AdapterParsed` vs. inferred — the adapter parses a vendor-specific quota error and supplies an explicit reset, or the tracker fills in `now + default_window_ms`. Host restart reads `estimated_reset_at_ms` and either resumes immediately or schedules the wake-up. Surfaces as `MissionEventKind::MissionPaused` → `MissionResumed`. ## Persistence and Event Model Worker events follow `event-schema`. The repository stores canonical event payloads and worker/task metadata in SQLite. Unknown event types are tolerated on replay so older builds can inspect newer logs without crashing. Mission events are separate and broadcast through `MissionRuntime` with bounded replay for late subscribers. A dedicated subscriber persists worker and mission audit summaries into `audit_reports`, using source-event timestamps, so cross-mission History does not depend on an open frontend listener. **Repository** (`crates/orchestrator/src/repository/mod.rs`) — SQLite via sqlx; pool `POOL_ACQUIRE_TIMEOUT = 5s`, per-connection `SQLITE_BUSY_TIMEOUT = 3s`. File-pool max 5 connections. Migrations 0001–0014 in `crates/orchestrator/migrations/`, with an upgrade-path test at `crates/orchestrator/tests/migration_upgrade.rs`. ## Cross-Cutting **Event schema** (`crates/event-schema/`) — runtime-free crate (only `serde` + `specta`). Closed `Vendor` set: `Claude`, `Codex`, `Gemini`, `Antigravity`, `Kiro`, `Copilot`, `Opencode`, `Mock`. Aider removed in schema 2.0 (major bump; `aider_removed.rs` test locks this). Envelope is `{schema_version, worker_id, task_id, seq, ts, type, payload}`. The memory submodule re-exports the canonical memory vocabulary (`MemoryEvent`, `MemoryNoteAuthored`, `MemoryPromoted`, `MemoryProposed`, `MemoryRatified`, `MemoryBarrier`, `MemoryWitnessRecorded`, `NoteKind`, `NoteState`, `Scope`, `WitnessKind`, `BarrierKind`). **Adapters** (per-vendor crates): - `crates/adapters/core` — `Adapter` trait + `MemoryIntent` extraction - `crates/adapters/claude` — `claude -p --output-format stream-json` parser - `crates/adapters/codex` — `codex --json` parser - `crates/adapters/antigravity` — production Antigravity raw-log adapter; its hosted gate exercises the full spawn, event, submission, integration, and verification path - `crates/adapters/kiro` — Kiro raw-log adapter with terminal synthesis - `crates/adapters/copilot` — Copilot raw-log adapter with terminal synthesis - `crates/adapters/gemini` — maintained legacy Gemini stream parser - `crates/adapters/supervisor` — **different shape.** Parses Claude-running-the-playbook into `SupervisorIntent` envelopes (`decompose`, `spawn_worker`, `review`, `declare_complete`) instead of canonical events. Audit and test gates run automatically; the supervisor doesn't edit files; it semantically reviews a bounded committed-diff excerpt after every real worker pass and makes mission-level decisions which map to mission events on a separate channel (`crates/adapters/supervisor/src/lib.rs:7-19`). **Mock harness** (`crates/mock-harness/`) — bundled scripts for credential-free demos: `claude_happy`, `codex_blocked`, `gemini_happy`, `gemini_blocked`, `gemini_failed`, `gemini_terminal`, `claude_quota_exhausted`. ## Testing Strategy - Adapter crates should have fixture-driven tests. - Orchestrator business logic should be testable without Tauri. - Tauri host tests should focus on IPC-adjacent glue and platform probes. - Real CLI tests stay ignored by default because they require local credentials and installed tools. Useful commands: ```sh cargo xtask test # self-contained: builds the release # mock-harness, then cargo test --workspace cargo test -p vigla-orchestrator --all-targets cargo test -p vigla-host --lib cd app && pnpm exec vitest run ``` `cargo xtask test` is the self-contained entry point — the Tauri host bundles `target/release/mock-harness` as a resource that `tauri_build` validates on every compile, so a bare `cargo test --workspace` fails from a clean tree until that binary exists. `cargo xtask {build,clippy,ci}` cover the other gates. ## Adding a New Vendor Adapter 1. Add or copy a crate under `crates/adapters//`. 2. Implement `adapter_core::Adapter`. 3. Add captured JSONL or text fixtures that reflect the vendor CLI output. 4. Add parser tests for normal completion, failure, cancellation/finalize behavior, and session id capture if the CLI supports resume. 5. Add a vendor profile under `crates/orchestrator/resources/vendor_profiles/` when the worker can be spawned by Vigla. 6. Wire the worker vendor routing only after parser tests are stable.