---
name: temporary-pnpm-package-links
description: Guidance for temporary pnpm package links across repositories, including consumer-local links, linked-source validation, committed development state, AI publication and unlink prohibitions, and registry verification before consumer production release.
---

# Temporary pnpm Package Links

Use this skill for unpublished package testing, cross-repository package demos, temporary `link:`
dependencies, or local resolver changes. It is the canonical policy for Post.Build.Ship and
standalone temporary-link work.

## Choose The Dependency Protocol

- Within one pnpm workspace, prefer that workspace's existing `workspace:` convention.
- Across repositories or workspaces, put a consumer-local `link:` specifier in each approved
  consumer `package.json`.
- Do not use global `pnpm link` state. The consumer manifest and lockfile must describe the tested
  dependency state.
- Approval is per linked package. Do not extend one package's approval to another package.
- Do not change a global catalog to `link:` unless every catalog consumer is intentionally part of
  the same test. Prefer exact consumer manifest changes and a narrowly scoped Syncpack ignore.

The link's presence alone does not block Build, QA, staging, or an approved development commit.
Complete consumer implementation, renderer integration, tests, review, production-mode validation
builds, and approved framework version preparation may continue while the link remains. Never
ignore QA failures merely because a link exists. Approved unpublished-package validation state is
committed by default.

## Ownership Boundary

AI agents must never publish packages or mutate registry state, even when a task or user message
explicitly approves publishing. AI agents must also never unlink a temporary package, install its
registry replacement, validate that replacement, stage the replacement state, or commit it. Those
release-finalization actions are user-owned and cannot be delegated to `post`, `build`, or `ship`.

Framework publication and consumer production release are separate events. After linked-source
validation is complete, the user may publish the validated framework package while the consumer
remains linked. Consumer deployment, distribution, and production release stay blocked until the
user replaces the link with the exact registry version and verifies that installed state.

Agents leave the approved link untouched and report two statuses separately:

- `implementation: complete against validated linked source`
- `manual release finalization: pending | complete`

Pending manual finalization does not make the linked-source implementation partial or incomplete.

## Commit Lifecycle And Isolation

Classify every agent-supported temporary pnpm-link commit with exactly one lifecycle value:

- `add` introduces approved temporary pnpm-link state.
- `update` changes existing temporary pnpm-link state while keeping it temporary.

Every `add` and `update` unit must be a dedicated commit whose complete header begins exactly
`--TEMP-- type(scope): subject`. The marker is reserved exclusively for agent-supported temporary
pnpm package-link lifecycle commits. Do not use it for temporary URLs, feature flags, experiments,
or other temporary state. Unlinking and replacement are manual release-finalization work, not an
agent-supported `cleanup` lifecycle or commit unit.

The dedicated commit may contain only the temporary-link lifecycle state that must travel together:
included consumer manifests, required `pnpm-lock.yaml` importer evidence, exact temporary ESLint
overrides, package-scoped Syncpack ignores, and approved temporary resolver/config state.
Hard-refuse permanent source, permanent documentation, unrelated dependency changes, and every
other unrelated hunk. Commit permanent work separately with the normal unmarked header, even when
it shares a file with temporary-link state.

Use hunk-level review and staging to prove the boundary. If permanent and temporary hunks overlap or
cannot be separated safely, stop before staging or committing. The Build-to-Ship handoff must record
the `add | update` lifecycle, marker applicability, old/new diff evidence, staged temporary-link
files and hunks, and every excluded permanent or unrelated hunk.

## Record Approval Before Editing

For each temporary package link, Post or the standalone plan must record:

1. package name and local source path
2. consumer repository path
3. every matching consumer `package.json`, including explicit exclusions
4. expected `link:` specifier for every included manifest
5. expected `pnpm-lock.yaml` importer evidence, normally both `specifier: link:...` and
   `version: link:...`
6. confirmation that the link is temporary unpublished-package validation state and should be
   committed by default
7. catalog and Syncpack handling, including exact consumer packages and dependencies in any ignore
8. every required resolver/config change, or an explicit finding that none is required
9. governing ESLint flat-config file for each manifest
10. whether the manifest is linted, the effective `no-external-package-links` rule ID when active,
    and the exact manifest path used by a temporary override
11. either the planned exact override coverage or a verified `no override required` finding for
    every included manifest
12. confirmation that unlinking, replacement installation, registry-state validation, staging, and
    the replacement commit are user-owned manual release finalization
13. validation permissions while linked: complete implementation, tests, QA, production-mode builds,
    review, staging, development commits, and approved framework version preparation
14. production guard: no consumer deployment, distribution, or production release until the user
    verifies the exact registry dependency
15. relative-layout portability risk and any known linked-package dependency-resolution or phantom
    dependency limitation
16. lifecycle value `add | update`, exact `--TEMP-- ` marker applicability, and the old/new diff
    evidence used to classify it
17. planned hunk-level isolation evidence, including permanent or unrelated work that must be
    committed separately
18. completion reporting for linked-source implementation and manual release finalization

If this metadata is missing, partial, or contradictory, stop before editing. Do not infer unlinking
from portability or CI risk, and do not add "restore before staging" or "do not commit the link"
language to an approved unpublished-package validation task.

## Build The Linked Validation State

For every approved package:

1. Verify the linked source path exists and contains a valid `package.json`.
2. Search every consumer manifest for the package name before editing.
3. Update every included matching dependency entry to its expected `link:` specifier. Stop before
   leaving an in-scope match on a different specifier unless it is explicitly excluded.
4. Run install from the consumer repository, never an unrelated parent workspace.
5. Verify the lockfile importer for every changed consumer records the approved `link:` specifier
   and linked version evidence.
6. When the dependency normally uses `catalog:`, add only the approved package-scoped Syncpack
   ignore. Do not change a shared catalog entry for a subset of its consumers.
7. Add only approved local resolver/config changes. Record why each is required, whether it escapes
   the repo or duplicates installed resolution, and that the user owns its later removal.
8. Classify ESLint coverage for every linked manifest using the lifecycle below.

Local resolver/config residue includes repo-escaping sibling paths, absolute paths, redundant
aliases, watch folders, path mappings, scripts, workflows, `.npmrc` entries, or catalog/workspace
entries added only for local testing. Preserve approved temporary residue during validation, but do
not introduce unrecorded residue.

## ESLint Override Lifecycle

Every approved linked manifest must have one of two recorded outcomes:

- an exact, effective temporary override for the active rule ID; or
- `no override required`, with evidence that the manifest is ignored/not linted or the rule is
  absent or off.

### Detect The Consumer's Active Rule ID

Inspect the governing consumer config and the effective config for each manifest, for example with
the consumer's supported equivalent of:

```sh
pnpm exec eslint --print-config package.json
pnpm exec eslint --print-config apps/web/package.json
```

Find the effective rule key whose final segment is `no-external-package-links` and record its full
ID and severity. Do not assume a plugin namespace. A shared config may expose
`custom/no-external-package-links`, while another consumer may register the same rule as
`no-external-package-links/no-external-package-links` or another namespace. If multiple active IDs
make ownership ambiguous, stop and resolve the governing config instead of guessing.

If the manifest is ignored/not linted or the effective rule is absent or off, record
`no override required` and the verification evidence. Do not register a plugin merely to turn its
rule off.

### Add An Exact Later Override

When the rule is active, add a dedicated flat-config object after the config object that enables the
rule. Cover only the exact linked manifests, using paths relative to that flat config:

```js
{
  files: ['package.json', 'apps/web/package.json'],
  rules: {
    // Package links are temporarily allowed for local framework-package testing.
    // Consumer production release requires user verification of the exact registry version.
    'no-external-package-links/no-external-package-links': 'off',
  },
}
```

Replace the example rule ID with the consumer's detected active ID. Do not use directory-wide or
recursive manifest globs when exact paths are known. Add a dedicated override instead of merging
into an unrelated object; extend an existing object only when it is already explicitly owned by
this temporary-link policy.

After editing, inspect effective config again for every linked manifest and verify the detected rule
ID is off. Also verify that unlinked manifests are not covered. A syntactically present override
that is ordered too early, uses the wrong namespace, misses a manifest, or never applies is inert
and does not satisfy this policy.

## Validation And Committed State

Run the consumer's approved QA after install and config changes. Web, Electron, and mobile surfaces
may all be implemented and tested against the linked source when they are in scope. Production-mode
build commands are valid validation evidence; they do not authorize deployment, distribution, or a
consumer production release.

Stage every approved changed manifest, `pnpm-lock.yaml` when changed, exact temporary ESLint
override, scoped Syncpack ignore, and approved resolver/config file. Inspect the diff for `link:`,
`file:`, global `pnpm link`, sibling paths, absolute paths, aliases, watch folders, path mappings,
scripts, workflows, and `.npmrc` changes.

When validation proof is an expected lint failure, it counts only when the user explicitly approved
committing that state and the evidence names the command, affected files, effective rule IDs or
diagnostics, and the unrelated-failure stop condition. Any unrelated QA failure remains blocking.

## Release Lifecycle

Linked-source validation and registry-based release validation are separate phases:

1. Link the framework source.
2. Implement the complete consumer feature and validate every in-scope surface against that link.
3. Finish review and QA until no code changes are anticipated.
4. Prepare and ship any approved framework version changes that reflect the validated source.
5. Report linked-source implementation as complete and manual release finalization as pending.
6. The user may publish the validated framework package while the consumer link remains.
7. The user later replaces the link with the exact registry version and owns installation,
   residue removal, registry-state validation, QA, staging, and the replacement commit.
8. Consumer deployment, distribution, and production release may proceed only after that exact
   registry dependency is verified.

Steps 6 and 7 are manual, out-of-scope follow-up. They must not appear as agent commit units,
acceptance criteria, Build checkpoints, or reasons to report the completed linked-source
implementation as partial.

## Ship Verification And Refusal

Ship rejects or pauses when any of these is true:

1. a linked package lacks per-package approval or task-specific metadata
2. an in-scope consumer is only partially linked or its lockfile lacks the expected importer proof
3. a global catalog link affects unapproved consumers, or a Syncpack ignore is overly broad
4. resolver/config changes are unapproved, non-portable, redundant, or leave unexplained scaffolding
5. any linked manifest lacks an effective exact override or a verified `no override required` result
6. an override is missing manifests, covers unlinked manifests, uses the wrong rule ID, is ordered
   before the enabling config, or is otherwise inert
7. a temporary-link override was merged into an unrelated config object
8. an AI agent is asked to publish, unlink, install or validate the registry replacement, stage the
   replacement, or commit it
9. consumer deployment, distribution, or production release is requested before the user verifies
   the exact registry dependency
10. lifecycle is missing or is not exactly `add` or `update`
11. the complete header does not begin exactly `--TEMP-- `, or the marker is used for work outside
    the agent-supported temporary pnpm-link lifecycle
12. the staged unit mixes permanent source, permanent documentation, unrelated dependency changes,
    or any other unrelated hunk
13. hunk-level separation or the handoff's marker-applicability and isolation evidence is missing,
    ambiguous, or unsafe

An approved exact `link:` state is expected in a development validation commit and must not be
silently replaced during Ship. Ship may accept approved framework version preparation while a
consumer remains linked, but it must refuse publication, unlinking, replacement installation, or
consumer release commands.

## Manual Release Finalization

The user exclusively owns framework publication, replacement of each `link:` specifier with the
exact registry version, installation, lockfile verification, temporary override and resolver/config
removal, registry-based QA, staging, and the replacement commit. Agents leave the link and its
approved residue untouched.

Agents may state the replacement condition and report whether manual finalization is pending or
complete. They must not execute, stage, validate, or commit any part of that manual sequence, and
must not make it an acceptance criterion or checkpoint for the linked-source implementation.
