weiqingy commented on issue #894: URL: https://github.com/apache/flink-agents/issues/894#issuecomment-4974043119
### 1. Freshness check Opening this as a PR now. I rebased it onto current `main` and re-verified: green today, and it fails correctly when I simulate each of the three bumps independently (Python upper bound, Ruff line length, Java version), so it isn't passing vacuously. ### 2. Worked examples — both of your concerns land, and the representativeness one is worse than I thought On conciseness: my draft appended 36 lines of prose to a 175-line file — roughly 20% growth on a file whose entire job is to be injected into a context window. That's the wrong trade, and I've reshaped it into a table, one row per case (~6 lines instead of 36). On representativeness: rather than argue for my picks, I tried to falsify them by mapping the four cases onto the change-type axis from your next point. They only cover two of the five buckets — `runtime/` state and recovery (#874, #880) and the Python-Java bridge (#846, #867), with nothing for `api/` contract changes, `dist`/dependency changes, or docs-only changes. So they are not representative: they cluster where I happen to have been reading recently. The fix is a selection *rule* rather than my taste — one case per change type, drawn from merged PRs. Which suggests folding this item and the matrix into a single change. You liked the matrix because it makes the injected context more focused; worked examples as a *separate section* cut directly against that. But as the evidence column *of the matrix*, they cost almost nothing: | Change type | Passes that matter most | Case that shows it | |---|---|---| | `runtime/` state & recovery | root cause through the serialization path; test the real runtime path | #874, #880 | | Python-Java bridge | Java/Python parity; reject at the boundary | #846, #867 | | `api/` contract | API clarity; parity; beta breaking-change policy | (gap) | | `dist` / dependency | shading and version-pin impact | (gap) | | docs-only | facts match their source of truth | (gap) | One table instead of two sections: each pass earns its place by pointing at a bug it actually caught, the doc gets shorter and more concrete at the same time, and the gaps are visible rather than hidden. If you would rather keep them separate I am happy to do that — but this way the conciseness concern and the matrix pull in the same direction instead of against each other. ### 3. Module-scoped `AGENTS.md` — you asked for prior art, and Flink itself is the prior art The standard is explicit that nesting is the intended monorepo pattern: "Place another AGENTS.md inside each package. Agents automatically read the nearest file in the directory tree, so the closest one takes precedence and every subproject can ship tailored instructions" (https://agents.md/). More usefully, the practice is already established in our own neighbourhood: - **apache/flink** ships module-scoped guides today — `flink-table/flink-table-planner/AGENTS.md` and `flink-table/flink-table-runtime/AGENTS.md` alongside the root one. - **apache/airflow** carries 14, scoped to `providers/`, `dev/`, the UI, and the task SDK. - **elastic/elasticsearch** (the closest structural analogue to us — JVM, Gradle, plugin modules) carries 6. The part that speaks to your context-window concern: nested guides are pulled in *on demand* when an agent touches files in that subtree, not at launch. So module-scoped files don't add to the always-on context — they subtract from it. That's the same property you liked in the matrix, which is a good sign the two ideas are pointing the same way. One wrinkle worth knowing before we commit to it: tools disagree on how they resolve "nearest". Copilot and Cursor key off the *file being edited*, so `python/AGENTS.md` applies whenever `python/**` is touched. Codex and Gemini CLI instead resolve relative to the session's *working directory*, so a nested file only applies if the session was started inside that directory. `apache/flink` hedges against this by having its root `AGENTS.md` link to the module files explicitly, so tools that only read the root still find them. If we do this, that seems worth copying. ### 4. `CLAUDE.md` and `AGENTS.md` — a correction to my own framing, then yes to your symlink I raised this as "avoid the two guides drifting", but that premise was wrong: there is no `CLAUDE.md` in this repo and there never has been. Nothing is drifting today, so the real question is whether to add a pointer at all. It does need one — Claude Code reads `CLAUDE.md`, not `AGENTS.md`, so today it picks up nothing from our guide. And your symlink instinct matches what the other Apache projects settled on: **apache/spark, apache/airflow, apache/superset, and apache/datafusion all check in `CLAUDE.md` as a symlink to `AGENTS.md`.** It is a tracked-symlink pattern we already use elsewhere in this repo (`python/LICENSE`), so it is not a new mechanism for us either. The one caveat is Windows. Creating a symlink there needs Administrator privileges or Developer Mode, and git's own docs note that with `core.symlinks=false` a symlink is checked out as "a small plain file that contains the link text" — so `CLAUDE.md` silently becomes a 9-byte file whose entire content is the string `AGENTS.md`, and an agent reading it gets nothing. For that reason the documented alternative is a one-line real `CLAUDE.md` containing `@AGENTS.md`, which is an import: same single source of truth, portable to Windows, and it leaves room for Claude-specific content later (https://code.claude.com/docs/en/memory). Both are one-line files and neither duplicates content, so I'm happy either way — the symlink has the Apache precedent, the import is the safer default for contributors on Windows. Your call. -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
