anbaric 1.20.0 → 1.21.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/README.md CHANGED
@@ -1,208 +1,380 @@
1
- # anbaric
1
+ # Anbaric
2
2
 
3
- Anbaric is a TypeScript framework for building stateful applications. An
4
- application is expressed as one or more state machines: long-lived jobs move
5
- through named states, driven by actions and transitions, with their data
6
- validated against a schema and every change recorded in an audit trail.
7
- Alongside the state machine the framework provides schema-validated document
8
- storage and secret storage.
3
+ Anbaric is a TypeScript framework for building stateful enterprise applications. Anbaric is designed to help vibe-coded applications go the last mile, by providing persistence, state management, authentication and auditing.
9
4
 
10
- Anbaric also provides a platform for deploying the applications built on it. The
11
- same application runs unchanged on a developer's machine, on a server you
12
- operate, or on Anbaric Cloud, where a single CLI command deploys it. Application
13
- code depends only on the interfaces in this package; the framework selects
14
- in-memory or platform-backed implementations from the environment, so no
15
- deployment detail appears in the code.
5
+ We believe that fully bespoke software is the future, and this project was created to help a wider range of people build their own solutions, without compromising enterprise IT standards.
16
6
 
17
- This package (`anbaric`) is the umbrella install for writing an application. It
18
- re-exports the app-facing surface of the underlying packages.
7
+ ## Getting started
8
+
9
+ Install the Anbaric package and the CLI:
19
10
 
20
11
  ```bash
12
+ npm init
21
13
  npm install anbaric
14
+ npm install -g anbaric-cli
22
15
  ```
23
16
 
24
- An Anbaric application is a standard Node.js ESM program written in TypeScript:
25
- set `"type": "module"` in `package.json`, point `main` at the TypeScript entry
26
- file, and run it with `tsx`.
27
-
28
- ## State machines
29
-
30
- A **`StateMachine`** defines a workflow. It is constructed with an identifier, a
31
- list of states, the name of the start state, and the property schema for its
32
- jobs.
33
-
34
- - A **`State`** is a named step. It holds a list of **actions** to run while a
35
- job sits in that state, and a list of **transitions** to the next state.
36
- - An **`Action`** is a unit of work. Its `run` function receives the job and
37
- returns a `Map` of property changes: `run(job) => Promise<Map<string, any>>`.
38
- An action does not mutate the job directly; the returned properties are
39
- validated and applied by the machine. Each action declares the **actor** that
40
- performs it.
41
- - A **`Transition`** names a target state and carries a predicate over the job.
42
- When a job is processed, the first transition whose predicate holds moves the
43
- job to that state.
44
- - A **`Job`** is one instance moving through the machine. It carries an
45
- identifier, its current `state`, a `Map` of `properties`, and provenance
46
- (`workflowId`, `startedBy`, `startedAt`, `lastUpdated`). Jobs are immutable;
47
- each change produces a new version.
48
- - A **`PropertyDefinition`** describes one property a job may carry: whether it
49
- is required and how its value is validated. Every property a job holds —
50
- including properties set by actions — must have a definition, or the change is
51
- rejected.
52
- - An **`Actor`** identifies who performs an operation, for authorization and
53
- auditing. The actor types are `Code`, `Human`, `Agent` and `System`. `Code`
54
- actions run automatically as jobs are processed; a `Human` or `Agent` actor
55
- represents work performed by a person or an autonomous agent.
56
-
57
- A job progresses automatically as it is processed: matching actions run, their
58
- properties are applied, and the first satisfied transition advances the state.
59
- This repeats until the job reaches a state from which nothing more applies.
17
+ Prompt your agent:
60
18
 
61
- There are three ways to influence a job:
19
+ ```
20
+ Use Anbaric to build me a CRM.
21
+ ```
22
+
23
+ Run locally as usual (`npm run start`) or deploy to the Anbaric Cloud (`anbaric app deploy`).
24
+
25
+ Anbaric is open source and you can self-host the platform or sign up at https://cloud.anbaric.ai to use the hosted version.
62
26
 
63
- - `startJob(properties?, actor?)` creates a job in the start state.
64
- - `updateJob(jobId, properties, actor)` applies an explicit property change.
65
- - `executeAction(jobId, action)` runs a single action immediately.
66
- - Actions subscribed to a state run automatically whenever a job in that state
67
- is processed.
27
+ ## Documentation
68
28
 
69
- Every operation is validated against the schema and written to the audit trail,
70
- which records the resource, the actor, the interactions (create, update, state
71
- change, delete, read), and a description of what changed.
29
+ A full user guide split into **features**, **patterns** and **API reference**
30
+ (TypeScript and web) lives in [`anbaric/docs`](anbaric/docs/README.md). Start
31
+ with [Core concepts](anbaric/docs/features/core-concepts.md), then the
32
+ [Build your first app](anbaric/docs/patterns/first-app.md) walkthrough.
72
33
 
73
- ## Documents and secrets
34
+ ## What the code looks like
74
35
 
75
- For data that does not belong to a job, the framework provides two stores,
76
- obtained from factories and used with an actor for auditing.
36
+ Anbaric has a collection of features that can be used in your application. Here are some examples:
77
37
 
78
- - **`JsonStore`** stores JSON documents in named collections, optionally
79
- validated against a JSON Schema.
80
- - **`SecretStore`** stores named secret strings, encrypted at rest, and never
81
- records secret values in the audit trail.
38
+ ### Persist JSON
39
+
40
+ In this example we will store a customer's details in a JSON document. Every change that is made in Anbaric requires an `Actor` to be specified, which is used to ensure a complete audit trail exists for any application built using Anbaric. In general, an actor will be either a "human" actor, an AI agent or code being executed by the system.
41
+
42
+ When your app serves a page to a signed-in user, `Human.fromSession` turns that request into the human actor behind it — it resolves the browser's platform session (the `anbaric_session` cookie) against the platform, so the audit trail names the real user. Pass it the incoming request (or the session token directly). Outside a request — a seed script or system code — construct the actor yourself, e.g. `new Human("ada", ["admin"])` or a `Code` actor.
82
43
 
83
44
  ```ts
84
- import {Human, JsonStoreFactory, SecretStoreFactory} from "anbaric";
45
+ import {Human, JsonStoreFactory} from "anbaric";
85
46
 
86
- const actor = new Human("ada", "admin");
47
+ // inside your app's HTTP handler, `request` is the incoming browser request
48
+ const actor = await Human.fromSession(request);
49
+ const customers = JsonStoreFactory.instance("customers");
50
+
51
+ await customers.create(actor, "ada", { name: "Ada Lovelace", email: "ada@example.com" });
52
+ const ada = await customers.retrieve("ada", actor);
53
+ ```
87
54
 
88
- const customers = JsonStoreFactory.instance("customers", {
89
- type: "object",
90
- required: ["name"],
91
- properties: { name: { type: "string" } },
55
+ ### Run a state machine
56
+
57
+ A state machine models work as jobs moving through named states. Actions run while a job sits in a state, and transitions decide where it goes next. A state machine can combine steps using different types of actors, so humans can own some action, AI agents and code can automate others.
58
+
59
+ ```ts
60
+ import {Action, Code, PropertyDefinition, State, StateMachine, Transition} from "anbaric";
61
+
62
+ const sendWelcome = new Action("Send welcome email", new Code("welcome"));
63
+ sendWelcome.run = async (job) => {
64
+ // Access properties stored against the job
65
+ const email = job.properties.get("email");
66
+ // Run some code
67
+ console.log(`Sending welcome email to ${email}`);
68
+ // Return new properties to add to the job
69
+ const newProperties = new Map();
70
+ newProperties.set("emailSent", true);
71
+ return newProperties;
72
+ };
73
+
74
+ const onboarding = new StateMachine("onboarding", [
75
+ new State("new", [sendWelcome], [new Transition("active", (job) => job.properties.get("emailSent") === true)]),
76
+ new State("active"),
77
+ ]);
78
+
79
+ const customer = await onboarding.startJob(new Map([["email", "ada@example.com"]]));
80
+ ```
81
+
82
+ The job starts in `new`; when it is processed the action runs, sets `emailSent`, and the transition advances it to `active`.
83
+
84
+ ### Using AI agents to automate states
85
+
86
+ An **agent** is an actor whose properties are produced by a model rather than by
87
+ hand-written code. A `RemoteLLMAgenticAction` gives the agent a prompt and a JSON
88
+ Schema, and applies the properties it returns to the job. Here an OpenAI-backed
89
+ agent triages a support ticket:
90
+
91
+ ```ts
92
+ import {OpenAIAgent, RemoteLLMAgenticAction, State, StateMachine, Transition} from "anbaric";
93
+
94
+ const triager = new OpenAIAgent("triager", "support", {
95
+ apiKey: process.env.OPENAI_API_KEY!,
96
+ model: "gpt-5.4-mini",
92
97
  });
93
- await customers.create(actor, "ada", { name: "Ada" });
94
- const record = await customers.retrieve("ada", actor);
95
98
 
96
- const secrets = SecretStoreFactory.instance();
97
- await secrets.create(actor, "api-key", "s3cr3t");
99
+ const triage = new RemoteLLMAgenticAction(
100
+ "Triage the ticket",
101
+ triager,
102
+ [{ role: "system", content: "Decide the priority of the support ticket from its subject." }],
103
+ { type: "object", properties: { priority: { type: "string", enum: ["low", "high"] } } },
104
+ );
105
+
106
+ const support = new StateMachine("support", [
107
+ new State("open", [triage], [new Transition("prioritised", (job) => job.properties.has("priority"))]),
108
+ new State("prioritised"),
109
+ ]);
98
110
  ```
99
111
 
100
- ## Running and deploying
101
-
102
- Persistence, queueing and consumers are supplied by environment-driven
103
- factories, so the same application runs in several ways without code changes.
104
-
105
- - **Local.** With no environment configured, every store, queue and consumer is
106
- in-memory and jobs progress automatically. Running the program with
107
- `npx tsx src/main.ts` is a complete local run, suitable for development and
108
- testing.
109
- - **Anbaric Cloud.** `anbaric app deploy` packages the application (source only, no
110
- `node_modules`) and runs it on the hosted platform. The platform installs the
111
- application's own dependencies as it builds the image, so any npm package the
112
- application imports works when deployed. The platform injects the configuration
113
- that points the factories at platform-backed persistence, queueing, documents
114
- and secrets; application code is unchanged. Authentication, job inspection and
115
- updates are available through the CLI.
116
- - **Self-hosted.** The [`anbaric-hosting`](https://npmjs.com/package/anbaric-hosting)
117
- package runs the platform — the API, dispatcher, build layer and app proxy —
118
- on infrastructure you operate, backed by Postgres.
112
+ Because the agent is just another actor, its work is audited like any other —
113
+ the triage decision is attributed to `triager`.
119
114
 
120
- Applications should not set the `ANBARIC_*` factory variables themselves; the
121
- platform sets them when the application is deployed.
115
+ ### Wait for human input
116
+
117
+ Sometimes a job cannot progress by itself — it needs a person to approve
118
+ something, fill in a form, or make a decision. An **`Await`** is a step in a
119
+ state's action list that *pauses* the job instead of running: when a job reaches
120
+ it, the job is parked in the **`Awaiting input`** status and is not processed
121
+ again until its properties are updated. Point people at wherever they provide
122
+ that input with a **`resolveUrl`** — a function of the job, so you can build a
123
+ per-job link with the job id (and anything else) in the query string.
122
124
 
123
- ## Example
125
+ Here an order waits for a human to approve it. The app serves a small approval
126
+ UI at `/approve` (any framework — the page itself is omitted here); it reads the
127
+ job id from the query string, collects the decision, and calls
128
+ `updateJob(jobId, { approved: true }, actor)`. The `Await` sends the reviewer
129
+ there, and a transition moves the job on once `approved` is set:
124
130
 
125
131
  ```ts
126
- import {Action, Code, PropertyDefinition, State, StateMachine, Transition} from "anbaric";
132
+ import {Await, State, StateMachine, Transition} from "anbaric";
127
133
 
128
- const name = new PropertyDefinition("name");
129
- name.required = true;
134
+ const approve = new Await("Approve the order", "HUMAN");
135
+ approve.fields = ["approved"]; // the input we expect back
136
+ approve.resolveUrl = (job) => `/approve?job=${job.id}`; // where the human provides it
130
137
 
131
- const email = new PropertyDefinition("email");
132
- email.required = true;
138
+ const fulfilment = new StateMachine("fulfilment", [
139
+ new State("review", [approve], [new Transition("approved", (job) => job.properties.get("approved") === true)]),
140
+ new State("approved"),
141
+ ]);
133
142
 
134
- const welcomeSent = new PropertyDefinition("welcomeSent");
135
- welcomeSent.validation = (value) => typeof value === "boolean";
143
+ const order = await fulfilment.startJob(new Map([["total", 4200]]));
144
+ // The job reaches `approve`, parks in "Awaiting input", and waits.
145
+ // When the approval UI calls updateJob(order.id, { approved: true }, actor),
146
+ // the job resumes, the transition fires, and it advances to `approved`.
147
+ ```
136
148
 
137
- const sendWelcome = new Action("Send welcome email", new Code("send-welcome"));
138
- sendWelcome.run = async (job) => {
139
- // ... send the email to job.properties.get("email") ...
140
- return new Map([["welcomeSent", true]]);
141
- };
149
+ The pause is recorded in the audit trail, and the [awaiting-input
150
+ widget](#the-admin-console-and-widgets) lists every parked job with a
151
+ clickable `resolveUrl` for those awaiting a human. Pass `"EXTERNAL_SYSTEM"`
152
+ instead of `"HUMAN"` when the input will come from another service rather than a
153
+ person.
142
154
 
143
- const onboarding = new StateMachine(
144
- "customer-onboarding",
145
- [
146
- new State("new", [sendWelcome], [
147
- new Transition("active", (job) => job.properties.get("welcomeSent") === true),
148
- ]),
149
- new State("active"),
150
- ],
151
- "new",
152
- [name, email, welcomeSent],
153
- );
155
+ ### Use an RDBMS
156
+
157
+ A full relational store is available for structured data. Locally it is SQLite; deployed, it is the tenant's PostgreSQL.
158
+
159
+ ```ts
160
+ import {Human, SqlStoreFactory} from "anbaric";
161
+
162
+ const actor = new Human("ada", "admin");
163
+ const sql = SqlStoreFactory.instance();
154
164
 
155
- const job = await onboarding.startJob(new Map([["name", "Ada"], ["email", "ada@example.com"]]));
165
+ await sql.execute(actor, "CREATE TABLE IF NOT EXISTS notes (id INTEGER PRIMARY KEY, body TEXT)");
166
+ await sql.execute(actor, "INSERT INTO notes (body) VALUES (?)", ["hello"]);
167
+ const rows = await sql.query(actor, "SELECT id, body FROM notes");
156
168
  ```
157
169
 
158
- The job starts in `new`. When it is processed the `sendWelcome` action runs and
159
- sets `welcomeSent`, and the transition then advances the job to `active`. Run
160
- locally this happens automatically in memory; deployed, it happens on the
161
- platform.
170
+ ### Serve a web UI
162
171
 
163
- ## Command-line interface
172
+ An app can serve its own HTTP frontend. Listen on `process.env.PORT` and the
173
+ platform's app proxy serves it at `<platform>/app/<name>/*`, stripping the
174
+ `/app/<name>` prefix before the request reaches your app — combine it with the
175
+ persistence and state-machine APIs above to put your data on a page. See
176
+ [Web APIs](anbaric/docs/api/web.md) for the full proxy contract (forwarded
177
+ headers, the absolute-URL caveat).
164
178
 
165
- The [`anbaric`](https://npmjs.com/package/anbaric-cli) CLI authenticates a
166
- terminal, deploys applications, and inspects and drives jobs on a platform. The
167
- principal commands are:
179
+ ```ts
180
+ import {createServer} from "node:http";
181
+
182
+ createServer((request, response) => {
183
+ response.writeHead(200, { "content-type": "text/html" });
184
+ response.end("<h1>My Anbaric app</h1>");
185
+ }).listen(Number(process.env.PORT ?? 3000));
186
+ ```
187
+
188
+ Serve trivial pages directly like this; build richer UIs with React and the
189
+ Anbaric design system (`anbaric-design-system`). `sample-apps/crm` is a complete
190
+ worked example — an HTTP server that renders its customers as HTML and exposes a
191
+ JSON API backed by a state machine.
192
+
193
+ ## Auditing
194
+
195
+ Every write to a job, document, secret or the SQL store is recorded against the
196
+ actor that made it — which is why the store methods take an actor. An audit
197
+ record captures the actor, the resource, the interaction (create, update, state
198
+ change, delete, kill…) and a short description. Locally the records print to the
199
+ console; deployed, the platform persists them and they are browsable in the
200
+ admin console. Reads and lists can be audited too, but the platform masks them
201
+ by default to keep the volume down.
202
+
203
+ ## Using the CLI
204
+
205
+ `anbaric-cli` authorizes your terminal against a platform, deploys apps, and
206
+ inspects and drives their jobs. After a one-time `anbaric login` (a browser
207
+ flow), a typical loop is:
208
+
209
+ ```bash
210
+ anbaric app deploy # deploy the current project and wait until it is live
211
+ anbaric jobs list # list jobs and their states
212
+ anbaric jobs watch <job-id> # follow a job as it progresses
213
+ anbaric jobs stats # counts per state and the queue depth
214
+ ```
215
+
216
+ Every interactive prompt also has a flag, so the CLI runs unattended in scripts
217
+ and CI. The full command list is in the [CLI reference](#cli-reference) below.
218
+
219
+ ## The Admin console and widgets
220
+
221
+ The platform serves an admin console at its root — a dashboard assembled from
222
+ **plugins**. The built-in `anbaric-plugins/state-machines` plugin lists your
223
+ state machines and their jobs. You add your own pages and widgets by writing a
224
+ small plugin — a `pages`/`widgets` object — and naming it in `ANBARIC_PLUGINS`.
225
+ Widgets are React components, optionally backed by a server-side data function,
226
+ rendered with the platform's design system. See
227
+ [`anbaric-plugins`](anbaric-plugins/README.md).
228
+
229
+ ## State machine deep-dive
230
+
231
+ A **`StateMachine`** is constructed from a workflow id, its `State`s, the start
232
+ state, and the property schema for its jobs. A **`State`** holds the **actions**
233
+ that run while a job sits in it and the **transitions** to other states. An
234
+ **`Action`** has a `run` function returning the property changes to apply — it
235
+ never mutates the job directly. A **`Transition`** names a target state and a
236
+ predicate; the first transition whose predicate holds moves the job. A **`Job`**
237
+ is one instance moving through the machine, carrying its `properties`, its
238
+ current `state`, and its history. A state can be marked terminal (or use the
239
+ `Terminal` helper, which carries a `SUCCESS`/`FAILURE` outcome); a job that
240
+ reaches one stops and is not processed again.
241
+
242
+ Every action also declares the **actor** it runs as (`Code`, `Human` or
243
+ `Agent` — pure identity objects), recorded for auditing and authorization.
244
+ There are three ways to influence a job:
245
+
246
+ 1. **Update it directly**, declaring who is acting:
247
+ `machine.updateJob(jobId, new Map([["approved", true]]), new Human("chris", "manager"))`.
248
+ 2. **Execute an action directly** — the actor is embedded in the action:
249
+ `machine.executeAction(jobId, approveAction)`.
250
+ 3. **Subscribe an action to a state** — pass it in the `State` constructor or
251
+ call `state.subscribe(action)`, and it runs (predicate permitting)
252
+ whenever a job is processed in that state.
253
+
254
+ Whichever way, property changes are schema-validated and audited, and each
255
+ job carries its history: who started it, every from→to transition and the
256
+ actor that made it.
257
+
258
+ A state's action list may also contain an **`Await`** — a pause point rather
259
+ than an actor acting. When a job reaches one it stops running actions and is
260
+ parked: its `status` becomes `Awaiting input` (distinct from its `state`), and
261
+ it holds a **`WaitForInput`** describing what is expected — the `fields`, a
262
+ resolved `resolveUrl`, whether a `HUMAN` or `EXTERNAL_SYSTEM` is expected, and
263
+ any metadata the `Await` computed for the job. A parked job is not re-processed
264
+ until an `updateJob` arrives; on resume it skips its actions and only
265
+ re-evaluates its transitions, so the input drives it on and the wait clears once
266
+ it moves to another state. Actions placed after an `Await` in the same state do
267
+ not run when the job resumes.
268
+
269
+ Everything is pluggable through env-driven factories: locally (no env vars)
270
+ you get in-memory persistence and queueing; deployed, the same factories talk
271
+ to the platform automatically. The same applies to `JsonStoreFactory`
272
+ (schema-validated documents), `SecretStoreFactory` (encrypted secrets) and
273
+ `SqlStoreFactory` (a relational store) from `anbaric-data-store`.
274
+
275
+ The SQL store is backed by SQLite locally (in-memory by default) and, once
276
+ deployed, by the tenant's PostgreSQL in a schema named after your app — its own,
277
+ isolated from every other app in the tenant. Write portable SQL where you can — the two
278
+ differ in a few places, notably parameter placeholders (`?` for SQLite, `$1`
279
+ for PostgreSQL); see the [`anbaric-data-store`](anbaric-data-store/README.md)
280
+ docs for the full list.
281
+
282
+ If your app serves HTTP, listen on `process.env.PORT` and users reach it at
283
+ `<platform>/app/<name>`. All front-end must be React and use the Anbaric
284
+ design system (`anbaric-design-system`) — see the living style guide by
285
+ opening `anbaric-design-system/dist/index.html`.
286
+
287
+ ## Run it locally
288
+
289
+ With no `ANBARIC_*` variables set, the factories return the in-memory
290
+ persistence, queue and stores, so the program runs entirely in-process — no
291
+ database or platform involved. Run the TypeScript entry file directly with tsx;
292
+ `npx` fetches it on demand if your project doesn't already depend on it:
293
+
294
+ ```bash
295
+ npx tsx src/main.ts
296
+ ```
297
+
298
+ Jobs are held in memory and progress as the in-memory consumer delivers them;
299
+ the state is gone when the process exits. This is the mode for development and
300
+ tests.
301
+
302
+ ## Deploy it
303
+
304
+ ```bash
305
+ npm install -g anbaric-cli # once; provides the anbaric command
306
+ anbaric login # pick a platform; a browser authorizes this terminal
307
+ anbaric app configure # writes .anbaric/app-config.json (name + internal port)
308
+ anbaric app deploy # packs, uploads, bakes an image, waits until live
309
+ ```
310
+
311
+ `app deploy` returns once the app is actually up — its built-in admin port
312
+ answers the platform's liveness ping. Watch it
313
+ work with `anbaric apps`, `anbaric jobs list [state-machine]`, and
314
+ `anbaric jobs watch <job-id>`. The `app` commands run from anywhere inside the
315
+ project — they walk up to the nearest `package.json`.
316
+
317
+ ### What deployment does (and expects)
318
+
319
+ The platform unpacks your upload onto a pre-canned base image, installs the
320
+ app's dependencies, bakes a Docker image and runs it as a container. One thing
321
+ it does **not** do:
322
+
323
+ - **No build step.** `npm run build` is never run — your TypeScript source is
324
+ executed directly (via tsx). Ship source, not `dist/`.
325
+
326
+ Dependencies, though, *are* installed: the image runs `npm install` for the
327
+ app's declared dependencies (the `anbaric-*` packages and any others), so
328
+ ordinary npm dependencies work. Only source is uploaded — `node_modules` is
329
+ not.
330
+
331
+ An app must have:
332
+
333
+ - `package.json` with `main` pointing at the entry file (e.g. `src/main.ts`)
334
+ and `"type": "module"`.
335
+ - `.anbaric/app-config.json` with a `name` (lowercase letters, numbers, `-`,
336
+ `_`) and an `internalPort` — `anbaric app configure` creates it, and
337
+ `app deploy` prompts if it's missing.
338
+
339
+ A built-in admin process answers the platform's liveness check, so an app needs
340
+ no HTTP server of its own to deploy. If it does serve HTTP (reached through the
341
+ app proxy), it listens on `process.env.PORT`. The platform injects all wiring as
342
+ env vars (`ANBARIC_*_TYPE=cloud`, the platform URL, the consumer and admin
343
+ ports) — never hardcode these.
344
+
345
+ ## CLI reference
168
346
 
169
347
  | Command | Purpose |
170
348
  | --- | --- |
171
- | `anbaric login` / `anbaric logout` | authorize this terminal against a platform, or revoke it |
172
- | `anbaric apps` | list deployed applications |
173
- | `anbaric app configure` | set an application's name and internal port |
174
- | `anbaric app deploy` | deploy an application and wait until it is live |
175
- | `anbaric app update` | deploy over a running application without prompting |
176
- | `anbaric app status <name>` | show an application's deploy state and whether it is up |
177
- | `anbaric app tail <name>` | stream an application's runtime logs |
178
- | `anbaric app tear-down <name>` | stop and remove a deployed application |
349
+ | `anbaric login` | choose a platform and authorize this terminal (browser flow; keypair saved to `~/.anbaric/`) |
350
+ | `anbaric apps` | list deployed apps |
351
+ | `anbaric app configure` | create or update `.anbaric/app-config.json` |
352
+ | `anbaric app deploy` | deploy the app (prompts before replacing a running one) |
353
+ | `anbaric app update` | deploy, replacing without prompting |
354
+ | `anbaric app status <name>` | show an app's deploy state and whether it is up |
355
+ | `anbaric app tail <name>` | stream an app's runtime logs |
356
+ | `anbaric app tear-down <name>` | stop and remove a deployed app |
179
357
  | `anbaric state-machines` | list registered state machines |
180
358
  | `anbaric jobs create <sm-id> <start-state> [k=v ...]` | create a job and queue it for processing |
181
359
  | `anbaric jobs list [state-machine-id]` | list jobs |
182
360
  | `anbaric jobs stats` | job counts per state and the queue size |
183
- | `anbaric jobs watch <job-id>` | follow a job's state as it changes |
184
- | `anbaric jobs set-state <job-id> <state>` | move a job to a state and re-queue it |
185
- | `anbaric jobs update <job-id> <key=value ...>` | change job properties and re-queue |
361
+ | `anbaric jobs watch <job-id>` | follow a job's state live |
362
+ | `anbaric jobs set-state <job-id> <state>` | move a job and re-queue it |
363
+ | `anbaric jobs update <job-id> <key=value ...>` | update job properties and re-queue |
186
364
  | `anbaric jobs kill <job-id>` | kill a job so it stops progressing |
187
365
  | `anbaric jobs kill-old <age>` | kill jobs not updated within `<age>` (e.g. `24h`, `7d`) |
188
366
 
189
- The `app configure`/`deploy`/`update` commands act on the application for the
190
- current project, located by walking up to the nearest `package.json`, so they
191
- run from anywhere inside it.
192
-
193
- Every command accepts flags (such as `--environment`, `--tenant`, `--name`,
194
- `--port`, `--yes`) that supply the answers a prompt would otherwise ask for, so
195
- the CLI can be run non-interactively in scripts and CI. See the
196
- [`anbaric-cli`](https://npmjs.com/package/anbaric-cli) documentation for the
197
- full command and flag reference.
367
+ All commands accept `--platform-url` and `--tenant`; `login` sets the
368
+ defaults. Manage your CLI keys in the browser at `<platform>/manage-keys`.
198
369
 
199
370
  ## Packages
200
371
 
201
- `anbaric` re-exports these packages; install them individually for a narrower
202
- dependency.
372
+ `anbaric` is the umbrella install for writing an application — it re-exports the
373
+ app-facing surface of the packages below. Install them individually for a
374
+ narrower dependency.
203
375
 
204
376
  - [`anbaric-tsapi`](https://npmjs.com/package/anbaric-tsapi) — the interfaces
205
- and value classes: `Job`, `State`, `Action`, `Transition`, `Actor`,
377
+ and value classes: `Job`, `State`, `Action`, `Await`, `Transition`, `Actor`,
206
378
  `JobPersistence`, `JsonStore`, `SecretStore`, `Auditor`.
207
379
  - [`anbaric-state-machine`](https://npmjs.com/package/anbaric-state-machine) —
208
380
  the `StateMachine`, actors, and in-memory implementations.
@@ -213,3 +385,24 @@ dependency.
213
385
  - [`anbaric-cli`](https://npmjs.com/package/anbaric-cli) — the platform CLI.
214
386
  - [`anbaric-hosting`](https://npmjs.com/package/anbaric-hosting) — run a
215
387
  platform yourself.
388
+
389
+ Applications should not set the `ANBARIC_*` factory variables themselves; the
390
+ platform sets them when the application is deployed, so the same code runs
391
+ in-memory locally and platform-backed once deployed.
392
+
393
+ ## Run your own platform
394
+
395
+ `npm install -g anbaric-hosting` provides the full hosting service - API,
396
+ dispatcher, build layers and proxy - bootable with the `anbaric-hosting`
397
+ command and configured entirely through `ANBARIC_*` environment variables.
398
+
399
+ ## Run a platform locally
400
+
401
+ ```bash
402
+ cd gitops/local
403
+ tofu init && tofu apply # Docker Desktop: Postgres + the platform on :8787
404
+ ```
405
+
406
+ See `gitops/README.md` for staging/prod and for enabling Auth0 login.
407
+ `sample-apps/crm` is a complete worked example — deploy it by running
408
+ `anbaric app deploy` from inside `sample-apps/crm`.
package/docs/README.md ADDED
@@ -0,0 +1,59 @@
1
+ # Anbaric user guide
2
+
3
+ Everything you need to build a real application on Anbaric — from your first
4
+ state machine to a deployed app with a human-in-the-loop workflow, a database, a
5
+ web UI and an audit trail.
6
+
7
+ Anbaric models an application as one or more **state machines**: long-lived
8
+ **jobs** move through named **states**, driven by **actions** and **transitions**,
9
+ with their data validated against a schema and every change recorded. The same
10
+ code runs in-memory on your laptop and platform-backed once deployed — you never
11
+ write deployment details into your app.
12
+
13
+ New here? Read [Core concepts](features/core-concepts.md), then work through the
14
+ [Build your first app](patterns/first-app.md) walkthrough.
15
+
16
+ ## Features
17
+
18
+ What the framework gives you, one capability at a time.
19
+
20
+ - [Core concepts](features/core-concepts.md) — jobs, states, actions, transitions, actors
21
+ - [State machines](features/state-machines.md) — defining and running a workflow
22
+ - [Actions and actors](features/actions-and-actors.md) — who does the work, and how
23
+ - [Awaiting input](features/awaiting-input.md) — pausing a job for a human or external system
24
+ - [AI agents](features/ai-agents.md) — letting a model drive a state
25
+ - [Documents and secrets](features/documents-and-secrets.md) — the JSON and secret stores
26
+ - [The SQL store](features/sql-store.md) — a relational database for structured data
27
+ - [Auditing](features/auditing.md) — the record of who changed what
28
+ - [Serving a web UI](features/serving-a-web-ui.md) — putting your data on a page
29
+ - [The admin console and widgets](features/admin-console-and-widgets.md) — dashboards and plugins
30
+ - [Deploying](features/deploying.md) — from laptop to Anbaric Cloud
31
+
32
+ ## Patterns
33
+
34
+ How to put the features together to build something real.
35
+
36
+ - [Build your first app](patterns/first-app.md) — an end-to-end walkthrough
37
+ - [Structuring an application](patterns/app-structure.md) — files, entry point, wiring
38
+ - [Modelling a workflow](patterns/modelling-workflows.md) — turning a process into states
39
+ - [Human-in-the-loop](patterns/human-in-the-loop.md) — approvals, forms and hand-offs
40
+ - [Integrating external systems](patterns/integrating-external-systems.md) — waiting on callbacks and webhooks
41
+ - [Authorization with actors and roles](patterns/authorization.md) — who is allowed to do what
42
+ - [Testing your app](patterns/testing.md) — driving a machine in memory
43
+
44
+ ## API reference
45
+
46
+ The surface you build against.
47
+
48
+ - [TypeScript API](api/typescript.md) — the full app-facing library
49
+ - [State machines](api/state-machine.md) — `StateMachine`, `State`, `Action`, `Await`, `Transition`, `Job`, `PropertyDefinition`
50
+ - [Actors and agents](api/actors-and-agents.md) — `Code`, `Human`, `Agent`, AI actions
51
+ - [Stores](api/stores.md) — `JsonStore`, `SecretStore`, `SqlStore` and their factories
52
+ - [Environment and factories](api/environment.md) — the `ANBARIC_*` variables
53
+ - [Web APIs](api/web.md) — serving HTTP, the app proxy, and the platform endpoints you call
54
+ - [CLI reference](api/cli.md) — the `anbaric` command
55
+
56
+ ---
57
+
58
+ Everything in this guide is app-author-facing: the public library, the CLI and
59
+ the web surface. You never need to know how the platform is built to build on it.