Skip to content

feat: use git worktrees for docs pipeline writing and MR creation #140

@aireilly

Description

@aireilly

Summary

Replace the fragile stash/reset/branch/pop sequence in create_merge_request.sh with git worktrees. Each workflow run gets an isolated checkout on its own branch, eliminating working tree pollution and enabling parallel ticket support.

Problem

The docs-orchestrator pipeline currently modifies the user's working tree directly during the writing (update-in-place mode) and create-merge-request steps. This causes three problems:

  1. Fragile branch creation: create_merge_request.sh (lines 120-151) performs a git stash push / git reset --hard / git checkout -b / git stash pop sequence. If the user has uncommitted work or stash conflicts, this breaks.
  2. Working tree pollution: Update-in-place mode writes directly to the user's current checkout, intermingling pipeline output with any in-progress work.
  3. No parallel ticket support: Two concurrent workflow runs would collide in the same working tree.

Proposal

Scope

Worktrees apply only to the docs repo (where documentation gets written). Analysis steps (requirements, planning, scope-req-audit, code-evidence) are read-only and continue writing metadata to .claude/docs/<ticket>/. Source code repos continue using shallow clones. Draft mode is unaffected.

Key changes

  1. New script: manage_worktree.sh — Creates/removes worktrees at <base-path>/worktree/ on a docs/<ticket> branch. Called by the orchestrator before the writing step.

  2. Orchestrator gains a "Prepare worktree" phase — Runs between planning and writing (non-draft mode only). Creates the worktree, records the path in the progress file, and passes it as --repo-path to writing and create-merge-request steps.

  3. Simplified create_merge_request.sh — With a --worktree flag, skips the stash/reset/branch/pop dance entirely. The worktree is already on a feature branch. Old logic preserved as fallback for standalone use.

  4. Progress file schema extended — New worktree field tracks path, branch, and repo root for resume across sessions.

Files to modify

File Change
plugins/docs-tools/skills/docs-orchestrator/scripts/manage_worktree.sh NEW — worktree lifecycle script
plugins/docs-tools/skills/docs-orchestrator/SKILL.md Add "Prepare worktree" section, update arg wiring, add cleanup
plugins/docs-tools/skills/docs-orchestrator/schema/step-result-schema.md Add worktree to progress schema
plugins/docs-tools/skills/docs-workflow-create-merge-request/scripts/create_merge_request.sh Add --worktree flag
plugins/docs-tools/skills/docs-workflow-create-merge-request/SKILL.md Document --worktree flag

Files NOT modified

  • build_writing_args.sh — already handles --repo-path
  • docs-workflow-writing/SKILL.md — orchestrator passes worktree path as --repo-path
  • Style-review, tech-review — read from <base-path>/writing/, not the repo
  • resolve_source.py — handles source code repos, not docs repos

Edge cases

  • Resume: Worktree persists at <base-path>/worktree/. Progress file records the path. On resume, orchestrator reuses it.
  • Draft mode: No worktree. worktree field is null.
  • User on feature branch: Worktree created from current branch, not origin/main.
  • User declines MR: Worktree kept for manual inspection.
  • Backward compatibility: create_merge_request.sh without --worktree flag retains old stash/branch logic.

Detailed plan

See attached plan file below.

Full implementation plan

1. New script: manage_worktree.sh

Path: plugins/docs-tools/skills/docs-orchestrator/scripts/manage_worktree.sh

Usage:
  manage_worktree.sh create <ticket> --base-path <path> [--repo-path <path>]
  manage_worktree.sh remove <ticket> --base-path <path>
  manage_worktree.sh status <ticket> --base-path <path>

create behavior:

  • Determine docs repo root: --repo-path or git rev-parse --show-toplevel
  • Determine base remote/default branch (check upstream first, fall back to origin)
  • Fetch latest: git fetch <remote> <default-branch>
  • Worktree path: <base-path>/worktree/
  • Branch name: docs/<ticket-lowercase>
  • Resume: if worktree exists, validate and emit action: "exists"
  • New: git worktree add -b <branch> <path> <remote>/<default-branch>
  • Emit JSON: { status, worktree_path, branch, base_ref, repo_root, action }

remove behavior:

  • git worktree remove <path> (fails on uncommitted changes)
  • git branch -d <branch> (only if merged)

status behavior:

  • Check existence, emit JSON with state

Why <base-path>/worktree/ not .claude/worktrees/: Lifecycle tied to ticket workspace. Avoids conflicting with Claude Code's own .claude/worktrees/.

2. Orchestrator updates

New "Prepare worktree" phase (orchestrator-internal, not a YAML step):

  1. Skip if options.draft is true
  2. Check progress file worktree field for resume
  3. Run manage_worktree.sh create
  4. Record in progress file
  5. Use worktree.path as --repo-path for writing step

Updated arg wiring:

  • Writing: --repo-path <worktree.path> instead of --docs-repo-path
  • Create-merge-request: --repo-path <worktree.path> --worktree

Cleanup on completion:

  • MR created successfully → manage_worktree.sh remove
  • MR not created → keep worktree, log path

3. Simplified create_merge_request.sh

  • Add --worktree flag
  • When set: skip stash/reset/branch/pop block (lines 113-151)
  • Without flag: old logic preserved for standalone use

4. Progress file schema

New top-level field:

{
  "worktree": {
    "path": "/absolute/path",
    "branch": "docs/<ticket>",
    "repo_root": "/absolute/path/to/docs-repo"
  }
}

Verification

  1. Unit test manage_worktree.sh against a test repo
  2. Draft mode: no worktree created
  3. Update-in-place: worktree created, writing goes there, MR created from worktree branch, user's tree clean
  4. Resume: worktree reused across sessions
  5. Parallel tickets: each gets own worktree
  6. Standalone create-merge-request: backward-compatible without --worktree

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions