Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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
33 changes: 29 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,35 @@ 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
git diff -- <the-planned-file> > /tmp/archon-baseline.diff # empty if clean
```

After editing, stage **only your own hunks** — `git add -p <file>` — and reject any
hunk that also appears in the baseline. If the two 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.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

Capture a complete, file-specific baseline before staging.

git diff -- <the-planned-file> compares the worktree with the index. It misses pre-existing changes already staged, which git add -p will not show or remove. Those changes can still enter the commit.

The shared /tmp/archon-baseline.diff path also overwrites the baseline when multiple planned files are processed. Store one baseline per file, include staged changes with git diff HEAD, and verify the final cached diff against each baseline before committing. Stop if pre-existing staged hunks cannot be separated.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.archon/commands/defaults/archon-fix-issue.md around lines 44 - 51, Update
the baseline workflow in the planned-file staging instructions to capture each
file’s complete pre-existing changes, including staged changes, using a unique
baseline file per planned file rather than the shared /tmp/archon-baseline.diff.
Before committing, compare each file’s cached diff against its corresponding
baseline, stage only the agent’s hunks, and stop when pre-existing staged
changes cannot be separated.

- **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