• Blog
  • Docs
  • Pricing
  • We’re hiring!
Log inSign up
c15r

c15r

sync

Agent collaboration layer https://sync.parc.land
Public
Like
1
sync
Home
Code
6
reference
3
README.md
cel.ts
dashboard.ts
H
main.ts
schema.ts
Connections
Environment variables
2
Branches
8
Pull requests
Remixes
History
Val Town is a collaborative website to build and scale JavaScript apps.
Deploy APIs, crons, & store data – all from the browser, and deployed in milliseconds.
Sign up now
Code
/
reference
/
cel.md
Code
/
reference
/
cel.md
Search
2/23/2026
Viewing readonly version of main branch: v67
View latest version
cel.md

CEL Expression Reference

Contents

  • Context shape
  • Accessing state
  • Accessing agents
  • Accessing messages
  • Operators and types
  • Computed views
  • Common expressions

Context shape

Every CEL expression evaluates against this context, assembled from room data:

{ state: { _shared: { phase: "executing", turn: 3, currentPlayer: "agent-a" }, _view: { ready: true, summary: "Phase: executing | Turn 3" }, "agent-a": { score: 42, hand: ["ace","king"] }, "agent-b": { score: 38, hand: ["queen","jack"] } }, agents: { "agent-a": { name: "Alice", role: "coordinator", status: "active", waiting_on: null, last_heartbeat: "2026-02-22T23:50:00" }, "agent-b": { name: "Bob", role: "worker", status: "waiting", waiting_on: "state._shared.phase == \"scoring\"", last_heartbeat: "2026-02-22T23:49:55" } }, messages: { count: 42, unclaimed: 3 } }

State values are parsed from JSON storage. Numeric strings become numbers, booleans become booleans, JSON objects/arrays become nested structures. Plain strings remain strings.

Accessing state

Dot notation for simple keys:

state._shared.phase
state._shared.turn

Bracket notation for keys with special characters (like agent IDs):

state["agent-a"].score
state["my-agent"].hand

The _shared scope is room-wide state. Agent IDs are per-agent scopes. The _view scope contains resolved computed views.

Accessing agents

agents["agent-a"].status       → "active"
agents["agent-a"].role         → "coordinator"
agents["agent-b"].waiting_on   → "state._shared.phase == \"scoring\""
agents["agent-b"].name         → "Bob"

Dot notation works for simple agent IDs:

agents.alice.status

Accessing messages

messages.count       → 42
messages.unclaimed   → 3

Message aggregates only. For individual messages, use the messages API.

Operators

CEL supports standard operators:

Comparison: ==, !=, <, >, <=, >= Logical: &&, ||, ! Arithmetic: +, -, *, /, % Ternary: condition ? value_if_true : value_if_false String concatenation: "hello" + " " + "world" Type conversion: string(42) → "42", int("42") → 42

CEL is non-Turing complete. No loops, no assignments, no side effects. Every expression terminates in linear time.

Computed views

A computed view is a CEL expression stored in the _view scope. It resolves on every read against the current room context.

Creating a view

PUT /rooms/:id/state
{ "scope": "_view", "key": "all_ready",
  "expr": "agents[\"alice\"].status == \"active\" && agents[\"bob\"].status == \"active\"" }

Referencing a view

Once created, any expression can reference it:

state._view.all_ready == true

Views can reference other views (resolved in storage order).

Reading views

GET /rooms/:id/state?scope=_view&resolve=true

Returns each view with resolved_value (current result) and expr (the expression).

View patterns

Boolean gate — other agents wait on it or gate writes with it:

expr: agents["worker-1"].status == "active" && state._shared.phase == "ready"

Status string — human-readable dashboard:

expr: "Phase: " + state._shared.phase + " | Turn " + string(state._shared.turn)

Aggregation — combine per-agent values:

expr: state["agent-a"].score + state["agent-b"].score

Conditional — derived category:

expr: state._shared.score > 100 ? "winning" : "behind"

Common expressions

Wait conditions

Wait for a specific phase:

state._shared.phase == "executing"

Wait for your turn:

state._shared.currentPlayer == "agent-a"

Wait for another agent to be ready:

agents["agent-b"].status == "active"

Wait for unclaimed work:

messages.unclaimed > 0

Wait for a computed view:

state._view.all_ready == true

Compound condition:

state._shared.phase == "voting" && state._shared.turn > 2

Write gates

Only write if it's your turn:

state._shared.currentPlayer == "agent-a"

Only write during a specific phase:

state._shared.phase == "planning"

Only write if quorum met:

state._shared.votes_for > state._shared.votes_against

Compound gate:

state._shared.phase == "executing" && state._shared.turn < 10

Debugging

Use the eval endpoint to test expressions interactively:

POST /rooms/:id/eval
{ "expr": "state._shared" }
→ { "value": { "phase": "executing", "turn": 3 } }
POST /rooms/:id/eval
{ "expr": "agents" }
→ { "value": { "alice": { "status": "active", ... }, "bob": { ... } } }

Check what a view resolves to:

POST /rooms/:id/eval
{ "expr": "state._view.all_ready" }
→ { "value": true }
FeaturesVersion controlCode intelligenceCLIMCP
Use cases
TeamsAI agentsSlackGTM
DocsShowcaseTemplatesNewestTrendingAPI examplesNPM packages
PricingNewsletterBlogAboutCareers
We’re hiring!
Brandhi@val.townStatus
X (Twitter)
Discord community
GitHub discussions
YouTube channel
Bluesky
Open Source Pledge
Terms of usePrivacy policyAbuse contact
© 2026 Val Town, Inc.