Skip to content

Copy & link rules ​

The optional .workler file at the project root declares what a fresh workspace needs. Without it, Workler simply creates the clone and branch. When present, it is applied automatically at the end of workler add and can be re-applied with workler apply.

The format ​

Line-based, like .gitignore but with an action first:

txt
# full-line comment
link node_modules   # inline comment
copy .env
copy "some folder/file.txt"
copy 'another file.txt'

Each line is <action> <path>:

  • link <path> creates a symlink in the workspace pointing back to the main project's copy.
  • copy <path> copies the file or folder into the workspace.

A third action, setup <command>, runs a shell command in the new workspace once the rules are applied; setup --if-missing <path> <command> does so only while <path> is absent, which is how link node_modules and pnpm install go together. The command is taken verbatim, so the quoting and comment rules below do not apply to it — see Setup commands.

Blank lines are ignored. A # at the start of a line or preceded by whitespace starts a comment; a # inside a quoted path (or glued to a word, like file#1.txt) does not. Quote a path with double or single quotes if it contains spaces or #.

linkcopy
Best forBig, regenerable directories: node_modules, build cachesLocal config a workspace may change: .env, local databases
Disk costNone — one shared copyFull copy per workspace
IndependenceChanges are shared with the main projectEach workspace has its own

A linked node_modules means a new workspace runs instantly with zero extra disk — but an npm install in any workspace changes the shared directory for everyone. Copy instead if workspaces need different dependency states.

Copying instead of linking ​

The choice above is made once, in .workler, for every workspace. When a single workspace needs to be fully independent — it will upgrade dependencies, or an agent in it must not touch shared state — pass --copy-links and its link rules are applied as copies instead:

bash
workler add isolated --copy-links        # new workspace, nothing shared
workler apply feature-a --copy-links     # convert an existing workspace

Converting replaces each symlink that still points at its source with a copy of that source. This needs no --force, because such a link holds no data of its own; every other kind of destination follows the usual conflict rules. Relative symlinks inside the copied tree (every node_modules/.bin entry) stay relative, so they resolve inside the copy. An absolute symlink that points inside the copied tree is re-aimed at the copy, so writing through it never reaches the main project; links to anywhere else are kept as they are.

The mode is recorded in the workspace (workler.copyLinks in its Git config), so a later workler apply or workler apply --all keeps the copies rather than reporting them as conflicts with their link rule. From then on those destinations behave exactly like copy rules: if the copy and the source drift apart, apply reports a conflict until you pass --force.

To go back, run workler apply <name> --no-copy-links --force. --force is required because the copies are now real data that the symlinks would replace.

Path restrictions ​

Paths must stay inside the project. The parser rejects, with the line, column, and offending line content:

  • absolute paths
  • paths containing ..
  • . (the whole project/workspace root)
  • .git (including leading ./ and case variants)
  • .worktrees
  • duplicate or parent/child-overlapping rule paths

Backslashes and forward slashes are both treated as separators so committed rules keep the same meaning on every supported platform.

text
.workler:3:6: paths with ".." are not allowed: "../outside"
  3 | copy ../outside

How rules are applied ​

For each rule, the destination inside the workspace is inspected first:

  • Source missing → the rule is skipped with a note (skip ... source does not exist). This is fine — e.g. link node_modules before anyone has run npm install.
  • Already correct → reported as ok and left alone. A symlink that already points at the right source counts as already linked; a copy whose destination content matches the source counts as up to date.
  • Fresh → the symlink is created (linked) or the content copied (copied).
  • Anything else — a symlink pointing elsewhere, a regular file, a directory — is a conflict. Nothing is overwritten; see Safety, --force, --dry-run.

Workler never follows a symlink or junction in a rule source's or destination's parent path. That case is refused even with --force, and is caught during workspace-creation preflight when already present in the source, because traversal could read, write, or delete outside the managed trees. A symlink at the rule path itself is still supported; only symlink ancestors are refused.

On macOS and Linux, links are relative symlinks, so a workspace keeps working if the whole project directory is moved.

On Windows the behavior differs by source type, and it is worth knowing before you write a link rule:

  • A directory source (link node_modules) becomes a junction. Junctions need no elevation, but Windows stores their target as an absolute path — so moving the project directory breaks them. Re-run workler apply after a move to repoint them.
  • A file source (link .env.local) becomes a real symlink, which on Windows requires Developer Mode or an elevated shell. Without that privilege the rule fails with EPERM; Workler does not silently fall back to copying. Use copy instead for files if you would rather not enable Developer Mode.

Re-applying rules ​

Rules are applied when a workspace is created, but you can refresh at any time — after editing .workler, or after .env changed in the main project:

bash
workler apply feature-a          # one workspace
workler apply --all              # every workspace
workler apply                    # run inside a workspace: refresh from its parent
workler apply feature-a --dry-run

apply follows the same conflict rules as add: an up-to-date destination is ok, a differing one is a conflict until you pass --force. Rules run sequentially, not as one transaction; if a later rule fails, earlier successful rules remain applied.

apply only touches copy/link rules. To re-run the setup commands, use workler setup.

Commit the file ​

If you use .workler, commit it so it documents what a working checkout needs and nested workspaces inherit the same rules and setup commands.

Released under the MIT License.