Knowledge Workspaces
An OKF knowledge workspace is a directory tree of Markdown documents, each carrying a
small YAML frontmatter block with a type: field drawn from a fixed vocabulary
(UmlClassDiagram, Concept, BpmnProcess, …) and — for diagram types — exactly one
` ``kuml ` fenced code block. `kuml workspace inspects, validates and renders such
workspaces.
The canonical entry point is the kuml workspace subcommand group:
kuml workspace init [--name <name>] [--mode knowledge|engineering] # scaffold a new workspace (see below)
kuml workspace info <dir> # mode + document inventory
kuml workspace validate <dir> # structural OKF conformance checks
kuml workspace render <dir> # render every ```kuml block to SVG/PNG
kuml workspace convert <src> --to okf|kts # convert between OKF notes and .kuml.kts scripts
init takes its target from the --output option (default ./<slug>), not a positional
directory argument; info, validate and render each take the workspace root as a
positional <dir>.
There are no top-level kuml validate/kuml render aliases for workspace operations —
kuml validate/kuml render operate on a single *.kuml.kts script, kuml workspace
validate/render operate on a whole document tree. Keep the two mental models separate.
kuml workspace init
kuml workspace init scaffolds a new workspace from a built-in template set — a
.kuml-workspace.toml marker plus starter documents — using the same scaffold engine as
kuml plugin init. The freshly generated workspace passes kuml workspace validate with
zero findings and renders cleanly out of the box.
kuml workspace init --name "My Club Bylaws" --mode knowledge
kuml workspace init --name "My Diagrams" --mode engineering --non-interactive
| Option | Meaning |
|---|---|
|
Human-readable workspace name. Used for the marker’s |
|
Template set to scaffold. |
|
Target directory. Defaults to |
|
Fail with a usage error instead of prompting for a missing |
|
Overwrite the target directory if it already exists and is non-empty. |
The knowledge-mode scaffold produces this tree:
<slug>/
├── .kuml-workspace.toml
├── index.md # type: KumlWorkspace
├── articles/01-introduction.md # type: Article
├── models/domain-classes.md # type: UmlClassDiagram
└── glossary/index.md # type: Glossary
kuml workspace convert
kuml workspace convert converts between OKF knowledge-workspace notes and bare
.kuml.kts engineering scripts (FT-7). The two formats share identical DSL text — an
OKF ` ``kuml ` block’s source is byte-for-byte a valid standalone `.kuml.kts body
(the same fact kuml workspace render relies on). "Convert" is therefore a text
wrap/unwrap plus frontmatter synthesis/stripping operation, not a model
re-serialization.
kuml workspace convert ./scripts --to okf --output ./vault/models # engineering -> knowledge
kuml workspace convert ./vault --to kts --output ./scripts # knowledge -> engineering
| Option | Meaning |
|---|---|
|
A single file or a directory. For |
|
Required. |
|
Output directory. Defaults to a sibling |
|
Overwrite an output file that already exists (default: skip it and report it under
|
|
Escalate |
|
Report output format, matching |
Directionality of losslessness
This is the one property to internalise before relying on convert for a real
workflow:
-
kts → okf → ktsis lossless for the DSL text. Wrapping adds only frontmatter and an H1 heading; extracting discards exactly that and nothing else, recovering the original script byte-for-byte (modulo trailing-newline normalisation — the wrapped block always carries exactly one trailing newline before the closing fence, regardless of how many the source had). -
okf → kts → okfis not lossless. The reverse round trip drops the original prose, the note’s owntitle:/tags:/other frontmatter, and any non-diagram document (Concept,Article,Glossary,KumlWorkspaceindex, …) entirely — only the diagram DSL survives. The regenerated note’stitle:and heading come from the diagram’s own name, not the original note’stitle:.
Keep prose-authored knowledge in the vault as the source of truth; use convert to
pull diagrams out for engineering-side editing, not as a way to shuttle whole documents
back and forth.
Type mapping and unmappable diagram kinds
--to okf evaluates each .kuml.kts script (the only way to know its concrete
diagram kind) and maps it to an OKF type: value. Most UML, C4, SysML 2, BPMN,
Blueprint and ERM diagram kinds have a vocabulary entry (see the type tables below).
A few UML 2.x and C4 diagram kinds do not (e.g. packageDiagram, objectDiagram,
deploymentDiagram, C4’s SystemLandscapeDiagram/DeploymentDiagram/DynamicDiagram)
— convert does not fabricate a vocabulary entry for these; it writes a deterministic
custom type: (e.g. UmlPackageDiagram) and reports OKF-C-003.
A script that declares multiple diagrams in one model only yields its first diagram
on --to okf — the same "first diagram" behaviour as kuml render.
Multi-block documents
Consistent with OKF-W-004 ("one file = one diagram"), a knowledge document with more
than one ` ``kuml ` block is split by `--to kts into <stem>-1.kuml.kts,
<stem>-2.kuml.kts, … (1-based) and reported as OKF-C-002.
Trust model
--to kts is pure text extraction and never evaluates anything — converting a
knowledge document to a script never runs its diagram code. --to okf evaluates every
.kuml.kts script to determine its concrete diagram kind, inheriting the same
arbitrary-code-execution trust model as kuml render / kuml workspace render: only
run it over scripts you already trust.
The .kuml-workspace.toml marker
An optional marker file at the workspace root declares its mode and OKF metadata instead
of leaving kuml workspace info to infer it:
[workspace]
mode = "knowledge"
name = "PZB Domain Model"
kuml-version = ">=0.30.0"
[okf]
version = "0.1"
vocabulary = "dev.kuml.okf@1.0"
strict = false
| Key | Meaning |
|---|---|
|
|
|
Free-form workspace display name. |
|
Declared kUML CLI version constraint (informational; not currently enforced). |
|
Declared OKF spec version the workspace was authored against. |
|
Declared |
|
Declared default for |
The parser is a small hand-rolled subset of TOML — comments (#), [section] headers,
and key = value lines with quoted or bare scalar values. It never throws: a malformed
or partial marker degrades to "field absent", falling back to the inference heuristic
above rather than aborting the scan.
The type: vocabulary
Every document’s frontmatter type: field is resolved against a fixed vocabulary
(current version: 1.0, 29 entries). Types with requiresKumlBlock = true must
contain exactly one ` ```kuml ` fenced code block; the others are prose/collection types.
UML
type: |
Requires a ```kuml block |
|---|---|
|
yes |
|
yes |
|
yes |
|
yes |
|
yes |
|
yes |
C4
type: |
Requires a ```kuml block |
|---|---|
|
yes |
|
yes |
|
yes |
|
yes |
SysML 2
type: |
Requires a ```kuml block |
|---|---|
|
yes |
|
yes |
|
yes |
|
yes |
|
yes |
|
yes |
|
yes |
|
yes |
BPMN
type: |
Requires a ```kuml block |
|---|---|
|
yes |
|
yes |
|
yes |
|
yes |
Knowledge (non-diagram)
type: |
Requires a ```kuml block |
|---|---|
|
no |
|
no |
|
no |
|
no |
|
no |
The vocabulary is checked into the codebase as a machine-readable contract at
kuml-docs/kuml-workspace/src/main/resources/okf/kuml-okf-vocabulary.json (id,
requiresKumlBlock, since, description per entry) and is kept in lockstep with the
OkfType enum by a dedicated contract test. An unrecognised type: value is not an
error by default — custom types are allowed — but see --strict-vocabulary below.
OKF finding codes
kuml workspace validate runs a fixed structural rule set:
| Code | Severity | Meaning | Blocks a Desktop save? |
|---|---|---|---|
|
ERROR |
Frontmatter missing or has no |
Yes |
|
WARNING (or ERROR under |
Unrecognised |
Yes |
|
ERROR |
A diagram type has no ```kuml block. |
No |
|
WARNING |
A document has more than one ```kuml block ("one file = one diagram"). |
No |
|
ERROR |
A relative Markdown link to a |
No |
|
WARNING |
The workspace root has no |
n/a — workspace-wide, never raised for a single document |
|
ERROR |
A |
n/a — render-only, not raised by validate |
The last column refers to kUML Desktop’s editable Knowledge Workspace document editor —
see "Editing documents in kUML Desktop" below. kuml workspace validate itself never
blocks anything; it only assigns severities.
kuml workspace convert (FT-7) reports its own, disjoint code space:
| Code | Severity | Meaning |
|---|---|---|
|
(skip, not a finding) |
A knowledge document has no |
|
WARNING (or ERROR under |
A document has more than one |
|
WARNING (or ERROR under |
The diagram’s kind has no OKF vocabulary entry; wrote a custom |
|
ERROR |
A |
OKF-W-002 findings include a did-you-mean suggestion (Levenshtein distance ≤ 3
against the vocabulary) when a close match exists, e.g. type: UmlClassDigram suggests
Did you mean 'UmlClassDiagram'?.
--strict-vocabulary
By default an unrecognised type: is a warning — custom, workspace-local vocabulary is
allowed. Pass --strict-vocabulary to kuml workspace validate to treat it as an error
instead (exit code 5, same as any other validation failure):
kuml workspace validate ./docs --strict-vocabulary
The finding code stays OKF-W-002 in both modes — only the severity changes — so a JSON
consumer parsing kuml workspace validate -o json output keys on a stable code space
regardless of strictness.
Trust model
kuml workspace render executes every ` ``kuml ` block’s Kotlin script source through
the same pipeline as `kuml render — this is arbitrary code execution by design, not
something introduced by workspace rendering. Only run it over workspaces you already
trust, exactly like kuml render itself.
Editing documents in kUML Desktop
Opening a Knowledge-mode workspace in kUML Desktop shows the usual document
tree | document | SVG-preview three-column layout, and the middle column is editable.
Every document has an independent Read / Edit toggle (a small segmented control
above the document, or a double-click on the rendered prose to jump straight into Edit;
Esc returns to Read as long as the buffer has no unsaved changes). The raw Markdown
editor is the same RSyntaxTextArea widget the single-file script editor uses — full
Undo/Redo and Ctrl+F find/replace work identically.
The header above the document also carries the type: and title: frontmatter fields
as first-class controls (a dropdown listing the full type: vocabulary — see
"The type: vocabulary" above — and a text field), so retyping YAML by hand is never
required for the two fields every OKF document has. Changing either splices the
corresponding line into the in-memory buffer directly — the rest of the frontmatter
(comments, unrelated keys, their order) is left byte-identical.
The save gate
Saving (Ctrl+S, or the Save button that appears once a document has unsaved changes) does not write whatever is in the buffer unconditionally. A persistent banner above the document — never a pop-up dialog, so it can’t be dismissed and forgotten — shows every current OKF finding (see "OKF finding codes" above) for the buffer, and exactly two of them refuse the save outright:
| Code | Why it blocks |
|---|---|
|
Frontmatter missing or has no |
|
An unrecognised |
There is deliberately no "save anyway" override for these two — the fix is one
click away, and a workspace-local document silently drifting out of OKF conformance
serves no one. Every other finding (OKF-E-003 no diagram block yet, OKF-W-004
multiple diagram blocks, OKF-E-005 a broken link) is shown as a warning in the same
banner but does not block the write: a document may legitimately point at a file
that’s about to be created next, or be saved mid-edit while its diagram block is being
cut and pasted back in.
Saving is atomic (write to a temporary file in the same directory, then rename over the
original) and re-validates the buffer immediately before writing — the same
kuml workspace validate rule set the CLI runs, invoked on exactly the one document
being saved. A successful save re-parses only that file and updates the workspace’s
in-memory document set and cross-link index accordingly; it never re-scans the whole
workspace tree, and — same as kuml workspace render — it never introduces a second
trust prompt: opening the workspace is still the only gate for evaluating a
` ```kuml ` block’s script.