worktree must be cross-platform as far as practical. Core semantics should work across macOS, Linux, and Windows. Copy-on-write is a platform/filesystem acceleration and must not define the product model.
createcreate(input: {
from: AbsolutePath
name?: string
into?: AbsolutePath
}): AbsolutePath
Default behavior:
from.name defaults to a generated directory name.into defaults to the managed worktree directory.HEAD in the new workspace.If from is already a managed worktree, create copies that exact worktree. Do not resolve back to an earlier workspace. Metadata should record the immediate source worktree as its parent.
Default storage is a hidden sibling directory of the original registered workspace:
/projects/app/ original workspace
/projects/.worktrees/app/task-a/ created worktree
/projects/.worktrees/app/task-b/ created worktree
from is an original unregistered workspace, its sibling .worktrees/<workspace-name>/ directory becomes the default destination directory.from is already managed, descendants use the default destination directory associated with the original workspace rather than nesting storage beside each descendant.into is provided, use it instead of the default destination directory.into on the same filesystem in that case.removeremove(input: {
at: AbsolutePath
}): void
remove deletes a managed worktree and its full descendant subtree.
at must identify a worktree created by this tool; the registered source root cannot be removed.parent_id and remove their directories deepest-first..worktree marker before deleting it.linklink(input: {
at: AbsolutePath
to?: AbsolutePath
}): void
link reconnects a moved managed worktree to its registry record and can change its parent.
.worktree at at.at, leave its location unchanged.at..worktree alone does not include the ancestry needed to rebuild the record..worktree is missing, look up at by its absolute path. If it matches an existing record, recreate the marker with that record's ULID..worktree is missing and at does not match an existing record, fail. A moved workspace without its marker cannot be identified safely.to is provided, set the worktree's parent to the managed worktree at to.to for an original registered workspace; only worktrees created by this tool can be reparented.to if it is at or a descendant of at, because reparenting must not create a cycle.childrenchildren(input: {
of: AbsolutePath
}): AbsolutePath[]
children returns the direct managed children created from of.
ancestorsancestors(input: {
of: AbsolutePath
}): AbsolutePath[]
ancestors returns the managed ancestry of of, ordered from its immediate parent to the root workspace.
Metadata is stored in a central SQLite database in the platform-appropriate user data directory.
SQLite is not overkill: multiple processes and agents may create, inspect, or remove worktrees concurrently. It provides cross-platform transactions and locking without building a safe JSON registry protocol.
Start with one table:
CREATE TABLE worktree (
id TEXT PRIMARY KEY,
parent_id TEXT REFERENCES worktree(id) ON DELETE CASCADE,
path TEXT NOT NULL UNIQUE,
created_at INTEGER NOT NULL
);
CREATE INDEX worktree_parent_id_idx ON worktree(parent_id);
id.id is a ULID generated when the workspace is first registered or created.id is stored in the central database and in a .worktree marker file at the root of the workspace..worktree contains the worktree ULID and allows a moved workspace to be rediscovered and verified against the database..worktree marker is replaced with the new workspace's ULID.parent_id = NULL.parent_id set to the source worktree id.path is its current location, not its identity.parent_id.remove deletes a whole subtree, so no surviving record depends on deleted ancestry.If a worktree is moved outside the tool, its recorded path becomes missing. The tool cannot discover an arbitrary new location without being given a path or scanning a configured directory.
When link is run against a directory containing .worktree, the tool reads its ULID and reconciles the database path if the recorded path no longer exists.
If both the recorded path and the provided path exist with the same ULID, the tool must refuse automatic reconciliation because the directory was copied without assigning a new identity.
Git support is an integration for directories that contain repositories; it does not define the core worktree model.
When registering or creating from a Git repository:
/.worktree to .git/info/exclude so the identity marker does not appear in local Git status.HEAD resolves to a commit, detach HEAD in the created destination at that same commit.Refuse creation from a Git repository when:
.git is not an independent directory.The tool does not create branches, commit changes, or otherwise replace normal Git commands.
Copying is implemented behind a strategy boundary so platform-specific copy-on-write backends can be added independently.
clonefile directory cloning.create fails.The project ships four interfaces backed by the same implementation and metadata model:
worktree executable.The CLI and language bindings should remain thin and expose the same API semantics as the native library.
For CLI ergonomics, worktree create defaults from to the current working directory when no source path is provided.