Github Issue Lifecycle
GitHub issue lifecycle tracker for swamp. Drives issues from open through triage, planning, implementation, PR linkage, and merge as versioned swamp data — with optional label sync and comment posting back to the issue.
No external dependencies beyond the gh CLI. Designed for solo developers
or small teams working on GitHub repos who want observable, queryable issue
lifecycle data without leaving the terminal.
State Machine
opened ──[start]──> triaging
triaging ──[triage]──> classified
classified ──[plan]──> planned
planned ──[iterate]──> planned (feedback loop)
planned ──[approve]──> approved
approved ──[implement]──> implementing
implementing ──[link_pr]──> pr_open
pr_open ──[pr_merged]──> done
pr_open ──[pr_failed]──> pr_failed
pr_failed ──[link_pr]──> pr_open (retry)
Any ──[close]──> closedUsage
swamp extension pull @webframp/github-issue-lifecycle
# Create a lifecycle tracker for a repo
swamp model create @webframp/github-issue-lifecycle tracker \
--global repo=webframp/swamp-extensions
# Start tracking an issue
swamp model method run tracker start --input issue_number=42
# Triage it
swamp model method run tracker triage \
--input issue_number=42 --input kind=bug --input priority=high
# Plan implementation
swamp model method run tracker plan \
--input issue_number=42 \
--input summary="Fix pagination bug" \
--input steps='["Read current code","Fix off-by-one","Add test"]'
# Approve and implement
swamp model method run tracker approve --input issue_number=42
swamp model method run tracker implement --input issue_number=42
# Link a PR
swamp model method run tracker link_pr \
--input issue_number=42 \
--input pr_url=https://github.com/webframp/swamp-extensions/pull/100
# Record merge
swamp model method run tracker pr_merged --input issue_number=42Prerequisites
ghCLI installed and authenticated (gh auth login)- swamp initialized in the repository (
swamp init)
2026.08.28.1
Changed: Normalized the extension license to Apache-2.0 and corrected the copyright holder to "Sean Escriva". Extensions that previously shipped an MIT LICENSE.md are now Apache-2.0, consistent with the repository root and every other extension. No code or behavioral changes.
Upgrade note: License text only. No API, schema, or runtime behavior changed.
2026.08.27.1
Changed: Test suite now uses the shared createModelTestContext factory
from @systeminit/swamp-testing instead of a hand-rolled method context. No
behavioral, schema, or method changes — the published model, workflow, and
report behave identically. The deno.json gains a dev-only
@systeminit/swamp-testing import-map entry.
Note: The lifecycle-metrics report test keeps its hand-rolled data
repository. The report matches stored artifacts through entry.tags.specName, a
field the factory's TestData type does not model, so the factory cannot drive
the report's filtering path without fabricating data. This is documented inline
in the test.
2026.08.26.3
Fixed: Restored inline npm:zod@4.4.3 import specifiers so the registry
quality scorer can resolve dependencies and score the extension. An earlier
release used a bare "zod" import-map specifier, which published but scored as
unscored.
Changed: Retained explicit compilerOptions.strict in deno.json. No
behavioral or schema changes.
Global Arguments
| Argument | Type | Description |
|---|---|---|
| repo | string | GitHub repo in owner/name format (e.g., webframp/swamp-extensions) |
| postComments | boolean | Post lifecycle transition comments to the GitHub issue |
| syncLabels | boolean | Sync lifecycle phase as a GitHub label (lifecycle:<phase>) |
| Argument | Type | Description |
|---|---|---|
| issue_number | number | GitHub issue number |
| Argument | Type | Description |
|---|---|---|
| issue_number | number | GitHub issue number |
| kind | enum | Category to assign during triage |
| priority? | enum | Priority to assign during triage |
| component? | string | Affected component or area |
| notes? | string | Triage notes |
| Argument | Type | Description |
|---|---|---|
| issue_number | number | GitHub issue number |
| summary | string | One-line summary of approach |
| steps | array | Implementation steps |
| risks? | array | Known risks or concerns |
| feedback? | string | Feedback from the last iteration |
| Argument | Type | Description |
|---|---|---|
| issue_number | number | GitHub issue number |
| summary | string | One-line summary of the revised approach |
| steps | array | Revised implementation steps |
| risks? | array | Known risks or concerns |
| feedback | string | What changed and why |
| Argument | Type | Description |
|---|---|---|
| issue_number | number | GitHub issue number |
| Argument | Type | Description |
|---|---|---|
| issue_number | number | |
| branch? | string | Working branch name if known |
| Argument | Type | Description |
|---|---|---|
| issue_number | number | |
| pr_url | string | Full PR URL |
| branch? | string |
| Argument | Type | Description |
|---|---|---|
| issue_number | number | GitHub issue number |
| Argument | Type | Description |
|---|---|---|
| issue_number | number | GitHub issue number |
| reason? | string | Why the PR failed CI or review |
| Argument | Type | Description |
|---|---|---|
| issue_number | number | GitHub issue number |
| close_issue? | boolean | Close the GitHub issue (default: true) |
| Argument | Type | Description |
|---|---|---|
| issue_number | number | GitHub issue number |
| reason? | string | Why the issue was closed |
| Argument | Type | Description |
|---|---|---|
| issue_number | number | GitHub issue number |
Resources
Drives a GitHub issue through the full lifecycle: start → triage → plan → approve → implement. Each job calls the corresponding lifecycle model method sequentially, with the agent providing classification and plan content as inputs. This workflow handles the pre-PR phases. Once implementation starts, the pr-fix-loop skill takes over and calls link_pr / pr_merged / pr_failed as the PR progresses through CI. Designed to be called once per issue when you want the agent to drive the full triage-to
Cycle-time metrics, stuck issues, and retry counts from lifecycle data
2026.08.27.1
Changed: Test suite now uses the shared createModelTestContext factory
from @systeminit/swamp-testing instead of a hand-rolled method context. No
behavioral, schema, or method changes — the published model, workflow, and
report behave identically. The deno.json gains a dev-only
@systeminit/swamp-testing import-map entry.
Note: The lifecycle-metrics report test keeps its hand-rolled data
repository. The report matches stored artifacts through entry.tags.specName, a
field the factory's TestData type does not model, so the factory cannot drive
the report's filtering path without fabricating data. This is documented inline
in the test.
2026.08.26.3
Fixed: Restored inline npm:zod@4.4.3 import specifiers so the registry
quality scorer can resolve dependencies and score the extension. An earlier
release used a bare "zod" import-map specifier, which published but scored as
unscored.
Changed: Retained explicit compilerOptions.strict in deno.json. No
behavioral or schema changes.
2026.08.26.3
Fixed: Restored inline npm:zod@4.4.3 import specifiers so the registry
quality scorer can resolve dependencies and score the extension. An earlier
release used a bare "zod" import-map specifier, which published but scored as
unscored.
Changed: Retained explicit compilerOptions.strict in deno.json. No
behavioral or schema changes.
2026.08.26.1
Changed: Normalized deno.json configuration for repo-wide consistency:
added explicit compilerOptions.strict and migrated zod dependency to the
import map (bare "zod" specifier instead of inline npm:zod@4.4.3). No
behavioral changes — runtime resolution is identical.
2026.08.25.1
Changed: Updated labels for improved extension discoverability. Added cross-cutting category labels (security, observability, finops, infrastructure, networking, compliance, devops, ai, incident-response) where applicable.
updated labels
2026.08.24.2
Added: Output metadata attributes for observability.
durationMs: Method execution duration in milliseconds.collectedBy: Extension name that produced the data.fetchedAt: ISO 8601 timestamp when data was fetched (added to resources that previously lacked it).
2026.08.24.1
Added Troubleshooting section documenting silent label sync failures, asymmetric comment/label error handling, best-effort issue close, start re-reset behavior, and gh CLI auth delegation.
2026.08.21.2
Changed: gh CLI failures raised by the model now name the exact command
that was run and its exit code, instead of a bare "gh failed: ..." message. A
non-JSON response from gh issue view (used by start and status) now raises
a clear "returned output that could not be parsed as JSON" error naming the
command, instead of a raw JSON.parse SyntaxError. The lifecycle-metrics
report's data reader now names the resource spec, instance, and model when a
stored JSON blob fails to parse, instead of throwing an unattributed
SyntaxError.
2026.08.21.1
Changed: Added .describe() documentation to previously undocumented fields
across the resource schemas (ContextSchema, ClassificationSchema,
PlanSchema, PullRequestSchema) and method argument schemas (triage,
plan, iterate, approve, pr_merged, pr_failed, close, status). No
behavioral change.
2026.08.15.1
Fixed: Every method that reads lifecycle state (start, triage, plan,
iterate, approve, implement, link_pr, pr_merged, pr_failed,
complete, close) threw before reaching GitHub because it relied on
ctx.storedResources, a field current swamp no longer passes to model methods.
All state reads now go through ctx.readResource(), the supported API.
Fixed: Resource instance names collided across specs — context, state,
classification, and pullRequest all wrote to the same issue-<n> storage
path for a given issue, since instance names must be unique across all specs on
a model, not just within one. Each spec now writes to a spec-prefixed path
(state-issue-42, pullRequest-issue-42, etc.), so per-issue data no longer
overwrites itself across specs.
Changed: pullRequest gained a retryCount field, incremented on every
pr_failed call and carried forward through link_pr retries and pr_merged.
The lifecycle-metrics report now reads this field directly instead of relying
on raw stored-resource access (also removed) to derive retry counts from
historical writes.
Upgrade note: Existing pullRequest data written before this version lacks
retryCount and will read as 0 going forward — no migration needed. Issues
already tracked under the old issue-<n> instance naming will not be found by
the new spec-prefixed lookups; re-run start to re-establish state under the
new naming for any in-flight issues.
2026.08.21.1
Changed: Added .describe() documentation to previously undocumented fields
across the resource schemas (ContextSchema, ClassificationSchema,
PlanSchema, PullRequestSchema) and method argument schemas (triage,
plan, iterate, approve, pr_merged, pr_failed, close, status). No
behavioral change.
2026.08.15.1
Fixed: Every method that reads lifecycle state (start, triage, plan,
iterate, approve, implement, link_pr, pr_merged, pr_failed,
complete, close) threw before reaching GitHub because it relied on
ctx.storedResources, a field current swamp no longer passes to model methods.
All state reads now go through ctx.readResource(), the supported API.
Fixed: Resource instance names collided across specs — context, state,
classification, and pullRequest all wrote to the same issue-<n> storage
path for a given issue, since instance names must be unique across all specs on
a model, not just within one. Each spec now writes to a spec-prefixed path
(state-issue-42, pullRequest-issue-42, etc.), so per-issue data no longer
overwrites itself across specs.
Changed: pullRequest gained a retryCount field, incremented on every
pr_failed call and carried forward through link_pr retries and pr_merged.
The lifecycle-metrics report now reads this field directly instead of relying
on raw stored-resource access (also removed) to derive retry counts from
historical writes.
Upgrade note: Existing pullRequest data written before this version lacks
retryCount and will read as 0 going forward — no migration needed. Issues
already tracked under the old issue-<n> instance naming will not be found by
the new spec-prefixed lookups; re-run start to re-establish state under the
new naming for any in-flight issues.
2026.07.27.1
Fixed: The fmt task ran deno fmt --check, so deno task fmt verified
formatting instead of applying it and there was no way to format the extension
through its own task. fmt now formats and a new fmt:check verifies, matching
every other extension in the repository.
Fixed: deno fmt no longer inspects CLAUDE.md / AGENTS.md. Those files
are gitignored and never present in CI, but deno fmt does not read .gitignore,
so deno task fmt:check could fail locally on a file CI does not have.
Upgrade note: Tooling and formatting only. No model, method, schema, or behavior change — nothing to do on upgrade.
2026.07.24.1
Added: Initial release of the GitHub issue lifecycle tracker.
- 12 methods covering the full issue lifecycle: start, triage, plan, iterate, approve, implement, link_pr, pr_merged, pr_failed, complete, close, status
- State machine with enforced valid transitions
- Optional lifecycle comment posting to the GitHub issue thread
- Optional
lifecycle:<phase>label sync on the issue - All state stored as versioned swamp resources (state, context, classification, plan, pullRequest) — queryable via CEL
- PR number auto-extraction from URL
- Idempotent link_pr (safe to re-link after retry)
- Configurable via globalArgs: repo, postComments, syncLabels
- Has README or module doc2/2earned
- README has a code example1/1earned
- README is substantive1/1earned
- Most symbols documented1/1earned
- No slow types (deprecated)1/1earned
- Dependencies pass trust audit2/2earned
- Has description1/1earned
- Platform support declared (or universal)2/2earned
- License declared1/1earned
- Verified public repository2/2earned