Skip to content

Commit 2282079

Browse files
authored
agents-md: send the AGENTS.md loaded line to the debug log (#98275)
1 parent 684800b commit 2282079

5 files changed

Lines changed: 23 additions & 13 deletions

File tree

‎mods/agents-md/README.md‎

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ same entry is keyed `"agents-md"`.
9191
| event | what the hook does |
9292
| --- | --- |
9393
| `session.start` | in every mode: passes the start straight through and floats the usage row for the configured mode, never awaited; the first start of a load logs how a stored `projectInstructions` value is read. The session's start never waits on this plugin |
94-
| `prompt.context` | under `claude-md-or-agents-md` and `claude-md-and-agents-md`: walks `$.fs.ancestors` for the `AGENTS.md` files above the working directory and answers them as `project` instruction files, each `@` import its own entry after its file, each placed where a project file of its directory stands (root first, before the first deeper project file, else after the last project file, before memory); files the engine already holds by path or by content are left out; under `claude-md-or-agents-md` it answers nothing when the project has a `CLAUDE.md` of its own (among the handed files, else found by a `$.fs.ancestors` walk, so a `CLAUDE.md` the engine loaded and then withheld still counts), and logs which files it loaded once, and again after a move to another project root; handed unknown files (a hook above rewrote the `claudeMd` text) it adds nothing; the first context of a load sends the load row (counts) and the feature mark; under `managed-only` (matcher: a `project`, `local` or `user` file present): answers the list without those kinds |
94+
| `prompt.context` | under `claude-md-or-agents-md` and `claude-md-and-agents-md`: walks `$.fs.ancestors` for the `AGENTS.md` files above the working directory and answers them as `project` instruction files, each `@` import its own entry after its file, each placed where a project file of its directory stands (root first, before the first deeper project file, else after the last project file, before memory); files the engine already holds by path or by content are left out; under `claude-md-or-agents-md` it answers nothing when the project has a `CLAUDE.md` of its own (among the handed files, else found by a `$.fs.ancestors` walk, so a `CLAUDE.md` the engine loaded and then withheld still counts), and names the files it loaded in the debug log (`$.ui.log` with `to: "debug"`: `no CLAUDE.md found; AGENTS.md loaded: <paths>`, nothing in the transcript) once, and again after a move to another project root; handed unknown files (a hook above rewrote the `claudeMd` text) it adds nothing; the first context of a load sends the load row (counts) and the feature mark; under `managed-only` (matcher: a `project`, `local` or `user` file present): answers the list without those kinds |
9595
| `agent.spawn` on `fork: true` | under `claude-md-or-agents-md` and `claude-md-and-agents-md`: a fork the Agent tool starts shares its parent's prompt prefix, so the parent loop's delivered nested files are copied to the fork's loop and not attached to it again (a `/fork` or `/subtask` fork does not raise `agent.spawn` yet and starts from an empty set, as every fork did before; a fork started in the same tool batch as a `Read` inherits that Read's file although its prefix holds a placeholder for it) |
9696
| `tool.call` on `Read` | under `claude-md-or-agents-md` and `claude-md-and-agents-md`, for a file under the session's project root (`$.session.root()`, read live, so `/cd`, a host's directory change and worktree moves are followed and a moved root starts the delivered sets and the fallback decision over; a file elsewhere gets nothing, as the engine attaches no nested `CLAUDE.md` there; and nothing anywhere in a run where the engine attaches nothing to a turn, `--bare` with its `CLAUDE_CODE_SIMPLE` or `CLAUDE_CODE_DISABLE_ATTACHMENTS`, read on every Read through `$.env.get` as the engine reads them on every turn): walks only the directories strictly between the root and the read file (`$.fs.ancestors` with `below: root`, as the engine walks only those for a nested `CLAUDE.md`, never up to the filesystem root again) and attaches their `AGENTS.md` files not yet given to that agent loop, not already among the context's instruction files (by path or, for a project file, by text) and not claimed by a `CLAUDE.md` of the same directory (or imported by one), as `context` after the tool result, framed `Contents of <path>:` byte for byte as the engine frames a nested `CLAUDE.md`, whatever its size; each file once per loop and conversation (the context's recomputation after a compaction or `/clear` starts the count over), the context's files never; a Read that attached files sends the nested row. A `~` or `~/` path is read under the home directory as the Read tool reads it |
9797

@@ -162,8 +162,8 @@ names a loader fact a plugin cannot reach through the events it has today.
162162
claude plugin test mods/agents-md
163163

164164
`tests/register.test.ts` covers the default mode: a project with `AGENTS.md`
165-
alone gets it as a project instruction file and one transcript line naming
166-
it, a project with a `CLAUDE.md` of its own is left to the engine without a
167-
walk, a failed walk leaves the context as handed, and the start hands
168-
`$.telemetry` the mode row alone where a test seats a provider for that
169-
noun, and goes on untouched where none is seated.
165+
alone gets it as a project instruction file and one debug-log line naming
166+
it, with nothing in the transcript, a project with a `CLAUDE.md` of its own is
167+
left to the engine without a walk, a failed walk leaves the context as handed,
168+
and the start hands `$.telemetry` the mode row alone where a test seats a
169+
provider for that noun, and goes on untouched where none is seated.

‎mods/agents-md/hooks/register.ts‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,7 @@ export function register(on: On, options: PluginOptions): void {
154154
.filter(file => file.parent === undefined)
155155
.map(file => file.path)
156156
.join(', '),
157+
{ to: 'debug' },
157158
)
158159
}
159160

‎mods/agents-md/tests/fixtures/started-of.ts‎

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,20 @@ import type { Started, ToastAsked } from './types'
66

77
/**
88
* A session that starts untouched beneath the plugins, rooted at SESSION's
9-
* working directory, every toast and transcript line they raise kept for the
10-
* test to read, on a mock clock the test settles before it reads them.
9+
* working directory, every toast, transcript line and debug-log line they
10+
* raise kept for the test to read, on a mock clock the test settles before it
11+
* reads them.
12+
*
13+
* A `$.ui.log` line lands in `lines` when it is bound for the transcript and
14+
* in `debugLines` when its `to` is `debug`, so a test tells the two apart.
1115
*
1216
* @param on the test's `on`
1317
* @returns the toasts, lines and walks raised, in order, and the clock
1418
*/
1519
export function startedOf(on: On): Started {
1620
const toasts: ToastAsked[] = []
1721
const lines: string[] = []
22+
const debugLines: string[] = []
1823

1924
on('session.start', ($, e) => ({ cwd: e.cwd }))
2025

@@ -27,10 +32,11 @@ export function startedOf(on: On): Started {
2732
})
2833

2934
on('ui.log', ($, e) => {
30-
lines.push(e.text)
35+
const sink = e.to === 'debug' ? debugLines : lines
36+
sink.push(e.text)
3137

3238
return { value: undefined }
3339
})
3440

35-
return { toasts, lines, walks: [], clock: mock.clock(on) }
41+
return { toasts, lines, debugLines, walks: [], clock: mock.clock(on) }
3642
}

‎mods/agents-md/tests/fixtures/types/started/started.ts‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,13 @@ import type { ToastAsked } from '../toast-asked'
44

55
/**
66
* What the plugins raised while a session ran: each toast as asked for, each
7-
* transcript line, the first name of each walk they asked for; `clock`
8-
* settles what they floated.
7+
* transcript line, each line sent to the debug log alone, the first name of
8+
* each walk they asked for; `clock` settles what they floated.
99
*/
1010
export type Started = {
1111
toasts: ToastAsked[]
1212
lines: string[]
13+
debugLines: string[]
1314
walks: string[]
1415
clock: MockClock
1516
}

‎mods/agents-md/tests/register.test.ts‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,8 @@ describe('register', () => {
4141

4242
await started.clock.settle()
4343

44-
expect(started.lines).toEqual([
44+
expect(started.lines, 'nothing new in the transcript').toEqual([])
45+
expect(started.debugLines).toEqual([
4546
'no CLAUDE.md found; AGENTS.md loaded: /repo/AGENTS.md',
4647
])
4748
})
@@ -69,6 +70,7 @@ describe('register', () => {
6970

7071
expect(started.walks).toEqual([])
7172
expect(started.lines).toEqual([])
73+
expect(started.debugLines).toEqual([])
7274
})
7375

7476
test('a failed walk leaves the context as handed', async ($, on) => {

0 commit comments

Comments
 (0)