auto-discoveredEdit on GitHub

Coco Workspace

coco workspace (alias: coco ws) is a multi-repo overview TUI. It scans your configured root directories, surfaces each repository's branch / dirty / ahead-behind / last-commit / open-PR data in a single sortable table, and lets you drill into any one as a full coco ui session — with the cursor returning to the same repo on exit.

If coco ui is the "deep view" of a single repository, coco workspace is the "wide view" across all of them. Use it when you switch context between 3–10 projects in a typical week and want one screen to see what needs attention.

Start The Workstation

bash
1# Default: scan the current directory (or workspace.roots, if configured)
2coco workspace
3
4# Alias
5coco ws
6
7# Override the root list inline (repeatable)
8coco workspace --root ~/code --root ~/work
9
10# Cap the recursion depth into each root (default 3)
11coco workspace --max-depth 2
12
13# Force a theme preset
14coco workspace --theme catppuccin
15NO_COLOR=1 coco workspace

The discovery walks each root, identifies git working trees (regular .git/ dirs, worktree pointer files, submodules), prunes node_modules / dist / build / hidden dirs, and stops descending the moment a directory is identified as a repo.

On a non-TTY (CI logs, piped output), coco workspace prints a plain repo list and exits.

Layout

┌────────────────────────────────────────────────────────────────────┐ │ coco · workspace · ~/code · 64/64 repos · sort: Recent · [List] │ ├──────┬─────────────────────────────────────────────────────────────┤ │ Tabs │ Workspace 64 visible │ │ │ REPO BRANCH STATUS LAST SUBJECT PATH │ │ │ │ │ ○ All 64 │ ↵ coco main ●2 ↓3 2d feat: thing ~/co… │ │ ● Dirty 3│ github-prof. main 2d Add localpr… ~/co… │ │ ↓ Behind 12│ BinWars main 3d Merge pull … ~/co… │ │ ⊙ PRs 5│ … │ ├──────┴─────────────────────────────────────────────────────────────┤ │ s sort · / filter · r/R refresh · a add · d remove · ? help · q │ │ │ └────────────────────────────────────────────────────────────────────┘
  • Header: chip-style identity row — coco · workspace · <roots> · N/M repos · sort: <mode> · [<focus>]. Identity + focus chips render in the accent color; chrome stays muted.
  • Sidebar (Tabs): four filter tabs — All / Dirty / Behind / PRs — each with a glyph (◯ ● ↓ ⊙) and a count. Below 100 columns the sidebar collapses to a 4-cell rail showing just the glyphs; tab focus expands it back.
  • Main panel (Workspace): the repo table. Columns adapt to the terminal width — drop priority is path → subject → date → branch → status (status is kept longest because it's the most actionable signal).
  • Footer: keymap hint on the first line, status line below (refreshed on workflow outcomes — Refreshed 64 repos., Added /Users/me/code/x.).

When discovery is in flight, every row that's still waiting for its gh pr list call gets a Braille spinner (⠋ ⠙ ⠹) in the status cell. The spinner drops as each row's data lands.

Focus Model

Two focusable panels mirror coco ui:

FocusKeysWhat they do
List (default)j / k / / Move the cursor through repos
g / GJump to top / bottom
enterDrill into the cursored repo (opens coco ui)
h / Jump focus to the sidebar
Tabsj / kCycle the active tab
enter / l / Jump focus back to the list
tab / shift-tab (any)Toggle focus between sidebar and list

Modal focuses (filter, add-repo, confirm-delete) own the input until dismissed with esc.

Keymap

The full keymap also lives behind ? inside the app.

Navigate

KeysAction
j / k / / Move cursor (list) · cycle tab (sidebar)
tab / shift-tabToggle focus between sidebar and list
h / Jump focus to the sidebar
l / Jump focus to the list
g / GJump to top / bottom of the list
enterDrill into the cursored repo (coco ui)

Filter & sort

KeysAction
/Filter the list by name or branch
sCycle sort mode (recency → name → dirty)

Repos

KeysAction
rRefresh all repos (discovery + PR counts)
RRefresh just the cursored repo (faster)
aAdd a repo via path prompt (tab-completes)
cClone a remote repo (URL → destination prompt; adds it on success)
dRemove the cursored repo from the known-repos store (y-confirm)

General

KeysAction
?Toggle the help overlay
escClear filter · close overlay · cancel prompt
q · ctrl+cQuit the workspace surface

Drill-In Loop

Pressing enter on a repo:

  1. Captures the current sort / tab / filter / cursor position
  2. chdirs into the repo
  3. Mounts coco ui for that repo (history view by default)
  4. When you quit ui, restores cwd and re-mounts the workspace surface with the cursor anchored back on the same repo

The glyph in the cursor column is a hint that pressing enter will drill in — the cursored row is the one that gets opened.

Sort & Filter

Sort modes (cycled with s):

  • Recency (default): newest commit first. Best for "what have I touched this week?"
  • Name: alphabetical. Best for memory / muscle-memory navigation.
  • Dirty: most working-tree changes first. Best for "what needs commits before EOD?"

Filter (/): case-insensitive substring match against repo name, branch, and path. Live-updates as you type. Press enter to commit, esc to cancel and restore the cursor to where it was before filtering.

Sidebar tabs filter on top of the sort + free-text filter:

  • ◯ All (default) — every repo
  • ● Dirty — repos with uncommitted changes
  • ↓ Behind — repos behind their upstream
  • ⊙ PRs — repos with open pull requests (requires gh authenticated; tab dims when not)

Adding & Removing Repos

Three ways to populate the workspace:

  1. workspace.roots in .coco.config.json — directories to walk. When unset (and no --root flag), the workspace scans the current working directory — so a bare coco / coco ws discovers repos wherever you launched it. Pin this (e.g. ["~/code"]) for a fixed tree regardless of where you run from.
  2. Add-repo prompt (a) — type a path, tab to complete. Supports ~/ prefix and walks the filesystem to suggest matching directories. Validates the path is a git working tree before adding. Saved per-user to ~/.cache/coco/workspace/known-repos.json (separate from your config file so the tool doesn't mutate something you might be version-controlling).
  3. Clone prompt (c) — clone a remote you don't have yet. A two-field prompt takes the URL (https://… or git@…) and the destination (pre-filled with <launch-dir>/<repo-name> derived from the URL, editable with tab-completion). Enter on the URL advances to the destination; Enter there clones. It refuses to overwrite an existing path, shows a Cloning… state while it runs, and on success drops the new repo into the list with the cursor on it — same as the add flow.

Remove an added repo with d (y-confirm). Only entries in the known-repos store can be removed via the prompt — repos discovered via workspace.roots get a status hint pointing you at the config.

Configuration

In your .coco.config.json:

jsonc
1{
2  "workspace": {
3    "roots": ["~/code", "~/work"],
4    "knownRepos": ["~/oss/coco"],
5    "maxDepth": 3
6  }
7}
FieldDefaultDescription
workspace.rootscurrent directory (cwd)Directories the discovery walks. Defaults to wherever you launched coco when unset; set it to pin a fixed tree.
workspace.knownRepos[]Explicit repo paths to include regardless of discovery. Merged with the per-user add-repo store.
workspace.maxDepth3Cap on recursion depth into each root.

Per-launch state — sort mode, sidebar tab, filter text — persists to ~/.cache/coco/workspace/preferences.<root-hash>.json so reopening the workspace lands where you left it. Two different workspace.roots configurations keep separate preferences (no collision).

Performance & Resilience

  • Three-stage boot: paint cached repo list immediately → mount Ink → run fresh discovery + PR fetch in the background. No "loading…" spinner on cold start once you've used it once.
  • gh pr list per-call timeout: 5s per repo, with AbortController killing the child process if it hangs. One slow repo can't stall the rest of the overview.
  • Concurrency-bounded: discovery and PR fetches run with at most 4 (PR) / 8 (discovery) workers in flight.
  • Best-effort persistence: every cache / preference / known-repos write swallows errors. A read-only $HOME or sandbox never blocks boot.
  • gh unavailable: the PRs tab dims, the PR badge column hides, and a one-line status notifies the user once.

Troubleshooting

  • "No repositories discovered". By default the workspace scans your current directory — cd to a folder that contains git repos, set workspace.roots in config, pass --root <dir>, or press a to add one by path. Common cause: launching from a directory with no git repos beneath it.
  • PR counts don't show up. Check gh auth status. If unauthenticated, the PRs tab dims and the per-row PR badge stays hidden until you log in.
  • yarn dev workspace restarts the app on every keypress. tsx watch intercepts Return and Ctrl+C before forwarding to the child. Use yarn dev:tui workspace instead — same code, no watch wrapper.
  • Workspace looks slow on a network filesystem. Lower workspace.maxDepth, or move the workspace cache off the network mount with XDG_CACHE_HOME=/local/path.

Related

  • Coco UI — single-repo full-screen workstation. coco workspace drills into coco ui.
  • Configuration Overview — full schema for .coco.config.json including the workspace.* section.