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
44 changes: 44 additions & 0 deletions packages/agents/content/skills/_data/gh-body-file.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# gh body file

Pattern for passing Markdown bodies to `gh` commands without routing content through bash.

## When to use

Any `gh` invocation that takes a Markdown body: `gh issue create`, `gh issue edit`, `gh issue comment`, `gh pr create`, `gh pr edit`, `gh pr comment`, and similar. Applies whenever the body may contain backticks, code fences, or other Markdown that shell quoting could mangle.

## Pattern

1. Write the body to a scratch file using the `Write` tool (raw string, no shell involvement):

```
path: $TMPDIR/gh-body-{timestamp}.md
```

Use `{timestamp}` in `YYYYMMDD-HHMMSSZ` format. When a skill writes bodies in a loop (e.g., one per insight), append an index or sub-second suffix — `gh-body-{timestamp}-{index}.md` — to keep paths unique within the same second.

2. Pass the path to `gh` via `--body-file`:

```bash
gh issue create --title "..." --body-file "$body_path" [other flags]
gh issue comment {number} --body-file "$body_path"
gh pr create --title "..." --body-file "$body_path" [other flags]
```

Name the variable `body_path` so retries and follow-on calls reuse the same file unambiguously.

No cleanup is required — `$TMPDIR` is OS-managed.

## Why

Historically, agents authored bodies via single-quoted bash heredocs:

```bash
gh issue create --body "$(cat <<'EOF'
...
EOF
)"
```

Although a `<<'EOF'` heredoc performs no expansion and backticks need no escaping, agents reflexively inserted `\` before every backtick — a habit carried over from double-quoted strings. GitHub rendered the backslashes literally, producing broken code spans (`` \`foo\` ``) and fences (``\`\`\`ts``). The bug recurred across creation flows in multiple repositories.

Writing the body through the `Write` tool removes bash from the path entirely. There is no shell context in which escaping could feel necessary, so the class of bug cannot arise. See codeassembly#442 for the originating incident.
6 changes: 4 additions & 2 deletions packages/agents/content/skills/create-gh-pr/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,12 @@ label_flags+=" --label \"{label_name}\""

### 2. Create the pull request

Write the body to a scratch file using the [gh body file](../_data/gh-body-file.md) pattern — do not inline the body into the shell command. Store the path so the retry step in step 3 can reuse it.

```bash
url=$(gh pr create \
--title "{title}" \
--body "{body}" \
--body-file "$body_path" \
--base "{base_branch}" \
--draft \
${label_flags})
Expand All @@ -53,7 +55,7 @@ If `gh pr create` fails and the error indicates one or more labels are invalid:

1. Identify the failing label(s) from the error message.
2. Remove the failing labels from the `--label` flags.
3. Retry `gh pr create` without the failing labels.
3. Retry `gh pr create` without the failing labels, reusing the same `$body_path` — do not rewrite the body or inline it.
4. Record which labels were skipped.

If the failure is unrelated to labels, report the error and stop.
Expand Down
8 changes: 4 additions & 4 deletions packages/agents/content/skills/create-ticket/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,10 +99,10 @@ json=$({platform_home_dir}/scripts/describe-change.sh --scope {scope} --type {ty
change_prefix=$(echo "$json" | grep -o '"ticket_prefix":"[^"]*"' | cut -d'"' -f4)
```

Create the issue **without** the ticket ID prefix in the title. Include `--label` flags if labels were resolved in step 4:
Create the issue **without** the ticket ID prefix in the title. Write the body to a scratch file using the [gh body file](../_data/gh-body-file.md) pattern — do not inline the body into the shell command. Include `--label` flags if labels were resolved in step 4:

```bash
url=$(gh issue create --title "${change_prefix}{title}" --body "{ticket body}"${label_flags})
url=$(gh issue create --title "${change_prefix}{title}" --body-file "$body_path"${label_flags})
```

Extract the issue number from the returned URL:
Expand Down Expand Up @@ -146,10 +146,10 @@ If a plan exists in conversation context, save it as a ticket-scoped artifact in
{YYYYMMDD-HHMMZ}_{slug}_plan.md
```

Then attach it as a comment on the remote issue:
Then attach it as a comment on the remote issue. Write the comment body to a scratch file using the [gh body file](../_data/gh-body-file.md) pattern — do not inline the comment into the shell command:

```bash
gh issue comment {number} --body "{plan comment}"
gh issue comment {number} --body-file "$body_path"
```

Plan comment format:
Expand Down
2 changes: 1 addition & 1 deletion packages/agents/content/skills/design-and-plan/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ Present the ticket to the user. Revise until approved.

**Remote issue update** — offer to update the remote issue only when the source was a remote ticket (URL or shorthand reference). This is a shared-state action — do not update without explicit consent.

- GitHub: `gh issue edit {number} --body "{refined body}"`
- GitHub: write the refined body to a scratch file using the [gh body file](../_data/gh-body-file.md) pattern, then `gh issue edit {number} --body-file "$body_path"`.
- Other platforms: note that automated update is not yet supported; suggest manual update

### Phase 5: Generate implementation plan
Expand Down
2 changes: 1 addition & 1 deletion packages/agents/content/skills/refine-plan/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ Compare the revised plan's approach/solution with the source ticket's solution s

**Material divergence** means a different technical approach (e.g., build-time flag changed to runtime detection) or changed scope boundaries (features added or removed). **Non-divergence** means refined details within the same approach (e.g., different function names, reordered steps).

- For GitHub tickets (resolved via `gh issue view` in step 1): offer to update via `gh issue edit {number} --body "{updated body}"`
- For GitHub tickets (resolved via `gh issue view` in step 1): offer to update by writing the revised body to a scratch file using the [gh body file](../_data/gh-body-file.md) pattern, then `gh issue edit {number} --body-file "$body_path"`.
- For file-based tickets: offer to update the file directly

This is a shared-state action — do not update without explicit consent. If the user declines, continue to step 7.
Expand Down
2 changes: 1 addition & 1 deletion packages/agents/content/skills/wrap-up/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,7 @@ Process confirmed actions in this order:

1. **Tickets for findings** — invoke `/create-ticket` once per ticket (or once for combined items). Use the item description as the ticket body seed. Apply the label from the issue's context (feature, bug, refactoring, dependencies, ci, tests). Classify items using the prefix: `fixme` → bug, `todo` → task, `warning` → bug, `recommendation` → improvement, `suggestion` → improvement.
2. **Tickets for legacy items** — invoke `/create-ticket` once per item. Label as technical debt or the appropriate category.
3. **Post insights to ticket** — post each `ticket comment` insight via `gh issue comment {number} --body "{insight}"` (ticket number from `get-session-context`). If no ticket is available, re-route to devlog.
3. **Post insights to ticket** — for each `ticket comment` insight, write the insight body to a scratch file using the [gh body file](../_data/gh-body-file.md) pattern, then post via `gh issue comment {number} --body-file "$body_path"` (ticket number from `get-session-context`). When posting multiple insights, use a loop-unique path (e.g., `gh-body-{timestamp}-{index}.md`) to avoid collisions. Do not inline insight content into the shell command. If no ticket is available, re-route to devlog.
4. **Save session devlog** — invoke `/create-devlog`. When the session was detected as orchestrated in Phase 1a, pass the captured run ID through as `/create-devlog --run-id={run_id}` so the devlog frontmatter links back to the run. Insights with `devlog` destination are automatically included in the devlog content; no separate action is needed for them.

**Between each action**, briefly report the result (ticket URL, artifact path) before proceeding to the next.
Expand Down
Loading