Skip to content
Open
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

Large diffs are not rendered by default.

6 changes: 6 additions & 0 deletions bun.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions docs/agent-instructions/describe.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,12 @@ of writing guesses. Optional fields need content only when they add meaning.

| Command | Target | Options |
| --- | --- | --- |
| `groma edit <id>` | an element ID: actor, external system, system, container, or component | `--title`, `--description`, `--overview`, `--technology` |
| `groma edit <id>` | an element ID: actor, external system, system, container, or component | `--title`, `--description`, `--overview`, `--technology`, `--icon`, `--colour` |
| `groma edit <draft-id>` | a draft ID | `--title`, `--overview` |
| `groma edit project` | the word `project`, meaning the project record | `--title`, `--description`, `--overview` |

`--title` renames the record; its ID stays. An empty `--description` or
`--technology` value removes that field, and an empty `--overview` clears the
`--title` renames the record; its ID stays. An empty `--description`,
`--technology`, `--icon` or `--colour` value removes that field, and an empty `--overview` clears the
body. `groma view` has no `project` target: the project record is
`<groma-root>/project.md`. Read that file, and change it only through
`groma edit project`.
Expand Down
2 changes: 1 addition & 1 deletion docs/agent-instructions/inspect.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ add descriptions, actors, flows, groups, or relationship rows.
| | a draft ID | Prints the draft's outcome and the elements it touches. |
| | an exact repository-relative source file | Prints the owning component's ID, kind, title, and parent, the file connections of map relationships split into incoming and outgoing, and the command for the owner's complete record. Rows between files of one component are not listed; `groma view <owner-id> --plain` lists relationships that name the owner element. |
| `groma scanner list` | none | Lists the configured scanners and whether each is ready. |
| `groma lint` | none | Pages possible duplicate logic from fresh scanner evidence. Findings are review questions: they are not relationships and do not merge components. |
| `groma lint` | none | Pages possible duplicate logic from fresh scanner evidence, then each element whose icon no installed pack resolves. Findings are review questions: they are not relationships and do not merge components. |

A relationship line reads `source -> target | description | technology`, with
a trailing `| draft` on a draft relationship. The overview lifts each end to
Expand Down
3 changes: 2 additions & 1 deletion docs/agent-instructions/structure.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,8 @@ combine instead collects the absorbed components' Code references on the
surviving component.

Combined records must have the same kind and parent. Absorbed records cannot
have body content, concept-addressed relationships, a group, or technology.
have body content, concept-addressed relationships, a group, technology, an
icon, or a colour.
The children a combine absorbs directly cannot have body content either, so a
system combine refuses a described container while a described component two
levels down relocates with it. A component move requires an empty body; a
Expand Down
4 changes: 3 additions & 1 deletion docs/architecture-findings.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@
Run `groma lint` to check for architecture issues. The first rule reports possible
duplicate logic, with operation names and source file:line locations. It uses
current evidence from configured, installed scanners and respects project
exclusions. It does not write architecture records or change scanner selections.
exclusions. A second rule lists each element whose `icon` is neither an icon of
an installed pack nor an emoji. The command does not write architecture records
or change scanner selections.

The command exits with code 1 when it finds issues or a scanner fails, and 0
otherwise. An empty result applies only to the available scanner evidence;
Expand Down
15 changes: 15 additions & 0 deletions docs/component-markdown.md
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,8 @@ groma.md-only fields live together under `groma`:
| `draft` | no | ID of the draft record this concept belongs to or that touches it. |
| `group` | no | Readable name of a hand-authored sibling cluster. |
| `technology` | no | Free text naming implementation technology, comma-separated. |
| `icon` | no | An installed icon name (optionally `pack-id:name`) or one emoji. |
| `colour` | no | Theme-independent accent: red, orange, amber, yellow, green, teal, cyan, blue, indigo, violet, purple, pink, brown, grey, or `#RRGGBB`. |
| `code` | no | Scanner-produced source evidence. |

There is no `kind` field. The standard `type` carries the C4 type, and the
Expand Down Expand Up @@ -444,3 +446,16 @@ TypeScript, NestJS, and PostgreSQL.

The live [groma.md system](../groma/systems/groma/system.md) and
[MVP draft](../groma/drafts/mvp.md) are a complete package example.

## Element appearance

`groma edit <id> --icon <name> --colour <name>` and the web details form
set the optional `groma.icon` and `groma.colour` fields. Empty values remove
them. Scans preserve both fields. These are Groma presentation semantics on
the existing C4 element, not C4 types or OKF requirements.

A colour name and its `#RRGGBB` value are the same colour. `groma edit
--combine` refuses to absorb a record that has an icon or a colour, as it does
for a group or technology. A revision comparison reports a changed icon or
colour as a modification of its component.
See [icon packs and colours](icons.md) for drawing, installation and publishing.
90 changes: 90 additions & 0 deletions docs/icons.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
# Architecture icons and colours

Give any architecture element an icon and a fixed accent through its details
form or the CLI. These are Groma presentation fields on the existing OKF
concept, not C4 types or additional architecture boundaries. Ordinary Markdown
readers retain the concept's title, prose, links and readable field values.

```sh
groma plugin add @groma/icons-architecture
groma edit storage --icon architecture:database --colour blue
groma edit storage --icon "📦" --colour "#397ed1"
groma edit storage --icon "" --colour ""
```

Colours accept the names documented in [the Markdown contract](component-markdown.md)
or six-digit hexadecimal RGB. An accent keeps its colour in light, dark and
blueprint themes and draws the element's outline. The element's surfaces are
the theme's paper mixed with the accent, and its title is the accent mixed
toward the theme's text colour, so titles stay readable on those surfaces in
every theme. The legend below the hierarchy lists each colour in use with
the number of elements that have it; a name and its hexadecimal value are the
same colour.

Icon names resolve through installed packs in configured order. Use `pack:name`
to select a particular pack. An unknown name draws no icon and `groma lint`
reports the element and name. A resolved pack icon travels with the map as its
SVG, so an exported page or a cover shows it without the pack and without
network access. An emoji needs no pack: the map draws it as text in the
reader's own emoji font. Covers show pack icons only, because the cover
renderer has no emoji font; the room of a hidden emoji stays, so a building's
name sits one line lower and a system's or container's name slightly right of
centre. The details panes list the icon's name, or the
emoji, and the colour; the web pane also draws a pack icon beside the title.

## Make a pack

A pack is a normal npm package with SVG files and this package.json metadata:

```json
{
"name": "my-architecture-icons",
"version": "1.0.0",
"files": ["icons"],
"groma": {
"icons": {
"id": "my-icons",
"icons": { "database": "./icons/database.svg" }
}
}
}
```

The pack id and icon names use lowercase kebab-case. Each value names an SVG
file inside the package. Use self-contained SVG with a viewBox, explicit
colours, and vector shapes; external files and fonts are not bundled. A pack
declares no entry: Groma reads only the SVG files it declares, as images, and
runs no code from it.

Install a development pack with `groma plugin add ./path/to/pack`. An npm or
pinned Git pack is installed like any plugin package, so the dependencies its
package.json declares are downloaded too, with install scripts disabled:
`groma plugin add my-architecture-icons@1.0.0` or
`groma plugin add git+https://example.com/icons.git#v1.0.0`.
Selections live in the `icons` array of `<groma-root>/plugins.json`, in the
order they answer an icon name that names no pack. A pack id cannot repeat the
id of another pack, a scanner or a work source:

```json
{ "scanners": [], "workSources": [], "icons": [
{ "id": "my-icons", "source": "my-architecture-icons@1.0.0" }
] }
```

`groma plugin list`, `remove`, `install` and `update` manage the selection;
Settings lists installed icon packs alongside scanners and work sources.

## Publish

Publish a third-party pack using `npm publish --access public` after choosing
its package name, version and licence. Include every declared SVG in `files`.

The official pack is `plugins/icons/architecture`. It supplies database, queue,
cache, browser, mobile-app, service, scheduler, file-store, mail, identity,
gateway and search. Its build function copies the manifest, SVGs and project
licence; the existing scanner release workflow stages it as `icons-architecture`
on each host, carries it through assembly and publishes it with the scanner
packages. It needs no platform-specific build. Follow the existing
[release procedure](scanners/publishing.md), bumping its version when its
contents change. Publication requires the same npm access or trusted-publisher
configuration as other official packages.
4 changes: 4 additions & 0 deletions docs/scanners/publishing.md
Original file line number Diff line number Diff line change
Expand Up @@ -143,3 +143,7 @@ home and only Git on PATH, checks useful local facts, repeats the scan and
compares source bytes. The JavaScript harness rejects network fetches.
This is evidence for the exercised host, not a claim of testing every target.
See [fresh-checkout validation](fresh-checkout-validation.md).

The release also stages and publishes the platform-independent
`@groma/icons-architecture` pack. See [icon packs](../icons.md) for its manifest,
assets, and third-party publishing contract.
13 changes: 7 additions & 6 deletions docs/scanners/setup.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@

`<groma-root>/plugins.json` explicitly selects project plugins. A missing file
selects none. No plugin is loaded just because its package or CLI is installed.
The file has one section per kind: `scanners` and `workSources`. This revision
supports at most one work source. Plugin ids are lowercase kebab-case, and one id
names one plugin across both sections. `exclude` and `useGitignore` apply to
scanners at the top level.
The file has one section per kind: `scanners`, `workSources` and `icons`. This
revision supports at most one work source. Plugin ids are lowercase kebab-case,
and one id names one plugin across all sections. `exclude` and `useGitignore`
apply to scanners at the top level.

```json
{
Expand All @@ -21,7 +21,8 @@ scanners at the top level.
```

Scanner entries require `id`, `source`, and `include`, and may contain `settings`
and `exclude`. Work-source entries contain only `id` and `source`. Sources use
and `exclude`. Work-source and [icon-pack](../icons.md) entries contain only
`id` and `source`. Sources use
an exact npm `package@version`, a local `./path`, or a
`git+https://repository#tag-or-commit`; adding a bare npm name selects a compatible
stable release and stores its exact version. Git tags are pinned to a commit.
Expand All @@ -34,7 +35,7 @@ groma plugin update backlog
groma plugin remove backlog
```

These commands manage both kinds; scanner commands remain available for scanner
These commands manage every kind; scanner commands remain available for scanner
setup, discovery, readiness, and existing scanner selections. Web and terminal
settings group selections by kind. Package availability and readiness are
separate: a missing package needs restoration; an incompatible Groma version
Expand Down
17 changes: 17 additions & 0 deletions groma/systems/groma-md/containers/cli/components/icon-packs.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
---
type: C4 Component
title: Icon packs
status: stable
groma:
id: icon-packs
parent: cli
code:
- scanner: typescript
file: src/icon-packs.ts
- scanner: typescript
file: plugins/icons/architecture/build.ts
symbol: buildPackage
description: Loads selected SVG icon packs and resolves element icons for maps and lint
---

Reads the icon packs selected in plugins.json through the shared package resolver and reports what this computer has of each. Resolves qualified or unqualified names to embedded SVG images, leaves an emoji as text for each viewer to draw, and reports unresolved names to lint. Plugin management adds, updates, removes and restores packs like every other plugin kind. Element metadata remains in ordinary architecture Markdown; image data exists only in the loaded view. The build script of the official architecture pack copies its manifest, SVG artwork and licence into the release staging directory.
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,4 @@ groma:
description: Builds shared settings state and applies plugin actions by kind
---

Combines scanner discovery and readiness with the explicitly selected work source. The browser and terminal settings screens group plugins by kind and use the same add, update, remove and restore operations. Scanner recommendations remain scanner-specific.
Combines scanner discovery and readiness with the explicitly selected work source and icon packs. The browser and terminal settings screens group plugins by kind and use the same add, update, remove and restore operations. Scanner recommendations remain scanner-specific.
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ groma:
description: Selects, resolves, installs and restores project plugins by kind
---

Reads explicit plugin selections from plugins.json and manages their package lifecycle. Resolves npm, Git and local sources for scanners and work sources; stores pinned sources and scanner defaults. Plugin commands, scanner commands and settings share one add, remove, update and restore operation addressed by plugin id. Resolving a package never runs plugin code; work-source loading checks host compatibility before it imports the adapter and asks its readiness.
Reads explicit plugin selections from plugins.json and manages their package lifecycle. Resolves npm, Git and local sources for scanners, work sources and icon packs; stores pinned sources and scanner defaults. Plugin commands, scanner commands and settings share one add, remove, update and restore operation addressed by plugin id. Resolving a package never runs plugin code; work-source loading checks host compatibility before it imports the adapter and asks its readiness. An icon pack has no code to run: its package resolves to the SVG file of each icon it declares.

## Relationships

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ groma:
- scanner: typescript
file: src/source-index.ts
symbol: sourceIndex
- scanner: typescript
file: src/element-appearance.ts
group: Architecture records
description: Builds the in-memory C4 model from stored Markdown records
---
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ groma:
file: src/lint-command.ts
symbol: registerLintCommand
group: Project commands
description: Reports possible duplicate logic from current scanner evidence
description: Reports possible duplicate logic and unknown icon names
---

Registers groma lint and checks current scanner evidence for possible duplicate logic. Reports findings and scan failures through the command exit status without changing saved architecture.
Registers groma lint. Checks current scanner evidence for possible duplicate logic and lists the elements whose icon no installed pack resolves. Reports findings and scan failures through the command exit status without changing saved architecture.
4 changes: 3 additions & 1 deletion groma/systems/groma-md/containers/export/components/map.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,10 @@ groma:
file: src/viewers/web/iso/painting/glow.ts
- scanner: typescript
file: src/viewers/web/iso/painting/layer-planes.ts
- scanner: typescript
file: src/viewers/web/iso/painting/appearance.ts
group: Map drawing
description: Paints the browser map as SVG buildings, routes and labels
---

Draws the map surfaces, buildings, labels, and connections as SVG. Applies selection and task emphasis.
Draws the map surfaces, buildings, labels, and connections as SVG. Applies selection and task emphasis. Draws each resolved icon, a pack's SVG image or an emoji as text, and fixed authored accent colours through the same painting functions used by the browser and cover exporter.
5 changes: 4 additions & 1 deletion groma/systems/groma-md/containers/export/components/shell.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,11 @@ groma:
file: src/viewers/web/chrome/credits.ts
- scanner: typescript
file: src/viewers/web/chrome/frame.ts
- scanner: typescript
file: src/viewers/web/chrome/colour-legend.ts
symbol: paintColourLegend
group: Browser controls
description: Browser toolbar, side panels and keyboard shortcuts
---

Shows the map toolbar and side panels. Handles keyboard shortcuts, panel expansion and empty map states, and measures the frame the visible chrome leaves for the camera.
Shows the map toolbar and side panels. Handles keyboard shortcuts, panel expansion and empty map states, and measures the frame the visible chrome leaves for the camera. The map legend lists authored accent colours and the number of elements using each, and hides those rows when no colours are assigned.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
"workspaces": [
"packages/*",
"plugins/scanners/*",
"plugins/icons/*",
"plugins/work-sources/*"
],
"bin": {
Expand Down
12 changes: 12 additions & 0 deletions plugins/icons/architecture/build.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { cp, mkdir } from 'node:fs/promises'
import path from 'node:path'
import { fileURLToPath } from 'node:url'

/** Platform-independent SVG package, staged alongside the official scanner packages. */
export async function buildPackage(output: string): Promise<void> {
const source = fileURLToPath(new URL('.', import.meta.url))
await mkdir(output, { recursive: true })
await cp(path.join(source, 'icons'), path.join(output, 'icons'), { recursive: true })
await cp(path.join(source, 'package.json'), path.join(output, 'package.json'))
await cp(fileURLToPath(new URL('../../../LICENSE', import.meta.url)), path.join(output, 'LICENSE'))
}
1 change: 1 addition & 0 deletions plugins/icons/architecture/icons/browser.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions plugins/icons/architecture/icons/cache.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions plugins/icons/architecture/icons/database.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions plugins/icons/architecture/icons/file-store.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions plugins/icons/architecture/icons/gateway.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions plugins/icons/architecture/icons/identity.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions plugins/icons/architecture/icons/mail.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Loading