Skip to content

Skills runtime and install

Skills are foxctl’s task plugins. Each skill has a manifest (skill.yaml), a binary or WASM entrypoint, and a well-defined I/O contract based on Protocol v1 JSON envelopes.

This page covers the three execution paths, all input modes, the manifest contract, runtime invariants, and the authoring workflow.

Choose a run path based on what you need:

NeedCommandWhy
Job history, dedupe, async, trajectory capturefoxctl run <skill> --input '<json>'Opens the jobs store, writes CAS and trajectory metadata
Sandbox-safe or hook-style execution without persistencefoxctl run <skill> --ephemeral --input '<json>'Skips job persistence; use for hooks, smoke tests, or one-off retrieval when ~/.foxctl is not writable
Direct parameter flags generated from skill.yamlfoxctl skills run <skill> --param valueExecutes the skill directly with manifest-derived parameter flags; clearest when flag form is more readable than raw JSON

The default path. foxctl run resolves the skill handle, opens the job store, runs the skill, and persists trajectory metadata:

Terminal window
foxctl run code/semantic_search --input '{"query":"error handling","limit":10}'

Use this when you need job history, deduplication, async execution, or when downstream tooling depends on job metadata.

Skips all job persistence. Useful for sandboxed agents, pre-commit hooks, one-off retrieval, or environments where ~/.foxctl is not writable:

Terminal window
foxctl run code/semantic_search --ephemeral --input '{"format":"tree"}'

foxctl skills run parses the skill manifest and exposes its parameters as CLI flags. Use this when a simple flag form is clearer than raw JSON:

Terminal window
foxctl skills run code/semantic_search --query "session restore"

This is also useful when validating skill parameters or testing manifest definitions.

If foxctl on PATH says Command 'run' not available in bundled mode, you are using a wrapper from another install. Run the repo-native binary instead:

Terminal window
./bin/foxctl run code/semantic_search --input '{"query":"test"}'

Or rebuild with make build.

All run paths accept input through several modes:

ModeSyntaxUse when
Raw JSON--input '{"key":"value"}'Small inline JSON inputs
From file--input-file input.jsonRepeatable local inputs stored on disk
From stdin (raw)--input-file -Piped raw JSON from another command
From stdin (envelope)--input stdinReads a Protocol v1 envelope from stdin and passes only its data field to the skill
From CAS--input sha256:<hex>Loads previously stored JSON from the content-addressable store

Direct skill binaries read JSON on stdin through skillmain.Main. They do not parse CLI flags or files themselves — the foxctl run and foxctl skills run wrappers handle loading files, extracting envelope data, and merging parameter flags into JSON.

Every skill is defined by a skill.yaml manifest. The manifest is the source of truth for runtime resolution.

FieldNotes
apiVersionMust be non-empty
kindMust be Skill
metadata.nameMust include namespace, e.g. code/semantic_search
metadata.versionSemantic version string
distribution.typeexec or wasi
distribution.exec.entryBinary entry path (for exec)
distribution.wasi.moduleWASM module path (for wasi)
signature.commandCommand ID exposed by the skill
FieldPurpose
ioInput/output schema metadata
capabilitiesRuntime policy: network, filesystem, pure
memoryMemory limits and constraints
openapiOpenAPI specification reference
DistributionArtifact resolutionRuntime rules
execPrefer bin-cgo (when requested), then bin, then exec.entryNetwork capability may be none or egress
wasimodule.wasm or manifest wasi.modulecapabilities.network must be none

Skills follow strict output and isolation rules:

  • Stdout is envelopes only. Skill stdout must be Protocol v1 JSON envelopes (version/status/command/data/meta). No free-form text on stdout.
  • Logs go to stderr. All diagnostic output goes to stderr, never stdout.
  • Large outputs go to CAS. When output exceeds the inline threshold (approximately 64KB), persist to the content-addressable store and return data.summary plus data.artifact pointer instead of an oversized inline payload.
  • WASI network isolation. WASI skills keep network: "none" — this is a Core v1 isolation guarantee with no exceptions.
  • Workspace/path policy checked. All file access goes through policy.PathValidator before execution, preventing path escapes.
  • meta.ts required. Every terminal envelope must include an RFC3339 UTC timestamp in meta.ts.

The repo-level agent guide uses a 64KB large-output threshold, while the Protocol v1 spec describes a lower default inline threshold for data.body. When in doubt, follow the stricter Protocol v1 artifactization rule.

List all installed skills:

Terminal window
foxctl skills list

Show detailed information about a specific skill, including its manifest, parameters, and runtime configuration:

Terminal window
foxctl skills info <skill-name>

Install a skill from a source directory or archive:

Terminal window
foxctl skills install <source>

Build and install all skills from the repository:

Terminal window
make skills-install

Or build a single skill explicitly:

Terminal window
CGO_ENABLED=0 go build -o ~/.foxctl/skills/my/skill/bin ./skills/my_skill

When a skill is executed, the runtime follows this sequence:

  1. Resolve the skill handle from installed skill.yaml manifests.
  2. Parse and validate manifest fields.
  3. Resolve artifact — prefer bin-cgo when requested, then bin, then the manifest entry path.
  4. Run via the exec runner (for exec distribution) or the WASI runner (for wasi distribution).
  5. Parse stdout as a Protocol v1 envelope.

The short version for creating a new skill:

  1. Create skills/<name>/main.go and skills/<name>/skill.yaml.
  2. Keep stdout output as Protocol v1-compliant JSON envelopes.
  3. Declare accurate capabilities (network, filesystem, pure).
  4. Build and install with make skills-install or the explicit go build command above.
  5. Verify with foxctl skills list, then test through both run paths:
Terminal window
foxctl run <command> --input '{"query":"test"}'
foxctl skills run <command> --param value

See the add a skill guide for the full authoring workflow.

These invariants hold for all skill executions:

InvariantWhy it matters
stdout must be protocol envelope JSONKeeps CLI, hooks, and automation stable
meta.ts present on terminal envelopesRequired by envelope contract
WASI network remains disabledCore v1 isolation guarantee
Workspace/path policy checked before executionPrevents path escapes
Large outputs go to CASAvoids oversized inline payloads