wotai-dev/woterclip/heartbeat

Claude Code and agent skill by wotai-dev/woterclip

Trust tier 2
  • community
LLM review pending
Source check pending

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/heartbeat

SKILL.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

  1. Read .woterclip/config.yaml. If missing, stop and instruct the user to run /woterclip-init. Nothing is created yet, so this exit records nothing.
  2. Check for lockfile at .woterclip/.heartbeat-lock.
  • Exists and less than stale_lock_hours old → 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.
  1. 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.

  1. 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.
  2. Every exit from here on records one beat line (step 9 format) naming that exit's stop reason, then applies the ownership rule. --dry-run and 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) minus started_epoch.

Check quiet hours: if quiet_hours.enabled and current time is within the quiet window:

  • behavior: "skip" → record a quiet_hours beat 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

  1. 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 ``

  1. Filter and sort client-side per ${CLAUDE_PLUGIN_ROOT}/references/status-mapping.md § Filter Rules and § Sort Order (labels come from the JSON above).
  2. Detect stale agent-working labels: if an issue has agent-working but no heartbeat comment within stale_lock_hours, clean the stale label (gh issue edit N --remove-label agent-working, post cleanup comment).

Step 3: Pick Issue

  1. If --persona <name> flag is set, filter to only issues matching that persona's label.
  2. Pick the first issue from the sorted inbox.
  3. 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) ``

  1. If no issues match → record a beat line (queue_empty when zero issues were worked this beat, otherwise complete with the running count), apply the ownership rule, exit: "No issues in queue. Heartbeat complete."

Step 4: Resolve Persona

  1. Read the issue's labels. Find the persona label by matching against the personas map in config.
  2. No persona label found → load the persona with is_default: true (typically Orchestrator).
  3. Load persona files from .woterclip/<persona.path>/:
  • SOUL.md → inject into context as identity instructions
  • TOOLS.md → inject into context as tool guidance
  • config.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 with gh auth status (exit 0) — this proves both the CLI and authentication
  • mcp__* 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 run command -v on an mcp__* name.
  • Other executables (e.g., docker) → verify with command -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-blocked label, remove agent-working if 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

  1. Read the issue's current labels: gh issue view N --json labels --jq '.labels[].name'.
  2. If agent-working is already present (from a previous heartbeat on same issue), proceed.
  3. Otherwise: gh issue edit N --add-label agent-working (atomic — no need to rewrite the label set).

Step 7: Understand Context

  1. Run date -u +%s and carry the printed value as this issue's start epoch — it covers the dispatch. Separate from the beat clock in the lockfile.
  2. Read issue title, body, and all comments: gh issue view N --json title,body,comments.
  3. If the issue is a sub-issue, read its parent for broader context: follow the Parent: #N reference in the issue body (guaranteed by the sub-issue creation procedure in ${CLAUDE_PLUGIN_ROOT}/references/sub-issues.md), then gh issue view <parent> --json title,body,comments.
  4. Identify new comments since the last heartbeat (look for comments after the last WoterClip-formatted comment).
  5. Parse heartbeat counter: find the last comment matching Heartbeat #N pattern. 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:

  1. Dispatch on the persona's model; the subagent returns a structured outcome that steps 9–10 consume.
  2. 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).
  3. 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: #N body 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_turns from 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 #N counter (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:

json
{"heartbeat": N, "timestamp": "ISO", "issue": "#12", "persona": "name", "duration_sec": N, "status": "in_progress|completed|blocked|triaged|decomposed", "actions": ["description"]}

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:

json
{"type": "beat", "started_at": "ISO", "ended_at": "ISO", "beat_elapsed_sec": N, "issues_worked": N, "stop_reason": "time_ceiling"}

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

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
vskill VERIFIED badge
[![vskill VERIFIED](https://verified-skill.com/api/v1/skills/wotai-dev/woterclip/heartbeat/badge)](https://verified-skill.com/skills/wotai-dev/woterclip/heartbeat)

Something wrong with this skill or its page? Tell us.