Skip to content

/heartbeat

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.

From plugin
567 skills1 agents3 commands
shell
$ npx -y skills add wotai-dev/woterclip --skill heartbeat --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.
  • You can call itInvoke it directly when you want it.
  • Slash command/heartbeat
How auto-invocation works

Context preview

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

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.

SKILL.md

heartbeat.SKILL.md
name: heartbeat
description: 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.
version: 0.1.0

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.

3. Take the lock. This one command creates it **and prints it**, so the beat observes its own id and start epoch:

   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)" \
     | tee .woterclip/.heartbeat-lock

Carry the printed `beat_id` and `started_epoch` forward — they are the beat's identity and its clock. 4. **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. 5. **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:

   gh issue list --repo <owner/name> --assignee @me --state open \
     --json number,title,labels,createdAt --limit 100

2. Filter and sort client-side per `${CLAUDE_PLUGIN_ROOT}/references/status-mapping.md` § Filter Rules and § Sort Order (labels come from the JSON above). 3. 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)

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

Read more
Read it on GitHub ↗

Showing the first part of this file.

Ships withwoterclip

GitHub Issues-backed agent orchestration for Claude Code. A single Claude instance wears different "hats" (personas) based on GitHub issue labels – an Orchestrator routes work, a CEO makes strategic calls, and worker personas execute.

Get the whole plugin, auto-invoked
Stats
56
Stars
0
Views
8
Forks
Active
Maintenance
MIT
License
7d ago
Last commit
4mo ago
Created

Repo: wotai-dev/woterclip

Other skills on woterclip.