Skip to content

Language reference

Use this page to look up syntax after you understand the core model. For guided decisions and realistic examples, use the design guides.

A document contains one flow, state, or sequence diagram. The language-version header is optional; an omitted header selects language version 1.

diagram.kdiagram
kdiagram 1
diagram "System title" {
// flow statements
}
diagram.kdiagram
sequence "Scenario title" {
// sequence statements
}
diagram.kdiagram
state "Order lifecycle" {
entry: initial "Start"
pending: state "Pending payment"
done: final "Completed"
entry -> pending
pending -> done "authorize [approved]"
}

State diagrams support initial, state, final, junction, fork, and join. Kekonic Diagrams checks that there is exactly one initial pseudostate, initial has no incoming transitions, and final states have no outgoing transitions.

Line comments begin with //. Block comments use /* … */. Semicolons and commas may separate properties but are not required.

When several pictures share one topology (C4 context + containers, review deck + detail), elevate to a model with embedded view lenses instead of copying files. Requires kdiagram 2. Simple diagrams should stay as a single diagram { … } — no modeling ceremony. A standalone diagram { … } is one-shot sugar: nodes, groups, edges, layout, and presentation live together.

diagram.kdiagram
kdiagram 2
model "Storefront" {
customer: person "Customer"
platform: system "Commerce platform" {
description: "Lets customers check out and coordinates payment."
}
boundary commerce "Commerce platform" {
web: container "Web application"
api: container "API application"
}
stripe: external "Stripe"
view context {
include customer, platform, stripe
customer -> platform "Uses"
platform -> stripe "Charges"
layout { direction: TD }
}
view containers {
include customer, commerce.*, stripe
customer -> web "Browses"
web -> api "Places orders"
api -> stripe "Charges"
layout { direction: LR; groupLayout: compound }
}
}
Construct Role
model "Title" { … } Shared nodes, structural groups, and styles. No edges, layout, or presentation at this layer.
view name { … } Named lens: include / exclude, edges, layout, presentation, animation, edge-route policy.
include / exclude Selectors: bare id, prefix.* (group subtree or id prefix), or *.
diagram { … } One-shot form — co-located nodes, groups, edges, and presentation. Default for a single picture.

Edges are illegal in a multi-view model body (FM222). Put a -> b inside each view. Level of detail uses explicit summary nodes in the model (for example platform: system "…" in context, commerce.* in containers) rather than view-time collapse.

When --view or a host view is omitted, the compiler prefers a view named default, then main, else the first view in source order.

Target a lens with kdiagrams render file.kdiagram --view context, Studio’s view picker, or <k-diagram view="context" show-view-switcher>. One self-contained .kdiagram file per model — there is no cross-file import in this draft.

Worked example: Storefront — shared model with views. Design notes: Architecture diagrams.

diagram.kdiagram
id: kind "Visible label" {
subtitle: "Secondary line"
technology: "Runtime or platform"
description: "Longer supporting text"
note: "Compact annotation"
icon: shopping-cart
iconColor: #7c3aed
iconPaint: theme
shape: hexagon
scale: 1.15
minWidth: 140
maxWidth: 260
styles: [warning]
}

Only the ID and kind are required. An omitted label is derived from the ID. IDs are referenced by connections and must be declared before use.

subtitle: true displays the built-in kind subtitle. A quoted subtitle replaces it with authored text. shape changes geometry without changing semantic kind. icon: none removes a kind’s default icon.

  • Architecture: user, person, actor, participant, system, external, container, component, service, application, module, package, deployment
  • Infrastructure: server, database, cache, store, bucket, queue, topic, stream, gateway, loadbalancer, cloud, firewall, zone
  • Messaging: broker, event, command, message, worker, producer, consumer, dlq, job
  • Flow: start, end, process, task, subprocess, choice, decision, io, document, preparation, manual, connector, success, warning, failure
  • Modeling: table, entity, class, interface, aggregate, projection, policy
  • State and Git: state, initial, final, junction, fork, join, commit, branch, tag
  • Annotation: note, label, image, icon

C4 element kinds render with distinct type names: person (Person), system (Software System), external (External System), container (Container), component (Component). Keep one C4 level per diagram. Turn on presentation { showKindSubtitles: true } (or subtitle: true per node) so the type line is visible. description is the C4 body; technology is the tech tag. A database at container level is still a container with shape: cylinder. Kekonic Diagrams does not provide a C4 code (class) view. See Architecture diagrams.

Unknown kinds produce a warning and use generic defaults, which allows extension without a parser failure.

Use geometry directly when meaning does not map to a semantic kind:

rectangle, rounded, pill, circle, ellipse, diamond, hexagon, triangle, parallelogram, trapezoid, folded-document, cylinder, and boundary.

Common short aliases such as rect, diam, and hex normalize to their full shape IDs.

diagram.kdiagram
source -> target "Optional label" {
priority: high
labelPosition: end
icon: mail
iconColor: #16a34a
branch: yes
styles: [success]
}
Operator Relationship Reverse form
-> direct or synchronous flow <-
=> asynchronous event <=
~> eventual or signal flow <~
..> dependency <..
-x failure or rejection x-
-- association without an arrow
<-> bidirectional flow

--> is a dashed dependency in flow diagrams and commonly a reply in sequence diagrams. Edge chains are allowed: a -> b -> c. Properties on a chain apply to each generated edge.

Priority values are low, normal, and high. Label positions are start, middle, and end. Branch values are yes, no, and neutral; labels such as “yes” and “no” are also recognized.

On ERD relationships, cardinality sets crow’s-foot multiplicity (1:N, 0..1:1, 1:0..N, and similar IE forms, or Mermaid-ish ||--o{). identifying: true paints a solid identifying line; false paints a dashed non-identifying line. Foreign-key columns usually infer both — override only when inference is wrong. See Tables.

diagram.kdiagram
group app "Application" {
chrome: true
padding: normal
icon: boxes
arrange: stack
align: stretch
gap: normal
api: gateway "API"
service: service "Orders"
}

boundary, zone, and swimlane are group variants. Groups may contain nodes and nested groups. Top-level swimlane groups infer groupLayout: swimlane and direction: LR (override with groupLayout: flat if you only want membership boxes). Lane chrome uses a left header strip. See Control layout.

Arrangement values inside a region are flow, pack, and stack. A parent containing child regions may use stack, row, grid, or surround, with columns, rows, column, row, span, colSpan, and rowSpan for tracks. surround places exactly one nested hub group in the center and sibling nodes on a ring; use side: west|east|north|south on those nodes for cardinal arcs. Optional shape: hexagon|circle|ellipse|rounded|rectangle sets group chrome silhouette (default rectangle). chrome: false keeps a structural group in layout without painting its border or label. See Control layout for complete patterns.

table (and entity with columns) draws an ERD card. The structured columns { } block is the canonical form; a columns: ["id PK uuid", …] array of compact specs is also accepted.

diagram.kdiagram
customers: table "customers" {
note: "Account holder"
columns {
id: uuid PK
email: varchar(320) UK NN
credit_limit: numeric(10,2)
default_locale: text NN // en|es
}
}
orders: table "orders" {
columns {
id: uuid PK
customer_id: uuid FK NN -> customers.id
billing_address_id: uuid FK NN -> addresses.id
shipping_address_id: uuid FK -> addresses.id
}
}
order_items: table "order_items" {
columns {
order_id: uuid PK FK NN -> orders.id
line_no: int PK NN
}
}
line_taxes: table "line_taxes" {
columns {
order_id: uuid PK FK NN -> order_items.order_id
line_no: int PK FK NN -> order_items.line_no
tax_code: text PK NN
rate: numeric(10,2) NN
}
}
payments: table "payments" {
columns {
id: uuid PK
order_id: uuid FK UK NN -> orders.id
}
}
// Override inference when it is wrong:
customers.id -> orders.customer_id { identifying: false, cardinality: "1:N" }

name: type markers -> ref // comment

  • Type is a documentation label. Parameterized forms such as varchar(320) and numeric(10,2) are one type; commas inside () do not start a new column.
  • Markers: PK (also PRIMARY), FK (FOREIGN), UK (UNIQUE), NN (NOT NULL, NOTNULL, NOT_NULL). Order is free relative to the type.
  • FK target: -> table.column, or composite -> table.(col_a, col_b). ref / references are aliases of ->.
  • Comment: // after the column becomes muted secondary text on the row.
  • Table note: paints under the title.

An FK target creates a column-anchored crow’s-foot relationship automatically. You do not need a second edge unless you are overriding inference.

Source Parent end Child end Line
Nullable FK optional (0..1) many (0..N) dashed
NN FK mandatory (1) many (0..N) dashed
UK + FK 1 or 0..1 1 or 0..1 dashed
FK columns that are the child’s PK 1 or 0..1 1 (identifying 1:1) solid
FK column that is part of a composite PK 1 or 0..1 many solid (identifying)

Several FK columns that point at different columns of the same parent merge into one relationship. Several FKs that share the same parent column stay as separate edges (billing vs shipping) and fan out on the parent key row.

parent.column -> child.column { identifying: true, cardinality: "1:N" }

cardinality accepts 1:N, 0..1:1, 1:0..N, 1:0..1, and similar IE forms, or Mermaid-ish ||--o{. Authored identifying / cardinality win over inference. A label that is only cardinality is omitted from the drawing (the crow’s foot already says it).

Wrap tables in a group for a schema or bounded context. Prefer layout { groupLayout: compound }. See Data models for rendered examples.

Kekonic Diagrams does not compile indexes, check constraints, defaults, IDEF1X categorization, or migrate SQL. Many-to-many needs an explicit junction table. Use a column // comment or table note: for those facts.

diagram.kdiagram
layout {
direction: LR
arrange: row
density: normal
spacingScale: 1.1
groupLayout: compound
nodePlacement: balanced
considerModelOrder: true
edgeNodeSpacing: 24
edgeEdgeSpacing: 14
edgeLabelSpacing: 12
}
edges {
route: metro
crossings: smart
cornerRadius: 8
arrowheads: true
}
render {
theme: dark
shadows: false
roundedCorners: false
}
presentation {
title: auto
titleSubtitle: "Optional visible subtitle"
groupAccent: true
showKindSubtitles: false
showEndpoints: false
clampLabels: true
}

Top-level shorthand direction LR and density normal are also accepted. API options override source policy; source policy overrides built-in defaults. A worked custom palette with shadows and roundedCorners is on Themes.

Directions are LR, RL, TD, and BT. Density values are compact, normal, and spacious. Diagram-level arrange values are row, stack, and grid; they place ungrouped nodes and top-level regions in declaration order. Nested groups can define their own arrange policy. Node placement values are straight, balanced, and basic. Route values are straight, bezier, orthogonal, rounded, and metro: metro/rounded/orthogonal paint the laid-out corridor; straight uses a port-to-port chord when the line of sight is clear; bezier is an obstacle-aware cubic along that corridor. Crossing values are none, gaps, jumps, and smart.

diagram.kdiagram
style degraded {
--node-fill: #2a1f08
--node-stroke: #d69e2e
}
cache: cache "Redis" is degraded
api -> cache is degraded

Styles contain renderer variables. Apply them with is styleName or styles: [one, two]. Built-in semantic styles are success, warning, danger, error, muted, and info.

Sequence participants use node declarations. Messages appear in source order.

diagram.kdiagram
sequence "Request" {
autonumber
client: actor "Client"
api: service "API"
client -> api "request"
activate api
api --> client "response"
deactivate api
}

Sequence-only statements include activate, deactivate, create, destroy, note over, divider, autonumber, and structured fragments: alternate/else, optional, loop, parallel/and, critical, and break. See Sequence diagrams for working examples.

diagram.kdiagram
animation "Happy path" {
dim *
activate client
wait 250ms
flow client -> api -> database for 1.2s
pulse database for 600ms
loop
}

An empty block enables inferred playback. Authored cues include dim, activate, deactivate, pulse, flow, wait, parallel, and loop. See Tell a story.