Documentation
¶
Overview ¶
Package checkoutmarker writes one `.worktree.md` into every checkout, stating what that checkout is and whether it may be written to.
Why a marker in every checkout, not only in the ones that must stay clean ¶
The obvious design is a warning file dropped into canonical clones. It does not work: a negative signal present only where writing is wrong means a MISSING file reads as "nothing here objects, go ahead", which is exactly the wrong default for the checkout WB has not reached yet. A marker in every checkout inverts that. An agent reads one file and learns where it is, and absence means "unknown, verify" rather than "safe".
It also degrades to readers the PreToolUse guard cannot reach: Codex, a human, and any tool that has not been written yet.
Why it stays untracked ¶
Committing `.worktree.md` and adding it to `.gitignore` does not work either: `.gitignore` has no effect on an already-tracked file, so a committed marker that WB rewrites shows up as ` M .worktree.md` — a dirty canonical clone, the very condition this exists to prevent — and conflicts on any pull that touches it. `git update-index --skip-worktree` is per-clone index state that silently reverts, which is not something to hang a safety guarantee on.
So WB generates the file locally and never commits it, and pairs every write with an ignore rule so `git status` stays clean. Verified against real Git: one entry in the common directory's `info/exclude` covers the canonical clone and every linked worktree cut from it, because linked worktrees have no `info/exclude` of their own. WB's own hooks read `git status --porcelain`, which never lists an ignored path, so the marker cannot trip the policy it advertises.
Index ¶
Constants ¶
const ExcludePattern = "/" + FileName
ExcludePattern is the ignore rule that keeps the marker out of git status. It is anchored so it can only ever match the checkout root's own marker.
const FileName = ".worktree.md"
FileName is the marker's name in every checkout.
const WorktreesExcludePattern = "/.worktrees/"
WorktreesExcludePattern keeps WB's repository-local linked checkout root out of status, recursive searches, and build discovery in its canonical clone. It applies only at the canonical checkout root.
Variables ¶
This section is empty.
Functions ¶
func EnsureExclude ¶
EnsureExclude appends the marker's ignore rule to a Git exclude file, and reports whether it had to. Every other line in that file is preserved: it is the user's, and WB only ever adds to it.
func Equivalent ¶
Equivalent compares two markers ignoring only their timestamps, so a refresh that would change nothing but the clock leaves the file alone. That is what makes repeated runs — on every sync, every create — free.
func Render ¶
func Render(descriptor Descriptor) string
Render produces the marker's exact contents: a machine-readable YAML document first, so a reader never has to parse prose, then the instructions a human or an agent acts on.
Types ¶
type DescribeOptions ¶
type DescribeOptions struct {
// ProjectsRoot is the directory holding {owner}/{repository} clones.
ProjectsRoot string
// BaseBranch is the protected branch a canonical clone must stay on.
BaseBranch string
// Version identifies the WB build that generated the marker.
Version string
// Now supplies the timestamp; nil means time.Now.
Now func() time.Time
}
DescribeOptions configures Describe.
type Descriptor ¶
type Descriptor struct {
Kind Kind
Writable bool
Repository string
CheckoutPath string
CanonicalPath string
Branch string
BaseBranch string
Task string
WorktreesRoot string
GeneratedAt time.Time
GeneratedBy string
}
Descriptor is everything the marker states. The field names are the schema agents key their decisions off, so they are part of the contract.
type Inspection ¶
type Inspection struct {
Descriptor Descriptor
ExcludePath string
}
Inspection is a described checkout together with the exclude file that keeps its marker out of git status.
func Describe ¶
func Describe(path string, options DescribeOptions) (Inspection, error)
Describe resolves what a checkout is, using filesystem reads only.
No Git process is started. Everything the marker states is already on disk: the shape of `.git` says whether the checkout is primary or linked, the `gitdir:` pointer says which canonical clone a worktree belongs to, and HEAD says which branch it is on. Keeping it process-free is what lets `wb sync` and `wb worktree create` refresh markers across the whole fleet without paying for a fork per checkout.
type Kind ¶
type Kind string
Kind is what a checkout is.
const ( // KindCanonical is the shared clone at <projects-root>/<owner>/<repository> // that every worktree in the fleet is cut from. It must stay clean. KindCanonical Kind = "canonical" // KindWorktree is a linked worktree: an isolated checkout that exists to be // written to. KindWorktree Kind = "worktree" )
type Result ¶
type Result struct {
// MarkerPath is where the marker lives.
MarkerPath string
// MarkerWritten is false when the marker was already exactly right.
MarkerWritten bool
// ExcludePath is the ignore file WB kept the rule in.
ExcludePath string
// ExcludeWritten is false when the rule was already present.
ExcludeWritten bool
}
Result reports what one Apply call did.
func Apply ¶
func Apply(descriptor Descriptor, excludePath string) (Result, error)
Apply writes the marker and its ignore rule, and is safe to run repeatedly.
The ignore rule goes first. A marker written before its rule exists is a dirty checkout for as long as the gap lasts, and WB's own pre-commit and pre-push hooks refuse a checkout with an untracked file — so the wrong order would, for that instant, break exactly the policy the marker describes.