fest-gateway 0.2.0 → 0.3.1

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,202 +1,116 @@
1
1
  # Fest
2
2
 
3
- [![CI](https://github.com/cliftonc/fest-gateway/actions/workflows/ci.yml/badge.svg)](https://github.com/cliftonc/fest-gateway/actions/workflows/ci.yml)
4
- [![npm](https://img.shields.io/npm/v/fest-gateway.svg)](https://www.npmjs.com/package/fest-gateway)
5
-
6
3
  A self-hosted gateway for Claude Code. Teams point their Claude Code at Fest the
7
4
  way they'd point at Bedrock, so one place can monitor requests, tokens and cost —
8
5
  and route to different models without Claude Code knowing the difference.
9
6
 
10
7
  **The distinguishing goal: Claude Max / Team subscription support.** Each
11
- developer authenticates with their *own* subscription. Fest relays their own
8
+ developer authenticates with their *own* subscription. Fest relays that
12
9
  credential and never stores it. Per-user pass-through, never pooling.
13
10
 
14
- > **Status: feature complete for a team trial.** A real Claude Code session on a
15
- > Max subscription runs through Fest, is attributed to its developer, metered
16
- > into SQLite, and shown on a dashboard behind a login. Model routing and
17
- > substitution work and are visible. Phase 0 cleared both gates
18
- > ([results](docs/PHASE0-RESULTS.md)), and `npm run canary` re-checks them
19
- > against each new Claude Code release.
11
+ Three ways to read this, depending on what you want:
20
12
 
21
- ```bash
22
- docker compose run --rm fest admin create you@corp.test # password shown once
23
- docker compose up -d
24
- docker compose run --rm fest token create dev@corp.test laptop # shown once
25
- ```
13
+ | | |
14
+ | --- | --- |
15
+ | [**Use it**](#use-it) | Someone runs a Fest; you want Claude Code going through it. |
16
+ | [**Run it**](#run-it) | You are standing one up for a team. |
17
+ | [**How it works**](#how-it-works) | What it can see, what it keeps, and what will bite you. |
18
+ | [**Develop it**](#develop-it) | Changing Fest itself. |
26
19
 
27
- Each developer then points Claude Code at the printed URL:
20
+ ---
28
21
 
29
- ```bash
30
- env -u ANTHROPIC_API_KEY -u ANTHROPIC_AUTH_TOKEN \
31
- ANTHROPIC_BASE_URL=http://fest.corp:8787/t/<token> claude
32
- ```
22
+ ## Use it
33
23
 
34
- Or, if the operator has configured Google/GitHub OAuth (see below), a developer
35
- can skip all of that and self-serve a token from their own machine:
24
+ Install the CLI. The package is `fest-gateway`; the command it installs is
25
+ `fest`, because plain `fest` was already taken on npm.
36
26
 
37
27
  ```bash
38
- npm install -g fest-gateway # the command it installs is `fest`
39
-
40
- fest login --server http://fest.corp:8787 # opens a browser, stores a token in ~/.fest
41
- fest claude # runs `claude`, env set up for you
42
- fest whoami # what's logged in, and whether it's still live
28
+ npm install -g fest-gateway
43
29
  ```
44
30
 
45
- The package is `fest-gateway` — plain `fest` was already taken on npm — but the
46
- binary it installs is `fest`. Without installing anything, `npx fest-gateway
47
- login …` does the same job.
48
-
49
- From a clone of this repo the CLI runs straight off the TypeScript instead:
50
- `npm run cli -- login …` (note the `--`), or `node server/bin/fest.ts login …`.
51
-
52
- Or without Docker:
31
+ Sign in to your team's gateway, then start a session:
53
32
 
54
33
  ```bash
55
- node server/bin/fest.ts admin create you@corp.test
56
- node server/bin/fest.ts token create dev@corp.test laptop
57
- FEST_REQUIRE_IDENTITY=1 node server/bin/fest.ts serve
34
+ fest login --server https://fest.corp.test # opens a browser, stores a token in ~/.fest
35
+ fest claude # runs `claude`, environment set up for you
58
36
  ```
59
37
 
60
- ## Why this is possible
38
+ That's it. `fest claude` spawns the real `claude` binary with the environment
39
+ already pointed at the gateway, on **your own Anthropic subscription** — Fest
40
+ meters the usage and never sees your Anthropic credential at rest.
61
41
 
62
- Claude Code's inference client attaches the subscription OAuth bearer with **no
63
- host check** against `ANTHROPIC_BASE_URL`. Point it at Fest while logged in with
64
- Max/Team and Fest receives `Authorization: Bearer sk-ant-oat…`. Confirmed both
65
- by reading the binary and by running it — see
66
- [docs/PHASE0-RESULTS.md](docs/PHASE0-RESULTS.md).
42
+ If your browser is already signed in to the dashboard, `fest login` is a single
43
+ approval click; otherwise it shows the gateway's login screen first.
67
44
 
68
- Token refresh happens client-side against `api.anthropic.com`, outside
69
- `ANTHROPIC_BASE_URL`. So Fest **forwards and forgets**: it never stores,
70
- refreshes or holds a subscription credential. That is a genuine security
71
- advantage over any "store the team's key" design, not just a side effect.
72
-
73
- ## Two things that will bite you
45
+ Other commands:
74
46
 
75
- **1. `ANTHROPIC_API_KEY` and `ANTHROPIC_AUTH_TOKEN` silently kill the
76
- subscription.** Claude Code demotes off OAuth if *any* Anthropic-issued
77
- credential is present — including an `apiKeyHelper`. So Fest's identity token
78
- never goes in those variables; it rides in the URL path prefix or a custom
79
- header. A design that ignores this silently moves a whole team off their
80
- subscriptions onto a server-held key, and the failure is invisible.
81
-
82
- **2. This is supported-by-absence, not by design.** There is no *documented*
83
- path for relaying a subscription bearer through a third-party gateway. It works
84
- because no guard exists. Treat it as a version-pinned dependency, and settle the
85
- policy question with Anthropic before a team-wide rollout.
47
+ ```bash
48
+ fest whoami # what's logged in, and whether the token is still live
49
+ fest logout # forget the local token (does not revoke it server-side)
50
+ fest claude gw # force org credentials + the gateway's extra models
51
+ ```
86
52
 
87
- The version dependency is enforced rather than remembered: `npm run canary`
88
- re-runs both load-bearing Phase 0 experiments against the installed release and
89
- refuses the rollout if either has changed. See [docs/CANARY.md](docs/CANARY.md);
90
- verdicts are recorded per version in `docs/canary-history.jsonl`.
53
+ Without installing anything, `npx fest-gateway login …` does the same job.
91
54
 
92
- Worth knowing: Anthropic ships its own self-hostable `claude gateway` (see
93
- `claude gateway --help`) with central metering, pricing and managed policies. It
94
- authenticates via OIDC and holds provider credentials itself, so it cannot do
95
- subscription pass-through — but if that requirement ever softens, it is the
96
- supported product.
55
+ ### If your operator hasn't set up OAuth
97
56
 
98
- ## Design commitments
57
+ They can mint you a token by hand instead, and you point Claude Code at it
58
+ directly:
99
59
 
100
- - **Byte-for-byte pass-through.** Subscription tokens are validated against
101
- request shape, so the body is relayed as opaque bytes — never parsed and
102
- re-serialised. No model rewriting or prompt shaping on that path.
103
- - **`cache_control` forwarded verbatim.** Stripping it silently destroys prompt
104
- caching and inflates every developer's token bill.
105
- - **Metadata only.** Token counts, models, latency, status — never prompt or
106
- completion content.
107
- - **No credential is persistable.** Not by policy, by construction: there is no
108
- store to put one in. Only fingerprints, enforced by tests.
109
-
110
- ## Layout
111
-
112
- ```
113
- server/bin/fest.ts CLI: serve | migrate | token | admin | seed |
114
- login | whoami | claude | logout
115
- server/pipeline/ passthrough (byte-for-byte) — the subscription path
116
- server/http/ sse parser, tee, header discipline, errors, routing
117
- server/store/ SQLite schema, write path, identity tokens
118
- server/usage/ accumulator, lean pricing, nullable cost algebra
119
- server/secret/ credential classification + redaction
120
- server/auth/oauth.ts Google/GitHub provider construction
121
- server/api/oauth.ts /api/auth/oauth/* and /api/auth/identity
122
- cli/ the developer half of the CLI — no DB access, ever.
123
- login (loopback OAuth flow) | whoami | claude | logout,
124
- and the ~/.fest config they share
125
- shared/types.ts the contracts both halves agree on
126
- shared/demotion-vars.ts env vars that silently kill subscription auth
127
- tools/capture-server.ts Phase 0 diagnostic (throwaway)
128
- docs/PHASE0.md the gating experiment runbook
129
- docs/CLI-AUTH.md OAuth setup and the fest login/whoami/claude flow
130
- test/ node --test
60
+ ```bash
61
+ env -u ANTHROPIC_API_KEY -u ANTHROPIC_AUTH_TOKEN \
62
+ ANTHROPIC_BASE_URL=https://fest.corp.test/t/<token> claude
131
63
  ```
132
64
 
133
- ## Accounting rules that are easy to get wrong
65
+ > **Never set `ANTHROPIC_API_KEY` or `ANTHROPIC_AUTH_TOKEN` yourself.** Either
66
+ > one silently drops you off your own subscription onto whatever credential the
67
+ > server holds. `fest claude` clears them for you; the raw form above does it
68
+ > with `env -u`.
134
69
 
135
- - **The four token buckets are disjoint.** `input_tokens` excludes cache reads
136
- and cache writes; context size is the sum. Folding cache reads into input is
137
- an order-of-magnitude error on a cache-heavy agent workload — and Claude Code
138
- is one (a trivial `-p` call here showed ~16k cache reads and ~12k one-hour
139
- cache writes).
140
- - **`null` cost means unavailable, never zero.** A subscription request is real
141
- usage with *no org spend*; an unknown model is unpriced, not free. Rollups
142
- therefore carry a priced sum plus `unpriced_requests` and
143
- `subscription_requests` separately, so a total renders honestly as
144
- `$12.3456 (+3 n/a)`.
145
- - **For a subscription developer, quota is the scarce resource, not dollars.**
146
- Anthropic returns 5h/7d utilisation on every response, so that is what the
147
- dashboard shows rather than an invented dollar figure.
70
+ ---
148
71
 
149
- ## What Fest can see, and what it keeps
72
+ ## Run it
150
73
 
151
- This is a gateway every prompt a team writes passes through, so it is worth
152
- being exact about what that means rather than reassuring.
153
-
154
- **Fest sees everything, because it has to.** A request body arrives at this
155
- process in full: prompts, file contents you asked Claude about, tool results,
156
- the lot. That is unavoidable for anything sitting on the wire, and no wording
157
- changes it.
74
+ ### Getting started
158
75
 
159
- **Fest keeps none of it.** Request bodies are relayed as opaque bytes and never
160
- parsed for storage. What is written down is metadata: who, when, which model,
161
- how many tokens in each of the four buckets, latency, HTTP status, error type,
162
- and the session id Claude Code already sends. There is no column anywhere in
163
- the schema for prompt or completion text — not disabled, absent — so "turn off
164
- content capture" is not a setting that could be misconfigured.
76
+ An owner account must exist before Fest will serve on anything but loopback, so
77
+ that comes first:
165
78
 
166
- **No credential is persistable, by construction rather than by policy.** A
167
- subscription bearer is forwarded and forgotten; there is no table to put one in.
168
- What is stored of a Fest identity token or a dashboard password is a hash. The
169
- leak tests grep the entire database, every log line and every API response for
170
- secret-shaped strings.
79
+ ```bash
80
+ docker compose run --rm fest admin create you@corp.test # password shown once
81
+ docker compose up -d
82
+ ```
171
83
 
172
- **Raw per-request rows age out after 30 days**; the hourly rollups, which are
173
- aggregate, are kept for 400 so a year of trends does not require a year of
174
- per-developer detail.
84
+ Then either let developers self-serve with `fest login` (configure OAuth below),
85
+ or mint tokens for them:
175
86
 
176
- **An admin can see who used what, and when.** That is the point of a team
177
- gateway, and the developers pointing their editors at it should be told so
178
- plainly. They cannot see each other: a `member` account sees only its own
179
- traffic, enforced in the query layer rather than in the UI.
87
+ ```bash
88
+ docker compose run --rm fest token create dev@corp.test laptop # shown once
89
+ ```
180
90
 
181
- ## Deploying it
91
+ Put Fest behind your own TLS proxy and set `FEST_SECURE_COOKIES=1` when you do:
92
+ the server only ever sees plain HTTP and cannot detect this for itself.
182
93
 
183
- `docker compose up -d` after creating an owner account. The image has no runtime
184
- dependencies — Node runs the TypeScript directly — so it is Node plus this
185
- repository.
94
+ ### Accounts
186
95
 
187
- The dashboard needs a sign-in: scrypt passwords, an opaque session cookie
188
- hashed at rest, an origin check on the two endpoints that mutate anything, and
189
- an audit log of administrative actions. Accounts are granted from the host with
190
- `fest admin create`; there is no self-registration and no email reset, because a
191
- gateway should not need mail credentials to run.
96
+ The dashboard needs a sign-in: scrypt passwords, an opaque session cookie hashed
97
+ at rest, an origin check on every mutating endpoint, and an audit log of
98
+ administrative actions. Accounts are granted from the host with `fest admin
99
+ create` — there is no self-registration and no email reset, because a gateway
100
+ should not need mail credentials to run.
192
101
 
193
102
  Before anyone has run `fest admin create`, Fest serves the dashboard **open on
194
103
  loopback and refuses to start on any other interface**. A single-developer trial
195
104
  needs no setup, and "bound it to 0.0.0.0 and forgot the password" cannot happen
196
105
  quietly.
197
106
 
198
- Put it behind your own TLS proxy and set `FEST_SECURE_COOKIES=1` when you do:
199
- the server only ever sees plain HTTP and cannot detect this for itself.
107
+ ```bash
108
+ docker compose run --rm fest admin create <email> [--role owner|admin|member]
109
+ docker compose run --rm fest admin list | admin passwd <email> | admin disable <email>
110
+ docker compose run --rm fest token list | token revoke <id>
111
+ ```
112
+
113
+ ### Configuration
200
114
 
201
115
  | | |
202
116
  | --- | --- |
@@ -204,29 +118,28 @@ the server only ever sees plain HTTP and cannot detect this for itself.
204
118
  | `FEST_DB`, `FEST_USAGE_LOG` | SQLite path, and the greppable JSONL trail. |
205
119
  | `FEST_REQUIRE_IDENTITY` | refuse unattributed requests. Off by default; **on** for a team. |
206
120
  | `FEST_SECURE_COOKIES` | set behind HTTPS. |
207
- | `FEST_ROUTES` | routing table path. Absent means everything passes through. |
121
+ | `FEST_ROUTES` | routing table path. Absent means everything passes through. See [docs/ROUTING.md](docs/ROUTING.md). |
208
122
  | `FEST_UPSTREAM_BASE_URL`, `FEST_LOG_LEVEL` | |
209
123
  | `FEST_PRICING_REFRESH` | set `0` to never fetch prices. Rates then come only from the vendored snapshot, which is always sufficient. |
210
124
  | `FEST_PRICING_URL` | internal mirror of litellm's price file. |
125
+ | `FEST_PUBLIC_URL` | base URL Fest is reachable at. Builds the OAuth redirect URI, and its path sets the mount point. Defaults to `http://<host>:<port>`. |
126
+ | `FEST_BASE_PATH` | mount path, if Fest is not at the root of its origin. Defaults to the path of `FEST_PUBLIC_URL`, so setting that is usually enough. |
211
127
  | `FEST_GOOGLE_CLIENT_ID`, `FEST_GOOGLE_CLIENT_SECRET` | Google OAuth, for `fest login` and the dashboard. Absent means Google sign-in is off. |
212
128
  | `FEST_GITHUB_CLIENT_ID`, `FEST_GITHUB_CLIENT_SECRET` | GitHub OAuth, same idea. |
213
129
  | `FEST_ALLOWED_EMAIL_DOMAINS` | comma-separated. **Required to enable OAuth at all** — empty refuses every OAuth login rather than allowing any Google/GitHub account. |
214
- | `FEST_PUBLIC_URL` | base URL Fest is reachable at, for building the OAuth redirect URI. Defaults to `http://<host>:<port>`. |
215
- | `FEST_BASE_PATH` | mount path, if Fest is not at the root of its origin. Defaults to the path of `FEST_PUBLIC_URL`, so setting that is usually enough. |
130
+ | `FEST_DASHBOARD_URL` | **dev only.** Where the dashboard is when it isn't this server; `npm run dev` puts it on Vite's port. Leave unset in production. |
216
131
 
217
- See [docs/CLI-AUTH.md](docs/CLI-AUTH.md) for the full OAuth setup and how
218
- `fest login`'s loopback flow works.
132
+ For the full OAuth setup, see [docs/CLI-AUTH.md](docs/CLI-AUTH.md).
219
133
 
220
- ### Behind Caddy, on a path
134
+ ### Behind a reverse proxy, on a path
221
135
 
222
- Fest can be mounted under a path rather than on its own hostname —
223
- `https://lastlight.nearform.dev/fest`. Set `FEST_PUBLIC_URL` to the full URL
224
- including that path and Fest takes the mount point from it: the dashboard's
225
- `<base href>` is rewritten to match, and the OAuth redirect URI is built
226
- against it.
136
+ Fest can be mounted under a path rather than on its own hostname. Set
137
+ `FEST_PUBLIC_URL` to the full URL including that path and Fest takes the mount
138
+ point from it: the dashboard's `<base href>` is rewritten to match, and the
139
+ OAuth redirect URI is built against it.
227
140
 
228
141
  ```caddyfile
229
- lastlight.nearform.dev {
142
+ fest.corp.test {
230
143
  handle_path /fest/* {
231
144
  reverse_proxy 127.0.0.1:8787 {
232
145
  # SSE: /api/live is a long-lived event stream, and a buffering
@@ -238,40 +151,172 @@ lastlight.nearform.dev {
238
151
  ```
239
152
 
240
153
  ```bash
241
- FEST_PUBLIC_URL=https://lastlight.nearform.dev/fest
154
+ FEST_PUBLIC_URL=https://fest.corp.test/fest
242
155
  FEST_SECURE_COOKIES=1
243
156
  ```
244
157
 
245
158
  `handle_path` strips the `/fest` prefix before proxying. A plain `handle` +
246
- `reverse_proxy`, which does not strip it, works too — Fest removes its own
247
- mount path from an incoming request when it is still there, so either spelling
248
- routes. Caddy passes the original `Host` upstream by default, which the CSRF
249
- origin check needs; on nginx that is `proxy_set_header Host $host`, and
159
+ `reverse_proxy`, which does not strip it, works too — Fest removes its own mount
160
+ path from an incoming request when it is still there, so either spelling routes.
161
+ Caddy passes the original `Host` upstream by default, which the CSRF origin
162
+ check needs; on nginx that is `proxy_set_header Host $host`, plus
250
163
  `proxy_buffering off` for the event stream.
251
164
 
252
165
  The registered OAuth redirect URI must include the path —
253
- `https://lastlight.nearform.dev/fest/api/auth/oauth/google/callback`. Developers
254
- point both Claude Code and the CLI at the full prefixed URL
255
- (`fest login --server https://lastlight.nearform.dev/fest`).
166
+ `https://fest.corp.test/fest/api/auth/oauth/google/callback`. Developers point
167
+ both Claude Code and the CLI at the full prefixed URL.
256
168
 
257
- ## Requirements
169
+ ---
258
170
 
259
- Node >= 22.18 (TypeScript runs directly via native type stripping — no build
260
- step for the server). Vite + React are used only for the dashboard, later.
171
+ ## How it works
172
+
173
+ ### Why this is possible
174
+
175
+ Claude Code's inference client attaches the subscription OAuth bearer with **no
176
+ host check** against `ANTHROPIC_BASE_URL`. Point it at Fest while logged in with
177
+ Max/Team and Fest receives `Authorization: Bearer sk-ant-oat…`. Confirmed both by
178
+ reading the binary and by running it — see
179
+ [docs/PHASE0-RESULTS.md](docs/PHASE0-RESULTS.md).
261
180
 
262
- ## Commands
181
+ Token refresh happens client-side against `api.anthropic.com`, outside
182
+ `ANTHROPIC_BASE_URL`. So Fest **forwards and forgets**: it never stores,
183
+ refreshes or holds a subscription credential. That is a genuine security
184
+ advantage over any "store the team's key" design, not a side effect.
185
+
186
+ ### Two things that will bite you
187
+
188
+ **1. `ANTHROPIC_API_KEY` and `ANTHROPIC_AUTH_TOKEN` silently kill the
189
+ subscription.** Claude Code demotes off OAuth if *any* Anthropic-issued
190
+ credential is present — including an `apiKeyHelper`. So Fest's identity token
191
+ never goes in those variables; it rides in the URL path prefix or a custom
192
+ header. A design that ignores this moves a whole team off their subscriptions
193
+ onto a server-held key, invisibly.
194
+
195
+ **2. This is supported-by-absence, not by design.** There is no *documented*
196
+ path for relaying a subscription bearer through a third-party gateway. It works
197
+ because no guard exists. Treat it as a version-pinned dependency, and settle the
198
+ policy question with Anthropic before a team-wide rollout.
199
+
200
+ That dependency is enforced rather than remembered: `npm run canary` re-runs both
201
+ load-bearing Phase 0 experiments against the installed Claude Code release and
202
+ refuses the rollout if either has changed. See [docs/CANARY.md](docs/CANARY.md);
203
+ verdicts are recorded per version in `docs/canary-history.jsonl`.
204
+
205
+ Worth knowing: Anthropic ships its own self-hostable `claude gateway` with
206
+ central metering, pricing and managed policies. It authenticates via OIDC and
207
+ holds provider credentials itself, so it cannot do subscription pass-through —
208
+ but if that requirement ever softens, it is the supported product.
209
+
210
+ ### What Fest can see, and what it keeps
211
+
212
+ This is a gateway every prompt a team writes passes through, so it is worth being
213
+ exact rather than reassuring.
214
+
215
+ **Fest sees everything, because it has to.** A request body arrives at this
216
+ process in full: prompts, file contents, tool results, the lot. That is
217
+ unavoidable for anything sitting on the wire.
218
+
219
+ **Fest keeps none of it.** Request bodies are relayed as opaque bytes and never
220
+ parsed for storage. What is written down is metadata: who, when, which model, how
221
+ many tokens in each of the four buckets, latency, HTTP status, error type, and
222
+ the session id Claude Code already sends. There is no column anywhere in the
223
+ schema for prompt or completion text — not disabled, *absent* — so "turn off
224
+ content capture" is not a setting that could be misconfigured.
225
+
226
+ **No credential is persistable, by construction rather than by policy.** A
227
+ subscription bearer is forwarded and forgotten; there is no table to put one in.
228
+ What is stored of a Fest identity token or a dashboard password is a hash. The
229
+ leak tests grep the entire database, every log line and every API response for
230
+ secret-shaped strings.
231
+
232
+ **An admin can see who used what, and when.** That is the point of a team
233
+ gateway, and developers pointing their editors at it should be told so plainly.
234
+ They cannot see each other: a `member` account sees only its own traffic,
235
+ enforced in the query layer rather than in the UI.
236
+
237
+ **Raw per-request rows age out after 30 days.** The hourly rollups, which are
238
+ aggregate, are kept for 400, so a year of trends does not require a year of
239
+ per-developer detail.
240
+
241
+ ### Design commitments
242
+
243
+ - **Byte-for-byte pass-through.** Subscription tokens are validated against
244
+ request shape, so the body is relayed as opaque bytes — never parsed and
245
+ re-serialised. No model rewriting or prompt shaping on that path.
246
+ - **`cache_control` forwarded verbatim.** Stripping it silently destroys prompt
247
+ caching and inflates every developer's token bill.
248
+ - **The four token buckets are disjoint.** `input_tokens` excludes cache reads
249
+ and cache writes; context size is the sum. Folding cache reads into input is an
250
+ order-of-magnitude error on a cache-heavy agent workload — and Claude Code is
251
+ one.
252
+ - **`null` cost means unavailable, never zero.** A subscription request is real
253
+ usage with *no org spend*; an unknown model is unpriced, not free. Totals
254
+ therefore render honestly as `$12.3456 (+3 n/a)`. See
255
+ [docs/PRICING.md](docs/PRICING.md).
256
+ - **For a subscription developer, quota is the scarce resource, not dollars.**
257
+ Anthropic returns 5h/7d utilisation on every response, so that is what the
258
+ dashboard shows rather than an invented dollar figure.
259
+
260
+ ---
261
+
262
+ ## Develop it
263
+
264
+ Node >= 22.18. There is **no build step for the server** — Node runs the
265
+ TypeScript directly via native type stripping. Only the dashboard is built, and
266
+ only the published npm package is compiled (Node refuses to strip types under
267
+ `node_modules`).
263
268
 
264
269
  ```bash
265
- npm test # node --test
266
- npm run canary # version gate: re-run before rolling out a Claude Code release
267
- npm run capture # Phase 0 capture server
268
- npm run typecheck # tsc --noEmit (needs npm install first)
269
- npm run dev # gateway + dashboard with hot reload
270
- npm run demo # synthetic traffic in a scratch database, then both of the above
270
+ npm install
271
+ npm run dev # gateway (node --watch) + dashboard (Vite, HMR), one terminal
272
+ npm test # node --test
273
+ npm run typecheck # tsc --noEmit, root then web/
274
+ npm run demo # synthetic traffic in a scratch database, then dev
275
+ npm run canary # version gate: re-run before rolling out a Claude Code release
271
276
  ```
272
277
 
273
- ```bash
274
- node server/bin/fest.ts admin create <email> [--role R] [--password-stdin]
275
- node server/bin/fest.ts admin list | admin passwd <email> | admin disable <email>
276
- node server/bin/fest.ts token create <email> [name] | token list | token revoke <id>
278
+ Both `npm test` and `npm run typecheck` must be clean before committing. From a
279
+ clone the CLI runs straight off the TypeScript: `npm run cli -- login …` (note
280
+ the `--`).
281
+
282
+ ### Layout
283
+
284
+ ```
285
+ server/bin/fest.ts CLI entrypoint: serve | migrate | token | admin | seed |
286
+ login | whoami | claude | logout
287
+ server/pipeline/ passthrough (byte-for-byte) — the subscription path
288
+ server/http/ sse parser, tee, header discipline, errors, routing
289
+ server/store/ SQLite schema, write path, identity tokens
290
+ server/usage/ accumulator, pricing, nullable cost algebra
291
+ server/secret/ credential classification + redaction
292
+ server/auth/, server/api/ sessions, OAuth, the dashboard's JSON API
293
+ cli/ the developer half of the CLI — no DB access, ever
294
+ shared/ contracts both halves agree on, and the env vars that
295
+ silently kill subscription auth
296
+ web/ the dashboard (Vite + React) — the only build step
297
+ tools/ dev runner, canary, Phase 0 capture, price sync
298
+ test/ node --test, flat
277
299
  ```
300
+
301
+ There is one `CLAUDE.md` per top-level folder with the conventions that apply
302
+ inside it — read the relevant one before working there.
303
+
304
+ ### Docs
305
+
306
+ | | |
307
+ | --- | --- |
308
+ | [CLI-AUTH.md](docs/CLI-AUTH.md) | OAuth setup and the `fest login` flow end to end |
309
+ | [ROUTING.md](docs/ROUTING.md) | the routing table format and the substitute path |
310
+ | [PRICING.md](docs/PRICING.md) | where rates come from, and spend vs. value |
311
+ | [POSTURES.md](docs/POSTURES.md) | subscription vs. key posture |
312
+ | [CANARY.md](docs/CANARY.md) | the version-upgrade gate |
313
+ | [PHASE0.md](docs/PHASE0.md) · [PHASE0-RESULTS.md](docs/PHASE0-RESULTS.md) | the gating experiment, and what it found |
314
+ | [CLIENT-GATEWAY-PROTOCOL.md](docs/CLIENT-GATEWAY-PROTOCOL.md) | what Claude Code actually sends |
315
+ | [FRONTEND.md](docs/FRONTEND.md) | the dashboard's screens and data flow |
316
+
317
+ ### Releasing
318
+
319
+ Bump `version` in `package.json`, then publish a GitHub Release tagged
320
+ `v<version>`. CI publishes to npm over trusted publishing (OIDC) — there is no
321
+ token in the repository — and refuses to publish if the tag and `package.json`
322
+ disagree.
package/dist/cli/login.js CHANGED
@@ -100,8 +100,14 @@ export async function runLogin(opts) {
100
100
  });
101
101
  try {
102
102
  const callbackUrl = `http://127.0.0.1:${port}/callback`;
103
- const startUrl = `${serverUrl}/api/auth/oauth/${opts.provider}/start?cli_redirect_uri=${encodeURIComponent(callbackUrl)}`;
104
- process.stdout.write(`Opening your browser to sign in with ${opts.provider}...\n`);
103
+ // Not the provider's start URL directly. This asks the GATEWAY first, which
104
+ // can see the browser's session cookie where this process cannot: already
105
+ // signed in means one approval click instead of a provider round trip, and
106
+ // if there is no session it hands off to the dashboard's own login screen —
107
+ // which is why `--provider` is not passed here. It still records which
108
+ // provider was asked for in the stored config.
109
+ const startUrl = `${serverUrl}/api/auth/cli/authorize?cli_redirect_uri=${encodeURIComponent(callbackUrl)}`;
110
+ process.stdout.write("Opening your browser to authorise this CLI...\n");
105
111
  process.stdout.write(`If it doesn't open, visit:\n ${startUrl}\n`);
106
112
  (opts.openBrowser ?? open)(startUrl).catch(() => { });
107
113
  const timeout = new Promise((resolve) => {
@@ -1 +1 @@
1
- {"version":3,"file":"login.js","sourceRoot":"","sources":["../../cli/login.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"login.js","sourceRoot":"","sources":["../../cli/login.ts"],"names":[],"mappings":"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"}
@@ -11,6 +11,7 @@ import { originAllowed, clientIp, sessionFromRequest } from "../auth/guard.js";
11
11
  import { recordAudit } from "../store/audit.js";
12
12
  import { log } from "../log.js";
13
13
  import { handleOauth } from "./oauth.js";
14
+ import { handleCliAuth } from "./cli-auth.js";
14
15
  import { configuredProviders } from "../auth/oauth.js";
15
16
  const MAX_BODY_BYTES = 4 * 1024;
16
17
  function json(res, status, body, extra = {}) {
@@ -88,6 +89,11 @@ export async function handleAuth(req, res, path, deps, session) {
88
89
  if (await handleOauth(req, res, path, { store: deps.store, orgId: deps.orgId, config: deps.config })) {
89
90
  return true;
90
91
  }
92
+ // Before the method and origin gates below: `authorize` is a GET that renders
93
+ // a page, and `approve` applies both checks itself for its own reasons.
94
+ if (await handleCliAuth(req, res, path, { store: deps.store, orgId: deps.orgId, config: deps.config }, session)) {
95
+ return true;
96
+ }
91
97
  if (path === "/api/auth/me" && method === "GET") {
92
98
  json(res, 200, {
93
99
  // Not 401: "am I signed in" is a question an anonymous caller is allowed
@@ -1 +1 @@
1
- {"version":3,"file":"auth.js","sourceRoot":"","sources":["../../../server/api/auth.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"auth.js","sourceRoot":"","sources":["../../../server/api/auth.ts"],"names":[],"mappings":"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"}