Skip to content

Commit 68727aa

Browse files
committed
docs: apply review feedback and tighten prose to ~65%
- Add the intro point that, with agents, Devframe is a fast foundation for bespoke or one-off devtools (addresses review comment on the introduction). - Fix the stale hosted-base default in the definition reference (/__<id>/) and drop the remaining deprecated cli.distDir mentions. - Continue the concision pass across the guide, adapters, frameworks, plugins, and helpers, bringing total markdown to ~65% of the original while preserving code, tables, warnings, links, and technical facts. Created with the help of an agent.
1 parent af5bcc6 commit 68727aa

33 files changed

Lines changed: 562 additions & 955 deletions

docs/adapters/cac.md

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,13 @@ outline: deep
44

55
# CLI (cac)
66

7-
Wraps a `DevframeDefinition` in a [`cac`](https://github.com/cacjs/cac)-powered CLI with `dev`, `build`, and `mcp` commands.
8-
9-
`cac` is an optional peer of this adapter:
7+
A [`cac`](https://github.com/cacjs/cac) CLI around a `DevframeDefinition` with `dev`, `build`, and `mcp` commands. `cac` is an optional peer:
108

119
```sh
1210
npm install devframe cac
1311
```
1412

15-
Tools using the [lower-level factories](#use-your-own-cli-framework) need no `cac`.
13+
The [lower-level factories](#use-your-own-cli-framework) need no `cac`.
1614

1715
```ts
1816
import { defineDevframe } from 'devframe'
@@ -28,8 +26,6 @@ const devframe = defineDevframe({
2826
await createCac(devframe).parse()
2927
```
3028

31-
Running the binary:
32-
3329
```sh
3430
my-devframe # dev server at http://localhost:9999/
3531
my-devframe --port 8080
@@ -38,7 +34,7 @@ my-devframe build --out-dir dist-static --base /devframe/
3834
my-devframe mcp # stdio MCP server
3935
```
4036

41-
The SPA serves at `/` standalone, `/__devframe/` when hosted ([Mount paths](./#mount-paths)).
37+
The SPA serves at `/` standalone, `/__devframe/` hosted ([Mount paths](./#mount-paths)).
4238

4339
## Options
4440

@@ -47,10 +43,10 @@ The SPA serves at `/` standalone, `/__devframe/` when hosted ([Mount paths](./#m
4743
| Option | Default | Description |
4844
|--------|---------|-------------|
4945
| `defaultPort` | `9999` (or `def.cli?.port`) | Dev port if `--port` unset. |
50-
| `configureCli` || `(cli: CAC) => void` — add commands/flags post-`cli.configure`. |
46+
| `configureCli` || `(cli: CAC) => void` — add commands/flags. |
5147
| `onReady` || `(info: { origin, port, app }) => void \| Promise<void>` — once listening. |
5248

53-
`createCac` returns a `CacHandle`:
49+
Returns a `CacHandle`:
5450

5551
```ts
5652
interface CacHandle {
@@ -59,8 +55,6 @@ interface CacHandle {
5955
}
6056
```
6157

62-
Add commands/flags via `cli` before `parse()`.
63-
6458
## Definition-level `cli` fields
6559

6660
```ts
@@ -91,7 +85,7 @@ defineDevframe({
9185

9286
## Headless logging
9387

94-
Wire `onReady` to print a banner:
88+
Print a banner via `onReady`:
9589

9690
```ts
9791
await createCac(devframe, {
@@ -103,7 +97,7 @@ await createCac(devframe, {
10397

10498
## Use your own CLI framework
10599

106-
Drop to the peer factories for a commander/yargs program or other structure:
100+
Peer factories for a commander/yargs program:
107101

108102
| Building block | Entry | Purpose |
109103
|----------------|-------|---------|

docs/adapters/dev.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ outline: deep
44

55
# Dev
66

7-
`createCac`'s building block: h3 + WebSocket RPC + the SPA at the resolved base path. Use it in a custom CLI or with middleware.
7+
`createCac`'s building block: h3 + WebSocket RPC + the SPA at the resolved base path.
88

99
```ts
1010
import { createDevServer } from 'devframe/adapters/dev'
@@ -19,13 +19,13 @@ const handle = await createDevServer(devframe, {
1919
process.on('SIGINT', () => handle.close().then(() => process.exit(0)))
2020
```
2121

22-
Returns the `StartedServer` (origin, port, h3 app, WS server, RPC group, `close()`).
22+
Returns a `StartedServer`: origin, port, h3 app, WS server, RPC group, `close()`.
2323

2424
| Option | Default | Description |
2525
|--------|---------|-------------|
2626
| `host` | `def.cli?.host ?? 'localhost'` | Bind host. |
2727
| `port` | resolved via `resolveDevServerPort` | Listen port. |
28-
| `flags` | `{}` | Passed to `setup(ctx, { flags })`. |
28+
| `flags` | `{}` | To `setup(ctx, { flags })`. |
2929
| `distDir` | `def.clientAssets` (falls back to deprecated `def.cli?.distDir`) | SPA dist; unset = bridge mode. |
3030
| `basePath` | `resolveBasePath(def, 'standalone')` | Mount override. |
3131
| `app` | fresh h3 app | Mount onto. |
@@ -35,19 +35,19 @@ Returns the `StartedServer` (origin, port, h3 app, WS server, RPC group, `close(
3535

3636
## WebSocket endpoint
3737

38-
The RPC socket shares the HTTP port on `__ws`, advertised *relative* so the client dials its own origin through a reverse proxy. Configure `def.cli.ws`:
38+
The RPC socket shares the HTTP port at `__ws`, advertised *relative*. Configure `def.cli.ws`:
3939

4040
| Field | Scenario | Advertised `websocket` |
4141
|-------|----------|------------------------|
4242
| `route` | same server, other route | `{ path: <route> }` |
4343
| `port` | different port | `{ port, path: <route> }` |
4444
| `url` | remote origin | URL verbatim |
4545

46-
Precedence `url` > `port` > `route`; for `url` the socket stays local on `route` — point your tunnel there.
46+
Precedence `url` > `port` > `route`; `url` keeps the socket local on `route`.
4747

4848
## Port resolution
4949

50-
`resolveDevServerPort(def, opts?)` resolves a port before start:
50+
`resolveDevServerPort(def, opts?)` resolves a port before start.
5151

5252
```ts
5353
import { resolveDevServerPort } from 'devframe/adapters/dev'

docs/adapters/initiate.md

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# The Standard Handler
22

3-
`initDevframe()` is the boundary the whole project is built on: it turns a `DevframeDefinition` into a live instance whose `.handler` — a Web Standard `(request: Request) => Promise<Response>` — carries the entire surface (SPA, `__connection.json` discovery, RPC socket, auth gate, MCP route) under one mount base. Every other serving path — the [adapters](./), the [framework packages](/frameworks/), and the [hub](../guide/hub-initiate) — is assembled from it. Mount it in any app with a catch-all route.
3+
`initDevframe()` turns a `DevframeDefinition` into a live instance whose `.handler` — a Web Standard `(request: Request) => Promise<Response>` — carries the entire surface (SPA, `__connection.json` discovery, RPC socket, auth gate, MCP route) under one mount base. Every other serving path — [adapters](./), [framework packages](/frameworks/), [hub](../guide/hub-initiate) — is assembled from it. Mount it with a catch-all route.
44

55
```ts
66
import { initDevframe } from 'devframe/initiate'
@@ -12,7 +12,7 @@ const devtools = initDevframe(myDevframe, { base: '/__my-tool/' })
1212
// devtools.connectionMeta(), devtools.close()
1313
```
1414

15-
`base` is required, so the mount path is explicit — pass `resolveBasePath(def, 'hosted')` (`def.basePath ?? /__<id>/`) if you don't want to pick one; the instance echoes it back as `devtools.base`. `handler`/`nodeMiddleware` await readiness internally, so hosts never race boot. Creating an instance binds no port — [the WebSocket binding](#the-websocket-binding) is the host's call.
15+
`base` is required — pass `resolveBasePath(def, 'hosted')` (`def.basePath ?? /__<id>/`) to default it; the instance echoes it back as `devtools.base`. `handler`/`nodeMiddleware` await readiness internally. The instance binds no port — [the WebSocket binding](#the-websocket-binding) is the host's call.
1616

1717
## Mount the handler
1818

@@ -108,25 +108,25 @@ export const GET = ({ request }) => devtools.handler(request)
108108

109109
:::
110110

111-
Frameworks with dev-time module reloading (Next, Nitro, SvelteKit) re-evaluate the calling module, so memoize the instance on `globalThis` — otherwise every reload leaks the previous socket. `@devframes/next`'s `createDevframeNextHandler` does this for you.
111+
Frameworks with dev-time module reloading (Next, Nitro, SvelteKit) re-evaluate the calling module, so memoize the instance on `globalThis` to avoid leaking a socket per reload. `@devframes/next`'s `createDevframeNextHandler` handles this.
112112

113113
## The WebSocket binding
114114

115-
Fetch handlers hand over `Request`s, so the host binds the RPC socket explicitly. The **local binding** resolves in precedence order:
115+
Fetch handlers only hand over `Request`s, so the host binds the RPC socket. The **local binding** resolves in this order:
116116

117117
1. **`ws.port`** — a side-car server on that exact port.
118-
2. **`server`** — share the host's `node:http` server; the upgrade binds at `<base>__ws`. No extra ports; the socket follows the app through proxies and HTTPS.
118+
2. **`server`** — share the host's `node:http` server; the upgrade binds at `<base>__ws`. No extra ports.
119119
3. **`ws: { sidecar: true }`** — a side-car server on a free port, for hosts whose handlers never see upgrades (Next.js route handlers, Nitro, Rsbuild).
120-
4. **The host's own upgrades** — with none of the above, the socket waits: `devtools.attach(server)` routes a server's `upgrade` events (returning a detach fn); `devtools.handleUpgrade(req, socket, head)` completes a single one from a listener you own. Built lazily.
120+
4. **The host's own upgrades** — with none set, the socket waits: `devtools.attach(server)` routes a server's `upgrade` events (returning a detach fn); `devtools.handleUpgrade(req, socket, head)` completes a single one from a listener you own.
121121

122-
`ws.url` controls the *advertisement* instead — the browser dials it verbatim. Alone, an external server owns the transport and its auth (wire in the instance's `context` via `createContextRpcServer` + a WS transport); alongside a local binding it overrides only what's advertised (the tunnel pattern).
122+
`ws.url` controls the *advertisement* instead — the browser dials it verbatim. Alone, an external server owns the transport and its auth (wire the instance's `context` via `createContextRpcServer` + a WS transport); alongside a local binding it overrides only the advertisement (the tunnel pattern).
123123

124-
`__connection.json` describes whichever combination is active. Asking a configured instance to also take over host upgrades reports `DF0055` (a local binding owns the socket) or `DF0056` (`ws.url` handed it off).
124+
`__connection.json` describes the active combination. Asking a configured instance to take over host upgrades reports `DF0055` (a local binding owns the socket) or `DF0056` (`ws.url` handed it off).
125125

126126
## Auth
127127

128-
The instance **gates by default**. The interactive OTP handler is wired automatically and prints its code/magic-link banner once the public origin is known (the first request, or the `origin` option). Pass `auth: false` for single-user localhost, or a `DevframeAuthHandler` for a custom scheme.
128+
The instance **gates by default**. The interactive OTP handler wires automatically, printing its code/magic-link banner once the public origin is known (the first request, or the `origin` option). Pass `auth: false` for single-user localhost, or a `DevframeAuthHandler` for a custom scheme.
129129

130130
## Relation to the other adapters
131131

132-
`createDevServer`, `devframeViteBridge` (`@devframes/vite`), and `@devframes/next` are assembled from this instance internally. To host **many** devframes with shared transport and docks, use [`initHub`](../guide/hub-initiate).
132+
`createDevServer`, `devframeViteBridge` (`@devframes/vite`), and `@devframes/next` are assembled from it internally. To host **many** devframes, use [`initHub`](../guide/hub-initiate).

docs/adapters/mcp.md

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ outline: deep
44

55
# MCP
66

7-
Translates a devframe's agent host into a [Model Context Protocol](https://modelcontextprotocol.io) server: agents call flagged RPCs and read exposed resources.
7+
Exposes a devframe's agent host as a [Model Context Protocol](https://modelcontextprotocol.io) server: agents call flagged RPCs and read resources.
88

99
```ts
1010
import { createMcpServer } from 'devframe/adapters/mcp'
@@ -13,11 +13,11 @@ import devframe from './devframe'
1313
await createMcpServer(devframe, { transport: 'stdio' })
1414
```
1515

16-
`@modelcontextprotocol/server` is a peer dependency. `createMcpServer` speaks `stdio`, spawned per session.
16+
`@modelcontextprotocol/server` is a peer dependency; `createMcpServer` speaks `stdio`, spawned per session.
1717

1818
## Route-based server
1919

20-
The dev server exposes the same surface over HTTP with live changes. Enable with `cli.mcp`:
20+
The dev server exposes the same surface over HTTP, live. Enable with `cli.mcp`:
2121

2222
```ts
2323
import { defineDevframe } from 'devframe'
@@ -30,13 +30,13 @@ export default defineDevframe({
3030
})
3131
```
3232

33-
The endpoint speaks Streamable-HTTP at `/__mcp` (`/__<id>/__mcp` under a host), sharing its origin/port. `--mcp` / `--no-mcp` override per run; `__connection.json` advertises the route.
33+
The endpoint speaks Streamable-HTTP at `/__mcp` (`/__<id>/__mcp` under a host), sharing its origin/port. `--mcp` / `--no-mcp` override; `__connection.json` advertises it.
3434

35-
Each session gets its own MCP server from the live context, keyed by `Mcp-Session-Id`. An origin gate requires `Origin` be loopback (or allow-listed); unlike WS it rejects `Origin`-less requests`devframe connect` sends its loopback origin explicitly. Widen for a tunnel/LAN origin with `cli: { mcp: { allowedOrigins: ['https://tunnel.example.com'] } }`.
35+
Each session gets its own MCP server, keyed by `Mcp-Session-Id`. An origin gate requires `Origin` be loopback (or allow-listed) and rejects `Origin`-less requests. Widen for a tunnel/LAN origin with `cli: { mcp: { allowedOrigins: ['https://tunnel.example.com'] } }`.
3636

3737
### Hosted bridges
3838

39-
Both bridges forward the option to their side-car dev server, advertising the endpoint in `__connection.json`:
39+
Both bridges forward it to their side-car dev server, advertising the endpoint in `__connection.json`:
4040

4141
```ts
4242
// Vite (@devframes/vite)
@@ -48,7 +48,7 @@ createDevframeNextHandler(devframe, { mcp: true })
4848

4949
## Custom hosts
5050

51-
`createMcpFetchHandler(ctx, options)` returns the endpoint as a `Request → Response` handler plus a `dispose()` for teardown — mount it on any fetch server.
51+
`createMcpFetchHandler(ctx, options)` returns the endpoint as a `Request → Response` handler plus a `dispose()` — mount on any fetch server.
5252

5353
```ts
5454
import { createMcpFetchHandler } from 'devframe/adapters/mcp'
@@ -63,7 +63,7 @@ const mcp = createMcpFetchHandler(ctx, {
6363

6464
## Discovery: `devframe connect`
6565

66-
The `devframe` bin ships an MCP **connector** ([next-devtools-mcp](https://github.com/vercel/next-devtools-mcp)-style) that finds every running devframe. Configure it once:
66+
The `devframe` bin ships an MCP **connector** ([next-devtools-mcp](https://github.com/vercel/next-devtools-mcp)-style) that finds every running devframe. Configure once:
6767

6868
```json
6969
{
@@ -75,9 +75,9 @@ The `devframe` bin ships an MCP **connector** ([next-devtools-mcp](https://githu
7575

7676
Two gateway tools (`devframe:connect:*` ids — see [tool ids and wire names](/guide/agent-native#tool-ids-and-wire-names)):
7777

78-
- **`devframe_connect_list-instances`** — list running dev servers and their MCP tools; those without a route hint at `--mcp`.
78+
- **`devframe_connect_list-instances`** — list running dev servers and their MCP tools.
7979
- **`devframe_connect_call-tool`** — invoke one tool on an instance (`{ port, tool, args }`) over Streamable-HTTP.
8080

81-
Discovery reads the **instance registry**: every `createDevServer` writes `~/.devframe/instances/<pid>-<port>.json` on boot; the connector dials each with its loopback origin. In-process hosts register via `registerDevframeInstance` (`devframe/node`). `--port <n>` probes an explicit port; `DEVFRAME_INSTANCES_DIR` relocates the registry, `DEVFRAME_DISABLE_INSTANCE_REGISTRY=1` opts out.
81+
Discovery reads the **instance registry**: every `createDevServer` writes `~/.devframe/instances/<pid>-<port>.json`, dialed with a loopback origin. In-process hosts register via `registerDevframeInstance` (`devframe/node`). `--port <n>` probes a port; `DEVFRAME_INSTANCES_DIR` relocates the registry, `DEVFRAME_DISABLE_INSTANCE_REGISTRY=1` opts out.
8282

83-
See [Agent-Native](/guide/agent-native) for the full API, safety model, and example.
83+
See [Agent-Native](/guide/agent-native) for the API and safety model.

0 commit comments

Comments
 (0)