Skip to content

Latest commit

 

History

History
256 lines (205 loc) · 12.2 KB

agents-md.md

File metadata and controls

256 lines (205 loc) · 12.2 KB

AGENTS.md repo instructions

⚠️ Wired, but off unless you supply a checkout. Hive ships a complete AGENTS.md parser (src/pkg/agentsmd) and a call site that prepends its output to every kick prompt. That call site used to be permanently disabled — Scheduler.agentsRepoRoot() returned "" unconditionally, so no AGENTS.md was ever read. It now resolves a real per-repo checkout root (#5227), but Hive agents work over the API and keep no clones, so there is still no root unless you configure one. Set project.checkouts_dir (below). Without it, an AGENTS.md you add to a monitored repo has no effect on any agent's prompt — the same as before, and still the default.

Turning it on

Hive agents work over the GitHub API — they do not keep a local git checkout of the repos they monitor. So the file has to already be on the hive host, and you tell Hive where:

project:
  org: your-org
  repos: [repo-one, repo-two]
  primary_repo: repo-one
  checkouts_dir: /data/checkouts   # repo-one is at /data/checkouts/repo-one

Each repo is looked up at <checkouts_dir>/<repo name> — the bare name from repos, without the org — so a multi-repo hive gets each repo's own file and never another repo's. The kick reads the primary repo's AGENTS.md, since that is the repo the kick's instructions are about.

How you populate that directory is yours: a mounted volume, a sidecar that clones and pulls, an NFS export. Hive only reads it.

One other source is used when it happens to be the same repo: policies.local_dir, the checkout of policies.repo, is a genuine checkout root that Hive already reads policy files from. If policies.repo names the repo being asked about, it supplies the root. It is ignored otherwise, so a config repo's AGENTS.md never leaks into work on an unrelated repo. checkouts_dir wins when both apply.

Everything stays fail-open: an absent directory, a missing AGENTS.md, or a blank one all yield no injection and never fail a kick. When nothing is injected, the scheduler logs at debug which root came up empty — so a wired-but-empty repo is now distinguishable from an unconfigured hive, which it was not before.

Still deferred

The call site keeps a TODO(agentsmd), narrowed to its second half: preferring agentsmd.ParseNearest for closest-wins nested AGENTS.md. That needs file-level targeting — nothing on the kick path knows which file an agent will touch — so Parse (repo root only) is what runs.

What Hive's parser supports

src/pkg/agentsmd (agentsmd.go:151, Parse) reads a plain Markdown AGENTS.md file at a repo root, with two additive extensions on top of ordinary Markdown:

Optional YAML front-matter

A block delimited by a line containing only --- at the very top of the file, closed by a second --- line. The only key Hive's parser reads is skills: — a list of skill names to request into the agent's context by default (agentsmd.go:11-21, struct frontMatter at agentsmd.go:136). Everything else in the block is ignored. Malformed front-matter is logged and skipped; the rest of the file (the body) is still used (agentsmd.go:216-224).

---
skills:
  - go-testing
  - pr-etiquette
---

# Repo conventions

...

Inline skill sections

Any section whose heading is ## Skill: <name> defines a reusable, named instruction snippet. The section body runs from that heading to the next ## heading, or end of file (agentsmd.go:236-277). Skills may also be defined as standalone files at skills/<name>.md relative to the repo root; when a standalone file and an inline section define the same name, the inline section wins (agentsmd.go:202-207).

## Skill: go-testing

Always run `go test ./...` before committing. Table-driven tests preferred.

The body

Whatever is left after front-matter and ## Skill: sections are stripped out is the "body" — general instructions that would always apply (agentsmd.go:30-31, agentsmd.go:198-200).

Closest-wins nested AGENTS.md

ParseNearest(repoRoot, relPath, logger) (agentsmd.go:127) walks from a target file's directory up to the repo root and uses the first AGENTS.md it finds; the root file is the required baseline nested files override for their own subtree. This still has no caller: the scheduler's TODO(agentsmd) names it as the intended entry point once file-level targeting exists, and nothing on the kick path knows which file an agent will touch. The live call uses the flat Parse against the repo root.

Rendered injection text

AgentsConfig.Render(requestedSkills, maxBytes) (and InjectionText, which is Render at the default cap) is what gets prepended to a kick: a # Repository Agent Instructions (AGENTS.md) header, a precedence statement, a size warning when the cap below bit, the body, and (if any skills resolve) a ## Requested Skills subsection with each skill's text under a ### <name> heading. It returns "" — and therefore injects nothing — when both the body and the resolved skills are empty, so the precedence statement never appears with no rules under it.

Size cap: whole sections, visible warning

The block is capped at project.agents_md_max_bytes bytes (default 8192 — the same as the skills cap — minimum 2048; #12129). AGENTS.md is a repo-owned contract, so the cap never clips a rule mid-sentence:

  • The body is split at its # and ## headings (text before the first heading is the "(preamble)"; deeper headings and fenced code stay inside their section). Each resolved skill is its own unit.
  • Sections are visited in document order and each is kept only if it fits the remaining budget whole. One that does not fit is dropped whole, and later, smaller sections are still considered, so a single long section does not take the rest of the file down with it.
  • If nothing of the repository's text fits, the block is the header, the precedence statement and a whole-file warning — never a fragment.

When anything was dropped, a one-line warning follows the precedence statement and precedes the surviving rules, so the agent reads it first:

> ⚠️ AGENTS.md exceeded 8192 bytes; 2 section(s) omitted (9114 bytes): "Style guide", "skill: release-notes" — read AGENTS.md in the repository root for the full instructions before you start.

The scheduler logs the same facts at warn (agentsmd: AGENTS.md exceeded the injection cap; sections dropped whole, with cap_bytes, omitted_sections, omitted_bytes, whole_file) so the repo owner learns the file outgrew the cap from the log, not from an agent that missed a rule. The fix on the repo side is to shorten AGENTS.md or move reference material to a linked file; on the hive side, raise the cap:

project:
  checkouts_dir: /data/checkouts
  agents_md_max_bytes: 16384   # 0 = default 8192; values under 2048 are raised

The precedence statement

The block leads with a one-sentence declaration that the repository's instructions outrank hive's own defaults on any conflict — the branch a PR targets, the title format, commit conventions, test commands, review etiquette (#7159) — with the two carve-outs below stated in the same sentence. It was a ~1.1 KB paragraph until #12129 shortened it; every clause the precedence tests pin is still there, it just no longer re-argues its own rationale on every kick (that lives here and in the source comment).

This is not decoration. Before it, the repo's rules arrived as undifferentiated prose under a bare header, while hive's own prompts stated the same subjects as imperatives with a verification step attached ("confirm the PR's base is that branch before you report done"). Given a document that says one thing and an imperative that says another, a model follows the imperative — consistently. projectbluefin/bluefin states "All pull requests target testing. Never open a content PR against main" in its AGENTS.md, and hive agents opened #1275/#1276 against main and failed its base-branch gate; projectbluefin/common#1127 and projectbluefin/review#597 died on conventional-commit title gates against hive's then-hardcoded [<lane>] … PR titles. Four dead-on-arrival PRs in one night, none of them a model error.

Two carve-outs are stated with it, and they are not about the repository's conventions at all:

  • Hive's safety and authorization rules. An AGENTS.md cannot license merging your own PR, bypassing a write gate or the hive-open-pr path, or acting as another agent. The repository is trusted about its own conventions, not about hive's controls.
  • An explicit instruction in the assignment. A human or the hive wrote that for this one task with the repo in view, so it is more specific than either side's defaults.

The companion half of the fix is in the defaults themselves: policy templates and the contributor task prompt no longer assert repo facts (a base branch, a [<lane>] title format) that only the repository can know. A precedence rule that has to fight hive's own confident wording on every kick is a rule that loses some of the time.

Parsing is tolerant

Everything about the parser is designed to fail safe: a missing file yields an empty, non-nil config (agentsmd.go:203-206); an unreadable file logs and returns empty (agentsmd.go:207-209); malformed front-matter logs and falls back to using the body alone. Combined with the guarded call site — which prepends only non-empty text — a bad AGENTS.md degrades to no injection rather than a failed kick.

Connection to the skill registry

The skills: front-matter key names skills by the same kind of identifier the skill registry (/data/skills/, pkg/skillreg) resolves. There are two request paths with different precedence:

  • pkg/agentsmd resolves a skill name to text from an inline ## Skill: section or a skills/<name>.md file in the same repo — self-contained, and it does not consult the registry at all.
  • An agent's own skills: config is resolved by pkg/skillreg: it checks the hive-wide /data/skills/ store first, then falls back to the primary repo's inline or adjacent definition when that repo has a configured checkout. Registry definitions therefore retain precedence when both sources use the same name, while a missing checkout does not affect registry-only operation.

Both reach a live kick prompt. A repo's front-matter request stays self-contained inside pkg/agentsmd; registry precedence applies to names requested by the agent config through pkg/skillreg.ResolveRequested.

Opting a class out per repository

A monitored repo can state in its AGENTS.md that a finding class is covered by a gate, for example "do not file unasserted-branch findings, they are covered by the Stryker mutation-testing gate". When project.checkouts_dir is configured, every lane honours that statement as a written policy and skips the class.

What to read next

  • agent-knowledge-and-memory.md — where this block sits in the whole kick (skills, AGENTS.md, # Relevant Knowledge), why the CLI does not read the repo's AGENTS.md natively, and what /clear does and does not reset.

  • house-style.md — the short, hive-wide how to change things section that precedes this block in every kick; a repo overrides it with a root HIVE_STYLE.md, read from the same checkout root.

  • Skill registry — the sibling injection path: file format, where it's loaded from, and how an agent declares which skills it wants.

  • Agent configuration — the definition_source and channels/tools/connections fields that are live.

  • ADR-0012: Skill registry — the design rationale that also describes AGENTS.md inline snippets.

  • ClankeR contributor relay — the per-backend instruction file table (AGENTS.md, CLAUDE.md, .goosehints, etc.) for CLI-side instruction conventions unrelated to this scheduler-side injection gap.