You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: .claude/skills/indexing-diagnostics/SKILL.md
+2-2Lines changed: 2 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1220,8 +1220,8 @@ Three env vars control the per-prerender-server shape. They're resolved once at
1220
1220
1221
1221
| Env var | Default | What it controls | When to change it |
1222
1222
|---|---|---|---|
1223
-
|`PRERENDER_PAGE_POOL_SIZE`|`5`|Total simultaneous Chrome tabs the pool can manage. Also the `capacity`the server reports to the manager on each heartbeat, which drives warm-vacancy routing. | Fleet capacity. Raise when `waits.semaphoreMs` dominates `launchMs` across rows from all realms (server-wide saturation); lower if you need to reduce memory footprint and you can confirm from snapshots that pending rarely approaches `totalTabs`. |
1224
-
|`PRERENDER_AFFINITY_TAB_MAX`|`5` (clamped to `PRERENDER_PAGE_POOL_SIZE`) | Max tabs a single affinity (realm or user) can simultaneously hold from the pool. | Rarely. Must be ≥ 2 for the self-referential prerender deadlock to be prevented — PagePool logs a warning at startup when it isn't. Lower only if you want to force multi-realm fairness at the tab-routing level. |
1223
+
|`PRERENDER_PAGE_POOL_MIN` / `_MAX`|unset → fixed pool of `options.maxPages` (5) | Dynamic-pool envelope. The pool boots at MIN, expands up to MAX under saturation, contracts back to MIN after sustained idle. The live capacity is what the server reports to the manager on each heartbeat, which drives warm-vacancy routing. | Fleet capacity. Raise MAX when `waits.semaphoreMs` dominates `launchMs` across rows from all realms (server-wide saturation); lower MAX if you need to reduce memory footprint and you can confirm from snapshots that pending rarely approaches `totalTabs`. Setting MIN === MAX disables expansion/contraction. |
1224
+
|`PRERENDER_AFFINITY_TAB_MAX`|`5` (clamped to the effective pool max: `PRERENDER_PAGE_POOL_MAX` when set, otherwise fixed `maxPages`) | Max tabs a single affinity (realm or user) can simultaneously hold from the pool. | Rarely. Must be ≥ 2 for the self-referential prerender deadlock to be prevented — PagePool logs a warning at startup when it isn't. Lower only if you want to force multi-realm fairness at the tab-routing level. |
1225
1225
|`PRERENDER_AFFINITY_FILE_CONCURRENCY`| unset → `max(1, PRERENDER_AFFINITY_TAB_MAX − 1)` (the deadlock-safety ceiling) | Cap on concurrent `file` renders within a single affinity. Module and command calls bypass admission; they're never capped by this knob. | Cross-realm fairness. When one realm's fan-out (e.g. a catalog reindex) is stealing render budget from every other realm, lower this below the ceiling to reserve tabs for other affinities. The effective cap is always `min(env, ceiling)` so this can't accidentally break the deadlock-safety invariant. |
1226
1226
1227
1227
**Default invariant**: when `PRERENDER_AFFINITY_FILE_CONCURRENCY` is unset, the effective file-admission cap equals the deadlock-safety ceiling — same behavior as before the knob existed. Changing the knob is an explicit operator decision driven by `admissionMs` telemetry; don't adjust it without data.
Copy file name to clipboardExpand all lines: .github/workflows/ci-lint.yaml
+97Lines changed: 97 additions & 0 deletions
Original file line number
Diff line number
Diff line change
@@ -125,3 +125,100 @@ jobs:
125
125
if: ${{ !cancelled() }}
126
126
run: pnpm run lint
127
127
working-directory: packages/boxel-cli
128
+
- name: Verify Boxel CLI plugin synopsis is fresh
129
+
# Regenerates the `<!-- generated:commands -->` blocks in plugin/skills/*/SKILL.md
130
+
# from the Commander tree and fails if the working tree changed — i.e. someone
131
+
# added or changed a CLI command without running `pnpm build:plugin`.
132
+
if: ${{ !cancelled() }}
133
+
run: |
134
+
pnpm run build:plugin
135
+
if ! git diff --exit-code -- plugin/skills; then
136
+
echo "::error::plugin/skills synopsis is stale. Run 'pnpm build:plugin' in packages/boxel-cli and commit the result."
137
+
exit 1
138
+
fi
139
+
working-directory: packages/boxel-cli
140
+
- name: Verify boxel-skills sync
141
+
# Regenerates plugin/skills/boxel-development and plugin/skills/boxel-design from
142
+
# cardstack/boxel-skills at the pinned tag in scripts/build-skills.ts. Fails if
143
+
# the working tree changed — i.e. someone hand-edited boxel-skills-derived
144
+
# content without bumping the pin and re-running `pnpm build:skills`.
145
+
if: ${{ !cancelled() }}
146
+
run: |
147
+
pnpm run build:skills
148
+
if ! git diff --exit-code -- plugin/skills; then
149
+
echo "::error::plugin/skills is out of sync with cardstack/boxel-skills. Bump BOXEL_SKILLS_VERSION in scripts/build-skills.ts (or fix upstream), run 'pnpm build:skills' in packages/boxel-cli, and commit the result."
150
+
exit 1
151
+
fi
152
+
working-directory: packages/boxel-cli
153
+
- name: Verify plugin version bumped when synopsis changed
154
+
# If a PR's diff against main touches any generated:commands block, the plugin's
155
+
# version must also bump in the same diff. Otherwise marketplace consumers won't
156
+
# see the update — Claude Code caches by version string.
echo "No generated synopsis changes detected; skipping version-bump check."
188
+
exit 0
189
+
fi
190
+
# Was the plugin manifest version touched?
191
+
if ! git diff "$BASE" "$HEAD" -- packages/boxel-cli/plugin/.claude-plugin/plugin.json \
192
+
| grep -qE '^[+-]\s*"version"'; then
193
+
echo "::error::plugin/skills synopsis changed but plugin.json version was not bumped. Marketplace consumers won't see the update without a new version. Bump 'version' in packages/boxel-cli/plugin/.claude-plugin/plugin.json."
194
+
exit 1
195
+
fi
196
+
echo "Synopsis changed and plugin.json version was bumped — OK."
197
+
working-directory: .
198
+
- name: Verify plugin version bumped when boxel-skills content changed
199
+
# Mirrors the synopsis-bump check above, but gates on changes to skill folders
200
+
# generated by `pnpm build:skills` (boxel-development/, boxel-design/). Any
201
+
# content change there requires a plugin.json bump so marketplace consumers
202
+
# actually pick up the new content — Claude Code caches by version string.
echo "No boxel-skills-derived changes detected; skipping version-bump check."
216
+
exit 0
217
+
fi
218
+
if ! git diff "$BASE" "$HEAD" -- packages/boxel-cli/plugin/.claude-plugin/plugin.json \
219
+
| grep -qE '^[+-]\s*"version"'; then
220
+
echo "::error::boxel-skills-derived content changed but plugin.json version was not bumped. Marketplace consumers won't see the update without a new version. Bump 'version' in packages/boxel-cli/plugin/.claude-plugin/plugin.json."
221
+
exit 1
222
+
fi
223
+
echo "boxel-skills content changed and plugin.json version was bumped — OK."
Copy file name to clipboardExpand all lines: README.md
+6-4Lines changed: 6 additions & 4 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -158,7 +158,8 @@ This sets the following defaults (all individually overridable):
158
158
| Variable | Normal | Turbo |
159
159
| ---------------------------- | ------ | ----- |
160
160
|`PRERENDER_COUNT`| 1 | 3 |
161
-
|`PRERENDER_PAGE_POOL_SIZE`| 4 | 4 |
161
+
|`PRERENDER_PAGE_POOL_MIN`| 4 | 4 |
162
+
|`PRERENDER_PAGE_POOL_MAX`| 4 | 4 |
162
163
|`WORKER_HIGH_PRIORITY_COUNT`| 0 | 4 |
163
164
|`WORKER_ALL_PRIORITY_COUNT`| 1 | 4 |
164
165
@@ -221,7 +222,7 @@ In environment mode, this is at `http://worker.environment-name.localhost/_index
221
222
Boxel supports server-side rendering of cards via a lightweight prerender service and an optional manager that coordinates multiple services.
222
223
223
224
- Prerender server: Handles POST `/prerender-card` (cards) and `/prerender-module` (modules) requests that include user/session permissions and a target URL. It launches a headless browser and maintains a small pool of per-realm pages (LRU-evicted) to speed up subsequent renders. Each page keeps a logged-in session for its realm and reuses the page for repeated renders of that realm.
224
-
- Pooling: Each prerender server maintains up to PRERENDER_PAGE_POOL_SIZE pages (default 4). When the pool is full, the least-recently-used realm is evicted (its browser context is closed). When a page becomes unusable (timeout or explicit unusable signal), the realm is evicted proactively.
225
+
- Pooling: Each prerender server maintains a dynamic page pool sized between `PRERENDER_PAGE_POOL_MIN` and `PRERENDER_PAGE_POOL_MAX` (both default 4 in dev). When the pool is full, the least-recently-used realm is evicted (its browser context is closed). When a page becomes unusable (timeout or explicit unusable signal), the realm is evicted proactively.
225
226
- Prerender manager: When multiple prerender servers are running, a central manager receives `/prerender-card` and `/prerender-module` requests and routes them to a suitable server. The manager tracks which servers are registered and which realms they actively handle. It supports realm affinity, multiplexing the same realm across multiple servers to handle high prerender throughput, capacity-aware selection, and health-based eviction of unreachable servers.
226
227
227
228
#### Pre-rendering start scripts
@@ -249,8 +250,9 @@ Prerender server:
249
250
- BOXEL_HOST_URL (optional): URL of the host app that serves the /render routes. Defaults to http://localhost:4200 in dev scripts.
250
251
- PRERENDER_MANAGER_URL (optional): Base URL of the prerender manager to register with. Defaults to http://localhost:4222.
251
252
- PRERENDER_COUNT (optional): Number of prerender server instances to start. Each gets its own headless Chrome. Default 1.
252
-
- PRERENDER_PAGE_POOL_SIZE (optional): Max number of per-realm pages to keep open in the pool. Default 4.
253
-
- PRERENDER_AFFINITY_TAB_MAX (optional): Max number of tabs a single realm can use within a prerender server. Defaults to PRERENDER_PAGE_POOL_SIZE (i.e. a realm can use all available tabs).
253
+
- PRERENDER_PAGE_POOL_MIN (optional): Idle floor for the dynamic page pool. The pool boots at this size and contracts back to it after sustained idle. Default 4 in dev (set in `mise-tasks/lib/env-vars.sh`).
254
+
- PRERENDER_PAGE_POOL_MAX (optional): Burst ceiling for the dynamic page pool. The pool expands up to this size under saturation. Default 4 in dev. Setting MIN === MAX disables expansion/contraction (fixed-size pool).
255
+
- PRERENDER_AFFINITY_TAB_MAX (optional): Max number of tabs a single realm can use within a prerender server. Defaults to 5, clamped to the effective pool max (`PRERENDER_PAGE_POOL_MAX` when set, otherwise the fixed `maxPages` pool size).
254
256
- BOXEL_SHOW_PRERENDER (optional): If set to 'true', opens a visible browser (useful for debugging locally). Headless otherwise.
Copy file name to clipboardExpand all lines: docs/aws-operations.md
+12-15Lines changed: 12 additions & 15 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -14,7 +14,7 @@ Conventions used throughout:
14
14
15
15
## Activate the dynamic-pool prerender server
16
16
17
-
Flips the boxel prerender server's `PagePool`from legacy fixed-size capacity (driven by `PRERENDER_PAGE_POOL_SIZE`) to the dynamic-pool envelope (driven by `MIN` / `MAX` / `HIGH_PRIORITY_MAX`). Use this once the dynamic-pool code is deployed and you're ready to activate the new behaviour on a deployed environment.
17
+
Sets the boxel prerender server's `PagePool` envelope (`MIN` / `MAX` / `HIGH_PRIORITY_MAX`). Use this when first activating dynamic-pool behaviour on a deployed environment, or when re-tuning the envelope after a workload shift.
18
18
19
19
### Pre-requisites
20
20
@@ -98,24 +98,21 @@ If the ECS task is still 4 vCPU / 8 GB, the recommended values would OOM at `HP_
98
98
99
99
### Rollback
100
100
101
-
Restoring legacy fixed-pool behaviour without a code change:
101
+
Restore the previous envelope values via SSM, then force-redeploy. Capture the pre-change values before applying new ones so rollback is a single `put-parameter` per knob — there is no longer a "fall back to a different env var" escape hatch, so the rollback target must be a known-good envelope.
102
102
103
103
```sh
104
-
# Reset all dynamic-pool knobs to the SSM placeholder value "0"
105
-
# (which the application code treats as "unset", falling back to
0 commit comments