A ThinkRail-branded desktop-and-mobile client for the pi
coding agent. ThinkRail is a thin host that runs pi in-process and bridges it to a rich, mobile-first
UI — pi owns models, skills, compaction, cost, and session state; the app owns the workspace, the
editor, and the wire.
Website: thinkrail.ai — a landing
page that is the IDE (see apps/website).
V1 is a Worktree IDE: open a git repo as a project, spin up workspaces as git worktrees (each its
own branch and cwd), and work across a tabbed Monaco editor, git Changes view, terminals, a read-only
spec-graph viewer, and multiple concurrent pi chat sessions — all scoped to the active worktree.
ThinkRail ships as a single self-contained executable per platform. The installer downloads the right
build from the GitHub releases, verifies its SHA-256 checksum, and puts thinkrail on your PATH.
macOS / Linux (also Windows under Git Bash):
curl -fsSL https://raw.githubusercontent.com/JetBrains/thinkrail/main/install.sh | bashWindows — the same command works from cmd and PowerShell:
powershell -c "irm https://raw.githubusercontent.com/JetBrains/thinkrail/main/install.ps1 | iex"Nightly builds and pinned versions:
# macOS / Linux
curl -fsSL https://raw.githubusercontent.com/JetBrains/thinkrail/main/install.sh | bash -s -- --channel nightly
curl -fsSL https://raw.githubusercontent.com/JetBrains/thinkrail/main/install.sh | bash -s -- --version 0.2.0# Windows — options are env vars (THINKRAIL_CHANNEL, THINKRAIL_VERSION, THINKRAIL_PREFIX, THINKRAIL_NO_MODIFY_PATH)
$env:THINKRAIL_CHANNEL='nightly'; irm https://raw.githubusercontent.com/JetBrains/thinkrail/main/install.ps1 | iex # PowerShell
set "THINKRAIL_VERSION=0.2.0" && powershell -c "irm https://raw.githubusercontent.com/JetBrains/thinkrail/main/install.ps1 | iex" # cmdThen run thinkrail (add a git repo path to open it as a project: thinkrail ~/code/my-repo). To update
later, run thinkrail update on any platform — it re-runs the installer for your channel (on Windows it
replaces the running thinkrail.exe in place). To remove it, run thinkrail uninstall: it takes out the
executable, the PATH entry the installer added, and the install metadata, and asks whether to delete your
~/.thinkrail app state (kept by default — pass --remove-data to delete it, -y to skip the
questions). thinkrail --help lists the flags; thinkrail --version prints the build.
Prebuilt platforms: macOS (Apple Silicon), Linux arm64 + x64, Windows x64 (.exe). Intel macOS isn't
prebuilt — use Apple Silicon or build from source.
Prefer a manual install? Download a binary +
SHA256SUMSfrom the releases page, verify the checksum,chmod +x, and move it onto your PATH.
Runtime prerequisites: git on PATH, and an authenticated pi provider (the agent runs against your
real provider credentials). App state lives under ~/.thinkrail.
- Bun ≥ 1.3 (the package manager and runtime)
- Node.js ≥ 22.19 (required by the in-process
piengine) - An authenticated
piprovider (the agent runs against your real provider credentials)
git clone <repo-url>
cd thinkrail
bun install
bun run devbun run dev boots the host and the web client together. Press Ctrl+C to stop.
To run the V1 CLI entrypoint (boots the host in-process and opens the browser):
bun run --filter @thinkrail/cli dev
# or build the standalone binary:
bun run build:binaryOn-disk app state (projects, workspaces, worktrees) lives under ~/.thinkrail.
- Engine host —
packages/server(+packages/shared), launched byapps/cli.createServer()is aBun.serveHTTP+WS host with anAgentSessionManager(one in-processpiAgentSessionper tab). - The wire —
packages/contracts: the typed, versioned protocol (types-only). - UI client —
apps/web: mobile-first React 19 + Zustand + Tailwind v4, ships independently and dials a host over the wire.
The engine is pi only, run in-process via @earendil-works/pi-coding-agent. apps/web depends on
packages/contracts only — never on the server — which is what makes the UI shippable on its own.
See goal-and-requirements.md and architecture.md for
the canonical product and design specs.
apps/
cli/ V1 entrypoint: boot host + open browser
web/ mobile-first UI client
desktop/ Electrobun launcher — deferred
website/ public landing page (GitHub Pages)
packages/
server/ createServer(): Bun.serve + AgentSessionManager
contracts/ the wire (types-only)
shared/ server-side helpers (shellEnv, freePort)
spec-graph/ portable pi extension: spec_* tools + skill
Fast gates (also the husky pre-commit hook):
bun run lint # biome
bun run typecheck # tsc across all packages
bun run test # unit tests (bun test, per package)End-to-end tests drive the real web UI against a booted host on an isolated state dir:
bunx playwright install chromium # one-time
bun run e2e # no-agent suite (fast, no auth)
bun run e2e:full # everything, including @agent specs (needs pi authenticated)
bun run e2e:agent # only the @agent specsThinkRail is developed spec-first: hierarchical, interconnected specs live in the repo alongside the
code — top-level specs at the root (goal-and-requirements.md, architecture.md) and a co-located
SPEC.md for every module. When you change a boundary, contract, or decision, update the corresponding
spec in the same change. See AGENTS.md for the spec workflow.
ThinkRail sends anonymous usage analytics to PostHog (EU cloud; on by default; a notice is printed the first time anything is sent). The data answers product questions — how many installs are active, on which versions/platforms, which models and providers get used, and which features matter — and nothing more.
This applies to every way of running ThinkRail, including a build you compiled yourself and a run
straight from a source checkout — each is reported as what it is (see channel and build below) rather
than kept silent. Automated runs never send: anything under CI, bun test, and the e2e suites are all
muted, so test traffic can't be mistaken for a person.
The only stable identifier is a random per-install id (a uuid4) minted on your machine and
stored in ~/.thinkrail/installation.json; it never leaves the host except as the anonymous
distinct_id on events. Events additionally carry only low-cardinality, non-personal metadata: app
version, release channel (stable/nightly/dev), how the code was built (binary for a compiled
executable, source for a repo checkout), OS (macos/linux/windows), architecture
(x64/arm64), and — on chat/login events — the model/provider name only if it is a pi built-in
(anything user-configured is reported as custom). Message activity is counted as a bare send event
carrying only how it was sent (prompt/steer/follow_up) — never the message itself. Events are sent personless (no person
profiles are ever built) and with GeoIP lookup disabled.
Never collected: file paths or names, prompts, code, chat transcripts, API keys, token counts, hostnames, usernames, or IP-derived fields.
Contributors: running bun run dev or the CLI from a checkout reports too, tagged channel=dev /
build=source. Your test and CI runs don't (they're muted, as above), and if you'd rather not report at
all, either switch it off in-app or export THINKRAIL_NO_ANALYTICS=1 in your shell.
Turn it off any time:
- In-app: Settings → Privacy → toggle off (saved on the host, synced to every client).
- Per run:
thinkrail --no-analytics(orTHINKRAIL_NO_ANALYTICS=1) — mutes that run without touching the saved setting.
Turning analytics off stops all sending immediately; the install id is kept (never rotated) and simply goes unused until you turn it back on.
Contributions are welcome — see CONTRIBUTING.md. This project and community are
governed by the Code of Conduct.
Licensed under the Apache License 2.0.