LoopBoard

agent
Guvenlik Denetimi
Basarisiz
Health Uyari
  • License — License: MIT
  • Description — Repository has a description
  • Active repo — Last push 0 days ago
  • Low visibility — Only 5 GitHub stars
Code Basarisiz
  • fs module — File system access in .claude/skills/readme-regen/readme-tool.js
  • exec() — Shell command execution in media/markdown.js
Permissions Gecti
  • Permissions — No dangerous permissions requested

Bu listing icin henuz AI raporu yok.

SUMMARY

VS Code extension that turns your TODO.md into an interactive Kanban board and runs autonomous Claude Code agent loops per task — markdown stays the source of truth.

README.md

LoopBoard logo

LoopBoard

Publish to Marketplace
Release
License: MIT
runtime deps: 0

The missing UI for Claude Code loops.

Claude Code is the engine.

LoopBoard is the cockpit.

You're still the pilot.

Less prompting. No babysitting. More building.

"I don't prompt Claude anymore. I have loops running that prompt Claude and figure out what to do. My job is to write loops."

— Boris Cherny, creator of Claude Code at Anthropic

LoopBoard demo — watch on YouTube

LoopBoard is a VSCode extension that turns your workspace .loopboard/ tracker into an interactive
board your Claude Code agent loops groom, build, and deliver from — while you keep the only three
keys that matter: what gets started, what gets accepted, and what gets sent back. Markdown stays
the source of truth.

Small on purpose

Agentic development breaks down when the task tooling becomes bloated and detached from the code it
is supposed to be about. LoopBoard is deliberately small:

  • Markdown is the single source of truth. .loopboard/ is plain files in your workspace. The
    board is a live view of them, never a second database, and everything survives the extension
    being uninstalled.
  • Exactly three human actions. Promote, accept, demote. Everything else on the board is a field
    patch the loops read on their next pass.
  • Zero runtime dependencies. Nothing ships with the extension but its own compiled code; the
    webview is vanilla HTML/CSS/JS with a CSP nonce on every script.
  • Native VSCode mechanisms only. A webview panel, an activity-bar view, and plain terminals —
    the same APIs any extension uses. LoopBoard does not wire itself into pre/post hooks, does not
    scatter files across your project, and adds no file that can conflict with your own. Install it
    and carry on working exactly as before; uninstall it and only .loopboard/ remains, which is
    yours and gitignored.
        you tick [x]                                    you tick [x]
             │                                               │
   New ──────┴──────► Backlog ────► In Progress ────► Review ┴────► Done (DONE.md)
    ▲                                    ▲   │                          
    └──── you click Demote ──────────────┘   └──► Feedback ─┐           
                                                  ▲          │           
                                                  └──────────┘           
                                              (your answers resume it)

Promote (New → Backlog) and Accept (Review → DONE.md) are ticks only you can make. Demote
(Backlog → New) is an immediate, non-destructive button click. A loop claims the top Backlog task
itself — at most one task board-wide is ever In Progress — and parks in Feedback rather than
guessing.

Why LoopBoard?

What you get, at a glance:

  • 🗂️ Your TODO.md is the board — markdown stays the source of truth; the UI is a live view, never a second database.
  • 🤖 Agents groom, build, and deliver — Groomer and Worker loops collaborate on each task while you hold the only three gates: promote, accept, demote.
  • ⏯️ Press Start, not prompts — spawn model-specific Claude Code loop terminals in one click instead of writing a fresh prompt per task.
  • 🧩 Multi-model slots — assign Opus / Sonnet / Fable per task (groom vs. work), each a configurable slot.
  • 🔒 Zero runtime dependencies — the extension ships no runtime deps; the webview is vanilla HTML/CSS/JS with a CSP nonce on every script.
  • 🧵 Context stays on the task — worklog, feedback, and delivery notes live in tasks/<id>.md, not scattered across chats.

How LoopBoard works

  1. Create a task.
  2. Start the Groomer and Worker loops.
  3. Review the Groomed story.
  4. Approve it.
  5. Let the Worker build.
  6. Answer questions—or chat with Claude when deeper discussion is needed.

That's it.

LoopBoard board in motion

Get started

Run LoopBoard: Initialize Workspace from the Command Palette (or the board's empty-state
button) to scaffold .loopboard/ in your workspace. Click the LoopBoard icon in the activity bar
for the sidebar summary, then Open Board (or run LoopBoard: Open Board). Accepted work is
archived to .loopboard/DONE.md.

Every command LoopBoard adds to the palette:

  • LoopBoard: Initialize Workspace — scaffold .loopboard/ here (refuses if it already exists).
  • LoopBoard: Open Board — open the board panel.
  • LoopBoard: Refresh — re-read .loopboard/ from disk, for an edit made outside VSCode.
  • LoopBoard: Start Loop — spawn a loop terminal, the same action as the sidebar's ▶.

Storage layout

.loopboard/
  TODO.md          slim task index — one entry per active task (id, phase, model, groomer, Q&A)
  DONE.md          accepted tasks, newest first (created lazily on the first acceptance)
  LOOP.md          workflow rules + the loop worker instructions the loops read every pass
  tasks/<id>.md    per-task detail: meta, description, notes, worklog, feedback, delivered
  cache/<id>/      staged image attachments (created on the first attach), see below

The board composes each card from the slim index entry plus its tasks/<id>.md. Every edit
re-reads the disk, applies one field-level patch, and writes the whole file back canonically
(atomic temp-file + rename) — so humans, the board, and multiple agent loops share it safely. On
acceptance the index entry moves to DONE.md while the task file stays in tasks/ as history.

.loopboard/ is gitignored, so anything under it — including staged attachments — is local-only
and never committed or shared via git. Attach an image to a task by dragging it onto a card (or
the New Story composer) or pasting it from the clipboard — no button, drag-drop/paste only — and
it's staged under .loopboard/cache/<id>/, referenced with a markdown link in the task's
description (or the specific comment/answer field it was dropped into; drafts carry the link in
their raw story text). In the New Story composer, pasting inserts a [name](…) link at the
caret and the image stays pending (the draft isn't saved yet) — Save Draft stages the bytes and
rewrites the link to the real cache path. Each card lists its staged images in an Attachments
area with a × that deletes the file and its link; all remaining staged files are deleted once
the task is accepted to DONE.md.

Using the board

The activity-bar sidebar (left) is a read-only, at-a-glance summary — click any row to jump into the board. From top to bottom, it shows:

LoopBoard sidebar
  • Attention banner — everything currently waiting on you: tasks in Review plus groomed proposals in New that are ready to promote.
  • Phases — every column (New, Backlog, In Progress, Feedback, Review, Done) with a live task count.
  • Loops — one row per model (Opus, Sonnet, Fable), each with its assigned role, a running-status dot, and ▶ spawn / ↻ recycle / ⏹ stop controls.
  • Settings — opens the extension's configuration.

On the board itself:

  • New — tick a task's checkbox to promote it to Backlog.
  • Backlog — click Demote to send a task back to New; it's immediate and non-destructive.
  • Feedback — type an answer under each question; the loop resumes once all are answered.
  • Review — read DELIVERED, optionally write review feedback (sends it back), or tick to accept → archived to DONE.md.
  • New story composer — write free text and choose the groom/worker models inline; it lands as a DRAFT: the loop grooms into a story.

Edits save on blur/Enter as field patches; if the file changed on disk under your edit, the disk
value wins and a toast tells you. The board performs only the three human actions — promote, accept
and demote — everything else is a field patch the loops react to on their next pass.

Loop terminals

The ▶ buttons open a plain VSCode terminal named Claude <Model> in the workspace root and run
claude --model <m> --permission-mode <cfg> with a tiny bootstrap prompt that points the loop at
.loopboard/LOOP.md's Automation section — the standing instructions each loop re-reads every pass.
↻ disposes and respawns for a fresh context. Loops die with the VSCode window; restart is one click,
since all state lives in .loopboard/.

Requires Claude Code 2.1.0 or newer. Loop terminals are spawned with --name, which is what
lets the context-usage bar tell one slot's session from another's. An older CLI rejects the unknown
option and the terminal exits immediately — and because a terminal's output can never be read back,
the extension cannot tell you why. If your loops die the instant they start, check claude --version
first.

Settings

The sidebar's Settings row opens LoopBoard's own settings page: the same keys, grouped into
four sections, with the three model slots drawn as one clickable grid (on · worker · groomer ·
--model · effort · groomers) instead of fourteen flat rows. It carries a modified marker and a
per-setting reset, and keeps an Open in VSCode Settings escape hatch to the native
@ext:SinnConsulting.loopboard-todo view for settings search and JSON editing.

These stay ordinary VSCode settings — settings.json and Settings Sync are unaffected — with one
deliberate restriction: every loopBoard.* key is "scope": "application", so it can only be set
in your USER settings.
See Security model.

The table below is generated from contributes.configuration in package.json, grouped and
ordered exactly as both settings pages render them.

LoopBoard: Models & Slots

Setting Default Description
loopBoard.defaultWorkerModel sonnet The model that owns (works) tasks with no explicit model: field.
loopBoard.defaultGroomerModel opus The model that grooms tasks/drafts with no explicit groomer: field.
loopBoard.models.opus.enabled true Opus slot. Show it in the Loops overview and the board's model selects. The two settings below apply to this slot.
loopBoard.models.opus.model "" Custom --model string spawned for the Opus slot (e.g. opus[1m]). Empty = opus. Invalid strings are ignored. Applies on the next loop start (▶) or restart (♻): a running loop keeps what it was spawned with.
loopBoard.models.opus.effort high Subagent reasoning-effort ceiling for the Opus slot — grooming subagents (Rule 14 in LOOP.md) and, with loopBoard.delegateWork on, the implementer and review subagents too — the loop chooses low..this ceiling by story complexity, reserving xhigh/max for when the ceiling allows it and the story explicitly asks for deep reasoning. Applies on the next loop start (▶) or restart (♻): a running loop keeps what it was spawned with.
loopBoard.models.opus.groomConcurrency 3 Cap on how many grooming subagents the Opus slot's loop may run in parallel during one pass (Rule 14 in LOOP.md). Eligible tasks over the cap are left in place, taken in index order top down, and picked up on a later pass — nothing is queued or dropped. Applies on the next loop start (▶) or restart (♻): a running loop keeps what it was spawned with.
loopBoard.models.sonnet.enabled true Sonnet slot. Show it in the Loops overview and the board's model selects. The two settings below apply to this slot.
loopBoard.models.sonnet.model "" Custom --model string spawned for the Sonnet slot (e.g. sonnet[1m]). Empty = sonnet. Invalid strings are ignored. Applies on the next loop start (▶) or restart (♻): a running loop keeps what it was spawned with.
loopBoard.models.sonnet.effort high Subagent reasoning-effort ceiling for the Sonnet slot — grooming subagents (Rule 14 in LOOP.md) and, with loopBoard.delegateWork on, the implementer and review subagents too — the loop chooses low..this ceiling by story complexity, reserving xhigh/max for when the ceiling allows it and the story explicitly asks for deep reasoning. Applies on the next loop start (▶) or restart (♻): a running loop keeps what it was spawned with.
loopBoard.models.sonnet.groomConcurrency 3 Cap on how many grooming subagents the Sonnet slot's loop may run in parallel during one pass (Rule 14 in LOOP.md). Eligible tasks over the cap are left in place, taken in index order top down, and picked up on a later pass — nothing is queued or dropped. Applies on the next loop start (▶) or restart (♻): a running loop keeps what it was spawned with.
loopBoard.models.fable.enabled true Fable slot. Show it in the Loops overview and the board's model selects. The two settings below apply to this slot.
loopBoard.models.fable.model "" Custom --model string spawned for the Fable slot. Empty = fable. Invalid strings are ignored. Applies on the next loop start (▶) or restart (♻): a running loop keeps what it was spawned with.
loopBoard.models.fable.effort high Subagent reasoning-effort ceiling for the Fable slot — grooming subagents (Rule 14 in LOOP.md) and, with loopBoard.delegateWork on, the implementer and review subagents too — the loop chooses low..this ceiling by story complexity, reserving xhigh/max for when the ceiling allows it and the story explicitly asks for deep reasoning. Applies on the next loop start (▶) or restart (♻): a running loop keeps what it was spawned with.
loopBoard.models.fable.groomConcurrency 3 Cap on how many grooming subagents the Fable slot's loop may run in parallel during one pass (Rule 14 in LOOP.md). Eligible tasks over the cap are left in place, taken in index order top down, and picked up on a later pass — nothing is queued or dropped. Applies on the next loop start (▶) or restart (♻): a running loop keeps what it was spawned with.

LoopBoard: Agent Setup

Setting Default Description
loopBoard.permissionMode auto --permission-mode passed to the claude CLI when spawning a loop terminal. This setting is deliberately user-scoped only — a cloned repository must never be able to decide how much authority your agent runs with. Applies on the next loop start (▶) or restart (♻): a running loop keeps what it was spawned with.
loopBoard.loopInterval 5m Interval passed to /loop (e.g. 1m, 5m). Applies on the next loop start (▶) or restart (♻): a running loop keeps what it was spawned with.
loopBoard.afterTask none What to do with a model's loop terminal once it finishes a task. Replaces the old loopBoard.autoRecycle / loopBoard.clearSessionAfterTask pair — if you still have either of those set and have not set this one, it is honoured (on → recycle, clear → clear). Whatever this is set to, the ♻ button still recycles a loop by hand at any time.
loopBoard.contextLimit.percent 0 Automatically restart a loop once its Claude session fills this percentage of its context window. 0 (default) never restarts a loop for its context size — the usage bar under each running loop row still shows. The window is taken from the model that actually ran, as recorded in the session transcript (the 5-series models are 1,000,000 tokens natively; a [1m] suffix also means 1,000,000; anything unrecognised falls back to 200,000), so 50 on a 1M slot is the 500k mark. A loop that owns the In Progress task is never interrupted: the restart waits for it to go idle.
loopBoard.contextLimit.action recycle What to do with a loop terminal when loopBoard.contextLimit.percent trips. Independent of loopBoard.afterTask, which reacts to a finished task rather than to context size.
loopBoard.nudgeLoops true When a board change gives one loop something to do — a note, a story whose questions are now FULLY answered, review feedback, a task promoted to Backlog — paste a line naming that task into that model's running loop terminal, so it acts on the change now instead of on its next scheduled pass. The text only seeds the REPL input, so it never interrupts work in flight, and it only ever supplements the loop's own board re-read. No terminal for that model: the nudge is held for its next start. Off disables the nudges entirely; loops keep working exactly as before.
loopBoard.autoRecycle false Deprecated. Replaced by loopBoard.afterTask. Still honoured while loopBoard.afterTask is unset (on → recycle); set that instead and clear this.
loopBoard.clearSessionAfterTask false Deprecated. Replaced by loopBoard.afterTask. Still honoured while loopBoard.afterTask is unset (on → clear); set that instead and clear this.

LoopBoard: Board & Workspace

Setting Default Description
loopBoard.maxAttachmentSizeMB 10 Maximum size (MB) for an image attached to a task (drag-drop, paste, or the picker). Attachments are staged under .loopboard/cache/ and cleaned up on acceptance.
loopBoard.pulseTemplateSync true Subtly pulse the sidebar's Synchronise Templates row when TODO.md/LOOP.md differ from the shipped templates, so it's easy to notice there's scaffolding to refresh. Off disables the animation entirely (independent of the OS-level reduced-motion setting, which is honoured either way).
loopBoard.debug off Opt-in verbose trace. With info/verbose, LoopBoard appends timestamped lines to .loopboard/debug.log. Field values are logged verbatim (no eliding) — this is safe because the log stays local under the gitignored .loopboard/ and is never committed. The log is tail-capped at 10 MB (oldest lines dropped); there is no separate command to open it.

LoopBoard: Beta (experimental)

Setting Default Description
loopBoard.delegateWork false Beta — experimental; this setting may change or be withdrawn in a future release. Off (default): each loop grooms through a subagent (Rule 14 in LOOP.md) but implements tasks inline in its own session. On: the loop also delegates every code-editing step — the Backlog claim, a Feedback resume, Review-feedback rework, code-touching notes — to an implementer subagent on the loop's own slot model under that slot's .effort ceiling; the subagent branches, commits and opens the PR, while the loop keeps all .loopboard/ bookkeeping. With loopBoard.delegateReview on (default) a second, sequential review subagent gates the PR and the loop squash-merges it on a pass before setting Review. The behaviour itself lives in the Automation section of LOOP.md; only the mode rides the loop's bootstrap prompt. Applies on the next loop start (▶) or restart (♻): a running loop keeps what it was spawned with.
loopBoard.delegateReview true Beta — experimental; this setting may change or be withdrawn in a future release. Only applies while loopBoard.delegateWork is on. On (default): after the implementer subagent returns its PR, a review subagent (same slot model, same .effort ceiling) reviews it; a pass lets the loop squash-merge the PR and set Review (= merged, awaiting your tick); a fail is handed back to the implementer once, then parks the task in Feedback with the findings as questions. Off: no review subagent runs and the loop does NOT merge — the implementer's PR goes to Review unmerged for you, exactly like the non-delegated flow. Applies on the next loop start (▶) or restart (♻): a running loop keeps what it was spawned with.

Renamed: loopBoard.delegateWork.review is now loopBoard.delegateReview. The old id
could never take effect: VSCode resolves settings as a tree, so a key holding a scalar cannot
also have a child key — with loopBoard.delegateWork set, VSCode logged
Ignoring loopBoard.delegateWork.review as loopBoard.delegateWork is true and discarded the
value, leaving the default (true) in force. Nothing that was actually being honoured is lost by
the rename; if you had set the old key, set the new one to the value you meant and delete the old
line from your user settings.json.

See FAQ.md for common questions (e.g. why there's no Haiku slot).

Workspace custom rules (edit .loopboard/LOOP.md directly)

Extra standing instructions for the loop workers in this workspace live as a hand-written
section in .loopboard/LOOP.md itself — free-form markdown, no setting involved. Freshly
initialized workspaces already carry the empty section (it ships in the template); in an older
workspace, add it yourself:

<!-- loopboard:custom:begin -->
## Custom rules (workspace)

Standing instructions for THIS workspace — free text, edited here; where they contradict a
Rule above, they win in this workspace.

1. PRs must be created before moving to in review. Otherwise task not done.
<!-- loopboard:custom:end -->
  • The file is the feature. Workers re-read LOOP.md on every pass, so an edit reaches running
    loops immediately — no terminal recycle, no extension involvement. The extension never parses,
    rewrites or validates the section; what you save is exactly what stays.
  • Workspace-isolated by construction. The text lives in this workspace's .loopboard/LOOP.md
    and can apply nowhere else.
  • Synchronise Templates never touches it. Sync rewrites only loopboard:sync:-marked template
    blocks; the loopboard:custom markers (and any other text outside sync markers) survive
    verbatim. The one caveat: a LOOP.md with no loopboard:sync: markers at all is treated as
    legacy and replaced wholesale on Sync (backed up to LOOP.md.bkp first) — any modern LOOP.md
    has those markers.
  • Precedence is prose. A custom rule that contradicts a predefined Rule wins in this workspace
    because the lead-in says so and workers read it — nothing is enforced by the extension.

Configuring models (loopBoard.models.<slot>)

The built-in model slots — opus, sonnet, fable — are what you assign to tasks
(model: / groomer:) and what the sidebar Loops rows spawn. Each slot is configured through
three keys:

  • loopBoard.models.<slot>.enabled — show/hide the slot in the Loops overview and the board's model selects.
  • loopBoard.models.<slot>.model — the actual string passed as claude --model <string> (e.g. opus[1m] or a dated snapshot). Empty falls back to the slot's built-in default; anything outside [A-Za-z0-9._\[\]-] is rejected before it reaches the terminal.
  • loopBoard.models.<slot>.effort — subagent reasoning-effort ceiling (lowmax) for that slot: grooming subagents per Rule 14 in LOOP.md, and the implementer/review subagents when loopBoard.delegateWork is on.
  • loopBoard.models.<slot>.groomConcurrency — how many grooming subagents that slot's loop may run in parallel in one pass (default 3, minimum 1; there is no unlimited setting). Eligible tasks over the cap are left in place, taken in index order top down, and picked up on a later pass.

The .effort and .groomConcurrency ceilings ride the loop's bootstrap prompt — as do loopBoard.delegateWork and loopBoard.delegateReview — so a change to any of them takes effect the next time that slot's loop is started or restarted (♻); a running loop keeps the values it was spawned with, exactly like loopBoard.loopInterval.

// Pin Opus to a dated snapshot; run Sonnet with the 1M-context window; hide Fable.
"loopBoard.models.opus.model": "claude-opus-4-8",
"loopBoard.models.sonnet.model": "sonnet[1m]",
"loopBoard.models.fable.enabled": false

Migrating from "Claude TODO Board" (≤ 0.1.1): the extension, command, and settings ids were
renamed from claudeTodo.* to loopBoard.* with no fallback — re-enter any custom settings.json
values under the new keys.

Build & contribute (Docker only)

Node and every other tool run inside Docker — nothing is installed on the host, which needs
only Docker, make, git, and VSCode (engines.vscode is ^1.90.0), plus an authenticated Claude
Code CLI to run the loops. make check is the verification gate and must be green before any
commit; pressing F5 to launch an Extension Development Host against this repo's own
.loopboard/ tracker is an optional extra smoke test. All toolchain commands are wrapped in the
Makefile:

make install    # npm install (typescript + @types/vscode only) in node:22
make build      # tsc -> out/
make test       # compile pure modules + run node --test round-trip / merge suites
make check      # build + test — the gate that must pass before committing
make package    # build a .vsix via @vscode/vsce

Zero runtime dependencies; the webview is vanilla HTML/CSS/JS with a CSP nonce on every script.

Security model

Treat .loopboard/ as trusted input. LoopBoard points an autonomous claude session at
.loopboard/LOOP.md's Automation block, running with the configured loopBoard.permissionMode
which may be bypassPermissions. Anything written into LOOP.md, or into the task files it opens,
steers an agent that can run commands on your machine. This is inherent to what LoopBoard does, not
a bug.

  • A .loopboard/ from a source you don't control (a cloned repo, a shared workspace) is a
    prompt-injection vector with arbitrary-command-execution reach. It stays in the repo by design —
    the tracker is the repo's — so it remains the one channel worth reading before you press ▶.
  • Review .loopboard/LOOP.md before starting a loop in a repo you didn't author, and set
    loopBoard.permissionMode no higher than you're comfortable running unattended.

The settings channel is enforced shut. Every loopBoard.* key is declared
"scope": "application", which means user settings only. A repository cannot set one — not through
its .vscode/settings.json, and not through a .devcontainer/devcontainer.json it ships (which is
why the scope is application and not machine: machine still permits remote settings, and a
dev container's settings come from inside the repo). loopBoard.permissionMode is the key this is
really about: a cloned repo must never get to decide how much authority your agent runs with.

VSCode Workspace Trust gates activation, but trusting a repo to open it is not the same as vetting
what its .loopboard/ will tell an agent to do.

Migrating from a workspace setting

If you previously set a loopBoard.* key in a workspace's .vscode/settings.json (or in a
.code-workspace file), that value no longer has any effect — VSCode does not migrate a
workspace value when a key stops being workspace-settable, it silently ignores it. Move any setting
you still want into your user settings (the sidebar's Settings row, or
@ext:SinnConsulting.loopboard-todo in VSCode's own Settings editor, both of which now write there
exclusively), and delete the stale workspace entries. No key was renamed, so the names are
unchanged.

The trade-off is accepted deliberately: a repository can no longer ship its own default models,
effort ceiling or delegation mode for a team to share. LoopBoard configuration belongs to the
person, not to the checked-out repo.

Usage volume

Advertised usage limits for Pro and Max plans assume "ordinary, individual usage of Claude Code and
the Agent SDK."
A tight loop (the default is 1m) spinning multiple model terminals unattended
around the clock can push past that, and Anthropic may rate-limit or enforce against the account.
LoopBoard drives your own locally-authenticated Claude Code CLI — nothing here is against the ToS,
but its design encourages high-frequency multi-model looping, so it's worth being aware of.


Less prompting. No babysitting. More building.

MIT License

Yorumlar (0)

Sonuc bulunamadi