shoka (書架, "bookshelf") is a repository workspace manager
written in Rust — a modern, jj-aware successor to
ghq and
rhq. It clones repos into
a flat <root>/<host>/<owner>/<name> layout, lets you fuzzy-cd
between them, runs commands in parallel across the whole shelf, and
surfaces every repo's working state at a glance via a TUI
dashboard.
Why another one
ghq and rhq nailed "where do I clone things" — but they're
git-only and stop at list / look. shoka picks up from there:
- jj as a first-class VCS alongside git —
shoka clone/execwork for both, noghq-jjshim needed. - TUI dashboard (Phase 2) for the whole shelf at a glance.
- Profiles to keep
work/personal/ossseparated. - Routes for per-org clone destinations + per-route VCS / protocol.
AGENTS.mdaware for AI-heavy workflows (shoka list --has-agents).- ghq layout compatible — drop-in for existing
~/ghq/...trees viashoka import. - In-process git via
gix— nogitsubprocess fan-out, soimportover a large shelf stays fast even on Windows whereCreateProcessdominates the cost.
Install
Pre-built binaries for Linux / macOS / Windows are attached to each GitHub release.
Quick start
# 1. (optional) adopt an existing ghq tree
# 2. or clone fresh
# 3. see what's on the shelf
# 4. jump into one (with the shell wrapper installed — see below)
# 5. run something across everything (or a tag-filtered subset)
Commands
| Command | What it does |
|---|---|
shoka clone <spec> |
Clone a repo via gix (or jj git clone when vcs = jj). Accepts full URLs, owner/name, or host/owner/name. |
shoka import <dir> |
Walk a directory, find existing .git/ repos, and adopt them onto the shelf. |
shoka list |
Print the shelf with optional --tag / --has-agents filters. |
shoka cd [hint] |
Resolve a repo to its on-disk path (use the shell wrapper to actually cd). |
shoka exec -- <cmd> |
Run <cmd> in each matching repo in parallel; output is captured + banner-headed per repo. |
shoka prune |
Drop shelf entries whose clone path is missing on disk. --dry-run to rehearse; --yes to skip the prompt. |
shoka cache {refresh,show,clear} |
Per-repo volatile cache. Auto-refreshed in the background after most commands. |
shoka doctor |
Diagnose environment + config. |
shoka init-shell <shell> |
Print the shell wrapper for cd (see below). |
shoka completion <shell> |
Print a shell-completion script. |
shoka tui |
TUI dashboard — branch / ↑↓ / dirty / PR / CI columns from the cached snapshot; j/k navigation, / for nucleo filter, Enter exits and emits the chosen repo's path so the shell wrapper can cd to it. |
shoka exec is the transparent escape hatch: shoka never
interprets the command. shoka exec -- git fetch, shoka exec -- jj git fetch, shoka exec -- cargo check all work the same way.
Output from each repo is captured and printed as a banner-headed
block when the process exits, so parallel runs don't interleave
into nonsense.
Shell integration for cd
A child process can't change its parent shell's cwd, so shoka cd
prints the chosen path and a small wrapper function does the
actual cd. The wrapper uses a SHOKA_CD_OUT sidechannel file so
the interactive fuzzy picker can render normally while the path
travels out-of-band.
PowerShell
# one-shot (current session):
shoka init-shell powershell --name s | Out-String | Invoke-Expression
# persistent (append to $PROFILE — create it first if missing,
# which it is on a fresh PowerShell install):
if (!(Test-Path $PROFILE)) { New-Item -Type File -Path $PROFILE -Force | Out-Null }
shoka init-shell powershell --name s | Add-Content $PROFILE
. $PROFILE
bash / zsh
# bash — add to ~/.bashrc:
# zsh — add to ~/.zshrc:
fish
# ~/.config/fish/config.fish:
shoka init-shell fish --name s | source
After that, s shoka cds straight into the repo, s with no
arg opens a fuzzy picker, s --tag rust filters before the picker.
Configuration
config.toml lives at the OS-standard config dir (Linux
$XDG_CONFIG_HOME/shoka/, macOS
~/Library/Application Support/yukimemi.shoka/, Windows
%APPDATA%\yukimemi\shoka\config\). A starter is auto-written on
first run.
Minimal example:
[]
= "~/src"
= "github.com"
= "https"
= "auto"
[]
= true
= 60
[[]]
= "host:github.com/mycompany"
= "~/src/work"
= "ssh"
[]
= "github.mycompany.com"
Route patterns support host:<host>, host:<host>/<owner>, and
/<regex>/. The first matching route wins. Profile beats routes
when profile.root is set; otherwise routes evaluate against the
raw [global] baseline.
Files in the same dir matching config.*.toml are layered on top
(alphabetical order; config.local.toml last wins). All values
flow through teravars so
[vars] self-references resolve before deserialization.
Roadmap
- Phase 1 — CLI MVP ✅
clone/import/list/cd/exec/prune/cache, shell integration, completion. Done. - Phase 2 — TUI dashboard ✅
ratatui+crossterm+nucleofuzzy. Per-repo cached status (branch / ahead-behind / dirty) fromgix, open PR count + CI status fromoctocrab. Done. - Phase 3 — Polish. Per-profile route overrides, scaffolding
via
shoka new, bulk org-move follow, OSC 7 cwd hint, contribution-graph column.
Development
PRs go through Gemini Code Assist +
CodeRabbit reviewers on top of standard
CI. The yukimemi/* convention is:
renri worktrees + kata apply for the shared template, see AGENTS.md for
the details.
License
MIT — see LICENSE.