# How the language works

> A .esk file compiles to definition records (IR-D) and nothing else. No construct has semantics of its own: every line becomes one or more of the ten kernel records, every record renders as an English sentence, and the whole thing is checkable without running anything. This page walks through Pebble, the smallest organization that has been run.

Canonical: https://endoskeletal.com/language/
Last updated: 2026-09-28

## Module header and vocabulary

*pebble.esk*

```esk
module pebble.core @ 1.0.0
  uses esk.kernel @ 1
  import lib.org         @ 2.* as org
  import lib.governance  @ 1.* as gov
  import lib.finance     @ 1.* as fin
  import lib.evidence    @ 1.* as ev
  import lib.realization @ 1.* as rz
  import lib.agents      @ 1.* as ag
  import lib.econ        @ 1.* as econ

vocabulary ws @ 1.0.0 {
  availability(r : Capability)     : claim   "availability of realization r over the observed window, in percent"
  price(c : Capability)            : claim   "per-instance monthly price of an offered compute capability"
  price-change(c : Capability)     : claim   "an offered capability's price changed"
  ScaleRequest(n : Number, projected : Quantity<currency>) : entity  "a request to run n instances"
  MigrationProposal(candidate : Capability) : entity "an Architect proposal to rebind WebService"
  Scale(n : Number)                : event external  "change the instance count of a compute realization"
  LoadTest(n : Number, rate : Number) : event external "drive synthetic load against a sandbox realization"
}
```

`uses esk.kernel @ 1` pins the kernel. Imports bind a version range; the lockfile pins the exact content hash each range resolved to. A **vocabulary** declares the organization's terms and what sort each one is: a `claim` can be T, F, N or B; an `entity` is a kind of thing; an `event external` is something done to the world, which will always need authorization.

## Scope, persona, positions

```esk
scope Pebble : org.Organization {
  persona PebbleCo
  use gov.Constitution(founders = { Owner }, amendBy = Owner, quorum = 1) as Const

  position Owner      : org.Owner   { cardinality 1  eligible when self is org.Person }
  position Operations : org.Officer { cardinality 1  eligible when self is ag.Autonomous }
  position Architect  : org.Officer { cardinality 1  eligible when self is ag.Autonomous
                                      incompatible with Operations }
  position Engine     : rz.Engine   { cardinality 1 }
```

The scope acts through its persona, `PebbleCo`. Positions carry cardinality, eligibility (by party kind: a person, an autonomous agent, a program, a model-based party) and incompatibilities. The engine that runs the organization is itself a position, so its authority is granted and checked like anyone else's.

## Intents and required capabilities

```esk
intent Available  : org.SLO { maintain holds ws.availability(WebService) >= 99.5 %  hard }
intent Responsive : org.SLO { maintain holds ws.p95-latency(WebService)  <= 300 ms  hard }
intent Frugal                { avoid holds ws.cost(WebService) > 500 USD per month  soft weight 0.5 }

requires capability WebService {
  operation serve(request : Entity) -> response : Entity
  operation scale(n : Number) -> outcome : Claim
  guarantee eventually holds ws.Served(request)
  property  availability  >= 99.5 % per day
  property  p95-latency   <= 300 ms
  property  cost          <= 500 USD per month
  for Available, Responsive, Frugal
}
```

Intents say what the scope wants. `hard` intents must be covered by a responsible position or a required capability; `soft` ones carry weights or priorities for comparisons. A required capability is a contract: operations, what it may assume, what it must guarantee, and properties with thresholds. Quantities carry dimensions; comparing `ms` to `USD` is a compile error.

## Norms and patterns

```esk
use rz.RealizationEnvelope(holder = Operations, requirement = WebService, operation = ws.Scale,
      admissible = a.n <= 5 and holds ws.price(bound(WebService)) * a.n <= 500 USD per month) as OpsEnvelope

use org.Approval(approver = Owner, subject = ws.ScaleRequest,
      threshold = s.n > 5 or s.projected > 500 USD per month,
      deadline = 1 business-days, escalateTo = Owner) as ScaleApproval

norm OwnerBinds { power of Owner to bind | unbind _ about WebService   level collective }

norm DailyCheck {
  obligation of Operations to persona
  when occurred tick(t) and t.boundary = "day"
  aim within 2 h: occurred derive(ws.daily-status(t.day)) by Operations
  not tradeable
}
```

A norm has a bearer, a deontic line, a condition (`when`), an aim, and optionally an or-else, a level, a source, a priority and tradeability. `use` instantiates a library pattern: `rz.RealizationEnvelope` expands to one power norm, `org.Approval` to four (the power to decide, the duty to decide by a deadline, the escalation, and a gate that prohibits executing before approval). Every expanded record keeps `expandedFrom`: the pattern, package, version and use site.

Note `holds ws.price(…)` inside the envelope. The price claim comes from the provider, whose statements start at N under Pebble's trust policy until two daily bills agree. Until then the envelope admits nothing and Operations has to ask.

## Information rules

```esk
  use ev.TrustPolicy(source-kind = ev.Monitor,  base = T) as MonitorTrust
  use ev.TrustPolicy(source-kind = ws.Provider, base = N,
        promote-when = ev.ConsecutiveDailyObservations(2), vocab = { ws.price, ws.price-change }) as ProviderTrust
}
```

Trust policies decide what status a claim gets from its source. Your own monitors are trusted; a provider's price page is not, until your bills corroborate it. A model-based party's output gets N by default in every reference organization.

## What the compiler produces

### Verbalization

> In Finance: when a spend request *r* occurs whose amount exceeds 10,000 USD, the Treasurer is obliged to *r*'s requester to decide to approve or reject *r* within 2 business days; otherwise the norm SpendEscalation applies. Operational level. Source: Acme Bylaws §3.2. Conflicts resolved by specificity.

Every record carries its rendering. A reviewer's sign-off is a `decide` event over the rendered text, so what people approved and what the engine runs are the same object.

### IR record

*IR-D (Stage 6 example)*

```json
{"@type":"Norm","@id":"esk:norm/eu-residency","scope":"esk:scope/acme",
 "deontic":"F","bearer":"esk:pos/member",
 "aim":["exists",["var","x","Entity"],
        ["and",["has-kind",["var","x"],"fin:PersonalData"],
               ["not",["in",["custody-jurisdiction",["var","x"]],["set","EU"]]]]],
 "condition":["true"],"source":{"issuer":"esk:party/eu","ref":"GDPR art. 44–49"},
 "level":"constitutional","tradeable":false,"defeasible":false,
 "verbal":"No member may cause personal data to be held outside EU jurisdiction. Source: GDPR. Not tradeable."}
```

### Check report

*out/static-check-report.json · Meridian, excerpt*

```console
summary              241 records · 0 E · 11 W · 77 U · 214 I
W-SINGLE-POINT       esk:pos/Meridian.Owner has cardinality 1, no Deputy pattern, and bears … exclusive powers
W-OVERLAPPING-POWER  Meridian.OwnerSpend and Meridian.FinanceSpend overlap on decide without declared priority
E-FREEZE-COVERAGE    OpexBudget.Freeze: exceptions cover all non-tradeable obligations in scope
E-ARCH-PRODUCTION    Architect holds no bind/unbind/authorize power over any production requirement
U                    esk:cap/Meridian.Database.rpo: satisfaction depends on observed evidence — UNKNOWN until runtime
```

The four severities: E the spec violates the kernel and can't be enacted; W enactable but suspicious; U undecidable until the organization runs (listed so that "we don't know yet" is an output of compilation); I information, including every chain of authority.

## Conditions are the whole constraint language

There's no separate policy language. Conditions combine claim tests (`holds`, `unknown`, `contradicted`, `false`), log tests (`occurred`, `count … over`, `since`), normative tests (`violated commitment of`, `breached`, `in-force`, `gap`) and bounded temporal operators (`within`, `before`, `until`). A condition that tests any claim is four-valued, and the checker warns (`W-UNKNOWN-BRANCH`) when no norm in scope says what happens if it evaluates to unknown.

The language has no loops, functions or string manipulation. Computation is done by capabilities, whatever realizes them, and its results come back as claims. That keeps the specification a description of what is required and what is in force, and stops it becoming a place for implementation to hide.
