fest-gateway 0.1.0 → 0.3.0

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