Skip to content

Start with Terminal, Files and themes, and pick more extensions in the setup assistant - #363

Merged
Piggidragon merged 5 commits into
mainfrom
feature/default-extensions-wizard
Nov 3, 2026
Merged

Piggidragon merged 5 commits into
mainfrom
feature/default-extensions-wizard

Conversation

@Piggidragon

@Piggidragon Piggidragon commented Nov 3, 2026 •

Copy link
Copy Markdown
Collaborator

Closes #304. A new portal starts with Terminal, Files and the theme pack only. Git, Canvases and Media become opt-in. The first-run setup assistant gets an Extensions step where you pick a preset or choose by hand.

What changes

  • Default set: extensions/defaults.json is ["terminal", "files", "themes"].

  • Presets (core/server/src/default-extensions.ts, served at GET /api/extensions/presets):

    • Minimal is the default set.
    • Developer adds Git, Docker for extensions and Documents.
    • Creative adds Media, Canvases and Voice.
    • Everything is every extension that comes with Pithagoras.
  • The setup assistant is now Provider, Model, Extensions, Agent.

    • The step shows the four presets. "Choose by hand" lists every extension that comes with Pithagoras, each with one line on what it does and "Needs Docker for extensions" where that applies.
    • It says that all of it can be changed later in Settings → Extensions.
    • Installing goes through the same path as Settings: the install plan first, so Docker for extensions comes first, as in feat: an extension can build on another: provide, use, requires and optional #232, then POST /api/packages.
    • It shows each extension's progress and errors, and offers Try again and Skip.
    • A Docker for extensions that was switched off is asked about, not switched on silently.
  • PORTAL_DEFAULT_EXTENSIONS takes:

    • off;
    • nothing, on or default;
    • a preset name;
    • a comma list of folder or package names.

    Extensions they need are installed first. A value that is none of these is refused whole: the log says why, and the default set is installed, so a typo cannot leave a new portal without a terminal.

  • No two writers to pi's settings: POST /api/packages waits for the start install, so the step and the first start never write pi's settings at once.

  • Docs: extensions.md (What a portal starts with), deploying.md and its environment table, configuration.md, upgrading.md, models.md, extension-ui.md. Also git.md, canvases.md, media.md, features.md and the README, which said Git, Canvases and Media come with a new portal. German texts are added.

How the issue's "To settle" points are built

  • Existing portals keep what they have. Shrinking the list uninstalls nothing, and the default_extensions_installed record is untouched. Tests pin a portal that recorded the old six and one with Git installed by hand.
  • Order on the first start. The three install at the first start, as before. The wizard's step installs the rest of the chosen preset or selection afterwards, and can be skipped.
  • Unattended installs. As above: off, a preset or a list.
  • Dependencies. Docker for extensions first, as feat: an extension can build on another: provide, use, requires and optional #232 does.
  • Who may use the step. The same rule as installing in Settings: anyone signed in. A test shows 401 before login on the presets, shipped, plan and packages routes.

Checks

  • npm run build and build:extensions: ok.

  • Web npx tsc -b: ok.

  • npm test -w core/server: 1610 pass, 0 fail.

  • Root npm test: 2106 pass, 0 fail.

  • tests/i18n: 17/17.

  • Playwright under the flock (settings, extension-bundled, extensions-settings, extension-requires): 69 passed. Among them are 10 new specs for the step:

    • the presets and the list;
    • Developer, and Creative with Docker first;
    • choosing by hand;
    • a failure with Skip, and Skip;
    • the phone layout, German;
    • the clicked set staying marked;
    • the installed list being reloaded;
    • a switched-off Docker being asked about.
  • Old code: with defaults.json back at six, the extension-packages and real-list tests fail. The three review-fix specs fail with the old components, and the lock test fails without the wait.

  • A real local portal with a fresh data folder:

    • Only Terminal, Files and the themes are installed at the start.
    • The presets endpoint gives the four sets.
    • Git and Documents, then Canvases, install through the step's call.
    • A data folder whose record names the old six keeps Git, Documents, Canvases and Media after a restart.

    The step itself was not clicked through in that portal, because it had a provider set already. The Playwright specs cover it.

  • One review round (correctness, security, spec): 5 findings, all fixed. The medium one was stale "installed on first start" wording in five docs pages.

Also: an empty update on the Docker page (#360)

CI failed on extensions/docker/test/update.test.mts, the same test that had failed once on main (d9082d5). The cause is a race in Docker for extensions' overview, not in this PR's code:

  • The overview took a row's update entry before it looked at the container's image, and asked whether there was one only after.
  • An update that began or ended in between came out as an empty update: {}, which the page and the test read as one that had ended.

The fix:

  • The entry is now read once, after the look.
  • The fake Docker can hold the answer to an inspect.
  • A new test begins an update while the page reads; it fails on the old code with {}.

On one CPU, the update test failed 6 of 168 runs before and 0 of 120 after.

Owner decisions (2026-11-03)

All kept as built: a portal coming straight from 0.1.0 starts with the three; a refused PORTAL_DEFAULT_EXTENSIONS installs the default set; Everything stays as wide as it is; only POST /api/packages waits for the start install.

What was asked

  1. 0.1.0 straight to this version: a portal that never ran 0.2.0 has no record, so it starts with the three and not the six that 0.1.0 had built in. This is documented in upgrading.md and not installed automatically. Should a used portal with no record get the old six on its first start instead? That would be a small change.
  2. A refused PORTAL_DEFAULT_EXTENSIONS: it logs and installs the default set. The alternatives are to install nothing (like off) or to refuse to start.
  3. Everything is the widest set: Creator, Kanban, Subagents and Voice servers included, plus Docker for Browser, Voice and Understory. Installing them starts no container. Narrower?
  4. The step sits third, before Agent, so Agent stays last with "Start a chat".
  5. One-line descriptions live in a web-side table (core/web/src/shipped-extensions.ts) with German entries, because the packages' own descriptions are long and English only. A new extension that comes with Pithagoras falls back to its package description until it is added there.
  6. Only POST /api/packages waits for the start install. POST /packages/update, DELETE /packages and PUT /extensions/enabled also write pi's settings and do not wait. Extend the wait to them?

🤖 Generated with Claude Code

Piggidragon and others added 4 commits November 3, 2026 12:15
…presets for PORTAL_DEFAULT_EXTENSIONS

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… hand

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…p and the new PORTAL_DEFAULT_EXTENSIONS values

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Nov 3, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

Warning

Review limit reached

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Next included review available in 27 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used all 2 included reviews currently available.

Learn how review limits work.

Review configuration:

Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: d706d050-c07b-4402-b407-6e0afefdddb0
Commits

Reviewing files that changed from the base of the PR and between 35a35b3 and 5b1a125.

Files selected for processing: 3
  • extensions/docker/src/docker.ts
  • extensions/docker/test/fake-docker.ts
  • extensions/docker/test/update.test.mts

No actionable comments were generated in the recent review.

Walkthrough

Fresh portals now install Terminal, Files, and Themes by default. The server supports extension presets and explicit selections, including dependency ordering. The setup assistant adds a step for selecting and installing extensions.

Changes: Extension defaults and setup

Layer / File(s) Summary
Default selection and installation
extensions/defaults.json, core/server/src/default-extensions.ts, core/server/test/default-extensions*.test.mjs, docs/guide/deploying.md, docs/guide/extension-ui.md, docs/guide/extensions.md, docs/guide/upgrading.md, docs/reference/configuration.md, tests/extension-packages.test.mts
Fresh installs default to Terminal, Files, and Themes. PORTAL_DEFAULT_EXTENSIONS supports disabling defaults, named presets, and comma-separated selections. Required extensions are ordered before dependents, and previously installed extensions remain installed.
Preset API and install coordination
core/server/src/api/extensions.ts, core/server/src/api/packages.ts, core/server/test/extension-presets-api.test.mjs, core/web/src/api.ts
The server adds an endpoint for preset IDs and extension lists. Package installation waits for default extension installation to finish. The web API adds the preset response type and request method.
Setup extension selection
core/web/src/components/SetupAssistant.tsx, core/web/src/components/SetupExtensions.tsx, core/web/src/components/ExtensionInstall.tsx, core/web/src/shipped-extensions.ts, core/web/src/locales/de.ts, tests/browser/settings.spec.mts, README.md, docs/guide/canvases.md, docs/guide/deploying.md, docs/guide/extensions.md, docs/guide/features.md, docs/guide/git.md, docs/guide/media.md, docs/guide/models.md
The setup assistant adds an Extensions step with preset and manual choices. It displays installation progress and failures, supports retry or skip, and installs missing choices. The guides describe opt-in extensions and setup choices.

Estimated code review effort: 4 (Complex) | ~45 minutes

Change: Feature

Sequence Diagram(s)

sequenceDiagram
  participant SetupAssistant
  participant SetupExtensions
  participant api
  participant ExtensionsPresetsRoute
  participant PackagesRouter
  SetupAssistant->>SetupExtensions: Load extension choice state
  SetupExtensions->>api: Request api.extensionPresets()
  api->>ExtensionsPresetsRoute: GET /extensions/presets
  ExtensionsPresetsRoute-->>api: Return preset IDs and extension lists
  api-->>SetupExtensions: Return presets
  SetupExtensions->>PackagesRouter: Install selected missing extensions
  PackagesRouter-->>SetupExtensions: Return install result
  SetupExtensions-->>SetupAssistant: Report completion or failure
Loading

Suggested reviewers: thecodacus

Merge Risk: Minimal · previous review 35a35

No actionable merge-blocking issue is established for the new defaults and setup selection flow. Merge after the normal checks and owner decisions.

Pre-merge checks: Passed 4 · Failed 1

Failed Failed checks: 1 warning

Check name Status Explanation Resolution
Docstring Coverage Warning Docstring coverage is 72.73% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff with cyclomatic complexity of at least 2. Documenta… Write docstrings for the functions missing them to satisfy the coverage threshold.
Passed Passed checks: 4 passed
Check name Status Explanation
Description Check Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check Passed The title clearly summarizes the main changes: the smaller default extension set and extension selection in the setup assistant.
Linked Issues check Passed Directly linked issue #304 has only coding requirements. Each one maps to head code:

1. Smaller default set: extensions/defaults.json at head is ["terminal", "files", "themes"]. Git, Canvases and M…
Out of Scope Changes check Passed The changes I could check connect to #304:

- Default list and presets (extensions/defaults.json, default-extensions.ts).
- PORTAL_DEFAULT_EXTENSIONS parsing (defaultsChoice).
- Wizard step an…
Full details: Linked Issues check

Explanation

Directly linked issue #304 has only coding requirements. Each one maps to head code:

  1. Smaller default set: extensions/defaults.json at head is ["terminal", "files", "themes"]. Git, Canvases and Media are removed from the list.
  2. Presets: core/server/src/default-extensions.ts defines Minimal (default set), Developer (git, docker, docs), Creative (media, canvas, voice) and Everything (all shipped). extensionPresets() drops folders that are absent. The summary reports GET /api/extensions/presets (auth-tested) and the web api.extensionPresets().
  3. Setup wizard step: core/web/src/components/SetupExtensions.tsx (ExtensionStep) shows the four presets as radio buttons. A "Choose by hand" list shows every shipped extension with a one-line description (shippedLine) and a "Needs ..." line from its requires. The step text says the choice can be changed later in Settings → Extensions. The summary reports Docker for extensions is listed first.
  4. Dependencies: withRequirements() orders required extensions before their dependents. run() installs extensions without requirements first and skips any already installed. A "needs Docker for extensions, which is installed first" notice is shown.
  5. Unattended installs: defaultsChoice() accepts off, empty/on/default, a preset name, or a comma list of folder or package names. Unknown values are refused whole, logged, and the default set is installed.
  6. Existing portals: installation is tracked by the default_extensions_installed record. Shrinking the list does not uninstall. The summary reports tests for this.
  7. First-start order: the three default extensions install at start. The wizard installs the rest. The issue allows this option.
  8. Docs and tests: the summary lists updated docs (extensions.md, deploying.md, upgrading.md, configuration.md) and new tests in default-extensions.test.mjs, extension-presets-api.test.mjs and the browser specs.

Residual notes, not failures: the catalog in core/web/src/shipped-extensions.ts gives one-line text for known names. Any other shipped extension falls back to its package description, which may not be one line. The PR lists this as an owner question. I did not confirm that the catalog covers every shipped extension. Settings-writing routes other than POST /api/packages do not wait for the start install. The issue does not require that wait.

Full details: Out of Scope Changes check

Explanation

The changes I could check connect to #304:

  • Default list and presets (extensions/defaults.json, default-extensions.ts).
  • PORTAL_DEFAULT_EXTENSIONS parsing (defaultsChoice).
  • Wizard step and its install path (SetupExtensions.tsx, SetupAssistant.tsx, ExtensionInstall.tsx announced option, which skips the confirmation for shipped installs).
  • Preset API (api/extensions.ts).
  • Serialization of POST /api/packages behind the start install (api/packages.ts, installingDefaults/afterDefaultsInstalled). It prevents concurrent writes to pi's settings during the wizard install and the first start.
  • The shipped-extension label and description table (shipped-extensions.ts), which the step uses.
  • German locale strings, documentation pages and README edits. These describe the new default set and the step.
  • Test updates: the stop-test threshold and the package-list expectation, which follow from the smaller default set.

I did not verify the replaceRetiredExtensions logic in default-extensions.ts (Dusk and Warm entries). The PR summary does not list it as a change, and its file comment reads as existing behavior. I did not confirm its history at the merge base. It does not conflict with #304 and I found no evidence that it is unrelated, so I do not mark it out of scope.

Full details: Docstring Coverage

Explanation

Docstring coverage is 72.73% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff with cyclomatic complexity of at least 2. Documentation-only edits and deletions within surviving functions are included; unchanged diff context and fully deleted functions are excluded. Analyzed 11 functions across 14 files. (12 skipped: 12 unsupported.)

Resolution

Write docstrings for the functions missing them to satisfy the coverage threshold.

Finishing Touches
Generate docstrings
  • Commit to this branch
  • Create a new PR
Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Tip

🎯 Customize your risk assessments

Guide how CodeRabbit assesses merge risk and security architecture risk. Highlight sensitive changes and explain your security boundaries using Merge Risk Instructions and Security Risk Instructions in your review settings. Security architecture risk assessments require the Advanced plan or above.

✅ Automatic approvals, with your rules

Let CodeRabbit approve pull requests once required threads are resolved, pre-merge checks pass, and your risk limits are met. Enable Automatic approvals in review settings, with overrides for teams or file paths.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

Share

CodeRabbit Verify

  • Run CodeRabbit Verify to test the changes in this pull request.
Recent review info
Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 6c18ab0c-b8c2-4980-8ba5-f594868fc244
Commits

Reviewing files that changed from the base of the PR and between d9082d5 and 35a35b3.

Files selected for processing: 26
  • README.md
  • core/server/src/api/extensions.ts
  • core/server/src/api/packages.ts
  • core/server/src/default-extensions.ts
  • core/server/test/default-extensions-stop.test.mjs
  • core/server/test/default-extensions.test.mjs
  • core/server/test/extension-presets-api.test.mjs
  • core/web/src/api.ts
  • core/web/src/components/ExtensionInstall.tsx
  • core/web/src/components/SetupAssistant.tsx
  • core/web/src/components/SetupExtensions.tsx
  • core/web/src/locales/de.ts
  • core/web/src/shipped-extensions.ts
  • docs/guide/canvases.md
  • docs/guide/deploying.md
  • docs/guide/extension-ui.md
  • docs/guide/extensions.md
  • docs/guide/features.md
  • docs/guide/git.md
  • docs/guide/media.md
  • docs/guide/models.md
  • docs/guide/upgrading.md
  • docs/reference/configuration.md
  • extensions/defaults.json
  • tests/browser/settings.spec.mts
  • tests/extension-packages.test.mts

Included review availability: This review used your included allowance. Your plan provides up to 2 included reviews per hour; 0 remain after this review.

…ns or ends during the read

The overview took a row's update entry before it looked at the container's
image and asked whether there was one after: an update that began or ended
in between came out as an empty update ({}), which the page and the update
test read as one that had ended. The entry is now read once, after the look.
The fake Docker can hold the answer to an inspect, and a new test begins an
update while the page reads; it fails on the old code with {}. The update
test that failed now and then on CI (main d9082d5, #363) failed 6 of 168
runs on one CPU before, 0 of 120 after.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Piggidragon added a commit that referenced this pull request Nov 3, 2026
…ns or ends during the read

The overview took a row's update entry before it looked at the container's
image and asked whether there was one after: an update that began or ended
in between came out as an empty update ({}), which the page and the update
test read as one that had ended. The entry is now read once, after the look.
The fake Docker can hold the answer to an inspect, and a new test begins an
update while the page reads; it fails on the old code with {}. The update
test that failed now and then on CI (main d9082d5, #363) failed 6 of 168
runs on one CPU before, 0 of 120 after.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Piggidragon
Piggidragon merged commit 8de924a into main Nov 3, 2026
5 checks passed
Piggidragon added a commit that referenced this pull request Nov 3, 2026
Piggidragon added a commit that referenced this pull request Nov 3, 2026
* Let a mode set model parameters, sent with every request of its chats

A mode the person made can set the temperature, top P, top K, min P and the
maximum answer length. They are kept on the mode (schema 17), read at each
request of a chat in it, and put on pi's stream options so that each API's
adapter sends them where its request has them. The model's own sampling
parameters in models.json stay for every field the mode leaves unset;
compactions and summaries are not touched.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* Set a mode's model parameters in Settings → Modes, and show them in the chat

The mode's page gets a Model parameters section with a field each for the
temperature, Top P, Top K, Min P and the longest answer, saved when the field
is left. The menu above the message box and the mode in the header name the
parameters a mode sets. The guide says what each field does, how it merges
over the model's own settings, and which services ignore which.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* Fix what the first review of the mode parameters found

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* Let a mode set the temperature only, and keep the schema at 16

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* Show a container's update whole on the Docker page, also when it begins or ends during the read

The overview took a row's update entry before it looked at the container's
image and asked whether there was one after: an update that began or ended
in between came out as an empty update ({}), which the page and the update
test read as one that had ended. The entry is now read once, after the look.
The fake Docker can hold the answer to an inspect, and a new test begins an
update while the page reads; it fails on the old code with {}. The update
test that failed now and then on CI (main d9082d5, #363) failed 6 of 168
runs on one CPU before, 0 of 120 after.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Default extensions: start with Terminal, Files and themes, and let the setup wizard offer presets or a manual choice

1 participant