cd /news/ai-agents/looop-a-tiny-portable-kubernetes-sha… · home topics ai-agents article
[ARTICLE · art-45030] src=github.com ↗ pub= topic=ai-agents verified=true sentiment=↑ positive

Looop – A tiny, portable, Kubernetes-shaped control loop for your LLM agent

Looop, a new open-source tool, launches as a tiny, portable autonomous control loop for LLM agents, operating as a single binary without external dependencies. It monitors sources like GitHub and Linear, runs worker agents, and introduces a human-in-the-loop design with two distinct interaction modes: async steering and sync answering. The project aims to make agent-driven work dependable by using level-triggered state and a one-move-per-beat policy.

read6 min views1 publishedJun 30, 2026
Looop – A tiny, portable, Kubernetes-shaped control loop for your LLM agent
Image: source

A tiny, portable, autonomous control loop for agent-driven work. One self-contained binary — no database, no server, no helper files.

looop is the brain, not a task runner. It watches the things you care about (GitHub, Linear, Grafana, …) and runs a fleet of worker agents. Each beat it senses the world and, if something changed, decides the single most important move and executes it — including spawning workers. The judgment lives inside looop (a small, gated LLM call per beat).

An autonomous loop is easy. The hard part — and the whole point of looop's design — is where and how a human enters the loop. Too much human and it isn't autonomous; too little and it's reckless. looop's answer is to pull you in at exactly two kinds of moments, and nowhere else.

There are two distinct ways you touch the loop — and that split is the design.

Steer — async, you initiate. You are a peer, not a driver. You shape what looop pursues by editing goals and the PLAYBOOK; it observes them next beat. This never blocks the loop — you set direction and walk away.

looop _ goal write ship-v2 -      # declare desired state (effective next beat)
looop _ playbook write -          # your judgment, priorities, guardrails

Answer — sync, the loop initiates. looop reaches back for you only when it genuinely must: a worker hits a decision only a human can make, or an irreversible action — merge, deploy, delete — needs an explicit yes. It blocks and waits for your call.

looop _ wait --only-asks          # block cheaply until the loop needs you
looop _ answer <id> "yes"         # unblock the worker / approve the gate

The key move: the intervention point is decoupled from any UI. Asks and answers are a durable file mailbox reached through one backend-agnostic contract (looop _ …

), so the loop never blocks on a particular terminal, tmux, or stdin — it just needs an answer eventually, from whatever channel reaches you:

  • a bare terminal— you typing the verbs yourself (the thinnest client); - an agent concierge— aclaude

/codex

/opencode

/pi

session that relays asks in plain language and answers on your behalf; - a notify script— a loop that pushes asks to Slack/SMS and relays your reply.

A client is an interface, never a decision-maker. looop decides; the client just carries the question to you and your answer back.

Two properties make all this dependable:

Level-triggered. All state is plain files, so the loop re-senses every beat and a crashed pulse just re-reads its files on restart. A pending ask survives restarts — no queues, no lost work.One move per beat. Each beat does at most one thing; a daily budget caps spend. Behavior stays legible and cheap — an unchanged world costs no LLM call.

SENSE— run everysensors/*.sh

, refreshingsnapshots/

. World unchanged since last beat → stop here, no LLM call.DECIDE— on change, hand the PLAYBOOK + goals + readings + pending asks to the LLM, which returns** onetyped move. ACT**— execute it: write a goal/sensor/PLAYBOOK, run one reversible command, or spawn a worker. Irreversible moves are gated — they wait for youranswer

(see above), and so does any worker that hits a human-only decision.

Layer What it is
core
the autonomous pulse + the durable state behind it. Decides and acts.
contract
the looop _ … verbs — the one stable, backend-agnostic surface to read and steer core.
client
anything that drives the contract for a human (terminal / concierge / notify). An interface, never a decision-maker.

State is plain files in the data dir, reached through the contract — not a public interface:

File / dir Role
PLAYBOOK.md
your judgment, priorities, guardrails
goals/*.md
desired state — one declarative spec per thing you push
sensors/*.sh
observers — each prints one JSON object
journal.md
action log — one line per move
asks/ answers/
the worker ↔ human mailbox
curl -fsSL https://raw.githubusercontent.com/yusukeshib/looop/main/install.sh | bash
cargo install looop

Only hard dependency: an LLM runner. claude

is the default; codex

, opencode

, and pi

also work — pick one with looop init

. (Workers that touch code isolate their own sandbox via git worktree

, or box

if available — a worker convention, not a looop dependency.)

looop init     # interactive setup — required before `up`; pick the runner wiring
looop up       # start the autonomous pulse (detached)
looop watch    # live log + running-session selector (read-only)
looop down     # stop the pulse and all workers

looop init

is required before looop up: the pulse refuses to start until the runner wiring exists, so the agent CLI driving every tick and worker is an explicit choice, never a silent default. To read and steer core, drive the

looop _ …

verbs by hand (looop _ state

, _ wait

, _ answer

, _ goal write

) or let a client drive them for you.looop runs headless, so it can't interview you. A fresh data dir is seeded with a starter PLAYBOOK, a setup

goal, and a real pending setup

ask so a client waiting on asks wakes immediately. The simplest way to answer is an agent client ("concierge") — a claude

/codex

/opencode

/pi

session you talk to in plain language:

claude   # then say:

The concierge runs looop up

, surfaces the pending setup ask, and edits your goals/PLAYBOOK via the write verbs — speaking plain language while driving the contract. Once customized, answer the starter ask and archive the setup

goal; looop runs from there.

You can skip the concierge entirely and steer by hand. See looop help

for the full command reference and design manual.

The config ($LOOOP_CONFIG

, default ~/.config/looop/config.json

) is just two shell commands. looop init

lets you pick claude

, codex

, opencode

, pi

, or custom

; after that looop treats the result as plain runner wiring:

Key Role
tick_command
run ONE disposable decision. The prompt is passed via the {{prompt_file}} placeholder (substituted with the prompt file path — read it with $(cat {{prompt_file}}) or @{{prompt_file}} ). If you omit the placeholder the prompt is piped in on stdin instead. Must run unattended (no permission prompts — the detached pulse can't answer them) and emit a structured event stream looop can render.
worker_command
launch a worker agent. Same {{prompt_file}} placeholder, substituted with the worker's prompt file path. (A worker can't use the stdin fallback — stdin is its live attach TTY.)

The built-in presets are:

claude (default)

{
  "tick_command": "claude -p --output-format stream-json --verbose --dangerously-skip-permissions --model sonnet \"$(cat {{prompt_file}})\"",
  "worker_command": "claude --dangerously-skip-permissions --model opus \"$(cat {{prompt_file}})\""
}

codex

{
  "tick_command": "codex exec --json --dangerously-bypass-approvals-and-sandbox \"$(cat {{prompt_file}})\"",
  "worker_command": "codex --dangerously-bypass-approvals-and-sandbox \"$(cat {{prompt_file}})\""
}

opencode (best-effort — verify against your installed version)

{
  "tick_command": "opencode run \"$(cat {{prompt_file}})\"",
  "worker_command": "opencode \"$(cat {{prompt_file}})\""
}

pi

{
  "tick_command": "pi -p --mode json -ne --model claude-sonnet-4-5 --thinking low @{{prompt_file}}",
  "worker_command": "pi --model claude-opus-4-8 --thinking medium @{{prompt_file}}"
}

Model ids above are examples. For claude, sonnet

/opus

are aliases that always resolve to the latest of each; pin a specific version (e.g. --model claude-opus-4-1

) if you need reproducibility.

── more in #ai-agents 4 stories · sorted by recency
── more on @looop 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
Live at https://your-agent.zahid.host
Get free account → Pricing
from €0/mo · no card required
LIVE [news/looop-a-tiny-portabl…] indexed:0 read:6min 2026-06-30 ·