Skip to content

PMM-7 Make AGENTS.md guidance reach Claude Code - #5885

Open
ademidoff wants to merge 12 commits into
mainfrom
PMM-7-update-go-code-style
Open

PMM-7 Make AGENTS.md guidance reach Claude Code#5885
ademidoff wants to merge 12 commits into
mainfrom
PMM-7-update-go-code-style

Conversation

@ademidoff

@ademidoff ademidoff commented Sep 3, 2026

Copy link
Copy Markdown
Member

Ticket number: PMM-7

Feature build: n/a — documentation and agent-tooling only, no code or user-facing change.

Three related fixes to the AGENTS.md setup, aimed at guidance actually reaching the agent that needs it, once.

1. Prefer '%s' over %q in logs and errors

Adds one bullet under Error Handling and one under Logging in the root AGENTS.md: don't interpolate strings with %q in log or error messages; use %s, or '%s' when the value can contain spaces.

%q nests inside logrus's own quoted field value and double-escapes. A message written as

fmt.Errorf("environment variable name %q is reserved", name)

reaches the log as

level=error error="environment variable name \"MONGODB_URI\" is reserved"

'%s' delimits the value just as clearly without the escaping, and plain %s is enough when the value can't contain spaces. This came up on #5781, where the pattern is visible in new test output.

This documents the convention for new and changed code. There are ~190 existing %q call sites in non-test Go; no sweep is proposed here, and nothing is enforced by a linter.

2. Per-component CLAUDE.md pointers

Claude Code reads CLAUDE.md, not AGENTS.md. Until now only the repo root had a pointer, and it imports the root AGENTS.md alone. The component guides are linked from a table in the root document, so they reached Claude only if it chose to open them — nothing merged them into context.

That is the reason a rule like the one above could be added to the root file and still be missed: managed/AGENTS.md carried its own self-contained Do/Don't list restating the error-handling and logging conventions, so an agent reading it saw a complete-looking set of rules with no %q entry.

Claude Code does load a nested CLAUDE.md on demand, the first time it reads a file in that directory, and a relative @import resolves against the importing file rather than the working directory (docs). So this adds a CLAUDE.md beside each of the 11 component AGENTS.md files, containing the import and nothing else:

@AGENTS.md

Each pointer is that single line and nothing else. The mechanism is explained once, in the root AGENTS.md, rather than repeated in all eleven files.

Verified locally: with managed/CLAUDE.md in place, reading managed/models/agent_model.go loads managed/AGENTS.md into context automatically; without it, the guide never loads.

3. Remove conventions duplicated between root and component guides

Once a component guide loads alongside the root one, a rule restated in both costs context twice and gains a second place to drift out of sync. One rule applied throughout:

A component guide keeps only what is specific to its area. Anything that merely restates the root's Global Development Conventions is removed.

managed/AGENTS.md carried the bulk of it — twelve of thirteen "Do" bullets and seven of ten "Don't" bullets restated the root, as did most of Testing and all of Code Generation. api/AGENTS.md and api-tests/AGENTS.md had four between them. The other seven guides were already clean and are untouched.

Three rules lived only in managed/AGENTS.md despite being general Go style, so they move up to the root rather than being deleted:

  • //nolint as the sole exception to the no-inline-comments rule
  • don't inline err != nil checks
  • existing github.com/pkg/errors uses may remain until refactored

Every removal was checked against the root to confirm the rule still has a home there. Net: −42/+11 lines across the guides, with managed/AGENTS.md down from 197 to 165.

The root's PMM-specific choices list is deliberately left alone — it repeats a handful of rules on purpose as a curated pitfall list, and now says so. The root also gains a short note stating where a new rule belongs, so this doesn't grow back.

4. Correct the "reform is pmm-managed only" claim

While applying (3) it turned out the repo states this in three places and it is false in all of them. pmm-agent's QAN collectors use reform to map monitored-database system views — 24 files under agent/ import reform.v1, three carry //go:generate go tool reform with checked-in models_reform.go, and reform.ErrNoRows appears in agent/agents/mysql/perfschema/history.go:73, agent/agents/mysql/perfschema/summaries.go:78, agent/agents/postgres/pgstatstatements/pgstatstatements.go:274 and agent/agents/postgres/pgstatmonitor/stat_monitor_cache.go:129.

Corrected:

  • the Tech Stack row no longer says "used in pmm-managed only"
  • agent/AGENTS.md no longer says reform is "not used (agent has no DB)"
  • agent/AGENTS.md no longer says "Don't use raw SQL — the agent has no database; all data comes via gRPC". pmm-agent having no datastore of its own is true; its data all arriving over gRPC is not, since QAN data is read out of the monitored database.

The real distinction, now stated: pmm-managed uses reform for PMM's own PostgreSQL; pmm-agent uses it as a row mapper against the monitored database's system views.

qan-api2/AGENTS.md's "no reform" note is correct and untouched — its ErrNoRows uses are sql.ErrNoRows.

  • API Docs updated — n/a, no API change

Nested inside logrus's own quoted field value, %q double-escapes and
produces output like:

  error="environment variable name \"MONGODB_URI\" is reserved"

'%s' delimits the value just as clearly without the escaping, and %s
alone is enough when the value cannot contain spaces.

This documents the convention for new and changed code; no sweep of
the ~190 existing %q call sites is intended.

Signed-off-by: Alex Demidoff <a@demidoff.me>
@ademidoff
ademidoff requested a review from a team as a code owner September 3, 2026 19:30
@ademidoff
ademidoff requested review from 4nte and JiriCtvrtka and removed request for a team September 3, 2026 19:30
@codecov

codecov Bot commented Sep 3, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 44.05%. Comparing base (31318c7) to head (d27fd8c).
⚠️ Report is 165 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #5885      +/-   ##
==========================================
+ Coverage   43.59%   44.05%   +0.45%     
==========================================
  Files         415      434      +19     
  Lines       43134    35474    -7660     
  Branches        0      581     +581     
==========================================
- Hits        18804    15627    -3177     
+ Misses      22454    18264    -4190     
+ Partials     1876     1583     -293     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@coderabbitai

coderabbitai Bot commented Sep 3, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Team

Run ID: 99fe5775-a18a-4a6f-90f8-672169d75308

📥 Commits

Reviewing files that changed from the base of the PR and between d4f8185 and 6b4b1cf.

📒 Files selected for processing (2)
  • AGENTS.md
  • managed/AGENTS.md
🔗 Linked repositories identified

CodeRabbit considers these linked repositories for cross-repo context during reviews:

  • percona/pmm-qa (manual)
  • percona/pmm (manual)
💤 Files with no reviewable changes (1)
  • AGENTS.md

Included review availability: Your plan provides up to 4 included reviews per hour; 1 remains after this review.


Walkthrough

Updated global and component AGENTS.md guidance for Claude Code loading, pointer maintenance, component scope, Go style, error handling, logging, code generation, and testing. Simplified component CLAUDE.md files so each contains only the local @AGENTS.md import directive. Reduced duplicated API and managed component guidance while retaining component-specific model, test data, and test execution instructions.

Merge Risk: ⚪ Minimal · up to 6b4b1

This change updates repository guidance and Claude Code pointer files without modifying application behavior. No current merge-blocking risk remains.

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly summarizes the primary change: making repository AGENTS.md guidance available to Claude Code through component-level pointers.
Description check ✅ Passed The description includes the ticket number, feature-build status, API documentation applicability, detailed change scope, rationale, and verification notes. It matches the repository template and expl…
Full details: Description check

Explanation

The description includes the ticket number, feature-build status, API documentation applicability, detailed change scope, rationale, and verification notes. It matches the repository template and explains that no API change occurred.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Claude Code reads CLAUDE.md, not AGENTS.md. Only the repo root had a
pointer, and it imports the root AGENTS.md alone -- the component guides
are merely linked from a table, so they reached Claude only if it chose
to open them. Nothing merged them into context automatically.

Claude Code does load a nested CLAUDE.md on demand, the first time it
reads a file in that directory, and an @import there resolves relative
to the importing file. So a one-line CLAUDE.md beside each component
AGENTS.md makes that guide load automatically for whichever component
is being worked on, without the root file pulling in all eleven.

Each pointer contains the import and nothing else; the maintainer note
is an HTML comment, which is stripped before the file enters context.

Signed-off-by: Alex Demidoff <a@demidoff.me>
@ademidoff
ademidoff requested review from a team and Nailya as code owners September 3, 2026 23:17
@ademidoff
ademidoff requested review from matejkubinec and mattiasimonato and removed request for a team September 3, 2026 23:17
@ademidoff ademidoff changed the title PMM-7 Prefer '%s' over %q in logs and errors PMM-7 Make AGENTS.md guidance reach Claude Code Sep 3, 2026

@coderabbitai coderabbitai 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.

Actionable comments posted: 1


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Team

Run ID: ce3bab62-8a66-4243-b559-2ea92d0f1466

📥 Commits

Reviewing files that changed from the base of the PR and between c1443aa and 60672d6.

📒 Files selected for processing (12)
  • AGENTS.md
  • admin/CLAUDE.md
  • agent/CLAUDE.md
  • api-tests/CLAUDE.md
  • api/CLAUDE.md
  • build/CLAUDE.md
  • dashboards/dashboards/CLAUDE.md
  • dashboards/pmm-app/CLAUDE.md
  • managed/CLAUDE.md
  • qan-api2/CLAUDE.md
  • ui/CLAUDE.md
  • vmproxy/CLAUDE.md
🔗 Linked repositories identified

CodeRabbit considers these linked repositories for cross-repo context during reviews:

  • percona/pmm-qa (manual)
  • percona/pmm (manual)

Included review availability: Your plan provides up to 4 included reviews per hour; 3 remain after this review.

Comment thread AGENTS.md
Now that a component AGENTS.md loads alongside the root one, a rule
restated in both costs context twice and gives it two places to drift.

Applies one rule: a component guide keeps only what is specific to its
area, and anything that merely restates the root's Global Development
Conventions is removed. The root's "PMM-specific choices" list is left
alone -- it repeats a handful of rules deliberately, as a curated set of
pitfalls, and says so.

managed/AGENTS.md carried the bulk of it: twelve of its thirteen "Do"
bullets and seven of its ten "Don't" bullets restated the root, as did
most of Testing and all of Code Generation. api/AGENTS.md and
api-tests/AGENTS.md had four between them. The remaining seven guides
were already free of it and are untouched.

Three rules existed only in managed/AGENTS.md despite being general Go
style, so they move up to the root instead of being deleted:

  - //nolint as the sole exception to the no-inline-comments rule
  - don't inline err != nil checks
  - existing github.com/pkg/errors uses may remain until refactored

Each removal was checked against the root to confirm the rule still has
a home there.

Signed-off-by: Alex Demidoff <a@demidoff.me>

@coderabbitai coderabbitai 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.

Actionable comments posted: 1


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Team

Run ID: 17e19303-38ba-4e1e-b4db-b765b9ca7e2a

📥 Commits

Reviewing files that changed from the base of the PR and between 60672d6 and 85b993a.

📒 Files selected for processing (4)
  • AGENTS.md
  • api-tests/AGENTS.md
  • api/AGENTS.md
  • managed/AGENTS.md
🔗 Linked repositories identified

CodeRabbit considers these linked repositories for cross-repo context during reviews:

  • percona/pmm-qa (manual)
  • percona/pmm (manual)
💤 Files with no reviewable changes (1)
  • api-tests/AGENTS.md

Included review availability: Your plan provides up to 4 included reviews per hour; 2 remain after this review.

Comment thread managed/AGENTS.md
The maintainer comment said the same thing eleven times, and the root
AGENTS.md already explains the mechanism in one place. Drop it; each
pointer is now the single import line it describes.

Signed-off-by: Alex Demidoff <a@demidoff.me>
It sat in the root's Error Handling list scoped with "in pmm-managed",
which is the tell that it belongs a level down. managed/AGENTS.md
already stated it, in the reform Key conventions list beside the other
reform rules, so this is a deletion from the root rather than a move.

Nothing is lost: the component guide now loads whenever Claude reads a
file under managed/, which is the only place the rule applies.

Every remaining bullet in the root's Error Handling list is genuinely
global.

Signed-off-by: Alex Demidoff <a@demidoff.me>
Same tell as reform.ErrNoRows: the root scoped it with "(pmm-managed
only)". managed/AGENTS.md already showed the directive in its reform
example, so the bullet there is promoted from "models carry
//go:generate directives" to naming the command and what regenerates
the *_reform.go files.

reform is still introduced at the root, in the Tech Stack table, so the
"reform: not used" notes in agent/ and qan-api2/ keep their referent.
The generated-file list keeps *_reform.go, which is a repo-wide rule
about what not to edit rather than a managed convention.

Signed-off-by: Alex Demidoff <a@demidoff.me>
The previous commit moved it into managed/AGENTS.md on the strength of
the root guide's own claim that reform is "pmm-managed only". That claim
is false: pmm-agent generates reform models too, in

  agent/agents/mysql/perfschema
  agent/agents/postgres/pgstatstatements
  agent/agents/postgres/pgstatmonitor

each with a //go:generate go tool reform directive and a checked-in
models_reform.go, and it uses them at runtime -- reform.NewDB in
perfschema.go, SelectRows and SelectAllFrom in the collectors.

Two components generate reform models, so the rule is global and belongs
in the root. Restored there without the false scope, and describing both
users: managed maps PMM's own PostgreSQL, agent maps the monitored
database's system views.

managed/AGENTS.md keeps its bullet, trimmed so it names where the models
live rather than repeating the directive.

Signed-off-by: Alex Demidoff <a@demidoff.me>
The claim appears in three places and is false in all of them.
pmm-agent's QAN collectors use reform to map monitored-database system
views: reform.ErrNoRows in perfschema/history.go, perfschema/summaries.go,
pgstatstatements.go and stat_monitor_cache.go, and reform.NewDB in
perfschema.go. 24 files under agent/ import reform.v1.

  - the Tech Stack row said "used in pmm-managed only"
  - agent/AGENTS.md said reform was "not used (agent has no DB)"
  - agent/AGENTS.md said "Don't use raw SQL -- the agent has no
    database; all data comes via gRPC", which is two claims: the agent
    having no datastore of its own (true) and its data all arriving by
    gRPC (false -- QAN data is read out of the monitored database)

An earlier commit in this branch trusted the first of these and pushed
the reform.ErrNoRows rule down to managed/AGENTS.md. It belongs in the
root, scoped to both users, and is restored there; managed's copy in the
reform key-conventions list goes, since the root now states it.

qan-api2's "no reform" note is correct and left alone -- its ErrNoRows
uses are sql.ErrNoRows.

Signed-off-by: Alex Demidoff <a@demidoff.me>
reform is used by two components out of eleven, so a root-level rule
makes every other component's reader carry it. Stated instead in
managed/AGENTS.md, in the reform key-conventions list, and in
agent/AGENTS.md, where it names the QAN collectors that read
monitored-database system views.

The layering note now says a rule belongs in the most specific guide or
guides that cover it, since a rule can apply to two components without
being global.

Signed-off-by: Alex Demidoff <a@demidoff.me>
Same placement as reform.ErrNoRows: managed/AGENTS.md and
agent/AGENTS.md both already described the directive, so the root bullet
was the redundant third copy.

managed/AGENTS.md names the full command again. It had been trimmed to
"a reform //go:generate directive" only because the root spelled it out;
with the root bullet gone that reason is gone too.

The root keeps what is genuinely repo-wide: *_reform.go in the
never-edit list, and the Tech Stack row, which introduces reform for the
agent/ and qan-api2/ guides that refer to it.

Signed-off-by: Alex Demidoff <a@demidoff.me>
Nobody runs //go:generate by hand -- make gen does it, via
go generate ./... in managed/Makefile. That is exactly why the directive
is worth documenting: go generate acts only on files that contain one,
and gen depends on clean, which deletes every *_reform.go first.

So a new model file missing the line gets no *_reform.go while the other
sixteen regenerate normally, with no error. The bullet now says that
instead of describing the directives already present, and drops the
make gen half, which the root guide's workflow and Definition of Done
already cover.

agent/AGENTS.md stays descriptive; reform models are not added there.

Signed-off-by: Alex Demidoff <a@demidoff.me>
api/ uses get 46 times, post 44, delete 10, put 8, and patch never. The
rule records that rather than introducing it.

Worth stating because the tempting cases already exist: ChangeAgent,
ChangeService and ChangeSettings all send just the fields being changed,
which is the shape a contributor would reach for PATCH to express. They
are PUT, so the Do bullet now says PUT covers partial updates too.

Nothing enforces it -- buf lint's STANDARD rules check proto
identifiers, not the method keys inside google.api.http -- so the bullet
says that, matching how the REST Path Naming section flags its own lack
of enforcement.

Signed-off-by: Alex Demidoff <a@demidoff.me>
@ademidoff

Copy link
Copy Markdown
Member Author

@coderabbitai Your preamble takes more than once full page. That's super distracting and it clutters the PR, making it difficult to find what really matters. Please configure yourself to prevent this from happening - it's quite annoyoing.

@coderabbitai

coderabbitai Bot commented Sep 4, 2026

Copy link
Copy Markdown

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

⚙️ CodeRabbit configuration inspected

Length of output: 5812


@ademidoff You are right. The preamble was too long.

The repository configuration already disables generated high-level summaries and changed-file summaries. It has no setting to limit one individual comment. Future review comments will omit long preambles and state only the issue and recommended fix.


✏️ Learnings added
Learnt from: ademidoff
URL: https://github.com/percona/pmm/pull/5885

Timestamp: 2026-09-04T00:07:09.182Z
Learning: For the `percona/pmm` repository, keep CodeRabbit review comments short and factual. Do not post long preambles or walkthrough-style text that can hide review findings. State the issue and the recommended fix first.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

You are interacting with an AI system.

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