Skip to content

Latest commit

 

History

History
432 lines (293 loc) · 12.4 KB

File metadata and controls

432 lines (293 loc) · 12.4 KB

OpenCode Loop

Idle-safe auto-continue, scheduled OpenCode work, and background loops.

OpenCode Loop adds /loop, scheduled prompt/command/shell jobs, compact scheduling, verification/checkpoints, and the opencode-loopd background daemon.

Current stable release: 0.5.35.

Install or update

Recommended:

npx -y @bybrawe/opencode-loop@latest

Run the same command again to update. Then fully restart OpenCode and verify:

/loop-help
/loop-doctor

Install/update Loop and the dedicated Goals companion together:

npx -y @bybrawe/opencode-loop@latest --with-goals --without-loop-goals

--without-loop-goals removes only Loop's older experimental /loop-goal* command files. It keeps normal /loop, command/shell scheduling, daemon support, and the separate /goal plugin.

Install only Loop and skip companion network work:

npx -y @bybrawe/opencode-loop@latest --loop-only

Global npm alternative:

npm install -g @bybrawe/opencode-loop@latest
opencode-loop

To uninstall:

npx -y @bybrawe/opencode-loop@latest --uninstall

or, for a global install:

opencode-loop --uninstall
npm uninstall -g @bybrawe/opencode-loop

Project Loop state under .opencode/opencode-loop/ is intentionally preserved by uninstall.

The mental model

Loop separates two ideas:

  1. When does work become due? Idle, a timer, a watch trigger, or /loop-now.
  2. When is it safe to dispatch? Only when the session is actually idle and no active tool/child work would overlap it.

A timer expiring does not intentionally inject a second model turn on top of an active one. Due work waits for idle.

Quick start

Keep saying “continue” whenever the assistant stops

/loop continue

Turkish shorthand works naturally too:

/loop devam et

Explicit equivalent:

/loop idle continue

This is an unlimited idle loop by default. When the assistant finishes and the session becomes safely idle, Loop sends the prompt again. When that turn finishes, it does the same again, until you pause/stop it or a configured limit is reached.

For very short continuation prompts such as continue, keep going, or devam et, Loop adds project-continuation guidance: treat the turn as continuation of the current repository/conversation, inspect relevant files/TODO/progress/git state as needed, find the next unfinished step, avoid redoing completed work, and verify meaningful changes when practical.

For project work, a strong default is:

/loop --safe --ask-never --progress-file progress.md devam et

Create a starter progress file first if needed:

/loop-init

Repeat every 5 minutes

/loop every 5m continue the project

This waits five minutes before the first run, then becomes due every five minutes. If the timer expires while OpenCode is busy, it waits for the next safe idle boundary rather than stacking prompts.

Do it once after 5 minutes

/loop after 5m continue once

Alias:

/loop in 5m continue once

This is a one-shot delayed job. Five minutes passing makes it due; it still waits for idle before dispatching.

Legacy compact syntax remains supported

/loop 5m continue the project

For backward compatibility, this form starts on the next safe idle boundary and then follows a five-minute interval.

Delay its first run explicitly:

/loop 5m --no-now continue the project

Legacy idle form is still valid:

/loop 0s continue

For the exact schedule truth table and edge cases, see docs/SCHEDULING.md.

Schedule summary

Command Meaning First dispatch Repeats
/loop continue auto-continue on idle next safe idle every idle
/loop idle continue explicit idle loop next safe idle every idle
/loop every 5m continue recurring timer after 5m, then idle yes
/loop after 5m continue delayed one-shot after 5m, then idle no
/loop in 5m continue delayed one-shot alias after 5m, then idle no
/loop 5m continue legacy recurring form next safe idle yes
/loop 5m --no-now continue legacy delayed-first recurring after 5m, then idle yes
/loop 0s continue legacy idle form next safe idle every idle

Understand an unfamiliar project and keep going

A useful first loop for an unfamiliar repository is:

/loop-init
/loop --safe --ask-never --progress-file progress.md Understand the existing project architecture and current state first. Inspect relevant source, tests, docs, TODOs, git status, and recent work. Record useful state in progress.md, choose the next unfinished safe improvement, implement it, verify it, update progress.md, and continue from there on later idle turns.

Once the project state is established, this is enough:

/loop --safe --ask-never --progress-file progress.md devam et

The short continuation form is deliberately interpreted as “resume this project”, not “invent a new task from scratch”.

Other job types

Schedule an OpenCode slash command:

/loop-command 200m /compact

Run a real shell command:

/loop-shell 10m npm test

Ask a recurring quality-control prompt:

/loop-ask 1h did you run tests, typecheck, and build? If not, run them and fix errors.

Watch a path:

/loop --watch progress.md inspect the updated progress and continue

Prompt, command, shell, compact, and watch jobs use the same idle-safe scheduling path but different execution transports.

Core commands

Command Purpose
/loop <prompt> Add/update an unlimited idle prompt loop
/loop idle <prompt> Explicit idle-loop form
/loop every <duration> <prompt> Recurring timer, first run delayed
/loop after <duration> <prompt> One-shot delayed prompt
/loop in <duration> <prompt> Alias for after
/loop <duration> <prompt> Backward-compatible compact interval form
/loop-command <interval> <slash-command> Schedule an OpenCode command
/loop-cmd <interval> <slash-command> Alias for /loop-command
/loop-ask <interval> <question> Schedule a recurring check/question
/loop-shell <interval> <command> Schedule a shell command
/loop-status Show jobs plus schedule/state
/loop-now [id/name/all] Mark selected jobs due now; still waits for idle
/loop-pause [id/name/all] Pause jobs
/loop-resume [id/name/all] Resume jobs
/loop-remove [id/name/all] Remove jobs
/loop-clear Remove all jobs for the current session
/loop-logs Show recent scheduler/runtime events
/loop-doctor Diagnose session/state/scheduling problems
/loop-init Create a starter progress.md
/loop-export Export current-session Loop state

Useful flags

Lifecycle and limits:

--name <name>
--max-runs <n>
--max-runtime <duration>
--max-failures <n>
--timeout <duration>
--no-now
--now

Safety and verification:

--safe
--ask-never
--no-overlap
--verify "npm test"
--preflight "npm install"
--postrun "git status --short"
--pause-on-verify-fail

Project context:

--progress-file progress.md
--prompt-file loop-prompt.md
--include-file ARCHITECTURE.md
--batch 5
--compact-every 20
--watch progress.md

Checkpoints:

--checkpoint-only
--git-checkpoint

--git-checkpoint may stage/commit work; use it only when intentional.

Status and diagnostics

/loop-status reports both the schedule definition and the current scheduler state. Examples:

schedule=every idle | state=waiting for idle
schedule=every 5m, first after 5m | state=due in 3m
schedule=once after 5m | state=due; waiting for idle

This is intentional: “due” is a clock fact, while “waiting for idle” is an admission/safety fact.

If a job says enabled but never runs

The problematic shape is typically:

enabled=true
paused=false
runCount=0
lastRunAt=0

Some OpenCode TUI versions can leave session.status at busy/retry after a plugin command acknowledgement. Loop cross-checks that stale state against the chronological message tail before the first Loop run too. It recovers only when the latest assistant message is actually completed and no active tool/child work is known. A genuinely unfinished assistant turn, latest user turn, active tool, busy child, or unknown completion remains busy.

Recovery is logged as:

status-message-idle-recovery

Busy retries are also written as throttled deferred events so loop.log does not misleadingly contain only the original add line.

Use:

/loop-status
/loop-logs
/loop-doctor

Session-bound state

Normal plugin Loop jobs are session-bound and stored under:

.opencode/opencode-loop/<session-id>.json

A new OpenCode session does not silently inherit another session's jobs. /loop-doctor reports other persisted session files that still contain enabled jobs, including jobs that have never run, so an old loop is visible instead of appearing lost.

For work that must continue after the TUI/session closes, use opencode-loopd.

Loop and dedicated OpenCode Goals

They can be installed together. Recommended split:

  • use /goal for durable outcome-driven work, evidence, verification, restart recovery, and semantic completion;
  • use /loop, /loop-command, /loop-shell, and opencode-loopd for scheduling/repetition/background infrastructure.

A prompt-producing Loop and an active dedicated /goal should not both own autonomous continuation of the same session. The runtime therefore blocks a new prompt Loop when it detects an active dedicated Goal for that session.

Recommended choices are to finish/pause the Goal or use a separate session. Advanced users can deliberately override the guard with:

/loop --allow-goal-overlap continue

That escape hatch can create competing autonomous turns; use it only when that is intentional.

Loop's older experimental /loop-goal* commands remain available for compatibility unless installed with --without-loop-goals. For new strongly verified Goal work, prefer:

npx -y @bybrawe/opencode-goal@latest

Recommended development loop

/loop --name dev --ask-never --safe --no-overlap --batch 5 --compact-every 200m --checkpoint-only --progress-file progress.md Treat progress.md as the project state. Continue with the next unfinished TODO, implement it, mark completed items, add useful follow-up TODOs, run tests/lint/build when available, and keep going while work remains.

Test/fix loop:

/loop --name testfix --ask-never --safe --verify "npm test" --max-failures 3 Continue from progress.md. If tests fail, analyze the failure, fix it, and run the tests again.

Background daemon

The normal /loop plugin is session-bound. opencode-loopd pins one exact OpenCode session for daemon iterations and can keep scheduling outside the normal interactive Loop timer lifecycle.

opencode-loopd --project . --every 5m --prompt-file loop-prompt.md

Immediate daemon cadence:

opencode-loopd --project . --every 0s --prompt "continue from progress.md and implement the next unfinished TODO"

Pin a session and limit runs:

opencode-loopd --project . --session ses_xxx --every 5m --max-runs 20 --timeout 30m --prompt-file loop-prompt.md

Windows Task Scheduler:

opencode-loopd install-task --project "C:\path\to\project" --every 10m --prompt-file loop-prompt.md --name OpenCodeLoop
opencode-loopd uninstall-task --name OpenCodeLoop

State and checkpoints

Runtime state and logs:

.opencode/opencode-loop/
.opencode/opencode-loop/loop.log

Patch checkpoints:

.opencode/opencode-loop/checkpoints/

Add .opencode/opencode-loop/ to .gitignore if runtime state should not be committed.

Permissions

For unattended work, avoid permanently allowing every shell command. Grant routine read/edit/test operations while keeping destructive commands on ask/deny. --safe reduces risk but does not replace OpenCode permission configuration.

Package and compatibility

@bybrawe/opencode-loop

Stable package peer range:

@opencode-ai/plugin >=1.4.0 <2

The repository contains experimental OpenCode 2 work, but the stable package does not claim full OpenCode 2 parity.

See docs/SCHEDULING.md for the scheduling contract and CHANGELOG.md for release history.

License

MIT