Shared installer SDK for bundled and public GitHub Agent Skills.
CLI authors ship or point to a skill. kitup models that skill as a directory tree, resolves safe agent targets, validates SKILL.md,
copies the full tree into the right host directories, and writes ownership metadata so updates stay safe.
mycli skill install
-> kitup SDK
-> local agent hosts
-> installed skill tree + .kitup.json
- detect installed agent hosts
- resolve user and project skill directories
- resolve safe CLI install selection before writing
- validate bundled skills
- install from a local directory, embedded bundle tree, or public GitHub bundle directory
- copy, update, and uninstall kitup-owned installs
- inspect installed ownership and CLI build metadata without parsing files directly
- refuse unsafe overwrite conflicts
- return structured install, status, and uninstall reports
- not a skill marketplace
- not a remote registry
- not a private GitHub auth client
- not a replacement for user-facing skill discovery tools
Bundle a skill in your CLI project:
mycli/
skills/mycli/SKILL.md
Your CLI owns the command name and framework shell. kitup owns the standard install flags, agent selector mapping,
host detection, safe selection policy, summary text, confirmation, workflow exit classification, target paths,
bundle validation, copy/update semantics, metadata, and conflicts.
The recommended user-facing command is skill install. Use --dry-run to preview writes. Do not add plan,
update, or upgrade subcommands; another install updates kitup-owned copies. Optional status and uninstall
commands call the primitive APIs. Only the Go Cobra adapter ships those commands.
Install:
npm install @kitup/sdkEmbed the install workflow:
import { directoryBundle, runBundledSkillInstall } from "@kitup/sdk";
await runBundledSkillInstall({
appId: "mycli",
skillBundle: directoryBundle("./skills/mycli"),
scope: "user",
});For full CLI flags, wire parseInstallFlags into runBundledSkillInstall with scopeSet and promptScope, then map exits with installFlagError and installWorkflowError; see API.
For embedded bundles or public GitHub directories, pass a different skillBundle value to the same install call:
import { githubBundle, moduleDirBundle } from "@kitup/sdk";
const embeddedSkillBundle = await moduleDirBundle(
import.meta.url,
"./skills/mycli",
);
const githubSkillBundle = githubBundle({
owner: "acme",
repo: "mycli-skills",
path: "skills/mycli",
ref: "v1.2.3",
});Attach CLI build identity to a bundled or embedded skill with withBundleMetadata. The SDK records it in the backward-compatible .kitup.json document and exposes it through readInstalledMetadata and statusBundledSkill.
Install:
go get github.com/lathe-cli/kitup/goUse the workflow API for user-facing install commands:
import (
"os"
kitup "github.com/lathe-cli/kitup/go"
)
result, err := kitup.RunBundledSkillInstall(kitup.InstallWorkflowOptions{
InstallOptions: kitup.InstallOptions{
AppID: "mycli",
SkillBundle: kitup.DirectoryBundle("./skills/mycli"),
Scope: kitup.UserScope,
Agents: kitup.AutoAgents(),
},
Yes: false,
Out: os.Stdout,
})For go:embed, pass the embedded directory tree:
result, err := kitup.RunBundledSkillInstall(kitup.InstallWorkflowOptions{
InstallOptions: kitup.InstallOptions{
AppID: "mycli",
SkillBundle: kitup.FSBundle(embeddedSkills, "skills/mycli"),
Scope: kitup.UserScope,
Agents: kitup.ExplicitAgents("codex"),
},
Yes: false,
})For Cobra CLIs, the adapter does not own installer behavior; it only wires Cobra flags to the core workflow.
import (
kitup "github.com/lathe-cli/kitup/go"
kitupcobra "github.com/lathe-cli/kitup/go-cobra"
)
root.AddCommand(kitupcobra.NewSkillCommand(kitupcobra.Options{
AppID: "mycli",
SkillName: "mycli",
Bundle: kitup.FSBundle(embeddedSkills, "skills/mycli"),
}))The adapter mounts skill install, skill status, and skill uninstall. Status and uninstall accept --json; non-interactive uninstall requires --yes, while interactive uninstall confirms before removing any target.
Install:
cargo add kitupUse:
Set stdin_tty from your CLI's terminal detection.
let result = kitup::run_bundled_skill_install(&kitup::InstallWorkflowOptions {
install: kitup::InstallOptions {
base: kitup::BaseOptions::default(),
app_id: "mycli".to_string(),
skill_bundle: kitup::directory_bundle("./skills/mycli"),
scope: kitup::Scope::User,
agents: kitup::AgentSelector::Auto,
force: false,
},
yes: false,
dry_run: false,
stdin_tty: stdin_tty,
current_agent: None,
default_scope: None,
scope_set: true,
prompt_scope: false,
})?;The workflow result contains the selected agents, dry-run plan, final install report, and cancellation state.
The final install report contains installed, updated, skipped, conflicts, and errors.
Install:
pip install kitup-sdkUse the workflow API for user-facing install commands:
from kitup import (
BaseOptions,
InstallOptions,
InstallWorkflowOptions,
directory_bundle,
run_bundled_skill_install,
)
result = run_bundled_skill_install(
InstallWorkflowOptions(
install=InstallOptions(
base=BaseOptions(),
app_id="mycli",
skill_bundle=directory_bundle("./skills/mycli"),
scope="user",
),
stdin_tty=True,
prompt_scope=True,
)
)Embed a skill directory shipped as package data with:
from importlib.resources import files
from kitup import resources_bundle
bundle = resources_bundle(files("mycli.skills") / "mycli")For non-interactive or embedding scenarios, call install_bundled_skill, status_bundled_skill,
read_installed_metadata, or uninstall_bundled_skill directly. plan_bundled_skill is dry-run install;
update_bundled_skill is install again.
Host adapter coverage builds on prior work from GitHub CLI gh skill and npx skills / skills.sh.