@workser/cli 0.3.1 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@workser/cli",
3
- "version": "0.3.1",
3
+ "version": "0.6.0",
4
4
  "description": "Workser CLI — give your local AI agent native DevOps & infrastructure on Workser. The agent runs `workser …` to provision, deploy, and manage real apps.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -37,7 +37,9 @@
37
37
  "format": "prettier --write \"src/**/*.ts\"",
38
38
  "start": "node dist/index.js",
39
39
  "test": "npm run build && vitest run",
40
- "prepublishOnly": "npm run typecheck && npm run test"
40
+ "preversion": "npm run typecheck && npm run test",
41
+ "postversion": "git push -u origin HEAD && git push --tags && npm publish",
42
+ "prepublishOnly": "npm run build && npm run typecheck && npm run test"
41
43
  },
42
44
  "dependencies": {
43
45
  "commander": "^14.0.0",
@@ -0,0 +1,54 @@
1
+ ---
2
+ topic: analysis
3
+ title: Analysis — running Python on this project's data
4
+ summary: Run pandas locally under a sandbox and a clock, so the code, the output and the timing land in the task where the owner can see them.
5
+ commands: [analysis]
6
+ ---
7
+
8
+ # Analysis — running Python on this project's data
9
+
10
+ ```
11
+ workser analysis runtime [--app <webAppId>]
12
+ workser analysis run --app <webAppId> --file report.py [--timeout <ms>]
13
+ workser analysis run --app <webAppId> --code 'print(1)'
14
+ ```
15
+
16
+ ## Why not just run `python` yourself
17
+
18
+ Two reasons, and the second matters more.
19
+
20
+ It runs inside the same OS sandbox a structured agent run gets, scoped to the
21
+ app's own folder — so a script that goes wrong goes wrong in one directory.
22
+
23
+ And it is **recorded**. The code, the output and how long it took land in the
24
+ task, where the owner can see them. An analysis nobody can see is an assertion,
25
+ which is the same problem `workser api call` solves for a service with no
26
+ screen. If a number is going to end up in front of the customer, run it here.
27
+
28
+ ## Check the runtime before you write the script
29
+
30
+ ```
31
+ workser analysis runtime --app <id> --json
32
+ ```
33
+
34
+ It reports the interpreter that would be used — the app's own `.venv` first, if
35
+ it has one — and whether `pandas` and `matplotlib` are importable. Exit code is
36
+ non-zero when Python is missing, so you find out in a second rather than after
37
+ writing a hundred lines.
38
+
39
+ ## Limits, said plainly
40
+
41
+ Five minutes by default, fifteen at most. Output is capped per stream and
42
+ truncation is reported. Nothing is silently dropped.
43
+
44
+ These are local limits and they are the right ones: this work does **not** go in
45
+ a deployed function. `maxDuration` is for a slow request; an analysis reads a lot
46
+ of rows and takes as long as it takes, so putting it behind a serverless timeout
47
+ means the useful analyses are exactly the ones that fail.
48
+
49
+ ## What counts as evidence
50
+
51
+ A number on its own is not a finding. When you report a result, say what the
52
+ query was, how many rows it covered, and what window of time — a figure with no
53
+ denominator is the easiest thing in this product to get wrong and the hardest
54
+ for the owner to check.
@@ -0,0 +1,79 @@
1
+ ---
2
+ topic: api
3
+ title: Services — calling one, and describing it
4
+ summary: Call this project's API through the same console the owner sees, and make sure every route it serves is written down before you call the task done.
5
+ commands: [api]
6
+ ---
7
+
8
+ # Services — calling one, and describing it
9
+
10
+ A service has no screen. Everything else you build can be looked at; an API can
11
+ only be *called* — so unless the calls go somewhere the owner can see, "the API
12
+ works" is an assertion with nothing behind it.
13
+
14
+ ```
15
+ workser api list [--app <webAppId>]
16
+ workser api call <path> [--app <id>] [--method <verb>] [--body <text>]
17
+ [--header 'Name: value'] [--env local|preview|production]
18
+ workser api spec [--check]
19
+ ```
20
+
21
+ ## Call it through the console, not through curl
22
+
23
+ `workser api call` goes through the same request console the owner has open. The
24
+ status, the timing and the body you see are the ones they see, and the
25
+ credentials come from the app's own environment rather than from your command
26
+ line — so a token never lands in a transcript.
27
+
28
+ ```
29
+ workser api call /orders --app <id> --json
30
+ workser api call /orders --app <id> --method POST --body '{"item":"latte"}' --json
31
+ ```
32
+
33
+ `--env` picks which copy to call. `local` is the dev server on this machine and
34
+ is the default; `preview` and `production` are the deployments. The host always
35
+ comes from that choice — a path is a path, never a URL, and passing one is
36
+ refused.
37
+
38
+ Exit code: non-zero only when nothing answered. A 404 or a 422 is a *successful*
39
+ call with an informative answer, so checking that a route correctly rejects bad
40
+ input works exactly as you would expect.
41
+
42
+ ## Save the calls that matter
43
+
44
+ Requests saved at `api/requests.json` in the service's repo show up in the
45
+ owner's console. Write the handful that describe what the service does — not a
46
+ test suite:
47
+
48
+ ```json
49
+ [
50
+ { "id": "list-orders", "name": "List today's orders", "method": "GET",
51
+ "path": "/api/orders", "note": "What the shop screen loads." },
52
+ { "id": "place-order", "name": "Place an order", "method": "POST",
53
+ "path": "/api/orders", "body": "{\"item\":\"latte\"}" }
54
+ ]
55
+ ```
56
+
57
+ They are in the repo on purpose: a call worth saving outlives the session that
58
+ saved it, and it shows up in the diff.
59
+
60
+ ## Describe every route before you call it done
61
+
62
+ ```
63
+ workser api spec --check
64
+ ```
65
+
66
+ It compares the routes the repo actually serves — read from the file layout, so
67
+ it cannot be fooled by a comment — with the paths your OpenAPI document
68
+ declares, and fails when one is missing. Write the document at
69
+ `api/openapi.json` (YAML also works).
70
+
71
+ It is not an OpenAPI validator and does not check schemas or responses. It asks
72
+ one question, so that it is cheap enough to run every time: is every route
73
+ written down. A health probe is exempt. A path in the spec that the repo does
74
+ not serve is reported but does not fail — you may be documenting something
75
+ built next.
76
+
77
+ Run it alongside `workser verify` before declaring an API task finished. An API
78
+ somebody can call and an API somebody can integrate with are different products,
79
+ and the spec is the difference.
@@ -58,3 +58,36 @@ other surface the brand feeds.
58
58
 
59
59
  For generating artwork *in* the brand's palette, see `workser help images` —
60
60
  put the colours from `design show` into the prompt.
61
+
62
+ ## The three places design lives — and which one you are in
63
+
64
+ They are separate on purpose, and confusing them is the commonest mistake here.
65
+
66
+ | What | Scope | Where |
67
+ | --- | --- | --- |
68
+ | **Brand** — colours, fonts, logo | The **project** | `business_settings`, read with `design show` |
69
+ | **Design files** — the `.fig` work | The **project**, many files | the project's design workspace folder |
70
+ | **Layout options** — choices to show the owner | **One app** | `design/options.json` in that app's folder |
71
+
72
+ **Design is not an app.** It has no port, no URL, nothing to deploy. Never create
73
+ an app for it.
74
+
75
+ When you write `design/options.json`, put the design file each option came from
76
+ in a `source` field:
77
+
78
+ ```json
79
+ { "options": [
80
+ { "id": "warm", "name": "Warm and simple", "route": "/",
81
+ "note": "Bigger type, more space.", "source": "hero-v2.fig" }
82
+ ] }
83
+ ```
84
+
85
+ `source` is a path **inside the project's design workspace** — relative, no
86
+ `..`, no absolute paths, no URLs. Anything else is dropped. Leave it out when the
87
+ option was written straight into code with no design file behind it; that is an
88
+ ordinary case and inventing a source is worse than omitting one.
89
+
90
+ Why it matters: the owner picks an option in one app and later opens the design
91
+ workspace. Without `source`, nothing connects the decision they just made to the
92
+ file it came from, and "why does the site look like this?" has three unrelated
93
+ answers.
@@ -0,0 +1,70 @@
1
+ ---
2
+ topic: checks
3
+ title: Checks — is it safe, and is it still up
4
+ summary: Scan the code for leaked secrets, known-bad dependencies and over-broad permissions, and check that what you published is still answering.
5
+ commands: [scan, health]
6
+ ---
7
+
8
+ # Checks — is it safe, and is it still up
9
+
10
+ Two questions nothing else in this CLI asks. `verify` tells you the code
11
+ compiles. These tell you it is not dangerous, and that it is still working an
12
+ hour after you shipped it.
13
+
14
+ Run both before you say a task is done.
15
+
16
+ ```
17
+ workser scan # deps · secrets · permissions, over this folder
18
+ workser scan --check # same, but exits non-zero on anything serious
19
+ workser scan --only secrets # one check: deps, secrets, permissions
20
+ workser scan --staged # look at staged changes only
21
+
22
+ workser health # is every published app still answering?
23
+ workser health --app <webAppId> # just one
24
+ ```
25
+
26
+ ## scan
27
+
28
+ Three checks, all local — no login, no project, no network except for `deps`.
29
+
30
+ **secrets** looks at what your changes ADD (`git diff HEAD`), not at the whole
31
+ tree, so it fires on the key you just wrote rather than on every example file
32
+ forever. It knows the shapes that are actually credentials — AWS, GitHub,
33
+ Stripe, OpenAI, Anthropic, Google, Slack, private keys, database URLs with a
34
+ password in them, and `API_KEY = "…"` with something real on the right. It
35
+ ignores placeholders (`your-api-key`, `process.env.X`, `<REPLACE_ME>`) and
36
+ example, fixture and lockfile paths.
37
+
38
+ **deps** runs `npm audit` and reports high and critical only. Moderate and low
39
+ advisories on transitive dev dependencies are real and are not worth a report
40
+ nobody finishes reading.
41
+
42
+ **permissions** catches three specific mistakes: a `NEXT_PUBLIC_…SECRET`
43
+ compiled into the browser bundle, an API that accepts credentialed requests
44
+ from any website, and a real `.env` committed to the repository.
45
+
46
+ **A check that could not run says so.** Offline, `deps` reports "not checked"
47
+ with the reason — never "nothing found". If you are quoting a scan result, quote
48
+ what it checked as well as what it found.
49
+
50
+ If it finds a secret: move the value to `workser env set`, and treat the old one
51
+ as leaked. Rotating it is the owner's decision, not yours — say so and let them.
52
+
53
+ ## health
54
+
55
+ Probes the stable preview and production addresses of every app in the project
56
+ and reports up or down, with the round trip. It exits non-zero if anything is
57
+ down, so a step can gate on it.
58
+
59
+ Two things worth knowing:
60
+
61
+ * It is the same check the desktop runs on a timer. Both fold into one streak,
62
+ so a run of yours counts toward the same total.
63
+ * After three failed checks in a row on a **production** address that has
64
+ worked before, an incident task is opened on the owner's board automatically.
65
+ A preview address is checked and reported but never escalated — it is not
66
+ customer-facing, and waking the owner for it teaches them to ignore the ones
67
+ that are.
68
+
69
+ An app that has never been published has no address, so there is nothing to
70
+ check. That is reported as a note, not as a pass.
@@ -13,6 +13,7 @@ them.
13
13
  ```
14
14
  workser artifact add <path> [--kind <k>] [-d <text>] # record a finished deliverable
15
15
  workser artifact add --url <url> --kind app # record a deployed app
16
+ workser artifact add <path> --kind <shape> --data <json> [--promote]
16
17
  workser artifact run # which task you're attached to
17
18
 
18
19
  workser ask "<question>" [--type <t>] [--option <o>] # ask the user, WAIT for the answer
@@ -39,6 +40,43 @@ are detected automatically); pass it explicitly for `app` / `url`.
39
40
  To publish an app: `workser deploy` (preview) or `workser deploy --prod` (live), then
40
41
  register the URL it returns as an `app` artifact so the user can open it from the task.
41
42
 
43
+ ## The shapes the task draws as cards
44
+
45
+ Most kinds say what kind of FILE something is. A few say what the user **asked
46
+ for**, and those get a card of their own on the task:
47
+
48
+ | `--kind` | What the card shows | `--data` it reads |
49
+ |---|---|---|
50
+ | `report` | the chart behind a number | — |
51
+ | `walkthrough` | the flow, as frames | `frames` |
52
+ | `before_after` | a wipe between two pictures | `shots: [{url,label}, …]` |
53
+ | `checks` | what was tested | `passed`, `total` |
54
+ | `web_app` | a published app | `deployedAt`, `pagesChanged` |
55
+ | `service` | a job and what it reaches | `nextRun` |
56
+ | `design` | a layout | — |
57
+
58
+ ```
59
+ workser artifact add ./checks.json --kind checks --data '{"passed":12,"total":12}'
60
+ workser artifact add --url https://acme.workser.app --kind web_app \
61
+ --data '{"deployedAt":"2026-08-20T14:02:00Z","pagesChanged":3}'
62
+ ```
63
+
64
+ **Every `--data` field is optional, and a missing one is left off the card — it
65
+ is never drawn as zero.** `0 pages changed` is a claim you cannot support and
66
+ reads as "it did nothing"; saying nothing reads as "not measured", which is
67
+ true. Only pass a figure you actually counted.
68
+
69
+ ## Handing something up to the task
70
+
71
+ `--promote` marks an artifact as one of the things the user asked for, so it
72
+ appears on the task itself instead of inside your step.
73
+
74
+ Use it when you know: the report they wanted, the app you published, the
75
+ document explaining what changed. Do **not** promote working material —
76
+ screenshots you took to check your own work, intermediate exports, a scratch
77
+ file. A task that hands up everything buries the six things they wanted under
78
+ sixty they did not.
79
+
42
80
  ## Ask the user something (and get an answer back)
43
81
 
44
82
  When you're blocked — a missing value, an ambiguous requirement, permission for
@@ -1,8 +1,8 @@
1
1
  ---
2
2
  topic: deploy
3
- title: Deploy, environment variables & logs
4
- summary: Ship the app, configure it, and find out why it is down.
5
- commands: [deploy, env, logs, versions, domain, open, verify]
3
+ title: Deploy, addresses & logs
4
+ summary: Ship the app, find its address, and find out why it is down.
5
+ commands: [deploy, logs, versions, urls, deployments, domain, open, verify]
6
6
  ---
7
7
 
8
8
  # Deploy, environment variables & logs
@@ -10,33 +10,53 @@ commands: [deploy, env, logs, versions, domain, open, verify]
10
10
  Getting the app online and configured, and finding out why it isn't.
11
11
 
12
12
  ```
13
- workser deploy [--prod] [--watch] # deploy (git → Vercel); --watch waits for live URL
13
+ workser deploy [--env production] [--watch] # deploy (git → Vercel); default is preview
14
14
  workser deploy status [id] # status of a deploy (default: latest)
15
- workser logs [-n 100] [-f] # recent logs
16
- workser versions # deploy history
17
- workser domain list # custom domains (read)
15
+ workser urls # every app's stable preview + live address
16
+ workser logs [-n 100] [-f] [--env production] [--app <id>]
17
+ workser versions [--env production] # history; the badge says which env is live
18
+ workser deployments list [--env production] [--app <id>]
19
+ workser deployments inspect <id> [--logs]
20
+ workser deployments promote # ship the latest build (the owner confirms)
21
+ workser deployments rollback <version> # put an earlier one back (the owner confirms)
22
+ workser domain list # custom domains
23
+ workser domain add shop.co.th # attach one (the owner confirms)
24
+ workser domain add app.shop.co.th --app <webAppId>
25
+ workser domain rm shop.co.th # detach one (the owner confirms)
18
26
  workser open # open the live app
19
27
  workser verify # run typecheck/lint/build
20
28
 
21
- workser env set KEY=VALUE [K2=V2…] # set env vars
22
- workser env list # list keys (values masked)
23
- workser env get KEY # one value (sensitive)
24
29
  ```
25
30
 
31
+ Settings — `workser env` — are their own topic: `workser help env`.
32
+
26
33
  ## Notes that matter
27
34
 
28
35
  - **`verify` gates "done".** Run `workser verify --json` before you say a task is
29
36
  finished. `"ok": false` means fix the listed errors and re-run — a green build is
30
37
  the bar, not your reading of the diff.
31
- - **`deploy` without `--prod` is a preview.** Preview first when the change is
32
- risky; `--prod` puts it in front of real users.
38
+ - **`deploy` without `--env` is a preview.** Preview first when the change is
39
+ risky; `--env production` (or the older `--prod`, which means the same) puts it
40
+ in front of real users. Passing both, disagreeing, is refused rather than
41
+ resolved.
42
+ - **`urls` is where the address comes from — not the deploy response.** The host
43
+ in a deploy response is per-build and the next deploy retires it. `urls`
44
+ returns the stable ones, and says why an app has none rather than printing a
45
+ blank.
46
+ - **`promote` and `rollback` are the same upstream call and two commands on
47
+ purpose.** Promote ships the newest build; rollback puts version N back. Both
48
+ ask the owner and return exit 7 (`awaiting_approval`) until they answer — and
49
+ that gate holds even on a "just do it" run.
50
+ - **There is no `deployments cancel`.** Nothing upstream can stop a build that is
51
+ already running. Wait for it and then promote or roll back.
33
52
  - **`--watch` blocks until there's a live URL.** Without it you get a deploy id and
34
53
  have to poll `deploy status`.
35
- - **`env set` writes a value you never see.** That's the point when the user has
36
- a secret, have them run it (or set it in Orbit) rather than pasting it to you.
37
- - **`env get` returns a secret.** Don't echo it into the conversation.
38
- - **`env rm` and `domain set` are owner-only** (exit 6). Tell the user to do it in
39
- Orbit; don't look for a workaround.
54
+ - **`domain add` and `domain rm` ask the owner to confirm** and return exit 7
55
+ (`awaiting_approval`) until they do tell them to approve, then retry the same
56
+ command. Domains Workser owns (`workser.ai` and its subdomains) and hostnames
57
+ the hosting provider assigns (`*.vercel.app`) are refused outright: those are
58
+ not attachable, and the app's own preview and live URLs already exist without
59
+ attaching anything.
40
60
 
41
61
  ## After a successful deploy
42
62
 
@@ -47,10 +67,3 @@ workser artifact add --url https://acme.workser.app --kind app -t "Storefront"
47
67
  ```
48
68
 
49
69
  See `reference/deliverables.md`.
50
-
51
- ## Local vs cloud environment
52
-
53
- `env set` configures the **cloud** environment (production and preview). The `.env`
54
- files in the app folder configure **this computer** — the user edits those in Orbit
55
- under Settings → "On this computer", and saving there restarts the dev server. Don't
56
- hand-edit `.env.local` to change cloud behaviour; they are different environments.
@@ -0,0 +1,55 @@
1
+ ---
2
+ topic: docs
3
+ title: Project documents
4
+ summary: Write and revise the project's pages, keep the markdown mirror readable, and put the diagram in the document rather than in your reply.
5
+ commands: [doc]
6
+ ---
7
+
8
+ # Project documents
9
+
10
+ A document is a page in the project's Docs panel and a git-tracked markdown
11
+ mirror at `.workser/docs/<id>.md`. Both are the same document: the panel renders
12
+ the rich text, the mirror is what you, git and the next agent can read as text.
13
+
14
+ ```
15
+ workser doc list [--work-item <id>]
16
+ workser doc show <id> [--markdown]
17
+ workser doc create <title> [--work-item <id>] [--markdown <text>]
18
+ [--content-json <json>]
19
+ workser doc update <id> [--title <text>] [--markdown <text>]
20
+ workser doc diagram <id> [--check]
21
+ ```
22
+
23
+ ## Revise the page that exists
24
+
25
+ The project outlives your session, and a second copy of a page is worse than no
26
+ page — nobody can tell which one is current.
27
+
28
+ ```
29
+ workser doc list --json # is there already a page for this?
30
+ workser doc update <id> --markdown "$(cat updated.md)"
31
+ ```
32
+
33
+ `workser doc show <id> --markdown` reports the mirror's path so you can open the
34
+ file with your normal tools instead of reconstructing prose from blocks.
35
+
36
+ `--work-item <id>` links a document to a Board card (a card has at most one). A
37
+ linked document renders on its card and is *hidden* from the Docs panel, so a
38
+ plan spanning several phases should stay unlinked — it belongs to the project,
39
+ not to phase 1.
40
+
41
+ ## Put the diagram in the document
42
+
43
+ A page explaining how something fits together should contain the picture, not a
44
+ paragraph describing one. Write it as a ```mermaid fence in the markdown: the
45
+ Docs panel renders it, `git diff` shows it as changed lines, and the next agent
46
+ reads it without a screenshot.
47
+
48
+ ```
49
+ workser doc diagram <id> --check # exits non-zero when the page has none
50
+ ```
51
+
52
+ Use `--check` on any page whose job is to explain a structure — an architecture
53
+ page, a data model, a flow. It reads the mirror on disk rather than the block
54
+ content, which is deliberate: a diagram that exists in the editor but not in the
55
+ mirror is invisible to git, to you, and to whoever opens the file next.
@@ -0,0 +1,115 @@
1
+ ---
2
+ topic: env
3
+ title: Settings — cloud, per environment, and on this computer
4
+ summary: Set and read an app's settings, hold a different value in production, and pull them onto this computer without clobbering local ones.
5
+ commands: [env]
6
+ ---
7
+
8
+ # Settings — cloud, per environment, and on this computer
9
+
10
+ ```
11
+ workser env set KEY=VALUE [K2=V2…] [--env production]
12
+ workser env list [--env production] # keys, masked; marks where they differ
13
+ workser env get KEY [--env production] # one value (sensitive)
14
+ workser env pull [--env production] [--overwrite]
15
+ ```
16
+
17
+ ## `--env` — say which environment you mean
18
+
19
+ `deploy`, `logs` and `versions` take `--env preview` or `--env production`.
20
+ `env set` takes those and `--env development` as well.
21
+
22
+ Without it: `deploy` builds a preview, `logs` and `versions` talk about
23
+ whichever deployment is newest, and `env set` writes to all three environments.
24
+ Those are the old defaults and they have not changed.
25
+
26
+ **There is no development deployment.** Nothing is ever built into it — it is
27
+ the environment the app uses when it runs on this computer — so `deploy --env
28
+ development` and `logs --env development` are refused rather than quietly shown
29
+ preview.
30
+
31
+ **A key can now hold a different value per environment.** `env set --env
32
+ production DATABASE_URL=…` writes an override; every other environment keeps
33
+ the shared value. `env list --env production` and `env get KEY --env production`
34
+ read it back.
35
+
36
+ Without `--env` you get the **shared** value — what the key is everywhere unless
37
+ overridden — and `env list` marks which keys differ:
38
+
39
+ ```
40
+ API_KEY = sk-••• (different in production)
41
+ ```
42
+
43
+ That marker is the one to read before changing anything: editing the shared
44
+ value will not touch production if production has its own.
45
+
46
+ `env rm KEY --env production` removes just that override and the key keeps its
47
+ shared value. `env rm KEY` removes the key entirely.
48
+
49
+ ## Local settings are this computer's, and are not overwritten
50
+
51
+ `env pull` writes into the app folder's own env file — `.env` for most runtimes,
52
+ `.env.local` for Next.js, because that is the file each one actually reads.
53
+
54
+ **It fills in what is missing and leaves what is already there alone.** A local
55
+ `DATABASE_URL` usually points at the developer's own database on purpose;
56
+ replacing it because somebody asked to pull one missing key destroys work
57
+ Workser cannot give back. Keys it left alone are **named** in the output.
58
+
59
+ ```
60
+ workser env pull # fill the gaps, touch nothing else
61
+ workser env pull --env production # fill them from production's values
62
+ workser env pull --overwrite # replace local values too
63
+ ```
64
+
65
+ Starting an app for the first time does the same thing automatically, with the
66
+ same rule.
67
+
68
+ ## A key can hold a different value per environment
69
+
70
+ `workser env set --env production DATABASE_URL=…` writes an override; every
71
+ other environment keeps the shared value.
72
+
73
+ Without `--env` you get the **shared** value — what the key is everywhere unless
74
+ overridden — and `env list` marks which keys differ:
75
+
76
+ ```
77
+ API_KEY = sk-••• (different in production)
78
+ ```
79
+
80
+ Read that marker before changing anything: editing the shared value will not
81
+ touch production if production has its own.
82
+
83
+ `env rm KEY --env production` removes just that override and the key keeps its
84
+ shared value. `env rm KEY` removes the key entirely.
85
+
86
+ ## Local settings are this computer's, and are not overwritten
87
+
88
+ `env pull` writes into the app folder's own env file — `.env` for most runtimes,
89
+ `.env.local` for Next.js, because that is the file each one actually reads.
90
+
91
+ **It fills in what is missing and leaves what is already there alone.** A local
92
+ `DATABASE_URL` usually points at the developer's own database on purpose;
93
+ replacing it because somebody asked to pull one missing key destroys work
94
+ Workser cannot give back. Keys it left alone are **named** in the output.
95
+
96
+ ```
97
+ workser env pull # fill the gaps, touch nothing else
98
+ workser env pull --env production # fill them from production's values
99
+ workser env pull --overwrite # replace local values too
100
+ ```
101
+
102
+ Starting an app for the first time does the same thing automatically, with the
103
+ same rule.
104
+
105
+ ## Notes that matter
106
+
107
+ - **`env set` writes a value you never see.** That's the point — when the user
108
+ has a secret, have them run it (or set it in Orbit) rather than pasting it to
109
+ you.
110
+ - **`env get` returns a secret.** Don't echo it into the conversation.
111
+ - **`env rm` is owner-only** (exit 6). Tell the user to do it in Orbit; don't
112
+ look for a workaround.
113
+ - **Cloud and local are different environments.** `env set` configures the
114
+ cloud; the files in the app folder configure this computer. Don't hand-edit
115
+ one to change the other.
@@ -1,18 +1,31 @@
1
1
  ---
2
2
  topic: neon
3
- title: The project's own Neon backend
4
- summary: Neon-branch object storage and functions. Dedicated tenancy only.
3
+ title: The project's own database
4
+ summary: Branches, databases, compute, plus Neon-branch object storage and functions. Dedicated tenancy only.
5
5
  commands: [neon]
6
6
  ---
7
7
 
8
- # The project's own Neon backend
8
+ # The project's own database
9
9
 
10
- S3-compatible object storage and Node.js HTTP functions on the project's own Neon
11
- branch they branch with the database. **Additive** infrastructure, not a
12
- replacement for `workser storage`.
10
+ The project's database, run the way an operator runs one: branches (copies of
11
+ the data), the databases on them, and the compute that serves them. Plus
12
+ S3-compatible object storage and Node.js HTTP functions on the same branch.
13
13
 
14
14
  ```
15
15
  workser neon status # tenancy + toggles + region verdict
16
+
17
+ workser neon branch list # copies of the data; the live one is marked
18
+ workser neon branch create qa-run # a copy to work on, made in a second
19
+ workser neon branch create qa --from <id> --no-compute
20
+ workser neon branch reset <branchId> # throw its changes away (asks the owner)
21
+ workser neon branch rm <branchId> # delete it and its data (asks the owner)
22
+
23
+ workser neon database list [--branch <id>]
24
+ workser neon database create <name> [--branch <id>] [--owner <role>]
25
+ workser neon database rm <name> [--branch <id>] # asks the owner
26
+
27
+ workser neon endpoints # what compute is running, and idle
28
+
16
29
  workser neon storage list | create <name> | rm <bucket>
17
30
  workser neon storage ls <bucket> [prefix]
18
31
  workser neon storage put <bucket> <local> [key]
@@ -30,6 +43,24 @@ Region is fixed when the project is created. `regionSupportsNeonBackend: false`
30
43
  **final, not retryable** — no amount of waiting or retrying changes it. When you see
31
44
  it, say so plainly and fall back to `workser storage` (the default bucket).
32
45
 
46
+ ## Branches are the useful one
47
+
48
+ A branch is a **full copy of the data**, made in about a second, costing almost
49
+ nothing until something writes to it. That is what lets a check run against real
50
+ data without being able to damage it — give a QA step its own branch instead of
51
+ pointing it at the live database.
52
+
53
+ Two things cannot happen at all, whatever anyone approves: **the branch the app
54
+ runs on cannot be deleted or reset**, and neither can **the database it connects
55
+ to**. Those refusals come from the server, not from the approval prompt. If you
56
+ meant to reset a copy and got that message, you named the live one.
57
+
58
+ `reset` deletes nothing by name and destroys just as much: it replaces a
59
+ branch's contents with its source's. It asks the owner for exactly that reason.
60
+
61
+ `--no-compute` makes a branch with no compute. It is cheaper and **nothing can
62
+ connect to it** — useful as a snapshot, useless as somewhere to run tests.
63
+
33
64
  ## Notes that matter
34
65
 
35
66
  - **`neon storage rm <bucket>` deletes the bucket and everything in it.** Not
@@ -38,5 +69,8 @@ it, say so plainly and fall back to `workser storage` (the default bucket).
38
69
  through Workser.
39
70
  - **Functions deploy from a zip.** Build the bundle first, then
40
71
  `workser neon functions deploy <slug> <zip>`.
41
- - **Most apps don't need this.** If the user just wants to store uploads, the default
42
- bucket in `reference/storage.md` is the answer.
72
+ - **`neon endpoints` is the cost question.** `active` means it is billing;
73
+ `idle` means it is not. It is the only place in the product that answers "what
74
+ is this database costing me while nothing is happening".
75
+ - **Most apps never need the storage or functions half.** If the user just wants
76
+ to store uploads, the default bucket in `reference/storage.md` is the answer.