install

package
v0.2.0 Latest Latest
Warning

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

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

Documentation

Overview

Package install owns the SOUL.md install conventions: harness detection, the per-framework target table, the overwrite gate, and the install receipt written by install.sh. Paths are injected so everything is testable without touching the real home directory.

Index

Constants

View Source
const ReceiptName = "positronick-install-receipt.json"

ReceiptName is the filename install.sh writes next to the binary — a cross-repo contract with install.sh and positronick.com/install.sh.

Variables

View Source
var SkillTargets = []string{"agents", "claude", "cursor", "grok", "codex", "openclaw"}

SkillTargets are the supported `skill install` destinations, in the order they are documented. agents is the shared standard (Codex, Cursor, Grok Build and OpenClaw all read it); codex has no user-level directory of its own and shares agents'.

View Source
var Targets = []string{"hermes", "claude", "cursor", "openclaw", "grok"}

Targets are the supported install targets, in detection-priority order.

Functions

func DescribeOpenClawWorkspaces added in v0.2.0

func DescribeOpenClawWorkspaces(workspaces []OpenClawWorkspace) string

DescribeOpenClawWorkspaces renders "<id> (<path>), <id> (<path>)..." — shared by every "several OpenClaw agents configured" error message (ResolveOpenClawWorkspaces callers included) so the format lives in one place.

func DetectHarness

func DetectHarness(cwd, home string) string

DetectHarness returns the install target for the first harness marker directory found — all markers are checked in cwd first (a project-local harness wins), then in home — or "" when none exists. Only directories count; an empty cwd/home is skipped.

func OpenClawSoulPath added in v0.2.0

func OpenClawSoulPath(workspaces []OpenClawWorkspace, pick, home string) (string, error)

OpenClawSoulPath resolves the SOUL.md destination among the configured OpenClaw workspaces: pick == "" requires exactly one workspace; otherwise pick is matched against a workspace ID, then treated as a directory when it looks like one (a path separator or a leading ~/.). home expands a leading "~" in pick — this package is injected-home throughout, so it never reads the real user home itself.

func SkillDir added in v0.2.0

func SkillDir(target string, project bool, cwd, home string) (string, error)

SkillDir returns the conventional skills directory for a target: a user-level (home-anchored) directory by default, or a project-level (cwd-anchored) directory when project is true. codex has no directory of its own at either level — it shares agents' (openclaw shares it too at project level; its user-level directory stays its own).

func SkillName added in v0.2.0

func SkillName(body string) (string, error)

SkillName parses the SKILL.md frontmatter `name:` field. body must start with a "---" frontmatter block; a missing block or a missing/empty name field is an error. No YAML library — this is a narrow, pure scan.

func TargetPath

func TargetPath(target, cwd, home string) (string, error)

TargetPath returns the conventional SOUL.md location for a target. hermes, claude, openclaw and grok are home-anchored; cursor is project-local (its rules live inside the repository). openclaw's result is the no-config default (~/.openclaw/workspace/SOUL.md) — the actual OpenClaw destination for `soul install` is resolved per-machine by ResolveOpenClawWorkspaces + OpenClawSoulPath, since OpenClaw reads SOUL.md from its configured agent workspace, not ~/.openclaw.

func WriteReceipt

func WriteReceipt(binPath string, r Receipt) error

WriteReceipt writes the receipt next to the binary at binPath, in the same shape install.sh produces.

Types

type OpenClawWorkspace added in v0.2.0

type OpenClawWorkspace struct {
	ID   string
	Path string
}

OpenClawWorkspace is one configured OpenClaw agent: its id and the workspace directory it reads SOUL.md from.

func ResolveOpenClawWorkspaces added in v0.2.0

func ResolveOpenClawWorkspaces(home string, getenv func(string) string, readFile func(string) ([]byte, error)) ([]OpenClawWorkspace, error)

ResolveOpenClawWorkspaces returns every configured OpenClaw agent and the workspace directory it reads SOUL.md from, sorted with the default agent first, then by id. home, getenv and readFile are injected so this is testable without touching the real filesystem/environment.

type Options

type Options struct {
	// Target is one of Targets. It picks the destination (when Path is
	// empty) and the formatting (cursor wraps the body in mdc frontmatter).
	// An empty Target with a Path writes the body verbatim to Path.
	Target string
	// Path, when set, overrides the target's conventional destination.
	Path string
	// SoulName fills the cursor frontmatter description.
	SoulName string
	// Cwd and Home anchor the conventional paths (injected for tests).
	Cwd, Home string
	// Force overwrites an existing file without asking.
	Force bool
	// Link, with Target "claude" or "grok", appends the link line to
	// ~/.claude/CLAUDE.md or $GROK_HOME/AGENTS.md when not already present.
	Link bool
	// Interactive enables the Confirm prompt for overwrites.
	Interactive bool
	// Confirm asks the user to approve overwriting the named file. Required
	// when Interactive and the destination exists.
	Confirm func(prompt string) (bool, error)
	// OverwriteHint names the flag suggested when refusing to overwrite
	// non-interactively; defaults to "--force".
	OverwriteHint string
	// Fetch returns the verbatim SOUL.md body. It is called only after the
	// overwrite gate passes: the server's .md endpoint bumps the public
	// download counter, and a refused install is not a download.
	Fetch func() (string, error)
}

Options configures one SOUL.md install.

type Receipt

type Receipt struct {
	Method  string `json:"method"`
	Version string `json:"version"`
}

Receipt records how the binary was installed. install.sh writes {"method":"installer","version":"..."}; `self update` rewrites it after a successful in-place update.

func ReadReceipt

func ReadReceipt(binPath string) Receipt

ReadReceipt reads the receipt next to the resolved binary at binPath. A missing, unreadable or malformed receipt yields method "unknown" — the binary is then treated like a package-manager install, which `self update` must never replace in place.

type Result

type Result struct {
	Path  string
	Bytes int
}

Result reports where an install landed and how many bytes were written.

func Install

func Install(opts Options) (*Result, error)

Install resolves the destination, gates overwrites (prompt when Interactive, Force otherwise), fetches the body, writes it (creating parent directories), and runs the claude CLAUDE.md link when asked.

type SkillOptions added in v0.2.0

type SkillOptions struct {
	// Dir is the destination's parent directory: either a target's
	// conventional skills directory (SkillDir) or an explicit --path
	// override. The install folder itself is always Slug.
	Dir string
	// Slug is the listing's slug: it names the install folder
	// (<Dir>/<Slug>/SKILL.md) and must equal the fetched body's
	// frontmatter name.
	Slug string
	// Force overwrites an existing file without asking.
	Force bool
	// Interactive enables the Confirm prompt for overwrites.
	Interactive bool
	// Confirm asks the user to approve overwriting the named file. Required
	// when Interactive and the destination exists.
	Confirm func(prompt string) (bool, error)
	// OverwriteHint names the flag suggested when refusing to overwrite
	// non-interactively; defaults to "--force".
	OverwriteHint string
	// Fetch returns the verbatim SKILL.md body. It is called only after the
	// overwrite gate passes: the server's .md endpoint bumps the public
	// download counter, and a refused install is not a download.
	Fetch func() (string, error)
}

SkillOptions configures one hosted-SKILL.md install.

type SkillResult added in v0.2.0

type SkillResult struct {
	Path  string
	Name  string
	Bytes int
}

SkillResult reports where a skill install landed, the name its frontmatter carried, and how many bytes were written.

func Skill added in v0.2.0

func Skill(opts SkillOptions) (*SkillResult, error)

Skill resolves <Dir>/<Slug>/SKILL.md, gates overwrites (reusing the same gate Install uses), fetches the body, verifies its frontmatter name equals Slug, and writes it verbatim. The name check runs after the gate but the file is written only once both pass, so a mismatch — like a refused overwrite — leaves nothing on disk.

Jump to

Keyboard shortcuts

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