Metadata-Version: 2.4
Name: stanchion
Version: 3.0.0
Summary: Local-first runtime governance daemon for coding agents.
Project-URL: Homepage, https://stanchionai.com
Author: Daniel Warren
License: PROPRIETARY LICENSE
        
        Copyright (c) 2026 Daniel Warren. All rights reserved.
        
        This software and associated documentation files (the "Software") are the
        confidential and proprietary information of Daniel Warren ("the Owner").
        Unauthorized copying, modification, distribution, public display, public
        performance, or use of the Software, in whole or in part, by any means, is
        strictly prohibited.
        
        No license, express or implied, by estoppel or otherwise, to any intellectual
        property rights is granted by this document. Any rights not expressly granted
        are reserved by the Owner.
        
        THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
        IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
        FITNESS FOR A PARTICULAR PURPOSE, AND NONINFRINGEMENT. IN NO EVENT SHALL THE
        OWNER BE LIABLE FOR ANY CLAIM, DAMAGES, OR OTHER LIABILITY, WHETHER IN AN
        ACTION OF CONTRACT, TORT, OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION
        WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
        
        For licensing inquiries, contact the copyright holder.
License-File: LICENSE
License-File: NOTICE
Classifier: Development Status :: 4 - Beta
Classifier: License :: Other/Proprietary License
Classifier: Operating System :: MacOS
Classifier: Operating System :: POSIX :: Linux
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Software Development
Classifier: Topic :: System :: Monitoring
Requires-Python: <3.14,>=3.11
Requires-Dist: anthropic<1.0,>=0.39
Requires-Dist: apscheduler<4.0,>=3.10
Requires-Dist: boto3<2.0,>=1.35
Requires-Dist: cryptography<47,>=43
Requires-Dist: fastapi<1.0,>=0.115
Requires-Dist: httpx<1.0,>=0.27
Requires-Dist: keyring<26,>=24
Requires-Dist: mcp<2.0,>=1.0
Requires-Dist: opentelemetry-api<2.0,>=1.27
Requires-Dist: opentelemetry-proto<2.0,>=1.27
Requires-Dist: opentelemetry-sdk<2.0,>=1.27
Requires-Dist: prometheus-client<1.0,>=0.20
Requires-Dist: protobuf<7,>=4
Requires-Dist: psutil<8.0,>=5.9
Requires-Dist: pydantic<3.0,>=2.9
Requires-Dist: pyyaml<7.0,>=6.0
Requires-Dist: rich<15.0,>=13.9
Requires-Dist: sqlmodel<0.1,>=0.0.22
Requires-Dist: starlette<2.0,>=1.0.1
Requires-Dist: textual<6.0,>=0.80
Requires-Dist: tiktoken<1.0,>=0.7
Requires-Dist: typer<1.0,>=0.13
Requires-Dist: uvicorn[standard]<1.0,>=0.32
Provides-Extra: attestation
Requires-Dist: in-toto>=2.0; extra == 'attestation'
Provides-Extra: browser
Requires-Dist: playwright>=1.48; extra == 'browser'
Provides-Extra: dev
Requires-Dist: bandit>=1.7; extra == 'dev'
Requires-Dist: boto3-stubs[s3,sts]>=1.35; extra == 'dev'
Requires-Dist: cyclonedx-bom>=4.5; extra == 'dev'
Requires-Dist: hypothesis<7.0,>=6.100; extra == 'dev'
Requires-Dist: libcst>=1.4; extra == 'dev'
Requires-Dist: mypy>=1.13; extra == 'dev'
Requires-Dist: pip-audit>=2.7; extra == 'dev'
Requires-Dist: pip-licenses>=5.0; extra == 'dev'
Requires-Dist: pytest-asyncio>=1.0; extra == 'dev'
Requires-Dist: pytest-cov>=6.0; extra == 'dev'
Requires-Dist: pytest-xdist>=3.6; extra == 'dev'
Requires-Dist: pytest>=8.3; extra == 'dev'
Requires-Dist: ruff==0.15.14; extra == 'dev'
Requires-Dist: semgrep>=1.90; extra == 'dev'
Requires-Dist: types-protobuf; extra == 'dev'
Requires-Dist: types-psutil; extra == 'dev'
Requires-Dist: types-pyyaml; extra == 'dev'
Provides-Extra: gcs
Requires-Dist: google-cloud-storage>=2.10; extra == 'gcs'
Provides-Extra: kafka
Requires-Dist: aiokafka>=0.10; extra == 'kafka'
Provides-Extra: ml
Requires-Dist: scikit-learn>=1.3; extra == 'ml'
Provides-Extra: otlp
Requires-Dist: opentelemetry-exporter-otlp-proto-grpc<2.0,>=1.27; extra == 'otlp'
Requires-Dist: opentelemetry-exporter-otlp-proto-http<2.0,>=1.27; extra == 'otlp'
Provides-Extra: postgres
Requires-Dist: psycopg[binary]<4,>=3.2; extra == 'postgres'
Requires-Dist: sqlalchemy[asyncio]>=2; extra == 'postgres'
Provides-Extra: rag
Requires-Dist: numpy>=1.24; extra == 'rag'
Requires-Dist: sentence-transformers>=2.2; extra == 'rag'
Requires-Dist: sqlite-vec>=0.1.0; extra == 'rag'
Provides-Extra: s3
Requires-Dist: boto3>=1.34; extra == 's3'
Provides-Extra: tui
Requires-Dist: textual>=0.50; extra == 'tui'
Provides-Extra: windows
Requires-Dist: oschmod>=0.3.12; extra == 'windows'
Requires-Dist: portalocker>=2.8; extra == 'windows'
Requires-Dist: pywin32>=306; (sys_platform == 'win32') and extra == 'windows'
Description-Content-Type: text/markdown

<div align="center">

<img src="docs/assets/stanchion-logo.png" width="160" alt="Stanchion" />

# Stanchion

**Local-first runtime governance for AI coding agents: see everything an agent does, and optionally block the risky parts — without your code or prompts ever leaving your machine.**

*Flagship product — Stanchion v3.0.0 — GA candidate (see `ga_gates.yaml`)*

`Confidential & Proprietary` · `Local-first` · `Zero data egress` · `40+ CLI verbs`

</div>

---

> ## ⚠️ Confidential and Proprietary Intellectual Property
>
> This repository, its source code, and all associated features, functions,
> algorithms, and design concepts are the **exclusive intellectual property of
> Daniel Warren**. It contains strictly confidential and proprietary
> information.
>
> Every source file in this repository carries the proprietary watermark
> below. Any unauthorized access, use, reproduction, modification,
> distribution, or alteration of this code — in whole or in part — is
> expressly forbidden without explicit, prior written consent from Daniel
> Warren.
>
> **© 2026 Daniel Warren. All rights reserved.**

```
/******************************************************************************
 *  PRODUCT:    Stanchion v3.0.0
 *  INVENTOR:   Daniel Warren
 *  CONFIDENTIAL AND PROPRIETARY INTELLECTUAL PROPERTY — ALL RIGHTS RESERVED.
 ******************************************************************************/
```

---

## Table of contents

- [Why Stanchion](#why-stanchion)
- [The three independently-verified surfaces](#the-three-independently-verified-surfaces)
- [5-minute quickstart](#5-minute-quickstart)
- [Honest scope — read this before you rely on anything](#honest-scope--read-this-before-you-rely-on-anything)
- [Platform breadth beyond the verified three](#platform-breadth-beyond-the-verified-three)
- [The three-plane architecture](#the-three-plane-architecture)
- [System architecture](#system-architecture)
- [Capture coverage](#capture-coverage)
- [Audit chain — tamper-evident ledger](#audit-chain--tamper-evident-ledger)
- [Extension-host safety](#extension-host-safety)
- [Fleet management](#fleet-management--multi-machine-governance)
- [Feature catalog](#feature-catalog)
- [Installation](#installation)
- [CLI reference](#cli-reference)
- [Configuration](#configuration)
- [Project structure](#project-structure)
- [Testing](#testing)
- [Security &amp; privacy](#security--privacy)
- [License](#license)

---

## Why Stanchion

An AI coding agent is fast and powerful — and opaque. Without instrumentation
the operator cannot answer basic questions mid-build:

- How many tokens has this session burned? Across which models? At what cost?
- What's the agent doing **right now** — and which files has it touched?
- Did it run anything dangerous? Is it looping? Is it stalling?
- Did the agent quietly swap to a non-approved model halfway through?
- Can I roll back the last prompt's changes if it went wrong — atomically?
- If this session is investigated next quarter, can I prove what happened?

**Stanchion** is a local-first control plane that sits alongside an AI coding
agent and gives the operator **live visibility and real, opt-in governance**
over what that agent is doing — every token, every tool call, every file
edit, every model swap, and every signal of behavioral drift — entirely on
the operator's own machine. It observes by default; you enable an
enforcement posture to block. The governance layer can **budget, detect,
gate, seal, and roll back**, and the **tamper-evident audit chain** means the
operator can still prove what happened after the fact.

Nothing but a signed license heartbeat — a secure, opaque install ID plus the
license token, and nothing else — leaves the host; your code, prompts,
and usage stay on this machine. The daemon is loopback-bound, state is local
SQLite (single-writer WAL) or PostgreSQL for multi-user deployments, and no
code or telemetry is transmitted to any third party without an explicit
operator-signed egress sign-off.

Stanchion is one engine (the Python daemon) consumed by platform surfaces (33
platform directories: 3 GA-verified, the rest experimental — see
`apps/PROXY_STATUS.json`) through two stable contracts — the daemon HTTP API and
the `@stanchion/client` SDK. Core never imports a platform.

---

## The three independently-verified surfaces

Stanchion ships **33 platform directories** (tiered in `apps/PROXY_STATUS.json`: **3 GA-verified** — OpenAI proxy + Codex/Gemini captures — the rest **experimental**, shipped + flagged in `doctor`, excluded from headline counts). Most have real code and pass
their unit tests, but "code exists and passes unit tests" is a different,
weaker claim than "we ran it against the real vendor and watched capture +
governance work end-to-end." Exactly **three** surfaces currently carry the
stronger claim:

| # | Surface | What was actually driven | How to reverify |
|---|---|---|---|
| 1 | **OpenAI cloud proxy** (`apps/stanchion-openai-proxy`) | A real ChatGPT/OpenAI-compatible request was routed through the proxy, captured, and governed end-to-end — not just unit-tested. | Run the proxy, point an OpenAI client at it, confirm a row lands under `/api/v1/capture/openai-proxy`. |
| 2 | **Codex CLI capture** (`apps/stanchion-shim`) | The shim-wrapped `codex-cli` was run live and its activity captured. | `stanchion hook install` for `codex-cli`, run a real Codex session, confirm the session appears in the dashboard's `/codex` tab. |
| 3 | **Gemini CLI capture** (`apps/stanchion-shim`) | The shim-wrapped `gemini-cli` was run live and its activity captured. | Same as above for `gemini-cli`; confirm under the `/gemini` tab. |

Everything else in the platform matrix — the VS Code VSIX, JetBrains plugin,
Zed extension, the other 8 in-IDE VS Code captures, the other 9 shim-wrapped
CLIs, Bedrock/Azure/Databricks proxies, and so on — is **real, buildable
source code with passing unit tests**, but has **not** been driven against
its live third-party vendor in this environment (no vendor account/credential
to do so). That is not a hidden gap: every one of those surfaces is itemized,
by name, with its exact maturity level, in
[`docs/GA_READINESS/TRANSPARENCY.md`](docs/GA_READINESS/TRANSPARENCY.md).

**Read that document before treating any integration beyond the three above
as "verified."** The per-claim evidence trail (which file, which test, which
command) is in
[`docs/GA_READINESS/CLAIM_VERIFICATION.md`](docs/GA_READINESS/CLAIM_VERIFICATION.md).

---

## 5-minute quickstart

**Requirements:** macOS or Linux · Python 3.11–3.13 ·
[uv](https://docs.astral.sh/uv/) · Node.js 20+ · VS Code with the `code` CLI
on `PATH` (only needed if you want the VS Code sidebar).

From a clone of this repository:

```sh
./tooling/installers/install-from-source.sh
```

This one script builds the dashboard, installs the `stanchion` CLI, builds
and installs the VS Code extension, initializes the local database and
operator token, and verifies the install with `stanchion doctor`. It is
idempotent — safe to re-run.

```sh
stanchion doctor       # confirms every subsystem is healthy
stanchion dashboard    # opens the Insights dashboard in your browser
```

At this point Stanchion is observing (not enforcing) any agent session you
run in an instrumented project. To also instrument a specific project, or to
skip the VS Code extension:

```sh
./tooling/installers/install-from-source.sh --project ~/code/my-app   # also instrument a project
./tooling/installers/install-from-source.sh --no-extension            # CLI + daemon only
```

Prefer a double-click installer instead of the shell script? See
[`docs/INSTALL.md`](docs/INSTALL.md) (production) or
[`docs/INSTALL-TESTERS.md`](docs/INSTALL-TESTERS.md) (testers) — note that
installers currently ship **unsigned** (Gatekeeper/SmartScreen will warn;
signing is wired but pending purchased certs, see
[`docs/CODE-SIGNING.md`](docs/CODE-SIGNING.md)).

Nothing here enforces anything by default — governance features are
flag-gated (see [Feature catalog](#feature-catalog)) and Stanchion observes
until you turn one on.

---

## Honest scope — read this before you rely on anything

Stanchion's own README banner has historically been the least reliable place
in this repository to learn what's real, because marketing drift is exactly
the failure mode a governance product cannot afford in its own documentation.
So the honest-scope material lives in three living documents instead, each
answering a different question, each kept current against the code:

| Document | Answers |
|---|---|
| [`docs/GA_READINESS/TRANSPARENCY.md`](docs/GA_READINESS/TRANSPARENCY.md) | What is real, what is a deliberate stub, what is external-blocked — and how to verify any of it yourself. |
| [`docs/GA_READINESS/CLAIM_VERIFICATION.md`](docs/GA_READINESS/CLAIM_VERIFICATION.md) | For every headline claim this product makes, the exact command or file that proves (or caveats) it. |
| [`docs/GA_READINESS/OPEN_ITEMS.md`](docs/GA_READINESS/OPEN_ITEMS.md) | Every honest gap — intentional stub, code-complete-but-unverified, or externally blocked (money/accounts/auditor) — in one register. |

The **deployment scope** in one paragraph: v3.0.0 ships two verified
backends — **single-seat (SQLite)** and **multi-user (PostgreSQL)**, full
test suite green on both. Multi-user means **N single-worker daemons sharing
one PostgreSQL** (shared truth in the DB; auth enforced on reads +
audit-writes), **not** one daemon with multiple uvicorn workers — that
configuration is intentionally **refused** (`--workers >1` errors out). The
single-worker rationale and the multi-user model are in
[`docs/runtime-architecture.md`](docs/runtime-architecture.md). SOC 2
controls are mapped but **not yet audited**. Real-vendor UAT
([`docs/UAT-RUNBOOK.md`](docs/UAT-RUNBOOK.md)) covers the three
already-verified surfaces above; every other advertised surface is
documented as "credential-deferred" until its own evidence file lands. The
accurate label for this repository, as of this revision, is **"alpha," not
"beta"** — the honest-scope docs explain exactly why.

The full backlog and remediation history that produced this honest framing —
the original beta-readiness audit, the no-trust re-verification pass, the
independent-assessment responses, the due-diligence report response, the
architecture review, the SWOT, and the ranked gap list — all remain in place
in [`docs/GA_READINESS/`](docs/GA_READINESS/) as historical record. The three
documents above are the current, synthesized entry point; the rest is the
audit trail behind them.

---

## Platform breadth beyond the verified three

**Platform status (last full inventory pass: 2026-05-31):**

| Tier | Count | What's actually true |
|---|---|---|
| **Live-verified end-to-end** | 3 | OpenAI cloud proxy, Codex CLI capture, Gemini CLI capture — see [above](#the-three-independently-verified-surfaces). |
| **Build artifact present, unit-tested, not live-UAT'd** | 8 | `vscode` (VSIX, 170 KB, 60/60 phase-5 tests), `jetbrains` (162 KB JAR built), `zed` (WASM target compiles), `browser` (Chrome ZIP + Firefox XPI), `spyder` (Python plugin imports), `windows-tray` (Python imports; PyInstaller needs Windows), `neovim` (Lua, no build step), `copilot`+`gemini` in-VSIX capture (via `*Capture.ts` wrappers). |
| **Source complete, build needs missing OS toolchain** | 2 | `visual-studio` (`Stanchion.csproj` complete — needs Windows + MSBuild), `macos-app` (Swift sources complete — needs an Xcode project). |
| **VS Code captures sharing the `vscode` extension build** | 8 | `cursor`, `windsurf`, `cline`, `cody`, `continue`, `tabnine`, `amazon-q`, `roo-cline` — each is a `platforms/vscode/src/*Capture.ts` file that talks to that vendor's extension API. Install via the single VS Code VSIX; **none has been driven against a live IDE session.** |
| **Cloud-proxy Python apps (beyond OpenAI)** | 3 functional-capable + 2 non-functional | Functional-capable: `databricks` (bearer passthrough works for basic serving, no Unity Catalog OAuth), `azure-openai` (api-key/api-version auth code present, needs a live Azure resource), `bedrock` (SigV4 signing implemented, needs AWS creds). **Not functional / roadmap:** `replit` (no public Replit AI API) and `web-chat` (claude.ai/chatgpt.com have no public API — capture works via the browser extension, not this proxy). |
| **Shim-wrapped CLI captures beyond Codex/Gemini** | 9 | `aider`, `cline-cli`, `copilot-cli`, `devin`, `jules`, `openhands`, `powershell`, `roo-cline`, `terminal` — each has an `install.sh` that drops a wrapper on `$PATH`. Shim package: 16 unit tests pass; **not driven against the real binaries.** |
| **Framework integration** | 1 | `langchain` (`apps/stanchion-langchain` — imports clean, not UAT'd). |
| **Pure stub (no code)** | 1 | `xcode` — no `install.sh`, no source. Manifest tagged `stub-with-manifest`. |
| **Manifest-only placeholder** | 1 | `amazon-q` proxy — `/q/*` returns `501 amazon_q_proxy_is_a_stub` by design; real Amazon Q has no stable standalone proxy API. |

The full itemised "verified vs scaffolded vs stubbed vs external" list, with
the reasoning behind every row, is
[`docs/GA_READINESS/TRANSPARENCY.md`](docs/GA_READINESS/TRANSPARENCY.md).
Where any surface stands in an in-flight remediation program is tracked in
[`docs/GA_READINESS/OPEN_ITEMS.md`](docs/GA_READINESS/OPEN_ITEMS.md).

**Test totals (last full-suite baseline, both engines, 2026-05-31)**:
- **`3050` passed / `10` skipped / `0` failed** on **SQLite *and* PostgreSQL 16**
  (`uv run pytest tests/`; PG via `STANCHION_TEST_PG_URL`).
- Gates: `ruff` + `ruff format` clean (repo-wide); `mypy` 0 errors / 481 files;
  Bandit 0 Medium/High, 0 *unsuppressed* B608/B310 (72 reviewed + justified
  suppressions — see `docs/GA_READINESS/TRANSPARENCY.md §5`); OpenAPI +
  catalog in sync.

Wave program summary: Phase 0 (tooling) + 30 waves shipped over a multi-day
push, documented under `docs/plans/waves/WAVE_*.md`. Bespoke dashboard tabs
ship for the agent integrations: `/copilot` `/gemini` `/codex` `/cursor`
`/windsurf` `/langchain` `/universal` (universal aggregates every captured
source — default landing).

---

## The three-plane architecture

v2.0 introduces a three-plane governance model. Each plane has a distinct
job; cross-plane signal flows through one correlation seam (run_id +
trace_id) so a single agent action can be followed across all three.

```mermaid
flowchart LR
  subgraph GP["Governance Plane"]
    direction TB
    POL["Policy<br/>(YAML control plane)"]
    POS["Posture<br/>(inactive/light/<br/>moderate/strict)"]
    DET["Detectors<br/>(scanner, anomaly,<br/>drift, fabrication)"]
    LCK["Lockdown FSM<br/>(5 tiers, escalate-only)"]
    AUD["Audit chain<br/>(HMAC-SHA256)"]
  end

  subgraph AP["Agent Plane"]
    direction TB
    CAP["Capture<br/>(20+ vendors)"]
    SES["Session graph<br/>(crew, topology)"]
    HOOK["Hooks<br/>(pre/post tool, prompt)"]
    INJ["Injection<br/>(operator break-in)"]
  end

  subgraph MP["Model Plane"]
    direction TB
    PRX["LLM proxy<br/>(Bedrock, Databricks,<br/>Azure OpenAI, OpenAI-compat)"]
    POLEV["model_policy<br/>(pin / strict / ack)"]
    BUD["Budget<br/>(token / cost / $)"]
  end

  AP -- run_id+trace_id --> GP
  MP -- run_id+trace_id --> GP
  GP -- verdict+intervention --> AP
  GP -- verdict (allow/deny/pin) --> MP

  style GP fill:#1a4d1a,stroke:#2d7a2d,color:#ffffff
  style AP fill:#1a3d6e,stroke:#2d5599,color:#ffffff
  style MP fill:#5a1a4d,stroke:#7a2d6e,color:#ffffff
```

- **Agent Plane** captures *what* the agent did — prompts, tool calls, file
  edits, MCP usage — across every supported IDE, CLI agent, and cloud agent
  platform.
- **Model Plane** sits in front of the LLM. It governs *which model* the
  agent talks to, enforces pins, gates unfamiliar models behind ack
  workflows, and meters tokens against budgets.
- **Governance Plane** owns *the rules*. It evaluates everything from both
  planes against policy, applies posture, runs detectors, drives the
  lockdown FSM, and writes every intervention to the HMAC-chained audit log.

---

## System architecture

The daemon is the only stateful piece; every platform shell is a producer
and/or a consumer over two stable contracts (HTTP API + the
`@stanchion/client` SDK).

```mermaid
flowchart TB
  subgraph PLATFORMS["33 platform dirs — 3 GA-verified, rest experimental"]
    direction LR
    IDE["IDE extensions<br/>VS Code · JetBrains ·<br/>Visual Studio · Cursor ·<br/>Windsurf · Zed · Spyder"]
    CLI["CLI &amp; agent shells<br/>Claude Code · codex-cli ·<br/>gemini-cli · cline · aider ·<br/>roo-cline · openhands · devin · jules"]
    SHELL["Shell / OS shells<br/>terminal · powershell ·<br/>neovim · macos-app ·<br/>windows-tray · xcode"]
    PROXY["Cloud-agent proxies<br/>bedrock · databricks ·<br/>azure-openai · langchain ·<br/>amazon-q · replit · web-chat ·<br/>browser ext"]
  end

  subgraph DAEMON["Stanchion daemon (FastAPI, loopback 52737)"]
    direction TB
    HTTP["HTTP API<br/>76 routers · OpenAPI"]
    CORE["Core engine<br/>capture · govern · observers ·<br/>topology · audit_chain · lockdown ·<br/>posture · crew · model_policy · MCP"]
    DB[("SQLite WAL / PostgreSQL 16<br/>53+ migrations<br/>single-writer per node")]
    SINKS["Audit sinks<br/>S3 Object Lock · WORM ·<br/>SIEM · Rekor"]
  end

  subgraph SDK["Shared front-end"]
    DASH["Insights dashboard<br/>(core-shared/dashboard, React)"]
    CLIENT["@stanchion/client<br/>typed API client"]
  end

  PLATFORMS -- "POST /api/v1/capture/&lt;source&gt;" --> HTTP
  HTTP <--> CORE
  CORE <--> DB
  CORE -.->|optional| SINKS
  DASH -- "@stanchion/client" --> HTTP
  PLATFORMS -- "@stanchion/client" --> HTTP

  style DAEMON fill:#0d2540,stroke:#1a4870,color:#ffffff
  style PLATFORMS fill:#1a3d2a,stroke:#2d6a4a,color:#ffffff
  style SDK fill:#3d2a1a,stroke:#6a4a2d,color:#ffffff
```

- **Daemon** — FastAPI service, loopback-bound on port `52737` (auto-falls
  back to 52738–52741 if the default is busy; live port written to
  `~/.stanchion/active-port.txt`). Owns capture ingestion, the governance
  engine, the snapshot API, an SSE event stream, the MCP gateway, the LLM
  proxy, and 76 HTTP routers exposed under `/api/v1/`.
- **Insights dashboard** — React/Vite SPA served by the daemon (bundled at
  `src/stanchion/insights_dist/`) and embedded into each platform's bespoke
  sidebar.
- **Two contracts only** — every platform talks to core through `/api/v1/`
  and the `@stanchion/client` SDK. Core never imports a platform.

Full walk-through: [`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md).

---

## Capture coverage

Stanchion captures agent activity from 20+ tools via in-process extension
hooks, native-host messaging, CLI shims, or cloud-agent proxies.

```mermaid
flowchart LR
  subgraph IDE["IDE extensions (in-process)"]
    direction TB
    C1["VS Code<br/>(+ Cursor, Windsurf forks)"]
    C2["JetBrains family<br/>(IntelliJ / PyCharm)"]
    C3["Visual Studio<br/>(WebView2)"]
    C4["Zed · Spyder · Xcode<br/>· macOS app"]
  end

  subgraph FIRST["First-party VS Code captures"]
    direction TB
    F1["Copilot"]
    F2["Continue.dev"]
    F3["Cody (Sourcegraph)"]
    F4["Tabnine"]
    F5["Amazon Q"]
    F6["Cline · roo-cline"]
    F7["Cursor (own protocol)"]
    F8["Windsurf (own protocol)"]
  end

  subgraph DORM["Dormant captures (opt-in)"]
    direction TB
    D1["Augment"]
    D2["Refact"]
    D3["Supermaven"]
    D4["Codeium (standalone)"]
    D5["Qodo"]
    D6["IntelliCode"]
    D7["GitHub Models (chat)"]
  end

  subgraph CLI_AGENTS["CLI / cloud agents (shim or proxy)"]
    direction TB
    A1["Claude Code (hooks)"]
    A2["codex-cli · gemini-cli"]
    A3["aider"]
    A4["openhands · devin · jules"]
    A5["LangChain / LangGraph"]
  end

  subgraph PROXIES["Model-plane proxies"]
    direction TB
    P1["Bedrock · 52740"]
    P2["Databricks · 52741"]
    P3["Azure OpenAI · 52742"]
    P4["OpenAI-compat · 52739"]
  end

  subgraph BROWSER["Browser extension"]
    B1["Chrome / Firefox<br/>(native-host messaging)"]
  end

  IDE --> DAEMON[("Stanchion daemon<br/>/api/v1/capture/*")]
  FIRST --> DAEMON
  DORM --> DAEMON
  CLI_AGENTS --> DAEMON
  PROXIES --> DAEMON
  BROWSER --> DAEMON

  style DAEMON fill:#0d2540,stroke:#1a4870,color:#ffffff
  style DORM fill:#3d2a1a,stroke:#6a4a2d,color:#ffffff
```

> Dormant captures are **off by default**. Toggle them via the
> `stanchion.captureThirdPartyAssistants` VS Code setting. Captured fields
> are limited to metadata + text length — never the suggested content itself.

---

## Audit chain — tamper-evident ledger

Every governance intervention, hook handoff, and operator action is appended
to the `audit_log` table and linked into an HMAC-SHA256 chain
(`audit_log_chain`). Each row binds to the previous row's HMAC, so any
re-ordering, insertion, deletion, or field mutation is detected by
`stanchion audit verify`.

```mermaid
flowchart LR
  EV1["audit_log row N-1<br/>actor, action, target,<br/>outcome, ts, detail,<br/>session_id, trace_id"] --> H1["HMAC(N-1)"]
  EV2["audit_log row N<br/>+ prev_hmac=HMAC(N-1)"] --> H2["HMAC(N)"]
  EV3["audit_log row N+1<br/>+ prev_hmac=HMAC(N)"] --> H3["HMAC(N+1)"]
  H1 --> EV2
  H2 --> EV3
  GEN["GENESIS_HMAC<br/>= b'\\x00'*32"] --> EV1

  CHAIN_KEY["~/.stanchion/<br/>.chain_secret<br/>(chmod 600)"] -.->|HMAC key| H1
  CHAIN_KEY -.->|HMAC key| H2
  CHAIN_KEY -.->|HMAC key| H3

  VERIFY["stanchion audit verify<br/>recomputes from<br/>audit_log (source of truth)"] -.->|"detects tamper"| H3

  style CHAIN_KEY fill:#3d1a1a,stroke:#6a2d2d,color:#ffffff
  style VERIFY fill:#1a4d1a,stroke:#2d7a2d,color:#ffffff
```

**Threat boundary (honest):**

- **Detects** post-hoc tampering by anyone *without* the chain secret —
  databases copied/exfiltrated, mounted read-only by a SIEM, edited offline,
  etc.
- **Does not, by itself, defend** against an attacker who already has the
  daemon user's local read access (they can read `.chain_secret` and forge
  valid chains). For that threat layer on:
  - off-host export to immutable storage (`stanchion sink s3`, `stanchion
    siem`) — local forgery becomes detectable by divergence;
  - OS-keyring storage of the secret (the `keyring` dep is already
    available);
  - the roadmap-`STANCHION_CHAIN_KEK_PROVIDER` external-KEK hook so the chain
    key is not at rest on the same host.

Full discussion: [`docs/ARCHITECTURE.md §7.1`](docs/ARCHITECTURE.md).

---

## Extension-host safety

Every fetch the VS Code extension makes against the daemon goes through one
centralized wrapper that injects `AbortSignal.timeout(3000)`. A frozen daemon
(thread exhaustion, locked file handle, TCP-without-FIN) can no longer pile
up unresolving promises in the extension host.

```mermaid
flowchart LR
  subgraph EXT["VS Code extension (TypeScript)"]
    direction TB
    CAP_TS["14 capture/sidebar files<br/>copilot · cursor · windsurf ·<br/>cody · tabnine · cline ·<br/>amazon-q · continue ·<br/>insights · emitter · ext core ·<br/>token exchange · coding-assistants ·<br/>dormant"]
    WRAPPER["daemonFetch wrapper<br/>+ AbortSignal.timeout(3000)<br/>+ AbortSignal.any(caller signal)"]
  end

  CAP_TS -- "every daemon call" --> WRAPPER
  WRAPPER -- "POST /api/v1/* (3s budget)" --> DAEMON[("Stanchion daemon<br/>loopback 52737")]
  WRAPPER -.->|"timeout/error"| OUTPUT["'Stanchion Capture'<br/>output channel<br/>(one-shot per vendor)"]

  style WRAPPER fill:#1a4d4d,stroke:#2d7a7a,color:#ffffff
  style DAEMON fill:#0d2540,stroke:#1a4870,color:#ffffff
```

The wrapper plus the per-vendor one-shot output-channel logger means a
daemon outage is non-fatal, never silent, and never leaks memory.

---

## Fleet management — multi-machine governance

For multi-machine operators, Stanchion ships an **Ed25519 root-of-trust**
fleet enrollment flow (a single-role, TUF-inspired design — NOT full TUF for
enrollment; see ADR-0014). A fleet server holds the root of trust; instances
enroll by signing a server-issued nonce with their Ed25519 private key.
Nonces are persisted to SQLite/PostgreSQL (m0053 migration) and swept
periodically. Separately, policy-bundle supply-chain verification uses a
**full TUF role model** (targets/snapshot/timestamp + delegations),
CLI-reachable via `stanchion fleet verify-bundle` — the two are distinct
components with distinct maturity; see
[`docs/GA_READINESS/CLAIM_VERIFICATION.md`](docs/GA_READINESS/CLAIM_VERIFICATION.md)
§4 for the precise claim on each.

```mermaid
sequenceDiagram
  participant I as Instance daemon
  participant FS as Fleet server
  participant DB as fleet_challenges<br/>(SQLite/PostgreSQL)
  participant FI as fleet_instances<br/>(SQLite/PostgreSQL)

  I->>FS: GET /api/v1/fleet/enroll/challenge?<br/>instance_id=...
  FS->>DB: INSERT (instance_id, nonce, issued_at)<br/>ON CONFLICT UPDATE
  FS-->>I: { nonce }
  Note over I: sign nonce with<br/>Ed25519 private key
  I->>FS: POST /api/v1/fleet/enroll<br/>{ instance_id, pubkey, label,<br/>  nonce, sig }
  FS->>DB: SELECT, verify, DELETE on match
  FS->>FI: INSERT fleet_instances<br/>(stamped with tuf_root_version)
  FS-->>I: { ok, tuf_root }
  Note over FS,DB: sweep runs at most<br/>once per 60s
  FS->>DB: DELETE WHERE issued_at &lt; now - 300s
```

- **Persistence:** a fleet-server restart during an enrollment wave no
  longer invalidates outstanding nonces.
- **Sweep:** issued-but-never-consumed nonces no longer grow unboundedly.
- **Replay:** a wrong-guess attempt does NOT void a future legitimate enroll
  for the same instance (only a successful match deletes the row).

---

## Feature catalog

Every governance feature is **flag-gated and off by default**. Stanchion
observes first; it acts only when the operator explicitly enables it.

| Feature | What it does | CLI / flag |
|---|---|---|
| **Live session telemetry** | 2s-poll observer derives liveness, tokens, context-window, activity feed | always on |
| **Threat state &amp; security governance** | Scanner rules → 5-tier escalate-only FSM; `emergency` raises a seal | `STANCHION_THREAT_ENABLED` |
| **Lockdown FSM** | Locked / guarded session states with sticky-unlock approvals | `stanchion lockdown` |
| **Budgets &amp; enforcement** | Daily token / cost / $ caps; hard block when enforcement on | `STANCHION_BUDGET_ENFORCE` |
| **Anomaly detection** | Heavy-prompt / stuck-turn detectors with tiered sidebar indicator (advisory, does not block by design) | tunable per profile |
| **Plan drift detection** | Plan-vs-execution drift (`docs/yaml-schema/logic.md`) | `logic.plan_drift` |
| **Backontask** | Stop-hook enforcer for drift/stall/fabrication on Claude Code's stop hook | `stanchion backontask` |
| **Watchdog** | Rule-library DSL for custom session-shape monitors | `stanchion watchdog` |
| **Emergency rollback** | Atomic, reversible rollback of the last prompt's file edits | `STANCHION_ROLLBACK_ENABLED` |
| **Audit chain** | HMAC-SHA256 chained log; `stanchion audit verify` proves integrity | always on |
| **Session replay** | Walk the transcript into a filterable step list | always on |
| **Historical analytics** | Daily rollups, per-model breakdown, w/o/w comparison | always on |
| **MCP gateway** | Proxy / document / govern MCP tool calls | `stanchion mcp` |
| **Crew capture** | Multi-agent (CrewAI/LangGraph) session graph | `stanchion crew` |
| **Model proxy** | LLM-plane gateway for Bedrock / Databricks / Azure OpenAI / OpenAI-compat | proxy ports 52739-52742 |
| **Model policy** | Pin / strict-mode / ack workflow on model selection | `policy.yaml` |
| **Posture** | Inactive / light / moderate / strict | `stanchion posture` |
| **Permission** | Tool-allow policy + overrides | `stanchion permission` |
| **Approvals** | Operator approval workflows + sticky-approval pattern matching | sidebar + CLI |
| **Operator notifications** | Inbox surfaced in dashboard | `stanchion notifications` |
| **Compliance reports** | Tamper-evident weekly / regression operational reports | `stanchion compliance` |
| **SIEM egress** | Signed ledger export to org SIEM | `stanchion siem` |
| **S3 / WORM audit sink** | Object-Lock backed off-host audit copy | `stanchion sink` |
| **GDPR** | Data-subject erasure / access | `stanchion gdpr` |
| **Attest / verify** | in-toto + Rekor attestation; determinism gates | `stanchion attest`, `verify` |
| **Airgap** | Zero-egress mode + signed sign-off for any allowed egress (in-process guard is defense-in-depth; authoritative airgap is `docker --network none`) | `stanchion airgap` |
| **License** | Offline-validatable license enforcement | `stanchion license` |
| **Observer mode** | LAN-mirrored read-only build view (QR-paired phone) | `stanchion observer` |
| **Fleet** | Ed25519 root-of-trust multi-machine enrollment + bundle distribution (not full TUF for enrollment) | `stanchion fleet` |
| **Control plane** | Optional central policy distribution | `stanchion control-plane` |
| **Argus** | Unified BI dashboard over capture history | `stanchion argus` |
| **Clippy** | Pattern-recognition advisory suggestions | `stanchion clippy` |

The Insights dashboard surfaces all of the above through tabs in the VS Code
sidebar and the standalone SPA.

---

## Installation

### Native installer (Windows / macOS) — for end users

A self-contained double-click installer is the recommended path for testers
and end users. It bundles the Python runtime, the daemon, the dashboard, and
the VS Code extension — **no prerequisites** — shows a license-acceptance
screen, and installs everything automatically.

- Production install: [`docs/INSTALL.md`](docs/INSTALL.md)
- Tester install: [`docs/INSTALL-TESTERS.md`](docs/INSTALL-TESTERS.md)
- Day-2 operations: [`docs/operations/RUNBOOK.md`](docs/operations/RUNBOOK.md), [`UPGRADE.md`](docs/operations/UPGRADE.md), [`BACKUP-RESTORE.md`](docs/operations/BACKUP-RESTORE.md), [`TROUBLESHOOTING.md`](docs/operations/TROUBLESHOOTING.md), [`DISASTER-RECOVERY.md`](docs/operations/DISASTER-RECOVERY.md)
- Build locally: `bash tooling/build/build-installer.sh` (needs `uv` + Node
  20+; Windows additionally needs Inno Setup 6+). Output lands in
  `dist/installers/`.
- CI builds via [`.github/workflows/installers.yml`](.github/workflows/installers.yml)
  on a `v*` tag or a manual run.
- Code signing: installers currently ship unsigned (pending certs) per
  [`docs/CODE-SIGNING.md`](docs/CODE-SIGNING.md); commands for signing and
  notarization are wired into the build scripts and ready to use when
  certs are procured.

### Install from source — for development

See [5-minute quickstart](#5-minute-quickstart) above.

### Public installer (curl | bash)

```sh
curl -LsSf https://github.com/dw425/Stanchion_v2.0_Master/releases/latest/download/install.sh | bash
```

The script detects `sha256sum` (Linux native) or falls back to `shasum -a
256` (macOS native), so a clean Linux container without Perl no longer
false-positives a checksum mismatch.

### Docker image

```sh
docker pull ghcr.io/dw425/stanchion:3.0.0
```

The image contains the frozen daemon + insights dashboard. Bind-mount your
`STANCHION_HOME` if you want state to persist across runs.

---

## CLI reference

Stanchion ships **40+ top-level CLI verbs**, grouped below by concern. Run
`stanchion --help` for the full list, or `stanchion <verb> --help` for any
subcommand tree.

| Category | Commands |
|---|---|
| **Daemon lifecycle** | `start`, `stop`, `status`, `restart`, `daemon`, `service` (Windows), `install-autostart` |
| **Setup / teardown** | `install`, `kickoff`, `connect`, `disconnect`, `uninstall`, `unbrick`, `repair` |
| **Diagnostics** | `doctor`, `debug`, `dashboard`, `monitor`, `launch` |
| **Auth / keys** | `auth`, `key` |
| **Capture / hooks** | `hook`, `inject`, `browser-host`, `run-id` |
| **Session / multi-agent** | `session`, `crew` |
| **Governance core** | `lockdown`, `posture`, `permission`, `bypass`, `notifications`, `backontask`, `watchdog`, `clippy` |
| **Policy** | `config`, `policy` (bundles), `mcp` |
| **Audit / compliance** | `audit`, `compliance`, `siem`, `sink`, `attest`, `verify`, `gdpr`, `ledger` |
| **Fleet / control plane** | `fleet`, `control-plane`, `airgap`, `license` |
| **Egress modes** | `airgap`, `observer`, `nba` |
| **Migration** | `migrate-from-v05` (legacy v0.5 → v2.0 schema) |
| **Operations / BI** | `argus`, `report` |

---

## Configuration

Most operators run with defaults. Override via environment variables or the
YAML control plane (see `docs/yaml-schema/`).

### Core environment variables

| Variable | Default | Purpose |
|---|---|---|
| `STANCHION_HOME` | `~/.stanchion` | State directory (DB, token, chain secret) |
| `STANCHION_PORT` | `52737` | Daemon port (loopback); auto-falls back to 52738–52741 |
| `STANCHION_OBSERVER_PORT` | `52800` | Observer LAN-gateway port |
| `STANCHION_LOG_LEVEL` | `INFO` | Python logging level (`DEBUG`/`INFO`/`WARNING`) |
| `STANCHION_PROJECT_ROOT` | inferred | Override the auto-detected project root |

### Governance feature flags (off unless set)

| Variable | Feature |
|---|---|
| `STANCHION_THREAT_ENABLED` | Threat / scanner evaluation |
| `STANCHION_BUDGET_ENFORCE` | Hard budget enforcement (vs. observe-only) |
| `STANCHION_ROLLBACK_ENABLED` | Change capture for emergency rollback |
| `STANCHION_FLEET_MANAGED` | Pin the host into managed mode (no local overrides) |
| `STANCHION_ALLOW_DOCTOR_RED` | Allow `stanchion install` to finish with red `doctor` rows |
| `STANCHION_SKIP_INTEGRITY` | Bypass installer `SHA256SUMS` check (NOT RECOMMENDED) |
| `STANCHION_CHAIN_KEK_PROVIDER` | Roadmap: external KEK for the chain key |

### YAML control plane

The control plane lives at `$STANCHION_HOME/stanchion/` (override via
`STANCHION_PROJECT_ROOT`). Three files map one-to-one with three concerns:

- `policy.yaml` — what's allowed (scanner rules, budgets, anomaly
  thresholds, optional governance add-ons).
- `logic.yaml` — how decisions are computed (cerberus, redaction,
  plan_drift, agent_frameworks).
- `control.yaml` — operational levers (managed-mode pins, approval-workflow
  defaults).

Apply / validate / diff via `stanchion config`. Schema docs in
[`docs/yaml-schema/`](docs/yaml-schema/).

---

## Project structure

Three tiers — **CORE** (shared, consistent experience) · **BRANCH**
(per-platform, bespoke) · **TOOLING**. Full walk-through in
[`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md); the core→platform impact map
is in [`docs/CORE_BRANCH_LEDGER.md`](docs/CORE_BRANCH_LEDGER.md).

```
src/stanchion/                 CORE — daemon engine (Python pkg `stanchion`)
  capture/                     Capture registry
  cli/                         40+ CLI verb modules
  config/                      Control plane (YAML, posture, enforcement)
  core/                        Governance: govern/, hooks/, observers/,
                               topology/, audit_chain, lockdown, posture,
                               crew, model_policy, fleet/, signing, MCP
  http/                        FastAPI app + 76 routers under /api/v1
  db/migrations/               53+ SQLite/PostgreSQL migrations
  insights_dist/               Built dashboard (generated, ships in wheel)
  services/                    Background services (S3 sink, etc.)
  telemetry/                   OpenTelemetry resource + GenAI semantic conv.

core-shared/                   CORE — shared front-end (single source of truth)
  dashboard/                   React/Vite InsightsHub SPA
  client-sdk/                  @stanchion/client — typed API client

platforms/                     BRANCH — 33 platform dirs (3 GA-verified; rest experimental — status table above)
  vscode/                      VERIFIED — 5.4k LOC, VSIX builds clean
  jetbrains/                   BUILT — 2.0k LOC, JAR built (build/libs/)
  visual-studio/               SOURCE COMPLETE — 1.2k LOC C# (needs MSBuild)
  neovim/                      SOURCE COMPLETE — 700 LOC Lua (no build step)
  macos-app/                   SOURCE COMPLETE — 531 LOC Swift (needs Xcode)
  spyder/  windows-tray/       BUILT — Python plugins import + test-green
  zed/                         BUILT — Rust WASM target compiles
  browser/                     BUILT — Chrome ZIP + Firefox XPI shipped
  (8 vendors)                  VS CODE CAPTURE — *Capture.ts inside vscode/
                                 (copilot, gemini, cursor, windsurf, cline,
                                  cody, continue, tabnine)
  (7 vendors)                  CLOUD PROXY — apps/stanchion-<v>-proxy
                                 (amazon-q, azure-openai, bedrock,
                                  databricks, replit, web-chat, openai)
  (11 vendors)                 SHIM CLI — install.sh + apps/stanchion-shim
                                 (aider, codex-cli, copilot-cli, devin,
                                  gemini-cli, jules, openhands, powershell,
                                  terminal, cline, roo-cline)
  langchain/                   FRAMEWORK — apps/stanchion-langchain
  xcode/                       STUB — manifest only, no code yet

tooling/
  installers/                  install.sh, install.ps1,
                               install-from-source.sh
  build/                       build-release.sh, build-insights.sh,
                               build-host-plugins.sh, build-installer.sh,
                               release.sh, sign-release.sh

installer/                     Native installer assets
  macos/                       build-pkg.sh, distribution.xml,
                               entitlements.plist, scripts/{post,uninstall}
  windows/                     stanchion.iss (Inno Setup)

docs/                          ARCHITECTURE.md, CORE_BRANCH_LEDGER.md,
                               adrs/, yaml-schema/, plans/, assets/,
                               GA_READINESS/ (honest-scope living docs)
tests/                         ~2,000 test functions / 2,300+ collected (parametrized)
```

Dependencies flow **one way: `platforms/ → core`**, only through two
contracts — the daemon HTTP API and the `@stanchion/client` SDK. Each
platform's sidebar/UI is bespoke (consistent experience, native
implementation) — never deduplicated into core.

---

## Testing

```sh
uv run pytest                                  # full suite
uv run pytest tests/v2_0                       # just v2.0 features
uv run pytest --ignore=tests/e2e -x -q         # quick CI run
```

The suite is ~2,000 test functions; the runner reports **2,400+ collected**
once parametrized cases are expanded (the static function count actually
decreased between v1.8 and v2.0 as redundant cases were retired; the 2,400+
comes from parametrized and property-based tests plus the 109-test
platform-conformance suite added in the platform-rollout pass — not new
function bodies). Coverage includes the 11-scenario E2E test, the
193-endpoint smoke gauntlet, the full lockdown / approvals / fleet /
audit-chain integration paths, and 109 per-platform conformance tests under
`tests/platforms/`. See
[`docs/GA_READINESS/CLAIM_VERIFICATION.md`](docs/GA_READINESS/CLAIM_VERIFICATION.md)
for the reproduction command behind every headline number in this README.

---

## Security &amp; privacy

- **Local-first** — the daemon binds loopback only; no code or telemetry
  leaves the host without an explicit operator-signed egress sign-off.
- **Tokens never persisted** — the inbound operator API key passes through
  and is never stored or logged. Storage is bearer-issued daemon-local; the
  audit log records the token's **scope**, not its value.
- **Tamper-evident audit log** — HMAC-SHA256 chain over every governance
  intervention; `stanchion audit verify` recomputes from source-of-truth
  rows, not a denormalized copy.
- **Per-installation chain secret** — `~/.stanchion/.chain_secret` (chmod
  600); roadmap external-KEK provider for off-host key custody.
- **Sandbox enforcement** — `SandboxProfile.network=deny` honored by
  Seatbelt (macOS), bubblewrap (Linux), Docker; refused with
  `strict_network: true` if the selected backend can't enforce.
- **Installer hardening** — every shell installer uses `mktemp -d` for
  per-run logs (no `/tmp/` symlink TOCTOU vector); macOS root-running
  scripts write to `/var/log/stanchion/` at mode 0700.
- **Redaction** — secrets are redacted before logging; observer feed is
  whitelist-redacted.
- **Fail-open for observability, fail-closed for risky actions** —
  `GET /api/v1/insights/snapshot` always returns HTTP 200 (governance state
  in the body); risky governance actions default to deny.

Threat-model detail (including the key-storage caveats and the 72 reviewed
Bandit suppressions) is in
[`docs/GA_READINESS/TRANSPARENCY.md`](docs/GA_READINESS/TRANSPARENCY.md).

---

## License

**Confidential and proprietary.** © 2026 Daniel Warren. All rights reserved.
Unauthorized use, reproduction, modification, or distribution is prohibited.
See [`LICENSE`](LICENSE) and [`NOTICE`](NOTICE) for the full terms and the
per-release SBOM + dependency manifest commitment.
