Skip to content
codejunctionPublic

About

Project-first multi-terminal for Windows and Linux. Real shells (PowerShell, cmd, Git Bash, WSL, bash, zsh, fish) grouped by project in your browser, with split or free-floating panes, session restore, git graph, scheduler and code search. One command: sd.

Resources

Code of conduct

Contributing

Security policy

Stars

2 stars

Watchers

0 watching

Forks

 
 

Repository files navigation

shelldeck logo

shelldeck

Your terminals, organised by project.
Real shells in the browser, on your own machine, with your AI coding agents working side by side.

PyPI Python CI Platforms License: MIT

Install · Terminals · Projects · AI agents · Tools · CLI · Remote access · Security

shelldeck with four named terminals in three projects: a git log, Claude Code, Codex asking to trust a folder, and sd top

Terminals that last

PowerShell, cmd, Git Bash, WSL, bash, zsh, fish. Split or floating panes that keep running with the browser closed and come back after a reboot.

Grouped by project

A colour per project, workspaces, VS Code .code-workspace import, git status at a glance, and SSH or RDP machines in the same sidebar.

Agents as a team

Claude Code, Codex, Gemini, Devin and more, detected automatically. They hand work to each other, and the project remembers what they learned.

Install

Windows (PowerShell) Linux
Standalone (default) irm https://raw.githubusercontent.com/codejunction/shelldeck/main/install.ps1 | iex curl -fsSL https://raw.githubusercontent.com/codejunction/shelldeck/main/install.sh | sh
uv tool & ([scriptblock]::Create((irm https://raw.githubusercontent.com/codejunction/shelldeck/main/install.ps1))) -Pip curl -fsSL https://raw.githubusercontent.com/codejunction/shelldeck/main/install.sh | sh -s -- --pip
Standalone uv tool
Needs nothing Python 3.12+ via uv (also pipx install shelldeck, or uvx shelldeck to try it)
Updates Settings › Updates, in place uv tool upgrade shelldeck
Plugins no yes

Requires Windows 10 1809+ (ConPTY) or Linux x64, and a modern browser. macOS gets the Python package and is untested.

sd                 # start shelldeck in the background and open it in your browser
sd ~/code/api      # add a folder as a project and open a terminal in it

The first visit asks you to create a password. Terminals keep running until you close them, even with the browser closed.

Standalone layout, installer options, updates

The installer downloads shelldeck-<version>-windows-x64.zip or -linux-x64.tar.gz from the latest GitHub release, checks its .sha256, unpacks it into %LOCALAPPDATA%\shelldeck or ~/.local/share/shelldeck and puts that folder on PATH:

shelldeck/
  current.txt              the version in use, e.g. 0.0.12
  sd.cmd, sd               shims that run versions/<current>/sd, so `sd` and agent hooks survive updates
  versions/
    0.0.12/                shelldeck, sd-pty, sd-ui, sd (+ .exe on Windows) and _internal/
Variable Effect
SHELLDECK_VERSION=0.0.12 a specific release, release candidates included
SHELLDECK_ROOT=<dir> install somewhere else
SHELLDECK_NO_MODIFY_PATH=1 leave PATH alone
SHELLDECK_ARCHIVE=<file> install from a downloaded archive

Running the installer again installs the newest release next to the old one.

Updates. Standalone: Settings › Updates (or the Update now toast) downloads the new release, checks its sha256, unpacks it next to the running one and restarts only the web app; terminals and their programs keep running. uv: uv tool upgrade shelldeck, then sd restart. Release candidates: SHELLDECK_VERSION=0.0.13rc1 with the installer, or uv tool install --force shelldeck==0.0.13rc1.

Processes. shelldeck supervises sd-pty, which owns the shells, and sd-ui, the web app, which restarts on its own. Task Manager shows all three. sd restart restarts only the web app; sd stop stops everything.

How it fits together

flowchart LR
    B["Browser<br/>xterm.js"] <-- "WebSocket" --> UI["sd-ui<br/>web app, API, auth"]
    CLI["sd CLI<br/>agents in terminals"] -- "HTTP" --> UI
    UI <-- "loopback TCP" --> PTY["sd-pty<br/>owns the shells"]
    PTY --> S1["pwsh / bash / zsh ..."]
    PTY --> S2["claude / codex / devin ..."]
    UI --- DB[("SQLite<br/>projects, context")]
Loading

sd-ui can restart (updates, crashes) while sd-pty keeps every shell and agent running. Everything stays on your machine.

Terminals

Feature What it does
Real shells Windows: pwsh, Windows PowerShell, cmd, Git Bash, WSL (any distro). Linux: every shell in /etc/shells.
Layouts Tiled splits (drag titles to split or swap, maximize) or floating windows on a canvas with Tile all.
Nothing lost Closing the tab keeps terminals running. After a restart each one reopens in its last folder, its old text above a restored line.
Shell integration The pane title shows the last command (red when it failed); Ctrl+Shift+Up/Down jumps between prompts. Your own prompt still loads.
Background Hide a pane with Ctrl+Alt+W and it keeps running; Ctrl+Alt+P replays the last command.
Links Port chips for dev servers; paths like src/app.py:12:5 and tracebacks open in VS Code or the built-in editor.
? and Ask Type ? on an empty prompt for commands, bookmarks and plugins. Type a question and Ask has an agent's model write one command for that shell (Enter types it, Shift+Enter runs it). Ctrl+I opens just Ask; sd ask "..." prints it.
Command palette filtered to split commands The ? menu at the shell prompt offering Ask for a question
Command palette · Ctrl+Shift+P ? menu with Ask · right at the prompt
Search all terminals dialog with highlighted matches Built-in editor previewing a markdown file
Search every terminal · Ctrl+Shift+F Editor and markdown viewer · sd edit, sd view

Projects

Feature What it does
Sidebar A colour per project (sidebar dot, pane border, background tint), added through a folder browser and reordered by drag.
Workspaces Group projects under a name and show one group at a time from the Projects header. Move to workspace… sets one.
VS Code workspaces A .code-workspace file adds each local folder in it as a project, in a workspace named after the file. Double-click it in the folder browser, paste its path, or run sd open X.code-workspace. Missing folders are listed, not dropped.
Git A ±N chip for uncommitted work; the git dialog shows changed files with diffs and the commit graph with one-click checkout.
Machines Switch between this computer and SSH machines (Linux; key, agent or password, LDAP names like CORP\jdoe). Windows machines open as RDP desktops. Test connection checks network and login. Passwords are never stored.
Git graph with branches, tags and authors Git changes tab with added and removed lines per file
Git graph · one-click checkout Changes · uncommitted diffs
Machine picker with local, an SSH machine and an RDP desktop Remote systems page listing SSH and RDP machines
Machine picker Remote systems · SSH and RDP

AI agents

Agents running in shelldeck terminals see each other, hand work to each other, and leave what they learned for the next one.

Hand-offs as a flow of cards: each sender, the tasks it gave out on connecting lines, and chains nested to the right, coloured by status

Hand-offs · who gave what to whom, chains nested to the right, coloured by how they ended

Feature What it does
Detected Claude Code, Codex, Devin, Gemini, Copilot, Cursor Agent, opencode, Aider, Amp, Qwen, Goose, Droid, Crush and Kiro get an AI chip with the model and how full the context window is.
Needs you Only when an agent asks something (a permission prompt, a question, [y/n]): an amber chip, a chime and a notification. The sidebar ranks agents by who needs you.
Exact state sd integration install hooks Claude Code, Codex, Gemini and Devin so they report working / blocked / done and can be resumed after a restart. 15 more have preview hooks. See docs/agent-integrations.md.
Teamwork Each terminal has a name (Maya, Kofi…). From inside one: sd agents, peek, tell, spawn "task" --model small|medium|large, handoff and done. A sub-agent's questions go to its parent, not to you.
Hand-offs The Hand-offs tab draws every hand-off as a card on a tree; click one for the full task and result, or cancel it. You can hand off too, from a running agent's Actions menu.
Context Each project keeps a task, next step, facts, decisions and activity (commands, tests, edited files; never output or secrets) locally and in .shelldeck/*.md. A new agent runs sd context and continues. sd recall searches every project. No model runs inside shelldeck.
A hand-off opened in full: task, result, and Open terminal Context page with the task, facts, decisions, open hand-offs and recent activity
A hand-off in full · task, result, open the terminal Context · what the project is working on
flowchart LR
    You -- "task" --> A["Arjun<br/>Claude Code"]
    A -- "sd spawn" --> B["Maya<br/>writes limits.py"]
    A -- "sd spawn" --> C["Tomas<br/>wires middleware"]
    C -- "sd handoff" --> D["Iris<br/>checks the proxy"]
    B & C & D -- "sd remember, sd done" --> K[("project context")]
    K -- "sd context" --> N["next agent"]
Loading

Tools

Tool What it does
Task manager Ctrl+Alt+M, sd top: CPU, RAM and NVIDIA GPU for the machine and each terminal's process tree.
Bookmarks Commands per project; insert, or Shift+Enter to run.
Scheduler Cron jobs in a project folder, with logs.
Tasks A board with due dates, reminders and Send to agent.
History Every command with exit code, duration and folder.
Scratchpad Markdown notes; agents add with sd notes.
Devices Every signed-in browser, which one is in use, and Sign out.
Radio cliamp channels in the top bar, streamed by your browser.
Task manager with CPU, memory, GPU and per-terminal usage Task board with backlog, to do, in progress and done
Task manager · per terminal Task board
More screenshots · bookmarks, scheduler, history, scratchpad, settings, radio, share, devices
Bookmarks list with commands per project Scheduler board with cron jobs
Bookmarks Scheduler
Command history with exit codes, durations and folders Scratchpad note rendered as a markdown checklist
Command history Scratchpad
Settings dialog with Appearance, Terminal, AI agents, Updates and Password sections Radio menu with cliamp channels and a volume slider
Settings Radio
Share dialog with the terms of sharing Devices page with the signed-in browser
Share · Cloudflare tunnel Devices

Plugins

A plugin is a Python package with a shelldeck.plugins entry point. Its commands show up in the ? menu (?docker logs web) and the CLI (sd docker logs web), and return text to show or a command line to type.

# pyproject.toml: [project.entry-points."shelldeck.plugins"]  docker = "shelldeck_docker:plugin"
from shelldeck.plugins import Plugin

plugin = Plugin("docker", "0.1.0")

@plugin.command("logs", "Follow a container's logs", usage="<container>")
def logs(args, ctx):  # ctx: session_id, cwd, shell, project
    return {"input": "docker logs -f " + " ".join(args)}

Install into shelldeck's environment (uv tool install shelldeck --with ./examples/shelldeck-docker) and restart. The Plugins page and sd plugin list|enable|disable manage them. Plugins run with your permissions; install only ones you trust. Guide: docs/plugins.md.

Keyboard shortcuts
Keys Action
Ctrl+Shift+P Command palette (Ctrl+K also works outside a terminal)
Ctrl+Alt+N New terminal in the current project
Ctrl+Alt+\ / Ctrl+Alt+- Split right / down
Ctrl+Alt+Arrows Focus the pane in that direction
Ctrl+Alt+1…9 Focus pane 1–9
Ctrl+Alt+Enter Maximize / restore the pane
Ctrl+Alt+Q Close the focused terminal (offers the background when a command runs)
Ctrl+Alt+P Replay the last command
Ctrl+Alt+W Send the terminal to the background (keeps running)
Ctrl+Alt+B Bookmark picker (Space selects several, Shift+Enter runs)
Ctrl+Alt+E Toggle the sidebar
Ctrl+Alt+S / Ctrl+Alt+T Scheduler / Tasks
Ctrl+Alt+M Task manager
Ctrl+Alt+R Command history
Ctrl+Shift+F Search all terminals
? / Ctrl+I (empty shell prompt) Command menu with Ask / just the Ask box
Ctrl+Alt+, Settings
Ctrl+Alt+L Lock
Ctrl+Alt+H Show shortcuts
Ctrl+C / Ctrl+V Copy the selection (otherwise sends Ctrl+C) / paste
Ctrl+F Find in the terminal
Ctrl+Shift+Up / Down Jump to the previous / next prompt

In the sidebar, Ctrl+click or middle-click a terminal to open it in a split. Right-click a project or terminal for its menu.

Settings
Setting Values Default
Theme dark, light, system dark
Terminal colors default (follows theme), Dracula, One Dark, Nord, Gruvbox Dark, Solarized Dark, Solarized Light, GitHub Light default
Terminal font / size any installed monospace font / 8–32 Cascadia or Nerd Font / 13
Pane layout tiled, free tiled
Project colors tint on, off on
Default shell Windows: pwsh, powershell, cmd, gitbash, wsl · Linux: shells from /etc/shells pwsh / $SHELL
WSL distribution any installed distro, or the system default system default
Open file paths with VS Code (at the line), shelldeck's editor, system default app VS Code
Ask agent / Ask model first installed, Claude Code, Codex, Gemini CLI, Devin CLI / that agent's models first installed / its smallest
Smart search off, first installed agent, Claude Code (haiku), Codex, Gemini CLI (flash-lite), Devin CLI off
Resume agent sessions after a restart ask, automatically, never ask
Updates installed and latest version, Update (standalone)
Password created on first visit, changed here (current + new) required

CLI

Everyday Agents and context
sd                   start and open the browser
sd PATH              add a project, open a terminal
sd X.code-workspace  import every folder in it
sd list / sd info    terminals / the one you're in
sd restart           restart the web app only
sd stop              stop everything
sd top / ps / kill   task manager
sd edit / view FILE  built-in editor / viewer
sd search QUERY      LLM-free code search
sd share             share over a tunnel
sd agents               agents in this project
sd peek / tell NAME     read / type into a terminal
sd spawn "TASK"         sub-agent in a new pane
sd handoff NAME "T"     give a task to an agent
sd done ID "RESULT"     close a hand-off
sd context              task, facts, decisions
sd remember FACT        save what you learned
sd recall QUERY         search every project
sd ask "QUESTION"       one command for this shell
sd integration install  exact agent state
Full command reference
sd [--port N] [--no-window] [--app]  start the server if needed, print the banner and open the browser (= sd web)
sd PATH / sd open [PATH] [--shell S] add PATH as a project and open a terminal in it (a .code-workspace file adds every folder in it)
sd list / sd info                    terminals grouped by project / the terminal you're in
sd restart / sd stop                 restart the web app (terminals keep running) / stop everything
sd serve [--host H]                  run the server in the foreground

sd agents [--all]                    AI agents in this project's terminals (--all: everywhere, plus installed CLIs)
sd peek TERMINAL [-n 40]             last lines of another terminal (by name like Maya, id or title)
sd tell TERMINAL "MESSAGE"           type a message into another terminal and press Enter
sd spawn "TASK" [--agent A] [--model small|medium|large|auto|NAME]   sub-agent in a new terminal
sd handoff TERMINAL "TASK" / sd done ID ["SUMMARY"] [--failed] / sd handoffs [--all]
sd answer TERMINAL KEY...            press keys in another terminal (1, y enter, esc)
sd close TERMINAL [--force]          close a terminal; from an agent only its own sub-agents
sd agent status|wait|start|prompt|rename|cmd|explain|resume|report|extract ...   agent lifecycle
sd integration list|detect|status|install|uninstall [AGENT] [--all]   lifecycle hooks
sd events subscribe [--types agent,handoff] [--since ID]   JSON lines of agent.*, handoff.* events

sd init [PATH] [--task TEXT]         set up .shelldeck/ (STATE, TASK, MEMORY, DECISIONS, AGENTS.md)
sd context [PROJECT] / sd resume     task, state, next action, memory, decisions, events
sd remember FACT... / sd discover FINDING / sd decide TITLE [-r REASON] / sd memory
sd task update [STATUS] [--task --step --next --tests --error]
sd recall QUERY [--smart | --agent A [--model M]]   search every project
sd switch AGENT [--note TEXT]        continue this project's task with another agent
sd ask "QUESTION"                    print one command for this terminal's shell and OS

sd notes list|add|append|show|replace|delete   Scratchpad
sd top / sd ps [TERMINAL] / sd kill TERMINAL PID [--force]   Task manager
sd edit FILE / sd view FILE          open a file in shelldeck's editor / viewer
sd search QUERY [--root DIR]         LLM-free code search with ranked snippets
sd render FILE                       pretty-print code or markdown
sd schedule list|add|run|toggle|delete|logs
sd task list|add|move|delete|alarms
sd plugin list|enable|disable|run    plugins; `sd <plugin> <command>` runs one
sd install-skill [AGENT...] [--remove]   teach agent CLIs the sd commands (automatic on start)
sd share [stop] [--new-link]         share over a Cloudflare tunnel (see Remote access)
sd login-link / sd reset-password    emergency, host only
  • Default port 5455 (--port or SHELLDECK_PORT). --app opens a chromeless Edge/Chrome window.
  • Inside a terminal: SHELLDECK_SESSION_ID, SHELLDECK_NICK, SHELLDECK_PORT, SHELLDECK_AGENT_REPORT_TOKEN, and SHELLDECK_PARENT for sub-agents.
  • To let Claude Code sub-agents report back on their own, allow Bash(sd:*) in its permissions.

Remote access

Way Setup Who sees the traffic
SSH tunnel (recommended) sd serve on the VM, ssh -N -L 5455:127.0.0.1:5455 you@vm locally only you
sd share cloudflared on PATH, no account Cloudflare (it ends TLS)
iPhone / iPad app scan the share QR once only you (end-to-end encrypted)
HTTPS on the VM sd serve --host 0.0.0.0 --cert cert.pem --key key.pem only you

sd share

sd share              # prints a QR code and a link; Ctrl+C stops sharing
sd share --new-link   # another one-use link for a second device
sd share stop

Or use the Share button in the top bar.

  • Each link works once, for 10 minutes. The device then waits until you allow it here. It shows a 4-digit code and so does the Allow prompt (toast, Devices, sd share): allow only if they match. The password is still required (12+ characters for sharing).
  • Cloudflare ends TLS, so in a browser it can see the traffic. For sensitive work in a browser use SSH or Tailscale, or the iPhone/iPad app.
  • The first share asks you to accept the terms. Stopping a share signs out every browser that came through it.

iPhone and iPad

The native app in ios/ is built and installed from Windows + WSL with xtool. A free Apple ID is enough; no Mac or paid developer account. It has Terminals (SwiftTerm, with each agent's state), System, Schedule, Scratchpad and Settings (several PCs, alert sounds). On iPad, projects sit in a sidebar with up to four tiled terminals.

shelldeck on iPad: projects in a sidebar and four tiled terminals (an API server log, a test run, a Vite dev server and a Terraform plan)

iPhone: terminals grouped by project iPhone: a terminal with the Esc, Ctrl, Tab and arrow key bar iPhone: CPU, memory and GPU of the PC, and usage per terminal iPhone: a scratchpad note
Topic How it works
Connecting Scan the share's QR once and allow the device. It is then trusted: it finds every new share by itself, with no QR or approval (the password is still asked). New share addresses reach it through ntfy.sh, encrypted with a key only your PC and the device hold.
End to end The QR carries the PC's public key after #, which never leaves the phone. All app traffic (API, terminals, your password) goes through one X25519 + AES-256-GCM channel to that key; Cloudflare and your Wi-Fi see only ciphertext.
Several devices An iPhone and an iPad on the same Apple ID share their trusted PCs through iCloud Keychain.
Managing The Devices page lists trusted devices and revokes them; a new one raises an alert on the PC.
Free Apple ID limits Reinstall every 7 days (ios/scripts/install.sh); alerts ring only while the app is open.

Setup and installing it for someone else: ios/README.md.

Plain HTTP on a non-local address is refused (--insecure-http overrides), and a first visit from another machine also needs the setup code sd serve prints. On phone browsers a key bar adds Esc, Tab, Ctrl and arrows, and dialogs open as bottom sheets.

Security

Guard What it does
Local only Binds to 127.0.0.1 and rejects requests whose Host or Origin isn't the app, so other websites can't reach your shells. Responses forbid framing, sniffing and referrers.
Password Required. PBKDF2-SHA256 (600k iterations); logins are HttpOnly, SameSite=Strict cookies stored as SHA-256; failed logins slow down; 30 minutes idle locks the browser.
One device at a time Logging in elsewhere takes over and idles the rest; the Devices page revokes any login.
CLI A token file readable only by your account, rotated on every start.
Sharing Shut until you allow a device whose matching code you checked. Through the tunnel, responses send HSTS and the cookie is Secure. Trusted app devices skip only the approval, never the password.
iPhone / iPad Only an end-to-end encrypted channel (X25519 + AES-256-GCM, key pinned from the QR). Neither the tunnel nor ntfy.sh can read or forge it.
Forgot the password On the host: sd login-link (one-time URL, 5 minutes) or sd reset-password. Never from the browser.
Your data ~/.config/shelldeck/ (SHELLDECK_HOME moves it).

Found a vulnerability? Report it privately; see SECURITY.md.

Development

git clone https://github.com/codejunction/shelldeck && cd shelldeck
uv sync
uv run shelldeck --port 5466 serve     # dev server, http://127.0.0.1:5466
uv run pytest -q                       # includes a real PTY round trip
uv run ruff check

FastAPI and uvicorn, pywinpty (ConPTY) or the stdlib pty, SQLite, and plain HTML/CSS/JS with vendored xterm.js (no build step). See CONTRIBUTING.md.

License

MIT. xterm.js is MIT-licensed too (see shelldeck/static/vendor/LICENSE-xterm.txt).

About

Project-first multi-terminal for Windows and Linux. Real shells (PowerShell, cmd, Git Bash, WSL, bash, zsh, fish) grouped by project in your browser, with split or free-floating panes, session restore, git graph, scheduler and code search. One command: sd.

Resources

Code of conduct

Contributing

Security policy

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages