@pyreon/config — API Reference
Generated from
config'ssrc/manifest.ts— the same source that powersllms.txtand MCPget_api. Do not edit this page by hand; edit the manifest.
Every Pyreon tool grew its own config file — atlas.config.ts, .pyreonlintrc.json, a zero() call in vite.config.ts, a loom key in package.json. Each is defensible alone; together they are four places to look and four things to keep in sync when a project moves a directory. @pyreon/config is the single file with a key per package: defineConfig gives it types and editor completion, CONFIG_FILENAMES is the filename list every loader tries, and sectionFrom is the one named-vs-default section lookup they share. The tool that reads a key owns its meaning, so nothing becomes a god object — and a key appears in the type ONLY once a package actually reads it, because a config surface that advertises options nothing consumes is the typed-but-unimplemented class this repo gates against.
Features
ONE file, a key per package:
atlas(the component workbench) andloom(the dependency observatory) today, each added in the change that made its reader realPer-tool files still WIN:
atlas.config.*beats this file'satlaskey, and the rootpackage.json'sloomkey beats itsloomkey — a project mid-migration is never silently overridden by the general fileUnknown keys are CARRIED, never rejected: a project may configure a tool this version does not know about (a newer package, a plugin) without losing type safety on the rest
CONFIG_FILENAMES+sectionFromare the shared loader primitives — atlas and loom both consume them, so "which filenames" and "how to pull a section out" have exactly one definition and cannot drift into a silently-ignored configTypes only — zero runtime dependencies, nothing to bundle into an app
Complete example
A full, end-to-end usage of the package:
// pyreon.config.ts
import { defineConfig } from '@pyreon/config'
export default defineConfig({
atlas: {
title: 'Acme Design System',
projects: [{ name: 'Core', dir: 'packages/core/src' }],
},
loom: {
// Package-relative globs that are NOT shipping source.
devPaths: ['src/manifest.ts', '**/*.gen.ts'],
// `reason` is mandatory and is shown in the report.
ignore: [{ dep: 'sharp', code: 'unused-dep', reason: 'loaded by the image plugin at runtime' }],
strict: true,
// Adopt incrementally: raise a code once clean, lower one while it burns down.
severity: { 'unused-dep': 'info', 'phantom-dep': 'error' },
},
})Exports
| Symbol | Kind | Summary |
|---|---|---|
defineConfig | function | Identity helper that gives a config file types and editor completion without the author writing satisfies PyreonConfig |
CONFIG_FILENAMES | constant | The filenames a loader tries, in order. |
sectionFrom | function | Read one tool's section out of a loaded config module, accepting either a default export or a named one. |
API
defineConfig function
defineConfig(config: PyreonConfig): PyreonConfigIdentity helper that gives a config file types and editor completion without the author writing satisfies PyreonConfig by hand — the same reason every config-driven tool ships one. Returns its argument untouched; there is no validation here, because the tool that READS a section is the one that can say what is wrong with it, and it reports that with the file named. PyreonConfig is indexed as well as keyed, so a section for a tool this version does not know about typechecks and is carried through.
Example
import { defineConfig } from '@pyreon/config'
export default defineConfig({
loom: { devPaths: ['src/manifest.ts'] },
})Common mistakes
Expecting
defineConfigto validate — it is identity by design; each tool validates its own section and names the offending file, because only that tool knows what its keys meanAssuming a key here overrides the per-tool file — it is the other way round:
atlas.config.*wins over theatlaskey, andpackage.json'sloomkey wins over theloomsection, so a half-finished migration is never silently reversedAdding a key for a tool that does not read it yet and expecting it to take effect — the type carries unknown keys deliberately, but carrying is not consuming
Writing the file as
pyreon.config.tsin a project whose tooling runs on a Node older than 23.6 —loom scanhas no bundler, so usepyreon.config.mjs(or the package.json key) there; the loader names the file and says so rather than skipping it
See also: CONFIG_FILENAMES · sectionFrom
CONFIG_FILENAMES constant
CONFIG_FILENAMES: readonly ['pyreon.config.ts', 'pyreon.config.tsx', 'pyreon.config.mjs', 'pyreon.config.js']The filenames a loader tries, in order. Exported so every consumer shares ONE list: atlas and loom both read it, so adding an extension here reaches both at once. The alternative — each loader restating the list — is a config file that is silently ignored the day the lists disagree, which is the exact failure this package exists to reduce.
Example
import { CONFIG_FILENAMES } from '@pyreon/config'
const found = CONFIG_FILENAMES.map((n) => resolve(cwd, n)).find(existsSync)Common mistakes
Restating the list in your own loader — that is the drift this export removes; iterate the constant (atlas's loader test does exactly that, so a new filename is covered without anyone remembering a second list)
Assuming order does not matter — it is a PRECEDENCE list, tried first-to-last
See also: sectionFrom · defineConfig
sectionFrom function
sectionFrom(module: Record<string, unknown>, tool: string): unknownRead one tool's section out of a loaded config module, accepting either a default export or a named one. Both spellings read naturally to an author, and guessing wrong between them produces a config that is silently ignored — so the lookup lives here once rather than in each consumer. Returns undefined when the file has no section for that tool, which callers must treat as "not configured", never as an error: a project configuring some other tool is the normal case.
Example
import { sectionFrom } from '@pyreon/config'
const section = sectionFrom(loadedModule, 'loom') // default OR named exportCommon mistakes
Treating
undefinedas a failure — apyreon.config.tswith no section for your tool is a project configuring something else, and saying nothing is correctValidating inside the loader instead of after — read the section here, then validate it with YOUR rules and name the file in the message
See also: CONFIG_FILENAMES · defineConfig