proteum 2.4.3 → 2.5.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 (74) hide show
  1. package/README.md +60 -55
  2. package/agents/project/AGENTS.md +112 -31
  3. package/agents/project/CODING_STYLE.md +2 -2
  4. package/agents/project/app-root/AGENTS.md +1 -3
  5. package/agents/project/client/AGENTS.md +1 -1
  6. package/agents/project/client/pages/AGENTS.md +21 -9
  7. package/agents/project/diagnostics.md +2 -2
  8. package/agents/project/optimizations.md +1 -1
  9. package/agents/project/root/AGENTS.md +105 -22
  10. package/agents/project/server/routes/AGENTS.md +30 -1
  11. package/agents/project/tests/AGENTS.md +1 -1
  12. package/cli/commands/doctor.ts +54 -3
  13. package/cli/commands/runtime.ts +6 -0
  14. package/cli/commands/worktree.ts +116 -0
  15. package/cli/compiler/artifacts/controllers.ts +16 -15
  16. package/cli/compiler/artifacts/discovery.ts +129 -17
  17. package/cli/compiler/artifacts/routing.ts +0 -5
  18. package/cli/compiler/artifacts/services.ts +253 -76
  19. package/cli/compiler/common/controllers.ts +159 -57
  20. package/cli/compiler/common/generatedRouteModules.ts +457 -363
  21. package/cli/mcp/router.ts +47 -3
  22. package/cli/presentation/commands.ts +25 -15
  23. package/cli/runtime/commands.ts +39 -12
  24. package/cli/runtime/worktreeBootstrap.ts +608 -0
  25. package/cli/scaffold/index.ts +28 -18
  26. package/cli/scaffold/templates.ts +44 -33
  27. package/cli/utils/agents.ts +14 -1
  28. package/client/services/router/index.tsx +23 -3
  29. package/client/services/router/request/api.ts +14 -4
  30. package/common/dev/contractsDoctor.ts +1 -1
  31. package/common/dev/mcpPayloads.ts +8 -1
  32. package/common/env/proteumEnv.ts +14 -2
  33. package/common/router/contracts.ts +1 -1
  34. package/common/router/definitions.ts +177 -0
  35. package/common/router/index.ts +23 -12
  36. package/common/router/pageData.ts +5 -5
  37. package/common/router/register.ts +2 -2
  38. package/common/router/request/api.ts +12 -2
  39. package/docs/agent-routing.md +5 -2
  40. package/docs/diagnostics.md +2 -0
  41. package/docs/mcp.md +6 -3
  42. package/eslint.js +36 -1
  43. package/package.json +1 -1
  44. package/server/app/commands.ts +5 -1
  45. package/server/app/container/console/http-client-error-context.test.cjs +10 -1
  46. package/server/app/container/console/index.ts +2 -1
  47. package/server/app/controller/index.ts +98 -40
  48. package/server/app/index.ts +92 -1
  49. package/server/app/service/index.ts +5 -1
  50. package/server/index.ts +6 -2
  51. package/server/services/router/index.ts +47 -38
  52. package/server/services/router/response/index.ts +2 -2
  53. package/tests/agents-utils.test.cjs +14 -1
  54. package/tests/cli-mcp-command.test.cjs +84 -0
  55. package/tests/definition-contracts.test.cjs +453 -0
  56. package/tests/dev-transpile-watch.test.cjs +37 -28
  57. package/tests/eslint-rules.test.cjs +39 -1
  58. package/tests/mcp.test.cjs +90 -0
  59. package/tests/worktree-bootstrap.test.cjs +206 -0
  60. package/types/aliases.d.ts +0 -5
  61. package/types/controller-input.test.ts +23 -17
  62. package/types/controller-request-context.test.ts +10 -11
  63. package/cli/commands/migrate.ts +0 -51
  64. package/cli/migrate/pageContract.ts +0 -516
  65. package/docs/migrate-from-2.1.3.md +0 -396
  66. package/scripts/cleanup-generated-controllers.ts +0 -62
  67. package/scripts/fix-reference-app-typing.ts +0 -490
  68. package/scripts/format-router-registrations.ts +0 -119
  69. package/scripts/migrate-explicit-controllers-and-request.ts +0 -423
  70. package/scripts/refactor-client-app-imports.ts +0 -244
  71. package/scripts/refactor-client-pages.ts +0 -587
  72. package/scripts/refactor-server-controllers.ts +0 -471
  73. package/scripts/refactor-server-runtime-aliases.ts +0 -360
  74. package/scripts/restore-client-app-import-files.ts +0 -41
package/README.md CHANGED
@@ -4,8 +4,6 @@ Proteum is an LLM-first SSR / SEO / TypeScript framework for full-stack web appl
4
4
 
5
5
  It is built for teams that want explicit server contracts, server-first rendering, deterministic generated artifacts, and a codebase that an AI agent can inspect without reverse-engineering hidden runtime magic.
6
6
 
7
- Migration guide for older apps: [docs/migrate-from-2.1.3.md](docs/migrate-from-2.1.3.md)
8
-
9
7
  ## Sponsor
10
8
 
11
9
  Proteum is sponsored by [Unique Domains](https://unique.domains/?utm_source=github&utm_medium=referral&utm_campaign=repo_proteum&utm_content=top_sponsor).
@@ -33,8 +31,8 @@ Proteum combines:
33
31
  ## Core Principles
34
32
 
35
33
  - **Server-first by default.** Put data loading in the page data function and keep client code focused on UI.
36
- - **Explicit request entrypoints.** Controllers are classes. Request access is explicit through `this.request`.
37
- - **Local validation.** Validate handler input inside the handler with `this.input(schema)`.
34
+ - **Explicit request entrypoints.** Routes and controllers are exported definition objects.
35
+ - **Local validation.** Declare controller input on `defineAction({ input, handler })`; handlers receive parsed `input`.
38
36
  - **Deterministic generation.** Proteum owns `.proteum/` and regenerates it from source.
39
37
  - **Explainability matters.** `proteum explain`, `proteum doctor`, `proteum diagnose`, `proteum perf`, and `proteum trace` expose the framework view of your app and its live requests, and the profiler renders the same diagnostics and perf surfaces for humans in dev.
40
38
  - **SEO is not an afterthought.** Identity, routes, layouts, and SSR data are part of the app contract.
@@ -76,9 +74,9 @@ Important files:
76
74
  - `proteum.config.ts`: typed Proteum compiler and connection settings such as `transpile` and `connect` via `Application.setup({ ... })`
77
75
  - `process.env` / optional `.env`: `PORT`, `ENV_*`, `URL`, `URL_INTERNAL`, any app-chosen variables referenced by `proteum.config.ts`, and `TRACE_*` environment variables loaded by the app
78
76
  - `server/config/*.ts`: plain typed config exports consumed by the explicit app bootstrap
79
- - `server/index.ts`: default-exported `Application` subclass that instantiates root services and router plugins
80
- - `client/pages/**`: SSR page entrypoints registered through `Router.page(path, options, data, render)`
81
- - `server/controllers/**`: request handlers that extend `Controller`
77
+ - `server/index.ts`: default-exported `defineApplication({ services, router, models, commands })` application graph
78
+ - `client/pages/**`: SSR page entrypoints that default-export `definePageRoute({ path, options, data, render })`
79
+ - `server/controllers/**`: generated API definitions that default-export `defineController({ path, actions })`
82
80
  - `commands/**`: dev-only internal commands that extend `Commands`
83
81
  - `server/services/**`: business logic that extends `Service`
84
82
  - `.proteum/**`: framework-owned generated contracts and manifests
@@ -169,25 +167,27 @@ export const routerBaseConfig = {
169
167
 
170
168
  ```ts
171
169
  // server/index.ts
172
- import { Application } from '@server/app';
170
+ import { defineApplication } from '@server/app';
173
171
  import Router from '@server/services/router';
174
172
  import SchemaRouter from '@server/services/schema/router';
175
173
  import Users from '@/server/services/Users';
176
174
  import * as userConfig from '@/server/config/user';
177
175
 
178
- export default class MyApp extends Application {
179
- public Users = new Users(this, userConfig.usersConfig, this);
180
- public Router = new Router(
181
- this,
182
- {
183
- ...userConfig.routerBaseConfig,
184
- plugins: {
185
- schema: new SchemaRouter({}, this),
176
+ export default defineApplication({
177
+ services: (app) => ({
178
+ Users: new Users(app, userConfig.usersConfig, app),
179
+ Router: new Router(
180
+ app,
181
+ {
182
+ ...userConfig.routerBaseConfig,
183
+ plugins: {
184
+ schema: new SchemaRouter({}, app),
185
+ },
186
186
  },
187
- },
188
- this
189
- );
190
- }
187
+ app
188
+ ),
189
+ }),
190
+ });
191
191
  ```
192
192
 
193
193
  Proteum reads `server/index.ts` as the source of truth for installed root services and router plugins, and reads `server/config/*.ts` `Services.config(...)` exports for typed config such as service priority overrides.
@@ -233,60 +233,59 @@ Default public asset validators depend on the environment: dev disables `ETag` a
233
233
  Proteum pages are explicit SSR entrypoints.
234
234
 
235
235
  ```tsx
236
- import Router from '@/client/router';
236
+ import { definePageRoute } from '@common/router';
237
237
 
238
- Router.page(
239
- '/',
240
- {
238
+ export default definePageRoute({
239
+ path: '/',
240
+ options: {
241
241
  auth: false,
242
242
  layout: false,
243
243
  },
244
- ({ Plans, Stats }) => ({
244
+ data: ({ Plans, Stats }) => ({
245
245
  plans: Plans.getPlans(),
246
246
  stats: Stats.general(),
247
247
  }),
248
- ({ plans, stats }) => {
248
+ render: ({ plans, stats }) => {
249
249
  return <LandingPage plans={plans} stats={stats} />;
250
- }
251
- );
250
+ },
251
+ });
252
252
  ```
253
253
 
254
254
  What happens here:
255
255
 
256
- - the first argument is the route path
257
- - the second argument is the explicit route-options object
258
- - the third argument is the page data function or `null`
256
+ - `path`, `options`, and error `code` metadata are static and compiler-readable
259
257
  - route behavior such as `auth`, `layout`, `static`, or `redirectLogged` lives in the options object
260
- - every key returned from the data function becomes page data
261
- - the renderer receives the resolved data and the generated controller/service context
258
+ - every key returned from `data` becomes page data
259
+ - runtime app/client references are allowed only inside `data` and `render`
262
260
 
263
261
  ## Example: Controller
264
262
 
265
263
  Proteum controllers are explicit request entrypoints.
266
264
 
267
265
  ```ts
268
- import Controller, { schema } from '@server/app/controller';
266
+ import { defineAction, defineController, schema } from '@server/app/controller';
269
267
 
270
- export default class AuthController extends Controller<MyApp> {
271
- public async loginWithPassword() {
272
- const { Auth } = this.services;
273
- const data = this.input(
274
- schema.object({
268
+ export default defineController({
269
+ path: 'Auth',
270
+ actions: {
271
+ loginWithPassword: defineAction({
272
+ input: schema.object({
275
273
  email: schema.string().email(),
276
274
  password: schema.string().min(8),
277
- })
278
- );
279
-
280
- return Auth.loginWithPassword(data, this.request);
281
- }
282
- }
275
+ }),
276
+ handler: ({ input, services, request }) => {
277
+ return services.Auth.loginWithPassword(input, request);
278
+ },
279
+ }),
280
+ },
281
+ });
283
282
  ```
284
283
 
285
284
  Controller rules:
286
285
 
287
- - read request-scoped values from `this.request`
288
- - validate once with `this.input(schema)`
289
- - call business logic through `this.services`, `this.models`, or `this.app`
286
+ - read request-scoped values from action context
287
+ - declare validation once with `defineAction({ input, handler })`
288
+ - call business logic through `services`, `models`, or `app`
290
289
  - return explicit values instead of relying on ambient globals
291
290
 
292
291
  ## Example: Command
@@ -386,6 +385,7 @@ Proteum ships with a compact CLI focused on the real app lifecycle:
386
385
  | `proteum init` | Scaffold a new Proteum app with built-in deterministic templates |
387
386
  | `proteum configure agents` | Interactively configure tracked Proteum instruction files for standalone or monorepo apps |
388
387
  | `proteum create` | Scaffold a page, controller, command, route, or root service inside an app |
388
+ | `proteum worktree` | Create or initialize Codex worktrees with a machine-readable bootstrap marker |
389
389
 
390
390
  Recommended daily workflow:
391
391
 
@@ -439,6 +439,8 @@ Useful scaffolding commands:
439
439
  proteum init my-app --name "My App"
440
440
  proteum init my-app --name "My App" --dry-run --json
441
441
  proteum configure agents
442
+ proteum worktree init --source /path/to/main-app
443
+ proteum worktree create /path/to/.codex/worktrees/feature --source /path/to/main-app --branch feature/name
442
444
  proteum create page marketing/faq --route /faq
443
445
  proteum create controller Founder/projects --method list
444
446
  proteum create service Conversion/Plans
@@ -448,6 +450,8 @@ proteum create service Conversion/Plans
448
450
 
449
451
  Every `proteum dev` start runs the same idempotent instruction check. It updates missing or stale managed sections automatically and prompts only when a blocked path would need to be replaced.
450
452
 
453
+ `proteum worktree init` writes `.proteum/worktree-bootstrap.json` for app roots under `/.codex/worktrees/`. The marker records `.env` copy status, refresh and dependency results, runtime status, key file hashes, and the active Proteum version. `proteum dev`, `proteum refresh`, `proteum runtime status`, `proteum verify`, and MCP `workflow_start` block inside Codex worktrees until the marker is fresh. Run `npx proteum worktree init --source <source-app-root>` for a new worktree, or add `--refresh` when stale state is reported. `PROTEUM_ALLOW_UNBOOTSTRAPPED_WORKTREE=1` bypasses the block but remains visible in runtime status, doctor, and MCP output.
454
+
451
455
  `proteum connect`, `proteum explain`, `proteum doctor`, and `proteum diagnose` share the same generated manifest and contract state. `proteum perf` uses the same dev request-trace store as the profiler `Perf` tab. `proteum runtime status` also inspects the configured router/HMR ports and returns an exact Start Dev action, so agents do not need to `curl` page routes to identify port owners. `proteum dev` exposes the app-root MCP contract at `/__proteum/mcp` and ensures one managed machine MCP daemon is running; `proteum mcp` is the machine-scope router agents register once. Agents should start with MCP `workflow_start`, use offline candidates to choose the correct app root when no dev server is live, then route repeated reads by the returned live `projectId`. For the full diagnostics and tracing model, see [docs/diagnostics.md](docs/diagnostics.md), [docs/mcp.md](docs/mcp.md), and [docs/request-tracing.md](docs/request-tracing.md).
452
456
 
453
457
  ## Dev Commands
@@ -573,13 +577,14 @@ If you are an LLM or automation agent, start here:
573
577
 
574
578
  1. Use `proteum mcp` as the one registered MCP server; `proteum dev` ensures the managed machine daemon is running.
575
579
  2. Call MCP `workflow_start` with `cwd` or a known `projectId`; if it is ambiguous or returns offline app candidates, use `project_resolve { cwd }`, choose the intended app root, follow its port-inspected next action when needed, then retry `workflow_start`.
576
- 3. Use the returned live `projectId` with MCP `runtime_status`, `orient`, `instructions_resolve`, `route_candidates`, `explain_summary`, `diagnose`, `trace_show`, `perf_request`, and `logs_tail` before CLI equivalents for repeated read-only app state.
577
- 4. Treat returned instruction previews as the allowed scope for read-only discovery and diagnostics. Read full file contents only before edits or git writes, when `fullRead`/`fullReadPolicy` requires it, or when compact previews are insufficient.
578
- 5. Use compact CLI commands for fallback, `dev`, `build`, `check`, `verify`, migrations, E2E, and final reproducible terminal evidence.
579
- 6. Use `proteum diagnose`, `proteum perf`, and compact `proteum trace` for reproducible command evidence when MCP is unavailable or the terminal output itself is needed.
580
- 7. If machine MCP routing fails, run `proteum mcp status` and `proteum runtime status` from the intended app root; if no live session exists, use the exact MCP offline or runtime-status next action. If the same app already responds on the configured port without live tracking, use or repair that runtime instead of starting another server. If a live session exists but runtime/MCP is unreachable, stop the listed session file first, then start dev again and retry `workflow_start`. Do not run diagnose, trace, or perf reads while runtime health is unreachable, and do not `curl` normal page routes to identify port ownership.
581
- 8. Inspect `server/index.ts`, controllers, services, or pages only after the routing/diagnostic surfaces identify the relevant owner. Do not run broad owner searches after MCP already returned the route/page/controller owner.
582
- 9. If the task touches a protected route or controller in dev and login UX is not the feature under test, use `proteum e2e --session-email <email> --session-role <role>` for Playwright suites or `proteum session <email> --role <role>` before direct HTTP calls.
580
+ 3. If the app root is inside `/.codex/worktrees/` and `workflow_start` or a guarded CLI command reports missing/stale bootstrap, run the returned `npx proteum worktree init --source <source-app-root>` command before runtime reads.
581
+ 4. Use the returned live `projectId` with MCP `runtime_status`, `orient`, `instructions_resolve`, `route_candidates`, `explain_summary`, `diagnose`, `trace_show`, `perf_request`, and `logs_tail` before CLI equivalents for repeated read-only app state.
582
+ 5. Treat returned instruction previews as the allowed scope for read-only discovery and diagnostics. Read full file contents only before edits or git writes, when `fullRead`/`fullReadPolicy` requires it, or when compact previews are insufficient.
583
+ 6. Use compact CLI commands for fallback, `dev`, `build`, `check`, `verify`, migrations, E2E, and final reproducible terminal evidence.
584
+ 7. Use `proteum diagnose`, `proteum perf`, and compact `proteum trace` for reproducible command evidence when MCP is unavailable or the terminal output itself is needed.
585
+ 8. If machine MCP routing fails, run `proteum mcp status` and `proteum runtime status` from the intended app root; if no live session exists, use the exact MCP offline or runtime-status next action. If the same app already responds on the configured port without live tracking, use or repair that runtime instead of starting another server. If a live session exists but runtime/MCP is unreachable, stop the listed session file first, then start dev again and retry `workflow_start`. Do not run diagnose, trace, or perf reads while runtime health is unreachable, and do not `curl` normal page routes to identify port ownership.
586
+ 9. Inspect `server/index.ts`, controllers, services, or pages only after the routing/diagnostic surfaces identify the relevant owner. Do not run broad owner searches after MCP already returned the route/page/controller owner.
587
+ 10. If the task touches a protected route or controller in dev and login UX is not the feature under test, use `proteum e2e --session-email <email> --session-role <role>` for Playwright suites or `proteum session <email> --role <role>` before direct HTTP calls.
583
588
 
584
589
  For implementation rules in a real Proteum app, treat the routed local `AGENTS.md` files plus `proteum orient`, compact CLI diagnostics, and MCP repeated-read surfaces as the task contract. This README is the framework overview, not the project-local instruction layer.
585
590
 
@@ -16,16 +16,14 @@ Managed compact root routers must use trigger -> canonical instruction file refe
16
16
  ## Fast Triggers
17
17
 
18
18
  - If `cwd` is inside `/.codex/worktrees/`, run Worktree Preflight before implementation:
19
- - Copy `.env` from the main worktree when missing.
20
- - Run `npx proteum refresh`.
21
- - Run `npm i` when dependencies are missing or stale.
19
+ - Run `npx proteum worktree init --source <source-app-root>` when the bootstrap marker is missing.
20
+ - Run `npx proteum worktree init --source <source-app-root> --refresh` when Proteum reports stale bootstrap state.
21
+ - Use `--skip-deps --reason "..."` only when dependency installation is intentionally skipped.
22
22
  - Run `npx proteum runtime status`.
23
23
  - For runtime-visible work, start or reuse one tracked `npx proteum dev` session using the Task Lifecycle launch workflow.
24
24
  - If you are working in a newly created Proteum worktree, before following the rest of these instructions:
25
- - Copy `.env` from the main worktree.
26
- - Run `npx proteum refresh`.
25
+ - Run `npx proteum worktree init --source <source-app-root>`.
27
26
  - Read and acknowledge the applicable `AGENTS.md` files.
28
- - Run `npm i`.
29
27
  - Run the dev server with the task-safe elevated-permissions launch workflow from `Task Lifecycle`, keep it running so user can see the results by himself, and print the live server URL as a clickable Markdown link.
30
28
  - If the user pastes raw errors without asking for a fix, do not implement changes yet. First run the task-safe local reproduction path: identify the likely app, route, command, or request from the error, boot or reuse the relevant dev server with the elevated-permissions workflow in `Task Lifecycle`, reproduce the failing surface locally, and inspect server output, browser console output, diagnostics, traces, or the smallest relevant command result. If the error does not identify enough context to reproduce, say what is missing and use the available local evidence before guessing. Then list likely causes and, for each one, give probability, why, and how to fix it. After this, every time you implement a fix:
31
29
  - test, re-run analysis and give a comparison table of before and after
@@ -36,6 +34,7 @@ Managed compact root routers must use trigger -> canonical instruction file refe
36
34
  - When a Proteum MCP client is available, first call MCP `workflow_start` with `cwd` or a known `projectId`. If it is ambiguous or returns offline app candidates, call `project_resolve { cwd }`, select the intended app root, start exactly one dev server from that app root when needed, then retry `workflow_start`. Pass the returned live `projectId` to every follow-up app-bound MCP tool. `npx proteum dev` ensures one managed machine MCP daemon is running; do not start a second managed daemon. Prefer MCP `runtime_status`, `orient`, `instructions_resolve`, `explain_summary`, `route_candidates`, `doctor`, `diagnose`, `trace_show`, `perf_request`, `logs_tail`, and `db_query` for read-only runtime/status/orientation/owner/route/trace/perf/log/database reads. Do not run CLI equivalents after a successful MCP result for the same read. Do not run broad source searches for route/page/controller ownership after MCP returns the owner. Use CLI commands when you need reproducible terminal validation, dev/build/check workflows, fallback repair, or output to share with a human.
37
35
  - MCP payloads are compact single-line `proteum-mcp-v1` JSON with capped and paginated detail. Do not expand MCP output for human readability.
38
36
  - For every non-trivial coding task, load and follow root-level `DOCUMENTATION.md` before coding.
37
+ - For bug fixes, regressions, incidents, broken public routes, auth/OAuth failures, integration failures, or production behavior fixes, load and follow root-level `DOCUMENTATION.md` before coding so the relevant fix note, regression-test docs, ADR, or explicit skip reason is handled in the same change.
39
38
  - If the user reports an issue, or the agent encounters one during exploration, implementation, verification, or runtime reproduction, load and follow root-level `diagnostics.md`.
40
39
  - If the task touches client-side files, especially `client/**` and page files, load and apply root-level `optimizations.md` only after implementation for post-implementation checking and optimization. Skip it at task start and skip it for server-only, test-only, doc-only, and non-client refactor tasks unless the user explicitly asks for optimization work.
41
40
  - If the task changes UX, copy, onboarding, pricing, product semantics, or commercial positioning, use root-level `DOCUMENTATION.md` to choose the smallest relevant `./docs/` pack before editing. If a dev server is already running, print the live dev server URL as a clickable Markdown link.
@@ -54,7 +53,7 @@ Managed compact root routers must use trigger -> canonical instruction file refe
54
53
 
55
54
  [optional body]
56
55
  ```
57
- Then treat `commit` as conversation-wide and cross-project, not task-scoped. Identify every affected git repository or worktree touched during that span, stage all conversation-related changed files in each affected repository or worktree with `git add` while still avoiding unrelated pre-existing user changes or incidental untracked files, and create one `git commit` per affected repository or worktree. Do not omit linked local dependencies, framework repos, connected projects, or producer apps when they were changed to make the delivered behavior actually work. Do not stop at only suggesting the message.
56
+ Then treat `commit` as conversation-wide and cross-project, not task-scoped. Before staging or committing, run the repository's non-coverage commit gate when it defines one, such as `npm run check:commit`; otherwise run targeted lint, typecheck, and test commands. Report any blocker instead of committing through a failed commit gate. Identify every affected git repository or worktree touched during that span, stage all conversation-related changed files in each affected repository or worktree with `git add` while still avoiding unrelated pre-existing user changes or incidental untracked files, and create one `git commit` per affected repository or worktree. Do not omit linked local dependencies, framework repos, connected projects, or producer apps when they were changed to make the delivered behavior actually work. Do not stop at only suggesting the message.
58
57
  After providing a commit message or after creating a commit, immediately follow it with this exact prompt and obey it:
59
58
  `Explain in short minimalistic and few bullet points what we changed in this thread, like you would do to your grandma. Start with a verb in the past.`
60
59
 
@@ -80,20 +79,21 @@ Managed compact root routers must use trigger -> canonical instruction file refe
80
79
  ### Before Finishing
81
80
 
82
81
  - Before finishing, re-check touched files against root-level `CODING_STYLE.md` and any narrower area `AGENTS.md` that applied to the edit. Re-check against root-level `optimizations.md` only for touched client-side files. Re-check against root-level `diagnostics.md` only if the task involved an issue, diagnosis, runtime reproduction, or verification failure.
83
- - Run the full project `npx proteum check` before finishing each feature or change. Targeted lint, typecheck, diagnose, request, browser, or E2E runs are still useful while iterating, but they do not replace the final full check. After implementing a new feature or changing existing feature behavior, always update the end-to-end coverage for that behavior and run the full Playwright test suite before finishing. For docs-only, wording-only, type-only, test-only, generated-output cleanup, or clearly local non-runtime refactors, skip Playwright unless the user explicitly asks for it or verification reveals a real issue.
82
+ - Before finishing a production code change, re-check root-level `DOCUMENTATION.md` update rules. If behavior changed, a bug was fixed, a decision changed, or an important route, auth/OAuth, or integration issue was addressed, update the relevant docs before committing or explicitly explain why no docs update was needed.
83
+ - Run targeted tests and checks that match the changed surface before finishing each feature or change. Continue running tests after changes, but do not run coverage by default. Reserve the non-coverage commit gate for commit workflows, and reserve the full `npm run check` gate for push workflows, explicit user requests, or when project-local instructions require the full gate. After implementing a new feature or changing existing feature behavior, update the relevant end-to-end coverage and run the cheapest trustworthy Playwright or browser verification for that behavior before finishing. For docs-only, wording-only, type-only, generated-output cleanup, or clearly local non-runtime refactors, skip Playwright unless the user explicitly asks for it or verification reveals a real issue.
84
84
  - Before finishing a task, stop every `proteum dev` session started during the task and confirm cleanup with `npx proteum dev list --json` or an explicit `npx proteum dev stop --session-file <path>`.
85
85
  - When you have finished your work, ask the user whether they want a commit message. After providing a commit message or after creating a commit, immediately follow it with this exact prompt and obey it:
86
86
  `Explain in short minimalistic and few bullet points what we changed in this thread, like you would do to your grandma. Start with a verb in the past.`
87
87
 
88
88
  ## Core Contracts
89
89
 
90
- - Client pages live in `client/pages/**` and register routes with top-level `Router.page(...)` or `Router.error(...)`.
91
- - Page URLs come from the explicit `Router.page('/path', ...)` call, not from the file path.
92
- - Callable app APIs live only in `server/controllers/**/*.ts` files that extend `Controller`.
90
+ - Client pages live in `client/pages/**` and default-export `definePageRoute(...)` or `defineErrorRoute(...)`.
91
+ - Page URLs come from the explicit route definition `path`, not from the file path.
92
+ - Callable app APIs live only in `server/controllers/**/*.ts` files that default-export `defineController(...)`.
93
93
  - Dev-only internal execution lives only in `commands/**/*.ts` files that extend `Commands`.
94
94
  - Manual HTTP endpoints live only in `server/routes/**`.
95
- - Controllers call `this.input(schema)` inside the method body, at most once per method.
96
- - Request-scoped state lives only on `this.request` and manual-route/router context objects.
95
+ - Controllers declare input on `defineAction({ input, handler })`; handlers receive parsed `input` in context.
96
+ - Request-scoped state lives only on action handler context and manual-route handler context objects.
97
97
  - Keep one class or one React/Preact component per file.
98
98
  - Prefer a deep tree grouped by business concern instead of long file names.
99
99
  - Use the default `*.ts` or `*.tsx` file unless an `*.ssr.ts` or `*.ssr.tsx` variant is truly required.
@@ -106,14 +106,15 @@ Managed compact root routers must use trigger -> canonical instruction file refe
106
106
  - Do not import runtime values from `@models`.
107
107
  - Do not use `@request` runtime globals.
108
108
  - Do not use `@app` on the client.
109
+ - Do not import `@app` in route, page, or controller files. Runtime app/services/router access belongs in typed callback parameters.
109
110
  - Prefer type inference rooted in the explicit application graph in `server/index.ts`.
110
111
 
111
112
  ## Surface Contracts
112
113
 
113
114
  ### App Bootstrap And Services
114
115
 
115
- - `server/index.ts` default-exports the app `Application` subclass and is the canonical type root.
116
- - Root services are public class fields instantiated with `new ServiceClass(this, config, this)`.
116
+ - `server/index.ts` default-exports `defineApplication({ services, router, models, commands })` and is the canonical type root.
117
+ - Root services are declared in the explicit `services` graph and instantiated with `new ServiceClass(app, config, app)`.
117
118
  - Typed root-service config lives in `server/config/*.ts` via `Services.config(ServiceClass, { ... })`.
118
119
  - Router plugins are instantiated explicitly inside the `Router` config `plugins` object.
119
120
  - Router plugins can subscribe to `request` and `request.finished`; `request.profiling` exists before `request` runs and carries the finalized request/API/SQL snapshot by `request.finished`.
@@ -125,6 +126,51 @@ Managed compact root routers must use trigger -> canonical instruction file refe
125
126
  - Companion client-callable entrypoints live in `server/controllers/**`.
126
127
  - `proteum create service ...` scaffolds the service file, a typed config export under `server/config/*.ts`, and the root registration in `server/index.ts`; review and adapt the generated names before committing.
127
128
 
129
+ Example app root shape; replace names with the project app type and service names:
130
+
131
+ ```ts
132
+ import { defineApplication, type Application } from '@server/app';
133
+ import Router from '@server/services/router';
134
+ import SchemaRouter from '@server/services/schema/router';
135
+ import BillingService from '@/server/services/Billing';
136
+
137
+ import * as appConfig from '@/server/config/app';
138
+
139
+ type ProjectServices = {
140
+ Billing: BillingService;
141
+ };
142
+
143
+ type ProjectRouterPlugins = {
144
+ schema: SchemaRouter;
145
+ };
146
+
147
+ export type ProjectRouter = Router<ProjectApp, ProjectRouterPlugins>;
148
+ export interface ProjectApp extends Application, ProjectServices {
149
+ Router: ProjectRouter;
150
+ }
151
+
152
+ const createProjectRouter = (app: ProjectApp): ProjectRouter =>
153
+ new Router<ProjectApp, ProjectRouterPlugins>(
154
+ app,
155
+ {
156
+ ...appConfig.routerBaseConfig,
157
+ plugins: {
158
+ schema: new SchemaRouter({}, app),
159
+ },
160
+ },
161
+ app,
162
+ );
163
+
164
+ const ProjectApplication = defineApplication<ProjectServices, ProjectRouter>({
165
+ services: (app) => ({
166
+ Billing: new BillingService(app, {}, app),
167
+ }),
168
+ router: createProjectRouter,
169
+ });
170
+
171
+ export default ProjectApplication;
172
+ ```
173
+
128
174
  ### Connected Projects
129
175
 
130
176
  - Declare connected namespaces in `proteum.config.ts` with explicit values such as `connect: { Product: { source: PRODUCT_CONNECTED_SOURCE, urlInternal: PRODUCT_URL_INTERNAL } }`.
@@ -136,13 +182,27 @@ Managed compact root routers must use trigger -> canonical instruction file refe
136
182
 
137
183
  ### Controllers
138
184
 
139
- - Files live under `server/controllers/**/*.ts` and default-export a class extending `Controller`.
140
- - Methods with bodies become generated client-callable endpoints.
141
- - Route path comes from the controller file path plus the method name.
142
- - `export const controllerPath = 'Custom/path'` can override the base path.
185
+ - Files live under `server/controllers/**/*.ts` and default-export `defineController({ path, actions })`.
186
+ - Actions declared with `defineAction(...)` become generated client-callable endpoints.
187
+ - Route path comes from the controller `path` plus the action name.
188
+ - Set `path: 'Custom/path'` on `defineController(...)` to override the base path.
143
189
  - Generated client calls use `POST`.
144
190
  - Prefer `proteum create controller ...` for new controller boilerplate, then adapt the generated method to real service calls.
145
191
 
192
+ ```ts
193
+ import { defineAction, defineController, schema } from '@server/app/controller';
194
+
195
+ export default defineController({
196
+ path: 'Billing',
197
+ actions: {
198
+ read: defineAction({
199
+ input: schema.object({ accountId: schema.string() }),
200
+ handler: ({ input }) => ({ accountId: input.accountId }),
201
+ }),
202
+ },
203
+ });
204
+ ```
205
+
146
206
  ### Commands
147
207
 
148
208
  - Files live under `commands/**/*.ts` and default-export a class extending `Commands` from `@server/app/commands`.
@@ -155,25 +215,47 @@ Managed compact root routers must use trigger -> canonical instruction file refe
155
215
 
156
216
  ### Client Pages
157
217
 
158
- - Proteum scans page files for top-level `Router.page(...)` and `Router.error(...)` calls.
159
- - File path controls chunk identity and layout discovery; route path comes from the explicit `Router.page(...)` string.
160
- - The only supported page signature is `Router.page(path, options, data, render)`.
218
+ - Proteum scans page files for default-exported `definePageRoute(...)` and `defineErrorRoute(...)` definitions.
219
+ - File path controls chunk identity and layout discovery; route path comes from the explicit definition `path` value.
220
+ - The supported page shape is `definePageRoute({ path, options, data, render })`.
161
221
  - `options` is always required. `data` is the only nullable argument and must be `null` when the page has no SSR data loader.
162
222
  - `data` returns one flat object. Route-option keys such as `auth`, `layout`, `static`, and `_static` are forbidden in page data and must live in `options`.
163
223
  - Controller fetchers and promises returned from `data` resolve before render.
164
224
  - `render` consumes resolved page data and uses generated controller methods from render args or `@/client/context`.
165
225
  - Use `api.reload(...)` or `api.set(...)` only when intentionally mutating active page data state.
166
- - Error pages use `Router.error(code, options, render)` in `client/pages/_messages/**`.
226
+ - Error pages use `defineErrorRoute({ code, options, render })` in `client/pages/_messages/**`.
167
227
  - Prefer `proteum create page ...` for new page boilerplate, then review the explicit route path, options object, and data payload.
168
228
 
229
+ ```tsx
230
+ import { definePageRoute } from '@common/router/definitions';
231
+
232
+ export default definePageRoute({
233
+ path: '/billing',
234
+ options: { auth: true },
235
+ data: ({ BillingController }) => ({ billing: BillingController.read({ accountId: 'current' }) }),
236
+ render: ({ billing }) => <BillingPage billing={billing} />,
237
+ });
238
+ ```
239
+
169
240
  ### Manual Routes
170
241
 
171
242
  - Use `server/routes/**` only for explicit HTTP behavior that should not be a generated controller action.
172
243
  - Good fits include redirects, sitemap or RSS output, OAuth callbacks, webhooks, and public resources with custom semantics.
173
- - Import server-side app services from `@app` and use route handler context for `request`, `response`, router plugins, and custom router context.
244
+ - Receive app services through `defineServerRoutes((app) => [...])` and use handler context for `request`, `response`, router plugins, and custom router context.
174
245
  - If the route is a normal app API, prefer a controller.
175
246
  - Prefer `proteum create route ...` for new manual-route boilerplate.
176
247
 
248
+ ```ts
249
+ import { defineServerRoute } from '@common/router/definitions';
250
+
251
+ export default defineServerRoute({
252
+ method: 'GET',
253
+ path: '/health',
254
+ options: {},
255
+ handler: ({ response }) => response.json({ ok: true }),
256
+ });
257
+ ```
258
+
177
259
  ### Models And Aliases
178
260
 
179
261
  - Use Prisma typings from `@models/types`.
@@ -183,19 +265,18 @@ Managed compact root routers must use trigger -> canonical instruction file refe
183
265
  - Aliases:
184
266
  - `@/client/...`, `@/server/...`, `@/common/...`: app code
185
267
  - `@client/...`, `@server/...`, `@common/...`: Proteum core modules
186
- - `@app`: server-side application services for manual routes only
187
268
  - `@generated/*`: generated app surfaces
188
269
 
189
270
  ## Verification Matrix
190
271
 
191
272
  Verify at the correct layer:
192
273
 
193
- - Default: use the cheapest trustworthy verification for the changed surface first, then run the full project `npx proteum check` before finishing.
274
+ - Default: use the cheapest trustworthy verification for the changed surface, including targeted tests for changed behavior. Do not run coverage by default during ordinary change closeout.
194
275
  - Route additions: boot the app and hit the real URL.
195
276
  - Controller changes: exercise the generated client call or generated `/api/...` endpoint.
196
277
  - SSR changes: use the browser MCP to load the real page and inspect rendered HTML plus browser console.
197
278
  - Router or plugin changes: verify request context, auth, redirects, metrics, and validation on a running app.
198
- - New features or feature-behavior changes: use the cheapest trustworthy verification while iterating, use the browser MCP for browser-visible validation, then update the relevant end-to-end coverage and finish by running the full Playwright suite plus the full project `npx proteum check`.
279
+ - New features or feature-behavior changes: use the cheapest trustworthy verification while iterating, use the browser MCP for browser-visible validation, then update and run the relevant end-to-end coverage. Save the non-coverage commit gate for commit workflows and the full `npm run check` gate for push workflows unless the user or project-local instructions explicitly ask for the full gate earlier.
199
280
  - Generated, connected, or ownership-ambiguous changes: start with MCP `workflow_start`, then `orient { projectId, query }` and `explain_summary { projectId, query }` only when more detail is needed; use `npx proteum orient <query>` and `npx proteum verify owner <query>` when MCP is unavailable or terminal evidence is required.
200
281
  - Browser-visible issues: use the browser MCP after request-level verification is insufficient. Use `npx proteum e2e --port <port> ...` only when automated end-to-end coverage or a Playwright suite is required.
201
282
  - Raw browser execution outside end-to-end suites: use the browser MCP only. Keep Playwright in `npx proteum e2e --port <port>` for targeted/full end-to-end suites.
@@ -233,7 +314,7 @@ Verify at the correct layer:
233
314
  ### Discouraged Patterns
234
315
 
235
316
  - request-scoped state inside normal service methods
236
- - hiding route registration behind abstractions that remove the top-level `Router.page(...)` call
317
+ - hiding route definitions behind abstractions that remove the default-exported `definePageRoute(...)` or `defineServerRoute(...)` contract
237
318
  - editing `.proteum` directly
238
319
 
239
320
  ## Hard Stops
@@ -242,7 +323,7 @@ Verify at the correct layer:
242
323
  - For read-only SQL diagnosis, use MCP `db_query` or `npx proteum db query "<sql>"`; only one capped `SELECT`, `SHOW`, or `EXPLAIN` statement is allowed.
243
324
  - Do not run `prisma *` yourself. If a schema change requires migration, ask the user to run `npx prisma migrate dev --config ./prisma.config.ts --name <migration name>` and wait for `continue`.
244
325
  - Do not run `git restore` or `git reset`.
245
- - Do not run write-mode git commands by default. The built-in exception is an exact `commit` reply, which allows `git add` and `git commit` in every affected repository or worktree touched during the whole conversation. Any other write-mode git action requires an explicit user request.
326
+ - Do not run write-mode git commands by default. The built-in exception is an exact `commit` reply, which allows `git add` and `git commit` in every affected repository or worktree touched during the whole conversation after the repository's non-coverage commit gate passes when it defines one, such as `npm run check:commit`. Any other write-mode git action requires an explicit user request. Before any explicit push, run `npm run check` in every affected repository or worktree that defines it and report any blocker instead of pushing through a failed check.
246
327
 
247
328
  ## Appendix
248
329
 
@@ -337,10 +418,10 @@ Agents working in generated Proteum projects must use this delivery workflow for
337
418
  1. BDD / ATDD: translate the requested behavior into acceptance scenarios before changing implementation code.
338
419
  2. TDD: write or update the smallest failing unit/integration test that proves the next behavior.
339
420
  3. Implementation: make the narrowest production change that satisfies the failing test while preserving Proteum boundaries.
340
- 4. Proteum check: refresh and validate generated framework contracts after route, page, controller, service, command, or config changes.
421
+ 4. Targeted validation: refresh generated framework contracts after route, page, controller, service, command, or config changes, then run the targeted tests/checks that match the changed surface.
341
422
  5. Validate unit + E2E: run the relevant unit tests and real-world journey E2E checks before calling the work complete.
342
423
 
343
- Unit test expectation: production changes must always add or update focused unit tests and maintain 100% whole-project Vitest unit coverage. Before claiming implementation work complete, run `npx vitest run --coverage` from the repository root and make sure global statements, branches, functions, and lines all meet the configured 100% thresholds. MCP endpoint-reference coverage, touched-path-only coverage, and focused test passes are not substitutes for whole-project Vitest coverage. Any excluded generated files, migrations, framework shims, unreachable defensive branches, or changes that cannot reasonably be unit-tested must be documented in the completion note, and agents must not claim the project has full unit coverage when an exception remains.
424
+ Unit test expectation: production changes must always add or update focused unit tests and run the targeted unit or integration tests that match the changed behavior. Do not run coverage after every change by default. Reserve whole-project coverage for the repository's full `npm run check` gate during push workflows or when the user explicitly requests it; do not run coverage for commit-only workflows by default. Any excluded generated files, migrations, framework shims, unreachable defensive branches, or changes that cannot reasonably be unit-tested must be documented in the completion note.
344
425
 
345
426
  E2E expectation: real-world journeys must follow the project-local instructions in `tests/e2e/REAL_WORLD_JOURNEY_TESTS.md`. These tests should model complete user workflows, role transitions, permissions, state changes, and cross-view consistency rather than isolated happy paths.
346
427
 
@@ -8,7 +8,7 @@ This file is the source of truth for codex coding style instructions in Proteum-
8
8
  - Write clean, consistent, readable code with a tab size of 4.
9
9
  - Keep functions and methods short.
10
10
  - Every time possible, create reusable functions and components instead of repeating.
11
- - Before finishing a feature or change, review touched files against this document and run the full project `npx proteum check`; coding-style regressions are defects, not optional cleanup.
11
+ - Before finishing a feature or change, review touched files against this document and run targeted lint/typecheck/tests for the changed surface. Do not run coverage by default after ordinary changes. Run the repository's non-coverage commit gate before committing, and run the full `npm run check` gate before pushing or when the user explicitly asks for it; coding-style regressions are defects, not optional cleanup.
12
12
 
13
13
  ## Type safety
14
14
 
@@ -21,7 +21,7 @@ This file is the source of truth for codex coding style instructions in Proteum-
21
21
  - Keep short arrow functions and short returned object literals compact when they are easy to scan.
22
22
  - Keep JSX multiline only when it is clearly more readable; otherwise keep short JSX compact.
23
23
  - Avoid staircase formatting and unnecessary blank lines inside short callbacks.
24
- - Keep `Router.page(...)` and `Router.error(...)` registrations in the compact inline-call shape when possible, for example `Router.page('/path', {}, null, render);`.
24
+ - Keep route definition metadata compact when possible, for example `definePageRoute({ path: '/path', options: {}, data: null, render });`.
25
25
 
26
26
  ## File organization
27
27
 
@@ -8,9 +8,7 @@ Do not put here: reusable Proteum architecture contracts, shared verification ru
8
8
  ## App-Root Triggers
9
9
 
10
10
  - If you are working in a newly created Proteum worktree, before following the rest of these instructions:
11
- - Copy `.env` from the main worktree.
12
- - Run `npx proteum refresh`.
11
+ - Run `npx proteum worktree init --source <source-app-root>`.
13
12
  - Read and acknowledge the applicable `AGENTS.md` files.
14
- - Run `npm i`.
15
13
  - Run the dev server with the task-safe elevated-permissions launch workflow from the reusable root `AGENTS.md`, keep it running so user can see the results by himself, and print the live server URL as a clickable Markdown link. If `proteum dev` reports blocked instruction paths, resolve them before continuing.
16
14
  - If the task changes UX, copy, onboarding, pricing, product semantics, or commercial positioning, use root-level `DOCUMENTATION.md` to choose the smallest relevant `./docs/` pack before editing. If a dev server is already running, print the live dev server URL as a clickable Markdown link.
@@ -25,7 +25,7 @@ Coding style source of truth: root-level `CODING_STYLE.md`.
25
25
  - Never depend on legacy `@app` imports on the client.
26
26
  - Errors from controller calls should never be silently swallowed. Rethrow or surface them clearly.
27
27
  - Caught frontend errors must always preserve the original failure. Never write `catch {}`, `.catch(() => ...)`, or a catch handler that only shows a generic toast/state without using the caught error.
28
- - Valid frontend error handling includes rethrowing the error, passing it to `Router.app.handleError(error)`, logging/reporting it with the original error, or surfacing original detail such as `error.message` in user-visible feedback.
28
+ - Valid frontend error handling includes rethrowing the error, passing it to `useContext().app.handleError(error)` or `context.app.handleError(error)`, logging/reporting it with the original error, or surfacing original detail such as `error.message` in user-visible feedback.
29
29
 
30
30
  ## Design
31
31
 
@@ -2,27 +2,39 @@
2
2
 
3
3
  This is the canonical page-file contract for Proteum-based projects.
4
4
  Role: keep only page-file rules here.
5
- Keep here: `Router.page(...)` registration, SSR `data` and `render` contracts, page payload shape, and page-local typing rules.
5
+ Keep here: `definePageRoute(...)` and `defineErrorRoute(...)`, SSR `data` and `render` contracts, page payload shape, and page-local typing rules.
6
6
  Do not put here: generic component rules, server/service implementation details, or app-wide workflow already covered by broader AGENTS files.
7
7
 
8
8
  Optimization source of truth: root-level `optimizations.md`.
9
9
  Diagnostics source of truth: root-level `diagnostics.md`.
10
10
  Coding style source of truth: root-level `CODING_STYLE.md`.
11
11
 
12
- ## Router.page Usage
12
+ ## Page Definition Usage
13
13
 
14
- - Proteum scans page files for top-level `Router.page(...)` and `Router.error(...)` calls.
15
- - File path controls chunk identity and layout discovery; route path comes from the explicit `Router.page(...)` string.
16
- - The only supported page signature is `Router.page(path, options, data, render)`.
14
+ - Proteum page files default-export `definePageRoute({ path, options, data, render })` or `defineErrorRoute({ code, options, render })`.
15
+ - File path controls chunk identity and layout discovery; route URL comes from the explicit `path` value.
17
16
  - `options` is always required and must be an object.
18
- - `data` is the only nullable argument. Pass `null` when the page does not need SSR data.
19
- - Keep the `Router.page(...)` call compact instead of exploding each outer argument onto its own line.
20
- - Keep route registration at top level. Do not hide it behind helper abstractions.
17
+ - `data` is the only nullable route field. Pass `null` when the page does not need SSR data.
18
+ - Keep route metadata static and serializable. Runtime app/client references belong only inside `data` and `render`.
19
+ - Do not import `@app`, `@/client/router`, or `@client/router` in page files.
20
+
21
+ ```tsx
22
+ import { definePageRoute } from '@common/router/definitions';
23
+
24
+ export default definePageRoute({
25
+ path: '/dashboard',
26
+ options: { auth: true },
27
+ data: ({ AccountController }) => ({
28
+ account: AccountController.accountPage(),
29
+ }),
30
+ render: ({ account }) => <Dashboard account={account} />,
31
+ });
32
+ ```
21
33
 
22
34
  ## Data And Render
23
35
 
24
36
  - Route behavior belongs in the explicit `options` object, not in page data.
25
- - `data` returns one flat object or `null` is passed as the third argument when no page data is needed.
37
+ - `data` returns one flat object, or the route definition sets `data: null` when no page data is needed.
26
38
  - Returning route-option keys such as `auth`, `layout`, `static`, `redirectLogged`, or their `_`-prefixed variants from `data` is a contract error.
27
39
  - Controller fetchers and promises returned from `data` resolve before render.
28
40
  - If a page needs route data, return it from `data` and read it in `render`.