Local Operator
An open-source AI agent hub: build organizations of collaborating agents that run on your own machine, around the clock
Roles, teams, and cross-agent messaging on top of a fast terminal UI, using every AI subscription you already pay for
A manager session with three workers running in the background (each with its own role, budget, and progress) while the shared plan updates.
Local Operator is a harness for organizations of agents: the runtime that hosts, supervises, and connects them. A single session plans its own work, runs tools, browses, and remembers what it did. Give it a team and it becomes a manager that delegates to tool-restricted workers, messages sibling sessions in other repos, schedules its own follow-ups, and picks those follow-ups back up after you close the terminal. Everything runs on your machine, asks before it writes or executes, and is MIT licensed. It draws on every ChatGPT, Claude, Kimi, Grok, Z.AI, and Qwen login you already have, pooled, load-balanced, and used with the prompt cache in mind.
📚 Table of Contents
- ✨ Why Local Operator
- 🚀 Quickstart
- 🪟 Desktop App (local-operator-ui)
- 🏢 Agent Organizations
- 🔁 Cross-Agent Communication
- 🛰️ Agent Mesh (your own devices)
- 🌙 Always On
- 💳 Subscriptions
- 🧮 Built for Token and Cache Efficiency
- 🖥️ A Tour of the Terminal UI (TUI)
- ⚙️ Headless & Server Modes
- 📱 Phone Access (Mobile Relay)
- 🌐 Drive Your Own Browser (Browser Extension)
- 📦 Installation Options
- 🔧 Configuration & Credentials
- 🌟 Radient: automatic model selection and agent sharing
- 🔒 Safety Model
- 📝 Examples
- 👥 Contributing
- 🙏 Credits and Acknowledgements
- 📜 License
✨ Why Local Operator
- Agent organizations with enforced roles. Roles are capability
reviewer loses the tools to edit what it reviews),
specialists carry their own standing instructions, and a team is a saved
roster (a manager plus members) with two short briefs: how the group works
together and what product it owns. Reuse the same roster on a different
product by swapping one brief. Nested teams show in the chart today; a
manager delegating into a nested team's manager is coming.
- Agents that talk to each other. A manager peeks at, questions, steers,
hub; independent sessions in
different repos message each other with send, choosing whether to leave a
note, wake an idle peer, or redirect one mid-turn. Loopback only, your OS
account only.
- Always on. Wakes persist and fire on schedule even after the terminal is
lop exec --background detaches a
whole task; a paused worker resumes after a process restart; the mobile
daemon keeps every session reachable from your phone.
- Every subscription you already pay for. Sign in to ChatGPT, Claude,
- Cheaper long sessions. The prompt is laid out so your provider's prompt
- Approval-gated by default. Reads run; writes and shell commands show the
/approvals auto or
--yolo. Every tool call leaves a visible receipt in the transcript.
- Reach beyond the terminal. Watch and steer sessions from your phone,
🚀 Quickstart
Bring Python 3.12+ and one of: a provider login (see the subscription table for the ids), an API key, or a local model server.
pip install local-operator # pipx install local-operator on systems whose Python is externally managed (Debian/Ubuntu, Homebrew)
lop login anthropic # opens your browser; paste the code back if asked. lop login lists providers
lop # start it, then type what you want done
lop is the short alias the install provides alongside local-operator; the
rest of this page uses it. lop login also sets that provider as
your default hosting and picks a default model when none is configured, so the
very next lop just works. Skip the login and an interactive lop opens in a
setup state and walks you through /login; a headless or piped run prints the
exact commands to configure hosting, model, and a key instead.
Inside, esc stops the agent, /help lists commands, /exit quits. Try
something like summarize this repo and list what's untested. lop update
upgrades the install from PyPI and restarts the mobile daemon when the
LaunchAgent is installed.
The main view of the Local Operator TUI: the splash, the keybinding hints, and the composer where you start your first prompt.
Prefer a local model? A 7–14B model needs roughly 10–16 GB of RAM or VRAM.
Start LM Studio, load a chat model, and enable its
server in the Developer tab; then /login lmstudio inside Local Operator
picks the endpoint and model. /login also offers Ollama, vLLM, llama.cpp,
and a generic OpenAI-compatible server. See the
local-provider guide. The CLI form still works for
a model installed in Ollama:
lop --hosting ollama --model qwen2.5:14b
🪟 Desktop App (local-operator-ui)
The terminal stays the core surface, and the rest of this page describes it. The desktop app is the second way in: Local Operator UI is a desktop application for macOS, Windows, and Linux that drives the same sessions, teams, schedules, and configuration, and adds the surfaces a terminal cannot draw.
The desktop app on the Invoices workspace: the rail with its chats, agents, teams, and mesh; the transcript's tool receipts and streamed write-up; two subagents running above the shared to-do list; and the composer holding a draft. Fixture-driven like the mesh figures below — the real interface over the app's own fixtures, not a live session.
What the app adds:
- A browser the agent can drive. A Chromium pane with its own tabs and
- A file canvas and viewer. Documents a session works on open beside the
- The same surfaces, as pages. Agents, schedules, and settings are pages;
- A terminal agents can use — coming soon. A per-session Console tab with
bash alone cannot.
A conversation where images are part of the turn: a chart pasted into the session, and the bar chart the agent plotted and showed inline above its write-up.
Easiest install — the desktop build. Download the installer for your
platform from the downloads page
(macOS, Windows, and Linux, with the system requirements listed there). The app
bundles its own backend and installs it on first run, and uses an existing
Local Operator install when it finds one, so a separate lop install is
optional.
Or install from a terminal (Node.js 22.13.1 or newer):
npx local-operator-ui # download and run in one command
npm install -g local-operator-ui # or install it globally
local-operator-ui # ...then start it by name
Source, issues, and release notes live at damianvtran/local-operator-ui.
🏢 Agent Organizations
Three layers: subagents are the parallel workers, roles decide what each one is allowed to touch, and a team is a saved roster you can point at a different product.
Subagents. Ask for parallel work and the agent fans it out into concurrent background workers, then keeps working while they run. The subagent dock shows each worker's status, spend, and progress live, and you can open any of them to read its transcript and plan (the reader's keys and limits are in docs/subagent-reader.md).
Two workers mid-run in the run pane — one drafting, one auditing — each with its role, elapsed time, context use, and spend, above the to-do list they share.
Roles are capability boundaries. A subagent launched as reviewer carries
vetted review guidance and loses the tools to edit code. It can read and run
tests, but it has no way to alter what it reviews. A restricted role cannot
enable new MCP tools either, and the restriction is inherited by everything
it delegates to, at any depth. Packaged starters for reviewer, coder,
architect, manager, designer, scout, ux-reviewer, tui-designer, and
copy-reviewer ship in the package:
task(agent=…) and /team use them even on a fresh install, and
agent install copies one into your registry so you can edit it.
lop agents list shows what's installed, so a fresh install prints "No agents
found." You can also author your own agent profiles: reusable roles and
named specialists with their own instruction sets, matched to tasks by
semantic routing. When a profile gives bad guidance, you fix the profile once
instead of every prompt that uses it.
Teams. A saved roster (a manager plus members with counts) layered with
two briefs the individual agents never hard-code: a collaboration brief (how
this group works together, who blocks a release) and a project brief (what
product this instance owns). Swap the project brief and the same roster staffs
a different product. A roster slot can name another team (team:), so a
team becomes an org of teams; /team chart draws it as an org chart.
Nesting is live: task(agent="team: starts that sub-team's manager,
with its own roster and briefs. lop teams list is empty until you create one.
A team in the desktop app: the roster — manager plus members and counts — and its two briefs, how the group works together and what it ships.
Sending a request to a team is one line: /team makes the
current agent that roster's manager, which breaks the work down and puts the
right roles on it. Agents and teams can also be managed from the CLI:
lop agents create "My Agent"
lop agents list
lop teams list
lop teams show lopdev
🔁 Cross-Agent Communication
Two shapes of conversation, one machine, no cloud in the middle.
Down the tree. Every worker a session spawns is addressable through hub:
peek reads the last few steps of its transcript without spending its
attention, ask poses a question and waits for the answer, send drops a
note, steer changes its course, pause stops it while keeping it resumable,
cancel ends it, and resume relaunches a stopped, paused, or settled child
against its own transcript, including after the parent process has restarted.
Across sessions. Two lop sessions you started yourself, in different
repos, with no parent between them and no shared context, can message each
other directly. One can tell another to hold off on a deploy, hand over a
finished branch, or claim a shared resource, without you relaying it between
terminals.
Two independent sessions negotiating a shared deploy slot. One claims it and asks for objections; the other checks its own in-flight work and clears it. No human in the loop.
lop sessions is the directory of every session on the machine: state,
pid, kind, conversation, model, memory footprint, uptime, and heartbeat age
(--json adds cwd and session_id). From a shell you use lop send; from
inside a session the agent uses its own send tool, which lands as an
auditable card in its transcript. Both share the same three delivery modes
and differ only in the default: the CLI drops to the mailbox unless you ask
otherwise, while an agent's send wakes an idle peer. --wake starts a
turn if the target is idle; --now injects mid-turn to redirect a session
that is actively working. A running bash, eval, or MCP call is never cut
short, and a session parked in wait returns early to read the message.
lop sessions
lop send "release cutter" "gates are green, ready for review"
lop send "release cutter" --wake "the deploy finished; verify prod"
lop send "ingest refactor" --now "hold off, the schema changed"
lop send --pid 12345 "gates are green, ready for review" # address by exact pid
git log -1 --stat | lop send "release cutter" # body from stdin
Every delivery leaves a receipt on both ends: the target sees an inbound
↔ peer message from " card, and the sender
gets back how the message landed. Targeting is a case-insensitive substring
over conversation name, session id, and cwd basename, and it refuses to guess:
an ambiguous match lists the candidates and exits non-zero rather than
delivering to the wrong session. The trust boundary is your OS account: every
session publishes a 0600 discovery record under a 0700 directory and
answers on an authenticated loopback server, so there is no remote or
cross-user path. The full targeting and refusal rules, the receipt strings,
and the limits (256 KB bodies; headless exec sessions may not receive) are
in the packaged peer-messaging guide.
🛰️ Agent Mesh (your own devices)
lop network pairs your machines into a mesh: a group of devices that trust
each other by a shared secret, each with a keypair of its own. Pair once, and
the sessions running on those devices become one list you can read and act on
from any of them — the desktop you work at, the laptop upstairs, the small box
in the cupboard. Another device's sessions appear in the sidebar under their own
heading, marked ⇄, and you can start, list, warm or stop a session on a peer
without leaving the machine you are sitting at.
The mesh is peer-to-peer: your devices dial each other directly, with no service in the middle, and the relay that coordinates them runs on your own machine (under a LaunchAgent on macOS). The trust boundary is the network itself — a device you paired — and pairing is a single-use token plus a code two people compare on two screens.
A device in a mesh: another machine's running sessions carry the ⇄ mark and group under it, beside this device's own pinned and active sessions. Captured from a real two-device mesh — the rows come from the peer's own listing, over a live link, not from a fixture.
/network: this device, the networks it is in, which peers answer, and whether the relay is running.
Getting started. On the device that should own the network:
lop network init devmesh # create the network, mint this device's identity, start the relay
lop network invite --role drive # a single-use token, written to a file, never printed into a pipe
It prints where the token went; hand that file to the other device out of band and, there:
lop network join @/path/to/token # both devices show a code; a person compares them, then confirms
lop network status # installed, identity, relay, and this device's links
lop network ls # devmesh n_2bf6b70bd36b1cca228daa9f epoch 1 admin 1 member(s) active
invite --print reads the token straight off a terminal when you would rather
copy it than move a file. Roles are read, drive and admin; a token can be
bound to one device and given a shorter life. The pairing did work when
lop network peers names the other machine — it is the live answer, not the
stored one — and lop network doctor is what to run when a device that should
be there is missing, since it reports reachability, epochs and identity per
link. The full walk-through — including what to do when a device is
unreachable, and the incident verbs (panic, disconnect) — is in the packaged
network guide.
From inside a session. The mesh is a slash-command family, so you never leave the composer:
/network this device's networks, peers and relay state, as a screen
/network peers which devices answer right now
/network sessions --all-peers what other devices are running: list, engage, stop
/network status relay health and the log path
/network log the recent mesh event trail
The pairing verbs are here too — /network new creates the network and
/network invite mints the token — and on a device that has never paired,
/network on its own opens a screen whose empty state names the whole path in
order: create, invite, join. **The joining half is the one step a TUI cannot
host.** Pairing shows a code on each device for a person to check across, so it
runs in a terminal, and /network join typed into the composer says exactly
that instead of half-starting a pairing that cannot finish.
Running a session on another device. /new remote creates the session on
the peer, with a trailing sentence as its first prompt:
/new remote radiant-m4 rebase the auth branch and run the test suite
/new lists the devices you paired: the row carries the whole remote <peer> argument, so the first Enter fills a command that runs, and the composer preview always shows exactly what will be sent. The splash's version line is the build this frame was captured from — a development worktree — and not the version of the release this page documents.
The session is minted, spawned and admitted by that device, and the receipt in
your transcript names it. /network sessions --peer radiant-m4 then lists what
that peer is holding, and --engage warms one or --stop
ends it — so a session started this way is visible and controllable from the
machine you are sitting at, without a second terminal. The same act is one
command from a shell, which is how a script or another agent asks:
lop network sessions --peer radiant-m4 --create --name "auth rebase" \
--prompt "rebase the auth branch and run the test suite"
Whichever front end starts it, the session is the peer's: it appears in that
device's own lop sessions, it shows up here under the ⇄ heading for that
device, and piloting it is what piloting a local session is — read the
transcript, send a turn, watch it work.
Moving a session between devices. Work that has outgrown the machine it started on, or work you want back in front of you, moves with its id and its transcript:
lop sessions move 9f3ac1e0b7d2 --to build-box # hand it to the peer; the copy here is retired
lop sessions move 9f3ac1e0b7d2 --to local # bring a remote one home to this machine
lop sessions move 9f3ac1e0b7d2 --to build-box --keep # copy it and leave the original running — a new id, marked as a fork
The device that will hold the conversation is the one that issues the move,
so --to is this machine asking the peer to pull and --to local is
this machine pulling; there is no push verb. A session with a turn in flight is
refused rather than interrupted, and --wait re-checks a busy one every five
seconds. Inside the TUI the same act is /move . lop sessions sync keeps this machine's copy of a conversation
a peer owns up to date without opening it, and lop sessions move recovers that copy as a new session for when the device
that held it is gone.
Recalling a conversation from a peer, and the --keep distinction in a single dialog: the recall deletes the copy on the device the conversation leaves — the subtitle names it, cloud-node-1 — while the other choice copies it and leaves the original running. The tab behind the dialog sits under a scrim (measured: about 40% of its brightness), so the choice is the only live thing on screen. Fixture-driven like the canvas below — the real page over local-operator-ui's own fixtures, not a live mesh.
Credentials are brokered, not copied. lop network credential share
lets a peer borrow a login this device holds, for a
bounded grant (network.credentials.grant_ttl_s, fifteen minutes by default),
and lop network credentials shows who owns what and what this device borrows.
A refresh belongs to the device that owns the credential — it lends a short-lived
access token and never its refresh token, which is why a token is never refreshed
on a device that does not own it. kimi is the one provider that can never be
lent: its grants are signed with the fingerprint of the device that made them.
The desktop app has its own view of it.
local-operator-ui mounts a
Mesh tab beside the sessions it lists: the networks this device is paired
with, the devices in each, and what each of them is holding. The tab appears once
this device is in a mesh — a device in none shows no Mesh row at all, so pairing
comes first.
The mesh in the desktop app: the networks this device is paired with, the devices in each, and what each of them is holding. It is also where a move is made by hand — a conversation is dragged from one device's node onto another's, which a still cannot show, and the dialog above is what that drag asks before it commits. From local-operator-ui's committed Mesh-tab evidence set — the real page over that repository's own fixtures, so the shapes are the backend's and the values are not a live mesh.
Nothing above documents a command that does not run today.
The design set behind all of it is in
docs/design/mesh-network.md — the spine, with
its requirements and, for each one, the document that owns it — alongside
mesh-transport-identity.md,
mesh-session-mobility.md,
mesh-credentials.md,
mesh-incident-response.md,
mesh-compute-pool.md and
mesh-ui.md.
🌙 Always On
Work keeps moving after you walk away.
- Scheduled wakes that survive a closed terminal. The agent's
waketool
/resume; /approvals auto or --yolo opts into unattended
execution. A session that was asleep past a due time fires the wake late
and reports how many occurrences it skipped, rather than replaying six
hourly checks at once. lop wake status reports whether the supervisor is
actually running (not merely installed), the soonest wake that will fire,
and how many are overdue, dormant, too stale for the supervisor to keep
retrying, or blocked by a wedged runtime holding the session lease; lop
wake list shows every schedule with that state per row. When the supervisor
has stopped or gone missing, lop wake install puts it back.
Human-readable wake times use the machine's
local timezone, labelled explicitly, with a 12-hour AM/PM clock by default.
Other dates include the month/day (and year when different). Choose **Wake
time format** in /settings → Appearance, or run
lop config edit display.time_format 24h for a 24-hour clock (12h restores
the default). This changes display only; stored timestamps and JSON output
remain epoch milliseconds, and existing transcript confirmations are not rewritten.
- Background jobs that report back on their own.
taskalways runs in
bash can (background=true); a long command
interrupted by a steer detaches instead of dying; and every settled job
auto-delivers its result when the session is idle. jobs peeks at new
output since your last look.
lop exec --backgrounddetaches a whole task with a log file and exits
- Waiting without polling.
waitblocks up to 60 minutes and returns the
send, a wake, a
subagent's hub note), or you steer. One sized wait replaces a chain of
short polls that each re-send the whole context.
- Resume after a restart. Transcripts persist and
/resumepicks a
hub
op='resume' after the parent process has restarted.
- A daemon that keeps sessions reachable.
lop mobile installruns a
lop update restarts the daemon when the LaunchAgent is installed.
The Schedules page: the recurring wakes a workspace runs, and the desktop app's reminder that they fire whether or not the window is open.
💳 Subscriptions
Sign in with the accounts you already have. lop login lists every
login-capable provider; the ids and plan requirements:
| You pay for | Type | Plan needed |
| --- | --- | --- |
| ChatGPT | lop login openai (openai-device on a headless box) | ChatGPT Plus/Pro |
| Claude | lop login anthropic | Claude Pro/Max |
| Kimi | lop login kimi | Kimi (Moonshot) |
| Grok | lop login xai-oauth (xai = API key) | Grok OAuth |
| Z.AI / GLM | lop login zai-oauth (zai = API key) | GLM Coding Plan |
| Qwen | lop login alibaba-token-plan-oauth | QwenCloud Token Plan (a personal plan also needs the console ticket for /usage) |
OpenAI, Anthropic, Z.AI, and Qwen logins are keyed by account identity, so a second login adds to the pool; Kimi holds one account (xAI identity is best-effort). API keys and local servers sit alongside.
What this means for you. With one account per provider, Local Operator uses that account's plan quota (no API bill) and, when it is rate-limited, falls back to the next model you listed. With two or more accounts on the same provider, it spreads your sessions across them so you hit the 5-hour/weekly limits later, and it deliberately does not hop accounts to balance load mid-conversation, because each provider caches your conversation per account and a hop would re-pay to rebuild it.
- Accounts on one provider form a rotation pool. New sessions start on
- Failover follows a fixed order. On a quota, auth, or 5xx failure the
retry.fallbackChains in
config.yml), backing off between attempts. /failovers prints the
cascade and marks which account is serving right now.
- **Pinned subagents descend the chain, cross-vendor only as the last
pinned X, ran on Y). The /settings row is Pinned child
fallback — allow cross-vendor (cross-family) by default; **same
family only** (same-family) restores the strict refusal.
- Cache-aware stickiness. A session prefers the account it started on,
retry.usageAwareFallback: true a low account is never an eviction; only
a depleted one moves a running session.
- Opt-in proactive switching.
retry.usageAwareFallbackspends one
retry.usageReservePercent (default 10) as the headroom floor.
- Everything is visible in-app.
/usageshows each provider's quota
/accounts lists every signed-in provider account
(the lop secret store is separate); /session reports the current session's
cost, cache, and request
diagnostics, and /session --copy copies the session ID. One exception:
QwenCloud's personal Token Plan window needs a
console ticket stored alongside
the login.
The packaged failover guide explains the routing in full, including how to change the order.
🧮 Built for Token and Cache Efficiency
Long-running agents spend most of their tokens re-sending context, so the harness treats the provider prompt cache as a resource to be managed:
- A stable prefix. The tools array is built in a deterministic order and
- Cache-aware pruning. Superseded tool outputs (an older read of a file
- Automatic 1-hour cache TTL. At or above 150k context tokens, Anthropic
providers.anthropic.cache_ttl_1h_min_context_tokens (0 disables it).
- Compaction before overflow. Context compacts itself before the window
/compact runs it on demand and /context reports what is occupying
the prefix right now.
- Lazy everything else. Skills are indexed semantically and their bodies
wait returns on job
settle or message arrival so a long job costs one round trip, not twelve.
🖥️ A Tour of the Terminal UI (TUI)
The TUI is a full-screen Textual app, not a
REPL. Everything the agent does shows up as a card or a one-line receipt: tool
cards expand (enter/space) to show the full command and output, and the
status line tracks the current step, token usage, and cost. Inside a
terminal multiplexer (tmux, wezterm, cmux, and others),
lop publishes a per-pane crash-restore binding
(multiplexer-resume.md) and, in a
Herdr Agents panel, reports whether it is idle, working,
or blocked (herdr-agents.md).
One session mid-task: streamed responses, expandable tool cards, and one-line receipts for everything the agent does.
When a tool call needs your sign-off, the approval prompt shows exactly what is about to run before anything touches your system:
Switching models goes through a picker rather than a config file. /model
lists every model your signed-in providers offer, with fuzzy filtering.
ChatGPT OAuth uses the account's supported maximum context by default while
keeping the provider default visible;
context limits and the opt-out explain how without
changing your compaction settings.
Coming back later is /resume, a picker over your recent sessions, each
with its title and age:
Slash commands
/help shows the full table in-app. The highlights:
| Command | What it does |
| --- | --- |
| /model | Switch model for this session; /model default saves the current one for new ones, /model saved reverts to it (/settings edits the boot default too) |
| /effort | Show or set reasoning effort (shift+tab cycles; save a level for new conversations with /model default) |
| /fast | Toggle fast mode where the provider sells one: the same answer sooner, at premium pricing |
| /approvals | Set whether tools ask first (ask/auto; add default to keep it) |
| /resume | Pick a past conversation and continue it |
| /new, /clear, /reload | Fresh conversation · wipe the screen · relaunch this conversation on the current install |
| /update | Install the latest version from PyPI and relaunch |
| /goal | Set the session objective and send the same text to start work. A judge checks it at each turn end and continues or marks it done. Bare /goal opens the goal card (other hosts print a one-line report). /goal --done marks it done, --dismiss clears a done goal, --history lists settled goals, and --clear deletes it without a history entry. None of these start a turn (/goal clear, none and reset still work) |
| /loop | Iterate autonomously toward the session objective: /loop for a bounded count, /loop toward an inline goal; /loop --stop cancels a running one and /loop --clear clears it — which on a detached owner means dismissing a finished run's published state |
| /btw | Ask a side question off the record; it never joins the conversation |
| /compact | Compact the context now (it also happens automatically) |
| /usage, /context | Provider quota and account spend · what's occupying the context window |
| /session | Current-session recorded usage, combined cost, cache, and request diagnostics; /session --copy copies the session ID to the clipboard |
| /failovers | The model cascade for this session, and which account is serving |
| /provider, /login, /logout, /accounts | Manage providers and signed-in accounts |
| /credential | Hand over a secret: type it after /credential and a space to have it masked and captured; a paste your terminal delivers as text is captured the same way; the composer's own paste key (Ctrl+V on macOS) is not. Bare /credential lists this session's credentials, and /credential --persist saves one to the long-term store. See Credentials and secrets |
| /search | Configure web-search providers and load balancing |
| /team | Launch a saved team: /team ; /team chart draws its org chart |
| /skills, /mcp | List loaded skills · MCP servers |
| /theme, /rename | Pick from 20+ built-in themes (arrows preview live) · rename the session |
/reload and /update can replace the terminal while its detached session
runtime keeps working. The new terminal reattaches to the same saved conversation,
including streamed output and unanswered approval or ask prompts. The runtime
adopts installed code only when all work is safely idle: active turns, tools,
compaction, gates, loops, child agents, background jobs, and imminent wakes defer
that refresh. Reloading an unchanged build does not restart the runtime. Local
in-process work and terminal-owned ! shell commands must finish first. A failed
update leaves the current terminal and runtime running.
Keys worth knowing
$: run a named skill on the rest of the line
$research the payments rewrite); $ alone opens the picker.
- Type while the agent works: your message is delivered at the next
esc— stop the agent without ending the session.ctrl+bor/sidebar— show or hide active and recent conversations in the
cmd+b is also accepted when the terminal forwards the Super
modifier. /settings → Session sidebar and Sidebar position control
visibility and left/right placement; the defaults are hidden and left.
f9 or /sidebar focus opens and focuses the list without changing your
draft. Arrow keys choose a row, Enter opens it, and Escape returns to the
previous input surface. F9 also returns focus without hiding a pinned list.
ctrl+shift+↑ / ctrl+shift+↓ switch straight to the previous/next
conversation in the list's order without opening it, wrapping at the ends;
the caret and your unsent draft stay where they were.
On narrow terminals, selecting a conversation dismisses the overlay drawer.
f8— open an aside (side question) without losing what you were typing;
ctrl+f promotes the aside into the conversation.
shift+tab: cycle reasoning effort.ctrl+l: clear the transcript (history is untouched).ctrl+t/ctrl+g: expand the todo list · cycle the subagent panel.- Hand over a secret:
/credentialfollowed by a space opens a masked
Cmd+V on macOS) is captured the same way. The
composer's own paste key (Ctrl+V on macOS) never consults the capture: it
reads the clipboard itself, so it inserts the value as ordinary text.
option+←/option+→(ctrl+←/ctrl+→on Linux and Windows): move the
shift to select by word. Works
the same in shell (!) mode and with a command list open, and option+↑ /
option+↓ behave as plain ↑ / ↓. On macOS this works whichever
option-key mode your terminal is set to. The default, "Use Option as Meta",
and "Esc+" all behave the same, so there is nothing to configure.
🔌 Providers
Every provider below runs on the same harness and the same model picker.
OAuth providers sign in through the browser and use your existing
subscription; API-key providers prompt once and store the key locally. Local
servers can be configured in the app with /login, including endpoints and
optional masked API tokens. See
Local and self-hosted providers for setup,
metadata overrides, desktop-app support, and server-specific limitations.
| Provider | Access |
| --- | --- |
| OpenAI / ChatGPT | openai / openai-device, or OPENAI_API_KEY |
| Anthropic / Claude | anthropic, or ANTHROPIC_API_KEY |
| Kimi (Moonshot) | kimi, or KIMI_API_KEY |
| xAI / Grok | xai-oauth, or xai / XAI_API_KEY |
| Z.AI (GLM) | zai-oauth, or zai / ZAI_API_KEY |
| Qwen (Alibaba) | alibaba-token-plan-oauth, or API key |
| Google Gemini | GOOGLE_AI_STUDIO_API_KEY |
| DeepSeek | DEEPSEEK_API_KEY |
| Mistral | MISTRAL_API_KEY |
| OpenRouter | OPENROUTER_API_KEY: one key, many models |
| Radient | RADIENT_API_KEY: automatic per-step model selection |
| LM Studio, Ollama, vLLM, llama.cpp | User-operated server; optional token |
| OpenAI-compatible | Explicit server URL; optional token; MLX/LocalAI/proxy escape hatch |
lop login # list login-capable providers
lop login openai # OAuth flow; for OpenAI/Anthropic/Z.AI/Qwen, repeat to add a second account
lop login-status # what's signed in
lop logout kimi
Legacy --hosting flags keep working, and API keys can
be stored with lop credential update (a masked prompt); the
lop secret store, and the /credential hand-over that keeps a secret out of
the prompt text, are covered in
[Credential
... (README truncated for length)