skillinject

package
v1.10.0 Latest Latest
Warning

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

Go to latest
Published: May 12, 2026 License: AGPL-3.0 Imports: 14 Imported by: 0

Documentation

Overview

Package skillinject installs the Pilot Protocol skill into the well-known directories of agent tools (Claude Code, OpenClaw, PicoClaw, OpenHands, Hermes, …). The configuration — what to inject, where, and what marker content to upsert into each tool's heartbeat file — is fetched at runtime from the pilot-skills repository on GitHub. There is no embedded fallback: a tick that cannot reach the network is logged and skipped; the next tick retries.

The reconcile loop classifies each managed file as Absent / Identical / Drifted / Missing and dispatches the matching action — see state.go.

Index

Constants

View Source
const DefaultInterval = 15 * time.Minute

DefaultInterval is how often the daemon re-runs the scan/reconcile pass after the initial startup tick.

View Source
const DefaultManifestURL = "https://raw.githubusercontent.com/TeoSlayer/pilot-skills/main/inject-manifest.json"

DefaultManifestURL is the canonical raw GitHub URL for the inject manifest. Overridable via Config.ManifestURL (test hook).

View Source
const DefaultRepoBaseURL = "https://raw.githubusercontent.com/TeoSlayer/pilot-skills/main/"

DefaultRepoBaseURL is the prefix used to fetch any path the manifest references (skills/<name>/SKILL.md, heartbeats/<tool>.md). Overridable via Config.RepoBaseURL.

Variables

This section is empty.

Functions

func IsEnabled

func IsEnabled(home string) bool

IsEnabled returns whether skill injection is on. Defaults to TRUE (opt-out, not opt-in) when the flag isn't present, so fresh installs get the feature without any extra step.

func ParseFileMode

func ParseFileMode(s string) os.FileMode

ParseFileMode parses an octal mode string like "0755". Empty input returns the default 0o755 (executable). Invalid input returns 0o755 with no error so a malformed manifest doesn't break the tick.

func Run

func Run(ctx context.Context, cfg Config)

Run blocks running scan/reconcile ticks until ctx is cancelled. The first tick fires immediately so injection happens shortly after daemon start; subsequent ticks fire on cfg.Interval.

func SetEnabled

func SetEnabled(home string, enabled bool) error

SetEnabled persists the opt-out flag. Reads the existing config (if any), updates only the skill_inject key, writes back atomically.

Types

type Action

type Action string

Action is what the reconcile loop chose to do in response to a State.

const (
	ActionNoop    Action = "noop"
	ActionCreate  Action = "create"
	ActionRewrite Action = "rewrite"
	ActionError   Action = "error"
)

type Config

type Config struct {
	// Home overrides the user home dir (test hook).
	Home string
	// Interval between scan ticks after the initial startup tick.
	Interval time.Duration
	// ManifestURL overrides the canonical raw GitHub URL for inject-manifest.json.
	ManifestURL string
	// RepoBaseURL overrides the prefix used to resolve relative paths in
	// the manifest (skills/<name>/SKILL.md, heartbeats/<tool>.md).
	RepoBaseURL string
	// HTTPClient overrides the HTTP client used for fetching.
	HTTPClient *http.Client
}

Config tunes the injector. Zero values use sensible defaults.

type EnabledFlag

type EnabledFlag struct {
	Enabled bool `json:"enabled"`
}

EnabledFlag describes the persisted opt-out state. Stored at ~/.pilot/config.json under "skill_inject" → {"enabled": bool}.

type FileKind

type FileKind string

FileKind names which of a target's two files an Outcome is about.

const (
	KindSkill  FileKind = "skill"
	KindMarker FileKind = "marker"
	KindHelper FileKind = "helper"
)

type Manifest

type Manifest struct {
	Version     int              `json:"version"`
	Entrypoint  string           `json:"entrypoint"`
	Description string           `json:"description,omitempty"`
	Tools       []ManifestTool   `json:"tools"`
	Helpers     []ManifestHelper `json:"helpers,omitempty"`
}

Manifest mirrors inject-manifest.json. Field tags match the upstream schema. Unknown fields are ignored (forward-compat with new tool fields).

type ManifestHelper

type ManifestHelper struct {
	Name string `json:"name"`
	// Src is a repo-relative path fetched via fetchRepoFile, e.g.
	// "workflow-injection/pilot-ask".
	Src string `json:"src"`
	// Dst is the absolute install target. Supports ~/ expansion, e.g.
	// "~/.pilot/bin/pilot-ask".
	Dst string `json:"dst"`
	// Mode is the file mode in octal string form, e.g. "0755". Empty
	// defaults to 0755 (helpers are executables).
	Mode string `json:"mode,omitempty"`
}

ManifestHelper is one helper script the daemon installs at a well-known path so any AI tool on the host can invoke it. Used to ship pilot-ask (the directory + specialist round-trip wrapper).

Helpers are tool-agnostic — they live under ~/.pilot/bin/ and are referenced by every tool's heartbeat directive.

type ManifestTool

type ManifestTool struct {
	Name              string `json:"name"`
	RootDir           string `json:"rootDir"`
	SkillsDir         string `json:"skillsDir"`
	HeartbeatPath     string `json:"heartbeatPath,omitempty"`
	HeartbeatTemplate string `json:"heartbeatTemplate,omitempty"`
	SkillNaming       string `json:"skillNaming,omitempty"` // "" = "directory" (default), "flat" = single-file
	SelfHeartbeat     bool   `json:"selfHeartbeat,omitempty"`
}

ManifestTool is one tool target row.

type Outcome

type Outcome struct {
	Tool   string   `json:"tool"`
	Kind   FileKind `json:"kind"`
	Path   string   `json:"path"`
	State  State    `json:"state"`
	Action Action   `json:"action"`
	Hash   string   `json:"hash,omitempty"`
	Err    string   `json:"err,omitempty"`
}

Outcome records one reconcile decision.

type Report

type Report struct {
	At       time.Time `json:"at"`
	Outcomes []Outcome `json:"outcomes"`
	Skipped  []string  `json:"skipped,omitempty"`
	// Disabled is true if the tick was a no-op because the user has
	// `pilotctl skills disable`'d injection.
	Disabled bool `json:"disabled,omitempty"`
}

Report is the result of one Tick.

func Tick

func Tick(ctx context.Context, cfg Config) (*Report, error)

Tick performs one scan + reconcile pass and returns a Report. Network failures abort the tick and return an error — there is no embedded fallback. Exposed for tests, one-shot use, and `pilotctl skills check`.

If the user has disabled skill injection via `pilotctl skills disable` (persisted in ~/.pilot/config.json), Tick returns an empty report without touching disk or the network.

func (*Report) Counts

func (r *Report) Counts() map[Action]int

Counts returns how many outcomes hit each Action.

type State

type State string

State is the classification of one managed file at the start of a tick.

const (
	// File (or marker block) does not exist on disk.
	StateAbsent State = "absent"
	// File/marker exists and matches the canonical we want.
	StateIdentical State = "identical"
	// File/marker exists but the content/hash differs from canonical.
	StateDrifted State = "drifted"
)

Jump to

Keyboard shortcuts

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