Version: 0.1 (draft) Status: Informational + Normative (uses MUST / SHOULD / MAY)
Skillflag is a CLI convention for exposing “agent skills” (skill directories, not just single markdown files) from a CLI tool via standardized flags, so that:
- the producing CLI does not contain agent- or editor-specific installation logic, and
- a separate installer/adaptor CLI (or simple shell redirection) can install a chosen skill into a chosen agent tool and scope.
Skillflag defines two primary operations:
- Discovery:
--skills - Export:
--skill <id> --export(exports the full skill directory as a tar stream on stdout)
Skillflag is designed around these constraints:
-
OS-independent distribution CLIs may be installed via language ecosystems (npm, cargo, pip, etc.) and run cross-platform. Filesystem conventions like global manpage directories are not a reliable assumption.
-
Skills are more than a markdown file A skill often includes scripts, templates, schemas, examples, test fixtures, or other assets that must be shipped as a directory bundle.
-
Avoid per-agent installation logic in producer CLIs It is undesirable for every CLI to learn how to install into every agent tool (Claude Code, Codex, Amp, etc.) and every scope (repo/user/system). That mapping belongs in a separate adaptor installer.
-
Bundling skills with the CLI package is simpler than maintaining a separate registry Publishing skills alongside the CLI’s normal distribution mechanism reduces operational overhead and version skew.
-
Users want selective installation Installing a CLI should not implicitly install all of its skills into all local agent tools. Users should be able to list available skills and install only what they want, where they want.
-
Provide a minimal, portable, shell-friendly interface:
- list skills
- export a skill directory
-
Keep producer CLIs tool-agnostic (no knowledge of target agent install paths).
-
Enable both interactive use (humans) and automation (scripts/CI).
- Defining how a specific agent tool discovers skills on disk.
- Defining a central skill registry, marketplace, signing infrastructure, or dependency installation mechanism.
- Defining how installers resolve conflicts, pin versions, or manage lockfiles (those can exist, but are outside the core Skillflag interface).
- Producer CLI: The tool that bundles skills and implements the Skillflag interface (e.g.,
mycli). - Skill: A directory containing
SKILL.mdand optional additional files (scripts/assets/etc.). - Skill ID: The identifier used with
--skill <id>. - Exporter: The part of the producer CLI that emits the skill bundle.
- Installer/Adaptor CLI: A separate tool that consumes a skill directory (or tar stream) and installs it into a specific agent tool and scope.
A Skillflag-compliant producer CLI MUST implement:
--skills--skill <id> --export
A producer CLI MAY additionally implement:
--skills --json--skill <id>(without--export) as a “view” mode
Skillflag does not require any particular command substructure (tool skills ...) because the goal is a “--help-class” universal convention based on flags.
tool --skillsMUST print the list of available Skill IDs to stdout.- Output MUST NOT include banners, progress text, or other non-data content on stdout.
- Diagnostics and errors MUST go to stderr.
- Each skill MUST appear on a single line.
- The line MUST begin with the
Skill ID. - A short summary MAY follow, separated by a single tab (
\t).
Recommended format:
<id>\t<summary>
If summaries are included:
<summary>MUST NOT contain newlines or tabs.
- Output ordering SHOULD be stable and predictable.
- Recommended: sort lexicographically by Skill ID.
If tool --skills --json is provided:
- It MUST print a single JSON object to stdout.
- It MUST NOT print additional text to stdout.
Minimal recommended schema:
{
"skillflag_version": "0.1",
"skills": [
{
"id": "tmux",
"summary": "Drive an interactive tmux session",
"version": "optional string",
"files": "optional: list or count",
"digest": "optional: sha256 of exported tar stream"
}
]
}(Fields beyond id are optional; keeping JSON minimal is consistent with the “lindy” goal.)
Because --skill <id> --export is the normative export mechanism, --skill <id> without --export is optional. If implemented:
tool --skill <id>SHOULD print a human-oriented representation of the skill to stdout.- Recommended: print
<id>/SKILL.mdcontent only (no extra banners).
This provides a “manpage-like” experience without OS-specific manpage infrastructure.
tool --skill <id> --exportMUST write the skill bundle to stdout as a tar stream.- The tar stream MUST contain exactly one top-level directory named
<id>/. - The directory MUST include
<id>/SKILL.md. - No additional output is permitted on stdout.
To maximize portability, exporters:
-
MUST produce a tar that can be read by common
tarimplementations. -
SHOULD use one of:
- POSIX ustar, or
- PAX tar (recommended if long paths are needed)
Exporters MUST ensure:
- No absolute paths.
- No
..path traversal segments. - All entries are relative under
<id>/.
For reproducible installs and caching:
- Exporters SHOULD emit entries in stable order.
- Exporters MAY normalize metadata (mtime/uid/gid/uname/gname) to stable values.
Determinism is recommended but not required for conformance.
A compliant implementation MUST return non-zero exit status on failure and MUST write error details to stderr.
Recommended exit code conventions:
0: success2: usage error / invalid flags3: skill not found (--skill <id>unknown)4: I/O error producing output (broken pipe, permission, etc.)5: internal error
(Exact codes may vary, but “not found” vs “usage error” separation is strongly recommended for scripting.)
Inside the producer CLI’s distribution artifact, skills SHOULD be stored under a dedicated resource path:
skills/<id>/SKILL.md(required)skills/<id>/...(optional additional files)
The producer CLI MUST map these bundled resources to the Skillflag interface:
--skillsenumerates available<id>directories.--skill <id> --exportexports the directory as<id>/...in tar form.
This deliberately avoids any assumption about package managers or OS-level install roots.
Skill IDs SHOULD be:
- stable across releases once published
- ASCII lowercase, digits, and
-/_(recommended) - no spaces
Rationale: IDs appear in shell scripts and filesystem paths.
Skillflag does not require a manifest file, but implementations MAY include metadata in one of these ways:
- YAML frontmatter at the top of
SKILL.md(common in markdown-based systems) - a sidecar file such as
SKILL.jsonorskill.toml
If metadata exists, it SHOULD be treated as advisory by installers.
Critically:
- Producer CLIs MUST NOT execute any bundled scripts as part of export.
- Installers SHOULD NOT execute bundled scripts by default.
Skillflag keeps the producer CLI in a “data export” role. That reduces risk, but does not eliminate it.
Recommendations:
-
Exporters must prevent path traversal and absolute paths (normative requirement).
-
Installers should treat exported bundles as untrusted input:
- provide
--dry-run/--inspect - optionally require explicit opt-in to execute any included scripts
- provide
-
Bundles may include binaries or scripts; installers should surface that fact clearly.
Skillflag is designed to compose cleanly with a dedicated installer/adaptor CLI that knows how to install into specific agent tools and scopes.
Expected pipeline shape:
tool --skill <id> --export | skill-install --agent <agent> --scope <scope>The installer is responsible for:
- mapping to agent-specific directories and precedence
- conflict resolution
- optional linking vs copying
- optional lockfiles / version pinning
None of that logic belongs in the producer CLI.
tool --skillstool --skill tmuxtool --skill tmux --export | tar -tf -tool --skill tmux --export | skill-install --agent codex --scope usermkdir -p .agents/skills/tmux
tool --skill tmux --export | tar -x -C .agents/skills(That last example assumes the installer semantics are simply “untar into a skills root”.)
A producer CLI is Skillflag-compliant if:
-
--skillslists Skill IDs on stdout with no extra stdout noise. -
--skill <id> --exportemits a tar stream on stdout. - The tar stream contains exactly one top-level directory
<id>/. -
<id>/SKILL.mdexists in the exported stream. - No absolute paths or path traversal segments appear in the tar entries.
- Failures produce non-zero exit code and write errors to stderr.
Scope: installs one skill bundle into one target agent/tool + scope.
- Skills are directories, not just
SKILL.md: they can include scripts, templates, references, assets, etc. (multiple tools describe skills this way). (OpenAI Developers) - Producer CLIs should not encode per-agent install logic. The producer just exposes skill bundles (via Skillflag:
--skills,--skill <id> --export). The installer maps to agent-specific locations. - Users must opt in: installing a CLI must not automatically install all of its skills into every local agent. So
skill-installtargets exactly one agent and one scope at a time. - Cross-agent portability exists but paths differ: several tools already read “portable” directories (notably
.agents/skillsand~/.config/agents/skills), while others have native roots like.claude/skills,.codex/skills,.github/skills, etc. (Block)
Install from a local skill directory:
PATHmust be a directory containingSKILL.mdat its root.
Example:
skill-install ./skills/tmux --agent claude --scope repoInstall from a tar stream (e.g., produced by a Skillflag producer’s export):
- If
PATHis omitted and stdin is not a TTY,skill-installmust read a tar stream from stdin. - The tar stream should contain a single top-level directory
<something>/...withSKILL.mdinside that root.
Example:
producer --skill tmux --export | skill-install --agent claude --scope user(Producer-side export format is defined by Skillflag: --skill <id> --export emits a tar bundle on stdout.)
skill-install [PATH]
--agent <claude|codex|vscode|copilot|cursor|amp|goose|opencode|factory|portable>
--scope <repo|user|cwd|parent|admin>
[--root <path>]
[--mode <copy|link>]
[--force]
[--dry-run]
[--json]
[--id <override-skill-id>]
[--dest <override-destination-root>]
[--native] # only for agents where “portable-first” is the default (goose/amp)
[--legacy] # only where a legacy target exists (vscode/copilot -> .claude/skills)--agentis required unless--destis provided.--scopeis required unless--destis provided.
Rationale: avoid silent installs into the wrong agent/tool.
By default, skill-install must validate:
-
SKILL.mdexists at bundle root. -
YAML frontmatter exists and includes:
name(string)description(string)
This matches major implementations’ documented expectations. (Claude Code)
Default skill_id is the YAML name.
- Destination directory name must be
skill_idunless overridden by--id. - If the incoming bundle root directory name differs from
skill_id,skill-installshould rename on install (and may warn on stderr).
When --scope repo is used:
- If inside a git worktree,
skill-installshould use the git repository root as<project-root>. - Otherwise, it should use the current working directory as
<project-root>. --root <path>overrides detection.
- Copy the entire skill directory tree to the destination.
- Preserve file contents exactly; preserve execute bits when the platform supports it.
- Should install atomically (write temp dir then rename) to avoid partial installs.
- Create a symlink/junction at the destination pointing to the source directory (or to an extracted cache if input was a tar stream).
- If linking is unsupported, fail unless the user explicitly chose a fallback.
If the destination already exists:
- Default behavior: fail without modifying anything.
--force: remove and replace.
skill-install must not run any scripts contained in the skill bundle as part of installation.
When reading a tar stream, skill-install must:
-
Reject absolute paths.
-
Reject
..traversal. -
Reject special files (device nodes/FIFOs).
-
Treat symlinks/hardlinks as unsafe by default:
- recommended: reject them outright, or ensure they stay within the extracted skill root.
This section is intentionally concrete and only covers widely-used tools with documented/observable conventions.
Portable roots are explicitly used by Amp and Goose and described as portable across agents in Goose docs. (Block)
--scope repo→<project-root>/.agents/skills/<skill_id>/--scope user→${XDG_CONFIG_HOME:-~/.config}/agents/skills/<skill_id>/
Claude Code documents these locations and precedence. (Claude Code)
repo→<project-root>/.claude/skills/<skill_id>/user→~/.claude/skills/<skill_id>/
Codex documents multiple repo layers and user/admin/system scopes. (OpenAI Developers)
Default mapping:
repo→<project-root>/.codex/skills/<skill_id>/user→${CODEX_HOME:-~/.codex}/skills/<skill_id>/admin→/etc/codex/skills/<skill_id>/(if supported/allowed)
Optional advanced repo scopes (because Codex distinguishes them):
cwd→$PWD/.codex/skills/<skill_id>/parent→$PWD/../.codex/skills/<skill_id>/(OpenAI Developers)
GitHub docs + VS Code docs agree on:
-
primary:
.github/skills/ -
legacy supported:
.claude/skills/(GitHub Docs) -
repo→<project-root>/.github/skills/<skill_id>/ -
repo --legacy→<project-root>/.claude/skills/<skill_id>/
user scope: unsupported (docs state repo-level only “currently”). (GitHub Docs)
Amp states skills install to .agents/skills/ by default and also reads ~/.config/agents/skills/ (plus Claude-compatible locations for compatibility). (AmpCode)
Portable-first mapping (default):
repo→<project-root>/.agents/skills/<skill_id>/user→${XDG_CONFIG_HOME:-~/.config}/agents/skills/<skill_id>/
Goose documents a search order that includes both portable and goose-specific locations (global + project). (Block)
Portable-first mapping (default):
repo→<project-root>/.agents/skills/<skill_id>/user→${XDG_CONFIG_HOME:-~/.config}/agents/skills/<skill_id>/
If --native is provided:
repo→<project-root>/.goose/skills/<skill_id>/user→${XDG_CONFIG_HOME:-~/.config}/goose/skills/<skill_id>/(Block)
OpenCode documents these locations (plus Claude-compatible ones it also searches). (OpenCode)
repo→<project-root>/.opencode/skill/<skill_id>/user→${XDG_CONFIG_HOME:-~/.config}/opencode/skill/<skill_id>/
Factory docs specify workspace and personal roots. (Factory Documentation)
repo→<project-root>/.factory/skills/<skill_id>/user→~/.factory/skills/<skill_id>/
repo→<project-root>/.cursor/skills/<skill_id>/user→ unsupported (until confirmed)
If you want to avoid this uncertainty, use --agent vscode (for Copilot) or --agent portable, which are documented.
-
By default,
skill-installshould print human-readable status to stderr. -
With
--json, print a single JSON object to stdout:agent,scope,skill_id,installed_to,mode,source(path or stdin),replaced(bool)
producer --skill tmux --export | skill-install --agent claude --scope repoproducer --skill api-setup --export | skill-install --agent portable --scope reposkill-install ./skills/gh-actions-debug --agent codex --scope userIf a tool isn’t listed, skill-install must support:
--dest <skills-root>which installs to<skills-root>/<skill_id>/...
This keeps the spec future-proof without baking in every new agent.