Repository navigation
v0.7.0
Learn an app's patterns
0.7 is about fitting mod to the app you already have. Agents can survey an app with the read-only mod-survey and mod-fit Boost tools and propose its patterns as a layout and scaffold recipes. Scaffolds have grown to express those patterns: they can ask for lists of records, repeat or toggle sections with template blocks, and make members optional. Apps can define their own page shapes from page entries, folder scaffolds and nearest-folder layouts, and mod:rename moves a whole page folder safely.
Mod::layout('modules')->frontend(pageEntries: ['Page', 'Modal']);
Mod::scaffold('resource-pages', fn (Scaffold $s) => $s
->asks('columns', type: 'records', shape: ['name' => 'string', 'sortable' => 'bool'])
->asks('modal', type: 'confirm', default: false)
->folder('pages', '{name}', as: 'pageFolder')
->makes('page', name: '{name}/Index/Page', as: 'indexPage')
->makes('page', name: '{name}/Create/Modal', as: 'createModal', when: 'modal'));Added
- Inline template blocks take a separator,
{{ #sorts sep=", " }}{{ value }}{{ /sorts }}, which goes between items and never after the last. Line blocks keep their behaviour, and a separator on a line block, an unclosed quote or an unknown option refuses before anything is written (#145). - A scaffold can own a frontend subtree with
folder('pages', '{name}', as: 'pageFolder'). Generation lists it without writing a directory; rename moves declared and undeclared contents once, preserves supported imports, maps render literals only for page entries and recovers interrupted subtree moves (#138). mod-surveyreports page-folder patterns and declared or inferred entry stems;mod-fitchecks proposed entry stems and data-only frontend folder members, including render literals that target non-entries (#139).- Scaffold member and insert stubs expose the placed group as
{{ group }}and the layout token's alias ({{ module }},{{ domain }}or a custom token), with name transforms and access inside template blocks (#142). - Layouts, mounted roots and packages can declare Inertia page-entry stems; installation emits literal include globs, helpers keep component identities without render names, and
Mod::pageEntry()refuses non-entries (#136). - A scaffold can ask for a list of records with
asks('columns', type: 'records', shape: [...]): interactive runs prompt per record, non-interactive runs take JSON or the recipe default, and answers are validated against the shape before anything is planned (#132). - Scaffold stubs support template blocks:
{{ #columns }}…{{ /columns }}repeats lines for each record, or renders when a boolean is true, and{{ ^name }}…{{ /name }}renders when it is false or empty. Tag lines leave nothing behind, block lines take the opening tag's indentation, blocks nest, and regenerating is byte-identical, so output stays Pint- and Prettier-clean (#132). {{ cols.php }}and{{ cols.ts }}or{{ cols.js }}print a scaffold list or records answer as a one-line PHP or script literal. The script forms use the app's PrettiersingleQuote(#132).- A scaffold member can be optional:
makes('page', when: 'modal')takes a confirm question, or a closure over the answers. Skipped members are listed underskippedwith a reason in--dry-run --json, inserts and placeholders that name them are skipped, andmod:rename --scaffold=treats them as absent. Optional sections inside a file use the same{{ #name }}…{{ /name }}blocks over a boolean (#133). nearestPageFile()finds an app-defined file in a page's own folder or closest ancestor, stopping at its owner's pages root; manual Inertia instructions print each owner's literal glob without changing layout callbacks (#137).- A
mod-learning-patternsBoost skill guides agents from an app survey to reviewable layouts and scaffold recipes, with source and history checks, fit-tool guidance and a generator-verified worked example (#61). - A scaffold recipe can declare a default name with
$scaffold->named('Acme'). Its command then runs without a name, shows the default in--help, and an explicit name still wins (#119). - The read-only
mod-surveyBoost tool reports app structure, references, recurring file sets, vendor ownership and Git identity within an enforced app-only privacy boundary (#62). - The read-only
mod-fitBoost tool checks uninstalled layouts and recipe manifests for ownership, conflicts, path and mechanism variances, outside references and unowned code configuration within the survey's app-only privacy boundary (#63).
Changed
- Calling
named()on a scaffold part is refused with guidance to declare the default name on the root scaffold (#126). - Discovery reuses unchanged inventories across application boots in one PHP process without a cache file, with directory-mtime invalidation,
Mod::flushDiscovery()and adiscovery.reuse_in_processopt-out (#148).
Fixed
- Generating a non-entry page directly or in a scaffold succeeds without a render-name crash or rollback. Its notice says to import it from a page; entry pages keep their render hint (#156).
- Rendering scaffolds into a root other than the running application's ignores classes declared outside the destination. In-app class-collision protection, test path-only checks and
--forcebehaviour are unchanged (#149). - Rerunning a scaffold with Pest or PHPUnit test members checks existing paths without loading test files, preserving collision refusal,
--skip-existing,--forceand interactive choices. Non-test artifacts still autoload class identities to detect classes declared elsewhere (#141). mod-surveyandmod-fitclassify classes from symlinked Composer path-repository packages as vendor-owned by their lexicalvendor/path, without following the link or reading the file, and report unusable vendor paths as skipped instead of failing (#131).
Docs
- A Vue-first walkthrough defines an app's page shape using public page entries, folder ownership, optional modal members, tab parts and nearest-folder layouts, with a React variant and a rename including hand-written partials (#140).
What's Changed
- Add a Boost tool that surveys an app's structure by @jaspertey in #114
- Add contributor guidance for coding agents by @jaspertey in #121
- Fix package frontend declarations and installation wiring by @jaspertey in #120
- Let scaffold recipes declare a default name by @jaspertey in #122
- Pin the README showcase and support reduced motion by @jaspertey in #125
- Refuse a default name on scaffold parts by @jaspertey in #127
- Add a Boost tool that checks how a layout or recipe fits an app by @jaspertey in #129
- Add a Boost skill that learns an app's patterns by @jaspertey in #128
- Classify path-repository packages in surveys and fit checks by @jaspertey in #135
- Add records, template blocks and optional members to scaffolds by @jaspertey in #134
- Find the nearest folder file for a page on the client by @jaspertey in #143
- Detect existing Pest tests without loading them by @jaspertey in #146
- Give scaffold stubs the target group as a placeholder by @jaspertey in #147
- Declare which files in a page tree are Inertia entries by @jaspertey in #144
- Reuse discovery across application boots in one process by @jaspertey in #150
- Let renders into another root ignore classes outside it by @jaspertey in #151
- Add separators to inline template blocks by @jaspertey in #152
- Let a scaffold own a frontend folder by @jaspertey in #154
- Recognize names carried in folders in surveys and fit checks by @jaspertey in #153
- Document defining your own page shape by @jaspertey in #155
- Generate non-entry pages without a render-name crash by @jaspertey in #157
- Generate the page-shape layout as a page member by @jaspertey in #158
Full Changelog: v0.6.1...v0.7.0