Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ The language is currently a proposal for Stack 1.0. No compatibility guarantee a
- [ADR-0004: Distribute shared editor language assets from the specification](./docs/decisions/0004-distribute-editor-language-assets.md)
- [ADR-0005: Separate provider icon namespaces from theme icons](./docs/decisions/0005-provider-icon-namespaces.md)
- [ADR-0006: Standardize protocol-neutral language intelligence](./docs/decisions/0006-standardize-language-intelligence.md)
- [ADR-0007: Let host configuration override theme palettes](./docs/decisions/0007-configured-theme-overrides.md)
- [Examples](./examples)
- [Conformance suite](./conformance)
- [`@stack-sh/language`](./packages/language)
Expand Down
14 changes: 11 additions & 3 deletions SPECIFICATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,8 @@ Identifiers match:

Identifiers contain between 1 and 64 ASCII characters. Keywords are recognized contextually. A word that matches a keyword may also be used where the grammar expects an identifier, although authors SHOULD avoid identifiers that make a declaration difficult to read. The lowercase ASCII form avoids quoting, normalization, and visually confusable references.

The `--` edge operator is recognized before bare identifiers. An identifier written in Stack source therefore MUST NOT contain two consecutive hyphens, even though each individual hyphen is otherwise an identifier character.

### 4.5 Strings

Strings are enclosed in double quotes. Source text may contain Unicode directly.
Expand Down Expand Up @@ -279,13 +281,19 @@ Failure to provide a required theme is a catalog or renderer implementation fail

Theme identifiers use the normal Stack identifier syntax and have no namespace. The first catalog pull request merged for an identifier registers it. A registered identifier MUST NOT be assigned to a different theme later, even if its original theme is deprecated or removed. This first-merged rule makes theme selection globally unambiguous without adding package or contributor names to source.

A requested theme that is not present in the installed catalog version produces warning `STK6001` and falls back to `default`, so the topology remains renderable.
A host MAY provide validated, user-configured theme overrides outside Stack source. An override has a normal Stack theme identifier, extends one of the required `default`, `light`, or `dark` themes from the installed catalog, and replaces only a subset of the nine semantic palette slots defined by the theme catalog contract. It cannot replace typography, node-kind visuals, connector geometry, icons, or asset provenance.

The override base is resolved from the installed catalog before any configured overrides are applied. A configured `default` that extends `default` therefore inherits the installed `default` theme without creating a self-reference. Configured themes do not extend one another.

Theme selection resolves the requested identifier from configured overrides first and the installed catalog second. A configured theme MAY intentionally use the same identifier as an installed or registered catalog theme; the first-merged rule applies only to public catalog registration. When the source omits a theme statement, the requested identifier is `default`, so a configured `default` becomes the host's effective default theme.

A requested theme that is absent from both configured overrides and the installed catalog version produces warning `STK6001` and falls back to the effective `default`, including a configured `default` override when present, so the topology remains renderable.

A theme may affect typography metrics and therefore exact element positions, but it MUST NOT change or hide nodes, groups, edges, labels, directionality, semantic kinds, or layout constraints. Every theme MUST preserve legibility, accessible contrast, and non-color distinctions required elsewhere in this specification.
A theme may affect typography metrics and therefore exact element positions, but it MUST NOT change or hide nodes, groups, edges, labels, directionality, semantic kinds, or layout constraints. Every catalog theme MUST preserve legibility, accessible contrast, and non-color distinctions required elsewhere in this specification. A host accepting user-configured colors SHOULD report contrast concerns, MUST preserve non-color distinctions, and MUST NOT silently rewrite the configured colors.

Each theme owns its unnamespaced icon collection. This is a one-to-many relationship: one selected theme resolves zero or more authored unnamespaced icon identifiers to theme-specific SVG assets. The same logical icon may therefore use different SVG artwork in `light`, `dark`, or any other theme. Namespaced provider icons are resolved from separate explicitly installed provider packs and preserve their provider artwork independently of the selected theme.

Stack source cannot define theme values, inherit from a network resource, or add per-element visual overrides. The catalog is explicitly installed or bundled by the renderer and MUST NOT be fetched solely because a theme identifier appears in source.
Stack source cannot define theme values, inherit from a network resource, or add per-element visual overrides. The catalog is explicitly installed or bundled by the renderer and MUST NOT be fetched solely because a theme identifier appears in source. Configured overrides are finite caller-owned data, require no network access, and contribute to the effective catalog revision recorded in render metadata.

## 7. Node Semantics

Expand Down
28 changes: 28 additions & 0 deletions conformance/valid/configured-theme-reference/expected.ir.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{
"schemaVersion": "1.0",
"languageVersion": {
"major": 1,
"minor": 0
},
"title": "Configured theme reference",
"themeId": "custom-theme",
"children": [
{
"type": "node",
"id": "app"
}
],
"nodes": [
{
"id": "app",
"label": "Application",
"kind": "service",
"iconId": null,
"detail": null,
"parentGroupId": null
}
],
"groups": [],
"edges": [],
"layout": null
}
7 changes: 7 additions & 0 deletions conformance/valid/configured-theme-reference/source.stack
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
stack 1.0

diagram "Configured theme reference" {
theme custom-theme

node app "Application"
}
30 changes: 30 additions & 0 deletions docs/decisions/0007-configured-theme-overrides.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# ADR 0007: Let host configuration override theme palettes

## Status

Accepted

## Context

Stack diagrams need reusable organization-specific colors without adding visual values to source, duplicating complete catalog themes, or allowing arbitrary CSS and assets. The public catalog also has a first-merged identifier rule, while users reasonably expect a local `default` definition to become their effective default.

Treating a configured `default` as an error would force a separate selection flag or a new source identifier. Letting configured themes extend one another would instead introduce ordering, recursion, and cycle handling that the initial palette-only feature does not need.

## Decision

Host configuration may supply named theme overrides. A configured name may intentionally match an installed catalog theme and takes precedence during theme selection.

Each override extends exactly one installed builtin theme: `default`, `light`, or `dark`. The host resolves every base from the installed catalog before registering any override, so `default` extending `default` is deterministic and non-recursive. An override may replace only the nine semantic palette colors. Typography, node-kind visuals, connector geometry, icons, and provenance remain inherited from the builtin base.

Omitting the source theme statement still requests `default`. If configuration contains a `default` override, that override is selected. Missing names retain `STK6001` and fall back to the effective `default`.

The theme catalog contract owns the portable override shape, validation, normalization, and effective revision algorithm. Native and browser hosts supply only validated caller-owned data to the pure engine. No theme name triggers filesystem or network discovery.

## Consequences

- Existing sources and hosts without theme overrides keep their current behavior.
- A user's configuration can deliberately change `default`, `light`, `dark`, or another installed theme without changing Stack source.
- Rendered appearance can depend on host configuration, so metadata must identify the effective catalog revision.
- User-configured colors are preserved exactly; hosts surface contrast concerns instead of silently rewriting them.
- Older hosts may reject the new configuration key, and documentation must identify the first supporting release.
- Changing the shipped builtin palettes remains a catalog change rather than a user-configured override.
2 changes: 1 addition & 1 deletion schemas/normalized-ir.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@
"$defs": {
"identifier": {
"type": "string",
"pattern": "^[a-z][a-z0-9_-]{0,63}$"
"pattern": "^(?!.*--)[a-z][a-z0-9_-]{0,63}$"
},
"iconIdentifier": {
"type": "string",
Expand Down