feat(web): add active publisher context#2744
Conversation
This reverts commit 30b0adbbd7c72de7040d5555c8973becbb120726.
|
@vyctorbrzezowski is attempting to deploy a commit to the Amantus Machina Team on Vercel. A member of the Team first needs to authorize it. |
|
@clawsweeper review |
|
🦞🧹 I asked ClawSweeper to review this item again. |
|
Codex review: needs changes before merge. Reviewed June 18, 2026, 9:42 PM ET / 01:42 UTC. Summary Reproducibility: yes. for the PR finding: the live CI run reproduces it across local-auth shards, and the source shows the trigger now prefers displayName over the @handle. This is not a current-main bug reproduction; it is a PR regression check. Review metrics: 2 noteworthy metrics.
Merge readiness Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch. Rank-up moves:
Risk before merge
Maintainer options:
Next step before merge
Security Review findings
Review detailsBest possible solution: Keep the active publisher model only if the header keeps a stable visible or accessible @handle for the active publisher, local-auth passes, and maintainers accept the global context UX. Do we have a high-confidence way to reproduce the issue? Yes for the PR finding: the live CI run reproduces it across local-auth shards, and the source shows the trigger now prefers displayName over the @handle. This is not a current-main bug reproduction; it is a PR regression check. Is this the best way to solve the issue? No, not merge-ready as-is. The active publisher approach is plausible, but the header trigger must preserve stable publisher identity and local-auth validation before maintainers decide the product direction. Full review comments:
Overall correctness: patch is incorrect AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning high; reviewed against 6bbdec2a4ef8. Label changesLabel changes:
Label justifications:
Evidence reviewedAcceptance criteria:
What I checked:
Likely related people:
What the crustacean ranks mean
Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics. How this review workflow works
|
Proposal
This PR adds a global active publisher context to ClawHub.
Until this change, ClawHub had enough publisher/org primitives in the data model, but the product UI still treated many signed-in actions as if they were implicitly personal. That made organization work feel patched on: users could belong to orgs, but the header, dashboard, settings, and publishing surfaces did not all share one obvious answer to “who am I acting as right now?”
This PR makes that answer explicit and consistent:
The goal is not to turn ClawHub into a workspace app with a heavy org switcher everywhere. The goal is a small, durable context model that lets users publish and manage work as either themselves or an organization without mixing account identity, publisher identity, and app-level controls.
Product model
The PR separates three concepts that were previously easy to blur:
In practice:
ownerHandleURL says otherwise.Header and global menu
The header now exposes the current publisher as the primary signed-in control.
For a personal publisher, the menu shows the personal publisher identity and the personal actions:
If the user has no organization yet,
Create organizationappears directly under their identity so the next step is discoverable without taking over the menu.For an organization publisher, the menu changes the publisher-scoped actions to organization language:
Account/app actions stay separated below the scoped actions.
Starsis intentionally not shown in the organization context because stars belong to the signed-in account, not to the active org.The switcher is nested inside the current publisher row instead of being a second competing dropdown. Selecting the publisher row opens a context switch panel with personal/org options and
Create organization. This keeps the main menu compact while still making the active context clear.Settings behavior
Settings are now context-aware.
When the active context is personal,
/settingsedits the signed-in user/personal publisher surface:When the active context is an organization,
/settingsedits that organization:This avoids mixing user profile editing and org profile editing in the same visual state. The page title/subtitle and sidebar reflect the active settings scope.
Role gating is preserved:
Organizations settings page
The personal settings area includes an Organizations view that lists the orgs available to the account.
Each org card shows:
The layout is intentionally card-based and supports two orgs per row on wide screens while staying compact enough for the common case where a user has one org.
Publish skill/plugin flows
The skill and plugin publish pages now show the current publishing owner at the top of the upload card.
The strip is intentionally lightweight:
The selector updates the
ownerHandleURL when switching context, so publishing state is shareable, reload-safe, and not only stored in client memory.Important behavior preserved:
ownerHandlein the URL wins when opening the page.Dashboard behavior
Dashboard queries now follow active publisher scope without breaking legacy personal ownership.
For org publishers, the dashboard queries by
ownerPublisherId.For personal publishers, the dashboard continues querying by
ownerUserId. This matters because local/legacy personal publishers can be synthesized or compatibility-backed; treating those as real publisher document IDs can hide existing personal content. This PR keeps personal dashboards on the user-owner path while allowing org dashboards to use publisher ownership.Backend/data changes
This PR adds a lightweight publisher membership query for the global context provider.
The existing richer
publishers.listMinequery is still useful for settings pages that need profile/status/count data. The app-level context provider does not need that full payload, so it now uses a narrower query that returns only publisher identity and role data.That avoids putting a heavy “all published items” subscription around the entire app shell.
The lightweight membership query still handles:
personalPublisherIdLoading and deep-link behavior
The settings page now avoids normalizing org-only deep links before publisher memberships finish loading.
For example,
/settings?view=membersshould not be immediately rewritten to/settings?view=profilejust because memberships have not arrived yet. The page can show a skeleton while loading, but it should preserve the requested view until it knows whether the active publisher is an org and whether the requested view is valid.This PR adds that loading guard and regression coverage.
What intentionally does not change
This PR does not change the underlying authorization rules for publishing or org management.
It also does not make stars organization-scoped. Stars remain personal/account-level.
It does not make appearance publisher-scoped. Appearance remains an app/user preference.
It does not make update publishing migrate owners automatically. Migration must remain explicit.
It does not remove direct URL ownership.
ownerHandleremains the shareable way to open publish flows in a specific owner context.Evidence
Personal account menu
The personal menu keeps account/app actions separate from publisher-scoped actions.
Create organizationis promoted only when there is no org yet, and Stars appears only in the personal context.Header context switch flow
This video shows the header interaction model: open the current publisher menu, use the nested publisher switcher, switch between personal/org contexts, and return to scoped actions for the selected publisher.
Open video directly
Organizations management in personal settings
The Organizations view lists available orgs from the signed-in account, with profile access, management access, role indication, and lightweight skill/plugin metadata.
Personal settings profile
When the active context is personal, Settings edits the user/personal profile rather than an organization.
Organization settings profile
When an org is active, Settings switches to the organization profile and exposes org-specific navigation such as Members and Danger zone.
Publish page context switcher
The skill publish page shows the current publishing owner and allows switching publisher from the publishing surface itself. The menu uses neutral selection styling with a checkmark and keeps personal/org options distinct.
Publish page owner strip
The publish owner strip is attached to the upload card and shows the active publishing owner without extra explanatory copy. It keeps the page focused on the upload task while making the publishing target visible before the user drops a folder.
Testing
bunx vitest run src/routes/-settings.test.tsx src/lib/activePublisher.test.tsx src/routes/-dashboard.test.tsx src/__tests__/header.test.tsx src/__tests__/skills-publish-route.test.tsx src/__tests__/plugins-publish-route.test.tsxbun run ci:staticbunx tsc --noEmitbun run ci:types-buildbun run ci:unit.agents/skills/autoreview/scripts/autoreview --mode branch --base upstream/main --engine opencode --model opencode-go/kimi-k2.7-code --thinking medium --no-web-searchReview notes
A second-model review with Kimi K2.7 Code via Opencode found no accepted/actionable findings after the final rebase.
The review specifically checked the product goal and the highest-risk paths:
ownerHandlepreservation