@akterjs/cli 0.1.0 → 0.1.2

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,17 +1,17 @@
1
1
  # @akterjs/cli
2
2
 
3
- The Akter CLI, also published as [`akter`](https://www.npmjs.com/package/akter) so `npx akter` runs it.
3
+ The Akter CLI. Installed, its command is `akter`; without installing, run it as `npx @akterjs/cli`.
4
4
 
5
5
  ## Start
6
6
 
7
7
  ```sh
8
- npx akter signup --email you@example.com # emails a code; creates your account
9
- npx akter organizations create --name acme
10
- npx akter apps create --organization acme --name notes
11
- npx akter deploy --organization acme --app notes # bundles src/app.layer.ts and deploys it
8
+ npx @akterjs/cli signup --email you@example.com # emails a code; creates your account
9
+ npx @akterjs/cli organizations create --name acme
10
+ npx @akterjs/cli apps create --organization acme --name notes
11
+ npx @akterjs/cli deploy --organization acme --app notes # bundles src/app.layer.ts and deploys it
12
12
  ```
13
13
 
14
- The CLI talks to Akter Cloud at `https://api.akter.dev` unless `--url` or `AKTER_CLOUD_URL` names another. `npx akter dev` runs your app on a local folder with no account, and `npx akter docs` prints these docs in the terminal. Agent apps can do the same through the MCP server at `https://mcp.akter.dev/mcp`.
14
+ The CLI talks to Akter Cloud at `https://api.akter.dev` unless `--url` or `AKTER_CLOUD_URL` names another. `npx @akterjs/cli dev` runs your app on a local folder with no account, and `npx @akterjs/cli docs` prints these docs in the terminal. Agent apps can do the same through the MCP server at `https://mcp.akter.dev/mcp`.
15
15
 
16
16
  Docs: https://docs.akter.dev. Pricing: https://docs.akter.dev/pricing.
17
17
 
@@ -36,7 +36,7 @@ The `akter` command, built on `effect/cli`:
36
36
  - `akter docs [topic]`: prints the pages of `apps/docs/content`, which `generate` embeds, as Markdown; `--json` prints one line of JSON.
37
37
  - Prompts: `Confirmation` (`src/terminal/`) asks only when stdin and stdout are terminals (`TerminalCapabilities.canPrompt`); otherwise it exits 4 at once, so a script or an agent never hangs on a question. `Approval` (`src/registry/approval.service.ts`) uses it for a registry command's confirmation, and turns the API's 428 `ConfirmationRequiredError` into an approval: at a terminal it requests the emailed code, asks for it, confirms it into a token and retries the command once with it; without one it exits 4 with reason `ApprovalRequired` and the `akter approvals` steps. The token is never printed.
38
38
  - Exit codes (`CliExitError.codes`): 0 done, 1 failed, 2 usage (and HTTP 400 or 422), 3 authentication (not signed in, HTTP 401 or 403), 4 confirmation or approval needed or declined (and HTTP 428), 5 unavailable (unreachable, timeout, HTTP 408, 429 or 5xx), 130 interrupted. With `--json`, a failure the CLI detects prints `CliExitError`'s JSON (`code`, `reason`, `message`) on stdout.
39
- - One program, two bins: `src/command/akter-program.config.ts` exports `runAkter`, which runs the command on the process's arguments, and `@akterjs/cli/program` exports it. This package's `akter` bin and the unscoped `akter` package's both call it, so `npx akter` is this CLI (ADR 0009). `akter --version` prints the package's version, which `generate` writes into `.generated`, so it follows the lockstep release version.
39
+ - One program, two bins: `src/command/akter-program.config.ts` exports `runAkter`, which runs the command on the process's arguments, and `@akterjs/cli/program` exports it. This package's `akter` bin and the unscoped `akter` package's both call it, so it is this CLI (ADR 0009); npm refused to publish the unscoped name, so `npx @akterjs/cli` is the way to run it without installing. `akter --version` prints the package's version, which `generate` writes into `.generated`, so it follows the lockstep release version.
40
40
  - Startup: `pnpm build && pnpm measure:startup` times spawn to first output for local commands on Node and Bun (`scripts/measure-startup.cli.ts`); the target is p95 ≤ 300 ms.
41
41
 
42
42
  An operation behind a feature flag (its `x-akter` hint names one, akter-cloud ADR 0030) still runs when named, but is left out of help and unknown-command suggestions, as is a group whose every command is flagged. The baked-in spec cannot tell which flags an organization has; the Cloud API refuses an organization without the flag. This also applies to the joined `actors fork` command: Cloud forks are behind `cloudFork`, default off. A named fork at a loopback URL still works on `akter dev`, which has no flags. The MCP server hides `actors_fork` from everyone until it can read organization flags; it never falls back to the Cloud-forbidden actor RPC.
@@ -7019,7 +7019,7 @@ const spec = {
7019
7019
  ]
7020
7020
  };
7021
7021
  // .generated/compiled/package-version.adapter.js
7022
- const version = "0.1.0";
7022
+ const version = "0.1.2";
7023
7023
  // src/command/akter-program.config.ts
7024
7024
  const main = gen(function* main() {
7025
7025
  const operations = yield* operationsOf(spec).pipe(orDie);
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { t as runAkter } from "./akter-program.config-C4cXx4Fr.mjs";
2
+ import { t as runAkter } from "./akter-program.config-Bhpa-tW7.mjs";
3
3
  // src/akter.cli.ts
4
4
  runAkter();
5
5
  export {};
@@ -2,7 +2,7 @@ import { a as withSubcommands, i as withDescription, t as make } from "../Comman
2
2
  import { importApp } from "../archive/archive-cli.config.mjs";
3
3
  import { bench, deploy, exportApp } from "../app-cli.config.mjs";
4
4
  import { login, logout, signup } from "../credentials/login.config.mjs";
5
- import { t as docs } from "../docs.config-_21Xi6HU.mjs";
5
+ import { t as docs } from "../docs.config-CWSzsV0h.mjs";
6
6
  import { localCommands } from "../local/environment-cli.config.mjs";
7
7
  import { logCommands } from "../logs/log-follow.config.mjs";
8
8
  import { actorCommands } from "../registry/actor-commands.config.mjs";
@@ -1 +1 @@
1
- export { t as runAkter } from "../akter-program.config-C4cXx4Fr.mjs";
1
+ export { t as runAkter } from "../akter-program.config-Bhpa-tW7.mjs";
@@ -1 +1 @@
1
- export { t as docs } from "../docs.config-_21Xi6HU.mjs";
1
+ export { t as docs } from "../docs.config-CWSzsV0h.mjs";
@@ -43,41 +43,9 @@ const pages = [
43
43
  "topic": "core/timers-and-messages"
44
44
  },
45
45
  {
46
- "markdown": "# AWS\n\nThere isn't a supported Akter self-hosting recipe for ECS, Fargate or Lambda.\n\nUse [Deploying](overview.md) for the implemented Cloud CLI and its current provisioning limitation. The CLI doesn't accept an AWS region, bucket or access key, and it doesn't create an ECS service.\n\n## The server\n\nThe public SDK provides a local SQLite engine for development. Running copies of that engine behind an AWS load balancer doesn't provide the production engine's placement, ownership fencing or host lifecycle. See [Operating locally](../guides/operating.md) for the scope of the local inspector.\n\n## Storage\n\nThe adopted Cloud design opens each actor's encrypted SQLite database and WAL directly on an Archil mount, under the shard's exclusive checkout. SQLite owns recovery and checkpointing. This page does not provide an AWS host adapter implementing that ownership and durable-commit path. A future guide needs an implemented hosting API and a real deployment test before it can offer infrastructure code.\n",
47
- "topic": "deploy/aws"
48
- },
49
- {
50
- "markdown": "# Cloudflare\n\nAkter contracts and clients can run in Workers, but a Worker isn't the production SQLite host. There isn't a supported Akter 1.0 recipe here for hosting the engine in Cloudflare Containers.\n\nThe old Container/R2 recipe depended on the retired 0.3 server and storage APIs and has been removed. Adding Node compatibility or an R2 binding does not turn that recipe into the current production engine.\n\n## Current deploy path\n\nUse [Deploying](overview.md) for the implemented Cloud CLI and what Akter Cloud doesn't do yet. It uploads through the Cloud API with an Akter API key; you don't supply a Cloudflare token or R2 credentials.\n\n## The server\n\nCloud hosting manages the edge and the stateful host lifecycle. This page doesn't provide a Worker entry, container health endpoint or customer-owned production host. Use [local development](../getting-started.md) for a checked app entry and [clients](../guides/client.md) for calling its actors.\n",
51
- "topic": "deploy/cloudflare"
52
- },
53
- {
54
- "markdown": "# Your own server\n\nThere isn't a supported Akter 1.0 production Docker recipe in this SDK. The old Docker/Caddy/R2 example imported the retired 0.3 server and storage APIs; it has been removed rather than presented as working infrastructure.\n\n## The server\n\n`Akter.local` and `akter dev` run the local development engine on a folder. Packaging them into a container doesn't add the production engine's placement, ownership fencing, authenticated host channels or lifecycle management. Don't scale several development processes over one actor folder.\n\nThe development RPC listener and read-only inspector bind to loopback. Don't expose the inspector through a reverse proxy as an operator endpoint; see [Operating locally](../guides/operating.md#operator-access).\n\n## Current deploy path\n\nUse [Deploying](overview.md) for the implemented Cloud CLI and its current provisioning limitation. You export an app entry, not the old `src/server.ts`, and authenticate with an Akter API key.\n\nA future self-hosting guide needs an implemented production hosting API and a real container deployment/teardown test. There is no checked Dockerfile, Caddy configuration or MinIO storage adapter to copy from this page today.\n",
55
- "topic": "deploy/docker"
56
- },
57
- {
58
- "markdown": "# Fly.io\n\nThere isn't a supported Akter 1.0 hosting recipe for Fly Machines. The old Machine/R2 deployment used the retired 0.3 server and storage APIs; its infrastructure code has been removed.\n\n## Current deploy path\n\nUse [Deploying](overview.md) for the implemented Cloud CLI and its current provisioning limitation. It doesn't create a Fly app, manage Machine replacement or accept a Fly token.\n\n## The server\n\nThe local SQLite engine is a development path, not a production host adapter for a Fly Machine. A future guide must implement and test host ownership, fencing and lifecycle behavior; setting a Machine to stay running isn't that integration. Keep the [local inspector](../guides/operating.md#operator-access) on loopback.\n",
59
- "topic": "deploy/fly"
60
- },
61
- {
62
- "markdown": "# Google Cloud\n\nThere isn't a supported Akter 1.0 deployment recipe for GKE, Cloud Run or Google Compute Engine. The old GKE/R2 recipe imported the retired 0.3 server and storage APIs; it has been removed rather than kept as an unchecked example.\n\n## Current deploy path\n\nUse [Deploying](overview.md) for the implemented Cloud CLI and its current provisioning limitation. The CLI doesn't create a Google Cloud cluster, service account or bucket.\n\n## The server\n\nA Kubernetes pod around the local development engine doesn't provide the production engine's placement, ownership fencing and host lifecycle. The [Kubernetes page](kubernetes.md) explains the same boundary. A future Google Cloud guide needs a supported production host adapter and a real deployment/teardown proof before it can offer cluster code.\n",
63
- "topic": "deploy/google-cloud"
64
- },
65
- {
66
- "markdown": "# Hetzner\n\nThere isn't a supported Akter 1.0 production hosting recipe for a Hetzner server. The old Docker/Caddy/R2 setup depended on the retired 0.3 server and storage APIs; its unchecked infrastructure code has been removed.\n\n## Current deploy path\n\nUse [Deploying](overview.md) for the implemented Cloud CLI and its current provisioning limitation. It doesn't create a Hetzner VM, install Docker or configure a public reverse proxy.\n\n## The server\n\nThe [self-hosting page](docker.md#the-server) distinguishes the local development engine from a production host. Don't expose the development inspector or start competing copies over the same folder. A future Hetzner guide needs an implemented host integration and an executed deployment/teardown test, not only a VM that runs a container.\n",
67
- "topic": "deploy/hetzner"
68
- },
69
- {
70
- "markdown": "# Kubernetes\n\nThere isn't a supported Akter 1.0 production StatefulSet or Helm recipe in this SDK. The old single-pod/R2 example depended on the retired 0.3 server and storage APIs and has been removed.\n\n## The server\n\nA StatefulSet and a persistent volume don't implement the production engine's placement, ownership fencing, authenticated host channels or lifecycle. Running `akter dev` in a pod doesn't supply that integration. The public local engine remains the [development path](../getting-started.md).\n\n## Current deploy path\n\nUse [Deploying](overview.md) for the implemented Cloud CLI and its current provisioning limitation. It doesn't apply manifests or read your kubeconfig.\n\nA future Kubernetes guide needs a supported production host adapter and tests for actual writes, replacement and teardown. This page does not provide unchecked manifests while that API is absent.\n",
71
- "topic": "deploy/kubernetes"
72
- },
73
- {
74
- "markdown": "# Deploying\n\n`akter deploy` bundles an app, uploads it through the Cloud API, confirms that the build is Ready and follows a deployment to `Live`, `NotServing` or `RolledBack`. It uses an Akter API key, not your cloud provider's credentials.\n\n## Sign up and create an app\n\nAkter Cloud's API is at `https://api.akter.dev`, which the CLI uses unless `--url` or `AKTER_CLOUD_URL` names another.\n\n```sh\nnpx akter signup --email you@example.com\nnpx akter organizations create --name acme\nnpx akter apps create --organization acme --name notes\n```\n\n`akter signup` emails you a six-digit code, asks for it, and asks you to accept the [terms of service](../legal/terms.md) and [privacy notice](../legal/privacy.md) once. The session it starts is saved in your OS keychain. An agent without a terminal passes `--code` and `--accept-terms` instead, as [Signing in](../reference/cli.md#signing-in) shows; an agent app can do all of this through the [MCP server](../guides/agents.md) at `https://mcp.akter.dev/mcp` instead.\n\nA new organization runs on the free allowance, $5 of usage a month. `akter billing checkout --organization acme` prints a link to a Stripe page where you add a card; see [Pricing](../pricing.md).\n\n## What a deploy needs\n\nYou need an organization and an app, and a session from `akter login` or an API key with the organization's deploy scope in `AKTER_API_KEY`. A key created with a list of apps reaches only those apps; one without covers every app in the organization. CI and agents use a key: `akter api-keys create` makes one with a name, its scopes (`deploy` for this), a spend cap and an expiry, and prints its secret once.\n\nThe app entry exports `app = { actors, layer }`, the same shape as [local development](../getting-started.md). It must load without starting a listener or running an unbounded program: the CLI builds its layer to inspect contracts and migrations.\n\n## Write the server\n\nYou don't write a separate server entry for the Cloud CLI. Export the actor definitions and their handler layer:\n\n```ts title=\"src/app.layer.ts\"\nimport { Effect, Schema } from \"effect\"\nimport { Akter } from \"@akterjs/effect\"\n\nexport const Note = Akter.make(\"Note\", {\n key: Schema.String,\n state: Schema.Struct({ written: Schema.Int }),\n initial: () => ({ written: 0 }),\n commands: {\n write: Akter.command({ payload: { body: Schema.String } }),\n },\n queries: {\n count: Akter.query({ success: Schema.Int }),\n bodies: Akter.query({ success: Schema.Array(Schema.String) }),\n },\n})\n\nexport const app = {\n actors: [Note],\n layer: Note.toLayer({\n migrations: {\n 1: (sql) => sql`CREATE TABLE notes (body TEXT NOT NULL)`,\n 2: (sql) => sql`INSERT INTO notes (body) VALUES (${\"seed\"})`,\n },\n commands: {\n write: (note, { body }) => Effect.gen(function* () {\n const sql = yield* Akter.sql\n yield* sql`INSERT INTO notes (body) VALUES (${body})`\n yield* Note.update({ written: note.written + 1 })\n }),\n },\n queries: {\n count: (note) => Effect.succeed(note.written),\n bodies: () => Effect.gen(function* () {\n const sql = yield* Akter.sql\n const rows = yield* sql<{ body: string }>`SELECT body FROM notes ORDER BY rowid`\n return rows.map((row) => row.body)\n }),\n },\n }),\n}\n```\n\n### Check it\n\nThis small entry demonstrates state and migrations, not a production authorization policy. Define the app's caller kinds and permitted commands using [Access](../core/access.md) before exposing application data.\n\nCheck the entry on real local SQLite before uploading it. Run this script in an empty working folder; it expects the seed row and one write.\n\n```ts title=\"check-app.ts\"\nimport assert from \"node:assert/strict\"\nimport { Effect, Layer } from \"effect\"\nimport { HttpServer } from \"effect/http\"\nimport { Akter } from \"@akterjs/effect\"\nimport { akterClient } from \"@akterjs/client/effect\"\nimport { app, Note } from \"./src/app.layer.ts\"\n\nconst server = Akter.serve({ actors: app.actors, port: 0 }).pipe(\n Layer.provide(Akter.local(\".akter\").pipe(Layer.provide(app.layer))),\n)\nconst client = Layer.unwrap(HttpServer.addressFormattedWith((url) => Effect.succeed(akterClient({ url }))))\n\nconst check = Effect.gen(function* () {\n const note = yield* Note.client(\"lobby\")\n yield* note.write({ body: \"uploaded entry\" })\n assert.equal(yield* note.count(), 1)\n assert.deepEqual(yield* note.bodies(), [\"seed\", \"uploaded entry\"])\n console.log(\"deployment entry checked: state 1; 2 SQL rows\")\n})\n\nEffect.runPromise(check.pipe(Effect.scoped, Effect.provide(client.pipe(Layer.provideMerge(server)))))\n```\n\n```text output\ndeployment entry checked: state 1; 2 SQL rows\n```\n\nThis checks the handlers and numbered SQL migrations. The deploy CLI separately hashes each actor's canonical contract and migrations into its build metadata. It doesn't infer migrations from a database on your laptop.\n\n## Deploy\n\nFrom your app's folder, signed in:\n\n```sh\nnpx akter deploy --organization acme --app notes --entry src/app.layer.ts\n```\n\nIn CI, set `AKTER_API_KEY` through your secret manager instead of signing in. Don't put it in the app entry or command arguments. The organization flag falls back to `AKTER_ORGANIZATION`, then the organization `akter login` saved. The entry defaults to `src/app.layer.ts`; the environment defaults to `prod`, so select the environment explicitly for a preview. See the [CLI reference](../reference/cli.md#akter-deploy) for the full flag list.\n\n## Releases\n\nThe CLI bundles the entry and derives its actor metadata, requests an upload and sends the bytes to the signed URL without its API bearer token. A matching Ready build can be reused without uploading again. It confirms Ready before creating a deployment, then prints the deployment id and its persisted notices once each, in order.\n\nA successful deployment reaches `Live` once every shard has a serving host, prints `Actors at https://<hostname>` and exits 0. The hostname is the environment's own, such as `notes--prod--acme.akter.run`, and an Akter client calls the app's actors there ([Calling actors](../guides/client.md)); a browser opening it gets a 404 that says so. `akter apps get` lists each environment's under `hostnames`, and `akter deploys get` shows a published deploy's `hostname` and `url`. A failed one reaches `RolledBack` and exits nonzero; inspect the failure instead of treating a completed upload as a successful release. A build that was published but had no serving host for every shard within 15 minutes reaches `NotServing`: the CLI prints the reason (for example, no host is up, or the app failed to load) and exits nonzero. It isn't rolled back, because the published build already serves your hostname; deploy a fix to replace it. Build confirmation has a five-minute deadline and deployment following a thirty-minute deadline. A timeout or interrupted CLI does not cancel the remote deployment.\n\nThe current preview's unsupported-owner refusal happens before it changes the live artifact. This isn't a promise that every later publication failure restores a previously published build.\n\n## Storage\n\nThe adopted Cloud design keeps each actor's encrypted SQLite database and WAL directly on the checked-out Archil mount. SQLite owns recovery and checkpointing, and the host waits for durable commit before publishing replies or side effects. A lease or a SQLite lock does not replace the shard's exclusive Archil checkout.\n\nBuild objects are separate from actor state and belong to the provisioned Cloud environment. This CLI uses an Akter API key, not customer storage credentials.\n\n## Where to deploy\n\nThe Cloud CLI is the implemented deployment transport. This page does not provide a supported 1.0 self-hosting recipe for AWS, Google Cloud, Fly.io, Railway, Hetzner, Kubernetes, Docker or Cloudflare Containers. The platform pages state that boundary without unchecked infrastructure code.\n\n`Akter.local` and `akter dev` are the local development path, not a substitute for the production engine's ownership, fencing and host lifecycle.\n\n## Health and shutdown\n\nThe deploy command is finite. It doesn't start your application listener, configure a platform health check, or drain hosts on shutdown. Keep the local [inspector](../guides/operating.md) on loopback; don't expose it as a production operator endpoint.\n\n## Shards\n\nThe Cloud engine owns placement and shard lifecycle. There is no CLI flag here for shard count or region selection.\n\n## Several servers\n\nDon't scale copies of `akter dev` over the same folder to implement a production cluster. Cloud hosts need coordinated shard ownership, fencing and lifecycle management.\n",
46
+ "markdown": "# Deploying\n\n`akter deploy` bundles an app, uploads it through the Cloud API, confirms that the build is Ready and follows a deployment to `Live`, `NotServing` or `RolledBack`. It uses an Akter API key, not your cloud provider's credentials.\n\n## Sign up and create an app\n\nAkter Cloud's API is at `https://api.akter.dev`, which the CLI uses unless `--url` or `AKTER_CLOUD_URL` names another.\n\n```sh\nnpx @akterjs/cli signup --email you@example.com\nnpx @akterjs/cli organizations create --name acme\nnpx @akterjs/cli apps create --organization acme --name notes\n```\n\n`akter signup` emails you a six-digit code, asks for it, and asks you to accept the [terms of service](../legal/terms.md) and [privacy notice](../legal/privacy.md) once. The session it starts is saved in your OS keychain. An agent without a terminal passes `--code` and `--accept-terms` instead, as [Signing in](../reference/cli.md#signing-in) shows; an agent app can do all of this through the [MCP server](../guides/agents.md) at `https://mcp.akter.dev/mcp` instead.\n\nA new organization runs on the free allowance, $5 of usage a month. `akter billing checkout --organization acme` prints a link to a Stripe page where you add a card; see [Pricing](../pricing.md).\n\n## What a deploy needs\n\nYou need an organization and an app, and a session from `akter login` or an API key with the organization's deploy scope in `AKTER_API_KEY`. A key created with a list of apps reaches only those apps; one without covers every app in the organization. CI and agents use a key: `akter api-keys create` makes one with a name, its scopes (`deploy` for this), a spend cap and an expiry, and prints its secret once.\n\nThe app entry exports `app = { actors, layer }`, the same shape as [local development](../getting-started.md). It must load without starting a listener or running an unbounded program: the CLI builds its layer to inspect contracts and migrations.\n\n## Write the server\n\nYou don't write a separate server entry for the Cloud CLI. Export the actor definitions and their handler layer:\n\n```ts title=\"src/app.layer.ts\"\nimport { Effect, Schema } from \"effect\"\nimport { Akter } from \"@akterjs/effect\"\n\nexport const Note = Akter.make(\"Note\", {\n key: Schema.String,\n state: Schema.Struct({ written: Schema.Int }),\n initial: () => ({ written: 0 }),\n commands: {\n write: Akter.command({ payload: { body: Schema.String } }),\n },\n queries: {\n count: Akter.query({ success: Schema.Int }),\n bodies: Akter.query({ success: Schema.Array(Schema.String) }),\n },\n})\n\nexport const app = {\n actors: [Note],\n layer: Note.toLayer({\n migrations: {\n 1: (sql) => sql`CREATE TABLE notes (body TEXT NOT NULL)`,\n 2: (sql) => sql`INSERT INTO notes (body) VALUES (${\"seed\"})`,\n },\n commands: {\n write: (note, { body }) => Effect.gen(function* () {\n const sql = yield* Akter.sql\n yield* sql`INSERT INTO notes (body) VALUES (${body})`\n yield* Note.update({ written: note.written + 1 })\n }),\n },\n queries: {\n count: (note) => Effect.succeed(note.written),\n bodies: () => Effect.gen(function* () {\n const sql = yield* Akter.sql\n const rows = yield* sql<{ body: string }>`SELECT body FROM notes ORDER BY rowid`\n return rows.map((row) => row.body)\n }),\n },\n }),\n}\n```\n\n### Check it\n\nThis small entry demonstrates state and migrations, not a production authorization policy. Define the app's caller kinds and permitted commands using [Access](../core/access.md) before exposing application data.\n\nCheck the entry on real local SQLite before uploading it. Run this script in an empty working folder; it expects the seed row and one write.\n\n```ts title=\"check-app.ts\"\nimport assert from \"node:assert/strict\"\nimport { Effect, Layer } from \"effect\"\nimport { HttpServer } from \"effect/http\"\nimport { Akter } from \"@akterjs/effect\"\nimport { akterClient } from \"@akterjs/client/effect\"\nimport { app, Note } from \"./src/app.layer.ts\"\n\nconst server = Akter.serve({ actors: app.actors, port: 0 }).pipe(\n Layer.provide(Akter.local(\".akter\").pipe(Layer.provide(app.layer))),\n)\nconst client = Layer.unwrap(HttpServer.addressFormattedWith((url) => Effect.succeed(akterClient({ url }))))\n\nconst check = Effect.gen(function* () {\n const note = yield* Note.client(\"lobby\")\n yield* note.write({ body: \"uploaded entry\" })\n assert.equal(yield* note.count(), 1)\n assert.deepEqual(yield* note.bodies(), [\"seed\", \"uploaded entry\"])\n console.log(\"deployment entry checked: state 1; 2 SQL rows\")\n})\n\nEffect.runPromise(check.pipe(Effect.scoped, Effect.provide(client.pipe(Layer.provideMerge(server)))))\n```\n\n```text output\ndeployment entry checked: state 1; 2 SQL rows\n```\n\nThis checks the handlers and numbered SQL migrations. The deploy CLI separately hashes each actor's canonical contract and migrations into its build metadata. It doesn't infer migrations from a database on your laptop.\n\n## Deploy\n\nFrom your app's folder, signed in:\n\n```sh\nnpx @akterjs/cli deploy --organization acme --app notes --entry src/app.layer.ts\n```\n\nIn CI, set `AKTER_API_KEY` through your secret manager instead of signing in. Don't put it in the app entry or command arguments. The organization flag falls back to `AKTER_ORGANIZATION`, then the organization `akter login` saved. The entry defaults to `src/app.layer.ts`; the environment defaults to `prod`, so select the environment explicitly for a preview. See the [CLI reference](../reference/cli.md#akter-deploy) for the full flag list.\n\n## Releases\n\nThe CLI bundles the entry and derives its actor metadata, requests an upload and sends the bytes to the signed URL without its API bearer token. A matching Ready build can be reused without uploading again. It confirms Ready before creating a deployment, then prints the deployment id and its persisted notices once each, in order.\n\nA successful deployment reaches `Live` once every shard has a serving host, prints `Actors at https://<hostname>` and exits 0. The hostname is the environment's own, such as `notes--prod--acme.akter.run`, and an Akter client calls the app's actors there ([Calling actors](../guides/client.md)); a browser opening it gets a 404 that says so. `akter apps get` lists each environment's under `hostnames`, and `akter deploys get` shows a published deploy's `hostname` and `url`. A failed one reaches `RolledBack` and exits nonzero; inspect the failure instead of treating a completed upload as a successful release. A build that was published but had no serving host for every shard within 15 minutes reaches `NotServing`: the CLI prints the reason (for example, no host is up, or the app failed to load) and exits nonzero. It isn't rolled back, because the published build already serves your hostname; deploy a fix to replace it. Build confirmation has a five-minute deadline and deployment following a thirty-minute deadline. A timeout or interrupted CLI does not cancel the remote deployment.\n\nThe current preview's unsupported-owner refusal happens before it changes the live artifact. This isn't a promise that every later publication failure restores a previously published build.\n\n## Storage\n\nThe adopted Cloud design keeps each actor's encrypted SQLite database and WAL directly on the checked-out Archil mount. SQLite owns recovery and checkpointing, and the host waits for durable commit before publishing replies or side effects. A lease or a SQLite lock does not replace the shard's exclusive Archil checkout.\n\nBuild objects are separate from actor state and belong to the provisioned Cloud environment. This CLI uses an Akter API key, not customer storage credentials.\n\n## Where to deploy\n\nAkter apps deploy to Akter Cloud, through the CLI or the Cloud API.\n\n`Akter.local` and `akter dev` are the local development path, not a substitute for the production engine's ownership, fencing and host lifecycle.\n\n## Health and shutdown\n\nThe deploy command is finite. It doesn't start your application listener, configure a platform health check, or drain hosts on shutdown. Keep the local [inspector](../guides/operating.md) on loopback; don't expose it as a production operator endpoint.\n\n## Shards\n\nThe Cloud engine owns placement and shard lifecycle. There is no CLI flag here for shard count or region selection.\n\n## Several servers\n\nDon't scale copies of `akter dev` over the same folder to implement a production cluster. Cloud hosts need coordinated shard ownership, fencing and lifecycle management.\n",
75
47
  "topic": "deploy/overview"
76
48
  },
77
- {
78
- "markdown": "# Railway\n\nThere isn't a supported Akter 1.0 production Railway recipe. The old service/volume/R2 setup used the retired 0.3 server and storage APIs; its infrastructure code has been removed rather than left unchecked.\n\n## Current deploy path\n\nUse [Deploying](overview.md) for the implemented Cloud CLI and its current provisioning limitation. It doesn't create a Railway service or volume and doesn't accept Railway credentials.\n\n## The server\n\nA persistent volume and a process kept awake don't supply the production engine's placement, ownership fencing or host lifecycle. The local development engine and [inspector](../guides/operating.md) are not that production integration. A future Railway guide needs an implemented hosting API and a real deployment/teardown test.\n",
79
- "topic": "deploy/railway"
80
- },
81
49
  {
82
50
  "markdown": "# Getting started\n\nYou'll write a counter actor, run it on a folder on your machine and call it. An actor is one thing your app keeps state for: a counter, a room, a sale.\n\n## Install\n\n```sh\nbun add @akterjs/effect @akterjs/client effect\nbun add -d @akterjs/cli\n```\n\n## Write the contract\n\nThe contract says what a counter holds and what callers can ask of it. It holds only schemas, so clients import it too.\n\n```ts title=\"src/counter.contract.ts\"\nimport { Schema } from \"effect\"\nimport { Akter } from \"@akterjs/effect/contract\"\n\nexport const CounterId = Schema.String.pipe(Schema.brand(\"CounterId\"))\n\nexport const Counter = Akter.make(\"Counter\", {\n key: CounterId,\n state: Schema.Struct({ count: Schema.Int }),\n initial: () => ({ count: 0 }),\n commands: {\n add: Akter.command({ payload: { by: Schema.Int }, success: Schema.Int }),\n },\n queries: {\n count: Akter.query({ success: Schema.Int }),\n },\n})\n```\n\n`key` names one counter. `initial` is the state of a counter nobody has called yet, so there's no step to create one.\n\n## Write the handlers\n\n```ts title=\"src/counter.actor.ts\"\nimport { Effect } from \"effect\"\nimport { Counter } from \"./counter.contract.ts\"\n\nexport const CounterLive = Counter.toLayer({\n commands: {\n add: (counter, { by }) =>\n Effect.gen(function* () {\n const count = counter.count + by\n yield* Counter.update({ count })\n return count\n }),\n },\n queries: {\n count: (counter) => Effect.succeed(counter.count),\n },\n})\n```\n\nA command runs in one SQLite transaction. `Counter.update` changes the state, and the caller gets the reply only after the change is on disk. A query reads and never writes.\n\n## Run it\n\n`akter dev` serves the actors your app lists, on a folder named `.akter`:\n\n```ts title=\"src/app.layer.ts\"\nimport { Counter } from \"./counter.contract.ts\"\nimport { CounterLive } from \"./counter.actor.ts\"\n\nexport const app = { actors: [Counter], layer: CounterLive } as const\n```\n\n```sh\nbunx akter dev\n```\n\n`akter dev` restarts when you change a file and keeps the data. Each actor is a folder inside `.akter` with its own SQLite file, which you can open with `sqlite3`.\n\n## Call it\n\nThis script calls the counter in the same process. `Akter.local` runs the app on the `.akter` folder, and `Akter.localClient` gives the script the same client that `akterClient` gives a browser or server: every call goes through the same contract checks and caller checks, but nothing listens on a port.\n\n```ts title=\"src/try.ts\"\nimport { Effect, Layer } from \"effect\"\nimport { Akter } from \"@akterjs/effect\"\nimport { app } from \"./app.layer.ts\"\nimport { Counter, CounterId } from \"./counter.contract.ts\"\n\nconst client = Akter.localClient({ actors: app.actors }).pipe(\n Layer.provide(Akter.local(\".akter\").pipe(Layer.provide(app.layer))),\n)\n\nconst program = Effect.gen(function* () {\n const counter = yield* Counter.client(CounterId.make(\"clicks\"))\n yield* counter.add({ by: 2 })\n yield* counter.add({ by: 3 })\n console.log(yield* counter.count())\n})\n\nEffect.runPromise(program.pipe(Effect.scoped, Effect.provide(client)))\n```\n\n```sh\nbun src/try.ts\n```\n\n```text output\n5\n```\n\nRun it again and it prints `10`, because the counter called `clicks` kept its count in `.akter`. To call a running `akter dev` instead, provide `akterClient({ url: \"http://localhost:4000\" })` from `@akterjs/client/effect` in place of `client`.\n\nEach method on `counter` is typed by the contract, so `counter.add({ by: \"two\" })` doesn't compile.\n\n## Next\n\n- [Actors](core/actors.md): keys, state, and actors you create with input.\n- [Commands](core/commands.md): errors, ids and time, and SQL inside a command.\n- [Jobs](core/jobs.md): sending email, calling APIs, anything with I/O.\n",
83
51
  "topic": "getting-started"
@@ -111,11 +79,11 @@ const pages = [
111
79
  "topic": "guides/testing"
112
80
  },
113
81
  {
114
- "markdown": "# Privacy notice\n\nversion: 2026-11-11-draft\n\n> **PLACEHOLDER, NOT LEGAL TEXT.** This draft has not been reviewed by a lawyer and is waiting for Dallen's legal review. It describes what Akter Cloud stores today so the sign-up flow can show and record acceptance. Don't rely on it until this banner is gone and the version above changes.\n\nThis notice says what personal data Akter Cloud keeps about you, why, and for how long. It shares its version with the [terms of service](./terms.md); accepting one at sign-up accepts both.\n\n## What Akter keeps\n\n- **Your account:** your email address, when the account was created, and which version of these documents you accepted and when.\n- **Sign-in:** one-time codes, kept only until they're used or expire, and your sessions, each with its creation and expiry time. A session's secret is shown to you once, at sign-in; agent keys are stored as hashes.\n- **Organizations:** your memberships and roles, invitations you send or receive, and the agent keys you create, with their scopes, apps, caps and expiry.\n- **Usage:** metered usage per organization, app and key, for limits and billing.\n- **Operational logs and traces:** request metadata such as times, operations and error types, used to run and secure the service.\n\nThe data your apps' actors store belongs to you and is processed only to run your apps; see the terms.\n\n## Who processes it\n\nAkter runs on infrastructure providers: Cloudflare (edge and Workers), Archil (storage and compute), Resend (sign-in email), Axiom (logs and traces) and Stripe (billing). Each receives only what it needs for its part.\n\n## How long\n\n- Codes expire after minutes; sessions after 30 days; logs and traces after the retention stated in the docs.\n- Deleting your account (`akter account delete`) ends its sessions and deletes the account record. Records the law requires Akter to keep, such as invoices, are kept for the required period.\n\n## Your choices\n\nYou can read your account (`akter whoami`), export your apps' data (`akter export`), revoke sessions and keys, and delete your account. Other requests: the contact address will be added at legal review.\n",
82
+ "markdown": "# Privacy notice\n\nversion: 2026-11-14\n\nThis notice says what personal data Akter Cloud keeps about you, why, and for how long. Akter Cloud is operated by Rika Labs, LLC, 805 N Roosevelt St, Suite 100, Boise, ID 83706, USA, which is responsible for that data. It shares its version with the [terms of service](./terms.md); accepting one at sign-up accepts both.\n\n## What Akter keeps\n\n- **Your account:** your email address, when the account was created, and which version of these documents you accepted and when.\n- **Sign-in:** one-time codes, kept only until they're used or expire, and your sessions, each with its creation and expiry time. A session's secret is shown to you once, at sign-in; agent keys are stored as hashes.\n- **Organizations:** your memberships and roles, invitations you send or receive, and the agent keys you create, with their scopes, apps, caps and expiry.\n- **Usage:** metered usage per organization, app and key, for limits and billing.\n- **Operational logs and traces:** request metadata such as times, operations and error types, used to run and secure the service.\n\nThe data your apps' actors store belongs to you and is processed only to run your apps; see the terms.\n\n## Who processes it\n\nAkter runs on infrastructure providers: Cloudflare (edge and Workers), Archil (storage and compute), Resend (sign-in email), Axiom (logs and traces) and Stripe (billing). Each receives only what it needs for its part.\n\n## How long\n\n- Codes expire after minutes; sessions after 30 days; logs and traces after the retention stated in the docs.\n- Deleting your account (`akter account delete`) ends its sessions and deletes the account record. Records the law requires Akter to keep, such as invoices, are kept for the required period.\n\n## Your choices\n\nYou can read your account (`akter whoami`), export your apps' data (`akter export`), revoke sessions and keys, and delete your account. Other requests, including access to or deletion of your personal data: dallenpyrah+akter@rikalabs.sh, or write to Rika Labs, LLC at the address above.\n",
115
83
  "topic": "legal/privacy"
116
84
  },
117
85
  {
118
- "markdown": "# Terms of service\n\nversion: 2026-11-11-draft\n\n> **PLACEHOLDER, NOT LEGAL TEXT.** This draft has not been reviewed by a lawyer and is waiting for Dallen's legal review. It describes how Akter Cloud works today so the sign-up flow can show and record acceptance. Don't rely on it as an agreement until this banner is gone and the version above changes.\n\nThese terms cover your use of Akter Cloud: the Cloud API, the `akter` CLI when it talks to Akter Cloud, and the hosted MCP server. The open-source packages (`@akterjs/*` and `akter`) are licensed under Apache-2.0 on their own; these terms don't change that license.\n\n## Your account\n\n- You sign up with an email address and a one-time code. You're responsible for keeping access to that mailbox and for every session, agent key and agent you allow to act for you.\n- An agent you connect, through the CLI, an agent key or the MCP server, acts as you within the roles and limits you gave it. You're responsible for what it does.\n- Akter asks a person to confirm dangerous actions, such as deleting an app. Don't build systems that confirm on a person's behalf.\n\n## Your apps and data\n\n- You keep your rights in the code you deploy and the data your actors store. You give Akter the rights it needs to run, store, back up and export them for you.\n- You can export your data at any time with `akter export`. Deleting an environment or an account deletes its data after the retention period stated in the docs.\n- Don't use Akter Cloud to break the law, to harm others, to attack or overload other systems, or to store data you have no right to store.\n\n## Usage, limits and billing\n\n- Usage is metered and priced as published. Spend caps on your organization and on agent keys stop new spend when they're reached.\n- A new metered dimension, or a higher price for an existing one, is announced at least 30 days before it is charged, with the date it starts, which is the earliest it can start. Only usage on or after that date is charged at the new price; earlier usage never is.\n- A command or query is billed when it's made with your credentials and Akter Cloud did its work for it: an authenticated, authorized call answered on your app's behalf, including your actor's own errors and the refusal of a malformed payload, such as one that doesn't match the call's schema. It isn't billed when it's refused for authentication or authorization (a 401 or 403, including an actor refusing a caller its rules don't allow), stopped by a spend cap, refused by a rate limit or an admission limit (such as a store past its disk ceiling or a session past its watch limit), or when it fails on Akter's side (a 5xx, an actor that's unavailable, or a request that hangs or is cancelled). A retry under the same command id that returns the recorded outcome is billed once.\n- An actor isn't charged for being connected or idle: the hosts that run it are included. Commands and queries are charged per call, stored data per GiB-month, and an actor's computers for the time they run.\n- Payment is handled by Stripe. Card details never pass through Akter, the CLI or an agent.\n\n## Service\n\n- Akter Cloud is provided as is, without warranties beyond those the law requires. Availability targets, if any, are stated separately.\n- Akter may suspend an account that breaks these terms or puts the service or other customers at risk, and will say why where it can.\n- These terms may change. A change gets a new version, and you'll be asked to accept it before your next sign-up or as described in the change.\n\n## Contact\n\nQuestions about these terms: the contact address will be added at legal review.\n\nSee also the [privacy notice](./privacy.md).\n",
86
+ "markdown": "# Terms of service\n\nversion: 2026-11-14\n\nThese terms cover your use of Akter Cloud: the Cloud API, the `akter` CLI when it talks to Akter Cloud, and the hosted MCP server. Akter Cloud is provided by Rika Labs, LLC, 805 N Roosevelt St, Suite 100, Boise, ID 83706, USA (\"Akter\" in these terms). The open-source packages (`@akterjs/*`) are licensed under Apache-2.0 on their own; these terms don't change that license.\n\n## Your account\n\n- You sign up with an email address and a one-time code. You're responsible for keeping access to that mailbox and for every session, agent key and agent you allow to act for you.\n- An agent you connect, through the CLI, an agent key or the MCP server, acts as you within the roles and limits you gave it. You're responsible for what it does.\n- Akter asks a person to confirm dangerous actions, such as deleting an app. Don't build systems that confirm on a person's behalf.\n\n## Your apps and data\n\n- You keep your rights in the code you deploy and the data your actors store. You give Akter the rights it needs to run, store, back up and export them for you.\n- You can export your data at any time with `akter export`. Deleting an environment or an account deletes its data after the retention period stated in the docs.\n- Don't use Akter Cloud to break the law, to harm others, to attack or overload other systems, or to store data you have no right to store.\n\n## Usage, limits and billing\n\n- Usage is metered and priced as published. Spend caps on your organization and on agent keys stop new spend when they're reached.\n- A new metered dimension, or a higher price for an existing one, is announced at least 30 days before it is charged, with the date it starts, which is the earliest it can start. Only usage on or after that date is charged at the new price; earlier usage never is.\n- A command or query is billed when it's made with your credentials and Akter Cloud did its work for it: an authenticated, authorized call answered on your app's behalf, including your actor's own errors and the refusal of a malformed payload, such as one that doesn't match the call's schema. It isn't billed when it's refused for authentication or authorization (a 401 or 403, including an actor refusing a caller its rules don't allow), stopped by a spend cap, refused by a rate limit or an admission limit (such as a store past its disk ceiling or a session past its watch limit), or when it fails on Akter's side (a 5xx, an actor that's unavailable, or a request that hangs or is cancelled). A retry under the same command id that returns the recorded outcome is billed once.\n- An actor isn't charged for being connected or idle: the hosts that run it are included. Commands and queries are charged per call, stored data per GiB-month, and an actor's computers for the time they run.\n- Payment is handled by Stripe. Card details never pass through Akter, the CLI or an agent.\n\n## Service\n\n- Akter Cloud is provided as is, without warranties beyond those the law requires. Availability targets, if any, are stated separately.\n- Akter may suspend an account that breaks these terms or puts the service or other customers at risk, and will say why where it can.\n- These terms may change. A change gets a new version, and you'll be asked to accept it before your next sign-up or as described in the change.\n\n## Contact\n\nQuestions about these terms: dallenpyrah+akter@rikalabs.sh, or write to Rika Labs, LLC at the address above.\n\nSee also the [privacy notice](./privacy.md).\n",
119
87
  "topic": "legal/terms"
120
88
  },
121
89
  {
@@ -123,7 +91,7 @@ const pages = [
123
91
  "topic": "pricing"
124
92
  },
125
93
  {
126
- "markdown": "# CLI\n\nThe `akter` executable belongs to `@akterjs/cli`. In an app workspace with that package installed, run `bunx akter`. Use `akter --help` and `akter <command> --help` for the flags in your installed build.\n\n| Command | Status |\n| --- | --- |\n| [`akter dev`](#akter-dev) | Local engine and read-only inspector. |\n| [`akter dev snapshots`, `akter dev environments`](#akter-dev-snapshots-and-akter-dev-environments) | Snapshot, branch and promote the local folder's environments, as on Akter Cloud. |\n| [`akter deploy`](#akter-deploy) | Cloud API build upload and deployment progress. |\n| [`akter migrate --all`](#akter-migrate) | Apply migrations to actors in a local folder. |\n| [`akter history`](#akter-history) | Read or verify a local actor's command journal. |\n| [`akter export`](#akter-export) | Download every actor's database and history from Akter Cloud into one `.akter` archive. |\n| [`akter import`](#akter-import) | Read an `.akter` archive into a local folder, checking every entry. |\n| [`akter bench`](#akter-bench) | Run a workload against `akter dev` or an Akter Cloud app and report every outcome. |\n| [`akter <group> <operation>`](#cloud-api-commands) | One command per Cloud API endpoint, such as `akter apps list`. |\n| [`akter login`, `akter signup`, `akter logout`](#signing-in) | Sign in or create an account with an emailed code, save or remove the login every Cloud command uses. |\n| [`akter docs`](#akter-docs) | Print these docs as Markdown. |\n\nOrganization, member, API key, app, build, deploy, domain, log, secret, account, session, usage and billing commands are [Cloud API commands](#cloud-api-commands). Calls to an app's actors are `akter actors call`, `query`, `state`, `watch`, `create`, `ensure` and [`fork`](#forking-an-actor); their files are `akter files` and their computers [`akter computers`](#akter-computers). Locally, [`akter dev snapshots` and `akter dev environments`](#akter-dev-snapshots-and-akter-dev-environments) snapshot, branch and promote. On Cloud, branch, restore and snapshot commands are not registered yet. Older operator commands aren't available either.\n\n## Shared app entry\n\n`dev`, `deploy`, `migrate` and `history` load `--entry`, defaulting to `src/app.layer.ts`. It must export the named value `app = { actors, layer }`. See the [checked deployment entry](../deploy/overview.md#write-the-server) for an example.\n\n## `akter dev`\n\n```sh\nbunx akter dev --entry src/app.layer.ts --dir .akter --port 4000\n```\n\n| Flag | Default | Meaning |\n| --- | --- | --- |\n| `--entry` | `src/app.layer.ts` | The module exporting `app`. |\n| `--dir` | `.akter` | The local actor folder. |\n| `--port` | `PORT`, otherwise `4000` | RPC listener port. |\n| `--inspector-port` | RPC port + 1 | Read-only inspector port; a zero RPC port selects a free inspector port. |\n| `--allowed-host` | Loopback names only | Additional allowed Host name; repeatable. |\n| `--reset` | Off | Ask before emptying the local actor folder. |\n| `--from` | None | An `.akter` archive to [import](#akter-import) into `--dir` first; `--dir` must not exist yet. |\n| `--environment` | The promoted one | Serve this environment of the folder, such as a quiet branch, instead of the one promoted to serve. |\n\nThe runner watches the entry for changes and restarts while keeping the folder. RPC is served at `/rpc`. Both listeners bind to loopback and check the Host header; an additional allowed name doesn't authenticate a caller. Don't expose the inspector publicly. See [Operating locally](../guides/operating.md#operator-access).\n\n## `akter dev snapshots` and `akter dev environments`\n\n```sh\nbunx akter dev snapshots create --name before-import\nbunx akter dev environments branch --name trial --snapshot before-import\nbunx akter dev --environment trial --port 4100 # call the quiet branch\nbunx akter dev environments promote --name trial\nbunx akter dev environments promote --name dev # promote back\n```\n\n| Command | Meaning |\n| --- | --- |\n| `snapshots create --name <n>` | Snapshot the serving environment, or `--environment`'s. The `akter dev` serving it takes it; until one does it stays `Pending`. |\n| `snapshots list`, `snapshots get --name <n>` | The environment's live snapshots. Ids are `snapshot-<n>`, numbered from 0 and never reused. |\n| `snapshots delete --name <n>` | Retire the snapshot and remove its copy. Its name is free again; its id isn't. |\n| `environments list`, `environments get --name <e>` | Every environment, deleted ones included, with `serving` and `quiet`. |\n| `environments branch --name <e> --snapshot <n>` | A new, quiet environment from a `Ready` snapshot of the serving environment, or `--from`'s. |\n| `environments promote --name <e>` | Serve `<e>` instead and lift its quiet. Promoting the one that serves changes nothing and prints the same result. |\n| `environments delete --name <e>` | Remove an environment that doesn't serve. `dev` and the serving one are refused; the name stays taken. |\n\nEvery command takes `--dir` and `--json`; with `--json` it prints the same shapes as Akter Cloud's `snapshots` and `environments` operations, and a refusal prints `code`, `reason` and `message`. The promote prints what it leaves out. See [Snapshots, branches and promote](../guides/operating.md#snapshots-branches-and-promote).\n\n## `akter deploy`\n\n```sh\nnpx akter deploy \\\n --organization \"$AKTER_ORGANIZATION\" \\\n --app \"$AKTER_APP\" \\\n --environment \"$AKTER_ENVIRONMENT\"\n```\n\n| Flag | Default | Meaning |\n| --- | --- | --- |\n| `--organization` | `AKTER_ORGANIZATION` | Existing organization. |\n| `--app` | Required | Existing app. |\n| `--environment` | `prod` | Provisioned destination environment. |\n| `--url` | `AKTER_CLOUD_URL`, then the saved login, then `https://api.akter.dev` | Cloud API base URL; HTTPS except for loopback development. |\n| `--entry` | `src/app.layer.ts` | The module exporting `app`. |\n| `--domain` | None | Claim this customer hostname for the environment and print the CNAME to add. |\n| `--json` | Off | Print the live deploy as one line of JSON in the API's `Deploy` schema, with its `hostname` and `url`; progress goes to stderr. |\n\nThe key comes from [signing in](#signing-in) and needs deploy scope for the organization. The key is exchanged for a short-lived bearer token; signed uploads don't receive that bearer. The CLI rejects redirects for token exchange, API requests and uploads.\n\nThe CLI uploads a new build or reuses a matching Ready one, confirms Ready, creates a new deployment and prints its id. Persisted notices are printed once each in order until `Live`, `NotServing` or `RolledBack`. `Live` prints `Actors at https://<hostname>`, the app's own hostname for that environment, where an Akter client calls its actors, and exits 0; `NotServing` prints why the published build isn't serving and exits nonzero; `RolledBack` exits nonzero. Build confirmation and deployment following have five-minute and thirty-minute deadlines respectively. Interrupting or timing out the CLI doesn't cancel the remote deployment.\n\n`akter deploy` doesn't create the organization or the app: `akter organizations create` and `akter apps create` do. An upload that succeeds doesn't by itself mean the deployment goes live; wait for `Live`.\n\nThere is no region flag. See [Deploying](../deploy/overview.md).\n\n## `akter migrate`\n\n```sh\nbunx akter migrate --all --dry-run --entry src/app.layer.ts --dir .akter\n```\n\n`--all` is required; migrating one actor from the CLI isn't implemented. Without `--dry-run`, pending migrations are applied now rather than on the actor's next open. Output names each actor's old and new migration version. A failure stops the command, so actors later in the traversal aren't migrated by that run. This command operates on a local folder, not the Cloud API.\n\n## `akter history`\n\n```sh\nbunx akter history Note/lobby --entry src/app.layer.ts --dir .akter --json\nbunx akter history Note/lobby --entry src/app.layer.ts --dir .akter --verify\n```\n\nThe journal is read oldest first. `--json` emits one JSON object per command. `--since` accepts a whole number with `ms`, `s`, `m`, `h` or `d`; a retained-history boundary is printed when the journal doesn't cover the full history.\n\n`--verify` replays the kept history against the current handlers and reports either no difference or the first mismatching outcome. It can't be combined with `--since`, and it refuses a replay whose initial history has been pruned. To verify a Cloud app's actors, export the app, import the archive and run `--verify` on the folder ([Use the exported data](../guides/exporting.md#use-the-exported-data)). See [History and replay](../core/history-and-replay.md).\n\n## `akter export`\n\n```sh\nbunx akter export \\\n --organization \"$AKTER_ORGANIZATION\" \\\n --app \"$AKTER_APP\" \\\n --url \"$AKTER_CLOUD_URL\" \\\n --out ./chat.akter\n```\n\n| Flag | Default | Meaning |\n| --- | --- | --- |\n| `--organization` | `AKTER_ORGANIZATION` | Existing organization. |\n| `--app` | Required | The app whose actors to export. |\n| `--url` | `AKTER_CLOUD_URL`, then the saved login, then `https://api.akter.dev` | Cloud API base URL; HTTPS except for loopback development. |\n| `--out` | Required | The `.akter` archive to write; it must not exist yet. Run again with the same path to resume. |\n\nThe key comes from [signing in](#signing-in) and needs export scope for the organization; a key with only deploy, call or read scope is refused. Every listing, snapshot and download request is authorized for that organization's app, and none of them reach another app or organization.\n\nAn export is one `.akter` file: a tar archive compressed with zstd (ADR 0019). Its first entry is `manifest.json`, which records the format version (1), when it was written, the size and SHA-256 of every other entry, the `computers` section with each computer the app's actors keep (its disk and checkpoint stay in Akter Cloud, so the checkpoint is marked `\"portable\": false`), and the `lineage` section, with one entry per forked actor: the actor, the actor it was forked from (`parent`), the fork's id (`fork`) and the parent's commit version at the cut (`forkedAt`). The entries after it are:\n\n- `shards/<shard>/<Actor>/<key>/actor.db` for each actor that has a database, in the layout `akter dev` uses, so `bunx akter dev --from ./chat.akter --dir ./chat` serves the exported actors.\n- Each `actor.db` is a plain, decrypted SQLite database that stock `sqlite3` opens. It holds the actor's whole database at one consistent point after its last committed command: its state, its own tables, its command journal (the history `akter history` reads), and its pending timers, outbox and jobs.\n- `shards/<shard>/<Actor>/<key>/files/<sha256>` for each distinct file the actor's database names, its plaintext content named by its SHA-256. The paths, sizes and times of the actor's files stay in its `actor.db`.\n- Nothing else. It holds no Cloud keys, no export records and no file keys: the CLI blanks every file grant in `actor.db` and rewrites the file before it archives it.\n\nAn erased actor has nothing to export: the CLI prints `<Actor>/<key>: erased, nothing to export` and goes on.\n\nEach actor is snapshotted on its own, after a commit and while no command runs on it, so its database is consistent. Actors are exported one after another, so two actors' snapshots come from different moments. The snapshot stays encrypted on the server under a key of its own, and only the download decrypts it. When the snapshot is taken, its completion record gets a MAC over every page in order. The server checks that MAC in the same pass that computes the snapshot's SHA-256, before it reports the snapshot, so a page rolled back to an earlier copy of itself stops the export with a gone-snapshot error instead of exporting stale data. That check covers the snapshot file only. The live `actor.db` on the server is authenticated page by page, so a page rolled back inside it is outside what export can detect, and a snapshot taken afterwards exports the rolled-back page as it is. Starting an actor's export replaces that actor's previous snapshot, so run one export of an app at a time.\n\nThe CLI downloads into a staging folder beside the archive, `<out>.staging`, at most 64 KiB per request, and prints each actor's progress every MiB and when it's done. It downloads an actor's files first, each into `files/<sha256>.export` and checked against its SHA-256 before it's renamed, then its database, which it checks against the SHA-256 the server computed when it took the snapshot, strips of file grants and only then renames to `actor.db`. While an actor downloads, `actor.db.export` holds the database's bytes so far and `actor.db.export.json` the snapshot they come from. A finished file is kept for the next run, and a file the actor's snapshot doesn't hold is removed from `files`. After an interruption, run the same command with the same `--out`: finished actors are kept, and a partly downloaded actor continues from the same snapshot. When every actor is in, the CLI writes the archive as `<out>.partial`, renames it to `<out>`, removes the staging folder and prints `Wrote <out> with <n> entries`. An export is complete only when it prints that line. If that snapshot was replaced, failed authentication on the server or doesn't match its SHA-256, the CLI deletes the partial download and exits nonzero; run it again to take a new snapshot.\n\nSee [Exporting an app](../guides/exporting.md) for a walkthrough.\n\n## `akter import`\n\n```sh\nbunx akter import ./chat.akter --dir ./chat\n```\n\n| Flag | Default | Meaning |\n| --- | --- | --- |\n| `<archive>` | Required | The `.akter` archive to read. |\n| `--dir` | `.akter` | A new folder to read the actors into; it must not exist yet. |\n\nThe CLI reads the archive as a stream into `<dir>.importing`, checks every entry against the size and SHA-256 its manifest records, takes each actor's `files/<sha256>` into the folder's file home, `files-home`, under the actor's local identity, and renames the folder to `--dir` only once every entry has passed and every file is in. It refuses an archive whose first entry isn't `manifest.json`, that holds an entry its manifest doesn't list, whose entry doesn't match its checksum, that was cut short, that a newer akter wrote, or whose files can't be taken in, and then leaves no folder behind. Every format version akter has written stays readable. `akter dev`, `akter history` and `akter migrate` read the imported folder.\n\n## `akter bench`\n\n```sh\nbunx akter bench tests/sale.workload.ts --duration 30s --concurrency 8\nbunx akter bench tests/doc.workload.ts --duration 60s --json\n```\n\nThe workload module exports `workload = ({ id, kind, url }) => ({ name, open, step })`. `id` names this run, `url` is the target and `kind` says what it is: `\"local\"` for `akter dev`, `\"cloud\"` for an Akter Cloud app and `\"comparison\"` for another system, so a workload sends a development identity such as the `akter-principal` header only when `kind` is `\"local\"`. `open` is an Effect that needs an Akter client and returns a session, and `step(session)` is one operation whose success value names its outcome. Without `--url`, the command starts `akter dev` with `--entry` on an empty temporary folder and stops it when the run ends. A loopback `--url` reuses a running `akter dev`. Any other `--url` is an Akter Cloud app: the command signs in with `AKTER_API_KEY` or the key `akter login` saved, and keeps the run signed in past the 15-minute token. `--system <name> --url <url>` runs a workload against another system for comparison and signs in to nothing.\n\n`--concurrency` workers (8 by default) each run one step at a time and start no new step after `--duration` (30s by default). A step, or the workload's `open`, with no answer within `--step-timeout` (30s by default) counts as `failed: no answer within <ms> ms` and the worker moves on, so one stuck step can't hold the run open. The report has one row per outcome, and a failed step counts as `failed: <error tag>`, so failures and losses stay in the table. Each row and the total give steps, steps per second over the whole run, and p50, p90, p99 and max latency in milliseconds. Cost per row is always `unmeasured`.\n\nA local run's output starts with a `LOCAL RUN` notice: the numbers describe this machine and this checkout, not Akter Cloud. A Cloud run's starts with `AKTER CLOUD RUN`: every latency includes the network path from the machine that ran the bench to the app. The report also names the hardware, the runtime, the versions of `@akterjs/cli`, `@akterjs/client`, `@akterjs/effect` and `effect`, the git commit and whether the worktree is clean, and the SHA-256 of the nearest lockfile. `--json` prints the same report as one JSON object, with `\"local\": true` for a local run and `false` for a Cloud run.\n\n## Operator commands\n\nThe old `inspect`, `log`, `snapshot` and `retention` command groups aren't registered. Local inspection is the read-only listener started by `dev`; see [Operating locally](../guides/operating.md).\n\n## Forking an actor\n\n`akter actors fork --url <app url> --actor <Actor> --key <key> --into <new key>` copies an actor into a new actor at another key: its state and files at one moment, with none of its work in flight, since its jobs, timers and undelivered messages stay with the original. It prints the original's commit version at the cut. A retry with the same `--command-id` makes one copy, and `--dry-run` prints the request without sending it. There is no top-level `akter fork`; don't use the old history-copying examples against a 1.0 actor folder.\n\nOn the local engine the copy also gets each of the actor's computers: its disk as it was at the cut, stopped, so no process the original ran runs in the copy. While it copies them the fork holds the original's computers paused under the fork's id: a step already running finishes first, and one sent meanwhile fails with `ComputerHeldError` naming the fork's id. Then each computer goes back to where it was. If the engine stops partway through a fork, the hold stays until a retry with the same id finishes the fork. A fork whose copies would pass the store's limit of 4 computers is refused with `InvalidRequestError`. Akter Cloud copies each computer by its disk alone too, but to do that it stops the original's computer first, so one that was running starts again from its disk with its memory and processes gone, and one that was paused stays stopped. A copy that fails keeps the hold until a retry with the same fork id copies it. Akter Cloud refuses, with `ActorUnavailableError`, a fork whose copies would pass the environment's limit of 4 computers, and a fork with computers into a key on another shard.\n\nWhere the fork runs depends on the target, the same rule every actor command and `akter bench` use. A loopback `--url` (or `AKTER_APP_URL`), such as the address `akter dev` prints, is the local engine: the command sends the actor's fork RPC, `<Actor>/fork`, with no sign-in and no question. Any other target is Akter Cloud, where forking is an operator action (decision 5): the gateway refuses the fork RPC for every caller, so the command runs the Cloud API operation `actorForks.create` instead, `POST /v1/organizations/{organization}/apps/{app}/environments/{environment}/actors/{actor}/{key}/forks` with `into` and `forkId`:\n\n```sh\nakter actors fork --organization acme --app shop --environment prod --actor Sale --key s1 --into s1-try\n```\n\nIt signs in with your credentials (`AKTER_API_KEY` or `akter login`) at the Cloud API (`AKTER_CLOUD_URL` or the URL `akter login` saved); `--organization` defaults as for every Cloud command, and `--command-id` is sent as the fork id. Like every dangerous Cloud command it asks the person at the terminal to confirm, and exits 4 when no terminal can ask. An API key's fork also needs its creator's approval: at a terminal the command asks for the emailed code and retries once with the token, and without one it takes `--approval <token>` from `akter approvals request` and `akter approvals confirm`. The key needs the `fork` scope. On the hosted MCP server the same fork is the `actors_fork` tool, which takes `organization`, `app`, `environment`, `actor`, `key`, `into` and `forkId` and asks the person before anything is sent. The Effect and Promise clients' `fork(into)` stays an actor RPC, so it forks on `akter dev` and is refused on Akter Cloud by design.\n\nCloud forks are a preview behind `cloudFork`, default off. The CLI leaves `actors fork` out of help but still accepts it by name; control refuses an organization without the flag. MCP currently hides `actors_fork` from everyone until it can read organization flags, without falling back to the forbidden actor RPC. Local forks do not use a flag.\n\n## Cloud API commands\n\nEvery Cloud API endpoint is one command, `akter <group> <operation>`, named after the API's own groups and operations: `akter apps list`, `akter apps create`, `akter deploys get`, `akter members change-role` and so on. `akter --help` lists the groups and `akter <group> --help` their operations. The same list, with the same names, descriptions, input schemas and safety hints, is what Akter's MCP tools are built from, so a command and its tool always agree.\n\n- Each field of the operation's input is a flag, such as `--organization` and `--name`. `--input '<json>'` takes the whole input as one JSON object, the same arguments the MCP tool takes; `--input @file.json` reads a file and `--input -` reads stdin. Flags override its fields. Pass a secret, such as a `secrets set` value, with `--input -` or `--input @file.json` rather than a flag, so it stays out of the process list and shell history; `--dry-run` prints the body, secret included. The CLI checks the input against the operation's schema before it sends anything and exits 2 when it doesn't match.\n- `--json` prints the API's answer as one line of JSON in the API's own schema, after checking it against that schema; an answer that doesn't match exits 1, because the CLI and the API disagree. Without `--json` the answer is printed indented. A refusal prints the API's error body with `--json`, and one line on stderr otherwise. After a 503 on a change that is safe to repeat, such as `akter actors erase`, that line adds that it may have stopped partway and to run the same command again.\n- A read that pages takes `--after` and answers with `next` while there is more: `akter actors list`, which lists an app's actors by name and key (`--actor Room` for one name, `--environment` for an environment other than `prod`), and `akter actors history`. An `akter actors list` page holds `--limit` actors (500 at most, and by default) unless it is the last, and the last page has no `next`, so read on until `next` is absent. `--all` does that: it sends each page's `next` as `--after` until a page has none and prints one answer in the API's schema with every page's entries and no `next`. A refused page stops it with that page's error and exit code.\n- Commands that change something take `--dry-run`, which checks the input and prints the request instead of sending it.\n- Destructive commands, such as `akter apps delete`, ask a person to confirm. When stdin or stdout isn't a terminal they never ask: they exit 4 at once, unless `--approval <token>` carries an approval for the action.\n- Signed in with an API key, a dangerous action also needs its creator's approval, and the API refuses it with 428 `ConfirmationRequiredError` until a token comes with it. At a terminal the CLI asks the API to email the key's creator a code, asks you to type it, turns it into a single-use token and sends the command once more; it never prints the token. A refused code exits 3. Without a terminal it exits 4 with reason `ApprovalRequired` and names the steps: `akter approvals request` emails the code, `akter approvals confirm` turns it into a token, and the command runs again with `--approval <token>`.\n- `--organization` defaults to `AKTER_ORGANIZATION`, then the organization saved by `akter login`; `--url` to `AKTER_CLOUD_URL`, then the saved URL, then `https://api.akter.dev`.\n\n## `akter computers`\n\n`akter computers <list|get|logs|pause|resume|stop|delete> --url <app url> --actor <Actor> --key <key>` reaches one actor's computers over its `<Actor>/computer/<op>` RPCs, and each operation is also the `computers_<op>` MCP tool. Every operation but `list` takes `--computer <name>`. `logs` prints a page of the computer's log, oldest first, each line with its `seq`; `--after <seq>` reads on after the last line printed and `--limit` takes 1 to 1000 lines. Each computer's lines also reach the app's log with source `computer` and subject `<environment>/<Actor>/<key>/<computer>`, so `akter logs follow --app <app> --source computer` follows every computer of the app at once. `pause` keeps memory and disk, `stop` keeps the disk, and `resume` fails while a fork holds the computer. There is no command to make a computer or run one of its commands: only the actor's own jobs do that.\n\n`delete` removes the computer and its disk, so it asks a person to confirm, exits 4 when stdin or stdout isn't a terminal, and prints the request without asking under `--dry-run`.\n\n## `akter logs follow`\n\n`akter logs follow --app <app>` prints an app's log lines as they arrive, oldest first, one per line: when, the level, what wrote it and what it's about, then the message. It keeps reading after the last line it printed and waits two seconds when nothing new has come. It runs until interrupted, or until `--count <n>` lines have printed. `--deploy`, `--since` and `--source` narrow it as they do `akter logs read`; the sources are `deploy`, a deploy's progress with its id as the subject, and `computer`, what happened to one of the app's computers. `--json` prints each line as one line of JSON in the API's `LogLine` schema.\n\nIt never prompts. A timeout, a dropped connection, 429 or 5xx is retried with backoff, and each retry is noted on stderr. Any other refusal ends it with the exit code below, such as 1 for an app that doesn't exist and 3 for a key without access.\n\n## Signing in\n\nEvery Cloud command, `deploy` and `export` included, signs in the same way:\n\n1. `AKTER_API_KEY`, an API key or an agent key, when it is set and not empty. Scripts, CI and agents use this. When `AKTER_CLOUD_URL` is set too, the key goes only to that origin: a `--url` naming another server exits 2 with `ApiKeyForOtherUrl`, naming both origins, instead of sending the key there. Drop `--url`, or point `AKTER_CLOUD_URL` at the server you mean.\n2. Otherwise the session or key `akter login` saved. It goes only to the Cloud URL it was saved for: a `--url` or `AKTER_CLOUD_URL` that names another server exits 3 with `LoginForOtherUrl` instead of sending it there. Sign in for that URL, or set `AKTER_API_KEY`.\n\n`akter login --email <address>` emails a six-digit code and asks for it when a person is at the terminal; `akter signup` is the same, for an address with no account yet, since the first sign-in creates it. Without a terminal, as an agent runs it, the command emails the code, prints how to finish (with `--json`, `{ \"codeSent\": true, \"email\", \"expiresAt\" }`) and exits 0 without waiting; `akter login --email <address> --code <code>` then finishes. A refused code exits 3 and saves nothing; `--email` missing without a terminal exits 2. A code that creates an account first needs Akter's terms of service and privacy notice accepted, which `akter docs legal/terms` and `akter docs legal/privacy` print. The CLI asks a person at the terminal once, naming their version, and then sends the same code again; `--accept-terms` accepts them without asking, for an agent. Without a terminal or the flag, it exits 4, names the flag and saves nothing, and the code still works for the next run. A sign-in to an existing account is never asked. The session's secret is saved like a key, below, and never printed: `--json` prints the account, whether this sign-in `created` it, the session's id and expiry, and where it was saved.\n\n`akter login --with-api-key --url <cloud-url>` saves a key instead: it reads the key from stdin or a hidden prompt, never from a flag, checks it with the Cloud API and saves it. The key goes to the OS keychain (macOS Keychain, or the Secret Service through `secret-tool` on Linux) when one is reachable, and otherwise into `$XDG_CONFIG_HOME/akter/login.json` (`~/.config/akter/login.json`), which only you can read (mode 0600). `akter logout` removes it.\n\nWithout either, a Cloud command exits 3.\n\n## `akter docs`\n\n`akter docs` lists the topics of these docs, and `akter docs <topic>` prints one page as Markdown, such as `akter docs reference/cli`, or `akter docs cli` when only one page has that name. `--json` prints the list, or the page with its topic and title, as one line of JSON. An unknown topic exits 2 and lists the topics that contain it.\n\n## Exit codes\n\n| Code | Meaning |\n| --- | --- |\n| 0 | Done. |\n| 1 | Failed: the API refused (404, 409 and the like), the answer broke its schema, or a command such as `deploy` ended without success. |\n| 2 | Usage: an unknown flag, a missing or invalid input, or a 400 or 422 from the API. |\n| 3 | Authentication: not signed in, the API answered 401 or 403, including when it refused the key at sign-in, or an actor refused the caller, by its kind (`CallerNotAllowedError`) or by its `files.authorize` rule (`FileAccessDeniedError`). |\n| 4 | Confirmation: a person had to confirm or approve and couldn't be asked, or declined; also a 428 from the API. |\n| 5 | Unavailable: the API couldn't be reached, timed out, or answered 408, 429 or 5xx, including at sign-in. Retrying may help. Every Cloud command's sign-in first retries a 5xx for about 30 seconds, so it rides out a Cloud deploy. |\n| 130 | Interrupted. |\n\n`deploy` and `export` use the same codes when the API answers with a status, and 1 when it can't be reached; signing in, their first step, exits 3 or 5 as above. Treat a nonzero exit as failure and retain its diagnostic. With `--json`, a failure the CLI detects itself prints one JSON object with `code`, `reason` and `message`. Help exits successfully, deployment success requires the terminal `Live` notice, and an export is complete only when it prints `Exported <n> actors to <folder>` and exits 0. An uploaded build, a printed deployment id or an interrupted follow isn't equivalent to a successful deployment.\n",
94
+ "markdown": "# CLI\n\nThe `akter` executable belongs to `@akterjs/cli`. In an app workspace with that package installed, run `bunx akter`. Use `akter --help` and `akter <command> --help` for the flags in your installed build.\n\n| Command | Status |\n| --- | --- |\n| [`akter dev`](#akter-dev) | Local engine and read-only inspector. |\n| [`akter dev snapshots`, `akter dev environments`](#akter-dev-snapshots-and-akter-dev-environments) | Snapshot, branch and promote the local folder's environments, as on Akter Cloud. |\n| [`akter deploy`](#akter-deploy) | Cloud API build upload and deployment progress. |\n| [`akter migrate --all`](#akter-migrate) | Apply migrations to actors in a local folder. |\n| [`akter history`](#akter-history) | Read or verify a local actor's command journal. |\n| [`akter export`](#akter-export) | Download every actor's database and history from Akter Cloud into one `.akter` archive. |\n| [`akter import`](#akter-import) | Read an `.akter` archive into a local folder, checking every entry. |\n| [`akter bench`](#akter-bench) | Run a workload against `akter dev` or an Akter Cloud app and report every outcome. |\n| [`akter <group> <operation>`](#cloud-api-commands) | One command per Cloud API endpoint, such as `akter apps list`. |\n| [`akter login`, `akter signup`, `akter logout`](#signing-in) | Sign in or create an account with an emailed code, save or remove the login every Cloud command uses. |\n| [`akter docs`](#akter-docs) | Print these docs as Markdown. |\n\nOrganization, member, API key, app, build, deploy, domain, log, secret, account, session, usage and billing commands are [Cloud API commands](#cloud-api-commands). Calls to an app's actors are `akter actors call`, `query`, `state`, `watch`, `create`, `ensure` and [`fork`](#forking-an-actor); their files are `akter files` and their computers [`akter computers`](#akter-computers). Locally, [`akter dev snapshots` and `akter dev environments`](#akter-dev-snapshots-and-akter-dev-environments) snapshot, branch and promote. On Cloud, branch, restore and snapshot commands are not registered yet. Older operator commands aren't available either.\n\n## Shared app entry\n\n`dev`, `deploy`, `migrate` and `history` load `--entry`, defaulting to `src/app.layer.ts`. It must export the named value `app = { actors, layer }`. See the [checked deployment entry](../deploy/overview.md#write-the-server) for an example.\n\n## `akter dev`\n\n```sh\nbunx akter dev --entry src/app.layer.ts --dir .akter --port 4000\n```\n\n| Flag | Default | Meaning |\n| --- | --- | --- |\n| `--entry` | `src/app.layer.ts` | The module exporting `app`. |\n| `--dir` | `.akter` | The local actor folder. |\n| `--port` | `PORT`, otherwise `4000` | RPC listener port. |\n| `--inspector-port` | RPC port + 1 | Read-only inspector port; a zero RPC port selects a free inspector port. |\n| `--allowed-host` | Loopback names only | Additional allowed Host name; repeatable. |\n| `--reset` | Off | Ask before emptying the local actor folder. |\n| `--from` | None | An `.akter` archive to [import](#akter-import) into `--dir` first; `--dir` must not exist yet. |\n| `--environment` | The promoted one | Serve this environment of the folder, such as a quiet branch, instead of the one promoted to serve. |\n\nThe runner watches the entry for changes and restarts while keeping the folder. RPC is served at `/rpc`. Both listeners bind to loopback and check the Host header; an additional allowed name doesn't authenticate a caller. Don't expose the inspector publicly. See [Operating locally](../guides/operating.md#operator-access).\n\n## `akter dev snapshots` and `akter dev environments`\n\n```sh\nbunx akter dev snapshots create --name before-import\nbunx akter dev environments branch --name trial --snapshot before-import\nbunx akter dev --environment trial --port 4100 # call the quiet branch\nbunx akter dev environments promote --name trial\nbunx akter dev environments promote --name dev # promote back\n```\n\n| Command | Meaning |\n| --- | --- |\n| `snapshots create --name <n>` | Snapshot the serving environment, or `--environment`'s. The `akter dev` serving it takes it; until one does it stays `Pending`. |\n| `snapshots list`, `snapshots get --name <n>` | The environment's live snapshots. Ids are `snapshot-<n>`, numbered from 0 and never reused. |\n| `snapshots delete --name <n>` | Retire the snapshot and remove its copy. Its name is free again; its id isn't. |\n| `environments list`, `environments get --name <e>` | Every environment, deleted ones included, with `serving` and `quiet`. |\n| `environments branch --name <e> --snapshot <n>` | A new, quiet environment from a `Ready` snapshot of the serving environment, or `--from`'s. |\n| `environments promote --name <e>` | Serve `<e>` instead and lift its quiet. Promoting the one that serves changes nothing and prints the same result. |\n| `environments delete --name <e>` | Remove an environment that doesn't serve. `dev` and the serving one are refused; the name stays taken. |\n\nEvery command takes `--dir` and `--json`; with `--json` it prints the same shapes as Akter Cloud's `snapshots` and `environments` operations, and a refusal prints `code`, `reason` and `message`. The promote prints what it leaves out. See [Snapshots, branches and promote](../guides/operating.md#snapshots-branches-and-promote).\n\n## `akter deploy`\n\n```sh\nnpx @akterjs/cli deploy \\\n --organization \"$AKTER_ORGANIZATION\" \\\n --app \"$AKTER_APP\" \\\n --environment \"$AKTER_ENVIRONMENT\"\n```\n\n| Flag | Default | Meaning |\n| --- | --- | --- |\n| `--organization` | `AKTER_ORGANIZATION` | Existing organization. |\n| `--app` | Required | Existing app. |\n| `--environment` | `prod` | Provisioned destination environment. |\n| `--url` | `AKTER_CLOUD_URL`, then the saved login, then `https://api.akter.dev` | Cloud API base URL; HTTPS except for loopback development. |\n| `--entry` | `src/app.layer.ts` | The module exporting `app`. |\n| `--domain` | None | Claim this customer hostname for the environment and print the CNAME to add. |\n| `--json` | Off | Print the live deploy as one line of JSON in the API's `Deploy` schema, with its `hostname` and `url`; progress goes to stderr. |\n\nThe key comes from [signing in](#signing-in) and needs deploy scope for the organization. The key is exchanged for a short-lived bearer token; signed uploads don't receive that bearer. The CLI rejects redirects for token exchange, API requests and uploads.\n\nThe CLI uploads a new build or reuses a matching Ready one, confirms Ready, creates a new deployment and prints its id. Persisted notices are printed once each in order until `Live`, `NotServing` or `RolledBack`. `Live` prints `Actors at https://<hostname>`, the app's own hostname for that environment, where an Akter client calls its actors, and exits 0; `NotServing` prints why the published build isn't serving and exits nonzero; `RolledBack` exits nonzero. Build confirmation and deployment following have five-minute and thirty-minute deadlines respectively. Interrupting or timing out the CLI doesn't cancel the remote deployment.\n\n`akter deploy` doesn't create the organization or the app: `akter organizations create` and `akter apps create` do. An upload that succeeds doesn't by itself mean the deployment goes live; wait for `Live`.\n\nThere is no region flag. See [Deploying](../deploy/overview.md).\n\n## `akter migrate`\n\n```sh\nbunx akter migrate --all --dry-run --entry src/app.layer.ts --dir .akter\n```\n\n`--all` is required; migrating one actor from the CLI isn't implemented. Without `--dry-run`, pending migrations are applied now rather than on the actor's next open. Output names each actor's old and new migration version. A failure stops the command, so actors later in the traversal aren't migrated by that run. This command operates on a local folder, not the Cloud API.\n\n## `akter history`\n\n```sh\nbunx akter history Note/lobby --entry src/app.layer.ts --dir .akter --json\nbunx akter history Note/lobby --entry src/app.layer.ts --dir .akter --verify\n```\n\nThe journal is read oldest first. `--json` emits one JSON object per command. `--since` accepts a whole number with `ms`, `s`, `m`, `h` or `d`; a retained-history boundary is printed when the journal doesn't cover the full history.\n\n`--verify` replays the kept history against the current handlers and reports either no difference or the first mismatching outcome. It can't be combined with `--since`, and it refuses a replay whose initial history has been pruned. To verify a Cloud app's actors, export the app, import the archive and run `--verify` on the folder ([Use the exported data](../guides/exporting.md#use-the-exported-data)). See [History and replay](../core/history-and-replay.md).\n\n## `akter export`\n\n```sh\nbunx akter export \\\n --organization \"$AKTER_ORGANIZATION\" \\\n --app \"$AKTER_APP\" \\\n --url \"$AKTER_CLOUD_URL\" \\\n --out ./chat.akter\n```\n\n| Flag | Default | Meaning |\n| --- | --- | --- |\n| `--organization` | `AKTER_ORGANIZATION` | Existing organization. |\n| `--app` | Required | The app whose actors to export. |\n| `--url` | `AKTER_CLOUD_URL`, then the saved login, then `https://api.akter.dev` | Cloud API base URL; HTTPS except for loopback development. |\n| `--out` | Required | The `.akter` archive to write; it must not exist yet. Run again with the same path to resume. |\n\nThe key comes from [signing in](#signing-in) and needs export scope for the organization; a key with only deploy, call or read scope is refused. Every listing, snapshot and download request is authorized for that organization's app, and none of them reach another app or organization.\n\nAn export is one `.akter` file: a tar archive compressed with zstd (ADR 0019). Its first entry is `manifest.json`, which records the format version (1), when it was written, the size and SHA-256 of every other entry, the `computers` section with each computer the app's actors keep (its disk and checkpoint stay in Akter Cloud, so the checkpoint is marked `\"portable\": false`), and the `lineage` section, with one entry per forked actor: the actor, the actor it was forked from (`parent`), the fork's id (`fork`) and the parent's commit version at the cut (`forkedAt`). The entries after it are:\n\n- `shards/<shard>/<Actor>/<key>/actor.db` for each actor that has a database, in the layout `akter dev` uses, so `bunx akter dev --from ./chat.akter --dir ./chat` serves the exported actors.\n- Each `actor.db` is a plain, decrypted SQLite database that stock `sqlite3` opens. It holds the actor's whole database at one consistent point after its last committed command: its state, its own tables, its command journal (the history `akter history` reads), and its pending timers, outbox and jobs.\n- `shards/<shard>/<Actor>/<key>/files/<sha256>` for each distinct file the actor's database names, its plaintext content named by its SHA-256. The paths, sizes and times of the actor's files stay in its `actor.db`.\n- Nothing else. It holds no Cloud keys, no export records and no file keys: the CLI blanks every file grant in `actor.db` and rewrites the file before it archives it.\n\nAn erased actor has nothing to export: the CLI prints `<Actor>/<key>: erased, nothing to export` and goes on.\n\nEach actor is snapshotted on its own, after a commit and while no command runs on it, so its database is consistent. Actors are exported one after another, so two actors' snapshots come from different moments. The snapshot stays encrypted on the server under a key of its own, and only the download decrypts it. When the snapshot is taken, its completion record gets a MAC over every page in order. The server checks that MAC in the same pass that computes the snapshot's SHA-256, before it reports the snapshot, so a page rolled back to an earlier copy of itself stops the export with a gone-snapshot error instead of exporting stale data. That check covers the snapshot file only. The live `actor.db` on the server is authenticated page by page, so a page rolled back inside it is outside what export can detect, and a snapshot taken afterwards exports the rolled-back page as it is. Starting an actor's export replaces that actor's previous snapshot, so run one export of an app at a time.\n\nThe CLI downloads into a staging folder beside the archive, `<out>.staging`, at most 64 KiB per request, and prints each actor's progress every MiB and when it's done. It downloads an actor's files first, each into `files/<sha256>.export` and checked against its SHA-256 before it's renamed, then its database, which it checks against the SHA-256 the server computed when it took the snapshot, strips of file grants and only then renames to `actor.db`. While an actor downloads, `actor.db.export` holds the database's bytes so far and `actor.db.export.json` the snapshot they come from. A finished file is kept for the next run, and a file the actor's snapshot doesn't hold is removed from `files`. After an interruption, run the same command with the same `--out`: finished actors are kept, and a partly downloaded actor continues from the same snapshot. When every actor is in, the CLI writes the archive as `<out>.partial`, renames it to `<out>`, removes the staging folder and prints `Wrote <out> with <n> entries`. An export is complete only when it prints that line. If that snapshot was replaced, failed authentication on the server or doesn't match its SHA-256, the CLI deletes the partial download and exits nonzero; run it again to take a new snapshot.\n\nSee [Exporting an app](../guides/exporting.md) for a walkthrough.\n\n## `akter import`\n\n```sh\nbunx akter import ./chat.akter --dir ./chat\n```\n\n| Flag | Default | Meaning |\n| --- | --- | --- |\n| `<archive>` | Required | The `.akter` archive to read. |\n| `--dir` | `.akter` | A new folder to read the actors into; it must not exist yet. |\n\nThe CLI reads the archive as a stream into `<dir>.importing`, checks every entry against the size and SHA-256 its manifest records, takes each actor's `files/<sha256>` into the folder's file home, `files-home`, under the actor's local identity, and renames the folder to `--dir` only once every entry has passed and every file is in. It refuses an archive whose first entry isn't `manifest.json`, that holds an entry its manifest doesn't list, whose entry doesn't match its checksum, that was cut short, that a newer akter wrote, or whose files can't be taken in, and then leaves no folder behind. Every format version akter has written stays readable. `akter dev`, `akter history` and `akter migrate` read the imported folder.\n\n## `akter bench`\n\n```sh\nbunx akter bench tests/sale.workload.ts --duration 30s --concurrency 8\nbunx akter bench tests/doc.workload.ts --duration 60s --json\n```\n\nThe workload module exports `workload = ({ id, kind, url }) => ({ name, open, step })`. `id` names this run, `url` is the target and `kind` says what it is: `\"local\"` for `akter dev`, `\"cloud\"` for an Akter Cloud app and `\"comparison\"` for another system, so a workload sends a development identity such as the `akter-principal` header only when `kind` is `\"local\"`. `open` is an Effect that needs an Akter client and returns a session, and `step(session)` is one operation whose success value names its outcome. Without `--url`, the command starts `akter dev` with `--entry` on an empty temporary folder and stops it when the run ends. A loopback `--url` reuses a running `akter dev`. Any other `--url` is an Akter Cloud app: the command signs in with `AKTER_API_KEY` or the key `akter login` saved, and keeps the run signed in past the 15-minute token. `--system <name> --url <url>` runs a workload against another system for comparison and signs in to nothing.\n\n`--concurrency` workers (8 by default) each run one step at a time and start no new step after `--duration` (30s by default). A step, or the workload's `open`, with no answer within `--step-timeout` (30s by default) counts as `failed: no answer within <ms> ms` and the worker moves on, so one stuck step can't hold the run open. The report has one row per outcome, and a failed step counts as `failed: <error tag>`, so failures and losses stay in the table. Each row and the total give steps, steps per second over the whole run, and p50, p90, p99 and max latency in milliseconds. Cost per row is always `unmeasured`.\n\nA local run's output starts with a `LOCAL RUN` notice: the numbers describe this machine and this checkout, not Akter Cloud. A Cloud run's starts with `AKTER CLOUD RUN`: every latency includes the network path from the machine that ran the bench to the app. The report also names the hardware, the runtime, the versions of `@akterjs/cli`, `@akterjs/client`, `@akterjs/effect` and `effect`, the git commit and whether the worktree is clean, and the SHA-256 of the nearest lockfile. `--json` prints the same report as one JSON object, with `\"local\": true` for a local run and `false` for a Cloud run.\n\n## Operator commands\n\nThe old `inspect`, `log`, `snapshot` and `retention` command groups aren't registered. Local inspection is the read-only listener started by `dev`; see [Operating locally](../guides/operating.md).\n\n## Forking an actor\n\n`akter actors fork --url <app url> --actor <Actor> --key <key> --into <new key>` copies an actor into a new actor at another key: its state and files at one moment, with none of its work in flight, since its jobs, timers and undelivered messages stay with the original. It prints the original's commit version at the cut. A retry with the same `--command-id` makes one copy, and `--dry-run` prints the request without sending it. There is no top-level `akter fork`; don't use the old history-copying examples against a 1.0 actor folder.\n\nOn the local engine the copy also gets each of the actor's computers: its disk as it was at the cut, stopped, so no process the original ran runs in the copy. While it copies them the fork holds the original's computers paused under the fork's id: a step already running finishes first, and one sent meanwhile fails with `ComputerHeldError` naming the fork's id. Then each computer goes back to where it was. If the engine stops partway through a fork, the hold stays until a retry with the same id finishes the fork. A fork whose copies would pass the store's limit of 4 computers is refused with `InvalidRequestError`. Akter Cloud copies each computer by its disk alone too, but to do that it stops the original's computer first, so one that was running starts again from its disk with its memory and processes gone, and one that was paused stays stopped. A copy that fails keeps the hold until a retry with the same fork id copies it. Akter Cloud refuses, with `ActorUnavailableError`, a fork whose copies would pass the environment's limit of 4 computers, and a fork with computers into a key on another shard.\n\nWhere the fork runs depends on the target, the same rule every actor command and `akter bench` use. A loopback `--url` (or `AKTER_APP_URL`), such as the address `akter dev` prints, is the local engine: the command sends the actor's fork RPC, `<Actor>/fork`, with no sign-in and no question. Any other target is Akter Cloud, where forking is an operator action (decision 5): the gateway refuses the fork RPC for every caller, so the command runs the Cloud API operation `actorForks.create` instead, `POST /v1/organizations/{organization}/apps/{app}/environments/{environment}/actors/{actor}/{key}/forks` with `into` and `forkId`:\n\n```sh\nakter actors fork --organization acme --app shop --environment prod --actor Sale --key s1 --into s1-try\n```\n\nIt signs in with your credentials (`AKTER_API_KEY` or `akter login`) at the Cloud API (`AKTER_CLOUD_URL` or the URL `akter login` saved); `--organization` defaults as for every Cloud command, and `--command-id` is sent as the fork id. Like every dangerous Cloud command it asks the person at the terminal to confirm, and exits 4 when no terminal can ask. An API key's fork also needs its creator's approval: at a terminal the command asks for the emailed code and retries once with the token, and without one it takes `--approval <token>` from `akter approvals request` and `akter approvals confirm`. The key needs the `fork` scope. On the hosted MCP server the same fork is the `actors_fork` tool, which takes `organization`, `app`, `environment`, `actor`, `key`, `into` and `forkId` and asks the person before anything is sent. The Effect and Promise clients' `fork(into)` stays an actor RPC, so it forks on `akter dev` and is refused on Akter Cloud by design.\n\nCloud forks are a preview behind `cloudFork`, default off. The CLI leaves `actors fork` out of help but still accepts it by name; control refuses an organization without the flag. MCP currently hides `actors_fork` from everyone until it can read organization flags, without falling back to the forbidden actor RPC. Local forks do not use a flag.\n\n## Cloud API commands\n\nEvery Cloud API endpoint is one command, `akter <group> <operation>`, named after the API's own groups and operations: `akter apps list`, `akter apps create`, `akter deploys get`, `akter members change-role` and so on. `akter --help` lists the groups and `akter <group> --help` their operations. The same list, with the same names, descriptions, input schemas and safety hints, is what Akter's MCP tools are built from, so a command and its tool always agree.\n\n- Each field of the operation's input is a flag, such as `--organization` and `--name`. `--input '<json>'` takes the whole input as one JSON object, the same arguments the MCP tool takes; `--input @file.json` reads a file and `--input -` reads stdin. Flags override its fields. Pass a secret, such as a `secrets set` value, with `--input -` or `--input @file.json` rather than a flag, so it stays out of the process list and shell history; `--dry-run` prints the body, secret included. The CLI checks the input against the operation's schema before it sends anything and exits 2 when it doesn't match.\n- `--json` prints the API's answer as one line of JSON in the API's own schema, after checking it against that schema; an answer that doesn't match exits 1, because the CLI and the API disagree. Without `--json` the answer is printed indented. A refusal prints the API's error body with `--json`, and one line on stderr otherwise. After a 503 on a change that is safe to repeat, such as `akter actors erase`, that line adds that it may have stopped partway and to run the same command again.\n- A read that pages takes `--after` and answers with `next` while there is more: `akter actors list`, which lists an app's actors by name and key (`--actor Room` for one name, `--environment` for an environment other than `prod`), and `akter actors history`. An `akter actors list` page holds `--limit` actors (500 at most, and by default) unless it is the last, and the last page has no `next`, so read on until `next` is absent. `--all` does that: it sends each page's `next` as `--after` until a page has none and prints one answer in the API's schema with every page's entries and no `next`. A refused page stops it with that page's error and exit code.\n- Commands that change something take `--dry-run`, which checks the input and prints the request instead of sending it.\n- Destructive commands, such as `akter apps delete`, ask a person to confirm. When stdin or stdout isn't a terminal they never ask: they exit 4 at once, unless `--approval <token>` carries an approval for the action.\n- Signed in with an API key, a dangerous action also needs its creator's approval, and the API refuses it with 428 `ConfirmationRequiredError` until a token comes with it. At a terminal the CLI asks the API to email the key's creator a code, asks you to type it, turns it into a single-use token and sends the command once more; it never prints the token. A refused code exits 3. Without a terminal it exits 4 with reason `ApprovalRequired` and names the steps: `akter approvals request` emails the code, `akter approvals confirm` turns it into a token, and the command runs again with `--approval <token>`.\n- `--organization` defaults to `AKTER_ORGANIZATION`, then the organization saved by `akter login`; `--url` to `AKTER_CLOUD_URL`, then the saved URL, then `https://api.akter.dev`.\n\n## `akter computers`\n\n`akter computers <list|get|logs|pause|resume|stop|delete> --url <app url> --actor <Actor> --key <key>` reaches one actor's computers over its `<Actor>/computer/<op>` RPCs, and each operation is also the `computers_<op>` MCP tool. Every operation but `list` takes `--computer <name>`. `logs` prints a page of the computer's log, oldest first, each line with its `seq`; `--after <seq>` reads on after the last line printed and `--limit` takes 1 to 1000 lines. Each computer's lines also reach the app's log with source `computer` and subject `<environment>/<Actor>/<key>/<computer>`, so `akter logs follow --app <app> --source computer` follows every computer of the app at once. `pause` keeps memory and disk, `stop` keeps the disk, and `resume` fails while a fork holds the computer. There is no command to make a computer or run one of its commands: only the actor's own jobs do that.\n\n`delete` removes the computer and its disk, so it asks a person to confirm, exits 4 when stdin or stdout isn't a terminal, and prints the request without asking under `--dry-run`.\n\n## `akter logs follow`\n\n`akter logs follow --app <app>` prints an app's log lines as they arrive, oldest first, one per line: when, the level, what wrote it and what it's about, then the message. It keeps reading after the last line it printed and waits two seconds when nothing new has come. It runs until interrupted, or until `--count <n>` lines have printed. `--deploy`, `--since` and `--source` narrow it as they do `akter logs read`; the sources are `deploy`, a deploy's progress with its id as the subject, and `computer`, what happened to one of the app's computers. `--json` prints each line as one line of JSON in the API's `LogLine` schema.\n\nIt never prompts. A timeout, a dropped connection, 429 or 5xx is retried with backoff, and each retry is noted on stderr. Any other refusal ends it with the exit code below, such as 1 for an app that doesn't exist and 3 for a key without access.\n\n## Signing in\n\nEvery Cloud command, `deploy` and `export` included, signs in the same way:\n\n1. `AKTER_API_KEY`, an API key or an agent key, when it is set and not empty. Scripts, CI and agents use this. When `AKTER_CLOUD_URL` is set too, the key goes only to that origin: a `--url` naming another server exits 2 with `ApiKeyForOtherUrl`, naming both origins, instead of sending the key there. Drop `--url`, or point `AKTER_CLOUD_URL` at the server you mean.\n2. Otherwise the session or key `akter login` saved. It goes only to the Cloud URL it was saved for: a `--url` or `AKTER_CLOUD_URL` that names another server exits 3 with `LoginForOtherUrl` instead of sending it there. Sign in for that URL, or set `AKTER_API_KEY`.\n\n`akter login --email <address>` emails a six-digit code and asks for it when a person is at the terminal; `akter signup` is the same, for an address with no account yet, since the first sign-in creates it. Without a terminal, as an agent runs it, the command emails the code, prints how to finish (with `--json`, `{ \"codeSent\": true, \"email\", \"expiresAt\" }`) and exits 0 without waiting; `akter login --email <address> --code <code>` then finishes. A refused code exits 3 and saves nothing; `--email` missing without a terminal exits 2. A code that creates an account first needs Akter's terms of service and privacy notice accepted, which `akter docs legal/terms` and `akter docs legal/privacy` print. The CLI asks a person at the terminal once, naming their version, and then sends the same code again; `--accept-terms` accepts them without asking, for an agent. Without a terminal or the flag, it exits 4, names the flag and saves nothing, and the code still works for the next run. A sign-in to an existing account is never asked. The session's secret is saved like a key, below, and never printed: `--json` prints the account, whether this sign-in `created` it, the session's id and expiry, and where it was saved.\n\n`akter login --with-api-key --url <cloud-url>` saves a key instead: it reads the key from stdin or a hidden prompt, never from a flag, checks it with the Cloud API and saves it. The key goes to the OS keychain (macOS Keychain, or the Secret Service through `secret-tool` on Linux) when one is reachable, and otherwise into `$XDG_CONFIG_HOME/akter/login.json` (`~/.config/akter/login.json`), which only you can read (mode 0600). `akter logout` removes it.\n\nWithout either, a Cloud command exits 3.\n\n## `akter docs`\n\n`akter docs` lists the topics of these docs, and `akter docs <topic>` prints one page as Markdown, such as `akter docs reference/cli`, or `akter docs cli` when only one page has that name. `--json` prints the list, or the page with its topic and title, as one line of JSON. An unknown topic exits 2 and lists the topics that contain it.\n\n## Exit codes\n\n| Code | Meaning |\n| --- | --- |\n| 0 | Done. |\n| 1 | Failed: the API refused (404, 409 and the like), the answer broke its schema, or a command such as `deploy` ended without success. |\n| 2 | Usage: an unknown flag, a missing or invalid input, or a 400 or 422 from the API. |\n| 3 | Authentication: not signed in, the API answered 401 or 403, including when it refused the key at sign-in, or an actor refused the caller, by its kind (`CallerNotAllowedError`) or by its `files.authorize` rule (`FileAccessDeniedError`). |\n| 4 | Confirmation: a person had to confirm or approve and couldn't be asked, or declined; also a 428 from the API. |\n| 5 | Unavailable: the API couldn't be reached, timed out, or answered 408, 429 or 5xx, including at sign-in. Retrying may help. Every Cloud command's sign-in first retries a 5xx for about 30 seconds, so it rides out a Cloud deploy. |\n| 130 | Interrupted. |\n\n`deploy` and `export` use the same codes when the API answers with a status, and 1 when it can't be reached; signing in, their first step, exits 3 or 5 as above. Treat a nonzero exit as failure and retain its diagnostic. With `--json`, a failure the CLI detects itself prints one JSON object with `code`, `reason` and `message`. Help exits successfully, deployment success requires the terminal `Live` notice, and an export is complete only when it prints `Exported <n> actors to <folder>` and exits 0. An uploaded build, a printed deployment id or an interrupted follow isn't equivalent to a successful deployment.\n",
127
95
  "topic": "reference/cli"
128
96
  },
129
97
  {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@akterjs/cli",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "The akter command: local engine, deploy, branch, restore, history, export, migrate and bench.",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -32,9 +32,9 @@
32
32
  "esbuild": "0.28.2"
33
33
  },
34
34
  "devDependencies": {
35
- "@akterjs/client": "0.1.0",
35
+ "@akterjs/client": "0.1.2",
36
36
  "@akterjs/cloud-api": "file:../../../akter-cloud/packages/cloud-api",
37
- "@akterjs/effect": "0.1.0",
37
+ "@akterjs/effect": "0.1.2",
38
38
  "@effect/openapi-generator": "4.1.2",
39
39
  "@effect/platform-node": "4.1.2",
40
40
  "@effect/vitest": "4.1.2",