rmb32 / barnark
Keeps a project's folders in step with an architecture template: make them from it, and check they still conform.
Requires
- php: ^8.5
- ext-ds: ^2.0
- ext-mbstring: *
- php-ds/php-ds: ^2.0
- rmb32/barn-paths: ^0.1@dev
- rmb32/barntree: ^0.1@dev
Requires (Dev)
- deptrac/deptrac: ^4.7
- infection/infection: ^0.35.4
- phpstan/phpstan: ^2.2
- phpunit/phpunit: ^11.0
- rector/rector: ^2.6
- rmb32/barnspec: ^0.1@dev
- rmb32/barnspec-cli: ^0.1@dev
- rmb32/barnspec-gui: ^0.1@dev
- rmb32/barntree-cli: ^0.1@dev
- rmb32/filesystem: ^1.0@dev
- rmb32/port-generator: ^0.1@dev
- rmb32/scenario-bridge: ^0.1@dev
- rmb32/scenario-runner: ^0.1@dev
- rmb32/typed-input: ^2.0@dev
- rmb32/typed-json: ^1.0@dev
- squizlabs/php_codesniffer: ^4.0
Suggests
None
Provides
None
Conflicts
None
Replaces
None
README
Early, version 0.x. Not ready for real projects yet; the minor version is the breaking one.
Part of Barn.
Architecture management for any project. Barnark keeps a catalogue of architecture templates — Domain Driven Design, Feature Based Architecture, Model View Controller, Library, Package App. You clone one into a template of your own, under a name you give it, and Barnark makes a new folder to that template and checks that the folder keeps to it. It isn't tied to any single architectural style.
In a barn it is the Ark tab, beside
Barnspec's story map. It works without Barn too: barnark init makes any project a barn.
Its templates are written as Barntree trees. This package is the core library; the command line and browser UI are separate packages.
The easiest way to use it is Barnark GUI, in your browser: create a folder, browse its tree, create what its template offers, and run checks. The command line does the same from a terminal, and is the better fit for scripts, CI and AI agents.

Template maps are presented alphabetically by display name through Barntree, including when reading earlier revisions. List members keep their sequence. Reading a revision leaves the stored revision untouched.
Requirements
- PHP 8.5+
- Composer
Installation
composer require --dev rmb32/barnark-cli rmb32/barnark-gui
./vendor/bin/barnark gui # opens the GUI in your browser
The command line brings this library in with it, and the GUI adds its gui
command. Leave the GUI out where only the command line is needed.
docs/installation.md covers a global install and the
files Barnark keeps in your project.
Barnark keeps its records only in a barn: the project's one .barn/ folder, which every Barn tool
shares. Start one with barnark init (or the GUI's offer); Barnark refuses to make a folder where
there is none, and asks before starting one inside another barn.
Barnark is for new projects, and converts no older record. A tracked-folders.json that binds several
folders is refused. To keep a folder bound, scaffold it again under the same path in
a new, empty scratch barn, and copy that barn's .barn/barnark/ into yours.
Quick start
vendor/bin/barnark init
vendor/bin/barnark template:list
vendor/bin/barnark template:clone Library Billing ./src
vendor/bin/barnark template:offers src/Internal/Feature
vendor/bin/barnark template:new Feature Invoicing src/Internal/Feature
vendor/bin/barnark template:check
vendor/bin/barnark template:copy Billing Invoicing
| Command | Description |
|---|---|
barnark init | Make a barn here if there is none, and say where Barnark keeps its records |
barnark template:list | List the project's template, your templates and the shipped ones |
barnark template:clone | Clone a template into the project, under a name you give, and make its folder |
barnark template:check | Check the bound folder against its template, or a given directory against a shipped template |
barnark template:copy | Copy any template into a new template of your own |
barnark template:delete | Delete one of your templates |
barnark template:offers | List what the template lets you create inside a folder |
barnark template:new | Add a folder you name to the template, as a new revision, and make it |
Run barnark <command> --help for every option.
Templates, bound and unbound
A shipped template is a read-only catalogue entry. Cloning one makes a template of your own: a copy under a name you give it, with nothing tying it to the one it came from. If the shipped template changes in a later Barnark, yours doesn't. Nobody calls their project "Domain Driven Design", so no shipped template's name can be used for one of yours.
A project has one bound template, made with its folder by the GUI's Clone into the project or
template:clone. Barnark records the folder it is bound to in .barn/barnark/tracked-folders.json, and
keeps each of the project's templates, with its revisions, in .barn/barnark/catalogue/. Commit both,
but not the save.lock files written while a template is saved. While a template
is bound, another clone is refused. The project's other templates are unbound, made by copying any
template (shipped, yours or the bound one, members included). An unbound template can be cloned into
a project with nothing bound, like a shipped template, its members' folders included, or deleted; git
keeps it if you need it back. Nothing unbinds the project's template or removes its folder: ending a
template's life is not built yet.
Each of the project's templates is kept as revisions, and none is changed in place. Its first revision is the copy, and the GUI's History tab shows each revision as a read-only tree. A folder you name and add (a context, a feature) is part of the template, so adding one makes a new revision, and so does deleting one. Barnark writes each revision's reason, such as "Added Context/Billing.". Nothing changes inside the folders it brings with it: every context has the same shape.
Checking a real project
A template describes a shape, not your code. It names some folders itself (DDD's Kernel, Library's
Api). Others are collections, such as Context or Aggregate, where you add folders of your own
as members, each of the collection's member type. A template says only what folders there are, so
files are never checked: what goes in a folder is yours to write.
template:check checks each member against its member type, so your real contexts and aggregates are
checked where they actually are. A folder you make by hand isn't added to the template, but one made
in a collection can only be a member of it, so it is checked as one. A folder made by hand anywhere
else is reported as unexpected. A folder in the template that has been deleted by hand is reported as
missing.
The barn's .barn/ folder is never part of the bound folder.
Creating by the template
template:new adds a member you name to a collection, and its folder arrives with the folders its
member type holds: a Context comes with its Domain, Application, Infrastructure and
PublicApi. Barnark never creates a file in your folders, except a .gitkeep so that git keeps a
folder created empty.
Tags
A template can tag its folders, to say what part each plays. Domain Driven Design tags its layers:
Application, Domain and Infrastructure in the Kernel and in every Context, and Transport. Package
App tags each Context's Application and Infrastructure. A tag has a meaning, and a folder carries
the tags of its kind of folder, so every Context you add brings its layers' tags. A folder the template
has no place for carries none. Picking out a tag shows the template's folders that carry it and the
folders above them, such as every context's Application/ together.
From PHP
Each factory in Rmb32\Barnark\Api\Factory gives you one part of Barnark.
use Rmb32\Barnark\Api\Factory\ArchitectureFactory;
use Rmb32\Barnark\Api\Factory\ProjectFactory;
use Rmb32\Barnark\Api\Factory\TemplateProfileRegistryFactory;
$names = new TemplateProfileRegistryFactory()->create()->names(); // the shipped templates
To see what a template looks like, read its tree: each Node is a folder every
scaffold has, and each MemberType is a kind of folder you create and name,
each with the meaning the template gives it.
$template = new TemplateProfileRegistryFactory()->create()->get('Domain Driven Design');
$template->description(); // what it is and what it suits
$template->root()->nodes[0]->name; // "Kernel", a folder every scaffold has
$template->root()->nodes[0]->memberTypes; // MemberType[]: what you may create in it
$template->tags(); // Tag[]: Application, Domain, Infrastructure, Transport
$template->root()->nodes[0]->nodes[0]->tags; // ["Application"]: the tags a folder carries
new ArchitectureFactory()->create()->planScaffold('Library'); // ["Api", "Api/Contract", ...]
$project = new ProjectFactory()->open('/path/to/project'); // a barn started with barnark init
$project->createFolder('src', '', 'Library', 'Billing'); // the template Billing, and src/ made to it
$project->check('/path/to/project/src', 'Billing', $project->slotsFor('src')); // slotsFor: each member's path and member type
$project->pickOutByTag('Domain Driven Design', 'Application'); // only the folders tagged Application, and those above them
ProjectFactory::create($root) manages a project's bound folder and its templates, bound and unbound
(listTemplates, copyTemplate, deleteTemplate), and
CheckFactory checks a directory against a shipped template, returning a Violation
for each folder that is missing or not part of it.
Related packages
- Barnark CLI — the
barnarkcommand. - Barnark GUI — clone a template into the project, browse its folder, create what its template offers, run checks and keep templates of your own, in a browser.
- Barntree — the trees the templates are written as.
More docs
Installation · Internals · History · Known issues
License
Proprietary. See LICENSE. Copyright (c) Roger Barnfather.