Skip to content

zac15987/zpit

Repository files navigation

Zpit

Zpit (zac + cockpit) — a TUI-based AI development cockpit that orchestrates Claude Code agents across multiple projects. Zpit acts as a dispatch center — it selects projects, launches agents in separate terminal windows, monitors their progress, coordinates the full issue lifecycle from requirement clarification to PR, and enables real-time cross-agent communication via a built-in HTTP broker + MCP channel.

Key principle: Claude Code runs in independent terminal windows. Zpit never wraps or embeds it — it monitors via session logs, coordinates via issue trackers, and bridges agents via a local channel broker.

TUI Preview

Main View

Four independently scrollable dock panels — Projects, Active Terminals, Loop Engine (left column, stacked), Hotkeys (right column). Catppuccin Mocha palette with a single-column mauve bar marking the focused panel.

 Zpit v0.1                                            04/19 15:04  Windows Terminal


▎ PROJECTS  7                                         HOTKEYS
  ──────                                              ──────
  › AI Inspection Cleaning Demo  ⚪ not deployed     [Enter] Launch Claude Code
     machine │ wpf, ethercat, basler                  [c] Clarify requirement
                                                      [l] Loop auto-implement
    ENR DUC  ⚪ not deployed                          [r] Review changes
     machine │ wpf, secsgem                           [f] Efficiency agent
                                                      [s] Status overview
    DisplayProfileManager  ⚪ not deployed            [o] Open project folder
     desktop │ wpf, nlog                              [i] Open Issue Tracker
                                                      [p] Open PR
    Zpit  🟢 deployed                                 [u] Undeploy agents
     terminal │ go, bubbletea                         [d] Redeploy all agents
                                                      [m] Channel communication
    Zplex  ⚪ not deployed                             [g] Git status
     desktop │ go, electron, xterm                    [G] Open lazygit
                                                      [U] Run claude update
    Zacfuse  🟢 deployed                              [a] Add project
     web │ astro, typescript, docs                    [e] Edit config
                                                      [x] Close Terminal
                                                      [Tab] Switch Panel
  ACTIVE TERMINALS  1                                 [?] Help
  ──────                                              [q] Quit
  ›[1] Zpit │ 🟡 Waiting for input 00:15
      Q: Commit 2198be6 pushed to `origin/dev`, working tre


  Press ? for help, q to quit

Tab cycles focus between Projects → Active Terminals (when any) → Loop Engine (when any slot exists); Hotkeys stays docked to the right as read-only reference. ↑↓/PgUp/PgDn scroll the focused panel only; mouse wheel scrolls whichever panel the cursor hovers. Below ~40 cols the left/right widths auto-shrink, but Hotkeys never drops below the other panels.

Status View

 Zpit v0.1                                        03/27 14:04  Windows Terminal


  Issues — AI Inspection Cleaning Demo
  ────────────────────────────────────────────────────────────

 › #25   [pending] feat(manual-control): Safety Interlock + Soft Limit + Reset Zero




  [y] Confirm (pending→todo)  [i] Open in browser  [Esc] Back

How It Works

You (TUI)                    Claude Code Agents
    │
    ├─ [c] Clarify ──────────► Clarifier agent (new terminal)
    │   requirement              asks questions, creates structured issue
    │   (press multiple times)   agents auto-discover via agent_type, enter Facilitator/Advisor meeting mode
    │
    ├─ [l] Loop ──────────────► Coding agent (worktree + new terminal)
    │   auto-implement           implements, commits, opens PR
    │        │
    │        └─ PR appears ───► Reviewer agent (same worktree)
    │             │              checks AC, writes review report
    │             ├─ PASS ────► waits for human merge
    │             └─ NEEDS CHANGES → auto-retry coding (up to N rounds)
    │
    ├─ [s] Status ────────────► shows issue list from tracker
    ├─ [r] Review ────────────► launches reviewer on demand
    ├─ [f] Efficiency ────────► lightweight agent (no hooks, no tracker, self-review)
    ├─ [d] Redeploy ──────────► undeploy + re-write all agents/hooks/docs (no launch)
    └─ [Enter] ───────────────► launches Claude Code directly

Features

  • Multi-project dashboard — switch between projects with arrow keys, mouse scroll support
  • Loop engine — fully automated: poll todo issues → create worktree → coding agent → reviewer → PR merge → cleanup
  • Task decomposition — when an Issue Spec contains ## TASKS, the coding agent delegates to task-runner subagents (sequential, or parallel batches with per-subagent isolation: "worktree")
  • Agent monitoring — real-time status via session log parsing (Working / Waiting / Permission / Ended), auto-detects running sessions on startup, survives /resume session switches
  • Notifications — Windows Toast + sound when an agent needs your input or awaits tool permission
  • Issue tracker integration — Forgejo/Gitea and GitHub via REST API + MCP
  • Cross-agent channel — real-time agent-to-agent communication via HTTP broker + MCP; supports same-project, cross-project, and global broadcast messaging
  • Meeting mode — multiple clarifier agents auto-discover via agent_type tracking, assign Facilitator/Advisor roles, and converge to a structured issue through coordinated channel communication
  • 5-layer safety system — agent-guidelines.md, allowed tools, PreToolUse hooks, git worktree isolation, human PR review
  • Per-issue branch control — clarifier asks target branch, coding agent enforces it
  • Auto-retry — reviewer judges NEEDS CHANGES → coding agent auto-fixes → re-review (configurable rounds)
  • i18n — TUI chrome localized to English or Traditional Chinese (zh-TW) via locale.T(); all agent output (Issue Specs, commits, PR bodies, channel messages) is always English regardless of TUI locale, for token efficiency
  • Per-role model selection[agent_models] lets you choose a model per agent role (defaults to Opus across all roles with 1M context, tuned for single-round coding→review accuracy); override any value in config
  • SSH remote accesszpit serve runs a headless SSH daemon (Wish), multiple clients share one dashboard with real-time state sync; auto_serve mode starts the server automatically when running zpit, enabling seamless mobile access without workflow interruption
  • Desktop agent[w] launches a global Claude Code session that drives the OS (mouse, keyboard, screenshots, accessibility actions) through a policy-enforced MCP proxy. Backed by zpit-desktop-mcp, our fork of @zavora-ai/computer-use-mcp. Single-instance, macOS + Windows only.

Session sync (cross-machine /resume)

When you work across multiple machines (laptop at home, desktop at the office) and want to continue a long Claude Code conversation on the other machine, the session JSONL file is the unit of replay — but Claude Code's ~/.claude/projects/<encoded-cwd>/ directory uses an OS-specific encoded folder name and embeds the absolute project path inside every session line. A naive file copy is invisible to claude --resume on the other side.

Zpit's [h] History view bridges this. From the main dock press h to open the Session Browser:

  • Top level: every encoded folder under ~/.claude/projects/. Each row shows session count, total size, last-modified time, and a 🟢 marker when at least one session is currently alive on this machine.
  • Drill into a folder: every *.jsonl session with multi-select checkboxes. 🧩 marks sessions that have a sibling <id>/subagents/ directory; 🟢 marks live sessions.

Export

In the session list, select one or more sessions with Space (or [a] to toggle all). Press [e] to export. Zpit warns if any selected session is currently active (informational — you can still proceed) and writes a zip bundle containing:

  • One <session-id>.jsonl per selected session at the zip root.
  • One <session-id>/subagents/ subtree per selected session that has subagents on disk (preserved verbatim).
  • A manifest.json describing the source OS and absolute project path so the importer can rewrite paths.
  • Optionally a memory/ subtree (opt-in via the [ ] Include memory/ checkbox at export time — off by default to avoid leaking project-private notes).

Default output path: ~/.zpit/exports/<folder-name>-<YYYYMMDD-HHMMSS>.zip.

You can also press [E] (capital) on a folder row in the top-level view to export every session in that folder in one shot.

Import

From the top-level folder list, press [i] (or select the [+] Import bundle... row + Enter) to open the import wizard. Steps:

  1. Bundle path entry — type the path to a .zip produced by the exporter above.
  2. Manifest preview — Zpit reads manifest.json and shows source OS, source path, session count, memory inclusion. Per-session checkboxes let you deselect individual sessions.
  3. Destination path — type the absolute path of the destination project on this machine.
  4. Final preview — Zpit shows the resolved ~/.claude/projects/<dest-encoded>/ and the action plan. Confirm to run.
  5. Run — Zpit rewrites cwd fields in each session JSONL line to the destination path (only the JSON cwd field, never literal path text in chat content), copies subagents verbatim, and optionally writes memory/ if the bundle included it.

If the destination already has a session with the same ID, you get a 3-button collision modal: Overwrite, Skip this session, or Cancel entire import. The same prompt applies to the memory/ directory.

After import, claude --resume <session-id> on this machine sees the new file.

Bundle format

The zip bundle contains:

<bundle.zip>
├── manifest.json                     # format_version, source_os, source_cwd,
│                                     # source_encoded_cwd, sessions[], exported_at,
│                                     # include_memory
├── <session-id>.jsonl                # one per session (lines streamed)
├── <session-id>/subagents/...        # one per session with subagents (verbatim)
└── memory/...                        # only when include_memory=true

source_cwd is sourced from any session line's cwd field when available; only when no line has one does the exporter fall back to a lossy reverse-derivation of the encoded folder name.

Requirements

  • Go 1.26+
  • Claude Code CLI installed and authenticated
  • Windows Terminal (Windows) or tmux (Linux/WSL)
  • A Forgejo/Gitea or GitHub issue tracker

Quick Start

# Build
go build -o zpit .

# First run — creates config template at ~/.zpit/config.toml
./zpit
# Edit the config with your projects and tracker tokens, then:
./zpit

# SSH server mode (remote access)
./zpit serve      # Start headless SSH daemon (default port 2200)
./zpit connect    # SSH connect to local server

# Or enable auto_serve in config — then just "./zpit" starts
# the SSH server automatically and connects to it.
# You can SSH in from your phone at any time.

Configuration

Config lives at ~/.zpit/config.toml. Override with ZPIT_CONFIG env var.

language = "en"             # en | zh-TW
broker_port = 17731         # HTTP broker port for cross-agent channel
# zpit_bin = "/usr/local/bin/zpit"  # explicit binary path for .mcp.json generation

[terminal]
windows_mode = "new_tab"    # new_tab | new_window
tmux_mode = "new_window"    # new_window | new_pane
# windows_terminal_profile = "PowerShell 7"  # WT profile name for -p flag

[notification]
tui_alert = true
windows_toast = true
sound = true
# sound_file = "D:/sounds/notify.mp3"  # custom notification sound (WAV/MP3/M4A/OGG)
re_remind_minutes = 2

[worktree]
base_dir_windows = "D:/worktrees"
base_dir_wsl = "/mnt/d/worktrees"
max_per_project = 5
poll_seconds = 10           # todo issue polling interval
pr_poll_seconds = 10        # PR merge polling interval (only used when auto_merge = false)
max_review_rounds = 3       # auto-retry rounds before needs-human
# dir_format = "{project_id}/{issue_id}--{slug}"
# auto_cleanup = false

# Per-role model selection — passed to Claude Code via --model at launch.
# Aliases (opus/sonnet/haiku) resolve per provider; append [1m] to opt
# into the 1M-context tier. Pin to a full ID (e.g. claude-opus-4-7[1m])
# if you need cross-provider consistency.
[agent_models]
clarifier = "opus[1m]"      # requirement clarification — deepest reasoning (1M context)
coding = "opus[1m]"         # feature implementation (1M context)
reviewer = "opus[1m]"       # PR review (1M context)
task_runner = "opus[1m]"    # advisory — subagents inherit the coding session's model
efficiency = "opus[1m]"     # efficiency-review agent (manual [f]) — deep reasoning

# Tracker providers — token read from env var, never stored in config
[providers.tracker.my-forgejo]
type = "forgejo_issues"
url = "https://your-forgejo.example.com"
token_env = "FORGEJO_TOKEN"

# Git providers (optional — for Forgejo/Gitea PR API)
# [providers.git.my-forgejo]
# type = "forgejo"
# url = "https://your-forgejo.example.com"
# token_env = "FORGEJO_TOKEN"

# Projects
[[projects]]
name = "My Project"
id = "my-project"
profile = "machine"         # display tag: machine | desktop | web | android | terminal (for TUI icon)
hook_mode = "strict"        # strict | standard | relaxed
log_policy = "standard"     # strict | standard | minimal — agent logging strictness
tracker = "my-forgejo"
# tracker_project = "My_Project"  # tracker project name if different from repo
# git = "my-forgejo"              # git provider for PR operations
repo = "org/repo"
base_branch = "dev"
channel_enabled = false     # enable cross-agent channel communication
channel_listen = []         # subscribe to other projects' events, e.g. ["_global", "other-proj"]
# auto_merge = false      # when true, Zpit calls the tracker merge API after ai-review PASS (opt-in)
# merge_method = "squash"  # squash | merge | rebase (used when auto_merge = true)
tags = ["go"]

[projects.path]
windows = "D:/Projects/my-project"
wsl = "/mnt/d/Projects/my-project"

# SSH server (optional — for remote TUI access)
# [ssh]
# port = 2200
# host = "0.0.0.0"
# host_key_path = "~/.zpit/ssh/host_ed25519"
# password_env = "ZPIT_SSH_PASSWORD"
# authorized_keys_path = "~/.ssh/authorized_keys"
# auto_serve = false    # when true, "zpit" auto-starts SSH server + connects

Hotkeys

Key Action
Enter Launch Claude Code in new terminal
c Clarify — open clarifier agent to create structured issue
l Loop — toggle automated coding + review cycle
r Review — launch reviewer agent
f Efficiency — lightweight agent (no hooks, no tracker, self-review)
s Status — view issue list from tracker
o Open project folder
i Open issue tracker in browser
p Open pull request in browser (in Loop Slot focus: the slot's PR; falls back to /pulls?head=<branch> if not yet open)
u Undeploy — remove deployed agents, docs, hooks
d Redeploy — undeploy then re-write all 4 agents + hooks + docs (no Claude launch)
m Channel — view cross-agent communication events
g Git Status — view branches (local + remote-only) and commit graph; [f] fetch, [p] pull (--ff-only)
G Open lazygit in new terminal (project root; in Loop Slot focus: slot's worktree)
U Run claude update in new terminal (stays open to show result)
a Add project (coming soon)
e Edit config — sub-menu: toggle channel, edit channel_listen, open in $EDITOR
w Window — launch desktop agent (macOS + Windows only; single instance across all clients)
x Close Terminal — force-close selected terminal (when Terminals panel focused)
Tab Switch focus between panels (Projects, Terminals, Loop Slots)
? Help
q Quit

Loop Engine

The loop engine automates the full coding cycle:

  1. Poll tracker for todo issues (configurable interval)
  2. Create worktree — isolated git worktree from base_branch
  3. Launch coding agent — writes implementation, commits, opens PR, sets review label
  4. Detect completion — polls issue labels for review (agents don't need to exit)
  5. Launch reviewer — checks acceptance criteria, writes review report, sets verdict label
  6. Detect verdict — polls issue labels for ai-review (PASS → wait for human merge) or needs-changes (auto-retry up to max_review_rounds)
  7. Cleanup — after PR merge, removes worktree and branch

Multiple issues run in parallel, limited by max_per_project.

Safety System

Zpit enforces 5 layers of safety to prevent agents from causing damage:

Layer Mechanism Scope
1 agent-guidelines.md behavioral rules Soft — agent reads on startup
2 --allowedTools per agent role Medium — Claude Code enforced
3 PreToolUse hooks Hard — enforced even with --bypass-all-permissions
4 Git worktree isolation Physical — agents can't touch main repo
5 Final merge gate (conditional) When auto_merge = false (default): human PR review is the final gate. When auto_merge = true: the AI reviewer's ai-review PASS label replaces the human gate and triggers the tracker's merge API. Only enable auto_merge when you trust the reviewer model quality on your repo.

PreToolUse hooks:

  • path-guard.sh — confines Write/Edit to worktree directory
  • bash-firewall.sh — blocks destructive commands (rm -rf, curl|bash, force push, etc.)
  • git-guard.sh — push whitelist (only feat/* branches), blocks merge, rebase, branch-delete, force push

Notification hook:

  • notify-permission.sh — writes signal file when Claude Code needs tool permission approval; TUI detects and shows 🟠 status + toast notification

Hook strictness is per-project: strict (all hooks), standard (path-guard + git-guard), relaxed (git-guard only). Notification hook is always active in all modes.

Issue Spec Format

The clarifier agent produces structured issues:

## CONTEXT
[Problem description with specific file names and behavior]

## APPROACH
[Selected solution + reasoning]

## ACCEPTANCE_CRITERIA
AC-1: [Specific, verifiable condition]
AC-2: ...

## SCOPE
[modify] path/to/file (reason)
[create] path/to/new-file (reason)

## CONSTRAINTS
[Hard limits]

## BRANCH
[Optional: PR target branch, defaults to project base_branch]

## TASKS
[Optional: Task decomposition — triggers subagent delegation]
T1: [task description] | [modify] path/to/file
T2: [task description] [P] | [modify] path/to/other  # [P] = parallelizable
T3: [task description] [depends:T1] | [create] path/to/new

## COORDINATES_WITH
[Optional: Cross-agent coordination for parallel work]
#42: Brief description of related issue

## REFERENCES
[Optional: URLs, related files]

Development

go build ./...           # Build
go test ./...            # Run all tests
make test-hooks          # Run hook tests (requires bash)
go run .                 # Local TUI (or auto-serve if ssh.auto_serve=true)
go run . serve           # SSH server mode
go run . connect         # SSH client shortcut

Logs: ~/.zpit/logs/zpit-YYYY-MM-DD.log — daily rotation, 30-day retention.

Desktop Agent

Press [w] from the main view to launch the desktop agent — a standalone Claude Code session that controls the operating system (mouse, keyboard, screenshots, window/app management, accessibility actions). Unlike project-scoped agents, it is global (cwd = $HOME / %USERPROFILE%) and limited to one active instance across all connected TUI clients.

The desktop agent is backed by zpit-desktop-mcp — our fork of @zavora-ai/computer-use-mcp by James Karanja Maina / zavora.ai. The fork adds Windows AUMID launch support in open_application, a stdio-entrypoint fix for Windows backslash paths, and tracks the upstream @modelcontextprotocol/sdk Zod 4 bump. Many thanks to the upstream authors — none of this would exist without their original work.

Safety is enforced by zpit serve-desktop-proxy, a Go MCP proxy that sits between Claude Code and the npx zpit-desktop-mcp subprocess. Every JSON-RPC tools/call frame is intercepted, evaluated against ~/.zpit/desktop-policy.toml (auto-created on first run), and either forwarded or rejected with a structured error. Hard-blocked tools include run_script, filesystem, process_kill, registry, notification, and all virtual-desktop tools; deny_keys blocks OS-level escape hatches like win+r, ctrl+alt+del, and alt+f4. The conventional 5-layer hook stack does not apply to the desktop agent — the proxy is the safety layer.

Platform support: macOS and Windows. On Linux, [w] is a no-op (the upstream Rust NAPI module has no Linux backend).

See docs/architecture/desktop-agent.md for the full design rationale (why proxy over hooks, tool-by-tool allowlist justification, default deny_keys per platform).

Architecture

See docs/architecture/ for the full architecture documents (split by topic, with an index).

Open Source Attributions

Zpit is built on top of the following open source libraries:

Library Purpose License
Bubble Tea TUI framework MIT
Bubbles TUI components (list, text input, etc.) MIT
Lip Gloss TUI styling and layout MIT
Huh Form and confirm dialogs MIT
Wish SSH server for TUI remote access MIT
BurntSushi/toml TOML config parser MIT
fsnotify Filesystem watcher (session log monitoring) BSD-3-Clause
go-colorful Color math for terminal rendering MIT
muesli/termenv Terminal environment detection MIT
rivo/uniseg Unicode text segmentation MIT
mattn/go-runewidth Rune display width calculation MIT
bubbletea-overlay Overlay rendering for confirm dialogs MIT
golang.org/x/sys, x/text Go extended standard library BSD-3-Clause

All Charmbracelet libraries (bubbletea, bubbles, lipgloss, huh, wish, ssh) are copyright © Charmbracelet, Inc., licensed under the MIT License. fsnotify and golang.org/x/* are BSD-3-Clause; their copyright notices are retained as required.

Desktop agent — upstream credit

The [w] desktop agent is backed by zpit-desktop-mcp, our fork of @zavora-ai/computer-use-mcp (forked at v6.1.0). The original computer-use-mcp package — including the Rust NAPI native backend, the MCP server scaffolding, and the full macOS + Windows toolset — is the work of James Karanja Maina / zavora.ai, released under the MIT License. Zpit's fork adds Windows AUMID launch support, the stdio-entrypoint backslash fix, and the SDK Zod 4 bump; everything else is upstream. Sincere thanks to the zavora.ai team for making this layer of zpit possible.

Package Purpose License
zpit-desktop-mcp (zpit fork) Desktop-control MCP server for the [w] agent MIT
@zavora-ai/computer-use-mcp (upstream) Original MCP server + Rust NAPI native backend MIT

License

MIT

About

TUI-based AI development cockpit that orchestrates Claude Code agents across projects with automated issue lifecycle, cross-agent channel communication, and a 5-layer safety system.

Topics

Resources

License

Stars

Watchers

Forks

Contributors

Languages