Skip to content

feat: close the AGENTS.md and CI hardening gaps #125

Description

@maehr

Motivation

The maintainer keeps a canonical AGENTS.md specification in this gist. A review of this repository against that specification found nine gaps.

This issue keeps the four gaps that carry a real failure mode. It moves two gaps to optional work. It drops three gaps and gives the reason for each.

Verified state

Checked on 2026-09-02 against the live repository.

Fact Command Result
CLAUDE.md is untracked git ls-files CLAUDE.md prints nothing
staging has no protection gh api repos/textrefs/textrefs.org/branches/staging/protection 404
staging has no ruleset gh api repos/textrefs/textrefs.org/rules/branches/staging []
main carries a legacy layer and a ruleset gh api repos/textrefs/textrefs.org/branches/main/protection both exist, and they disagree
The ruleset requires two checks gh api repos/textrefs/textrefs.org/rulesets/17092029 data and linkcheck
Every action floats on a tag grep -rn "uses:" .github/workflows/ 13 lines, no commit SHA
check:links is undocumented grep -n "check:links" AGENTS.md prints nothing

Required work

Track A: agent instruction files (target staging)

A1. Track CLAUDE.md. The file holds the single line @AGENTS.md. .gitignore does not list it. Claude Code reads CLAUDE.md and ignores AGENTS.md. A fresh clone therefore loads no agent instructions. Commit the file.

A2. Add the same bridge to textrefs/registry. That repository holds data/AGENTS.md and no CLAUDE.md. Open a matching issue there.

A3. Add a GitHub-workflow section to AGENTS.md. An agent reads AGENTS.md first, and AGENTS.md never names staging, the fork, the squash merge, or the signed commit. Keep the new section to five rules:

  1. Sign every commit. Ruleset 17092029 sets required_signatures.
  2. Branch from staging for content, documentation, and copy.
  3. Branch from main for CI, build tooling, and release work.
  4. Open every pull request from the maehr fork.
  5. Merge with a squash merge only.

Then link CONTRIBUTING.md from the Pointers list. Also add npm run check:links to the Commands list.

Track B: repository settings (target main)

B1. Add a ruleset for staging. Require the data check and the linkcheck check. Add a deletion rule and a non_fast_forward rule.

Both workflows already run on a pull request into staging, so this change adds enforcement only. Dependabot version updates target staging. An unreviewed workflow bump can therefore land on staging today.

B2. Repair ruleset 17092029, then delete the legacy protection on main.

Caution: repair the ruleset before you delete the legacy layer. The legacy layer sets dismiss_stale_reviews: true. The ruleset sets dismiss_stale_reviews_on_push: false. The other order lets a stale approval survive a new push.

  1. Set dismiss_stale_reviews_on_push: true on ruleset 17092029.
  2. Add the CodeQL check to the required checks of the ruleset.
  3. Delete the legacy protection on main.

The ruleset covers every other rule that the legacy layer holds. The legacy layer reports a false policy, because it sets required_signatures: false, enforce_admins: false, and required_approving_review_count: 0. GitHub applies the union of both layers, so the ruleset governs today. The legacy layer is dead weight, and it misleads anyone who reads it.

Optional work

C1. Pin the three third-party actions to a commit SHA. The actions are lycheeverse/lychee-action, peter-evans/create-issue-from-file, and softprops/action-gh-release.

Keep the five actions/* entries on a major tag. GitHub owns them, so a commit SHA adds weekly Dependabot noise for a small gain.

C2. Add a dependency-review-action workflow. The action blocks a pull request that adds a vulnerable dependency. Add the check to ruleset 17092029 after the workflow runs one time.

Dropped work, with reasons

Do not enable delete_branch_on_merge.

Caution: keep the flag false while staging has no deletion rule. GitHub deletes the head branch of a merged pull request, and it exempts a protected branch only. The publish pull request uses staging as the head branch. The flag therefore deletes staging at the next release. Revisit the flag after B1 lands.

Do not copy section 1 of the specification into AGENTS.md. The model tier, the parallel limits, and the context ladder describe an agent harness, not this repository. That content belongs in the private global instructions. AGENTS.md holds what only this repository knows.

Do not add the toolchain departure table. The Commands section already names npm, Prettier, Husky, and commitlint. A table that compares this repository to a private specification helps no contributor. npm run check:links is the one real omission, and A3 adds it.

Do not change the permissions in links.yml, and do not change CODEOWNERS. links.yml has one job, so a top-level issues: write scope has the same effect as a job-level scope. Code-owner review stays advisory on a repository with one owner, and that owner holds a pull_request bypass.

Acceptance criteria

  • git ls-files CLAUDE.md prints CLAUDE.md.
  • An issue for the data/CLAUDE.md bridge exists on textrefs/registry.
  • AGENTS.md states the five workflow rules and documents npm run check:links.
  • gh api repos/textrefs/textrefs.org/rules/branches/staging returns the data check and the linkcheck check.
  • Ruleset 17092029 sets dismiss_stale_reviews_on_push: true and requires the CodeQL check.
  • gh api repos/textrefs/textrefs.org/branches/main/protection returns 404, and ruleset 17092029 stays active.
  • delete_branch_on_merge stays false until staging has a deletion rule.

Optional:

  • The three third-party actions name a 40-character commit SHA.
  • A dependency-review-action workflow runs on a pull request.

Activity

  1. added
    documentationImprovements or additions to documentation
    enhancementNew feature or request
    github_actionsPull requests that update GitHub Actions code
    triageNeeds maintainer triage
    post-v0.1.0Deferred past the v0.1.0 baseline. Revisit if the need arises.
    and removed
    triageNeeds maintainer triage
    post-v0.1.0Deferred past the v0.1.0 baseline. Revisit if the need arises.
    on Sep 1, 2026
  2. maehr commented on Sep 2, 2026

    @maehr
    MemberAuthor

    Both tracks are implemented. Track B is live, because a repository setting needs no pull request. Track A waits for review in #141.

    Track A

    Track B

    B2, step 1. Ruleset 17092029 now sets dismiss_stale_reviews_on_push: true. Every other rule, the conditions, and the bypass actor are unchanged.

    B2, step 2. The ruleset now requires the CodeQL check. The name is CodeQL, which is the aggregate check that the default setup posts. Do not require Analyze (javascript-typescript), because that name changes with the analysed language.

    B2, step 3. The legacy protection on main is deleted. gh api repos/textrefs/textrefs.org/branches/main/protection returns 404, and ruleset 17092029 stays active.

    B1. Ruleset 22142888 protects staging. It holds a deletion rule, a non_fast_forward rule, and the data and linkcheck required checks.

    Two choices in B1 depart from the main ruleset. Both are recorded here for review.

    1. The bypass mode is always, not pull_request. A required check blocks a direct push to a branch, and no workflow runs on a push to staging. The always mode therefore keeps the direct push open for the maintainer. Change the mode to pull_request to close it.
    2. strict_required_status_checks_policy is false. A true value forces a rebase of every grouped Dependabot pull request whenever staging moves.

    Finding: CodeQL does not analyse a pull request into staging

    The default setup analyses a pull request that targets the default branch only. Every analysis on a pull request reference belongs to #4, which is the standing staging to main pull request.

    gh api "repos/textrefs/textrefs.org/code-scanning/analyses?per_page=30" --jq '.[].ref' | sort -u
    # refs/heads/main
    # refs/pull/4/head

    A CodeQL alert therefore reaches a human at the release pull request, not at the content pull request. The main ruleset now blocks that release until the check passes, so nothing ships unanalysed. Adding the check to the staging ruleset would block every merge, because the check never reports there.

    State of the acceptance criteria

    Optional work stays open: C1 pins the three third-party actions, and C2 adds the dependency-review-action workflow.

    Caution: staging now has a deletion rule, so delete_branch_on_merge is safe to enable. Enable the flag only after you confirm that the rule protects staging.

    🤖 Generated with Claude Code

    https://claude.ai/code/session_01NtQMT2WCNxEAEbEbdhVmuX

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    documentationImprovements or additions to documentationenhancementNew feature or requestgithub_actionsPull requests that update GitHub Actions code

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions