Phase 11 and Phase 15 demoted dashboard, goals, costs, activity,
org, inbox, convert, approvals, and routines to per-project tabs,
settings pages, or folded them into the Studio / Assistant
surfaces. Phase 16b deletes the top-level route definitions and
the now-orphaned page components.
/issues and /agents top-level lists become Navigate redirects to
/projects for one release cycle (issue and agent detail pages
remain). /convert redirects to the Studio Convert workshop.
boardRoutes now lands on /assistant (not /dashboard). BOARD_ROUTE_
ROOTS is pruned to only the roots that still render pages.
CommandPalette and CompanyRail quick-links are updated to match.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Rewrites InstanceGeneralSettings.tsx into the consolidated /instance/
settings/general destination per spec §8.1 — a single-column scroll
that stacks eight section cards (Workspace, Local AI, Cloud Providers,
Skills, Routines, Telegram, About, Danger Zone).
App.tsx nested settings sub-routes collapse:
- /instance/settings/heartbeats → redirect to /general
- /instance/settings/experimental → redirect to /general
The /instance/settings/plugins tree is left intact: it is a
plugin-system surface with its own pages, not a settings sub-page.
Deletes InstanceSidebar.tsx (already unmounted by Phase 8),
InstanceSettings.tsx (scheduler heartbeats dashboard, folded out per
spec), and InstanceExperimentalSettings.tsx (experimental toggles are
now part of the Workspace section).
Also fixes ToastInput shape (title/tone instead of message/type) in
CloudProvidersSection and TelegramSection, and drops the unavailable
cronExpression access in RoutinesSection since the RoutineListItem
trigger Pick does not include it.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Controller integration pass after the three wave 2 subagents (phases
9, 10, 11) completed their phase implementations. Three changes in
one commit because they're a single coordinated post-dispatch step:
1. App.tsx routing
- Adds 5 new per-project builder tab routes for phase 11:
projects/:projectId/agents
projects/:projectId/gates
projects/:projectId/costs
projects/:projectId/activity
projects/:projectId/org
plus their unprefixed UnprefixedBoardRedirect variants so
direct nav and deep links resolve through the same fallback
chain as /overview and /issues.
- Adds content-studio/:workshopSlug as a sibling route for
phase 10's workshop detail view. Without this, clicking a
workshop card hit the * fallback NotFoundPage because the
existing content-studio route was an exact match and the
ContentStudio-internal pathname workaround couldn't fire.
- Does NOT rename the legacy /convert route. ConvertPage still
renders directly at /convert for backwards compat; Studio's
Convert workshop reuses the ConvertPanel body inside its own
detail shell.
2. IconRail volt-dot indicator
- Imports useCompany from CompanyContext and useGateIndicator
from the new phase 11 hook.
- When selectedCompanyId resolves to a company with at least
one pending approval (displayed as "gates" per phase 11's
display rename), renders a 6px volt dot overlay in the
top-right of the Assistant destination icon and updates
the link's aria-label to "Assistant (pending gates)".
- This is the single global notification surface specified by
spec section 10.4 - no badge counts, no inbox icons, no toasts.
3. IconRail.test.tsx
- Mocks useGateIndicator at module scope so tests don't need
a QueryClientProvider for the rail's useQuery-backed data.
- Replaces the plain function mock with a vi.fn() spy so
per-suite overrides can flip hasPendingGates without dynamic
imports.
- Adds a sibling describe block that verifies the volt dot
renders and the aria-label updates when hasPendingGates is true.
- 7 original tests pass; 2 new tests cover dot-absent and
dot-present cases. 9 tests total.
Verification: 211/211 tests passing across 22 files in the combined
frame + assistant + studio + projects suites; tsc clean on every
wave 1 and wave 2 file plus App.tsx.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Stop showing Paperclip's board UI by default. First-time users now
land on Personal Assistant (v1.5), see a Nexus-first sidebar, and the
NexusOnboardingWizard (built in v1.5) actually fires on first run
instead of sitting behind a dead "Start Onboarding" button click.
App.tsx
- CompanyRootRedirect now reads useNexusMode() and lands the user
at /${prefix}/assistant by default. Only project_builder mode
lands at /${prefix}/dashboard. "personal_ai" and "both" (the
default) both go to the Assistant.
- NoCompaniesStartPage gutted: the old "Create your first company"
button is gone. Single-workspace mode doesn't ask users to name
workspaces; the onboarding wizard handles it. Replaced with a
minimal "Setting up your workspace..." loading shim.
- OnboardingRoutePage now auto-opens the wizard on mount when no
companies exist. Closes the dead-button gap: previously the user
had to click "Start Onboarding" to actually get the wizard; now
the wizard opens itself as soon as they land.
Sidebar.tsx
- Restructured around two mode-gated sections:
* Always visible (Nexus essentials): Assistant, Content Studio,
Convert, Inbox, Skills, Settings. Plus the New Issue button and
plugin sidebar items.
* project_builder-only: Work (Issues, Routines, Goals), Projects,
Agents, and the remaining Workspace items (Org, Costs, Activity).
- Top bar no longer renders a company switcher dropdown — single-
workspace mode shows the workspace name as a static label with
the search button beside it.
- Dashboard link removed from the always-visible section. The
default landing is /assistant; users who explicitly want the
Paperclip dashboard can type the URL or switch to project_builder
mode.
Layout.tsx
- Removed both <CompanyRail /> renderings (mobile and desktop
branches). Single-workspace mode doesn't need a multi-company
icon rail. Import preserved with a [nexus] comment for upstream
rebase compat.
- Onboarding useEffect's authenticated-mode gate removed (root
cause of the v1.5 wizard-not-firing bug on fresh DB). This
effect is now a belt-and-suspenders fallback; the real auto-
trigger lives in OnboardingRoutePage because Layout isn't
actually mounted during the zero-company first-run state
(CompanyRootRedirect navigates to /onboarding before Layout
ever renders).
NexusOnboardingWizard.tsx
- handleSubmit and handleStartChat both used to hardcode the post-
creation navigation to /${prefix}/dashboard. Now mode-aware:
project_builder lands at /dashboard, everything else lands at
/assistant. Matches the Sidebar and CompanyRootRedirect logic —
a fresh user never touches the Paperclip dashboard unless they
explicitly chose project_builder during the wizard.
Not changed:
- The Paperclip pages themselves (Dashboard, Issues, Projects,
Agents, Org, etc.) — still present, still accessible by URL,
still upstream-mergeable. Just hidden from the default nav.
- CompanyRail.tsx, CompanySwitcher.tsx, NewCompanyDialog — files
preserved for upstream rebase diff minimization. No call sites
remain.
- /NEX/companies route still registered in boardRoutes(), just
unlinked from the default UI.
TypeScript: zero new errors (pre-existing errors in AgentConfigForm,
command.tsx, useKeyboardShortcuts, usePiperTts, useVadRecorder,
OnboardingSummaryStep.test, PersonalAssistant unchanged).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Zero-terminal first boot. Previously the bootstrap_ceo invite had to be
created via a CLI command (paperclipai auth bootstrap-ceo) and the UI
showed a code block instructing the user to run it. Nexus is meant to
be zero-terminal, so the server now auto-creates the invite on startup
when no instance admin exists and exposes its relative path through
/api/health. BootstrapPendingPage redirects straight to /invite/{token}.
The CLI command is left intact for headless/SSH-only setups.
Invite flow fixes that surfaced during testing:
- InviteLanding's invite query had default React Query refetch
behavior. After a successful bootstrap accept, the invite is marked
accepted server-side, so the refetch returned "not available" and
shadowed the success screen, making it look like the bootstrap had
failed when it actually succeeded. Set staleTime: Infinity +
refetchOnWindowFocus/Mount/Reconnect: false so the first fetch is a
one-shot snapshot.
- Reordered the render checks so result?.kind === "bootstrap" / "join"
are evaluated before the invite-availability error check — defensive
against any stray refetch that still leaks through.
- On bootstrap success, window.location.replace("/") lands the new
admin directly on the board; the "Bootstrap complete" confirmation
screen is now an unreachable safety net.
Vite onnxruntime middleware replaces the earlier public/ dump. The
previous commit put ort-wasm-simd-threaded.{mjs,wasm} in ui/public/ so
VAD's onnxWASMBasePath: "/" would find them. That works at runtime but
trips vite's dep optimizer: it scans onnxruntime-web, resolves the
dynamic import string to the public asset, and errors with "files in
/public should not be imported from source code." Remove the files and
add a vite plugin (configureServer middleware) that serves the two URLs
straight from node_modules/.pnpm/onnxruntime-web@*/. Runtime keeps
working and the files never enter vite's module graph.
Production build caveat: the middleware only runs in dev. When building
a static dist for production, the wasm files will need a different
mechanism (e.g. generateBundle hook). Not addressed here.
Also bundled (load-bearing for LAN browser testing):
- ui/src/lib/queryKeys.ts: add missing 'nexus' group. useNexusMode
referenced queryKeys.nexus.settings since commit 7bb72a5a (Phase
33-02) but the key was never added. Caused a blank screen crash on
any page that mounts Sidebar.
- ctl.sh: read PORT from .env instead of hardcoding 3100, and read it
once at the top so every subcommand honors it. Fixes the Version /
Mode showing '?' in status output after the port move to 6100.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- InviteLanding: skill bootstrap and invite heading use VOCAB.appName and VOCAB.company
- IssueDetail: Board actor identity uses VOCAB.board
- NewAgent: first agent name/title defaults to VOCAB.ceo
- NotFound: company not found message uses VOCAB.company
- PluginManager: breadcrumb fallback uses VOCAB.company
- PluginSettings: breadcrumb fallback uses VOCAB.company
- Routines: error messages and creation hint use VOCAB.appName
- App: startup log messages use VOCAB.appName; CLI command unchanged
Introduce a singleton instance_settings store and experimental settings API, add the Experimental instance settings page, and gate execution workspace behavior behind the new enableIsolatedWorkspaces flag.
Co-Authored-By: Paperclip <noreply@paperclip.ing>
The export page now syncs the selected file with the URL path, e.g.
/PAP/company/export/files/agents/cmo/AGENTS.md. Navigating to such a
URL directly selects and reveals the file in the tree. Browser
back/forward navigation is supported without page refreshes.
Co-Authored-By: Paperclip <noreply@paperclip.ing>
merge Usage page into Costs as two tabs ('Spend' and 'Providers'),
extract shared date-range logic to useDateRange() hook, delete /usage
route and sidebar entry, fix quota-windows bugs from prior review
adds a new /usage page that lets board operators see how much each ai
provider is consuming across any date window, with per-model breakdowns,
rolling 5h/24h/7d burn windows, weekly budget bars, and a deficit notch
when projected spend is on track to exceed the monthly budget.
- new GET /companies/:id/costs/by-provider endpoint aggregates cost events
by provider + model with pro-rated billing type splits from heartbeat runs
- new GET /companies/:id/costs/window-spend endpoint returns rolling window
spend (5h, 24h, 7d) per provider with no schema changes
- QuotaBar: reusable boxed-border progress bar with green/yellow/red
threshold fill colors and optional deficit notch
- ProviderQuotaCard: per-provider card showing budget allocation bars,
rolling windows, subscription usage, and model breakdown with token/cost
share overlays
- Usage page: date preset toggles (mtd, 7d, 30d, ytd, all, custom),
provider tabs, 30s polling plus ws invalidation on cost_event
- custom date range blocks queries until both dates are selected and
treats boundaries as local-time (not utc midnight) so full days are
included regardless of timezone
- query key to timestamp is floored to the nearest minute to prevent
cache churn on every 30s refetch tick
- Add /:company/company/export page with file tree, checkboxes for
per-file selection, and read-only preview pane (skills-style layout)
- Add /:company/company/import page with source form (GitHub/URL/local),
target/collision settings, preview tree with action badges, and detail pane
- Add Import/Export buttons to the Org Chart page header
- Replace import/export sections in CompanySettings with redirect links
- Clean up ~800 lines of dead code from CompanySettings
- Register new routes in App.tsx
Co-Authored-By: Paperclip <noreply@paperclip.ing>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* public-gh/master:
Drop lockfile from watcher change
Tighten plugin dev file watching
Fix plugin smoke example typecheck
Fix plugin dev watcher and migration snapshot
Clarify plugin authoring and external dev workflow
Expand kitchen sink plugin demos
fix: set AGENT_HOME env var for agent processes
Add kitchen sink plugin example
Simplify plugin runtime and cleanup lifecycle
Add plugin framework and settings UI
# Conflicts:
# packages/db/src/migrations/meta/0029_snapshot.json
# packages/db/src/migrations/meta/_journal.json