Skip to main content

Lake Terminal

A cross-platform execution control plane for humans and coding agents.
Persistent terminals, process attribution, durable command history, normalized events, and one observable state model for CLI tools, IDE agents, automation, and remote execution hosts.

macOS · Linux · Windows · VS Code-compatible editors · Claude Code · Codex · Cursor · Devin Local Agent


Why Lake Terminal exists

Software development is no longer driven by one person typing into one terminal. A modern workspace can have a developer, an IDE-hosted coding agent, a CLI agent, background automation, remote SSH hosts, and several shells all changing the same project at once.

The hard problem is no longer merely starting a terminal. It is knowing:

  • which execution belongs to which agent or human;
  • which commands are still running;
  • whether a terminal is actually reconnectable;
  • what happened before an agent disappeared or a window closed;
  • how to inspect several execution surfaces without maintaining separate state;
  • how an editor integration can observe terminals without scraping UI state;
  • and how to retain useful history without casually persisting secrets.

Lake Terminal turns those executions into one local control plane. It uses a canonical session model, SQLite-backed state, normalized lifecycle events, process-tree inspection, provider hooks, and platform-specific terminal backends. CLI, TUI, web, daemon, and editor integrations all consume that same state instead of inventing their own registries.

Human terminal ───────┐
Claude / Codex ───────┤
Cursor / Devin ───────┤        ┌───────────────┐
IDE processes ────────┼───────▶│ Lake Terminal control │
Remote hosts ─────────┘        │     plane      │
                               └───────┬───────┘
                                       │
                ┌──────────────────────┼──────────────────────┐
                ▼                      ▼                      ▼
          persistent PTY          SQLite state          event stream
          tmux / ConPTY      sessions/commands/...     daemon / TUI / web

What you get

Capability What Lake Terminal provides
Persistent execution tmux-backed sessions on macOS/Linux and ConPTY-backed sessions on Windows when the platform supports them.
Honest fallback Direct IDE/extension-host processes remain observable in process-only mode instead of being falsely labelled reconnectable.
Agent attribution Native hooks for Claude Code, Codex, Cursor and Devin Local Agent, plus configurable process/environment signatures.
One state model SQLite is the only persistent session/control-plane database. There is no JSON session registry or state mirror.
Command lifecycle Durable command start/finish/exit information with process-tree observation as a fallback.
Observability CLI status, interactive TUI, read-only views, event subscriptions, history and a live web dashboard.
Editor integration A machine-readable local API and daemon event stream suitable for VS Code-compatible extensions.
Remote hosts Named SSH execution hosts and aggregated status without recursively confusing local and remote state.
Privacy controls Redaction before persistence, configurable retention, bounded transient output buffers and explicit purge.
Recovery Transactional schema upgrades, backend reconciliation, diagnostics and SQLite integrity handling.

Quick start

From this checkout:

python lake_terminal/install.py

The installer supports an interactive component wizard as well as non-interactive install, plan, status, and uninstall operations. A normal installed command is lake.

# Create and attach to a managed persistent shell.
lake

# Create a managed shell, run a command, then keep the shell alive.
lake pytest -q

# See everything Lake Terminal currently knows about.
lake --status

# Interactive multi-session monitoring.
lake --watch

# Browser dashboard backed by the same control-plane state.
lake --web

# Deep diagnostics.
lake --doctor --full

Designed for the agentic development loop

A coding agent should not need a special, invisible terminal universe. Lake Terminal makes agent execution inspectable through the same primitives used for human execution.

Provider hooks record the strongest attribution available: provider, provider session, workspace and lifecycle state. When a native provider hook is unavailable, Lake Terminal can progressively fall back to editor/environment/process evidence. The resulting attribution is stored with the session rather than inferred independently by every UI.

This matters when several agents work concurrently. An editor can ask for machine-readable local status:

lake --status --json --local-only

Automation can consume normalized events:

lake --subscribe

An agent can idempotently obtain/reuse its managed session:

lake --agent
# or
lake --ensure

The result is a useful separation of concerns: agents execute work; Lake Terminal owns execution identity, lifecycle and observability.

Platform model

Lake Terminal detects the execution host rather than assuming the desktop operating system is the execution environment.

macOS and Linux

When tmux is available, Lake Terminal uses it for persistent, reconnectable terminals and read-only capture. Process-tree inspection augments terminal state with workload information.

Windows

When the Windows pseudoconsole API is available, Lake Terminal uses ConPTY for persistent PowerShell/session execution. The ConPTY layer supports creation, input, output, resize, liveness and termination.

Process-only environments

If no persistent PTY backend is available—or an IDE runs a process directly—Lake Terminal still records and observes the execution, but marks it as non-reconnectable. This is intentional: observability does not imply terminal persistence.

One database, one truth

Canonical state lives in:

~/.lake_terminal/lake.db

The normalized SQLite model stores sessions, commands, events, observed processes, remote hosts, web-server registration and agent context. Updates are transactional. Stable session/host/process identities protect the model from PID reuse and short-lived process ambiguity.

JSON is used only where it is appropriate—for user configuration or explicit JSON transport/output—not as a parallel state database.

Everyday commands

lake                         # create/attach
lake <id>                    # attach to a reconnectable session
lake <id> --exec <cmd...>    # execute in an existing session
lake <id> --send <text...>   # type text into a session and press Enter
lake <id> --send-key <key>   # press one key (Enter, C-c, Escape, Up, ...)
lake <id> --kill             # terminate/remove
lake --list                  # list local sessions
lake --status [--json]       # local + configured remote status
lake --watch [--once]        # TUI dashboard
lake --view <id>             # read-only session view
lake --history               # durable command history
lake --events                # normalized events
lake --web                   # live web dashboard
lake --hosts                 # configured remote hosts
lake --doctor --full         # diagnostics
lake --purge                 # apply retention policy immediately
lake --mcp                   # resident MCP stdio server for agent clients

lake --help is intentionally a complete operational manual, including agent-routing, daemon, remote-host and internal integration endpoints.

MCP server

lake --mcp starts a resident MCP (Model Context Protocol) stdio server. The server keeps LakeTerminal in-process for the client's lifetime, so every call avoids interpreter and service startup cost; requests execute directly against the live session backends.

lake --mcp

Exposed tools:

Tool Purpose
lake_exec Run a shell command in a session; returns captured output and exit status.
lake_send Type text and/or press keys (C-c, Enter, Escape, Up, Tab, ...) to answer prompts, drive REPLs or interrupt processes. Enter defaults to true when text is given, false for key-only input.
lake_output Read the recent pane output of a session.
lake_sessions List live sessions.
lake_new Create a detached session; optional command and cwd.
lake_kill Destroy a session and its backend.
lake_events Recent normalized activity events; optional limit and filter.
lake_commands Recorded command history; optional limit and session_id.

Tools that target a session accept an optional session_id; it defaults only when exactly one live session exists. Every tool returns human-readable content plus machine-readable structuredContent matching its declared outputSchema (protocol 2025-06-18). Sessions created through lake_new are attributed as agent-initiated.

The installer registers the server for you (python lake_terminal/install.py install --with mcp): it edits Claude Desktop's claude_desktop_config.json (only when Claude Desktop is installed) and uses claude mcp add-json --scope user for Claude Code, falling back to ~/.claude.json. lake --doctor reports whether it is registered. lake --mcp --read-only (or LAKE_MCP_READ_ONLY=1) exposes only the inspection tools (lake_sessions, lake_output, lake_events, lake_commands).

To register the server manually with an MCP client such as Claude Desktop, add it to the client's server configuration:

{
  "mcpServers": {
    "lake-terminal": {
      "command": "lake",
      "args": ["--mcp"]
    }
  }
}

Agent identity: one variable, every provider

Lake resolves who is running a shell from the provider's own environment, so no hook is needed for attribution. LAKE_AGENT / LAKE_AGENT_SESSION win when set; otherwise the first native session variable present is used:

Provider Session variable(s), strongest first Surface
Claude Code CLAUDE_CODE_SESSION_ID, CLAUDE_SESSION_ID CLAUDE_CODE_ENTRYPOINT: cli, claude-vscode → vscode, claude-desktop → desktop, sdk-* → sdk
Codex CODEX_SESSION_ID, CODEX_THREAD_ID
Cursor CURSOR_SESSION_ID
Devin DEVIN_SESSION_ID

Claude Code and Devin run shell commands in their own non-interactive processes, so their native hooks also record each Bash/exec tool call into a non-reconnectable hook session (state, command, exit status) and lake --doctor shows the identity resolved for the current process. VS Code forks (Devin, Cursor, Windsurf, VSCodium) are told apart from the IPC hook path.

Control-plane architecture

                    ┌─────────────────────────────┐
                    │        provider hooks       │
                    │ Claude · Codex · Cursor ·   │
                    │ Devin · configurable agents │
                    └──────────────┬──────────────┘
                                   │ attribution
                                   ▼
┌─────────────┐          ┌──────────────────────┐          ┌─────────────┐
│ tmux / PTY  │◀────────▶│      LakeTerminal      │◀────────▶│ process tree│
│   ConPTY    │          │ backend-neutral core │          │ inspection  │
└─────────────┘          └──────────┬───────────┘          └─────────────┘
                                   │
                         ┌─────────▼──────────┐
                         │   LakeDatabase   │
                         │ SQLite-only state  │
                         └─────────┬──────────┘
                                   │
              ┌────────────────────┼─────────────────────┐
              ▼                    ▼                     ▼
        daemon / IPC          CLI / TUI             web dashboard
        event stream          history/status        WebSocket actions

The core deliberately keeps presentation surfaces downstream of the canonical model. The web dashboard, TUI and editor bridge do not maintain independent session registries.

Privacy and retention

Lake Terminal redacts common credential forms before persistence, including token/password assignments, authorization headers and common secret-token formats. Additional patterns can be configured in:

~/.lake_terminal/privacy.json

Default policy values are 30 days of command history, 90 days of events, no persisted terminal output, and a 256 KiB output limit when persistence is enabled. lake --purge applies the active retention policy immediately.

Remote and editor workflows

Remote machines are modeled as execution hosts. Add them with:

lake --host-add build-box user@example-host lake
lake --hosts
lake --status

--status may aggregate configured hosts over SSH. --local-only disables aggregation and is the correct mode for editor integrations and remote recursion prevention.

For VS Code-compatible integrations, the intended machine interface is the SQLite-backed CLI plus daemon events—not direct database mutation and not a JSON registry.

Installation model

The component installer can install only what a machine needs: launcher, tmux, shell lifecycle hooks, agent routing, provider hooks, web startup and the native lake-terminal:// URI handler.

python lake_terminal/install.py plan --preset default
python lake_terminal/install.py install --preset default --yes
python lake_terminal/install.py status
python lake_terminal/install.py uninstall

Two deployment modes are supported:

  • live — the launcher points at the checkout; useful while developing Lake Terminal;
  • copy — the package is copied into the configured library directory.

The install manifest is stored at ~/.lake_terminal/install.json so uninstall removes Lake Terminal-owned artifacts rather than indiscriminately deleting user configuration.

Python API

Lake Terminal is also usable as a Python library. The main programmatic entry points are LakeTerminal, SessionRepository, LakeDatabase, CommandLifecycle, RuntimePlatform, ProcessInspector, AgentConfiguration, WebDashboard, EventServer, and the provider hook adapters.

from pathlib import Path

from lake_terminal.core import SessionRepository, LakeTerminal
from lake_terminal.storage import LakeDatabase

home = Path.home()
database = LakeDatabase(home=home)
repository = SessionRepository(home=home)
service = LakeTerminal(repository=repository)

entry = service.create(initial_command=("python", "-m", "pytest"))
print(entry.id)
print(database.schema_version())

For the complete API, data model, CLI semantics, configuration files, daemon protocol, platform backends and every public class/function, see DOCS.md.

Project principles

Lake Terminal is intentionally built around a few constraints:

  1. One state store. SQLite is canonical; there is no JSON state path.
  2. No fake persistence. A process is reconnectable only when its backend actually supports it.
  3. Provider-neutral core. Provider-specific behavior stays in hook adapters.
  4. Execution-host truth. Capabilities belong to the machine/container/remote host running the command.
  5. One event model. CLI, TUI, web and editor surfaces consume normalized lifecycle state.
  6. Privacy before persistence. Redaction and retention are control-plane concerns, not UI afterthoughts.
  7. Headless first. Status, execution, subscriptions and lifecycle endpoints are automation-friendly.

Development

The repository includes Python tests for the control plane and Node tests for the web assets. The project is designed to run across macOS, Linux and Windows, with backend-specific tests isolated behind capability/fake layers.

python -m pytest tests/tools/lake_terminal
node --test tools/lake_terminal/lake_terminal/web_assets/app.test.mjs

The test suite is hermetic: tests/conftest.py strips CLAUDE*, CODEX_*, CURSOR_*, DEVIN_*, LAKE_* and VSCODE_* variables, so it gives the same result when run from inside Claude Code, Devin or Cursor.

Documentation

  • DOCS.md — complete architecture, capabilities, configuration and Python API reference.
  • lake --help — complete command-line operational manual.

Lake Terminal makes concurrent agent execution observable, attributable and controllable without forcing every agent, editor and terminal to invent its own state.

Directory contents

Files

  • LICENSE — Provide LICENSE project content.
  • PLATFORMS.md — Lake Terminal is OS- and CPU-architecture independent at the control-plane layer. Backend capabilities are discovered at runtime.
  • SECURITY.md — Lake Terminal is a local execution control plane. Session metadata, command history, process information, IPC authentication material, and optional terminal output are private user data.
  • __init__.py — Runnable wrapper exposing the Lake Terminal control-plane entry points.
  • __main__.py — Execute the Lake Terminal control plane as a module or directory.
  • install.py — Install, inspect, and remove the Lake Terminal control-plane integration.
  • lake_entry.py — Entry script frozen by tools.release_builder into native installers.
  • pyproject.toml — Provide pyproject toml content.
  • pyz_main.py — Entry point of the self-contained lake-terminal archive.
  • release-builder.toml — Provide release builder toml content.

Subdirectories

  • integration/ — This harness validates the part of Lake Terminal most likely to fail in real agentic development: execution attribution under concurrent providers and surfaces.
  • lake_terminal/ — Cross-platform coding-agent execution observability and control plane.

Integration qualification

Lake includes a first-class qualification harness for the ambiguity that matters most in multi-agent development: provider/session attribution under concurrent execution.

lake test integration synthetic all
lake test integration concurrent
lake test integration real codex
lake test integration real claude
lake test integration real cursor
lake test integration real devin
lake explain SESSION_ID

Synthetic qualification is unattended and suitable for CI/Docker. Real mode prints a unique probe command for the selected agent and waits for the provider metadata propagated by Lake's actual hook/environment integration. It therefore verifies observed identity rather than trusting which provider the operator said they were testing.

See integration/README.md for the concurrency matrix, Docker workflow, and Docker Sandboxes workflow.

Arrow URI control

Lake Terminal uses the independent tools/arrow framework as its URI trust boundary. LakeArrow creates signed, expiring, one-use lake-terminal:// control URIs and dispatches validated operations into the existing authenticated IPC daemon. The installer registers the URI scheme with Launch Services on macOS, XDG on Linux, and the per-user URL Protocol registry on Windows.

Metadata

Release files for lake-terminal 1.0.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for lake-terminal 1.0.1
File Size Uploaded Provenance
lake_terminal-1.0.1.tar.gz 168.7 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for lake-terminal 1.0.1
File Interpreter ABI Platform
lake_terminal-1.0.1-py3-none-any.whl Python 3 none any Details

Total release size: 358.0 kB

Release files / lake_terminal-1.0.1.tar.gz

Download URL lake_terminal-1.0.1.tar.gz
Size 168.7 kB
Tags Source
SHA-256 checksum
How to use checksums
9d9fb3e95ad2ecbeb6a899e577b2d452bb3f9e8ff9760f3e071b31e39c652bfc
BLAKE2b-256 checksum
How to use checksums
81df01ee72bdb2cc9b73061c8cfc5ef9763ec0baeaef1aef3c06143593bed8d2
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.9

Release files / lake_terminal-1.0.1-py3-none-any.whl

Download URL lake_terminal-1.0.1-py3-none-any.whl
Size 189.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
327aa96a86d04a5dbb38e357fd474ab66d52c80178de2008cda19c5cfb817a17
BLAKE2b-256 checksum
How to use checksums
96fab5a97fb8d360c6eccad64067871d08b01b2a4dd352dd3cb0e5394d77bf7b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.9

Security for lake-terminal 1.0.1

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

1.0.1 This release

2 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page