caspian-utils 0.0.24 → 0.0.26

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.
@@ -53,13 +53,17 @@ Use prompts like these to check whether AI lands on the correct docs and files.
53
53
  | Prompt | First docs AI should read | Controlling files AI should reach | Verification focus |
54
54
  | --- | --- | --- | --- |
55
55
  | Create a protected dashboard section with child routes and a shared shell. | [index.md](./index.md), [routing.md](./routing.md), [auth.md](./auth.md), [project-structure.md](./project-structure.md) | `src/app/**`, `src/lib/auth/auth_config.py`, `main.py`, `.venv/Lib/site-packages/casp/layout.py` | section layout ownership, route privacy mode, and child-route wrapping |
56
+ | Make a grouped shell keep sidebar scroll while resetting page content on child-route navigation. | [index.md](./index.md), [routing.md](./routing.md), [pulsepoint.md](./pulsepoint.md), [core-runtime-map.md](./core-runtime-map.md) | `src/app/**/layout.html`, `public/js/pp-reactive-v2.js`, `main.py` | `pp-reset-scroll` placement, push-vs-history scroll behavior, and shared-shell ownership |
56
57
  | Create a new contact page with interactive form behavior. | [index.md](./index.md), [routing.md](./routing.md), [pulsepoint.md](./pulsepoint.md), [components.md](./components.md) | `src/app/**/index.html`, `main.py`, `.venv/Lib/site-packages/casp/components_compiler.py`, `.venv/Lib/site-packages/casp/scripts_type.py` | single-root template shape, script-inside-root authoring, and authored-vs-runtime boundaries |
57
58
  | Add a file manager page with upload progress and persisted metadata. | [index.md](./index.md), [file-uploads.md](./file-uploads.md), [fetch-data.md](./fetch-data.md), [database.md](./database.md) | `src/app/**/index.html`, `src/app/**/index.py`, `src/lib/**`, `prisma/schema.prisma` when Prisma applies | route-owned upload actions, persisted metadata flow, and Prisma-backed storage boundaries |
58
59
  | Explain why authored Caspian templates use a plain `<script>` instead of `type="text/pp"`. | [index.md](./index.md), [pulsepoint.md](./pulsepoint.md), [components.md](./components.md), [routing.md](./routing.md) | `main.py`, `.venv/Lib/site-packages/casp/scripts_type.py`, `.venv/Lib/site-packages/casp/components_compiler.py` | script rewriting, `pp-component` injection, and authored-vs-runtime boundaries |
59
60
  | Debug why `StateManager` does not persist across a full redirect. | [index.md](./index.md), [state.md](./state.md), [auth.md](./auth.md), [core-runtime-map.md](./core-runtime-map.md) | `main.py`, `.venv/Lib/site-packages/casp/state_manager.py` | wire vs non-wire reset behavior and `request.state.session` dependency |
60
- | Trace the auth cookie and CSRF cookie names used in development. | [index.md](./index.md), [auth.md](./auth.md), [core-runtime-map.md](./core-runtime-map.md) | `main.py`, `.venv/Lib/site-packages/casp/auth.py` | development cookie scoping and CSRF or session naming ownership |
61
- | Find how route params and query params reach `page()`. | [index.md](./index.md), [routing.md](./routing.md), [core-runtime-map.md](./core-runtime-map.md) | `main.py`, `.venv/Lib/site-packages/casp/layout.py` | path-dict delivery, query coercion, and `request` injection |
62
- | Decide whether a dashboard child route should use page caching. | [index.md](./index.md), [cache.md](./cache.md), [routing.md](./routing.md), [fetch-data.md](./fetch-data.md) | `main.py`, `.venv/Lib/site-packages/casp/cache_handler.py`, the route's `index.py` | route-level cache ownership, cacheable HTML scope, and invalidation points |
61
+ | Trace the auth cookie and CSRF cookie names used in development. | [index.md](./index.md), [auth.md](./auth.md), [core-runtime-map.md](./core-runtime-map.md) | `main.py`, `.venv/Lib/site-packages/casp/auth.py` | development cookie scoping and CSRF or session naming ownership |
62
+ | Find how route params and query params reach `page()`. | [index.md](./index.md), [routing.md](./routing.md), [core-runtime-map.md](./core-runtime-map.md) | `main.py`, `.venv/Lib/site-packages/casp/layout.py` | path-dict delivery, query coercion, and `request` injection |
63
+ | Decide whether a dashboard child route should use page caching. | [index.md](./index.md), [cache.md](./cache.md), [routing.md](./routing.md), [fetch-data.md](./fetch-data.md) | `main.py`, `.venv/Lib/site-packages/casp/cache_handler.py`, the route's `index.py` | route-level cache ownership, cacheable HTML scope, and invalidation points |
64
+ | Add a PulsePoint context provider to a reusable component. | [index.md](./index.md), [pulsepoint-runtime-map.md](./pulsepoint-runtime-map.md), [pulsepoint.md](./pulsepoint.md), [components.md](./components.md) | `public/js/pp-reactive-v2.js`, component `.html`, `.venv/Lib/site-packages/casp/components_compiler.py` | `Context.Provider` usage, logical ancestry, single-root template shape |
65
+ | Add upload progress to an existing file manager. | [index.md](./index.md), [pulsepoint-runtime-map.md](./pulsepoint-runtime-map.md), [file-uploads.md](./file-uploads.md), [fetch-data.md](./fetch-data.md) | `src/app/**/index.py`, `src/app/**/index.html`, `src/lib/**`, `public/js/pp-reactive-v2.js` | `pp.rpc` upload options, state replacement, persisted metadata, BrowserSync ignore rules |
66
+ | Decide whether MCP files should be created. | [index.md](./index.md), [mcp.md](./mcp.md), [commands.md](./commands.md), [project-structure.md](./project-structure.md) | `caspian.config.json`, `settings/restart-mcp.ts`, `package.json`, `src/lib/mcp/**` when enabled | `mcp` feature gate, update workflow, nested FastMCP config ownership |
63
67
 
64
68
  Treat the table as a prompt pack for spot checks, not as a full validation matrix.
65
69
 
@@ -70,6 +74,7 @@ Treat the table as a prompt pack for spot checks, not as a full validation matri
70
74
  - AI edits framework internals when the task only requires app-owned route or helper changes.
71
75
  - AI treats runtime HTML examples as authored template examples.
72
76
  - AI generates a route or component template with a valid-looking root element but leaves a sibling top-level `<script>` or second top-level element after it.
77
+ - AI puts `pp-reset-scroll="true"` on the whole shell or `body` when only the page-content pane should reset, causing persistent sidebars or rails to lose their scroll position.
73
78
  - AI decides behavior from memory without checking the owning implementation details.
74
79
 
75
80
  ## Decision Rule
@@ -26,11 +26,18 @@ Import the API like this:
26
26
  from casp.cache_handler import Cache, CacheHandler
27
27
  ```
28
28
 
29
- The current installed implementation lives in `.venv/Lib/site-packages/casp/cache_handler.py`.
30
-
31
- Use [core-runtime-map.md](./core-runtime-map.md) when a cache task crosses `main.py` request flow, cache lookup timing, and the installed cache-handler internals.
32
-
33
- The real API surface is:
29
+ The current installed implementation lives in `.venv/Lib/site-packages/casp/cache_handler.py`.
30
+
31
+ Use [core-runtime-map.md](./core-runtime-map.md) when a cache task crosses `main.py` request flow, cache lookup timing, and the installed cache-handler internals.
32
+
33
+ ## Source Of Truth
34
+
35
+ - Route cache intent belongs in `src/app/**/index.py` through module-level `cache_settings = Cache(...)`.
36
+ - Cache lookup and save timing are controlled by `main.py`.
37
+ - Disk-backed cache behavior lives in `.venv/Lib/site-packages/casp/cache_handler.py`.
38
+ - Cache invalidation after writes usually belongs in the owning route `@rpc()` action or a shared helper under `src/lib/**`.
39
+
40
+ The real API surface is:
34
41
 
35
42
  - declarative route config with `Cache(ttl=..., enabled=...)`
36
43
  - disk-backed HTML lookup with `CacheHandler.serve_cache(...)`
@@ -7,9 +7,10 @@ related:
7
7
  links:
8
8
  - /docs/project-structure
9
9
  - /docs/core-runtime-map
10
- - /docs/routing
11
- - /docs/pulsepoint
12
- - /docs/fetch-data
10
+ - /docs/routing
11
+ - /docs/pulsepoint
12
+ - /docs/pulsepoint-runtime-map
13
+ - /docs/fetch-data
13
14
  - /docs/index
14
15
  ---
15
16
 
@@ -39,7 +40,7 @@ When the task is about component internals rather than normal app-owned componen
39
40
  - `.venv/Lib/site-packages/casp/html_attrs.py` owns `get_attributes(...)` and the Python-side `merge_classes(...)` contract.
40
41
  - `.venv/Lib/site-packages/casp/syntax_compiler.py` owns Caspian template syntax transpilation before Jinja render.
41
42
 
42
- Use [core-runtime-map.md](./core-runtime-map.md) when you need the broader runtime-module map.
43
+ Use [core-runtime-map.md](./core-runtime-map.md) when you need the broader Python runtime-module map. Use [pulsepoint-runtime-map.md](./pulsepoint-runtime-map.md) when a component task is specifically about browser-side PulsePoint state, refs, context, portals, events, RPC, or SPA behavior.
43
44
 
44
45
  ## Basic Component
45
46
 
@@ -8,9 +8,10 @@ related:
8
8
  - /docs/project-structure
9
9
  - /docs/routing
10
10
  - /docs/auth
11
- - /docs/fetch-data
12
- - /docs/pulsepoint
13
- - /docs/index
11
+ - /docs/fetch-data
12
+ - /docs/pulsepoint
13
+ - /docs/pulsepoint-runtime-map
14
+ - /docs/index
14
15
  ---
15
16
 
16
17
  This page maps the app entry point and the installed Caspian runtime modules to the packaged docs that explain them.
@@ -24,19 +25,60 @@ Use it when you already know a behavior is controlled by `main.py` or `.venv/Lib
24
25
  - the task is about framework internals rather than normal app-owned route or component code
25
26
  - AI needs to know which packaged doc should be kept aligned with a core-file change
26
27
 
27
- ## App Entry Point
28
+ ## App Entry Point
28
29
 
29
30
  | Concern | Core file | Read first | Why it matters |
30
31
  | --- | --- | --- | --- |
31
32
  | App bootstrap and request flow | [main.py](../../../../main.py) | [project-structure.md](./project-structure.md), [routing.md](./routing.md), [auth.md](./auth.md) | FastAPI app creation, static asset routes, middleware order, route registration, cache check and save, exception handlers, and final HTML transforms all live here. |
32
-
33
- Important current `main.py` behaviors AI should keep in mind:
33
+ | Browser runtime, SPA navigation, and scroll restoration | [public/js/pp-reactive-v2.js](../../../../public/js/pp-reactive-v2.js) | [pulsepoint.md](./pulsepoint.md), [fetch-data.md](./fetch-data.md) | The shipped `pp` runtime, same-origin SPA interception, per-history-entry scroll state, `pp-reset-scroll` behavior, and browser RPC helpers live here. |
34
+
35
+ Important current `main.py` behaviors AI should keep in mind:
34
36
 
35
37
  - In development, `_scoped_cookie_name(...)` appends the active BrowserSync or dev port to both the session cookie name and the CSRF cookie name. The scope is resolved from `CASPIAN_BROWSER_SYNC_PORT`, then `settings/bs-config.json`, then `PORT`.
36
38
  - `register_single_route(...)` passes path params to `page()` as one positional dict, injects matching query params by name, and injects `request` by keyword when declared.
37
39
  - The render pipeline is `transform_components(...)`, then `render_with_nested_layouts(...)`, then `transform_scripts(...)`.
38
40
  - Route-level generators returned from `page()` are wrapped in `SSE(...)` before the response is sent.
39
41
  - Middleware is added in source order as `RPCMiddleware`, `AuthMiddleware`, `CSRFMiddleware`, `SessionMiddleware`, so the effective request order is reversed at runtime.
42
+ - `public/js/pp-reactive-v2.js` saves scroll positions per history entry, resets window scroll on push navigation, and uses `pp-reset-scroll="true"` to opt specific containers or the whole body into reset behavior.
43
+
44
+ ## Caspian Core Feature Map
45
+
46
+ Use this table when the task names a framework feature but the owning file is not obvious yet.
47
+
48
+ | Core feature | App-owned entry points | Runtime owner | Packaged docs |
49
+ | --- | --- | --- | --- |
50
+ | Feature flags and generated surface area | `caspian.config.json` | `casp.caspian_config` | [commands.md](./commands.md), [project-structure.md](./project-structure.md) |
51
+ | File-based routing | `src/app/**/index.html`, `src/app/**/index.py` | `main.py`, `casp.layout`, `casp.caspian_config` | [routing.md](./routing.md) |
52
+ | Nested layouts | `src/app/**/layout.html`, `src/app/**/layout.py` | `casp.layout`, `main.py` | [routing.md](./routing.md), [metadata.md](./metadata.md) |
53
+ | Metadata | route or layout `metadata`, runtime metadata helpers | `casp.layout`, `main.py` | [metadata.md](./metadata.md), [routing.md](./routing.md) |
54
+ | Component imports and `x-*` tags | `src/components/**`, `src/app/**/*.html` | `casp.components_compiler`, `casp.component_decorator` | [components.md](./components.md), [routing.md](./routing.md) |
55
+ | Auth and route protection | `src/lib/auth/auth_config.py`, `main.py`, route decorators | `casp.auth`, `main.py` middleware | [auth.md](./auth.md) |
56
+ | RPC and server actions | route or component Python modules with `@rpc()` | `casp.rpc`, `main.py` middleware | [fetch-data.md](./fetch-data.md), [file-uploads.md](./file-uploads.md) |
57
+ | Streaming | route `page()` generators, RPC generators | `casp.streaming`, `casp.rpc`, `main.py` | [fetch-data.md](./fetch-data.md) |
58
+ | Server state | request handlers and RPC actions | `casp.state_manager`, `main.py` middleware | [state.md](./state.md) |
59
+ | Page caching | route-level `Cache(...)` declarations | `casp.cache_handler`, `main.py` cache check/save | [cache.md](./cache.md) |
60
+ | Validation | route and RPC input boundaries | `casp.validate` | [validation.md](./validation.md) |
61
+ | Tailwind class merge | Python components and PulsePoint templates | `casp.html_attrs`, browser `twMerge(...)` | [components.md](./components.md), [pulsepoint.md](./pulsepoint.md) |
62
+ | Prisma persistence | `prisma/**`, `src/lib/prisma/**`, route/RPC code | generated Prisma and Python clients | [database.md](./database.md), [fetch-data.md](./fetch-data.md) |
63
+ | MCP tools | `src/lib/mcp/**` when enabled | app-owned FastMCP server | [mcp.md](./mcp.md), [commands.md](./commands.md) |
64
+
65
+ For browser-side PulsePoint details, use [pulsepoint-runtime-map.md](./pulsepoint-runtime-map.md) instead of expanding this Python-runtime map.
66
+
67
+ ## Task-To-File Examples
68
+
69
+ Protected dashboard route:
70
+
71
+ 1. Check `caspian.config.json` for enabled features such as Prisma and Tailwind.
72
+ 2. Read [routing.md](./routing.md) for the section layout shape.
73
+ 3. Read [auth.md](./auth.md) for route privacy and decorators.
74
+ 4. Update `src/app/dashboard/layout.html` for the shared shell and child `index.html` or `index.py` files for page-specific behavior.
75
+ 5. Verify auth bootstrap and middleware ownership in `main.py` only if route protection behaves unexpectedly.
76
+
77
+ Interactive CRUD page:
78
+
79
+ 1. Read [fetch-data.md](./fetch-data.md) for the `page()` plus `@rpc()` split.
80
+ 2. Read [pulsepoint-runtime-map.md](./pulsepoint-runtime-map.md) for browser-side `pp.rpc(...)` behavior.
81
+ 3. Keep first-render data in `src/app/**/index.py`, visible markup in `src/app/**/index.html`, reusable helpers in `src/lib/**`, and database schema changes in `prisma/**`.
40
82
 
41
83
  ## Installed Runtime Map
42
84
 
@@ -65,6 +107,7 @@ Use these behavior checkpoints when AI needs the fastest verification path for a
65
107
  | Runtime area | Verify these behaviors |
66
108
  | --- | --- |
67
109
  | `main.py` routing and request flow | route registration, path and query injection, static asset handling, and exception rendering |
110
+ | `public/js/pp-reactive-v2.js` browser runtime | SPA interception, history-vs-push scroll behavior, `pp-reset-scroll` semantics, and browser-side `pp.rpc()` behavior |
68
111
  | `casp.auth` | auth settings, signin and signout flow, provider wiring, and page protection behavior |
69
112
  | `casp.rpc` and streamed RPC responses | middleware interception, CSRF and session expectations, registry behavior, and helper-level RPC contracts |
70
113
  | `casp.layout` | layout discovery, metadata merge, root handling, and layout rendering rules |
@@ -12,9 +12,10 @@ related:
12
12
  - /docs/database
13
13
  - /docs/file-uploads
14
14
  - /docs/cache
15
- - /docs/routing
16
- - /docs/pulsepoint
17
- - /docs/project-structure
15
+ - /docs/routing
16
+ - /docs/pulsepoint
17
+ - /docs/pulsepoint-runtime-map
18
+ - /docs/project-structure
18
19
  - /docs/index
19
20
  ---
20
21
 
@@ -139,10 +140,11 @@ Validate incoming form and mutation payloads before persisting them. See [valida
139
140
 
140
141
  If an RPC action needs transient request-scoped success or error state beyond its direct return payload, read [state.md](./state.md) and verify the current wire-request lifecycle before depending on persistence across navigations or full-page reloads.
141
142
 
142
- Important:
143
-
144
- - `pp.rpc()` posts to the current route RPC bridge.
145
- - Older docs may refer to `pp.fetchFunction()`. In this repo's current runtime, the supported helper is `pp.rpc()`.
143
+ Important:
144
+
145
+ - `pp.rpc()` posts to the current route RPC bridge.
146
+ - Older docs may refer to `pp.fetchFunction()`. In this repo's current runtime, the supported helper is `pp.rpc()`.
147
+ - Use [pulsepoint-runtime-map.md](./pulsepoint-runtime-map.md) when debugging browser-side RPC options such as streaming, upload progress, abort behavior, redirects, or SPA interaction.
146
148
 
147
149
  ## Streaming Responses
148
150
 
@@ -16,11 +16,20 @@ related:
16
16
 
17
17
  This page documents the recommended file upload and file manager pattern for Caspian projects.
18
18
 
19
- Treat uploads as normal route behavior. Keep the owning browser UI in the route template, keep upload and delete `@rpc()` actions in the owning route `index.py`, and move reusable storage or persistence helpers into `src/lib/`.
20
-
21
- If the file manager lives inside a grouped subtree such as a dashboard, account area, or admin area, apply the section layout pattern from [routing.md](./routing.md): keep the shared shell in the parent folder's `layout.html` and keep the file-manager route itself in a child folder.
22
-
23
- ## Default Pattern
19
+ Treat uploads as normal route behavior. Keep the owning browser UI in the route template, keep upload and delete `@rpc()` actions in the owning route `index.py`, and move reusable storage or persistence helpers into `src/lib/`.
20
+
21
+ If the file manager lives inside a grouped subtree such as a dashboard, account area, or admin area, apply the section layout pattern from [routing.md](./routing.md): keep the shared shell in the parent folder's `layout.html` and keep the file-manager route itself in a child folder.
22
+
23
+ ## Source Of Truth
24
+
25
+ - File picker UI and upload progress state belong in `src/app/**/index.html`.
26
+ - Upload, delete, and list refresh actions belong in the owning `src/app/**/index.py` as `@rpc()` actions.
27
+ - Reusable storage, naming, and persistence helpers belong in `src/lib/**`.
28
+ - Durable metadata belongs in Prisma when `caspian.config.json` enables Prisma.
29
+ - Browser-side progress, state replacement, and `pp-for` list rendering follow [pulsepoint-runtime-map.md](./pulsepoint-runtime-map.md).
30
+ - BrowserSync upload ignore behavior belongs in `settings/bs-config.ts`.
31
+
32
+ ## Default Pattern
24
33
 
25
34
  - Keep first-render file manager data in `page()` so the initial HTML already contains the current asset list and storage summary.
26
35
  - Keep upload and delete actions in the route's `index.py`; do not move ordinary upload flows into `main.py`.
@@ -8,8 +8,9 @@ related:
8
8
  - /docs/ai-validation-checklist
9
9
  - /docs/installation
10
10
  - /docs/commands
11
- - /docs/core-runtime-map
12
- - /docs/mcp
11
+ - /docs/core-runtime-map
12
+ - /docs/pulsepoint-runtime-map
13
+ - /docs/mcp
13
14
  - /docs/file-uploads
14
15
  - /docs/project-structure
15
16
  - /docs/components
@@ -23,15 +24,41 @@ The docs can mention optional features even when those features are disabled in
23
24
 
24
25
  Before making feature, tooling, or file-placement decisions in a Caspian project, read `./caspian.config.json` almost immediately. That file tells you which optional capabilities are enabled, such as Prisma, MCP, TypeScript, Tailwind, backend-only mode, and component scan directories.
25
26
 
26
- ## Default Stack
27
-
28
- When generating or editing a Caspian app, treat these as the default choices unless the task explicitly requires something else:
27
+ ## Default Stack
28
+
29
+ When generating or editing a Caspian app, treat these as the default choices unless the task explicitly requires something else:
29
30
 
30
31
  - Use PulsePoint for reactive frontend behavior.
31
32
  - Treat every authored route, layout, and component HTML file like a React component return value: exactly one top-level parent HTML element or one imported `x-*` root, with any owned plain `<script>` kept inside that same root.
32
33
  - When `caspian.config.json` has `tailwindcss: true`, use Python `merge_classes(...)` plus browser `twMerge(...)` as the only supported Tailwind class-merging path.
33
- - Use `@rpc()` plus `pp.rpc()` for browser-triggered reads, writes, streaming, and uploads.
34
- - Use `Validate` and `Rule` from `casp.validate` for server-side input validation and sanitization.
34
+ - Use `@rpc()` plus `pp.rpc()` for browser-triggered reads, writes, streaming, and uploads.
35
+ - Use `Validate` and `Rule` from `casp.validate` for server-side input validation and sanitization.
36
+
37
+ ## AI Doc Shape
38
+
39
+ Each packaged feature doc should help AI answer the same five questions quickly:
40
+
41
+ - When does this doc apply?
42
+ - Which `caspian.config.json` flag, if any, gates the feature?
43
+ - Which app-owned files usually change?
44
+ - Which `main.py` or installed `casp` runtime files own the behavior?
45
+ - Which behavior should be verified before editing or explaining the feature?
46
+
47
+ Keep project-specific facts, temporary file inventory, and current app feature flags out of packaged docs. Put those in `AGENTS.md`, `.github/copilot-instructions.md`, or the project code instead.
48
+
49
+ Use [core-runtime-map.md](./core-runtime-map.md) for Python-side Caspian runtime ownership and [pulsepoint-runtime-map.md](./pulsepoint-runtime-map.md) for browser-side PulsePoint runtime ownership.
50
+
51
+ ## Redundancy Rule
52
+
53
+ Prefer one canonical explanation plus links from related docs.
54
+
55
+ - Put the full authored-template and PulsePoint runtime contract in [pulsepoint.md](./pulsepoint.md).
56
+ - Put the full route and layout placement contract in [routing.md](./routing.md).
57
+ - Put the full reusable component contract in [components.md](./components.md).
58
+ - Put the full Python runtime ownership map in [core-runtime-map.md](./core-runtime-map.md).
59
+ - Put the full PulsePoint feature lookup map in [pulsepoint-runtime-map.md](./pulsepoint-runtime-map.md).
60
+
61
+ Other docs should summarize these rules only when the reminder prevents a common mistake, then link to the canonical page instead of restating the whole rule block.
35
62
 
36
63
  ## Docs Location
37
64
 
@@ -45,19 +72,20 @@ The packaged Caspian docs referenced by this index live here:
45
72
  - `ai-validation-checklist.md` - workflow and representative prompts for checking whether AI can find the correct Caspian docs, core files, and verification checkpoints
46
73
  - `installation.md` - First-time setup flow for creating a new Caspian application
47
74
  - `commands.md` - Main Caspian CLI workflows for project creation, generation, updates, and config-aware maintenance
48
- - `core-runtime-map.md` - map of `main.py` plus installed `casp` modules to the packaged docs that explain them and the behaviors AI should trace there
49
- - `mcp.md` - MCP-specific layout, launch flow, and AI routing rules for projects where `caspian.config.json` enables MCP
75
+ - `core-runtime-map.md` - map of `main.py` plus installed `casp` modules to the packaged docs that explain them and the behaviors AI should trace there
76
+ - `pulsepoint-runtime-map.md` - fast feature-to-runtime lookup for PulsePoint state, effects, refs, context, portals, lists, events, RPC, uploads, streaming, SPA navigation, scroll restoration, and Tailwind merge behavior
77
+ - `mcp.md` - MCP-specific layout, launch flow, and AI routing rules for projects where `caspian.config.json` enables MCP
50
78
  - `database.md` - Prisma schema, migration, seed, and client-generation workflow for projects where `caspian.config.json` enables Prisma, plus Python-side helper caveats
51
79
  - `auth.md` - Session-backed authentication with `casp.auth`, centralized `auth_config.py`, public-vs-private route mode guidance, RPC-first signout guidance, RBAC, and OAuth provider helpers
52
80
  - `components.md` - Create reusable Python components, template-backed UI, HTML-first `x-*` component tags, the single-parent authored-root rule for component HTML files, and the Python-side `merge_classes(...)` contract when Tailwind CSS is enabled
53
- - `pulsepoint.md` - Default reactive frontend runtime contract for component scripts, state, effects, directives, client-side behaviors, and direct browser `twMerge(...)` usage when Tailwind CSS is enabled
81
+ - `pulsepoint.md` - Default reactive frontend runtime contract for component scripts, state, effects, directives, SPA navigation scroll restoration, `pp-reset-scroll`, and direct browser `twMerge(...)` usage when Tailwind CSS is enabled
54
82
  - `fetch-data.md` - Initial server-side data loading and browser-triggered RPC flows with `pp.rpc()`, streaming, uploads, and auth-aware actions
55
83
  - `file-uploads.md` - Route-local file uploads and file-manager flows with `@rpc()`, `pp.rpc()`, Prisma metadata, public asset storage, and BrowserSync ignore rules
56
84
  - `state.md` - Request-scoped server state with `StateManager`, session-backed JSON persistence, and listener callbacks for transient flows
57
85
  - `cache.md` - Route-level HTML caching with `Cache`, `CacheHandler`, TTL behavior, file-system storage, and invalidation patterns
58
86
  - `validation.md` - Input validation and sanitization with `Validate`, `Rule`, direct field checks, and multi-rule workflows for routes and RPC actions
59
87
  - `metadata.md` - Static and dynamic metadata, SEO inheritance, and Open Graph or Twitter card tags
60
- - `routing.md` - Next.js App Router-style file-based routing with `src/app`, dynamic segments, dashboard and section layouts, route groups, nested layouts, single-parent authored templates, and backend Python companions that do not own visible markup
88
+ - `routing.md` - Next.js App Router-style file-based routing with `src/app`, dynamic segments, dashboard and section layouts, route groups, nested layouts, shared-shell scroll-reset ownership, single-parent authored templates, and backend Python companions that do not own visible markup
61
89
  - `project-structure.md` - Default Caspian layout and where route files, reusable UI in `src/components/`, reusable non-UI code in `src/lib/`, and database files belong
62
90
 
63
91
  ## AI Retrieval Notes
@@ -70,12 +98,13 @@ Preferred lookup order:
70
98
  2. Read `./caspian.config.json` before making any feature assumption. A doc existing in the package does not mean that feature is enabled in the current project.
71
99
  3. Before authoring or editing any `src/app/**` or component HTML template, apply the single-root invariant: one authored root only, any owned `<script>` inside that root, and no handwritten `pp-component` or `type="text/pp"`.
72
100
  4. Treat `caspian.config.json` as the single source of truth for optional features. Use feature-specific docs only when the matching flag is enabled. If a feature is disabled and the user wants it, ask first, then update `caspian.config.json` and follow the update workflow in `commands.md`.
73
- 5. If the task touches `main.py` or `.venv/Lib/site-packages/casp/**`, read `core-runtime-map.md` to jump to the controlling runtime file and the matching feature doc.
74
- 6. After the feature is confirmed, inspect the actual project files that decide behavior, such as `package.json`, `main.py`, `src/app/**`, `src/lib/**`, `settings/**`, `prisma/**`, and the installed `casp` runtime.
75
- 7. Use `commands.md` for scaffold and update workflows, `project-structure.md` for placement decisions, and the feature docs such as `mcp.md`, `database.md`, `auth.md`, `fetch-data.md`, and `file-uploads.md` for task-specific guidance.
76
- 8. Prefer packaged Caspian docs before upstream documentation when generating code, commands, or migration guidance.
77
- 9. Use `ai-validation-checklist.md` when you want to verify that the docs lead AI to the correct files and behavior checkpoints.
78
- 10. Keep `index.md` and cross-links aligned so AI can quickly discover the right doc.
101
+ 5. If the task touches `main.py` or `.venv/Lib/site-packages/casp/**`, read `core-runtime-map.md` to jump to the controlling runtime file and the matching feature doc.
102
+ 6. If the task names a PulsePoint feature or directive, read `pulsepoint-runtime-map.md` for the fastest feature-to-runtime lookup, then read `pulsepoint.md` for authoring rules.
103
+ 7. After the feature is confirmed, inspect the actual project files that decide behavior, such as `package.json`, `main.py`, `src/app/**`, `src/lib/**`, `settings/**`, `prisma/**`, and the installed `casp` runtime.
104
+ 8. Use `commands.md` for scaffold and update workflows, `project-structure.md` for placement decisions, and the feature docs such as `mcp.md`, `database.md`, `auth.md`, `fetch-data.md`, and `file-uploads.md` for task-specific guidance.
105
+ 9. Prefer packaged Caspian docs before upstream documentation when generating code, commands, or migration guidance.
106
+ 10. Use `ai-validation-checklist.md` when you want to verify that the docs lead AI to the correct files and behavior checkpoints.
107
+ 11. Keep `index.md` and cross-links aligned so AI can quickly discover the right doc.
79
108
 
80
109
  ## Maintenance
81
110
 
@@ -12,9 +12,17 @@ related:
12
12
 
13
13
  This page explains how Caspian handles document metadata, SEO fields, and social sharing tags.
14
14
 
15
- At render time, Caspian resolves metadata through the layout engine and exposes the merged result to templates as `[[ metadata.* ]]`.
16
-
17
- ## Overview
15
+ At render time, Caspian resolves metadata through the layout engine and exposes the merged result to templates as `[[ metadata.* ]]`.
16
+
17
+ ## Source Of Truth
18
+
19
+ - Metadata objects and layout merge behavior are implemented in `.venv/Lib/site-packages/casp/layout.py`.
20
+ - Route registration and runtime metadata collection are controlled by `main.py`.
21
+ - Shared metadata defaults belong in `src/app/**/layout.py`.
22
+ - Page-specific static or dynamic metadata belongs in `src/app/**/index.py`.
23
+ - Rendered metadata is consumed from layout templates through `[[ metadata.* ]]`.
24
+
25
+ ## Overview
18
26
 
19
27
  Caspian uses a cascading metadata model similar to the Next.js App Router. Define defaults high in the tree, then override them closer to the final route.
20
28
 
@@ -0,0 +1,129 @@
1
+ ---
2
+ title: PulsePoint Runtime Map
3
+ description: Use this page when AI needs a fast feature-to-runtime lookup for PulsePoint behavior before editing `src/app/**`, component templates, or `public/js/pp-reactive-v2.js`.
4
+ related:
5
+ title: Related docs
6
+ description: Use the PulsePoint guide for authoring rules, the routing and component guides for template placement, and the core runtime map when Python-side transforms are involved.
7
+ links:
8
+ - /docs/pulsepoint
9
+ - /docs/routing
10
+ - /docs/components
11
+ - /docs/fetch-data
12
+ - /docs/core-runtime-map
13
+ - /docs/index
14
+ ---
15
+
16
+ This page is the quick AI routing layer for PulsePoint core features.
17
+
18
+ Use [pulsepoint.md](./pulsepoint.md) for the full authoring contract. Use this file when you need to jump from a feature name, directive, or runtime symptom to the files and behavior checkpoints that matter.
19
+
20
+ ## Source Of Truth
21
+
22
+ - `public/js/pp-reactive-v2.js` is the shipped browser runtime.
23
+ - `main.py` owns the final render pipeline that calls `transform_components(...)` and `transform_scripts(...)`.
24
+ - `.venv/Lib/site-packages/casp/components_compiler.py` injects `pp-component` after component expansion and validates the single-root contract.
25
+ - `.venv/Lib/site-packages/casp/scripts_type.py` rewrites authored body `<script>` tags to `type="text/pp"`.
26
+ - `.venv/Lib/site-packages/casp/html_attrs.py` owns Python-side class and attribute helpers such as `merge_classes(...)`.
27
+
28
+ If an inspected browser DOM disagrees with authored template source, remember that the runtime DOM includes framework-managed output. Do not copy runtime-only attributes back into authored templates.
29
+
30
+ ## Feature Map
31
+
32
+ | PulsePoint feature | Authoring surface | Runtime owner | Verify before changing |
33
+ | --- | --- | --- | --- |
34
+ | Component roots | `src/app/**/index.html`, `layout.html`, component `.html` files | `components_compiler.py`, `pp-reactive-v2.js` | one authored root, final expanded root receives one `pp-component`, no sibling scripts |
35
+ | Component scripts | plain `<script>` inside the authored root | `scripts_type.py`, `pp-reactive-v2.js` | authored scripts are plain, runtime scripts become `type="text/pp"`, one owned script per root |
36
+ | Template expressions | text and attributes with `{...}` | `pp-reactive-v2.js` | top-level script bindings are exported, nested bindings are not assumed |
37
+ | State | `pp.state(initial)` | `pp-reactive-v2.js` | setters accept values or updater functions, state belongs to the component instance |
38
+ | Effects | `pp.effect(...)`, `pp.layoutEffect(...)` | `pp-reactive-v2.js` | callbacks may return cleanup functions, promises are not awaited |
39
+ | Refs | `pp.ref(...)`, `pp-ref` | `pp-reactive-v2.js` | generated ref internals are runtime-managed; do not author `data-pp-ref` |
40
+ | Context | `pp.createContext(...)`, `<Context.Provider>`, `pp.context(token)` | `pp-reactive-v2.js` | ancestry is logical component ancestry; do not invent `pp-context` or `pp.provideContext` |
41
+ | Portals | `pp.portal(ref, target?)` | `pp-reactive-v2.js` | context should preserve logical ancestry through the registry |
42
+ | Lists | `<template pp-for="item in items">` | `pp-reactive-v2.js` | `pp-for` belongs on `<template>`, use plain `key`, not `pp-key` |
43
+ | Events | native `onclick`, `oninput`, `onsubmit` | `pp-reactive-v2.js` | event scope exposes `event`, `e`, `$event`, `target`, `currentTarget`, and `el` |
44
+ | RPC | `pp.rpc(...)` in scripts, `@rpc()` in Python | `pp-reactive-v2.js`, `casp/rpc.py` | use `pp.rpc`, not legacy `pp.fetchFunction`; protected actions use `@rpc(require_auth=True)` |
45
+ | Upload progress | `pp.rpc(..., { onUploadProgress })` | `pp-reactive-v2.js`, `casp/rpc.py` | XHR path is used for progress callbacks; replace state from returned payload |
46
+ | Streaming | `pp.rpc(..., { onStream })` | `pp-reactive-v2.js`, `casp/rpc.py`, `casp/streaming.py` | server generators become SSE responses |
47
+ | SPA navigation | `body[pp-spa="true"]`, links | `pp-reactive-v2.js`, `main.py` | same-origin eligible links intercept; root-layout mismatches hard reload |
48
+ | Scroll restoration | `pp-reset-scroll="true"` | `pp-reactive-v2.js` | push navigation resets window; mark only content panes that should reset |
49
+ | Tailwind merge | `{twMerge(...)}`, Python `merge_classes(...)` | `html_attrs.py`, `pp-reactive-v2.js` | Python emits frontend-ready expressions when Tailwind is enabled |
50
+
51
+ ## AI Decision Rules
52
+
53
+ - Read `caspian.config.json` first when the task depends on Tailwind, generated files, or optional project features.
54
+ - Read [routing.md](./routing.md) before adding route or layout templates.
55
+ - Read [components.md](./components.md) before adding reusable Python components or `x-*` imports.
56
+ - Read [fetch-data.md](./fetch-data.md) before adding browser-triggered backend work.
57
+ - Use this map when the task names a PulsePoint feature and you need the owning runtime file quickly.
58
+ - Verify implemented behavior in `public/js/pp-reactive-v2.js` before adding new PulsePoint API claims.
59
+
60
+ ## Copy-Safe Authoring Rules
61
+
62
+ - Author one root element or one imported `x-*` root per route, layout, or component template.
63
+ - Keep any owned plain `<script>` inside that same root.
64
+ - Do not handwrite `pp-component`, `type="text/pp"`, `data-pp-ref`, `pp-owner`, `pp-event-owner`, or other runtime-managed attributes.
65
+ - Use `pp.rpc(...)` for current browser-to-server calls.
66
+ - Use `Context.Provider` and `pp.context(...)` for context.
67
+ - Use `pp-for` only on `<template>` and plain `key` for keyed lists.
68
+ - Prefer PulsePoint state and directives over manual `innerHTML` repainting.
69
+
70
+ ## Compact Examples
71
+
72
+ Context provider:
73
+
74
+ ```html
75
+ <section>
76
+ <script>
77
+ const ThemeContext = pp.createContext("light");
78
+ const [theme, setTheme] = pp.state("dark");
79
+ </script>
80
+
81
+ <ThemeContext.Provider value="{theme}">
82
+ <button onclick="setTheme(theme === 'dark' ? 'light' : 'dark')">
83
+ Theme: {theme}
84
+ </button>
85
+ </ThemeContext.Provider>
86
+ </section>
87
+ ```
88
+
89
+ Upload progress:
90
+
91
+ ```html
92
+ <section>
93
+ <input type="file" onchange="{uploadFile(event.target.files?.[0])}" />
94
+ <p>{progress}%</p>
95
+
96
+ <script>
97
+ const [progress, setProgress] = pp.state(0);
98
+
99
+ async function uploadFile(file) {
100
+ if (!file) return;
101
+
102
+ await pp.rpc("upload_asset", { file }, {
103
+ onUploadProgress: (event) => setProgress(event.percentage ?? 0),
104
+ });
105
+ }
106
+ </script>
107
+ </section>
108
+ ```
109
+
110
+ Grouped shell scroll reset:
111
+
112
+ ```html
113
+ <section class="dashboard-shell">
114
+ <aside class="dashboard-sidebar">...</aside>
115
+ <main class="dashboard-content" pp-reset-scroll="true">
116
+ [[ children | safe ]]
117
+ </main>
118
+ </section>
119
+ ```
120
+
121
+ ## Verification Prompts
122
+
123
+ Use these prompts after docs or runtime changes to confirm AI can route correctly:
124
+
125
+ - "Create an interactive filter in a Caspian route template."
126
+ - "Explain why authored scripts are plain `<script>` but browser output shows `type=\"text/pp\"`."
127
+ - "Debug a dashboard sidebar losing scroll during child-route navigation."
128
+ - "Add an upload widget with progress and a reactive file list."
129
+ - "Use context to share theme state between parent and child components."
@@ -1,14 +1,15 @@
1
1
  ---
2
2
  title: PulsePoint Runtime Guide
3
- description: Use this page when the task mentions PulsePoint, `pp.state`, `pp.effect`, `pp-ref`, `pp-style`, `pp-for`, portals, SPA navigation, or `public/js/pp-reactive-v2.js`.
3
+ description: Use this page when the task mentions PulsePoint, `pp.state`, `pp.effect`, `pp-ref`, `pp-style`, `pp-for`, portals, `pp-reset-scroll`, SPA navigation, or `public/js/pp-reactive-v2.js`.
4
4
  related:
5
5
  title: Related docs
6
6
  description: Read the components, routing, data-fetching, and project-structure docs alongside the PulsePoint runtime contract.
7
7
  links:
8
8
  - /docs/components
9
9
  - /docs/routing
10
- - /docs/fetch-data
11
- - /docs/core-runtime-map
10
+ - /docs/fetch-data
11
+ - /docs/pulsepoint-runtime-map
12
+ - /docs/core-runtime-map
12
13
  - /docs/project-structure
13
14
  - /docs/index
14
15
  ---
@@ -17,7 +18,7 @@ related:
17
18
 
18
19
  This file documents the PulsePoint contract for the shipped Caspian browser runtime. Treat it as the AI-facing source of truth when generating or reviewing interactive Caspian UI.
19
20
 
20
- If a task involves `pp.state`, `pp.effect`, `pp.layoutEffect`, `pp-ref`, `pp-style`, `pp-spread`, `pp-for`, context, portals, SPA navigation, or component boundary behavior, read this page first and keep generated code aligned with the current Caspian runtime.
21
+ If a task involves `pp.state`, `pp.effect`, `pp.layoutEffect`, `pp-ref`, `pp-style`, `pp-spread`, `pp-for`, context, portals, `pp-reset-scroll`, SPA navigation, or component boundary behavior, read this page first and keep generated code aligned with the current Caspian runtime.
21
22
 
22
23
  Use `components.md` for authoring Python `@component` files, same-name HTML templates, and HTML-first `x-*` component tags. Use this page for the browser-side PulsePoint contract, the authoring rules that feed it, and the React-style mental model used by the shipped runtime.
23
24
 
@@ -43,7 +44,9 @@ Important current facts:
43
44
 
44
45
  If docs, generated examples, or older notes disagree with `public/js/pp-reactive-v2.js` plus `main.py`, follow the code that actually runs.
45
46
 
46
- Use [core-runtime-map.md](./core-runtime-map.md) when the controlling runtime file is not obvious yet.
47
+ Use [core-runtime-map.md](./core-runtime-map.md) when the controlling runtime file is not obvious yet.
48
+
49
+ Use [pulsepoint-runtime-map.md](./pulsepoint-runtime-map.md) when the task names a specific PulsePoint feature or directive and you need a quick feature-to-runtime lookup before reading the full guide.
47
50
 
48
51
  ## Default Frontend Rule
49
52
 
@@ -401,7 +404,12 @@ Example:
401
404
  - `pp-loading-content="true"` marks the page region that gets swapped or faded during navigation.
402
405
  - Route-specific loading states are looked up with `pp-loading-url`.
403
406
  - `pp-loading-transition` accepts JSON with `fadeIn` and `fadeOut` timing values.
404
- - `pp-reset-scroll="true"` resets scroll positions during navigation.
407
+ - The runtime saves scroll positions per history entry while SPA navigation is enabled.
408
+ - Push navigation resets window scroll to the top.
409
+ - Saved history-entry scroll state is used during history traversal instead of relying only on the live DOM scroll at the time the user clicks Back or Forward.
410
+ - Unmarked scrollable containers may keep their outgoing scroll on push navigation so shared shells such as sidebars, rails, and docs nav panes stay stable across child-route changes.
411
+ - `pp-reset-scroll="true"` on a scroll container opts that container into reset-on-navigation behavior. Use it on the main content pane of a grouped shell when page content should start at the top on each child-route navigation.
412
+ - `body[pp-reset-scroll="true"]` is the global override for routes that should reset window scroll and every scrollable element.
405
413
  - Navigation dispatches `pp:navigation:start`, `pp:navigation:complete`, and `pp:navigation:error` events on `document`.
406
414
 
407
415
  RPC notes:
@@ -447,6 +455,7 @@ Use these rules when generating or editing PulsePoint runtime code:
447
455
  - If a development-only source tree exists behind the shipped runtime, treat it as optional implementation detail rather than something generated apps are guaranteed to contain.
448
456
  - In authored Caspian templates, do not handwrite `pp-component` or `type="text/pp"`; let the render pipeline inject them.
449
457
  - For grouped subtrees, follow the section layout pattern in [routing.md](./routing.md), keep the shared interactive shell in the parent folder's `layout.html`, and keep route-specific PulsePoint code in each child `index.html`.
458
+ - For grouped shells with independent shell and content scrolling, put `pp-reset-scroll="true"` on the content pane rather than the whole shell when only the page content should reset between child-route navigations.
450
459
  - Prefer PulsePoint state and template directives over manual DOM mutation for reactive updates.
451
460
  - If you are explicitly editing raw runtime HTML or internals, keep `pp-component` unique per live instance.
452
461
  - In authored templates, use a plain `<script>` inside the root. In runtime HTML, the owned script appears as `script[type="text/pp"]`.
@@ -10,9 +10,10 @@ related:
10
10
  - /docs/components
11
11
  - /docs/cache
12
12
  - /docs/file-uploads
13
- - /docs/metadata
14
- - /docs/pulsepoint
15
- - /docs/index
13
+ - /docs/metadata
14
+ - /docs/pulsepoint
15
+ - /docs/pulsepoint-runtime-map
16
+ - /docs/index
16
17
  ---
17
18
 
18
19
  Caspian follows the same mental model as the Next.js App Router: routes live under `src/app`, folders define URL segments, layouts nest automatically, and special folder names control grouping and dynamic matching.
@@ -31,6 +32,7 @@ Start with these rules:
31
32
  - Add `index.py` only when the same route needs metadata, `page()`, `@rpc()` actions, auth checks, caching, redirects, or other server-side logic.
32
33
  - Use a standalone `index.py` only for non-visual routes such as redirects or action-only handlers.
33
34
  - When a folder owns child routes, use `layout.html` to wrap them. This is the default pattern for dashboards, admin sections, account areas, settings trees, and route groups.
35
+ - In grouped shells with separate shell and content scrolling, put `pp-reset-scroll="true"` on the content pane in `layout.html` when that pane should reset on child-route navigation while the shell sidebar or rail keeps its own scroll.
34
36
  - Use `layout.py` when a layout needs shared synchronous props or metadata before rendering.
35
37
  - Keep visible route and layout markup in `index.html` and `layout.html`. Treat `index.py` and `layout.py` as backend companions, not as places to author visible HTML.
36
38
  - Treat every authored route and layout template like a React component body: it must have exactly one top-level parent HTML element or one imported `x-*` root, and any owned plain `<script>` must live inside that same root.
@@ -145,6 +147,8 @@ src/
145
147
 
146
148
  Use this pattern when the app has a public grouped section that should stay out of the URL and a private dashboard section that should appear in the URL. The root layout owns app-wide chrome, `(marketing)/layout.html` owns the shared public marketing shell, and `dashboard/layout.html` owns the shared dashboard shell for `/dashboard/*` child routes.
147
149
 
150
+ When a shared shell has its own scrollable sidebar or rail plus a separate page-content scroller, keep the persistent shell scrollers unmarked and put `pp-reset-scroll="true"` on the page-content scroller in `layout.html`. That gives grouped sections the common app-router behavior where the main pane resets on child-route navigation while the sidebar keeps its scroll position. Use `body[pp-reset-scroll="true"]` only when the target route should reset every scrollable surface.
151
+
148
152
  ## Core Concepts
149
153
 
150
154
  Every route lives inside `src/app`. For routes that render UI, `index.html` owns the markup and `index.py` is only an optional companion for server logic or metadata.
@@ -224,7 +228,7 @@ Also bad:
224
228
  </section>
225
229
  ```
226
230
 
227
- Use [pulsepoint.md](./pulsepoint.md) when you need the full authored-vs-rendered example instead of this routing-focused reminder.
231
+ Use [pulsepoint.md](./pulsepoint.md) when you need the full authored-vs-rendered example instead of this routing-focused reminder. Use [pulsepoint-runtime-map.md](./pulsepoint-runtime-map.md) when a route task names a specific PulsePoint directive or SPA behavior and you need the owning runtime file quickly.
228
232
 
229
233
  ### `index.py`
230
234
 
@@ -392,15 +396,15 @@ Example:
392
396
  ```python
393
397
  from casp.auth import auth
394
398
 
395
- def layout(context_data):
396
- user = auth.get_payload()
397
-
398
- return {
399
- "user": user,
400
- "dashboard_body_class": "w-screen h-screen overflow-hidden",
401
- "theme": "dark",
402
- }
403
- ```
399
+ def layout(context_data):
400
+ user = auth.get_payload()
401
+
402
+ return {
403
+ "user": user,
404
+ "dashboard_body_class": "w-screen h-screen overflow-hidden",
405
+ "theme": "dark",
406
+ }
407
+ ```
404
408
 
405
409
  `context_data` includes URL parameters such as dynamic route values.
406
410
 
@@ -498,6 +502,7 @@ If an AI agent is choosing where to add or update route code, apply these rules
498
502
  - Use a normal folder such as `dashboard/` when the segment should appear in the URL. Use `(group)/` only when the folder should organize or wrap child routes without adding a path segment.
499
503
  - Use [cache.md](./cache.md) when an `index.py` route should opt into page-level HTML caching.
500
504
  - Use `layout.html` for shared wrappers and `layout.py` for layout-level synchronous props or metadata.
505
+ - For grouped shells with separate shell and content scrolling, put `pp-reset-scroll="true"` on the content pane instead of the whole shell when only the page content should reset between child routes.
501
506
  - When one route needs to change a parent layout, return `(render_page(__file__, ...), {"dashboard_body_class": ...})` from `page()` and read that value as `[[ layout.dashboard_body_class ]]` in the wrapping `layout.html`.
502
507
  - Use `layout.py` for layout props that should apply across an entire subtree. Use `render_layout(__file__, {...})` only when the layout should consume direct local variables such as `[[ my_class ]]` instead of the standard `[[ layout.* ]]` namespace.
503
508
  - Keep `<!-- @import ... -->` directives at the top of `index.html` and `layout.html`, above the single authored parent node.
@@ -27,11 +27,18 @@ Import the public API like this:
27
27
  from casp.state_manager import StateManager
28
28
  ```
29
29
 
30
- The current installed implementation lives in `.venv/Lib/site-packages/casp/state_manager.py`.
31
-
32
- Use [core-runtime-map.md](./core-runtime-map.md) when a state task crosses `main.py` middleware setup, wire-request behavior, and the installed state-manager internals.
33
-
34
- The real API surface is:
30
+ The current installed implementation lives in `.venv/Lib/site-packages/casp/state_manager.py`.
31
+
32
+ Use [core-runtime-map.md](./core-runtime-map.md) when a state task crosses `main.py` middleware setup, wire-request behavior, and the installed state-manager internals.
33
+
34
+ ## Source Of Truth
35
+
36
+ - Request initialization and middleware timing are controlled by `main.py`.
37
+ - The server state implementation lives in `.venv/Lib/site-packages/casp/state_manager.py`.
38
+ - Route and RPC code should use `StateManager` only for transient server request state.
39
+ - Browser interaction state belongs in PulsePoint; read [pulsepoint.md](./pulsepoint.md) before moving UI state into `StateManager`.
40
+
41
+ The real API surface is:
35
42
 
36
43
  - request initialization with `StateManager.init(request)`
37
44
  - top-level state reads with `StateManager.get_state(...)`
@@ -26,9 +26,16 @@ Import the public API like this:
26
26
  from casp.validate import Validate, Rule
27
27
  ```
28
28
 
29
- The current installed implementation lives in `.venv/Lib/site-packages/casp/validate.py`.
30
-
31
- The real API surface is:
29
+ The current installed implementation lives in `.venv/Lib/site-packages/casp/validate.py`.
30
+
31
+ ## Source Of Truth
32
+
33
+ - The implemented validation API lives in `.venv/Lib/site-packages/casp/validate.py`.
34
+ - Route and RPC input boundaries live in `src/app/**/index.py`.
35
+ - Reusable app-owned validation workflows belong in `src/lib/**`.
36
+ - Browser-side validation is UX only; server-side `Validate` and `Rule` checks remain authoritative.
37
+
38
+ The real API surface is:
32
39
 
33
40
  - direct single-value validation with `Validate.*(...)`
34
41
  - multi-rule validation with `Validate.with_rules(...)`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "caspian-utils",
3
- "version": "0.0.24",
3
+ "version": "0.0.26",
4
4
  "description": "Caspian tooling",
5
5
  "main": "index.js",
6
6
  "scripts": {