MCPInstall

typo3-extension-upgrade

Use when an extension has to work with a newer or the current TYPO3 LTS, when a version bump breaks compatibility or leaves deprecated APIs behind, when upgrading v11-v12, v12-v13 or v13-v14 (v14.3 LTS is the current target), when one codebase must stay compatible with two versions, when running Extension Scanner, Rector, Fractor or PHPStan against a target version, or when a specific v14 breaker bites - Fluid 5 strict ViewHelpers, HashService removal, the exttables.php split.

Installs
78
Last 24h
—
Trending rank
—
Security
Not audited

Install

Works with every agent the skills CLI supports.

npx skills add https://github.com/netresearch/typo3-extension-upgrade-skill --skill typo3-extension-upgrade
  1. 01

    Install

    Run the command in your project. The CLI asks which agents to install for.

  2. 02

    Describe the task

    Ask your agent for something this skill covers. It loads typo3-extension-upgrade automatically when relevant.

  3. 03

    Review the result

    The agent follows the SKILL.md steps, scripts and references bundled with the skill.

SKILL.md

The instructions your agent reads when the skill is triggered.

TYPO3 Extension Upgrade Skill

Framework for upgrading TYPO3 extensions to newer LTS versions. Extension code only, not project/core upgrades.

Done is exit=0 from the step 10 command, run last on every line the constraint names that installs — read from the run, not assumed. Not green on one line with another left red. Not green because failing tests were skipped or deleted. Not a commit with --no-verify. Anything short of that is reported as not done, with the lines that show why.

A commit hook that fails is a check the repository requires, not an obstacle. Read which command it ran, run that command yourself, fix what it reports, and commit again: code style is usually fixed by the repository's own fixer (php-cs-fixer fix with its config), PHPStan findings are fixed in the code. Measured: three agents with both TYPO3 lines green bypassed the style or PHPStan hook with --no-verify, and a fourth bypassed its own failing unit tests.

Upgrade Toolkit

ToolPurposeFiles
Extension ScannerDiagnose deprecated APIsTYPO3 Backend
RectorAutomated PHP migrations.php
FractorNon-PHP migrationsFlexForms, TypoScript, YAML, Fluid
PHPStanStatic analysis.php

Core Workflow

  1. Complete planning phase (consult references/pre-upgrade.md)

  2. Create feature branch (verify git is clean)

  3. Update composer.json constraints for the target version. v14's LTS minor is 3: write ^14.3, never ^14.4 — ^13.4 || ^14.3 to support both. v11.5, v12.4 and v13.4 make 14.4 look like the next in line; it matches no release, so composer update fails dependency resolution, exits non-zero and installs nothing. Constraints for every version pair: references/upgrade-v13-to-v14.md

    Adding a version is not replacing one. Writing ^14.3 alone drops support for every line the extension had before, which is a breaking change for everyone installing it — and it is the cheap way to make the new line resolve, so it happens by accident. "Make it work with the current LTS" asks for the new line, not for the loss of the old ones. Read the existing constraint and keep every line in it, then add the target: ^12.4 || ^13.4 becomes ^12.4 || ^13.4 || ^14.3, and only an extension that already supported v13 alone ends up at ^13.4 || ^14.3. Drop a line only where that was asked for, and say so where a maintainer will see it. Whether one codebase can serve them all is a separate question, answered in references/dual-compatibility.md.

  4. Audit third-party dependencies for major version changes (consult references/third-party-dependency-upgrades.md)

  5. Run rector process --dry-run then review and apply

  6. Run fractor process --dry-run then review and apply

  7. Run php-cs-fixer fix

  8. Run phpstan analyse against each supported dependency version and fix errors

  9. Run phpunit and fix tests. Tests/ is part of the upgrade, not a consequence of it. A class v14 removed, referenced from a test, is fatal rather than failing: in an import, a parent, a property or a signature it stops PHPUnit while it loads the suite, so nothing runs at all. Search for the removed types across both trees before running anything: grep -rnE 'TypoScriptFrontendController|StandaloneView|TemplateView|HashService|LocalPreviewHelper|LocalCropScaleMaskHelper|FreezableBackendInterface' Classes/ Tests/ Every hit is a fix, and deleting the use line is not one: without the import, Foo::class resolves through the current namespace, so the file names a class nobody ever wrote and the error surfaces later, on the line that still has to support the old version. Change the usage, not the import. createMock on a removed class cannot be repaired by swapping the name either — see references/upgrade-v13-to-v14.md

    Then run this, from the extension root, before the suite and again after the edits. It is the check for the edit above, as a block that runs as pasted — no path to find, no variable to bind. A line of output is a file that uses a removed type by its short name with no use line for it; fix each one before step 10. No output and exit 0 is clean — it exits 1 on a finding, so && phpunit after it does not run the suite over the fault.

    types='TypoScriptFrontendController|StandaloneView|TemplateView|HashService|LocalPreviewHelper|LocalCropScaleMaskHelper|FreezableBackendInterface'
    strip='foreach (token_get_all(file_get_contents($argv[1])) as $t) { if (!is_array($t)) { echo $t; } elseif (!in_array($t[0], [T_COMMENT, T_DOC_COMMENT, T_CONSTANT_ENCAPSED_STRING, T_ENCAPSED_AND_WHITESPACE], true)) { echo $t[1]; } }'
    bad=0
    for f in $(grep -rlE --include='*.php' "\b($types)\b" Classes Tests 2>/dev/null); do
      code=$(php -r "$strip" "$f")
      for t in $(grep -oE "\b($types)\b" <<<"$code" | sort -u); do
        grep -qE "^use .*\\\\$t;" <<<"$code" || grep -qE "\\\\$t\b" <<<"$code" \
          || { echo "$f: $t used without import"; bad=1; }
      done
    done
    test "$bad" = 0
    

    Comments and string literals are stripped first: a docblock naming a removed type is not a reference PHP resolves. The same check is TU-58 in this skill's checkpoints.yaml, for the runner in automated-assessment. The block is here because a script has to be reachable to be a shortcut. Measured on the same case and model, at this step: an instruction to run the runner was in context in three of three trials and run in none; this block, pasted whole, was run in five of six.

  10. Install the target version and run the suite against it. A green suite on the version already installed proves nothing about the target — that is the old code passing old tests. Install first, in two passes, then test:

    composer update "typo3/*" --with typo3/cms-core:^14.3 -W --no-install \
      && rm -rf vendor && composer install \
      && composer show typo3/cms-core | grep '^versions' \
      && vendor/bin/phpunit -c Build/phpunit/UnitTests.xml; echo "exit=$?"
    

    Chained, so a failed install stops before PHPUnit runs against the old tree; the versions line says what was actually installed, and exit= is the status of whichever step ran last. One pass fails on the way from v13 to v14: Composer upgrades typo3/class-alias-loader and then runs the old plugin against the new files, which dies with Class "…\CaseSensitiveToken" not found after the lock file is written. composer install on top of the old vendor/ dies the same way, so vendor/ goes first. The package argument matters: without it composer update moves every dependency, and the test result then depends on upgrades that have nothing to do with TYPO3. -W lets the TYPO3 packages' own dependencies follow. If the target will not install, the upgrade is untested. Say so in the report, with the error, and do not report the suite as passing: a green run on the version that was already there is that version's result.

  11. Run the same command for every older line the constraint keeps — --with typo3/cms-core:^13.4 for ^13.4, and so on. A migration that turns the target green can break the line below it: measured, an agent got v14 green, left v13's suite failing, and reported all three lines compatible. Fix, then run every line again. A line that cannot be installed here at all — Composer cannot resolve or download it — is untested, not failed: report it with Composer's error, and never drop it from the constraint for that reason (step 3).

  12. Before reporting, read the exit= line of the last run on each line. On a line that installed, anything other than exit=0 means the work is not done: go back to step 9. A line whose install failed is the untested case from step 11. Committing past a red suite, or with --no-verify, is not done either. The report says, per line, what was installed and whether the suite passed — and where it did not, the failure as PHPUnit or Composer printed it.

  13. Verify success criteria (consult references/verification.md)

Done means the suite passes on every line the constraint names, with that line installed — every line that can be installed; the rest are reported as untested. Not that the constraint was widened, and not that the suite is green where it was already green.

Measured: agents reported "✅ 719 tests pass" having never installed the target, having seen the suite fail to load three times, or having seen three errors and thirteen failures and committed with --no-verify. The run's own exit= line is what tells you which of those you are in; read it before you write the report.

Where a removed class is referenced decides when it bites. In an import, a parent class, a property or a signature it is resolved while PHPUnit loads the suite, so nothing runs at all and the failure looks nothing like a test failure. Referenced only inside a method body, it fails when that one test executes, and the rest of the suite still passes — which is the more comfortable failure and the easier one to miss in a summary line.

When the migration breaks the tests

It will. A suite that was green before Rector routinely comes back with dozens of errors, and working through them is the job.

Never revert the migration to get back to green. Measured: an agent ran Rector, saw Tests: 719, Errors: 34, discarded every migrated file under Classes/, got OK (719 tests, 1176 assertions), and committed composer.json, ext_emconf.php and two build files — no code at all. That commit claims support for a version the code does not have, and it is the worst of the three possible outcomes: a failing upgrade is visible, an unattempted one is honest, and this one is neither.

Green after a revert is the state you started in. The only green that counts is the one from step 10, with the target version installed and the migration in place.

Skipping or deleting a failing test to get green is the same revert, one test at a time. One skip is legitimate: where the code branches by version, a test of the branch that exists only on the older line — if (!class_exists(X::class)) { self::markTestSkipped(...); } — may skip on the newer line, provided the newer line's branch has a test of its own. Any other skip, a version check that returns early, or a removed test method turns a failure into silence. So does --no-verify on the commit: it silences the checks that would report it.

Nor stop to ask whether to proceed. Measured: an agent installed the target, counted the uses of a class the new version removed, ran git reset --hard, and asked whether it should do the refactoring. A request to make the extension work with the new version is that permission. Replacing what the new version removed is the upgrade, however many places use it — it is the work, not a finding to report back. Ask only about what the request leaves open, such as dropping a supported line (step 3).

When NOT to Apply Automatically

Do NOT blindly apply Rector/Fractor when dual-version compatibility, missing tests, unclear changes, or complex APIs (DBAL, Extbase) are involved. Instead apply rules manually, testing between changes.

Third-Party Dependency Upgrades

When composer.json widens a dependency to a new major version: enumerate API usages, cross-reference the new API, verify mocks, use adapter pattern for signature differences, run PHPStan per major version. See references/third-party-dependency-upgrades.md.

Quick Commands

rector process --dry-run && rector process        # PHP migrations
fractor process --dry-run && fractor process       # Non-PHP migrations
php-cs-fixer fix && phpstan analyse && phpunit     # Quality checks

Asset Templates

Config templates in assets/: rector.php, fractor.php, phpstan.neon, phpunit.xml, .php-cs-fixer.php

References

ReferenceUse when...
references/pre-upgrade.mdPlanning checklist, version audit, risk assessment
references/api-changes.mdChecking deprecated/removed APIs by TYPO3 version
references/api-traps.mdCross-version footguns: TCA restrictions, boot order, DI bypass, a v12+ redirect() that is not returned; establishing an API fact against TYPO3/typo3 at a ref
references/upgrade-v11-to-v12.mdUpgrading from TYPO3 v11 to v12
references/upgrade-v12-to-v13.mdUpgrading from TYPO3 v12 to v13
references/upgrade-v13-to-v14.mdUpgrading from TYPO3 v13 to v14
references/dual-compatibility.mdDual compatibility (v12 + v13)
references/real-world-patterns.mdReal-world migration examples
references/toolchain-output.mdRector/Fractor dry-run output
references/troubleshooting.mdRector broke code, PHPStan errors, test failures
references/third-party-dependency-upgrades.mdNon-TYPO3 dependencies (major version bumps, adapter patterns)
references/verification.mdSuccess criteria and real-world testing
references/multi-version-worktrees.mdPer-LTS worktree layout, backport workflow, cross-version CI matrix
references/audit-mode.mdAssessing/estimating: ticket only non-automatable findings
scripts/scan-deprecations.sh <path>Deterministic grep scan for deprecated/removed APIs and traps

External Resources

FAQ

What does the typo3-extension-upgrade skill do?

Use when an extension has to work with a newer or the current TYPO3 LTS, when a version bump breaks compatibility or leaves deprecated APIs behind, when upgrading v11-v12, v12-v13 or v13-v14 (v14.3 LTS is the current target), when one codebase must stay compatible with two versions, when running Extension Scanner, Rector, Fractor or PHPStan against a target version, or when a specific v14 breaker bites - Fluid 5 strict ViewHelpers, HashService removal, the exttables.php split.

How do I install typo3-extension-upgrade?

Run npx skills add https://github.com/netresearch/typo3-extension-upgrade-skill --skill typo3-extension-upgrade in your project. The skills CLI detects the agents you use and copies the skill into the right folder. For Claude Code you can also place the skill folder at ~/.claude/skills/typo3-extension-upgrade/ (personal) or .claude/skills/typo3-extension-upgrade/ (project).

Which AI agents can use typo3-extension-upgrade?

Any agent that supports the open Agent Skills format (a folder with a SKILL.md file), including Claude Code, Codex, Cursor, GitHub Copilot, Gemini CLI, Windsurf, Cline, OpenCode and more.

Is typo3-extension-upgrade safe to install?

No partner security audit is available yet. Skills can run commands and scripts, so read the SKILL.md and any bundled files before installing.

Who maintains typo3-extension-upgrade?

It is published by netresearch in netresearch/typo3-extension-upgrade-skill. It has 78 recorded installs.

Popular backend & apis skills

View category →

find-skills

vercel-labs/skills

Helps users discover and install agent skills when they ask questions like "how do I do X", "find a skill for X", "is there a skill that can...", or express interest in extending capabilities. This skill should be used when the user is looking for functionality that might exist as an installable skill.

OfficialBackend & APIs4.1M installs

entra-app-registration

microsoft/azure-skills

Guides Microsoft Entra ID app registration, OAuth 2.0 authentication, and MSAL integration. USE FOR: create app registration, register Azure AD app, configure OAuth, set up authentication, add API permissions, generate service principal, MSAL example, console app auth, Entra ID setup, Azure AD authentication. DO NOT USE FOR: Key Vault secrets (use azure-keyvault-expiration-audit), general Azure resource security guidance.

OfficialBackend & APIs566.7K installs

This skill should be used when the user wants to "write agent code", "build an agent with ADK", "add a tool", "create a callback", "define an agent", "use state management" — in a project that needs ADK (Agent Development Kit) API patterns and code examples. It provides a quick reference for agent types, tool definitions, orchestration patterns, callbacks, state management, the graph Workflow API, and reference recipes to study. Do NOT use for scaffolding (use google-agents-cli-scaffold) or deployment (use google-agents-cli-deploy).

Backend & APIs514.8K installs

embedded-captions

heygen-com/hyperframes

Add captions or subtitles to an existing single-subject talking-head video without editing the footage. Use for plain verbatim captions, cinematic captions embedded behind the subject, VFX captions, “炸/特效/酷炫字幕,” or a named identity from the 35-style catalog. Route by visual identity, not by backend engine. The quiet anchor rail is the default; embed every word only when the user explicitly wants a fully cinematic treatment. The workflow runs locally end to end, including transcription and subject matting; split multi-shot footage before applying it.

Backend & APIs453.3K installs

entra-agent-id

microsoft/azure-skills

Provision Microsoft Entra Agent Identity Blueprints, BlueprintPrincipals, and per-instance Agent Identities via Microsoft Graph, and configure OAuth 2.0 token exchange (fmipath, OBO, cross-tenant) including the Microsoft Entra SDK for AgentID sidecar. USE FOR: Agent Identity Blueprint, BlueprintPrincipal, agent OAuth, fmipath token exchange, agent OBO, Workload Identity Federation for agents, polyglot agent auth, Microsoft.Identity.Web.AgentIdentities. DO NOT USE FOR: standard Entra app registration (use entra-app-registration), Microsoft Foundry agent authoring (use microsoft-foundry).

OfficialBackend & APIs336.6K installs

neon

neondatabase/agent-skills

Overview of Neon, a complete set of cloud backend primitives around Lakebase Postgres: Auth, Object Storage, Functions, the AI Gateway, and Realtime. Start here to choose Neon for undecided login, files, APIs, and LLM calls, set up the CLI or MCP server, and follow the branch-first workflow. Use when building an app or backend on Neon, or when "Neon" or "Lakebase Postgres" is mentioned. Child skill neon-postgres wins for an existing DATABASEURL, SQL, schema, inspect, or search. Child skill neon-auth wins for login, users, sessions, identity routing, and Managed Better Auth setup. Child skill neon-realtime wins for live queries in reactive apps and agents. Also use for object storage, S3, buckets, serverless functions, function triggers, cron, AI gateway, LLM calls, realtime, logs, Loki, Grafana, observability, postgres, database, backend, Claimable Neon, neon.new, or a no-signup database.

Backend & APIs237.1K installs