Skip to content

chore: canonical npm name, OIDC publish workflow, release docs - #53

Merged
PrzemekGalarowicz merged 10 commits into
mainfrom
chore/rename-to-pharn-publish-ci
Jul 22, 2026
Merged

chore: canonical npm name, OIDC publish workflow, release docs#53
PrzemekGalarowicz merged 10 commits into
mainfrom
chore/rename-to-pharn-publish-ci

Conversation

@PrzemekGalarowicz

@PrzemekGalarowicz PrzemekGalarowicz commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

What

Three commits:

  1. af34d3a — finalize the pharn-clipharn rename across docs, config, dev artifacts, and source comments; set publishConfig.provenance: false (automatic provenance needs a CI OIDC provider and aborts with provider: null on a local npm publish).
  2. 9b889fc — rename the npm package pharn → the scoped @pharn-dev/pharn across all user-facing surfaces (package.json name, README badge + npx install, docs/, CONTRIBUTING, SECURITY, CHANGELOG, issue templates, pharn -h usage, git-prereq error message). The installed bin stays pharn (unscoped) — only the package identity is scoped. Also syncs stale in-code comments left by the module-model removal (init.ts, constitution.ts, repo.ts).
  3. 815acf2 — add .github/workflows/publish.yml: publishes to npm on a GitHub Release (or manual dispatch) with provenance via id-token: write + an explicit --provenance flag, which overrides the false default so local and CI publishing both work.

CI green locally: format, lint, typecheck, 378 tests.

Maintainer follow-ups

  • Add an NPM_TOKEN repo secret (an npm automation/granular token that bypasses 2FA) for the publish workflow.
  • Publishing @pharn-dev/pharn needs the pharn-dev npm org/scope (+ --access public, already set in publishConfig and the workflow).
  • origin is still pharn-dev/pharn-cli while package.json points at pharn-dev/pharn — rename the GitHub repo (or revert the URLs) to reconcile. README CI/CodeQL badges still point at pharn-cli (correct until the repo is renamed).

Deliberately NOT touched (pre-existing, out of scope)

  • Stale module-model references in SECURITY.md (manifest.ts, MODULE_NAME_RE, schemaVersion gate) and CHANGELOG.md (pharn remove <module>, pharn-core) that predate the module-model removal.
  • CHANGELOG still describes publishConfig as "(public access + provenance)"; with provenance: false + CI-based provenance you may want to reword.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • The package is now published under the canonical pharn name with a single pharn command.
    • Added automated npm publishing for GitHub releases and manual runs.
    • Installation guidance now supports archetype- and capability-based setup through npx pharn init.
  • Bug Fixes

    • Legacy module-based configurations are now detected clearly, with guidance to rerun pharn init.
  • Documentation

    • Updated installation, command, security, contribution, and troubleshooting documentation to consistently use pharn and describe the current workflow.

Rename remaining `pharn-cli` -> `pharn` references across docs, config,
dev artifacts, and source comments: repo/bugs/homepage URLs in
package.json, plus README, THREAT-MODEL, LIMITS, SECURITY, CHANGELOG,
CONSTITUTION, CONTRIBUTING, docs/, and .dev/ plan artifacts.

Set publishConfig.provenance to false so `npm publish` runs from a local
machine. npm's automatic provenance requires a supported CI provider
(GitHub Actions / GitLab OIDC) and aborts with "provider: null" when run
locally. A follow-up CI workflow re-enables provenance via an explicit
--provenance flag that overrides this default.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jul 22, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The PR aligns the repository and feature records from pharn-cli to pharn, updates CLI and security documentation, adds an npm publishing workflow, changes npm provenance configuration, and refreshes development-tooling records and verification artifacts.

Changes

Product naming and public documentation

Layer / File(s) Summary
Public identity and repository references
README.md, CHANGELOG.md, SECURITY.md, THREAT-MODEL.md, docs/*, .github/*, package.json, .github/workflows/publish.yml
Public-facing naming, CLI instructions, security guidance, package publication settings, and the release workflow are updated for pharn.
CLI installation and capability documentation
CLAUDE.md, src/*, docs/commands/init.md, .claude/commands/*
Current archetype/capability installation, configuration handling, validation boundaries, and legacy-config behavior are documented.
Feature plans and verification records
.dev/features/*
Plans, reviews, grill logs, verification reports, ship records, and regression records update product naming, package metadata, repository references, and gate results.
Development tooling and write scope
.claude/hooks/*, .dev/floor/*, .pharn/*
Tooling comments, scanner metadata, recorded gate results, and write-scope metadata are updated for the renamed product and new feature artifact.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately captures the main package rename, OIDC publish workflow, and release documentation updates.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch chore/rename-to-pharn-publish-ci

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

PrzemekGalarowicz and others added 2 commits July 22, 2026 16:33
…ments

Rename the npm package `pharn` -> the scoped `@pharn-dev/pharn` across all
user-facing surfaces: package.json `name`, README (badge + npx install),
docs/, CONTRIBUTING, SECURITY, CHANGELOG, the GitHub issue templates, the
`pharn -h` USAGE text (src/index.ts), and the git-prereq error message
(src/steps/prereqs.ts). The installed bin stays `pharn` (unscoped); only the
npm package identity is scoped.

Also correct stale in-code comments left by the module-model removal:
src/commands/init.ts (no manifest fallback), src/lib/constitution.ts
(test-only now that wizard.ts is gone), and src/lib/repo.ts (capability index,
not manifest.json).

Fix a CHANGELOG garble the earlier repo-wide pharn-cli->pharn rename
introduced (`pharn` -> `pharn`), restoring the historical `pharn-cli`.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Publish to npm on a GitHub Release (or manual dispatch). Uses OIDC
(id-token: write) + `npm publish --provenance` for a signed provenance
attestation; the flag overrides package.json's `provenance: false`, so CI
gets provenance while local `npm publish` stays functional.

Requires an NPM_TOKEN repository secret (npm automation/granular token).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@PrzemekGalarowicz
PrzemekGalarowicz force-pushed the chore/rename-to-pharn-publish-ci branch from 89c5f88 to 815acf2 Compare July 22, 2026 14:33
@PrzemekGalarowicz PrzemekGalarowicz changed the title chore: finalize pharn rename + add npm publish workflow chore: rename npm package to @pharn-dev/pharn + add npm publish workflow Jul 22, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 9

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
CONSTITUTION.md (1)

20-24: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Align capability-document wording with the install artifacts.

README.md describes capabilities as the install unit and says there’s no module catalog/manifest.json, but CONSTITUTION.md and LIMITS.md still say pharn fetches manifests/module manifests and installs modules. These security-document sections should use the README’s capability-frontmatter/artifact wording, otherwise the same trust boundary is documented in two different systems.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@CONSTITUTION.md` around lines 20 - 24, The capability-document wording is
inconsistent with README.md: update CONSTITUTION.md lines 20-24 and LIMITS.md
lines 21-31 to describe capability frontmatter and install artifacts as the
trust boundary, removing references to manifests, module manifests, module
catalogs, and module-based installation while preserving the stated security
principles and limitations.
🧹 Nitpick comments (1)
CLAUDE.md (1)

48-49: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Document the fetch invariant for repo.ts too.

This section names only skills-version.ts, but the repository rule applies to both src/lib/skills-version.ts and src/lib/repo.ts; repo.ts owns the commit-metadata fetch. List both files so future edits preserve redirect rejection, the 8-second timeout, and the 256 KB body cap.

As per coding guidelines, remote fetches in src/lib/{skills-version,repo}.ts must use redirect errors, an 8-second timeout, and a 256 KB body limit.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@CLAUDE.md` around lines 48 - 49, Update the remote-fetch invariant
documentation in CLAUDE.md to name both skills-version.ts and repo.ts,
explicitly requiring redirect rejection, an 8-second timeout, and a 256 KB
response-body cap for each. Preserve the existing validation and
path-containment guidance.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.dev/features/canonical-npm-name/PLAN.md:
- Around line 1-5: Reconcile the verification records with the current scoped
package identity: in .dev/features/canonical-npm-name/PLAN.md lines 1-5, replace
the unscoped pharn objective or mark the plan superseded; in
.dev/features/canonical-npm-name/GRILL.md lines 29-34, update tarball and
package assertions to `@pharn-dev/pharn`; in
.dev/features/canonical-npm-name/REVIEW.md lines 1-5, align the reviewed rename
direction with the scoped identity; and in
.dev/features/npm-publish-metadata/SHIP.md line 21, replace the pharn→pharn
statement with the actual `@pharn-dev/pharn` rename.

In @.dev/features/canonical-npm-name/SHIP.md:
- Around line 3-4: Correct the ship record’s package identity and release
direction: update the increment description to rename `pharn-cli` to
`@pharn-dev/pharn` while preserving the installed `pharn` binary, and remove the
unscoped-package/deprecation guidance. If this is stale historical output rather
than an active record, remove the artifact instead.

In @.dev/features/canonical-npm-name/verify-report.json:
- Around line 8-12: Update the verification artifact and its underlying
validation flow so the validate gate passes rather than leaving verdict as FAIL;
exclude generated test-*/ fixtures from validation as appropriate. Ensure the
resulting verify.verdict is PASS and failing_gates is empty, preserving the
.dev/floor/check-ship.mjs contract and requiring all CI gates to pass.

In @.dev/features/npm-publish-metadata/PLAN.md:
- Around line 10-13: The plan should use the scoped npm package name
`@pharn-dev/pharn` throughout package metadata and installation instructions,
while retaining pharn as the executable/bin name. Update the package.json,
README.md, CHANGELOG.md, and CLAUDE.md entries to replace unscoped package
references and change the npx command to target `@pharn-dev/pharn`.
- Around line 24-27: Align the repository metadata claim with the actual package
configuration: in .dev/features/npm-publish-metadata/PLAN.md lines 24-27, either
update the documented repository URL to pharn-dev/pharn-cli or change
package.json consistently to pharn-dev/pharn; in
.dev/features/npm-publish-metadata/GRILL.md line 51, remove the “EXACT”
assertion unless the package metadata is updated to match.

In @.github/workflows/publish.yml:
- Around line 3-8: Add a pre-publish validation step in the publish workflow
that compares the GitHub Release tag (removing the v prefix as needed) with the
version in package.json and fails on mismatch. Restrict workflow_dispatch
publishing to the intended release ref, while preserving the existing
release-triggered publishing behavior.
- Around line 21-24: Update the actions/setup-node configuration in the
privileged publish job to disable automatic package-manager caching by setting
package-manager-cache to false, and remove the cache: npm setting. Leave
dependency caching enabled only in the non-publishing CI jobs.

In `@CHANGELOG.md`:
- Around line 96-97: Update the initial release note to remove the duplicate bin
names, restoring the historical second binary name or clearly stating that only
the pharn binary is exposed.

In `@SECURITY.md`:
- Around line 3-9: The security documentation understates the installation write
surface. In SECURITY.md, update the description to cover .claude/, the mirrored
capability layout, root product surfaces, and pharn.config.json; in
THREAT-MODEL.md, expand Surface A beyond .claude/ to include every installed
location. Preserve the existing remote-input and safe-write security model while
ensuring both documents describe the current layout consistently.

---

Outside diff comments:
In `@CONSTITUTION.md`:
- Around line 20-24: The capability-document wording is inconsistent with
README.md: update CONSTITUTION.md lines 20-24 and LIMITS.md lines 21-31 to
describe capability frontmatter and install artifacts as the trust boundary,
removing references to manifests, module manifests, module catalogs, and
module-based installation while preserving the stated security principles and
limitations.

---

Nitpick comments:
In `@CLAUDE.md`:
- Around line 48-49: Update the remote-fetch invariant documentation in
CLAUDE.md to name both skills-version.ts and repo.ts, explicitly requiring
redirect rejection, an 8-second timeout, and a 256 KB response-body cap for
each. Preserve the existing validation and path-containment guidance.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 883be253-0cb0-4632-a400-bb3af6d26fe4

📥 Commits

Reviewing files that changed from the base of the PR and between ffc0322 and afe7334.

📒 Files selected for processing (76)
  • .claude/commands/pharn-dev-build.md
  • .claude/hooks/enforce-writes-scope.cjs
  • .claude/hooks/enforce-writes-scope.test.cjs
  • .dev/features/archetype-enum-align/PLAN.md
  • .dev/features/archetype-file-tree-scan/PLAN.md
  • .dev/features/archetype-io-boundary/PLAN.md
  • .dev/features/archetype-missing-signal/PLAN.md
  • .dev/features/archetype-path-context/PLAN.md
  • .dev/features/canonical-npm-name/GRILL.md
  • .dev/features/canonical-npm-name/PLAN.md
  • .dev/features/canonical-npm-name/REGRESSION.md
  • .dev/features/canonical-npm-name/REVIEW.md
  • .dev/features/canonical-npm-name/SHIP.md
  • .dev/features/canonical-npm-name/VERIFY.md
  • .dev/features/canonical-npm-name/regression-report.json
  • .dev/features/canonical-npm-name/verify-report.json
  • .dev/features/capability-resolver/PLAN.md
  • .dev/features/commands-off-manifest/PLAN.md
  • .dev/features/commands-off-manifest/REVIEW.md
  • .dev/features/commands-off-manifest/SHIP.md
  • .dev/features/commands-off-manifest/VERIFY.md
  • .dev/features/commands-off-manifest/verify-report.json
  • .dev/features/config-loader-honest-errors/GRILL.md
  • .dev/features/config-loader-honest-errors/PLAN.md
  • .dev/features/fresh-check-git-rce/PLAN.md
  • .dev/features/harden-install-path/GRILL.md
  • .dev/features/harden-install-path/PLAN.md
  • .dev/features/harden-install-path/REVIEW.md
  • .dev/features/harden-install-path/VERIFY.md
  • .dev/features/init-archetype-default/PLAN.md
  • .dev/features/init-archetype-default/REVIEW.md
  • .dev/features/init-install-capabilities/GRILL.md
  • .dev/features/init-install-capabilities/PLAN.md
  • .dev/features/installer-layout-mirror/PLAN.md
  • .dev/features/installer-layout-mirror/SHIP.md
  • .dev/features/list-archetype-aware/PLAN.md
  • .dev/features/model-routing-config/PLAN.md
  • .dev/features/npm-publish-metadata/GRILL.md
  • .dev/features/npm-publish-metadata/PLAN.md
  • .dev/features/npm-publish-metadata/REGRESSION.md
  • .dev/features/npm-publish-metadata/SHIP.md
  • .dev/features/npm-publish-metadata/VERIFY.md
  • .dev/features/regress/PLAN.md
  • .dev/features/remove-dead-docs-url/GRILL.md
  • .dev/features/remove-dead-docs-url/PLAN.md
  • .dev/features/remove-dead-docs-url/REGRESSION.md
  • .dev/features/remove-vendor-skill/PLAN.md
  • .dev/features/remove-vendor-skill/REGRESSION.md
  • .dev/floor/lens-scanner-map.json
  • .dev/floor/lens-scanner-map.test.mjs
  • .github/ISSUE_TEMPLATE/bug_report.md
  • .github/ISSUE_TEMPLATE/feature_request.md
  • .github/PULL_REQUEST_TEMPLATE.md
  • .github/workflows/publish.yml
  • .pharn/pharn-dev-regress/base-results.json
  • .pharn/pharn-dev-regress/head-results.json
  • .pharn/pharn-dev-verify/results.json
  • .pharn/writes-scope.json
  • CHANGELOG.md
  • CLAUDE.md
  • CODE_OF_CONDUCT.md
  • CONSTITUTION.md
  • CONTRIBUTING.md
  • LIMITS.md
  • README.md
  • SECURITY.md
  • THREAT-MODEL.md
  • docs/README.md
  • docs/commands/init.md
  • docs/contributing.md
  • docs/getting-started.md
  • package.json
  • src/commands/init.ts
  • src/lib/constitution.ts
  • src/lib/repo.ts
  • src/types.ts

Comment on lines +1 to +5
# PLAN — canonical-npm-name (rename npm package `@pharn-dev/pharn` → `pharn`)

- spec_content_hash: bca940a5ad247c120e6d8a3acba119d0d8df51dca275964d0e54c48d729d3c4e # fix #4 (ARCHITECTURE.md)
- increment: Publish the package under the canonical **unscoped** name `pharn` by setting `package.json.name` and aligning every npm-name reference in the docs/repo surface — no version bump, no CLI behavior change.
- layer(s): packaging (`package.json`) + docs/repo-surface (`*.md`, `docs/**`, `.github/ISSUE_TEMPLATE/**`) — **no `src/` code-behavior layer** (ARCHITECTURE.md §4). See OQ1 for the one src edge case.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Reconcile the package identity in the verification records.

These artifacts describe publishing the unscoped pharn package, while this PR targets scoped @pharn-dev/pharn. That mismatch can mislead release operators and invalidate the recorded tarball/package checks. Update the records to the scoped identity, or clearly mark them as superseded historical artifacts.

  • .dev/features/canonical-npm-name/PLAN.md#L1-L5: replace the unscoped package objective or mark this plan superseded.
  • .dev/features/canonical-npm-name/GRILL.md#L29-L34: update the tarball/package assertions to match the scoped package.
  • .dev/features/canonical-npm-name/REVIEW.md#L1-L5: align the reviewed rename direction with the current package identity.
  • .dev/features/npm-publish-metadata/SHIP.md#L21-L21: correct the nonsensical pharn→pharn metadata statement and record the actual rename.
🧰 Tools
🪛 LanguageTool

[uncategorized] ~5-~5: The official name of this software platform is spelled with a capital “H”.
Context: ...+ docs/repo-surface (*.md, docs/**, .github/ISSUE_TEMPLATE/**) — **no src/ code-...

(GITHUB)

📍 Affects 4 files
  • .dev/features/canonical-npm-name/PLAN.md#L1-L5 (this comment)
  • .dev/features/canonical-npm-name/GRILL.md#L29-L34
  • .dev/features/canonical-npm-name/REVIEW.md#L1-L5
  • .dev/features/npm-publish-metadata/SHIP.md#L21-L21
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.dev/features/canonical-npm-name/PLAN.md around lines 1 - 5, Reconcile the
verification records with the current scoped package identity: in
.dev/features/canonical-npm-name/PLAN.md lines 1-5, replace the unscoped pharn
objective or mark the plan superseded; in
.dev/features/canonical-npm-name/GRILL.md lines 29-34, update tarball and
package assertions to `@pharn-dev/pharn`; in
.dev/features/canonical-npm-name/REVIEW.md lines 1-5, align the reviewed rename
direction with the scoped identity; and in
.dev/features/npm-publish-metadata/SHIP.md line 21, replace the pharn→pharn
statement with the actual `@pharn-dev/pharn` rename.

Comment on lines +3 to +4
Increment: rename the npm package `@pharn-dev/pharn` → `pharn` (canonical unscoped name), no version
bump, no behavior change. Run via `/pharn-dev-ship` (gated mode).

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Correct the package identity in this ship record.

This record says the package is changing from @pharn-dev/pharn to unscoped pharn, and advises deprecating the scoped package. The PR objective is the opposite: pharn-cli@pharn-dev/pharn, with the installed binary remaining pharn. Update this artifact to describe the scoped publish, or remove it if it is stale historical output; otherwise the active ship record can mislead release and deprecation steps.

Also applies to: 45-47

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.dev/features/canonical-npm-name/SHIP.md around lines 3 - 4, Correct the
ship record’s package identity and release direction: update the increment
description to rename `pharn-cli` to `@pharn-dev/pharn` while preserving the
installed `pharn` binary, and remove the unscoped-package/deprecation guidance.
If this is stale historical output rather than an active record, remove the
artifact instead.

Comment on lines +8 to +12
"validate": 1
},
"verdict": "FAIL",
"failing_gates": [
"validate"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

Do not leave the ship verification verdict as FAIL.

The ship helper computes a green floor only when verify.verdict === "PASS". With validate: 1, this artifact blocks shipping despite describing the failure as pre-existing. Either make validate pass by excluding the generated test-*/ fixtures, or update the ship policy and report contract to explicitly accept pre-existing failures.

Based on the supplied .dev/floor/check-ship.mjs contract, floorGreen requires a PASS verification verdict. Based on learnings, all CI gates must pass.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.dev/features/canonical-npm-name/verify-report.json around lines 8 - 12,
Update the verification artifact and its underlying validation flow so the
validate gate passes rather than leaving verdict as FAIL; exclude generated
test-*/ fixtures from validation as appropriate. Ensure the resulting
verify.verdict is PASS and failing_gates is empty, preserving the
.dev/floor/check-ship.mjs contract and requiring all CI gates to pass.

Source: Learnings

Comment on lines +10 to +13
- `package.json` — npm publish metadata (see concrete values below): `name` pharn→**pharn**, `description`, `keywords`, `repository`/`bugs`/`homepage`, `bin`→`{pharn}`, `publishConfig{access,provenance}`, `scripts.prepublishOnly` + `scripts.prepack`, `engines` (decision Q1). `version` **stays 0.2.0** (metadata, not behavior). — layer: repo packaging
- `README.md` — add an **Install** section (`npx pharn@latest init`); update the npm badge `pharn`→`pharn` and the "npm package is `pharn` / both bins" note (line ~43) to the new name + single bin. **No** module-prose rewrite (see Q4). — layer: docs
- `CHANGELOG.md` — one `[Unreleased]` entry: rename to `pharn` + publish-readiness metadata, Keep-a-Changelog format. — layer: docs
- `CLAUDE.md` — update the "Published as `pharn-cli`, exposing both `pharn` and `pharn-cli` bins" line to the new `pharn` package name + single bin. — layer: project guidance
- `CLAUDE.md` — update the "Published as `pharn`, exposing both `pharn` and `pharn` bins" line to the new `pharn` package name + single bin. — layer: project guidance

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

Use the scoped npm package name from the PR contract.

The objective requires @pharn-dev/pharn; this plan still describes the package as unscoped pharn and implies npx pharn@latest. Keep the executable name pharn, but use the scoped package name in metadata and install instructions.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.dev/features/npm-publish-metadata/PLAN.md around lines 10 - 13, The plan
should use the scoped npm package name `@pharn-dev/pharn` throughout package
metadata and installation instructions, while retaining pharn as the
executable/bin name. Update the package.json, README.md, CHANGELOG.md, and
CLAUDE.md entries to replace unscoped package references and change the npx
command to target `@pharn-dev/pharn`.

Comment on lines +24 to +27
- `repository`: `{ "type": "git", "url": "git+https://github.com/pharn-dev/pharn.git" }` (EXACT — provenance attestation validates this against the building repo)
- `bugs`: `{ "url": "https://github.com/pharn-dev/pharn/issues" }`
- `homepage`: `"https://github.com/pharn-dev/pharn#readme"`
- `bin`: `{ "pharn": "dist/index.js" }` (Q2 — drop the `pharn` alias)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Align repository metadata claims with the actual package configuration.

The plan and grill record pharn-dev/pharn as the exact repository URL, but the supplied package.json evidence still points to pharn-dev/pharn-cli. This must be either an intentional metadata migration or an inaccurate verification record.

  • .dev/features/npm-publish-metadata/PLAN.md#L24-L27: update the concrete metadata claim or change package.json consistently.
  • .dev/features/npm-publish-metadata/GRILL.md#L51-L51: remove the “EXACT” assertion until it matches the actual package metadata.
📍 Affects 2 files
  • .dev/features/npm-publish-metadata/PLAN.md#L24-L27 (this comment)
  • .dev/features/npm-publish-metadata/GRILL.md#L51-L51
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.dev/features/npm-publish-metadata/PLAN.md around lines 24 - 27, Align the
repository metadata claim with the actual package configuration: in
.dev/features/npm-publish-metadata/PLAN.md lines 24-27, either update the
documented repository URL to pharn-dev/pharn-cli or change package.json
consistently to pharn-dev/pharn; in .dev/features/npm-publish-metadata/GRILL.md
line 51, remove the “EXACT” assertion unless the package metadata is updated to
match.

Comment thread .github/workflows/publish.yml Outdated
Comment on lines +21 to +24
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v6
with:
node-version: 20
cache: npm

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== workflow files =="
git ls-files .github/workflows || true

echo
echo "== publish workflow =="
if [ -f .github/workflows/publish.yml ]; then
  cat -n .github/workflows/publish.yml
fi

echo
echo "== zizmor references / secrets usage in publish workflow =="
rg -n "npm_cache|cache|NPM_TOKEN|npm publish|setup-node|permissions|contents|contents:|github-token|id-token|GITHUB_TOKEN|zizmor" .github/workflows/publish.yml || true

echo
echo "== all github token / npm cache references in workflows =="
rg -n "github-token:|GITHUB_TOKEN|NPM_TOKEN|npm_cache|actions/cache|setup-node|permissions:" .github/workflows || true

Repository: pharn-dev/pharn-cli

Length of output: 3071


🌐 Web query:

zizmor npm cache poisoning setup-node cache npm publish NPM_TOKEN

💡 Result:

The connection between zizmor, npm, and cache poisoning arises primarily from the default behavior of actions/setup-node (v5 and later), which automatically caches package manager dependencies [1][2][3]. If a repository's cache is poisoned by a low-privileged workflow—such as one triggered by an untrusted event—this poisoned cache can be consumed by a high-privileged release workflow, potentially leading to the injection of malicious code into a published npm package [4][3][5]. Zizmor, a static analysis tool for GitHub Actions, includes a cache-poisoning audit specifically designed to detect this risk [1][6][7]. Key security considerations and mitigations include: 1. Disable Automatic Caching in Sensitive Workflows: For workflows with elevated privileges (such as those performing npm publishing), it is strongly recommended to explicitly disable automatic npm caching by setting package-manager-cache: false in your actions/setup-node step [4][2][8][3]. 2. Use Trusted Publishing: Avoid manual npm tokens (NPM_TOKEN) in CI/CD secrets whenever possible [9][10]. Instead, use npm's Trusted Publishing mechanism, which allows GitHub Actions to securely authenticate with npm via short-lived, OIDC-based identity tokens [9][5]. Zizmor can detect and flag workflows that still rely on manual tokens despite having the necessary permissions for trusted publishing [9]. 3. GitHub Actions Cache Security: GitHub has implemented improvements to mitigate cache-based privilege escalation, including issuing read-only cache tokens for untrusted triggers on the default branch [11]. However, this does not eliminate the need for proper configuration in your own workflows [3]. 4. Zizmor Usage: Zizmor automatically scans for these patterns [7][12]. If you encounter a false positive or have unique requirements, you can review its audit rules [13] and documentation [14]. Zizmor also tracks various npm publishing patterns to ensure they align with security best practices [9][10]. For further guidance, consult the official documentation for actions/setup-node regarding cache poisoning mitigation [8] and the zizmor documentation for audit specifics [14][13].

Citations:


Remove npm caching from the privileged publish job.

actions/setup-node caches dependencies automatically with cache: npm, and this job also runs with ids: write for provenance while publishing authenticated with NPM_TOKEN. Keep caching only in non-publishing CI jobs; disable it here with package-manager-cache: false.

🧰 Tools
🪛 zizmor (1.26.1)

[error] 21-21: runtime artifacts potentially vulnerable to a cache poisoning attack (cache-poisoning): this step

(cache-poisoning)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/publish.yml around lines 21 - 24, Update the
actions/setup-node configuration in the privileged publish job to disable
automatic package-manager caching by setting package-manager-cache to false, and
remove the cache: npm setting. Leave dependency caching enabled only in the
non-publishing CI jobs.

Source: Linters/SAST tools

Comment thread CHANGELOG.md
Comment on lines +96 to +97
Initial published release. `pharn` bootstraps the PHARN stack into an existing
Next.js project. Exposes both `pharn` and `pharn` bins.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Fix the duplicate bin names.

The release note currently says the release exposes both pharn and pharn bins. Restore the historical name or state that only the pharn binary is exposed.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@CHANGELOG.md` around lines 96 - 97, Update the initial release note to remove
the duplicate bin names, restoring the historical second binary name or clearly
stating that only the pharn binary is exposed.

Comment thread SECURITY.md
Comment on lines +3 to 9
PHARN is an audit-grade methodology — taking security seriously is part of the brand, not an afterthought. `pharn` is the bootstrapper that fetches and installs that methodology, so it sits at a trust boundary: it pulls remote content over the network and writes it into a user's project. We welcome coordinated disclosure of any vulnerability in this repository.

## What `pharn-cli` is, and its security surface
## What `pharn` is, and its security surface

This repository **is `pharn-cli`** — an ESM-only Node CLI (`"type": "module"`, NodeNext, `engines.node >= 20`) that runs a wizard, fetches the selected PHARN modules from `pharn-dev/pharn-oss` via `degit`, copies them into the user's `.claude/`, and writes `pharn.config.json`. It has a small, thin dependency set (`@clack/prompts`, `degit`, `minimist`, `picocolors`), no bundled runtime services, and no telemetry. Its security-relevant surface is exactly the two things that cross a trust boundary: **remote input** (the `manifest.json` / `module.json` it reads and the repo content it clones) and **file-system writes** (everything it copies into `.claude/` and the config it writes).
This repository **is `pharn`** — an ESM-only Node CLI (`"type": "module"`, NodeNext, `engines.node >= 20`) that runs a wizard, fetches the selected PHARN modules from `pharn-dev/pharn-oss` via `degit`, copies them into the user's `.claude/`, and writes `pharn.config.json`. It has a small, thin dependency set (`@clack/prompts`, `degit`, `minimist`, `picocolors`), no bundled runtime services, and no telemetry. Its security-relevant surface is exactly the two things that cross a trust boundary: **remote input** (the `manifest.json` / `module.json` it reads and the repo content it clones) and **file-system writes** (everything it copies into `.claude/` and the config it writes).

The CLI's security model is **deterministic, not model-driven**: it never asks an AI to decide what is safe. Every value that arrives from the network is validated against strict regex allowlists, rejected for `..` and control characters, and every copy is confined with a `safeJoin` guard so nothing can escape its intended target — checks that hold regardless of what the fetched content says. Preserve that shape: a security fix that relies on "the content will be well-behaved" is not a fix.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Align the security boundary with the current installation layout.

Both documents understate the write surface by treating .claude/ as the destination for installed methodology. The current flow also writes capabilities and fixed product surfaces outside .claude/; the threat model and security policy should name or clearly abstract all of those paths.

  • SECURITY.md#L3-L9: describe writes to .claude/, the mirrored capability layout, root product surfaces, and pharn.config.json.
  • THREAT-MODEL.md#L18-L22: expand Surface A beyond .claude/ so the residual analysis covers every installed location.
🧰 Tools
🪛 LanguageTool

[style] ~7-~7: Consider an alternative for the overused word “exactly”.
Context: ...metry. Its security-relevant surface is exactly the two things that cross a trust bound...

(EXACTLY_PRECISELY)

📍 Affects 2 files
  • SECURITY.md#L3-L9 (this comment)
  • THREAT-MODEL.md#L18-L22
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@SECURITY.md` around lines 3 - 9, The security documentation understates the
installation write surface. In SECURITY.md, update the description to cover
.claude/, the mirrored capability layout, root product surfaces, and
pharn.config.json; in THREAT-MODEL.md, expand Surface A beyond .claude/ to
include every installed location. Preserve the existing remote-input and
safe-write security model while ensuring both documents describe the current
layout consistently.

PrzemekGalarowicz and others added 6 commits July 22, 2026 22:19
Convert publish.yml to pure OIDC Trusted Publishing — no secrets in the workflow:

- delete the env NODE_AUTH_TOKEN / NPM_TOKEN block (auth is now OIDC)
- gate the publish job behind the `npm-publish` environment
- bump Node to 24 and install npm@latest (Trusted Publishing needs npm >= 11.5.1)
- drop the workflow_dispatch trigger (releases only)
- guard: the release tag must equal package.json version before publish

Requires an out-of-band `npm-publish` GitHub environment and an npmjs.org
Trusted Publisher for publish.yml + that environment; the first publish stays
a manual local `npm publish`.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The PHARN dev-loop record for the publish.yml OIDC conversion (commit 7b84868):
PLAN, GRILL, REGRESSION, VERIFY, REVIEW, SHIP + the two machine reports. It
records the floor verdicts read at each stage — build `validate` RED and verify
FAIL were the same pre-existing untracked test-app artifact (CI-equivalent
green), proceeded past only by explicit human decision at the build / GATE-2
gates.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@PrzemekGalarowicz PrzemekGalarowicz changed the title chore: rename npm package to @pharn-dev/pharn + add npm publish workflow chore: canonical npm name, OIDC publish workflow, release docs (#53) Jul 22, 2026
@PrzemekGalarowicz PrzemekGalarowicz changed the title chore: canonical npm name, OIDC publish workflow, release docs (#53) chore: canonical npm name, OIDC publish workflow, release docs Jul 22, 2026
@PrzemekGalarowicz
PrzemekGalarowicz merged commit c425edd into main Jul 22, 2026
7 checks passed
@PrzemekGalarowicz
PrzemekGalarowicz deleted the chore/rename-to-pharn-publish-ci branch July 22, 2026 21:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant