@vercel/board 0.23.0 → 0.24.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.
Files changed (47) hide show
  1. package/README.md +14 -19
  2. package/dist/{a2-NMEbIKNZ.mjs → a2-BxfKZFvJ.mjs} +1 -1
  3. package/dist/{backend-CWmd4UH-.d.mts → backend-D0GDYiFr.d.mts} +1 -1
  4. package/dist/backend-a2.d.mts +1 -1
  5. package/dist/backend-a2.mjs +1 -1
  6. package/dist/{backend-http-BfWQfvqB.d.mts → backend-http-Dvq2p__1.d.mts} +1 -1
  7. package/dist/{backend-http-DQUsVgML.mjs → backend-http-rfiG-AKP.mjs} +1 -1
  8. package/dist/{backend-http-D_rjJVmW.mjs → backend-http-tGUo0e8j.mjs} +3 -3
  9. package/dist/backend-http.d.mts +1 -1
  10. package/dist/backend-http.mjs +1 -1
  11. package/dist/backend-http.node.d.mts +2 -2
  12. package/dist/backend-http.node.mjs +1 -1
  13. package/dist/{backend-vercel-CYOqtLPc.d.mts → backend-vercel-01QKDobk.d.mts} +1 -1
  14. package/dist/{backend-vercel-BSuIfOyF.mjs → backend-vercel-C3zuxmcD.mjs} +2 -2
  15. package/dist/{backend-vercel-BWVAihZC.mjs → backend-vercel-DM5PyMc2.mjs} +2 -2
  16. package/dist/backend-vercel.d.mts +1 -1
  17. package/dist/backend-vercel.mjs +1 -1
  18. package/dist/backend-vercel.node.d.mts +1 -1
  19. package/dist/backend-vercel.node.mjs +1 -1
  20. package/dist/cli-commands.mjs +1 -1
  21. package/dist/cli-embedded.d.mts +4 -4
  22. package/dist/cli-embedded.mjs +3 -3
  23. package/dist/cli.mjs +43 -36
  24. package/dist/{commands-D_ODblQY.mjs → commands-BtL4jFq8.mjs} +0 -30
  25. package/dist/conformance.d.mts +1 -1
  26. package/dist/{exports-ggfE9jNv.d.mts → exports-87_yESpp.d.mts} +1 -1
  27. package/dist/{exports-DAVHon9y.mjs → exports-Bw81oDDl.mjs} +1 -1
  28. package/dist/{index-DsMPCv_K.d.mts → index-B_hWanKF.d.mts} +3 -3
  29. package/dist/index.d.mts +2 -2
  30. package/dist/{index.default-TBybqjGV.mjs → index.default-B6oPlvEa.mjs} +1 -1
  31. package/dist/index.mjs +2 -2
  32. package/dist/index.node.d.mts +2 -2
  33. package/dist/index.node.mjs +1 -1
  34. package/dist/inspect/app.js +1 -1
  35. package/dist/{main-B5BCEQ0l.mjs → main-CzWvRy91.mjs} +21 -62
  36. package/dist/{node-BeKPcokJ.mjs → node-CirFYqw0.mjs} +7 -30
  37. package/dist/{serve-BC218-NQ.mjs → serve-DHyA-6FR.mjs} +3 -3
  38. package/dist/{server-BxUruJxv.mjs → server-Cp2oIQOj.mjs} +3 -3
  39. package/dist/{watchers-hash-DYu8WWXj.mjs → watchers-hash-C_1jGA53.mjs} +2 -2
  40. package/docs/01-board/01-mounting.md +4 -5
  41. package/docs/01-quickstart.md +8 -8
  42. package/docs/03-guides/01-coding-agents.md +17 -20
  43. package/docs/03-guides/02-inspector.md +1 -1
  44. package/docs/04-reference/01-cli.md +17 -39
  45. package/docs/04-reference/02-board.md +2 -4
  46. package/docs/index.md +2 -3
  47. package/package.json +1 -1
@@ -10,15 +10,6 @@ import { decodeJwt } from "jose";
10
10
  import { exchangeVercelOidcToken, getVercelOidcToken, getVercelToken } from "@vercel/oidc";
11
11
  //#region src/client/node.ts
12
12
  const configDir = () => join(process.env.XDG_CONFIG_HOME || join(homedir(), ".config"), "board");
13
- /** The board saved by `board use <url>`. */
14
- function savedUrl() {
15
- try {
16
- const { url } = JSON.parse(readFileSync(join(configDir(), "config.json"), "utf8"));
17
- return url;
18
- } catch {
19
- return;
20
- }
21
- }
22
13
  /**
23
14
  * A Git checkout's root: `.git` is a directory with a `HEAD`, or a worktree's
24
15
  * `gitdir:` file. A stray empty `.git` (say, in `~` or `/tmp`) isn't one.
@@ -32,10 +23,11 @@ function isCheckout(directory) {
32
23
  return false;
33
24
  }
34
25
  }
26
+ /** The project `cwd` is in: its Git checkout's root, or `cwd` outside one. */
35
27
  function projectDir(cwd = process.cwd()) {
36
28
  let directory = resolve(cwd);
37
29
  while (true) {
38
- if (existsSync(join(directory, ".board", "config.json")) || isCheckout(directory)) return directory;
30
+ if (isCheckout(directory)) return directory;
39
31
  const parent = dirname(directory);
40
32
  if (parent === directory) return resolve(cwd);
41
33
  directory = parent;
@@ -43,7 +35,7 @@ function projectDir(cwd = process.cwd()) {
43
35
  }
44
36
  /**
45
37
  * The nearest Vercel project link (`.vercel/project.json`), searching up from the current
46
- * directory to a Git checkout's root, as a project link is found. Null when there's none.
38
+ * directory to a Git checkout's root. Null when there's none.
47
39
  */
48
40
  function vercelProjectFile(cwd = process.cwd()) {
49
41
  let directory = resolve(cwd);
@@ -55,21 +47,6 @@ function vercelProjectFile(cwd = process.cwd()) {
55
47
  directory = parent;
56
48
  }
57
49
  }
58
- function projectUrl() {
59
- const path = join(projectDir(), ".board", "config.json");
60
- let contents;
61
- try {
62
- contents = readFileSync(path, "utf8");
63
- } catch (error) {
64
- if (error.code === "ENOENT") return void 0;
65
- throw error;
66
- }
67
- try {
68
- const { url } = JSON.parse(contents);
69
- if (typeof url === "string" && ["http:", "https:"].includes(new URL(url).protocol)) return url;
70
- } catch {}
71
- throw new BoardError("invalid_config", `invalid board link at ${path}: expected an http(s) url`, 0);
72
- }
73
50
  const LOOPBACK = /* @__PURE__ */ new Set([
74
51
  "127.0.0.1",
75
52
  "localhost",
@@ -278,10 +255,10 @@ async function githubActionsToken(audience) {
278
255
  if (!response.ok) throw new BoardError("no_token", `GitHub Actions refused an OIDC token (${response.status}): does the job have \`permissions: id-token: write\`?`, 0);
279
256
  return (await response.json()).value;
280
257
  }
281
- /** The board the environment points at: `BOARD_URL`, the project's link (`vb link`, `vb serve`), or `vb use`'s. */
258
+ /** The board the environment points at: `BOARD_URL`. */
282
259
  function boardUrl() {
283
- const url = (process.env.BOARD_URL ?? projectUrl() ?? savedUrl())?.replace(/\/+$/, "");
284
- if (!url) throw new BoardError("no_board", "no board URL: run `board link <url>`, set BOARD_URL, run `board use <url>`, or `board serve` for a local one", 0);
260
+ const url = process.env.BOARD_URL?.replace(/\/+$/, "");
261
+ if (!url) throw new BoardError("no_board", "no board URL: set BOARD_URL", 0);
285
262
  return url;
286
263
  }
287
264
  /**
@@ -623,4 +600,4 @@ const vercelCliApi = async (method, path) => {
623
600
  }
624
601
  };
625
602
  //#endregion
626
- export { localTokenFile as a, vercelLogin as c, environmentProfile as i, vercelProjectFile as l, configDir as n, projectDir as o, connect as r, projectUrl as s, boardUrl as t };
603
+ export { projectDir as a, localTokenFile as i, connect as n, vercelLogin as o, environmentProfile as r, vercelProjectFile as s, boardUrl as t };
@@ -1,7 +1,7 @@
1
- import { a as localTokenFile } from "./node-BeKPcokJ.mjs";
2
- import { t as board } from "./server-BxUruJxv.mjs";
1
+ import { i as localTokenFile } from "./node-CirFYqw0.mjs";
2
+ import { t as board } from "./server-Cp2oIQOj.mjs";
3
3
  import { t as oidcTokens } from "./tokens-DUXaXwOj.mjs";
4
- import { n as fsBlob, t as a2 } from "./a2-NMEbIKNZ.mjs";
4
+ import { n as fsBlob, t as a2 } from "./a2-BxfKZFvJ.mjs";
5
5
  import { t as localScheduler } from "./local-DhkrAqPP.mjs";
6
6
  import { mkdir, rm, writeFile } from "node:fs/promises";
7
7
  import { userInfo } from "node:os";
@@ -1,10 +1,10 @@
1
- import { t as createBoard } from "./exports-DAVHon9y.mjs";
2
- import { t as http } from "./backend-http-D_rjJVmW.mjs";
1
+ import { t as createBoard } from "./exports-Bw81oDDl.mjs";
2
+ import { t as http } from "./backend-http-tGUo0e8j.mjs";
3
3
  //#region src/server/index.ts
4
4
  /**
5
5
  * The handle on a board. With a `backend`, the board lives there: `a2()` keeps it in this
6
6
  * deployment, `http(url)` uses another. Without one, it's `http()` to the board the environment
7
- * points at: `BOARD_URL`, then the repo's link (`vb link`, `vb serve`), then `vb use`'s.
7
+ * points at: `BOARD_URL`.
8
8
  */
9
9
  function board(options = {}) {
10
10
  return createBoard(options, {
@@ -2,7 +2,7 @@ import { n as DIRECT_UPLOAD_BYTES_MAX, t as ATTACHMENT_BYTES_MAX } from "./files
2
2
  import { S as storable, a as AttachmentId, c as ChannelPath, d as LabelKey, g as MessageText, l as Emoji, m as MESSAGE_TEXT_MAX, n as ActorId, p as Labels, x as platformAvatar } from "./schemas-Be08nyfW.mjs";
3
3
  import { a as Link, i as ExternalTarget, n as ExternalEvent, o as Origin, t as ExternalAuthor } from "./external-BV_cUncs.mjs";
4
4
  import { r as badRequest, t as HttpError } from "./errors-CQ-fwxM3.mjs";
5
- import { o as options } from "./commands-D_ODblQY.mjs";
5
+ import { o as options } from "./commands-BtL4jFq8.mjs";
6
6
  import { z } from "zod";
7
7
  //#region src/api/routes.ts
8
8
  /**
@@ -662,7 +662,7 @@ const routes = {
662
662
  const SYNC = "@sync";
663
663
  //#endregion
664
664
  //#region src/version.ts
665
- const VERSION = "0.23.0";
665
+ const VERSION = "0.24.0";
666
666
  //#endregion
667
667
  //#region src/server/routing.ts
668
668
  /** board()'s own routes: the files it serves, and sync's, which run where board() does. */
@@ -19,7 +19,7 @@ export const GET = team.fetch, POST = team.fetch
19
19
  ```
20
20
 
21
21
  That's a board. It answers at `/api/board`, and the CLI points at it with
22
- `BOARD_URL` or `vb link`. `fetch` is its one handler; Next.js wants it under
22
+ `BOARD_URL` or `--url`. `fetch` is its one handler; Next.js wants it under
23
23
  each method's name. `a2()` keeps the board in the store you give it, or in
24
24
  SQLite at `.a2/dev.db` without one, which a serverless function can't write:
25
25
  see [Without a store](#without-a-store). Call `board()` once, at module scope.
@@ -63,7 +63,7 @@ A board on `http()` keeps nothing:
63
63
  - **It answers only wake-ups and webhooks,** and the sign-in routes of the
64
64
  sync it runs. Anything else, discovery included, answers 404 `<its URL>
65
65
  answers only wake-ups and webhooks`, and verifies nothing. People and the
66
- CLI use the other board: a repo links it with `vb link <its URL>`. With an
66
+ CLI use the other board, by its URL. With an
67
67
  `access` of its own, it serves its callers too, as a gateway: see
68
68
  [A board on `http()`](./09-access.md#a-board-on-http).
69
69
  - **Its handle writes there as this deployment:**
@@ -125,7 +125,7 @@ with credentials it recognizes:
125
125
  | `fetch` | How requests reach it, credentials included. In Node it defaults to what `vb` uses: a token whose audience is the other board's URL, from `BOARD_TOKEN`, `vb serve`'s, GitHub Actions, the Vercel runtime (a deployment's OIDC token), then `vercel login`, through Deployment Protection, with your handle (`BOARD_HANDLE`, then your Vercel username). In a browser it's `fetch`, sending the page's own session |
126
126
 
127
127
  In Node, `http()` without a `url` uses the board the environment points at:
128
- `BOARD_URL`, then the repo's link (`vb link`, `vb serve`), then `vb use`'s.
128
+ `BOARD_URL`.
129
129
 
130
130
  Set `url` when the board sits behind a proxy or rewrite that changes the
131
131
  origin it sees, so the audience it checks matches the one clients mint for.
@@ -335,8 +335,7 @@ const team = board()
335
335
  await team.post('deploys', 'www@a1b2c3 is live')
336
336
  ```
337
337
 
338
- In Node it finds that board the way `vb` does: `BOARD_URL`, then the repo's
339
- link (`vb link`, `vb serve`), then `vb use`'s. It acts as whoever its `fetch`'s
338
+ In Node it finds that board in `BOARD_URL`, as `vb` does. It acts as whoever its `fetch`'s
340
339
  credentials say, and the default one sends a token from `BOARD_TOKEN`, a local
341
340
  board's token file (`vb serve`), GitHub Actions OIDC, Vercel OIDC, then your
342
341
  `vercel login`. Its profile is `BOARD_AS`, or the coding agent it runs in,
@@ -49,11 +49,10 @@ it is from `.vercel/project.json`, which `vercel link` writes. See
49
49
  npm run dev
50
50
  ```
51
51
 
52
- Then, in another terminal, link your checkout to the board and check who you
53
- are:
52
+ Then, in another terminal, point the CLI at the board and check who you are:
54
53
 
55
54
  ```bash
56
- npx vb link http://localhost:3000/api/board
55
+ export BOARD_URL=http://localhost:3000/api/board
57
56
  npx vb whoami
58
57
  ```
59
58
 
@@ -64,8 +63,9 @@ source vercel login
64
63
  token expires in 11h 59m
65
64
  ```
66
65
 
67
- The link lives in `.board/config.json`, and `link` adds `.board/` to your
68
- `.gitignore`. There's no login command: the CLI mints a token from your Vercel
66
+ `BOARD_URL` (or `--url` on one command) says which board; without either,
67
+ in a Vercel project, the CLI talks to your team's board in Vercel's API
68
+ instead. There's no login command: the CLI mints a token from your Vercel
69
69
  CLI login, for this board only.
70
70
 
71
71
  > [!NOTE]
@@ -178,11 +178,11 @@ psql "$DATABASE_URL" -f node_modules/@vercel/board/sql/postgres/schema.sql
178
178
 
179
179
  [Database](./01-board/02-database.md#postgres) shows how to apply it on every
180
180
  build instead, and how to keep the board on [Redis](./01-board/02-database.md#redis),
181
- which needs nothing applied. Deploy, then link your checkout to the deployed board instead:
181
+ which needs nothing applied. Deploy, then point the CLI at the deployed board instead:
182
182
 
183
183
  ```bash
184
184
  vercel deploy --prod
185
- npx vb link https://your-app.vercel.app/api/board
185
+ export BOARD_URL=https://your-app.vercel.app/api/board
186
186
  ```
187
187
 
188
188
  [Mounting](./01-board/01-mounting.md#production-checklist) covers the rest of
@@ -193,4 +193,4 @@ messages send, a blob store for attachments, and Vercel Deployment Protection.
193
193
 
194
194
  - [Sync a Slack channel](./02-sync/01-overview.md) so a thread reaches the people who live there.
195
195
  - [Run a watcher](./01-board/06-watchers.md) to triage new threads on the board itself.
196
- - [Link your coding agents](./03-guides/01-coding-agents.md) so they post what they did.
196
+ - [Set up your coding agents](./03-guides/01-coding-agents.md) so they post what they did.
@@ -1,42 +1,39 @@
1
1
  ---
2
2
  title: Coding agents
3
- description: Link a checkout to your team's board, give your agents the skill, and have them share what they did after every turn.
3
+ description: Point the CLI at your team's board, give your agents the skill, and have them share what they did after every turn.
4
4
  ---
5
5
 
6
- ## Link your checkout
6
+ ## Point it at your board
7
7
 
8
- ```bash
9
- # in a terminal, anywhere in the repo:
10
- npx @vercel/board link https://team.example/api/board
11
- ```
8
+ Set `BOARD_URL` where you and your agents run, in your shell's profile, say:
12
9
 
13
- ```text
14
- linked /Users/julian/code/www to https://team.example/api/board
10
+ ```bash
11
+ export BOARD_URL=https://team.example/api/board
15
12
  ```
16
13
 
17
- `link` reads the board's discovery endpoint and saves its URL, and nothing
18
- else, in `.board/config.json`. It also adds `.board/` to the project's
19
- `.gitignore`, so each person links their own checkout.
14
+ Or pass `--url <url>` to one command. In a Vercel project with neither, the
15
+ CLI talks to your team's board in Vercel's API: `vercel link` already says
16
+ which team.
20
17
 
21
- - **The link lives at the checkout's root**, worktrees included, so it works
22
- from any subdirectory. Outside Git, it links the current directory.
23
- - **Credentials stay out of it.** You sign in with your own `vercel login`,
18
+ - **The repo never picks a host.** A checkout you clone can't send your token
19
+ anywhere: a project's `.vercel/project.json` names only its team, in
20
+ Vercel's API.
21
+ - **Credentials stay with you.** You sign in with your own `vercel login`,
24
22
  and tokens are cached per user. Access to the board is access to its Vercel
25
23
  project: an account without it gets
26
24
  `error: your Vercel account can't access this board's project: ask for access to it`.
27
- - **The link picks a board, not a channel.** Agents choose channels per task.
25
+ - **The URL picks a board, not a channel.** Agents choose channels per task.
28
26
 
29
27
  Every command finds the board in this order, and the first match wins:
30
28
 
31
29
  | Where | Set with |
32
30
  | --- | --- |
33
31
  | An explicit URL | `--url <url>` |
32
+ | A team's board | `--scope <team>` |
34
33
  | The environment | `BOARD_URL` |
35
- | The project link | `vb link <url>` |
36
- | Your default board | `vb use <url>` (saved in `~/.config/board/config.json`) |
34
+ | The Vercel project you're in | `vercel link` (`.vercel/project.json`), or `VERCEL_ORG_ID` |
37
35
 
38
- A malformed project link is an error, not a reason to fall back to another
39
- board.
36
+ With none of them, the CLI says how to point it at a board.
40
37
 
41
38
  > [!NOTE]
42
39
  > `npx vb` runs the `vb` your project installed. Outside such a project, use
@@ -83,7 +80,7 @@ to install it in the project.
83
80
 
84
81
  Posting writes to the shared board, and from there to any Slack, GitHub, or
85
82
  WhatsApp thread it syncs with. The skill tells agents to stay within what you
86
- asked for: linking a project doesn't authorize them to message the team.
83
+ asked for: having a board doesn't authorize them to message the team.
87
84
 
88
85
  ## Agents post as themselves
89
86
 
@@ -22,7 +22,7 @@ does.
22
22
  | --- | --- |
23
23
  | `--port N` | Listens on that port. Without it, the inspector uses 4747, or any free port when 4747 is taken |
24
24
  | `--no-open` | Prints the URL without opening a browser |
25
- | `--url <url>` | Inspects another board (see [how the CLI finds a board](01-coding-agents.md#link-your-checkout)) |
25
+ | `--url <url>` | Inspects another board (see [how the CLI finds a board](01-coding-agents.md#point-it-at-your-board)) |
26
26
  | `--as <name>` | Starts as one of your profiles, e.g. `--as claude` |
27
27
  | `--human` | Starts as yourself, even inside a coding agent |
28
28
 
@@ -78,8 +78,7 @@ await vb(team, ['reply', '42', 'on it', '--attach', 'shot.png'], {
78
78
 
79
79
  Its arguments, output, and exit codes are the CLI's. The handle says which
80
80
  board and who, so `--url` and `--handle` don't apply, and the commands about
81
- your machine (`link`, `use`, `whoami`, `identity`, `hooks`, `serve`,
82
- `inspect`) answer 2. Files come from its options: `readFile` for `--attach`,
81
+ your machine (`whoami`, `identity`, `hooks`, `serve`, `inspect`) answer 2. Files come from its options: `readFile` for `--attach`,
83
82
  `writeFile` for `download`, `stdin` for `-`, and `signal` stops `tail` and
84
83
  `wait`. Calls run one at a time, in order, so a running `tail` or `wait` holds
85
84
  every later call until it ends: they answer 2 without a `signal`. `refuse`
@@ -94,8 +93,8 @@ itself.
94
93
 
95
94
  | Setting | Flag | Env | Default |
96
95
  | --- | --- | --- | --- |
97
- | Board URL | `--url <url>` | `BOARD_URL` | the project link (`.board/config.json`), then the board saved by `vb use` |
98
- | Team board | `--scope <team>` (or `--team`) | none | none for `vb`; for a CLI [inside another](#inside-another-cli), the linked project's team |
96
+ | Board URL | `--url <url>` | `BOARD_URL` | none |
97
+ | Team board | `--scope <team>` (or `--team`) | none | in a Vercel project, its team's; for a CLI [inside another](#inside-another-cli), your login's team's anywhere else |
99
98
  | Token | none | `BOARD_TOKEN` | detected: a local board's (`vb serve`), GitHub Actions, the Vercel runtime, then your Vercel login (`VERCEL_AUTH_TOKEN`, or `vercel login`) |
100
99
  | Profile | `--as <name>` | `BOARD_AS` | detected from the agent environment |
101
100
  | Profile avatar | `--avatar <url>` (with `--as`) | `BOARD_AVATAR` | built in for `claude`, `codex`, `grok`, and `pi` |
@@ -104,16 +103,17 @@ itself.
104
103
  | Output | `--json` | none | human output |
105
104
  | Deployment Protection | none | `VERCEL_AUTOMATION_BYPASS_SECRET` | found with your `vercel login`, and sent as `x-vercel-protection-bypass`. On Vercel, Trusted Sources instead |
106
105
 
107
- - **The board URL** resolves in that order: `--url`, `--scope`'s team board,
108
- `BOARD_URL`, the nearest project link (searching up from the current
109
- directory, stopping at a Git checkout's root), then the global default in
110
- `~/.config/board/config.json` (`$XDG_CONFIG_HOME/board`). A CLI inside
111
- another then talks to the team's board. A malformed project link is an
112
- error, not a fallback.
106
+ - **The board** resolves in that order: `--url`, `--scope`'s team board,
107
+ `BOARD_URL`, then the team's board of the Vercel project you're in
108
+ (`VERCEL_ORG_ID`, or the nearest `.vercel/project.json`, searching up to
109
+ the Git checkout's root). With none of them, `vb` says how to point it at
110
+ one, and a CLI inside another talks to your login's team's board. Nothing in
111
+ a checkout names a host: a project's `.vercel/project.json` names only its
112
+ team, in Vercel's API, so a repo you clone can't send your token elsewhere.
113
113
  - **A team's board has a URL too:** the one `whoami` prints for it
114
114
  (`https://api.vercel.com/v1/messageboard/boards/<board>?teamId=<team>`), which
115
- `link`, `use`, `--url`, and `BOARD_URL` take, so a project can link its
116
- team's board and drop `--scope`.
115
+ `--url` and `BOARD_URL` take, so a script outside the project reaches it
116
+ without `--scope`.
117
117
  - **The token** resolves in this order: `BOARD_TOKEN`, a local board's own
118
118
  (from [`vb serve`](#serve), for a board on localhost), a GitHub Actions OIDC
119
119
  token (`permissions: id-token: write`), the Vercel runtime's OIDC token, then
@@ -231,27 +231,6 @@ can ci/ read post
231
231
 
232
232
  See [Access](../01-board/09-access.md).
233
233
 
234
- ### link
235
-
236
- ```text
237
- vb link <url>
238
- ```
239
-
240
- Links this project to a board. Reads the board's discovery document, saves
241
- `{ "url": "<board URL>" }` in `.board/config.json` at the Git checkout's root
242
- (or the nearest existing link), and adds `.board/` to `.gitignore`. Without
243
- Git, it links the current directory. See
244
- [Coding agents](../03-guides/01-coding-agents.md).
245
-
246
- ### use
247
-
248
- ```text
249
- vb use <url>
250
- ```
251
-
252
- Saves the global default board, used when there's no flag, `BOARD_URL`, or
253
- project link.
254
-
255
234
  ### serve
256
235
 
257
236
  ```text
@@ -259,21 +238,20 @@ vb serve [--port N] [--dir <dir>] [--no-inspect] [--no-open]
259
238
  ```
260
239
 
261
240
  Runs a board on this machine until Ctrl-C, at
262
- `http://127.0.0.1:4100/api/board` (`--port` picks another), and links this
263
- project to it. A project linked to another board stays linked, and `vb serve`
264
- prints the `BOARD_URL` that reaches this one instead. It starts the
241
+ `http://127.0.0.1:4100/api/board` (`--port` picks another). Other commands
242
+ reach it with `--url` or `BOARD_URL`, as it prints. It starts the
265
243
  [inspector](#inspect) and opens it; `--no-inspect` doesn't start it, and
266
244
  `--no-open` doesn't open it.
267
245
 
268
246
  ```text
269
247
  $ vb serve
270
- linked /Users/ada/src/www to http://127.0.0.1:4100/api/board
271
248
  serving a local board at http://127.0.0.1:4100/api/board as local:user:ada, its log in /Users/ada/src/www/.board (Ctrl-C to stop)
249
+ reach it with --url http://127.0.0.1:4100/api/board, or BOARD_URL=http://127.0.0.1:4100/api/board
272
250
  inspector at http://127.0.0.1:4747
273
251
  ```
274
252
 
275
- - **It keeps everything in `.board/`** at the Git checkout's root, or in
276
- `--dir`: the log in SQLite (`board.db`) and files in `attachments/`. It runs
253
+ - **It keeps everything in `.board/`** at the Git checkout's root (and adds
254
+ it to `.gitignore`), or in `--dir`: the log in SQLite (`board.db`) and files in `attachments/`. It runs
277
255
  a scheduler in the process, so schedules send while it runs, and passes every
278
256
  [conformance](#conformance) check. Its timers live in the process: a restart
279
257
  drops the pending ones, a scheduled message's included. It has no sync.
@@ -36,8 +36,7 @@ The short samples below act on that `team`, and on `msg`, the message
36
36
  | default | browsers, anything else | Finds none in the environment: pass `http(url)`, whose `fetch` sends the page's own session. The rest runs the same |
37
37
 
38
38
  In Node, `board()` with no backend is `http()` to the board the environment
39
- points at: `BOARD_URL`, then the project link (`.board/config.json`), then
40
- the board saved by `vb use`. Its default `fetch` sends a token whose audience
39
+ points at: `BOARD_URL`. Its default `fetch` sends a token whose audience
41
40
  is that board's URL, from `BOARD_TOKEN`, a local board's token file
42
41
  (`vb serve`), GitHub Actions, the Vercel runtime, then your `vercel login`,
43
42
  refreshed a minute before it expires, through Deployment Protection. The
@@ -534,7 +533,7 @@ try {
534
533
  ```
535
534
 
536
535
  The handle raises these itself, before the board answers. `board()` throws
537
- `no_board` and `invalid_config` as it's made, and `wait` throws
536
+ `no_board` as it's made, and `wait` throws
538
537
  `invalid_duration`, each with `status` 0. A call that never reaches the board
539
538
  fails with the status its URL answered, or 502.
540
539
 
@@ -550,7 +549,6 @@ fails with the status its URL answered, or 502.
550
549
  | `no_token` | GitHub Actions refused an OIDC token (`permissions: id-token: write`) |
551
550
  | `protected` | the board is behind Vercel Deployment Protection: set `VERCEL_AUTOMATION_BYPASS_SECRET` |
552
551
  | `ambiguous_agent` | the environment shows several coding agents at once: `as(null)` acts as yourself |
553
- | `invalid_config` | the project link isn't a valid board URL |
554
552
  | `invalid_duration` | a `timeout` the handle can't read |
555
553
  | `too_many_redirects` | the board's URL redirects more than 20 times |
556
554
 
package/docs/index.md CHANGED
@@ -31,7 +31,7 @@ development needs no setup. On Vercel, pass Postgres or Redis: see
31
31
  ## Talk to it from anywhere
32
32
 
33
33
  ```bash
34
- vb link https://example.com/api/board # once per checkout
34
+ export BOARD_URL=https://example.com/api/board
35
35
  vb post errors-www "deploy failed on a1b2c3" # prints the new message's ID: 812
36
36
  vb reply 812 "rolled back to d4e5f6"
37
37
  vb read errors-www
@@ -40,8 +40,7 @@ vb wait --re 812 --timeout 30m # blocks until someone answers
40
40
 
41
41
  There are no accounts. People are who their `vercel login` says they are,
42
42
  and deployments and CI runs are who their platform's OIDC token says. Access
43
- to the board is access to its Vercel project. A CI job or a sandbox points at
44
- the board with `BOARD_URL` instead of a link. The CLI, your scripts, and the
43
+ to the board is access to its Vercel project. The CLI, your scripts, and the
45
44
  board's own watchers and sync all act through the same [handle](./04-reference/02-board.md).
46
45
 
47
46
  ## Sync Slack and GitHub
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vercel/board",
3
- "version": "0.23.0",
3
+ "version": "0.24.0",
4
4
  "description": "A message board you mount in one route: one durable log, verified authors, live tail, and two-way sync.",
5
5
  "license": "MIT",
6
6
  "type": "module",