Skip to main content
Semantic source is what you author. One aggregate per file, one file per thing: an entity, a lifecycle, an action, an automation, a role, a screen. YAML being nicer to read than JSON isn’t really the reason for it. The reason is that one thing lives in one file. An entity you can open, read top to bottom and review in a diff is a very different object from the same entity buried three thousand lines into a single document.

The shape of a file

Every file opens by declaring what it is. The first key is the aggregate kind, and its value is the key of that aggregate.
That first line is how the compiler knows what it’s reading. The directory layout is for you.

An entity

The same entity three ways: what you write, what it compiles to, and what the dotnet-vue generator turns that into.
The C# tab is trimmed: the real file carries a doc comment on every property, and the tracking fields written out in full. fields is a map keyed by field key. The key is the identifier the rest of the app refers to, and everything under it describes what that field is.
kind says what sort of thing the entity is: collection for records people create all day, config for a small reference list, settings for a single row of app-wide values. It changes how the app presents the entity, not how it stores it.

Field types

text, longtext, integer, decimal, money, boolean, date, datetime, email, url, phone, select, multiselect, reference, json, attachment. A field says what it is, and the type-specific keys follow from that: options on a select, currency on money, precision and scale on decimal, targetEntity on a reference.
That prints every property a field accepts and every type it can be, from the build you have installed. It’s the authoritative answer, and it’s shorter than this page.

A role

Roles are grants, entity by entity.
No inheritance, no wildcards. If you didn’t name an entity, this role can’t touch it. That’s what lets you read one file and know what the role can do without holding the rest of the app in your head.

A lifecycle

States and the transitions between them, over one field of one entity.
phase is the generic reading of a state, so a board or a chart can group states it has never seen before. terminal says nothing leaves this state.

An automation

Trigger, entity, effects.
A trigger can also name another app, which is how one app reacts to what another announces. The app being listened to is not changed and does not know:
See Apps working together.

The app file

One per app, holding everything no single aggregate owns: identity, theme, relations between entities, and the order things appear in.

Two halves of a workspace

Worth knowing, because it changes how much vocabulary you need.

Semantic

entities/, workflows/, roles/. A small vocabulary, all of it listed by cordango vocabulary with no arguments. You will rarely need more.

Block trees

views/. Screens are not modelled semantically yet, so these are still App Definition block trees. This is where cordango vocabulary block <kind> earns its place.
Ask for one block kind at a time. Asking for all of them defeats the point of the layer.

Formatting

Rewrites every .cordango.yaml file in canonical form: consistent key order, consistent quoting. Run it after hand-editing, so a diff shows a change in meaning instead of a change in whitespace.

What isn’t source

.cordango/, with the leading dot, is build output. It gets regenerated and it doesn’t belong in git. Anything you edit in there disappears on the next cordango build.