mastermind _repeat command (monomind)
Scanned 9/10/2026
Install to Claude Code
npx -y skills add monoes/monomind --skill monomind-monomind-monomind-mastermind-repeat --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Monomind Monomind Monomind Mastermind Repeat?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/monoes-monomind-monomind-monomind-mastermind-repeat)More formats (shields.io, HTML) on the badges page.
---
description: mastermind _repeat command (monomind)
type: flow
name: monomind-monomind-monomind-mastermind-repeat
---
<!-- Shared inter-session repeat protocol. Referenced by mastermind and monomind commands via "Follow the Repeat Preamble/Postamble from mastermind-repeat/SKILL.md". -->
## Shared Repeat Protocol
Adds `--repeat <N> --wait <seconds>` and `--tillend --wait <seconds>` inter-session looping to any command. Uses `ScheduleWakeup` to pause between runs and `.monomind/loops/<id>.json` for dashboard tracking.
---
## REPEAT PREAMBLE
Apply immediately after flag extraction, before any other command logic.
### 1. Extract repeat flags
Extract and remove these flags from `$ARGUMENTS` before passing the remainder to the command's own parser:
| Flag | Variable | Default | Notes |
|---|---|---|---|
| `--repeat <N>` | `repeat_count` | `0` | N ≥ 2 activates repeat; N < 2 = disabled |
| `--tillend` | `tillend_mode` | `false` | Run until empty round (no findings, no actions). Overrides --repeat. |
| `--maxruns <N>` | `tillend_maxruns` | `50` | Safety cap for --tillend; stops after N runs even if AI hasn't signaled done |
| `--wait <seconds>` | `wait_seconds` | `60` | Minimum 60 (enforced by ScheduleWakeup) |
| `--rep <N>` | `current_rep` | absent | Internal; injected by ScheduleWakeup on continuation runs |
| `--loop <id>` | `loop_id` | absent | Internal; preserves loop identity across runs |
If both `--tillend` and `--repeat <N>` are present, `--tillend` takes precedence.
### 2. If `--rep N` is present (continuation run)
- Set `current_rep` = N, `loop_id` from `--loop <id>`
- Set `is_continuation = true`
- The calling command MUST skip its empty-prompt check and intake when `is_continuation = true`
**First — staleness guard (run before anything else):**
Check whether the loop file exists and whether this wakeup is stale:
```bash
LOOP_FILE=".monomind/loops/${LOOP_ID}.json"
if [ ! -f "$LOOP_FILE" ]; then
echo "[repeat] Stale wakeup: loop ${LOOP_ID} is already complete (state file gone). Skipping."
# STOP — do not execute the command
else
LOOP_CURRENT_REP=$(python3 -c "import json; print(json.load(open('${LOOP_FILE}'))['currentRep'])" 2>/dev/null \
|| jq -r '.currentRep // 0' "${LOOP_FILE}" 2>/dev/null || echo "0")
if [ "${current_rep}" -lt "${LOOP_CURRENT_REP}" ]; then
echo "[repeat] Stale wakeup: got --rep ${current_rep} but loop is already at rep ${LOOP_CURRENT_REP}. Skipping."
# STOP — do not execute the command
fi
fi
```
If the stale guard fires (either branch): **STOP immediately. Do not proceed to HIL check or command execution.**
**Before proceeding, check for a pending HIL file:**
```bash
HIL_FILE=".monomind/loops/${LOOP_ID}-hil.md"
LOOP_HIL_PENDING=false
LOOP_HIL_ANSWERED=false
if [ -f "$HIL_FILE" ]; then
RESPONSES=$(grep -cE "^[[:space:]]*>[[:space:]]+[^[:space:]]" "$HIL_FILE" 2>/dev/null)
RESPONSES=${RESPONSES:-0}
if [ "$RESPONSES" -eq 0 ]; then
LOOP_HIL_PENDING=true
else
LOOP_HIL_ANSWERED=true
fi
fi
```
**If `LOOP_HIL_PENDING=true` (HIL file exists but unanswered):**
- Output (tillend mode): `[tillend] Loop paused before run <current_rep>: waiting for human responses in ${HIL_FILE}.`
- Output (fixed-count mode): `[repeat] Loop paused before run <current_rep>/<repeat_count>: waiting for human responses in ${HIL_FILE}.`
- Update state file:
```bash
python3 -c "import json; f='.monomind/loops/${LOOP_ID}.json'; d=json.load(open(f)); d['status']='hil:pending'; open(f,'w').write(json.dumps(d,indent=2))" 2>/dev/null \
|| jq '.status="hil:pending"' ".monomind/loops/${LOOP_ID}.json" > ".monomind/loops/${LOOP_ID}.json.tmp" && mv ".monomind/loops/${LOOP_ID}.json.tmp" ".monomind/loops/${LOOP_ID}.json" 2>/dev/null || true
```
- Emit `loop:hil:waiting`:
```bash
REPO_ROOT=$(git rev-parse --show-toplevel 2>/dev/null || pwd)
CTRL_URL=$(jq -r '.url // "http://localhost:4242"' "$REPO_ROOT/.monomind/control.json" 2>/dev/null || echo "http://localhost:4242")
curl -s -X POST "${CTRL_URL}/api/mastermind/event" -H "x-monomind-token: $(cat "${REPO_ROOT:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/.monomind/dashboard-token" 2>/dev/null || true)" \
-H "Content-Type: application/json" \
-d "{\"type\":\"loop:hil:waiting\",\"loopId\":\"${LOOP_ID}\",\"hilFile\":\"${HIL_FILE}\",\"rep\":<current_rep>,\"ts\":$(date +%s)000}" || true
```
- Re-schedule a check (not a full run) using ScheduleWakeup:
- `delaySeconds`: `min(wait_seconds, 300)` — check at most every 5 minutes
- `prompt`: same full continuation prompt (same `--rep <N>`)
- `reason`: tillend mode: `"HIL pending for /<command> tillend run <current_rep> — re-checking"` / fixed-count: `"HIL pending for /<command> run <current_rep>/<repeat_count> — re-checking"`
- STOP. Do not execute the command yet.
**If `LOOP_HIL_ANSWERED=true` (human responded):**
- Output: `[repeat] Human response received. Archiving HIL file and resuming.`
- Archive: `mv "$HIL_FILE" ".monomind/loops/${LOOP_ID}-hil-resolved-$(date +%s).md"`
- Emit `loop:hil:resolved`:
```bash
REPO_ROOT=$(git rev-parse --show-toplevel 2>/dev/null || pwd)
CTRL_URL=$(jq -r '.url // "http://localhost:4242"' "$REPO_ROOT/.monomind/control.json" 2>/dev/null || echo "http://localhost:4242")
curl -s -X POST "${CTRL_URL}/api/mastermind/event" -H "x-monomind-token: $(cat "${REPO_ROOT:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/.monomind/dashboard-token" 2>/dev/null || true)" \
-H "Content-Type: application/json" \
-d "{\"type\":\"loop:hil:resolved\",\"loopId\":\"${LOOP_ID}\",\"rep\":<current_rep>,\"ts\":$(date +%s)000}" || true
```
- Update state file:
```bash
python3 -c "import json; f='.monomind/loops/${LOOP_ID}.json'; d=json.load(open(f)); d['status']='running'; open(f,'w').write(json.dumps(d,indent=2))" 2>/dev/null \
|| jq '.status="running"' ".monomind/loops/${LOOP_ID}.json" > ".monomind/loops/${LOOP_ID}.json.tmp" && mv ".monomind/loops/${LOOP_ID}.json.tmp" ".monomind/loops/${LOOP_ID}.json" 2>/dev/null || true
```
- Proceed to execute the command:
- Tillend mode: `[tillend] Run <current_rep> of /<command> starting...`
- Fixed-count: `[repeat] Run <current_rep>/<repeat_count> of /<command> starting...`
**If no HIL file:**
- Tillend mode: `[tillend] Run <current_rep> of /<command> starting...`
- Fixed-count: `[repeat] Run <current_rep>/<repeat_count> of /<command> starting...`
Proceed to the command's core logic.
### 3. If `--rep` is absent — first run
**Branch A: `tillend_mode = true`** OR **Branch B: `repeat_count ≥ 2`**
If neither condition is true, skip to Section 4.
1. Generate loop ID and write state file:
```bash
mkdir -p .monomind/loops
# Portable millisecond timestamp (BSD date has no %N; GNU date has %3N)
NOW_MS=$(python3 -c 'import time;print(int(time.time()*1000))' 2>/dev/null || echo "$(date +%s)000")
LOOP_ID="<command_slug>-${NOW_MS}"
# Dashboard expects interval in MINUTES (rounded)
INTERVAL_MIN=$(( (<wait_seconds> + 30) / 60 ))
PROMPT_JSON=$(printf '%s' "<prompt>" | python3 -c "import sys,json; print(json.dumps(sys.stdin.read()))" 2>/dev/null \
|| printf '%s' "<prompt>" | node -e "process.stdout.write(JSON.stringify(require('fs').readFileSync('/dev/stdin','utf8')))" 2>/dev/null \
|| printf '"%s"' "$(printf '%s' "<prompt>" | sed 's/\\/\\\\/g; s/"/\\"/g; s/$/\\n/g' | tr -d '\n' | sed 's/\\n$//')")
```
**If `tillend_mode = true`:**
```bash
cat > ".monomind/loops/${LOOP_ID}.json" << EOF
{
"id": "${LOOP_ID}",
"sessionId": "${LOOP_ID}",
"type": "tillend",
"command": "/<command>",
"prompt": ${PROMPT_JSON},
"maxReps": <tillend_maxruns>,
"interval": ${INTERVAL_MIN},
"wait": <wait_seconds>,
"currentRep": 1,
"startedAt": ${NOW_MS},
"lastRunAt": ${NOW_MS},
"nextRunAt": ${NOW_MS},
"status": "running",
"source": "mastermind-repeat/SKILL.md"
}
EOF
```
**If `repeat_count ≥ 2` (fixed-count mode):**
```bash
cat > ".monomind/loops/${LOOP_ID}.json" << EOF
{
"id": "${LOOP_ID}",
"sessionId": "${LOOP_ID}",
"type": "repeat",
"command": "/<command>",
"prompt": ${PROMPT_JSON},
"maxReps": <repeat_count>,
"interval": ${INTERVAL_MIN},
"wait": <wait_seconds>,
"currentRep": 1,
"startedAt": ${NOW_MS},
"lastRunAt": ${NOW_MS},
"nextRunAt": ${NOW_MS},
"status": "running",
"source": "mastermind-repeat/SKILL.md"
}
EOF
```
2. Emit `loop:start` to dashboard (failure is non-fatal):
```bash
REPO_ROOT=$(git rev-parse --show-toplevel 2>/dev/null || pwd)
CTRL_URL=$(jq -r '.url // "http://localhost:4242"' "$REPO_ROOT/.monomind/control.json" 2>/dev/null || echo "http://localhost:4242")
# For tillend mode, repeat field is the safety cap
REPEAT_VAL=$( [ "<tillend_mode>" = "true" ] && echo "<tillend_maxruns>(cap)" || echo "<repeat_count>" )
curl -s -X POST "${CTRL_URL}/api/mastermind/event" -H "x-monomind-token: $(cat "${REPO_ROOT:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/.monomind/dashboard-token" 2>/dev/null || true)" \
-H "Content-Type: application/json" \
-d "{\"type\":\"loop:start\",\"loopId\":\"${LOOP_ID}\",\"command\":\"/<command>\",\"mode\":\"$( [ '<tillend_mode>' = 'true' ] && echo 'tillend' || echo 'repeat' )\",\"repeat\":\"${REPEAT_VAL}\",\"wait\":<wait_seconds>,\"ts\":$(date +%s)000}" || true
```
3. Set `current_rep` = 1, `is_continuation` = false
4. Output:
- **tillend mode**: `[tillend] Starting tillend loop for /<command> (runs until empty round, safety cap: <tillend_maxruns>, <wait_seconds>s between runs). Run 1...`
- **fixed-count mode**: `[repeat] Starting <repeat_count> runs of /<command> (<wait_seconds>s between each). Run 1/<repeat_count>...`
### 4. If neither `tillend_mode` nor `repeat_count ≥ 2`
No repeat behavior. Proceed normally. The REPEAT POSTAMBLE is a no-op.
---
## REPEAT POSTAMBLE
Apply after the command's core logic fully completes (after skill returns, after final step, etc.).
**If neither `tillend_mode` nor `repeat_count ≥ 2`:** skip this section entirely.
**Otherwise:**
### 1. Check for stop request
```bash
[ -f ".monomind/loops/${LOOP_ID}.stop" ] && REPEAT_STOP=true
```
If `REPEAT_STOP=true`:
- Output: `[repeat] Stop requested. Halting after run <current_rep>/<repeat_count>.`
- `rm -f ".monomind/loops/${LOOP_ID}.json" ".monomind/loops/${LOOP_ID}.stop"`
- STOP.
### 2. Report this run complete
Output:
- Tillend mode: `[tillend] Run <current_rep> complete.`
- Fixed-count: `[repeat] Run <current_rep>/<repeat_count> complete.`
### 3. Detect HIL items from this run
Check for files written since this run started that signal human decisions are needed:
```bash
# Collect any humaninloop*.md files created or modified in the last 600 seconds
RECENT_HIL=$(find . -maxdepth 3 \( -name "humaninloop*.md" -o -name "humaninloopreview*.md" \) \
-newer ".monomind/loops/${LOOP_ID}.json" 2>/dev/null | head -10)
```
**If `RECENT_HIL` is non-empty (HIL items were written by this run):**
1. Write a loop HIL file aggregating all items:
```bash
HIL_FILE=".monomind/loops/${LOOP_ID}-hil.md"
# Use run label appropriate to mode
RUN_LABEL=$( [ "<tillend_mode>" = "true" ] && echo "run <current_rep> (tillend)" || echo "run <current_rep>/<repeat_count>" )
cat > "$HIL_FILE" << EOF
# Human-in-Loop — /<command> ${RUN_LABEL}
Loop: ${LOOP_ID}
Created: $(date -u +"%Y-%m-%d %H:%M UTC")
Status: pending
The following files contain items requiring human decisions before the loop continues:
$(echo "$RECENT_HIL" | while IFS= read -r f; do [ -n "$f" ] && echo "- \`$f\`"; done)
## Instructions
1. Open each file listed above and fill in **Your response** for each item.
2. Any non-empty response after a \`> \` line is treated as "answered".
3. Once you have filled in at least one response, the loop will auto-resume on the next check.
**Your answer (fill in to resume):**
>
EOF
```
2. Update state file:
```bash
python3 -c "import json; f='.monomind/loops/${LOOP_ID}.json'; d=json.load(open(f)); d['status']='hil:pending'; open(f,'w').write(json.dumps(d,indent=2))" 2>/dev/null \
|| jq '.status="hil:pending"' ".monomind/loops/${LOOP_ID}.json" > ".monomind/loops/${LOOP_ID}.json.tmp" && mv ".monomind/loops/${LOOP_ID}.json.tmp" ".monomind/loops/${LOOP_ID}.json" 2>/dev/null || true
```
3. Emit `loop:hil` to dashboard:
```bash
REPO_ROOT=$(git rev-parse --show-toplevel 2>/dev/null || pwd)
CTRL_URL=$(jq -r '.url // "http://localhost:4242"' "$REPO_ROOT/.monomind/control.json" 2>/dev/null || echo "http://localhost:4242")
curl -s -X POST "${CTRL_URL}/api/mastermind/event" -H "x-monomind-token: $(cat "${REPO_ROOT:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/.monomind/dashboard-token" 2>/dev/null || true)" \
-H "Content-Type: application/json" \
-d "{\"type\":\"loop:hil\",\"loopId\":\"${LOOP_ID}\",\"command\":\"/<command>\",\"hilFile\":\"${HIL_FILE}\",\"rep\":<current_rep>,\"files\":$(echo "$RECENT_HIL" | grep -v '^$' | jq -R . | jq -cs .),\"ts\":$(date +%s)000}" || true
```
4. Output:
```
[repeat] Human-in-loop items detected from run <current_rep>.
Action required: open the files listed in ${HIL_FILE} and fill in responses.
```
5. Compute `next_rep = current_rep + 1`. Build the HIL poll continuation prompt:
**If `tillend_mode = true`:**
- HIL continuation prompt: `/<command> --tillend --maxruns <tillend_maxruns> --wait <wait_seconds> --rep <next_rep> --loop ${LOOP_ID} <original prompt>`
- Output: `Loop will resume automatically once responses are provided.`
- `delaySeconds`: `min(wait_seconds, 300)`
- `reason`: `"HIL pending for /<command> tillend run <current_rep> — waiting for human response"`
- Schedule via `ScheduleWakeup` and STOP.
**If `current_rep >= repeat_count`** (HIL detected on the final fixed-count run):
- Output: `[repeat] All <repeat_count> runs of /<command> complete (HIL items pending in ${HIL_FILE}).`
- Emit `loop:complete`:
```bash
REPO_ROOT=$(git rev-parse --show-toplevel 2>/dev/null || pwd)
CTRL_URL=$(jq -r '.url // "http://localhost:4242"' "$REPO_ROOT/.monomind/control.json" 2>/dev/null || echo "http://localhost:4242")
curl -s -X POST "${CTRL_URL}/api/mastermind/event" -H "x-monomind-token: $(cat "${REPO_ROOT:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/.monomind/dashboard-token" 2>/dev/null || true)" \
-H "Content-Type: application/json" \
-d "{\"type\":\"loop:complete\",\"loopId\":\"${LOOP_ID}\",\"command\":\"/<command>\",\"ranReps\":<repeat_count>,\"hilPending\":true,\"ts\":$(date +%s)000}" || true
```
- `rm -f ".monomind/loops/${LOOP_ID}.json"`
- STOP. (HIL file remains for human review; loop is done.)
**Otherwise** (HIL on an intermediate fixed-count run):
- Output: `Loop will resume automatically at run <next_rep>/<repeat_count> once responses are provided.`
- `delaySeconds`: `min(wait_seconds, 300)`
- `prompt`: `/<command> --repeat <repeat_count> --wait <wait_seconds> --rep <next_rep> --loop ${LOOP_ID} <original flags and prompt>`
- `reason`: `"HIL pending for /<command> run <current_rep>/<repeat_count> — waiting for human response"`
- Schedule via `ScheduleWakeup` and STOP.
**If `RECENT_HIL` is empty:** proceed to section 4.
---
### 4. Tillend completion check (tillend mode only)
**Skip this section if `tillend_mode` is not true.** Proceed to section 5.
**`LOOP_ASYNC_PENDING` escape hatch:** If the calling skill set `LOOP_ASYNC_PENDING=true` before invoking the postamble (because it spawned background agents whose results have not yet arrived in this turn), skip the empty-round check entirely — treat this round as non-empty and go directly to section 6 to schedule the next run. The next scheduled run will evaluate results from the agents that are currently in-flight. Output: `[tillend] Async work in flight — deferring empty-round check to run <next_rep>.`
After each run in tillend mode, evaluate whether this run produced **zero findings and zero actions**. The loop stops only when a complete round finds nothing new and makes no changes — not when the AI predicts there is nothing left.
<EXTREMELY-IMPORTANT>
**Anti-premature-stop rules:**
- "I think the work is done" is NOT a reason to stop. Only the checks below decide.
- "There's nothing more to find" is a PREDICTION, not an observation. Predictions do not stop loops.
- You MUST run the git verification command below. If git shows changes, the round is non-empty. Period.
- Only a round where git shows NO changes AND you confirm zero findings AND zero actions qualifies as empty.
</EXTREMELY-IMPORTANT>
**Step 4a — Machine verification (REQUIRED — run this command before any self-assessment):**
```bash
GIT_CHANGES=$(git diff --stat HEAD 2>/dev/null; git diff --cached --stat 2>/dev/null; git status --porcelain 2>/dev/null | grep -v '^\?\?' | head -20)
echo "GIT_CHANGES_DURING_RUN: ${GIT_CHANGES:-NONE}"
```
If `GIT_CHANGES` is non-empty, files were modified — `TILLEND_EMPTY=false` regardless of self-assessment. Skip directly to "Otherwise" below.
**Step 4b — Self-assessment (only if git shows no changes):**
Only if `GIT_CHANGES` was empty, answer these two questions about this run:
1. **Were any findings produced?** — issues found, problems detected, items identified, things flagged, errors reported, tasks discovered, security vulnerabilities found, etc.
2. **Were any actions taken?** — tasks created, content written, configs changed — anything not captured by git diff.
**Set `TILLEND_EMPTY=true` only if git shows no changes AND BOTH answers are "no".**
**Important:** If this round found things AND fixed them all, `TILLEND_EMPTY=false`. The loop must run once more to verify the fixes didn't introduce new issues. A "clean" prediction after a productive round is not enough — only an actually empty round stops the loop.
**If `TILLEND_EMPTY=true` (round produced nothing):**
- Output:
```
[tillend] Empty round — nothing found, nothing changed in run <current_rep>.
/<command> tillend loop complete (ran <current_rep> run(s)).
```
- Emit `loop:complete`:
```bash
REPO_ROOT=$(git rev-parse --show-toplevel 2>/dev/null || pwd)
CTRL_URL=$(jq -r '.url // "http://localhost:4242"' "$REPO_ROOT/.monomind/control.json" 2>/dev/null || echo "http://localhost:4242")
curl -s -X POST "${CTRL_URL}/api/mastermind/event" -H "x-monomind-token: $(cat "${REPO_ROOT:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/.monomind/dashboard-token" 2>/dev/null || true)" \
-H "Content-Type: application/json" \
-d "{\"type\":\"loop:complete\",\"loopId\":\"${LOOP_ID}\",\"command\":\"/<command>\",\"mode\":\"tillend\",\"ranReps\":<current_rep>,\"reason\":\"empty-round\",\"ts\":$(date +%s)000}" || true
```
- `rm -f ".monomind/loops/${LOOP_ID}.json"`
- STOP.
**If `current_rep >= tillend_maxruns` (safety cap reached):**
- Output:
```
[tillend] Safety cap reached (<tillend_maxruns> runs). Stopping loop.
If work is still incomplete, re-run: /<command> --tillend --maxruns <N> --wait <wait_seconds> <prompt>
```
- Emit `loop:complete`:
```bash
REPO_ROOT=$(git rev-parse --show-toplevel 2>/dev/null || pwd)
CTRL_URL=$(jq -r '.url // "http://localhost:4242"' "$REPO_ROOT/.monomind/control.json" 2>/dev/null || echo "http://localhost:4242")
curl -s -X POST "${CTRL_URL}/api/mastermind/event" -H "x-monomind-token: $(cat "${REPO_ROOT:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/.monomind/dashboard-token" 2>/dev/null || true)" \
-H "Content-Type: application/json" \
-d "{\"type\":\"loop:complete\",\"loopId\":\"${LOOP_ID}\",\"command\":\"/<command>\",\"mode\":\"tillend\",\"ranReps\":<current_rep>,\"reason\":\"safety-cap\",\"ts\":$(date +%s)000}" || true
```
- `rm -f ".monomind/loops/${LOOP_ID}.json"`
- STOP.
**Otherwise (`TILLEND_EMPTY=false` and cap not reached):**
- Output: `[tillend] Run <current_rep> produced work (findings or actions). Continuing...`
- Proceed to section 5 to schedule the next run.
---
### 5. Fixed-count: check if all runs done (`current_rep ≥ repeat_count`)
**Skip this section if `tillend_mode = true`** (tillend has no fixed count; section 4 handles its termination).
- Output: `[repeat] All <repeat_count> runs of /<command> complete.`
- `rm -f ".monomind/loops/${LOOP_ID}.json"`
- Emit `loop:complete`:
```bash
REPO_ROOT=$(git rev-parse --show-toplevel 2>/dev/null || pwd)
CTRL_URL=$(jq -r '.url // "http://localhost:4242"' "$REPO_ROOT/.monomind/control.json" 2>/dev/null || echo "http://localhost:4242")
curl -s -X POST "${CTRL_URL}/api/mastermind/event" -H "x-monomind-token: $(cat "${REPO_ROOT:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/.monomind/dashboard-token" 2>/dev/null || true)" \
-H "Content-Type: application/json" \
-d "{\"type\":\"loop:complete\",\"loopId\":\"${LOOP_ID}\",\"command\":\"/<command>\",\"ranReps\":<repeat_count>,\"ts\":$(date +%s)000}" || true
```
- STOP (do not schedule another run).
### 6. Schedule next run
Set `next_rep` = current_rep + 1.
Update state file (read `prompt` and `startedAt` from the existing file to preserve them):
```bash
# Portable millisecond timestamp (BSD date has no %N; GNU date has %3N)
NOW_MS=$(python3 -c 'import time;print(int(time.time()*1000))' 2>/dev/null || echo "$(date +%s)000")
NEXT_AT=$(( NOW_MS + <wait_seconds> * 1000 ))
INTERVAL_MIN=$(( (<wait_seconds> + 30) / 60 ))
LOOP_TYPE=$( [ "<tillend_mode>" = "true" ] && echo "tillend" || echo "repeat" )
MAX_REPS=$( [ "<tillend_mode>" = "true" ] && echo "<tillend_maxruns>" || echo "<repeat_count>" )
PROMPT_JSON=$(jq '.prompt' ".monomind/loops/${LOOP_ID}.json" 2>/dev/null \
|| python3 -c "import json,sys; json.dump(json.load(open('.monomind/loops/${LOOP_ID}.json'))['prompt'], sys.stdout)" 2>/dev/null \
|| echo '"<prompt>"')
STARTED_AT=$(jq '.startedAt' ".monomind/loops/${LOOP_ID}.json" 2>/dev/null \
|| python3 -c "import json; print(json.load(open('.monomind/loops/${LOOP_ID}.json'))['startedAt'])" 2>/dev/null \
|| echo "${NOW_MS}")
cat > ".monomind/loops/${LOOP_ID}.json" << EOF
{
"id": "${LOOP_ID}",
"sessionId": "${LOOP_ID}",
"type": "${LOOP_TYPE}",
"command": "/<command>",
"prompt": ${PROMPT_JSON},
"maxReps": ${MAX_REPS},
"interval": ${INTERVAL_MIN},
"wait": <wait_seconds>,
"currentRep": <next_rep>,
"startedAt": ${STARTED_AT},
"lastRunAt": ${NOW_MS},
"nextRunAt": ${NEXT_AT},
"status": "running",
"source": "mastermind-repeat/SKILL.md"
}
EOF
```
Emit `loop:tick`:
```bash
REPO_ROOT=$(git rev-parse --show-toplevel 2>/dev/null || pwd)
CTRL_URL=$(jq -r '.url // "http://localhost:4242"' "$REPO_ROOT/.monomind/control.json" 2>/dev/null || echo "http://localhost:4242")
curl -s -X POST "${CTRL_URL}/api/mastermind/event" -H "x-monomind-token: $(cat "${REPO_ROOT:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/.monomind/dashboard-token" 2>/dev/null || true)" \
-H "Content-Type: application/json" \
-d "{\"type\":\"loop:tick\",\"loopId\":\"${LOOP_ID}\",\"command\":\"/<command>\",\"mode\":\"${LOOP_TYPE}\",\"completedRep\":<current_rep>,\"nextRep\":<next_rep>,\"nextAt\":${NEXT_AT},\"ts\":$(date +%s)000}" || true
```
**Output and ScheduleWakeup:**
**If `tillend_mode = true`:**
- Output: `[tillend] Work remains. Next run in <wait_seconds>s (run <next_rep>, cap: <tillend_maxruns>)...`
- `ScheduleWakeup`:
- `delaySeconds`: `<wait_seconds>`
- `prompt`: `/<command> --tillend --maxruns <tillend_maxruns> --wait <wait_seconds> --rep <next_rep> --loop ${LOOP_ID} <all original flags and prompt text, minus --rep and --loop>`
- `reason`: `"tillend run <next_rep> of /<command> (cap: <tillend_maxruns>)"`
**If fixed-count mode:**
- Output: `[repeat] Next run in <wait_seconds>s (run <next_rep>/<repeat_count>)...`
- `ScheduleWakeup`:
- `delaySeconds`: `<wait_seconds>`
- `prompt`: `/<command> --repeat <repeat_count> --wait <wait_seconds> --rep <next_rep> --loop ${LOOP_ID} <all original flags and prompt text, minus --rep and --loop>`
- `reason`: `"repeat run <next_rep>/<repeat_count> of /<command>"`
---
## Notes for Calling Commands
- **Async agents in loop mode**: In `--repeat` or `--tillend` mode, all subagents MUST be synchronous (`run_in_background: false` or omitted). The postamble's empty-round check runs in the same turn as the command — background agents complete in a later turn and their output is invisible to the check. If a skill must go async (e.g. it needs to spawn a long-running agent), set `LOOP_ASYNC_PENDING=true` before invoking the postamble; section 4 will skip the empty-round check and schedule the next run unconditionally. The next run will then evaluate the results.
- **Loop state is durable across turns**: The counter and all loop parameters survive across `ScheduleWakeup` fires via two mechanisms: (1) `--rep <N> --loop <ID>` is re-encoded in every ScheduleWakeup prompt, and (2) the `.monomind/loops/<ID>.json` file stores current state persistently. There is no in-memory counter — the counter is always re-read from the prompt flags or the file.
- **`<command_slug>`**: lowercase command name without namespace (`build` for `/mastermind:build`, `mastermind-idea` for `/mastermind:idea`)
- **Dashboard**: the monomind panel reads `.monomind/loops/*.json`; `type` field is `"repeat"` or `"tillend"`; HIL status shows as `"hil:pending"`
- **Stopping a loop**: create `.monomind/loops/${LOOP_ID}.stop` or delete the `.json` file; the next wake-up detects it
- **`wait_seconds` < 60**: ScheduleWakeup clamps to 60; the state file may reflect the user's requested value
- **Continuation runs skip intake**: calling commands check `is_continuation` and bypass empty-prompt checks and vague-prompt intake
- **HIL file naming**: commands write `humaninloop*.md` or `humaninloopreview*.md`; the repeat protocol detects these automatically via `find` — no changes needed in individual commands
- **HIL resume**: the human fills in any `> ` answer line in the HIL files; the next check detects this via `grep -cE "^[[:space:]]*>[[:space:]]+[^[:space:]]"` and resumes the loop
- **HIL check interval**: while HIL is pending, ScheduleWakeup fires every `min(wait_seconds, 300)` seconds to poll; this is transparent to the user
- **`--tillend` termination**: the loop stops only when a complete round produces ZERO findings AND ZERO actions. If the round found+fixed things, it continues — even if the AI predicts "all done". Only a genuinely empty verification round stops the loop. `reason: "empty-round"` in the `loop:complete` event.
- **`--tillend` safety cap**: default 50 runs. Override with `--maxruns <N>`. Always emit a warning when stopping on cap so user knows to re-run if needed
- **Combining flags**: `--tillend` overrides `--repeat N` if both are present. `--maxruns` only applies to `--tillend`
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!