{"id":47908514,"url":"https://github.com/defactosoftware/werksfeer","last_synced_at":"2026-04-04T05:01:48.106Z","repository":{"id":343266565,"uuid":"1176987700","full_name":"DefactoSoftware/werksfeer","owner":"DefactoSoftware","description":"Universal git worktree setup tool — copies env files, symlinks build dirs, clones databases. Designed for AI coding agents.","archived":false,"fork":false,"pushed_at":"2026-03-18T13:30:21.000Z","size":99,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-03-19T04:26:30.171Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"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/DefactoSoftware.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-09T15:24:25.000Z","updated_at":"2026-03-18T13:30:22.000Z","dependencies_parsed_at":null,"dependency_job_id":"5e77e5f8-08b7-4e72-b6ba-097c4fbe5a51","html_url":"https://github.com/DefactoSoftware/werksfeer","commit_stats":null,"previous_names":["defactosoftware/werksfeer"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/DefactoSoftware/werksfeer","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DefactoSoftware%2Fwerksfeer","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DefactoSoftware%2Fwerksfeer/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DefactoSoftware%2Fwerksfeer/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DefactoSoftware%2Fwerksfeer/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/DefactoSoftware","download_url":"https://codeload.github.com/DefactoSoftware/werksfeer/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DefactoSoftware%2Fwerksfeer/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31388169,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-04T04:26:24.776Z","status":"ssl_error","status_checked_at":"2026-04-04T04:23:34.147Z","response_time":60,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":[],"created_at":"2026-04-04T05:01:47.463Z","updated_at":"2026-04-04T05:01:48.094Z","avatar_url":"https://github.com/DefactoSoftware.png","language":"Shell","readme":"# werksfeer\n\nUniversal git worktree setup tool. Automatically provisions isolated development environments when creating git worktrees — copies env files, symlinks build directories, clones databases, and runs setup commands.\n\nDesigned to run unattended for AI coding agents, but works great for humans too.\n\n## Install\n\n```sh\ncurl -fsSL https://raw.githubusercontent.com/DefactoSoftware/werksfeer/main/install.sh | sh\n```\n\nOr manually:\n\n```sh\ncurl -fsSL https://raw.githubusercontent.com/DefactoSoftware/werksfeer/main/werksfeer -o ~/.local/bin/werksfeer\nchmod +x ~/.local/bin/werksfeer\n```\n\n## Quick start\n\n1. Add a `.worktree.toml` to your project root (can be empty — defaults are auto-detected):\n\n```sh\ntouch .worktree.toml\n```\n\n2. Set up werksfeer for your workflow (see [Setup](#setup) below).\n\n3. Create a worktree — werksfeer runs automatically:\n\n```sh\nwt switch -c my-feature\n```\n\n```\n[werksfeer] ==\u003e Setting up worktree\n[werksfeer] Copied .env\n[werksfeer] Symlinked node_modules -\u003e /path/to/main/node_modules\n[werksfeer] Cloning myapp_development -\u003e worktree_feature_branch_my_feature\n[werksfeer] ==\u003e Worktree setup complete!\n```\n\n## What it does\n\nWhen a new worktree is created, werksfeer:\n\n1. **Copies env files** (`.env`, `.envrc`, `.tool-versions`) from the main worktree\n2. **Symlinks shared directories** (`node_modules`) to avoid redundant installs\n3. **Copies build directories** (`_build`, `deps`, `.bundle`, etc.) from the main worktree\n4. **Clones PostgreSQL databases** using `CREATE DATABASE ... WITH TEMPLATE` for instant isolation\n5. **Allocates a unique port and Redis database** per worktree, tracked in a registry\n6. **Writes overrides** (DB names, port, Redis URL) to `.env.local` (Rails) or `.envrc` (Elixir)\n7. **Runs setup commands** (`bin/setup`, `mix deps.get`, `pip install`, etc.)\n\nEverything is idempotent — safe to re-run.\n\n## Setup\n\n### Git hooks\n\nThe included `post-checkout` hook triggers werksfeer automatically on worktree creation (via `wt switch -c` or `git worktree add`). It only activates for worktree creation (not regular branch checkouts) and only when `.worktree.toml` exists.\n\n```sh\n# Global — all repos (note: replaces per-repo hooks):\ngit config --global core.hooksPath ~/.local/share/werksfeer/hooks\n\n# Single repo:\ncp ~/.local/share/werksfeer/hooks/post-checkout .git/hooks/\n```\n\n### Claude Code (CLI)\n\nClaude Code's `WorktreeCreate` hook replaces the default worktree creation, so the hook must create the worktree itself and print its path to stdout.\n\nAdd to `.claude/settings.json` (or `.claude/settings.local.json`):\n\n```json\n{\n  \"hooks\": {\n    \"WorktreeCreate\": [\n      {\n        \"hooks\": [\n          {\n            \"type\": \"command\",\n            \"command\": \"bash -c 'set -e; NAME=$(cat | jq -r .name); DIR=\\\"$CLAUDE_PROJECT_DIR/.worktrees/$NAME\\\"; git worktree add \\\"$DIR\\\" --detach HEAD \u003e\u00262; cd \\\"$DIR\\\" \u0026\u0026 werksfeer \u003e\u00262; echo \\\"$DIR\\\"'\"\n          }\n        ]\n      }\n    ],\n    \"WorktreeRemove\": [\n      {\n        \"hooks\": [\n          {\n            \"type\": \"command\",\n            \"command\": \"bash -c 'cat | jq -r .worktree_path | xargs werksfeer --cleanup'\"\n          }\n        ]\n      }\n    ]\n  }\n}\n```\n\nThe `WorktreeRemove` hook drops the worktree's cloned databases when the session ends. Note that Claude Code does not always fire this hook reliably (e.g. when the worktree directory is already deleted before the hook runs). Use `werksfeer --prune` periodically to catch any missed cleanups.\n\n### Claude Desktop\n\nClaude Desktop does **not** fire `WorktreeCreate` or `WorktreeRemove` hooks. Use the [git hooks](#git-hooks) approach instead, and run `werksfeer --prune` to clean up after worktrees are removed.\n\n### Codex App\n\nCreate `.codex/setup.sh` in your project:\n\n```sh\n#!/usr/bin/env bash\nwerksfeer\n```\n\nThen select it as your Local Environment setup script in the Codex app settings.\n\n### Cursor\n\nAdd to `.cursor/worktrees.json`:\n\n```json\n{\n  \"setup-worktree\": [\n    \"werksfeer\"\n  ]\n}\n```\n\n### WorkTrunk (`wt`)\n\nWe recommend [WorkTrunk](https://github.com/max-sixty/worktrunk) for managing worktrees. With git hooks configured, werksfeer runs automatically:\n\n```sh\nwt switch -c my-feature\n```\n\nTo launch an AI agent in a new worktree:\n\n```sh\nwt switch -x claude -c feature-auth -- 'Add user authentication'\n```\n\n### Other agents / manual use\n\nRun werksfeer after creating a worktree:\n\n```sh\nwt switch -c my-feature\nwerksfeer\n```\n\nOr with plain git:\n\n```sh\ngit worktree add ../my-feature feature-branch\ncd ../my-feature\nwerksfeer\n```\n\nIf your agent supports post-worktree hooks or setup scripts, point them at `werksfeer`. It is idempotent and runs fully unattended.\n\n### Cleanup on worktree removal\n\nWhen a worktree is removed, `--cleanup` drops its cloned databases and releases its port/redis allocations. You can run this manually from inside a worktree before deleting it, or pass a path.\n\nMost tools either lack removal hooks entirely (Cursor, Codex, Claude Desktop) or don't fire them reliably (Claude Code CLI). Use `werksfeer --prune` periodically to clean up orphaned databases and stale allocations from deleted worktrees — this is the most reliable approach.\n\n```sh\n# Clean up current worktree (drops DBs, releases port/redis)\nwerksfeer --cleanup\n\n# Or specify a path\nwerksfeer --cleanup /path/to/worktree\n\n# Prune current project — drops orphaned DBs and stale allocations\nwerksfeer --prune\n\n# Prune all registered projects\nwerksfeer --prune-all\n```\n\n## Supported project types\n\n| Type | Detected by | Symlinked | Copied | Setup command | DB pattern |\n|------|------------|-----------|--------|---------------|------------|\n| Rails | `Gemfile` + `config/database.yml` | `node_modules` | `.bundle`, `tmp/cache` | `bin/setup` | `{name}_development` / `{name}_test` |\n| Elixir | `mix.exs` | `node_modules` | `_build`, `deps` | `mix deps.get` | `{name}_dev` / `{name}_test` |\n| Python | `pyproject.toml` / `requirements.txt` | — | `.venv`, `__pycache__` | `uv sync` / `pip install` | — |\n| Node | `package.json` | `node_modules` | `.next`, `.nuxt`, etc. | `npm ci` / `yarn` / `pnpm` / `bun` | — |\n\n## Project setup\n\nYour project needs to read the environment variables werksfeer sets (`PORT`, `DATABASE_NAME`, `TEST_DATABASE_NAME`, `REDIS_URL`, `REDIS_PORT`). See **[docs/project-setup.md](docs/project-setup.md)** for a step-by-step guide with examples for Rails and Elixir/Phoenix.\n\n## Port and Redis allocation\n\nEach worktree gets a unique port, Redis port, and Redis database number, so you can run multiple worktrees simultaneously without conflicts.\n\n- **Ports** are allocated sequentially starting from the base port + 1 (e.g. 3001, 3002, ... for Rails). Ports are globally unique across all projects.\n- **Redis ports** are allocated sequentially starting from 6380. Each worktree runs its own Redis instance.\n- **Redis databases** are allocated per-project from 1–15 for extra isolation.\n- Allocations are tracked in a registry at `~/.local/share/werksfeer/allocations` and released on `--cleanup` or `--prune`.\n\nYour project needs to read the `PORT` environment variable for this to work. Examples:\n\n**Rails** — `Procfile.dev`:\n```\nweb: bin/rails server -p ${PORT:-3000}\nredis: redis-server --port ${REDIS_PORT:-6379}\n```\n\n**Elixir** — `config/dev.exs`:\n```elixir\nconfig :myapp, MyAppWeb.Endpoint,\n  http: [port: String.to_integer(System.get_env(\"PORT\") || \"4000\")]\n```\n\n## Configuration\n\nCreate `.worktree.toml` in your project root. All settings are optional:\n\n```toml\n[database]\n# Override base database name (default: lowercase directory name)\nbase_name = \"myapp\"\n# Override suffixes\ndev_suffix = \"_development\"\ntest_suffix = \"_test\"\n\n[port]\n# Base port for the web server (default: 3000 for Rails/Node, 4000 for Elixir, 8000 for Python)\n# Worktrees are allocated ports starting from base+1.\nbase = 3000\n\n[redis]\n# Base Redis URL (default: redis://localhost:6379 for Rails, empty for others)\n# Each worktree gets a unique Redis port (starting from 6380) and database number.\nurl = \"redis://localhost:6379\"\n\n[sync]\n# Override directories to symlink (default: node_modules)\nsymlink = [\"node_modules\"]\n# Override directories to copy (default: build dirs per project type)\ncopy_dirs = [\"_build\", \"deps\"]\n# Override files to copy\ncopy = [\".env\", \".envrc\"]\n# Directories to skip\nskip = [\"tmp\"]\n\n[setup]\n# Override setup command\ncommand = \"make setup\"\n\n[hooks]\n# Run after setup completes\npost_setup = \"echo done\"\n```\n\n## Pruning orphaned databases\n\nWhen worktrees are deleted (via `wt remove` or `git worktree remove`), their cloned databases and port/redis allocations remain. Werksfeer can clean them up:\n\n```sh\n# Prune current project (drops orphaned DBs, releases stale allocations)\nwerksfeer --prune\n\n# Prune all registered projects\nwerksfeer --prune-all\n```\n\nSmart pruning compares `worktree_*` databases against active worktrees — only orphaned databases are dropped and only stale allocations are released.\n\n## How the git hook works\n\nThe `post-checkout` hook fires on every `git checkout` and worktree creation (via `wt switch -c` or `git worktree add`). Werksfeer only activates when all three conditions are met:\n\n1. It's a branch checkout (not a file checkout)\n2. The previous HEAD is the null ref (new worktree, not a branch switch)\n3. `.git` is a file (we're in a worktree, not the main checkout or a fresh clone)\n\nIf `.worktree.toml` doesn't exist in the repo, the hook exits silently.\n\n## Requirements\n\n- **bash** 3.2+ (ships with macOS, Linux, WSL)\n- **git** 2.5+ (worktree support) — [WorkTrunk](https://github.com/max-sixty/worktrunk) (`wt`) recommended for worktree management\n- **psql** (optional — only needed for database cloning)\n- **curl** (only for installation)\n\n## Debug\n\n```sh\nWERKSFEER_DEBUG=1 werksfeer\n```\n\n## License\n\nMIT\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdefactosoftware%2Fwerksfeer","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdefactosoftware%2Fwerksfeer","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdefactosoftware%2Fwerksfeer/lists"}