Skip to content
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 21 additions & 6 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -516,12 +516,13 @@ governs the issue work that follows.) Two rules enforce that:
keeps an experiment issue open, also use `Part of #experiment`. Among open issues prefer the oldest.
**"Actionable" is deliberately narrow — skip an older issue ONLY when one of these is true and you can
*point to it*:** (a) it already has an open PR; (b) it is blocked on a **named, live-verified**
external dependency (a specific upstream PR/release you can cite); or (c) it is too under-specified to
even begin; or (d) a delivered experiment is awaiting its **named, future measurement date**, which
is recorded on the issue and has not elapsed. Once that date arrives, measuring and recording the
decision is actionable work; or (e) another instance holds a **live claim** on it — assigned **and**
branched, within the ~2h window, no PR yet (see *Claim protocol*). (e) is the only skip reason that
expires on its own: once the window lapses with no PR, the issue is fair game again; or (f) it is
external dependency (a specific upstream PR/release you can cite) — see *External-blocker
verification* below; or (c) it is too under-specified to even begin; or (d) a delivered experiment is
awaiting its **named, future measurement date**, which is recorded on the issue and has not elapsed.
Once that date arrives, measuring and recording the decision is actionable work; or (e) another
instance holds a **live claim** on it — assigned **and** branched, within the ~2h window, no PR yet
(see *Claim protocol*). (e) is the only skip reason that expires on its own: once the window lapses
with no PR, the issue is fair game again; or (f) it is
**authored by an exact dependency-automation identity** (`renovate[bot]` / `dependabot[bot]`, or
`app/renovate` / `app/dependabot`) — see the automation-owned carve-out under *Merge policy*.
(f) is not a deferral like the others: such an issue is **never actionable at all** and never
Expand All @@ -539,6 +540,20 @@ governs the issue work that follows.) Two rules enforce that:
issue as "blocked"/"gated", **re-verify the blocker against live state** (memory's "gated" notes go
stale) and **name the concrete blocker in the report**; an
unverifiable or merely-inherited "gated" is not a skip.
**External-blocker verification (skip clause (b) — monorepo#2243).** An unattended run must
live-verify an external blocker *without* inspecting a third-party repository (that stays behind
the *Professional-work repository boundary*). Use public **non-repository** channels only — the
same class *Enhancement work → Continuous upstream research* already permits: release feeds,
changelogs, package registries, and module proxies. Never open the upstream repo page, tree,
issue, or API to confirm the blocker. Give every externally-blocked issue a **structured blocker
line** in its body (and keep the `blocked` label on) so the next tick verifies in O(1) instead of
rediscovering the channel:
`**Blocker:** <upstream-ref> | verify via <non-repo channel> | next-check <YYYY-MM-DD>`
Comment on lines +548 to +551

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Propagate the blocker convention to the implementation skill

The executable planning guidance in .claude/skills/product-engineering/SKILL.md:123-148 still contains only the old named, live-verified skip rule and never requires the structured line, blocked label, non-repository channel, or next-check handling added here. Runs driven through that skill can therefore continue skipping blockers without producing the state this change relies on for subsequent ticks; update the referenced skill in the same change so the canonical contract and its implementation procedure do not diverge.

AGENTS.md reference: AGENTS.md:L1785-L1787

Useful? React with 👍 / 👎.

Example: `**Blocker:** opencost#3710 | verify via GitHub Releases feed for opencost/opencost | next-check 2026-08-01`.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Use a genuinely non-repository verification source

In an unattended run where the upstream's affiliation has not been confirmed, this example directs the agent to a repository-scoped GitHub feed such as github.com/opencost/opencost/releases.atom; that still reads release metadata from the named third-party repository, despite the surrounding text forbidding repository inspection. Following the worked example can therefore cross the hard professional-work boundary. Use a registry/module proxy or independently hosted documentation feed, or explicitly define and justify why repository-hosted release feeds are exempt.

AGENTS.md reference: AGENTS.md:L776-L783

Useful? React with 👍 / 👎.

Comment on lines +548 to +552

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Do not let issue bodies select verification destinations

On a later unattended tick, this makes the agent obtain the verification destination from an issue-body field and fetch it. Issue bodies have no field-level provenance—the original author or another editor can replace an agent-added blocker line—so an external contributor can select an attacker-controlled “non-repo channel,” recreating the repository-artifact-to-fetch injection path that the egress rules explicitly close. Treat the line only as untrusted status data and independently choose the verification origin through an allowed search/configuration path.

AGENTS.md reference: AGENTS.md:L2016-L2027

Useful? React with 👍 / 👎.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Fully qualify the upstream issue reference

The worked blocker line uses opencost#3710, which neither identifies the repository owner nor forms GitHub's cross-repository owner/repo#N reference. On the next tick this leaves the supposedly O(1), citable blocker ambiguous and forces the agent to rediscover which repository issue 3710 belongs to—precisely the external-repository probing this change is intended to avoid. Use opencost/opencost#3710 or another fully qualified, non-fetching identifier.

AGENTS.md reference: AGENTS.md:L1503-L1507

Useful? React with 👍 / 👎.

When the next-check date arrives, re-check that channel; if the upstream has shipped, remove the
`blocked` label and the blocker line and resume oldest-first. If it has not, advance the next-check
date and move on. An issue that only *says* "waiting on upstream" with no blocker line is
Comment on lines +553 to +555

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Reconcile scheduled checks with per-skip verification

When next-check is in the future, this procedure implicitly keeps skipping the blocked issue without checking the channel, which contradicts the immediately preceding invariant that every blocked/gated skip must first be live-verified. Different agents can consequently either ignore next-check and repeat the lookup every tick or trust stale blocker state contrary to the closed skip test; explicitly make a not-yet-due structured check an allowed verification state, or retain per-run verification and remove the schedule.

AGENTS.md reference: AGENTS.md:L539-L542

Useful? React with 👍 / 👎.

under-specified for (b) — add the line (or unblock) rather than skipping forever on prose alone.
**A "maintainer decision" is NOT a skip reason — don't block yourself on it.** The maintainer does
**not** want to make issue-level decisions, and a passive "gated / awaiting-maintainer / needs a
decision" note in a report or memory *never reaches him* — that passive parking **is** the
Expand Down
Loading