Skip to content
Agentmart
Submit a tool

dependency-management

Adds, upgrades and removes npm packages in Expo apps under a written policy - expo install, exact pins, 7-day release age, script review, licences.

Skill by zakariaf

IndexedMIT★ 11
Write a review

Install

Works with Claude Code, Claude apps, Codex, Cursor, Gemini CLI, GitHub Copilot, VS Code, OpenCode, Goose, Windsurf. Read the repository before you give any tool access to your data.

npx agentmarket install skill/zakariaf-dependency-management

Asks which of your tools to add it to (Claude Code, Codex, Cursor, VS Code, Windsurf, Gemini CLI, Claude Desktop) and shows the change first. See https://agentmart.dev/cli.

Get the weekly diff

The weekly diff: one email a week with new agent tools, notable updates and grade changes, plus security alerts for tools you follow. Double opt-in, one-click unsubscribe.

We use your email only for this newsletter. Privacy

About

Adds, upgrades and removes npm packages in Expo apps under a written policy - expo install, exact pins, 7-day release age, script review, licences. Use when adding or bumping a package or on ETARGET. Not for SDK majors (expo-sdk-upgrade).

No reviews yet. Installed it? Reviews come from verified installers only. How reviews work

Permissions

What this skill can do and what it asks for, from its SKILL.md and code. Checked Oct 26, 2026.

Tools
No tools found
Secrets
None asked for
Install scripts
None found
Runs as
Node.js package

Network hosts it talks to 1

  • codeload.github.com · found in install command

Files it touches

  • ~/.claude/skills/dependency-management

What's inside

Skill name
dependency-management
Description
Adds, upgrades and removes npm packages in Expo apps under a written policy - expo install, exact pins, 7-day release age, script review, licences. Use when adding or bumping a package or on ETARGET. Not for SDK majors (expo-sdk-upgrade).
License
MIT
Instructions
268 lines in SKILL.md · view on GitHub

Before installing

  • Ships executable scripts

Agent Skills spec issues

  • files: referenced but missing: scripts/deps/check-deps.ts

Files (83)

  • SKILL.md
  • banned-packages.json · assets/
  • expo-sdk-57-module-map.json · assets/
  • npmrc-exclude-block.txt · assets/
  • shared.json · assets/
  • add-expo-haptics.md · examples/
  • policy-contract.md · references/
  • procedures.md · references/
  • release-age-policy.md · references/
  • supply-chain.md · references/
  • versions.md · references/
  • check-deps-policy.mjs · scripts/
  • check-lib.mjs · scripts/
  • policy.mjs · scripts/lib/
  • plan-dependency.mjs · scripts/
  • selftest.mjs · scripts/
  • dependency-policy.json · templates/contracts/
  • dot-npmrc · templates/
  • audit-licenses.ts · templates/scripts/audit/
  • license-policy.test.ts · templates/scripts/audit/
  • license-policy.ts · templates/scripts/audit/
  • system-clock.test.ts · templates/scripts/clock/
  • system-clock.ts · templates/scripts/clock/
  • banned-packages.test.ts · templates/scripts/deps/
  • banned-packages.ts · templates/scripts/deps/
  • check-deps.ts · templates/scripts/deps/
  • check-npm-config.ts · templates/scripts/deps/
  • dependency-policy.test.ts · templates/scripts/deps/
  • dependency-policy.ts · templates/scripts/deps/
  • effective-npm-config.test.ts · templates/scripts/deps/
  • effective-npm-config.ts · templates/scripts/deps/
  • engines-floor.test.ts · templates/scripts/deps/
  • engines-floor.ts · templates/scripts/deps/
  • expo-patch-age.test.ts · templates/scripts/deps/
  • expo-patch-age.ts · templates/scripts/deps/
  • release-age-excludes.test.ts · templates/scripts/deps/
  • release-age-excludes.ts · templates/scripts/deps/
  • unpinned-approvals.test.ts · templates/scripts/deps/
  • unpinned-approvals.ts · templates/scripts/deps/
  • workspace-lockstep.test.ts · templates/scripts/deps/
  • workspace-lockstep.ts · templates/scripts/deps/
  • package.json · tests/bases/monorepo/.agents/skills/vendored-skill/tests/fixtures/bad/
  • uses.ts · tests/bases/monorepo/.agents/skills/vendored-skill/tests/fixtures/bad/src/
  • app.config.ts · tests/bases/monorepo/apps/notes/
  • package.json · tests/bases/monorepo/apps/notes/
  • _layout.tsx · tests/bases/monorepo/apps/notes/src/app/
  • app.config.ts · tests/bases/monorepo/apps/tasks/
  • package.json · tests/bases/monorepo/apps/tasks/
  • _layout.tsx · tests/bases/monorepo/apps/tasks/src/app/
  • package-lock.json · tests/bases/monorepo/
  • package.json · tests/bases/monorepo/
  • package.json · tests/bases/monorepo/packages/core/
  • task.ts · tests/bases/monorepo/packages/core/src/
  • package.json · tests/bases/monorepo/packages/ui/
  • expo-haptics-adapter.ts · tests/bases/monorepo/packages/ui/src/haptics/
  • uses.ts · tests/bases/monorepo/skills/demo-skill/examples/
  • uses.ts · tests/bases/monorepo/vendor/third-party-skill/examples/
  • package.json · tests/bases/single-app/.agents/skills/vendored-skill/tests/fixtures/bad/
  • uses.ts · tests/bases/single-app/.agents/skills/vendored-skill/tests/fixtures/bad/src/
  • app.config.ts · tests/bases/single-app/
  • …and 23 more

SKILL.md (first lines)

# Dependency management

Keeps every package of an Expo app on a written, verified set: the right version and specifier, in
the right place, old enough, not deprecated, reviewed, allowed to ship, and installed once. The facts
live in the app's `contracts/dependency-policy.json`; this skill seeds it, plans every change, and
proves the repo against it.

## Rules that must hold

1. **One written policy.** `contracts/dependency-policy.json` holds the versions table (version,
   specifier, place, why), held-back majors, do-not-add, bans and the licence policy, seeded from
   `templates/contracts/dependency-policy.json` (the canonical stack verified 2026-10-03, Expo SDK
   57). A row changes in the same commit as `package.json` and `package-lock.json`. *Why:* npm
   `latest` is the wrong major for several packages today (React Native 0.87, TypeScript 7, ESLint 10,
   Jest 30); one written truth stops upgrades from memory.
2. **Install Expo-managed packages only with `npx expo install <pkg>@<row spec>`, and keep the
   specifier it writes.** *Why:* Expo tests one native set per SDK and `expo install --check` verifies
   it; without the spec, `npx expo install` writes whatever Expo's online list names today, which can
   be a patch published that morning. A same-day Expo patch is a `WARN` with its due date, never an
   install.
3. **Pin every other package exactly, in its place** (`save-exact=true`): runtime code in
   `dependencies`, tools in `devDependencies`. *Why:* a patch of a native wrapper changes binaries;
   Expo's checks only test that the installed version is inside its range, so the exact pin is what
   makes each change a reviewed lockfile commit.
4. **One copy of everything.** Companions a row lets float are installed in the same command or
   pinned in the root `overrides` (all ten `@typescript-eslint/*` at the `typescript-eslint` pin);
   one `react`, one `react-native`; `npm ls <pkg>` shows one version. *Why:* two `@typescript-eslint`
   plugins crash ESLint, and a native module can be compiled into a build only once.
5. **Commit `package-lock.json`, install clean trees with `npm ci` (EAS Build does too), and never
   delete the lockfile, set `package-lock=false`, use `--force` / `--legacy-peer-deps` (on the
   command line, in `.npmrc` or in an `NPM_CONFIG_*` variable), or set `EAS_NO_FROZEN_LOCKFILE`.**
   *Why:* the lockfile is what makes every machine and CI build the same app: EAS Build runs
   `npm ci` and fails on a lockfile out of sync, while `npm install` (what developers run, and EAS
   Build under `EAS_NO_FROZEN_LOCKFILE`) ignores it under `package-lock=false`; `ETARGET` means too
   young, `ERESOLVE` means off the SDK set, and `legacy-peer-deps=true` silences that for every
   later install.
6. **`.npmrc` holds `min-release-age=7` (or a stricter number of days), `engine-strict=true`,
   `save-exact=true` and `strict-allow-scripts=true`; the root `package.json` holds `engines`
   `npm >=11.17.0` and `node >=22.18`; nothing weakens them: no later line, no `before=`, no
   `NPM_CONFIG_*` variable in `eas.json` or CI, no `~/.npmrc` line the project file leaves open.** A
   younger release enters only through a dated `# exclude-block expires=YYYY-MM-DD reason=…` block
   the developer agreed to, naming exact packages, expiring on the publish date + the release age,
   deleted (never extended) on that date. *Why:* a 7-day wait lets most malicious or broken releases
   be pulled first; npm keeps the last value of a key and reads command line, then environment, then
   project `.npmrc`, then `~/.npmrc`; `engine-strict` guards nothing without `engines`, and the npm
   of the default EAS images ignores the release age and `allowScripts`.
7. **Review an install script before it runs, one package at a time.** With
   `strict-allow-scripts=true` npm stops an install whose tree holds an unreviewed script before
   anything runs (`ESTRICTALLOWSCRIPTS`); without it npm 11.17 runs the script and only prints a
   notice afterwards. Read the script the plan prints, write its pinned key
   (`"<pkg>@<x.y.z>": true`) into the root `allowScripts`, then install; a bump needs a new review.
   Never a name-only approval (`"<pkg>": true`, `"<pkg>@*": true`): npm runs every future version's
   script under it; a name-only `false` (deny every version, what `npm deny-scripts` writes) is
   fine. npx and `npm exec` inside the repo follow `.npmrc` but never the root `allowScripts`: a
   tool the repo runs is a devDependency (npx then runs the reviewed local copy), EAS CLI (expo-doctor
   refuses it as a dependency) a global install with the policy flags, and `allow-scripts` stays out
   of every `.npmrc` and variable. *Why:* an install script runs arbitrary code on every machine and
   CI runner that installs.
8. **Never add a banned package:** the supply-chain floor (compromised or deprecated packages), plus
   the app's own bans and opt-in profiles (`offline-only`, `no-telemetry`), all listed in the
   policy's `banned`. *Why:* the app's own gate reads only the policy, so the list is complete there.
9. **No deprecated direct dependency without a written reason in its row.** *Why:* deprecated code
   gets no fixes; a deliberate hold (ESLint 9, held back) stays visible instead of silent.
10. **Ship only allowed licences** (by default MIT, ISC, Apache-2.0, BSD-2/3-Clause, 0BSD, OFL-1.1,
    CC0-1.0) or an approved exception with its exact licence and reason; audit the release bundle,
    not the lockfile, and read the native SDKs a native module brings by hand. *Why:* only shipped
    code carries obligations into the app, and the bundle audit sees JavaScript only: the CocoaPods
    and Gradle SDKs under a native module (an ads or crash SDK) ship too.
11. **`npx expo install --check` and `npx expo-doctor` pass.** *Why:* they see SDK drift and
    duplicate native modules that `tsc` and Jest cannot.
12. **Respect held-back majors until their written triggers; move Expo SDK majors only with the
    expo-sdk-upgrade skill.** *Why:* each held-back major breaks a verified part of the stack.
13. **Install a package in the same change as the code that uses it.** *Why:* an unused package ages
    unreviewed, and knip cannot see an unused native module once a shared package peers it.
14. **Stop and ask the developer before a package not in the policy, a dated exception, a licence
    exception or a deprecation hold,** bringing the facts `plan-dependency.mjs --online` prints.
15. **Read a library's versioned docs before coding against it, never memory,** and re-verify a row
    before trusting it when the policy's `verified` date is more than a few weeks old.

When multi-package (npm workspaces), rules 3 and 4 also mean: a native module is never in a shared
package's `dependencies` or at the root (Expo's checks verify only an app's direct dependencies, and
only one copy of a native module can be compiled); a shared package lists the native modules its code
imports as `"*"` peers; every app that depends on it installs them with one specifier; the root
`overrides` pin each peer at the apps' version, plus `react` and `react-native`. A JavaScript library
the apps and a shared package both import is one row whose `where` lists both places.

## Workflow

1. Name the task: add, upgrade, remove, the monthly pass, a dated exception, or a failing dependency
   gate. A failing gate: go straight to "When a gate in this area fails" in
   [references/supply-chain.md](references/supply-chain.md).
2. No `contracts/dependency-policy.json` yet: copy `templates/contracts/dependency-policy.json`,
   delete the rows the app will never use, and read
   [references/policy-contract.md](references/policy-contract.md). No `.npmrc`: copy
   `templates/dot-npmrc` to `.npmrc`.
3. Read the package's row (and [references/versions.md](references/versions.md) for why the seed
   says what it says), then the matching section of
   [references/procedures.md](references/procedures.md).
4. Plan: `node ${CLAUDE_SKILL_DIR}/scripts/plan-dependency.mjs <pkg>[@<version>] . --online` (add
   `--remove` to remove; when multi-package, `--peer-of <workspace>` when a shared package imports it;
   offline, save `npm view <pkg>@<v> version time license scripts deprecated --json` to a file and
   pass `--npm-view <file>`). A `FAIL` line (`banned`, `do-not-add`, `held-back`, `not-in-table`,
   `version-differs`, `too-young`, `deprecated`, `licence`) means stop: fix the request, follow the
   upgrade procedure, or ask the developer.
5. Too young but needed: read [references/release-age-policy.md](references/release-age-policy.md),
   get the developer's agreement, fill `assets/npmrc-exclude-block.txt` (expiry = the publish date +
   the `.npmrc` min-release-age; the plan's `too-young` fix line prints it) and append it to `.npmrc`
   after one blank line.
6. Review before installing: when the plan prints a `review first` step, read that script and write
   its pinned key into the root `allowScripts` ([references/supply-chain.md](references/supply-chain.md),
   "Install scripts"). An install that stops with `ESTRICTALLOWSCRIPTS` ran nothing: review each
   package it names the same way, then run the install again. A tool run through npx (EAS CLI, a
   scaffolder) follows "npx and one-off tools inside the repo" in the same reference instead.
7. Run the printed install steps exactly, in order (companions in the same command; when
   multi-package, the peer and its root override first, then every app in the same change). Then
   `npm approve-scripts --allow-scripts-pending` must print `No packages with unreviewed install
   scripts.`
8. A config plugin: one entry in the `plugins` list of `app.config.ts`, with a comment naming the
   owning skill; never a second list, never an edit in the generated `ios/` or `android/`. A package

From zakariaf/ReactNative-Skills, MIT.

More from zakariaf/ReactNative-Skills

Signals

Stars
11
Forks
2
Open issues
0
Last commit (this folder)
Oct 17, 2026 (12 days ago)

From GitHub (fetched Oct 24, 2026).

Details

License
MIT
First seen
Oct 24, 2026
Last checked
Oct 24, 2026

More from zakariaf

Cite this page

dependency-management skill. Agent Mart. https://agentmart.dev/skills/zakariaf-dependency-management (last updated 2026-10-24)