Lirah
0/200k

Your agent reads less.
You decide what.

Lirah is a desktop workspace for CLI coding agents.

Claude Code or opencode runs unchanged in a real terminal. You send it each file as full text, signatures or a skeleton.

24%cheaper16%fasteron cross-file questions in Lirah's own codebase, with the index. How we measured ↓
curl -fsSL https://raw.githubusercontent.com/emdmed/lirah/main/scripts/install.sh | bash

Linux · v0.4.15 · picks .deb, .rpm or AppImage for your distro · builds from source on Arch · other formats

demo session · ~/projects/acme-api
2terminalclaude

~/projects/acme-api main $ claude

> add refresh-token rotation to the auth middleware

● I'll start by exploring the codebase.

exploring

3prompt

No context attached. The agent will go looking.

add refresh-token rotation to the auth middleware
~0 tokens attachedsend^↵

A replica you can use. Click files and chips to change the context. Demo data; token counts are illustrative.

in the terminalClaude Codeopencodeheadless jobsCodexGeminiCursorAmp

// context

Stop paying for files your agent didn't need.

Left alone, an agent reads whole files to find one function. You pay for every line, and the session compacts away what you told it earlier. In Lirah you pick what it sees, and send big files as signatures instead of every line: schema.ts goes from 12.6k tokens to 2.1k.

The prompt footer shows the estimate before you send.

detail leveltry itsrc/db/schema.ts
import { pgTable, uuid, text, timestamp, boolean } from "drizzle-orm/pg-core";
export const sessions = pgTable("sessions", {
id: uuid("id").primaryKey().defaultRandom(),
userId: uuid("user_id").references(() => users.id),
refresh: text("refresh").notNull(),
expiresAt: timestamp("expires_at").notNull(),
revoked: boolean("revoked").default(false),
});
export async function findSessionByRefresh(token: string) {
const [row] = await db.select().from(sessions)
.where(and(eq(sessions.refresh, token), eq(sessions.revoked, false)));
return row ?? null;
}
… 368 more lines
12.6k / 12.6k tokens

This file is in the demo prompt, so the meter at the top of the page moves with it.

prompt controls
EDITREADCOPY
Intent per file. Change it, read it without touching it, or copy its pattern, like an existing route to model a new one on.
hookcontext
Box or terminal. Send from the prompt box, or type straight into Claude Code and Lirah's hook appends what you picked.
setauth-flow
Context sets. Save a selection by name and load it next time you work on that part of the code.
  • @mention a file
  • altalttemplates and .patterns
  • ^⇧Zkeep or restore context

// index

Your agent greps an index instead of reading the repo.

Lirah keeps a symbol index of your project and tells the agent to grep it before opening files, then read only the lines a hit points to. It pays off most on questions that span several files, and we measured it: the results are below.

It runs as a hook on every prompt in each Claude Code session Lirah starts, and can be switched off in settings.

terminal · claudetry itacme-api

> add refresh-token rotation to the auth middleware

● Search(pattern: "refresh", path: "src")

Found 9 files

● Read(src/routes/index.ts)

● Read(src/routes/session.ts)

● Read(src/middleware/auth.ts)

● Read(src/lib/token.ts)

● Read(src/db/schema.ts)

opened before the first edit: 5 whole files → 2 line ranges

Switch between the two to compare. A demo transcript; the measured results are below.

how the index works
grepused-by
Finds the right lines first. Each hit names a file and line range, plus every caller and the function it sits in. The agent opens those lines and nothing else.
.orchestration/
Stays current on its own. The index rebuilds when sources change, in the background on big repos, and never lands in git.
^⇧P
Never in your way. Switch it per tab with the key or :compact on; it applies on the next prompt. A failing hook never blocks a prompt, and your own hooks still run.
measured · 48 runsthe evals ↗

24%

cheaper on cross-file questions in Lirah's own codebase, and 16% faster.

  • 13% lower API cost per question overall
  • 18% fewer tool calls
  • cheaper on 7 of 8 tasks

Same answers: every run correct, with or without the index.

8 questions that each need 3+ files, 3 runs each way, on a small repo and on Lirah's own app. Every answer graded against the files it should name. Sonnet · Claude Code 2.1.280.

// tokens

Budgets that catch a runaway session.

Give a project a daily or weekly budget. Lirah warns you at 80% and again at 95%, so a runaway session gets caught before it burns through the rest of the week.

Usage is read from Claude Code's session files: totals per day and per project over a day, a week or a month, with CSV and JSON export.

token dashboarddemo data^⇧D
[overview][projects][history][insights]dayweekmonth
tokens this week
2.41M+18% vs last week
sessions
63
projects
4
Tokens per day this week by project, demo data. Today is the heaviest day at 843k.
budgets · daily
Tokens used today against each project's daily budget, demo data
acme-api412k/500k82%
acme-web118k/400k30%
acme-db291k/300k97%
infra22k/150k15%
  • acme-db97% of daily budget14:02
  • acme-api82% of daily budget11:47

// workspace

One window, an agent per project.

Each project tab has its own terminal, agent and sandbox. Hook plugins for Claude Code and opencode report when an agent is working, needs permission, is waiting on you or is done, and the tab row lights to match.

Nvim and lazygit open full window in the tab's second terminal, with your own config, while the agent keeps working. Lirah's shortcuts step aside until you quit.

workspace · tabstry itnext waiting altA
Contexttabagentbranchlast turnplan
apiworkingfeat/token-rotationauth.ts token.tsauth-hardening 4/7
uineeds permissionmainLoginForm.tsx·
dbwaiting on youmigrations0008_api_keys.sql·
doneops/tf-1.9main.tf variables.tf·
same repo as acme-api
workingfix/rate-limitlimiter.ts·
idlemain··

Pick a tab and the meter at the top switches to it · attach a tab's last-turn files to another tab's prompt · desktop notifications when an agent stops for you · demo data

  • ^Klaunch the tab's agent
  • ^`second terminal
  • altNaltLnvim, lazygit
  • :command line
  • ^⇧Fsearch scrollback
  • ^Hevery shortcut

// jobs and plans

Work you don't have to watch. You choose what lands.

Start headless runs of any supported agent from a template and your context files, each in its own git worktree if you want. Race several agents on one task, compare what they wrote, and apply the one you want.

For longer work, import a *_plan.md: Lirah implements it chunk by chunk in the tab's agent and commits each one.

jobsacme-api
race · add rate limiting to /login3 worktrees

context: your prompt above · 5 files · 8.5k each

  • claudeediting limiter.ts
  • codex+84 -12
  • geminiconflict in routes/login.ts
[compare][review diff][reconcile]
  • applied · fix flaky session test · claude+12 -4
  • failed · lint sweep · opencode · type check
  • archived · 6 jobs

Read the diff and send notes back first. Applying waits for the TypeScript check to pass and asks before touching a dirty tree.

planauth-hardening

1–3 implemented · 3 commits

4 · rotate refresh tokens on use

implementing in acme-api · commit trailer Plan-Chunk: 4

  • 5 · revoke sessions on password change
  • 6 · add api key scopes
  • 7 · audit log for auth events

:autopilotchains the remaining chunks

Check, review, roll back, skip or reorder any chunk. Autopilot stops when the agent asks a question, needs permission or forgets to commit.

// git

Commits drafted. Merges shown first.

When a change is ready, an agent reads the staged diff and drafts a conventional commit message for you to edit. Merging the branch back lists every git command before any of them runs.

All of it is local git, run on your machine.

auto commit · acme-api^⇧space
  • Msrc/auth/token.ts+48 -12
  • Msrc/auth/middleware.ts+21 -9
  • Asrc/auth/token.test.ts+64 -0
message · drafted by claude40/72

feat(auth): rotate refresh tokens on use

Issue a new refresh token on every refresh and revoke the old one, so a stolen token works at most once.

commit
auto merge · acme-apialtM

feat/token-rotation → main · --no-ff

  1. git switch main
  2. git merge --no-ff -m "Merge branch 'feat/token-rotation' into main" feat/token-rotation

on conflict: git merge --abort, nothing changed

Fast-forward or --no-ff. It knows when either branch is checked out in another worktree.

merge
^[^]

Diff viewer. Side by side, word level, unchanged regions folded. Step file to file and leave review notes as you read.

// sandbox

Let the agent run, inside a sandbox.

On Linux, each tab can run in a bubblewrap sandbox. The root filesystem is read-only. Your home and the project stay writable, while keys, shell rc files and your git config stay read-only. /tmp is private to the tab.

macOS and Windows builds run without the sandbox.

sandbox · bwraptry itacme-api
network isolation off
Filesystem and namespace access inside the sandbox
/ro
~rw
~/projects/acme-apirw
~/.sshro
~/.gnupgro
Filesystem and namespace access inside the sandbox, continued
~/.bashrc ~/.zshrc ~/.profilero
~/.gitconfigro
~/.config/autostartro
/tmpprivate
pid ipc utsisolated

Switch it off to see what an unsandboxed tab can reach.

  • network

    Network isolation. One more switch cuts the tab off from the network.

  • apparmor

    Set up for you. On Ubuntu 24.04 and later Lirah installs the AppArmor profile bubblewrap needs.

  • retry

    Never a dead end. If the sandbox can't start, Lirah offers to retry the tab without it.

// faq

Questions before you install.

Something not covered here? Open an issue on GitHub.

faq
Does Lirah replace or wrap my agent?

No. Lirah starts the agent's own CLI in a real login-shell PTY, the same program you would run in any terminal, with your config, your login and your plan. Lirah doesn't call a model API itself. Its git and job features also work by starting those CLIs.

Which agents and platforms does it support?

Claude Code and opencode run interactively in a tab, with hook plugins that report their state. Codex, Gemini, Cursor and Amp run as headless background jobs, alongside Claude Code and opencode.

Linux is the primary platform. macOS and Windows builds exist and work without the sandbox, which is Linux-only.

What do Lirah's hooks add to Claude Code?

Lirah loads a plugin into each Claude Code it starts with --plugin-dir, so your own hooks and settings stay as they are. Its hooks report the agent's state to the tab, append the context you picked to prompts typed in the terminal, and, in tabs where you switch it on, point the agent at a fresh project index. The index lives in .orchestration/ and is kept out of git. Each hook can be turned off in settings.

What happens if I stop using Lirah?

Nothing to migrate. The agents are the same CLIs you would run in any terminal, with their own config, and the commits and merges Lirah makes are ordinary local git. Your repos look the same with or without it.

Is it free?

Yes. Lirah is open source under the MIT license, with no account. The source is at github.com/emdmed/lirah. You still pay for whatever agent plan you use.

Does anything leave my machine?

Lirah itself makes one request: at launch and every four hours it asks GitHub's API for the latest release, to tell you about updates. It sends no data of yours with it. There is no telemetry. Lirah runs only local git commands and never pushes, pulls or fetches.

Token figures are read from Claude Code's session files on disk, and budgets are stored locally. The agents you run talk to their own providers, and features that use an agent send through it what they need: auto commit hands it your staged diff. If Claude Code isn't installed, launching it falls back to npx, which downloads it from npm.

Why not tmux and my editor?

Keep them. The agent runs in a real login-shell PTY, and the second terminal opens nvim and lazygit beside it. What Lirah adds is what a multiplexer can't see: which files the agent is given and at what detail, how full each tab's context is and whether its agent is waiting on you, background jobs in their own worktrees, and plans that commit chunk by chunk.

// download

Give your agents less to read and more to do.

Lirah is a free, open-source workspace for the coding agents you already use. MIT licensed, no account, no telemetry.

curl -fsSL https://raw.githubusercontent.com/emdmed/lirah/main/scripts/install.sh | bash

Linux · v0.4.15 · picks .deb, .rpm or AppImage for your distro · builds from source on Arch

source on GitHubbuild from source

release v0.4.15all releases
Installers in v0.4.15
Your systemsystemformatarchsizeDownload
LinuxAppImage · x64x6480 MB[get]
Linuxdeb · x64x645.9 MB[get]
Linuxrpm · x64x645.9 MB[get]
macOSdmg · IntelIntel5.2 MB[get]
macOSdmg · Apple siliconApple silicon5.0 MB[get]
Windowsexe · x64x644.2 MB[get]
Windowsmsi · x64x646.0 MB[get]