Skip to content

Move PR, comment, commit and doc writing rules into skills (PROF-16542) - #959

Open
rkennke wants to merge 8 commits into
mainfrom
rkennke/PROF-16542-writing-skills
Open

rkennke wants to merge 8 commits into
mainfrom
rkennke/PROF-16542-writing-skills

Conversation

@rkennke

@rkennke rkennke commented Nov 9, 2026 •

Copy link
Copy Markdown
Contributor

What does this PR do?:

Moves the PR, comment, commit and documentation writing rules from AGENTS.md into two agent skills, and adds a CI check that keeps every skill loadable.

  • .agents/skills/pr-writing/: PR descriptions, PR and Jira comments, commit messages.
  • .agents/skills/doc-writing/: pages under doc/.
  • utils/check-skills.py, run by qualityChecks, fails on:
    • frontmatter outside a strict YAML subset: every line blank, a column-0 comment, or key: value with a one-line string value;
    • a missing name or description;
    • a name that differs from its directory;
    • a description over 1024 characters;
    • a broken .claude/skills symlink;
    • an AGENTS.md mention of a skill that does not exist.
  • AGENTS.md keeps a one-line pointer per moved section and shrinks from 586 to 544 lines.

Motivation:

AGENTS.md loads into every session. These rules apply only while an agent writes a PR, a comment, a commit message or a doc page, and they can be compacted away before then. A skill loads at that moment. This is step 2 of PROF-16466; the design is on PROF-16542.

The check exists because Pi silently skips a SKILL.md with malformed frontmatter or without a description. A broken skill would never load, and nothing would report it. A description such as Use when: ... is enough: Pi dropped that skill in a test.

The check accepts a strict YAML subset instead of parsing YAML, so CI needs no YAML library. It is stricter than YAML: no nested mappings, lists or multi-line values, and a few plain values must be quoted. The error names the fix.

Additional Notes:

  • Reviewer acknowledgment needed: the AGENTS.md header said writing rules for PRs, comments and commits stay inline. This PR changes it to "rules for writing code and code comments", because those rules now live in skills.
  • What stays inline:
    • the commit rules "logical chunks", "no scratch files" and "never commit design artifacts": they apply at every commit, whether or not a skill is loaded; pr-writing keeps only the commit-message rule;
    • the ban on citing plans, phases and review reports: it moves into the Comments bullet and now covers doc/ too.
  • Not in this PR: ticket-writing, work-planning, ci-script-change, verify-profiler-change and the pre-pr-review depth policy follow in later PRs of PROF-16542.
  • Pre-PR review: Sphinx (standard effort) on the first two commits found 0 Critical/High/Medium issues and 8 Low test gaps; the third commit closes them. The fourth commit follows the Codex and Bits finding on YAML validity. Three /code-review (medium) rounds reviewed it; their findings are fixed.
  • Merge with Leave PR commands for other repositories to their own policy #954: both PRs edit AGENTS.md and utils/README.md. A test merge with Leave PR commands for other repositories to their own policy #954's head (git merge-tree) has no conflicts.

How to test the change?:

Check State
bash utils/tests/test_quality_check_scripts.sh (T8 covers check-skills.py) passed, 231 groups; 46 hand mutations of the script each fail the suite
Accept/reject decisions vs. PyYAML, 56 values and 20 frontmatter blocks passed: never looser than PyYAML
Hook suites in node:22-bookworm on a clean clone, Pi cases included passed on 1cafd29: test_gradle_hook.sh 78/78, test_review_marker.sh 213/213, test_knowledgebase_guard.sh 48/48; the fourth commit changes only check-skills.py and its tests
Claude Code 2.1.319, headless, prompts that do not name a skill passed: pr-writing and doc-writing load
Pi 1.2.0, same prompts passed: both SKILL.md files are read
Same prompts on main vs. this branch passed: PR drafts fill all template sections; doc pages are PascalCase and indexed, in both trees

For Datadog employees:

  • If this PR touches code that signs or publishes builds or packages, or handles
    credentials of any kind, I've requested a security review (run the dd:platform-security-review
    skill, or file a request via the PSEC review form).
    bewaire also runs automatically on every PR.
  • This PR doesn't touch any of that.
  • JIRA: PROF-16542

🤖 Generated with Claude Code

rkennke and others added 3 commits November 9, 2026 14:43
Add utils/check-skills.py to qualityChecks. Pi silently skips a SKILL.md
with malformed frontmatter or without a description, so a broken skill
never loads and nothing reports it. The check fails on:

- a skill directory without SKILL.md, or without a `---` frontmatter block;
- a missing name or description, a name that differs from its directory
  or breaks the naming rule, a description over 1024 characters, or a
  YAML block scalar the line parser cannot read;
- a .claude/skills entry that is not the symlink to ../.agents/skills,
  through which Claude Code reads the skills;
- an AGENTS.md "`<name>` skill" mention without a matching skill.

Hermetic tests are T8 in test_quality_check_scripts.sh.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
AGENTS.md loads into every session, but these rules apply only while an
agent writes a PR description, a comment, a commit message or a doc page.
The pr-writing and doc-writing skills now carry them and load at that
moment. Each AGENTS.md section keeps a one-line pointer that names the
moment and the skill.

What stays in AGENTS.md:

- the header now lists code and code-comment rules as inline, instead of
  all writing rules for PRs, comments and commits;
- "never commit design artifacts" and "no scratch files": they apply at
  every commit, whether or not a skill is loaded;
- the ban on citing plans, phases and review reports moves into the
  Comments bullet and covers doc/ too, replacing its copy in the
  documentation rules;
- "update this file from repeated failures" moves to the header, because
  it maintains AGENTS.md itself.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…6542)

Add T8w-T8ad. Each case fails when its parser rule changes:

- double quotes are stripped before the description length check;
- frontmatter must start on the first line, and ends at its closing `---`;
- indented lines are not top-level fields;
- the first colon splits key and value;
- a block-scalar name is rejected;
- files directly under .agents/skills/ are not skills;
- names may contain digits.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@dd-octo-sts

dd-octo-sts Bot commented Nov 9, 2026 •

Copy link
Copy Markdown
Contributor

Scan-Build Report

User:runner@runnervmwuk1x
Working Directory:/home/runner/work/java-profiler/java-profiler/ddprof-lib/src/test/make
Command Line:make -j4 all
Clang Version:Ubuntu clang version 21.1.8 (6ubuntu1)
Date:Mon Nov 9 20:46:16 2026

Bug Summary

Bug TypeQuantityDisplay?
All Bugs2
Logic error
Dereference of null pointer1
Unused code
Dead initialization1

Filter Results by File

Reports

Bug Group Bug Type ▾ File Function/Method Line Path Length
Unused codeDead initializationreferenceChains.cppapplyOomRamp4971
Logic errorDereference of null pointerperfEvents_linux.cppunregisterThread72026

@dd-octo-sts

dd-octo-sts Bot commented Nov 9, 2026 •

Copy link
Copy Markdown
Contributor

CI Test Results

Run: #42695877308 | Commit: 638d196 | Duration: 20m 13s (longest job)

✅ All 32 test jobs passed

Status Overview

JDK glibc-aarch64/debug glibc-amd64/debug musl-aarch64/debug musl-amd64/debug
8 - ✅ - -
8-ibm - ✅ - -
8-j9 ✅ ✅ - -
8-librca - - ✅ ✅
8-orcl - ✅ - -
11 - ✅ - -
11-j9 ✅ ✅ - -
11-librca - - ✅ ✅
17 ✅ ✅ - -
17-graal ✅ ✅ - -
17-j9 ✅ ✅ - -
17-librca - - ✅ ✅
21 ✅ ✅ - -
21-graal ✅ ✅ - -
21-librca - - ✅ ✅
25 ✅ ✅ - -
25-graal ✅ ✅ - -
25-librca - - ✅ ✅

Legend: ✅ passed | ❌ failed | ⚪ skipped | 🚫 cancelled

Summary: Total: 32 | Passed: 32 | Failed: 0


Updated: 2026-11-09 21:08:16 UTC

@datadog-prod-us1-3

datadog-prod-us1-3 Bot commented Nov 9, 2026 •

Copy link
Copy Markdown

Pipelines

This comment will be updated automatically if new data arrives.
🔗 Commit SHA: 231d290 | Docs | Give us feedback!

@dd-octo-sts

dd-octo-sts Bot commented Nov 9, 2026 •

Copy link
Copy Markdown
Contributor

✅ All 40 integration tests passed

📊 Dashboard · 👷 Pipeline · 📦 231d2901

@rkennke
rkennke marked this pull request as ready for review November 9, 2026 15:46
@rkennke
rkennke requested a review from a team as a code owner November 9, 2026 15:46
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Nov 9, 2026 •

Copy link
Copy Markdown
Codex Review Summary: ✅ Completed

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-11-09T15:49:05.346047Z 1cafd29 Draft marked ready
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 1cafd2915e

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread utils/check-skills.py Outdated
Comment on lines +61 to +65
key, _, value = line.partition(":")
value = value.strip()
if len(value) >= 2 and value[0] == value[-1] and value[0] in "'\"":
value = value[1:-1]
fields[key.strip()] = value

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 Validate frontmatter with YAML semantics

When a future skill contains malformed YAML such as description: "unterminated or description: Use when: a colon, this line parser still returns a nonempty description and qualityChecks succeeds, while a YAML loader rejects the document and Pi silently skips the skill. This defeats the check's stated purpose and can remove mandatory instructions without a CI signal; reject unsupported scalar syntax or validate the complete frontmatter as YAML, with tests for these malformed cases.

AGENTS.md reference: AGENTS.md:L382-L389

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in 6a35adcdf. Confirmed first: Pi drops a skill whose description is Use when: ...; of two test skills, it listed only the valid one.

The check now accepts only a closed subset of YAML, so it needs no YAML library in CI:

  • Every frontmatter line is blank, a column-0 comment, or key: value with a unique key. Indented, list and continuation lines are errors.
  • Every value is empty or a one-line string: a plain value that starts with a letter, uses only a fixed character set, has no : , # or trailing :, and is not a null or boolean word; or a quoted string with only \"/\\ escapes, or '' doubling.
  • Quoted values are decoded before the length check. Invalid UTF-8 is an error.

T8aa now expects the unquoted : value to fail. New cases cover malformed quotes, unknown escapes, non-string values, every line-grammar rule and the character-range boundaries. 231 test groups pass, and each of 46 hand mutations of the check fails the suite. Over the tested values and blocks, the check never accepts what PyYAML rejects; it is stricter in a few places, and the error then names the fix.

@datadog-prod-us1-3 datadog-prod-us1-3 Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Bits Code Review: FAIL

The new validator accepts malformed YAML and reports success, allowing CI to approve a skill that cannot load. An existing test also incorrectly treats an unquoted colon-space value as valid YAML.

Open Bits AI session

🤖 Bits Code Review · Commit 1cafd29

Comment thread utils/check-skills.py Outdated
value = value.strip()
if len(value) >= 2 and value[0] == value[-1] and value[0] in "'\"":
value = value[1:-1]
fields[key.strip()] = value

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 Validate YAML syntax before accepting skill frontmatter

An unterminated value such as description: "Use when writing a PR. is accepted as a nonempty string. Substituting it into pr-writing still produces skills: OK (3 skills) and exit 0, although a YAML parser rejects it. The CI guard therefore approves malformed frontmatter that prevents the skill from loading. Validate YAML syntax and require string fields; also update T8aa, which currently expects an invalid unquoted colon-space value to pass, and add coverage for malformed quotes.

React: 👍 useful · 👎 wrong · 😕 unclear · 👀 right, but not acting on it

What each reaction means
  • 👍 Useful: correct, and you're fixing it or will.
  • 👎 Wrong: the finding is incorrect, for example the bug can't happen or the code was misread.
  • 😕 Unclear: you can't tell what it means or why it matters.
  • 👀 Right, not acting: correct, but intended, out of scope for this PR, a known risk, or too minor.

🤖 Bits Code Review · Open Bits AI session

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in 6a35adcdf. Confirmed first: Pi drops a skill whose description is Use when: ...; of two test skills, it listed only the valid one.

The check now accepts only a closed subset of YAML, so it needs no YAML library in CI:

  • Every frontmatter line is blank, a column-0 comment, or key: value with a unique key. Indented, list and continuation lines are errors.
  • Every value is empty or a one-line string: a plain value that starts with a letter, uses only a fixed character set, has no : , # or trailing :, and is not a null or boolean word; or a quoted string with only \"/\\ escapes, or '' doubling.
  • Quoted values are decoded before the length check. Invalid UTF-8 is an error.

T8aa now expects the unquoted : value to fail. New cases cover malformed quotes, unknown escapes, non-string values, every line-grammar rule and the character-range boundaries. 231 test groups pass, and each of 46 hand mutations of the check fails the suite. Over the tested values and blocks, the check never accepts what PyYAML rejects; it is stricter in a few places, and the error then names the fix.

check-skills.py read `key: value` lines without YAML rules and skipped
lines it did not understand. It passed frontmatter that a YAML loader
rejects, such as `description: Use when: x`, an unterminated quote, an
unknown escape, `name:value` or a stray line. Pi silently drops such a
skill: of two test skills, it listed only the one without `Use when: ...`
in its description.

The frontmatter must now follow a closed line grammar that needs no YAML
library in CI:

- every line is blank, a column-0 `#` comment, or `key: value` with a
  unique key; indented, list and continuation lines are errors;
- every value is empty or a one-line string: a plain value that starts
  with a letter, uses only letters, digits, spaces, non-ASCII text and
  common punctuation, has no `: `, ` #` or trailing `:`, and is not a
  YAML null or boolean word; or a double-quoted string with only the \"
  and \\ escapes, or a single-quoted string with '' doubling;
- non-ASCII text is limited to YAML's printable range, without U+2028,
  U+2029, the byte-order mark and U+FFFD; a file that is not valid UTF-8
  is an error, and a tab after the colon gets its own message.

Quoted values are decoded before the length check. Over the test values
and blocks, the check never accepts what PyYAML rejects. It is stricter
for nested mappings, multi-line values, a byte-order mark, and a few
plain values YAML reads as strings, such as `1.2.3`; the error names the
fix.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
rkennke and others added 3 commits November 9, 2026 18:53
`doc/README.md` is upper case, so calling it "the only lowercase
exception" was wrong. It is the only doc name that is not PascalCase,
which is the rule check-doc-index.py enforces.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…16542)

The old sentence said a page "changes a subsystem contract", which a doc
page does not do; the AGENTS.md "keep this file current" rule already
covers code changes that alter a contract. The doc-side duty is
different: adding, renaming or removing a subsystem page means updating
its row in the AGENTS.md "Architecture — Subsystem Index" table, which
no CI check covers.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
"Commit in logical chunks" decides how work is split, before any message
is written, so it belongs with the other always-loaded commit rules in
AGENTS.md, not in pr-writing. pr-writing keeps only the commit-message
rule, and drops its copy of the ticket-reference rule, which AGENTS.md
Work Tracking already states.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Two gaps surfaced while PROF-16542 was run:

- doc-writing had no sentence-style rule. Test drives of the pre-PR
  review's repeated-failure step found it in both Claude Code and Pi:
  after two corrections on sentence style in doc text, each proposed a
  rule for doc-writing. doc-writing now asks for Simplified Technical
  English in the text being added or rewritten, and leaves other text
  alone.
- Three ticket comments carried wrong counts that came from memory.
  pr-writing gets a "Measured numbers" section: take them from output, a
  saved log or a CI result for the current candidate, name that source,
  and update them when the candidate changes. Its scope statement now
  names PR titles and commit messages. doc-writing's "verify numbers"
  rule becomes its own bullet: verify each added or changed number
  against the code, a reproducible measurement or a named observation,
  and fix numbers the change makes stale.

The rules are stated in each skill, not by reference, so an agent that
loads only one skill still has them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

This branch has not been deployed

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant