Harness Engineering¶
This document defines the enforcement architecture that ensures developers automatically comply with coding standards, security policies, and operational conventions — without requiring prior knowledge of the rules.
For language-specific toolchain details, see:
Overview¶
Harness engineering is the practice of embedding rule enforcement into the development workflow infrastructure so that compliance is structural rather than behavioral. The goal: a developer — whether using an AI agent or writing code manually — still produces compliant code without reading the coding standards.
This is achieved through a 6-layer enforcement architecture where each layer catches violations that the previous layer missed or that the developer bypassed. Layers 1–2 apply only to AI-assisted development; for manual development, Layer 3 (pre-commit) is the first enforcement point.
Enforcement Architecture¶
┌─────────────────────────────────────────────────────────────────┐
│ Local Development Loop │
│ │
│ Developer writes code │
│ │ │
│ ▼ │
│ Layer 1: Agent Instructions ← Guides AI code generation │
│ (instructions.md / steering) (AI-assisted only) │
│ ▼ │
│ Layer 2: Agent Hooks ← Auto-format + validate │
│ (PostToolUse / Stop) (AI-assisted only) │
│ ▼ │
│ Layer 3: pre-commit ← Block non-compliant commits │
│ (commit-msg + pre-commit) (all developers) │
│ │
└──────────────────────────┬──────────────────────────────────────┘
│ push
▼
┌─────────────────────────────────────────────────────────────────┐
│ Remote Verification │
│ │
│ Layer 4: CI ← Block non-compliant merges │
│ (GitHub Actions reusable) │
│ │
└─────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────┐
│ Async / Infrastructure (independent lifecycle) │
│ │
│ Layer 5: Renovate ← Automated dependency governance │
│ (Shared policy presets) Triggers CI on update PRs │
│ │
│ Layer 6: Setup Automation ← Ensures layers 1-3 are active │
│ (devcontainer init.sh) Runs on environment creation │
│ │
└─────────────────────────────────────────────────────────────────┘
Layer 1: Agent Instructions¶
Instructions (.apm/instructions/*.instructions.md) define coding rules that AI agents follow during code generation. APM (Agent Package Manager) distributes these instruction files and hooks to each project. These are soft controls — they guide but cannot enforce.
Role: Reduce violations at the point of generation. Complemented by review skills that provide structured assessment.
Layer 2: Agent Hooks¶
Hooks execute automatically during AI agent operation. Two trigger points:
- PostToolUse — runs after the agent writes/edits a file (auto-formatting)
- Stop — runs when the agent completes a task (validation gate)
Multi-agent support: Each hook script detects the active agent (Claude Code, Copilot CLI, Cursor, Kiro CLI, VS Code, Antigravity) from stdin JSON and responds in the expected format. Hook JSON definitions are packaged per-target (common-hooks-claude, common-hooks-copilot, common-hooks-cursor).
Layer 3: pre-commit¶
pre-commit hooks run at commit time. Two hook types are installed:
- pre-commit — runs on staged files before commit
- commit-msg — validates commit message format
Common pre-commit hooks¶
| Category | Hooks |
|---|---|
| General | check-added-large-files, check-merge-conflict, end-of-file-fixer, trailing-whitespace |
| Secrets | detect-secrets, detect-aws-credentials, detect-private-key, gitleaks |
| Shell | shellcheck, shfmt |
| GitHub Actions | actionlint, zizmor |
| Markdown | markdownlint-cli2 (--fix), markdown-link-check |
| JSON/YAML/TOML | check-json, check-yaml, check-toml, pretty-format-json |
commit-msg hooks¶
| Hook | Purpose |
|---|---|
| commitlint | Enforces Conventional Commits format (type(scope): subject) |
commitlint configuration (.commitlintrc.yaml):
- Extends
@commitlint/config-conventional - Allowed types:
build,chore,ci,docs,feat,fix,perf,refactor,revert,style,test - Header max length: 100 characters
- Subject must start lowercase
Layer 4: CI (GitHub Actions)¶
Reusable workflows enforce standards on push/PR regardless of local setup. See language-specific documents for workflow details.
| Workflow | Language |
|---|---|
ci-go.yaml |
Go |
ci-aws-terraform.yaml |
Terraform |
ci-github-actions-workflow.yaml |
Common |
ci-markdown.yaml |
Common |
ci-shell-script.yaml |
Common |
Layer 5: Renovate¶
Shared Renovate presets automate dependency governance.
| Policy | Effect |
|---|---|
| Patch automerge | Go modules, npm, aqua, mise patches merge automatically |
| Minimum release age | 7 days before adoption (supply-chain risk reduction) |
| Tool version grouping | golangci-lint, terraform, tflint, trivy updates are grouped across mise + CI inputs |
| Vulnerability alerts | OSV alerts with security label |
Layer 6: Setup Automation¶
env/common/scripts/init.sh runs in devcontainer postCreateCommand and ensures all enforcement layers are active:
| Step | Effect |
|---|---|
mise trust + install |
Installs pinned tool versions (Go, Terraform, linters, etc.) |
apm install --frozen |
Deploys instructions, hooks, skills, MCP servers |
pre-commit install |
Activates pre-commit hooks |
pre-commit install --hook-type commit-msg |
Activates commitlint |
Result: A developer who opens the devcontainer has all enforcement layers active without any manual setup.
Design Decisions¶
| Decision | Rationale |
|---|---|
| gitleaks in Agent hooks despite pre-commit coverage | Provides immediate feedback during AI-assisted development before commit time. |
| commitlint via pre-commit only (no Agent hook) | Commit timing is identical; adding an Agent hook provides no additional coverage. |
| Shared lint configs in repository (not APM) | APM distributes agent-related files only. .golangci.yaml, .tflint.hcl, trivy.yaml are distributed via install_go.sh / install_terraform.sh. |
Known Gaps and Future Direction¶
Lint config drift across repositories¶
APM distributes agent instructions and hooks but cannot distribute lint config files (.golangci.yaml, .tflint.hcl, trivy.yaml) because they are not agent-specific. These files are distributed via install scripts (install_go.sh, install_terraform.sh) that consumer projects run to bootstrap shared configs.
Current mitigation: Install scripts copy configs on first setup; Renovate presets group tool version updates so all projects receive version bumps together. However, rule configuration changes (e.g., enabling a new linter) require re-running the install script or manual propagation.
Planned approach: Adopt a repository-files-sync GitHub Action to push config changes from this distribution source to consumer repositories via automated PRs. This preserves project autonomy (PRs can be reviewed) while preventing silent drift.
Tool version single source of truth¶
All layers (Agent Hooks, pre-commit, CI) resolve tool binaries from the same source: mise.toml pins versions, mise install provisions them in the devcontainer, and all hooks execute within that environment. AI agents running inside the devcontainer use the same PATH-resolved binaries. CI workflows pin versions via mise.toml or explicit action inputs that Renovate keeps in sync. No separate tool registry exists for agent environments.
Escape hatch governance¶
This document defines enforcement architecture, not operational policy. Bypass mechanisms (--no-verify, nolint directives, [skip ci]) are governed by the team's code review process: PRs that bypass enforcement layers require explicit reviewer approval, and CI logs record which checks were skipped. Detailed audit trail requirements are out of scope for this architecture document.
Pending Items¶
| Item | Status | Rationale for deferral |
|---|---|---|
| Lint config sync (repository-files-sync) | Pending | Install scripts handle bootstrap; automated ongoing sync not yet implemented |
apm audit --ci in consumer CI |
Deferred | MCP distribution causes persistent drift; tool not stable enough |