HI CLI Scaffolding Runbook
HI CLI Scaffolding Runbook
Use this runbook when a repo is adopting or refreshing the Harness Intelligence CLI.
Agent Rule
Activate $hi-cli before acting on hi output or generated .devpunks artifacts.
The skill is responsible for reading scaffold handoffs, following generated specs, reconciling assets into the real repo shape, and reporting unresolved Harness friction.
Reusable Harness skills are authored in /Users/stefan/Desktop/repos/wearedevpunks-skills. Edit that source repo first, push it to wearedevpunks/skills, then run bun run sync:skills from this repo so apps/cli/skills/* is generated from the public source tree. Scaffold/update uses that distributed bundle to emit consumer .agents/skills/* copies. Do not hand-edit those local copies as the source change unless a local-only experiment was explicitly requested.
The upstream create-spec template must keep a non-empty string title in frontmatter, and its quality-bar self-review must verify that field before saving a spec, especially when the destination is a routed Fumadocs tree.
Shared phase contracts now treat behavior-changing implementation as RED/GREEN-audited work. create-plan should write tdd_status, red_command, expected_red_failure, green_command, reason_not_testable, red_evidence, and green_evidence fields. implement-spec should not mark behavior-changing tasks complete until RED/GREEN evidence is recorded, and review-phase should fail missing proof unless the non-testable reason is valid. Review starts with review, separating Standards findings from Spec findings before autoreview. UI implementation tasks also need durable before/after screenshot asset links in IMPLEMENTATION-NOTES.md, then the same links in the PR body, PR comment, or PR-ready handoff.
Runtime validation is a separate task contract from review_mode. create-plan sets runtime_validation: required when acceptance depends on workers, queues, persistence, providers, tracing, deployment wiring, or a similar process or infrastructure boundary. It also records the supported runtime_target, required public and durable runtime_evidence, and provenance-scoped runtime_cleanup. implement-spec carries those fields into sequential and parallel worker briefs, exercises the supported public entrypoint first, and records correlated public plus durable evidence in IMPLEMENTATION-NOTES.md. If proof remains inconclusive, the exact blocker is recorded and the task and affected acceptance criterion stay blocked; cleanup may remove only resources proven to belong to the validation run.
Plan-mode detail belongs in create-plan and the resulting PLAN.md, not in generated shared AGENTS.md prose. The generated .agents/AGENTS.md should state only the compact scaffold policy: subagent-based work is mandatory; use one active execution/implementation worker by default; use parallel implementation only when the user explicitly asks; if the subagent/thread set is full, close existing completed or finished subagents before retrying; use parallel readonly subagents whenever readonly discovery splits across independent questions, paths, or hypotheses.
Root prompt specs scaffold criteria and invariants for the setup agent to materialize from repo evidence; they are not final prompt bodies. The setup handoff should direct the next agent to author root AGENTS.md from the actual apps, packages, contracts, tools, and docs it finds. Root AGENTS.md is a concise repo router, not a root primary-skill list. It should provide a repo surface map, workflow routing, cross-surface contract rules, validation routing, and short source/URL/docs rules. Route loose oversized fog to finder-phase before bounded requirements-phase; route product design work with existing evidence to explicit design-phase; route accepted specs, issues, or plans to delivery-phase. Generated available workflow entrypoints include design-phase, while scoped Primary skills here lists exclude it with every other lifecycle phase.
grilling is the sole generic contract for frontier scheduling, question shape, fact lookup, branch settlement, state restatement, and shared-understanding completion. requirements-grill adds domain pressure tests and persists stable question ids, prerequisites, current-frontier membership, answer state, and confirmation state in <wiki-root>/content/docs/project/grilling/<topic>-grill-status.md and <topic>-grill-log.md. Other wrappers keep only stricter local formats, output mappings, and downstream transitions.
write-backlog now materializes the canonical backlog kinds fog, grilling, research, prototype, epic, and story as first-class provider items. fog stays at the backlog root and is not delivery-eligible; concrete non-fog items live under modules/milestones; stories remain children of epics. Provider sync must use the accepted Kind storage rules: Linear Kind/... label group, GitHub Projects V2 Kind single-select field, monday.com Kind Status/Dropdown column, and Azure DevOps Custom.DevpunksKind.
docs-ingest-phase is also the routed learning refresh loop. For durable bug or knowledge learning, scan the scoped routed learning area first, then choose keep, update, consolidate, replace, delete, or mark_stale. Canonical learning stays in routed wiki/project docs and must expose at least one future-use hook; memory notes are only compact routing aids for hard-to-discover gotchas.
When changing a phase wrapper, preserve resumable phase routing. The wrapper may name the lifecycle sequence, but it should choose the current gate from repo/tracker/artifact state before loading child skills. delivery-phase keeps SKILL.md as an entrypoint, routes through phases/router.md, loads one selected phases/*.md module, and writes handoff state before stopping or re-entering routing.
Keep bug-discovery-phase, bug-resolution-phase, delivery-phase, design-phase, finder-phase, requirements-phase, and resolve-debt-phase explicit-only: their Claude frontmatter must set disable-model-invocation: true, and their Codex agents/openai.yaml must set policy.allow_implicit_invocation: false. Only review-phase, debugging-phase, and docs-ingest-phase stay model-invocable as delivery's internal delegates. Design and debt resolution must build and present a delivery brief, then stop for explicit user invocation of $delivery-phase instead of loading or running it.
Install or repair the global operator skill through the verified lifecycle:
hi operator installThe command requires Skills CLI >=1.5.17 and installs the immutable compatible target selected by the CLI. Do not substitute a moving main URL. Missing, unsupported, malformed, timed-out, failed, incorrectly bound, unsafe, unreadable, or identity-mismatched Skills CLI results remain explicit failures rather than absence.
Current Commands
hi init
hi scaffold
hi scaffold --yes
hi ensure
hi tools ensure
hi check
hi update --check
hi update --write
hi update --yes
hi report --help
hi operator status
hi operator install
hi operator update
hi operator migrate
hi upgrade --help
hi --version
hi -vThe former backlog scaffold subcommand is not part of the current command contract.
Discovery And Output Contract
Executable help and generated command references come from one recursive registration graph. The current graph has ten roots: check, ensure, init, operator, report, scaffold, skills, tools, update, and upgrade. Its nested commands are operator status, operator install, operator update, operator migrate, deprecated skills rename, and tools ensure. init and scaffold are root commands; there are no scaffold children.
Commands publish presentation-neutral OperationResult facts once through the root-provided presentation sink. The root selects interactive, redirected plain, or JSON output once, then owns rendering, stdout, stderr diagnostics, and exit status. JSON is non-interactive and emits one document. Redirected plain output is deterministic and contains no ANSI. Prompt interaction owns terminal input and cleanup separately from result rendering.
Operator status and mutations keep the complete public IP322 evidence in that result, including scope, immutable identity, compatibility, legacy copies, project roots, agent bindings, guarded retries, reinspection outcomes, removal barriers, and reload guidance. Baseline-aware commands keep IP323 stable, bundled, and exact-version selectors.
The developer renderer catalog is a review tool, not a command or package feature. It imports the production renderer in one direction and is excluded from dist and npm packaging. See /docs/cli/commands/command-discovery and /docs/cli/product-foundation/cli-presentation-contract; those pages explain the flow and contract without becoming a second graph or renderer authority.
hi init
Run init first when the repo needs existing-project docs onboarding, requirements discovery, and the initial wiki structure.
It asks which backlog provider, asset provider, and repository manager the project uses, plus the absolute HTTP(S) URL of the backlog project:
- GitHub Projects/Issues, default on blank input
- Linear
- Azure DevOps
- monday.com
It records provider authority in .devpunks/settings.json:
{
"backlogProvider": "linear",
"backlogProjectUrl": "https://linear.app/acme/team/ENG",
"repositoryManager": "github",
"assetProviderSlug": "linear",
"requiredTools": ["agent-browser", "gh", "opensrc", "portless", "skills"]
}When .devpunks/settings.json exists, scaffold/update, backlog writing, durable
visual asset handling, and required-tool validation must use it before wiki hints.
Legacy wiki provider files are compatibility hints only for repos that have not
been migrated.
Settings have three authority classes. Operators own provider, repository-manager, and backlog-URL choices. The CLI derives required tools. Accepted init/scaffold/update writes own CLI and baseline version pins. Reads preserve unknown fields, report an unambiguous legacy omission as SafeSettingsUpgrade, and do not write. Missing, invalid, inaccessible, or contradictory legacy evidence returns a typed error instead of guessing.
hi ensure
Use hi ensure to reconfigure the existing .devpunks/settings.json without rerunning scaffold initialization. It uses the same provider and project-URL selector as hi init, with current values as defaults, and updates only operator choices plus their reconciled required tools in the settings file. It does not stamp managed versions.
The backlog project URL is trimmed and must be an absolute HTTP(S) URL. Legacy settings without the field remain readable and can be upgraded by this command. If settings do not exist yet, run hi init first.
Changing the repository manager removes tools required by the previous manager, adds the selected manager's required tools, and preserves every other required tool even when another manager can also use it. hi ensure does not install them; use hi tools ensure for tool installation or repair.
Scaffolded write-backlog reads backlogProvider and backlogProjectUrl before provider work. Missing or invalid destination settings stop backlog materialization with guidance to run hi ensure; agents do not discover or guess another destination.
Root hi init also distributes the accepted default-pack scaffold surface that setup/update can later manage:
.devpunks/scaffold-manifest.json.devpunks/AGENT-HANDOFF.md.devpunks/AGENT-SYSTEM-PROMPT.md- default-pack skills, hooks, scripts, prompt specs, source guides, and subagent manifest files
It still seeds the init-specific adoption surfaces:
.agents/skills/docs-onboarding.agents/skills/requirements-grill.agents/skills/write-backlog.agents/skills/create-spec- a wiki root:
apps/wikifor monorepos,app/wikifor app-surfaced single repos with direct app package surfaces underapp/and no workspace signals or with an already-selectedapp/wikiroot, orwikifor standalone single-repo layouts .devpunks/settings.json, pinning provider settings for later agents and update checks<wiki-root>/backlog-provider.md, kept as a legacy migration hint rather than authority<wiki-root>/wiki-framework.md, pinning either Next.js or TanStack Start for later update checks- routed project sections at
<wiki-root>/content/docs/project/specs,<wiki-root>/content/docs/project/onboarding, and<wiki-root>/content/docs/project/public-docs - a wiki content sync script at
<wiki-root>/scripts/sync-content.mjs - Mermaid rendering support for fenced
mermaiddiagrams
init does not detect overlapping skills. Its operator prompt tells the follow-up agent to inspect .agents/skills, .claude/skills, .codex/skills, .cursor/skills, and .opencode/skills; exact name/id overlaps keep HI baseline active with local evidence archived under .devpunks/replaced-skills/<skill-id>/..., non-overlapping local skills stay preserved and exposed through later harness mirrors, and baseline-worthy local knowledge goes through hi report.
The generated wiki package can use Next.js or TanStack Start. It runs content sync before build and check-types. The sync script exports syncWikiContent and SyncContentError for wiki tests and runs only when invoked as the script entrypoint. The --check path reports stale projected pages, recursive meta.json changes, and stale generated files or folders without writing; the apply path refreshes existing generated pages even when they already contain frontmatter, adds a missing frontmatter title from the page heading, and prunes stale generated files or folders. The sync projects <wiki-root>/specs and monorepo docs/requirements, docs/reference, docs/runbooks, and docs/tech-decisions.md into Fumadocs content/docs/project routes when those sources exist, then writes recursive meta.json files for copied folders. Root <wiki-root>/specs, <wiki-root>/raw, <wiki-root>/index.md, and <wiki-root>/log.md remain source/input/bookkeeping surfaces, not duplicate article trees. Fresh scaffold does not create content/docs/project/domains; project/domain routes are added only when the repo defines them. Next.js wiki scaffolds enable Fumadocs next/og metadata images for docs pages at /og/docs/[...slug]. Wiki package metadata keeps @typescript/native on TypeScript 7 for the compiler binary and aliases typescript directly to npm:typescript@^6.0.2; that direct TypeScript 6 package exposes the version and sys.getCurrentDirectory JS API required by Next/Fumadocs tooling. Because both packages publish a tsc binary, generated type-check scripts resolve @typescript/native/package.json through Node module resolution and import its compiler entrypoint. This keeps TS7 selection explicit without assuming the dependency lives in the wiki's local node_modules. Rerunning init against an existing wiki repairs metadata that still uses the @typescript/typescript6 wrapper, replaces an unqualified tsc in managed type-check scripts, updates the managed sync script and package hooks, adds missing wiki package dependencies such as Mermaid support, skips scaffolded folder routes when a flat routed page already owns that path, and does not overwrite existing routed pages with projected source docs. hi update reads the pinned wiki framework and preserves TanStack Start wikis instead of restaging them as Next.js. Scaffolded wiki apps include a wiki-local .gitignore for generated output including .source and .next. If the wiki app is deployed from an app-root Vercel project where monorepo docs/ is absent, the sync leaves checked-in routed content in place.
For app-root Vercel monorepo deployments, use Vercel native affected-project skipping on each project instead of generated ignoreCommand fallbacks. The ignored-build hook still creates noisy deployments and can consume build/concurrency accounting before it exits, while native skip uses the workspace dependency graph and project root directories.
init removes exact .cursor, .codex, .claude, .agents, and .opencode ignore patterns from root .gitignore when present, because those generated Harness surfaces must be visible to git.
After init, read .devpunks/AGENT-SYSTEM-PROMPT.md, then activate $docs-onboarding from the generated operator prompt. The skill assumes init provided the proper wiki root, then inspects code, existing repo docs, and backlog context. It probes the repo settings backlog provider first when access exists, inspects local backlog clues after that, writes content/docs/project/onboarding/project-map.md, onboarding-grill-status.md, and onboarding-grill-log.md, persists each targeted requirements-grill round in those artifacts, and calls create-spec after $requirements-grill completes. Keep the selected providers and wiki framework pinned unless the user explicitly changes them. If the generated wiki root obviously conflicts with the repo layout, fix that before writing durable onboarding/spec docs. For app-surfaced single repos, create or move the wiki to the canonical app/wiki surface before authoring specs, raw inputs, routed project docs, or ingest bookkeeping.
hi scaffold
Run hi scaffold after the repo shape is ready for repo-aware AI setup.
It detects repository facts, resolves packs, asks for confirmation unless --yes accepts the resolved default selection, writes managed Harness assets, records .devpunks/scaffold-manifest.json, and emits follow-up handoff artifacts.
hi scaffold --json prints the complete scaffold confirmation payload, including detected packs, generated files, projection status, and tool bootstrap results. Its process exit status still follows the normalized operation outcome.
Repo detection ignores agent/cache/worktree directories such as .claude, .codex, .cursor, .opencode, and worktrees so setup does not scan cloned repositories from local agent state. Pack detection also ignores selected wiki roots (apps/wiki, app/wiki, and wiki) so Fumadocs dependencies and generated wiki TypeScript do not select framework, frontend, or language packs by themselves.
Expo package detection selects the expo pack when manifests list expo or @expo/* packages. The pack distributes the shared Expo skills for Expo app structure, EAS workflows, deployment, updates/observe, native UI, modules, web-to-native migration, and eval workflows.
Effect package detection selects the effect pack when manifests list effect or @effect/* packages. The pack distributes the pinned Effect v4 effect skill as its canonical patterns and authoring core, including focused Effect-Atom and observability references, plus the distinct effect-backend-structure and effect-recoverable-actions workflows. It does not retain the superseded effect-authoring or effect-best-practices branches or route by installed Effect semver.
Prompt target discovery includes authored scoped AGENTS.md files outside managed/generated directories even when they are not package workspaces. Keep root, .agents, docs, and package-manifest targets deduped, but preserve real non-package surfaces such as infra/opentelemetry/AGENTS.md so generated prompt specs, subagent specialists, and native agent mirrors follow the consumer repo shape instead of Harness placeholder paths.
Setup writes opensrc/*.md guide cards for detected package sources that agents commonly need to inspect. These files are indexes for opensrc, not vendored source. The package source remains in the global ~/.opensrc cache; the card tells the next agent to run opensrc path --cwd . <package> or a fallback repository lookup before reading internals.
Setup does not detect overlapping repo skills. Generated .devpunks/AGENT-HANDOFF.md, .devpunks/AGENT-SYSTEM-PROMPT.md, CLI summary output, and $hi-cli follow-through direct the next agent to inspect .agents/skills, .claude/skills, .codex/skills, .cursor/skills, and .opencode/skills. Exact canonical directory id/name overlap keeps the HI baseline skill active; the agent archives local evidence under .devpunks/replaced-skills/<skill-id>/... and removes active local copies or mirrors. Non-overlapping local skills remain repo-owned guidance and should stay exposed through harness mirrors or symlinks. Semantic overlap and baseline integration proposals go through model-guided hi report, not command runtime.
Setup applies selected pack-owned Oxlint assets into nearest package/app oxlint.config.ts files, extending Ultracite core/framework presets and adding explicit overlay rules where a pack needs them. It also adds missing lint dev dependencies to the owning package.json. Generated Next.js wiki packages declare oxfmt, oxlint, and ultracite, but their wiki-local Oxlint starter follows the root correctness baseline instead of full Ultracite-core enforcement so adopting the wiki does not surface unrelated strict-style debt.
When the neutral format hook is scaffolded, setup writes OpenCode project formatter config in opencode.json. The plugin itself stays in .opencode/plugins, where OpenCode auto-loads it, so setup must not also add the same local file to the plugin list. The hook skips scaffold-owned hooks, scripts, skills, and hook mirrors so managed scaffold assets remain hash-stable after update. Python .py edits route through Ruff with uv run --project <python-project>; nearest pyproject.toml wins, with conventional backend paths such as apps/backend as fallback. Python uv workspaces that include package.json only for tooling metadata stay on the Python lint route and do not receive JS Oxlint scaffolding unless they declare JS runtime dependencies. JS/TS linting lets Oxlint resolve the nearest config for the edited file instead of forcing a root config.
Setup also scaffolds a session-start update hook for Codex, Claude Code, Cursor, and OpenCode. The command runs hi check; clean managed repos report Harness scaffold check: OK., while drift reports command output back to the agent before work starts so accepted hi upgrade or hi update remediation can run in a subagent. Generated .codex/config.toml retains agents.max_depth and Harness hooks but does not set legacy agents.max_threads, which is incompatible with Codex multi_agent_v2.
Setup also removes exact .cursor, .codex, .claude, .agents, and .opencode ignore patterns from root .gitignore when present. Generated subagent sync projects shared prompts, hooks, and skills into Codex, Claude, Cursor, and OpenCode surfaces. On Windows, symlink creation can fail with EPERM when the user lacks administrator rights or Developer Mode. Setup must keep completing by using Windows-compatible directory links where available and copying managed mirrors when link creation is blocked. Claude hook injection merges into .claude/settings.json; existing settings, including permissions.allow, are user-authored state and must survive reruns.
Required tool bootstrap is best-effort. If a package install or postinstall hook fails, setup prints the underlying stack trace plus an agent recovery prompt and still writes the selected scaffold output. The next agent must read .devpunks/settings.json, run hi tools ensure, and verify the required binaries before deeper repo work.
Setup should not force an agent-browser Chrome download when a supported Chrome, Chromium, or Brave executable is already installed.
The required tool baseline pins opensrc to >=0.7.2. If an older binary is already on PATH, setup reinstalls the global package before treating the tool as available.
Context plan and harness projection
Setup compiles repository meaning once after discovery and final pack resolution. It persists neutral semantic evidence at .devpunks/context-plan.json, then projects that same plan through the Claude, Codex, Cursor, and OpenCode capability adapters. Harness targets and filesystem writes do not belong in the context plan.
The projection shell writes .devpunks/harness-projection-receipt.json and exposes its path and aggregate status in setup/default-stage output:
success: all supported actions applied. Proceed with normal scaffold reconciliation.partial: supported output applied, but known unsupported capabilities or preservation rules produced typed warnings and omissions. Inspect them before continuing; rerunning setup does not add a capability the harness lacks.failure: the command exits nonzero because input, adapter behavior, path containment, source resolution, or filesystem application failed. Inspect the typed failures, repair the source or implementation boundary, and rerun.
Failures can coexist with successful independent actions and omissions. Never read partial or failure as full projection success. Preserving a consumer-owned regular prompt is an intentional omission and may make the result partial; invalid context, unsafe paths, missing canonical sources, and failed writes are failures. Lifecycle reconciliation enables a consumer hook only after both its canonical source and managed target materialize. A failed hook mirror blocks its matching configuration during application while unrelated actions continue.
The receipt is evidence, not desired state. Do not hand-edit it or the context plan to force native output. A missing context plan alone selects the legacy compatibility path; a present malformed or schema-invalid plan fails and never silently falls back.
hi init, hi check, and hi update derive one desired scaffold state from the same semantic inputs, then use separate lifecycle stages. Init applies it, check observes and compares without a writable temporary tree, and update stages it for reconciliation. Projection plans used between those stages are explicit run-scoped transport: ambient DP_HARNESS_PROJECTION_PLAN is cleared, supplied plans are validated against canonical context, and only the caller-owned temporary plan directory is removed. Malformed context or inconsistent plan/trace evidence fails; trace identities shared by real summaries across different contribution kinds remain valid.
Internal model references: /docs/cli/scaffold-model/context-plan, /docs/cli/scaffold-model/harness-capability-projection, and /docs/cli/scaffold-model/shared-scaffold-model.
After setup:
- Read
.devpunks/AGENT-SYSTEM-PROMPT.mdwhen present. - Read
.devpunks/AGENT-HANDOFF.md. - Inspect
.devpunks/scaffold-manifest.json,.devpunks/settings.json, and.devpunks/specs/**. - Read matching
opensrc/*.mdcards before relying on third-party package internals. - Reconcile generated prompt, hook, skill, subagent, and wiki guidance with the real repo boundaries.
- Verify worker handoff is usable for the active harness before implementation: active harness global/project settings enable subagent execution,
.agents/subagents/manifest.mjsexists, and the selected specialist owns the target paths with matching guidance files and skills. Follow the generated.agents/AGENTS.mdworker policy above. If the worker guard fails, repair it or report the blocker; do not implement in the main thread. Default readonly archetypes such asplanning-discovery,requirements-synthesizer,backlog-shaper,spec-reviewer, andplan-reviewerdo not own parent decisions, user interaction, final artifact writes, or provider sync. - Validate the resulting repo-specific files before committing.
hi update
Use update only after .devpunks/scaffold-manifest.json exists.
Operator follow-through is change-sensitive. Read the current update summary and changed paths before generated artifacts. A clean preview or write reports success and stops; existing handoffs and specs do not reopen work. Same-ID skill content inspects only affected skills and active mirrors. Prompt, subagent, lint, hook, tool, and pack work runs only when its input changed. Source-guide refreshes inspect affected cards without running opensrc unless the current task needs library source. Wiki changes receive route- or runtime-targeted validation.
Auto-accepted default or detected pack additions route through their affected categories without a prompt or setup rerun. Full setup follow-through is reserved for first adoption, missing or corrupt final outputs, or an accepted optional-pack, removal, policy, or surface-shape decision that requires repo-authored outputs. After write modes, run targeted validation and one fresh hi check --json. Rerun update once only when that gate detects new CLI or baseline drift. An assigned execution worker runs its bounded command and does not delegate it again.
hi check is the read-only pre-work drift command. It composes CLI executable drift, scaffold/baseline drift, and compact changelog summaries when available, then exits nonzero when action is needed. .devpunks/settings.json records cliVersion and baselineVersion pins at init/scaffold/update acceptance points; read-only checks do not update those pins.
--check reports managed drift without writing. --write refreshes managed assets from the recorded manifest and selected baseline. --yes is the non-interactive apply flag for harnesses that cannot answer prompts and has the same managed-file apply behavior as --write. Pack drift reports when current auto-resolved packs are missing from the recorded finalPacks, while recorded extra packs remain prior accepted selections until an operator makes an explicit removal decision; only packs originally selected as optional are optional choices. In apply modes, update accepts newly resolved default or detected packs such as debug or expo, persists them in .devpunks/scaffold-manifest.json, and refreshes pack-owned skills, prompt specs, hooks, settings, and harness mirrors without requiring a separate hi scaffold run. Update reads older manifests that still list .devpunks/required-tools.json, but new writes use .devpunks/settings.json as required-tool authority. Stale .devpunks/required-tools.json references in generated .devpunks/AGENT-HANDOFF.md and .devpunks/AGENT-SYSTEM-PROMPT.md are reported and rewritten in place to .devpunks/settings.json without replacing local handoff text. Drift checks skip project-authored prompt specs, handoff text, scaffold manifest hashes, subagent manifest guidance, scaffold-time tailored .agents/scripts/sync-subagents.mjs, and generated harness agent prompt mirrors; static assets such as skills, hooks, lint specs, source guides, settings, and wiki scaffold structure remain checked.
Stable and exact-version selection comes from the control-plane API unless DP_BASELINE_URL is an explicit file:///absolute/path to an unpacked local baseline. That local override resolves before control-plane URL requirements, validates declared CLI compatibility, preserves metadata tag and commit, reports local authority, and must match any exact --baseline <version> selector. Missing or invalid explicit local bytes fail typed instead of silently continuing to remote or bundled content; non-file baseline URLs do not bypass authority. Without the local override, stable must agree with the newest complete published baseline identity; a newer non-stable publication, stale configured identity, conflicting immutable metadata, incomplete inventory, digest mismatch, or unavailable authority fails typed. An exact request selects the matching stable release, never the newest release, and returns not-found when absent. The selected manifest supplies identity and the archive digest; schema-v2 manifests also supply compatibility. Verified release inventory or deployment configuration supplies the retrieval URL and manifest digest. A verified schema-v1 release uses deployment compatibility only when it is the currently configured stable or matching exact version; historical schema-v1 releases fail typed integrity until backfilled. The CLI never continues to GitHub or bundled content after an authority failure. It reuses cache only when the stored archive and materialized files match the selected digest; otherwise it retrieves the version-bound authority URL and verifies digest, extracted version, provenance, and CLI compatibility. Use --baseline bundled or DP_BASELINE=bundled only as an explicit verified bundled request. Any other --baseline <value> is an exact immutable version request and fails rather than substituting another version.
Deploy the authority with required DP_BASELINE_VERSION, DP_BASELINE_PROVENANCE, DP_BASELINE_CLI_VERSION_RANGE, DP_BASELINE_MANIFEST_URL, DP_BASELINE_MANIFEST_SHA256, DP_BASELINE_ARCHIVE_URL, and DP_BASELINE_ARCHIVE_SHA256. DP_BASELINE_TAG and DP_BASELINE_COMMIT_SHA are optional traceability fields. The API reads a GitHub-compatible release inventory from its default endpoint and follows same-origin Link pagination and redirects before selection; cycles, cross-origin navigation, incomplete pages, or more than 100 pages fail typed. DP_BASELINE_RELEASE_INVENTORY_URL overrides the inventory endpoint for isolated or alternate supported runtimes. DP_CONTROL_PLANE_PUBLIC_URL or VERCEL_URL must resolve an API-owned public origin; otherwise authority metadata fails unavailable. Artifact links contain the selected version. Each download revalidates that version, buffers the configured source, and verifies its SHA-256 digest before returning bytes; mismatch is a typed integrity failure and retrieval failure is typed unavailable.
Update reconciliation keeps desired state, observed repository state, and the prior successful receipt separate. Files, dependencies, and structured configuration are planned per entry in deterministic order. Exact prior content, kind, and type-aware mode evidence can authorize safe replacement or removal. Divergent managed values become ScaffoldConflictPreserved; invalid observations and ownership overlap become typed planning failures. Those blocked entries do not suppress independent safe actions or authorize whole-file replacement of unrelated user content.
Write mode returns one typed outcome for every planned item: ScaffoldActionSucceeded, ScaffoldActionBlocked, ScaffoldEntrySkipped, ScaffoldDegradationRecorded, ScaffoldConflictPreserved, ScaffoldPlanningFailed, or ScaffoldActionFailed. No blocked outcome means succeeded. Blocked outcomes plus at least one success mean partial; blocked outcomes without a success mean failed. Partial and failed writes exit nonzero at the command boundary even though independent work may have applied.
Dependency changes refresh the detected lockfile through the owning package manager: Bun and pnpm use lockfile-only installs, npm uses package-lock-only, Yarn Classic uses noninteractive scripts-disabled installation, and modern Yarn uses update-lockfile mode. If that process fails, update restores the previous package manifest and every recognized lockfile snapshot. The prior receipt remains authoritative so retry repeats the incomplete action.
The receipt is persisted last from unchanged evidence, successful actions, and truthful known omissions/degradations. Conflicts, planning failures, blocked dependent actions, and application failures never advance ownership. A rejected receipt operation returns receiptPersisted: false and does not roll back independent successful actions. The default manifest write is not atomic, so after a low-level write failure inspect or repair the on-disk receipt before relying on it. After a partial run, resolve only the reported conflict and retry; completed state remains stable and unresolved work stays visible.
Update also stages the current wiki with the latest baseline wiki scaffold and runs the staged content sync. It preserves existing wiki roots in this order before shape fallback: apps/wiki/, app/wiki/, then wiki/. This keeps monorepo apps/wiki behavior, preserves app-surfaced single-repo app/wiki selections without proposing competing wiki/ or apps/wiki/ trees, and keeps standalone wiki/ roots stable. This lets hi update --check report wiki-structure drift and lets hi update --write add missing wiki seed files, update managed package hooks, and project existing repo docs into Fumadocs routes without overwriting existing routed pages. Scaffold init/setup creates the default apps/wiki/scripts/sync-content.mjs; update/check preserves an existing project-authored script at that exact path, while a missing script remains managed drift and write mode recreates it. Required-tool checks read .devpunks/settings.json when present; wiki provider pages are not update authority.
Generated JavaScript maintenance scripts must run through an actual script runtime. Packaged CLI builds can expose the CLI entrypoint through both process.execPath and Bun.execPath, so update/scaffold internals default to node and allow DP_SCRIPT_RUNTIME as an override. If a global install fails by trying to execute dist/index.js <temp-script>.mjs, validate this runtime path before treating the scaffold output itself as corrupt.
For wiki-only project-docs migrations, update treats stale root docs/AGENTS.md-only trees as removable managed drift instead of recreating docs prompt/subagent surfaces. Durable project documentation should stay under the selected wiki root: usually apps/wiki/content/docs/project for monorepos, app/wiki/content/docs/project for app-surfaced single repos, or wiki/content/docs/project for standalone wiki roots.
Update also reports exact .cursor, .codex, .claude, .agents, and .opencode ignore patterns in root .gitignore as harness drift, then removes them when applying.
Write-mode update uses the same best-effort required-tool bootstrap behavior as setup: tool install failures are shown with stack traces and recovery guidance, but managed updates still apply.
Update inherits the same agent-browser browser check as setup and hi tools ensure; an existing supported Chrome, Chromium, or Brave executable should satisfy the browser requirement without a forced Chrome download.
Installed consumer validation
Run bun run validate:consumer-repositories when CLI packaging, bundled baseline loading, scaffold materialization, or update reconciliation changes. Each invocation copies the CLI into its own temporary build workspace, builds and packs only that copy, installs the actual tarball offline, and uses the installed hi and hint binaries for three isolated scenarios: interactive init, repeated scaffold to a fixed point, and check/update with a user-modified managed file.
The gate requires exact CLI/baseline provenance, managed paths and hashes, preserved consumer-owned bytes, a path-specific preserved-conflict outcome, update idempotence, a final clean check, and deletion of the run-owned temporary root. Interactive init accepts only explicit success and partial terminal states with matching exit codes. npm excludes .gitignore files by default and renames an included package .gitignore to .npmignore during installation. The package gate therefore copies the declared package surface into a run-owned staging root, adds the nested pack-control file only there, verifies the exact installed bytes against a manifest hash, maps that physical npm name back to the logical .gitignore identity for bundled digest verification, and materializes the logical .gitignore name in consumer output. Ambiguous, missing, mismatched, or unlisted aliases fail closed.
Complete cutover repeat validation
Run bun run validate:cutover-repeat only when the complete local architecture-cutover gate is expected to pass. One invocation runs two complete composites sequentially. Each composite includes root test and check, direct non-mutating wiki generation/type/build, the filtered non-wiki build, packaged-product validation, and one caller-owned installed-consumer lifecycle. Turbo work is forced uncached with a run-owned cache. Two additional consumer/package lifecycles then overlap as an isolation stress; they are compared separately and do not claim to be complete repository gates.
The direct wiki order is next typegen, fumadocs-mdx, scripts/assert-wiki-generated-source.mjs, native TypeScript with --noEmit --incremental false, then next build. The assertion requires the four generated modules to be regular non-symlink files with module syntax and records sorted path, mode, and raw content SHA-256 evidence. patches/fumadocs-mdx@14.3.2.patch sorts resolved glob paths and serializes eager import mutation: Fumadocs 14.3.2 otherwise combines unordered async Tinyglobby results with shared eager import IDs under Promise.all. Keep the package and lockfile patchedDependencies entry until an upstream release proves byte-stable generation under the normal thread pool.
The report binds every lifecycle to the same Git HEAD and exact dirty-patch digest. Package name, version, and the canonical installed tree—sorted relative path, type, mode, file-byte hash or symlink target, and exact entry count—are authoritative across packaged-product and consumer validation. Each actual tarball SHA-256 remains observational evidence because archive bytes may include non-product metadata; only that archive SHA and declared volatile run, PID, path, timing, ownership, and cleanup-location leaves are normalized. Stable exit, timeout, cleanup action/result, process/service state, residue, and installed-package authority remain in equality evidence. Complete-run equality and concurrent-stress equality stay separate. The fifth lifecycle acquires its owned root, raises CutoverRepeatInjectedFailure, awaits cleanup, and is excluded from equality.
Inspect each lifecycle's spawnedPids, preCleanup, cleanupActions, and postCleanup. Cleanup revalidates directory identity before removal. A child cleanup failure remains visible: the parent session refuses to recursively remove a nonempty session. Successful complete, stress, failure-probe, and session lifecycles end with empty path, process, and service arrays. Every command has a bounded timeout.
The IP-324 T8 replacement matrix exited 0 at HEAD 5e1637f939818e43b69a8a5262c3de012e54518c, bound to dirty-patch SHA-256 633b1614c0081cd52d7dda086cb241c2fd62f279c2b9d4fe26914e7695faf806 (56,308 tracked bytes; 6 untracked paths). Complete runs matched at 739c91c0ae08234d6cd7611ffbfda8eed19aa14b1f4355b349d12a546162fe0d; stress runs matched at dbbed7e6af71a7a1bdf63b9444045743503343e5f86770a4f15cce1c78fd7bac. The observational archive SHA-256 was cc49bfd06a303ee9f6cf4c5a1a991404c1641de0567c3df77b7032f381d1361; authoritative installed identity was @punks/cli@2.6.2, 664 entries, tree SHA-256 991c96fbcf2e7a0d2b26733704e53944783523e61c47b3fa2319eba48f7f2cb9. Four generated wiki modules matched at fd36d0636ae488eaa5acb37823cf0f4bf6846e0f16452d387312a847be2fe422. Focused coverage passed 31/31 with 214 assertions, static checks passed 12/12, and complete, stress, injected-failure, and session cleanup path/process/service sets were empty.
hi tools ensure
Use hi tools ensure to check and repair required external tools directly, without rerunning scaffold setup or applying an update.
In a scaffolded repo, hi tools ensure reads tool IDs from .devpunks/settings.json. Outside a scaffolded repo, it validates the default Harness toolchain.
hi tools ensure is not read-only. It may install or repair missing installable tools using the same required-tool registry and installer path as setup/update. Install contracts come from the selected verified baseline, not repo-owned metadata; bundled content is used only when explicitly requested.
For agent-browser, validation should skip the browser install step when a supported Chrome, Chromium, or Brave executable is already installed. If the agent-browser command itself is missing, the CLI may still install the package, then skip only the redundant browser download.
hi report
Use hi report for reusable Harness friction: stale skill guidance, broken CLI/docs behavior, setup pain, or workflow/tooling problems maintainers should triage.
Reports submit raw issue context to /api/reports; the API validates relevance, rejects trolling/profanity/non-coding reports, generates deterministic fallback title/body for public CLI submissions, checks open harness-report issues for duplicates, and creates a GitHub issue with API-held credentials. Requested GitHub creation fails before provider calls or persistence when the integration is disabled. Provider and AI SDK work is aborted when the submission is interrupted. hi report must return a GitHub URL or fail; do not treat internal-only storage as a successful maintainer report. AI SDK + OpenRouter metadata generation remains limited to authenticated backoffice operator sessions. Use --message, --area, --skill-pack, --command, --expected, --actual, --steps, and --labels to make the issue descriptive and classifiable. Keep project product backlog work out of reports unless maintainers explicitly promote it.
Backoffice ingests CLI telemetry for artifact pulls, init, scaffold, scaffold update writes, and successful harness report submissions.
hi operator
Use hi operator status, install, update, or migrate to manage the independently installed hi-cli operator skill. The current target is hi-cli version 1.0.0 from shared-skills revision 45072f4721d9668177bc4dd006802935ae61e70f, compatible with CLI versions >=2.6.1 <3.0.0. The source URL includes that exact revision; no operator command follows a moving branch.
status inspects both global and current-directory project scopes for the active agent. Inside a project, a compatible project-local copy is effective and the global copy remains visible as shadowed. Outside that project, the global copy remains the fallback. Every observed copy reports source, version, revision, compatibility, scope, project root when applicable, and bound agents. Listing or verification failure is reported as detection failure, never as absence.
install always ensures the global default, even when a project-local copy is already effective. update addresses every detected hi-cli scope and fails with install guidance when no copy exists. A successful-looking write counts only after reinspection verifies the immutable identity, compatible range, scope, project root, and active-agent binding. Independent scopes are not rolled back: a mixed update prints every verified, failed, or unverified outcome, retains successful work, and exits nonzero.
Failed or unverified writes print a guarded retry that freezes the target, scope, cwd, and active agent, then re-enters post-write verification. Inspection failures rerun the operator lifecycle without converting unknown state into an install. migrate verifies every affected fallback before removing any active-agent dp-cli copy; barrier loss or target drift refuses removal and prints a guarded migrate retry. hi skills rename remains a deprecated delegate to hi operator migrate; it owns no separate lifecycle or rename policy.
Any observed successful write prints guidance to reload or reactivate $hi-cli, including partial-success cases. Operator commands do not inspect .devpunks, reconcile scaffold output, change packs, resolve or publish baselines, upgrade the executable, or synchronize the shared skill source. Use scaffold/update commands, baseline release tooling, hi upgrade, and the shared-skill source-first sync workflow for those separate jobs.
hi upgrade
Use hi upgrade to update the CLI executable itself. The command checks the selected npm dist-tag, detects whether the current global install came from Bun, pnpm, npm, or Yarn, and runs the matching global reinstall command. Detection resolves the invoked bin symlink first, so Bun global layouts such as bin/hi -> ../install/global/node_modules/@punks/cli/dist/index.js are treated as Bun installs instead of generic unknown commands. It forces minimum release age to 0 for the upgrade run so a just-published CLI release can be installed immediately. Use --tag next for prerelease channels and --force to reinstall the selected tag even when no newer version is detected.
Interactive hi commands also check for a newer CLI before running. When an update exists, hi asks for y/n confirmation, installs through the detected package manager, and exits so the operator can rerun the command with the upgraded binary. The prompt is skipped for help/version output, CI, non-interactive shells, and HI_NO_UPDATE_CHECK=1.
hi -v is equivalent to hi --version.
Release Bookkeeping
Every npm executable release needs one CHANGELOG.md section named for the package version before publishing. Put user-facing notes under categories such as ### Changed and ### Fixed; publish metadata can stay above those categories for the docs changelog. bun run release:publish reads that section, refuses missing, empty, or uncategorized notes, builds dist/index.js as a portable Node script with bundled scaffold assets, publishes @punks/cli, pushes v<version>, and creates or updates the matching GitHub release title and notes from only the categorized content. GitHub release notes use compact labels such as changed: and fixed:. The build can regenerate the tracked bundled-baseline identity. Publication therefore checks worktree cleanliness again immediately after build and stops before npm publish, tag push, or GitHub release mutation when the refreshed identity is uncommitted; commit that identity and rerun. If npm publish succeeds but release bookkeeping is interrupted or a GitHub release was created with stale notes, rerun bun run release:publish from the same commit; when the version already exists on npm, the script skips package build/publish and reconciles the tag and GitHub release.
The installed npm command should not require Bun at runtime. Bun is a repo build/publish dependency only. Release validation should include the built dist/index.js under node, plus a sanitized npm-package install into a temporary prefix, then run hi and hint help commands from that prefix.
Baseline releases remain separate. They use baseline/stable/* tags and require a matching BASELINE_CHANGELOG.md section. Publish with BASELINE_VERSION=YYYY.MM.DD-short-slug BASELINE_CLI_VERSION_RANGE='>=2.6.0 <3' bun run --cwd apps/cli baseline:publish. Publication requires the explicit nonblank range; ordinary baseline:build defaults to =<current CLI package version>.