Skip to content
Merged
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
45 changes: 41 additions & 4 deletions .archon/commands/defaults/archon-fix-issue.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,47 @@ created a git worktree on the correct branch. In that case:
operator's `.archon/` directory — workflows, commands, scripts — into every run
worktree, deliberately, so a workflow can be iterated on before it is committed.
Those files are present *before* you start and are not your changes.
- **Modifications under `.archon/` are never yours to commit, stash, or remove.**
Leave them exactly as they are and commit only the files your implementation touched.
Before every commit, confirm with `git diff --cached --name-only` that nothing under
`.archon/` is staged.
- **Pre-existing modifications under `.archon/` are never yours to commit, stash, or
remove.** Leave them exactly as they are and commit only the files your implementation
touched. Before every commit, confirm with `git diff --cached --name-only` that no
`.archon/` file you did not deliberately change is staged.
- **The exception: when the issue's fix genuinely lives under `.archon/`.** Workflows,
commands and scripts are source too, and an issue can legitimately target one. If your
plan says to edit a specific `.archon/` file, edit and commit **that file** — the rule
above exists to stop you sweeping up the operator's unrelated copied-in edits, not to
make a whole directory unfixable.

Distinguish the two by intent, not by path: a file your plan names is your work; every
Comment thread
coderabbitai[bot] marked this conversation as resolved.
other dirty `.archon/` file is not. On 2026-08-03 a run blocked outright on this,
correctly reporting "contradictory instructions" because the issue required editing a
workflow YAML while this section forbade touching anything under `.archon/`. It was
right to refuse rather than guess — and the rule was wrong to be absolute.

**A named file is not a blank cheque for that file.** It may already carry copied-in
edits from before you started, and staging it whole would commit those too — the
path-level check above cannot see inside a file. So before you touch a planned
`.archon/` file, record its baseline:

```bash
# HEAD, not the index: `git diff -- <file>` compares the worktree against the
# INDEX, so pre-existing changes that are already STAGED do not appear — and
# `git add -p` will neither show nor remove them, so they ride into your commit
# invisibly. Diffing against HEAD captures staged and unstaged alike.
git diff HEAD -- <the-planned-file> > /tmp/archon-baseline.diff # empty if clean
```

Then, before staging anything of your own, clear that file out of the index so the
only thing you can stage is what you deliberately pick:

```bash
git restore --staged <the-planned-file> # no-op if nothing was staged
git add -p <the-planned-file> # stage ONLY your own hunks
```

Reject any hunk that also appears in the baseline. If yours and theirs are entangled
such that you cannot separate them, stop and say so rather than committing someone
else's work under your change. That is the same call the 2026-08-03 run made, and it
was the right one.
- **Dirty paths outside `.archon/` are also not a reason to stop, and also not yours.**
They are either your own work from an earlier attempt at this run (resume reuses the
worktree) or something the operator left behind. Either way: leave them alone, do not
Expand Down
55 changes: 44 additions & 11 deletions .archon/workflows/defaults/archon-fix-github-issue.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -31,22 +31,55 @@ nodes:

Request: $ARGUMENTS

Rules:
- If the message contains an explicit issue number (e.g., "#709", "issue 709", "709"), extract that number.
- If the message is ambiguous (e.g., "fix the SQLite timestamp bug"), use `gh issue list` to search for matching issues and pick the best match.

CRITICAL: Your final output must be ONLY the bare number with no quotes, no markdown, no explanation. Example correct output: 709
A reference is an ATOMIC pair: a number, and the repo it belongs to. Never take the
number from one reference and the repo from another — that combination fetches an
issue nobody asked for.

Recognised reference forms, each yielding one complete pair:
- `#709`, `issue 709`, `709` -> {issue_number: "709", repo: ""}
- `owner/repo#709` -> {issue_number: "709", repo: "owner/repo"}
- `https://github.com/owner/repo/issues/709`
-> {issue_number: "709", repo: "owner/repo"}

An empty `repo` means "the current checkout" — the common case. NEVER guess a repo.

Then:
- Exactly one reference -> use it.
- Several references, all resolving to the SAME pair -> use it.
- Several DIFFERENT references (e.g. a bare number and a cross-repo URL) -> the
request is ambiguous. Do NOT pick one. Fail with a message naming every pair you
found and asking which was meant. Guessing here silently investigates the wrong
issue, which is worse than stopping.
- No reference at all (e.g. "fix the SQLite timestamp bug") -> search the CURRENT
repo with `gh issue list`, pick the best match, and leave `repo` empty.
output_format:
type: object
properties:
issue_number:
type: string
repo:
type: string
required:
- issue_number
- repo

- id: fetch-issue
bash: |
# $extract-issue-number.output is injected pre-quoted by Archon — do NOT
# wrap it in double quotes (that corrupts the value; see issue #1884).
ISSUE_NUM=$(echo $extract-issue-number.output | grep -oE '[0-9]+' | head -1)
if [ -z "$ISSUE_NUM" ]; then
echo "Failed to extract issue number from:" $extract-issue-number.output >&2
# Substitutions are injected already shell-quoted by Archon — assign them
# unquoted, then quote normally as locals (see #1884).
num=$extract-issue-number.output.issue_number
repo=$extract-issue-number.output.repo
if ! printf '%s' "$num" | grep -qE '^[0-9]+$'; then
echo "extract-issue-number did not yield a numeric issue id: $num" >&2
exit 1
fi
gh issue view "$ISSUE_NUM" --json title,body,labels,comments,state,url,author
# An explicit owner/repo must be preserved: `gh issue view <n>` resolves against
# the CURRENT checkout, so a cross-repo URL would silently read this repo's #<n>.
if [ -n "$repo" ]; then
gh issue view "$num" --repo "$repo" --json title,body,labels,comments,state,url,author
else
gh issue view "$num" --json title,body,labels,comments,state,url,author
fi
depends_on: [extract-issue-number]

- id: classify
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,22 +125,56 @@ nodes:

Request: $ARGUMENTS

Rules:
- If the message contains an explicit issue number (e.g., "#709", "issue 709", "709"), extract that number.
- If the message is ambiguous (e.g., "fix the SQLite timestamp bug"), use `gh issue list` to search for matching issues and pick the best match.

CRITICAL: Your final output must be ONLY the bare number with no quotes, no markdown, no explanation. Example correct output: 709
A reference is an ATOMIC pair: a number, and the repo it belongs to. Never take the
number from one reference and the repo from another — that combination fetches an
issue nobody asked for.

Recognised reference forms, each yielding one complete pair:
- `#709`, `issue 709`, `709` -> {issue_number: "709", repo: ""}
- `owner/repo#709` -> {issue_number: "709", repo: "owner/repo"}
- `https://github.com/owner/repo/issues/709`
-> {issue_number: "709", repo: "owner/repo"}

An empty `repo` means "the current checkout" — the common case. NEVER guess a repo.

Then:
- Exactly one reference -> use it.
- Several references, all resolving to the SAME pair -> use it.
- Several DIFFERENT references (e.g. a bare number and a cross-repo URL) -> the
request is ambiguous. Do NOT pick one. Fail with a message naming every pair you
found and asking which was meant. Guessing here silently investigates the wrong
issue, which is worse than stopping.
- No reference at all (e.g. "fix the SQLite timestamp bug") -> search the CURRENT
repo with `gh issue list`, pick the best match, and leave `repo` empty.
output_format:
type: object
properties:
issue_number:
type: string
repo:
type: string
required:
- issue_number
- repo
model: small

- id: fetch-issue
bash: |
# Strip quotes, whitespace, markdown backticks from AI output
ISSUE_NUM=$(echo "$extract-issue-number.output" | tr -d "'\"\`\n " | grep -oE '[0-9]+' | head -1)
if [ -z "$ISSUE_NUM" ]; then
echo "Failed to extract issue number from: $extract-issue-number.output" >&2
# Substitutions are injected already shell-quoted by Archon — assign them
# unquoted, then quote normally as locals (see #1884).
num=$extract-issue-number.output.issue_number
repo=$extract-issue-number.output.repo
if ! printf '%s' "$num" | grep -qE '^[0-9]+$'; then
echo "extract-issue-number did not yield a numeric issue id: $num" >&2
exit 1
fi
gh issue view "$ISSUE_NUM" --json title,body,labels,comments,state,url,author
# An explicit owner/repo must be preserved: `gh issue view <n>` resolves against
# the CURRENT checkout, so a cross-repo URL would silently read this repo's #<n>.
if [ -n "$repo" ]; then
gh issue view "$num" --repo "$repo" --json title,body,labels,comments,state,url,author
else
gh issue view "$num" --json title,body,labels,comments,state,url,author
fi
depends_on: [extract-issue-number]

- id: classify
Expand Down
Loading
Loading