Build or verify cross-repo STITCH.md linking backend + frontends in a product group. Modes: create, verify, diff, section. Uses CODEMAPs as drift source by default. Trigger: '/stitch create <group>', '/stitch diff <group>'.
Scanned 9/5/2026
Install to Claude Code
npx -y skills add mikeprasad/aria-knowledge --skill stitch --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Stitch?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/mikeprasad-stitch-fd517b8b)More formats (shields.io, HTML) on the badges page.
---
description: "Build or verify cross-repo STITCH.md linking backend + frontends in a product group. Modes: create, verify, diff, section. Uses CODEMAPs as drift source by default. Trigger: '/stitch create <group>', '/stitch diff <group>'."
argument-hint: "<create|verify|diff|section> <group> [section-name] [--append|--out=path|--no-archive]"
allowed-tools: Read, Write, Edit, Glob, Grep, Bash
---
# /stitch — Cross-repo stitch layer
Generate a cross-repo binding artifact (`STITCH.md`) for a product group (backend + one or more frontends). Tables only, not narrative. Drift detection uses CODEMAP endpoint sections by default with explicit opt-in fallback to grep.
## Step 0: Load config
<!-- shared-block: group-loader -->
Read `~/.claude/aria-knowledge.local.md`. Parse YAML frontmatter `projects_groups` (multi-line YAML block — see `CONFIG.md` "Skill-only fields" for canonical schema, including the optional `stitch_path` sub-field and custom-role conventions).
Look up `<tag>` in `projects_list` (get `project_root`) and `projects_groups` (get role → folder dict).
- If `<tag>` missing from `projects_list`: stop with *"unknown project tag: <tag>"*.
- If `<tag>` in `projects_list` but missing from `projects_groups` and `<project_root>` has multiple distinct codebases that must stay in sync (separate repo-marker sub-dirs, OR one repo with a shared-contract source + multiple generated/typed clients — see scan below): trigger **auto-propose bootstrap**. The git-repo boundary is NOT the signal — a monorepo with a `contract/` → `ios/`+`android/`+`backend/` seam qualifies just as much as separate repos.
- If `<tag>` is a single undifferentiated codebase (no separate sub-dirs and no contract→multi-client seam): load `<project_root>/CODEMAP.md` only.
**Auto-propose bootstrap** (when `projects_groups[<tag>]` is missing but `<project_root>` contains multiple sync-bound codebases — separate repo dirs or a contract→clients seam):
1. Scan `<project_root>` one level deep for sub-directories with repo or contract markers:
- `openapi.{yaml,yml,json}` / `*.proto` / `schema.graphql` (or a dir named `contract`/`contracts`/`api-spec`/`proto`) → `contract` (the shared source clients are generated from — its drift is what STITCH tracks)
- `manage.py` + `settings.py` → `backend` (Django)
- `composer.json` + `artisan` → `backend` (Laravel)
- `Gemfile` with `rails` → `backend` (Rails)
- `package.json` with `express`/`fastify`/`nestjs` → `backend` (Node)
- `pyproject.toml`/`requirements.txt` with `fastapi`/`pydantic` → `backend` (FastAPI)
- `Package.swift` / `*.xcodeproj` / an `ios` dir → `ios` (Swift/SwiftUI)
- `build.gradle{,.kts}` with an `android` dir → `android` (Kotlin/Android)
- `next.config.*` → `web` (Next.js)
- `app.json` + `expo` in package.json → `mobile` (Expo)
- `package.json` with `react` (no `next`/`expo`) → `web` (React SPA)
- other `package.json` → prompt user for role name
2. Handle role conflicts: if two dirs inferred as same role, prompt user to assign distinct keys (`web`, `web-admin`, etc.).
3. Propose the group structure to user: sub-repo names, inferred roles, YAML block to insert. Show a preview diff of the change to `~/.claude/aria-knowledge.local.md`.
4. On approval, edit the config file to add the `projects_groups[<tag>]` entry, preserving existing fields and YAML structure.
5. On decline, stop with *"proceed after registering group manually"*.
Resolve each `(role, folder)` pair to absolute path: `<project_root>/<folder>`. For each absolute path, read `CODEMAP.md` if it exists. Read `<project_root>/STITCH.md` if it exists. Return resolved path map + warnings for any missing CODEMAPs.
<!-- /shared-block: group-loader -->
**For `/stitch` specifically:** the group MUST have **≥2 distinct codebases bound by a shared contract** — at least one contract/backend source role + at least one client role that must stay in sync with it. **Whether they live in separate git repos or one monorepo is irrelevant** — the load-bearing condition is "multiple codebases that drift apart," not "multiple repos." A monorepo's `contract/` → `ios/`+`android/`+`backend/` seam (the dual-native keystone — one OpenAPI/proto/GraphQL source feeding generated clients) is exactly the drift seam STITCH exists to document. Only stop when there's a **single undifferentiated codebase** with no such seam: *"/stitch needs ≥2 contract-bound codebases; this looks like one codebase — use `/codemap`."*
## Step 1: Resolve paths & output target
- `BACKEND_ROOT` = `<project_root>/<backend folder>` (the one role=backend entry)
- `FRONTEND_ROOTS` = list of `<project_root>/<folder>` for all non-backend roles
- `STITCH_FILE` = `<project_root>/STITCH.md` by default. Override: if `projects_groups[<tag>]` contains a `stitch_path` field, use that (relative to `<project_root>`).
For `create` mode, require `BACKEND_ROOT/CODEMAP.md` and each `frontend_root/CODEMAP.md`. If any missing, list what's missing and recommend running `/codemap create` in each affected repo first.
## Step 2: Load template (create mode only)
Start from `${CLAUDE_PLUGIN_ROOT}/template/stitch/STITCH.template.md`. Fill **Group identity** with:
- Group tag
- Backend repo folder name + `git rev-parse HEAD` if git available
- Frontend repo folder names + revisions
- CODEMAP absolute paths for each repo
- Configured `STITCH_FILE` path
## Step 3: Build sections 2–5 (create + section modes)
Using the loaded CODEMAPs, populate:
- **2. Auth stitch** — token path FE → BE. Source: FE auth slice/hook + BE auth middleware/JWT handler. Table rows: step | location (file) | notes. Mermaid optional, keep minimal.
- **3. Endpoint stitch** — union of FE RTK/fetch calls → BE routes. Normalize paths (strip env prefixes, trailing slashes). Table columns: FE hook/client | HTTP method | FE file | Path | BE urls module | View/handler | Permission | Notes.
- **4. Entity stitch** — when traceable from CODEMAP model/serializer/type tables. Columns: Domain | FE type/schema | BE serializer | Model | Notes.
- **5. Integration stitch** — external services from backend CODEMAP's Integrations section; note FE usage where mentioned. Columns: Service | Env keys | Owner repo | Files | FE usage.
Only populate cells with information that appears in the loaded CODEMAPs. Leave cells blank rather than inventing.
## Step 4: Drift log (create + diff modes)
**Precedence (check in order):**
1. **User-provided script** — check for `<workspace_root>/analyze-stitch.sh` or `<workspace_root>/analyze-stitch.py`. If either exists, invoke with JSON stdin:
```json
{"backend_root": "<abs path>", "frontend_roots": ["<abs path>", ...], "group": "<tag>"}
```
Expect JSON stdout:
```json
{"fe_orphans": [{"call": "...", "file": "..."}, ...], "be_orphans": [{"route": "...", "file": "..."}, ...]}
```
Label output section: *"Drift source: user script (analyze-stitch.*)"*.
2. **CODEMAP-based** (default expected path) — check both CODEMAPs for required endpoint sections:
- **Backend:** look for URLConf tree section (match heading like `## N. URLConf` or similar). Parse endpoint rows.
- **Frontend:** look for API client / RTK Query / endpoint table section. Parse endpoint definitions.
- If both present → normalize to `method + path` tuples, diff the sets. Label: *"Drift source: CODEMAPs (sections: <backend section name>, <frontend section name>)"*.
3. **Missing CODEMAP endpoint data** — **prompt user explicitly** (do NOT silently fall through):
```
STITCH drift detection requires endpoint sections in both CODEMAPs.
Currently missing:
- <backend_path>/CODEMAP.md: <missing section name>
- <frontend_path>/CODEMAP.md: <missing section name> (if applicable)
Recommended: run `/codemap section <missing section>` in the affected repo(s) first
(better accuracy, self-improving as you maintain CODEMAPs).
Fallback: proceed with grep-based drift (coarse — catches presence/absence,
misses HTTP methods, dynamic paths, non-REST conventions). Output will be
labeled "Drift source: fallback grep."
Choose: [C]odemap (stop here, regenerate first) / [G]rep fallback (proceed now)
```
4. **On [G]rep fallback** — grep FE for `/api/` strings (and `api/v1/`, `apiSlice`, `fetch(` variants), grep backend for route definitions (Django `urls.py` patterns, or equivalent). Compare normalized sets. Label output: *"Drift source: fallback grep — CODEMAPs incomplete; see recommendation above"*.
5. **On [C]odemap choice** — exit `/stitch` with instruction: *"Run `/codemap section <name>` in <repo>, then re-invoke `/stitch <mode> <tag>`."*
Populate STITCH.md section 6 (Drift log):
- Header row with drift source labeled
- FE orphans table (FE calls missing BE routes): columns FE call | FE file | Notes
- BE orphans table (BE routes unused by FE): columns BE route | BE file | Notes
## Step 5: Write STITCH.md (create mode)
**Overwrite safety** (mirrors `/distill` Step 4):
- If `STITCH_FILE` exists and non-empty, **first-run notice** explains auto-archive.
- **Default:** move existing `STITCH_FILE` to `<workspace>/.aria-stitch/archive/STITCH-YYYY-MM-DD-HHMMSS.md`, then write fresh.
- **Flags:**
- `--append` — add new dated section below existing (rare for `/stitch`; `section <n>` mode usually preferred; warn user)
- `--out=<path>` — write to alternate path
- `--no-archive` — destructive overwrite, explicit opt-in
## Modes
| Mode | Behavior |
|------|----------|
| `create <group>` | Execute Steps 0-5. Write full `STITCH_FILE`. |
| `verify <group>` | Re-read `STITCH_FILE` tables; check cited file paths still exist on disk; flag stale rows. No rewrite unless user requests. |
| `diff <group>` | Run drift detection only (Step 4). Print drift summary; do not modify `STITCH_FILE`. |
| `section <group> <n>` | Rebuild section `n` in-place in `STITCH_FILE`. Skips overwrite safety (only that section changes). |
## Rules
- Tables over narrative.
- Every file path cited must exist on disk when written.
- Do not invent endpoints not evidenced in CODEMAP or code.
- If `--append` is used for `create`, warn user: *"Append on /stitch is rare; `section <n>` is usually the right mode for incremental updates."*
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!