Grid · Section

Language

The six axes, BNF, and worked examples

Specification

The expression language.

Lifted from @/theory/grid-expression-language, locked 2026-04-08.


The grid expression language is the surface that humans and AI (residents) both speak when they want to do anything to a grid. It is not SQL, not Python, not a query DSL bolted onto a database. It is the language Grid programs are interrogated, mutated, and observed in. The same evaluator runs an expression typed at a terminal, an expression embedded in an attention cell, and an expression that defines a capability slice.

Design discipline (locked)

The grammar is designed for completeness, not coverage. The test is not "does this verb match a scenario we listed" but "is the algebra closed under composition such that any reasonable scenario reduces to it." If a scenario cannot be expressed by composing the six axes below, that is a real hole, the algebra grows by exactly the missing axis, never by a new feature-flag verb.

The six axes (closed set)

1

SELECT

pick a set of cells out of the grid

2

PROJECT

render the selection in a chosen shape

3

FILTER

narrow a selection by a predicate

4

MUTATE

write, supersede, move

5

OBSERVE

react to changes over time

6

COMPOSE

pipe one expression's output into another's input

Every other operation is a combination of these. fetch is SELECT(addr) PROJECT(full). trace is SELECT(history-of addr) PROJECT(line). diff is SELECT(a) compared-with SELECT(b). count is SELECT PROJECT(count). The grammar freezes the six axes and nothing else.

Grammar (BNF)

expression := pipeline
pipeline := stage ( "|" stage )*
stage := select | mutate | observe
select := "study:" target
( "where:" predicate )?
( "as:" projection )?
mutate := write | move
write := "write" address
"type:" typename
"body:" body-string
( "by:" identity )?
move := "move" address "to" address
observe := "watch" select-or-pipeline
target := address
| glob
| refs-of
| type-query
| history-of
refs-of := "refs-of:" address
history-of := "history-of:" address
type-query := "type=" typename
predicate := atom ( ("and"|"or") atom )*
atom := slot-pred | type-pred | address-pred | ref-pred
| "not" atom | "(" predicate ")"
slot-pred := "slot:" slotname op value
type-pred := "type=" typename
op := "=" | "!=" | "<" | ">" | "<=" | ">="
| "contains" | "matches"
projection := "full" | "line" | "compact" | "summary"
| "addresses" | "types" | "json" | "count"
address := "@/" segment ( "/" segment )*

Operator note: contains and matches accept barewords on their right-hand side. where: slot:title contains widget works without quoting widget. Quoted strings are also accepted for values that need spaces or special characters.

The @, &, ?, :, =, #, + markers above are the seven sigils. See Sigils for the canonical reference on each one.

Examples

Each of these parses + round-trips against the real evaluator.

Selection

1. Single cell, full body, the default projection.

study: @/crm/contacts/cameron-silva

2. Glob across a subtree.

study: @/crm/interactions/2026-04-*/*

3. Reverse-ref selection (zero body reads), every cell that references this contact.

study: refs-of: @/crm/contacts/cameron-silva

4. Type-indexed selection (no glob).

study: type=interaction

Projection

5. Render as line digest, one row per cell.

study: type=interaction as: line

6. Count projection, cheap probe of cardinality.

study: type=interaction where: slot:promised < today as: count

7. Address projection, cheap navigation without reading bodies.

study: refs-of: @/crm/contacts/cameron-silva as: addresses

Filter

8. Predicate with slot match against today.

study: type=interaction where: slot:promised < today

9. Composite predicate (and / or).

study: type=interaction where: slot:promised < today and slot:direction = outbound

10. Parens + negation.

study: type=contact where: not (refs @/crm/accounts/acme)

History

11. Every supersession of one cell, projected as a line digest. git log for cells.

study: history-of: @/crm/contacts/cameron-silva as: line

Compose

12. Pipeline: select, then filter that result, then project.

study: type=interaction | study: where: slot:promised < today as: line

Mutate

13. Write a new cell.

write @/crm/contacts/new-person type: contact body: name: jane doe, role: cto

14. Move.

move @/crm/contacts/old-name to @/crm/contacts/new-name

move is canonical in the grammar. The executor is deferred by design: move reduces to a write at the destination plus a tombstone at the source, both of which already work via write and delete. Until the executor lands, compose those two stages directly.

Observe

15. Watch, wrap any select-or-pipeline. Re-evaluates whenever a write could change the result.

watch study: type=interaction where: slot:direction = inbound

What falls out of the algebra (not separate features)

The CLI's surface area is much larger than its verb count suggests, because the grammar is closed under composition. A few capabilities that are not implemented as separate features:

  • Live customer-support inbox in a terminal: watch study: type=interaction where: slot:direction = inbound
  • git log for cells: study: history-of: @/crm/contacts/cameron-silva as: line
  • See the grid the way another identity sees it: grid as alice 'study: @/', spatial capability becomes a one-flag UX feature.
  • Query your own terminal history with grid expressions: study: type=repl-history where: slot:identity = ant as: line
  • The access-control configuration is itself queryable: study: type=capability, the security surface is the same surface as the data surface.

We use cookies to analyze site traffic and improve your experience. By accepting, you consent to the use of cookies for analytics and advertising purposes.