feral/core
feral/core provides the shared foundation for the Feral Laravel/PHP ecosystem, including core utilities and integration points for building applications and companion packages. It is a lightweight base for projects using the Feral stack.
Before writing any application code, understand what feral/core 1.0.0 actually is: a framework-agnostic library of NoLoCo primitives. The 1.0.0 release explicitly removed the Docker harness and the Symfony integration so the core "can be a true library available for any framework." That is the single most important fact for a Laravel developer — there is no framework bridge, and what integration code existed has been deliberately dropped.
Minimal path to a first look:
composer.json (PHP constraint, PSR-4 namespace, actual package name — the vendor may not be feral), then README.md, then the src/ tree, then tests/. In a package this size, the tests are the specification; there is no docs site.composer require into an existing application first. Create a scratch project, add the package by path repository or VCS, and get its own test suite green. Because Docker was removed in 1.0.0, there is no shipped environment — expect to supply your own PHPUnit setup and CI config before you learn anything. This tells you whether it runs on your PHP version before you've entangled it with anything."feral/core": "^1.0" is now defensible in a way a commit SHA was before — 1.0.0 signals an API-stability intent. Verify with a second release before fully trusting it; until then, a lockfile is your real pin.The right first use case is a single internal CRUD screen over one existing table — a back-office list/edit view for something you'd otherwise hand-write. NoLoCo's premise is that entities, forms, and screens are described as metadata and the framework generates the plumbing. Build exactly one of those, end to end, before deciding whether the abstraction earns its place. If your first slice takes longer than hand-writing the controller and Blade views, stop there.
Where to look first in the source: the entry point that loads a definition, the interfaces the core expects you to implement (persistence, rendering), and the git history around the removed Symfony integration — that is now your best reference for the intended seams. Those three things tell you the integration contract.
Treat core as a kernel, not a framework. The 1.0.0 release formalises this: it is a library, not a bundle. Expect abstract contracts and metadata handling, with persistence and presentation supplied by you. Plan to write adapters for Eloquent (or your DB layer) and Blade (or your view layer) rather than assuming they ship.
Mine the pre-1.0 history for the Symfony bridge. The removed Symfony integration is documentation you can still read in git — it shows which contracts get bound, in what order, and what a working host looks like. Read it, do not depend on it. Recreate its shape in Laravel terms; don't try to resurrect the package.
Wrap it behind your own boundary. Do not let NoLoCo types leak into your domain code. Put a thin service class in front of it:
final class BackOfficeScreen
{
public function __construct(private ScreenRenderer $noloco) {}
public function render(string $entity): string
{
return $this->noloco->render($entity);
}
}
When (not if) you need to replace or fork it, you change one class instead of forty call sites.
Build the Laravel provider yourself — it is the deliverable. There is no shipped NoLoCoServiceProvider. Bind the core's interfaces in a dedicated provider and drive paths via config/noloco.php:
public function register(): void
{
$this->app->bind(Persistence::class, EloquentPersistence::class);
$this->app->bind(Renderer::class, BladeRenderer::class);
}
This is your extension point for overriding behaviour without patching vendor code, and it lets you conditionally disable the package per environment.
Definition-first workflow. The day-to-day rhythm with a low-code core is: edit a metadata definition (fields, types, validation, layout) → reload → observe the generated screen or endpoint. Keep those definitions in version control as first-class files, not in a database, so they diff and review like code. This matters more now that you own the loader.
Use it for internal tooling, not the critical path. Back-office screens, admin panels, data-entry forms over legacy tables, and prototypes are the sweet spot. Customer-facing flows, anything with an SLA, and anything handling payments or PII should stay in code you control and can patch.
Prototype-first, then measure. Time-box a vertical slice to a day. Compare against the hand-rolled equivalent. Keep the result only if it's clearly faster to change afterward — that's the actual claim low-code has to defend.
src/ against the previous tag before assuming anything about the contracts — a framework-agnostic refactor often means interfaces were loosened, moved, or renamed, not just that a directory was deleted.docker-compose.yml or a CI workflow you write yourself. If that feels disproportionate for an evaluation, that is itself an answer.composer.json constraint will collide with modern Laravel versions. The Symfony removal may have loosened things, or may have left stale constraints behind — check before assuming it installs cleanly. Re-run the suite after each bump to see what actually breaks.composer.json, not from the repository slug. Vendor/name mismatches are common in small packages and will waste an hour of composer require guessing.LICENSE/NOTICE files and state changes if you modify and redistribute. This matters more than usual because you will likely be modifying it.How can I help you explore Laravel packages today?