.agents/skills/opik-frontend/permissions.md
Every new or modified component in apps/opik-frontend/src/ that performs a guarded action (create, delete, edit, configure, or view gated content) should be evaluated for permission guards.
Read the current permissions in apps/opik-frontend/src/plugins/comet/PermissionsProvider.tsx. This file lists all available permission flags (e.g., canCreateDatasets, canDeleteTraces, canViewDashboards).
Check if sibling or similar components use usePermissions(). If nearby components in the same page or feature already consume permissions, the new component likely needs them too.
Logically match the UI action to a permission flag. Do not rely on naming patterns — reason about what the component does and which permission governs that action:
canViewExperiments, canViewDashboards, canViewDatasets)canCreateDatasets, canCreateProjects)canEditDashboards, canEditDatasets)canDeleteTraces, canDeletePrompts)canConfigureWorkspaceSettings, canUpdateAIProviders)canAnnotateTraceSpanThread, canTagTrace, canWriteComments)If a logically matching permission exists, do NOT add it automatically. Instead, inform the user which permission you believe matches and why, then ask for confirmation before adding the guard.
If no matching permission exists, inform the user:
When applying a permission, use the pattern appropriate to the context:
Page-level access control — wrap entire pages with a guard component:
const { permissions: { canViewDashboards } } = usePermissions();
return (
<NoAccessPageGuard resourceName="dashboards" canViewPage={canViewDashboards} />
);
Conditional rendering of actions — hide buttons or menu items:
const { permissions: { canCreateDatasets } } = usePermissions();
return (
<>
{canCreateDatasets && (
<Button onClick={handleCreate}>Create dataset</Button>
)}
</>
);
Disabling queries — prevent unnecessary API calls:
const { permissions: { canViewDatasets } } = usePermissions();
const { data } = useDatasetsList(params, {
enabled: canViewDatasets,
});
Read-only component states — render immutable versions instead of hiding:
const { permissions: { canTagTrace } } = usePermissions();
const tagsProps = canTagTrace
? { tags }
: { tags: [], immutableTags: tags };
Not all UI actions have permission guards yet. This is expected. Do not add guards speculatively; only add them when a logically matching permission flag exists in PermissionsProvider.tsx or the user confirms a new one should be created.
SideBarMenuItems.tsx)enabled to prevent thisv1/, the equivalent v2/ component should also be guarded, and vice versaapps/opik-frontend/src/types/permissions.tsapps/opik-frontend/src/contexts/PermissionsContext.tsxapps/opik-frontend/src/plugins/comet/PermissionsProvider.tsxapps/opik-frontend/src/plugins/comet/useUserPermission.tsapps/opik-frontend/src/plugins/comet/types.ts (ManagementPermissionsNames)