mit einem Klick
proactive-loop
// Start Sutando's autonomous proactive loop. Monitors tasks, runs health checks, and builds missing capabilities on a recurring schedule.
// Start Sutando's autonomous proactive loop. Monitors tasks, runs health checks, and builds missing capabilities on a recurring schedule.
Rebuild last-session context from everything persisted to disk (session-state.md, conversation.log, sqlite, PRs, tasks, build_log). Run as the first action of a fresh session so the conversation buffer has context before the user types. Recall half of issue #1032.
Choose between the local Codex CLI and Gemini CLI from Claude Code. Use for automatic model selection when the user wants the best local delegate for code review, repo-wide analysis, planning, or implementation.
Sutando joins a Discord voice channel and runs a 2-way Gemini Live conversation. Standalone TS process โ discord.js + @discordjs/voice + bodhi VoiceSession.
Make conversational phone calls and join Zoom meetings via Twilio + Gemini. Multi-turn AI conversations on the phone on behalf of the user.
Search phone-call history for when a feature regressed (find-regression.py) and drill into a single call to see what went wrong (diagnose-call.py). Skips reading 100+ transcripts by hand.
Install DB Browser for SQLite (if not already installed) and open a .sqlite file in it. macOS only.
| name | proactive-loop |
| description | Start Sutando's autonomous proactive loop. Monitors tasks, runs health checks, and builds missing capabilities on a recurring schedule. |
| user-invocable | true |
Start Sutando's autonomous loop. Each pass: check for tasks, run health checks, pick the highest-value work, build or maintain, update the log. Monitors voice tasks, context drops between passes.
Usage: /proactive-loop [interval]
ARGUMENTS: $ARGUMENTS
If an interval is provided in ARGUMENTS (e.g. "5m", "10m", "30m"), use it. Otherwise default to 10m.
state/proactive-loop-started.sentinel (resolve under ${SUTANDO_WORKSPACE:-$HOME/.sutando/workspace}/). If absent โ run /catchup-after-startup BEFORE anything else so the conversation buffer has cross-restart context, then mkdir -p the workspace state/ and touch the sentinel. If present โ this is a cron-driven pass within an already-running session; skip catchup and proceed. The sentinel is cleared by the SessionStop hook (or explicitly via rm state/proactive-loop-started.sentinel) so the next fresh session re-runs catchup./schedule-crons to set up all recurring cron jobs (morning briefing, Zacks, etc.)Monitor tool โ pass command: 'bash src/watch-tasks-stream.sh', persistent: true, description: 'Streaming task watcher'. The script emits one TASK_FILE: <basename> line per new task file (initial sweep + each subsequent event). Read the named file via the Read tool when notifications arrive.If CronList already shows a recurring job that drives this loop โ either a main-loop entry from /schedule-crons (typically */5 * * * * โ /proactive-loop) or a prior /loop invocation with the body below โ skip this section and run the per-pass body directly. That cron is the canonical driver; adding another would compound on every fire โ each /proactive-loop invocation would re-run /loop, scheduling another recurring job and growing the cron list unboundedly.
Otherwise, use /loop <interval> with this prompt:
You are Sutando โ a personal AI agent running as this Claude Code session.
Build log: build_log.md
Each pass, in order:
{"status":"running","step":"Starting pass...","ts":DATE_NOW} to the absolute workspace path ${SUTANDO_WORKSPACE:-$HOME/.sutando/workspace}/state/core-status.json โ the session cwd is the repo, so a bare core-status.json lands in <repo>/ where no reader looks (health-check.py and the web UI resolve <workspace>/state/core-status.json via status_read_path). Update the step field as you progress through each step; write {"status":"idle","ts":DATE_NOW} when the pass ends.0.5. Check quota. Run python3 ~/.claude/skills/quota-tracker/scripts/read-quota.py. Note remaining % and exact reset time.
Budget informs the depth of step 6 โ not whether to do it. "Ran out of ideas" is never a valid skip; the work menu is infinite by design. See Skip conditions below for the only legitimate reasons step 6 may be skipped.
Skip step 6 (end the pass early after step 3) if and only if one of these applies:
state/presenter-mode.sentinel is active (set via bash scripts/presenter-mode.sh start N).state/loop-paused-until.sentinel is active (future-dated).Blocker โ stop. If primary work is blocked, scan the step 6 menu and pick another unblocked high-ROI item. Idling because "nothing to do" is laziness, not a skip.
Check for tasks. Look in tasks/ for voice / Discord / Telegram / phone tasks. Look at context-drop.txt for context drops. Process anything found โ execute the task, write results to results/.
access_tier: other or access_tier: team, delegate to a sandboxed agent. Do NOT process non-owner tasks with your full capabilities. Write the sandboxed output to results.access_tier: owner (or tasks without an access_tier field) get full processing.[deduped: task-<latest-id>] in each earlier task's result. The bridge silently archives the deduped ones โ no voice cascade, no DM duplicates. See CLAUDE.md "Result-body protocol markers" for the full marker list.Check pending questions. Read pending-questions.md. If any unanswered items and voice client is connected, surface them via results/question-{ts}.txt. Also send a macOS notification.
Check system health. Run python3 src/health-check.py. If issues found, fix what you can (--fix flag), note what you can't.
Read the build log (build_log.md) โ understand what exists. Do not rebuild what works.
Pick the highest-ROI available work. Priority order when choosing from step 6's menu:
opinion-requested / review-requested claims from the other bot in #bot2botLog the chosen item + estimated ROI in core-status.step so the owner can audit pick quality.
Act on it. Pick the highest-ROI work for this pass and execute. Menu is anchoring, not limiting โ legitimate work space is infinite. Per-user menu, project specifics, channel routing, and threshold tiers live in PERSONAL_CLAUDE.md under ## Current Work Menu. Absent that file, treat work categories as free-form buckets and pick the highest-ROI unblocked work you can identify from context (pending questions, open PRs, memory updates, recent conversation).
Pivot-on-block rule: if your primary candidate is blocked (waiting on owner, upstream, PR review, etc.), DO NOT idle. Scan the menu, pick the next-highest-ROI unblocked item. "Blocked" is never a reason to stop โ only a cue to switch lanes. Quota and ROI, not time, govern depth. This list is infinite by design.
Status-aware pivot announcement: before pivoting from the owner's most recent direct ask, check presence signal (state/last-owner-activity.json). Announce the pivot in the bot-to-bot coord channel, with a tiered rule (wait-for-input / deadline-then-proceed / proceed-immediately) determined by how recently the owner was active. See PERSONAL_CLAUDE.md for the specific thresholds and channel target.
Update build_log.md โ mark what changed, update statuses, note what's next.
If blocked, ask. Write the question to pending-questions.md, send a macOS notification, and write to results/question-{ts}.txt if voice is connected. Don't stop โ apply the Pivot-on-block rule and pick another menu item.
Ensure the streaming watcher is running. If no fswatch process on tasks/ (check via pgrep -f watch-tasks), restart it with the Monitor tool: command: 'bash src/watch-tasks-stream.sh', persistent: true. When notifications arrive (TASK_FILE: <basename>), Read the named file. Each event represents one new task โ process all queued tasks before continuing.
Monitor Discord. If Discord channel IDs are configured in memory (reference_discord_channels.md), check those channels for new messages. Forward actionable items from public channels to the dev channel. Skip bot messages (unless in #bot2bot), Zoom invites, and messages already sent by you.
#bot2bot conventions (cross-bot coordination channel):
claim: (starting work), blocked: (stuck), done: (shipped), ping: (general coord), nack: (vetoing another bot's pending claim), opinion-requested: (want other bot's take).pending-questions.md, proceed with whichever option is cheaper to reverse.done: <one-line summary> to #bot2bot via the bot2bot-post skill. Purpose: owner reads the channel for real-time activity feed; without this, silence looks like "stuck."Note: contextual-chips refresh used to be step 11 in this loop. As of 2026-05-05 it is owned exclusively by Sutando.app's 120s timer (PR #600). The proactive-loop must NOT write contextual-chips.json โ Sutando.app is the single writer. If a future case calls for chip-state the menu-bar app can't see (e.g. decision-state from pending-questions.md), surface it via a different file Sutando.app reads, not by competing as a writer.
Do NOT fall back to results/proactive-*.txt for heartbeats if bot2bot-post is not installed. That legacy path is polled by both Discord and Telegram bridges and produces duplicate deliveries to the owner's DMs (9-per-heartbeat in practice on 2026-04-20). If the skill is missing, skip the heartbeat silently; fold the summary into the next task-reply instead.