Skip to content
Skill Authoring
Skill

/closing-issues

Close a GitHub issue with a synthesis comment as a flowing graph — validate the synthesis, post the closing comment, close, then run a pluggable callback (e.g. memory store) detached. Use when closing an issue should also capture the LEARNING (not just the diff log) and when the

BOOST
From plugin
claude-skills
15498 skills1 agent
Install
$ npx -y skills add oaustegard/claude-skills --skill closing-issues --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/closing-issues

Context preview

The summary Claude sees to decide when to auto-load this skill.

Close a GitHub issue with a synthesis comment as a flowing graph — validate the synthesis, post the closing comment, close, then run a pluggable callback (e.g. memory store) detached. Use when closing an issue should also capture the LEARNING (not just the diff log) and when the

SKILL.md

closing-issues.SKILL.md
name: closing-issues
description: Close a GitHub issue with a synthesis comment as a flowing graph — validate the synthesis, post the closing comment, close, then run a pluggable callback (e.g. memory store) detached. Use when closing an issue should also capture the LEARNING (not just the diff log) and when the post-close work shouldn't block the close ack.
metadata:
  version: 0.1.0
  requires: flowing

Closing Issues

A `flowing` graph that turns "close GitHub issue + capture what I learned" into a structural DAG. The synthesis text is validated upfront, the close happens against the GitHub API, and an optional post-close callback runs detached so the close ack is unblocked.

from closing_issues import close_issue

result = close_issue(
    repo="owner/repo",
    number=42,
    synthesis=(
        "Pattern X works because of Y. Constraint: don't apply to Z. "
        "Future note: revisit when feature Q lands."
    ),
)

print(result["issue_url"])    # https://github.com/.../issues/42
print(result["comment_url"])  # ...#issuecomment-...

Why a synthesis, not a "done" comment

Closing an issue produces two artifacts:

  • **The Issue itself** — implementation log. The diff and commit history

already show *what* was done.

  • **The closing comment / synthesis** — what was *learned*. Lasts longer

than the diff in mental cache.

Good closing comments lead with *why*, not *what*. Failure modes, constraints discovered, alternatives rejected. The synthesis is the seed of an institutional memory.

Internal shape

prepare_synthesis ──▶ close_github_issue           [terminal]
                              │
                              └──▶ post_close_callback  [detached, when=callback]
  • **`validate=must_have_synthesis_text`** runs against the raw input

string. Empty or whitespace-only → FAILED with no GitHub API call. This is structural: callers can't accidentally close-with-no-text.

  • **`close_github_issue`** posts the synthesis as a comment, then

PATCHes the issue to `state=closed, state_reason=completed`. Returns the issue URL and comment URL.

  • **`post_close_callback`** (optional) runs detached. Caller plugs in

any extra work — store synthesis in a memory system, ping a tracker, emit a webhook. Failure here lands in `result["detached_failures"]` and does NOT bubble up as a close failure. Skipped via `when=` if the callback isn't provided.

Pluggable post-close callback

def store_in_my_memory(synthesis: str, issue_url: str, repo: str, number: int):
    # Whatever your memory layer is — Turso, sqlite, a JSON file, etc.
    db.execute("INSERT INTO learnings (issue, synthesis) VALUES (?, ?)",
               (issue_url, synthesis))
    return {"stored": True}

result = close_issue(
    repo="owner/repo",
    number=42,
    synthesis="...",
    post_close_callback=store_in_my_memory,
)

if result["callback_result"] is None and result["detached_failures"]:
    # The callback failed but the issue is still closed.
    print("Memory store failed:", result["detached_failures"])

The callback receives keyword arguments: `synthesis`, `issue_url`, `repo`, `number`. Anything it returns goes into `result["callback_result"]`.

Result shape

{
    "issue_url":        "https://github.com/owner/repo/issues/N",
    "comment_url":      "https://github.com/.../issues/N#issuecomment-...",
    "comment_id":       12345,
    "callback_result":  <whatever the callback returned, or None>,
    "detached_failures": [],   # populated if callback raised
}

Raises `RuntimeError` only if the GitHub close itself fails. Callback failures are detached.

Auth

Requires `GH_TOKEN` (or `GITHUB_TOKEN`) in the environment. Classic PAT or fine-grained PAT with `repo` scope (specifically `issues:write`).

When NOT to use

  • Closing an issue without a synthesis. If you genuinely have nothing

to say beyond "done," just `gh issue close N` directly. This skill is for the synthesis use case.

  • Closing many issues at once (use a script that calls this in a loop —

fine, but the flow setup cost per call is small but not zero).

See also

  • `flowing` — the DAG runner this skill is built on
  • `opening-prs` — the symmetric "open and merge" flow
Read more
Ships withclaude-skills

A collection of Claude skills distributed as a Claude Code plugin marketplace. Skills are primarily designed for the Claude.ai PaaS skill compute environment; mileage will vary if used as Claude Code Agent Skills.

Get the whole plugin

Other skills on claude-skills.