config

package
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: Jul 7, 2026 License: Apache-2.0 Imports: 15 Imported by: 0

Documentation

Index

Constants

View Source
const (
	BlockOriginNamespace = "namespace"
	BlockOriginMod       = "mod"
	BlockOriginCustom    = "custom"
)

Block origins stored on sandbox records, lowest to highest precedence. Frozen (see VMState) — and doubly so here: blockOriginRank sends unknown strings to the lowest precedence, so a renamed origin would silently invert which rules win.

View Source
const DefaultNamespace = "default"

DefaultNamespace is the grouping a sandbox belongs to when none is set.

View Source
const DefaultPolicyName = "default"

DefaultPolicyName is reserved for the built-in dev allowlist; it can be loaded but never saved or deleted, and it is the chain a sandbox gets when no `use` list was ever written.

View Source
const RecordSchemaVersion = 1

RecordSchemaVersion is the current shape of a sandbox record's JSON, stamped onto Sandbox.RecordSchema at every Save. Bump only when a record written by this clawk would be misread by the previous one — additive omitempty fields don't count.

Variables

View Source
var DefaultAllowedDomains = []string{}/* 137 elements not displayed */

DefaultAllowedDomains are domains allowed by default for development. Originally seeded from Andrew Lock's microVM sandbox allow list: https://andrewlock.net/running-ai-agents-safely-in-a-microvm-using-docker-sandbox/

Every entry here is a contract in both directions: removing one after release breaks users who rely on it, and each one is a destination the agent can reach without asking — i.e. a potential exfiltration endpoint. Additions must be (a) operated by the organization they claim to serve and (b) needed by a mainstream development workflow, not one project. When in doubt, leave it out — users can `clawk network allow` per sandbox or per namespace.

View Source
var ErrPolicyNotFound = errors.New("policy not found")

ErrPolicyNotFound is returned by LoadPolicy for a name with no record on disk (and no builtin).

Functions

func CurrentSchemaVersion

func CurrentSchemaVersion() int

CurrentSchemaVersion is the schema version this build targets.

func DisplayName

func DisplayName(key string) string

DisplayName is the human-facing form of a store key. It currently returns the key unchanged — anchored sandboxes are keyed by a clean `<base>` and carry their binding in Sandbox.Anchor, so no key needs rewriting for display. Retained as the single seam every surface (`clawk list`/`status`, the workspace CLAUDE.md, the menubar) routes through, should display names ever need to diverge from keys again.

Types

type HostFile

type HostFile struct {
	HostPath  string `json:"host_path"`
	GuestPath string `json:"guest_path"`
	Mode      uint32 `json:"mode,omitempty"`
}

HostFile is a snapshot-on-up file pushed from host into guest. Sourced from clawk.mod `files (...)` and refreshed on every `clawk up` — edits on the host are NOT live (use HostShare for that). HostPath is tilde- and env-expanded at compose time; Mode == 0 preserves the host file's permissions.

type HostShare

type HostShare struct {
	HostPath  string `json:"host_path"`
	GuestPath string `json:"guest_path"`
	ReadOnly  bool   `json:"read_only"`
}

HostShare is a virtio-fs live mount from host directory into guest. Sourced from clawk.mod `shares (...)`. Reflects on the host immediately — credentials that rotate underneath (~/.aws after `aws sts assume-role`, ~/.config/gcloud) stay in sync without a clawk-up cycle. Defaults to ReadOnly=true at parse time so an accidental in-VM write can't clobber the host credential.

type Namespace

type Namespace struct {
	Name           string   `json:"name"`
	AllowedDomains []string `json:"allowed_domains,omitempty"`
	AllowedIPs     []string `json:"allowed_ips,omitempty"`
	// DeniedDomains are blocked outright (a block overrides any allow). They
	// come from inline `deny` entries; `deny source "<url>"` blocklists are
	// registered as source policies referenced via Use instead.
	DeniedDomains []string `json:"denied_domains,omitempty"`
	// DeniedIPs are the IP/CIDR counterparts of DeniedDomains, from
	// `deny ip <addr>` entries in a namespace manifest.
	DeniedIPs []string `json:"denied_ips,omitempty"`
	// Use names the policies forming the base of every member sandbox's
	// chain, in increasing precedence. nil means unspecified (the built-in
	// "default" applies unless a sandbox writes its own list); a non-nil
	// list is complete. Together with the inline allow/deny entries above,
	// these resolve live at up/reload — they are never copied into
	// sandbox records, so a namespace edit propagates to existing members.
	Use    []string    `json:"use,omitempty"`
	Files  []HostFile  `json:"files,omitempty"`
	Shares []HostShare `json:"shares,omitempty"`
	Env    []string    `json:"env,omitempty"`
	// Instructions and Memory seed every sandbox in the namespace: extra
	// CLAUDE.md guidance and baseline auto-memory respectively. They merge
	// with a repo's clawk.mod equivalents — namespace first, as the broader
	// scope — in applyNamespaceDefaults.
	Instructions []string `json:"instructions,omitempty"`
	Memory       string   `json:"memory,omitempty"`
}

Namespace holds per-namespace defaults merged into every sandbox created in it: a shared network allowlist plus files/shares/env injected into each sandbox (e.g. context markdown). Stored at namespaces/<name>/namespace.json, co-located with that namespace's sandboxes — so a namespace's whole footprint (config + sandboxes) is one directory. An empty namespace is fine: it's a pure grouping until you give it defaults.

type NetworkBlock

type NetworkBlock struct {
	Origin       string   `json:"origin"`
	Name         string   `json:"name,omitempty"`
	AllowDomains []string `json:"allow_domains,omitempty"`
	AllowIPs     []string `json:"allow_ips,omitempty"`
	DenyDomains  []string `json:"deny_domains,omitempty"`
	DenyIPs      []string `json:"deny_ips,omitempty"`
}

NetworkBlock is one origin-labeled layer of a sandbox's network policy. Origins mirror the chain in the design doc: "namespace" and "mod" carry file-composed entries, "custom" carries CLI edits and persisted interactive grants. Policy-referenced layers ("default", "policy", "source") are never stored on the sandbox — they resolve from Use at up/reload so a policy edit propagates without rewriting sandbox records.

type NetworkPolicy

type NetworkPolicy struct {
	// AllowedDomains, AllowedIPs and DeniedDomains are the legacy flat
	// policy of pre-block sandbox records. Normalize folds them into the
	// "custom" block on load; new records are written block-shaped and
	// leave these empty.
	AllowedDomains []string `json:"allowed_domains,omitempty"`
	AllowedIPs     []string `json:"allowed_ips,omitempty"`
	// DeniedDomains are blocked outright — the domain and every subdomain.
	// A block overrides any allow and suppresses the interactive prompt, so
	// the agent is refused immediately without asking again. Entries are
	// registrable (root) domains: "telemetry.example.com" is blocked by an
	// entry of "example.com".
	DeniedDomains []string `json:"denied_domains,omitempty"`

	// Use names the policies whose blocks form the base of this sandbox's
	// chain, in increasing precedence. nil means the chain was never made
	// explicit and resolves to ["default"]; a non-nil list is complete —
	// include "default" where wanted.
	Use []string `json:"use,omitempty"`
	// Blocks are the sandbox's own policy layers, lowest precedence first.
	// They sit above every Use-referenced policy; the "custom" block (CLI
	// edits and persisted interactive grants) stays last, above the "mod"
	// block (entries composed from clawk.mod).
	Blocks []NetworkBlock `json:"blocks,omitempty"`
}

NetworkPolicy controls outbound network access from the sandbox.

AllowedDomains support wildcards like "*.example.com" and are matched at DNS-resolution time. AllowedIPs accept plain addresses or CIDR ranges like "10.0.0.0/24" and are checked on every TCP SYN, catching direct-IP connections (useful for provisioning new servers that don't have DNS yet).

func (*NetworkPolicy) Block

func (n *NetworkPolicy) Block(origin string) *NetworkBlock

Block returns the policy's layer with the given origin, appending an empty one if absent. The returned pointer is valid until Blocks next grows — mutate it before any further Block call.

func (*NetworkPolicy) Normalize

func (n *NetworkPolicy) Normalize()

Normalize migrates a legacy flat record into block form and restores the block-order invariant. Idempotent; the store applies it on every load.

type Phase

type Phase struct {
	Repo     string      `json:"repo"`
	Branch   string      `json:"branch"`
	Status   PhaseStatus `json:"status"`
	Order    int         `json:"order"`
	Worktree string      `json:"worktree,omitempty"` // path to the git worktree on host
	Setup    []string    `json:"setup,omitempty"`    // commands to run in the VM after every boot (template `on up`)

	// OnCreate is the list of commands to run once after the very first
	// boot of the sandbox, before the runner attaches. Sourced from the
	// repo Clawkfile's `on create` block. Hard-fails the up — see
	// Sandbox.CreatePending.
	OnCreate []string `json:"on_create,omitempty"`
	// OnCreateAt records the wall-clock time `on create` last completed
	// successfully for this phase. Zero means it has not run yet (or the
	// sandbox is in the create-pending state). Used by up.go to decide
	// whether to run `on create` again after a failure.
	OnCreateAt time.Time `json:"on_create_at,omitempty"`

	// InPlace, if true, means Worktree points at the user's actual
	// directory rather than a dedicated git worktree. Set by
	// `clawk here`. Destroy skips `git worktree remove` for these.
	InPlace bool `json:"in_place,omitempty"`
}

type PhaseStatus

type PhaseStatus string
const (
	PhaseStatusPending PhaseStatus = "pending"
	PhaseStatusActive  PhaseStatus = "active"
	PhaseStatusMerged  PhaseStatus = "merged"
)

type Policy

type Policy struct {
	Name         string   `json:"name"`
	AllowDomains []string `json:"allow_domains,omitempty"`
	AllowIPs     []string `json:"allow_ips,omitempty"`
	DenyDomains  []string `json:"deny_domains,omitempty"`
	DenyIPs      []string `json:"deny_ips,omitempty"`
	// Source is an external blocklist URL (hosts/Adblock/plain formats).
	// Fetched entries live in the sibling cache file, not here.
	Source string `json:"source,omitempty"`
	// Refresh bounds cache staleness, as a Go duration string ("24h").
	Refresh string `json:"refresh,omitempty"`
}

Policy is a named, reusable block of network rules, referenced from sandboxes via `use <name>`. Stored at policies/<name>/policy.json.

func BuiltinDefaultPolicy

func BuiltinDefaultPolicy() *Policy

BuiltinDefaultPolicy is the "default" chain block: the dev allowlist. It is never stored on disk — LoadPolicy synthesizes it so a `use default` entry always resolves.

func (*Policy) RefreshInterval

func (p *Policy) RefreshInterval() (time.Duration, error)

RefreshInterval returns the policy's refresh interval, defaulting to 24h when unset.

type PolicyCache

type PolicyCache struct {
	FetchedAt    time.Time `json:"fetched_at"`
	ETag         string    `json:"etag,omitempty"`
	DenyDomains  []string  `json:"deny_domains"`
	AllowDomains []string  `json:"allow_domains,omitempty"` // @@ exceptions
}

PolicyCache holds entries fetched from Policy.Source. Regenerable; stored at policies/<name>/cache.json.

type PortForward

type PortForward struct {
	HostPort  int `json:"host_port"`
	GuestPort int `json:"guest_port"`
}

PortForward maps a host port to a guest port so services running in the VM are reachable from the host (e.g., dev servers). Applied at VM start time; changes require an `up` cycle to take effect.

func (PortForward) String

func (p PortForward) String() string

type Provider

type Provider string

Provider identifies which VM backend runs a sandbox. Values are persisted in sandbox records and clawk.mod files — frozen (see VMState); legacyProviderVFKit below is what a rename costs.

const (
	// ProviderVZ runs sandboxes on macOS via Apple's
	// Virtualization.framework (no external VMM binary) with gvproxy for
	// userspace networking and ACL enforcement. The default on macOS.
	ProviderVZ Provider = "vz"
	// ProviderFirecracker runs sandboxes on Linux via Firecracker.
	// Networking is TAP-on-bridge with no host-side filtering.
	ProviderFirecracker Provider = "firecracker"
)

func (Provider) Normalize

func (p Provider) Normalize() Provider

Normalize maps retired provider identifiers onto their current equivalent so configs written before a rename keep working. Unknown values pass through unchanged for the caller to reject with a clear error.

type Sandbox

type Sandbox struct {
	Name     string   `json:"name"`
	Provider Provider `json:"provider"`
	Profile  string   `json:"profile,omitempty"` // active overlay profile (if any)
	// Namespace groups the sandbox for organization and (Phase 2)
	// per-namespace defaults. Empty is treated as DefaultNamespace; use
	// NamespaceName for the resolved value.
	Namespace string `json:"namespace,omitempty"`
	// Anchor is the directory this sandbox is bound to, set for sandboxes
	// created by the bare `clawk` invocation (addressed by being in the
	// directory rather than by a typed name). Empty means the sandbox is
	// explicitly named. Its presence is the cwd-vs-ticket discriminator.
	Anchor string `json:"anchor,omitempty"`
	// DesiredState is the lifecycle state the user wants: VMStateRunning after
	// `clawk up`, VMStateStopped after `clawk down`. Empty means no explicit
	// intent yet. It's *spec* (desired), distinct from VMState below (*status*,
	// observed) — and it's what a future server-side reconciler converges to,
	// so the imperative up/down commands are already declarative edits.
	DesiredState VMState `json:"desired_state,omitempty"`
	// ResourceVersion increments on every spec write. Groundwork for optimistic
	// concurrency once there are multiple writers (the cloud control plane);
	// today it's just a monotonic "this record changed" counter.
	ResourceVersion int `json:"resource_version,omitempty"`
	// RecordSchema is the schema version of this record's JSON shape,
	// stamped by Store.Save on every write (RecordSchemaVersion). Distinct
	// from the store-wide version in meta.json: that one drives directory
	// migrations, this one says which clawk shape wrote THIS record, so a
	// selective per-record migration is possible without guesswork. Zero
	// means the record predates the field: schema 1.
	RecordSchema int           `json:"record_schema,omitempty"`
	Phases       []Phase       `json:"phases"`
	Network      NetworkPolicy `json:"network"`
	Forwards     []PortForward `json:"forwards,omitempty"`
	// Files is the list of host->guest file copies refreshed on every
	// `clawk up`. See HostFile. Empty = no snapshots.
	Files []HostFile `json:"files,omitempty"`
	// Shares is the list of host->guest virtio-fs live mounts. See
	// HostShare. Empty = no live mounts.
	//
	// Changes to this list require `clawk down && clawk up` to re-emit
	// the provider's device list, but the disk image survives.
	Shares []HostShare `json:"shares,omitempty"`
	// Instructions are extra persistent-guidance blocks rendered into the
	// generated workspace CLAUDE.md (see sandbox.WorkspaceDocFile), sourced
	// from the namespace and a repo's clawk.mod. Each entry is a markdown
	// block read on every boot — the place for "always ask before X" or
	// project conventions that must survive a throwaway VM.
	Instructions []string `json:"instructions,omitempty"`
	// Memory is seed content for the agent's auto-memory MEMORY.md, sourced
	// from the namespace and clawk.mod. Written into the memory dir once on
	// first boot and never afterward (see sandbox.SeedClaudeMemory), so a
	// fresh sandbox starts with baseline knowledge without clobbering memory
	// the agent has since accumulated.
	Memory string `json:"memory,omitempty"`
	// Image is the OCI image reference this sandbox boots as its root
	// filesystem (clawk.mod `vm ( image <ref> )`). The provider builds an
	// ext4 rootfs from the image (with clawk-init and the pty-agent
	// injected), boots it via direct-kernel, and the sandbox runs
	// sshd-free — all host access goes over the vsock agent.
	Image string `json:"image,omitempty"`
	// Kernel overrides the guest kernel the vz provider direct-boots: a
	// local vmlinux path or an http(s) URL. Empty = the default Kata
	// kernel. Declared via clawk.mod `vm ( kernel <path|url> )` or the
	// --kernel flag. The main use is supplying a KVM-enabled kernel for
	// nested virtualization (the stock Kata kernel has KVM disabled, so
	// the guest has no /dev/kvm).
	Kernel string `json:"kernel,omitempty"`
	// GuestABI records the guest-contract version (the clawk-init boot
	// manifest schema + the pty-agent vsock protocol; see
	// sandbox.CurrentGuestABI) baked into this sandbox's disk at create.
	// Guest binaries are never updated in place, so this is the record a
	// later host consults to fail readably ("recreate this sandbox")
	// instead of hitting an in-guest version error mid-boot. Zero means
	// the record predates the field: ABI 1.
	GuestABI int `json:"guest_abi,omitempty"`
	// RequiredEnv holds the names (not values) of host env vars this
	// sandbox wants exported inside the VM. Declared in clawk.mod via
	// `env ( NAME ... )`. Values are read from the host shell at
	// sandbox-create time and written to /etc/profile.d/99-clawk-env.sh
	// in the guest — never persisted to disk on the host alongside the
	// name so we don't check secrets into the sandbox state file.
	RequiredEnv []string `json:"required_env,omitempty"`
	// NestedVirt opts the VM into hardware-assisted nested
	// virtualization so the guest can run its own VMs (Docker with KVM,
	// Firecracker, etc.). Requires macOS 15+ and M3-or-newer Apple
	// Silicon. Enabled per-sandbox at create time; changes require a
	// destroy+recreate to take effect.
	NestedVirt bool `json:"nested_virt,omitempty"`

	// CPU is the vCPU count exposed to the guest. Zero means the provider
	// picks a default. Not a reservation — KVM and VZ don't charge host CPU
	// time for idle vCPUs.
	CPU uint `json:"cpu,omitempty"`

	// MemoryMiB is the baseline memory target in mebibytes. When
	// MemoryMaxMiB > MemoryMiB, providers that support virtio-balloon
	// reclaim (max - baseline) back to the host at boot and let the guest
	// grow on demand via deflate_on_oom. Zero = no ballooning.
	MemoryMiB uint64 `json:"memory_mib,omitempty"`

	// MemoryMaxMiB is the guest-visible hard cap on memory in mebibytes —
	// the amount allocated at boot. Zero = provider default.
	MemoryMaxMiB uint64 `json:"memory_max_mib,omitempty"`

	// IdleTimeoutSec is how long the sandbox may sit idle (no attached
	// session, quiescent guest) before its VM daemon stops it to reclaim
	// host memory. Zero = the built-in default; negative = never stop.
	// Declared via clawk.mod `vm ( idle_timeout <dur|off> )`. An idle stop
	// is a park, not a `clawk down`: DesiredState stays running and any
	// attach boots the VM back.
	IdleTimeoutSec int64 `json:"idle_timeout_sec,omitempty"`

	// --- Status: observed runtime state, NOT user-authoritative ---------------
	// A reconciled cache; the provider/OS is the source of truth. Reconcile via
	// observe() before trusting these for a decision (clawk list/status/migrate
	// already do).
	VMState VMState `json:"vm_state"`
	// StopReason records why the VM last left the running state, when the
	// stop wasn't an explicit user verb. Today the only value is
	// StopReasonIdle (the daemon parked an idle VM). Cleared on every boot
	// and on explicit `clawk down`, so a bare "stopped" always means the
	// user asked for it.
	StopReason StopReason `json:"stop_reason,omitempty"`
	VMPid      int        `json:"vm_pid,omitempty"`
	GuestIP    string     `json:"guest_ip,omitempty"`
	GatewayIP  string     `json:"gateway_ip,omitempty"`
	MACAddress string     `json:"mac_address,omitempty"`

	// CreatePending is set when one of the phase `on create` commands has
	// failed at least once. The VM is left running so the user can shell in
	// and investigate; runner attach is refused with an actionable message;
	// the next `clawk up` re-runs `on create` from scratch. `clawk destroy`
	// is the explicit reset.
	CreatePending bool `json:"create_pending,omitempty"`
	// CreatePendingReason carries the human-readable failure (phase name +
	// failing command + provider error) so `clawk status` can surface it
	// without re-running anything. Cleared on a successful `on create`.
	CreatePendingReason string `json:"create_pending_reason,omitempty"`

	// SessionProject is the stable identifier of the session-history repo
	// this sandbox's Claude Code conversations belong to (see
	// internal/sessions.ProjectID). Sandboxes that work on the same repo set
	// share one history repo — each on its own branch — so a fresh sandbox
	// for the same project boots with prior transcripts and memory. Computed
	// and persisted on first bring-up; empty on sandboxes created before the
	// feature, in which case it is derived again from the phases. Currently
	// populated by the vz provider only.
	SessionProject string `json:"session_project,omitempty"`

	CreatedAt time.Time `json:"created_at"`

	// PRRefreshedAt is the wall-clock time of the last successful
	// PR-state refresh via `gh`. v2 derives Phase.Status from PR
	// state; this timestamp gates a 60-second cache so `clawk
	// status` doesn't shell out on every invocation.
	PRRefreshedAt time.Time `json:"pr_refreshed_at,omitempty"`
}

func (*Sandbox) DisplayName

func (s *Sandbox) DisplayName() string

DisplayName returns the sandbox's human-facing name. See DisplayName.

func (*Sandbox) Key

func (s *Sandbox) Key() string

Key is the sandbox's store key, "<namespace>/<name>" — the identity the store resolves to an on-disk location. Bare names passed to the store (e.g. from CLI args) resolve to the default namespace; this is the explicit form for callers that hold the sandbox.

func (*Sandbox) NamespaceName

func (s *Sandbox) NamespaceName() string

NamespaceName is the sandbox's namespace, resolving the empty zero value to DefaultNamespace so callers never have to special-case it.

type StopReason

type StopReason string

StopReason qualifies a VMStateStopped that the user didn't ask for. Values are persisted in sandbox records — frozen (see VMState).

const StopReasonIdle StopReason = "idle"

StopReasonIdle marks a VM the daemon stopped after the sandbox sat idle past its idle timeout. Distinct from an explicit `clawk down` so the CLI can render "stopped (idle)" and the attach path knows a mid-attach shutdown was a park it should transparently boot through.

const StopReasonSuspended StopReason = "suspended"

StopReasonSuspended marks a VM stopped by `clawk snapshot`: its memory + device state sits in a suspend file next to the VM, and the next boot (resume, up, or any attach verb) restores it exactly where it left off instead of cold-booting. Rendered as "stopped (suspended)".

type Store

type Store struct {
	// contains filtered or unexported fields
}

func NewStore

func NewStore() (*Store, error)

func NewStoreAt

func NewStoreAt(rootDir string) *Store

NewStoreAt creates a Store rooted at an explicit directory, skipping the home-dir resolution and legacy migration NewStore does. Used by `clawk image gc` (which targets a caller-supplied clawk root) and by tests.

func (*Store) CacheDir

func (s *Store) CacheDir() string

CacheDir returns the shared cache directory.

func (*Store) Delete

func (s *Store) Delete(name string) error

func (*Store) DeletePolicy

func (s *Store) DeletePolicy(name string) error

DeletePolicy removes a policy's whole directory — record and cache both.

func (*Store) Exists

func (s *Store) Exists(name string) bool

func (*Store) HistoryDir

func (s *Store) HistoryDir() string

HistoryDir returns the root holding per-project session-history repos — the bare git repos that version Claude Code conversations across sandboxes (see internal/sessions). Lives outside per-sandbox dirs so destroying one sandbox never touches the shared history.

<rootDir>/history/<projectID>.git

func (*Store) List

func (s *Store) List() ([]Sandbox, error)

func (*Store) ListNamespaces

func (s *Store) ListNamespaces() ([]Namespace, error)

ListNamespaces returns every namespace present on disk — those with a namespace.json and those that merely hold sandboxes.

func (*Store) ListPolicies

func (s *Store) ListPolicies() ([]*Policy, error)

ListPolicies returns every policy record on disk, sorted by name. The builtin "default" is synthesized, not stored, so it never appears here.

func (*Store) Load

func (s *Store) Load(name string) (*Sandbox, error)

func (*Store) LoadNamespace

func (s *Store) LoadNamespace(name string) (*Namespace, error)

LoadNamespace returns a namespace's config. A namespace directory with no namespace.json yet (e.g. one that only holds sandboxes) returns an empty config, so "no record" reads as "no defaults" rather than an error.

func (*Store) LoadPolicy

func (s *Store) LoadPolicy(name string) (*Policy, error)

LoadPolicy returns a policy by name. The reserved name "default" resolves to BuiltinDefaultPolicy; an absent record returns ErrPolicyNotFound.

func (*Store) LoadPolicyCache

func (s *Store) LoadPolicyCache(name string) (*PolicyCache, error)

LoadPolicyCache returns a policy's fetched-entry cache. An absent cache reads as an empty one (zero FetchedAt → always stale), so "never fetched" needs no special casing at call sites.

func (*Store) NamespaceConfigExists

func (s *Store) NamespaceConfigExists(name string) bool

NamespaceConfigExists reports whether a namespace has a config record (vs. being a bare grouping that only holds sandboxes).

func (*Store) NamespaceConfigPath

func (s *Store) NamespaceConfigPath(name string) string

NamespaceConfigPath is the on-disk path of a namespace's config record (for `clawk namespace edit`).

func (*Store) RootDir

func (s *Store) RootDir() string

RootDir returns the top-level clawk directory (~/.clawk on a real host, or a temp dir for tests via NewStoreAt). Callers that need host-scoped artifacts living outside the per-sandbox subdirectories — provision.sh overrides, the long-lived OAuth token, image cache roots — anchor on this path.

func (*Store) RunMigrations

func (s *Store) RunMigrations(w io.Writer) error

RunMigrations replays every pending migration step in order, advancing the recorded version after each. Idempotent: steps already applied are skipped, and a step is safe to re-run. A disruptive step that defers running sandboxes does not advance the version (so it retries) and, by strict ordering, blocks later steps until it fully applies.

func (*Store) Save

func (s *Store) Save(sb *Sandbox) error

func (*Store) SaveNamespace

func (s *Store) SaveNamespace(ns *Namespace) error

func (*Store) SavePolicy

func (s *Store) SavePolicy(p *Policy) error

SavePolicy writes a policy record, validating its name first (the builtin "default" is reserved and cannot be overwritten).

func (*Store) SavePolicyCache

func (s *Store) SavePolicyCache(name string, c *PolicyCache) error

SavePolicyCache writes the fetched-entry cache for a policy. The cache is regenerable, so it lives beside the record rather than inside it — refresh is a one-file rewrite picked up by every referencing sandbox.

func (*Store) SchemaVersion

func (s *Store) SchemaVersion() int

SchemaVersion is the store's recorded on-disk schema version (0 if unset).

func (*Store) StateDir

func (s *Store) StateDir(sandboxName string) string

StateDir returns the per-sandbox persistent state directory — host storage that lives OUTSIDE the sandbox's VMDir and therefore survives destroy + recreate cycles. Used to mount Claude Code's conversation and memory directories from a stable location per sandbox name.

Layout:

<rootDir>/state/<sandboxName>/
  claude/
    projects/   # mounted as /home/agent/.claude/projects/
    memory/     # mounted as /home/agent/.claude/memory/

The directory is created lazily by callers that need it.

func (*Store) VMDir

func (s *Store) VMDir(sandboxName string) string

VMDir returns the VM state directory for a sandbox.

func (*Store) WorktreeDir

func (s *Store) WorktreeDir(sandboxName string) string

WorktreeDir returns the worktree directory for a sandbox.

type VMState

type VMState string
const (
	VMStateStopped VMState = "stopped"
	VMStateRunning VMState = "running"
)

VMState values are persisted in sandbox records: frozen — never rename an existing value, only add. Same rule for StopReason, Provider and the BlockOrigin* constants below; the vfkit→vz Provider rename left Normalize() carrying migration code forever, which is the tax this rule avoids.

Jump to

Keyboard shortcuts

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