Most developer tooling is built for single-repo workflows. Your framework CLI scaffolds one project. Your test runner watches one directory. Your IDE opens one workspace. That’s fine when your world is one repo.

Mine isn’t. I regularly work across 40+ repositories: mobile apps, web frontends, backend APIs, infrastructure, shared libraries. Different languages, different deploy targets, different teams. The friction isn’t in any single repo. It’s in the space between them.

So I built a workspace CLI. I mentioned it briefly in The Terminal Renaissance as “multi-repo orchestration.” This is the deep-dive on what that actually looks like as a daily driver.

The Problem With Multi-Repo

The obvious pain is git operations. Running git pull in 40 directories is tedious. But the deeper problem is context: which repos have uncommitted work? Which branches am I on? When did I last touch that service three directories over?

Standard tools don’t help. git status works per-repo. Your IDE’s git panel shows one project. You end up with a mental model that’s always slightly stale, and that staleness costs you time in ways that are hard to measure but impossible to ignore.

The friction isn’t in any single repo. It’s in the space between them.

What It Does

The CLI groups into a few areas that each solve a different kind of friction.

Workspace awareness

A single status command shows every repo in a table: current branch, dirty state, ahead/behind counts, last commit date. pull rebases all of them. switch gives you an interactive recent-branch picker scoped to whichever repo you’re in. It sounds simple because it is. But having a single view of 40 repos changes how you think about your workspace.

Local dev stacks

Running the platform locally means orchestrating multiple services: APIs, workers, databases, emulators. Different combinations depending on what you’re working on. The run command lets you spin up a named stack in one shot. Backend APIs, frontend workers, mobile simulators, delivery services: each stack knows which repos to build, which containers to start, and how to wire them together.

Logs from every service pipe into a single stream, which matters more than you’d think. When an agent is debugging an integration issue, it can read the combined output across services instead of guessing which container to check. One command to start, one stream to watch.

Linear integration with directory awareness

This is where things get interesting. The CLI maps each repo to its Linear project and team. When you run an issue command from inside a repo directory, it already knows which project you’re working in. No flags needed.

Creating an issue, checking project progress, commenting on a ticket: all zero-config when you’re in the right directory. The CLI resolves teams, users, milestones, and labels with fuzzy matching, so you don’t need to memorize UUIDs.

The default command (no subcommand) generates a project dashboard: progress bars for active projects, team member activity breakdowns, and AI-generated one-liner summaries per project. It’s become our standup replacement.

AI-powered timesheets

This one surprised me with how useful it became. The report command scans your commits across all repos for a given period and generates a timesheet CSV. Each day’s commits get sent to an LLM that writes business-language descriptions: “Implemented order validation for the ecommerce checkout flow” instead of “fix: null check on cart items”.

The team version takes it further. It scans every team member’s commits, then classifies them against a list of project codes with percentage allocations. A month of work across 40 repos, distilled into a table of project codes and percentages. What used to take a full afternoon of manual categorization now takes about 90 seconds.

Holiday redistribution

The timesheet handles public holidays by redistributing any commits on those days to adjacent business days. It also supports partial-day overrides for people on flexible schedules. Small details, but they’re the difference between a tool you tolerate and one you trust.

Agent config distribution

This ended up being the most impactful feature, and I didn’t expect that when I built it.

Every repo in the workspace needs Claude Code configuration: safety hooks that prevent force-pushes, skills that describe the ecosystem architecture, shared context about workflows. Committing these to each repo isn’t practical. 40+ repos, each with their own PR review process, for config that changes centrally.

The solution: a claude-shared/ directory in the workspace root containing hooks, skills, and a shared settings template. During workspace init, the CLI creates symlinks in each repo’s .claude/ directory pointing back to the shared source. The symlinked paths get added to each repo’s .git/info/exclude so they never pollute git status or get accidentally committed.

The merge logic for settings is versioned: it strips old shared hooks, preserves repo-specific hooks, injects the current shared set, and bumps a version number to prevent redundant processing. It handles worktrees, malformed JSON recovery, and migration from old naming schemes.

The result: I update a skill file once, and every repo in the workspace picks it up immediately. No PRs, no syncing, no drift. And for new team members, onboarding is install the CLI, run init, and you’ve got 40+ repos cloned with shared agent config already in place.

The symlink trick

Using .git/info/exclude instead of .gitignore means the shared config is invisible to version control without modifying any tracked files. Each repo’s .gitignore stays clean, and the shared artifacts exist only on machines that have the workspace CLI installed.

A tool for agents, not just humans

The shared skills don’t just describe the ecosystem. They teach agents how to use the CLI itself. An agent working in any repo knows it can run workspace commands to create Linear issues, check project status, look up other repos, or follow BAU workflows. It doesn’t need to be told. The skill is already there.

This changes the shape of what you delegate. Triaging a support ticket, creating and linking sub-issues across projects, checking what’s stale on the board: these become things you hand to an agent with a one-line prompt. The CLI is the interface layer that makes the workspace legible to agents the same way it’s legible to you.

Building a CLI that agents can drive turns out to be one of the highest-leverage things you can do. Every command you add for yourself is a command agents can use too.

What It Doesn’t Solve

Being honest about the costs:

  • Maintenance burden - The CLI is another piece of software to maintain. When Linear changes their API, when a new repo gets added, when the shared hooks need updating: that’s on you.
  • Feature creep - The temptation to keep adding commands is real. Every workflow annoyance looks like a nail when you’re holding a CLI hammer. I’ve had to deliberately stop myself from building features that would be used once a quarter.
  • Symlink fragility - Symlinks break when directories move. If someone restructures the workspace layout, every repo’s shared config breaks until they re-run init.

Why It Compounds

The individual features are useful but not revolutionary. Git status across repos is a shell script. Linear queries are API calls. Timesheets are data munging. What makes the CLI valuable is the compound effect.

When your workspace tool knows about your repos AND your project tracker AND your team members AND your AI agent configuration, things connect. The timesheet command works because the CLI already knows every repo and can scan all of them. The Linear integration works zero-config because the CLI already has a repo-to-project mapping. The agent config distribution works because init already touches every repo.

Each feature becomes a building block for the next one. That’s the real return on building a workspace CLI instead of a collection of scripts.

The best developer tools don’t add capabilities. They remove the micro-friction that makes you avoid doing the right thing.
— Six months of daily use

Lessons Learned

  • Start with status, not automation. The first command I built was status. Seeing the whole workspace at a glance changed my workflow more than any automation did.
  • Auto-detect everything you can. The Linear integration became 10x more useful when it started reading the current directory instead of requiring flags. Zero-config for the common case, flags for the edge case.
  • AI is best at translation, not creation. The timesheet’s AI doesn’t write content. It translates git commits into business language. That’s a much more reliable use of LLMs than open-ended generation.
  • Symlinks over copies. Copying shared config creates drift. Symlinks create a single source of truth. The tradeoff is fragility, but in practice the fragility is manageable and the consistency is invaluable.
  • Version your merge logic. When you’re programmatically modifying config files across dozens of repos, you need idempotency and migration paths. A simple version number in the output file saved me hours of debugging.

If you’re working across more than a handful of repos and spending time on the glue between them, a workspace CLI might be worth the investment. Not as a product. As infrastructure for your own velocity.