Remove a single installed capability — a griller or a lens — from an existing project (one with a
pharn.config.json). The inverse of add: it deletes exactly that capability's directory and
drops its entry from pharn.config.json.
pharn remove <name> # e.g. pharn remove a11y
pharn remove <role>:<name> # e.g. pharn remove lens:n-plus-one
pharn remove # no arg, in a terminal: interactive multi-select pickerrm is accepted as an alias for remove.
- Reads
pharn.config.json. If none exists — or it is a pre-archetype (module) config — it exits with a hint to runpharn initfirst. - With no argument in a terminal, opens an interactive multi-select picker (grouped by role) over
the capabilities you have installed, then asks for one confirmation listing your picks. With an
argument, resolves it to one installed capability. In a non-interactive context (CI, a pipe),
no-argument
pharn removedoes not prompt — it exits with a usage error (unless nothing is installed, which is reported plainly). - Deletes each selected capability's isolated directory and drops its entry from
capabilities. - Prunes that capability's entries from
pharn.records.json, so the store never describes files that are gone.
Removal needs no network and no clone — everything is derivable from capabilities plus your
filesystem. CONSTITUTION.md, memory-bank/, and your detected archetypes are never touched.
Each capability lives in its own directory, addressed at your project's recorded layout — flat
(pharn-review/<name> for a lens, pharn-pipeline/grillers/<name> for a griller) or the same paths
under pharn/. Removal is therefore precise; siblings are never touched.
- Not installed → a no-op (nothing is written); the CLI lists the capabilities you actually have as the valid values.
- Ambiguous (a name installed in both roles, given without a role) → the CLI asks you to
disambiguate with
griller:/lens:. - Already-deleted directory → treated as done (idempotent).
remove takes no options at all. --yes / -y is an update flag, and
pharn remove --yes is refused (exit 1) rather than accepted and ignored. There is nothing here
for it to skip: the named form above deletes without asking, and the picker's one confirmation is the
destructive gate itself — it is always shown, it lists exactly what will be deleted, and it defaults
to No.
Earlier releases accepted
pharn remove --yesand silently dropped it. See Unsupported option for this command.
remove takes the project lock (.pharn.lock) around its delete → prune → config write — on the
named path, and on the picker path after its one confirmation. A second pharn writer refuses with a
named message and exit 1. Worth knowing because remove is otherwise entirely local: it makes no
network call and clones nothing, so a refusal is the one thing that can stop it for a reason outside
your project. See
Another pharn process is running.
Removing a capability also drops its entries from pharn.records.json
— the sidecar recording a hash per file pharn wrote — so nothing in it describes bytes that no longer
exist. Every other entry, and the store's skillsVersion/commit stamp, is left exactly as it was:
remove changes neither version nor commit. If the store is absent, unreadable, or stamped for a
different install state, remove leaves the file untouched rather than minting or rewriting one it
cannot verify — the same rule add follows. The removal itself proceeds either way.
If the entry's recorded source is auto — it was selected for your archetypes by
init or a prior update — remove prints a warning that the next
pharn update will reinstall it (and will name it in its report), because update
re-resolves your archetypes every run. Removing a manual entry (one you added with
add) warns nothing.
The warning asserts "will", not "may", because it is derived from the stored source alone — remove
makes no network call and cannot re-resolve. The next section is why that is a heuristic rather than a
guarantee.
Silence is not a promise that the removal is permanent. update writes
resolve(archetypes) ∪ manual; dropping the entry removes it from the manual half, but the
resolved half is unaffected. If your archetypes still select that capability — and most capabilities
are universal, so they usually do — the next update may re-add it as auto and name it under
ADDED. remove cannot warn about this: it has no capability index and never fetches one, so it
cannot know whether your archetypes select the thing you are removing. To keep a capability out for
good, remove the archetype that selects it.
The warning is derived from the stored field alone, so remove stays offline. An entry whose source
is absent (a config predating the field) warns nothing — its provenance is genuinely unknown until
the next update infers it, and a wrong warning would be worse than none. See
capabilities[].source.