A folder of cron scripts, each one a .php file with hand-parsed $argv. That is what CLI looked like on our legacy Kohana application until last month. One line fixed it:
composer require symfony/console
Now each script is a small Command class with named options, --help for free, and exit codes that cron can actually check. The framework around it did not notice anything. Console does not care who serves your HTTP.
Symfony is not only the full-stack framework. It is also a shelf of separate components, and you can take one without the rest. People know this in theory. In practice I rarely see it used, which is a pity, because it is the cheapest way to get modern code into an old project.
Same trick works elsewhere. HttpFoundation gives you a sane Request object instead of digging in superglobals. EventDispatcher gives you events without inventing your own observer. Each component is one require line and one boundary in the code.
The boundary is the important part. Legacy code calls the new library. Never the reverse. The Command class may use our services, but no service should import a Kohana class to serve the console. Keep the arrow pointing one way and you can migrate piece by piece for years without a big-bang rewrite.
One risk, and I know it from the inside. Take Console, then DI, then Routing, then HttpKernel, and congratulations, you have assembled your own framework. Nobody documents it, nobody else has debugged it, every new hire learns it from you personally. If you catch yourself wiring five components together, stop and ask whether you are avoiding a framework or writing one.
Components are for boundaries. The glue should stay thin. Mine is at three components and I am watching it.