wotai-dev/woterclip/heartbeat
Claude Code and agent skill by wotai-dev/woterclip
- community
Checking that the SKILL.md file is still in the repository.
This skill should be used when the user asks to "run a heartbeat", "run the agent loop", "process GitHub issues", "check for work", or runs the /heartbeat command. Executes the WoterClip heartbeat — picks up GitHub issues, resolves personas, does work, and reports back.
Install
npx vskill@latest install wotai-dev/woterclip/heartbeatSKILL.md
WoterClip Heartbeat
Execute the WoterClip heartbeat cycle: pick up assigned GitHub issues, resolve the right persona, do the work, and report back with structured comments. All GitHub operations go through the gh CLI — no MCP server required.
Arguments:
--dry-run— Show what would be picked up without doing work--persona <name>— Only pick issues matching a specific persona
Reference files (consult as needed during execution):
${CLAUDE_PLUGIN_ROOT}/references/comment-format.md— Comment templates and rules${CLAUDE_PLUGIN_ROOT}/references/label-conventions.md— Label lifecycle and atomic label operations${CLAUDE_PLUGIN_ROOT}/references/status-mapping.md— GitHub state model, sort order, inbox filtering${CLAUDE_PLUGIN_ROOT}/references/sub-issues.md— Canonical create/attach/verify procedure for sub-issues${CLAUDE_PLUGIN_ROOT}/references/persona-dispatch.md— Subagent dispatch, outcome contract, and fallback rules${CLAUDE_PLUGIN_ROOT}/references/beat-economics.md— Clock capture, time ceiling, stop reasons, log fields
All gh issue / gh api calls below target the repo from config github.repo (pass --repo <owner/name> explicitly — never rely on the working directory's default remote).
Step 1: Load Config & Lock
- Read
.woterclip/config.yaml. If missing, stop and instruct the user to run/woterclip-init. Nothing is created yet, so this exit records nothing. - Check for lockfile at
.woterclip/.heartbeat-lock.
- Exists and less than
stale_lock_hoursold → stop: "Previous heartbeat still active. Skipping." This beat never took the lock — do not delete it and do not record a beat line. - Exists and older than
stale_lock_hours→ delete it, log: "Cleaned stale lockfile." - No lockfile → proceed.
- Take the lock. This one command creates it and prints it, so the beat observes its own id and start epoch:
```bash printf '{"beat_id":"%s","started_at":"%s","started_epoch":%s}\n' \ "$(date -u +%s)-$$" "$(date -u +%Y-%m-%dT%H:%M:%SZ)" "$(date -u +%s)" \
`` Carry the printed beat_id and started_epoch` forward — they are the beat's identity and its clock.
- Ownership rule, applied at every exit from here on. Re-read
.woterclip/.heartbeat-lock. Delete it only if it still carries this beat's `beat_id`; if it is missing or carries another id, a later beat cleaned and re-took it — leave it alone. Deleting a lock this beat does not own hands two beats the same repo. - Every exit from here on records one beat line (step 9 format) naming that exit's stop reason, then applies the ownership rule.
--dry-runand a superseded beat record none. The exit-to-reason map is in${CLAUDE_PLUGIN_ROOT}/references/beat-economics.md. Beat elapsed is$(date -u +%s)minusstarted_epoch.
Check quiet hours: if quiet_hours.enabled and current time is within the quiet window:
behavior: "skip"→ record aquiet_hoursbeat line, apply the ownership rule, exit: "Quiet hours active. Skipping."behavior: "triage-only"→ proceed but only load Orchestrator persona (skip worker personas in step 3).
Step 2: Check Inbox
- Fetch open issues assigned to the authenticated user:
``bash gh issue list --repo <owner/name> --assignee @me --state open \ --json number,title,labels,createdAt --limit 100 ``
- Filter and sort client-side per
${CLAUDE_PLUGIN_ROOT}/references/status-mapping.md§ Filter Rules and § Sort Order (labels come from the JSON above). - Detect stale
agent-workinglabels: if an issue hasagent-workingbut no heartbeat comment withinstale_lock_hours, clean the stale label (gh issue edit N --remove-label agent-working, post cleanup comment).
Step 3: Pick Issue
- If
--persona <name>flag is set, filter to only issues matching that persona's label. - Pick the first issue from the sorted inbox.
- If
--dry-run, report what would be picked, then apply the ownership rule and exit. No beat occurred, so record no beat line:
`` Dry run — would pick: #12 [backend] "Issue title" (in-progress, priority:high) Queue: #15 [frontend] "Other issue" (todo) ``
- If no issues match → record a beat line (
queue_emptywhen zero issues were worked this beat, otherwisecompletewith the running count), apply the ownership rule, exit: "No issues in queue. Heartbeat complete."
Step 4: Resolve Persona
- Read the issue's labels. Find the persona label by matching against the
personasmap in config. - No persona label found → load the persona with
is_default: true(typically Orchestrator). - Load persona files from
.woterclip/<persona.path>/:
SOUL.md→ inject into context as identity instructionsTOOLS.md→ inject into context as tool guidanceconfig.yaml→ read runtime settings
The persona's config.yaml supplies model, thinking_effort, max_turns, and enable_chrome; how each feeds the step 8 dispatch is defined in ${CLAUDE_PLUGIN_ROOT}/references/persona-dispatch.md.
Step 5: Validate Tools
Read required_tools from persona config. Verify each entry by its kind:
gh→ verify withgh auth status(exit 0) — this proves both the CLI and authenticationmcp__*entries (e.g.,mcp__neon) → these are MCP tool prefixes, not executables: verify by checking whether any tool starting with that prefix is available in the current session. Never runcommand -von anmcp__*name.- Other executables (e.g.,
docker) → verify withcommand -v <tool>
If `gh` itself is unavailable or unauthenticated: no GitHub mutation is possible — do not attempt the blocked-comment path (it needs gh). Record a blocked_exit beat line, apply the ownership rule, and exit with an error message telling the user to run gh auth login. (Same rule as the mid-work failure in step 8.)
If any other required tool is unavailable → stop work on this issue immediately:
- Post a blocked comment naming the missing tool
- Apply
agent-blockedlabel, removeagent-workingif present:
gh issue edit N --add-label agent-blocked --remove-label agent-working
- Proceed to step 11 (next issue). This is not a beat exit — record no beat line and do not touch the lockfile; the beat's stop reason still comes from step 11.
Step 6: Lock Issue
- Read the issue's current labels:
gh issue view N --json labels --jq '.labels[].name'. - If
agent-workingis already present (from a previous heartbeat on same issue), proceed. - Otherwise:
gh issue edit N --add-label agent-working(atomic — no need to rewrite the label set).
Step 7: Understand Context
- Run
date -u +%sand carry the printed value as this issue's start epoch — it covers the dispatch. Separate from the beat clock in the lockfile. - Read issue title, body, and all comments:
gh issue view N --json title,body,comments. - If the issue is a sub-issue, read its parent for broader context: follow the
Parent: #Nreference in the issue body (guaranteed by the sub-issue creation procedure in${CLAUDE_PLUGIN_ROOT}/references/sub-issues.md), thengh issue view <parent> --json title,body,comments. - Identify new comments since the last heartbeat (look for comments after the last WoterClip-formatted comment).
- Parse heartbeat counter: find the last comment matching
Heartbeat #Npattern. Next comment will be#N+1. If none found, start at#1.
Step 8: Do Work
Dispatch the work to a persona subagent per ${CLAUDE_PLUGIN_ROOT}/references/persona-dispatch.md — prompt composition, the model parameter, fallback, error handling, and the outcome contract are all defined there. The branch shape:
- Dispatch on the persona's
model; the subagent returns a structured outcome that steps 9–10 consume. - Refused at invocation — no subagent primitive, or override rejected before execution began → work inline on the session model; record the fallback for the step 9 report (never block the issue for this reason alone).
- Failure after execution may have begun, or unparseable outcome → treat as a blocked outcome (step 10 blocked path); when indeterminate, prefer blocked — re-running inline could duplicate work.
The work itself — wherever it runs — follows the persona's SOUL.md instructions and varies by persona:
Orchestrator persona: Triage the issue – apply persona labels, create sub-issues, or escalate. Never write code.
CEO persona: Make strategic decisions – prioritization, scope, architecture, coordination. Never write code.
Worker personas (backend, frontend, etc.):
- Use repo tools (Read, Write, Edit, Bash, Grep, Glob) to implement changes
- For large scope: decompose into GitHub sub-issues following
${CLAUDE_PLUGIN_ROOT}/references/sub-issues.md(create with--assignee @me+ persona label +Parent: #Nbody reference, attach by issue ID with-F sub_issue_id=, verify the attach, summarize in your returned outcome) - For small scope: work directly, use internal tasks to track progress
- Commit changes with descriptive conventional commit messages
- Respect
max_turnsfrom persona config as a work budget
If `gh` auth expires or GitHub API errors persist mid-work: Stop immediately. Leave agent-working in place (cleaned as stale by a later beat). Record a blocked_exit beat line, apply the ownership rule, exit.
Step 9: Report
Before posting, re-read the lockfile and confirm it still carries this beat's beat_id, and that the issue still carries agent-working. If a later beat superseded this one, exit silently — no comment, no beat line, no lock deletion; all three are the successor's. A beat line here would close its in-flight group. If the report post itself fails with persistent gh errors, follow the step 8 mid-work rule.
Post a structured comment on the GitHub issue: gh issue comment N --repo <owner/name> --body "...".
Follow the comment format from ${CLAUDE_PLUGIN_ROOT}/references/comment-format.md:
- Include
Heartbeat #Ncounter (incremented from step 7) - Include timestamp and duration
- Include the
**Model:**line naming the model that performed the work — the loop's dispatch parameter (session model on fallback, naming both configured and actual); the subagent's self-reported model is advisory only - Include persona name in footer
- List commits with SHAs, sub-issues created, and next steps
- For blocked status: @-mention who needs to act (Board user's login from
github.board_user) and include the required `Clears when:` line naming what will unblock the issue
Append an issue line to .woterclip/heartbeat-log.jsonl — one per issue worked. duration_sec is date -u +%s now, minus the start epoch printed at step 7 — seconds on this issue, not the beat's cost:
At each beat exit that still owns its lock — step 3, 5, 8, 9, or 11 — append exactly one beat line. Field, exception, and stop-reason definitions are in ${CLAUDE_PLUGIN_ROOT}/references/beat-economics.md:
Step 10: Update State
Read the issue's current labels (gh issue view N --json labels), then update based on outcome:
Transitions are defined in ${CLAUDE_PLUGIN_ROOT}/references/status-mapping.md § WoterClip Outcomes. Two ordering rules the loop must honor:
This is the start of the file. Read the full SKILL.md on GitHub.
Security
- Security scanPassed, 100 of 100Pattern checks on the skill's files.
- Model reviewNot runA model review is scheduled for the next rescan.
Quality evaluation
- Task evaluationNot runNo evaluation yet. Run one in Skill Studio.
Source
- SKILL.md in the repositoryCheckingskills/heartbeat/SKILL.md
Popularity
- Repository stars
- 59
- Repository forks
- 8
- 7-day trend score
- 20
Stars and forks are for the whole GitHub repository, not this skill alone. Not refreshed yet.
Works with
Any agent vskill installs to: 56 targets in all. These 39 have a page on this site.
- Claude Code
- Cursor
- GitHub Copilot
- Windsurf
- Codex
- Gemini CLI
- Cline
- Amp
- Roo Code
- Goose
- Continue
- Kilo Code
- Junie
- Trae
- OpenHands
- Qwen Code
- AI Agent
- Tabnine Chat
- Sourcegraph Cody
- Amazon Q
- Firebase Genkit
- Sweep
- Devin
- Phind
- Mentat
- Claude Desktop
- Aider
- GPT Pilot
- Plandex
- bolt.new
- v0
- Replit Agent
- Anse
- TypingMind
- BetterChatGPT
- LibreChat
- Warp AI
- Pieces
- Fig AI
Embed badge
[](https://verified-skill.com/skills/wotai-dev/woterclip/heartbeat)