GitHub Integration
GitHub Integration — Usage Guide
Operational reference for running githubclip with the GitHub MCP provider.
Prerequisites
gh auth status # must show authenticated
ls .githubclip/config.yaml # must exist (run /githubclip-init if not)
cat .githubclip/config.yaml | head -3 # provider: github
Running the Heartbeat
/heartbeat --dry-run # preview queue without side effects
/heartbeat # pick top issue and do work
Dry-run is safe to run at any time. It reads the queue and prints what would be picked — no labels, comments, or field mutations.
How the Queue Works
githubclip fetches all GitHub Project items assigned to the configured user_name and filters to:
- Status:
TodoorIn Progressonly - No
agent-blockedlabel (unless new human comments have been posted since blocking)
Ranking order:
- Status (
In ProgressbeforeTodo) - Priority (
Urgent > High > Medium > Low > None) updated_atdescending (most recently updated wins ties)
Expected dry-run output:
Dry run — would pick:
#42 [backend] "Fix auth bug" (In Progress, High)
Queue:
#17 [frontend] "Update nav" (Todo, Medium)
#9 [orchestrator] "Triage inbox" (Todo, Low)
Persona Routing
Issues are routed based on their GitHub label:
| Label | Persona | Behavior |
|---|---|---|
backend |
Backend | Implementation, tests, APIs |
frontend |
Frontend | UI, components, styles |
ceo |
CEO | Architecture, strategy, prioritization |
| (none) | Orchestrator | Default — triages and routes unlabeled issues |
One persona label per issue. Orchestrator is always the fallback.
Heartbeat Comments
Every heartbeat posts a comment on the issue:
## Heartbeat #N — YYYY-MM-DD HH:MM UTC (Xm Ys)
**Status:** In Progress | Completed | Blocked
### What was done
- Description of work completed
### Next steps
- What comes next
### Blockers
None
---
*githubclip · persona-name · [#N](...) · from [Heartbeat #N-1](...)*
The counter N is derived from existing comments on the issue — not stored locally. It increments safely across restarts.
State Transitions
After work completes, the heartbeat updates Project fields and labels based on outcome:
| Outcome | Project Status | Labels |
|---|---|---|
completed |
Done |
remove agent-working |
blocked |
In Progress (unchanged) |
remove agent-working, add agent-blocked |
more_work |
In Progress (unchanged) |
keep agent-working |
triaged |
Todo (unchanged) |
add persona label (e.g. backend) |
agent-working and agent-blocked are mutually exclusive — the heartbeat manages this via read-modify-write on the labels array.
Anti-Fragile Behaviors
Degradation mode
If a Project field mutation fails, the heartbeat downgrades to read-only for that run. Comments are still posted and labels still applied; only field mutations are skipped. The comment will include a degradation marker (❌ Degraded).
Circuit breaker
After 3 consecutive field mutation failures, all future runs auto-downgrade to read-only. The circuit breaker resets after a successful run with a working config.
Stale lock cleanup
If agent-working has been on an issue longer than stale_lock_hours (default: 4 hours), the heartbeat removes it, posts a cleanup comment, and re-queues the issue.
Schema drift sentry
On startup the heartbeat validates that field IDs in config match the actual GitHub Project schema. On mismatch it stops early with a repair message — no mutations are attempted.
Debugging Live Issues
Check the queue manually
gh issue list --assigned @me --state open
gh project item-list PROJECT_NUMBER --owner OWNER
Check field values on an issue
gh api graphql -f query='
query {
node(id: "ISSUE_NODE_ID") {
... on Issue {
projectItems(first: 1) {
nodes {
fieldValues(first: 5) {
nodes {
... on ProjectV2ItemFieldSingleSelectValue {
name
field { ... on ProjectV2FieldCommon { name } }
}
}
}
}
}
}
}
}
'
Check heartbeat log
tail -20 .githubclip/heartbeat-log.jsonl | jq '.'
Each line is a JSON record: timestamp, issue, heartbeat, step, status.
Common issues
| Symptom | Check | Fix |
|---|---|---|
| No issues in queue | Issues assigned to you? In Project? Status = Todo/In Progress? | Assign issues, add to Project, set Status |
| Wrong queue order | Project Priority/Status values correct? | Update fields via Project UI |
| Field mutations not working | field_id values null in config? |
Re-run /githubclip-init (merge mode) |
| Stuck in read-only | Circuit breaker active? | Fix config, run /heartbeat once to reset |
| Persona not routing | Label exactly matches config key? | Check cat .githubclip/config.yaml \| grep personas -A 20 |
Refreshing Config
If Project fields are renamed or IDs drift, re-run init in merge mode:
/githubclip-init # choose "merge" when prompted
Merge mode only adds missing values — it never deletes existing ones. It is safe to run at any time.