Terminal coding agent. Bring your own model.
macOS / Linux / WSL
curl -fsSL https://raw.githubusercontent.com/notshekhar/loop/main/install.sh | bash
Windows (PowerShell)
irm https://raw.githubusercontent.com/notshekhar/loop/main/install.ps1 | iex
Windows (cmd.exe)
curl -fsSLo %TEMP%\loop-install.cmd https://raw.githubusercontent.com/notshekhar/loop/main/install.cmd && %TEMP%\loop-install.cmd
Then:
loop login
loop
Prebuilt binaries — no Node required. Targets: darwin-x64, darwin-arm64, linux-x64, linux-arm64, windows-x64.
Built on top of pi by Mario Zechner / earendil-works. The TUI renderer (
packages/tui) is an in-repo fork of pi-mono'spi-tui; the message/tool renderers, theme engine, session tree, and skills loader are our own ports of pi-mono's components. This repo wires those primitives to multiple model providers via the Vercel AI SDK. See Credits.
- One TUI, many models. Switch with
/model, cycle agents with Tab. - Renders streaming text, reasoning, tool calls, and diffs inline.
- Sessions are append-only trees:
/treenavigates branches,/forkbranches from any earlier message, abandoned branches can be summarized back into context. - Subagents: the
tasktool runs a named agent in its own context window and reports back. - Goals: background tasks —
/goal convert utils.js to tsruns it detached right now;/goal check the deps every day at 9amruns headless on an OS timer (launchd / systemd / Task Scheduler) even when loop is closed. - MCP servers (stdio + http/sse, OAuth included) and a JS extension system (custom tools, providers, middleware).
- Claude Code-compatible lifecycle hooks — your existing
~/.claudehooks and plugins load as-is. - Works from a one-shot prompt (
loop run "...") or interactively. - Exposes a JSON-RPC server for programmatic use.
| Provider | Auth | Notes |
|---|---|---|
| xAI (Grok) | OAuth (SuperGrok) or API key | Default: xai/grok-build-0.1 |
| Anthropic | API key | Claude 4.x — Opus / Sonnet / Haiku |
| OpenAI | API key | GPT-5 family |
| API key | Gemini 3.1 Pro / Flash / Flash-Lite | |
| OpenRouter | API key | 100+ models, searchable picker |
| GitHub Copilot | OAuth (device flow) | Subscription-billed |
| AWS Bedrock | none (AWS creds/SSO) | Auto-detected from the aws CLI / env |
| DeepSeek / Mistral / GLM / Z.AI / Groq / Cerebras / ZenMux | API key | Built-in |
| Ollama | none (local daemon) | Auto-detected; LOOP_OLLAMA_BASE_URL to point |
| Custom | 6 auth methods (below) | Any OpenAI/Anthropic/Google-compatible gateway |
Custom providers (/login custom): name + base URL + auth + model list, saved to ~/.loop/ and usable like any built-in — handy for gateways like Bifrost or LiteLLM. Six auth methods:
- API key — stored key, sent in the vendor header (
x-api-key/Bearer/x-goog-api-key). - Bearer token — always
Authorization: Bearer, for gateways with their own tokens. - OAuth / SSO — browser sign-in. Endpoints auto-discover from
.well-knownmetadata; when the server exposes none, the wizard asks for the authorization/token endpoint URLs (and a client id if the server doesn't support dynamic registration). Tokens refresh automatically; add theoffline_accessscope if the server needs it for refresh tokens. - Environment variable — read at request time, nothing stored.
- Command (key helper) — a shell command whose stdout is the key (a vault read, or a vendor login command that mints a short-lived key). Stdout can also be JSON —
{"key": "…", "expiresAt": <epoch-ms or ISO-8601>}(apiKey/tokenandexpiresInMsalso accepted) — so the key's real expiry drives re-runs instead of the default 5-minute TTL. Keys persist in~/.loop/auth.jsonacross restarts until they expire, and a 401 always forces a fresh mint. - None / headers only — for mTLS, custom headers, or open endpoints.
loop # interactive TUI
loop run "explain this repo" # one-shot (also: echo "prompt" | loop run -)
loop login [provider] # auth (xai, anthropic, openai, google, openrouter, github-copilot, ollama, custom)
loop logout [provider] # remove auth
loop sessions # list sessions in cwd
loop goals <cmd> # goals: list, add, rm, run, tick, daemon install|uninstall|status
loop mcp <cmd> # MCP servers: add, list, remove, login, …
loop install / extensions # install / list JS extensions
loop models # list catalog
loop whoami # active provider + auth status
loop cost audit # verify the cost ledger reconciles
loop upgrade # self-update
loop rpc [--socket] # JSON-RPC over stdio or Unix socket
loop help # full usageFlags: --model <provider/id>, --provider <id>, --cwd <path>, --session <id>, --max-steps <n> (run mode).
| Group | Commands |
|---|---|
| Sessions | /new /clear /resume /sessions /session /name /export /import /share /compact /context |
| Tree | /tree /fork /clone |
| Models | /model /provider /thinking /scoped-models (+ Ctrl+P cycle) |
| Agents | /agents /<agent> <message> (one-shot) |
| Automation | /goal /daemon /reminder /timer /recap |
| Setup | /login /logout /settings /mcp /extensions /hooks /bashdeny /doctor /reload /update |
| Misc | /help /cost /memory /init /attach /paste /copy /cd /hotkeys /changelog /quit |
/clear starts a fresh session (and clears the screen). Messages and slash commands typed while the agent is generating queue up and run after the turn.
Sessions are stored as trees — every entry has a parent, and the "leaf" is where the next message lands.
/tree— navigate the whole session as an ASCII tree: fold branches, filter (no-tools / user-only / labeled / all), type-to-search, bookmark entries with labels (shift+l). Selecting an earlier point branches there; loop offers to summarize the abandoned branch (optionally with a custom prompt) so its context survives the switch./fork— pick a previous user message; the path up to it is copied into a new session and the message text returns to your editor for editing./clone— duplicate the current conversation into a new session.
Existing flat sessions migrate automatically on first open.
- Built-ins:
default(full toolset),plan(read-only investigator), anddata-analyst(SQL-first, activated via/datasource). Create your own with/agents— custom system prompt + tool allowlist + optional pinned model, registered as/<name>for one-shot use. - Tab (empty prompt) or Shift+Tab cycles agents.
- The plan agent delivers plans as a deliverable: when its plan is final it calls the
plantool, which ends the turn and renders the full plan as markdown. You then choose implement it (pick an agent — the plan is handed over as a one-shot) or talk about it (keep refining with the plan agent). - The
tasktool spawns a subagent: a fork of the current agent (same prompt, same tools minustask, fresh context). Activity streams live in the task box; only the final report enters the main context. Toggle via/settings → subagents.
A goal is a background task tied to a directory. /goal <text> parses natural language with your current model — schedule words and agent mentions included — then confirms before acting:
/goal convert utils.js to typescript → runs NOW, in the background
/goal remind me to rebase in 45 minutes → runs once, in 45 min
/goal check outdated deps every day at 9am with plan agent → cron, pinned to the plan agent
- No time mentioned = run immediately in the background (detached, headless) — like background tasks in other coding agents. You get a desktop notification when it finishes.
- Scheduled goals (once / cron) run headless via the goals daemon — toggle it with
/daemon(orloop goals daemon install): a launchd agent (macOS), systemd user timer (Linux), or Task Scheduler job (Windows) ticks every minute and runs due goals even when loop is closed. - Every run is a normal session (named
goal: …, resumable from/resumeor the/goalpanel's "open last run"), records status + summary on the goal, and notifies on completion. - Every goal can pin its own model and agent (otherwise it inherits your defaults at run time). Manage everything in the
/goalpanel or withloop goalson the CLI.
read · bash · edit · write · grep · find · ls · sql · task — colored diffs, syntax-highlighted output, file previews. read also fetches http(s):// URLs as readable text (and takes offset/limit for large files). edit/write enforce read-before-modify per session. Opt-in extras: websearch (DuckDuckGo, no API key — /settings → websearch) and ask (the agent pauses to ask you multiple-choice questions — /settings → askUser). The plan tool belongs to planner agents (see Agents above).
- MCP servers —
loop mcp add(or/mcp): stdio and http/sse transports, OAuth login flows,${env:VAR}secrets, per-project servers in.loop/mcp.json. Server tools join the agent's toolset automatically. - Extensions —
loop install <spec>//extensions: JS extensions can add tools, slash commands, providers, status-line segments, and tool/turn middleware.loop linkdevelops one from a local folder.
bash can run each command inside an OS-enforced sandbox (@notshekhar/loop-sandbox), so the model's shell access is bounded by the kernel, not just by trust. Enable and shape it via the sandbox setting in settings.json:
enabled— turn the sandbox on.network—"deny"(default) blocks outbound network, or allow it per your config.allowWrite/denyWrite/allowRead/denyRead— filesystem boundaries (the working directory is writable by default; everything else is read-only unless allowed).allowGitConfig— let commands read your git config.
It is fail-open by design for the normal case: if the boundary can't be applied on your platform (unsupported OS, missing dependency, wrap failure) the command still runs, but loop appends a [loop sandbox] … ran WITHOUT isolation warning — never a silent downgrade. The read-only plan agent is the exception: it is fail-closed — bash there runs in a kernel-enforced read-only, network-denied sandbox, and is refused outright if that can't be enforced.
Before anything runs, bash checks the command against the bashDeny list and refuses a match — a guardrail, not a security boundary. It resolves each command to its real name + subcommand, looking past wrappers (sudo, env, nohup, time, xargs, rtk, …), sh -c "…" scripts, and $(…)/backtick substitutions, and normalizes full paths to their basename (/bin/rm → rm). Patterns match by name (rm) or name + subcommand prefix (git commit).
It defaults to git commit and git push (commits/pushes stay with the human). Override the whole list in settings.json or manage it with /bashdeny. String inspection is fundamentally bypassable (base64-pipe-to-sh, write-a-script-then-run-it, …) — that's what the sandbox above is for; the denylist just reliably stops honest, ordinary invocations.
Lifecycle hooks (PreToolUse, PostToolUse, SessionStart, Stop, …) run shell commands with a JSON payload on stdin — Claude Code-compatible: hooks and plugins from ~/.claude/settings.json and .claude/ are imported automatically (filter with the claudeHooksFilter setting). Manage loop-owned hooks with /hooks; project hooks live in <repo>/.loop/settings.json. First open of a repo that ships hooks/skills asks for project trust before anything executes.
/thinking off | minimal | low | medium | high | xhigh
Mapped per provider: Anthropic budget tokens, OpenAI/xAI/OpenRouter reasoning effort, Google thinkingConfig.
Paste image (Cmd+V / Ctrl+V), /attach <path>, or Ctrl+I for the file picker.
*.mdunder~/.loop/agent/skills/or.loop/skills/— auto-registered as/skill:<name>.*.mdunder~/.loop/agent/prompts/— invokable as a slash command.AGENTS.md/CLAUDE.mdin the repo are loaded as workspace context automatically.
The footer shows live cost/usage/context per step (subagents included). /cost breaks it down by session, directory, today, last 7 days, month, and lifetime per provider. Anthropic prompt caching is managed automatically (moving cache breakpoints across multi-step turns).
dark and light built in; drop pi-mono-format JSON themes in ~/.loop/agent/themes/ and pick via /settings → theme (applies live).
Run loop headlessly in CI — review PRs, answer questions about a diff, or automate anything a one-shot prompt covers:
on:
pull_request:
permissions:
contents: read
pull-requests: write
jobs:
review:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: notshekhar/loop@v0
with:
prompt: "Review the changes in this checkout and summarize bugs and risks."
model: anthropic/claude-sonnet-4-6
post-comment: "true"
env:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}| Input | Default | What it does |
|---|---|---|
prompt |
(required) | The prompt to run |
model |
(required) | Fully-qualified provider/model id |
version |
action's own tag | loop release to install (vX.Y.Z); falls back to latest |
working-directory |
. |
Directory loop runs in |
max-steps |
40 |
Step cap for the turn |
post-comment |
false |
On PRs: post the response as a comment, updated in place on later pushes |
github-token |
github.token |
Token for release lookup + comment posting |
The agent's response is exposed as the response output and appended to the job summary. Auth rides the caller's env (<PROVIDER>_API_KEY, same fallback as the CLI) — no config files. post-comment: "true" needs pull-requests: write permission. Linux/macOS runners.
curl -fsSL https://raw.githubusercontent.com/notshekhar/loop/main/install.sh | bashDownloads the latest GitHub Release binary tarball (bun-compiled, zero runtime), verifies sha256, runs the binary once to confirm it works on your machine, and symlinks loop and agent into /usr/local/bin or ~/.local/bin (with an exact PATH line for your shell if needed). musl distros (Alpine) get a clear pointer to gcompat or a source build.
Env knobs: LOOP_VERSION (pin a tag), LOOP_FORCE, LOOP_FROM_SOURCE, LOOP_HOME, LOOP_BIN_DIR, LOOP_UNINSTALL=1 (clean removal — keeps ~/.loop config).
PowerShell:
irm https://raw.githubusercontent.com/notshekhar/loop/main/install.ps1 | iexcmd.exe (bootstraps PowerShell):
curl -fsSLo %TEMP%\loop-install.cmd https://raw.githubusercontent.com/notshekhar/loop/main/install.cmd && %TEMP%\loop-install.cmdInstalls to %USERPROFILE%\.loop-bin\loop.exe, adds it to user PATH and the current session — loop works immediately, no new terminal needed. Windows on ARM gets the x64 build (runs under Windows 11's emulation). First run shows SmartScreen — click "More info" → "Run anyway".
Env knobs: $env:LOOP_VERSION, $env:LOOP_FORCE, $env:LOOP_HOME, $env:LOOP_UNINSTALL = '1' (clean removal — keeps ~\.loop config).
/update inside the TUI, or loop update from the shell — both check the latest release and run the platform installer in place (self-update works while loop is running, on Windows too). The TUI also tells you at startup when a newer release exists. LOOP_SKIP_VERSION_CHECK=1 silences the startup check.
git clone https://github.com/notshekhar/loop.git
cd loop
bun install
bun run build
bun run linkEverything under ~/.loop/:
~/.loop/
├── auth.json # provider tokens + custom gateways (mode 600)
├── settings.json # defaultModel, thinkingLevel, hooks, mcpServers, …
├── models.json # user-added models / catalog overrides
├── catalog.json # model catalog cache
├── agent.db # SQLite: session trees, cost ledger, per-project memory, reminders, goals
├── agents/*.md # custom agents (and built-in prompt overrides)
├── extensions/ # installed JS extensions
└── agent/
├── prompts/*.md # custom slash commands
├── skills/*.md # auto-registered skills
└── themes/*.json # custom themes
Per-project config in <repo>/.loop/ (settings + hooks + skills), gated by project trust. The last model picked in a folder is remembered per project.
If a model isn't in the catalog (a brand-new release, an OpenRouter :free variant, a private deployment), add it via /model → + add model… in the TUI, or by hand in ~/.loop/models.json:
{
"openrouter/nex-agi/nex-n2-pro:free": {
"id": "openrouter/nex-agi/nex-n2-pro:free",
"provider": "openrouter",
"name": "Nex AGI: Nex-N2-Pro (free)",
"contextWindow": 262144,
"maxOutput": 262144,
"cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 },
"reasoning": true,
"modalities": ["text", "image"],
"available": true
}
}Keys are full provider/model-id ids; entries merge over the built-in catalog, so the same file also overrides pricing or context windows of known models. cost is per million tokens and defaults to 0 — set it if you want cost tracking to bill the model. The id is not validated up front; a wrong one simply errors on the first request. The catalog itself refreshes from models.dev hourly, so new public models usually just appear.
- TypeScript (strict, ESM). Runtime: bun-compiled single binary (no Node required for users). Dev: bun ≥ 1.2
- Vercel AI SDK v7 — agent loop, streaming, tool use, reasoning, subagents
@notshekhar/loop-tui— the TUI core, forked from earendil-works/pi (pi-tui): differential terminal rendering, editor, markdown, select listszodv4 schemas,configstorefor config, SQLite (WAL, viabun:sqlite) for sessions/cost/goals- Distributed as GitHub Release tarballs
packages/
core/ @notshekhar/loop-core — auth, providers, catalog, session trees, agent loop, tools, hooks, RPC
tui/ @notshekhar/loop-tui — terminal renderer, forked from earendil-works/pi (pi-tui)
cli/ @notshekhar/loop — bin: `loop` / `agent` (TUI + run + RPC)
- No cloud agents — the goals daemon runs on your machine only.
- No multi-device sync.
- No web / desktop UI — terminal only.
bun install
bun run dev # run the CLI from source
bun run build # gen catalog → core → tui → cli
bun test # unit tests (hooks, agents, cost, compaction, sessions)
bun run format # prettierRelease:
git tag v0.x.y
git push origin v0.x.yCI runs build (version sync, install, build, typecheck, smoke test, tar+sha256) then github-release (uploads tarball to the GitHub Release).
- Package-manager distribution: Scoop bucket, winget (Homebrew tap exists).
- More providers — Azure OpenAI.
- Web / desktop client over JSON-RPC.
PRs welcome.
loop exists because other people did the hard parts first.
- Mario Zechner / earendil-works — author of earendil-works/pi (pi-mono). The TUI core in
packages/tuiis a direct fork of his MIT-licensedpi-tui— the differential renderer, editor, and component model are his work. The session tree format, message components, tool renderer, theme engine, and skills loader are ports of pi-mono's source. Without pi-mono this CLI would be a fraction of what it is. - Vercel — the AI SDK carries the agent loop, multi-provider streaming, tool use, and reasoning.
- xAI / Anthropic / OpenAI / Google / OpenRouter / GitHub / Ollama — model APIs and runtimes.
MIT.