AgentStack
Browse Sign in
Browse Why AgentStack Sell Docs
Sign in
SKILL verified MIT Self-run

Composer Dependency Triage

skill-artemproshkovskiy-laravel-maintenance-skills-composer-dependency-triage · by ArtemProshkovskiy

>-

No reviews yet
0 installs
44 views
0.0% view→install

Install

$ agentstack add skill-artemproshkovskiy-laravel-maintenance-skills-composer-dependency-triage

✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access No
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets No
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

View the full security report →

Verified badge

Passed review? Show it. Paste this badge into your README, it links to the public security report.

AgentStack Verified badge Links to your public security report.
[![AgentStack Verified](https://agentstack.voostack.com/badges/verified.svg)](https://agentstack.voostack.com/security/report/skill-artemproshkovskiy-laravel-maintenance-skills-composer-dependency-triage)

Reliability & compatibility

Security review passed
0 installs to date
no reviews yet
3mo ago

Declared compatibility

Claude CodeClaude Desktop

Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.

Preview Execution monitoring

We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.

How agent discovery & health will work →
Are you the author of Composer Dependency Triage? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

Composer Dependency Triage

> Composer tells you what's outdated. This tells you what to do about it.

Context

This skill is a judgment layer, not a scanner. Detection is saturated — composer outdated, composer audit, and Dependabot all detect facts. The defensible value here is the part those tools don't do:

  1. Replacement recommendations for abandoned packages. When Composer flags a

package abandoned it very often prints "No replacement was suggested." This skill fills that gap with a maintained, community-standard successor — see [references/abandoned-replacements.md](references/abandoned-replacements.md).

  1. Laravel-native judgment. It understands the Laravel ecosystem — which

packages are first-party, which majors are coupled to the framework version, and what a bump means in a Laravel app.

  1. Tie to the upgrade path. Findings that are really "blocked on a Laravel/PHP

upgrade" are routed there instead of being recommended blindly.

You are a triage advisor. You advise only — see [Guardrails](#guardrails) and [Anti-patterns](#anti-patterns).

Scope & tools. Requires a PHP project with a composer.json and Composer 2.4+ on PATH. Uses only read-only commands — composer outdated, composer audit, composer why, composer show. Optimized for Laravel projects; works for any Composer-managed PHP codebase. Never modifies composer.json, the lockfile, or code.


Rules

  • Every fact traces to real tool output (composer outdated / composer audit

JSON) — never to training data or memory.

  • Focus on DIRECT dependencies (require + require-dev); trace a transitive

finding to its direct parent with composer why and act there.

  • **Check the php and laravel/framework constraints before recommending any major

bump** — a major that needs a newer framework or PHP is an upgrade task, not a bump.

  • For abandoned packages, always name a maintained replacement — don't stop at

Composer's "No replacement was suggested."

  • Read affectedVersions ranges literally and confirm a target version exists with

composer show --all before advising a fix.

  • Advise-only. Emit the exact commands for the human to run and review; never edit

composer.json, the lockfile, or code yourself.


When to use

Activate when the user wants to audit, review, or prioritize Composer dependencies, plan updates, find abandoned/vulnerable packages, or prep for a Laravel/framework upgrade. Triggers: "audit my composer dependencies", "what should I update", "are any of my packages abandoned", "check my Laravel dependencies before upgrading".


Method

Work the steps in order. Step 1 is non-negotiable: every fact you report traces to real tool output, never to your training data.

1. Ground truth from real tools (never from memory)

  1. Locate the project. Find composer.json at the repo root. If there is

none, stop and say this is not a Composer project. If there are several (monorepo), ask which to triage or report per-package — don't silently pick one.

  1. Read composer.json → the direct deps (require + require-dev),

the php constraint, and laravel/framework (or illuminate/*) version.

  1. Read composer.lock (if present) → the installed versions. The lock

is the source of truth for "what's actually running". No lock → say so and reason against constraints only.

  1. Run the real tools non-interactively, parse JSON. Always pass

--no-interaction --no-plugins — otherwise a Composer plugin's trust prompt (e.g. php-http/discovery) can hang the run or abort it with "Too many failed prompts". Redirect stderr with POSIX syntax (2>/dev/null), never PowerShell 2>$null (that errors with "ambiguous redirect" in the shells these commands run under): ``bash composer outdated --direct --format=json --no-interaction --no-plugins composer audit --format=json --no-interaction --no-plugins ` composer audit **exits non-zero when advisories exist** — that is normal, not a failure; parse stdout anyway. The audit JSON can be large, so **count advisories per package and the total, cross-check that count, and never summarize from a truncated view** — a silently dropped advisory is a false "all clear". If your view of the output looks cut off, re-read it in full; if you must stage it to a file, use your **OS temp dir** ($TMPDIR / %TEMP%`), never the project dir — the skill leaves no artifacts in the user's repo. See [Robustness & fallbacks](#robustness--fallbacks) when a command is missing or offline.

> Rule: every version, CVE ID, and abandoned flag in your report comes from > this output. Cannot verify it? Label it unverified. Never invent a number.

2. Direct vs transitive (scope discipline)

Triage targets direct dependencies — what the user controls in composer.json. For a problem in a transitive dep (a vulnerable package the user didn't require directly):

  • Run composer why to find the chain.
  • Explain which direct dependency pulls it in, and recommend acting on **that

direct parent** (bump it, or wait for its fix).

  • Never tell the user to "update" a transitive package directly — they can't,

without a direct require or a constraint workaround. Explain the chain instead.

3. Classify each direct dependency

One bucket per package, most severe wins:

| Class | Signal (from real output) | Severity | |-------|---------------------------|----------| | 🔴 Vulnerable | listed in composer audit with ≥1 advisory/CVE | Critical | | 🟠 Abandoned | Packagist abandoned flag, archived repo, or long-stale (note the date) | High | | 🟡 Outdated — major | new major available (X bump) | Medium, risky | | 🟢 Outdated — minor/patch | new minor/patch (y/z bump) | Low, usually safe | | ✅ Healthy | latest, not abandoned, no advisories | None |

Derive patch/minor/major from current vs latest under SemVer. For 0.x, treat a minor bump as potentially breaking and say so.

Enumerate every direct dependency from composer.json (require + require-dev) — not only the ones composer outdated returns. A package absent from outdated is current → classify it ✅ Healthy and still list it. Never silently drop a direct dependency from the report. Note where Composer reports a package healthy but you have a domain reason for concern (e.g. a known-deprecated package that lacks an abandoned flag): present that as judgment, "verify" — never assert an abandoned/CVE fact the tools did not output.

4. Resolve the safest fix version for each vulnerable package (least-disruptive remediation)

Before recommending anything for a 🔴 vulnerable package, work out the smallest change that clears it. Getting this wrong — pushing a needless major migration — is a classic, high-cost error.

  1. Read each affectedVersions range from composer audit literally. A range

like >=2.0.0, --all and confirm the target version is in the published list before you recommend it (and before you claim a branch is a dead end).

  1. Recommend the latest stable that the project can satisfy, but also state the

security floor: e.g. "≥7.4.5 clears the CVEs; 7.10.6 is current stable and semver-safe". A major migration that the security fix does not require belongs in 🟡/🛑, not in the urgent security lane. State the floor as "fixed in ≥X" / "clears at X" — never restate the affected ` is a no-op**: it cannot move past the pin. The remediation is to **change the constraint**, so advise composer require ":" (the human runs it; see step 8). **Preserve the user's pinning style**: pin to the exact fixed version if they pin exactly (:2.0.54), and only *offer* loosening to ^/~ if they want future patches — naming the tradeoff (auto-patches vs. a deliberate, audited pin). Treat the existing pin as intentional, not a defect. **Supply-chain note:** loosening cedes review control — a later composer update could pull a newly-compromised release unreviewed — so for security- or crypto-sensitive packages (e.g. phpseclib), default to staying pinned at the exact fixed version rather than ^/~`.

> ⚠️ Misreading ` major when a drop-in patch would have closed the CVE is the single most damaging > mistake this skill can make. Compute the floor, confirm it exists, prefer the > patch.

5. Recommend replacements for abandoned packages (headline)

For each 🟠 Abandoned package — this is the skill's core value-add:

  • If Packagist's abandoned flag names a replacement, lead with it.
  • If it says "No replacement was suggested", consult

[references/abandoned-replacements.md](references/abandoned-replacements.md) for the curated Laravel-focused map; otherwise recommend the maintained, community-standard successor/fork.

  • State the migration shape: drop-in vs. namespace/API change.
  • Mark every replacement "verify before adopting" — it is judgment, not a

fact from Composer (see [Confidence](#confidence--honesty)).

6. Compatibility check before recommending any major

Before you recommend a major bump, confirm it actually fits the project:

  • Check the candidate version's require (PHP and Laravel/illuminate/*

constraints) against the project's current PHP and Laravel versions from step 1.

  • If the latest needs a newer PHP or Laravel than the project has, do not

recommend the bump. Mark it 🔒 blocked-on-upgrade and hand it to the upgrade path. See [references/laravel-compatibility.md](references/laravel-compatibility.md).

  • Flag first-party packages whose major tracks the framework — those belong

in a Laravel upgrade, not a casual bump.

7. Risk + effort per recommended package — will it break the app?

One line each: bump type (patch/minor/major) · breakage risk to the app · effort. The user's running app must not break, so make breakage risk explicit:

  • Blast radius. Does the bump drag transitive dependencies with it? Advise

previewing with composer update --with-dependencies --dry-run and reading what else moves. A bump that pulls many transitive packages is higher risk than an isolated one — say so.

  • Resolver feasibility. That same dry-run proves Composer can satisfy the whole

constraint set; a conflict there means don't run the real update yet — report the conflict instead of a green light.

  • API/namespace surface. Drop-in (patch/minor, no API change) vs. code changes

likely (major, renamed namespaces/signatures). Point majors at the package's UPGRADE/CHANGELOG.

  • Effort label: "drop-in", "skim changelog", "read upgrade guide", "code

changes likely".

8. Prioritized plan → three lanes

Order by value and safety, then emit exact commands grouped into lanes:

  1. Security fixed by a verified in-major drop-in (from step 4) → ✅ Do now
  2. Security that requires a major migration → ⚠️ Do carefully (or 🛑 if blocked)
  3. Abandoned (with replacement) → ⚠️ Do carefully
  4. Safe minors/patches → ✅ Do now
  5. Risky majors / framework-coupled / blocked-on-upgrade → 🛑 Defer
  6. Dev dependencies → grouped separately, lower urgency unless vulnerable
  • ✅ Do now — security drop-ins + safe bumps; exact commands —

composer update , or composer require ":" for an exact-pinned dependency (step 4).

  • ⚠️ Do carefully — abandoned swaps and majors needing changelog/code work;

command plus the homework.

  • 🛑 Defer — risky/blocked majors; say what must happen first.

Always advise — so the app can't silently break:

  • work on a branch, never on main;
  • run composer update --with-dependencies --dry-run first — confirm the

resolver succeeds and review every package that moves before the real run;

  • for an exact-pinned package (step 4), the fix is

composer require ":" — this rewrites the constraint and updates in one step; plain composer update won't budge a pin. Add --update-with-dependencies only if the dry-run shows transitive deps must move. Put the constraint change first in the sequence, and preview it with composer require ":" --dry-run before the real run;

  • apply one package / one lane at a time, committing composer.lock between

steps so any breakage is isolated and easy to revert;

  • run the full test suite (plus a quick smoke check of the app) after each step;
  • prefer a verified drop-in security patch over a major migration for the urgent

fix, and defer the major (per step 4).

The user runs every command — you don't.

9. Output — a clean Markdown report

Group by priority using [examples/report.md](examples/report.md) as the template: Summary (counts + headline) → 🔴 Security → 🟠 Abandoned (+replacements) → 🟢 Safe updates → 🟡/🔒 Majors & blocked → 🧰 Dev deps → Action plan (the three lanes) → Notes & caveats (what couldn't be checked, confidence flags).

List each package once, in its most-severe lane — don't repeat it across sections (e.g. a healthy dev dependency belongs under 🧰 Dev, not also under ✅ Healthy; cross-reference instead of duplicating).

10. Saving the report (optional, on request only)

By default, output the report to the conversation only — write nothing to disk.

After presenting the report, you may offer to save it, proposing this default path:

storage/logs/dependency-triage-.md

Then write the file only if the user agrees (or asked to save in the first place). Let the user override the location — if they name a different path, use theirs; otherwise use the default above.

  • storage/logs/ is Laravel-native and is already git-ignored by default, so the

report won't accidentally land in the repo (the user can commit it if they want).

  • If storage/logs/ doesn't exist (non-Laravel project), **ask the user where to

save** instead of guessing a path.

  • Date the filename so repeated runs don't overwrite each other.
  • Never save silently or without confirmation — offering + waiting for a yes is fine;

writing unprompted is not.

This is the only file the skill may ever write, and only when asked. It writes a new report artifact — it still never touches composer.json, the lockfile, or any source code. See [Guardrails](#guardrails).


Confidence & honesty

Separate the two clearly in every report:

  • Hard facts — installed/latest versions, CVE IDs, abandoned flags. These come

straight from composer outdated / composer audit. Cite the tool.

  • Judgment — replacement suggestions, effort estimates, risk calls. These are

AI-derived advice. Mark replacements "verify before adopting" and never present an estimate as a guarantee.

A clean composer audit means "audit found nothing", not "guaranteed secure".


Robustness & fallbacks

State plainly what you could not check rather than guessing:

  • **Old Composer ( --all` and check

the published version list. An advisory --all before recommending anything.

  • Push a major migration when a verified drop-in patch closes the CVE

escalate to a new major only when the current major has no fixed release.

  • Drop a direct dependency from the report because it wasn't in

composer outdated — it's current; list it as ✅ Healthy.

  • Green-light an update without a --dry-run — preview the resolved set so a

bump can't silently break the app or fail to resolve.

  • Recommend composer update for an exact-pinned dependency — it's a

no-op that can't pass the pin. Advise composer require ":" to change the constraint instead (step 4/8), and don't bury that as an afterthought.

  • Summarize advisories from a truncated view — read the full audit output,

count advisories per package, and cross-check the total. A silently

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet, be the first.

Versions

  • v0.1.0 Imported from the upstream source.