InkShell is for people who already live in a coding-agent CLI — claude, opencode,
maybe both — and have no intention of leaving it, but who juggle several projects
at once and want a desktop around them. Every session in a pane, every project in
one window, each with its own configuration, so work and personal never share
credentials or history and switching between them costs nothing.
It stays a thin shell around the real thing. InkShell never reimplements either CLI: it spawns your own locally-installed binary inside a pseudo-terminal, so you are always running the original, stable CLI, and a feature reaches you the day it ships to the terminal rather than whenever we catch up. No fork, no repackaged binary, no version lag. Close InkShell and your CLI is exactly where you left it.
InkShell is a community project and is not affiliated with Anthropic. "Claude" and "Claude Code" are trademarks of Anthropic.
- A split workspace, not a tab strip: show 1, 2 or 4 panes at once and drag a chat from the sidebar — or from another pane — into any of them. Panes minimize and maximize without touching the process behind them, so a session you push off-screen keeps running and comes back exactly as you left it.
- Every project in one window: the sidebar is a tree — each project, with its open chats, terminals and files nested underneath, a badge showing which pane each one currently sits in, and drag-to-reorder for the list itself. Every project row carries one-click buttons — in the CLI's own mark — to start a Claude Code chat, an Opencode chat, or a plain terminal in that project, whether or not it's the one currently selected. The list is yours alone: nothing is imported from the CLIs on a first launch, which opens straight on the New project screen.
- Two CLIs, one window: Claude Code and Opencode run side by side, each chat driving the real binary with its own flags, session store and history. Pick the agent per chat — a repo migration might call for one, a quick script for the other — without leaving the window.
- History that is the CLIs' own: InkShell reads Claude Code's transcript
store (
~/.claude/projects) and Opencode's session database to list past sessions — a toggle above the list picks which CLI's history you're browsing. Claude sessions are named with the sameai-titlethe CLI uses; a click resumes one in a pane, a right-click deletes it from the list. - Per-project configuration: each project carries an accent color that marks
every tab belonging to it, its own Claude config directory
(
CLAUDE_CONFIG_DIR) — point a project at a separate config dir and its sessions, history and login all follow it; no shell aliases, no.envrcjuggling — and a default model for each CLI. - Plain terminals, same window: open your own
$SHELLin the project directory as just another pane — for thegit rebaseor the dev server you didn't want to spend a chat on. - Launch defaults, not switchers: the model new chats start on — and Claude
Code's effort level — are plain settings, global in Settings and overridable
per project, passed straight to the CLI's
--model/--effortat spawn. What a session runs on after that is the CLI's own to manage from its prompt: the status bar stays a quiet working-directory line, and model, context and effort live where the CLI itself shows them. - Git panel: stage, unstage, commit, and push without leaving the window; browse the branch history with unpushed commits marked, and open any diff, file or commit as a pane of its own.
- Files, diffs, and a real editor: the project's tree with modified files marked, files opening in a Monaco editor you can actually edit and save, and diffs and commits rendered as Monaco diffs. A single click peeks at a file, a double click pins it. File paths Claude mentions in its output are clickable — verified against the disk, so only real files light up.
- Quick Open: fuzzy-search every file in the active project and open it straight into the editor.
Four panes, one window — a Claude Code chat and an Opencode chat on the same project, a terminal, and a file in the editor. Drag any of them between panes; what you push off-screen keeps running.
| Keys | Action |
|---|---|
⌘T / Ctrl+T |
New chat in the selected project |
⌘W / Ctrl+W |
Minimize the focused pane (the session keeps running) |
⌘P / Ctrl+P |
Quick Open — fuzzy file search in the active project |
⌘S / Ctrl+S |
Save the file open in the editor |
| Middle click | On a pane: minimize it · on a sidebar item: close it |
| Right click | On a project: its settings · on a history card: delete the chat |
- Claude Code and/or
Opencode installed (the
claude/opencodecommands must run in your terminal) — each chat drives whichever of the two you pick. InkShell asks your login shell where they are and also checks the usual install locations, so it still finds the CLIs when the app is opened from the Finder with a truncatedPATH. A non-standard install can be pointed at directly withINKSHELL_CLAUDE_BIN/INKSHELL_OPENCODE_BIN. - Node.js ≥ 20 and npm to build from source.
curl -fsSL https://raw.githubusercontent.com/inkshell/inkshell/main/install.sh | shThat downloads the latest release
— a universal build that runs on Apple Silicon or Intel — and installs it into
/Applications (or ~/Applications when that isn't writable).
A Windows version is coming soon. Until it lands, Windows and Linux users can run InkShell from source — see Getting started below.
Why a script and not a plain download? InkShell builds aren't code-signed yet,
and macOS quarantines anything a browser downloads, so opening the app that
way greets you with a misleading "InkShell is damaged and can't be opened"
dialog. curl downloads are never quarantined, so the script installs an app
that just opens. (You can read the script first — it's ~70
lines of sh.)
Installing by hand instead
Download the .zip from the
Releases page, unzip it,
move InkShell.app to /Applications, then clear the quarantine flag your
browser attached to the download:
xattr -dr com.apple.quarantine /Applications/InkShell.appWithout that last step, macOS shows the "damaged" dialog above — the file is fine; the message is Gatekeeper's way of saying "unsigned and quarantined".
# 1. Clone
git clone https://github.com/inkshell/inkshell.git
cd inkshell
# 2. Install (also rebuilds the native node-pty module for Electron)
npm install
# 3. Run in development (hot reload)
npm run devTo produce a distributable app for your platform:
npm run pack:mac # .zip
npm run pack:win # NSIS installer
npm run pack:linux # AppImage + .debmacOS is the only target that ships today. The Windows and Linux builds are wired up but haven't been tested yet — if you try one, an issue (or a PR) telling us how it went is very welcome.
InkShell is a standard three-process Electron app:
| Process | Responsibility |
|---|---|
| main | Spawns claude / opencode (or your $SHELL) in a pseudo-terminal (node-pty), reads config & both CLIs' histories, drives git, owns the window. |
| preload | A tiny contextBridge exposing a typed, sandboxed window.inkshell API. |
| renderer | React UI: the pane grid, sidebar tree, git/files dock, an xterm.js view per session and a Monaco editor per file. |
Two rules the code holds to: the renderer never touches the OS except through
the typed IPC contract in src/shared, and the CLIs' own data is read, never
written — ~/.claude/projects and Opencode's store belong to the CLIs;
InkShell keeps its own config in ~/.inkshell/config.json.
See docs/ARCHITECTURE.md for the full picture.
Every color, radius, and glow lives in CSS variables at the top of
src/renderer/src/styles/theme.css.
Re-theming InkShell is a one-file edit.
Today InkShell speaks Claude Code and Opencode. The design doesn't depend on either, though: the app drives a real CLI agent inside a pseudo-terminal and reads the transcripts that agent already writes, which is a shape more than one tool fits.
Codex and GitHub Copilot are the next targets. The goal isn't a lowest common denominator across all of them, but one window where each project opens the agent it actually calls for.
Contributions are very welcome. See CONTRIBUTING.md and our
Code of Conduct. Good first issues are labeled
good first issue.
Licensed under the Apache License 2.0. See NOTICE for attribution and trademark details.





