{"id":50977026,"url":"https://github.com/bastos/dot-worktreeinclude","last_synced_at":"2026-06-19T09:03:52.374Z","repository":{"id":344630020,"uuid":"1182485799","full_name":"bastos/dot-worktreeinclude","owner":"bastos","description":".worktreeinclude SPEC proposal","archived":false,"fork":false,"pushed_at":"2026-03-15T20:19:03.000Z","size":32,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-03-16T04:51:31.627Z","etag":null,"topics":["claude-code","git","pi-mono","worktree","worktrees"],"latest_commit_sha":null,"homepage":"","language":"Shell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/bastos.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-03-15T15:32:59.000Z","updated_at":"2026-03-15T20:19:06.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/bastos/dot-worktreeinclude","commit_stats":null,"previous_names":["bastos/dot-worktreeinclude"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/bastos/dot-worktreeinclude","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bastos%2Fdot-worktreeinclude","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bastos%2Fdot-worktreeinclude/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bastos%2Fdot-worktreeinclude/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bastos%2Fdot-worktreeinclude/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/bastos","download_url":"https://codeload.github.com/bastos/dot-worktreeinclude/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bastos%2Fdot-worktreeinclude/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34523991,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-19T02:00:06.005Z","response_time":61,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["claude-code","git","pi-mono","worktree","worktrees"],"created_at":"2026-06-19T09:03:51.132Z","updated_at":"2026-06-19T09:03:52.368Z","avatar_url":"https://github.com/bastos.png","language":"Shell","funding_links":[],"categories":[],"sub_categories":[],"readme":"# .worktreeinclude\n\nA spec for materializing local development files into fresh Git worktrees.\n\n## The problem\n\nGit worktrees are great for working on multiple branches simultaneously, but they don't carry over your ignored local files. Every new worktree starts without your `.env.local`, database credentials, development keys, or that 200MB GeoIP database you need to run the app.\n\nSo you copy things by hand. You forget one. You waste an afternoon.\n\n`.worktreeinclude` is a manifest file that lives at the repository root and declares which ignored or local-only paths should be materialized into new worktrees automatically.\n\n## How it works\n\nCreate a `.worktreeinclude` file at your repository root:\n\n```\n.env.local\nconfig/credentials/development.key\n# @optional\n.env.test.local\n# @symlink\nstorage/local/GeoLite2-City.mmdb\n```\n\n- **Paths are literal** -- no globs, no patterns, just repository-relative paths.\n- **Copy is the default** -- each entry is copied from your source checkout into the new worktree.\n- **Missing required paths fail loudly** -- because silent absence is a terrific way to waste an afternoon.\n\n### .worktreeinclude Extra\n\nThe spec defines two conformance levels. The **base** level is copy-only: every path is copied, every missing source fails. This makes it trivial to implement and means any tool that reads the manifest gets useful behavior for free.\n\nThe **Extra** level adds two directives:\n\n- **`# @symlink`** -- symlinks the next entry instead of copying (good for large, read-mostly assets).\n- **`# @optional`** -- skips the next entry without failing if the source path doesn't exist.\n\nDirectives apply only to the next path entry and can stack:\n\n```\n# @optional\n# @symlink\nvendor/models/embeddings\n```\n\nThis entry is symlinked if present, skipped if absent.\n\nA base-only implementation sees the directives as regular comments and copies everything. The same manifest works at both levels -- you just get more control with an Extra implementation.\n\n## Quick examples\n\n**Rails**\n\n```\nconfig/database.yml\nconfig/credentials/development.key\nconfig/credentials/test.key\n.env.development.local\n# @optional\n.env.test.local\n# @symlink\nstorage/local/GeoLite2-City.mmdb\n```\n\n**Next.js**\n\n```\n.env.local\n.env.development.local\n# @optional\n.env.test.local\n.vercel/project.json\n# @symlink\npublic/dev-assets/embeddings\n```\n\n**Django**\n\n```\n.env\n.env.local\nconfig/settings.local.py\n# @symlink\ndata/GeoLite2-City.mmdb\n# @optional\n# @symlink\ndata/ml-models\n```\n\n## What doesn't belong here\n\nTracked files. Git already handles those. Listing `package.json` or `Gemfile` in `.worktreeinclude` is either pointless or dangerous.\n\nLarge generated caches that are cheap to recreate are better handled by a bootstrap script than by this manifest.\n\n## Key rules\n\n- Entries must be repository-relative paths (no absolute paths, no `..` escapes, no `.git`)\n- Tracked paths are rejected -- this is for ignored/local-only files\n- Existing destination paths cause failure by default (no silent overwrites)\n- Symlinks prefer relative targets, falling back to absolute when necessary\n- The manifest itself is the source of truth -- no sidecar metadata files\n\n## Install\n\nRun this from any git repository to set up `.worktreeinclude`:\n\n```sh\ncurl -fsSL https://raw.githubusercontent.com/bastos/dot-worktreeinclude/main/install.sh | sh\n```\n\nThis creates three things in your repo:\n\n1. **`scripts/worktreeinclude.sh`** -- the Bash reference implementation (no dependencies)\n2. **`.claude/settings.json`** -- `WorktreeCreate`/`WorktreeRemove` hooks so Claude Code automatically materializes files into new worktrees\n3. **`.worktreeinclude`** -- a starter template if you don't already have one\n\nThe installer is idempotent -- running it again skips anything that already exists.\n\n### Options\n\n```sh\n# Use the Python implementation instead of Bash\ncurl -fsSL ... | sh -s -- --python\n\n# Install the script to a different directory\ncurl -fsSL ... | sh -s -- --dir bin\n```\n\n### Requirements\n\n`curl`, `jq`, and `git`. The `--python` variant also requires `python3`.\n\nIf you already have a `.claude/settings.json` with other hooks configured, the installer appends to your existing hook arrays rather than replacing them.\n\n## Gotchas\n\n### Tracked files in `.worktreeinclude` and Claude Code hooks\n\nIf your `.worktreeinclude` lists a file that is tracked by Git (e.g. `config/database.yml` that you committed), the entry is redundant -- Git already populates tracked files in new worktrees.\n\n**Before v0.3**, the implementations treated tracked paths as hard errors, which caused `WorktreeCreate` hooks to exit non-zero and left Claude Code without the worktree path. The symptom was the hook appearing to hang, with this in the logs:\n\n```\nERR   path is tracked by Git — .worktreeinclude is for untracked/ignored paths only\n```\n\n**Since v0.3 (current default)**, tracked paths are **warned and skipped** instead of failing. A stale manifest with tracked files won't break your hooks. The earlier **Key rules** section describes the original strict behavior, which you can restore with `--pedantic` if you want tracked paths to be treated as errors.\n\n```sh\n# Default: warn + skip tracked paths\nworktreeinclude.sh create --source /repo --target /worktree\n\n# Strict (--pedantic): fail on tracked paths (matches \"Key rules\")\nworktreeinclude.sh create --source /repo --target /worktree --pedantic\n```\n\n### Logging\n\nBoth implementations log to `worktree.log` in the current directory. Use `--quiet` to suppress stderr output while still writing to the log file. This is useful in hook mode where you only want stdout (the worktree path) and the log file for debugging.\n\n## Implementations\n\nReference implementations in Python and Bash are in [`implementations/`](implementations/). Both support full spec conformance (Base + Extra), integrate with Claude Code hooks and [agent-worktree](https://github.com/nekocode/agent-worktree), and have no third-party dependencies.\n\n## Spec\n\nThe full specification is in [SPEC.md](SPEC.md). It covers the file format, path validation, materialization modes, failure semantics, cross-platform behavior, and two conformance levels (Base and Extra).\n\n**Status:** Draft v0.2\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbastos%2Fdot-worktreeinclude","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbastos%2Fdot-worktreeinclude","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbastos%2Fdot-worktreeinclude/lists"}