@abloatai/ablo 0.12.0 → 0.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +2 -2
- package/CHANGELOG.md +29 -0
- package/README.md +3 -3
- package/dist/BaseSyncedStore.js +39 -32
- package/dist/batching/index.d.ts +57 -0
- package/dist/batching/index.js +150 -0
- package/dist/cli.cjs +158 -40
- package/dist/client/Ablo.d.ts +16 -25
- package/dist/client/Ablo.js +1 -1
- package/dist/client/auth.js +11 -0
- package/dist/client/createModelProxy.d.ts +33 -8
- package/dist/client/createModelProxy.js +4 -4
- package/dist/errorCodes.d.ts +3 -1
- package/dist/errorCodes.js +10 -1
- package/dist/schema/index.d.ts +2 -2
- package/dist/schema/index.js +2 -2
- package/dist/schema/model.d.ts +38 -84
- package/dist/schema/model.js +12 -12
- package/dist/schema/roles.d.ts +49 -0
- package/dist/schema/roles.js +21 -0
- package/dist/schema/schema.d.ts +1 -1
- package/dist/schema/schema.js +1 -1
- package/dist/schema/serialize.d.ts +4 -2
- package/dist/schema/serialize.js +4 -2
- package/dist/schema/sugar.d.ts +7 -28
- package/dist/schema/sugar.js +2 -7
- package/dist/schema/sync-delta-row.d.ts +2 -0
- package/dist/schema/sync-delta-row.js +2 -1
- package/dist/schema/tenancy.d.ts +67 -28
- package/dist/schema/tenancy.js +93 -23
- package/dist/server/commit.d.ts +8 -3
- package/docs/api.md +7 -6
- package/docs/cli.md +43 -4
- package/docs/client-behavior.md +2 -2
- package/docs/coordination.md +12 -12
- package/docs/examples/agent-human.md +6 -6
- package/docs/examples/ai-sdk-tool.md +1 -1
- package/docs/examples/existing-python-backend.md +0 -2
- package/docs/examples/nextjs.md +2 -2
- package/docs/examples/scoped-agent.md +3 -3
- package/docs/examples/server-agent.md +4 -4
- package/docs/identity.md +27 -20
- package/docs/index.md +0 -1
- package/docs/integration-guide.md +12 -9
- package/docs/interaction-model.md +1 -1
- package/docs/mcp.md +17 -5
- package/docs/quickstart.md +3 -3
- package/docs/react.md +69 -0
- package/llms.txt +2 -3
- package/package.json +8 -2
- package/docs/mcp/claude-code.md +0 -35
- package/docs/mcp/cursor.md +0 -35
- package/docs/mcp/windsurf.md +0 -33
- package/docs/roadmap.md +0 -55
- package/docs/the-loop.md +0 -21
- package/llms-full.txt +0 -396
|
@@ -142,20 +142,23 @@ model(
|
|
|
142
142
|
},
|
|
143
143
|
/* relations */ {},
|
|
144
144
|
{
|
|
145
|
-
//
|
|
146
|
-
|
|
145
|
+
// Axis 1 — `policy`: who may READ a row (tenant isolation / RLS). A
|
|
146
|
+
// row-local `organization_id` column is the default, so you omit this for
|
|
147
|
+
// normal tables; set it only for the exceptions (parent-inherited / global).
|
|
147
148
|
|
|
149
|
+
// Axis 2 — `groups`: which sync-group CHANNELS a row fans into.
|
|
148
150
|
// Scope root: rows form the group `matter:<id>`. Children point at it with
|
|
149
151
|
// `relation.belongsTo('matters', 'matterId', { parent: true })` to inherit.
|
|
150
|
-
|
|
152
|
+
groups: { root: 'matter' },
|
|
151
153
|
}
|
|
152
154
|
);
|
|
153
155
|
```
|
|
154
156
|
|
|
155
|
-
For rows that don't carry `organization_id` themselves but inherit
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
157
|
+
For rows that don't carry `organization_id` themselves but inherit tenancy via a
|
|
158
|
+
foreign key, set `policy: { by: 'parent', fk: '<fk>', parent: '<parentTable>' }`.
|
|
159
|
+
For genuinely global/reference data, `policy: { by: 'none' }`. ⚠ `by: 'none'`
|
|
160
|
+
exposes the whole table cross-tenant, so it's an explicit, named branch — never a
|
|
161
|
+
falsy flag. See `packages/sync-engine/src/schema/model.ts` for the full option set.
|
|
159
162
|
|
|
160
163
|
## 2. Create The Client
|
|
161
164
|
|
|
@@ -444,7 +447,7 @@ scope.
|
|
|
444
447
|
```ts
|
|
445
448
|
await using claim = await ablo.weatherReports.claim({
|
|
446
449
|
id: reportId,
|
|
447
|
-
|
|
450
|
+
reason: 'forecasting',
|
|
448
451
|
});
|
|
449
452
|
const claimed = claim.data;
|
|
450
453
|
if (!claimed) return;
|
|
@@ -510,7 +513,7 @@ them.
|
|
|
510
513
|
| `update({ id, data, ...opts })` | Update through the model client. |
|
|
511
514
|
| `delete({ id, ...opts })` | Delete through the model client. |
|
|
512
515
|
| `claim.state({ id })` | See who is currently working on a row (synchronous). |
|
|
513
|
-
| `claim({ id,
|
|
516
|
+
| `claim({ id, reason?, ttl? })` | Acquire a disposable handle: wait for your turn, re-read, and hold the row. |
|
|
514
517
|
|
|
515
518
|
Keep first integrations on the model methods above. Every mutation and
|
|
516
519
|
server-read verb takes one options object; only the synchronous `get(id)` stays
|
|
@@ -70,7 +70,7 @@ automatically when the scope exits:
|
|
|
70
70
|
```ts
|
|
71
71
|
await using claim = await ablo.weatherReports.claim({
|
|
72
72
|
id: 'report_stockholm',
|
|
73
|
-
|
|
73
|
+
reason: 'editing',
|
|
74
74
|
});
|
|
75
75
|
await ablo.weatherReports.update({ id: claim.data.id, data: { status: 'ready' } }); // rejected if the row changed under the claim
|
|
76
76
|
```
|
package/docs/mcp.md
CHANGED
|
@@ -67,11 +67,23 @@ Point your assistant at the hosted endpoint — no auth, no token:
|
|
|
67
67
|
claude mcp add --transport http ablo https://<your-app>/api/mcp
|
|
68
68
|
```
|
|
69
69
|
|
|
70
|
-
|
|
70
|
+
The endpoint is identical for every client — only the config surface differs:
|
|
71
71
|
|
|
72
|
-
-
|
|
73
|
-
-
|
|
74
|
-
-
|
|
72
|
+
- **Claude Code** — run the `claude mcp add` command above; verify with `/mcp list`, remove with `claude mcp remove ablo`.
|
|
73
|
+
- **Cursor** — add the server to `~/.cursor/mcp.json` (macOS / Linux), then restart.
|
|
74
|
+
- **Windsurf** — add the same JSON via Settings → Cascade → MCP, then restart.
|
|
75
|
+
|
|
76
|
+
Cursor and Windsurf use the same config shape:
|
|
77
|
+
|
|
78
|
+
```json
|
|
79
|
+
{
|
|
80
|
+
"mcpServers": {
|
|
81
|
+
"ablo": { "transport": "http", "url": "https://<your-app>/api/mcp" }
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Each client then lists the Ablo tools (`search_ablo_docs`, `get_recipe`, `get_api_surface`, `validate_schema`, `scaffold_app`) in its MCP panel.
|
|
75
87
|
|
|
76
88
|
### What it exposes
|
|
77
89
|
|
|
@@ -96,7 +108,7 @@ loading everything into context.
|
|
|
96
108
|
Reusable, parameterised templates that drive an end-to-end flow:
|
|
97
109
|
|
|
98
110
|
- `integrate-sync-engine` — wire the SDK into an existing project.
|
|
99
|
-
- `add-agent` — add an agent worker that coordinates via
|
|
111
|
+
- `add-agent` — add an agent worker that coordinates via claims and
|
|
100
112
|
conflict-safe writes.
|
|
101
113
|
- `define-schema` — design a Zod-first schema from a description, then run
|
|
102
114
|
`validate_schema` before committing.
|
package/docs/quickstart.md
CHANGED
|
@@ -222,7 +222,7 @@ Call `handle.release()` when your work is done.
|
|
|
222
222
|
// Claim the row so other participants serialize behind us while we work.
|
|
223
223
|
const handle = await ablo.weatherReports.claim({
|
|
224
224
|
id: 'weather_stockholm',
|
|
225
|
-
|
|
225
|
+
reason: 'checking_weather',
|
|
226
226
|
ttl: '2m',
|
|
227
227
|
});
|
|
228
228
|
|
|
@@ -260,7 +260,7 @@ write through the model.
|
|
|
260
260
|
```ts
|
|
261
261
|
const active = ablo.weatherReports.claim.state({ id: 'weather_stockholm' });
|
|
262
262
|
if (active) {
|
|
263
|
-
console.log(`${active.heldBy} is ${active.
|
|
263
|
+
console.log(`${active.heldBy} is ${active.reason}`);
|
|
264
264
|
}
|
|
265
265
|
|
|
266
266
|
const handle = await ablo.weatherReports.claim({ id: 'weather_stockholm' });
|
|
@@ -268,7 +268,7 @@ await ablo.weatherReports.update({ id: handle.data.id, data: { status: 'ready' }
|
|
|
268
268
|
await handle.release();
|
|
269
269
|
```
|
|
270
270
|
|
|
271
|
-
Use `{
|
|
271
|
+
Use `{ queue: false }` on `claim` when work should be skipped instead of queued
|
|
272
272
|
behind an active holder.
|
|
273
273
|
|
|
274
274
|
## Next steps
|
package/docs/react.md
CHANGED
|
@@ -224,6 +224,75 @@ function wired into the provider (bound to your transport). If no `beginClaim`
|
|
|
224
224
|
is wired, the returned invoker throws `AbloValidationError` with code
|
|
225
225
|
`claim_not_wired`.
|
|
226
226
|
|
|
227
|
+
## useWatch — scoped presence + read interest
|
|
228
|
+
|
|
229
|
+
`useWatch` is the React form of `ablo.<model>.watch`. It joins multiplayer for a
|
|
230
|
+
scope on the engine's existing socket (one TCP connection, N logical
|
|
231
|
+
sub-syncgroup participants) and returns the reactive participant facade. Use it
|
|
232
|
+
when a mount should both *see* who else is on an entity and, optionally, declare
|
|
233
|
+
write interest in it.
|
|
234
|
+
|
|
235
|
+
```tsx
|
|
236
|
+
'use client';
|
|
237
|
+
|
|
238
|
+
import { useWatch } from '@abloatai/ablo/react';
|
|
239
|
+
|
|
240
|
+
export function DeckPresence({ deckId }: { deckId: string }) {
|
|
241
|
+
const { peers, claims, status } = useWatch({
|
|
242
|
+
scope: { slideDecks: deckId },
|
|
243
|
+
claim: true, // I intend to write — pin the scope + let peers observe the claim
|
|
244
|
+
hydrate: true, // backfill the deck's current rows if not already loaded
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
if (status !== 'joined') return <span>connecting…</span>;
|
|
248
|
+
return <span>{peers.length} other{peers.length === 1 ? '' : 's'} here</span>;
|
|
249
|
+
}
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
Options (`UseWatchOptions`):
|
|
253
|
+
|
|
254
|
+
| Option | Default | Effect |
|
|
255
|
+
| --- | --- | --- |
|
|
256
|
+
| `scope` | — | Model-form scope (`{ slideDecks: id }`), resolved through the schema. Omit for engine-wide. |
|
|
257
|
+
| `claim` | `false` | Acquire a write-claim on the scope (sent so peers observe it; pins the scope so it never warm-drops while held). A viewer is not a claimant — leave `false` for read-only. |
|
|
258
|
+
| `hydrate` | `false` | Backfill the scope's current rows into the pool once on enter, then keep them fresh via the live tail. Set `true` for deep-linked / never-opened entities. Single-flight; soft-fails. |
|
|
259
|
+
| `ttlSeconds` | — | Lease TTL for the scope claim. |
|
|
260
|
+
| `paused` | `false` | Tear down and don't re-join while true. |
|
|
261
|
+
|
|
262
|
+
Returns (`UseWatchReturn`): `{ participant, peers, claims, status, error }`.
|
|
263
|
+
`peers` is everyone else on the scope's sync groups; `claims` is their active
|
|
264
|
+
write-claims; `status` is the join lifecycle. Auto-cleans up on unmount or when
|
|
265
|
+
`paused` flips true.
|
|
266
|
+
|
|
267
|
+
## usePeers — read-only presence
|
|
268
|
+
|
|
269
|
+
`usePeers` is a *pure reader* of the presence stream already flowing on the
|
|
270
|
+
connection. Unlike `useWatch`, it does **not** enter/leave a scope (no
|
|
271
|
+
`update_subscription`, no warm-TTL churn) — so reading it never changes what the
|
|
272
|
+
connection is subscribed to.
|
|
273
|
+
|
|
274
|
+
```tsx
|
|
275
|
+
'use client';
|
|
276
|
+
|
|
277
|
+
import { usePeers } from '@abloatai/ablo/react';
|
|
278
|
+
|
|
279
|
+
export function CursorBroadcaster({ deckId }: { deckId: string }) {
|
|
280
|
+
const peers = usePeers({ slideDecks: deckId });
|
|
281
|
+
const alone = !peers.some((p) => p.participantKind === 'user');
|
|
282
|
+
// suppress live-cursor broadcasts while alone
|
|
283
|
+
}
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
Pass `scope` to narrow to a sync group's peers, or omit it for everyone on the
|
|
287
|
+
engine's groups. Returns `ReadonlyArray<Peer>`, where each `Peer` carries
|
|
288
|
+
`participantKind` (`'user' | 'agent' | 'system'`), `participantId`, optional
|
|
289
|
+
`label`, `syncGroups`, `activity`, `lastActive`, and optional `activeClaims`.
|
|
290
|
+
|
|
291
|
+
Reach for `usePeers` (not a second `useWatch`) when some **other** mount already
|
|
292
|
+
owns the scope's read interest — scope `leave` is not reference-counted, so a
|
|
293
|
+
second `useWatch` on the same scope would warm-drop the owner's subscription on
|
|
294
|
+
unmount.
|
|
295
|
+
|
|
227
296
|
## Next.js
|
|
228
297
|
|
|
229
298
|
The Next.js [App Router landing](/nextjs) walks through Server Components
|
package/llms.txt
CHANGED
|
@@ -12,7 +12,7 @@ First action when integrating into an app: run `npx ablo init --yes --framework
|
|
|
12
12
|
|
|
13
13
|
Second: make sure a key exists — WITHOUT printing it. The key is a secret; it must never appear in your output, your reasoning, or a file you echo (it would live in the conversation history forever). Check PRESENCE only: `[ -n "$ABLO_API_KEY" ] && echo set` and `grep -cq '^ABLO_API_KEY=' .env.local && echo wired` — never `cat .env.local`, never `echo $ABLO_API_KEY`. If neither check passes, ask the HUMAN to run `npx ablo login` once — it opens a browser and saves a `sk_test_` key locally; an agent must NOT run it. You never copy the key by hand: the next step writes it into `.env.local` (and gitignores it) for you.
|
|
14
14
|
|
|
15
|
-
Then PUSH — this is the step everything depends on. The server keeps its OWN copy of the schema. Run `npx ablo push
|
|
15
|
+
Then PUSH — this is the step everything depends on. The server keeps its OWN copy of the schema. Run `npx ablo push`: it pushes `ablo/schema.ts` (sandbox) AND writes `ABLO_API_KEY` into `.env.local` from the stored login. Until the schema is pushed, EVERY write to a new or changed model fails with `server_execute_unknown_model`. Re-run it after schema changes. `push` is one-shot; `dev` is the watcher, so use `npx ablo dev --no-watch` only when you intentionally want the dev command to push once and exit.
|
|
16
16
|
|
|
17
17
|
## Projects (one org, many apps)
|
|
18
18
|
|
|
@@ -29,7 +29,6 @@ TYPES: the project registers its schema ONCE via declaration merging — `npx ab
|
|
|
29
29
|
|
|
30
30
|
const schema = defineSchema({
|
|
31
31
|
weatherReports: model({
|
|
32
|
-
id: z.string(),
|
|
33
32
|
location: z.string(),
|
|
34
33
|
status: z.enum(['pending', 'ready']),
|
|
35
34
|
forecast: z.string().optional(),
|
|
@@ -190,6 +189,6 @@ Do not teach `/api`, `/agent`, `/ai-sdk`, `/core`, `/realtime`, or internal subp
|
|
|
190
189
|
- `npx ablo init --yes` (flags: `--framework`, `--auth`, `--storage direct|endpoint` (default `direct`), `--no-agent`, `--no-pull`, `--no-install`, `--no-login`). Generates `ablo/schema.ts` + the client; `--storage direct` (default) wires `databaseUrl`, `--storage endpoint` scaffolds the `ablo/data-source.ts` endpoint above instead.
|
|
191
190
|
- Key: see "Start here" — env → `.env.local` → ask the human to `npx ablo login`; never run `login` yourself, never copy keys by hand (`ablo push` writes `.env.local`).
|
|
192
191
|
- Adopt an existing DB: `npx ablo pull prisma [path]` / `npx ablo pull drizzle <module>`.
|
|
193
|
-
- `npx ablo push
|
|
192
|
+
- `npx ablo push` pushes the schema (sandbox) AND writes `ABLO_API_KEY` to `.env.local`; `npx ablo dev --no-watch` is the push-once form of the watcher; `npx ablo logs --no-follow` exits instead of tailing forever; `npx ablo mode sandbox|production` always needs the argument. `npx ablo push`/`status`/`pull`/`check`/`generate` are one-shot.
|
|
194
193
|
|
|
195
194
|
Canonical docs to read before integrating: `quickstart`, `schema-contract`, `integration-guide`, `guarantees`, `client-behavior`, `data-sources`, `examples/existing-python-backend`, `api`, `examples/ai-sdk-tool`, and `examples/server-agent`. When upgrading an existing integration, read `migration` — every breaking change, what to change, and which version introduced it.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@abloatai/ablo",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.14.0",
|
|
4
4
|
"description": "The Collaboration Layer For AI Agents",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
@@ -43,6 +43,11 @@
|
|
|
43
43
|
"import": "./dist/core/index.js",
|
|
44
44
|
"default": "./dist/core/index.js"
|
|
45
45
|
},
|
|
46
|
+
"./batching": {
|
|
47
|
+
"types": "./dist/batching/index.d.ts",
|
|
48
|
+
"import": "./dist/batching/index.js",
|
|
49
|
+
"default": "./dist/batching/index.js"
|
|
50
|
+
},
|
|
46
51
|
"./agent": {
|
|
47
52
|
"types": "./dist/agent/index.d.ts",
|
|
48
53
|
"import": "./dist/agent/index.js",
|
|
@@ -119,7 +124,6 @@
|
|
|
119
124
|
"examples",
|
|
120
125
|
"AGENTS.md",
|
|
121
126
|
"llms.txt",
|
|
122
|
-
"llms-full.txt",
|
|
123
127
|
"LICENSE",
|
|
124
128
|
"NOTICE",
|
|
125
129
|
"README.md",
|
|
@@ -131,9 +135,11 @@
|
|
|
131
135
|
"build:cli": "tsup --config tsup.cli.config.ts",
|
|
132
136
|
"typecheck:cli": "tsc -p tsconfig.cli.json",
|
|
133
137
|
"pack:check": "npm_config_cache=${TMPDIR:-/tmp}/ablo-npm-cache npm pack --dry-run",
|
|
138
|
+
"lint": "npm run lint:imports && npm run lint:errors && npm run lint:docs",
|
|
134
139
|
"lint:imports": "node scripts/check-js-extensions.mjs",
|
|
135
140
|
"generate:errors": "tsx scripts/generate-error-docs.mts",
|
|
136
141
|
"lint:errors": "tsx scripts/check-error-docs.mts",
|
|
142
|
+
"lint:docs": "node scripts/check-doc-drift.mjs",
|
|
137
143
|
"lint:pkg": "publint",
|
|
138
144
|
"prepublishOnly": "npm run build && npm run lint:pkg",
|
|
139
145
|
"check:dist": "node scripts/check-dist-fresh.mjs",
|
package/docs/mcp/claude-code.md
DELETED
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
# Claude Code
|
|
2
|
-
|
|
3
|
-
## Install
|
|
4
|
-
|
|
5
|
-
```bash
|
|
6
|
-
claude mcp add --transport http ablo https://<your-app>/api/mcp
|
|
7
|
-
```
|
|
8
|
-
|
|
9
|
-
That's it — no token or header needed. The endpoint is public and serves
|
|
10
|
-
only docs, schema lint, and scaffolds. The next `/help` in Claude Code will
|
|
11
|
-
list the Ablo Sync tools.
|
|
12
|
-
|
|
13
|
-
## Verify
|
|
14
|
-
|
|
15
|
-
In Claude Code, run:
|
|
16
|
-
|
|
17
|
-
```
|
|
18
|
-
/mcp list
|
|
19
|
-
```
|
|
20
|
-
|
|
21
|
-
You should see `ablo` with the integration tools enumerated:
|
|
22
|
-
`search_ablo_docs`, `get_recipe`, `get_api_surface`, `validate_schema`,
|
|
23
|
-
`scaffold_app`.
|
|
24
|
-
|
|
25
|
-
## Removing
|
|
26
|
-
|
|
27
|
-
```bash
|
|
28
|
-
claude mcp remove ablo
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
## More
|
|
32
|
-
|
|
33
|
-
- [MCP overview](/docs/mcp) — what the server exposes and how the transport works.
|
|
34
|
-
- [Cursor setup](/docs/mcp/cursor) — same URL, different UI.
|
|
35
|
-
- [Windsurf setup](/docs/mcp/windsurf) — same URL, different UI.
|
package/docs/mcp/cursor.md
DELETED
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
# Cursor
|
|
2
|
-
|
|
3
|
-
## Install
|
|
4
|
-
|
|
5
|
-
Add the Ablo Sync MCP server to Cursor's `mcp.json`:
|
|
6
|
-
|
|
7
|
-
```json
|
|
8
|
-
{
|
|
9
|
-
"mcpServers": {
|
|
10
|
-
"ablo": {
|
|
11
|
-
"transport": "http",
|
|
12
|
-
"url": "https://<your-app>/api/mcp"
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
```
|
|
17
|
-
|
|
18
|
-
The file lives at `~/.cursor/mcp.json` on macOS / Linux. No auth header is
|
|
19
|
-
needed — the endpoint is public and serves only docs, schema lint, and
|
|
20
|
-
scaffolds.
|
|
21
|
-
|
|
22
|
-
Restart Cursor. The Ablo Sync tools appear under the MCP icon in the agent
|
|
23
|
-
panel.
|
|
24
|
-
|
|
25
|
-
## Verify
|
|
26
|
-
|
|
27
|
-
In Cursor's agent panel, open the MCP tools list. You should see the
|
|
28
|
-
Ablo Sync integration tools and their JSON schemas: `search_ablo_docs`,
|
|
29
|
-
`get_recipe`, `get_api_surface`, `validate_schema`, `scaffold_app`.
|
|
30
|
-
|
|
31
|
-
## More
|
|
32
|
-
|
|
33
|
-
- [MCP overview](/docs/mcp) — what the server exposes and how the transport works.
|
|
34
|
-
- [Claude Code setup](/docs/mcp/claude-code) — CLI install.
|
|
35
|
-
- [Windsurf setup](/docs/mcp/windsurf) — same JSON shape.
|
package/docs/mcp/windsurf.md
DELETED
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
# Windsurf
|
|
2
|
-
|
|
3
|
-
## Install
|
|
4
|
-
|
|
5
|
-
Add the Ablo Sync MCP server to Windsurf's MCP config:
|
|
6
|
-
|
|
7
|
-
```json
|
|
8
|
-
{
|
|
9
|
-
"mcpServers": {
|
|
10
|
-
"ablo": {
|
|
11
|
-
"transport": "http",
|
|
12
|
-
"url": "https://<your-app>/api/mcp"
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
```
|
|
17
|
-
|
|
18
|
-
The config path differs by platform — Windsurf surfaces it in Settings →
|
|
19
|
-
Cascade → MCP. Restart Windsurf after saving. No auth header is needed —
|
|
20
|
-
the endpoint is public and serves only docs, schema lint, and scaffolds.
|
|
21
|
-
|
|
22
|
-
## Verify
|
|
23
|
-
|
|
24
|
-
Cascade's MCP panel lists every configured server with its tools. You
|
|
25
|
-
should see `ablo` with the integration tools enumerated:
|
|
26
|
-
`search_ablo_docs`, `get_recipe`, `get_api_surface`, `validate_schema`,
|
|
27
|
-
`scaffold_app`.
|
|
28
|
-
|
|
29
|
-
## More
|
|
30
|
-
|
|
31
|
-
- [MCP overview](/docs/mcp) — what the server exposes and how the transport works.
|
|
32
|
-
- [Claude Code setup](/docs/mcp/claude-code) — CLI install.
|
|
33
|
-
- [Cursor setup](/docs/mcp/cursor) — same JSON shape.
|
package/docs/roadmap.md
DELETED
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
# Roadmap
|
|
2
|
-
|
|
3
|
-
What is shipped, what is next, and what we will not build.
|
|
4
|
-
|
|
5
|
-
## Shipped
|
|
6
|
-
|
|
7
|
-
- **Models, claims, commits** — the core API.
|
|
8
|
-
- **Audit log** — a tamper-evident, hash-chained record of who did what,
|
|
9
|
-
per principal.
|
|
10
|
-
- **MCP transport** — HTTP server at `/api/mcp`.
|
|
11
|
-
- **TypeScript SDK** — `@abloatai/ablo`, with React bindings.
|
|
12
|
-
- **Dashboard** — keys, audit, metrics, allowed origins.
|
|
13
|
-
- **Schema migrations** — change a model's shape after it already has data.
|
|
14
|
-
Ablo plans the migration, tells you which changes are safe to auto-apply,
|
|
15
|
-
and backfills the rest; the server applies and activates a migration only
|
|
16
|
-
if it succeeds. `ablo generate` emits typed clients from a pushed schema.
|
|
17
|
-
- **Structured errors** — every error has a stable code and a request id,
|
|
18
|
-
and the same codes work whether you reach Ablo over HTTP, WebSocket, or MCP.
|
|
19
|
-
- **Sync groups** — clients automatically receive only the records they have
|
|
20
|
-
access to, based on relationships you declare in the schema.
|
|
21
|
-
- **Agent coordination** — when several agents work on the same model, they
|
|
22
|
-
take turns instead of overwriting each other, via `intent(id)` handles
|
|
23
|
-
that claim, wait, and commit.
|
|
24
|
-
|
|
25
|
-
## In flight
|
|
26
|
-
|
|
27
|
-
- **Real-time presence** — see who else is viewing/editing a model
|
|
28
|
-
(coordination primitives landed; presence surface in progress).
|
|
29
|
-
- **Cross-instance fan-out via Redis** — pub/sub deltas at scale.
|
|
30
|
-
|
|
31
|
-
## On deck
|
|
32
|
-
|
|
33
|
-
- **Field-level subscriptions** — subscribe to one path, not the whole row.
|
|
34
|
-
- **Bulk import/export** — CSV/JSON round-trip with chain verification.
|
|
35
|
-
|
|
36
|
-
## Maybe, if demand
|
|
37
|
-
|
|
38
|
-
- **Python SDK** — when a customer is shipping a Python-only product.
|
|
39
|
-
- **Go SDK** — same.
|
|
40
|
-
- **Multi-region replication** — when latency requirements force it.
|
|
41
|
-
|
|
42
|
-
## We will not build
|
|
43
|
-
|
|
44
|
-
- **A general-purpose Postgres wrapper** — Ablo is for state with
|
|
45
|
-
concurrency semantics, not for storing every table.
|
|
46
|
-
- **Server-side compute** — no triggers, no stored procedures. Compute
|
|
47
|
-
belongs in your application code.
|
|
48
|
-
- **A document database UI** — your data lives in Ablo; the UI is your
|
|
49
|
-
product, not ours.
|
|
50
|
-
|
|
51
|
-
## How priorities shift
|
|
52
|
-
|
|
53
|
-
We move items between sections based on what customers ask for in
|
|
54
|
-
production. Filing a [feature request](/docs/contact) with a concrete use
|
|
55
|
-
case is more effective than a thread on Twitter.
|
package/docs/the-loop.md
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
# The loop: how your data flows
|
|
2
|
-
|
|
3
|
-
This explainer moved to the canonical, maintained docs:
|
|
4
|
-
|
|
5
|
-
**→ https://abloatai.com/docs/webhooks**
|
|
6
|
-
|
|
7
|
-
The short version: Ablo has the same two-sided shape as Stripe — **you call Ablo to make changes (the client), and Ablo calls you to persist them (a signed webhook)** — plus realtime sync to every connected client.
|
|
8
|
-
|
|
9
|
-
```
|
|
10
|
-
your app ──write──▶ Ablo (hosted) ──realtime sync──▶ other clients
|
|
11
|
-
(the client) the transaction log (live, optimistic)
|
|
12
|
-
│
|
|
13
|
-
└──signed event──▶ /api/ablo/[...all] ──▶ YOUR database
|
|
14
|
-
(the webhook route)
|
|
15
|
-
```
|
|
16
|
-
|
|
17
|
-
Ablo owns the ordered transaction log (the source of truth); your database is a
|
|
18
|
-
materialized copy you keep via the webhook. See the link above for the full
|
|
19
|
-
guide: scaffolding the handler (`ablo init`), local testing (`ablo dev`),
|
|
20
|
-
registering an endpoint (`ablo webhooks create`), signature verification, the
|
|
21
|
-
delivery/retry model, and best practices.
|