cli

package
v0.3.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 29, 2026 License: Apache-2.0 Imports: 36 Imported by: 0

Documentation

Overview

Package cli holds embeddable Kong commands for the bones binary.

Each command type is a Kong-tagged struct with a Run method. The command tree is assembled in cmd/bones/cli.go alongside libfossil/cli and EdgeSync/cli.

Index

Constants

This section is empty.

Variables

View Source
var ErrHubRepoNotBootstrapped = errors.New("hub repo not bootstrapped")

ErrHubRepoNotBootstrapped is returned by hubRepoPath when the workspace has no hub.fossil yet. Callers can switch on this to emit role-appropriate guidance: orchestrator commands tell the user to run `bones up`; leaf commands (`swarm join`) refuse to bootstrap and tell the agent the orchestrator must do it.

Functions

This section is empty.

Types

type DoctorCmd added in v0.1.1

type DoctorCmd struct {
	edgecli.DoctorCmd
}

DoctorCmd extends EdgeSync's doctor with bones-specific checks. The embedded EdgeSync DoctorCmd runs the base health gate (Go runtime, fossil, NATS reachability, hooks); then this wrapper adds the swarm-session inventory described in ADR 0028 §"Process lifecycle and crash recovery" so stuck or cross-host slots surface here.

Embedded — not aliased — so EdgeSync's flags (--nats-url) still participate in Kong parsing.

func (*DoctorCmd) Run added in v0.1.1

func (c *DoctorCmd) Run(g *libfossilcli.Globals) error

Run invokes the EdgeSync doctor first; on completion (regardless of pass/warn/fail) it appends a "swarm sessions" section that iterates bones-swarm-sessions and reports each entry's state.

type DownCmd added in v0.3.0

type DownCmd struct {
	Yes        bool `name:"yes" short:"y" help:"skip the confirmation prompt"`
	KeepSkills bool `name:"keep-skills" help:"do not remove .claude/skills"`
	KeepHooks  bool `name:"keep-hooks" help:"do not edit .claude/settings.json"`
	KeepHub    bool `name:"keep-hub" help:"do not stop hub or remove .orchestrator/"`
	DryRun     bool `name:"dry-run" help:"print plan without executing"`
}

DownCmd reverses bones up: stops the hub, removes the workspace marker (.bones/), the orchestrator state (.orchestrator/), the scaffolded skills (.claude/skills/{orchestrator,subagent, uninstall-bones}), and the bones-installed SessionStart/Stop hooks from .claude/settings.json. Other hooks in settings.json are left untouched.

Destructive — requires --yes or an interactive y/N confirmation. Idempotent: re-running on a clean tree is a no-op.

func (*DownCmd) Run added in v0.3.0

func (c *DownCmd) Run(g *libfossilcli.Globals) error

Run is the Kong entry point. Resolves the workspace root (walking up from cwd if a marker exists, falling back to cwd otherwise), builds an execution plan, prompts unless --yes, and executes.

type HubCmd added in v0.1.1

type HubCmd struct {
	Start HubStartCmd `cmd:"" help:"Start the embedded Fossil hub + NATS server"`
	Stop  HubStopCmd  `cmd:"" help:"Stop the embedded Fossil hub + NATS server"`
	User  HubUserCmd  `cmd:"" help:"Manage fossil users in the hub repo"`
}

HubCmd is the umbrella command for the embedded Fossil + NATS hub.

Subcommands:

hub start [--detach]    bring the hub up
hub stop                tear it down
hub user add <login>    pre-create a fossil user in the hub repo
hub user list           list fossil users in the hub repo

The shipped scripts under .orchestrator/scripts/ are thin shims around these subcommands, kept for backward compatibility with .claude/settings.json hooks generated before the Go-native hub.

type HubStartCmd added in v0.1.1

type HubStartCmd struct {
	Detach     bool `name:"detach" help:"return immediately after the hub is reachable"`
	FossilPort int  `name:"fossil-port" help:"Fossil HTTP port" default:"8765"`
	NATSPort   int  `name:"nats-port" help:"NATS client port" default:"4222"`
}

HubStartCmd wires `bones hub start` flags to hub.Start.

--detach (default false) is what shell hooks want: spawn a background hub and return immediately once both servers are reachable. Without --detach, the command runs the hub in the foreground and shuts both servers down on SIGINT/SIGTERM. Foreground mode is the easiest way to see hub logs interactively.

func (*HubStartCmd) Run added in v0.1.1

type HubStopCmd added in v0.1.1

type HubStopCmd struct{}

HubStopCmd wires `bones hub stop` to hub.Stop. Idempotent.

func (*HubStopCmd) Run added in v0.1.1

func (c *HubStopCmd) Run(g *libfossilcli.Globals) error

type HubUserAddCmd added in v0.1.1

type HubUserAddCmd struct {
	Login string `arg:"" help:"login (e.g. slot-rendering)"`
	Caps  string `name:"caps" default:"oih" help:"fossil caps (default: clone+checkin+history)"`
}

HubUserAddCmd creates a user in the hub repo. Idempotent: if the user already exists, exits 0 without changing anything.

func (*HubUserAddCmd) Run added in v0.1.1

type HubUserCmd added in v0.1.1

type HubUserCmd struct {
	Add  HubUserAddCmd  `cmd:"" help:"Add (or noop-if-exists) a user to the hub repo"`
	List HubUserListCmd `cmd:"" help:"List users in the hub repo"`
}

HubUserCmd groups subcommands that manage the fossil user table on the hub repo (.orchestrator/hub.fossil). The table is consulted by every `fossil commit --user X` against that repo, so swarm slots that commit under their own identity (slot-rendering, slot-physics, etc.) must exist here first or fossil rejects the commit with "no such user."

This primitive is the manual escape hatch; future swarm-join tooling will call into the same internal helpers automatically.

type HubUserListCmd added in v0.1.1

type HubUserListCmd struct{}

HubUserListCmd prints the hub repo's user table.

func (*HubUserListCmd) Run added in v0.1.1

type InitCmd

type InitCmd struct{}

InitCmd creates a new bones workspace in the current directory.

func (*InitCmd) Run

func (c *InitCmd) Run(g *libfossilcli.Globals) error

type JoinCmd

type JoinCmd struct{}

JoinCmd locates and verifies an existing workspace from cwd.

func (*JoinCmd) Run

func (c *JoinCmd) Run(g *libfossilcli.Globals) error

type OrchestratorCmd

type OrchestratorCmd struct{}

OrchestratorCmd installs the hub-leaf orchestrator scripts, skills, and Claude Code hooks into an existing workspace.

func (*OrchestratorCmd) Run

type PeekCmd added in v0.1.1

type PeekCmd struct {
	Port int    `name:"port" help:"bind the UI on this port (default: fossil chooses)"`
	Page string `name:"page" default:"timeline?y=ci&n=50" help:"fossil page (e.g. timeline)"`
}

PeekCmd opens the workspace's hub Fossil repo in the system fossil binary's web UI (timeline, branches, files). It is an *enhancement*, not a hard dependency: when `fossil` isn't on PATH, peek prints the hub repo path with a one-line install hint and exits cleanly.

libfossil's embedded HTTP server (used by `bones hub start` to serve /xfer for sync) does not implement the rich Fossil web UI; peek shells out to the canonical `fossil ui` for that.

func (*PeekCmd) Run added in v0.1.1

func (c *PeekCmd) Run(g *libfossilcli.Globals) error

type SwarmCloseCmd added in v0.1.1

type SwarmCloseCmd struct {
	Slot    string `name:"slot" help:"slot name (defaults to single active slot on this host)"`
	Result  string `name:"result" default:"success" help:"success|fail|fork"`
	Summary string `name:"summary" default:"swarm close" help:"final summary posted to task thread"`
	Branch  string `name:"branch" help:"only with --result=fork: branch name"`
	Rev     string `name:"rev" help:"only with --result=fork: rev"`
	HubURL  string `name:"hub-url" help:"override hub fossil HTTP URL"`
}

SwarmCloseCmd ends a swarm session: posts a dispatch.ResultMessage to the task thread, then has the lease close the task in KV (on result=success), release the claim hold, stop the leaf, remove the host-local pid file, and CAS-delete the session record.

Idempotent against partial-cleanup states: a missing session record (already closed) is not an error so re-running close after a crash converges.

func (*SwarmCloseCmd) Run added in v0.1.1

type SwarmCmd added in v0.1.1

type SwarmCmd struct {
	Join   SwarmJoinCmd   `cmd:"" help:"Open a leaf, claim a task, prepare a worktree"`
	Commit SwarmCommitCmd `cmd:"" help:"Commit changes (heartbeats the session)"`
	Close  SwarmCloseCmd  `cmd:"" help:"Release claim, post result, stop the leaf"`
	Status SwarmStatusCmd `cmd:"" help:"List active swarm sessions"`
	Cwd    SwarmCwdCmd    `cmd:"" help:"Print the slot's worktree path"`
	Tasks  SwarmTasksCmd  `cmd:"" help:"List ready tasks matching slot"`
	FanIn  SwarmFanInCmd  `cmd:"" name:"fan-in" help:"Merge open hub leaves into trunk"`
}

SwarmCmd groups the agent-shaped swarm verbs introduced in ADR 0028: per-slot leaf lifecycle wrapped around coord.Leaf so subagent prompts shrink from ~12 substrate calls to ~5 swarm verbs.

All verbs are workspace-local (joinWorkspace from cwd). Agent prompts run them as plain shell commands; the orchestrator skill (R6 follow-up) renders them inline.

type SwarmCommitCmd added in v0.1.1

type SwarmCommitCmd struct {
	Slot       string   `name:"slot" help:"slot name (defaults to single active slot on this host)"`
	Message    string   `name:"message" short:"m" required:"" help:"commit message"`
	Files      []string `arg:"" optional:"" help:"files to commit (default: all modified)"`
	HubURL     string   `name:"hub-url" help:"override hub fossil HTTP URL"`
	NoAutosync bool     `name:"no-autosync" help:"branch-per-slot mode (skip pre-commit hub pull)"`
}

SwarmCommitCmd commits in-flight changes from the slot's worktree to the slot's leaf, triggers a sync round to the hub, and bumps the swarm session record's TTL via CAS.

Files default to "all modified files in wt/" if no positional arguments are passed.

All the assembled scaffold (Resume the lease, claim, announce holds, commit via leaf, push to hub, renew session) lives in internal/swarm.ResumedLease. This verb is flag parsing + file gathering + ResumedLease.Commit + result printing.

func (*SwarmCommitCmd) Run added in v0.1.1

type SwarmCwdCmd added in v0.1.1

type SwarmCwdCmd struct {
	Slot string `name:"slot" required:"" help:"slot name"`
}

SwarmCwdCmd prints the slot's worktree path on stdout. Designed for shell substitution:

cd "$(bones swarm cwd --slot=rendering)"

Pure path derivation — no NATS round-trip, no KV lookup. Only requires a workspace context to compute the absolute path. Callers who want the wt path AND a liveness check should use `swarm status`.

func (*SwarmCwdCmd) Run added in v0.1.1

type SwarmFanInCmd added in v0.1.1

type SwarmFanInCmd struct {
	User    string `name:"user" default:"orchestrator" help:"fossil user attributed to merge"`
	Message string `name:"message" short:"m" default:"" help:"merge commit message"`
	DryRun  bool   `name:"dry-run" help:"show what would be merged without committing"`
}

SwarmFanInCmd merges every open leaf on the hub repo's trunk into a single integration tip. After Phase 1 swarm slots close, the hub typically has N leaves (one per slot lineage) — fan-in collapses them so a downstream `fossil update` materializes a single merged working tree.

Implementation shells out to the system `fossil` binary because libfossil's Repo.Merge requires distinct src/dst branch names, but concurrent slot work produces sibling leaves on the SAME branch (typically trunk). Same-branch leaf merging needs the multi-step orchestration fossil's CLI does (open temp checkout → fossil merge <UUID> → fossil commit). Acceptable: fan-in is an admin-scale operation invoked once per swarm, not a hot path; the same `fossil` dependency is already used by `bones peek`.

On systems without `fossil` on PATH, `bones swarm fan-in` prints an install hint and exits non-zero so a wrapping orchestrator can fall back to manual instructions.

func (*SwarmFanInCmd) Run added in v0.1.1

type SwarmJoinCmd added in v0.1.1

type SwarmJoinCmd struct {
	Slot          string `name:"slot" required:"" help:"slot name (matches plan [slot: X])"`
	TaskID        string `name:"task-id" required:"" help:"open task id to claim"`
	Caps          string `name:"caps" default:"oih" help:"fossil caps for the slot user"`
	ForceTakeover bool   `name:"force" help:"clobber an existing slot session (recovery only)"`
	HubURL        string `name:"hub-url" help:"override hub fossil HTTP URL"`
	NoAutosync    bool   `name:"no-autosync" help:"branch-per-slot mode (skip pre-commit hub pull)"`
}

SwarmJoinCmd opens a per-slot leaf, ensures the slot's fossil user exists in the hub, claims the named task, writes the swarm session record to KV, and prints the slot's worktree path on stdout (for `cd $(bones swarm cwd ...)`-style sourcing).

On a successful return, the leaf process has been stopped (per the per-CLI-invocation lifetime contract — ADR 0028 §"Process lifecycle"). The session record persists so subsequent `swarm commit` and `swarm close` invocations can Resume.

All the assembly (workspace check, fossil-user creation, KV session record CAS, leaf open/claim) lives in internal/swarm (ADR 0028). This verb is a thin adapter from CLI flags to swarm.Acquire + FreshLease.Release.

func (*SwarmJoinCmd) Run added in v0.1.1

Run drives the join flow per ADR 0028 §"swarm join", via swarm.Acquire: open workspace, Acquire (which does the role-guard check, ensures the slot user, CAS-writes the session record, opens the leaf, claims the task, writes the pid file), emit the report, FreshLease.Release.

type SwarmStatusCmd added in v0.1.1

type SwarmStatusCmd struct {
	JSON bool `name:"json" help:"emit JSON"`
}

SwarmStatusCmd lists every active swarm session in the workspace. Output is derived purely from KV state — there is no per-process liveness probe because every swarm verb is a fresh CLI invocation whose pid dies at end of verb. LastRenewed is the canonical signal: active = renewed within activeThresholdSec, stale = older.

func (*SwarmStatusCmd) Run added in v0.1.1

type SwarmTasksCmd added in v0.1.1

type SwarmTasksCmd struct {
	Slot string `name:"slot" required:"" help:"slot name"`
	JSON bool   `name:"json" help:"emit JSON"`
}

SwarmTasksCmd lists ready tasks scoped to a slot. Wraps the same readiness model as `bones tasks list --ready` (coord.Ready handles blocks/supersedes/duplicates/parent edges) and filters the result to tasks whose slot annotation matches --slot.

Slot membership is resolved in three places, first-match-wins:

  1. Task.Context["slot"] equals --slot
  2. Task title contains "[slot: <name>]" literal
  3. Any file path starts with "<slot>/" or contains "/<slot>/"

(3) mirrors the validate_plan slot-disjointness rule so plans that don't yet stamp Context["slot"] still surface their tasks here.

func (*SwarmTasksCmd) Run added in v0.1.1

type TasksAggregateCmd

type TasksAggregateCmd struct {
	Since time.Duration `name:"since" default:"1h" help:"window size"`
	JSON  bool          `name:"json" help:"emit JSON"`
}

TasksAggregateCmd produces a per-slot summary of tasks within a window.

func (*TasksAggregateCmd) Run

type TasksAutoclaimCmd

type TasksAutoclaimCmd struct {
	Enabled  *bool         `name:"enabled" help:"enable tick (default: env AGENT_INFRA_AUTOCLAIM)"`
	Idle     bool          `name:"idle" default:"true" help:"treat session as idle for this tick"`
	ClaimTTL time.Duration `name:"claim-ttl" default:"1m" help:"claim TTL for auto-claimed task"`
}

TasksAutoclaimCmd runs a single autoclaim tick: if the session is idle and no task is currently claimed by this agent, atomically pick the oldest Ready task and claim it, then post a "claimed by" notice on the task thread.

One-shot — the caller (e.g. an agent harness's idle hook) decides when to invoke. There is no daemon mode; if a `--watch` mode is ever needed, the helper below moves into a package. ADR 0035 records why this lives here for now.

func (*TasksAutoclaimCmd) Run

type TasksClaimCmd

type TasksClaimCmd struct {
	ID   string `arg:"" help:"task id"`
	JSON bool   `name:"json" help:"emit JSON"`
}

TasksClaimCmd claims a task as the current agent.

func (*TasksClaimCmd) Run

type TasksCloseCmd

type TasksCloseCmd struct {
	ID     string `arg:"" help:"task id"`
	Reason string `name:"reason" help:"close reason (optional)"`
	JSON   bool   `name:"json" help:"emit JSON"`
}

TasksCloseCmd closes a task.

func (*TasksCloseCmd) Run

type TasksCmd

type TasksCmd struct {
	Create    TasksCreateCmd    `cmd:"" help:"Create a new task"`
	List      TasksListCmd      `cmd:"" help:"List tasks"`
	Show      TasksShowCmd      `cmd:"" help:"Show a task"`
	Update    TasksUpdateCmd    `cmd:"" help:"Update a task"`
	Claim     TasksClaimCmd     `cmd:"" help:"Claim a task"`
	Close     TasksCloseCmd     `cmd:"" help:"Close a task"`
	Watch     TasksWatchCmd     `cmd:"" help:"Stream task lifecycle events"`
	Status    TasksStatusCmd    `cmd:"" help:"Snapshot of all tasks by status"`
	Link      TasksLinkCmd      `cmd:"" help:"Link two tasks with an edge type"`
	Prime     TasksPrimeCmd     `cmd:"" help:"Print agent-tasks context (prime)"`
	Autoclaim TasksAutoclaimCmd `cmd:"" help:"Run one autoclaim tick"`
	Dispatch  TasksDispatchCmd  `cmd:"" hidden:"" help:"Dispatch parent/worker (hub-only)"`
	Aggregate TasksAggregateCmd `cmd:"" help:"Aggregate per-slot task summary"`
}

TasksCmd groups all `bones tasks <verb>` subcommands. The Hipp audit folded ready/stale/orphans/preflight (plus the literal 'add' alias of 'create') into 'list' filter flags; dispatch is hub-only and hidden.

type TasksCreateCmd

type TasksCreateCmd struct {
	Title      string   `arg:"" help:"task title"`
	Files      string   `name:"files" help:"comma-separated file list"`
	Parent     string   `name:"parent" help:"parent task id"`
	DeferUntil string   `name:"defer-until" help:"RFC3339 time"`
	Slot       string   `name:"slot" help:"slot name; stamps Context[slot]"`
	Context    []string `name:"context" help:"key=value (repeatable)" sep:"none"`
	JSON       bool     `name:"json" help:"emit JSON"`
}

TasksCreateCmd creates a new task.

func (*TasksCreateCmd) Run

type TasksDispatchCmd

type TasksDispatchCmd struct {
	Parent TasksDispatchParentCmd `cmd:"" help:"Run dispatch parent"`
	Worker TasksDispatchWorkerCmd `cmd:"" help:"Run dispatch worker"`
}

TasksDispatchCmd groups dispatch parent/worker subcommands.

type TasksDispatchParentCmd

type TasksDispatchParentCmd struct {
	TaskID             string `name:"task-id" required:"" help:"task id"`
	WorkerBin          string `name:"worker-bin" help:"worker binary path (default: this process)"`
	WorkerResult       string `name:"worker-result" default:"success" help:"worker final result"`
	WorkerSummary      string `name:"worker-summary" default:"done" help:"worker final summary"`
	WorkerClaimHandoff bool   `name:"worker-claim-handoff" help:"worker takes claim ownership"`
}

TasksDispatchParentCmd runs the parent side of the dispatch flow: spawn a worker process, subscribe for its result, then close/fork the claimed task accordingly.

func (*TasksDispatchParentCmd) Run

type TasksDispatchWorkerCmd

type TasksDispatchWorkerCmd struct {
	TaskID           string        `name:"task-id" required:"" help:"task id"`
	TaskThread       string        `name:"task-thread" required:"" help:"task chat thread"`
	WorkerAgentID    string        `name:"worker-agent-id" required:"" help:"worker agent id"`
	ClaimFromAgentID string        `name:"claim-from-agent-id" help:"expected previous claimer"`
	HandoffTTL       time.Duration `name:"handoff-ttl" default:"30s" help:"handoff hold ttl"`
	Result           string        `name:"result" default:"success" help:"success|fork|fail"`
	Summary          string        `name:"summary" default:"done" help:"final summary"`
	Branch           string        `name:"branch" help:"fork branch"`
	Rev              string        `name:"rev" help:"fork rev"`
}

TasksDispatchWorkerCmd runs the worker side of the dispatch flow: optionally take over a claim, post progress to the task thread, then close (on success-with-handoff) or just announce the result.

func (*TasksDispatchWorkerCmd) Run

type TasksLinkCmd

type TasksLinkCmd struct {
	From string `arg:"" help:"from task id"`
	To   string `arg:"" help:"to task id"`
	Type string `name:"type" help:"edge type: blocks|supersedes|duplicates|discovered-from"`
	JSON bool   `name:"json" help:"emit JSON"`
}

TasksLinkCmd links two tasks with a typed edge.

func (*TasksLinkCmd) Run

type TasksListCmd

type TasksListCmd struct {
	All       bool   `name:"all" help:"include closed tasks"`
	Status    string `name:"status" help:"open|claimed|closed"`
	ClaimedBy string `name:"claimed-by" help:"agent id, or - for unclaimed"`
	Ready     bool   `name:"ready" help:"only tasks ready to claim (open, unblocked, not deferred)"`
	Stale     int    `name:"stale" help:"only tasks not updated in N days; 0 = off"`
	Orphans   bool   `name:"orphans" help:"only claimed tasks whose claimer is offline"`
	JSON      bool   `name:"json" help:"emit JSON"`
}

TasksListCmd lists tasks. Filter flags compose: status → ready → stale → orphans. --ready and --orphans require a coord session; --stale and the others run from the in-memory task list only.

func (*TasksListCmd) Run

type TasksPrimeCmd

type TasksPrimeCmd struct {
	JSON bool `name:"json" help:"emit JSON"`
}

TasksPrimeCmd prints an agent context summary (open/ready/claimed tasks, recent threads, peers online).

func (*TasksPrimeCmd) Run

type TasksShowCmd

type TasksShowCmd struct {
	ID   string `arg:"" help:"task id"`
	JSON bool   `name:"json" help:"emit JSON"`
}

TasksShowCmd prints a single task.

func (*TasksShowCmd) Run

type TasksStatusCmd

type TasksStatusCmd struct{}

TasksStatusCmd prints a one-shot snapshot of hub and backlog state.

Output:

hub:      http://127.0.0.1:8765 (pid 12345)
nats:     nats://127.0.0.1:4222
backlog:  3 open · 1 claimed · 2 closed (last 24h)

func (*TasksStatusCmd) Run

type TasksUpdateCmd

type TasksUpdateCmd struct {
	ID         string   `arg:"" help:"task id"`
	Status     string   `name:"status" help:"open|claimed|closed"`
	Title      *string  `name:"title" help:"new title"`
	Files      *string  `name:"files" help:"comma-separated file list (replaces existing)"`
	Parent     *string  `name:"parent" help:"parent task id"`
	DeferUntil *string  `name:"defer-until" help:"RFC3339 time (empty clears)"`
	Context    []string `name:"context" help:"key=value (repeatable; merges)" sep:"none"`
	ClaimedBy  *string  `name:"claimed-by" help:"agent id to claim as"`
	JSON       bool     `name:"json" help:"emit JSON"`
}

TasksUpdateCmd updates a task. Flags are pointer-typed so we can detect "flag absent" vs "flag set to empty string" — a distinction the underlying mutator depends on (only set fields get applied).

func (*TasksUpdateCmd) Run

type TasksWatchCmd

type TasksWatchCmd struct{}

TasksWatchCmd subscribes to the tasks KV bucket and streams human-readable lifecycle events to stdout until Ctrl-C or context cancellation.

func (*TasksWatchCmd) Run

type UpCmd

type UpCmd struct{}

UpCmd performs full bootstrap from a fresh clone: workspace init, orchestrator scaffold, leaf binary resolution, and hub bootstrap.

func (*UpCmd) Run

func (c *UpCmd) Run(g *libfossilcli.Globals) error

type ValidatePlanCmd

type ValidatePlanCmd struct {
	Path      string `arg:"" type:"existingfile" help:"Markdown plan path"`
	ListSlots bool   `name:"list-slots" help:"emit JSON slot→task list (still runs validation)"`
}

ValidatePlanCmd parses a Markdown plan, extracts [slot: name] annotations, and verifies:

  1. Every Task heading has a [slot: name].
  2. Slots are directory-disjoint (no two slots share a directory prefix).
  3. Each task's Files: paths begin with the slot's owned directory.

Exits 0 if valid, 1 if violations are reported. With --list-slots, also emits a JSON slot→task mapping to stdout on success.

func (*ValidatePlanCmd) Run

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL