Skip to main content
ClaudeWave
Skill5.8k repo starsupdated 4d ago

brownfield

Scan and manage brownfield repository/worktree defaults for interviews

Install in Claude Code
Copy
git clone --depth 1 https://github.com/Q00/ouroboros /tmp/brownfield && cp -r /tmp/brownfield/skills/brownfield ~/.claude/skills/brownfield
Then start a new Claude Code session; the skill loads automatically.

SKILL.md

# /ouroboros:brownfield

Scan a root directory for existing git repositories and linked worktrees, then manage default repos used as context in interviews.

## Usage

```
ooo brownfield                # Scan repos and set defaults
ooo brownfield scan           # Scan only (no default selection)
ooo brownfield defaults       # Show current defaults
ooo brownfield set 6,18,19   # Set defaults by repo numbers
ooo brownfield detect [path]  # Author mechanical.toml via one AI call
```

**Trigger keywords:** "brownfield", "scan repos", "default repos", "brownfield scan", "mechanical detect"

---

## How It Works

### Default flow (`ooo brownfield` with no args)

**Step 1: Scan**

Show scanning indicator:
```
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
  Scanning for Existing Projects...
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

Looking for git repositories and worktrees up to two directories below the scan root.
Local repos and repos with any remote name are eligible.
This may take a moment...
```

**Implementation — use MCP tools only, do NOT use CLI or Python scripts:**

**CRITICAL — deferred-schema guard (prevents "Invalid tool parameters"):**
This skill can call `ouroboros_brownfield` across multiple turns (`scan`,
`set_defaults`, `defaults`, and `set`). A deferred schema loaded for one turn is
NOT guaranteed to remain loaded for the next. Immediately before EVERY
`ouroboros_brownfield` call, re-run `tool discovery query: "+ouroboros brownfield"`
(idempotent — a no-op when already loaded). If the load returns no matching tool (and the tool is not already callable — an empty load for an already-exposed tool is an expected no-op, not absence),
stop with the MCP-not-available message instead of retrying the failing call.

1. Load the brownfield MCP tool: `tool discovery query: "+ouroboros brownfield"`
2. Call scan+register:
   ```
   Tool: ouroboros_brownfield
   Arguments: { "action": "scan" }
   ```
   This walks `scan_root` (up to two directory levels deep) for valid seed repos/worktrees and registers them in DB. Each repo or worktree found directly by the walk is registered self-only — Git worktree families are not expanded, so worktrees outside the depth-bounded walk (e.g. under `.ouroboros/worktrees`) are not pulled in. Existing defaults are preserved.

The scan response `text` already contains a pre-formatted numbered list with `[default]` markers. **Do NOT make any additional MCP calls to list or query repos.**

**Display the repos in a plain-text 2-column grid** (NOT a markdown table). Use a code block so columns align. Example:

```
Scan complete. 8 repositories registered.

 1. repo-alpha                   5. repo-epsilon
 2. repo-bravo *                 6. repo-foxtrot
 3. repo-charlie                 7. repo-golf *
 4. repo-delta                   8. repo-hotel
```

Include `*` markers for defaults exactly as they appear in the scan response.

**If no repos found**, show:
```
No git repositories or worktrees found.
```
Then stop.

### Scan boundaries

- The filesystem walk starts at `scan_root`; when omitted, `scan_root` defaults to the current user's home directory.
- Repositories are discovered by walking directories inside `scan_root`, at most two levels deep (so `~/repo` and `~/group/repo` are found; deeper nesting is not).
- Dot-prefixed directories and known noisy directories such as `node_modules` are not walked as seed locations.
- Both normal repos (`.git` directory) and linked worktrees (`.git` file) are registered when the walk reaches them. Git worktree families are NOT expanded — a worktree is only registered if the walk finds it directly, not because its main repo's Git metadata reports it.
- Local repos, repos without remotes, and repos whose remotes are not named `origin` are all eligible.

**Step 2: Default Selection**

**Do NOT use `AskUserQuestion` for this selection.** Two rendering constraints
make it unusable here:

- Assistant text emitted between tool calls (scan result → grid → question
  dialog) is not guaranteed to render, so the user may face the dialog
  without ever seeing the repo list.
- Embedding the list in option `preview` fields does not work either — the
  preview box has a fixed height and silently truncates long lists
  ("N lines hidden"), and repo lists routinely exceed it.

Instead, **end the turn with the repo grid as the final message** so its
display is guaranteed, and collect the selection as a plain chat reply.

Immediately below the grid (same message, same code block or right after it),
append the selection prompt:

**If defaults exist:**
```
Current defaults: <current default names> (numbers <current default numbers>)

Reply with repo numbers to change defaults (e.g. "6, 18, 19"),
"keep" to keep the current defaults, or "none" to clear them.
```

**If no defaults exist:**
```
No defaults set.

Reply with repo numbers to set defaults (e.g. "6, 18, 19"),
or "none" to run interviews in greenfield mode.
```

Then **end the turn** — no tool calls after the grid. The RFC #1392
breadcrumb footer is still the last line of the message.

On the next turn, parse the user's reply:

- Numbers (any separator) → those indices
- "keep" (defaults exist) → stop; no MCP call needed, confirm defaults unchanged
- "none" → empty indices (clear all)
- Anything else → ask again in plain text; do not guess

Then re-run `tool discovery query: "+ouroboros brownfield"` and use ONE MCP call to update all defaults at once:

```
Tool: ouroboros_brownfield
Arguments: { "action": "set_defaults", "indices": "<comma-separated IDs>" }
```

Example: if the user picks IDs 6, 18, 19 → `{ "action": "set_defaults", "indices": "6,18,19" }`

This clears all existing defaults and sets the selected repos as default in one call.

If "none" → `{ "action": "set_defaults", "indices": "" }` to clear all defaults.

**Step 3: Confirmation**

```
Brownfield defaults updated!
Defaults: grape, podo-app, podo-backend

These repos will be used as context in interviews.
```

Or if