Harness Intelligence Wiki
SpecsCLILefthook Commit Gate for Catalogue Consumers

Plan: Lefthook Commit Gate for Catalogue Consumers

Plan: Lefthook Commit Gate for Catalogue Consumers

Plan state

  • Status: Complete; review_count=1; repair_count=1
  • Delivery goal: Linear Story IP-425 through Task IP-426
  • Task identity mode: provider-task
  • Architecture applicability: architecture-bearing
  • Evidence: a new public contribution family connects shared schemas, CLI policy, compilation, materialization, observation, receipts, check output, agent follow-through, and docs.
  • Branch: feat/pre-commit-hooks
  • Immutable start: b0c53c2552e3c0a1ab34519e7486a9bfe11d1fbb
  • Pre-implementation HEAD: 9a633d2395aef00f77eaf442506498bd21cf8d8b
  • Post-implementation route: review 1 accepted IP426-CG-001/IP426-CG-002; repair epoch 1 complete; consumer validator, affected lint/check graph, and supplemental CI-repair review pass. Hosted exact-head CI and Devpunks provider completion readback remain closeout gates.

Initial situation and problem

The accepted spec and requirements grill are complete. The branch contains the canonical spec, research, glossary, and backlog handoff, but no Commit Gate implementation. A fresh hi check --json on 2026-09-01 reports current CLI/settings, no scaffold drift, no degradation, and no pending action.

Typed project settings, neutral context compilation, ownership-aware scaffold reconciliation, managed desired-state receipts, read-only repository check, and staged owner selection already exist. None represents a first-class Commit Gate, complete Quality Command Contract, Hook Migration Proposal, unresolved Post-Command Handoff, separate Commit Gate Lifecycle Receipt, or exact current health state.

Solution shape

Create one deep CLI-owned commit-gate feature. Its public interface consumes typed policy, compiled contribution, desired scaffold evidence, and observed repository facts. It returns typed desired actions, conflicts, handoff requirements, lifecycle-receipt validity, and current health. Keep filesystem, Git, package-manager, config parsing, and process mechanics in adapters. Keep packages/scaffold behavior-free and limited to stable contribution/context schemas.

Use one packaged consumer runner for staged path parsing, owner routing, exactly-once Quality Command Contract dispatch, parallel lint/format execution, and aggregate failures. Generate or merge one HI-owned Lefthook pre-commit.commands.lint entry. Use upstream lefthook.yml only when HI creates config; preserve recognized existing config and return unsupported, ambiguous, or colliding state for user decision.

The CLI persists policy and desired state. It does not silently migrate managers or claim hook installation. Scaffold emits a structured unresolved Post-Command Handoff. The $hi-cli agent performs only authorized lifecycle work, verifies exact dependency/config/hook facts, and records the separate lifecycle receipt. hi check re-observes facts, validates receipt binding, and never repairs.

Design-it-twice selected this boundary over adding branches directly across broad existing modules. The dedicated feature hides policy, coexistence, health, and proof complexity while existing owners retain settings, compilation, materialization, adapters, and presentation.

Locked decision ledger

DecisionStatusReason
Consumer eligibilityLockedSupported JavaScript package manager and lockfile plus complete Quality Command Contract.
PolicyLockedcommitGate accepts enabled or disabled; absent means enabled; init/ensure persist policy only.
ContributionLockedCommit Gate is separate from AI-agent lifecycle hooks.
DependencyLockedProject-local lefthook@2.1.10, pinned to reviewed evidence.
ConfigurationLockedHI owns exactly pre-commit.commands.lint; consumer entries remain unchanged.
MigrationLockedOther manager or unsafe config defers all materialization and yields a non-authorizing proposal.
ExecutionLockedStaged applicable owners once; lint/format parallel; aggregate failures; empty scope starts no tools.
ProofLockedManaged receipt proves desired state; separate lifecycle receipt proves live operation.
CheckLockedExact current health, read-only, no historical bypass claim.
AuthorityLockedCI remains merge authority; deliberate local bypass remains possible.

Assumptions and constraints

  • The canonical spec, grill artifacts, glossary, and 2026-09-01 backlog handoff are authority. No product question remains open.
  • Retained provider readback maps exactly one execution Task, IP-426, to Story IP-425 and V4.1, with no retained native blocker. Connected Linear cannot refresh IP-*; current provider readback is required before tracker mutation or closeout.
  • The immutable spec blob is verified at commit 3751d60e47d03e136147b6c1aee62b339319f429, blob c633ac62917d7a781219b0392fd5646eb1b69f73.
  • Do not install Lefthook in Harness. Runtime proof uses an isolated Commit Gate Consumer because Harness already owns .githooks through core.hooksPath.
  • Never use Lefthook force/reset or remove-config flags automatically. Never infer contracts from arbitrary runtime package scripts.
  • Preserve settings keys, Lefthook commands/config, hook managers, and unrelated receipt entries.

Dependency and branch readiness

Ready: npm lefthook@2.1.10, integrity sha512-K7mM4WoqMwqfXYK11EHy+lSH1uW8XHni3Yn/bSqyerPkUPygGdf3xn18JoV5HyA06xuQL3ofGAOjG01QX9oJ4w==, gitHead 8d9cfec5f52367af6374a5430b4e9568844856e5, tarball https://registry.npmjs.org/lefthook/-/lefthook-2.1.10.tgz.

Research and findings

  • Consolidated report: Lefthook Commit Gate Delivery Planning Research.
  • Project Settings has no policy field; raw-key preservation exists.
  • Context plans have no Commit Gate or Quality Command Contract family; detection lacks package-manager/lockfile/quality evidence.
  • Reconciliation already supports narrow ownership-aware dependency/file/structured-entry changes.
  • Managed scaffold and projection receipts cannot prove a live Git hook.
  • The current staged selector is owner-aware and empty-safe but sequential, fail-fast, and Harness-specific.
  • Repository check is read-only but has no Commit Gate health result.

Target ownership topology

packages/scaffold/src
└── schemas; entrypoint: package exports; paths: catalog.ts, context-plan.ts, index.ts
    forbidden: filesystem, Git, process, policy, health, installation

features/project-settings
└── policy; entrypoint: index.ts; paths: feature directory and colocated tests
    forbidden: desired state, Git observation, health classification

features/repository-analysis + features/context-planning
└── eligibility/compilation; entrypoints: each index.ts; paths: both feature directories
    forbidden: runtime package-script discovery or scaffold mutation

features/commit-gate
└── desired/conflict/handoff/receipt/health; entrypoint: index.ts exporting CommitGate/results
    paths: feature directory and colocated tests
    forbidden: rendering, command parsing, raw filesystem/Git/process implementation

platform + integrations
└── CommitGateCapabilities adapters; entrypoint: platform/commit-gate-capabilities.ts
    paths: named adapter modules/tests; forbidden: policy, desired state, presentation

scaffold + update + repository-check + presentation
└── consume CommitGatePlan/CommitGateHealth; entrypoints: existing public surfaces
    paths: apps/cli/src/{cli,scaffold,update}, features/repository-check, presentation, ui
    forbidden: duplicate eligibility/conflict/receipt/health policy

data/scripts
└── runner; entrypoint: commit-gate-runner.mjs plus declaration
    paths: runner/declaration/tests; forbidden: settings, migration, installation, receipts

Declared dependency graph

packages/scaffold contracts -- imported by --> repository-analysis/context-planning
packages/scaffold contracts -- imported by --> features/commit-gate

project-settings policy -------------------- data --> features/commit-gate
compiled contribution ---------------------- data --> features/commit-gate
scaffold-state evidence -------------------- data --> features/commit-gate
platform/integration observations ---------- data --> features/commit-gate

CommitGatePlan ----------------------------- data --> scaffold/update/handoff
CommitGateHealth --------------------------- data --> repository-check --> JSON/terminal
runner declaration ------------------------- data --> packaged runner --> Lefthook lint

Allowed edges use public feature/package entrypoints. Forbidden edges: packages/scaffold importing CLI code; catalogue data, presentation, adapters, or repository check owning policy; repository check mutating state; commit-gate importing renderers/handlers; lifecycle receipts deriving desired state; consumer assets importing CLI source internals.

Responsibility acceptance criteria

CriterionOwnerObservable assertionEvidenceDue
CG-ARCH-01packages/scaffoldFirst-class contribution and complete contract decode/encode; lifecycle-hook remains distinct.bun run --cwd packages/scaffold test -- src/context-plan.test.ts and package typecheck.A1
CG-ARCH-02analysis/context planningApplicable consumer compiles lint + read-only format; incomplete applicable input fails typed.bun run --cwd apps/cli test -- src/features/context-planning/compiler.test.ts.A1
CG-ARCH-03features/commit-gateOne public seam owns desired/observed/conflict/handoff/receipt/health decisions.bun run --cwd apps/cli test -- src/features/commit-gate; inspect caller imports through index.ts.A1
CG-ARCH-04scaffold/update adaptersOpt-out and migration conflict yield no dependency/config/install action; shared config is preserved.bun run --cwd apps/cli test -- src/cli/behavioral-portfolio.test.ts src/update/run.test-cases.test.ts src/scaffold/run.test.ts; retain before/after hashes in IMPLEMENTATION-NOTES.md#coexistence-evidence.A1
CG-ARCH-05packaged runnerOwners run once; lint/format concurrently; all failures return; empty scope spawns nothing.bun run --cwd apps/cli test -- src/data/scripts/commit-gate-runner.test.ts and isolated git commit transcript.A1
CG-ARCH-06handoff/proofHandoff unresolved until exact verification; separate receipt stales on relevant changes.bun run --cwd apps/cli test -- src/features/commit-gate -t "handoff receipt"; retain exact dependency/config/hook inspection in IMPLEMENTATION-NOTES.md#commit-gate-lifecycle-readback.A1
CG-ARCH-07check/presentationExact disabled, healthy, unresolved, dependency/config/hook/manager states remain read-only.bun run --cwd apps/cli test -- src/cli/check-command.test.ts src/cli/public-output-contract.test.ts; retain before/after repository SHAs in IMPLEMENTATION-NOTES.md#read-only-health-evidence.A1

Architecture and worker waves

Architecture waveDeltaEntryCriteriaTemporary seamsCheckpoint
A1Establish shared schema and CLI feature, connect every caller, close real consumer behavior.Agent-ready spec, retained IP-426 projection, clean scaffold check.CG-ARCH-01–07NoneCompare owners/imports/seams with plan; run focused/outward validation and real commit proof; ledger empty.
W1 / A1
└── T1 = IP-426
    vertical RED -> GREEN cycles across AC-001–AC-012
    -> convergence checkpoint
    -> retained review handoff

One Task wave is required because the provider backlog contains one Task and every slice converges on the same public seam.

Public seam contract

SeamOwnerConsumers
CommitGateContribution, QualityCommandContract package schemaspackages/scaffoldCLI catalogue/context compiler and contract tests.
ProjectSettingsValue.commitGate, CommitGatePolicyChangefeatures/project-settings/index.tsinit, ensure, scaffold/update assessment, check.
CommitGate returning CommitGatePlan and CommitGateHealthfeatures/commit-gate/index.tsscaffold, update, check, platform composition.
CommitGateCapabilities portfeature contract; platform/integration implementationsCommit Gate action/process composition.
commit-gate-runner.mjs --contracts <path>apps/cli/src/data/scriptsGenerated Lefthook lint.run only.
PostCommandHandoff.commitGate: CommitGateHandoffscaffold/content$hi-cli follow-through and diagnostics.
CommitGateLifecycleReceipt, verifyLifecycleReceiptfeatures/commit-gate/index.tsAgent verification writer and check validator.
RepositoryCheckResult.commitGate: CommitGateHealthrepository-check/presentationJSON and terminal renderers.

Migration ledger

Empty. Any compatibility alias, duplicate policy calculation, receipt mirroring, or second runner introduced during implementation must amend this ledger with owner/removal proof. A1 closes only with an empty ledger.

T1: Implement and prove the Commit Gate

  • depends_on: []
  • location: packages/scaffold/src; apps/cli/src/features; apps/cli/src/platform; apps/cli/src/integrations; apps/cli/src/scaffold; apps/cli/src/update; apps/cli/src/content; apps/cli/src/presentation; apps/cli/src/ui; apps/cli/src/data; apps/cli/src/cli; docs; apps/wiki/content/docs/project/specs/cli/lefthook-commit-gate.
  • owned_paths: packages/scaffold/src; apps/cli/src/features/project-settings; apps/cli/src/features/repository-analysis; apps/cli/src/features/context-planning; apps/cli/src/features/commit-gate; apps/cli/src/features/scaffold-state; apps/cli/src/features/repository-check; apps/cli/src/platform; apps/cli/src/integrations; apps/cli/src/cli; apps/cli/src/scaffold; apps/cli/src/update; apps/cli/src/content; apps/cli/src/presentation; apps/cli/src/ui; apps/cli/src/data/catalog; apps/cli/src/data/scripts; apps/cli/package.json; bun.lock; docs/README.md; docs/runbooks/hi-cli-scaffolding.md; apps/wiki/content/docs/project/specs/cli/lefthook-commit-gate; apps/wiki/log.md.
  • wave_boundary: W1; one worker because IP-426 is the only provider Task and all slices share the Commit Gate seam.
  • description: Add typed policy, eligibility and contract compilation, first-class contribution, deep feature boundary, safe desired-state integration, staged runner, exact merge/conflict behavior, structured unresolved handoff, separate receipt, ownership-aware disable/migration evidence, and read-only exact health. Preserve consumer state. Prove real commit success/failure in an isolated fixture. Update implementation notes and operator docs. Do not install Lefthook in Harness.
  • validation: Map AC-001–12 to public tests; cover manager/config collisions, partial materialization, failed follow-through, stale receipts, no-write check; prove isolated Git behavior; run package/CLI typecheck, lint, format, build, affected/full tests, consumer validation, classifier, and hi check --json; prove CG-ARCH-01–07 and empty ledger.
  • status: In progress
  • log: Initial RED retained; shared contract, compiler, Commit Gate feature seam, observation adapter, runner, docs, and implementation notes added. Full runtime lifecycle and parent closeout remain pending.
  • files edited/created: packages/scaffold/src/context-plan.ts; packages/scaffold/src/context-plan.test.ts; apps/cli/src/features/context-planning/{compiler.ts,compiler.test.ts,compilation-error.ts,errors.ts,index.ts}; apps/cli/src/features/repository-analysis/{model.ts,index.ts}; apps/cli/src/integrations/repository-detector.ts; apps/cli/src/features/project-settings/{model.ts,service.ts,index.ts}; apps/cli/src/features/commit-gate/{index.ts,index.test.ts}; apps/cli/src/platform/commit-gate-capabilities.{ts,test.ts}; apps/cli/src/data/scripts/commit-gate-runner.{mjs,d.ts,test.ts}; apps/cli/src/scaffold/output.ts; docs/README.md; docs/runbooks/hi-cli-scaffolding.md; apps/wiki/log.md; IMPLEMENTATION-NOTES.md
  • task_identity_mode: provider-task
  • backlog_item_id: IP-426
  • backlog_item_url: https://linear.app/devpunks/issue/IP-426/implement-lefthook-commit-gate-for-catalogue-consumers
  • relation_mode: native
  • backlog_sync_skip_reason:
  • assigned_skills: [create-plan, grilling, parallel-research, show-me, swarm-planner, wait-what, backend-domain-structure, backend-recoverable-actions, codebase-design, effect, effect-backend-structure, effect-recoverable-actions, effect-service-design, improve-codebase-architecture, quality-types, tdd, turborepo, writing-for-agents, implement-spec]
  • implementation_skill_guidance:
    • skill: backend-domain-structure applicable_behavior: Keep policy in one feature, adapters outside it, and imports one-way through public entrypoints.
    • skill: backend-recoverable-actions applicable_behavior: Classify preflight, local desired-state writes, external package/Git work, follow-through, and receipt commit; make partial failure explicit and repairable.
    • skill: codebase-design applicable_behavior: Maintain a small deep interface and test through the same seam callers use.
    • skill: effect applicable_behavior: Use project-compatible Effect v4 Schema/errors/workflows; decode untrusted settings/config/receipt input; keep expected failures typed.
    • skill: effect-backend-structure applicable_behavior: Keep actions as orchestration owners, adapters at boundaries, and feature-local Effect tests.
    • skill: effect-recoverable-actions applicable_behavior: Use typed failure channels and explicit collect-all read-only concurrency; do not pretend external Git/package effects are locally atomic.
    • skill: effect-service-design applicable_behavior: Use an authority service only where lifecycle/filesystem variability earns it; keep deterministic policy/projections pure.
    • skill: improve-codebase-architecture applicable_behavior: Compare cumulative implementation with the selected deep-module topology; surface drift before adding another seam, owner, or compatibility layer.
    • skill: quality-types applicable_behavior: Use discriminated unions for eligibility, conflicts, handoff, receipt, and health; derive related types.
    • skill: tdd applicable_behavior: Capture every public-result RED before production code; advance one tracer at a time; retain evidence.
    • skill: turborepo applicable_behavior: Preserve package boundaries and affected/focused task dependency order.
    • skill: writing-for-agents applicable_behavior: Make handoff/guidance authority, exact verification, unresolved state, and stop conditions explicit.
    • skill: implement-spec applicable_behavior: Execute with one scoped worker; parent coordinates, reviews, validates, and routes durable evidence.
  • tdd_status: required
  • tdd_target: First create only the public-result test. compileContextPlan must return typed IncompleteQualityCommandContract for an applicable consumer missing format-check and expose no Commit Gate desired action.
  • red_command: bun run --cwd apps/cli test -- src/features/context-planning/compiler.test.ts -t "rejects an incomplete Commit Gate quality contract"
  • expected_red_failure: The assertion expects _tag: "IncompleteQualityCommandContract" and zero Commit Gate contributions/actions, but the current compiler returns a successful plan without that typed failure.
  • green_command: bun run --cwd packages/scaffold test && bun run --cwd packages/scaffold check-types && bun run --cwd apps/cli test && bun run --cwd apps/cli check-types && bun run --cwd apps/cli build
  • reason_not_testable:
  • red_evidence: bun run --cwd apps/cli test -- src/features/context-planning/compiler.test.ts -t "rejects an incomplete Commit Gate quality contract" failed before production implementation with the compiler returning { version: "1", scopes: [{ id: "fixture-consumer", packs: [], contributions: [] }] }; an earlier run recorded vitest: command not found, resolved by bun install --frozen-lockfile.
  • green_evidence: Focused compiler, feature, runner, and platform tests pass (8 tests); bun run --cwd apps/cli check-types, bun run --cwd packages/scaffold test, and bun run --cwd packages/scaffold check-types pass. Full green_command, consumer runtime, check presentation, and build remain pending.
  • codebase_design_notes: features/commit-gate is the deep module. Eligibility, desired state, merge/conflict policy, receipt binding, and health remain pure where possible. Filesystem/Git/process variability uses narrow ports. Scaffold/update/check orchestrate or present the result, not duplicate policy.
  • review_mode: cli
  • runtime_validation: required
  • runtime_target: Contained temporary Git repository representing an eligible JavaScript Commit Gate Consumer, with isolated Git config and project-local Lefthook 2.1.10.
  • runtime_evidence: Commands/output proving default and opt-out policy; safe materialization or deferral; unresolved handoff; verified dependency/config/hook; receipt binding; normal commit success; lint, format, and dual failures; multi-owner once; empty no-spawn; every health state; deliberate bypass possible without historical claim.
  • runtime_cleanup: Record fixture path/identity; remove only that fixture and local Git config. Do not alter global Git config, Harness hooks, or external repositories.
  • architecture_wave: A1
  • behavior_owner: apps/cli/src/features/commit-gate
  • integration_surface: Context schemas, settings, repository analysis, scaffold/update, adapters, handoff, check, packaged runner.
  • public_seam: Plan-level seams centered on one Commit Gate assessment/planning interface.
  • topology_delta: Add shared contract and one CLI feature authority; connect callers without moving behavior into packages/scaffold.
  • forbidden_ownership: AI lifecycle hooks, managed receipts, renderer, catalogue data, adapters, or check command may not own policy or operational truth.
  • temporary_seams: []
  • responsibility_acceptance_criteria: [CG-ARCH-01, CG-ARCH-02, CG-ARCH-03, CG-ARCH-04, CG-ARCH-05, CG-ARCH-06, CG-ARCH-07]

TDD and validation strategy

Execute one tracer at a time: incomplete contract; policy; eligibility; contribution; safe config; opt-out/migration; runner routing/concurrency/aggregation; handoff/receipt; health; JSON/terminal facts; isolated Git behavior. Never batch all tests before implementation.

Validation expands outward: focused tests; full scaffold/CLI tests/typechecks/build; targeted Oxlint/Oxfmt and git diff --check; bun run check:repo, bun run test:ci, bun run validate:consumer-repositories; isolated Git scenarios; hi check --json; bun run release:classify -- --base b0c53c2552e3c0a1ab34519e7486a9bfe11d1fbb --head HEAD.

Risks and mitigations

  • Postinstall can force-install hooks: preflight before dependency desired state; no force/reset; failure remains unresolved.
  • Config variants can lose content: support only structurally safe recognized config; preserve untouched nodes; otherwise return evidence.
  • One Task is broad: one worker, vertical tracers, durable evidence, final convergence checkpoint.
  • Receipt misuse can overstate health: separate schemas and observed-fact binding.
  • Check can mutate through tooling: inspection-only adapters and before/after fingerprints.
  • Harness hooks can be damaged by proof: use contained fixture only.
  • Linear access unavailable: preserve identity; do not mutate or claim current tracker state until refreshed.

Review, docs, and unresolved state

  • Retain IMPLEMENTATION-NOTES.md with per-tracer evidence, deviations, commands, runtime provenance, and architecture checkpoint.
  • Full delivery invokes review after implementation; repairs preserve IP-426 and review lineage.
  • Update docs/README.md and docs/runbooks/hi-cli-scaffolding.md in T1.
  • After clean review, docs-ingest-phase ingests or records a no-op. Closeout separates branch/PR, local validation, CI/provider, tracker, and release evidence.
  • Only unresolved question: current Devpunks Linear readback is externally blocked. This does not block local implementation from the retained same-day exact handoff, but blocks tracker mutation/current closeout claims.

On this page