Markdown 153 lines
<div align="center">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="../assets/eeco_logo_dark.png">
<img src="../assets/eeco_logo_light.png" alt="eeco" width="280">
</picture>
<h1>Cockpit</h1>
<p><i>eeco as a provider-agnostic AI-cockpit generator.</i></p>
<p>
<a href="../README.md"><b>README</b></a> ·
<a href="../VISION.md"><b>Vision</b></a> ·
<b>Cockpit</b> ·
<a href="USAGE.md"><b>Usage</b></a> ·
<a href="ARCHITECTURE.md"><b>Architecture</b></a> ·
<a href="PUBLIC_API.md"><b>Public API</b></a> ·
<a href="../EXTENDING.md"><b>Extending</b></a> ·
<a href="../CONTRIBUTING.md"><b>Contributing</b></a> ·
<a href="UPGRADING.md"><b>Upgrading</b></a> ·
<a href="../VERSIONING.md"><b>Versioning</b></a> ·
<a href="../CHANGELOG.md"><b>Changelog</b></a> ·
<a href="../SECURITY.md"><b>Security</b></a>
</p>
</div>
---
> **Status: documented; pre-1.0.** This is the canonical reference for the
> `eeco cockpit` surface — eeco as a provider-agnostic AI-cockpit generator.
> The cockpit ships today, but it is **pre-1.0 and not yet part of the frozen
> enumeration** in [`PUBLIC_API.md`](PUBLIC_API.md): it is governed by the
> pre-stability clause of [`VERSIONING.md`](../VERSIONING.md) §2.1, so its
> shapes MAY still change in a `v0.x` MINOR with a migration note. Treat this
> document as the working contract for the surface.
## What the cockpit is
eeco does not run AI as a product capability. It **generates and maintains the
config that makes a harness run AI well** — the provider-agnostic AI cockpit.
The AI runs in the harness; eeco is the cockpit's author and mechanic.
A **playbook** is eeco's neutral, harness-independent description of one AI
procedure: a description, a structured safety contract (`intent`), a capability
allowlist, ordered steps, and an output format. The shipped library lives in
`internal/playbooks` (one embedded JSON source per playbook, the single
reviewable source of truth). A **renderer** (one per harness target) is the only
component that knows a target's file layout and permission spelling.
## The safety invariant
The product-defining guarantee is a machine-checked one: an emitted artifact can
**never** grant a write-capable git verb that a playbook declares forbidden.
The gate (`ScanAllowlistForWriteGitVerbs`) derives both the allowlist and the
prose warning from the structured `intent`, and **generation refuses** rather
than silently drop a forbidden verb. The invariant is **uniform across every
target** — advisory targets do not relax or bypass it.
## Targets and fidelity
| Target | File | Shape | Harness enforcement |
|---|---|---|---|
| `claude` | `<username>/.claude/skills/<name>/SKILL.md` | per-playbook | **enforced** (`allowed-tools`) |
| `cursor` | `<username>/.cursor/rules/<name>.mdc` | per-playbook | advisory |
| `agents` | `<username>/AGENTS.md` | aggregate (one file for the set) | advisory |
| `gemini` | `<username>/GEMINI.md` | aggregate (one file for the set) | advisory |
**Fidelity honesty.** Only Claude enforces a tool allowlist at runtime. The
advisory targets carry a loud `ADVISORY ONLY — NOT HARNESS-ENFORCED` banner and
a fidelity line; `generate` and `status` report the achieved enforcement. eeco
never lets the operator believe enforcement that isn't there. (Enforced settings
emission for Gemini/Cursor — their separate permissions layers — is deferred to
a later slice.)
All artifacts are written **only** into the gitignored `<username>/` private
tree; a renderer-supplied path that is absolute or escapes via `..` is rejected
(`relUnder`), so generation can never write a tracked file.
## Selecting targets
eeco asks at first `eeco init` which harness(es) you use and records the active
set in `<username>/.eeco/cockpit.json` (the selection store, separate from the
emission ledger at `<workspace>/state/cockpit.json`). Manage it later with:
```
eeco cockpit target list # active targets (+ fidelity) and available ones
eeco cockpit target add <target> # activate a target
eeco cockpit target rm <target> # deselect a target (does NOT delete emitted files)
```
`eeco cockpit target rm` deselects only — it never deletes emitted files; run
`eeco cockpit off --target <t>` to remove them (reversibility stays an explicit,
consented step).
### A cross-project default set
Add `--global` to any `eeco cockpit target` verb to manage a user-global target
set, stored as `cockpit.json` under the user-global config directory
(`$EECO_CONFIG_HOME`, else `$XDG_CONFIG_HOME/eeco`, else `~/.config/eeco`):
```
eeco cockpit target --global add cursor # every project inherits this set
eeco cockpit target --global list # show the global set
```
A project with no `cockpit.json` of its own inherits the global set; a workspace
selection always wins over the global one, which in turn wins over the built-in
default (Claude alone). This mirrors the three-layer `config.local` resolution
(see [`USAGE.md`](USAGE.md) §4a).
## Generating, verifying, removing
```
eeco cockpit generate [--target T] [--playbook P] # emit the active set (or one target/playbook)
eeco cockpit verify [--target T] [--playbook P] # check emitted artifacts match + hold the invariant
eeco cockpit off [--target T] [--playbook P] # remove eeco's artifacts (sha-gated, reversible)
eeco cockpit status # one line per emitted artifact
eeco cockpit show [--playbook P] # print the neutral playbook source (JSON)
```
With no `--target`, `generate`/`verify`/`off` act on the **active set**:
per-playbook targets render every selected playbook; aggregate targets render
one shared file for the whole set. `--target T` scopes to one target (it need
not be active — a one-off). Every emit is **reversible** (a pre-existing foreign
file is backed up and restored on `off`), **sha-gated** (a hand-edited artifact
is left untouched), and **byte-idempotent** (re-emit of unchanged bytes is a
no-op).
### Verification by target
- **Claude (enforced):** on-disk `allowed-tools` is re-scanned for write-git
verbs, the bytes are sha-compared against a fresh render, and an optional
`--parity <answer-key>` runs a 3-tier structural comparison against a
hand-built reference skill.
- **Advisory targets:** there is no answer key, so verification runs a
**self-consistency** check on the on-disk bytes — every forbidden verb/phrase
must still be surfaced, the step/output structure intact, the banner present,
and **no** write-git verb leaked into an Allowed block.
## Playbook library (C2)
`handover` (write into the private tree, propose-only), `commit` (propose a
Conventional-Commits message; never stages/commits/tags), `doc-drift` (report
changelog-vs-tag drift; reads tags via `git for-each-ref`, never `git tag`),
`memcheck` (audit memory-file anchors; never edits a memory). Every shipped
playbook carries **zero** write-git verbs in its allowlist — a test
(`TestAllSources_NoWriteGitVerb`) proves it at build time.
---
[← Prev: Vision](../VISION.md) · [Next: Usage →](USAGE.md)