Browse pages
Project File
.litespec/project.json is the one record of what a consumer project (an application repository built against one pinned LiteSpec release) selected: its size, shape, technology stacks, extensions, paths, and pinned release. The team edits it when the selection changes and validates it with the litespec model check command before relying on it. This page lists every field the file holds, states what reads each field, and shows the errors a wrong value produces.
Reference#
The supported scope page states which sizes, shapes, stacks, and extensions a project can select. The stacks page states what selecting a stack applies. The init page states how a new file is written, the model page states how it is validated and how paths feed the project model. Terms such as stack, shape, size, extension, and preset follow the glossary.
File Location and Schema#
| Item | Value |
|---|---|
| Path | .litespec/project.json at the consumer root |
| Schema | schemas/litespec-project.schema.json in the pinned release |
| Template | templates/consumer/project.json in the release the tool carries |
| Presets | templates/presets/android-client.json, templates/presets/blazor-client.json, templates/presets/dotnet-react.json, templates/presets/dotnet-svelte.json |
litespec init merges the template with one preset and stamps the size, name, and reviewed release. litespec model check validates the written file against the schema and then runs the selection checks below. The model builder reads the paths, stack config, size, shape, and stacks from the same file.
Top-Level Fields#
| Field | Type | Required | Default |
|---|---|---|---|
$schema | string | no | none |
project | object | yes | none |
size | string | yes | none |
conformance | string | yes | none |
shape | string | no | "server" |
stacks | array of string | at traced and full | none |
proof | object | no | none |
marks | string | no | "xml" |
dependencies | object | no | none |
screenshots | object | no | none |
refusals | object | no | the default codes |
reviewedLiteSpecVersion | string | yes | none |
paths | object | yes | none |
selectedExtensions | array of object | yes | none |
stackConfig | object | no | none |
What each field means and what reads it:
$schemaholds the editor hint that points at the project schema. Only the editor reads it.projectnames the project.litespec model checkchecks it against the schema. See theprojectobject below.sizeissmallorlarge. Small requires the core record types with Architecture and Integration test projects, and large adds goals, problems, features, journeys, and scenarios with the Acceptance project.litespec model checkchecks the value, and the model builder sizes the record set it expects.conformanceis the conformance level the project claims:records,tracedorfull. Atrecordsthe project claims its Intent, Behavior, governance and glossary records; attracedit also claims marks in its code and tests and proof from its test runs, in a code layout of its own; atfullit also claims the selected stacks, LiteSpec's code layout, the analyzers and the operations provisions.litespec model check, the book,litespec rulesand the analyzers report only the part the level claims.shapeisserverorclient-only. A server names exactly one backend stack, and a client-only project names no backend stack.litespec initwrites it from the preset,litespec model checkchecks the backend count, and the model builder applies the shape.stackslists the selected stack ids:dotnetfor the backend and one entry per frontend from its platform. It is required attracedandfull; atrecordsa stack is informational.litespec model checkrefuses an id the pinned release does not ship.prooftunes how the model builder confirms proof claims for the project. See theproofobject below.marksis the mark style:xmlfor documentation tags,attributefor generated attributes. The model builder, the analyzers and the source generator read it, and each reports a mark in the other style asmark-style-invalid.dependenciesnames the dependency gate: the licenses every shipped package may carry without an admitting decision. See thedependenciesobject below.screenshotsnames the screenshot galleries the model builder reads for screen captures. See thescreenshotsobject below.refusalsnames the codes the derived generic results carry. See therefusalsobject below.reviewedLiteSpecVersionrecords the LiteSpec release whose complete contract the project last reviewed, such as"4.0.0".litespec model checkcompares it with the release of the installedlitespectool and fails the run when the two differ.pathsdeclares every location the tools read. See thepathsobject below.selectedExtensionslists the extensions the project selected, each with its criterion. See the extension entry below.stackConfigholds per-stack configuration keyed by stack id. See thestackConfig.dotnetobject below.
The project Object#
| Field | Type | Required | Default |
|---|---|---|---|
name | string | yes | none |
What each field means and what reads it:
nameis the project name, such as"shop".litespec initsets it from--nameor from the root folder name.
The proof Object#
| Field | Type | Required | Default |
|---|---|---|---|
jobTriggerSteps | array of string | no | none |
outcomeOnlySteps | array of string | no | none |
What each field means and what reads it:
jobTriggerStepsnames the steps classes whosewhensteps run a job, such as one that moves a simulated clock. Each entry matches^[A-Z][A-Za-z0-9]*$.outcomeOnlyStepsnames the steps classes whosethensteps state only that a request succeeded or was refused. Each entry matches^[A-Z][A-Za-z0-9]*$.- The model builder reads both lists when it confirms proof claims for the project.
The dependencies Object#
| Field | Type | Required | Default |
|---|---|---|---|
licenses | array of strings | no | none |
licenseslists the SPDX license identifiers the project accepts, such asMITandApache-2.0. A shipped package under any other license needs an admitting decision that names it.
The screenshots Object#
| Field | Type | Required | Default |
|---|---|---|---|
galleries | array of string | no | none |
pattern | string | no | "{route}--{theme}--{width}.png" |
What each field means and what reads it:
gallerieslists the gallery folders holding screenshot captures, one per frontend that photographs its routes, such as"apps/web/test-results/gallery". The model builder reads the captures from these folders.patternis the capture file-name pattern, with{route}for the route slug,{theme}for the theme, and{width}for the width in pixels. When omitted, the default pattern applies.
The refusals Object#
| Field | Type | Required | Default |
|---|---|---|---|
forbidden | string | no | "authorization.forbidden" |
invalidInput | string | no | "request.validation-failed" |
prefixes | string array | no | none |
composed | string array | no | none |
What each field means and what reads it:
forbiddenis the code the derivedresult/<use-case>.forbiddencarries, derived for a use case whoseaccess.grantis a permission.invalidInputis the code the derivedresult/<use-case>.invalid-inputcarries, derived for a use case with anyinputfield carryingrules.prefixeslists the refusal-code prefixes the project shares across modules, such assharedfor a shared kernel. Therefusal-code-invalidcheck accepts them beside every declared module and the genericrequest,authorizationandclientprefixes.composedlists the refusal codes the project builds at run time from a key, each a template with one{key}placeholder after a prefix and a dot, such as"uniqueness.{key}-taken"for the conflict a commit answers when an aggregate loses a uniqueness key. Therefusal-code-invalidcheck accepts the template prefix. Therefusal-unimplementedcheck counts a code matching a template as raised when its key is a kebab-case literal in the code, such as the key scopecopy-barcodeon the book aggregate foruniqueness.copy-barcode-taken.- The model builder reads
forbiddenandinvalidInputwhen it derives the generic results. When the object is omitted, the defaults apply.
The paths Object#
| Field | Type | Required | Default |
|---|---|---|---|
docs | string | no | .litespec |
glossary | string | no | .litespec/glossary.yaml |
unstructuredDocs | array of string | no | none |
behaviorDocs | string | yes | none |
records | object | no | none |
testRoots | array of string | no | none |
testResults | string | no | TestResults |
contract | string | no | none |
alerts | array of strings | no | none |
operations | array of strings | no | none |
checkResults | string | no | .litespec/proof/checks |
sbom | array of strings | no | none |
apiClient | string | no | packages/api |
surfaces | array of object | no | none |
uiPackage | object | no | none |
uiPatterns | string | no | none |
frontends | array of object | for a client-only project | none |
sites | array of object | no | none |
What each field means and what reads it:
docsis the root of the specification tree. Every record file under it holds one record page, with an explanation file beside it where one exists, and every other Markdown file is a document, unless its path is listed inunstructuredDocs. Whendocsis omitted, the tools use.litespec.glossarynames the project glossary.litespec model checkvalidates it and scans the pages against its rejected words and mannered terms.unstructuredDocslists the paths whose Markdown is navigation or prose rather than specification.behaviorDocsnames the behavior documentation root. It is required.recordsmaps a record type to its home folder where it differs from the default the model states. Keys come from the closed listproduct,goal,constraint,research,decision,requirement,problem,feature,actor,role,permission,journey,module,aggregate,rule,use-case,result,scenario,event,entry-point,external-system,reaction,job,notification,setting,integration-event,runbook,exception, andterm.testRootslists the directories that hold automated test source. The model builder reads scenarios from these roots.testResultsnames where the latest test run results live, so passing and failing proof is read from them.contractnames the committed OpenAPI document, solitespec model checkcompares each operation'sx-litespec-use-casewith its endpoint's mark.alertsnames the alert rule files or folders, in the YAML shape Prometheus rule files and Grafana alert provisioning share, so each rule'srequirementandrunbooklabels are checked and the alert inventory is rendered from them.operationsnames the deployment, proxy, host, and CI workflow files or folders that carryfollowsmarks in their#comments; below a named folder every file counts except Markdown documentation.checkResultsnames where drill and harness check results live, read beside the measured-check results undertestResults.sbomnames the bill of materials files or folders, SPDX or CycloneDX JSON, checked against the manifest pins, the admissions, anddependencies.licenses.apiClientnames the generated API client the frontends import, so route calls resolve to the use cases they reach. The model builder appendssrcto the configured path, and the reader takes operations only from the files the client generator writes (*.gen.ts), so a hand-written helper beside them is not an operation.surfacesnames the surfaces outsidepaths.frontendsthat invoke a use case: a command-line tool, a distributed server, a background host, or a reaction. Each entry holdsname,description, and an optionalpath.uiPackagedeclares the one shared UI package of the workspace. A workspace with no controlled web frontend omits it. See theuiPackageobject below.uiPatternsnames the workspace UI pattern catalog. A workspace that records no pattern decisions omits it.frontendslists every browser frontend the project ships. See the frontend entry below.siteslists the static public websites the consumer ships beside its application. Each entry holdsname,path, andgenerator, and the only generator isastro.
The stackConfig.dotnet Object#
| Field | Type | Required | Default |
|---|---|---|---|
modules | string | no | apps/api/src/*.Modules |
sharedKernel | string | no | apps/api/src/*.SharedKernel |
domain | string | no | apps/api/src/*.Domain under layer-projects, none otherwise |
infrastructure | string | no | apps/api/src/*.Infrastructure under layer-projects, none otherwise |
webapi | string or array of string | no | apps/api/src/*.WebApi |
worker | string or array of string | no | apps/api/src/*.Worker |
apiSolution | string | no | none |
templateStore | string | no | none |
What each field means and what reads it:
modulesis the code root the model builder reads: the modules project holding every module. A*in one segment expands to the first matching folder.sharedKernelnames the shared kernel project holding what every module builds on, where reasonless names are allowed. When omitted, the default applies andlitespec model checkreportsname-reason-missingfor every reasonless folder or type outside it.domainandinfrastructurename the Domain and Infrastructure projects the model builder reads, underlayer-projectsonly. Without that extension they default to none.webapiandworkername the web and worker host projects the model builder reads: one path, or a list for a backend with several hosts.apiSolutionnames the API solution the model builder reads. A consumer with no backend omitsapiSolutionand records the decision that it has none.templateStorenames the one C# file holding the notification template store: its top-level dictionary keys are the template keys, and its texts write parameters as{{PascalCaseName}}. When omitted, the template checks stay silent.
The uiPackage Object#
| Field | Type | Required | Default |
|---|---|---|---|
name | string | yes | none |
path | string | yes | none |
componentsJson | string | yes | none |
primitives | string | yes | none |
tokens | string | yes | none |
sourceLock | string | yes | none |
designContract | string | yes | none |
publicExports | array of string | yes | none |
What each field means and what reads it:
nameis the package name, such as"@shop/ui".pathis the package root, such as"packages/ui".componentsJsonis the registry configuration,primitivesis the directory that holds the registry source the pinned CLI copied in,tokensis the token stylesheet,sourceLockis the source lock, anddesignContractis the design contract.publicExportslists the entry points applications import, with at least one entry. A primitive the composites are built from is not one of them.litespec model checkreports a missingpaths.uiPackagewhen a controlled frontend is declared without one, and validates every listed file. A controlled frontend is one whose platform isreactorsvelte.
A frontends Entry#
| Field | Type | Required | Default |
|---|---|---|---|
name | string | yes | none |
path | string | yes | none |
platform | string | yes | none |
entryPoint | string | no | the entry points of its screens |
refusalDictionary | string | no | none |
routeSuite | string | no | none |
visualGoldens | string | no | none |
ui | object | no | none |
What each field means and what reads it:
nameis the frontend name, such as"web". It matches^[a-z][a-z0-9-]*$.pathis the frontend directory, such as"apps/web".litespec model checkreports a frontend whose directory does not exist.platformisreact,svelte,blazor, orandroid. Every entry declares it, so a frontend outside the controlled UI contract still declares that position instead of omitting the field. Areactorsveltefrontend is controlled and requires auiblock and the shared package. Ablazororandroidfrontend is skipped by the controlled UI check.entryPointnames the browser or device entry point the frontend serves, such as"entry-point/claimwick-app". The model builder reads the frontend's screens, use cases and records file through it. Without it, the entry points its screens name decide, and before any screen exists every browser entry point does.refusalDictionarynames the file or folder holding that frontend's refusal dictionary: one sentence per refusal code, keyed by the refusalcode. The model builder reads it forrefusal-sentence-missing, so a refusal a screen can reach is shown from that frontend's own words.routeSuitenames the file or folder holding that frontend's route suite. The model builder reads it for the route-suiteprovescheck, so the suite has a named subject instead of a convention.visualGoldensnames the folder holding that frontend's visual goldens. The model builder reads it for the same check, so a golden outside the named folder proves nothing.uiholdsprofile, which is required, andglobalCss, which is optional. The profile is one ofpublic-light,application-balanced, oradmin-dense. TheglobalCssvalue is the one stylesheet the frontend declares, and it imports the shared package tokens.litespec model checkchecks the profile value and the stylesheet path.
A sites Entry#
| Field | Type | Required | Default |
|---|---|---|---|
name | string | yes | none |
path | string | yes | none |
generator | string | yes | none |
The generator is astro.
A selectedExtensions Entry#
| Field | Type | Required | Default |
|---|---|---|---|
id | string | yes | none |
criterion | string | yes | none |
What each field means and what reads it:
idis the extension id in the pinned manifest, such as"locale".litespec model checkrefuses an id the pinned release does not ship and lists the known ids.criterionstates the criterion that was met, such as"The product ships in English and Dutch.".litespec/core/scope#record-selected-extensionsrequires the entry, andlitespec/core/scope#select-conditional-extensions-explicitlyrequires selecting an extension only when its criteria apply.
Placeholders and the Init Fill#
The template names the project as __PROJECT__ in paths and package names. litespec init fills every __PROJECT__ value with the --name value, or with the root folder name when --name is omitted; in an npm package scope such as @__PROJECT__/ui it writes that name in lowercase kebab case, because npm names are lowercase. After it writes the file it prints Next step: dotnet litespec model check. litespec model check treats a leftover placeholder as an error and names each one:
.litespec/project.json: template placeholder '__PROJECT__' is not filled [litespec/core/scope#select-a-size-a-shape-and-stacks]A preset without a controlled web frontend, such as blazor-client or android-client, declares no package that a frontend uses, so litespec init removes paths.uiPackage and paths.uiPatterns from the written file.
A Complete Example#
This example shows the file litespec init --preset dotnet-react --size small --name shop writes from the template and the dotnet-react preset. It ran against release 4.0.0. The preset selects shape server, stacks dotnet and react, and one react frontend web at apps/web.
{
"$schema": "https://litespec.dev/4.0.0/schemas/litespec-project.schema.json",
"project": {
"name": "shop"
},
"size": "small",
"shape": "server",
"stacks": [
"dotnet",
"react"
],
"reviewedLiteSpecVersion": "4.0.0",
"paths": {
"docs": "docs",
"behaviorDocs": ".litespec/behavior",
"unstructuredDocs": [],
"testRoots": [
"apps/api/tests"
],
"uiPackage": {
"name": "@shop/ui",
"path": "packages/ui",
"componentsJson": "packages/ui/components.json",
"primitives": "packages/ui/src/components",
"tokens": "packages/ui/src/styles/tokens.css",
"sourceLock": "packages/ui/ui-source-lock.json",
"designContract": "packages/ui/DESIGN.md",
"publicExports": [
"@shop/ui/floorplans"
]
},
"uiPatterns": ".litespec/implementation/patterns/catalog.json",
"frontends": [
{
"name": "web",
"path": "apps/web",
"platform": "react"
}
],
"sites": []
},
"stackConfig": {
"dotnet": {
"modules": "apps/api/src/shop.Modules",
"sharedKernel": "apps/api/src/shop.SharedKernel",
"apiSolution": "apps/api/shop.slnx"
}
},
"selectedExtensions": []
}The other three presets differ only in shape, stacks, frontends, and the shared package. dotnet-svelte selects shape server, stacks dotnet and svelte, and one svelte frontend web at apps/web. blazor-client selects shape client-only, stack blazor, and one blazor frontend app at apps/app, with no uiPackage and no uiPatterns. android-client selects shape client-only, stack android, and one android frontend android at apps/mobile/src/{ProjectName}.Android, with no uiPackage and no uiPatterns. The init page states all five presets. The records preset selects shape server, conformance records, and no stacks or frontends.
Validation Errors#
litespec model check validates the project record, the pinned release, the stacks, the extensions, and the frontends. The messages below are quoted from the validator. The schema check runs first, so a wrong type or an unknown field reports a schema problem before these messages appear.
| Mistake | Message |
|---|---|
| A placeholder is left in the file | .litespec/project.json: template placeholder '__PROJECT__' is not filled [litespec/core/scope#select-a-size-a-shape-and-stacks] |
| The installed release and the reviewed release differ | .litespec/project.json: reviewedLiteSpecVersion '3.0.0' does not match the installed LiteSpec tool release 4.0.0; install the reviewed release with 'dotnet tool update LiteSpec.Cli --version 3.0.0' and run 'dotnet tool restore', or re-review the contract and record 4.0.0 |
| The reviewed release is missing | .litespec/project.json: missing 'reviewedLiteSpecVersion'; the installed LiteSpec tool release is 4.0.0 |
| A stack id is unknown | .litespec/project.json: stack 'rails' is not a stack the pinned LiteSpec release ships [litespec/core/scope#select-a-size-a-shape-and-stacks] |
| A client-only project names a backend stack | .litespec/project.json: shape 'client-only' names backend stack 'dotnet'; a client-only project names no backend stack [litespec/core/scope#select-a-size-a-shape-and-stacks] |
| A server names zero or two backend stacks | .litespec/project.json: stacks name 0 backend stacks; name exactly one of dotnet [litespec/core/scope#select-a-size-a-shape-and-stacks] |
| An extension id is unknown | .litespec/project.json: extensions 'search' is not an extension in the pinned LiteSpec release; known ids are ai, audit, automation, bdd, cache, compat, concurrency, delegation, delivery, devices, efcore, integrations, jobs, layer-projects, lifecycle, locale, mcp, outbox, plans, stage, tenancy |
| A frontend declares no platform | .litespec/project.json: frontend 'web' declares no 'platform'; one of android, blazor, react, svelte is required [litespec/core/scope#select-a-size-a-shape-and-stacks] |
| A frontend names a stack the project does not select | .litespec/project.json: frontend 'web' platform 'react' is not a stack the project names in stacks [litespec/core/scope#select-a-size-a-shape-and-stacks] |
| A controlled frontend has no shared package | .litespec/project.json: 1 controlled frontend(s) and no 'paths.uiPackage'; the shared UI package every controlled web frontend composes is undeclared |
| A configured path does not exist | .litespec/project.json: paths.docs 'docs' does not exist; the page scan finds no record to check |
The last row stands for every configured path: the message names the field, the missing path, and the check that goes quiet. The docs root, the glossary, each frontend directory, each uiPackage file, and each frontend stylesheet follow this shape.
Notes#
The field lists follow schemas/litespec-project.schema.json and the consumer template. The init behavior follows apps/cli/src/LiteSpec.Cli/Init/InitCommand.cs. The validation messages follow apps/cli/src/LiteSpec.Cli/Consumer/ConsumerValidator.Project.cs and apps/cli/src/LiteSpec.Cli/Consumer/ConsumerValidator.Glossary.cs. The path defaults follow apps/cli/src/LiteSpec.Cli/Model/ConsumerConfig.cs. The presets are templates/presets/dotnet-react.json, templates/presets/dotnet-svelte.json, templates/presets/blazor-client.json, and templates/presets/android-client.json, read with templates/consumer/project.json. Example sections stay within 120 words; the project file carries no setting for the bound.