@aihq/harness 0.5.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -3,6 +3,7 @@
3
3
  [![CI](https://github.com/samartomar/ai-harness/actions/workflows/ci.yml/badge.svg)](https://github.com/samartomar/ai-harness/actions/workflows/ci.yml)
4
4
  [![CodeQL](https://github.com/samartomar/ai-harness/actions/workflows/codeql.yml/badge.svg)](https://github.com/samartomar/ai-harness/actions/workflows/codeql.yml)
5
5
  [![OpenSSF Scorecard](https://api.scorecard.dev/projects/github.com/samartomar/ai-harness/badge)](https://scorecard.dev/viewer/?uri=github.com/samartomar/ai-harness)
6
+ [![codecov](https://codecov.io/gh/samartomar/ai-harness/graph/badge.svg)](https://app.codecov.io/gh/samartomar/ai-harness)
6
7
  [![License: Apache-2.0](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](LICENSE)
7
8
  [![Node ≥20](https://img.shields.io/badge/node-%E2%89%A520-339933.svg)](package.json)
8
9
 
@@ -14,7 +15,9 @@ A cross-platform CLI that helps prepare developer workstations and repositories
14
15
  **reviewable, governed AI-assisted coding behind a corporate proxy**. It extracts
15
16
  corporate trust, tunes local inference, adds repo guardrails, wires up
16
17
  MCP / observability / sandboxing, and lays down a tool-agnostic context
17
- architecture — all from one command surface.
18
+ architecture — all from one command surface. On top of that setup it runs a
19
+ governance loop for external agent skills — vet → approve → pack → marketplace →
20
+ evidence — anchored in a committed approval lock (`aih-skills.lock.json`).
18
21
 
19
22
  > Implements the architectural blueprint *"Enterprise DevSecOps AI Bootstrapping:
20
23
  > Cryptographic Trust, Local Performance Optimization, and Unified Observability"*
@@ -28,6 +31,12 @@ architecture — all from one command surface.
28
31
 
29
32
  - **Dry-run by default.** `aih <cmd>` computes and prints a plan; nothing is
30
33
  written until you add `--apply`. Add `--verify` to run read-only checks.
34
+ - **Gated writes.** `--apply` refuses a dirty git worktree unless you add
35
+ `--force`. Commands resolve a governance posture (`--posture vibe|team|enterprise`,
36
+ default `vibe`): the skill-install gate refuses unapproved skills at
37
+ `team`/`enterprise` and stays advisory at `vibe`; pack installs are fail-closed
38
+ at every posture. Once a repo is initialised, every run is recorded in the
39
+ local [run ledger](#run-ledger).
31
40
  - **Never mutates a remote system.** Every unit of work is a local `write`, a
32
41
  local `exec` (icacls/chmod/junction…), a read-only `probe`, or a `doc` (the
33
42
  exact commands for cloud setup — SSO, gateways, Langfuse, MDM — emitted for a
@@ -89,6 +98,7 @@ aih init . --apply # apply it
89
98
  | `aih trust` | Vet, pin, and gate external GitHub repos and skills before an agent acquires them. `scan <target>` grades danger (auto-exec hooks, dependency-confusion, typosquat, incoming-MCP, secrets) and emits SARIF; `allow`/`pin` record reviewed sources + pinned SHAs in org policy; `list`/`verify` audit the committed policy and trust-lock evidence. |
90
99
  | `aih skill` | The **skill lifecycle** on top of `trust` — a complete governance loop for external agent skills. `vet <src>` runs the read-only gate pipeline (shape, license, trust scan) to a **GREEN/YELLOW/RED/UNKNOWN** verdict + a local evidence artifact (never installs). `card`/`approve --pin --owner` turn that evidence into committed governance: a skill card + a root **`aih-skills.lock.json`** entry, behind a fail-closed chain (pin → evidence → approvable verdict → license → owner; RED blocked, UNKNOWN refused, YELLOW = the manual review). The lockfile has **install-time teeth**: `workspace add` refuses promoting a skill with no committed approval *for that source's pinned commit* at `team`/`enterprise` posture (advisory at `vibe`) — a same-named skill from an unrelated source never inherits an approval, and stale approvals are refused. `inventory` joins on-disk skills against the approvals — approved / unapproved / stale-pin / quarantined, one row per physical install — and feeds a "Skill governance" panel in `report --v9`. `quarantine --name <skill>` **disables reversibly** (dir → `.aih/quarantine/`, approval kept; move it back to restore). `remove --name <skill>` retracts: archives the skill dir reversibly (`--delete` to hard-delete), drops the approval + card; refuses ambiguous duplicates, nested-skill collateral, machine-root installs, and stranding a parked copy's approval; cleans up orphaned approvals. |
91
100
  | `aih pack` | **Curation manifests** on top of the per-skill lifecycle — a committed root `aih-packs.json` names sets of approved skills so a team installs "the docs-quality pack", not N individual approvals. The `aih-skills.lock.json` stays the **pin authority**: every manifest ref is a fail-closed cross-check against the lock entry (`pack.pin-mismatch` blocks; a disagreeing manifest is never a second pin). `status`/`validate` grade each pack on the two orthogonal axes (approval × install) — `validate` is the **CI gate** (coded findings: `pack.missing-approval`, `pack.pin-mismatch`, `pack.duplicate-name`). `add`/`remove-entry`/`init` author the manifest with refs **derived from the lock** (authoring never invents a pin; `init` seeds a pack from `skill approve --pack` tags; an emptied pack is dropped whole). `plan`/`install` drive the gated two-phase acquisition once per source — **gate ALL sources before promoting ANY**, promote only the pack's refs (subset-exact), route drifted installs back through the gate, resume idempotently — fail-closed at every posture (clean approvals required even at `vibe`; `--acknowledge` refused, acknowledgements stay per-source). `uninstall` retracts every installed member with `skill remove`'s exact per-member semantics — reversible archive (or `--delete`), approval + card dropped, loader-ref advisories, the same refusal guards, and **one blocked member refuses the whole plan**; the manifest curation stays. Installed skills' pack tags roll up in the report's Skill-governance panel. |
101
+ | `aih marketplace` | Package the approved skill set into a **reproducible, verifiable distribution artifact** — a directory a team can host anywhere (git repo or static host), never a registry/server. `build` reads `aih-skills.lock.json` (the **approval authority**) and emits the exact vetted skill bytes (trust-lock hash cross-checked), the committed skill cards, the content-addressed vet evidence, a `marketplace.json` manifest, and `SHA256SUMS` — byte-identical across builds from identical inputs (no wall-clock; `--stamp` is operator-supplied), and **fail-closed whole**: an approved skill that is uninstalled, drifted, ambiguous, or missing its card/evidence refuses the entire build. `validate` is the **read-only CI gate** over a built or fetched artifact (coded findings: `marketplace.manifest-parse`, `marketplace.path-traversal`, `marketplace.missing-file`, `marketplace.checksum-mismatch`, `marketplace.sums-coverage`, `marketplace.unapproved-verdict`, `marketplace.signature`), containment-checking every manifest/sums path **before** touching the filesystem with it. `publish` signs the artifact's `SHA256SUMS` (cosign or a GitHub attestation — a publish without a signer is refused; that's just a build); `validate --require-signature` then **fails rather than skips** when that signature can't be verified. Consumers stay on `aih workspace add` — the vet gate still runs at consume time. |
92
102
  | `aih mcp` | Generate the MCP server config **for the targeted CLIs** (`--cli`/`--all-tools`, default claude): Claude/Cursor/Kiro/Kimi get their correct project file written (`.mcp.json`, `.cursor/mcp.json`, …); Codex (TOML), Copilot, OpenCode, Zed, and global-config tools get exact per-tool guidance instead of a file aih would get wrong. Scopes: local/project/remote. For locked-down orgs, `--mode offline` (vendored local-command servers) or `--mode none` (no MCP + a CLI-tool fallback) plus a `managed-mcp.json` admin template. |
93
103
  | `aih sandbox` | Generate a devcontainer + managed sandbox settings (egress allowlist, `failIfUnavailable`). |
94
104
  | `aih telemetry` | Inject OpenTelemetry env, a redacting Bindplane collector, and an analytics fetcher (usage + skills endpoints → `{ usage_report, skills }`). |
@@ -103,13 +113,37 @@ aih init . --apply # apply it
103
113
  | `aih init` | Initialize a repo: profile + superpowers + bootstrap-ai + scaffold + secrets + guardrails + mcp + sandbox in one pass (one writer per file). ECC is a separate gated network step — run `aih ecc` when ready (it points at ECC's own installer). |
104
114
  | `aih adopt` | Converge an **existing** AI canon onto aih's managed model **without overwriting your work** (brownfield migration) — for a repo that already has an `AGENTS.md`/`.cursor`/`ai-*` setup. `--migrate-cli` folds committed CLI-native content into the canon (copy + pointer-convert, content-verified, backed up); `--ack <paths>` marks paths as intentionally tool-native so adopt stops flagging them. |
105
115
  | `aih workspace` | Scaffold a **multi-repo** workspace (parent-only): cross-repo architecture map (write-once) + per-repo discipline, a VS Code `.code-workspace`, combined graph/filesystem MCP spanning every child repo, and a `.aih-workspace.json` marker. |
106
- | `aih bundle` | Build a deterministic **fleet bundle** — the repo contract, org policy, and managed config packaged with a checksum manifest (and an optional `gh`-attested signature) for distribution to a team or CI. `aih bundle verify` re-checks a bundle against its checksums + signature. |
116
+ | `aih bundle` | Build a deterministic **fleet bundle** — the repo contract, org policy, and managed config packaged with a checksum manifest (and an optional `gh`-attested signature) for distribution to a team or CI. `aih verify-bundle` re-checks a bundle against its checksums + signature. |
117
+ | `aih policy` | Schema gates for the org policy. `validate` is the **read-only CI gate** over the committed `aih-org-policy.json` — a missing file is a friendly skip (vibe repos carry no org policy), a parse/schema failure is a coded finding (`org-policy.invalid`) — or, under `--bundle <path>`, over a distributable **policy-bundle envelope** (`org-policy.bundle-invalid`, naming which layer failed: the envelope or the embedded policy). |
118
+ | `aih evidence` | Package the **audit trail aih already emits** — approval lock, packs manifest, trust lock, skill cards, vet evidence, run logs, report/SARIF outputs — into one deterministic **evidence bundle** (`build`): the exact fleet-bundle layout (`files/<rel>` copies, `manifest.json`, `SHA256SUMS`, optional best-effort `--sign cosign\|gh`) plus `evidence.json`, a typed kind index. Byte-identical across builds from identical inputs (no wall-clock); absent artifact kinds are skipped silently; re-check any copy with `aih verify-bundle --bundle <out>`. |
107
119
  | `aih doctor` | Fail-closed verification of the workstation/repo configuration (+ workspace mode: validates each child repo). Includes a **canon markdown lint** (read-only) over the scaffolded `ai-coding/` tree. |
108
120
  | `aih status` | Read-only inventory of what the harness has configured. |
109
121
 
110
- Global flags: `--apply`, `--verify`, `--json`, `--support-out <dir>`, `--no-log`, `--context-dir <dir>`, `--root <dir>`, `--cli <list>`, `--all-tools`.
122
+ Shared flags: `--apply`, `--force`, `--verify`, `--json`, `--posture <vibe|team|enterprise>`, `--support-out <dir>`, `--no-log`, `--context-dir <dir>`, `--root <dir>`, `--cli <list>`, `--all-tools`, `--detect`, `--yes` (the read-only `doctor`/`status`/`verify-bundle` take the relevant subset).
111
123
  Settings also read from `AIH_*` env vars (`AIH_APPLY`, `AIH_CONTEXT_DIR`, `AIH_LOG`, …).
112
124
 
125
+ ### Plugins
126
+
127
+ At startup `aih` probes for exactly one optional peer package: **`@aihq/enterprise`** — the literal
128
+ name, never env- or config-selectable, so nothing can point the probe at other code. When installed,
129
+ its `aihCommands` export (a `CommandSpec[]`) registers as native subcommands through the identical
130
+ path as the built-ins: shared flags, posture resolution, the dirty-worktree gate, and the run ledger
131
+ all apply unchanged. Not installed → zero output, fully local. `AIH_NO_PLUGINS=1` disables the
132
+ probe. A plugin that fails to load, exports the wrong shape, or ships an invalid spec degrades to
133
+ local-only with a one-line `aih: plugin:` warning on stderr — and a plugin command can never shadow
134
+ a built-in (built-ins always win). Installing the plugin package **is** the trust decision:
135
+ importing it runs its code, exactly like any other dependency you install.
136
+
137
+ The probe is hardened at its seams. The package must resolve from **the install tree `aih` itself
138
+ runs from** (the `node_modules` chain above the aih binary), so a global or `npx`-run `aih` pointed
139
+ at an untrusted repo never imports a `node_modules/@aihq/enterprise` planted inside that repo.
140
+ Honesty note: when aih is installed *inside* the target repo, the repo already controls the binary
141
+ itself — the boundary is exactly "the tree aih runs from", nothing stronger. The import also races
142
+ a 2-second startup budget (timeout → local-only with a warning), and `aih --version` skips the
143
+ probe entirely. Plugin specs cannot claim shared or reserved flags (`--apply`, `--json`, `--help`,
144
+ …), cannot take the names `help`/`version`, and any `skipWorktreeGate` field is stripped — the
145
+ dirty-worktree preflight always applies to plugin commands.
146
+
113
147
  ### Dashboard
114
148
 
115
149
  `aih report --open` builds a **self-contained, offline** HTML dashboard (dark by default with a
@@ -120,7 +154,11 @@ data never reads as real. When the report derives findings (see [Support tickets
120
154
  a **Suggested actions** section leads with copy-to-clipboard tickets. Add `--demo` for showcase data,
121
155
  or `--refresh <sec>` to keep it live.
122
156
 
123
- ![aih report dashboard full view with `--demo` showcase data](docs/assets/ai_harness_report_3_columns.png)
157
+ ![aih report --v9 developer-console dashboard rendered with --demo showcase data, showing the harness-wiring score, ranked fix actions, and the remediation ledger](docs/assets/aih-report-v9.png)
158
+
159
+ *The `--v9` developer console with `--demo` showcase data: harness-wiring score, ranked
160
+ fix actions, and the remediation ledger. `aih report --demo --v9` opens the same dashboard
161
+ locally.*
124
162
 
125
163
  ### Targeting CLIs
126
164
 
@@ -312,9 +350,7 @@ aih usage --rollup ../repo-a,../repo-b
312
350
  latest minor receives fixes.
313
351
  - **Supply chain** — every release publishes via npm **Trusted Publishing** with build
314
352
  **provenance** and ships an **SPDX SBOM** + **SHA256 checksum** on the GitHub Release.
315
- Verify an install with `npm audit signatures`. The first npm publish is tracked in
316
- [#37](https://github.com/samartomar/ai-harness/issues/37); until then, install from source
317
- (above).
353
+ Verify an install with `npm audit signatures`.
318
354
  - **Support** — [SUPPORT.md](SUPPORT.md) · **Security** — [SECURITY.md](SECURITY.md)
319
355
  (private reporting) · **Contributing** — [CONTRIBUTING.md](CONTRIBUTING.md).
320
356
 
@@ -327,7 +363,9 @@ npm run lint # biome
327
363
  npm run build # tsup → dist/
328
364
  ```
329
365
 
330
- Stack: TypeScript (ESM) · commander · zod · vitest · biome · tsup. See
366
+ Stack: TypeScript (ESM) · commander · zod · vitest · biome · tsup. Coverage floors
367
+ are enforced in [vitest.config.ts](vitest.config.ts) — set just below the achieved
368
+ levels so coverage only ratchets up; CI and releases fail on regression. See
331
369
  [CONTRIBUTING.md](CONTRIBUTING.md) for the contributor workflow.
332
370
 
333
371
  ## License