AI/workspace-harness.md

Workspace Harness

An opinionated workflow for building within a connected set of repositories, leveraging AI agents with cross-repo context.

Philosophy

A workspace harness (not a monorepo build — you're not bundling these together) keeps related repos discoverable, bootable, and consistent. Each repo keeps its own identity, build, and deploy config; the workspace is just the folder that holds them plus shared glue:

  • One init script to clone everything and set up tooling.
  • One CLI to start/stop/log all dev servers.
  • One .gitignore that hides repo folders from the editor's file-finder.
  • One AGENTS.md that tells AI agents how the pieces fit together.
  • One docs/ folder for cross-repo documentation.

Directory Layout

workspace/
├── README.md           # Workspace overview, quick-start, app table
├── AGENTS.md           # Instructions for AI agents
├── .gitignore          # Ignores cloned repos — keeps file-finder clean
├── scripts/
│   ├── init.sh         # Clone all repos, install tooling
│   └── app.sh          # CLI: start/stop/log/status dev servers
├── docs/               # Cross-repo documentation
│
├── repo-a/             # Cloned repos — gitignored at workspace level
├── repo-b/
├── repo-c/
│
├── _internal/          # Shared libs, internal packages (gitignored)
├── _deprecated/        # Archived repos — read-only
└── _private/           # Local-only config, logs, scratch

Underscore convention

Prefix _ signals special scope to both humans and agents:

Prefix Purpose
_internal/ Shared libraries, design system, internal packages
_deprecated/ Archived repos — don't edit, read-only reference
_private/ Local-only logs, env overrides, scratch (not committed)
_agent/ Agent session data, scratch pads

Quick Start

# 1. Clone the workspace meta-repo
git clone <workspace-url> && cd workspace

# 2. Bootstrap — clones all repos, installs tooling
./scripts/init.sh

# 3. Link the CLI into your PATH
ln -sf "$(pwd)/scripts/app.sh" ~/bin/app

# 4. Start everything
app all start

# 5. Check health
app all status

Init Script (scripts/init.sh)

A single idempotent script run once on a fresh machine. It should:

  1. Clone repos — skip if .git already exists.
  2. Install tooling — nvm, Node, pm2 (or Docker, etc.).
  3. Be safe to re-run — every step checks "already done?" before acting.
# Pattern (simplified):
clone_if_missing() {
  local dir="$1" url="$2"
  if [ -d "$dir/.git" ]; then
    echo "  [SKIP] already cloned"
  else
    echo "  [CLONE] $url -> $dir"
    git clone "$url" "$dir"
  fi
}

clone_if_missing "$ROOT/repo-a" "git@github.com:org/repo-a.git"
clone_if_missing "$ROOT/repo-b" "git@github.com:org/repo-b.git"

App CLI (scripts/app.sh)

A thin shell script that wraps pm2 to manage all dev servers from one command.

Usage

app <app-name> <command>

  app:      repo-a | repo-b | all
  command:  start | stop | restart | log | status
Command Description
start Launch the app's dev server via pm2
stop Kill the pm2 process
restart Restart (useful after pulling new code)
log Tail live logs
status Show pm2 status

Canonical names

If users might refer to the same app by different names (e.g. api and api-python), normalise them internally so pm2 never gets duplicate processes.

Logs

Logs write to _private/server-logs/{app}.log by default. Override with an env var:

APP_LOG_DIR=/tmp/logs app all start

Agent Context (AGENTS.md)

The file AI agents read first. Structure:

1. Repo table

Quick-reference for every repo:

Repo Description Stack Port
repo-a Customer portal Next.js, MongoDB 3000
repo-b Backend API FastAPI, Supabase 8000

Note the underscore convention so agents know _deprecated/ isn't active work.

2. Commands per repo

### repo-a
\`\`\`bash
npm run dev      # Next.js dev server
npm run build    # Production build
npm test         # Vitest
\`\`\`

3. Architecture notes

Key patterns to save agents from rediscovering: auth approach, API route conventions, folder layout, testing setup.


Editor & .gitignore

The .gitignore lists every cloned repo directory. This means:

  • Cmd+P / Ctrl+P file-finder — ignores those folders by default. Only workspace-level files show up.
  • Sidebar — folders still visible when expanded, so collapse repos you're not actively working on.
  • Git status — workspace stays clean; each repo manages its own git.
# .gitignore — ignore cloned repos so they don't clutter the workspace
repo-a/
repo-b/
repo-c/
_internal/
server-logs/

VS Code / code-server override

If you want gitignored repos to still appear in Quick Open (Cmd+P), add a .vscode/settings.json in the workspace root:

{
  "search.useIgnoreFiles": false,
  "search.exclude": {
    "_deprecated/**": true,
    "_internal/**": true,
    "_private/**": true
  }
}
  • search.useIgnoreFiles — when false, VS Code ignores .gitignore patterns for its file indexer, making repos visible in Cmd+P.
  • search.exclude — selectively re-hide folders you don't need in the file finder (typically the _-prefixed ones).

This only affects the editor's file index, not git — your .gitignore still works as expected.


Docs

A docs/ folder in the workspace holds cross-repo documentation that no single repo owns: architecture overviews, runbooks, meeting notes, ADRs.

For a richer docs experience, run a lightweight markdown server:

# e.g. a simple Node.js server rendering markdown to HTML
cd docs-server && npm run dev

Conventions

  • Files use lowercase kebab-case (deployment-runbook.md).
  • Internal links update when a doc is renamed or moved.

App Table (in README.md)

Every workspace README.md should have a table listing each repo:

App Directory Stack Port Purpose
app-a repo-a/ Next.js, MongoDB 3000 Customer portal
app-b repo-b/ FastAPI, Postgres 8000 Backend API

Environment Variables

Each app manages its own .env / .env.local. Keep a .env.example at each app root. Shared secrets go through the deployment platform (Vercel, etc.), not checked in.


Deployment

Each repo deploys independently — no shared build step. Each has its own platform config (vercel.json, fly.toml, etc.). The workspace CLI is dev-only.


Common Patterns

Pattern Recommendation
Shared UI library Place in _internal/, publish as @org/ui
Deprecated code Move to _deprecated/ — don't delete outright
Version consistency .nvmrc per repo; init.sh installs one workspace-level Node
Running tests Per-repo; no workspace-wide test runner
Adding a new repo Clone it → add to init.sh.gitignoreREADME.md table → app.sh