Systematic audit of sync primitives, surfaces, help system, and MCP integration conducted through the workspace room. Findings derived from live tool calls, source code review of c15r/sync (platform) and c15r/sync-mcp (MCP server), and dashboard testing.
12 custom actions registered, organized by domain:
Task lifecycle — add_task, update_task_status, assign_task, remove_task, clear_done
All operate on _shared.tasks array via CEL expr:true writes. clear_done has an if precondition gating on existence of done tasks.
Knowledge capture — add_note, log_decision, link_resource
Append-only to respective arrays. Each captures structured objects via CEL expression writes.
Agent status — set_status (broken, see §3.1)
Administration — _set_shared, configure_dashboard
11 views registered:
| View | Expression | Purpose |
|---|---|---|
task_count_total | size(state["_shared"]["tasks"]) | Metric |
task_count_todo | tasks.filter(t, t.status == "todo").size() | Metric |
task_count_active | tasks.filter(t, t.status == "in_progress").size() | Metric |
task_count_done | tasks.filter(t, t.status == "done").size() | Metric |
notes_count | size(state["_shared"]["notes"]) | Metric |
decisions_count | size(state["_shared"]["decisions"]) | Metric |
agent_count | size(agents) | Metric |
task_board | state["_shared"]["tasks"] | Data |
notes_feed | state["_shared"]["notes"] | Data |
decision_log | state["_shared"]["decisions"] | Data |
resources | state["_shared"]["resources"] | Data |
task_summary | status-only projection | Data |
status_summary_md | CEL string concatenation | Markdown (broken newlines, see §3.5) |
agent_count | size(agents) with render: {type: "metric"} | Render hint test |
4-section surface layout:
Overview — view-grid with task metrics (total/todo/active/done) + knowledge metrics (notes/decisions/agents)
Task Board — watch on _shared.tasks + action-form for add_task + action-bar for update/assign/remove + conditional action-bar for clear_done (gated on views["task_count_done"] > 0)
Activity — feed filtered to chat + milestone kinds, with compose
Knowledge — watch on notes/decisions/resources + action-bar for add_note/log_decision/link_resource
Views compute (server-side, full CEL). All complex logic lives here.
Surfaces display (client-side, declarative). Reference view IDs and action IDs, no business logic.
Actions mutate (server-side, CEL preconditions + write templates). All state changes flow through actions.
Append-only (via append: true) is ideal for logs. Mutable arrays require full-array replacement via CEL map/filter. Alternative: map-keyed-by-ID pattern eliminates contested writes.
Limited to state.scope.key OP value, views["id"] OP value, basic boolean operators. Complex conditions must be pre-computed into views.
_context.help is situationally computed. _context._expand provides mechanical expansion hints. Requesting only=actions auto-includes _contested view.
resolveToken prefers room > agent > view. Room tokens have no identity (self = ""). All ${self} scoped writes fail. All messages show from: null.
Source: sync-mcp auth.ts line 548, sync main.ts line 1526-1533.
Schema comment says views with render_json are surfaces. Dashboard only reads _dashboard.surfaces. The render hint feature is unimplemented in the frontend.
Source: schema.ts line 14-15, Dashboard.tsx line 741.
No _uuid function in CEL. Title-match is fragile.
Ternary wrapping map output fails. Must put ternary inside each field.
CEL \n becomes literal \\n via JSON-RPC serialization.
Deletes and re-creates vault entries instead of UPDATE. Changes entry IDs.
| Topic | What agents need |
|---|---|
surfaces | All 10 types, _dashboard config, enabled expression syntax |
write_templates | ${} interpolation, expr:true, append, increment, merge |
cel_patterns | filter/map/exists/size, ternary gotcha, "key" in pattern |
token_types | room vs agent vs view authority, self scope, when to use which |
| Condition | Suggested key |
|---|---|
_dashboard.surfaces present | surfaces |
Views with render_json exist | surfaces |
${self} write fails | token_types |
First expr:true action registered | write_templates |
| CEL error in write evaluation | cel_patterns |
Missing patterns: update_in_list (functional array item update), remove_from_list (filter by predicate), clear_list (reset to empty). These are CEL patterns more than registerable actions — they need parameterized field names which can't be expressed generically.
- JSON Schema strictness (fixed): bare arrays, untyped properties broke ChatGPT
- GET endpoints unauthenticated: tool list exposed without auth
- Dashboard URL was wrong (fixed): now uses
?room=...#token=... - All token types now get dashboard links (fixed)
- Auto-surface views with
render_jsonin Dashboard.tsx - Add
_uuid()to CEL environment - Expand
_context.helptriggers (§4) - Add help entries for surfaces, write_templates, cel_patterns, token_types
- Standard library patterns for list mutation