# Changelog

All notable changes to this project will be documented in this file.

## [Unreleased]

## [2.1.1] - 2026-09-09

### Added

- **Committed CodeQL code-scanning workflow** — a single-job `CodeQL` workflow now runs code scanning on every PR instead of relying on default setup, whose silent large-PR ceiling left big PRs (e.g. #478, 133 files) with no CodeQL report at all; the required `CodeQL` check now has a real reporter on both small and large PRs (#481, #482)

### Changed

- **Default ruleset required checks reconciled** — the unsatisfiable `code_quality` / `copilot_code_review` / `CodeQL` contexts (no live reporter for the first two, no workflow for the third) are removed from the ruleset's required checks, so the list only contains checks that actually run and non-admin PRs are no longer blocked on a phantom check (#481, #482)
- **release.yml validation precedes publish** — the ARD-catalog validation gate now completes before the irreversible `npm publish`, so a failing gate can no longer leave a half-published release (npm live, GitHub draft) (#485)
- **ARD ecosystem submission refreshed to spec v0.91** — the submission flow is now self-hosted: `/.well-known/ard.json` (ArdManifest) is served alongside the legacy `ai-catalog.json` (still recognized with a conformance warning), listing happens via well-known + Agent Finder crawl onboarding (GitHub Agent Finder, Hugging Face Discover) instead of the dead PR-based `ards-project/community` registry, and `ARD-SUBMISSION.md` documents the v0.91 reality (#488)

### Fixed

- **ARD catalog gate schema-guarded** — the release validates the generated `ai-catalog.json` against the vendored ARD schema via `scripts/validate-ard-schema.mjs` (with clear JSON-path error reporting) instead of hardcoding a `specVersion` field, so a future envelope change breaks loudly at the gate instead of silently killing the release on a real tag (#486)
- **Empty ARD export rejected loudly** — `writeArdCatalog`/`discover ard-export` on a cold tree (no discovery state) no longer writes a plausible-but-empty `ai-catalog.json`; it fails loudly with a clear message, and the release pins the ARD asset to the tag's committed catalog or a full `discover full` run (#484)
- **pack-smoke tolerates npm 12 pack output and spawns npm shell-less** — `src/tests/pack-smoke.ts` reuses `toPackRecordList` + `buildNpmInvocation` from `scripts/package-audit.mjs`, fixing the npm 12 `npm pack --json` object-vs-array regression (the tarball-filename assert crashed on the new payload shape) and the win32 `shell: true` invocation (Node DEP0190), keeping the smoke aligned with the already-green `release:package-audit` / `release:package-smoke` (release blocker, review)

## [2.1.0] - 2026-09-04

### Added

- **Breadth-pass state-invalidation warning** — `discover breadth` is a full discovery pass that replaces the catalog/selection outputs; it now inspects the state root first and warns, naming the lifecycle artifacts built from the previous catalog that are now stale (recommendations.json, mirror bundle locks, install generations, activation manifests), and its summary reports the previous catalog size vs the new one (#452)
- **Coverage-truth gates extended to live-fetch paths** — the ARD registry sync, VS Code Marketplace popularity/category sweeps, package-registry search delegates, and the official-index per-index cap are no longer hidden behind `c8 ignore start|stop` blocks; real mocked-HTTP contract tests now cover pagination, cursors, caps, failures, and shape handling, and `scripts/check-coverage-exclusions.mjs` fails the gate when a new inline ignore block appears in product code without an allowlisted, documented justification (#451)
- **ARD registry sync actually fetches** — the adapter called `fetchJsonWithGuards` without `allowedOrigins`, so the origin guard rejected every request and the consumer could never sync; it now uses the source-sync fetch layer (`fetchRequiredJson` + `getAllowedOrigins`) with retries and standard headers (#451)

### Fixed

- **Review wave (2026-08-11 from-scratch audit) closed**:
  - **Install-domain host validation and bundle lookups print clean one-liners** — `install reconcile/reset/refresh --host` validation now throws the shared `CliUsageError` (one message shape, subcommand usage hint) instead of a raw stack, and `bundle explain <unknown-bundle>` reports "Bundle lock not found" with a recovery pointer instead of a bare ENOENT stack; spawned-CLI regression tests assert stack-free stderr on all four paths (review)
  - **Exact-stack requires ecosystem affinity for every source class** — the ecosystem gate and mismatch penalty now apply to non-package-registry assets published under an unambiguous source-family language (`wordpress`/`drupal`/`joomla` → php): an `official-index:WordPress` skill loses `fit:exact-stack` and takes the 2× penalty in a TypeScript workspace instead of ranking via the synonym-collapsed `api → node-backend` coincidence (#443 AC3 review)
  - **Declared-dependency identity matches outrank exact-stack tiles** — a signal whose demand term carries package identity and whose token appears in the asset's RAW curated identity (uncanonicalized: the synonym table maps `duckdb → data`, so canonical identities lost the token) receives the `identityMatchMultiplier` (policy, default 4); live repro: the official DuckDB skill moved from opencode rank 25 to rank 11 (#443 AC2 review)
  - **Native install plans exclude single-token coincidence extensions with explicit status lines** — entries carry the optional `coincidentalMatchOnly` flag (included only when true; consumers treat an absent flag as `false`) when their only declared-package matches are identity-denied tokens; `install native` excludes them from plan and apply/remove with a note naming the signal, and every kept extension prints its basis plus "native install via host CLI (not mirrored)" (#444 AC3 review)
  - **All-axes suite hardening** — BOM stripping (a BOM'd fetched feed used to silently sync nothing) + duplicate-key/`__proto__` semantics pinned; 0-byte/255-char/whitespace/null-byte/extension-less file-shape battery; Codex added to cli-smoke and workspace-smoke (was absent from every CLI-level suite); cli-smoke asserts output + clean stderr; e2e wire round-trip asserts stack-free re-apply/reset with no managed leftovers; pack-smoke inspects tarball contents against the single source of truth; detection quality gains per-fixture floors; perf-path gains a 10,000-entry scale case with a super-linearity guard (review)
- **Declared dependencies select correctly** — scoped dependency evidence (`npm:@duckdb/node-api`, `pypi:duckdb`, …) now contributes each distinctive package-identity token as an independent high-signal term, so official DuckDB skills are selected instead of being rejected on demand-relevance while coincidental-token junk (WordPress, cargo crates, lookalike PyPI packages) passed (#443)
- **Ranking attributes asset-side evidence only** — `matchedSignals` evidence counts now describe evidence about the asset (its own terms and provenance), never the workspace's demand evidence; `fit:exact-stack` requires ecosystem affinity, declared-dependency identity in the asset's curated identity, and no language contradiction, so single-token collisions no longer top the rankings (#444)
- **Unknown CLI flags rejected across every domain** — `recommend`, `mirror`, `install`, `activate`, `quarantine`, `rebuild`, and `discover inspect` now reject unknown `--flag` tokens with a clean error and usage hint before doing work, matching the #431 fix's coverage of discover/wire/workspace/setup (#445)
- **User-input failures print clean one-line errors** — argument-validation failures across activate/recommend/discover-diff/mirror-explain/quarantine/install-generations no longer print raw stacks, and `setup login --provider <unknown>` exits non-zero (#446)
- **wire reset restores pre-apply state for every host** — Codex's adapter-created `marketplace.json` is removed on reset (pre-existing files keep their entries removed), OpenCode re-apply no longer poisons the gitignore snapshot (a pre-existing user gitignore survives byte-for-byte), and VS Code deletes an adapter-created `settings.json` instead of leaving empty managed keys while preserving user keys added after apply (#447)
- **Codex marketplace ownership survives an unchanged reapply** — a second apply recomputed whole-file ownership from the file's mere existence, flipping a harness-created marketplace to `false` and stranding the leftover empty file on reset; the ownership record now preserves a prior `created: true` across reapplies (review)
- **Codex passing a smaller agent set reconciles dropped profiles** — an apply with a subset of the previous agents replaced the ownership manifest with only the incoming records, orphaning dropped agents' generated TOML profiles (and their displaced user content) in `.codex/agents`; reapply now removes harness-created profiles and restores displaced user content before rewriting the manifest (review)
- **`check:version-sync` became a `guardrails` gate and allows a forward-bump** — the tag-vs-manifest guard (#467) now runs first inside `validate`, rejects a version that regresses below the highest released tag, and treats a bumped version awaiting its post-merge tag as valid (the tag is created on main after merge; the release workflow enforces it for tagged runs)
- **Native installer no longer uses `shell: true` concatenation** — `.cmd`/`.bat` wrappers run through PowerShell single-quoted literals (shared `windows-shell.ts` helpers with preflight), eliminating Node DEP0190 and keeping the fail-closed metacharacter refusal (#448)
- **ARD export emits no epoch dates** — catalog entries with the `1970-01-01` maintenance sentinel no longer publish false `updatedAt` values in `ai-catalog.json`; the export target path is documented as `<state-root>/.well-known/ai-catalog.json` (#449)
- **README/cheatsheet flags match the CLI** — non-existent flags (`activate diff --baseline`, `mirror plan/acquire --host`) are gone from the docs and the doc cross-check parses every example against the flag tables; `activate rollback`, `discover environment-index`, and `bundle explain` help list all supported flags (#450)
- **Coverage roadmap describes the truth** — `COVERAGE-100-ROADMAP.md` previously claimed `.c8rc.json` excludes `dist/*.js` (it does not: only `dist/tests/**`, `dist/types/**`, `scripts/tests/**`) and carried stale test counts; both corrected, and the remaining inline ignore blocks are itemized with justifications (#451)
- **Doc/env nits** — `docs/README.md` (the documentation index) is linked from the README, plain `CI=true` behavior is documented next to `AGENT_HARNESS_CI`, `OPENAI_API_KEY` appears in the README env section as an asset prerequisite, the stale "171/170+ sources" claims are normalized to the measured 50+ sources, and the cheatsheet timeout value is marked as an example (default: no deadline) (#453)

- **Lifecycle path budget gates** — `benchmark:paths` enforces 10-second wall-clock budgets on the recommend, activate-selection, and mirror-plan hot paths over a synthetic 1,000-entry catalog; it runs in `validate:quality` alongside `benchmark:scan` so complexity regressions fail CI (#428 hardening)
- **HTTP wire-format test suite** — the GitHub fetch path and response readers are now exercised against a real localhost TCP server (content-length vs chunked framing, error bodies, rate-limit headers, retry-after, connection refusal, stall aborts, byte-limit truncation) instead of only mocked `Response` objects (#428 hardening)
- **Cross-process contention tests** — eight concurrent CLI writers plus reader/writer churn against one state root assert the atomic-write contract holds across real OS processes (no torn state, no `.tmp-*` litter) (#428 hardening)
- **Native-command injection tests** — strict VS Code extension-id boundary battery plus byte-exact hostile-argv round-trips; on Windows a real `.cmd` wrapper proves safe arguments survive PowerShell quoting verbatim while metacharacter arguments are refused before any shell sees them (#428 hardening)
- **RTL/unicode path suite** — dedicated tests drive Arabic, Hebrew, CJK, combining marks, zero-width/bidi-format characters, emoji, and full-width confusables through safe-path resolution, mirror/asset id sanitization, posix conversion, lifecycle fingerprints (punycode-folded non-ASCII URL hostnames, verbatim non-URL unicode identity), report grouping with unicode duplicate ids, and real filesystem round-trips through RTL directory names; the contract asserted is that unicode is data, never a traversal bypass (#428 hardening)
- **Quarantine size-boundary suite** — pins the stars popularity cut-off (100 vs 101), the 0..100 score clamp, the exact 40/70 decision boundaries, risky-kind and risk-flag overrides, the duplicate-group −10 penalty, the acquisition status precedence (prompt injection, executable/community/high risk, reference-only, official warning vs community quarantine), the NFKC confusable detection for prompt injection (full-width, mathematical-bold, bidi-wrapped, patterns spread across materialized files) with no false positives on innocent international text, and byte-exact preservation of a 1.5 MiB quarantined artifact (#428 hardening)
- **Duplicate-id edge suite** — singleton groups never surface as duplicate decisions but keep their identity tag; group members, evidence, and fingerprint lists are deterministically sorted; unmirrored members expose absent content hashes honestly; duplicate catalog ids are preserved rather than de-duplicated; cross-source duplicates converge on one canonical upstream identity (hostname casing, terminal `.git` folding) while source-scoped identity stays distinct; and the in-process select pipeline records decisions only for real groups and rejects exactly the duplicate loser (#428 hardening)

- **Conan and Meson demand detection** — `conanfile.txt`, `conanfile.py`, and `meson.build` are now inspectable strong-evidence manifests emitting C/C++ language signals plus `conan` package-manager/tooling (or `meson` tooling) signals. The demand-relevant source gate previously checked `conan`/`meson` ecosystem terms that nothing produced — those paths were dead code, and C++ projects using only Conan/Meson manifests could miss `conan-registry` in demand-filtered discovery (#424 follow-up)
- **Real Hex.pm keyword search** — demand harvesting for `hex-registry` now queries `https://hex.pm/api/packages` (download-sorted); ConanCenter is documented as sitemap-only (no public keyword API) (#424)
- **First-run sync UX** — `discover full` prints a proactive hint before the first sync of 6+ sources ("First-time sync of N sources may take several minutes — pass --no-sync to use cached discovery state or --sync-all…") even when nothing was skipped; per-source completion lines now include a cumulative remaining-time estimate (`done (7242ms, ~2m 5s remaining)`) (#439)
- **Coverage-gate exclusion guard** — `npm run validate` and the CI quality job now fail if a product module is added to `.c8rc.json`'s exclude list. The "100% coverage" claim must cover the whole product (#428)
- **Demand-based source filtering** — `discover full` now syncs only sources relevant to the detected project ecosystem, reducing first-run sync time from 5+ minutes to under 60 seconds for typical TypeScript projects. Sources are mapped from demand signals (languages, frameworks, package managers) to relevant registries. Universal sources (mcp-registry, skills-sh, ui-skills, clawhub) are always synced. Use `--sync-all` to override and sync every enabled source (#419)
- **Demand-sync progress hint** — after demand detection, `discover full` prints an ecosystem-aware summary: "Detected TypeScript project. Syncing 12/47 demand-relevant sources (35 skipped). Use --sync-all for full sync or --no-sync to skip entirely." (#420)
- **`--sync-all` flag** — new flag for `discover full` that bypasses demand-based source filtering and syncs all enabled sources (#419)
- **hex-registry (Hex.pm)** — Elixir/Erlang ecosystem package registry via sitemap-based sync at https://hex.pm/sitemap.xml. Automatically included when demand signals detect Elixir, Erlang, mix, hex, or rebar
- **conan-registry (ConanCenter)** — C/C++ ecosystem package registry via sitemap-based sync at https://conan.io/sitemap.xml. Automatically included when demand signals detect C, C++, cmake, meson, or conan
- **pub-dev-registry (pub.dev)** — Dart/Flutter ecosystem package registry via JSON API paginated sync at https://pub.dev/api/package-names. Automatically included when demand signals detect Dart, Flutter, or pub

- **Review-2026-08-09 gap wave** — the from-scratch review verdict was READY with a defined minor set, now closed:
  - **Named regression tests**: NFKC prompt-injection folding is pinned through `sanitizeMirrorId` (full-width/zero-width confusables fold to the same ASCII-safe id; canonically equivalent combining-mark spellings sanitize identically); a property suite proves `restoreEnvVar` never leaks the literal `"undefined"` string; demand profiles distinguish an empty working dir (valid empty profile) from a missing one (ENOENT surfaces)
  - **Committed stress fixtures**: high-load atomic-churn stress (16 writers × 20 rounds, 8 KiB payloads, 8 readers), three-contender seed-lock serialization (sections never overlap under the O_EXCL polling race), and the exact adversarial path shapes from the CodeQL js/polynomial-redos alert notes against the segment-scan classifier (deep `./rules/` repetitions, 300-deep plugins chains, 100k-char segments)
  - **DRY + #433 shape**: the cargo/pyproject/pubspec extractors share one `walkSectionedLines` iterator (configurable comment stripping + column-0 header requirement), and all regex-group `match[N]!` assertions are replaced by the guarded `requiredCaptureGroup` with descriptive errors (throw arms covered directly)
  - **#428 AC letter**: the gate tools' own c8-ignore comments are gone — the direct-execution guards of `check-coverage-exclusions.mjs` and `check-env-readme-drift.mjs` are now covered by spawned direct runs merged back into the gate; `maintenance-bot-plan.mjs` keeps its documented pre-existing guard (direct run needs the live bot-plan environment)
  - **Metadata/docs hygiene**: `docs/README.md` indexes `cheatsheet.md` and `ADAPTER-DEVELOPMENT.md`; `SEMANTIC-SCORING.md` drops the dead `--no-semantic` future-flag sentence (the flag hard-errors under #431 strict validation); the four stale pre-wave audit reports were relocated to the QA reports dir; the stray PowerShell module-analysis cache is deleted and its pattern gitignored. The npm keywords were evaluated against the pruning suggestion and KEPT: the package-metadata contract test pins them as the handled asset surface (the harness wires and mirrors MCP-server assets, shared-MCP flows, and registry queries), while the #425 role-overclaim fix lives in the description and AGENTS.md
- **Polynomial-ReDoS paths hardened (CodeQL high-severity)** — the first code-scanning run on the PR flagged seven `js/polynomial-redos` alerts: the Cursor-config classifiers in `local-harvesters.ts` used nested `.+` quantifiers (`^(?:plugins\/.+\/)?rules\/.+\.[mc]d$` etc.) that backtrack polynomially on adversarial relative paths, and `sanitizeAssetId` / `normalizeSessionIntentValue` used `+` over negated character classes on untrusted input. The classifiers now use the unambiguous `(?:[^/]+/)*` level-delimited form (identical accepted-language, linear matching), and the run-collapse logic is a shared one-pass `replaceRunsWithDash` scan (no regex backtracking at all)
- **Cross-platform coverage gaps closed for the CI matrix** — the first 3-OS gate run revealed platform-isolated branches the Windows-only local gate never exercised: the fail-closed Windows-shell-wrapper refusals in `preflight.ts` (`runRuntimeCommand`) and `extension-installer.ts` (`executeNativeCommand`) only execute on win32, and the discover `--summary` already-seen-reason map branch needed a duplicated warning reason. The refusal decisions are extracted into platform-parameterized helpers (`buildWrapperRefusal` / `buildShellWrapperRefusal`, exported via the internals seams) so tests force the win32 wrapper branch on any runner; the summary test seeds two failed sources sharing one reason. The coverage gate now passes on ubuntu/macos/windows, not just the dev machine
- **Workspace/doctor test fixtures are hermetic for host config dirs** — the first CI run (this branch's PR) exposed six latent platform/isolation failures: the fixtures resolved host config dirs from the real machine's environment, so `setup doctor` / `wire` failed with `opencode-config-directory`/`vscode-user-settings-directory` errors on clean runners (they only passed locally because the dev machine happens to have an opencode config dir and the opencode CLI installed, which masked the check by creating the dir on probe), and the workspace pipeline tests seeded only `catalog.assets.jsonl` — which the pipeline genuinely regenerates from discovery state — so the recommend phase found zero entries on machines without real host config dirs. The shared fixtures now redirect `AGENT_HARNESS_HOME`/`APPDATA`/`HOME`/`USERPROFILE`/`XDG_CONFIG_HOME` into the isolated temp root (with config-cache reset, restoring via `restoreEnvVar`), materialize the platform-appropriate opencode and VS Code config roots, and the pipeline tests seed an indexed source + sync state + entry artifacts so catalog generation is deterministic. Verified locally with the real config dirs absent: 41/41 in the affected files, full suite green
- **CI coverage gate runs on Node 24** — the quality and maintenance workflows pinned Node 22, but the gate's `--test-isolation=none` (single-process isolation, load-bearing for the honest 100% claim) ships with Node 23, so the first PR run failed with `node: bad option: --test-isolation=none` (exit 9). The workflows now use Node 24 — matching `release.yml` and the documented floor — and `engines`/README/badge were corrected from `>=22` to `>=23` with the reason stated
- **Atomic readers retry the Windows-transient open window** (#427/#428) — the atomic writer already retried EPERM/EACCES during its remove-and-rename window, but a concurrent reader opening the same destination could hit the same momentary lock (AV scan, open handle, a competing writer's rename) and surface a transient error — violating the churn contract ("old | absent | complete-new, never a transient open error") that the cross-process contention suite asserts. `readJsonFile`, `readTextFileOrNull`, and `readBinaryFileOrNull` now retry the identical bounded window (EPERM/EACCES only; ENOENT is still the contract's "absent" and is never retried), with a `filesInternals.setReadFileOpenOverride` failure-injection seam and unit tests for retry-then-success, exhaustion, and fail-fast paths
- **Package-audit fixtures kept in sync with the pinned required-set** — the tarball pin added the split-domain runtime files (`dist/activate/{help,selection,state}.js`, `dist/quarantine/{help,state}.js`) to `REQUIRED_PACKED_FILES` but the fixture in `package-audit.test.mjs` kept its own copy of the old list, so every fixture-based audit test failed deterministically (`Missing required files: dist/activate/help.js, ...`) and the direct-execution / missing-trust-docs assertions matched the wrong message. The fixture now imports the exported required set — one source of truth for checker and check (red-gate at HEAD, caught by the closeout suite re-run)
- **Environment restore no longer leaks the literal string `"undefined"` into the suite** — restoring a previously-unset variable with `process.env.X = previousX` coerces to `"undefined"` (Node semantics), and the coverage gate's `--test-isolation=none` carried that string across test files and into every spawned child: the e2e CLI children handed `XDG_CONFIG_HOME="undefined"` / `AGENT_HARNESS_HOME="undefined"` to the setup-doctor host probes, and the installed opencode CLI resolved its config dir from them, creating a stray `undefined/opencode` directory in the repo root (the review's cosmetic stray dir was a symptom, not the cause). `discover-breadth.test.ts` — the only unguarded site — and `github-catch-coverage.test.ts` now restore through the shared delete-guarded `restoreEnvVar` helper (`src/tests/env-test-utils.ts`), and every other inline restore in the suite (30 files, 74 sites) was migrated to the same helper. Verified: the discovery+e2e pair no longer creates the directory, and the full suite passes without resurrecting it
- **Coverage gate restored at HEAD** (#428) — the v2.1.0 refactor wave left the repo's own gate red: 66 public exports of the new split modules lacked docstrings and the cli.ts help-dispatch switch plus the install/quarantine/rebuild/setup subcommand-help printers sat outside the measured set (spawned CLI children strip `NODE_V8_COVERAGE` by design). All 66 docstrings are restored and the help surface is now covered in-process, returning the gate to a verified 0/0/0/0 uncovered statements/branches/functions/lines.
- **State-root seeding serialized across concurrent CLI processes** (#428 hardening) — two first runs against the same fresh state root raced `prepareStateRoot`'s managed-asset copy (one crashed with EEXIST, or worse, one process's clean deleted a tree the other had just populated). Seeding now runs under an exclusive per-root lock file (`O_EXCL`) with bounded waits, stale-lock recovery, and a clear timeout error naming the lock path.
- **Windows host wrapper commands fail closed on shell metacharacters** (#428 hardening) — cmd.exe re-parses the raw command line of a `.cmd`/`.bat` invocation, so PowerShell single-quoting could not protect arguments containing operators, redirection, or `%VAR%` expansion (a test proved `a&b` broke out and attempted to execute `b`). Wrapper targets now refuse any argument containing cmd metacharacters before a shell is involved; the VS Code extension installer applies the same guard on its shell-backed candidate path. Safe arguments (static literals, filtered extension ids) round-trip unchanged.
- **Coverage gate branch honesty** (#428 follow-up) — `normalize-lcov` serialized branch records as `BRDA:<line>:<block>:<branch>,<taken>` while `parseLcov` reads canonical comma format `BRDA:<line>,<block>,<branch>,<taken>`, so re-parsing the normalized file produced `taken = NaN` and `assert-full-coverage` could never fail on branches (`NaN <= 0` is false). The serializer now emits canonical records (with `-` for never-taken branches) and `coverage-gap-report` consumes the shared parser instead of a private divergent copy. Round-trip regression tests cover normalize-lcov, assert-full-coverage, and the gap report; the gate now genuinely enforces branch coverage.
- **Dead defensive c8-ignores removed** — 13 `c8 ignore` comments added during the v2.1.0 branch were replaced with real tests (fixture-registry adapters driving the `requiresLifecycleHostPaths ?? mutatesHostPaths` fallbacks in wire/workspace/setup, runtime-metadata placeholder arms in `setup hosts`, first-run-hint null arm, ard-registry catalog diagnostic, rejection-sample cap, doctor cumulative-signal race via a new injection seam, script direct-CLI argv arms) or removed with the dead code (silent `catch { return "2.0.0" }` version fallback, `AbortSignal.timeout` reason fallback, index-aligned `?.id ??` fallbacks).
- **`discover catalog` ard-registry honesty** — an enabled ard source before its first sync now prints an explicit hint instead of silently falling through the closed-union switch; the switch's exhaustive `default` fails loudly on any future unhandled `SourceKind`.
- **Registry attribution integrity** — `conan-registry` and `hex-registry` no longer harvest npm packages as official C++/Elixir assets. `getPackageRegistryKind` now has an explicit mapping for every package-registry source in `discover/sources.json` and fails closed (`null`) for unknown ids instead of defaulting to npm; demand harvesting and sitemap sync skip unmapped ids. Catalog ids are now `hex-registry:hex:*` / `conan-registry:conan:*` with correct origin URLs, removing the inflated trust-98 npm entries that topped every recommendation (#424)
- **Atomic JSON state writes** — `writeJsonFile` now writes to a `.tmp` sibling and renames over the destination (crash-safe), with a bounded retry + remove-and-retry fallback for the Windows EPERM locked-destination race. The private duplicate in `ai-enrichment.ts` is gone; all 74 call sites (demand profiles, sync state, generation manifests, acquire state, selection reports, quarantine, activate) are covered (#427)
- **Activation truth and boundaries** — assets with a negative recommendation score for the activation's recommendation host can never be selected (main selection and Copilot fallback pool); staged-bundle breadth for never-recommended assets remains intentional and is now documented in `docs/guides/V2-CONTRACT.md` together with the recommendation → mirror → install → activate hand-off. `activate explain` reasons are truthful per state (recommended / not-recommended breadth / legacy-negative) (#426)
- **Unknown CLI options print errors** — an unknown `--flag` at top-level, domain, or subcommand depth now prints `error: unknown option '<flag>'` plus a usage pointer on stderr and exits 1, instead of dumping full help (or silently executing). Strict known-flag validation covers `discover full/sync/select/breadth/recall/candidate-pool/enrich/stats`, `workspace <host>`, `wire <host>`, `setup doctor/hosts/login` (#431)
- **Guarded catalog term lookup** — `catalog-selection.ts` no longer uses an unchecked `!` on `Map.get`; a guarded throw with entry context replaces it, with the guard reachable through `catalogSelectionInternals` (#433)
- **Parent help lists alias-only subcommands** — top-level `--help` now shows `discover recall` / `discover candidate-pool` (aliases) and `quarantine inspect` / `quarantine report`; the surface-audit suite asserts every dispatch-switch subcommand appears in parent help (#430)
- **Coverage gate measures the whole product — 100%** — the 11 previously-excluded top-level orchestration modules are measured again (56,391 statements at HEAD). The coverage gate now runs **single-process** (`--test-isolation=none`), which eliminates the Windows multi-process merge artifact class (duplicate per-line/column DA records that fabricated false zeros on provably-executed lines and defeated `c8 ignore` suppression — verified with per-file single-process runs and a minimal instrumenter probe). The suite was made single-process-safe: adapter-registry snapshot/restore, script argv defaults gated on direct-entry execution, per-test cold caches for module-level resolution maps, load-generator semantics for the writer churn stresses, and proven-dead defensive branches removed outright. The gate post-processes the merged lcov through `scripts/normalize-lcov.mjs` (canonical max-aggregation of duplicate records) and enforces the hard 100% contract via `scripts/assert-full-coverage.mjs`; `coverage/coverage-gaps.md` is regenerated from the normalized file. Every in-process gap on the fresh gap map is closed with real unit/integration/e2e tests — sanitization, concurrency, and stress axes included (#428)
- **`recommend` subcommand --help shows subcommand-specific options** — `recommend report --help`, `recommend evaluate --help`, `recommend ai-review --help`, and `recommend policy:print --help` now show subcommand-specific usage and options instead of the parent recommend command list (#416)
- **`install refresh --help` uses correct command name** — help headings and usage lines now show `install` (the primary command) instead of the legacy `stage` alias. Parent help says "install commands (stage is a legacy alias)" (#417)
- **`bundle explain --help` shows correct heading** — `bundle explain --help` now shows "bundle explain — Explain why assets are present in a bundle lock" instead of the incorrect "mirror explain" heading (#418)
- **ARD 1.0 export** — `discover ard-export` now emits the public ARD 1.0 root contract: `specVersion`, optional `host`, and `entries`; every entry carries exactly one of `url` or inline `data`, `urn:air:` URN identifiers, and ARD `metadata` for harness round-trip fields. The importer stays backward-compatible with older `data.assetKind` catalogs, trust metadata uses schema-valid HTTPS identity envelopes without inventing unverifiable attestations, and a vendored snapshot of the upstream ARD 1.0 schema plus a dependency-free validator check the generated catalog in tests and in `validate:release` (release, review)
- **`setup doctor` readiness verdict** — stdout reports per-adapter and cumulative timeout scopes separately, routes diagnostics to stderr, and finishes with an explicit `N/M hosts ready` line so the per-adapter vs cumulative timeout contract is checkable (release, review)
- **Unicode-aware ARD schema minLength** — the ARD schema validator counts Unicode code points (not UTF-16 code units) for `minLength` checks, so multi-byte text is validated correctly (release)
- **`kind: docs` sources are metadata-only provenance references** — the 8 existing docs-kind sources (and any future docs-kind source from packs) are disabled before enabled-source, health, harvest, and selection counts are computed; the measured registry is 50 configured sources / 39 enabled asset-producing sources, and tests assert enabled-source counts include only asset-producing kinds (#477)
- **Windsurf dropped from the compatible-host matrix** (#475) — Windsurf is no longer treated as a wiring target; source packs must not imply the harness wires it, and the adapter-development guide uses a neutral example host instead of Windsurf-specific wiring
- **Claude Code wires a real local plugin root** — `wire claude-code` emits `.claude-plugin/marketplace.json` (a managed local `./plugins/agent-harness` source) and `plugins/agent-harness/.claude-plugin/plugin.json`, and both Claude and Codex share a plugin-dir claim guard so an unowned plugin directory is never silently adopted (release, review P1)
- **package-audit runs npm shell-less** — the packed-package audit launches `npm` via `node <npm-cli>` with `shell: false` (no `shell: true`), normalizes the npm 12 `pack --json` shape, exists-checks npm-cli resolution, and drops the dead bare-npm fallback; the DEP0190 shell-script doctrine is never violated (release, review)
- **packed-package smoke tolerates cold runners** — the pack-smoke spawn timeout is raised to 300 s so a cold CI runner (fresh npm cache + AV scan) does not fail the gate at the old 120 s bound; a real cold-runner SIGTERM at the old bound is documented as the failure signature, not a product bug (release, review)
- **`setup doctor` propagates non-timeout adapter errors after signal abort** — the dead `signal.aborted` arm is removed; a real `AbortSignal.timeout` abort surfaces a DOMException `TimeoutError`, while a non-timeout adapter error now propagates/rejects instead of being masked as a timeout (release, review)

### Changed

- **Recommend ranking 17x faster** — a CPU profile of the ranking/selection loop showed ~80% of wall time in phrase canonicalization: `shouldEnforceConcernTarget` rescanned every policy synonym per candidate per selection round, and `normalizePhrase` re-ran three regex passes per term. The enforced-concern set (invariant across the loop) is now precomputed once per host, and the pure normalization is memoized; a 1,000-entry recommendation report went from ~16.3s to ~0.97s on the reference machine with identical golden-fixture output (#428 hardening, `npm run benchmark:paths`)
- **Quarantine dispatcher split** — the last ~600-line monolith from the split wave became a `src/quarantine/` domain: help text in `help.ts`, the state/report/review model in `state.ts`, and the dispatcher + command flows down to 224 lines (#435)
- **CLI dispatch boilerplate consolidated** — the identical unknown-command guard in all seven domain dispatchers is one `handleUnknownCommand` helper, setup's repeated unknown-flag guards are a flag-spec table, `rejectUnknownFlags` is renamed to the predicate `hasUnknownFlag`, and the setup/workspace preflight injection seams share one `PreflightFunctionOverrides` type (standards axis)
- **Self-hosting suite budget raised to 450s** — the full-pipeline self-host test measured ~5m40s on Windows, over the old 300s budget; TROUBLESHOOTING documents the honest runtime and CI headroom (standards axis)
- **Module decomposition** — `discover.ts` (2,003 → 619 total / 539 real-logic lines, under the #434 ~600 real-logic budget) split into `discover-help.ts` (help copy) and `discover-pipeline.ts` (breadth assessment, semantic relevance filtering, demand-relevant source selection); `demand-signals.ts` (1,364) split into `demand-dependency-extractors.ts` (397 total / 264 logic), `demand-file-classification.ts` (274 total / 195 logic), and `demand-manifest-enrichment.ts` (674 total / 507 logic), leaving a 336-line coordinator; `activate.ts` (1,149) became a 507-line dispatcher plus the `src/activate/` domain (`help.ts` 119, `selection.ts` 422 total / 282 logic, `state.ts` 326 total / 240 logic); `recommend/counts.ts` middle-man wrappers collapsed to `countCoverageTagsForItems`; `mirror/plan.ts` reads discovery artifacts through the shared typed `loadDiscoveryArtifacts` loader; the duplicated test-framework filename check in `demand-signals.ts` is one `isTestFrameworkConfigFileName` helper (#434, #435, #436, #437, #438)
- **no-magic-numbers guard re-pointed** — the CONTRIBUTING-documented rule's file list drifted during the split wave: it still named the pre-split homes (`src/activate.ts`, `src/domains/discovery/demand-signals.ts`) while the policy thresholds moved into `src/activate/selection.ts`, `src/activate/state.ts`, and the demand-dependency/file-classification/manifest-enrichment modules, vacating the enforcement for the code it polices. The list now follows the constants (verified live: a bare return literal in `src/activate/state.ts` is reported, the same literal in an unguarded module is not) (standards axis, review finding)
- **Allowed env-var documentation drift** — every `AGENT_HARNESS_*` variable read in `src/` must now appear in both README and `.env.example` (test-only hooks exempt); the drift guard scans `process.env.X` and `env.X` binding styles and 9 previously undocumented variables are now documented (#429)
- **Package metadata truthfulness** — npm `description` no longer claims an MCP-server role; no MCP protocol server exists (`mcp-server` is an asset kind classifier) (#425)

### Breaking Changes

- **Unknown options are now rejected** — `recommend`, `mirror`, `install`, `activate`, `quarantine`, `rebuild`, and `discover inspect` subcommands previously ignored unknown flags silently; they now print a clean one-line error and exit 1. Scripts passing undocumented flags will start failing (#445)
- **User-input failures exit non-zero with a clean message** — CLI user-input errors print `error: <msg>` (plus a usage hint where one exists) and exit 1 instead of dumping raw stack traces; `setup login` with an unknown provider now exits non-zero instead of 0 (#446)
- **ARD export drops `updatedAt` for epoch-sentinel catalog entries** — entries whose `updatedAt` was the epoch sentinel (1970-01-01) no longer emit the field; consumers must treat a missing `updatedAt` as unknown rather than parsing it as the epoch (#449)
- **Recommendation ranking and `fit:exact-stack` gating tightened** — evidence strength now describes the asset side only (workspace-side signals are no longer attributed to assets), and `fit:exact-stack` requires ecosystem affinity plus declared-dependency identity, so single-token collisions no longer push unrelated assets to the top of exact-stack results (#444)
- **Native install plans no longer auto-include single-token lookalike extensions** — `install native` excludes extensions whose only recommendation match is a coincidence token (no curated-identity match) from the plan and from apply/remove execution, with a visible note; automation that consumed the previous plan output should re-read the plan (review)
- **ARD export is now ARD 1.0** — `discover ard-export` emits the ARD 1.0 root contract: `specVersion` (no root `version`/publisher fields), `urn:air:` URN identifiers (replacing `urn:ai:`), and exactly one of `url` or inline `data` per entry; harness round-trip fields move into ARD `metadata`. Consumers of pre-1.0 output must migrate, and the doc covers the 492 stale `legacy` records removed at the 2026-08-21 fix-up (release, review)

## [2.0.0] - 2026-08-02

### Breaking Changes

- **Demand-scan file ordering changed** — binary files are now deprioritised below source files in demand-scan ordering (previously binary and source files were interleaved lexicographically). Tools or tests that assert a fixed scan order or specific truncation behaviour may need to be updated (#280).
- **`.worktrees/` directories excluded from all scans** — file discovery, demand detection, and source-sync traversal now skip `.worktrees/` subdirectories. Workspaces that deliberately stored assets inside `.worktrees/` will no longer have them picked up (#277).
- **Packagist registry enforces a hard 500-entry cap** — Packagist source-sync stops at 500 entries per source. Operators who previously indexed full high-volume Packagist namespaces will observe a reduced catalog for those sources (#286).
- **`source-health` dormant/never-synced `reason` field is now always populated** — previously the `reason` field on dormant and never-synced entries was an empty string; it now carries a descriptive message. Code that matched on empty-string reason will need to update its checks (#281).

### Fixed

- **MSYS path normalisation** — `--state-root /c/Projects/...` is now correctly resolved to `C:\Projects\...` on Windows, preventing silent data misdirection to phantom `C:\c\...` paths (#397)
- **Stopword filtering in capabilities** — `splitIntoKeywords` now filters English stopwords and single-character tokens, preventing noise like "the", "a", "is" from appearing in ARD capabilities and representative queries (#400, #406)
- **Discover stats fallback** — when `catalog.assets.jsonl` is missing but `catalog.selected.jsonl` exists, breakdowns are now built from the available selection instead of showing empty maps (#398)
- **Install malformed-artifact resilience** — `installBundles` now skips malformed mirror artifacts with a warning (including the assetId for diagnosis) instead of aborting the entire install pipeline (#409)
- **ARD trust manifests** — `deriveArdTrustManifest` now generates identity-based trust manifests for all official-first-party, official-compatible, and trusted-community sources, and includes publisher-verified attestations (#399)
- **Dependency directory exclusion** — GitHub repo harvesting now skips files under `node_modules/`, `vendor/`, `.venv/`, `__pycache__/`, and other dependency directories, preventing catalog pollution (#405)
- **Wire plan preview output** — `wire cursor --preview` and `wire vscode --preview` now print a structured plan preview (matching the OpenCode format) instead of showing only preflight diagnostics (#403)
- **CI maintenance noise reduction** — dormant-source false positives from ephemeral CI state roots are filtered; broken sources (severity=error) now surface as bot-plan issues ahead of drift warnings; discovery state cache is persisted between CI runs via GitHub Actions cache (#412, #413, #414)
- **Codex native install** — the Codex host adapter now supports native extension installation via the same mechanism as VS Code/Cursor, replacing the previous `nativeInstall=none` (#407)
- **Help output restructured** — `--help` now includes a Quick Start section at the top and groups commands by lifecycle phase (Discover, Recommend, Mirror & Install, Activate & Wire, Workspace, Setup & Doctor) instead of a dense 40+ command flat list (#410)
- **`--timeout-seconds` global flag** — long-running operations (recommend report, discover catalog) can now be given a configurable deadline via `--timeout-seconds <n>` (clamped 10–3,600) or the `AGENT_HARNESS_TIMEOUT_SECONDS` env var, preventing silent timeout failures on large catalogs (#402, #404)
- **Swift Package Index source disabled** — the `swift-package-index` source is now disabled (sitemap returns 403 Forbidden), eliminating a permanent severe source-health error from every maintenance run (#411)
- **CHANGELOG date corrected** — `[2.0.0]` date updated to `2026-07-31` to reflect the actual release timeline (#408)
- **ard-export Prettier compliance** — `discover ard-export` now formats `.well-known/ai-catalog.json` with Prettier inline, so the output passes `npm run format:check` immediately after generation (#348)
- **Asset-kind diversity threshold** — the diversity penalty for overrepresented asset kinds now applies to the 3rd candidate of the same kind rather than the 4th; prevents extensions from crowding out skills and agents in top-N recommendations (#401 follow-up)
- **MSYS bare drive letter** — `/c` without a trailing slash is now correctly resolved to `C:\` on Windows alongside the existing `/c/X` → `C:\X` normalisation (#397 follow-up)
- **Language identifier preservation** — `splitIntoKeywords` now preserves single-character programming language identifiers (`C`, `R`) and normalises punctuation-based aliases (`C++` → `cpp`, `F#` → `fsharp`) before generic token filtering, ensuring language tokens survive stopword and length checks (#400/#406 follow-up)
- **Catalog file-existence detection** — `discover stats` now distinguishes a genuinely absent raw catalog file (falls back to selected+rejected for breakdowns) from a present-but-empty file (preserves empty breakdown with `catalogSource: raw-catalog`) instead of using the array-length heuristic (#398 follow-up)
- **Install progress skipped-asset tracking** — `InstallProgressState` now records `skippedAssetIds` per bundle (malformed, missing, or uninstallable artifacts), excludes them from `lastBatchAssetIds`, and preserves them in the remaining-asset count so a completed bundle cannot silently omit required batch work (#409 follow-up)
- **Structured source-health reason codes** — dormant CI sources now carry `reasonCode: "ephemeral-ci-state-root"` instead of a bare boolean `ciDetected` flag; the maintenance bot plan matches on the structured code, making the filter self-documenting and extensible for future conditions (#412 follow-up)
- **CLI help quarantine expansion** — `--help` now lists `quarantine approve`, `quarantine reject`, and `quarantine pin` alongside `quarantine list`, and splits Quarantine and Rebuild & Bundle into separate labelled groups (#410 follow-up)
- **Workspace pipeline silent failure** — `workspace <host>` now exits non-zero and stops at the recommend phase when recommendations cannot be produced, instead of silently continuing through mirror/install/activate with empty output (#349)
- **`isAborted()` coverage** — removed `/* c8 ignore */` markers; the helper is now exported and tested through the preflight pipeline with aborted `AbortSignal` (#355)
- **Setup doctor Pi cold-start timeout** — raised default `preflightTimeoutMs` from 10 s to 15 s, eliminating spurious timeout warnings on Pi's first invocation (#350)
- **Source-sync transient-failure resilience** — fetch operations now retry up to 3 times with exponential backoff (1 s, 2 s, 4 s) via shared `fetchWithRetry` wrapper. Non-transient errors distinguished structurally (`NonTransientFetchError` class + HTTP 4xx detection) rather than fragile string-matching. Sources self-heal on next successful sync (#351)
- **Source-sync stale-data fallback** — when a previously-successful source fails to fetch, existing catalog entries are preserved under `status: "stale"` with `severity: "warning"` for up to 3 consecutive failures; only escalates to `severity: "error"` (`status: "failed"`) after persistent failure. Sources self-heal on next successful sync (#351)
- **Broad-fallback host identification** — `recommend evaluate` now lists which specific host IDs produce broad-fallback top recommendations via the new `broadFallbackHosts` field (#354)
- **OpenCode `.gitignore` self-reference** — removed `.gitignore` from `REQUIRED_ENTRIES`; entries now only target lockfiles and `node_modules` (#356 item 2)
- **OpenCode non-null assertion eliminated** — extracted `buildNpmInstallNotes()` helper with proper `== null` guard, removing the `!` assertion. Uses `!= null` (loose) per AGENTS.md convention to guard both null and undefined (#356 item 5 / S2)
- **Duplicate retry-loop code eliminated** — extracted shared `fetchWithRetry<T>()` generic, eliminating ~60 lines of copy-pasted retry logic across `fetchRequiredText` / `fetchRequiredJson` (S1)
- **Error discrimination hardened** — replaced fragile string-matching `isNonTransientError()` with `NonTransientFetchError` class + structured HTTP 4xx status check (J1)
- **Prettier error visibility** — `ard-catalog` catch block now logs `console.warn` with the error cause when Prettier formatting is skipped, instead of silently swallowing (J2)

### Added

- `wire opencode --preview` now prints a structured wire-plan summary to stdout before any file is written, listing linked-asset paths count, resolved MCP server identifiers, native-config operations, and contextual notes so operators can review changes before committing (#284)
- `WirePlanManifest.npmInstallSummary` field documenting the expected OpenCode plugin npm-install footprint (package.json path, declared dependency count, estimated installed-package count derived from lockfile entries or a fallback estimate) so tooling can distinguish OpenCode-managed npm artefacts from reference-pack files wired by agent-harness (#282)
- `SelectionReport.rejectionSummary` (`Record<string, number>`) tallying catalog rejections by reason, and `SelectionReport.sampleRejected` (stratified up-to-20 `{assetId, reason}` entries guaranteeing at least one sample per distinct rejection reason) surfacing demand-relevance and duplicate-rejection signals for diagnostics (#285)
- `RecommendationReport.recommendations[]` flat deduplicated array providing a stable programmatic surface over the recommendation set alongside the existing grouped structure (#283)
- Ecosystem-affinity mismatch penalty (flat 40 pts) in package-registry source scoring — assets from a registry whose ecosystem does not match any detected workspace package manager are penalised; no penalty is applied when the workspace has no package-manager signals or the source is not a package registry (#278)
- Non-empty contextual reason strings for every dormant and never-synced source in source-health reports; previously empty-string reasons are replaced by descriptive messages (last-seen age, zero-entry signal, configuration note) (#281)
- Node CLI framework demand signal: workspaces with `bin` entries and `engines.node` in `package.json` now emit a `node-cli` framework signal used by scoring and policy (#279)
- Binary files are now deprioritised below source files in demand-scan ordering (stable, lexicographic tie-breaking within each tier ensures reproducible truncation across platforms); the CLI emits a stderr warning when the scan is truncated, reporting the truncation reason and the number of files and MB actually scanned (#280)
- `.worktrees/` directories are excluded from all recursive scan passes (file discovery, demand detection, and source-sync traversal), preventing accidental cross-worktree signal bleed (#277)
- Packagist registry source-sync now enforces a hard 500-entry cap per source to prevent runaway catalog inflation from high-volume package namespaces (#286)
- Five new source packs registered in `discover/source-packs/`:
  - **official.json** — `anthropics-knowledge-work-plugins-pack`: official Anthropic collection of 11 role-specific knowledge-worker plugins (productivity, sales, legal, finance, bio-research, etc.) bundling domain skills, slash commands, MCP connector manifests, and sub-agents; `official-first-party`, priority 95
  - **community.json** — `egonex-ai-understand-anything`: multi-platform 6-agent + Tree-sitter codebase-analysis plugin producing interactive knowledge graphs with semantic search, architecture tours, and diff-impact analysis; `unverified-community`, priority 70
  - **community.json** — `leonxlnx-taste-skill`: 13 portable design-taste SKILL.md files (10 code-gen + 3 image-gen) replacing generic frontend boilerplate with high-quality layout, typography, and motion output (39k+ stars); `trusted-community`, priority 72
  - **community.json** — `mukul975-anthropic-cybersecurity-skills`: 754 cybersecurity skills across 26 domains mapped to MITRE ATT&CK v19.1, NIST CSF 2.0, MITRE ATLAS v5.4, D3FEND v1.3, and NIST AI RMF 1.0; community-authored, not affiliated with Anthropic; `unverified-community`, priority 70
  - **community.json** — `imbad0202-academic-research-skills`: full academic research pipeline (research → write → review → finalize) across 4 skill packages with 32+ agents and a 10-stage orchestrator; CC BY-NC 4.0; `unverified-community`, priority 70
- v2 agent asset supply-chain workflow covering discover, recommend, mirror, stage/install, refresh, activate, host wire-in, and rebuild flows across VS Code + Copilot, OpenCode, Cursor, Zed, Claude Code, Pi, and OpenAI Codex
- Codex host adapter support with project-local workspace/wire commands, documented boundaries, source compatibility, recommendation policy coverage, and safe reset behavior for #229
- README hero repositioning, proof points, one-command quick start, concrete lifecycle outputs, command-style conventions, supported-host/asset badges, and a real autoplay demo GIF with a sound-on walkthrough link for #225, #226, #230, #232, #233, #234, and #236
- workspace evolution, maintenance, quarantine, safe-default, trust-center, host support matrix, v1-to-v2 upgrade, release-process, and reproducible demo documentation for #239, #248, #252, #254, #255, #256, #258, and #259
- unknown workspace-signal backlog reports, source/catalog health doctor reports, candidate source queues, scheduled maintenance and maintenance-bot workflows, discover diff summaries, explainability commands, experimental environment index metadata, and evidence-weighted asset classification confidence for #240, #242, #245, #246, #247, #261, #262, #263, and #264
- coverage hardening roadmap and reproducible `coverage:gaps` reporting for #207, plus broad behavioral tests across recommendation, discovery, host-adapter, install, mirror, GitHub, HTTP, release-script, manifest-validation, and utility edge paths
- branch-residual coverage suites for AI enrichment, discovery harvesters, recommendation review/policy/selection, host wiring, install refresh, mirror acquisition, HTTP/preflight utilities, and source-sync helpers, raising the latest verified local run to 100% statements, branches, functions, and lines
- native-host recommendation fixture coverage for Cursor, Zed, Claude Code, and Pi defaults for #208
- demand-detection coverage matrix, targeted stack/vertical signatures, and false-positive fixtures for monorepos, serverless/edge, cross-platform mobile, AI-agent frameworks, commerce/CMS, workflow orchestration, desktop, infrastructure, and related project types for #209
- scenario-based recommendation-limit scaling guidance and copy-paste `preserve` / `scale` examples for #210
- ui-skills.com registered as a community skill registry source (`ui-skills`), discovered via flat sitemap with an item-URL predicate filtering to two-segment `/skills/{author}/{name}/` leaf pages; `itemCompatibilityMode: "adaptable"` across all supported hosts
- ARD (Agentic Resource Discovery) v0.9 interoperability: `discover ard-export` command publishing `.well-known/ai-catalog.json` with URN identifiers, media-type mapping, trust-manifest derivation, and synthetic representative queries for registry discovery (#325)
- README ARD section with ecosystem architecture diagram, publisher/consumer role descriptions, and cross-references to implementation tickets (#329)
- ARD trust-manifest signal consumption: `ard-identity-bound` (+4), `ard-compliance-attested` (+3), `ard-soc2` (+3), `ard-hipaa` (+3), and `ard-signed` (+5) trust-score boosts (#328)
- ARD registry source adapter consuming `POST /search` endpoints, mapping ARD results to `AssetCatalogEntry` with `SourceKind: "ard-registry"`, federated referral tracking, and semantic-score normalization (#327)
- ARD ecosystem community submission documentation for ards-project, GitHub Agent Finder, and HuggingFace Discover (#326)
- ARD representativeQueries wired into SemanticScorer — entries with ARD-generated natural-language query text use 1.2× weighted cosine similarity via `ARD_REPRESENTATIVE_QUERY_WEIGHT`; `buildEntryEmbeddingText` prioritizes `representativeQueries` over keyword-derived capability terms when present (#327)
- ARD publisher FQDN now configurable via `AGENT_HARNESS_ARD_PUBLISHER_FQDN` environment variable with hardcoded default `ar27111994.dev` — production paths use `getArdPublisherFqdn()` getter
- Comprehensive catalog breadth documentation — new `docs/guides/CATALOG-BREADTH.md` guide with two-phase offline index workflow, production configuration table, source coverage breakdown, scheduled CI workflow template, and catalog size projections; README updated with "Building a comprehensive catalog" section
- VS Code Marketplace popularity sweep default raised from 10 to 50 pages (2,500 extensions by install count, configurable via `AGENT_HARNESS_VSCODE_MARKETPLACE_POPULARITY_SWEEP_PAGES`) for offline index builds
- Fixed skills-sh registry source — sitemap URL updated to `www.skills.sh` (308 redirect) and leaf predicate expanded to match `sitemap-(skills|agents|misc|owners)` patterns (#336)
- **`--quiet` / `--summary` flags for `discover full`** — `--quiet` suppresses expected "none survived selection" warnings; `--summary` prints aggregate breakdown by reason instead of per-source counts (#352)
- **`SelectionReport.acceptanceRate`** — computed as `selectedCount / inputCount` (rounded to 4 decimal places); 0 when inputCount is 0. Backfilled for pre-v2.0.0 reports (#353)
- **`SourceSyncStatus` extended** — new `"stale"` variant for sources using fallback data after transient fetch failures

### Changed

- source-sync prune predicate now uses `allPreviousCursorsCompleted` to determine whether a run constitutes a full re-scan, replacing the previous `observedEntryIds` guard; correctly prunes stale entries on legitimately empty sources while preventing accidental pruning during mid-stream cursor resumes
- `no-magic-numbers` ESLint rule extended to the full `src/domains/discovery/source-sync/**/*.ts` sub-tree following the decomposition in #270, covering all nine per-registry adapters and shared helpers
- default workspace troubleshooting docs now include a diagnostic ladder, artifact checklist, anti-vibes evidence requirements, and clearer playbook handoffs for #211
- coverage thresholds were raised to the verified 100% release floor while keeping runtime exclusions narrow instead of masking uncovered code
- recommendation policy maps now recognize the newly emitted demand/stack terms so detection, policy quality, and recommendation validation stay aligned
- `source-sync.ts` (1,916 lines) decomposed into 16 focused sub-modules under `src/domains/discovery/source-sync/` — shared types, state I/O, fetching, HTML engines, references, reporting, orchestrator, and 9 per-registry adapters — with `source-sync.ts` retained as a thin re-export barrel so all existing import paths are unchanged for #270
- `no-magic-numbers` ESLint rule expanded to `activate.ts`, `official-index-harvester.ts`, and `demand-signals.ts`; 11 new named constants extracted (`COPILOT_PROFILE_ID_MAX_LENGTH`, `COPILOT_VSCODE_ACTIVATION_BUDGET`, `OPENCODE_ACTIVATION_BUDGET`, `DEFAULT_ACTIVATION_BUDGET`, `FOCUSED_ACTIVATION_BUCKET_MAX_SIZE`, `COPILOT_FALLBACK_SKILL_POOL_LIMIT`, `COPILOT_PROFILE_ID_ASSET_SEGMENT_COUNT`, `OFFICIAL_FIRST_PARTY_SOURCE_PRIORITY`, `NON_FIRST_PARTY_SOURCE_PRIORITY`, `MAX_DEPENDENCY_SIGNALS_PER_FILE`, `TEXT_SIGNAL_READ_LIMIT`) for #271
- **Activation budget lookup** — replaced sequential `if` branches in `getActivationBudget` with a `Map<ActivationHost, number>` lookup (#356 item 1)
- **Rejection sample size constant** — extracted inline `SAMPLE_SIZE = 20` to file-level `REJECTION_SAMPLE_SIZE` for consistency (#356 item 6)

- `writeJsonFileAtomically` no longer performs a pre-delete before the atomic rename, closing a window where a crash between `rm` and `rename` could leave a discovery artifact missing entirely (#316)
- `swapActivationRuntimeRoot` now surfaces rollback failures via `AggregateError` when both the apply and the restore rename fail, preventing the runtime root from being silently left in a missing state (#317)
- `readSharedMcpAssetIds` validates that `pkg.manifestPath` stays within the install root before reading, closing a path-traversal risk via tampered bundle manifests (#318)
- Extension-ID parsing in `verifyVsCodeExtensionInstalled` now strips only the trailing `@version` suffix instead of splitting at the first `@`, so scoped extension IDs are no longer truncated (#319)
- `writeJsonLinesFile` no longer performs a pre-delete before the atomic rename, closing the same window as #316 for all catalog JSONL output files — `catalog.assets.jsonl`, `catalog.selected.jsonl`, and `catalog.rejected.jsonl` (#306)
- Publisher name for VS Code Marketplace extensions is now resolved from the per-extension `publisher.publisherName` field harvested at sync time rather than the source-level publisher override, so extensions from non-Microsoft publishers are correctly attributed (#300)
- `install refresh` no longer crashes with ENOENT on a clean checkout: missing `mirror/bundles/*.lock.json` files are now gracefully skipped during `resolveBundleLocks` (#298)
- `setup doctor` now runs all host-adapter preflights concurrently and enforces a per-adapter wall-clock timeout (default 5 s, configurable via `AGENT_HARNESS_SETUP_DOCTOR_HOST_TIMEOUT_MS`), preventing a blocked CLI probe from hanging the entire command (#302)
- `recommend report` now fails immediately with a clear error when `catalog.selected.jsonl` is absent or empty, instead of hanging for 10+ seconds against an empty dataset; the error message directs users to run `discover full` or `discover select` first (#303)
- `synonymLookup` map is now built once per recommendation report instead of once per candidate entry, eliminating an O(tokens × synonyms) hot path that caused `recommend report` to stall for 81 s on real 2,000-entry catalogs (#299, #321)
- Packagist PHP entries no longer rank in the top results for TypeScript/Node workspaces: the ecosystem-affinity mismatch penalty is now doubled (2×) when the workspace has package-manager signals and none match the candidate registry's ecosystem (#278)
- Per-source entry cap enforced in `discover select`: no single source may contribute more than `AGENT_HARNESS_MAX_ENTRIES_PER_SOURCE` (default 200) entries to the selected catalog; excess entries are logged as `"source-cap"` rejections; a `sourceDiversityWarning` field is emitted when any source still exceeds 20% after capping (#304)
- `assertRecommendationReport` backfill shim is now documented as a legacy-only compatibility path; fresh report writes are validated for the `recommendations` key before the validator runs, so write-path regressions are immediately visible in tests (#283)
- Agent coding conventions and contributor guidance added to `CONTRIBUTING.md` (not `AGENTS.md`, which is gitignored) (#322)
- `docs/guides/TROUBLESHOOTING.md` created, covering host CLI setup, version failures, doctor hang, install ENOENT, concurrent-write safety, and Packagist asset dominance; linked from README (#305)

- `wire opencode --apply` idempotently writes `.opencode/.gitignore` listing `node_modules`, `package-lock.json`, `bun.lockb`, `yarn.lock`, and `pnpm-lock.yaml` before OpenCode starts, ensuring its overlay scanner skips npm install artefacts and eliminating ~800 spurious `OVERLAY:` log lines per run (#282)
- Go module index cursor now encodes `timestamp|lastSeenPath` (pipe-delimited) instead of a bare timestamp, eliminating the gap-or-duplicate hazard when multiple modules share the same timestamp at a page boundary; legacy bare-timestamp cursors are transparently upgraded on first resume
- npm changes-feed adapter now calls `deleteIndexedCatalogEntry` for rows with `deleted: true`, immediately removing stale catalog entries instead of leaving them until the never-firing prune-on-complete path
- improved release synchronization, version-check, GitHub resilience, guarded HTTP, path/file, native wire, install refresh, mirror acquisition, and recommendation validation regression coverage with deterministic tests
- `evidence.classification` is now populated for all harvested assets — `buildClassificationConfidence` synthesizes classification evidence from the asset's known `assetKind` so the field is never `null` in catalog output (#301)
- GitHub harvester now emits an `oms-trust-anchor` repo-level trust signal when `nv-agent-root-cert.pem` is detected, and a per-asset `oms-signed` signal when a sibling `skill.oms.sig` file is present; trust-score effects are `+3` and `+5` respectively (#315)
- `discover index` command added as a dedicated catalog-index build step — writes `catalog-index.jsonl` plus a freshness-aware meta companion; `discover sync` reuses a fresh index when it is within `AGENT_HARNESS_DISCOVERY_INDEX_MAX_AGE_DAYS` (default 7) rather than re-harvesting from scratch; raised `AGENT_HARNESS_SOURCE_SYNC_MAX_PAGES_FOR_INDEX_BUILD` default to 500 for index-build runs (#289)
- VS Code Marketplace harvesting now runs a popularity-first sweep (top installs by count) ahead of the alphabetical demand-query loop, and a category-sweep phase driven by workspace demand → VS Code category taxonomy mappings; both phases are runtime-configurable via `AGENT_HARNESS_VSCODE_MARKETPLACE_POPULARITY_SWEEP_PAGES` and `AGENT_HARNESS_VSCODE_MARKETPLACE_CATEGORY_SWEEP_ENABLED` (#290, #291)
- Official skills index expanded from 1 to 16 entries; `AGENT_HARNESS_OFFICIAL_INDEX_MAX_ITEMS_PER_INDEX` enforces a per-index cap (0 = unlimited) to prevent runaway harvesting from large official feeds (#292)
- `discover/source-packs/official.json` seeded with 12 high-value MCP vendor entries (Anthropic, Stripe, Cloudflare, Supabase, GitHub, Sentry, Docker, Linear, Notion, Resend, Postmark, Braintrust); `authorityTier` and `assetKinds` are now required fields on all source-pack entries; a `scripts/seed-source-packs.ts` seeding automation and matching guide doc added (#293)
- Six new official source-pack entries covering `google/gemini-cli-extensions`, `/sre`, `data-agent-kit`, `conductor`, `NVIDIA/skills`, and `solana-foundation/pay-skills`; new `"payable-api"` and `"acp-agent"` asset kinds added to the `AssetKind` union and validated constants (#307, #308, #309, #310, #311, #313)
- Host surface gaps documented across Cursor, Windsurf, Cline, JetBrains, Zed, and Copilot plugin compatibility; `HOST-SURFACE-AUDIT.md` updated; VS Code extension compatibility notes, ACP/forwarding notes, and Claude-plugin schema notes added to support-matrix and README (#314)
- `AssetCatalogEntry.compatibleHosts` field introduced; compatibility matrix derives cross-host support from asset kinds during harvesting; recommendation selection respects `compatibleHosts` when filtering candidates for each target host (#312)
- Semantic similarity scoring added as an optional selection filter — `SemanticScorer` uses `@xenova/transformers` (optional peer) with cosine similarity and `fit.fitLevel` tagging (`"strong" | "moderate" | "weak" | "none"`); falls back to keyword-overlap gating when the runtime dependency is unavailable; configurable via `AGENT_HARNESS_DISCOVERY_SEMANTIC_SCORING` and `AGENT_HARNESS_DISCOVERY_MIN_SIMILARITY` (#294)
- Registry metadata enrichment for 7 additional registries — static adjacent-tooling matrix and live search APIs for crates.io, NuGet, Maven, Packagist, RubyGems; `AssetEvidence` extended with `discoveryMethod` field (#295)

### Documentation

- added full Codex surface table (13 rows) to `HOST-SURFACE-AUDIT.md` documenting all managed path segments, config files, and lifecycle hooks for #229
- surfaced `HARNESS-MAINTENANCE-GUIDE.md` link in README Quick Start so post-wire-in maintenance steps are discoverable for #248
- added icons to all supported-host badges (VS Code + Copilot, OpenCode, Cursor, Zed, Claude Code, Pi, OpenAI Codex) and all asset-type badges using Simple Icons slugs and inline SVG data URIs where shields.io slug support lags
- documented source-sync SSRF trust boundary, allowed-origin derivation algorithm, and operator-facing SSRF backstop guidance in `SECURITY.md` and `SOURCE-SYNC-DECOMPOSITION-PLAN.md` for #272
- audited and updated all stale reference documentation: `Roadmap.md`, `IMPLEMENTATION-PLAN.md`, `FUTURE-IMPROVEMENTS.md`, `COVERAGE-100-ROADMAP.md`, and `SOURCE-SYNC-DECOMPOSITION-PLAN.md` now reflect v2.0.0 execution status, shipped capabilities, and current coverage metrics for #273

## [1.0.8] - 2026-05-17

### Fixed

- `rebuild full` now refreshes selected mirror artifacts whose raw cache directory predates the mirror `manifest.json` format, preventing install from failing on stale `mirror/index.jsonl` entries after upgrading existing workspaces
- CodeQL URL-sanitization alerts in mirror/install regression tests are resolved by parsing mocked request URLs before checking allowed hostnames

## [1.0.7] - 2026-05-14

### Added

- durable user-owned recommendation policy overrides for both the shared base policy and per-host policy layers, so package defaults can be extended safely without losing local operator intent
- explicit recommendation-limit override modes that distinguish `preserve` from `scale`, shared runtime/recommendation constants, and clearer effective-policy metadata in `recommend policy:print`
- a reusable built-CLI test harness, dedicated self-hosting integration suite, GitHub resilience regression coverage, and enforced coverage reporting with CI-published summaries
- demand-detection, source-coverage, and logging-strategy playbooks to document the new operational quality gates and tuning workflow

### Changed

- CLI help rendering now flows through shared output helpers instead of repeated ad hoc printers, keeping subcommand help output consistent without preparing state as a side effect
- lint guardrails now enforce tighter console usage and magic-number discipline in the policy/runtime hot paths, and the quality workflow now runs coverage-gated unit/integration tests before publishing a summarized coverage report
- `FUTURE-IMPROVEMENTS.md` now reflects the current implementation state so shipped capabilities are marked as implemented or partial instead of being left as stale future work

### Fixed

- GitHub remote harvesting now preserves cache-backed degraded operation under rate limits, serializes source-health cache repairs, and has regression coverage for malformed persisted state
- recommendation selection/reporting now uses extracted shared thresholds and weights instead of repeated literals, reducing configuration drift across runtime and ranking code
- release preparation for `v1.0.7` now keeps `package.json` and `package-lock.json` synchronized at the published version header

## [1.0.6] - 2026-05-13

### Added

- automated GitHub Release synchronization on release tags so the workflow now creates or updates the GitHub Release page, blends curated changelog notes with GitHub-generated notes, and stays rerun-safe
- extracted non-trivial release/build/version-check logic into readable `scripts/` modules with direct script-level regression tests

### Fixed

- updated the remaining stale multi-intent prompt wording in `AI-ENRICHMENT-PLAYBOOK.md` and `RECOMMENDATION-POLICY-PLAYBOOK.md`
- standardized the user-facing VS Code host name to `vscode` across recommend/policy command surfaces while still mapping it to the internal `copilot-vscode` recommendation host where needed

## [1.0.5] - 2026-05-13

### Changed

- aligned README and playbook guidance with the shipped multi-intent behavior so repeated `--intent` flags are documented as additive recommendation/workspace inputs while the first intent remains the primary activation/manifests context
- clarified that `agent-harness workspace <host>` is the straightforward default end-to-end path for new users, while `discover breadth` remains the recall-first diagnostic flow and `wire <host>` remains the lifecycle-output wiring command

### Fixed

- removed stale single-intent wording that still implied repeated `--intent` flags were unsupported after the `1.0.4` multi-intent implementation landed
- prepared release metadata for `v1.0.5` by synchronizing the package version and lockfile version headers
- added a version-synchronization validation check so CI fails when `package.json` and `package-lock.json` drift out of sync

## [1.0.4] - 2026-05-12

### Added

- `--intent` now accepts repeated values to combine multiple session intents additively in a single run (e.g. `--intent backend --intent docs`); the first intent is recorded as the primary for backward compatibility; single-intent runs are unaffected
- long-running discovery and workspace flows now print visible phase and batch progress so `discover demand-profile`, `discover sources`, `discover sync`, `discover catalog`, `discover select`, `discover full`, `discover breadth`, and workspace mirror/install orchestration expose live progress instead of appearing stalled

### Fixed

- `recommend report` no longer hangs on large selected candidate sets; policy-derived search term sets (`concernKeywordMap`, `taskModeKeywordMap`, `domainKeywordGroups`) are now precomputed once per report build via `buildPolicySearchContext(...)` instead of once per candidate per host, reducing time from ~7 minutes to under 5 seconds on a 5.5k-entry selected pool

## [1.0.3] - 2026-05-11

### Added

- structured host-native file payload support so assets can synthesize documented OpenCode, Cursor, Zed, Claude Code, and Pi config surfaces when explicit native payloads are present
- explicit `cursor-marketplace` source coverage in the checked-in discovery registry plus regression coverage for direct official host-source representation
- checked-in `mattpocock/skills` trusted-community repo coverage in the discovery registry
- widened generic official/community repo and registry sources to target every supported host instead of legacy minimized host pairs where the assets are portable across adapters
- recommendation fixture evaluation now records aggregate quality metrics, including top-rank reason mix, top-rank confidence mix, broad-fallback frequency, and local-availability frequency
- scenario-specific playbooks for discovery breadth, AI enrichment, asset refresh/update, recommendation policy tuning, and dry-run operator setup so both manual setup and agent-operated setup can follow the same verified workflows

### Changed

- OpenCode now projects managed instruction assets into `opencode.json` and native adapters can apply reversible structured payload merges for documented host config files
- Cursor now writes project-local agent files under `.cursor/agents/agent-harness/` in addition to the staged plugin-compatible bundle
- README and `HOST-SURFACE-AUDIT.md` now document current host-native synthesis boundaries, direct per-host discovery coverage, and the current CLI surface without migration-era wrapper-binary framing
- README now documents the layered confidence model, explain-output reason classes, and how to read `recommend evaluate` as a precision-vs-fallback signal instead of only a pass/fail check
- source-sync now reruns finite indexed sources from the beginning on completed passes, evicts entries that disappeared upstream after a fresh complete sync, and keeps append-only cursors resumable for feed-style registries
- install refresh now blocks ambiguous multi-bundle mirror conflicts instead of silently picking the last seen mirror id, and refresh report validation now checks nested fingerprint and native-install payloads
- guarded HTTP body timeouts now cancel active readers before surfacing timeout failures, demand-context session intent signals still apply when no demand profile is available, `discover breadth` now provides a first-class recall-first discovery command for widening the candidate pool before ranking, and `stage` is now the clearer preferred lifecycle term with `install` retained as a supported alias
- README and `AGENT-SETUP-PLAYBOOK.md` now consistently mark lifecycle artifact paths as state-root-relative, distinguish state-root lifecycle output from workspace-local host files, and clarify the real lifecycle ordering plus the bounded meaning of the stage/install phase
- the workspace pipeline now runs indexed discovery sync before catalog/recommendation so one-shot host flows use the same broadened discovery universe as explicit breadth audits

### Fixed

- active documentation no longer frames primary usage and troubleshooting around removed wrapper binaries instead of the supported `agent-harness` CLI surface
- AI enrichment validators now accept nullable fingerprint hashes for disabled/skipped artifact fingerprints during explicit opt-out and other non-completed flows
- Zed and Pi native reset cleanup now removes empty managed parent directories instead of leaving empty host metadata folders behind
- demand discovery now prioritizes root manifests under scan-budget pressure and ignores `.agent`, `.dart_tool`, and `.specify` metadata directories by default so real-workspace detection is less distorted by tool metadata
- JSONL state reads now tolerate ENOENT races during streaming, rethrow non-ENOENT stream failures correctly, and JSONL writes replace existing destinations reliably on Windows while avoiding repeated chunk byte-length rescans
- discovery catalog generation now buckets indexed entries by source once, avoids stack-overflowing on very large indexed source populations, trusted-local demand gating no longer lets concern-only phrases reject trusted-local guidance, source-sync avoids pruning indexed entries after transient zero-observation complete runs, and source-utilization fallback coverage matches source kind defaults
- `.env.example` keeps install refresh policy comments adjacent to the policy key, recommendation-report coverage now documents validator defaulting side effects, and install refresh due-only coverage asserts the persisted schedule state is left untouched when a run is skipped

## [1.0.2] - 2026-05-08

### Added

- added `AGENT-SETUP-PLAYBOOK.md`, a dedicated dry-run setup guide with a troubleshooting decision tree, asset-action classification guidance, and reusable AI-agent prompts for workspace/host/intention-based setup flows

### Changed

- README now links the dedicated `AGENT-SETUP-PLAYBOOK.md` guide and documents a preview-first workflow for AI-assisted setup/operator usage
- README now includes a dry-run troubleshooting decision tree that separates demand detection, selection breadth, ranking/policy, and install/runtime follow-up

### Fixed

- documented operator guidance now makes it explicit that increasing selection count should not be the first move when relevant assets already exist in the selected set

## [1.0.1] - 2026-05-08

### Changed

- made the Release workflow rerun-safe for manual `workflow_dispatch` runs so already-published versions skip duplicate publish steps instead of failing noisy follow-up checks
- normalized the `Unreleased` changelog section headings to keep post-release changelog structure consistent

### Fixed

- `official-index-entry` mirror acquisition now falls back to structured official-index page content when repo-backed package materialization fails for non-cap reasons, which unblocks the real `InterActNote` + OpenCode workspace flow that previously stopped on Flutter-related `materialize-failed` skips
- official-index HTML entity decoding now unescapes ampersands last, preventing double-decoding of values like `&amp;quot;`

## [1.0.0] - 2026-05-01

### Added in 1.0.0

- centralized runtime configuration with schema-style validation, automatic current-working-directory `.env` loading, documented `.env.example` defaults, and shared preflight diagnostics
- cross-platform path handling for VS Code settings, home-relative display paths, generated local source seeds, and source endpoint resolution
- modular discovery detector packs for docs, notebooks, datasets, media/design assets, CAD/hardware, research, game engines, mobile, and ML artifact repos
- scan budgets, expanded ignore profiles, link lifecycle tests, scan benchmark budgets, and Windows/macOS/Linux CI coverage
- source utilization reporting that separates configured sources from operationally harvested sources
- dependency-evidence package registry harvesting for npm and PyPI plus docs, registry, and marketplace reference harvesters
- `github-awesome-copilot-site` as a default official docs source so discovery can harvest the `awesome-copilot.github.com` catalog alongside the backing repository
- `clawhub` as a default community registry source for broader catalog/reference coverage without enabling default mirror/install promotion
- host adapter registry with capability matrices, guided setup/doctor commands, adapter-specific CLI readiness diagnostics, native project-local auto-wiring for Cursor, Zed, Claude Code, and Pi, independent per-host recommendation policies, extension install planning, prompt-template/command coverage, and shared MCP wire plan projection
- policy coverage reporting that checks detector-emitted terms against recommendation policy maps, fails CI on unmapped terms, and emits human-reviewed draft policy suggestions
- regression tests for dotenv duplicate/multiline parsing, CLI option missing-value handling, VS Code settings patching, safe mirror artifact paths, and PyPI metadata normalization
- guarded HTTP helpers with origin allowlists, timeouts, and response byte limits for external content reads
- domain-specific discovery modules for demand profiling, source indexing, source utilization, package/reference/local/GitHub/official-index harvesting, catalog selection, and catalog trust utilities
- focused install-domain modules, domain-local manifest validators, and localized type modules that preserve stable public barrel entrypoints while reducing large shared files
- scoped public package identity as `@ar27111994/agent-harness`, package metadata, npm `files` allowlist, prepack build, packed-artifact smoke validation, and release workflow with OIDC trusted publishing, provenance-ready publish checks, and package build validation in the publish job
- Dependabot version and security update configuration for npm packages and GitHub Actions plus repository funding metadata and README npm/sponsor badges
- mutable state-root support through `--state-root` and `AGENT_HARNESS_STATE_ROOT`, with packaged CLI defaults writing lifecycle output to workspace-local `.agent-harness/` instead of the package install directory
- `quarantine list/inspect/approve/reject` review commands with review logging for quarantined mirror artifacts
- optional `discover enrich` AI-assisted enrichment reports through an explicitly configured OpenAI-compatible endpoint
- `setup login` provider guidance for GitHub, npm, and optional AI enrichment configuration
- `mirror diff` and `mirror explain` commands for phase-level inspection
- explicit `.npmignore` release-artifact controls that keep source, tests, source maps, CI metadata, runtime state, local tarballs, and planning-only docs out of packed artifacts
- registry-driven recommendation-host enumeration, extensible host-target validation, package entry points, TypeScript declaration output, and release checks across Ubuntu, macOS, and Windows
- regression coverage for real-world TypeScript/Apify, Flutter/Firebase, native mobile, finance/trading, BI, DevOps/networking, MLOps/RAG, embedded/robotics/blockchain, data-mining/SEO, demand relevance selection, command help side effects, executable MCP package search, and human-readable generic asset names

### Changed in 1.0.0

- bumped the package version to `1.0.0`
- routed ad hoc environment access through the centralized config module
- replaced checked-in workstation-specific local source paths with home-relative defaults
- split new architecture, discovery, wire, host adapter, config, install, manifest-validation, type, and preflight work into package-style seams, including host-native implementations under `src/host-adapters/`
- consolidated workspace execution on `agent-harness workspace <host>`, removed legacy `agent-harness-vscode` and `agent-harness-opencode` package binaries, and added workspace scripts for all registered adapters
- ignored local environment files, local package tarballs, mirror index snapshots, and generated project-local native host wiring artifacts for Cursor, Zed, Claude Code, and Pi to prevent accidental commits from local smoke runs
- extended Copilot workspace profiles and wire plans to distinguish plugins, extensions, native install actions, and shared MCP assets
- expanded detection quality fixtures to cover roadmap archetypes and made recommendation policy tuning evidence-driven instead of ad hoc
- refined host compatibility, activation host validation, native JSON merge safety, OpenCode shared MCP projection resilience, and Python dependency evidence extraction including Poetry `pyproject.toml` sections
- changed `wire <host>` to default to preview mode; `--apply` or `--reset` is required for mutating wire operations
- made workspace and full rebuild runs invoke the recommendation stage explicitly after discovery selection instead of relying on hidden `discover select` side effects
- made docs, registry, and marketplace source references attempt guarded summary harvesting and source utilization distinguish active, reference-only, and dormant sources
- mirror acquisition now accepts pinned GitHub-tree and official-index artifacts when raw content verifies against the pinned blob SHA even if the GitHub branch-commit lookup is temporarily unavailable
- README and `.env.example` now document that GitHub tokens help both discovery and GitHub-backed mirror acquisition on larger real-workspace runs
- made VS Code settings path resolution lazy so `.env` overrides for path-related variables are honored after CLI bootstrap
- centralized CLI option parsing and rejection of flag-looking tokens as missing option values
- split recommendation policy loading, CLI commands, host enumeration, internal recommendation models, and report/scoring logic into `src/recommend/` modules behind the stable `src/recommend.ts` facade
- split mirror planning, bundle locking, acquisition/materialization, inspection, constants, and path handling into `src/mirror/` modules behind the stable `src/mirror.ts` facade
- tightened ESLint with type-aware no-floating-promise and unsafe-access rules plus scoped console-output enforcement for CLI boundary modules
- reduced `src/discover.ts`, `src/install.ts`, `src/manifest-validation.ts`, and `src/types.ts` to stable entrypoints backed by focused domain modules
- made catalog selection demand-aware before duplicate selection so irrelevant source-pack entries are rejected before recommendation
- aligned OpenCode, Zed, Pi, Cursor, and Claude Code capability matrices with documented host-specific assets including OpenCode commands, Zed MCP/reference support, Pi prompt templates, Cursor prompt/plugin assets, and Claude Code prompt/MCP assets
- made CLI `--help` and `-h` flags route to command-group usage before lifecycle state is prepared

### Fixed in 1.0.0

- mirror multi-file artifact writes now reject path traversal outside the raw mirror root, clean raw artifact directories before writing, store file manifests, and verify aggregate hashes during install
- PyPI metadata is validated and normalized field-by-field before repository URL extraction
- GitHub process-local rate-limit and health-update state can be reset between repeated in-process CLI invocations
- install batching no longer treats a missing progress state as a completed bundle
- demand profiling honors `.gitignore`, `.ignore`, and `.agent-harnessignore` patterns in addition to built-in generated-directory skips, including simple glob wildcards and negation re-inclusion rules
- GitHub/repo assets are mirrored through guarded fetches during mirror acquisition instead of being fetched live during wire-in
- guarded pinned GitHub lookups now honor Node's `lookup(..., { all: true })` callback shape, which eliminates the `ERR_INVALID_IP_ADDRESS` failure mode that caused real-workspace GitHub fetches to be skipped as null
- official-index upstream repository links are constrained by a checked-in owner allowlist and schema-backed `discover/official-upstreams.json` asset
- install and activation now enforce bundle activation eligibility, verify/copy only mirror-manifest-listed files, and skip quarantined or unpromoted assets
- mirror acquisition quarantines prompt-injection-like community content for manual review
- VS Code and OpenCode wire-in preserve unmanaged instruction/`AGENTS.md` content through managed sections instead of wholesale replacement
- isolated CLI and offline workspace lifecycle smoke tests now run against temporary home/config/state roots so validation does not mutate real user host configuration
- Cursor native extension installation is planned through a compatible VS Code-style `cursor` CLI when structured extension IDs are available
- mirror evidence file reads are restricted to the working directory, state root, and known local seed roots before any local file content is mirrored
- optional AI enrichment now uses centralized runtime configuration, static public-provider origin allowlists, and private/loopback/link-local hostname rejection before sending API keys
- install bundle discovery now derives lock paths from registered host adapter bundle defaults and warns when expected locks are missing
- duplicate checked-in local source definitions were removed in favor of runtime-generated local sources with dynamic endpoints
- shared mirror path guards are reused by both mirror acquisition and bundle installation, and GitHub timeout handling uses one `AbortError` helper
- guarded HTTP fetches now resolve and pin public DNS answers before requests, mirror evidence reads reject symlink escapes, GitHub mirror downloads verify raw-byte upstream blob SHAs, and prompt-injection quarantine detection covers normalized jailbreak and secret-exfiltration variants
- recommendation selection now preserves policy minimums above one, keeps hard source/duplicate caps in fallback selection, and keeps suggested bundles within activation budgets
- native and VS Code wire-in now preserve applied preview state, reuse activation asset path sanitization, and avoid clobbering user-owned global skill-location preferences
- rebuild, scanning, discovery, activation, and install flows now use workspace roots consistently, skip generated discovery output, reuse demand-signal file reads, atomically stage activation runtime views before swapping, merge bundle membership, mirror audit-only assets, reject truncated GitHub snapshots, and validate all Copilot workspace profile selection arrays
- public exported declarations now include API docstrings with a regression test that fails when exported source declarations lack JSDoc coverage
- demand profiling now uses delimited technology text-marker matching to avoid substring false positives such as `ros` inside common TypeScript words
- demand profiling now covers broader repo archetypes including finance/trading, BI/reporting, DevOps/platform engineering, network automation, advanced security, MLOps/RAG/vector search, creative media, embedded/firmware, robotics simulation, extended blockchain, data mining, slicer/3D-printing, and CMS/SEO/content workflows
- dependency parsing now feeds technology signatures for Cargo, Go, Maven/Gradle, NuGet, RubyGems, Packagist, and SwiftPM manifests, handles Poetry inline table dependencies, requirements variants, Cargo workspace dependencies, Gradle two-part coordinates, NuGet central package management, and avoids prose-scanning lockfiles
- demand profiling now detects Dart/Flutter `pubspec.yaml`, Firebase `pub` dependencies, Kotlin/Java Android, Swift, Objective-C, CocoaPods, SwiftPM, C#/.NET MAUI, and Xamarin mobile projects
- package-registry discovery now uses demand-derived npm search queries for executable MCP servers instead of checked-in package-name allowlists, and registry MCP classification recognizes executable server package patterns
- GitHub tree harvesting no longer treats Markdown files that mention MCP as executable MCP servers
- generic catalog filenames such as `SKILL.md` and `README.md` now fall back to human-readable parent directory names
- Claude Code and Cursor local config harvesting now recognizes host-native agents, commands/prompt packs, skills, hooks, plugin manifests, MCP config files, and rule/context files while keeping generated local config sources catalog-only by default
- Cursor wire-in now stages a plugin-compatible component tree under `.cursor/agent-harness/cursor-plugin`, and Claude Code wire-in now writes a managed `.claude/agents/agent-harness.md` project agent
- native host wire-in now exposes every selected asset kind through host managed references and wire-plan buckets for Cursor, Zed, Claude Code, and Pi
- recommendation redundancy scoring now uses maintained selection indexes instead of scanning every selected candidate for each score

## [0.2.0] - 2026-04-27

### Added in 0.2.0

- a policy-driven recommendation engine with host-specific overrides, schema-backed policy files, richer recommendation reporting, and golden recommendation fixtures
- a stronger developer quality toolchain with ESLint, Prettier, Husky, lint-staged, and CI validation for both code quality and recommendation behavior
- a centralized manifest validation layer and expanded discovery, mirror, install, and activation plumbing across the end-to-end pipeline
- roadmap and implementation-planning documentation tied directly to milestone and work-item tracking issues

### Changed in 0.2.0

- promoted validation from a single typecheck command to a broader `typecheck`, `lint`, `format`, `validate`, and `validate:recommendations` workflow
- expanded recommendation authoring into modular base and per-host policy files instead of one large policy blob
- improved VS Code and OpenCode wire-in behavior, including better curated runtime projection and Windows-friendly directory linking
- broadened source packs, schemas, and registry inputs to improve catalog generation and recommendation quality

## [0.1.0] - 2026-04-13

### Added in 0.1.0

- the initial end-to-end agent asset lifecycle covering discover, mirror, install, activate, and host wire-in
- workspace wrappers for GitHub Copilot in VS Code and OpenCode to run the full pipeline against a target workspace
- source discovery across local generated assets, official repositories and indexes, trusted community inputs, docs, and package registries
- staged host-specific package stores, generation-aware activation outputs, and reproducible mirror artifacts with quarantine support

### Changed in 0.1.0

- established the project baseline as a Node.js 22+ TypeScript CLI with published `agent-harness`, `agent-harness-vscode`, and `agent-harness-opencode` entrypoints
