CLI for managing AI code-agent packages (skills, agents, commands) via your own private Git repository — no central registry, no third-party host.
You point pskt at your own repo (a private GitHub repo works fine), and the CLI handles installation, updates, versioning, and publishing of your packages to the chosen code-agent's directory at the chosen scope (global or per-project).
Supported code-agents: Claude Code, opencode, Qwen Code, OpenAI Codex CLI. You pick which one each scope targets at pskt init time — see Code-agents below.
One-liner (Linux / macOS, requires Python 3.11+):
curl -fsSL https://raw.githubusercontent.com/Alecell/Perskent/main/install.sh | shThe script detects python3.11+, ensures pipx is available on your system, and installs perskent into an isolated environment. The pskt and perskent commands become available on your PATH.
Direct install via pipx:
pipx install git+https://github.com/Alecell/Perskent.gitUpgrade later:
pipx upgrade perskentpskt init # registry URL + token, and which code-agent each scope targets
pskt find remote # list packages available in the registry
pskt install my-agent root # install in the global dir of the chosen code-agent
pskt install my-skill project # install in the project dir of the chosen code-agent
pskt install # or run without args for an interactive picker
pskt code-agent opencode root # later: switch the root scope to a different code-agent| Command | Description |
|---|---|
pskt init |
Configure remote registry URL and clone it into ~/.pskt/ |
pskt doctor |
Diagnostics (Python, git, paths, token, reachability) |
pskt status |
Consolidated view: workspace state, registry packages, installations (outdated/orphaned) |
pskt sync |
git pull on the local workspace |
pskt find remote |
List packages available in the registry |
pskt find local |
List installed packages (root + project) |
pskt show <name> |
Show details of a package |
pskt search <term> |
Search by name or description |
pskt install [<name>] [<root|project>] [--force] |
Install a package (interactive picker if args omitted) |
pskt remove [<name>] [<root|project>] |
Uninstall a package (interactive picker if args omitted) |
pskt update [<name>] [<root|project>] |
Upgrade a package, preserving files marked in [update].preserve (interactive picker if args omitted) |
pskt push [<name>] [-m <msg>] |
Bump + commit + push a locally-edited package (interactive picker if name omitted) |
pskt destroy <name> [-y] |
Permanently delete a package from the registry (workspace + remote). Does not affect installed copies. |
pskt code-agent [<tool>] [<root|project>] |
Show or change which code-agent each scope targets. Without args, shows the current config. |
For any command that accepts <name>: if packages with the same name exist in multiple kinds, use the qualified name — agents/my-thing, skills/my-thing, commands/my-thing.
push, install, remove, and update accept their arguments interactively when omitted — arrow keys + enter:
pskt push # picker for workspace packages
pskt install # picker for registry packages → scope picker
pskt remove # scope picker → picker for packages installed in that scope
pskt update # scope picker → picker for packages installed in that scopeExample output:
? Scope?
❯ root
project
? Which package to update in root?
❯ agents/my-agent v1.0.0
skills/helper v0.3.0
commands/init v0.2.0
Partial arguments still work — pskt install foo only prompts for the missing scope; pskt update agents/foo root runs non-interactively.
For remove and update, scope must be provided (either as a positional argument or via the picker). This prevents silent updates of the wrong installation when a package is installed in both root and project.
- Remote registry — your private Git repository (e.g.
your-user/my-registry) that stores versioned packages. - Local workspace — clone of the registry at
~/.pskt/. This is where you edit packages;pskt pushsyncs them to the remote. - Installation — copies files from the local workspace into the directory consumed by the chosen code-agent (not a symlink; code-agents read physical files).
root— installs into the chosen code-agent's global directory (e.g.~/.claude/,~/.config/opencode/), available across all projects.project— installs into the chosen code-agent's project-local directory (e.g../.claude/,./.opencode/), this project only.
The two scopes can target different code-agents. pskt find local shows both scopes simultaneously when run from inside a project, with the code-agent of each scope labelled.
pskt init asks which code-agent each scope targets and persists the choice. CLIs found on PATH are offered first as defaults.
| Code-agent | Root install dir | Project install dir |
|---|---|---|
claude (Claude Code) |
~/.claude/ |
./.claude/ |
opencode |
~/.config/opencode/ |
./.opencode/ |
qwen (Qwen Code) |
~/.qwen/ |
./.qwen/ |
codex (OpenAI Codex CLI) |
~/.codex/ |
./.codex/ |
Switch later with pskt code-agent <tool> [root|project]. Without arguments, pskt code-agent prints the current configuration.
Per-code-agent supported kinds. perskent only orchestrates files — it does not edit the code-agent's settings.json / config.toml. Some code-agents accept a given kind only inline in their config, not as a standalone file; in those cases pskt install refuses the kind with a clear message:
| Kind | claude | opencode | qwen | codex |
|---|---|---|---|---|
agent |
✓ | ✓ | ✓ | ✗ (inline in config.toml) |
skill |
✓ | ✓ | ✓ | ✓ (installed into ~/.agents/skills/, by Codex convention) |
command |
✓ | ✓ | ✓ | ✗ (no file-based slash commands) |
The file content (frontmatter format, etc.) is the package author's responsibility — perskent never reads or rewrites the files it copies, so a package written for one code-agent's frontmatter conventions may not work on another without adjustments.
<your-registry>/
├── agents/
│ └── my-agent/
│ ├── manifest.toml
│ ├── agents/my-agent.md → <code-agent-dir>/agents/my-agent.md
│ └── agent-memory/my-agent/... → <code-agent-dir>/agent-memory/my-agent/...
├── skills/
│ └── my-skill/
│ ├── manifest.toml
│ └── skills/my-skill/SKILL.md → <code-agent-dir>/skills/my-skill/SKILL.md
└── commands/
└── my-cmd/
├── manifest.toml
└── commands/my-cmd.md → <code-agent-dir>/commands/my-cmd.md
The parent folder (agents, skills, commands) signals the package kind. Each package's contents (except manifest.toml) are mirrored 1:1 into the code-agent's directory for the chosen scope — no renaming, no imposed layout convention. The author decides the structure inside the package.
[package]
name = "my-agent"
version = "1.0.0"
description = "..."
author = "you"
# Optional. Without this section, the default is to overwrite everything on update.
[update]
preserve = [
"agent-memory/my-agent/MEMORY.md", # exact file
"agent-memory/my-agent/notes/", # whole folder (recursive, trailing /)
]On pskt update, files whose paths match a preserve pattern are not overwritten if they already exist in the destination. This protects user-accumulated data (agent memory, notes, etc.) across versions.
| Scenario | Without preserve |
With preserve |
|---|---|---|
| First install | File is created | File is created (initial template) |
| Update, file exists in destination | Overwritten | Left untouched |
| Update, new version added a file | Created | Created |
| Update, new version removed a file | Removed from destination | Left untouched |
- HTTPS: token (GitHub PAT) stored in the OS keyring when available, or in
~/.config/pskt/tokenwithchmod 600as a fallback (WSL2, headless servers, containers). - SSH: delegated to
ssh-agent/ your SSH key — no token managed by the CLI.
The choice is automatic based on the URL form provided to pskt init.
perskent ships tab completion for bash, zsh, fish, and PowerShell (via Typer).
Install it for your current shell:
pskt --install-completionThe output prints which rc file was modified. Reload your shell (or source the rc file) and tab completion kicks in:
pskt <TAB> # lists commands (init, doctor, status, install, ...)
pskt --<TAB> # lists global flags
pskt install --<TAB> # lists flags for the install subcommandTo preview the completion script without installing it:
pskt --show-completionBoth commands also accept an explicit shell: pskt --install-completion bash, pskt --show-completion zsh, etc.
Note: completion of dynamic values (package names from the registry) is not wired up — completion covers commands and flags only.
- Python 3.11+ on
PATH gitinstalled- A remote Git repository (private or public) you control, to serve as your registry
Versions are published as GitHub Releases. Each release lists the changes and the install command.
MIT