npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@pugi/plugin-personas

v0.1.0-alpha.2

Published

Pugi persona registry plugin - loads curated persona packs plus user overrides, classifies user messages, and injects layered system prompts into the Pugi chat surface.

Downloads

68

Readme

@pugi/plugin-personas

Persona registry + keyword classifier + system-prompt assembly for the Pugi runtime. Ships as part of the Pugi 1.0 soft fork sprint (see ADR-0081).

The npm name is @pugi/plugin-personas. There is also a sibling package @pugi/personas in this monorepo that ships the Cyber-Zoo brand persona roster used by the landing and Console. The two coexist by intent. The brand roster does not import this plugin and this plugin does not import the brand roster.

What it does

  • Loads a curated persona pack at startup (pugi-default 8 personas or pugi-extended 16 personas), then optionally merges in *.persona.json files from a configurable personaDir.
  • Caches the last user-message text per session via the chat.message hook (bounded LRU, 256 sessions).
  • Resolves the active persona for each session: explicit override first, else keyword classifier, else the configured default.
  • Pushes a layered system-prompt block to experimental.chat.system.transform. Layered budget: Pugi global rules + persona prompt + few-shot examples, trimmed to a configurable per-persona token budget (default 1500 tokens).
  • Exposes pugiPersonaPreferredModel, pugiPersonaFallbackModel, and pugiPersonaSlug on the chat.params options bag so a future @pugi/plugin-anvil-provider patch can route on persona.
  • Registers tools pugi.persona.list, pugi.persona.get, pugi.persona.active, pugi.persona.switch.
  • Registers the slash command /persona <slug> [reason] so the operator can pin the persona mid-session.

Install

pnpm add @pugi/plugin-personas

Configuration

// pugi.config.ts
import type { Config } from '@pugi-ai/plugin';

export default {
  plugin: [
    [
      '@pugi/plugin-personas',
      {
        personaPack: 'pugi-default',           // or 'pugi-extended' or 'custom'
        personaDir: '~/.pugi/personas',        // user-supplied overrides
        defaultPersona: 'pugi',                 // coordinator (never 'mira', never 'oes-dev')
        enableAnimalAvatars: false,             // TUI text only; web avatars opt-in
        personaSlugRoutingMap: {                // exact substring overrides for the classifier
          'design system review': 'marcus',
        },
      },
    ],
  ],
} satisfies Config;

Persona schema

Each persona is a JSON object:

{
  "slug": "marcus",                  // /^[a-z][a-z0-9-]*$/, never reserved
  "name": "Marcus",
  "role": "architect",
  "expertise": ["system-design", "adr-writing"],
  "systemPrompt": "You are Marcus, the system architect ...",
  "fewShotExamples": [               // optional, capped at 3
    { "user": "...", "assistant": "..." }
  ],
  "preferredModel": "qwen3-coder-480b",
  "fallbackModel": "deepseek-coder-v2-16b",
  "brand": {
    "animal": "wolf",                // informational; TUI never renders it
    "accentColor": "oklch(0.45 0.10 260)",
    "tagline": "System architect."
  },
  "voiceRules": ["pugi-voice-default"]
}

Roles (capability scopes)

Roles and personas are orthogonal. A user-facing surface displays the persona name; the role is the SDLC capability scope it covers.

| Role | Persona examples | | --- | --- | | coordinator | Pugi | | product-planner | Olivia, Sofia, Yuki | | architect | Marcus, Sigma | | dev-producer | Olivia, Daniel | | builder | Hiroshi, Tom | | reviewer | Priya, Omar, Anika | | release | Diego | | out-of-sdlc | Hannah, Mateo, Lena |

Bundled pack matrix

pugi-default (8): pugi, hiroshi, marcus, olivia, priya, omar, diego, sigma.

pugi-extended (16): the eight above plus sofia, yuki, daniel, tom, anika, hannah, mateo, lena.

Routing logic

The classifier is keyword-based and deterministic (no LLM). Precedence:

  1. Explicit personaSlugRoutingMap substring match (operator-set).
  2. Ranked keyword rules (security, devops, architecture, review, product, QA, builder).
  3. Default fallback (defaultPersona, default pugi).

If the classifier ever returns a reserved or unknown slug the registry refuses it and the coordinator (pugi) takes over. The oes-dev slug is never selected as a fallback, ever.

Safety rails

  • mira, codeforge, oes-dev are reserved slugs. Custom files using them get rejected with a startup warning.
  • Any Mira string inside a persona systemPrompt is rewritten to Pugi with a mira-mention-rewritten warning.
  • Codeforge strings inside persona content are rewritten to Pugi.

Token budget

Total prompt budget before the user message: 8000 tokens.

| Layer | Budget (approx) | | --- | --- | | Pugi global rules | ~80 tokens | | Active persona prompt + tagline | 1500 tokens (configurable) | | Few-shot examples (max 3) | sized to fit within persona budget | | Other plugins (codegraph, RAG) | up to the remaining ~6400 tokens |

Token approximation: Math.ceil(textLength / 4). Same convention as @pugi/plugin-codegraph.

Console / Web surface

The plugin runs in the Pugi server, not in the Console web app. The console-web app consumes persona data via the separate @pugi/personas brand roster, which exports a curated subset (THE_TEN). The plugin's persona registry is exclusively for runtime system-prompt shaping.

Tools

| Tool | Args | Returns | | --- | --- | --- | | pugi.persona.list | {} | array of {slug,name,role,tagline} | | pugi.persona.get | {slug} | full Persona JSON or {error:'not-found'} | | pugi.persona.active | {} | {slug, sessionID} | | pugi.persona.switch | {slug, reason?} | text confirmation |

Slash command

/persona <slug> [reason] switches the active persona for the session. /persona with no args lists every loaded persona and the matching role.

License

MIT. See LICENSE.