notes-worktree
This skill should be used when the user asks to "set up notes worktree", "create documentation branch", "separate docs from code", "keep markdown in separate branch", "symlink documentation", "move docs to separate branch", or discusses keeping markdown files in a separate git branch while maintaining access via symlinks in the main project.
SKILL.md
| Name | notes-worktree |
| Description | This skill should be used when the user asks to "set up notes worktree", "create documentation branch", "separate docs from code", "keep markdown in separate branch", "symlink documentation", "move docs to separate branch", or discusses keeping markdown files in a separate git branch while maintaining access via symlinks in the main project. |
name: notes-worktree description: This skill should be used when the user asks to "set up notes worktree", "create documentation branch", "separate docs from code", "keep markdown in separate branch", "symlink documentation", "move docs to separate branch", or discusses keeping markdown files in a separate git branch while maintaining access via symlinks in the main project. version: 2.0.0
Notes Worktree Pattern
A documentation management system that keeps markdown files in a separate git branch while maintaining contextual access via symlinks. This keeps the main branch clean from documentation commits while documentation remains accessible in its logical locations.
Overview
The notes worktree pattern solves a common problem: documentation clutters git history and code reviews. By storing .md files in a separate orphan branch mounted as a git worktree, documentation:
- Has its own commit history
- Does not appear in main branch diffs or PRs
- Remains accessible via symlinks in expected locations
- Can be maintained by different contributors
When to Use
Use this pattern when:
- Documentation changes frequently and clutters PRs
- Multiple teams contribute to docs vs code
- The codebase has many README files per folder
- Keeping the main branch focused on code changes
Setup Instructions for Claude
When setting up a notes worktree, first check if the branch already exists, then either use existing configuration or ask the user.
Step 1: Check for Existing Branch
Before asking any questions, check if the notes branch already exists:
- Run the init script with just
--branch notes - The script will automatically:
- Check if branch exists locally
- If not, check if branch exists on remote and fetch it
- If branch exists, read configuration from
.notesrcfile - If branch doesn't exist, require all parameters
If branch exists: Skip all questions and proceed with setup using existing configuration.
If branch is new: Continue to Step 2 to gather configuration.
Step 2: Ask for Configuration (New Branches Only)
Only ask these questions if the branch does NOT exist:
-
Exclusion method: How should symlinks be hidden from git?
gitignore- Shared with team via.gitignoreexclude- Local only via.git/info/exclude
-
Move existing files: Move existing
.mdfiles to notes and create symlinks?- Yes or No
-
VSCode integration: Configure VSCode to hide notes directory?
- Yes or No
-
Exclude patterns: Comma-separated list of file patterns to exclude from sync
- Example:
SKILL.md,CHANGELOG.md,*.generated.md - Default: empty (no exclusions)
- Example:
Step 3: Run Setup Script
The scripts are located in this skill's directory. Run the init script using the skill's scripts path:
For existing branches (config read from .notesrc):
<SKILL_SCRIPTS_DIR>/init-notes-worktree.sh --branch notes
For new branches (all params required):
<SKILL_SCRIPTS_DIR>/init-notes-worktree.sh \
--branch notes \
--dir ./notes \
--exclusion <gitignore|exclude> \
[--exclude "pattern1,pattern2"] \
[--move-files] \
[--vscode]
Where <SKILL_SCRIPTS_DIR> is the scripts subdirectory of this skill's base directory.
Example: Existing Branch Setup
Claude: I'll set up a notes worktree for documentation management.
Claude runs: <skill_base_dir>/scripts/init-notes-worktree.sh --branch notes
Script output:
Found existing local branch 'notes'
Reading configuration from existing branch...
Configuration loaded from .notesrc
Setting up worktree from existing branch 'notes'...
Claude: Your notes worktree is set up! The configuration was loaded from the existing branch.
Example: New Branch Setup
Claude: I'll set up a notes worktree for documentation management.
Claude runs: <skill_base_dir>/scripts/init-notes-worktree.sh --branch notes
Script output:
Branch name 'notes' is available.
--dir required for new branch
Claude: The branch doesn't exist yet. Let me ask a few questions to configure it.
[AskUserQuestion: Exclusion method, Move files, VSCode integration, Exclude patterns]
User selects: gitignore, yes, yes, "SKILL.md"
Claude runs:
<skill_base_dir>/scripts/init-notes-worktree.sh \
--branch notes --dir ./notes \
--exclusion gitignore --exclude "SKILL.md" --move-files --vscode
CLI Reference
All scripts are accessed via the $PROJECT_ROOT/notes/scripts symlink which points to the plugin directory.
init-notes-worktree.sh
Initialize notes worktree setup. Automatically detects existing branches and reads configuration from .notesrc.
./notes/scripts/init-notes-worktree.sh [OPTIONS]
Required:
--branch NAME Branch name for documentation (e.g., "notes")
Required for NEW branches only (auto-detected from .notesrc for existing branches):
--dir PATH Worktree directory path (e.g., "./notes")
--exclusion METHOD Exclusion method: 'gitignore' or 'exclude'
Optional:
--move-files Move existing .md files to notes and create symlinks
--exclude PATTERNS Comma-separated file patterns to exclude from sync
(e.g., "SKILL.md,CHANGELOG.md,*.generated.md")
--vscode Configure VSCode to hide notes directory
-h, --help Show help
If the branch already exists (locally or on remote), the script reads configuration from the branch's .notesrc file and skips questions. This makes it easy to set up the worktree on a new machine or after cloning.
sync-notes.sh
Sync documentation files between main project and notes worktree.
./notes/scripts/sync-notes.sh [OPTIONS]
Options:
--dry-run Show what would happen without making changes
--cleanup Remove dangling symlinks and stale exclusions
-v, --verbose Show detailed output
-q, --quiet Show only errors
--watch Watch for file changes and auto-sync
--no-interactive Skip interactive conflict prompts
-h, --help Show help
Features:
- Forward sync: Moves
.mdfiles from main project to notes, creates symlinks - Reverse sync: Creates symlinks for files in notes lacking them in main
- Auto-gitignore: Non-README/CLAUDE files are automatically untracked when using gitignore exclusion
status-notes.sh
Show status of notes worktree setup.
./notes/scripts/status-notes.sh [OPTIONS]
Options:
-v, --verbose Show detailed file listings
-q, --quiet Show only errors and summary counts
-h, --help Show help
Shows:
- Synced files (symlinks pointing to notes)
- Dangling symlinks (target missing)
- Notes files without symlinks
- Stale exclusion entries
- Uncommitted/unpushed changes
cleanup-notes.sh
Clean up notes worktree issues.
./notes/scripts/cleanup-notes.sh [OPTIONS]
Options:
--dangling Remove broken symlinks only
--stale Clean stale exclusion entries only
--all Fix everything (default)
--dry-run Show what would be done
-v, --verbose Show detailed output
-q, --quiet Show only summary
-h, --help Show help
teardown-notes.sh
Remove notes worktree setup and clean up.
./notes/scripts/teardown-notes.sh [OPTIONS]
Options:
--keep-branch Don't delete the notes branch
--keep-files Convert symlinks back to real files
--force Skip confirmation prompts
--dry-run Show what would be done
-h, --help Show help
notes-commit.sh
Quick commit helper for notes branch.
./notes/scripts/notes-commit.sh [MESSAGE]
Arguments:
MESSAGE Commit message (default: "Update documentation")
notes-push.sh
Push notes branch to remote.
./notes/scripts/notes-push.sh [REMOTE]
Arguments:
REMOTE Remote name (default: "origin")
notes-pull.sh
Pull notes branch from remote and sync symlinks.
./notes/scripts/notes-pull.sh [OPTIONS] [REMOTE]
Arguments:
REMOTE Remote name (default: "origin")
Options:
--auto-stash Automatically stash local changes before pull
--no-sync Skip running sync after pull
-h, --help Show help
combine-notes.sh
Generate combined markdown from all notes.
./notes/scripts/combine-notes.sh > docs.md
./notes/scripts/combine-notes.sh | pandoc -o docs.pdf
manage-excludes.sh
Manage file exclusion patterns for sync operations.
./notes/scripts/manage-excludes.sh <command> [OPTIONS] [patterns...]
Commands:
list Show current exclusion patterns
add <patterns> Add patterns (comma-separated or space-separated)
remove <patterns> Remove patterns
Options:
--no-commit Don't auto-commit .notesrc changes
-q, --quiet Minimal output
-h, --help Show help
Examples:
# View current patterns
./notes/scripts/manage-excludes.sh list
# Add patterns
./notes/scripts/manage-excludes.sh add "SKILL.md,CHANGELOG.md"
./notes/scripts/manage-excludes.sh add TODO.md
# Remove patterns
./notes/scripts/manage-excludes.sh remove "*.generated.md"
# Add without committing
./notes/scripts/manage-excludes.sh add "DRAFT.md" --no-commit
Key Concepts
Git Worktree
A git worktree allows checking out a branch into a separate directory:
project/
├── .git/ # Main repo
├── src/ # Main branch content
├── client/
│ └── README.md # Symlink → notes/client/README.md
└── notes/ # Worktree (notes branch)
├── .git # Pointer to main .git
├── scripts # Symlink → plugin scripts directory
└── client/
└── README.md # Actual file
Symlinks
Relative symlinks connect original locations to the notes directory:
client/README.md→../notes/client/README.md- Edit via symlink or directly in notes - same file
Script Symlink
The notes/scripts symlink (inside the worktree) points directly to the plugin scripts directory. Scripts are NOT copied into the worktree - they remain in the plugin and are accessed via this symlink.
Dual Exclusion Strategy
Main branch exclusion (.git/info/exclude or .gitignore):
/notes/
client/README.md
Notes branch .gitignore (negates exclusions):
/scripts
!**/README.md
!CLAUDE.md
Common Workflows
Adding New Documentation
Create in notes directly:
mkdir -p notes/server/new-feature
echo "# New Feature" > notes/server/new-feature/README.md
./notes/scripts/sync-notes.sh # Creates symlink
Or create normally and sync:
echo "# New Feature" > server/new-feature/README.md
./notes/scripts/sync-notes.sh # Moves to notes, creates symlink
Cloning a Project with Notes
The init script automatically detects and fetches existing remote branches:
# Option 1: Use the init script (recommended - handles everything)
./path/to/init-notes-worktree.sh --branch notes
# Option 2: Manual setup
git worktree add ./notes notes
./notes/scripts/sync-notes.sh # Creates all symlinks
Updating Documentation
vim client/README.md # Edit via symlink
./notes/scripts/notes-commit.sh "Update client documentation"
./notes/scripts/notes-push.sh
Pulling Remote Changes
./notes/scripts/notes-pull.sh --auto-stash
Troubleshooting
Dangling symlinks after deleting files:
./notes/scripts/status-notes.sh # Check for issues
./notes/scripts/sync-notes.sh --cleanup # Fix them
Symlink appears in git status:
Check that the path is in exclusion file. Run ./notes/scripts/sync-notes.sh to update exclusions.
Permission denied on scripts:
chmod +x ./notes/scripts/*.sh
Uninstall completely:
./notes/scripts/teardown-notes.sh # Interactive teardown
./notes/scripts/teardown-notes.sh --keep-files # Keep docs as regular files