contexts

package
v0.1.0-beta.15 Latest Latest
Warning

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

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

Documentation

Overview

Package contexts manages one canonical global agent-context file (AGENTS.md per the agents.md spec) and projects it into each linked client's global context mechanism: a dedicated file in a rules directory, an @-import shim line, or a marker-delimited managed block. Per-project AGENTS.md files stay version-controlled in their repos and are out of scope. Every operation is a pure file operation; no running gateway is required.

Index

Constants

View Source
const (
	StateUnsupported   = "unsupported"
	StateNeverSynced   = "never-synced"
	StateInSync        = "in-sync"
	StateStale         = "stale"
	StateDrifted       = "drifted"
	StateTargetMissing = "target-missing"
)

Client sync states. "stale" means the target still matches what gridctl wrote but the canonical file has changed since (a sync is pending).

View Source
const (
	ActionCreated            = "created"
	ActionUpdated            = "updated"
	ActionUnchanged          = "unchanged"
	ActionSkippedDrift       = "skipped-drift"
	ActionSkippedUnavailable = "skipped-unavailable"
	ActionWouldCreate        = "would-create"
	ActionWouldUpdate        = "would-update"
	ActionError              = "error"
)

Sync result actions.

Variables

View Source
var (
	ErrNoCanonical     = errors.New("no canonical context file; run 'gridctl ctx init' first")
	ErrCanonicalExists = errors.New("canonical context file already exists (use --force to overwrite)")
	ErrUnknownClient   = errors.New("unknown client")
	ErrUnsupported     = errors.New("client has no global context file mechanism")
	ErrNotAvailable    = errors.New("client not initialized on this machine")
	ErrNotSynced       = errors.New("client has never been synced")
	ErrOverCap         = errors.New("rendered content exceeds the client's size limit")
)

Sentinel errors callers branch on.

View Source
var ErrNewerLockVersion = errors.New("context lock file was written by a newer gridctl version")

ErrNewerLockVersion signals a lock file written by a newer gridctl.

Functions

func HasFailures

func HasFailures(results []SyncResult) bool

HasFailures reports whether any result needs the caller's attention: a write error or a drifted target that was skipped.

func NeedsSync

func NeedsSync(statuses []ClientStatus) bool

NeedsSync reports whether any client requires attention: drifted, stale, or a recorded sync whose target file has gone missing. Backs `ctx sync --check` and the status exit code.

func SupportedSlugs

func SupportedSlugs() []string

SupportedSlugs lists the supported client slugs, derived from the strategy table so error messages and help text never go stale.

Types

type ClientEntry

type ClientEntry struct {
	Strategy string `yaml:"strategy"`
	// Target is the absolute path gridctl wrote to.
	Target string `yaml:"target"`
	// InstalledHash is the managed-region hash exactly as written.
	InstalledHash string `yaml:"installed_hash"`
	// CanonicalHash is the canonical file's hash at sync time.
	CanonicalHash string `yaml:"canonical_hash"`
	// CreatedFile records whether gridctl created the target file itself
	// (unsync then removes the whole file, not just the managed region).
	CreatedFile bool      `yaml:"created_file"`
	SyncedAt    time.Time `yaml:"synced_at"`
}

ClientEntry is one client's sync record.

type ClientStatus

type ClientStatus struct {
	Slug         string     `json:"slug"`
	Name         string     `json:"name"`
	Supported    bool       `json:"supported"`
	Available    bool       `json:"available"`
	Experimental bool       `json:"experimental,omitempty"`
	Strategy     string     `json:"strategy,omitempty"`
	TargetPath   string     `json:"target_path,omitempty"`
	State        string     `json:"state"`
	Detail       string     `json:"detail,omitempty"`
	SyncedAt     *time.Time `json:"synced_at,omitempty"`
}

ClientStatus is one client's row in `ctx status` and GET /api/context.

type LockFile

type LockFile struct {
	Version int `yaml:"version"`
	// Scope is "global" today. Present so a future project scope can
	// share the schema without a format break.
	Scope   string                  `yaml:"scope"`
	Clients map[string]*ClientEntry `yaml:"clients"`
}

LockFile records, per client, what gridctl last wrote and from which canonical revision. Drift is judged against InstalledHash; staleness against CanonicalHash.

type Manager

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

Manager owns the canonical global context store under <home>/.gridctl/context and every projection into client files. All target paths resolve against home, so tests point it at a temp dir. Mutating operations serialize on mu so concurrent API requests never interleave lockfile read-modify-write cycles.

func NewManager

func NewManager() (*Manager, error)

NewManager builds a Manager rooted at the user's home directory.

func NewManagerWithHome

func NewManagerWithHome(home string) *Manager

NewManagerWithHome builds a Manager rooted at an explicit home directory. Tests use this to stay isolated from $HOME.

func (*Manager) Adopt

func (m *Manager) Adopt(ctx context.Context, slug string) error

Adopt pulls a target's managed content back into the canonical file (chezmoi re-add semantics), then re-syncs that client so its hashes return to in-sync. Other clients become stale, which is correct: the canon changed.

func (*Manager) CanonicalContent

func (m *Manager) CanonicalContent() (string, error)

CanonicalContent reads the canonical file.

func (*Manager) CanonicalPath

func (m *Manager) CanonicalPath() string

CanonicalPath returns the canonical global context file path.

func (*Manager) Diff

func (m *Manager) Diff(ctx context.Context, slug string) (string, error)

Diff renders a unified diff between the canonical content and one client's current managed content.

func (*Manager) Dir

func (m *Manager) Dir() string

Dir returns the canonical store directory.

func (*Manager) HasCanonical

func (m *Manager) HasCanonical() bool

HasCanonical reports whether the canonical file exists.

func (*Manager) InitFromClient

func (m *Manager) InitFromClient(slug string, force bool) error

InitFromClient adopts a client's existing global context file as the canonical context. Content gridctl previously managed there (block, shim line, header chrome) is stripped so adoption never round-trips gridctl's own markers into the canon.

func (*Manager) InitFromFile

func (m *Manager) InitFromFile(path string, force bool) error

InitFromFile adopts an arbitrary file as the canonical context.

func (*Manager) InitFromTemplate

func (m *Manager) InitFromTemplate(force bool) error

InitFromTemplate scaffolds the starter canonical file.

func (*Manager) SaveCanonical

func (m *Manager) SaveCanonical(content string) error

SaveCanonical writes the canonical file with a backup of the previous revision. Content is normalized to end with exactly one newline.

func (*Manager) Scan

func (m *Manager) Scan() []ScanEntry

Scan inspects every supported client's import location so init can offer adoption before scaffolding.

func (*Manager) Statuses

func (m *Manager) Statuses(ctx context.Context) ([]ClientStatus, error)

Statuses computes the per-client sync state for every known client, supported and unsupported, in display order.

func (*Manager) SyncAll

func (m *Manager) SyncAll(ctx context.Context, opts SyncOptions) ([]SyncResult, error)

SyncAll projects the canonical context to every supported, available client. Unavailable clients are reported as skipped, never errors.

func (*Manager) SyncClient

func (m *Manager) SyncClient(ctx context.Context, slug string, opts SyncOptions) (SyncResult, error)

SyncClient projects the canonical context to one explicitly named client. Unlike SyncAll, an unavailable client is an error here: the user asked for it by name and should hear why nothing happened.

func (*Manager) Unsync

func (m *Manager) Unsync(ctx context.Context, slug string) (UnsyncResult, error)

Unsync removes one client's managed artifact and clears its lock entry. Files gridctl created are deleted outright; files the user owned lose only the managed region or shim line.

func (*Manager) UnsyncAll

func (m *Manager) UnsyncAll(ctx context.Context) ([]UnsyncResult, error)

UnsyncAll removes every synced client's managed artifact.

type ScanEntry

type ScanEntry struct {
	Slug   string `json:"slug"`
	Name   string `json:"name"`
	Path   string `json:"path"`
	Exists bool   `json:"exists"`
	Size   int64  `json:"size"`
}

ScanEntry reports what already exists at one client's likely global context location. Scanning never writes anything.

type Strategy

type Strategy string

Strategy is how gridctl projects the canonical global context into one client's global context mechanism. Strategies are ordered by safety: a dedicated file gridctl fully owns, a single import line in a user-owned file, and a marker-delimited block in a shared file.

const (
	// StrategyDedicatedFile writes a whole file gridctl owns inside a
	// rules directory the client reads (zero merge risk).
	StrategyDedicatedFile Strategy = "dedicated-file"
	// StrategyImportShim inserts one @-import line referencing the
	// canonical file; everything else in the target stays untouched.
	StrategyImportShim Strategy = "import-shim"
	// StrategyBlock writes the full file when the target is absent, or a
	// marker-delimited managed block when user content exists.
	StrategyBlock Strategy = "block"
)

type SyncOptions

type SyncOptions struct {
	// Force overwrites drifted targets and repairs corrupt blocks.
	Force bool
	// DryRun renders and diffs without writing anything.
	DryRun bool
}

SyncOptions configure a sync pass.

type SyncResult

type SyncResult struct {
	Slug       string `json:"slug"`
	Name       string `json:"name"`
	Strategy   string `json:"strategy"`
	TargetPath string `json:"target_path"`
	Action     string `json:"action"`
	BackupPath string `json:"backup_path,omitempty"`
	Diff       string `json:"diff,omitempty"`
	Error      string `json:"error,omitempty"`
}

SyncResult describes what happened (or would happen) for one client.

type Target

type Target struct {
	Slug     string
	Name     string
	Strategy Strategy
	// Paths is the write target per OS. A missing key means the client
	// has no known global context path on that platform.
	Paths map[string]string
	// ImportPaths is where a user's pre-existing hand-written global
	// context most likely lives, for `ctx init --import`. Defaults to
	// Paths when empty.
	ImportPaths map[string]string
	// DetectDirs mark the client as initialized on this machine when any
	// of them exists. Sync refuses to create client config trees
	// wholesale, so these gate every write.
	DetectDirs []string
	// Frontmatter is prepended verbatim to dedicated files for clients
	// whose rules format requires it (e.g. VS Code *.instructions.md).
	Frontmatter string
	// MaxChars caps the rendered target file size; 0 means unlimited.
	// Windsurf enforces a 6,000-character limit on global_rules.md.
	MaxChars int
	// Experimental marks targets whose documented path rests on
	// unofficial sourcing; surfaced in status output.
	Experimental bool
}

Target describes one client's global context surface. Paths are ~-templates expanded against the Manager's home directory, keyed by GOOS ("darwin", "linux", "windows").

func FindTarget

func FindTarget(slug string) (Target, bool)

FindTarget returns the supported target for slug.

func Targets

func Targets() []Target

Targets returns the supported client targets in display order. The slugs match pkg/provisioner registry slugs so status output and the clients: block speak one identifier language.

type UnsupportedClient

type UnsupportedClient struct {
	Slug   string
	Name   string
	Reason string
}

UnsupportedClient is a linked client with no writable global context file mechanism. Surfaced honestly in status output instead of hacks.

func Unsupported

func Unsupported() []UnsupportedClient

Unsupported returns linked clients with no file mechanism to sync to.

type UnsyncResult

type UnsyncResult struct {
	Slug       string `json:"slug"`
	TargetPath string `json:"target_path"`
	// Action is "removed-file", "removed-region", or "already-gone".
	Action string `json:"action"`
}

UnsyncResult describes the removal of one client's managed artifact.

Jump to

Keyboard shortcuts

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