Multi-package output
By default SKMTC writes every generated file under a single root — client.json#settings.basePath — and every cross-file import renders through one @/… alias. Multi-package output lets a project route…
By default SKMTC writes every generated file under a single root —
client.json#settings.basePath — and every cross-file import renders through
one @/… alias. Multi-package output lets a project route generated files
into separate packages of a monorepo (generated models in one package,
generated server or UI code in others) with cross-package imports that resolve
correctly.
The feature is client.json#settings.packages. It is first-class in
@skmtc/core but easy to miss — without it an agent emits raw relative imports
or assumes cross-package output isn't supported.
basePath has two meanings
basePath is the on-disk anchor for generated output. Its precise role depends
on whether packages is set:
- Single-package (no
packages):basePathis the consumer app's bundler@alias root —@/foolands at<basePath>/foo, and the app's bundler is configured so@resolves there. - Multi-package (
packagesset):basePathis purely a common on-disk ancestor of every package — typically the monorepo root. It is not a bundler alias;@is per-package (see below).
The packages setting
Every package is a { rootPath, moduleName? } entry. rootPath is a forward
path — relative to basePath, with no .. segments. Because basePath is a
common ancestor, every package sits forward from it:
{
"source": "skmtc-hub/packages/api/dist/openapi.json",
"settings": {
"basePath": "skmtc-hub",
"packages": [
{ "rootPath": "packages/models/src", "moduleName": "@skmtc/models" },
{ "rootPath": "apps/mock-server", "moduleName": "@skmtc/mock-server" }
]
}
}rootPath is where that package's generated files live — on disk,
join(basePath, rootPath). moduleName is its npm/JSR package name, used when
other packages import from it.
Forward paths only. A
rootPath(orbasePath) containing a..segment is rejected at config load. A..meansbasePathwas placed below some output location — liftbasePathto a common ancestor instead. Hand-counting../segments, and keeping that count in lockstep across config fields, is exactly the silent-misplacement footgun the forward-path rule removes.
How a file is routed
Two resolutions — where the file lands on disk and how an import to it renders.
On disk. toResolvedArtifactPath is join(basePath, exportPath). A
generator targeting a package returns a toExportPath that is a forward path
under that package's rootPath (e.g. packages/models/src/User.ts); joined
onto basePath it lands in the right place. No ...
In imports. normalizeModuleName (dsl/File.ts) resolves a cross-file
import three ways:
- importer and target in the same package → intra-package
@/…(the target'sexportPathwith the packagerootPathreplaced by@); - importer and target in different packages → the target package's
moduleName; - no package match → the raw
exportPath.
So @ is per-package, not a single global alias: a file under
packages/models/src sees @/ rooted at that package; a file in another
package importing it gets @skmtc/models.
Barrels: a re-export-only file
A package usually wants one entry point that re-exports everything it generated.
A barrel does not need an accumulator class — it is a File populated only
with re-exports:
context.register({
reExports: { [modelExportPath]: [settings.identifier] },
destinationPath: barrelPath,
});reExports is Record<string, Identifier[]> (module → identifiers); each
identifier's entity type selects export { x } vs export type { x }. Multiple
generators may register re-exports into the same destinationPath — the
File.reExports map merges them. A File with only reExports (no
Definitions) is a valid emitted artifact: there is no shared value, just a
shared file accumulating re-export entries.
See also
projects-and-workspaces.md— the single-basePathmodelfiles-and-dedup.md— theFilemodel and import normalisationskmtc-cliskill §6 — theclient.jsonshape
Projects and workspaces
The .skmtc/<project>/ directory layout — what files exist, which are derived, which are user-edited. A SKMTC project is a generator configuration, not a consuming application: it specifies which…
The manifest
The structured JSON record of every SKMTC generation run. Captures which files were written, which (generator, item) pairs succeeded, failed, or were skipped, what parse issues surfaced, and the…