- Add user management: admins can invite teammates as member or admin, list, and delete users from a new Users page (
/settings/users). Invites and password resets are delivered as single-use, 7-day links — only a sha256 hash is stored server-side, the raw token lives only in the link. A public set-password page redeems a link, sets an Argon2 password, and logs the user in; everyone can self-service change their password from a new Account page. Passwords stay one-way hashed (no reversible encryption). Deleting yourself or the last remaining admin is blocked. Schema addsusers.status(invited/registered) + a nullablepassword_hashand a newuser_link_tokenstable (migration0025). Six new audit actions thread the acting user through every write. - Enforce role-based access control in the UI to match the existing API guards. A new
AdminRouteguard redirects non-admins to/dashboardbefore admin pages mount, and the sidebar hides Audit Log, Tokens, Integrations, and Users from members — previously a member could open these and land on a 403-broken view. - Gate the onboarding walkthrough by role and telemetry state. Onboarding auto-mints an admin-only OTLP token, so members now route straight to
/dashboardinstead of hitting "Forbidden"; admins skip it too once telemetry is flowing (a Loki integration exists or OTLP push has events). The guard lives inOnboardingPage, so it also covers direct-URL entry and reloads. - Resolve invite/reset link base URLs from the browser Origin (falling back to
window.location.origin) instead of the backend request URL, so links point at the frontend rather than the API port./api/confignow returns the explicitly-configuredPUBLIC_BASE_URLornull, andapiFetchunwraps{ error }bodies so pages show the message instead of raw JSON. - Set the documented default
ADMIN_PASSWORD_INITIALtoadmin12345across.env.example, Docker compose, and the README.
- Support self-hosted GitLab marketplace sources. A source now carries an explicit
provider(auto/github/gitlab/bitbucket, selectable in the add-source form); GitLab content — bothmarketplace.jsonand each plugin'sskills/listing — is fetched through the GitLab REST API ("get raw file" and repository-tree endpoints) instead of the/-/raw/web route, which 302-redirectedPRIVATE-TOKENauth to the sign-in page and 404'd private repos. The provider origin is derived from the source git URL so any GitLab host is targeted, not justgitlab.com; this also fixes privategitlab.comrepositories that previously failed the same way. External-plugin token forwarding is now restricted to the same host and origin so a token can't leak across GitLab instances. Migration0024adds theprovidercolumn (defaultauto, preserving existing behavior).
- Promote skill identity from
(skill_name, plugin_name)to the full tuple(skill_name, plugin_name, marketplace_name, skill_source). The same plugin-less skill observed from user settings vs project settings (and per source) are now independent rows in the Skills table with independent approve/deny/ignore status, instead of silently collapsing into one. The status, bulk-status, and delete APIs carry the full key end-to-end; event deletion is scoped byskill.sourceso removing one identity no longer takes out another's events. - Fix a runtime crash when a marketplace source declared the same skill in more than one plugin:
external_skill_plugin_mappingskeyed only onskill_name, so a single upsert batch carrying a skill twice failed withON CONFLICT DO UPDATE command cannot affect row a second time. Its primary key is now(skill_name, plugin_name, marketplace_name), letting a skill legitimately belong to several plugins. Migrations0022and0023widen the two primary keys (idempotent; existing rows are preserved). - Surface redacted
third-partyplugins in the Plugins catalog instead of dropping them. Claude Code reports every anonymous (non-marketplace) plugin under the shared namethird-party, carrying its real identity inplugin_id_hash; these are now synthesized at query time as one catalog row per hash (labeledthird-party · <hash>) with their load and unique-loader counts and a per-hash weekly-loaders chart. The rows are read-only — they own no skills and have no stored catalog entry, so bulk-select and status editing are disabled. As before, they remain hidden until the "Show plugins without skills" toggle is on.
- Expand the Co-usage combo drawer with a per-session timeline view that renders each session's skill activations in chronological order, color-coded by skill, so the order in which skills fire within a combo is observable rather than just their co-occurrence. Backed by a new
GET /api/co-usage/sessions/:sessionId/timelineendpoint that returns ordered(skillName, pluginName, timestamp)events for a given session.
- Add Packmind as a second kind of marketplace source alongside git-backed ones: instead of cloning a
marketplace.json, Packmind sources are fed by the@packmind/clibinary (packages list/packages show <slug>), and each Packmind package becomes a plugin keyed by its@space/slug. The marketplace-source form now exposes a kind selector, Packmind rows carry a "Packmind" badge, and "Test connection" runspackmind-cli whoamifor Packmind sources. The Docker image installs@packmind/cliglobally sopackmind-cliis onPATHout of the box. - Add an
external_skill_plugin_mappingstable (with an in-memory cache refreshed after every Packmind sync) consulted at OTLP ingest time, soskill_activatedevents from Packmind telemetry — which don't carryplugin.name— retro-link to their owning plugin instead of creating orphan rows. - Add a "Repository" link at the bottom of the sidebar pointing to the GitHub repo.
- Flip the StatusChip dropdown above its trigger when there isn't enough room below, so the status menu on the last row of the Skills table no longer gets clipped under the viewport.
- Pluralize the
Sessionscolumn header in the Skills table.
- Add a Co-usage page that surfaces groups of skills (pairs, triples, 4+) recurring inside the same
session_id, with an Ignore-noise filter that re-projects sessions when omnipresent skills are excluded. - Add a
Sessioncolumn to the Skills table (betweenUsersandLoaders) showing the count of distinct sessions in which each skill was activated over the selected window.
- Surface the owning plugin under the skill name with a chip for
plugin:skillentries, and strip the redundant prefix from the displayed name. - Replace the plugin chip link with a hover menu offering two disambiguated actions: filter the Skills table by the plugin, or jump to the plugin's page.
- Track
plugin_loadedevents to surface adoption-funnel metrics (loaders vs. activations), including a weekly unique-loaders chart in the plugin drawer. - Track plugin version history in a new
plugin_versionstable so version drift across loads is observable. - Include
plugin_loadedin the default Loki query (and backfill the earliest-default lookup) so existing integrations capture the new event without manual edits. - Harden the separation between session JWTs and OTLP ingestion tokens, and gate admin-only routes accordingly.
- Speed up the Skills usage table with a
plugin_loadedpartial index, and stop refetching the Skills/Plugins tables on every window focus. - Converge Skills, Plugins, and Marketplaces pages onto the shared design system primitives, with consistent header styling, status indicator strips, and tooltips on non-obvious columns.
- Surface stat-card explanations via a HelpTip popover on the Dashboard.
- Drop
HH:MMfrom the relative-time fallback for cleaner timestamps.
- Trigger an immediate sync when a new Loki integration is saved, so users see data without waiting for the first interval tick.
- Publish a GitHub Release on every
release/x.y.ztag, using the matchingChangelog.mdsection as the release body.
- Fix deployment issues.
- First initial release.