Skip to content

Latest commit

 

History

History
357 lines (306 loc) · 20 KB

AGENTS.md

File metadata and controls

357 lines (306 loc) · 20 KB

AGENTS.md

Repo shape

This is a Harn-only operations repo. There is no Python or shell glue in the harnesses themselves.

The entry points are:

  • check_prless_branches.harn: reads the complete remote branch inventory and publishes a workflow summary and JSON receipt. It has no issue-write or branch-mutation authority. A missing PR does not establish abandonment; cleanup tasks must name a bounded batch and its disposition.
  • bump_fleet.harn: finds local ~/projects/{*harn*,*burin*} repos with .github/workflows/bump-harn.yml, dispatches Harn runtime bump workflows, polls them, and enables auto-merge on the resulting PRs.
  • release_harn.harn: delegates live ship-pr --yes-live-release to Harn's no-input workflow opener on main and records its typed handoff. Local live preparation refuses; historical preparation remains an offline mock rehearsal.
  • watch_harn_release.harn: reads the recorded handoff, an explicitly selected release PR, and its exact merge-group producer attempt. It verifies the public tag target and seven public files against the certificate. Missing evidence stays named pending. The live watcher has no tag, merge, dispatch, or recovery capability.
  • sweep_release_refs.harn: inventories historical local and remote release refs. It is dry-run-first and applies only exact, tag-backed deletions.
  • abandon_release_attempts.harn: frees a version wedged by leftover release-attempt/vX.Y.Z/ refs by renaming each unclaimed attempt into release-failed/vX.Y.Z/<oid>-abandoned. Dry-run-first, and it refuses when a tag, a published release, or an open PR still claims an attempt. Both modes hold the release-owner lease and refuse while a live release owns it.
  • harness_self_review.harn: a local meta-audit over recent .harn-runs/ artifacts. It is not CI and should stay out of the main release/bump path.
  • sync_agent_guidance.harn: checks or applies the manifest-owned shared agent contract and CLAUDE.md projection without replacing local rules.
  • sync_package_ci.harn: checks or applies package CI for repositories that delegate ownership in fleet.toml. package_ci_ownership = "fleet" owns the whole ci.yml. "pin" owns only the canonical package job's uses: line. Use "pin" for a repository whose CI is a superset of that job, and whose other jobs are its own.
  • sync_bump_workflows.harn: checks or applies exact runtime-bump adapters for every repository that delegates bump workflow ownership in fleet.toml.
  • sync_connector_secrets.harn: checks or applies the manifest-owned [providers.setup].required_secrets projection for every first-party connector. policy.connector_secret_schema keeps the output compatible with the released Harn manifest schema until the fleet can move as one.
  • promote-released-orchestration.yml: started by a Harn release's repin job. It promotes fleet.toml's orchestration pin to the released commit with promote_bump_workflow.harn --repositories-json '["burin-labs/harn-bump-fleet"]'. Convergence and each consumer adapter's push-triggered bump do the rest, so a release never dispatches consumer bumps through an older orchestration contract. When that bump ends without a pull request, check_fleet_pin_staleness.harn dispatches the next one when its pin is behind and no bump run or pull request is open, at most once per release.
  • converge_fleet_projections.harn: the remote counterpart to the sync_* harnesses. It reads every fleet-owned projection from its target's default branch and proposes the repair as a pull request, so drift converges without a machine holding all twenty-six checkouts. Pin-only package CI is derived from current default-branch bytes and preserves repository-owned jobs. Dry-run first; --apply writes. --apply also arms auto-merge, leased to the commit it published, so each repair lands once that repository's own checks pass. --no-auto-merge holds arming; it never merges anything itself.
  • check_projection_source_drift.harn: the trigger half of the same repair. A projection has two inputs, the renderer here and the canonical source file in another repository, and only the renderer had an event. This compares each declared source's current head against the head it last converged from and dispatches convergence for the consumers of the sources that moved. A head it cannot resolve, a source with no record, and a source recorded twice all read as unknown and converge; none of them may read as unchanged. Records live in refs/heads/projection-source-converged/, one per source, read in a single git ls-remote. This harness writes none of them: converge_fleet_projections.harn records a source once every consumer that projects it reports clean, because only that run knows whether the bytes are in place. A proposed repair is not a converged one, so a run that opened a pull request records nothing and the comparison asks again.

Shared code belongs in lib/*.harn. Every shared module should have focused coverage in tests/*.harn.

release_harn.harn is the thin orchestration entrypoint and public facade. Release implementation changes belong in the stage that owns the behavior:

  • release_runtime: CLI/config, harness paths, typed git/GitHub adapters, mock commands, run events, and timing
  • release_analysis: release facts, commit/PR evidence, and deterministic analysis prompts
  • release_agent_tools / release_agent: agent tool boundaries, review, validation, artifacts, and recovery
  • release_prepare / release_checkout: prepare-audit reuse, cutoff/tag reconciliation, branch setup, and checkout state
  • release_note_fold / release_notes: candidate-tree folding, release notes, and fixup/drift state
  • release_reporting: PR rendering and execution summaries
  • release_crystallization: deterministic, agent, and tool fixture streams plus their manifest and artifact writer
  • release_modes: prepare execution, thin ship-phase composition, and cleanup
  • release_ship_prepare: prepared commit and immutable attempt publication
  • release_ship_certify: cutoff and exact-candidate certification gates
  • release_ship_pr: canonical workflow opener and typed handoff; mock PR publication
  • release_watch_handoff: immutable PR, merged-source, and producer-attempt identities
  • release_archive_observation: certificate identity and measured public-file digests
  • release_watch_runtime: read-only canonical publication observation and mock control flow
  • release_candidate_tag: certified-candidate tagging and write-once receipt binding
  • release_main_tag: historical merged-main recovery and bump reversal
  • release_main_drift: the drift reading those recoveries decide on, and the union of ruleset-required and repository-declared release contexts
  • release_preflight: interactive flags, planner/fleet/sccache checks, and build-lock lifecycle

Do not put stage policy back in the entrypoint or add a second implementation behind a compatibility helper. check_source_length.harn enforces a 1,500-line ceiling for every maintained handwritten source file.

check_regex_captures_coverage.harn parses every tracked module, finds every regex_captures call site, and refuses one that no test pipeline reaches. regex_captures returns match objects rather than capture strings, and a caller that misreads that shape behaves exactly like a no-match, which neither the type checker nor a test that stubs the function can catch. Cover a new call site by putting it in a function a test calls, or record it by name with a reason in regex-captures-coverage-baseline.json; the baseline is exact in both directions, so a site it lists that is now covered is also a failure.

Every pull request this repository opens gets its title from lib/pr_title_convention.harn, never from a literal at the call site. burin-labs/harn runs a required title gate that refuses a subject without a leading [Area] from its own area list, and a bot pull request is not exempt. check_pr_title_convention.harn refuses a registered title that gate would reject, and refuses a pull-request call site the module does not name, so a new opener cannot ship an unowned title.

Commands

Use the pinned Harn version from .harn-version.

scripts/install_harn.sh
.harn/bin/harn install --locked
scripts/harn-project.sh verify
scripts/harn-project.sh test
.harn/bin/harn test tests-risky/release_ref_cleanup_git_push.harn --approve-risky git.push --verbose

scripts/harn-project.sh verify includes tracked and non-ignored untracked Harn sources with filename-safe argument handling. Use scripts/harn-project.sh format for formatting fixes. CI passes --tracked-only to verify the exact committed tree.

Common harness runs:

scripts/with_env.sh harn run --no-sandbox bump_fleet.harn -- --dry-run
scripts/with_env.sh harn run --no-sandbox bump_fleet.harn -- --only burin-labs/harn-cloud
scripts/with_env.sh harn run --no-sandbox release_harn.harn
scripts/with_env.sh harn run --no-sandbox release_harn.harn -- --mock --agent --mode ship-pr
scripts/with_env.sh harn run --no-sandbox release_harn.harn -- --mode ship-pr --yes-live-release
scripts/watch_harn_release.sh --receipt PATH --release-pr NUMBER --producer-run RUN_ID
scripts/with_env.sh harn run --no-sandbox sync_agent_guidance.harn -- --check
scripts/with_env.sh harn run --no-sandbox sync_package_ci.harn -- --check
scripts/with_env.sh harn run --no-sandbox sync_bump_workflows.harn -- --check
scripts/with_env.sh harn run --no-sandbox sync_connector_secrets.harn -- --check
scripts/with_env.sh harn run --no-sandbox converge_fleet_projections.harn -- --check

Harn does not auto-load .env; use scripts/with_env.sh when provider keys are needed. On macOS, wrap long local runs with scripts/harn_shielded.sh if another session may replace the harn binary while the process is running. Watch runs use scripts/watch_harn_release.sh. The live launcher retains Harn's worktree sandbox and grants its receipt/cache locations, shared leases, the minimal GitHub login environment, and the explicit artifact/public-file egress profile. It needs no local Harn checkout, signing roots, or git.push grant. Other fleet operations still need --no-sandbox until they have an equivalent typed root inventory.

Run scripts/install_harn.sh after a .harn-version repin. By default it installs the pinned CLI into this repo's ignored .harn/bin. scripts/with_env.sh and scripts/harn_shielded.sh prefer that binary over a stale global harn on PATH.

Use the release/watch launchers for their entrypoints and scripts/with_env.sh harn ... for other documented harness invocations. They install and select the repo-pinned runtime before Harn parses the program and load the provider environment without putting secrets on the command line. Direct ambient harn invocations are not a supported release path. Harn's workflows own live preparation, certification, and promotion. Run only one live release watcher; the watcher host lease refuses a second local receipt writer. Always start that watcher through scripts/watch_harn_release.sh; it selects and shields the repo-pinned runtime and gives the observer no release-mutation authority.

Implementation rules

Keep GitHub side effects deterministic. Production GitHub reads and writes go through typed connector contracts, and every head-sensitive mutation carries the observed PR-head lease. gh is limited to read-only diagnostic agent allowlists and explicit manual-recovery instructions. Model output may summarize, audit, or draft text. Deterministic code must validate or parse that output before it affects files, PRs, tags, dispatches, or merge settings.

An out-of-band harness that rewrites shared release refs must serialize on the release-owner host lease, the same lane release_harn takes. Terminal evidence — a tag, a published release, an open PR — cannot substitute for it. A release that has not tagged yet has none of those. Its in-flight candidate is therefore indistinguishable from abandoned state. abandon_release_attempts.harn holds the lane in both modes for exactly this reason.

sweep_release_refs.harn does not need the lease. Every deletion it applies is gated on positive proof that a published tag recovers the exact OID, and an in-flight candidate can never satisfy that. Adding a new mutation path means deciding which of those two shapes it has, and saying so.

Route model defaults through lib/llm_defaults:

  • Use planner_defaults("HARN_<ROLE>") for new planner calls.
  • Use install_binder(tools) for every tool-using agent loop. It is a no-op when disabled.
  • Print planner_audit_line and binder_audit_line where a harness already reports model routing.

Prefer the Harn stdlib over local helpers:

  • std/cli::parse_args for argv parsing.
  • std/command for long-running side effects and reusable output artifacts.
  • std/git for checkout cleanup and base-branch sync.
  • std/poll, std/settled, std/jsonl, and std/config for polling, settled-result handling, JSONL, and env parsing.
  • std/agent/loop::agent_loop for each model turn. Fleet's lib/interactive_agent_chat.harn owns TTY input, slash commands, and presentation; do not rebuild an orchestration plane around it.

When adding a prompt or run artifact, keep deterministic facts separate from model-authored text. Generated artifacts under .harn-runs/ and .harn/ stay ignored and must not be committed.

Release policy

Harn's bump-release.yml on main owns version selection, preparation, and the release PR. Its merge-group build owns certification; the promoter publishes the same certified files. Fleet delegates to that owner and observes its result. Never restore the retired candidate-only dispatch or manually tag an old prepared candidate.

The watcher binds the selected PR, its actual merged source, and the successful build-release-binaries.yml merge-group run and attempt. A manifest must name that same repository, source, and producer. Public promotion requires the matching tag target and measured bytes for every file in the shared release catalog. Empty, partial, failed, or unreported evidence cannot verify it. Crate publication, the versioned container, the development bump, and downstream convergence remain separate named obligations before a release is finished.

Use the release procedure for this interface and Harn's owning maintainer runbook for workflow recovery. Keep receipts and immutable source custody on failure. Historical prepare, tag, recovery, and warm-cache controllers are mock rehearsal paths and refuse live invocation.

preflight_package_test_compatibility.harn runs package test discovery for every managed package under the candidate runtime before a cut, without mutating any repository. A package whose test files discover no tests is a named compatibility failure carrying the files and the migration, never a green count: that is the shape this gate exists for, because package verification used to pass while running nothing. A receipt that is absent, malformed, or missing its counts is recorded as unmeasured rather than as a pass, and a run whose inventory mutated the checkout fails outright. The fleet's pinned runtime in .harn-version must be a release whose harn package test-inventory can perform the inventory; an older pin makes every row unmeasured, which the gate reports rather than hides.

A consumer pre-tag gate retries a dispatch the network dropped. Transport failures and 5xx responses are sent again with bounded backoff, five sends over about two minutes, because a request that was dropped in transit may never have arrived and sending it again is the only way to find out. A refusal the remote actually answered is not retried: it is a fact about that request and repeating it only delays a real answer. Every send is recorded on the gate receipt, so a retry that ran can be told from one that did not, and an exhausted bound reports consumer_dispatch_unreachable naming the last error rather than a bare unreadable. Whether a failure is transient is decided by fleet_observation_class, which owns that question for every connector error here, so the two answers cannot drift apart.

Repo hygiene

This repo is public. Do not commit private repo details, customer data, secrets, local paths from private investigations, or inside-baseball notes from private Burin repositories.

Keep agent-facing docs short. Put durable reference material in README.md or code comments near the relevant logic. Avoid time-sensitive comments that compare against older implementations; explain the current invariant and why it exists.

Documentation should read plainly: no emoji, no title-case section headings, no marketing phrasing, no vague claims, and no filler endings. Use bullets only where they make scanning easier.

Before opening a PR, check the current integration base and review your diff for stale comments and duplicated abstractions. Update the branch when a conflict, dependency, or relevant intervening change requires it; rerun only affected verification and preserve evidence whose inputs are unchanged. Then push a branch, and enable auto-merge when required checks and review pass.

Pull requests

Title every pull request [Area] Sentence case description. Capitalize the first word of the description and proper nouns only, and leave the trailing period off.

Area is one of these, chosen from this repository's directory map:

Area Covers
Release release_*.harn, release_harn.harn, the watchers, and publication proof
Fleet fleet.toml membership and policy, dispatch, and repair
Bump Runtime bump orchestration, .harn-version pins, and bump adapters
Projections Fleet-owned file projections, drift checks, and convergence
CI This repository's own workflows and required checks
Scripts Launchers and wrappers under scripts/
Docs README.md, AGENTS.md, CONTRIBUTING.md, and docs/
Tests tests/ and tests-risky/ coverage

Pick the area that owns the behavior you changed, not the file you touched most. A change to lib/release_ship_pr.harn is [Release] even though it lives under lib/. If two areas fit, the pull request is probably two pull requests.

Keep the description to 3-5 sentences: what changed, why, the one risk, and how you verified it. Do not list test commands. .github/pull_request_template.md carries a worked example.

The same words are the area/* labels in .github/labels.yml, so a title and a label agree.

Use Closes #N only when the pull request lands every enumerated sub-ask in that issue. A partial resolution uses Partial: #N items: 1, 3 or Refs #N; adding an item suffix after Closes #N does not stop GitHub from closing the whole issue. Use Single-ask: #N only when the issue has no enumerated sub-asks and the pull request resolves it completely.

Ecosystem working agreement

  • Build ambitious outcomes behind small typed interfaces; give behavior one owner and generate or parity-test projections instead of duplicating policy.
  • Work autonomously within approved scope. Pause for destructive or production effects, exceptional spend, material ambiguity, or new authority.
  • Treat stop, wait, stand down, pivot, and steer as control events.
  • Use the smallest owning product-path check. Add a falsifier for contested, load-bearing, or potentially vacuous claims; record controls, recovery, and blind spots.
  • Evidence follows source/artifact identity. Reuse proof when relevant code, build inputs, and dependencies are unchanged. Repeat affected checks for relevant changes, failures, deployment, or packaging differences. Do not rebuild or recapture solely for main.
  • Ship means owning-main integration with terminal merge and applicable release/deploy checks. Confirm landed content and result; an open PR is incomplete.
  • Use ship where deployed; otherwise use protected PRs: queue when required, or squash with --match-head-commit after required reviews/checks. Never --admin or bypass protections.