Skip to content

Latest commit

 

History

History
99 lines (77 loc) · 5.59 KB

File metadata and controls

99 lines (77 loc) · 5.59 KB

pharn remove

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 picker

rm is accepted as an alias for remove.

Behavior

  1. Reads pharn.config.json. If none exists — or it is a pre-archetype (module) config — it exits with a hint to run pharn init first.
  2. 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 remove does not prompt — it exits with a usage error (unless nothing is installed, which is reported plainly).
  3. Deletes each selected capability's isolated directory and drops its entry from capabilities.
  4. 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.

The capability argument

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 --yes and silently dropped it. See Unsupported option for this command.

Concurrency

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.

The record store

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.

Removing an auto-selected capability

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.

Related