Skip to content

Personas with provenance

IdentitySDKHTTPCLIMCPDashboardlt.personas.seedgranted_by_personaassign_personaltc personas

A persona bundles roles at chosen scopes; assigning it writes ordinary memberships that remember which persona sustains them.

The situation

A production lead needs write access to packing and review, and read access to shipping. Every new lead needs the same set. When the job changes, the set should change for everyone holding it, without touching grants an admin made by hand.

The recipe

seed/personas.ts
import { createClient } from '@hotmeshio/long-tail';
const lt = createClient({ auth: { userId: adminId } });
await lt.personas.seed([
{
key: 'production-lead',
title: 'Production lead',
description: 'Works packing and review, watches shipping.',
roles: [
{ role: 'packing', relationship: 'write-all' },
{ role: 'review', relationship: 'write-all' },
{ role: 'shipping', relationship: 'read-all' },
],
},
]);
relationship read_scope write_scope
write-all all all
write-self all self
read-all all none

Assign with POST /api/users/:id/personas, lt.personas.assign, ltc personas, or the assign_persona MCP tool. Each role brings its own pins, list schema and form schema, so one assignment composes the member’s whole dashboard.

The guarantee

Personas are not a second authorization path: assignment fans out to ordinary lt_user_roles rows. Each row carries granted_by_persona, so unassigning removes only the rows that persona sustains, and a row a sibling persona still grants is re-homed instead of removed. Highest allowance wins per role. The seed is idempotent and reconciles every current holder in the same transaction. See Identity.