mirror of
https://github.com/badlogic/pi-mono.git
synced 2026-11-05 23:37:25 +00:00
feat(coding-agent): support AGENTS.override.md (#7681)
This commit is contained in:
parent
3852cb2b81
commit
8ecf8a9883
8 changed files with 41 additions and 5 deletions
|
|
@ -324,6 +324,8 @@ Pi loads `AGENTS.md` (or `CLAUDE.md`) at startup from:
|
|||
- Parent directories (walking up from cwd)
|
||||
- Current directory
|
||||
|
||||
If a directory contains `AGENTS.override.md`, Pi loads it instead of `AGENTS.md` or `CLAUDE.md` from that directory. Context files from other directories are still concatenated.
|
||||
|
||||
Use for project instructions (`AGENTS.md`/`CLAUDE.md`), conventions, common commands. All matching files are concatenated.
|
||||
|
||||
Disable context file loading with `--no-context-files` (or `-nc`).
|
||||
|
|
|
|||
|
|
@ -100,6 +100,8 @@ Pi loads:
|
|||
- `~/.pi/agent/AGENTS.md` for global instructions
|
||||
- `AGENTS.md` or `CLAUDE.md` from parent directories and the current directory
|
||||
|
||||
If a directory contains `AGENTS.override.md`, Pi loads it instead of `AGENTS.md` or `CLAUDE.md` from that directory.
|
||||
|
||||
Restart pi, or run `/reload`, after changing context files.
|
||||
|
||||
## Common things to try
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ Trusting a project allows pi to load project resources that require trust, inclu
|
|||
- missing project packages configured through project settings
|
||||
- project-local extensions and project package-managed extensions
|
||||
|
||||
Declining trust skips protected resources. `AGENTS.md` and `CLAUDE.md` context files are loaded regardless of project trust unless context loading is disabled. Before trust is resolved, pi only loads context files, user/global extensions, and CLI `-e` extensions. User/global and CLI extensions can handle the `project_trust` event; the first extension that returns a yes/no decision owns the decision.
|
||||
Declining trust skips protected resources. Context files such as `AGENTS.override.md`, `AGENTS.md`, and `CLAUDE.md` are loaded regardless of project trust unless context loading is disabled. Before trust is resolved, pi only loads context files, user/global extensions, and CLI `-e` extensions. User/global and CLI extensions can handle the `project_trust` event; the first extension that returns a yes/no decision owns the decision.
|
||||
|
||||
Non-interactive modes (`-p`, `--mode json`, and `--mode rpc`) do not show a trust prompt. Without an applicable saved trust decision, `defaultProjectTrust: "ask"` and `"never"` ignore such resources, while `"always"` trusts them. Use `--approve`/`-a` or `--no-approve`/`-na` to override project trust for one run.
|
||||
|
||||
|
|
|
|||
|
|
@ -103,6 +103,8 @@ Pi loads `AGENTS.md` or `CLAUDE.md` at startup from:
|
|||
- parent directories, walking up from the current working directory
|
||||
- the current directory
|
||||
|
||||
If a directory contains `AGENTS.override.md`, Pi loads it instead of `AGENTS.md` or `CLAUDE.md` from that directory. Context files from other directories still layer normally.
|
||||
|
||||
Use context files for project conventions, commands, safety rules, and preferences. Disable loading with `--no-context-files` or `-nc`.
|
||||
|
||||
### System Prompt Files
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ function resolvePromptInput(input: string | undefined, description: string): str
|
|||
}
|
||||
|
||||
function loadContextFileFromDir(dir: string): { path: string; content: string } | null {
|
||||
const candidates = ["AGENTS.md", "AGENTS.MD", "CLAUDE.md", "CLAUDE.MD"];
|
||||
const candidates = ["AGENTS.override.md", "AGENTS.md", "AGENTS.MD", "CLAUDE.md", "CLAUDE.MD"];
|
||||
for (const filename of candidates) {
|
||||
const filePath = join(dir, filename);
|
||||
if (existsSync(filePath)) {
|
||||
|
|
@ -90,7 +90,7 @@ function loadContextFileFromDir(dir: string): { path: string; content: string }
|
|||
|
||||
/**
|
||||
* The main repo's context file that a nested linked worktree's own copy shadows: both
|
||||
* are the same tracked AGENTS.md/CLAUDE.md, so loading both loads it twice. Returns
|
||||
* occupy the same logical repository scope, so loading both applies that context twice. Returns
|
||||
* undefined when nothing is shadowed, leaving normal ancestor inheritance alone.
|
||||
*
|
||||
* Returned canonicalized (realpath), because `git worktree add` writes the `.git`
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ interface CompactReadClassification {
|
|||
label: string;
|
||||
}
|
||||
|
||||
const COMPACT_RESOURCE_FILE_NAMES = new Set(["AGENTS.md", "AGENTS.MD", "CLAUDE.md", "CLAUDE.MD"]);
|
||||
const COMPACT_RESOURCE_FILE_NAMES = new Set(["AGENTS.override.md", "AGENTS.md", "AGENTS.MD", "CLAUDE.md", "CLAUDE.MD"]);
|
||||
|
||||
/**
|
||||
* Pluggable operations for the read tool.
|
||||
|
|
|
|||
|
|
@ -355,7 +355,27 @@ Content`,
|
|||
expect(agentsFiles.some((f) => f.path.includes("AGENTS.md"))).toBe(true);
|
||||
});
|
||||
|
||||
it("should prefer AGENTS.override.md within each directory while preserving ancestor layering", async () => {
|
||||
const nestedCwd = join(cwd, "service");
|
||||
mkdirSync(nestedCwd);
|
||||
writeFileSync(join(agentDir, "AGENTS.md"), "global instructions");
|
||||
writeFileSync(join(agentDir, "AGENTS.override.md"), "global override");
|
||||
writeFileSync(join(cwd, "AGENTS.md"), "project instructions");
|
||||
writeFileSync(join(nestedCwd, "AGENTS.md"), "service instructions");
|
||||
writeFileSync(join(nestedCwd, "AGENTS.override.md"), "service override");
|
||||
|
||||
const loader = new DefaultResourceLoader({ cwd: nestedCwd, agentDir });
|
||||
await loader.reload();
|
||||
|
||||
expect(loader.getAgentsFiles().agentsFiles).toEqual([
|
||||
{ path: join(agentDir, "AGENTS.override.md"), content: "global override" },
|
||||
{ path: join(cwd, "AGENTS.md"), content: "project instructions" },
|
||||
{ path: join(nestedCwd, "AGENTS.override.md"), content: "service override" },
|
||||
]);
|
||||
});
|
||||
|
||||
it("should ignore context file candidates that are directories", async () => {
|
||||
mkdirSync(join(cwd, "AGENTS.override.md"));
|
||||
mkdirSync(join(cwd, "AGENTS.md"));
|
||||
writeFileSync(join(cwd, "CLAUDE.md"), "Fallback instructions");
|
||||
const consoleError = vi.spyOn(console, "error").mockImplementation(() => {});
|
||||
|
|
@ -368,10 +388,12 @@ Content`,
|
|||
content: "Fallback instructions",
|
||||
});
|
||||
expect(consoleError).not.toHaveBeenCalledWith(expect.stringContaining(join(cwd, "AGENTS.md")));
|
||||
expect(consoleError).not.toHaveBeenCalledWith(expect.stringContaining(join(cwd, "AGENTS.override.md")));
|
||||
consoleError.mockRestore();
|
||||
});
|
||||
|
||||
it("should skip AGENTS.md and CLAUDE.md discovery when noContextFiles is true", async () => {
|
||||
it("should skip context file discovery when noContextFiles is true", async () => {
|
||||
writeFileSync(join(cwd, "AGENTS.override.md"), "# Override Guidelines\n\nBe helpful.");
|
||||
writeFileSync(join(cwd, "AGENTS.md"), "# Project Guidelines\n\nBe helpful.");
|
||||
writeFileSync(join(cwd, "CLAUDE.md"), "# Claude Guidelines\n\nBe helpful.");
|
||||
|
||||
|
|
|
|||
|
|
@ -461,6 +461,14 @@ describe("ToolExecutionComponent parity", () => {
|
|||
hidden: "Hidden resource instructions",
|
||||
absent: undefined,
|
||||
},
|
||||
{
|
||||
title: "AGENTS.override.md",
|
||||
path: join(process.cwd(), ".pi", "AGENTS.override.md"),
|
||||
content: "Hidden override instructions",
|
||||
compact: "read resource .pi/AGENTS.override.md",
|
||||
hidden: "Hidden override instructions",
|
||||
absent: undefined,
|
||||
},
|
||||
{
|
||||
title: "outside AGENTS.md",
|
||||
path: resolve(process.cwd(), "..", "AGENTS.md"),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue