Skip to content

Installed extensions surface in the shell - #250

Merged
czpython merged 1 commit into
mainfrom
installed-extensions-surface
Aug 14, 2026
Merged

Installed extensions surface in the shell#250
czpython merged 1 commit into
mainfrom
installed-extensions-surface

Conversation

@czpython

Copy link
Copy Markdown
Owner

What

An extension installed against the published image is now visible and usable from the dashboard without shipping any frontend.

  • GET /api/extensions — the installed roster: name, icon, description, builtin, subject types, has-frontend. The extension dropdown and the events filter read it (the settings projection is filtered to knob-carrying extensions and was the wrong wire for nav).
  • Shell registration — every roster entry lands in the same UI registry the bundled extensions use. Bundled registration wins per extension; roster extras follow A→Z, so the default landing is unchanged.
  • Generic pages — a backend-only extension gets a home page with its subject boards stacked (one row per subject: status, id, the summary's own fields) and a subject page with summary facts, the run timeline, the newest run's transcript, and gate answer/cancel/retry via the platform run routes.
  • Shipped dist — an extension whose wheel carries dist/ (already served at /app/<name>) gets its app-switcher entry linked there; reaching it is a document load, not an SPA navigation.
  • The in-app review, cancel, and retry controls move from ship's work-item page to shared components; ship renders them from the new location, and the generic subject page uses the same UI.

Why

The backend treats every installed extension uniformly — boards, timelines, transcripts, and gate answering are all platform wire — but the shell derived nav, routes, and landing only from the import-time bundle registry. uv pip install <app> registered everything except a way for the operator to find it.

Acceptance

Stock deploy, uv pip install a druks-apps extension, restart: the dropdown lists it, its boards render, a parked run's gate is answerable from its subject page. No typed URL, no SPA rebuild.

The backend already gives every installed extension a full read-side —
boards, subject timelines, transcripts, gate answering — but the shell
derived its nav, routes, and landing only from the import-time bundle
registry, so an extension installed against the published image was
invisible to the operator.

GET /api/extensions now serves the installed roster (name, icon,
description, builtin, subject types, has-frontend). The shell registers
every roster entry into the same UI registry the bundled extensions use:
a backend-only extension gets generic pages — its subject boards stacked
on a home page, and a subject page with summary facts, the run timeline,
the newest run's transcript, and the gate controls — while an extension
that ships its own dist/ gets an external home at /app/<name>. Bundled
registration wins per extension; roster extras follow A→Z.

The extension dropdown and the events filter read the roster instead of
the settings projection, which is filtered to knob-carrying extensions
and was the wrong wire for nav. The in-app review, cancel, and retry
controls move from ship's work-item page to shared components so the
generic subject page answers gates with the same UI.
@czpython
czpython force-pushed the installed-extensions-surface branch from c3f6ae8 to d7b4b08 Compare August 14, 2026 14:34
@czpython
czpython enabled auto-merge (squash) August 14, 2026 14:35
@czpython
czpython merged commit 858ced3 into main Aug 14, 2026
2 checks passed
@czpython
czpython deleted the installed-extensions-surface branch August 14, 2026 14:36
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.

1 participant