Skip to content
Back to skills

Workspace Mode

ASecurity

Use when cwd is a parent dir holding multiple sibling git repos — defines repo auto-detection, --repos/--repo/--all-repos/--this-repo precedence, per-repo dispatch, and linked-PR mechanics.

  • 6 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added October 9, 2026
ai-agentsgobashdockercode-reviewgitapi

Works with

  • cursor
  • api

Security analysis

A100/100

Scanned October 9, 2026

npx -y skills add HigorAlves/orc --skill workspace-mode --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Workspace Mode?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Workspace Mode
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/higoralves-workspace-mode/badge)](https://www.skillsdirectory.com/skills/higoralves-workspace-mode)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: workspace-mode
description: Use when cwd is a parent dir holding multiple sibling git repos — defines repo auto-detection, --repos/--repo/--all-repos/--this-repo precedence, per-repo dispatch, and linked-PR mechanics.
---

# Workspace mode

## Overview

orc auto-detects two contexts at session start:

- **repo** — cwd is inside a git repo. Single-repo mode (the original orc behavior).
- **workspace** — cwd is *not* inside a git repo, but ≥2 immediate child directories *are* git repos.

In workspace mode, one orc flow can span multiple repos: a single shared plan, the same branch name created in each targeted repo, per-repo implementers running in parallel, and N linked PRs at ship time.

**Announce at start:** "I'm using the workspace-mode skill because the SessionStart banner showed `orc context: workspace[…]`."

## Detection

The session-start hook (`hooks/scripts/session-start-using-orc.sh`) sources `lib/workspace-detect.sh` and emits a banner. Commands that need the same context source the helper themselves:

```bash
. "${CLAUDE_PLUGIN_ROOT}/lib/workspace-detect.sh"
eval "$(orc_detect_context)"
# now: $ORC_CONTEXT, $ORC_WORKSPACE_ROOT, $ORC_WORKSPACE_NAME,
#      $ORC_WORKSPACE_REPOS (comma-sep), $ORC_REPO_ROOT, $ORC_STATE_DIR
```

Detection precedence:
1. `git rev-parse --show-toplevel` succeeds → `repo`.
2. ≥2 immediate child dirs of cwd are git repos → `workspace`.
3. Otherwise → `loose` (commands refuse with a hint to `cd`).

The helper is the single source of truth — never reimplement detection inline.

## Flag precedence (repo-touching commands)

When the context is `workspace`, every repo-touching command (`/orc:flow`, `/orc:plan`, `/orc:start`, `/orc:ship`, `/orc:address`, `/orc:qa`, `/orc:debug`, `/orc:cleanup`, `/orc:resume`, `/orc:code-review`, `/orc:fan-out`) honors:

| Flag | Meaning |
|------|---------|
| `--repos a,b,c` | Broadcast to the listed repos. |
| `--repo a` | Narrow to one. Mutually exclusive with `--repos`. |
| `--all-repos` | Broadcast to every detected repo. Skips the prompt. |
| `--this-repo` | Pin to cwd's repo (escape hatch from workspace prompts). |
| *(no flag)* | **Prompt** via `AskUserQuestion`. Options: "all N detected repos / pick a subset / just this repo / cancel". |

**Iron rule (from `using-orc`): no silent broadcast.** A command in workspace mode MUST NOT touch more than the cwd's repo without one of the flags above or a confirming prompt.

## State layout

Workspace = `~/work/myapp/`, branch = `feat/sso-login` → sanitized `feat-sso-login`:

```
~/work/myapp/
├── .orc/                                          # workspace-level (shared)
│   ├── orc.json                                   # workspace registry
│   ├── feat-sso-login/files/
│   │   ├── plan.md                                # SHARED plan, slices tagged repo:
│   │   ├── checkpoint.md                          # flow-level phase tracking
│   │   ├── progress.md                            # rollup of per-repo logs
│   │   ├── docker-env-state.json                  # workspace Docker env (orc:env-provisioning)
│   │   ├── docker/                                # generated compose files (never committed)
│   │   ├── env/                                   # env evidence: ps.json, readiness.txt, boot.log
│   │   └── qa/                                    # cross-repo QA evidence
│   └── .worktrees/
│       ├── api/feat-sso-login/                    # workspace-default tree location
│       └── ui/feat-sso-login/
├── api/.orc/feat-sso-login/files/
│   ├── checkpoint.md                              # this repo's slice cursor
│   ├── progress.md                                # orc-implementer's per-repo log
│   ├── workspace-link.json                        # back-pointer (see below)
│   └── qa/                                        # repo-local QA only
└── ui/.orc/feat-sso-login/files/...
```

Rules:
- `plan.md` is authored once at workspace level. Each slice carries a `repo:` annotation declaring ownership.
- Worktrees default to `<workspace>/.orc/.worktrees/<repo>/<branch>/` — outside the repo, so `.gitignore` collisions are avoided by construction.
- Cross-repo QA (e.g. ui+api integration walks) lives at workspace level. Repo-local QA stays per-repo.

## Registry schema (workspace)

`<workspace>/.orc/orc.json` (`schemaVersion: 2`):

```json
{
  "schemaVersion": 2,
  "context": "workspace",
  "workspaceName": "myapp",
  "workspaceRoot": "/Users/x/work/myapp",
  "repos": [
    { "name": "api", "path": "/Users/x/work/myapp/api", "remote": "git@github.com:acme/api.git" },
    { "name": "ui",  "path": "/Users/x/work/myapp/ui",  "remote": "git@github.com:acme/ui.git" }
  ],
  "sessions": [
    {
      "session_id": "01HYZ...",
      "command": "flow",
      "scope": "workspace",
      "branch": "feat/sso-login",
      "branchSanitized": "feat-sso-login",
      "repos": ["api", "ui"],
      "planPath": ".orc/feat-sso-login/files/plan.md",
      "perRepoState": {
        "api": { "repoPath": "api", "worktree": ".orc/.worktrees/api/feat-sso-login", "currentSlice": 2, "prUrl": null },
        "ui":  { "repoPath": "ui",  "worktree": ".orc/.worktrees/ui/feat-sso-login",  "currentSlice": 1, "prUrl": null }
      },
      "linkedPRs": [],
      "current_phase": 5,
      "total_phases": 9,
      "status": "in_progress",
      "created_at": "2026-05-04T14:10:00Z",
      "updated_at": "2026-05-04T15:02:11Z"
    }
  ]
}
```

Per-repo `<repo>/.orc/orc.json` keeps the existing single-repo schema. New entries set `"scope": "repo"` (existing behavior) or `"scope": "workspace-member"` (back-pointer record only). `/orc:status` and `/orc:resume` discriminate by reading `scope`.

## Per-repo agent dispatch

Code-touching agents accept these new inputs in workspace mode:

| Input | Meaning |
|-------|---------|
| `repo` | Repo name (e.g. `api`). |
| `repoPath` | Absolute path to the repo's worktree. |
| `siblingRepos` | List of names — awareness only; do NOT touch. |
| `crossRepoContract` | Optional pointer to a plan.md section describing the API/wire-format contract between repos. Frozen during implementation. |

Agents updated: `orc-implementer`, `orc-code-fixer`, `orc-test-author`, `orc-pr-reviewer`, `orc-qa-validator`, `orc-debug-investigator`.

**Dispatch pattern**: one implementer per repo, in parallel. Repo boundary is a stricter form of the parallel-safe slice boundary already in `agents/orc-implementer.md` — sibling implementers literally cannot touch each other's files because their worktrees are different directories. Per-repo toolchains and failure isolation argue for per-repo dispatch over a single iterating invocation.

The orchestrator (`commands/flow.md` Phase 5) groups slices by `repo:` tag, then within each repo applies the existing sequential/parallel-batch logic. Outer loop: `for repo in targetRepos: dispatch implementer(s)`.

## Linked PRs

`/orc:ship` runs in two passes:
1. `gh pr create` per repo, capturing each PR URL into the workspace registry's `linkedPRs`.
2. `gh pr edit` per repo, injecting a "Linked PRs" block referencing the others + merge order from the plan.

### Schema

Each entry in `linkedPRs[]` is:

```json
{
  "repo": "api",
  "url": "https://github.com/acme/api/pull/311",
  "stackId": null,
  "stackPosition": null,
  "stackedOn": null
}
```

The three stack fields are populated when `/orc:stack-pr` (or `/orc:ship`'s Phase 4.5 size-gate routing into stack-pr) produced this PR as part of a stack:

| Field | Type | Meaning |
|---|---|---|
| `stackId` | `string \| null` | Stable identifier for the stack group. Format: `<sessionId>-<repo>` in workspace mode, `<sessionId>` in single-repo mode. Reused on re-stack of the same branch. |
| `stackPosition` | `int \| null` | 1-indexed position within the stack. Position 1 is the root (stacked on the base branch). |
| `stackedOn` | `string \| null` | URL of the parent PR (position N-1). `null` for position 1 — its parent is the base branch, not another PR. |

**Backward compatibility.** Pre-stack-support entries are `{repo, url}` only. Readers (e.g. `/orc:cleanup`, `/orc:address`) MUST treat missing `stackId`/`stackPosition`/`stackedOn` as `null` and behave identically to a single-PR session. Writers populate all three fields (using `null` when not stacked) so the shape is uniform going forward.

`/orc:cleanup` groups by `stackId` and enforces bottom-up branch deletion (parents merge before children's branches are deletable). `/orc:address` iterates the array unchanged — stack metadata is additive.

Verbose body (matches default ship template):

```
## Linked PRs

This PR is part of a workspace change spanning N repos:

- org/api#311 — this PR
- org/ui#447 — UI changes

Merge order: api → ui (per workspace plan).
```

Caveman variant (matches `caveman-pr` style):

```
## Linked
api#311 (this) · ui#447
order: api → ui
```

Merge order is sourced from the plan's "Repo touchpoints" section; omit the line if the plan didn't specify one.

## Branch-name collision handling

In workspace mode, `/orc:start` (and `/orc:flow` Phase 4) check the chosen branch against every target repo:

```bash
for r in $repos; do
  git -C "$r" show-ref --verify --quiet "refs/heads/$branch"
done
```

| Repo state | Action |
|------------|--------|
| Branch absent locally and on origin | OK — create. |
| Branch absent locally, present on origin | OK — `git fetch && git worktree add -B`. |
| Branch present, points at base HEAD | OK — adopt. |
| Branch present, has divergent commits | **Conflict — escalate via `AskUserQuestion`.** |

On conflict, print the Gate headline first (`**⛔ Gate — branch collision**`, one line naming the conflicting repos, per `orc:callouts`).

Recovery options on conflict (one prompt covering all conflicting repos at once):

1. **Suffix all repos** — append `-2` to the branch name everywhere so the workspace stays aligned (`feat/sso-login-2` in all repos). The suffix is recorded in the registry.
2. **Suffix only conflicting repos** — keep `feat/sso-login` in clean repos; `feat/sso-login-api` in the dirty one. `perRepoState[<repo>].branch` records the override; `branch` field tracks the canonical name.
3. **Adopt the existing branch** — assume prior work is the intended starting point. Surface the divergent commits in the plan-confirmation gate so the user explicitly opts in.
4. **Pick a different canonical name** — restart the branch-name input.
5. **Abort** — stop the flow; nothing written.

**Iron rule: workspace mode never silently picks.**

## Backward compatibility (workspace ↔ single-repo)

The risk: a workspace flow writes `<workspace>/.orc/feat-sso-login/files/plan.md`. Later the user `cd`s into one repo and runs `/orc:status` — old code would only look at `<repo>/.orc/orc.json` and miss the workspace state.

Defenses:

1. **`workspace-link.json` stub** in every per-repo `<repo>/.orc/<branch>/` written by a workspace flow:
   ```json
   { "scope": "workspace-member", "workspaceRoot": "../..", "workspaceName": "myapp", "sessionId": "01HYZ...", "branch": "feat/sso-login" }
   ```
   `/orc:status` and `/orc:resume` test for this file and walk to the workspace registry when present.
2. **Disjoint artifact sets** — workspace-member dirs never contain `plan.md`; single-repo dirs always do. Presence of `plan.md` is the second-line collision detector.
3. **Detection precedence** — if cwd is inside a repo, the helper returns `repo` even when that repo lives under a workspace. Routing-up happens via the link file.
4. **`scope` discriminator** on every registry entry. Legacy entries with no `scope` are read as `repo` by default.
5. **Refuse-and-prompt on real collision** — workspace flow refuses to overwrite a per-repo `.orc/<branch>/` whose `plan.md` exists and is not workspace-member; user picks rename or `/orc:cleanup` evict.
6. **Schema bump** — `schemaVersion: 2` (workspace-aware). Reads handle both; writes upgrade in place.

## Resume + cleanup semantics

- `/orc:resume` (workspace mode, no flag) resumes every repo of the workspace session at the same phase. `--repo a` narrows to one.
- `/orc:resume` from inside a workspace-member repo follows the `workspace-link.json` back-pointer up to the workspace registry and resumes from there.
- `/orc:cleanup` (workspace mode) waits until **all** linked PRs are merged before cleaning per-repo worktrees + state. `--per-repo` overrides to clean each as it merges (rare; use only when you intend to abandon the others).

## When NOT to use workspace mode

- **Single-repo work** — even when cwd happens to be a workspace, if the change touches one repo, run from inside that repo or pass `--this-repo`.
- **Cross-workspace flows** — work that spans repos in different parent dirs is two separate flows. Don't try to staple them together.
- **Sequencing-blocked work** — if repo B can't start until repo A's PR merges, run them as sequential single-repo flows. A coordinated flow is for changes that ship as one logical unit.

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…