projectskills
v0.14.3
Published
Pull your project's Skills and Constitution into your repository, and ask its analysis and dependency graph from the terminal.
Maintainers
Readme
ProjectSkills CLI
Pull your project's Skills and Constitution into the repository, so the agent in your editor reads them from disk — and ask the analysis and the dependency graph from the terminal, so it can check what a change touches before making it.
npm install -g projectskills
pskl login # approve in the browser
pskl init # create a project for this folder
pskl analyze --watch
pskl pull # write .claude/skills/**/SKILL.mdYour code never needs to be on a public git host, and no GitHub App has to be
installed. init and analyze work on the folder you are standing in — a
private repository, or a directory with no git at all.
Commands
| | |
| ------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| pskl login | Connect this terminal. Shows a code, opens the browser, waits for approval. --token for CI. |
| pskl logout | Remove the credential from this machine. |
| pskl whoami | Who this terminal is signed in as, and on which plan. |
| pskl init | Create a project for this directory and link it. --name, --analyze, -y. |
| pskl link [project] | Bind the directory to a project that already exists. No argument lists them. |
| pskl unlink | Remove the link from this directory. |
| pskl status | Analysis state, model, snapshot, Skills and graph on one screen. |
| pskl explain | A guided read of this codebase, for somebody who did not write it. --snapshot, --markdown. |
| pskl pull | Write Skills and the Constitution. --out, --force, --prune, --for claude\|agents\|all; a Skill or Constitution the audit holds back is not written unless --allow-findings. |
| pskl mcp install | Connect a coding tool so an agent can ask, not only read — every tool below. --for <tools>\|all\|detected, --scope project\|user, --print. No token in any file. |
| pskl mcp serve | The local MCP server a tool starts on this machine: relays to the server with your sign-in or PROJECTSKILLS_TOKEN. You do not run it yourself. |
| pskl mcp doctor | Check that an agent can reach the analysis: token, server, tools, linked project, and every tool configured here at either scope. Prints each fix in your shell; never the token. |
| pskl models | Which AI model analyses your projects, what each costs. --select, --set, --clear. |
| pskl tree | The dependency tree. --depth. |
| pskl graph summary | Size and readiness. Answers on every plan. |
| pskl graph resolve <q> | Find node keys — needed before any traversal. |
| pskl graph node <key> | One node, with neighbours and evidence. |
| pskl graph community <n> | What is in one subsystem, with its cohesion. |
| pskl graph export <fmt> | json, graphml or mermaid. |
| pskl skills list | Every Skill, and which of them were requested. |
| pskl skills freshness | Whether each Skill still describes the code. Names the source files that changed, and says when it cannot tell. |
| pskl skills show <slug> | One Skill in full, with its review, provenance and audit. --markdown for the document alone; a held-back Skill needs --allow-findings. |
| pskl skills new "<subject>" | Ask for a Skill the analysis did not write. Premium. --detail. |
| pskl skills regenerate [slug] | Rewrite a Skill against the current analysis. -y. |
| pskl skills rm <slug> | Delete a Skill you requested. Catalogue Skills cannot be deleted. -y. |
| pskl impact <node> | What breaks if this changes. --out inverts it, --depth, --limit. |
| pskl why <a> <b> | How these two are connected. --max-hops, --undirected. |
| pskl ask "<question>" | The part of the graph a question touches. --depth, --limit. |
| pskl insights | Cycles, hubs and edges that should not exist. --limit. |
| pskl diff | What changed in the graph between two snapshots. --from, --to, --list. |
| pskl findings | What the deterministic detectors found, which of them actually ran, and what each one could not check. --severity, --category, --detector, --snapshot, --limit, --fail-on. |
| pskl findings diff | Findings that are new, persisting or resolved between two snapshots. --base, --head, --fail-on, --markdown. |
| pskl findings trend | Whether this project is getting better, across snapshots. A snapshot that was not fully checked is a break, not a low point. --limit. |
| pskl findings hotspots | Files where findings, change and dependency land together. An unmeasured signal prints as unmeasured, never as zero. --snapshot, --limit. |
| pskl skills audit | What the deterministic rules found in the Skills this project generated — and, first, how many nobody has audited. Advisory: exit stays 0 unless you ask for a gate. --slug, --run, --fail-on. |
| pskl constraints | The floor this project holds itself to, and whether the last snapshot cleared it. A check that never concluded is counted apart from one that passed. --dimension, --status, --snapshot, --fail-on. |
| pskl snapshots | Every capture of this project: when it was taken, whether it was a commit or a working tree, and what it changed against the one before. |
| pskl changes | Which files were added, modified, deleted or renamed in a snapshot — and which could not be compared at all. --snapshot, --kind, --limit. |
| pskl intelligence | What the analysis concluded, every claim with its confidence. --section, --evidence, --snapshot. |
| pskl sbom | A CycloneDX bill of materials. Built from manifests, never claims to be complete, and states no licence it does not know. --snapshot, --out. |
| pskl share create | A read-only link to this snapshot's report, for somebody with no account. Shown once, expires. --days, --label, --snapshot. |
| pskl share list | Every link, whether it is live, and how often it was opened. |
| pskl share revoke <id> | Stop a link working, immediately. |
| pskl webhooks list | Every destination registered, with what happened to the last delivery. |
| pskl webhooks add <url> | Register a destination. https only, public address only; the signing secret is shown once. --events. |
| pskl webhooks rm <id> | Stop delivering to a destination. |
| pskl webhooks deliveries <id> | What happened to recent deliveries. REFUSED means this service declined to make the request, not that yours refused it. --limit. |
| pskl stack | Technologies detected, and what each detection rests on. --category, --evidence. |
| pskl architecture | The deterministic fact sheet — routes, tables, entry points, languages. --routes. |
| pskl files | How the snapshot classified what it ingested, including anything classified secret. |
| pskl usage | Tokens and cost for the month, by project, model and task. --project, --from, --to. |
| pskl quota | How much of each limit is left, and when it resets. |
| pskl history | Every analysis run, with cost, duration and what it produced. --limit, --status, --all. |
| pskl keel start | Open a design session. --quadrant (FOUND · ORIGIN · FIT · CHART), -m. |
| pskl keel say "<text>" | Send one turn and wait for the reply. --session. |
| pskl keel show | Where the interview is, what it settled, and which model answered. --session. |
| pskl keel list | Every session on this account. |
| pskl keel skip <slot> | Record that nobody knows this yet — not the same as moving on. --session. |
| pskl keel next | Close this stage and move on, whatever is still open. --session. |
| pskl keel pull | Write KEEL.md, keel-session.md and keel-scaffold/. Premium. --out, --force, --session. |
| pskl keel stale | Whether the plan is still true of the code it was written about. --session. |
| pskl keel retry <kind> | Rebuild a plan or scaffold whose composition failed. Premium. --session. |
| pskl keel abandon <id> | Close a session for good. The id is never resolved for you. |
| pskl analyze | Start an analysis. --include-uncommitted, --allow-secrets, --github, --public, --zip, --watch. |
| pskl analyze --local | Send a digest instead of the code: paths, sizes, hashes and dependency manifests. No source leaves the machine. Produces the file index, dependencies and SBOM — not the graph or the findings. |
| pskl analyze status | The steps of the most recent run. --watch follows it. |
Connecting a coding tool
pskl mcp install --for <tool> connects one tool, or several separated by
commas; --for all is every tool with a repository config, and --for detected
every tool installed on this machine. --print writes nothing and shows each
entry and where it goes.
Two scopes, and neither ever writes the token:
- In the repository (
--scope project, the default where a tool supports it) — a file meant to be committed. VS Code asks for the token once and keeps it in its secret storage; the other tools readPROJECTSKILLS_TOKENfrom the environment, each in its own syntax. - On this machine (
--scope user) — the tool startspskl mcp serve, which uses yourpskl login. Nothing to set, and it works for an editor opened from the Dock or the Start menu, which never sees a shell's variables. The entry names Node and this CLI by absolute path, so it needs no shell on Windows either; re-run it after moving either one (pskl mcp doctorsays when).
| Tool | --for | In the repository | On this machine |
| ----------------------------------------- | ---------------------------------------------------------- | ------------------------- | ------------------------------------------------------------- |
| Claude Code | claude | .mcp.json | prints a claude mcp add --scope user command |
| Codex | codex | .codex/config.toml | ~/.codex/config.toml (CODEX_HOME) |
| Cursor | cursor | .cursor/mcp.json | ~/.cursor/mcp.json |
| VS Code | vscode | .vscode/mcp.json | VS Code's user mcp.json |
| Google Antigravity | antigravity | — | ~/.gemini/config/mcp_config.json |
| JetBrains IDEs (PyCharm, IntelliJ IDEA …) | jetbrains, pycharm, intellij, webstorm, goland … | — | prints the JSON for Settings → Tools → AI Assistant → MCP |
| Junie | junie | — | ~/.junie/mcp/mcp.json |
| Gemini CLI | gemini | .gemini/settings.json | ~/.gemini/settings.json |
| GitHub Copilot CLI | copilot | — | ~/.copilot/mcp-config.json |
| Devin Desktop (formerly Windsurf) | devin, windsurf | — | Devin's mcp_config.json, or Windsurf's where only it exists |
| Kiro | kiro | .kiro/settings/mcp.json | ~/.kiro/settings/mcp.json |
| Roo Code | roo | .roo/mcp.json | Roo's mcp_settings.json inside VS Code |
| Cline | cline | — | Cline's cline_mcp_settings.json inside VS Code |
| Zed | zed | — | context_servers in Zed's settings.json, comments kept |
| Claude Desktop | claude-desktop | — | claude_desktop_config.json (macOS, Windows) |
| Visual Studio | visual-studio | — | %USERPROFILE%\.mcp.json (Windows) |
| OpenCode | opencode | opencode.json(c) | ~/.config/opencode/opencode.json |
| Continue | continue | — | prints a block for .continue/mcpServers/projectskills.yaml |
A tool with no repository column cannot take the token from its environment,
so the only repository config it could have would contain the token. Only the
ProjectSkills entry changes in any file: other servers, settings and comments
survive, and the previous version is kept as <file>.projectskills.bak. A file
that does not parse is left alone.
.mcp.json is Claude Code's. GitHub Copilot CLI, VS Code and Visual Studio read
it too but do not expand ${PROJECTSKILLS_TOKEN} in it; connect each through
its own config, as above. pskl mcp doctor warns when one of them is installed
and is not.
Exit codes
A tool that answers 1 for everything cannot be branched on in a script.
| | |
| --- | --------------------------------------------- |
| 0 | fine |
| 1 | failed |
| 2 | wrong usage |
| 3 | not signed in |
| 4 | plan does not include it |
| 5 | not found |
| 6 | rate limited |
| 7 | not ready yet (no graph, analysis unfinished) |
Where things go
.claude/skills/<name>/SKILL.md— the artefacts. The directory name must match the front-mattername:or Claude Code will not load them..projectskills/project.json— the link. Commit it. A project id is not a secret: the API answers "not found" to anyone who is not a member..projectskills/artifacts.json— what was written, and its hash. This is howpullknows not to overwrite a file you edited by hand.~/.config/projectskills/credentials.json— the token,0600.- A coding tool's MCP config — see the table above.
Machine-scope files this creates are
0600, and none ever holds the token.
PROJECTSKILLS_TOKEN overrides the stored credential and is never written to
disk. That is the CI path.
Motion
analyze --watch paces a small robot along the line while the pipeline runs,
captioned with the step it is on; uploads, packing and the sign-in wait get a
spinner. All of it turns itself off when stdout is not a terminal, under
--json, when CI is set, and on TERM=dumb — escape sequences in a log file
are corruption, not decoration. The cursor is restored on exit and on Ctrl-C.
Notes
pskl analyze packs the current directory through git, so .gitignore is
honoured by the same rules your own tooling uses — untracked node_modules and
build output stay out.
.gitignore does not exclude a file git is already tracking. A .env
committed before anyone thought to ignore it is still in your history, and would
be uploaded. So before sending anything, analyze checks the archive against the
same secret patterns the server uses and refuses, naming the files and how to
untrack them. --allow-secrets overrides it.
- In a git repository it archives HEAD, so uncommitted work is excluded. It says how many changes it left behind.
--include-uncommittedsends the working tree instead. Your staging area is never touched: it builds the tree through a throwaway index.- A plain directory works too. No repository is needed — a temporary git directory is created outside your folder, and nothing is written into it.
pull never overwrites a generated file you have edited. It says which ones
and exits non-zero; --force overrides.
