@abloatai/ablo 0.37.1 → 0.38.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/docs/migration.md CHANGED
@@ -214,10 +214,10 @@ commonly a Data Source handler keyed on `mode`. The mapping is exactly
214
214
  source resolvers, so per-project and per-environment traffic can be routed to
215
215
  distinct stores.
216
216
 
217
- > **CLI note:** the legacy single-file config that stored `test`/`live` key
218
- > buckets is no longer auto-migrated. If `ablo status` can't find your keys after
219
- > upgrading, re-run `ablo login` to write the current `sandbox`/`production`
220
- > layout.
217
+ > **CLI note:** current login stores one mode-free `mk_` project management
218
+ > credential. Legacy runtime key slots remain readable during the cutover, but
219
+ > re-run `ablo login` before using branch/project commands so the CLI can store
220
+ > the new credential.
221
221
 
222
222
  ### New (non-breaking): `transport: 'http'`
223
223
 
package/docs/projects.md CHANGED
@@ -30,7 +30,7 @@ projects existed are default-project keys automatically.
30
30
  ## Keys belong to exactly one project
31
31
 
32
32
  A key's project is fixed at mint and can never be changed or overridden —
33
- the same discipline as its sandbox/production mode. Everything a key mints
33
+ the same discipline as its immutable branch binding. Everything a runtime key mints
34
34
  inherits its project: the short-lived session credentials (`ek_`), agent
35
35
  keys (`rk_`), everything. There is no way to "switch projects" with an
36
36
  existing key; you use a key minted for the project you mean.
@@ -12,7 +12,7 @@ schema** — your migration tool stays in charge of the shape of your database.
12
12
 
13
13
  > No database yet? Pass an `apiKey` only and Ablo keeps your rows in its own log,
14
14
  > so you can build the whole app today — like Stripe test mode. Point it at a
15
- > separate or local Postgres for a throwaway sandbox, or at your production
15
+ > separate or local Postgres for a development branch, or at your production
16
16
  > database when you're ready.
17
17
 
18
18
  ## 1. Install and initialize
@@ -23,22 +23,23 @@ npx ablo init
23
23
  ```
24
24
 
25
25
  `ablo init` scaffolds your project (next step shows what it creates) and ends
26
- by signing you in — one browser click, and a `sk_test_` key is saved locally
27
- for the CLI. Later, `npx ablo push` (step 4) writes `ABLO_API_KEY` into your
28
- `.env.local` so the SDK finds it too — no manual copy-paste. `npx ablo login`
29
- also exists standalone. In CI, or to manage the key by hand, set it yourself
30
- instead:
26
+ by signing you in — one browser click, and a project-scoped `mk_` management
27
+ credential is saved locally. Later, `npx ablo dev` (step 4) prepares an isolated branch and writes
28
+ its temporary `ABLO_API_KEY` into `.env.local`, so the SDK follows your Git
29
+ branch with no manual copy-paste. `npx ablo login` also exists standalone. In
30
+ CI, set project management access explicitly:
31
31
 
32
32
  ```bash
33
- export ABLO_API_KEY=sk_test_...
33
+ export ABLO_MANAGEMENT_KEY=mk_...
34
34
  ```
35
35
 
36
- Every SDK and CLI call needs a key. Test and live keys work like Stripe's:
37
- `sk_test_*` for the sandbox, `sk_live_*` for production. In production a key
38
- points at the database *you* own; in the sandbox you can skip the database
39
- entirely and let Ablo's test plane host the rows (apiKey only). There is no
40
- keyless mode a key is always required. (The public `/sandbox` page is a
41
- separate hosted demo, not your app.)
36
+ Every runtime call needs a branch-bound API key. `ablo dev` exchanges the
37
+ stored management credential for
38
+ an expiring `sk_test_*` key bound to the current development branch.
39
+ Production runtimes use `sk_live_*`. In production a key points at the database
40
+ *you* own; on a development branch you can skip the database entirely and let
41
+ Ablo host the rows (apiKey only). There is no keyless mode — a key is always
42
+ required. (The public `/sandbox` page is a separate hosted demo, not your app.)
42
43
 
43
44
  ## 2. Your Ablo schema (init scaffolded it)
44
45
 
@@ -166,17 +167,24 @@ The full setup, the honest footprint (publication + slot + the `REPLICATION` and
166
167
  writer roles + the `wal_level` restart + slot/WAL retention Ablo monitors), and the
167
168
  Preview status are in [Connect Your Database](./data-sources.md).
168
169
 
169
- ## 4. Push the schema, then map it to tables
170
+ ## 4. Start the branch development loop
170
171
 
171
172
  ```bash
172
- npx ablo push # pushes the schema definition and writes ABLO_API_KEY to
173
- # .env.local. Add --watch to re-push on every save.
173
+ npx ablo dev # prepare this Git branch, push, and watch ablo/schema.ts
174
174
  ```
175
175
 
176
- `ablo push` uploads the schema *definition* model names, fields, types. That
177
- metadata is what tells Ablo which models to coordinate. Skipping it makes every
178
- write to a new or changed model fail with `server_execute_unknown_model` — that
179
- error literally means "run `npx ablo push`."
176
+ `ablo dev` discovers your Git branch, ensures a matching isolated Ablo branch,
177
+ mints an eight-hour branch credential, writes it to gitignored `.env.local`,
178
+ uploads the schema *definition*, and watches for schema edits. Model names,
179
+ fields, and types tell Ablo which models to coordinate. Skipping the push makes
180
+ every write to a new or changed model fail with
181
+ `server_execute_unknown_model`.
182
+
183
+ Use `npx ablo dev --no-watch` when you only need to prepare and push once. Use
184
+ `npx ablo push` as the lower-level one-shot command when you deliberately want
185
+ to push with the currently active key, including a reviewed production deploy.
186
+ The complete mental model and CI examples are in
187
+ [Branch-first development](./branch-development.md).
180
188
 
181
189
  Now map those models to your real Postgres tables. **Your migration tool owns the
182
190
  tables** — Ablo reads them, it does not create or migrate them:
@@ -191,8 +199,8 @@ tables** — Ablo reads them, it does not create or migrate them:
191
199
  > your schema needs. Once they exist, your own migration tool stays in charge
192
200
  > of them — Ablo adopts whatever shape you evolve.
193
201
 
194
- Nothing runs locally there is no dev server to start. Your app talks to Ablo's
195
- hosted API; the rows live in your database.
202
+ No Ablo server runs locally. The `ablo dev` process only watches your schema;
203
+ your app talks to Ablo's hosted API, and the rows live in your database.
196
204
 
197
205
  ## 5. Write through the model
198
206
 
package/docs/webhooks.md CHANGED
@@ -116,10 +116,10 @@ work asynchronously after responding.
116
116
 
117
117
  ## 2. Test locally
118
118
 
119
- You don't register a `localhost` URL. `npx ablo dev` forwards committed changes
120
- to your machine with a local signing secret the same idea as Stripe's
121
- `stripe listen`. Run your app, run `ablo dev`, and writes flow into your local
122
- handler.
119
+ `npx ablo dev` prepares an isolated schema branch; it does not forward webhook
120
+ deliveries. Register an HTTPS endpoint that Ablo can reach. For local handler
121
+ development, expose your app with the HTTPS tunnel your team already trusts,
122
+ then register that temporary URL and remove the endpoint when you finish.
123
123
 
124
124
  ## 3. Register your endpoint
125
125
 
package/llms.txt CHANGED
@@ -23,9 +23,9 @@ The two MCP servers do different jobs and are the most common mix-up: to change
23
23
 
24
24
  First action when integrating into an app: run `npx ablo init --yes --framework <nextjs|vite|remix|vanilla>`. Agents have no TTY — `--yes` is REQUIRED or it HANGS. It scaffolds `ablo/schema.ts`, the `Ablo({ schema, apiKey })` client, and (for Next.js) the browser provider + session route. All on the current API. Edit the generated files rather than hand-writing from this doc. Connecting a database is a SEPARATE step with one path — logical replication via `npx ablo connect` (see Storage Boundary); the signed Data Source endpoint is the fallback when database credentials must stay inside the app.
25
25
 
26
- 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.
26
+ 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 project-scoped branch-management key locally; an agent must NOT run it. You never copy a runtime key by hand: the next step mints one for the development branch, writes it into `.env.local`, and gitignores it.
27
27
 
28
- 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.
28
+ Then PREPARE THE BRANCH AND PUSH — this is the step everything depends on. The server keeps its OWN copy of the schema. Run `npx ablo dev --no-watch --branch <git-or-ci-ref>`: it ensures an isolated child branch, exchanges the CLI key for an expiring branch-only `sk_test_` key, writes that key to gitignored `.env.local`, pushes `ablo/schema.ts`, and exits. 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. Plain `dev` watches forever; never run it bare in an agent. `push` is the lower-level one-shot command for an already selected credential, including a reviewed production deployment.
29
29
 
30
30
  ## Projects (one org, many apps)
31
31
 
@@ -182,22 +182,23 @@ claims, stale-write rejection, receipts, and deltas, but it does not use a real
182
182
  API key. It also exposes a Claude Code / Codex handoff prompt. Prefer that shape
183
183
  when an agent is asked to "make Ablo work" in an existing app.
184
184
 
185
- Authenticated org sandboxes are real test environments. Treat the default
186
- sandbox like Stripe test mode: it has an isolated sync group prefix and mints
187
- `sk_test_*` keys. The sandbox CAN host rows in Ablo's test plane, so you can try
188
- Ablo with NO database — `apiKey` only, nothing else. (In production, your own
189
- Postgres is the system of record.) Extra sandboxes can start blank or copy live
190
- configuration. Resetting a sandbox creates a clean future stream without
191
- touching live data. Use `sk_live_*` only for production.
185
+ Authenticated development branches are real test environments. `ablo dev`
186
+ derives one from Git and mints an expiring `sk_test_*` key bound to its immutable
187
+ branch id. A branch CAN host rows in Ablo's test plane, so you can try Ablo with
188
+ NO database — `apiKey` only, nothing else. (In production, your own Postgres is
189
+ the system of record.) Branch schemas and rows are isolated from siblings and
190
+ production. There is no shared-sandbox escape hatch. Use `sk_live_*` only for
191
+ production.
192
192
 
193
- For coding agents, the sandbox success path is: pick one shared model,
194
- declare schema, create the Ablo client, replace one direct mutation with a typed
195
- `ablo.<model>.update(...)`, use selector `useAblo` for live reads, and add a
196
- two-writer stale/claim smoke test.
193
+ For coding agents, the development success path is: pick one shared model,
194
+ declare schema, prepare an explicit branch with
195
+ `ablo dev --no-watch --branch <git-or-ci-ref>`, create the Ablo client, replace
196
+ one direct mutation with a typed `ablo.<model>.update(...)`, use selector
197
+ `useAblo` for live reads, and add a two-writer stale/claim smoke test.
197
198
 
198
199
  ## Production
199
200
 
200
- A PLANE is what a credential acts on: `production` is the root, sandboxes sit beside it. Rows, the registered database, and the active schema artifact are all PER PLANE, and a key's plane is fixed at mint by its prefix (`sk_live_` → production, `sk_test_` → sandbox) — there is no runtime override, which is why app code never passes an environment. ONE ASYMMETRY: a sandbox with no schema artifact of its own READS PRODUCTION'S, so a production push reaches sandboxes; a SANDBOX push does NOT reach production — it creates a sandbox artifact that shadows production for that sandbox's readers only. Production gets models when you push to production.
201
+ A PLANE is what a credential acts on: `production` is the root branch and development/preview branches are children. Rows, the registered database, and the active schema artifact are all PER PLANE. A key's immutable branch binding is fixed at mint (`sk_live_` → production; `sk_test_` → one child), so app code never passes an environment. A child copies its parent's active schema at creation and owns its artifact after that. A CHILD push does NOT reach production. Production gets models only when the reviewed deployment pushes to the root.
201
202
 
202
203
  Going live is three things, each done with a `sk_live_` key: register the production database (`ablo connect apply` — the DIRECT host, never a pooler; a pooler refuses in the words of a wrong password), push the schema AHEAD of the code that needs it, and hold the right credential per runtime (server/serverless `sk_live_`; browser `pk_live_` read-only or an `authEndpoint` minting `ek_`). The live key `ablo login` stores is a RESTRICTED observe-only `rk_live_` and CANNOT push schema — a production push needs a dashboard `sk_live_` in `ABLO_API_KEY`. Gate a deploy on `npx ablo status --json` having an EMPTY `blockers` array; each blocker carries a `problem` and the one `fix`. Your agents do NOT each hold a database connection — they talk to Ablo, and Ablo holds at most 4 connections per plane (`application_name = 'ablo-direct-writer'`) however many callers write behind them, so size the database for that number and not for your agent count. Read `deployment` for the full path.
203
204
 
@@ -214,8 +215,9 @@ Import from these public paths only:
214
215
  - `@abloatai/ablo/source/drizzle` — `drizzleDataSource`.
215
216
  - `@abloatai/ablo/source/kysely` — `kyselyDataSource`.
216
217
  - `@abloatai/ablo/source/conformance` — `runDataSourceTests` to prove a custom adapter/handler.
218
+ - `@abloatai/ablo/ai-sdk` — thin AI SDK tools over typed model reads, creates, coordinated updates, and claimed deletes.
217
219
 
218
- Do not teach `/api`, `/agent`, `/ai-sdk`, `/core`, `/realtime`, or internal subpaths. (`/source` IS public it's the Data Source endpoint surface above.)
220
+ Do not teach `/api`, `/agent`, `/core`, `/realtime`, or internal subpaths. (`/source` and `/ai-sdk` are public.)
219
221
 
220
222
  ## CLI: agents run it NON-INTERACTIVELY
221
223
 
@@ -223,10 +225,10 @@ Do not teach `/api`, `/agent`, `/ai-sdk`, `/core`, `/realtime`, or internal subp
223
225
 
224
226
  - `npx ablo init --yes` (flags: `--framework`, `--auth`, `--storage replication|endpoint`, `--no-agent`, `--no-pull`, `--no-install`, `--no-login`). Generates `ablo/schema.ts` + the `Ablo({ schema, apiKey })` client. `--storage replication` (the default) pairs with `ablo connect`; `--storage endpoint` also scaffolds the `ablo/data-source.ts` fallback endpoint.
225
227
  - `npx ablo connect` connects your database via logical replication — the read path (prints the `wal_level=logical` + publication + `REPLICATION`-role SQL); `npx ablo connect register` registers it, `npx ablo connect check` validates the registered database from Ablo's own side and needs only `ABLO_API_KEY` (no database credential in your environment). `npx ablo connect apply` does the whole setup from a one-time admin connection and leaves your app holding only `ABLO_API_KEY`.
226
- - 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`).
228
+ - Key: see "Start here" — env → `.env.local` → ask the human to `npx ablo login`; never run `login` yourself, never copy keys by hand (`ablo dev` mints and wires the temporary branch key).
227
229
  - Adopt an existing DB: `npx ablo pull prisma [path]` / `npx ablo pull drizzle <module>`.
228
- - `npx ablo push` pushes the schema (sandbox) AND writes `ABLO_API_KEY` to `.env.local`. A PRODUCTION push (`sk_live_` key) needs `--yes`: with no TTY it REFUSES rather than deploying unattended, and interactively it demands the destination project typed by name. Destructive steps (dropped model/field, narrowed enum, lossy cast) need `--force`; a new required field on a populated table needs `--backfill model.field=value`. `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.
230
+ - `npx ablo dev --no-watch --branch <git-or-ci-ref>` ensures an isolated branch, mints and wires its temporary key, pushes once, and exits. Plain `dev` watches forever. `npx ablo branch check <id-or-slug>` prints lifecycle, schema/parent compatibility, datasource identity, and readiness. `npx ablo push` pushes with the already selected key and does NOT choose a branch for you. A PRODUCTION push (`sk_live_` key) needs `--yes`: with no TTY it REFUSES rather than deploying unattended, and interactively it demands the destination project typed by name. Destructive steps (dropped model/field, narrowed enum, lossy cast) need `--force`; a new required field on a populated table needs `--backfill model.field=value`. `npx ablo logs --no-follow` exits instead of tailing forever. `npx ablo push`/`status`/`pull`/`check`/`generate` are one-shot.
229
231
 
230
232
  - `npx ablo docs` lists every documentation page; `npx ablo docs <page>` prints one as markdown. These pages ship INSIDE the installed package, so they describe the version in `node_modules` and need no network. Prefer them over a docs URL whenever the project pins a version: a website always describes the newest release, so on an older pin it will hand you a call your package does not have (`retrieve`/`list` replaced `get`/`getAll`/`getCount` in 0.35.0). One-shot, safe to run unattended.
231
233
 
232
- Canonical docs to read before integrating: `quickstart`, `schema-contract`, `integration-guide`, `deployment`, `guarantees`, `client-behavior`, `data-sources`, `examples/existing-python-backend`, `api`, `examples/ai-sdk-tool`, and `examples/server-agent` — read each with `npx ablo docs <page>`. When upgrading an existing integration, read `migration` — every breaking change, what to change, and which version introduced it. When the customer's database has row-level-security policies, read `session-settings` — the identity context Ablo sets before every write, and how to map it to the setting names those policies already read.
234
+ Canonical docs to read before integrating: `quickstart`, `branch-development`, `schema-contract`, `integration-guide`, `deployment`, `guarantees`, `client-behavior`, `data-sources`, `examples/existing-python-backend`, `api`, `examples/ai-sdk-tool`, and `examples/server-agent` — read each with `npx ablo docs <page>`. When upgrading an existing integration, read `migration` — every breaking change, what to change, and which version introduced it. When the customer's database has row-level-security policies, read `session-settings` — the identity context Ablo sets before every write, and how to map it to the setting names those policies already read.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@abloatai/ablo",
3
- "version": "0.37.1",
3
+ "version": "0.38.0",
4
4
  "description": "The public Ablo SDK for coordinated reads, commits, claims, observation, and reactive applications.",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
@@ -70,6 +70,11 @@
70
70
  "import": "./dist/coordination.js",
71
71
  "default": "./dist/coordination.js"
72
72
  },
73
+ "./ai-sdk": {
74
+ "types": "./dist/ai-sdk.d.ts",
75
+ "import": "./dist/ai-sdk.js",
76
+ "default": "./dist/ai-sdk.js"
77
+ },
73
78
  "./wire": {
74
79
  "types": "./dist/wire.d.ts",
75
80
  "import": "./dist/wire.js",
@@ -99,6 +104,9 @@
99
104
  "test": "vitest run",
100
105
  "generate:errors": "tsx scripts/generate-error-docs.mts",
101
106
  "lint:errors": "tsx scripts/check-error-docs.mts",
107
+ "generate:openapi": "tsx --conditions=@ablo/source scripts/generate-openapi.mts",
108
+ "lint:openapi": "tsx --conditions=@ablo/source scripts/generate-openapi.mts --check",
109
+ "validate:openapi": "redocly lint ../../docs/ablo/public/openapi.json --extends=recommended --skip-rule=no-server-example.com",
102
110
  "build:docs": "node scripts/build-blume-docs.mjs",
103
111
  "lint:docs": "node scripts/check-doc-drift.mjs",
104
112
  "lint:pkg": "publint"
@@ -114,13 +122,17 @@
114
122
  "directory": "packages/ablo"
115
123
  },
116
124
  "dependencies": {
117
- "@abloatai/humans": "^0.37.1",
118
- "@abloatai/transaction": "^0.37.1"
125
+ "@abloatai/humans": "^0.38.0",
126
+ "@abloatai/transaction": "^0.38.0"
119
127
  },
120
128
  "peerDependencies": {
129
+ "ai": "^6.0.0 || ^7.0.0",
121
130
  "react": "^19.2.8"
122
131
  },
123
132
  "peerDependenciesMeta": {
133
+ "ai": {
134
+ "optional": true
135
+ },
124
136
  "react": {
125
137
  "optional": true
126
138
  }