OpenCode plugin • Server + TUI

Background goals that loop.

opencode-loopd is a Codex-inspired goal engine for OpenCode. Create a goal with /goal, watch an autonomous child session loop in the background, and monitor everything from a modal TUI dashboard — without blocking the parent chat.

⬢ AGPL-3.0 ⚡ bun ≥1.1.0 ◈ opencode ≥1.4 ☆ like Claude Code loop

Install in 30s

Add to both configs, restart OpenCode:

// ~/.config/opencode/opencode.jsonc
{ "plugin": ["@bojackduy/opencode-loopd"] }

// ~/.config/opencode/tui.json
{ "plugin": ["@bojackduy/opencode-loopd"] }

Or one-line installer (adds /goal + skill):

npx -y @bojackduy/opencode-loopd@latest

Dashboard: /loop or <leader>d (Ctrl+X → d) • Shift+B bug report

opencode — Loop Dashboard • NORMAL • 0 goals • ○ 0 RUNNING • 7 done
Loop Dashboard modal TUI inside OpenCode terminal — showing NORMAL mode, goal list, and vivid status colors

Modal dashboard (/loop / <leader>d): vivid per-status coloring, running spinner, NORMAL vs INSERT — keys trapped, no chat leak.

Engine-driven

Idle + lease + 30s polling re-prompts the child with accumulated steering (progress + transcript tail + inbox). Not a parent re-prompt machine.

👁️ Parent ↔ child

Owner tools inspect/steer; inbox injects into next turn. Wake-up on complete/block without polling.

🛡️ Safe

Per-goal artifact isolation .opencode/loopd/goals/<id>/, maxTurns force-finish → semantic summary → parent.

Architecture — how the loop runs

                        ┌─────────────────────────┐
                        │  Main session (parent)  │
                        │  owner tools            │
                        │  inspect / steer / pause│
                        └────────────┬────────────┘
                                     │  inbox → child
                                     │  wake-up ← engine
             ┌───────────────────────┼───────────────────────┐
             ▼                       ▼                       ▼
        ┌─────────┐           ┌──────────┐            ┌─────────┐
        │  Goal A │           │  Goal B  │            │  Goal C │
        │ active  │           │ blocked  │            │  paused │
        └────┬────┘           └────┬─────┘            └────┬────┘
             │                     │                       │
             └─────────────────────┼───────────────────────┘
                                   │
                     ┌─────────────┴─────────────┐
                     ▼                           ▼
              Loopd engine  ──────────►   Child worker (subagent)
              (plugin server)  steering   get_goal / report / complete
                 │  lease / retry / polling       │  block / question
                 │  force-finish / notify         ▼
                 │                         .opencode/loopd/goals/<id>/
                 │                           progress.md / artifacts
                 └─────────────────────────────────┘

Each goal is a GoalID — the loop identity. The dashboard is a modal dialog that pushes loopd.dashboard onto the keymap so the chat prompt never sees your keys. Artifacts are namespaced per-goal; if your objective says save to ./reports/, that wins.

Quick start — background goals in OpenCode

/goal fetch the latest AI news and save 10 items to ai-news.md
# agent clarifies → loopd_create_goal → child loops every ~30s
/loop                          # or <leader>d  (Ctrl+X → d)
j/k  move   o open child   :send hello   :force done   ? help   q close
Shift+B  → prefilled GitHub bug report (like lazyjira / lazyconfluence)

Prefer the TUI? Ctrl+L also works if your terminal passes it; <leader>d is the reliable leader binding.

Why loopd vs. plain loop?

Plain /loop injects prompts into the main session — it pollutes the transcript. Codex goals keep history per-thread and steer via internal context. Loopd does the same for OpenCode: one child session per goal, continuation steering with progress history + transcript tail, and an explicit artifact namespace. The parent stays clean.

opencode-loopd

Child session per goal, no transcript pollution, artifact isolation, parent wake-up injection.

Plain /loop

Single session, prompt injected into main chat, manual polling to see progress.

Codex / Claude Code

Inspiration: Codex goals keep per-thread history and steer via internal context — same model for OpenCode.

FAQ — SEO for OpenCode loop & background agents

How to run background agents in OpenCode?

Install @bojackduy/opencode-loopd as a plugin (both opencode.jsonc and tui.json), restart, then /goal in any session. The engine spawns a child worker that loops autonomously; you monitor with /loop.

Is this like Claude Code's loop or Codex goals?

Yes — same mental model: engine-driven idle → continuation steering with accumulated context → child calls complete_goal/block_goal → parent wake-up. Like Codex, but native to OpenCode's session model.

Where do loop outputs go?

Per-goal: .opencode/loopd/goals/<id>/ (e.g. progress.md). If your objective names ./reports/, that wins.

How to report a bug?

In the dashboard press Shift+B or :bug — opens github.com/bojackduy/opencode-loopd/issues/new prefilled with environment (version, OS, goal context).