todo: resurrect projects/apps, with the archaeology attached
the idea is not settled. the card exists so the history is not dug out twice: user apps were born 2026-02-27 as a publishing system that made a personal app a first-class workspace panel, /projects was its authoring surface, and both went a day apart at the end of july — 1440 deletions. the part worth knowing before rebuilding: the app registry used to be mutable at runtime, registerApp keyed on email/slug, and the note left where it stood argues well against it. the plugin system solved the same problem afterwards by generating at build time, so the first question is whether a user app is just a plugin with a different author. nothing on disk was ever touched. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -20,41 +20,41 @@ the owner's OS user and can never be granted. Indirection there really is accide
|
||||
|
||||
## Themes
|
||||
|
||||
**89 open, 29 closed**, across 31 themes.
|
||||
**90 open, 29 closed**, across 31 themes.
|
||||
|
||||
| Theme | Open | Closed |
|
||||
| ------------------------------------------------------------------------------------------ | ---- | ------ |
|
||||
| [Affordances](todo/affordances/) | 1 | 0 |
|
||||
| [Agents coordinating agents](todo/agent-coordination/) | 2 | 0 |
|
||||
| [Speaking into a session from the backend](todo/agent-delivery/) | 1 | 1 |
|
||||
| [Backburner](todo/backburner/) | 2 | 0 |
|
||||
| [Background jobs](todo/background-jobs/) | 2 | 1 |
|
||||
| [Chat interface](todo/chat/) | 1 | 0 |
|
||||
| [Code editor](todo/code-editor/) | 1 | 0 |
|
||||
| [Components — the shared UI layer](todo/components/) | 1 | 0 |
|
||||
| [File watchers](todo/file-watchers/) | 1 | 0 |
|
||||
| [Fleet — one command across every server](todo/fleet/) | 5 | 2 |
|
||||
| [Headscale](todo/headscale/) | 0 | 5 |
|
||||
| [Infra (alpha)](todo/infra/) | 7 | 0 |
|
||||
| [Known bugs](todo/known-bugs/) | 3 | 2 |
|
||||
| [Mobile apps](todo/mobile-apps/) | 3 | 0 |
|
||||
| [Multi-user](todo/multi-user/) | 16 | 5 |
|
||||
| [Notifications](todo/notifications/) | 1 | 0 |
|
||||
| [Plugin ecosystem — before it opens to third parties (2026-08-18)](todo/plugin-ecosystem/) | 3 | 0 |
|
||||
| [Plugin infrastructure](todo/plugin-infrastructure/) | 2 | 0 |
|
||||
| [Plugin repos — what writing their READMEs turned up](todo/plugin-repos/) | 10 | 9 |
|
||||
| [Plugin system — gaps the email extraction found (2026-08-18)](todo/plugin-system/) | 3 | 0 |
|
||||
| [Prompt library](todo/prompt-library/) | 1 | 0 |
|
||||
| [SendOff](todo/sendoff/) | 1 | 0 |
|
||||
| [Settings — portable, and readable by an agent](todo/settings/) | 2 | 0 |
|
||||
| [Shell — spotlight and the dock](todo/shell/) | 4 | 1 |
|
||||
| [Sub-agents — agents spawning agents](todo/sub-agents/) | 0 | 2 |
|
||||
| [Sudo terminal modal](todo/sudo-terminal-modal/) | 1 | 0 |
|
||||
| [Tooling — the list about the list](todo/tooling/) | 0 | 1 |
|
||||
| [Transmission](todo/transmission/) | 6 | 0 |
|
||||
| [URL state — routing, query strings and selection](todo/url-state/) | 4 | 0 |
|
||||
| [Waiting on the owner to run it](todo/waiting-on-owner/) | 3 | 0 |
|
||||
| [Workspaces & Panels](todo/workspaces-panels/) | 2 | 0 |
|
||||
| Theme | Open | Closed |
|
||||
| --- | --- | --- |
|
||||
| [Affordances](todo/affordances/) | 1 | 0 |
|
||||
| [Agents coordinating agents](todo/agent-coordination/) | 2 | 0 |
|
||||
| [Speaking into a session from the backend](todo/agent-delivery/) | 1 | 1 |
|
||||
| [Backburner](todo/backburner/) | 3 | 0 |
|
||||
| [Background jobs](todo/background-jobs/) | 2 | 1 |
|
||||
| [Chat interface](todo/chat/) | 1 | 0 |
|
||||
| [Code editor](todo/code-editor/) | 1 | 0 |
|
||||
| [Components — the shared UI layer](todo/components/) | 1 | 0 |
|
||||
| [File watchers](todo/file-watchers/) | 1 | 0 |
|
||||
| [Fleet — one command across every server](todo/fleet/) | 5 | 2 |
|
||||
| [Headscale](todo/headscale/) | 0 | 5 |
|
||||
| [Infra (alpha)](todo/infra/) | 7 | 0 |
|
||||
| [Known bugs](todo/known-bugs/) | 3 | 2 |
|
||||
| [Mobile apps](todo/mobile-apps/) | 3 | 0 |
|
||||
| [Multi-user](todo/multi-user/) | 16 | 5 |
|
||||
| [Notifications](todo/notifications/) | 1 | 0 |
|
||||
| [Plugin ecosystem — before it opens to third parties (2026-08-18)](todo/plugin-ecosystem/) | 3 | 0 |
|
||||
| [Plugin infrastructure](todo/plugin-infrastructure/) | 2 | 0 |
|
||||
| [Plugin repos — what writing their READMEs turned up](todo/plugin-repos/) | 10 | 9 |
|
||||
| [Plugin system — gaps the email extraction found (2026-08-18)](todo/plugin-system/) | 3 | 0 |
|
||||
| [Prompt library](todo/prompt-library/) | 1 | 0 |
|
||||
| [SendOff](todo/sendoff/) | 1 | 0 |
|
||||
| [Settings — portable, and readable by an agent](todo/settings/) | 2 | 0 |
|
||||
| [Shell — spotlight and the dock](todo/shell/) | 4 | 1 |
|
||||
| [Sub-agents — agents spawning agents](todo/sub-agents/) | 0 | 2 |
|
||||
| [Sudo terminal modal](todo/sudo-terminal-modal/) | 1 | 0 |
|
||||
| [Tooling — the list about the list](todo/tooling/) | 0 | 1 |
|
||||
| [Transmission](todo/transmission/) | 6 | 0 |
|
||||
| [URL state — routing, query strings and selection](todo/url-state/) | 4 | 0 |
|
||||
| [Waiting on the owner to run it](todo/waiting-on-owner/) | 3 | 0 |
|
||||
| [Workspaces & Panels](todo/workspaces-panels/) | 2 | 0 |
|
||||
|
||||
## Records — no items, kept for the reasoning
|
||||
|
||||
@@ -65,6 +65,7 @@ the owner's OS user and can never be granted. Indirection there really is accide
|
||||
|
||||
## Newest ten
|
||||
|
||||
- `2026-08-25` **Resurrect Projects/Apps** — [backburner/resurrect-projects-apps](todo/backburner/resurrect-projects-apps.md)
|
||||
- `2026-08-23` **A worker cannot verify that the owner delegated to a manager, so it has to ask every time** — [agent-coordination/a-peer-cannot-verify-a-delegation](todo/agent-coordination/a-peer-cannot-verify-a-delegation.md)
|
||||
- `2026-08-23` **An agent cannot learn its own transcript id, so it cannot sign its own work** — [agent-coordination/an-agent-cannot-learn-its-own-session-id](todo/agent-coordination/an-agent-cannot-learn-its-own-session-id.md)
|
||||
- `2026-08-23` **The SendOff file size limit is one constant for everybody** — [sendoff/per-user-size-limit](todo/sendoff/per-user-size-limit.md)
|
||||
@@ -74,4 +75,3 @@ the owner's OS user and can never be granted. Indirection there really is accide
|
||||
- `2026-08-22` **A user's settings should export and import as a plain file** — [settings/a-user-s-settings-should-export-and-import-as](todo/settings/a-user-s-settings-should-export-and-import-as.md)
|
||||
- `2026-08-22` **The same for system settings, owned by the Super Admin** — [settings/the-same-for-system-settings-owned-by-the](todo/settings/the-same-for-system-settings-owned-by-the.md)
|
||||
- `2026-08-22` **All keyboard shortcuts configurable** — [shell/all-keyboard-shortcuts-configurable](todo/shell/all-keyboard-shortcuts-configurable.md)
|
||||
- `2026-08-22` **Ctrl+? shows every keyboard shortcut in a modal** — [shell/ctrl-shows-every-keyboard-shortcut-in-a-modal](todo/shell/ctrl-shows-every-keyboard-shortcut-in-a-modal.md)
|
||||
|
||||
@@ -0,0 +1,101 @@
|
||||
---
|
||||
id: backburner/resurrect-projects-apps
|
||||
title: "Resurrect Projects/Apps"
|
||||
theme: backburner
|
||||
status: open
|
||||
created: 2026-08-25
|
||||
date_source: stated
|
||||
order: 3
|
||||
---
|
||||
|
||||
**Resurrect Projects/Apps.** The idea is not settled — this card exists so the archaeology is not done
|
||||
twice. Everything below was read out of git on 2026-08-25.
|
||||
|
||||
## What existed
|
||||
|
||||
Two features, one cluster, removed a day apart.
|
||||
|
||||
**User apps — born `fd4d77a3`, 2026-02-27:** *"user app publishing system — build, serve, and use
|
||||
personal apps in workspace panels."* You wrote an app, published it, and it appeared as a **first-class
|
||||
workspace panel** beside Terminal and Chat. `/api/apps` (298 lines) built and served it; `/api/app-serve`
|
||||
served the built output; `/api/dev-server` (314 lines) plus a websocket proxy ran it live; a shared
|
||||
`html-rewrite.ts` made both viewable through the platform's own origin.
|
||||
|
||||
**`/projects` — the authoring surface.** A list screen and a project screen, a 244-line list panel, a
|
||||
**612-line preview panel**, a publish dialog. Projects had a *type*, a *template*, and
|
||||
`hasBackend` / `hasAuth` flags — so it was scaffolding as well as hosting. A `projects` table, and
|
||||
`proj-meta` / `proj-layout` / `proj-terminals` / `proj-host-terminals` branches in the dashboards
|
||||
endpoint.
|
||||
|
||||
## Why each went
|
||||
|
||||
**`/projects`, `5a1e3d7e`, 2026-07-30.** Not a design failure — a scheduling one:
|
||||
|
||||
> Being retired, so it is deleted rather than fixed — it had both defects dashboards just had (edit
|
||||
> dropping `?selected=`, an abandoned edit following you onto the next item) and repairing them was
|
||||
> work for something on its way out.
|
||||
|
||||
**Apps, `188b45c1`, 2026-07-31.** The rest of the cluster, **1,440 deletions**: `/api/apps`,
|
||||
`/api/app-serve`, `/api/dev-server` and its websocket proxy, `html-rewrite`, the Preview panel, the
|
||||
UserApp panel and header, `useUserApps`, `/settings/apps`, `getUserProjectsDir`, `getUserAppsDir`, the
|
||||
`ProjectType` and `ProjectDefinition` types, and the `dev-server` websocket provider.
|
||||
|
||||
**Nothing on disk was touched.** Both commits say so explicitly. Whatever was under `Projects/` is still
|
||||
there.
|
||||
|
||||
## The interesting part: the App Registry used to be dynamic
|
||||
|
||||
This is the piece worth understanding before rebuilding anything. Alongside the compiled-in apps:
|
||||
|
||||
```tsx
|
||||
const { registerApp } = useAppRegistry(apps);
|
||||
const { apps: userApps, email } = useUserApps();
|
||||
|
||||
registerApp(`${email}/${app.slug}`, {
|
||||
name: app.name,
|
||||
icon: resolveIcon(app.icon),
|
||||
component: createUserAppPanel(app.slug),
|
||||
header: createUserAppHeader(app.name, resolveIcon(app.icon)),
|
||||
});
|
||||
```
|
||||
|
||||
Keyed per user, with the icon resolved from a **string name** at runtime (`utils/resolve-icon.ts`, 116
|
||||
lines — also deleted).
|
||||
|
||||
**That capability is gone, and the argument against it is good.** The note left where it stood:
|
||||
|
||||
> there is no `registerApp` any more because nothing ever called one, and a registry that can be added
|
||||
> to at runtime is a registry whose contents depend on what has mounted so far.
|
||||
|
||||
Today `seedAppRegistry` writes the registry once, before anything renders, from 17 static meta lists.
|
||||
|
||||
**So the constraint to design around, rather than re-litigate: user apps need to reach the registry
|
||||
without making it mutable at runtime.** The plugin system — which arrived *after* this was deleted —
|
||||
already solved a version of exactly this by generating `Plugins.gen` at build time and mounting plugin
|
||||
routers at boot. Any resurrection should start by asking whether a user app is just a plugin with a
|
||||
different author, rather than a second mechanism beside it.
|
||||
|
||||
## What survived, and is still working
|
||||
|
||||
**`dev-proxy`** (`/api/dev-proxy/5173/…` → `127.0.0.1:5173`). The reasoning in its header is worth
|
||||
reading before rebuilding the dev-server half — it explains why neither obvious approach works:
|
||||
`http://localhost:5173` resolves on the *viewer's* machine, and `http://<server>:5173` is mixed content
|
||||
inside an https page. So the bytes must arrive over the platform's own origin. It costs no certificate,
|
||||
no proxy-host entry, and no open port, and it lets a dev server stay bound to loopback.
|
||||
|
||||
Its stated limit: the app believes it is at `/` and is not. Absolute paths are rewritten on the way out,
|
||||
which covers Bun's dev server and ordinary relative assets, but not an app that builds URLs in ways the
|
||||
rewrite cannot see.
|
||||
|
||||
## Open questions, if this is picked up
|
||||
|
||||
1. **Is a user app a plugin?** The app store, the plugin manifest, `ownerOnly`, sidecars and
|
||||
`Plugins.gen` all landed after this was removed. Rebuilding a parallel mechanism would be the
|
||||
expensive mistake.
|
||||
2. **What is the scaffolding half worth?** Templates, `hasBackend`, `hasAuth` — the agent can now write
|
||||
an app from a prompt, which may make a template picker the least valuable part of what was lost.
|
||||
3. **Multi-user changes the shape.** The old key was `${email}/${slug}`, written when the platform was
|
||||
effectively single-user. Whose apps appear in whose dock is now a permissions question, not a
|
||||
namespacing one.
|
||||
4. **Does it need its own theme?** It is in `backburner` because the idea is not settled. If it becomes
|
||||
real it is bigger than one card.
|
||||
Reference in New Issue
Block a user