Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
130 changes: 130 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
# AGENTS.md

## Issue Discovery Standard

When looking for new issues, do not rely only on casual code inspection. Prefer evidence-backed discovery methods and only file issues that are narrow, reproducible, and worth tracking.

### Core rule

A new issue should only be created if it is:
- verified on the current codebase state
- narrow in scope
- reproducible with a concrete command, test, request flow, or minimal example
- supported by actual observed behavior
- easy for another engineer to validate and pick up

### Preferred issue-finding strategies

Use these methods before proposing new issues:

1. Run code paths, not just static scans
- Prefer executing small targeted checks over only reading code.
- Use focused commands, test nodes, or minimal scripts to validate behavior.

2. Re-run stale or suspicious test suites
- Look for:
- `XPASS`
- `xfail`
- skipped tests that may now be stale
- stale or obsolete tests that may no longer match reality
- Unexpected passes and stale expected failures are strong sources of real issues.

3. Compare public API surfaces
- Check package-level exports vs submodule exports.
- Look for duplicated helper names with different behavior.
- Validate that documented imports and actual imports behave consistently.

4. Compare claims vs runnable behavior
- Check README/docs statements such as:
- "supported"
- "in progress"
- "planned"
- "coming soon"
- Verify whether the smallest runnable path actually matches the claim.

5. Compare neighboring execution paths
- Look for behavior that differs across:
- runtime vs test client
- native backend vs fallback backend
- sync vs async
- middleware vs no middleware
- top-level import vs direct submodule import

6. Use differential testing mindset
- When relevant, compare behavior to a reference implementation or expected contract.
- For framework-style repos, compare against the documented compatibility target.

7. Use property-based or fuzz-style thinking
- Especially for:
- routers
- parsers
- protocol handlers
- validation layers
- path/header/query normalization
- Prefer generated edge cases where practical.

8. Look for issue-worthy drift
- Documentation says one thing
- tests assume another
- runtime does a third
- public exports expose a fourth
- These mismatches often produce strong, narrow issues.

### What counts as a strong issue

A strong issue has:
- one concrete problem
- one reproducible path
- actual observed failure or mismatch
- clear expected behavior
- nearby passing controls or guards
- narrow, testable acceptance criteria
- explicit non-goals if scope could sprawl

### What does not count as a strong issue

Do not file issues that are:
- speculative
- based only on code inspection when runtime proof is possible
- broad umbrella complaints
- duplicate broad trackers without narrowing them
- warning-only cleanup unless there is a compelling reason
- multiple unrelated findings bundled together

### Required issue evidence

Before creating an issue, gather:

1. Exact repro
- One concrete command, test node, API call, UI flow, or script.

2. Observed result
- The actual failure output, incorrect result, mismatch, or unexpected behavior.

3. Expected result
- What should happen instead.

4. Nearby passing checks
- One or two closely related tests/commands/behaviors that still pass.

5. Narrow acceptance criteria
- The repro passes.
- The expected behavior is present.
- Nearby guards remain green.

6. Non-goals
- Clarify what the issue is not asking for.

### Filing rule

If the issue cannot be reduced to:
- one concrete problem
- one reproducible path
- one observed failure
- one expected behavior
- one or two nearby passing checks
- one narrow fix target

do not file it yet.

Gather better evidence first.
14 changes: 7 additions & 7 deletions src/tools.zig
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ fn validateIssueDraft(alloc: std.mem.Allocator, title: []const u8, body: []const
if (std.mem.trim(u8, body, " \t\n\r").len == 0) {
return std.fmt.allocPrint(
alloc,
"issue body is required and must follow the CONTRIBUTING.md / AGENT.md issue template. Missing body.\n\nRequired template:\n{s}",
"issue body is required and must follow the CONTRIBUTING.md / AGENTS.md issue template. Missing body.\n\nRequired template:\n{s}",
.{ISSUE_TEMPLATE},
) catch null;
}
Expand All @@ -119,7 +119,7 @@ fn validateIssueDraft(alloc: std.mem.Allocator, title: []const u8, body: []const

return std.fmt.allocPrint(
alloc,
"issue body does not satisfy CONTRIBUTING.md / AGENT.md issue requirements. Missing required section(s): {s}.\n\nRequired template:\n{s}",
"issue body does not satisfy CONTRIBUTING.md / AGENTS.md issue requirements. Missing required section(s): {s}.\n\nRequired template:\n{s}",
.{ joined.items, ISSUE_TEMPLATE },
) catch null;
}
Expand Down Expand Up @@ -281,8 +281,8 @@ pub const tools_list =
\\{"name":"get_project_state","description":"Return all open issues grouped by status label, all open branches, and all open PRs. Use this to understand current project state before picking up work.","inputSchema":{"type":"object","properties":{},"required":[]}},
\\{"name":"get_next_task","description":"Return the single highest-priority unblocked issue that has no open branch. Use this to decide what to work on next.","inputSchema":{"type":"object","properties":{},"required":[]}},
\\{"name":"prioritize_issues","description":"Apply priority labels (priority:p0–p3) to a set of issues based on their dependency order. Sinks (no dependents) get p0; independent issues get p2.","inputSchema":{"type":"object","properties":{"issue_numbers":{"type":"array","items":{"type":"integer"},"description":"Issue numbers to prioritize"}},"required":["issue_numbers"]}},
\\{"name":"create_issue","description":"Create a single GitHub issue with title, body, labels, and optional milestone. Automatically applies status:backlog if no status label is provided. This tool enforces the issue requirements from CONTRIBUTING.md and AGENT.md: the body must include One-sentence problem, Exact repro, Observed result, Expected result, Nearby passing checks, Acceptance criteria, and Non-goals. If parent_issue is provided, create_issue only appends `Parent issue: #N` to the issue body for context; use link_issues for explicit dependency relationships.","inputSchema":{"type":"object","properties":{"title":{"type":"string"},"body":{"type":"string","description":"Required. Must follow the CONTRIBUTING.md / AGENT.md issue template with the required evidence sections."},"labels":{"type":"array","items":{"type":"string"}},"milestone":{"type":"string"},"parent_issue":{"type":"integer","description":"Optional parent issue number to append as `Parent issue: #N` in the issue body for context only. This does not create a durable GitHub subtask/dependency relationship; use link_issues for explicit links."}},"required":["title","body"]}},
\\{"name":"create_issues_batch","description":"Create multiple GitHub issues in one call. Issues are fired concurrently in batches of 5 with a 200ms collection window. Use this after decompose_feature to create all issues at once. Each issue body must satisfy the same CONTRIBUTING.md / AGENT.md evidence template enforced by create_issue.","inputSchema":{"type":"object","properties":{"issues":{"type":"array","items":{"type":"object","properties":{"title":{"type":"string"},"body":{"type":"string","description":"Required. Must follow the CONTRIBUTING.md / AGENT.md issue template with the required evidence sections."},"labels":{"type":"array","items":{"type":"string"}},"milestone":{"type":"string"}},"required":["title","body"]}}},"required":["issues"]}},
\\{"name":"create_issue","description":"Create a single GitHub issue with title, body, labels, and optional milestone. Automatically applies status:backlog if no status label is provided. This tool enforces the issue requirements from CONTRIBUTING.md and AGENTS.md: the body must include One-sentence problem, Exact repro, Observed result, Expected result, Nearby passing checks, Acceptance criteria, and Non-goals. If parent_issue is provided, create_issue only appends `Parent issue: #N` to the issue body for context; use link_issues for explicit dependency relationships.","inputSchema":{"type":"object","properties":{"title":{"type":"string"},"body":{"type":"string","description":"Required. Must follow the CONTRIBUTING.md / AGENTS.md issue template with the required evidence sections."},"labels":{"type":"array","items":{"type":"string"}},"milestone":{"type":"string"},"parent_issue":{"type":"integer","description":"Optional parent issue number to append as `Parent issue: #N` in the issue body for context only. This does not create a durable GitHub subtask/dependency relationship; use link_issues for explicit links."}},"required":["title","body"]}},
\\{"name":"create_issues_batch","description":"Create multiple GitHub issues in one call. Issues are fired concurrently in batches of 5 with a 200ms collection window. Use this after decompose_feature to create all issues at once. Each issue body must satisfy the same CONTRIBUTING.md / AGENTS.md evidence template enforced by create_issue.","inputSchema":{"type":"object","properties":{"issues":{"type":"array","items":{"type":"object","properties":{"title":{"type":"string"},"body":{"type":"string","description":"Required. Must follow the CONTRIBUTING.md / AGENTS.md issue template with the required evidence sections."},"labels":{"type":"array","items":{"type":"string"}},"milestone":{"type":"string"}},"required":["title","body"]}}},"required":["issues"]}},
\\{"name":"update_issue","description":"Update an existing issue's title, body, or labels.","inputSchema":{"type":"object","properties":{"issue_number":{"type":"integer"},"title":{"type":"string"},"body":{"type":"string"},"add_labels":{"type":"array","items":{"type":"string"}},"remove_labels":{"type":"array","items":{"type":"string"}}},"required":["issue_number"]}},
\\{"name":"close_issues_batch","description":"Close multiple issues at once. Each issue is marked status:done. Use this instead of calling close_issue N times.","inputSchema":{"type":"object","properties":{"issue_numbers":{"type":"array","items":{"type":"integer"},"description":"Issue numbers to close"},"pr_number":{"type":"integer","description":"PR number that resolves all these issues (optional)"}},"required":["issue_numbers"]}},
\\{"name":"close_issue","description":"Close an issue and mark it status:done. Optionally reference the PR that resolved it.","inputSchema":{"type":"object","properties":{"issue_number":{"type":"integer"},"pr_number":{"type":"integer","description":"PR number that resolves this issue"}},"required":["issue_number"]}},
Expand Down Expand Up @@ -3122,9 +3122,9 @@ fn handleRunTask(
}

test "tools_list encodes evidence-backed issue filing guidance" {
try std.testing.expect(std.mem.indexOf(u8, tools_list, "This tool enforces the issue requirements from CONTRIBUTING.md and AGENT.md") != null);
try std.testing.expect(std.mem.indexOf(u8, tools_list, "Each issue body must satisfy the same CONTRIBUTING.md / AGENT.md evidence template enforced by create_issue") != null);
try std.testing.expect(std.mem.indexOf(u8, tools_list, "CONTRIBUTING.md and AGENT.md") != null);
try std.testing.expect(std.mem.indexOf(u8, tools_list, "This tool enforces the issue requirements from CONTRIBUTING.md and AGENTS.md") != null);
try std.testing.expect(std.mem.indexOf(u8, tools_list, "Each issue body must satisfy the same CONTRIBUTING.md / AGENTS.md evidence template enforced by create_issue") != null);
try std.testing.expect(std.mem.indexOf(u8, tools_list, "CONTRIBUTING.md and AGENTS.md") != null);
try std.testing.expect(std.mem.indexOf(u8, tools_list, "run_explorer") != null);
try std.testing.expect(std.mem.indexOf(u8, tools_list, "Maximum time for agent execution (default 300, max 600)") != null);
try std.testing.expect(std.mem.indexOf(u8, tools_list, "Maximum total time for the full chain (default 300, max 600)") != null);
Expand Down
Loading