lsh: LogiShell without a window
One static binary, two names on a machine: lsh for every day, logishell
where the long name reads better (scripts, npx).
lsh # a conversation in this directory
lsh "why is the api test failing" # the same thing, as one question
lsh scan . # a verb, if you know it
The first word that is not a verb is taken as the whole question. A word that
looks like a verb (two edits away, scna for example) gets a question back,
not a paid turn to the model.
Bare lsh opens a conversation only in a terminal. In a pipe (echo x | lsh,
a script, CI) it prints help and exits with code 1, the way it always did: no
one's script should one day hang in an interactive loop.
Install
curl -fsSL https://logishell.com/lsh.sh | sh
Or without installing anything: npx logishell scan .
Everything it answers
The table below is not written by hand. It is the answer of
lsh commands --format json, which is the same registry that builds the help
text and the shell completion. A verb without a line in that registry does not
exist for any of the three.
<!-- cli-doc:start -->
| verb | what it does |
|---|---|
lsh onboard | from a bare terminal to a working LogiShell, safe to run again |
lsh login | sign this machine in with a short code shown right here |
lsh whoami | which account this machine is signed in as, and under what name |
lsh logout | revoke this machine's token and forget it here |
lsh scan <path> | read a repository as a map of blocks instead of reading the code |
lsh project-map <path> | how much of this repository there is, and who already knows what about it |
lsh blocks | blocks as the unit of work: verify yours, see what is proven, run one by name |
lsh mcp | what an agent in this shell can see of LogiShell |
lsh claude | what this machine has to do with Claude: the LogiShell mod inside Claude Code, and the subscriptions it holds |
lsh browser | the Playwright tools an agent knows, pointed at this machine's browser |
lsh navigator | draft the marks of a website for the LOG Navigator: headings, navigation, buttons and forms |
lsh code | an agent in this terminal (the same thing bare lsh opens) |
lsh game <path> | put a built game on the LogiShell Gaming shelf |
lsh slate | rebuild the Slate page index from the working copy |
lsh qa | play your own product's scenarios in the pool's browser |
lsh product | what to pick up today: what is promised, built, shipped and actually proven |
lsh env | is this machine ready for a role from .logishell/env.yaml, and make it ready |
lsh icons | the project's icons: SVG frames that compile into one self-animating SVG |
lsh remote | how the road to another machine of yours feels: key echo, reconnects, drops |
lsh machine | any machine of yours: its privacy zones, its name, sleep and roles |
lsh run | give one piece of work to another machine of yours, and let it survive the machine going away |
lsh models <model> | local models on this machine: what is here and alive, install one, run it, remove it |
lsh project | your projects across your machines, and moving one to another machine |
lsh on | work on another machine of yours, from this terminal |
lsh forward | a port of another machine of yours, open on this one |
lsh disk <path> | what build directories hold and which of them can go |
lsh desk | virtual desks on this machine: a sandbox with a screen you open in LogiShell |
lsh unpushed <path> | work on this machine that is not on any remote yet |
lsh lane | where each task stands from card to prod, and why it is stuck |
lsh spend | what the work cost on this machine, today and over 30 days |
lsh night | the night shift of this machine, and the tap that stops it |
lsh context <path> | ask about a symbol instead of reading the files around it |
lsh rlm | what a turn in this tree is made of: prompts, orders, retrieval, the recursion itself |
lsh sessions | what became of the work in each agent session on this machine |
lsh terms | what is happening in the terminals of this machine, and where you are needed |
lsh runs | long runs on this machine: steps, where each one is, ETA and result |
lsh why <path> | why this code is the way it is, with the alternative that was rejected |
lsh tasks <sync> | bring the task board into the task files of this working copy, and back |
lsh contracts <args> | the contracts tool: list drafts, scan, verify, export |
lsh confirm <name> | freeze a draft contract as the reference; only a person does this |
lsh lanes | which roads to a model are open on this machine right now |
lsh savers | what saved context tokens on this machine, with a measured number for each |
lsh tokens | where the tokens of this machine went, and what they would have cost |
lsh learn | five things to try, on this repository |
lsh completion | the Tab-completion script for your shell |
lsh commands | this surface itself, for a person or (with --format json) for an agent |
45 verbs.
Flags of the bare conversation
-p: one turn, answer to stdout, no conversation--allow(edit, run): in -p, permit a class of effect: edit, run--continue: carry on the last conversation of this working copy--resume: pick an earlier conversation of this working copy--model: what to think with, as <provider>/<model>--dir: work in that repository instead of this one--base-url: server for local/ and compatible/ models--format(text, json): in -p, text (default) or json--no-mcp: do not borrow tools from the MCP servers in .mcp.json--plain: the conversation as a stream of lines, without the chat screen--mcp: in -p, also borrow tools from the MCP servers in .mcp.json--estimate: in -p, print what the turn would cost and send nothing--without-tools: leave out every tool whose name begins with this prefix, e.g. context_
Inside a conversation
/help: these commands, the model, the door, what is allowed/model: print the lanes open today, or switch to one/new: start a fresh conversation in this repository/compact: fold the history into a summary now/cost: what this conversation has spent/status: model, cache, map, MCP servers and the savers of this project, at length/savers: what saved context tokens here and on this machine, with a number each/plan: plan a task on the planner model, read-only; the estimate first, then y/verify: check the working tree's diff against the plan on the planner model/tools: what this agent can do right now, and what asks first/map: this repository as a map of packages and doors/why: why a path is the way it is, and what was rejected/resume: pick an earlier conversation of this working copy/version: walk to another version of a message, by its turn id/exit: leave
lsh onboard
from a bare terminal to a working LogiShell, safe to run again
lsh onboard: from this terminal into a working LogiShell: find or start the engine, register this directory as a workspace, open the surface; safe to run again
lsh login
sign this machine in with a short code shown right here
lsh login: sign this machine in: a short code, a link and a QR appear here, you confirm them anywhere you are already signed in, and this machine gets its own token (~/.logishell/session.token, revocable in Device Center). --name calls the machine something other than its hostname
Flags:
--name: what to call this machine in LogiShell--no-color: draw the QR without colour
lsh whoami
which account this machine is signed in as, and under what name
lsh whoami: which account this machine is signed in as, and the name it carries in your Device Center
lsh logout
revoke this machine's token and forget it here
lsh logout: revoke this machine's token in LogiShell and delete it from this computer; the revoke happens first, because a forgotten live token is still a key
lsh scan
read a repository as a map of blocks instead of reading the code
lsh scan <path>: read a repository as a map of blocks — packages, files, and (with --depth sym) what each symbol calls; --format json for a machine, --help for the ceilings
Flags:
--format(md, json, text): md (default), json or text--depth(file, sym): file (default) or sym--group: name the subsystems, using your own key
lsh project-map
how much of this repository there is, and who already knows what about it
lsh project-map [path]: an inventory of this repository: code by language and by directory (files and lines), how many of its parts a person has named and how many are only derived, and which of the layers that answer those questions have never been built here — each missing one named together with the command that builds it. It walks nothing of its own, and what the repository itself ignores is not counted; --format json for a machine
Flags:
--format(text, json): text (default) or json--fresh: re-walk the context index first, without a language server--drift: also say what moved since the feature map was written
lsh blocks
blocks as the unit of work: verify yours, see what is proven, run one by name
lsh blocks verify <file>: hand in a {definition, source} draft (YAML or JSON): its own tests run in the node sandbox and the block reaches the shelf only with every test green; red tests are printed with their reason, nothing is writtenlsh blocks shelf [query...]: what is proven in this working copy: name, ports, receipt, how often reusedlsh blocks run <id@version>: run a verified shelf block by name and print its outputs; --in '{"port": value}', plain values only, no files, no networklsh blocks drafts: what here could already be a block: exported Go functions and package.json scripts with typed ports, side proven or admitted unknownlsh blocks run <f.go#Fn>: run a Go function proven pure and print its outputs; --in '{"port": value}', plain values only
lsh mcp
what an agent in this shell can see of LogiShell
lsh mcp: what an agent in this shell can see of LogiShell;lsh mcp installadds the server to this projectlsh mcp serve: the local door for this working copy, over stdio — an agent starts it, you do not. The listing is medium: the tools an agent uses in code (map, context, the room, decisions, proofs, docs) plus find_tools and call_tool, which reach the rest by name. --lean cuts it to the room and the journal; --full lists all of them again, at about nine thousand tokens in the prefix of every turn
Flags:
--full: serve: list every tool's schema instead of the medium listing--lean: serve: the leanest listing (the room, the journal, find_tools)
lsh claude
what this machine has to do with Claude: the LogiShell mod inside Claude Code, and the subscriptions it holds
lsh claude: is the LogiShell mod installed here, which Claude Code this machine has, and the one next step. The mod draws your context, your cost and the part of the repository you are working in above the prompt, and leaves one record of each session in this machine's journallsh claude mode install: put the mod in place, or update the one already there; by hand this is four steps, each with its own way of silently not working. Claude Code older than 2.1.287 cannot load mods at all: that is said out loud with the command that updates it, and nothing is touchedlsh claude mode remove: take the mod off this machine; open sessions keep it until /reload-pluginslsh claude brief: what a session is told about where it runs: the project, the branch, and which LogiShell doors to use before plain file reads. --hook reads Claude Code's SessionStart payload and answers in the hook's shape; the plugin calls it, you do not. It never fails: a machine without a runner gets a brief that says solsh claude inbox: what other agent sessions of this repository said since this one last looked. --hook answers in the shape of Claude Code's UserPromptSubmit hook, which is how a message reaches a session without the session polling for it; the plugin calls it, you do not. Silent when there is nothing newlsh claude screen: the PreToolUse hook in front of computer-use: --hook tells the runner which agent is at the screen and what it last said, so the island shows it as LOG at the screen; while the person pressed "leave the screen alone" on the island it answers exit code 2 and the action does not happen. The plugin calls it, you do not. A runner that does not answer never blocks the agentlsh claude statusline: the status line command of a Claude tab LogiShell opens: Claude Code hands it the subscription limits it already knows (five hours and week, used and reset), the tap keeps them for AI left and then prints your own status line unchanged. LogiShell never reads the subscription token. Claude Code calls it, you do not; --probe says whether this lsh knows itlsh claude gate: is the tool gate hook installed in this project, and in which mode it runs. The gate judges the serious tool calls of an agent tab (a write outside the repository, a command, a message sent out, a deploy, a secret) and leaves reads, searches and edits inside the repository alone. While LOGISHELL_DECIDE is off it does nothing; in shadow it writes what it would have done to the decision ledger and stops nothinglsh claude gate install: write the PreToolUse hook into .claude/settings.local.json of this project: your own settings, not committed. --shared writes the committed .claude/settings.json instead, for a team that decided so together. Other hooks in the file are kept as they arelsh claude gate remove: take the hook out of both settings files of this project
Flags:
--shared: in gate install: write the committed settings file, so the whole team gets the hook--format(text, json): text (default) or json--to: in push: which machine of yours receives the subscription
lsh browser
the Playwright tools an agent knows, pointed at this machine's browser
lsh browser mcp: the Playwright tools an agent knows, pointed at this machine's browser: no window ever pops up over your work; put it in .mcp.json instead of the plugin's barenpx @playwright/mcp
lsh navigator
draft the marks of a website for the LOG Navigator: headings, navigation, buttons and forms
lsh navigator crawl <url>: fetch a page (and, with --pages N, the same-origin pages its navigation links to) and write a draft marks.yaml: every heading becomes a section, every navigation link a place, every button something to click, every form something to fill; elements that already carry data-lsh-mark keep their id. Edit what, when and can, then drop log-navigator.js on the page (docs/NAVIGATOR.md)
Flags:
--out: where to write the draft; default marks.yaml, - for stdout--pages: how many same-origin pages to follow; default 1
lsh code
an agent in this terminal (the same thing bare lsh opens)
lsh code: an agent in this terminal: it reads the repository, proposes edits and commands, and never writes or runs anything without your y/n; --model picks the provider (anthropic/, openai/, xai/, deepseek/, openrouter/ through the facade; local/ or ollama/ on this machine; compatible/ for your own server). Barelshopens the same thing.
lsh game
put a built game on the LogiShell Gaming shelf
lsh game publish <dir>: put a built game on the LogiShell Gaming shelf — people play it in the browser, nothing to install
lsh slate
rebuild the Slate page index from the working copy
lsh slate reindex: rebuild the Slate page index from the working copy: the files are the truth, the database only their index — this is the run that proves it
lsh qa
play your own product's scenarios in the pool's browser
lsh qa run: test YOUR product inside LogiShell: scenarios from your repository are played by the runner in the pool's browser and the run is visible as a tab; no Playwright on your machinelsh qa prove --scenario <text>: prove ONE path works: replay the scenario with a frame after every step, a filmstrip and a replay page in .logishell/qa/proofs/<id>/; attach it to a card or a hand-in with the local door's qa_attachlsh qa attach <proofId> card:<KEY>: attach a proof to the task it closes: the frames go to the cloud named and with thumbnails, and the card shows them as an evidence strip you can search and open on any device; also feedback:<id> and worklsh qa shot (--session <id> | --file <image>) --label <text>: one frame of a check into a proof instead of /tmp or the Desktop: the file is moved into .logishell/qa/proofs/<id>/steps/, --proof latest keeps adding to the current check, --show puts it in front of the human in LogiShell
lsh product
what to pick up today: what is promised, built, shipped and actually proven
lsh product: four queues instead of a catalogue: promised and not built, built and not shipped, shipped and not proven, proven and gone stale; the stage of a feature is computed from its code and its runs, never writtenlsh product check: go red when the registry stops matching the tree: a path that resolves to nothing, a card with no way to prove it, a confirmation the code has moved out from underlsh product confirm <id>: sign off that the acceptance criteria were walked again; needs a live terminal, because this is the one step in the registry a person does rather than a computation
Flags:
list: every feature with its computed stageshow: one card: why, code, proof, confirmationreport: markdown for docs/PRODUCT_STATE.md
lsh env
is this machine ready for a role from .logishell/env.yaml, and make it ready
lsh env roles: the roles the project declares (dev, ci, desktop-builder, sandbox, window, tiny), the job classes each may take and the tools it needslsh env check --role <role>: what this machine misses for the role, each gap with its fix; versions come from the files env.yaml pins (.nvmrc, go.mod, packageManager). Exit 1 while anything is missinglsh env apply --role <role>: install what is missing: node, pnpm, go and doppler through mise, system packages through apt or brew when this user may, Chromium's libraries through Playwright. One receipt line per install in ~/.lsh/env-receipts.jsonl. Docker and secrets are never touched: the doppler CLI comes without a login
Flags:
--role: which role from .logishell/env.yaml--json: the answer for a program--dry-run: apply: print the plan, install nothing--root: the repository (default: search up from here)--receipts: apply: where the receipts go
lsh icons
the project's icons: SVG frames that compile into one self-animating SVG
lsh icons [list]: every icon in .logishell/icons with its frames, cycle length and whether the compiled file matches its frameslsh icons show <id>: one icon: its icon.json and where the compiled SVG lieslsh icons add <file.svg> --id <id> --name <name>: one drawing becomes a static icon; a drawing with a script, an event handler or a link outside itself is refused by namelsh icons import-sheet <sheet.svg> --id <id> --name <name>: a storyboard (a grid of drawings on one page) is cut into frames in reading order and compiled into an animation; the sheet is kept as source.svglsh icons build [--check]: recompile every icon; --check writes nothing and fails when a compiled file was edited by hand or its frames changed
Flags:
--force: replace an existing icon; its leftover frames are removed--box: import-sheet: the box each cell was drawn in (512)--hold: import-sheet: ms each frame stays (400)--fade: import-sheet: fade length in ms; 0 cuts--once: import-sheet: play once and stop on the last frame--pick: import-sheet: cells to keep, 1-based, comma separated--poster: import-sheet: frame shown with reduced motion--check: build: write nothing, fail on a stale icon
lsh remote
how the road to another machine of yours feels: key echo, reconnects, drops
lsh remote bench --machine <machine>: measure the road a keystroke takes to ANOTHER machine of yours (this computer, the cloud, that machine's runner and back) and print four numbers: key echo p50/p95, the time from a drop to Connecting, from a drop to a live channel again, and drops per hour. It changes nothing and opens no shell: probes go through their own door.--forhow long to watch (default 60s),--cutshow many deliberate reconnects to time,--fromnames where it runs from; the JSON lands in .logishell/qa/remote-bench
lsh machine
any machine of yours: its privacy zones, its name, sleep and roles
lsh machine profile work: mark this machine as a work machine: your journal, memory and recall stay off it and guests never run here;personalundoes itlsh machine zone work <folder>: give one folder its own zone (personal, work or client:<name>); the stricter of machine and folder wins, so an employer's repository stays closed even on a personal machinelsh machine update <machine>: tell ANOTHER machine of yours to fetch the published LogiShell version, check its checksum and replace its own binary. It keeps its open shells through that: it replaces its image, it does not restart.--allwalks every machine and reports each one, because half a fleet is asleep at any moment;--to <version>pins a version instead of the one the cloud publishes, and--channel betaasks a channel other than stable what it publishes. A desktop refuses on purpose: there the app updates its runnerlsh machine setup <machine>: set up ANY machine of yours without going to it:--namewhat it is called,--profile personal|work,--stay-awake on|off(the same LaunchAgent, systemd-inhibit or scheduled task the installer sets),--builds on|off(it accepts desktop builds),--ci on|off(it runs the CI runner already installed there),--lights on|offand--service on|off(the system keeps the runner without the app window: a launch agent or a user unit, no sudo, and the runner working now is left alone). With no flags it prints what the machine is set to, and every line says what that system actually supports. Only the person who paired the machine reaches itlsh machine lights <machine> off: switch the case and keyboard lighting of another machine of yours,on,offorstatus. On Windows and Linux this presses OpenRGB; switching it off also leaves a logon task that repeats it, because the board brings the lighting back after a restart.statusanswers with the last thing LogiShell applied and says so: the lighting cannot be read back without leaving a server port open on the machinelsh machine clean <machine>: give back the space that build work left on ANOTHER machine of yours: the same categorieslsh diskknows (node_modules, target, .next, .turbo), folded into one list with a total. The machine counts and removes it itself, writes the same recordlsh disk restorereads, and nothing is removed until the list has been shown;--dry-runstops at the listlsh machine ps <machine>: the LogiShell processes on another machine of yours (runner, agent sessions, browser pool, lsh-embed) with what each holds, plus the ceilings that machine runs under. Nothing of a stranger's is listed: the whole machine lives in Computeslsh machine health: the instrument of this machine: load against the number of cores, memory, space WHERE THE DATA LIVES and how long it has been up. A node whose root is filled by the volume image says so instead of passing for "disk almost full"; what the provider promised is printed beside what was measured. A machine that can say it adds its power: mains or battery, the charge, battery cycles and wear, whether heat is holding the processor back, and when it will fall asleep. --fleet asks every machine of this owner, and a machine that says nothing is named, not skippedlsh machine models: what this machine is made of, how many gigabytes of weights it can carry and which local models it should run;--load maxasks the same of a machine given over to the work,--jsonfor a scriptlsh machine status: what this machine tells the cloud about ITSELF: its fingerprint and whether the credentials in ~/.logishell/node.json were refused as belonging to another machine. A copied node.json used to knock the real machine offline every thirty seconds in silence; now the refusal is said out loud, here and in the runner loglsh machine mode linked: what a work zone may send to your cloud:strictnumbers only,linkedalso names of tasks and notes; code and recordings never leavelsh machine queue <machine>: what that machine has not finished: work waiting for it, work running on it, and work it LOST by going quiet in the middle. Lost is not failed: the machine stopped answering, the work itself may be fine.--retry <work> --to <machine>puts that piece on another machine of yours as a new line in its queue, and leaves the old one as history
Flags:
--retry: queue that piece of work again--to: ...on another machine of yours
lsh run
give one piece of work to another machine of yours, and let it survive the machine going away
lsh run --on <machine> -- <command>: one command on that machine. It goes through your hub, so a machine that is on gets it at once, a sleeping one is woken for it, and a machine that is away keeps it queued and runs it when it is back. The answer is the id of the work, not its output: it runs for minutes and the relay is one frame per request.lsh machine queue <machine>says where it got to. Everything after--belongs to the command, flags and alllsh run --on <machine> --agent claude -- "<task>": start an agent there instead of a shell and hand it the text as its first message. The kind is remembered, so the queue saysagentand notshell: that is how a person finds this piece again among twentylsh run --on <machine> --in <project> --kind build -- <command>: name the folder on THAT machine when it has several open; a machine with one open project needs no--in, and one with several lists them rather than guesses.--kind buildonly changes what the queue calls it, and that is the point: a build hidden among shells is not found exactly when it is looked for
Flags:
--on: which machine, by name or id--in: the folder on that machine--kind: shell (default), build or agent--agent: run an agent there and hand it the text--note: what to call this work in the queue
lsh models
local models on this machine: what is here and alive, install one, run it, remove it
lsh models: every local model this machine holds or could hold, with its state (absent, downloading N%, installed, running at an address, failed with the reason), the three engines, the Ollama next door, the compute slot and the link to your hub;--watchkeeps it live,--jsonfor a script. The same answer the IDE shows in the Resource Center, read from the same doorlsh models install <id>: download a model into ~/.lsh/models and, if its engine is not on this machine, the engine too, saying first what will be downloaded and from where. Progress in bytes and percent, resumes after a dropped connection, verifies the sha256 and writes a manifest. <id> is a catalog id (whisper-tiny, e5-small, qwen2.5-0.5b) or owner/repo:file from Hugging Face, the same key the model store hands to logishell://store/add;--kind llm|speech|embedwhen the file name does not say,--yesto skip the questionlsh models run <id>: start the engine for an installed model (llama-server for a GGUF language model, lsh-voice for speech, lsh-embed for embeddings) and print where it answers, or the engine's own last words when it did not start. One engine per kind: running a second language model replaces the firstlsh models stop [id]: stop one engine, or every engine when no id is givenlsh models remove <id>: stop it if it runs and delete its files; a file from an older install is named, not deleted
Flags:
--json: machine-readable answer--watch: list: redraw every two seconds--yes: install: do not ask before downloading--kind(llm, speech, embed): install: what a hub file is for
lsh project
your projects across your machines, and moving one to another machine
lsh project: every project open on every machine of yours, with its branch and whether it has uncommitted work. A machine that said nothing is named under the table, because a list that hides it reads as complete when it is notlsh project put <machine> <git-url>: clone it there (--as <name> for another folder name, --ref <branch> for another branch), or--empty <name>to start an empty one. A machine with no git access of its own says so and names the cure: the credential stays on that machine and never travels through uslsh project move <project> --to <machine>: move the project AND its Claude/Codex conversations to another machine: git history, uncommitted work and drafts travel in verified 1 MiB pieces. Running processes do not travel, nothing can move those. The copy stays on the source, so coming back costs nothing; --from <machine> when the same name lives in two places. A destination where nobody signed into that agent is refused BEFORE the first byte leaves
Flags:
--to: which machine the project moves to--from: which machine it moves from, when the name is ambiguous--as: folder name on the destination--ref: branch to clone--empty: start an empty project instead of cloning
lsh on
work on another machine of yours, from this terminal
lsh on: your machines and whether a session can start on each right now: a sleeping one says so, one waiting for approval says that insteadlsh on <machine>: a shell on that machine, in the folder it has open; several folders are listed rather than guessed (--in names one), and a machine with no folder open gives its own terminal, whose program is that machine's setting and not our choice. The PTY is real: bytes both ways and the window size travels, so claude and vim work as they do locallylsh on <machine> claude: start that program there instead of a shell: shell, claude, codex, gemini, grok, opencode. The list is closed because the name travels into argv on the other machine; an arbitrary command goes to --runlsh on <machine> --default: remember that machine as where work goes by default, and forget it withon none --default. The choice lives in your hub, not in this terminal, so the window, the phone and the watch all follow it; a machine that is asleep is still a legitimate choice and the answer says it is asleeplsh on <machine> --run "<command>": one command in that machine's folder. The answer arrives WHOLE when it finishes, not as a stream: the relay is one frame per request with an 8 MiB ceiling. Long work belongs in a session, not here
Flags:
--in: which folder on that machine the session opens in--run: one command there instead of a session; the answer comes whole--default: remember that machine as where work goes by default
lsh forward
a port of another machine of yours, open on this one
lsh forward: your machines: name, system, whether a request reaches them right now and whether they are approved; the list a port has to be picked fromlsh forward <machine>: what that machine is listening on locally: port, process, pid and the command behind it, as the machine itself reports them; a machine that could not collect the list says why instead of showing an empty onelsh forward <machine> <port>: open that port on 127.0.0.1 here and keep it open until Ctrl+C: every connection gets its own websocket through the control plane and lands on 127.0.0.1:<port> over there. Bytes, not requests, so an HMR socket and absolute asset paths survive where a path-prefix proxy breaks them; --local <port> when the same number is already taken here. The machine is named by id or by part of its name, case ignored, and two matches are refused with the list rather than picked for you
Flags:
--local: listen on this number here instead of the machine's own
lsh disk
what build directories hold and which of them can go
lsh disk <folder>: what build directories (node_modules, target, .next, .turbo) hold in the folders you name and which can go; --ollama adds the models a pull can return byte for byte;lsh disk clean --applyremoves only what is provably disposable and idle,lsh disk restorebrings it back
lsh desk
virtual desks on this machine: a sandbox with a screen you open in LogiShell
lsh desk new [name]: start a desk: a container with a display, a window manager, a terminal and a browser, shown in LogiShell over the same WebRTC as a real screen. --image runs your own image built FROM the desk image, --size 1920x1080 sets the screen. Each desk has its own container and network, capped CPU and memory, no docker socket and none of the machine's secrets; a machine allows two sandboxes by default (LOGISHELL_DESK_MAX). The desk named main is the screen of a machine that has nonelsh desk ls: the desks of this machine and their statelsh desk rm <name>: remove a desk without a trace: container, files, screenlsh desk open <name>: print the link that opens the desk's screen in LogiShelllsh desk control on|off|status: let your devices click and type on this machine's desks and screen over the video (writes ~/.logishell/screen-input, the same flag as the app's switch); each control session is still approved in LogiShell and written to this machine's journal, and off ends live sessions within a second
Flags:
--image: run this image instead of the built-in desk--size: screen size, WIDTHxHEIGHT
lsh unpushed
work on this machine that is not on any remote yet
lsh unpushed [folder...]: every working copy the runner knows (and the folders you name) with commits or files that are not on the remote, oldest first: yellow after an hour, red after three, and whether the runner could save it to a wip/<branch> on the remote. Run it before reinstalling or wiping a machine; it exits 1 while such work exists. --push saves every copy to its wip/ branch now without touching the branch, index or files; --json prints the report
Flags:
--push: save every unpushed copy to its wip/ branch now--json: print the report as JSON
lsh lane
where each task stands from card to prod, and why it is stuck
lsh lane [KEY]: one row per task: the stage it stands on (PLAN, READY, RUN, CI, LIVE, PROVEN) with minutes and, for a red, stale or waiting stage, one reason line: the failed job and the first error line of its log, the missing tool, or who it waits for. Branches that name no card are listed apart. Reads the board, the delivery feed and this working copy's git; asks no model and answers within two seconds, naming any source it could not read; --json prints the same report as a document
Flags:
--json: the report as JSON--dir: which working copy; default the git top level here--board: which board; default board:tasks-lsh
lsh spend
what the work cost on this machine, today and over 30 days
lsh spend: one table per window (today, 30 days): electricity as a class estimate scaled by load average, tokens per provider from the usage journal at list price, subscriptions and servers from your tariff file; every row says whether it is measured, a tariff or an estimate, and currencies are never added together. Without a tariff the kWh are shown and the money is not invented; --json prints the same report as a documentlsh spend tariff: what the tariff file holds;--kwh 0.30 --currency EURsets the electricity price,--initwrites an example file once. This is the only thing the verb ever writes
Flags:
--json: the report as JSON
lsh night
the night shift of this machine, and the tap that stops it
lsh night status: the night shift of this machine: shifts, the latest brief, live workers, the stop tap;lsh night seed "<text>"queues a line for tonight,pause/resumeis the stop tap,sleepstarts the shift now,brief [date]prints a night in full
lsh context
ask about a symbol instead of reading the files around it
lsh context find <name>: where a name lives in this repository: file, line and kind for every symbol that answers to it; two symbols with one name come back as two, and the answer says it is ambiguous instead of choosinglsh context outline [path]: the shape of a package or a file: declarations with signatures and no bodies, a fraction of the cost of reading it; no path names the packages of the whole repositorylsh context refs <symbol>: who calls this symbol (--direction callees for what it calls); the question to ask before changing anything, because callers are what a change breakslsh context read <symbol>: the body of one symbol, by the id find printed (sym:path/file.go#Name) or by its bare namelsh context pack "<task>": one answer for a whole task: the shape of the files it touches, the symbols ranked by how they are reached, and the decisions recorded against those paths, so the code arrives with the why beside itlsh context install --hook: print the SessionStart hook for .claude/settings.json (it runslsh context pack --format jsononce a session) and offer to write it; the file belongs to you, so it prints first, asks second and writes only after y, and a settings.json with a SessionStart of its own is left alone
Flags:
--format(text, json): text (default) or json--size(small, medium, large): in outline and pack: budget of the answer, small, medium (default), large--direction(callers, callees): in refs: callers (default) or callees--kind: in find: func, method, struct, class, interface, const, var, enum--limit: in find: how many hits at most--no-wait: do not wait afterwards for the index to finish being written--hook: in install: the SessionStart hook, shown first and written only after y
lsh rlm
what a turn in this tree is made of: prompts, orders, retrieval, the recursion itself
lsh rlm: what a turn in this tree is made of, in one page: the prompts a model is instructed with, the orders that say what counts as done, the retrieval an answer is built from, and where the RLM recursion itself lives, with what to type to open each one, and what is honestly missinglsh rlm <shelf>: one shelf only: prompts, specs, rag or recursion; the paths with their counts and how to open each, for when the question is just "where are the prompts"lsh rlm ask "<question>": ask the RLM loop itself: the runner splits a large question into narrow subquestions, answers each from the retrieval index and folds the summaries back up, then says how it searched, how many branches it spent and why it stopped; --tree also prints the subquestions
Flags:
--format(text, json): text (default) or json--path: the working copy to look at (default: this one)--tree: in ask: also print the tree of subquestions--depth: in ask: how deep the tree may go--branches: in ask: how many subquestions in total--budget: in ask: token budget of the whole walk--per-branch: in ask: chunks per subquestion
lsh sessions
what became of the work in each agent session on this machine
lsh sessions: what became of the work in each agent session: whose request is still unanswered, who was cut off mid-action, who finished; --unfinished for only the first two, --format json for a machine. Reads the recordings and the conversations from disk, so it answers even when the runner is the thing that died. Under a session,effects:counts the turns that changed the world outside the working copy (a push, a deploy, a write to someone's API) and the ones that ran a command whose effect its text does not showlsh sessions --effects <sid|conversation>: those turns of one session as a list: turn number, time, kind (push, deploy, publish, remote-write, message, machine, database) and the command with secrets masked;unknownis a script or a program whose effect cannot be read from the command, never a promise that nothing happened. Going back to an earlier turn of the conversation does not undo what is listed after itlsh sessions restore <id>: put a Claude Code or Codex conversation back from the backup machine of ~/.logishell/guard.json (or from ~/lsh-backup/transcripts on that machine itself) whereclaude --resume <id>orcodex resume <id>finds it; the start of the id is enough. --cwd names the folder to continue in when the original path does not exist here, and the conversation's cwd is rewritten to it. Never overwrites a different version of the same conversationlsh sessions mirror: send the new lines of every agent conversation to the backup machine now instead of waiting for the runner's next guard pass (every 15 minutes); the copy there has secrets masked and an index by session id, folder, branch and task. --all keeps going until nothing is left
Flags:
--effects: the turns of one session that changed the world outside the working copy--unfinished: only the sessions that did not finish--format(text, json): text (default) or json--limit: how many sessions at most (20 by default)--scope: only this workspace
lsh terms
what is happening in the terminals of this machine, and where you are needed
lsh terms: every live session of this machine in one list, the ones that STOPPED and wait for a keypress first, then the ones printing right now, then the quiet ones: what runs there, where, for how long, and one line about what it is doing. The state is counted by the runner, not guessed by a model; --waiting for only the ones holding your work, --closed to add the recently ended with the reason they endedlsh terms tail <sid>: what is on the screen in one session: the last lines, with the escape sequences, redraws and spinners taken out and values that look like secrets replaced by a word saying one was there. Read-only, and the output of a work zone does not leave the machinelsh terms watch: follow them and say only what CHANGED: a session started waiting for you, went back to work, went quiet or is gone. Leave it running beside the work (--every 10s, --for 30m); --format json prints one event per line for a program
Flags:
--waiting: only the sessions where the work is standing still--closed: add the recently ended sessions and why they ended--scope: only this workspace--lines: tail: how many lines (40 by default)--limit: how many closed sessions at most (10 by default)--every: watch: how often to look (10s by default)--for: watch: stop after this long (runs until interrupted by default)--format(text, json): text (default) or json
lsh runs
long runs on this machine: steps, where each one is, ETA and result
lsh runs: the latest long runs, newest first, one line each: a chain of steps (a build, CI, a print, a wait) that lives in a file and survives a runner restart; --active for only the ones still going or waiting for youlsh runs status <id>: one run: its steps, where it is now, how long is left and when it ends, the reason of a red step; --wait follows it until it endslsh runs start <spec.json>: start a run from the spec POST /companion/runs takes (- reads stdin); a step with a gate waits for you in LOG and is approved there
Flags:
--active: only the runs still going or waiting for you--wait: status: follow the run until it ends--limit: how many runs to list (10 by default)--json: print the runner answer as JSON
lsh why
why this code is the way it is, with the alternative that was rejected
lsh why for <path>: why this code is the way it is: decisions recorded against it, each with the alternative that was rejected;lsh why promote <id>moves one from this machine's journal into the repository
lsh tasks
bring the task board into the task files of this working copy, and back
lsh tasks sync [--pull] [--dry] [--json]: one pass of the task mirror, the same as the runner door: cards made on the board land as files, edits on either side follow, a card changed on both is named, not overwritten; --pull only brings the board in and never writes it
lsh contracts
the contracts tool: list drafts, scan, verify, export
lsh contracts [args]: runs the contracts tool (mvp.logishell.com/lsh.mjs) under node with the arguments unchanged; LSH_CONTRACTS_CLI names a local copy, otherwise the first use downloads it into ~/.lsh/contracts
lsh confirm
freeze a draft contract as the reference; only a person does this
lsh confirm <name> [name ...]: short forlsh contracts confirm: the drafts an agent wrote become confirmed contracts that lsh_verify checks every change against
lsh lanes
which roads to a model are open on this machine right now
lsh lanes: not the list of providers this binary can spell, but the ones that will actually work here: which have a key or a token, whether a model is running on this machine, and what is missing from the rest. Nothing is spent to find out; --format json for a script deciding where to send work
Flags:
--format(text, json): text (default) or json
lsh savers
what saved context tokens on this machine, with a measured number for each
lsh savers: the context savers (prompt cache, repository map, conversation fold, local lane, MCP doors) and what each one measured over the window: tokens spent against tokens that would have gone to the provider without it, a tilde on every estimate, exact and estimated never added together; --window 24h for today, --format json for a program
Flags:
--format(text, json): text (default) or json--window(7d, 24h): 7d (default) or 24h
lsh tokens
where the tokens of this machine went, and what they would have cost
lsh tokens: the last 7 days read from the journals the agents keep themselves (Claude Code, Codex, runner lanes, the local model): fresh input, cache write, cache read and output kept apart, the day they were spent, the projects and the single conversations that cost the most. Money is an api-equivalent, not a bill: work under a subscription costs nothing per token, and who paid is printed beside the figurelsh tokens sources: which journals were read, how many files each holds and when it last wrote. A source that stopped writing shows as silent rather than as zerolsh tokens window: how long a token stays in a context window: what was written into one once against what was re-read on later turns, where the volume sits by how big the window already was, the floor paid on every turn (system prompt, tool schemas, memory), and what the same work would have cost folded at a cap, folds paid for. Reads the transcripts turn by turn, so it is slower than the rest of the verb
Flags:
--window(24h, 7d, 30d, all): 7d (default), 24h, 30d or all--by(day, project, session, model, agent): one slice only--project: only one working copy; . for the one you are in--top: how many rows per list (default 10)--format(text, json): text (default) or json
lsh learn
five things to try, on this repository
lsh learn: a short tour on YOUR working copy: ask in your own words, read the repository as a map, hold a conversation, say no to a change, carry one on tomorrow. Stops and resumes where you left it; finishes on a machine with no key at all
Flags:
--restart: start from the first step again--format(text, json): text (default) or json
lsh completion
the Tab-completion script for your shell
lsh completion zsh|bash|fish: print the completion script for that shell, built from this binary's own list of verbs:lsh completion zsh > ~/.zsh/completions/_lshand Tab knows every verb this version has, including the ones added after the script was written
lsh commands
this surface itself, for a person or (with --format json) for an agent
lsh commands: everything lsh can do, in one place; --format json hands the same list to another agent so it can learn this CLI without reading our docs
Flags:
--format(text, json): text (default) or json
<!-- cli-doc:end -->