skills/golem-powers/cron-payload-discipline/SKILL.md
Use when writing or reviewing any cron, /loop, recurring monitor payload, merge/worker queue tick, or freeze-prone cmux monitor. Enforces loop discipline: live-query-first frames, no hardcoded state strings, drive-to-completion outcomes, verified counter resets, one full-read freeze rotation, and timestamped stale-tick detection.
npx skillsauth add etanhey/golems cron-payload-disciplineInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Cron payloads must query reality first. If the prompt already claims the state, the loop is rotten before it runs.
/loop, cron tick, or recurring monitor payloadAnthropic-native ! preprocessing is the foundation here:
"The
!syntax runs shell commands before the skill content is sent to Claude."
That means the payload should render live facts before Claude reasons about them. Claude should see current data, not a baked claim like BLOCKED REVIEW_REQUIRED.
Never hardcode state strings inside a cron payload when the state can be queried live.
Forbidden examples:
PR #123 is BLOCKED REVIEW_REQUIRED3 PRs are waiting at merge gatesurface:7 is idleno collab changes since last tickRequired replacement pattern:
Tick frame:
- now: $(date -Iseconds)
- cycle: <N>
- last-action-timestamp: <ISO-8601>
Step 1: run a live query with `!`
!gh pr view <repo> <pr> --json mergeable,mergeStateStatus,reviewDecision
!list_surfaces
!find <dir> -newer <last-action-timestamp>
!brain_search "<topic>"
Step 2: reason from the rendered output, not from the template text
Step 3: dispatch, verify-and-decrement, or escalate-park based on the live result
For monitor loops, extend the frame:
- last-genuine-dispatch-time: <ISO-8601>
- consecutive-no-change-ticks: <N>
- consecutive-no-push-ticks: <N>
- park-threshold: <N>
Step 1 in every cron payload must execute a live query.
Acceptable first-step queries:
!gh pr view!gh pr list!list_surfaces!read_screen!find <dir> -newer <timestamp>!brain_searchIf step 1 is explanation, status narration, or a pre-baked claim, the payload is invalid.
Do not embed review state, merge state, agent state, or queue state as facts in the payload body.
Allowed:
REVIEW_REQUIRED, dispatch reviewer follow-up."Not allowed:
REVIEW_REQUIRED, keep waiting."Any review-dispatch payload must identify the PR by immutable head, not only by branch name. Branch names can be renamed or force-pushed mid-review; PR #453's review prompt named a branch that had already drifted.
Required payload data:
headRefNameheadRefOidAllowed target forms:
headRefOid=<sha> from gh pr view <N> --json headRefName,headRefOid,baseRefName,urlrefs/pull/<N>/head plus a cross-check that git ls-remote origin refs/pull/<N>/head
matches headRefOidForbidden:
<name>" as the only targetEvery recurring payload must include:
$(date) or equivalent rendered current timestamplast-action-timestampWithout these, identical frames are hard to distinguish from a stuck loop.
The payload's branching logic must reference the output of the live query, not a static narrative written above it.
Good:
!gh pr view reports mergeable=MERGEABLE, dispatch merge."Bad:
Every recurring monitor tick must end in exactly one primary outcome:
| Outcome | Use when | Required side-effect |
|---|---|---|
| dispatch | Live data shows a specific unblock or next action | Send one targeted instruction and update last-genuine-dispatch-time |
| verify-and-decrement | Progress is claimed or implied but not proven | Read the source of truth; decrement/reset only if the side-effect exists |
| escalate-park | Repeated ticks show no material queue delta | Escalate once with the exact blocker, then park/kill the loop branch |
Passive output like "I'm monitoring", "still watching", or repeated SILENT
with no decision context is invalid.
Reset consecutive-no-change-ticks and consecutive-no-push-ticks only after a
real queue decrement:
No-op pings, identical telemetry, timestamp changes, and worker replies like "still looking" are not progress.
Repeated parsed_only output, unchanged token counts, or quiet panes are hints,
not verdicts. When several surfaces look frozen:
parsed_only_signature, consecutive_matching_parsed_ticks,
last_full_read_time, last_full_read_summary,
last_known_long_running_op, and idle_candidate_since.active, idle-candidate, long-running, or
unknown-needs-recheck.Idle requires both:
›, >, or $)60sKnown long-running operations (tests, builds, installs, deploys, migrations)
park the monitor branch, not the worker. Record the operation and re-check after
15m unless a stronger signal arrives.
If a cron payload exceeds 30 lines and does not run a live query in step 1, treat it as a violation and rewrite it before use.
When a payload violates this skill:
$(date), cycle, last-action-timestamp.! live query to step 1.dispatch, verify-and-decrement, or escalate-park.| Anti-pattern | Why it fails | Fix |
|---|---|---|
| "Monitor pass: 3 PRs blocked" | Prompt claims state before checking it | Replace with !gh pr list/view in step 1 |
| 40-line cron prompt, live query in step 6 | Stale framing dominates reasoning | Put live query in step 1 |
| SILENT autonomous repeated with no timestamps | Cannot tell fresh tick from copied frame | Add $(date), cycle, last-action-timestamp |
| BLOCKED REVIEW_REQUIRED copied from yesterday | Model parrots stale state | Query review state live every tick |
| Resetting because a worker replied "looking" | Reply is not queue-decrement | Keep counting until a side-effect is verified |
| Parsed-only wrapper says idle | Wrapper text is telemetry, not truth | Rotate one full read onto the worst offender |
| Token count frozen, so worker is idle | Tool calls may continue without token movement | Full-read before any idle verdict |
| Build output stable for 2 minutes | Long-running ops can look unchanged | Park monitor branch and re-check later |
| Skill | How it composes |
|---|---|
| /never-fabricate | Prevents reporting prompt-state as verified reality |
| /cmux-agents | Supplies surface/agent inspection and prompt-delivery mechanics |
| /pr-loop | Merge queues should use these tick rules before claiming PR state |
tools
The human-eval UX contract for Phoenix views: turn-by-turn scrollable replay (not a scorecard), hide-but-copyable IDs, collapsed thinking, identity chips, tool filters, tiny frozen starter datasets, mark-wrong-in-thread, mobile-first. Use when: building or reviewing ANY Phoenix/eval view, annotation UI, session replay, or human-grading surface. Triggers: phoenix view, eval UI, annotation view, session replay, human eval UX, grading interface. NOT for: Phoenix data pipelines/ingest (capture scripts have their own specs).
tools
macOS systems specialist — AppKit NSPanel architecture, launchd services, socket activation, MCP bridge resilience, syspolicyd, and high-frequency SwiftUI dashboards. Use when building menu-bar apps, LaunchAgents, debugging syspolicyd/Gatekeeper/TCC, resilient UDS/MCP bridges, or SwiftUI dashboards at 10Hz+.
development
Bulk LLM-judging protocol for fleet-dispatched verdict runs (KG cluster, eval harness). Use when: dispatching or running judge workers (J1/J2/RT), planning bulk-apply from verdict JSONL, or triaging evidence_degraded outputs. Triggers: judge fleet, bulk judge, R3 verdicts, kg-judge, RT gate, evidence_degraded. NOT for: single-item code review, Phoenix view UX (use phoenix-human-view), or non-judge eval pipelines.
development
Quiet-down protocol for sprint close: when the fleet wraps, delete ALL polling crons and monitors, send ONE final dashboard + ONE message, then go SILENT. Use when: fleet wraps, all workers done, overnight queue exhausted, sprint close, Etan asleep/away with nothing approved left. Triggers: fleet wrap, wrap the fleet, stand down, going quiet, sprint close. NOT for: mid-sprint monitoring (keep your loops), spawning a successor (use /session-handoff first).