Harness Intelligence Wiki
SpecsCLIRegistry Baseline

Registry Baseline

Spec: Registry Baseline

Context

The operating agent and the human operator need the harness content in a repository to be current, to know when it is not, and to update it without manual repair. Today the hi CLI proves its own previous output with 654 recorded hashes, stages a temporary copy of the repository for every update, and regenerates files the operator tailored. Of 47 CLI issues, 15 trace to persisted derived state, 19 to generation logic, and 6 to the temporary candidate; hash drift and candidate failures each recurred after four fix waves. Issue #232 is open: the generated lint runner caps output at 10 MiB and the commit gate inlines the full owner file set into one shell string.

The user closed the grill on 2026-09-27 with Q1 to Q35 and Glossary Q32a accepted in the decision log. The glossary defines canonical terms. The retained architecture is ARCHITECTURE.md at commit 3e63ec3cdb0a07922db908dc625b6cfabfdb2a1a (blob https://github.com/wearedevpunks/harness-intelligence/blob/3e63ec3cdb0a07922db908dc625b6cfabfdb2a1a/apps/wiki/content/docs/project/specs/cli/registry-baseline/ARCHITECTURE.md). Source evidence: the architecture research report and the target system brainstorm.

Non-Goals

hi report and telemetry; the backoffice; a selectable harness set per repository (parked, Q29); single Registry Item selection outside Packs (parked, Q35); registry credentials or a CLI login (rejected, Q19); a bundled offline Baseline (rejected, Q10); on-demand rendering of prompt specs, handoff, or system prompt (rejected, Q9); a copy fallback for failed symlinks (rejected, Q27); a hi add command (rejected, Q30); implementation order, task breakdown, and backlog projection.

Requirements Outcomes

OUT-001: One public Registry is the only Baseline source

Source: Q1, Q8, Q10, Q19.

  • A Registry in the shadcn registry format is the only Baseline distributor and the only source for drift management. GitHub release artifacts and the control-plane promotion path are retired.
  • The Registry is hosted with the existing HI API on Vercel. The exact mount is delivery detail.
  • The Registry is public. The installer sends no credential. No hi login, header configuration, or token storage is introduced.
  • No bundled Baseline exists inside the npm package. hi init needs network access.

OUT-002: Immutable Baseline identity and catalog

Source: Q14, Q15, Q17, Q18.

  • A Baseline is one Registry version named YYYY.MM.DD-<short sha> and is immutable once published; a correction is a new Baseline.
  • The catalog registry.json holds one latest pointer that moves on publish. There is no promotion step.
  • Each Baseline declares a compatible CLI version range. The CLI refuses a Baseline outside its range and tells the user to upgrade.
  • The catalog carries a sha256 per Registry Item, used only to verify the installer's download cache, never for repository drift.

OUT-003: Registry publication from the existing release flow

Source: Q4, Q16.

  • The existing release workflow builds the Registry from apps/cli/skills and apps/cli/src/data and publishes it. BASELINE_CHANGELOG.md remains the product selector. The skills repository remains the source of truth through the existing sync.
  • Registry Item JSON stays byte-compatible with the shadcn registry-item schema so npx shadcn add and shadcn mcp remain usable fallbacks for Copied Artifacts. Harness-specific needs live under item meta: symlinks, structured merges into repository-owned JSON and YAML, per-workspace devDependencies, and templates with declared inputs.

OUT-004: The Registry serves the full harness context

Source: Q7, Q9, user constraint recorded in the brainstorm boundary.

  • Registry Items cover skills, hooks, runtime scripts, source guides, lint assets, prompt specs, the shared prompt, the subagent spec, AGENT-HANDOFF.md, AGENT-SYSTEM-PROMPT.md, the Commit Gate, the wiki starter, and the required tools list.
  • Anti-slop rules stay the default lint asset for TypeScript Software Scopes. Their files stay scoped to each app and package.
  • Prompt specs, handoff, and system prompt stay tracked Built Artifacts produced from Registry templates.

OUT-005: Two local state files with one writer each

Source: Q2, Q20, Q22.

  • .devpunks/settings.json holds intent only: registries, selected Packs, Software Scopes, providers, required tools. A human, or the agent on request, writes it.
  • .devpunks/installed.json is the Installed Record: installed Baseline version, Recorded Shape (workspace paths, Pack ids, detected technologies), item-to-path map, and failed symlinks. Only the installer writes it.
  • Selected Packs are explicit in settings. Detection runs at hi init and on request and only proposes. A detected but unselected Pack is information, never drift.
  • No content hash of any Managed Artifact is stored in the repository.

OUT-006: Three Managed Artifact kinds with three rules

Source: Q9, Q24, Q31, Glossary Q32a.

  • A Copied Artifact is written verbatim from a Registry Item. Update overwrites it; identical content is skipped.
  • A Built Artifact is rendered from a Registry Item template, Project settings, and the Recorded Shape. Update re-renders it; identical content is skipped.
  • An Authored Artifact is written once when absent and never compared or overwritten afterwards. AGENTS.md files, .agents/subagents/manifest.mjs, the wiki starter, .codex/config.toml, and Project Skills are Authored Artifacts.
  • With --yes, a Copied Artifact that has both a local edit and an upstream change is overwritten and its path is reported; git keeps the local version.

OUT-007: One idempotent update pipeline

Source: Q13, Q23, Q26, Q27.

  • hi update runs in this order: fetch catalog and check the CLI range; resolve selected Packs to Registry Items through registry dependencies; plan every path; validate that every structured merge target parses; write Copied Artifacts; render Built Artifacts; write absent Authored Artifacts; apply merges; create symlinks; add required workspace devDependencies and remove stale ones; remove stale Copied Artifacts and report stale Authored Artifacts; write the Installed Record last; run managed lint on the real repository; report.
  • No temporary repository candidate, lint preview, or pending-publication marker exists. Any invalid merge target stops the run before any write.
  • A stale devDependency is removed only when no first-party source file in that workspace imports the package; otherwise it is reported and kept.
  • A symlink that cannot be created is reported with its path and target. No copy is made. The next update retries.
  • Re-running update after a failure at any step converges without manual repair.

OUT-008: Three-way Drift Check

Source: Q2, Q25, Q27.

  • hi diff compares, per managed path, local bytes, the Registry Item at the installed Baseline, and the Registry Item at the latest Baseline, and writes nothing.
  • Copied Artifacts compare after normalizing line endings and trailing whitespace only. Built Artifacts compare by re-rendering at the installed Baseline with the Recorded Shape; a re-render with the current shape that differs is shape-drift. Authored Artifacts are never byte-compared; a changed template is reported as information.
  • Every path reports exactly one class: update-available, local-edit, conflict, shape-drift, missing, stale, or link-failed.

OUT-009: Cheap, honest check and session start

Source: Q6, Q21.

  • hi check fetches the catalog, compares the installed Baseline version with latest, verifies required tools, and returns status from the closed set current, update-available, unavailable, not-installed. It does not run the full Drift Check.
  • When the Registry cannot be reached, status is unavailable and the output includes the cached installed version. The output never states that no drift was confirmed after a failed fetch.
  • The session-start hook keys on status only and stays installed for Claude, Codex, Cursor, and OpenCode.
  • The edit hook reads protected paths from the Installed Record. When the record is missing, it treats nothing as managed and never blocks an edit.

OUT-010: Harness Adapters replace the shipped projection script

Source: Q3, Q12, Q29.

  • The hi CLI builds each subagent body once from .agents/subagents/manifest.mjs and wraps it in one envelope per harness through a Harness Adapter for Claude, Codex, Cursor, and OpenCode, always all four.
  • sync-subagents.mjs and .agents/scripts/harness-projection/* are no longer distributed or executed in consumer repositories.
  • Per-harness subagent files are rebuilt only by hi update and hi diff. The edit hook does not rebuild them.

OUT-011: Command surface

Source: Q30.

  • The commands are hi init, hi update, hi diff, hi check.
  • hi init detects the repository once, proposes Packs and Software Scopes, writes Project settings from the confirmed selection, then runs the update pipeline. hi scaffold is retired into init. No hi add exists.

OUT-012: Project Skills are preserved

Source: Q31, Q34.

  • Skills present in a repository before Harness, and skills no Registry Item provides, are Project Skills under .agents/skills/<id>. They are reachable through the existing harness symlinks.
  • The installer never removes, compares, or overwrites a Project Skill.
  • When a Registry Item later provides a skill with a Project Skill's id, the Baseline skill wins: the Project Skill directory is renamed [DEPRECATED] <name>, the Registry skill is installed under the original id, and the command reports each such case.
  • The replaced-scaffold, replaced-skills, and pre-existing-skills archives are retired. A conflict shows as a git diff.

OUT-013: One-run migration of manifest-based repositories

Source: Q33.

  • The first registry-based hi update in a repository that has .devpunks/scaffold-manifest.json and no Installed Record migrates in the same run: it reads the old settings for Packs, Software Scopes, providers, and required tools; runs detection once to build the Recorded Shape; moves skills from pre-existing-skills into .agents/skills as Project Skills; deletes scaffold-manifest.json, harness-projection-receipt.json, context-plan.json, specs/lint/assets.json, replaced-scaffold, replaced-skills, and the emptied archive; keeps every Authored Artifact; writes the Installed Record; and reports each deletion.
  • No separate migrate command exists.

OUT-014: Managed lint and Commit Gate work on large Software Scopes

Source: Q5, Q28.

  • Issue #232 is fixed in the same release that ships the Registry.
  • The managed lint runner preserves lint-finding exit semantics for any output size; a 13.5 MB oxlint JSON report is classified as findings, not as an operational failure.
  • The Commit Gate passes file sets to lint and format commands without exceeding operating-system argument limits, and keeps the rule that a lint configuration change lints the full owner file set.
  • The Commit Gate's staged-file listing does not fail on large staged sets.

OUT-015: Aligned language and operator knowledge

Source: Q32, repository guidance on docs updates.

  • The canonical terms Registry, Registry Item, Baseline, Installed Record, Recorded Shape, Copied Artifact, Built Artifact, Authored Artifact, Project Skill, Harness Adapter, and Drift Check are used in CLI output, docs, and the operator skill. Scaffold Manifest, Validation Candidate, Prepared Installation, Validation Result, Cache Entry, and Context Plan as a file are retired from current documentation.
  • docs/README.md, the scaffolding runbook, the hi-cli operator skill post-command flow, and rule HI-REPO-002 describe the delivered behavior in the same delivery.

Acceptance Criteria

  • AC-001: With the control-plane baseline endpoints and GitHub release artifacts unavailable, hi init and hi update succeed against the Registry alone.
    • Covers: OUT-001
  • AC-002: hi sends no Authorization header and reads no credential when fetching the Registry, and the Registry responds without one.
    • Covers: OUT-001
  • AC-003: The published @punks/cli package contains no bundled Baseline, and hi init without network access reports unavailable instead of installing.
    • Covers: OUT-001
  • AC-004: Re-publishing an existing version identifier is rejected by the publisher, and fetching a version returns the same bytes on every request.
    • Covers: OUT-002
  • AC-005: After a publish, registry.json latest equals the new version and no promotion call is required for hi update to select it.
    • Covers: OUT-002
  • AC-006: With a Baseline whose CLI range excludes the installed CLI, hi update writes nothing and reports the required CLI range.
    • Covers: OUT-002
  • AC-007: A cached Registry Item whose bytes do not match the catalog sha256 is discarded and refetched, and the sha256 is never used in a Drift Check class decision.
    • Covers: OUT-002
  • AC-008: The release workflow produces registry.json and one item JSON per Registry Item from apps/cli/skills and apps/cli/src/data, and a run whose changed changelog paths exclude BASELINE_CHANGELOG.md publishes no Registry.
    • Covers: OUT-003
  • AC-009: Every published item JSON validates against the shadcn registry-item schema, and npx shadcn add of a Copied-only item writes its files under the repository root.
    • Covers: OUT-003
  • AC-010: For a repository selecting all default Packs, hi update installs every artifact kind listed in OUT-004, including anti-slop files inside each TypeScript Software Scope and tracked prompt spec, handoff, and system prompt files.
    • Covers: OUT-004
  • AC-011: After hi update, .devpunks/ contains settings.json and installed.json and no file containing a content hash of a Managed Artifact.
    • Covers: OUT-005
  • AC-012: hi update never modifies settings.json, and no command other than hi init and hi update modifies installed.json.
    • Covers: OUT-005
  • AC-013: A Pack detected but absent from settings.json is reported as information and produces no drift class and no non-zero exit.
    • Covers: OUT-005
  • AC-014: A locally edited Copied Artifact is overwritten by hi update --yes with its path in the report, and an identical file is reported skipped.
    • Covers: OUT-006
  • AC-015: A Built Artifact changes after hi update only when its template, Project settings, or the Recorded Shape changed.
    • Covers: OUT-006
  • AC-016: An existing Authored Artifact is byte-identical before and after hi update, with or without --yes.
    • Covers: OUT-006
  • AC-017: hi update performs its steps in the order in OUT-007, and installed.json is written after every other file effect.
    • Covers: OUT-007
  • AC-018: With one unparsable merge target, hi update exits non-zero and no repository file changes.
    • Covers: OUT-007
  • AC-019: A devDependency no longer required by any installed lint asset is removed when no first-party source in that workspace imports it, and kept with a report when one does.
    • Covers: OUT-007
  • AC-020: When symlink creation fails, hi update reports the path and intended target, creates no copy, records the failure in installed.json, and completes the remaining steps.
    • Covers: OUT-007
  • AC-021: hi update interrupted after any step, then re-run, produces a repository byte-identical to an uninterrupted run.
    • Covers: OUT-007
  • AC-022: hi diff reports one class per managed path from the set in OUT-008 and modifies no file.
    • Covers: OUT-008
  • AC-023: A Copied Artifact that differs only in line endings or trailing whitespace is reported as no drift; one that differs in other bytes is reported local-edit.
    • Covers: OUT-008
  • AC-024: Adding a workspace to a repository makes hi diff report shape-drift on affected Built Artifacts and local-edit on none of them.
    • Covers: OUT-008
  • AC-025: hi check --json returns status from the set in OUT-009, completes without fetching any Registry Item, and does not read repository file contents.
    • Covers: OUT-009
  • AC-026: With the Registry unreachable, hi check --json returns status: unavailable with the installed version and the session hook message contains no statement that drift is absent.
    • Covers: OUT-009
  • AC-027: In a git worktree without installed.json, the edit hook allows every edit, and hi check returns status: not-installed.
    • Covers: OUT-009
  • AC-028: After hi update, each subagent in manifest.mjs has one file in each of .claude/agents, .codex/agents, .cursor/agents, .opencode/agents with an identical body and the harness envelope, and no sync-subagents.mjs or harness-projection script exists under .agents/scripts.
    • Covers: OUT-010
  • AC-029: Editing manifest.mjs changes no harness agent file until hi update runs, and hi diff reports those files stale in between.
    • Covers: OUT-010
  • AC-030: hi --help lists exactly init, update, diff, check as scaffold lifecycle commands, and hi scaffold and hi add are unknown commands.
    • Covers: OUT-011
  • AC-031: In a repository with a skill under .claude/skills/foo that no Registry Item provides, hi init leaves foo installed under .agents/skills/foo, reachable through .claude/skills, and never modifies or removes it on later updates.
    • Covers: OUT-012
  • AC-032: When a later Baseline provides foo, hi update renames the Project Skill directory to [DEPRECATED] foo, installs the Registry foo, and lists the rename in its report.
    • Covers: OUT-012
  • AC-033: After hi update, no replaced-scaffold, replaced-skills, or pre-existing-skills directory exists under .devpunks/.
    • Covers: OUT-012
  • AC-034: In a repository with scaffold-manifest.json and no installed.json, one hi update run leaves installed.json present, every file in the OUT-013 deletion list absent, every Authored Artifact byte-identical, archived skills present as Project Skills, and each deletion listed in the report.
    • Covers: OUT-013
  • AC-035: A Software Scope whose oxlint JSON output exceeds 10 MiB returns lint findings and the findings exit code, not an operational failure.
    • Covers: OUT-014
  • AC-036: A lint configuration change followed by git commit lints the full owner file set for a scope whose file list exceeds ARG_MAX, and the gate exits with the lint result.
    • Covers: OUT-014
  • AC-037: Current docs/README.md, the scaffolding runbook, the hi-cli operator skill, and rule HI-REPO-002 use the OUT-015 canonical terms and contain none of the retired terms except in historical references.
    • Covers: OUT-015

Constraints

  • Shared skills stay sourced from the skills repository main branch through the existing sync; apps/cli owns the executable and generated assets; apps/api owns the control plane (repository guidance).
  • Changed changelog paths remain the release product selector; BASELINE_CHANGELOG.md selects the Registry (Q16).
  • Each local state file has exactly one writer (glossary axiom).
  • A Baseline is immutable; a correction is a new Baseline (glossary axiom).
  • Compare and report in ASD-STE100 Simplified Technical English using the canonical terms (repository guidance).

Dependency Readiness

No Stack Required. The retained architecture is a source, not a delivery dependency. The unmerged branch team/stefan/codex-edit-hooks (commit ffee129a, issue #231) is superseded by OUT-009 and is not a dependency.

Branch/Base Intent

Not applicable. No parent or base constraint was accepted. The architecture and this spec are retained on team/stefan/registry-baseline-architecture as requirements bookkeeping; delivery chooses its own branch.

Accepted Technical Decisions

The architecture's blocks ARC-001 to ARC-012 and flows FLOW-001 to FLOW-005 are the accepted design. In summary: a static, public, versioned Registry with a latest pointer; an in-house installer that reads shadcn-compatible item JSON plus meta extensions; two local files with one writer each; Copied, Built, and Authored Artifact rules; a plan-validate-apply pipeline that writes the Installed Record last and has no candidate or marker; a three-way Drift Check; Harness Adapters inside the CLI; and a migration branch inside hi update. Retired: the baseline HTTP API group and promotion store, the bundled channel, the Scaffold Manifest, projection receipt, context plan, Validation Candidate, sync-subagents.mjs, the harness-projection scripts, and the three archives.

Delivery detail left to planning: the exact Vercel mount, the meta extension field names, the Harness Adapter envelope formats, the migration branch's internal structure, and the lint runner's streaming mechanism.

Accepted Testing Decisions

No testing decisions were accepted upstream. Verification derives from the seams below and from the acceptance criteria; create-plan owns test files, fixtures, and commands. The issue #232 reproduction (13.5 MB oxlint output; owner file set beyond ARG_MAX) is the accepted regression witness for OUT-014.

Verification Seams

  • hi init, hi update, hi diff, hi check JSON output: status, applied version, one row per path with its action or drift class.
  • .devpunks/installed.json contents after each command.
  • Registry catalog and item JSON as served, and the release workflow's publish step.
  • Repository file effects: Copied, Built, and Authored Artifacts, harness agent files, workspace package.json devDependencies, symlink presence, Project Skill directories.
  • Session-start and edit hook outputs for Claude, Codex, Cursor, OpenCode.
  • Managed lint runner and Commit Gate exit codes and reports under the #232 reproduction.

Parked Decisions

  • Selectable harness set per repository. Owner: user. Resume trigger: a repository that must exclude one harness (Q29).
  • Single Registry Item selection outside Packs. Owner: user. Resume trigger: a real request for one skill that no Pack contains (Q35).

Decision Log

DecisionEvidenceRationale
One public Registry replaces artifacts, promotion, and bundleQ1, Q8, Q10, Q14–Q19Nine authority issues came from three sources and a promotion step
Two intent and record files, no hashesQ2, Q20–Q22Six hash-drift and two portability issues came from persisted derived state
Copied, Built, Authored rules; Project Skills preservedQ9, Q24, Q31, Q34Seven issues came from overwriting tailored files
Plan-validate-apply, record last, no candidateQ23, Q26, Q27Six issues came from the temporary candidate
Three-way Drift Check; version-only session checkQ2, Q6, Q25Drift without stored hashes; session hook's drift branch was dead
Harness Adapters in the CLIQ3, Q12, Q29Body is identical across harnesses; the script was a second writer
Four commands; one-run migrationQ30, Q33Smallest surface that converges existing repositories
#232 fixed in the same releaseQ5, Q28Runner and gate are Registry Items in that release

Compilation Evidence

15 unique outcomes and 37 uniquely identified acceptance criteria cover Q1 to Q35 and Glossary Q32a; Q11 is superseded by Q19. Every criterion names its outcome. Two branches are parked with owner and trigger. Compilation is not implementation, release readiness, or remote retention.

Current compilation validation

  • HI-WIKI-001: pass — owning route metadata registered; bun run --cwd apps/wiki check:content passed.
  • HI-WIKI-003: pass — frontmatter validates; links resolve in the routed tree.
  • HI-DOCS-001: pass for this artifact — requirements and glossary stay in routed project knowledge; implemented docs are OUT-015 delivery work.
  • API, runtime, UI, release, and generated-asset checks: not-applicable to this documentation wave.

On this page