Multi-tenant persona layer adds org management and firm-level system-prompt injection

Chris-o-O repositions Mike from a single-user tool into something deployable at a law firm: organizations, member roles, and a persona block that injects org context into every system prompt. The `en`/`fr` language flag and `bar_number` field hint at a Canadian/bilingual market.

multi-tenantpersonas

Migration 002_personas.sql adds organizations, organization_members, and organization_invites tables, then extends user_profiles with org_id, user_role, practice_areas, user_custom_instructions, and bar_number. RLS is enabled on all three new tables; service-role backend traffic bypasses it. The /organizations/* REST module (444 lines) covers the full org lifecycle: create, join, edit, invite, member management. A /user/persona GET/PATCH endpoint handles individual profile updates.

The most portable piece is persona.ts, roughly 100 lines. It assembles a USER & ORGANISATION CONTEXT: block from org name, jurisdictions, practice areas, language, user role, firm-level instructions, then user-level instructions - and chat.ts and projectChat.ts inject it into every request. This block is provider-agnostic and small enough to lift independently of the org tables if your fork only needs per-user context.

Several things to audit before adopting. Invites are keyed by email with no requirement that the invitee verifies ownership before accepting membership. bar_number is plaintext, no format validation. Most significant: user_custom_instructions is injected verbatim into the system prompt, so anyone with profile-edit access can change how the assistant behaves for themselves. An org admin can do the same to the whole firm via custom_instructions. That prompt-injection surface is worth a hard look before firm deployment. Migration 002 also redundantly re-adds openrouter_api_key - already present from migration 001, but safe because it uses if not exists.

The PR is large (~1,420 lines, including two 444-line files) and ships without tests.

So what Worth a look if you want firm-level deployment with shared org context and role-aware system prompts. The persona-injection design is the genuinely portable piece. Skip if you need single-user simplicity or can't accept the prompt-injection surface as-is.

View this fork on GitHub →

Spotted something wrong? Or know the PR text has fresher detail than the writeup above?

Commits in this thread

2 commits from Chris-o-O/mike-intell, oldest first. Source extracted verbatim from the harvested git log.

SHA Subject Author Date
a64edcdc Merge pull request #1 from Chris-o-O/claude/add-features-rEBxK Chris-o-O 2026-05-07 ↗ GitHub
Add organizations, semantic search, and user personas
4f16dc2b feat: personas, company/team management, organisation context injection Claude 2026-05-08 ↗ GitHub
commit body
- Company & Team tab: create/join/edit orgs, manage members and invites, admin roles
- My Profile section in General tab: role, practice areas, bar number, personal AI instructions
- DB: organizations, organization_members, organization_invites tables + user_profiles persona columns
- Persona context injected into every chat and project chat system prompt
- REST API: /organizations/* CRUD + /user/persona GET/PATCH
- Textarea UI component

https://claude.ai/code/session_01NJxa5NasJ9qhaMkzEyqr2u

Capture this thread into my fork

Download a single Markdown prompt that tells Claude how to port every commit above into your working tree — adapting paths and structure to match your repo. Run it via claude -p < capture-thread-173.md from inside the repo you want the changes in.

⬇ Download capture-thread-173.md