Last updated

/iblai-vibe-admin

Mirrored from iblai/vibe · skills/users/iblai-vibe-admin/SKILL.md. This page is generated — edit it in the repository, not here.

First time here? If iblai.env has no ARCHITECTURE=, run /iblai-vibe-start first (four questions; two minutes) — it decides single-org / multi-org / headless and who signs in, and every skill reads the answer.

Every app on the platform has two audiences: members (they sign in and use the app) and org admins (they manage users, agents, spend, memory, and branding). This skill is the pattern vibe-starter uses for both, and the map of every admin surface the SDK already ships.

Admin mode — the admin cluster in the navbar
Admin mode — the admin cluster in the navbar
User mode — the same app as a member sees it
User mode — the same app as a member sees it
/admin/users — Management + invitations
/admin/users — Management + invitations

Common setup (brand, conventions, env files, verification): see docs/skill-setup.md.

The model in three sentences

  • The platform has two predefined roles per org — Admin and User — plus optional policies (RBAC) for finer grants; an admin implicitly holds every policy.
  • An app learns who is an admin from the tenants list the sign-in stored: isTenantAdmin() = the is_admin flag on the entry whose key is the org the app is pinned to. Not the SDK's useIsAdmin(), which answers for the SDK's current organization — they can differ.
  • Admins get a User / Admin switch; in User mode they see exactly what a member sees. Admin-only UI gates on adminMode (admin and switched on); anything that must stay admin-only regardless of the view gates on isTenantAdmin().

Until your app has an admin area, os.ibl.ai is your admin console: Admin mode → settings → Management / Integrations / Billing / Memory / Organization.

What you get (vibe-starter ships it)

PieceFileDoes
isTenantAdmin(), readTenants()lib/iblai/tenant.tsthe rule above
AdminModeProvider, useAdminMode()lib/iblai/admin-mode.tsxview state: default Admin, resets on reload
AdminModeSwitchcomponents/navbar/admin-mode-switch.tsxthe switch (hidden for members)
AccountPanelcomponents/admin/account-panel.tsxone SDK Account surface opened on a tab, full-width
/admin/usersapp/(app)/admin/users/page.tsxUsers · Groups · Roles · Policies · Teams · Alerts + InviteUserDialog / InvitedUsersDialog
/admin/analytics/*, /admin/billing, /admin/memory, /admin/organizationapp/(app)/admin/…/iblai-vibe-analytics, -billing, -memory, -org-metadata surfaces
route gateapp/(app)/layout.tsxadmin links only when adminMode; /admin/* redirects home otherwise
requireAdmin(req)lib/iblai/platform.tsserver-side proof for admin routes (/iblai-vibe-api)

Step 1: Install (existing app)

Render the assets (strip .j2; no variables): admin-mode.tsx.j2 → lib/iblai/admin-mode.tsx, admin-mode-switch.tsx.j2 → components/navbar/admin-mode-switch.tsx, account-panel.tsx.j2 → components/admin/account-panel.tsx, admin-users-page.tsx.j2 → app/(app)/admin/users/page.tsx, tenant.test.ts.j2 → __tests__/tenant.test.ts. Add readTenants / isTenantAdmin to lib/iblai/tenant.ts (copy them from vibe-starter). Needs shadcn switch.

Step 2: Wire the layout

In the authenticated layout: read the session once, wrap the tree in AdminModeProvider, split nav links into member and admin arrays, render the admin ones only when isAdmin && adminMode, and redirect /admin/* home otherwise. vibe-starter's app/(app)/layout.tsx is the reference — copy it.

const liveAdmin = isAdmin && adminMode;
const links = liveAdmin ? [...MEMBER_LINKS, ...ADMIN_LINKS] : MEMBER_LINKS;
useEffect(() => {
  if (pathname.startsWith("/admin") && !liveAdmin) router.replace("/");
}, [pathname, liveAdmin, router]);

Put <AdminModeSwitch /> in the navbar's right cluster (and in the profile menu on narrow screens if you have one).

Step 3: Pick the admin surfaces

AccountPanel tab="…" mounts the SDK Account on one of: organization, management, integrations, advanced, billing, memory, monetization. Each is documented by its own skill:

Admin needTab / componentSkill
Users: role Admin/User, policies, activate/deactivate, searchmanagement → Usersthis skill; REST management
Invite (single, CSV: email, first_name, last_name, platform_key, company_name, user_group)InviteUserDialog, InvitedUsersDialog/iblai-vibe-invite
Roles and policies (custom grants)management → Roles / Policies (RolesTab, PoliciesTab)/iblai-vibe-rbac
Groups, teams, alertsmanagement/iblai-vibe-account
LLM keys, data-source credentials, API tokensintegrations/iblai-vibe-account, /iblai-vibe-credential
Default agent, feature toggles, help URLadvanced/iblai-vibe-account
Plan, credits, spend capsbilling/iblai-vibe-billing, /iblai-vibe-pricing
Everyone's memoriesmemory/iblai-vibe-memory
Name, logos, support email + your app's org settingsorganization + OrgSettingsForm/iblai-vibe-org-metadata
Sell itemsmonetization/iblai-vibe-monetization
Org-wide analytics, per-agent with ?agent=AnalyticsLayout + tabs/iblai-vibe-analytics
Directory sync— (REST only)scim

For sharing one agent with editors/chat users, use the agent's Access tab (/iblai-vibe-agent-access), not org roles.

Step 4: Admin-only server work

Anything an admin does for someone else (write another user's metadata, create an agent, send a notification) is a server route that first proves the caller is an admin — requireAdmin(req) from /iblai-vibe-api — then uses the org's key. Never trust a client-side isAdmin for a write.

Verify

  1. pnpm typecheck && pnpm test (__tests__/tenant.test.ts).
  2. Sign in as an admin: the switch and the admin links are there; flip to User: they vanish and /admin/users sends you home. Sign in as a member: no switch at all.
  3. Touch test /admin/users in the browser as /iblai-vibe-ops-test says: the Management surface and the Invite button are there; open and cancel the invite dialog.
  • /iblai-vibe-rbac — roles, policies, action strings, checkRbacPermission
  • /iblai-vibe-invite — the invitation dialogs
  • /iblai-vibe-account — the SDK Account page as one modal
  • /iblai-vibe-api — admin routes

Copyright © ibl.ai | support@iblai.zendesk.com