name: dxos-echo description: >- Guide for ECHO (DXOS object graph / local-first DB). Use when adding or changing queries, filters, schema types, Ref/DXN handling, Database service layers, EchoClient/space DB access, or React ECHO hooks.
ECHO (DXOS)
ECHO is the typed object graph backed by Automerge: spaces expose a Database you mutate with reactive proxies and query with Filter / Query ASTs. Core types and both imperative and Effect-style DB access live in @dxos. Client wiring (sync, hypergraph, EchoClient) is in @dxos/echo-db.
For Effect patterns (Layer, Effect.gen, services), read .cursor/skills/effect/SKILL.md.
Packages (where code lives)
| Package | Role |
|---|---|
@dxos/echo |
Types, Database interface, Effect Database.Service, Query/Filter/Ref/Type/Obj, schema registry surface |
@dxos/echo-db |
EchoClient, EchoHost, EchoDatabaseImpl, hypergraph, migrations, sync helpers |
@dxos/echo-react |
useQuery, useObject, useSchema |
@dxos/echo-host |
Host-side pipeline (EchoHost, indexes, services) |
Obtaining a Database
- App / client:
EchoClient.constructDatabase(...)returns an implementation ofDatabase(seeEchoDatabaseImpl). - Plugins / runtime: often
space.db(or equivalent) after space is open—same interface. - Tests:
EchoTestPeerbuilds a client + DB for isolated runs.
API reference (short)
Imperative / non-Effect (Database instance)
Use the object from echo-db / space. Primary entry: Database interface (add, remove, query, getObjectById, makeRef, flush, graph, schemaRegistry).
| Area | Notes |
|---|---|
| Mutations | db.add(obj), db.remove(obj); mutate proxies in place for field updates. |
| Query | db.query(filterOrQuery) → QueryResult with .subscribe / .run(). |
| Lookup | db.getObjectById(id), db.makeRef(dxn). |
| Schema | db.schemaRegistry.query(...), registration via graph/registry APIs used in your stack. |
| Refs | Ref, DXN export from @dxos/echo. |
EchoDatabase extends this with sync/migrations (getSyncState, runMigrations, events).
Effect (@dxos/echo/Database module)
The same logical operations are exposed as Effects that require Database.Service in context.
| Export | Purpose |
|---|---|
Service |
Context.Tag — yield* Database.Service → { db }. |
layer(db) / notAvailable |
Layer for providing or stubbing DB. |
query / runQuery |
Query with service. |
schemaQuery / runSchemaQuery |
Schema registry queries. |
add / remove / flush |
Mutations / persistence. |
resolve |
Resolve DXN or Ref via graph. |
load |
Load Ref; use Effect.catchTag('EntityNotFoundError', …) when a missing target is acceptable. Does not require Database.Service. |
Wire-up pattern (operations, agents, composable code):
import * as Database from '@dxos/echo/Database';
import { Effect } from 'effect';
const program = Effect.gen(function* () {
const objects = yield* Database.query(SomeFilter).run;
return objects;
});
await Effect.runPromise(program.pipe(Effect.provide(Database.layer(db))));
Database.layer is the usual bridge from an imperative db to Effect code; see plugin operation resolvers for real merges with other layers.
React (non-Effect, subscription-based)
From @dxos/echo-react: useQuery, useObject, useSchema — subscribe to query results / single object / schema state in components.
Query & filter builders
Query— graph-shaped selections (select,reference, etc.).Filter— predicates / props shorthand; types underFilter.Any,Query.Any.
Prefer importing subpaths when you need one module only, e.g. @dxos/echo/Filter, @dxos/echo/Query (see package.json exports).
When to use which style
- Imperative
db: UI event handlers, existing callback code, small scripts, anything that already holdsdb. - Effect
Database.*: operation handlers, assistant/toolkit flows, anyEffectprogram that should declareDatabase.Serviceand compose with other layers (see Effect skill). - React hooks: read-mostly UI and local subscriptions.
Related docs in-repo
- Effect runtime patterns: .cursor/skills/effect/SKILL.md.
- DXOS SDK notes: .agents/sdk/ (follow project conventions there).