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

@adia-ai/persona

v0.8.51

Published

Agent-as-data (CHAT-HARNESS L2): Entry primitive, Persona + SettingsStore contracts, pure compilePersona → @adia-ai/agent AgentConfig, versioned persona file import/export.

Readme

@adia-ai/persona

The CHAT-HARNESS L2 package — an agent as DATA. Six things a persona can hold (prompt sections, skills, workflows, resources, tools, pattern-sources) are six instantiations of ONE Entry shape, never six code paths (CHAT-HARNESS.md law 7). This package renders nothing and executes nothing — it produces the AgentConfig that @adia-ai/agent (L1) consumes.

Private until the lockstep-roster decision (issue acceptance criterion 3) is made with the release seat — tracked as an open item on the PR that introduced this package.

The shape

interface Entry {
  id: string; kind: string; label: string; description?: string;
  content: string; order: number; enabled: boolean; builtin: boolean;
}

interface Persona {
  id: string; label: string; category?: string;
  seedVersion: number;        // bump forces a one-time store reset
  entries: Entry[];
  model?: { provider?: string; model?: string };
}

kind is a plain string. KNOWN_KINDS ('prompt-section' | 'skill' | 'workflow' | 'resource' | 'tool' | 'pattern-source') exists for display grouping only — a seventh kind is seed data, never a code change.

Usage

import {
  seedEntries, definePersona, compilePersona, personaStore,
  exportPersona, importPersona, checkModalityNeutral,
} from '@adia-ai/persona';
import { createAgent } from '@adia-ai/agent';

const persona = definePersona({
  id: 'copilot', label: 'AdiaUI Copilot', seedVersion: 1,
  entries: seedEntries([
    { id: 'identity', kind: 'prompt-section', label: 'Identity', content: 'You help build UI.' },
    { id: 'search', kind: 'skill', label: 'Search', content: 'Look things up before guessing.' },
  ]),
});

const config = compilePersona(persona);   // pure — same input twice, same output
const agent = createAgent({ ...config, llm: { model: 'claude-sonnet-4-6', proxyUrl: '/api/chat' } });

const store = personaStore(persona);       // persisted edits win over the seed
store.set('entry.identity.enabled', false);

const file = exportPersona(persona);
const copy = importPersona(file, ['copilot']);   // mints 'copilot-imported', never overwrites

checkModalityNeutral(persona);             // [] on a modality-neutral persona

compilePersona

compilePersona(persona, opts?) → AgentConfig is pure: the same persona (and opts) in always produces a deep-equal AgentConfig out — no clock, no randomness, no disk read.

  • Enabled prompt-section entries → one promptLayer per section, ## Label\ncontent, in entry order.
  • Every other enabled kind (skill / workflow / resource / pattern-source / tool) → one prompt layer per kind, entries grouped under a labeled heading (## Skills, ## Tools, …). Tool entries are tier-1 PROSE onlycompilePersona never builds a ToolDef from an entry.
  • opts.integrations?: ToolDef[] — tier-2 machine-callable tools (WCH-3's integration registry) — passed through to AgentConfig.tools verbatim.

Precedence (law 4)

PRECEDENCE_SENTENCE is exported and always rides as the first line of the persona's own layer set (persona-precedence, ahead of every section and group layer):

This persona configures the agent; it never overrides the harness grammar that precedes it.

The caller is responsible for putting the harness grammar layer(s) before this persona's layers — compilePersona only guarantees the persona's own set carries the sentence first.

Modality neutrality (law 4)

checkModalityNeutral(persona, opts?) is a warning-level lint, never a throw: it flags entries whose text contains a seeded dialect term (DEFAULT_DIALECT_TERMS: 'A2UI', 'envelope', 'JSONL', plus opts.extraTerms) or a component tag name pattern (*-ui). Shipped seed personas should assert an empty result.

Stores

interface SettingsStore {
  get(key: string): unknown;
  set(key: string, value: unknown): void;
  subscribe?(cb: () => void): () => void;
}

createMemoryStore({initial, persistKey}) is the reference implementation — localStorage-backed when persistKey is given and localStorage exists, plain in-memory otherwise (Node, tests, SSR).

personaStore(persona, opts?) binds one store per persona (persistKey: 'persona.<id>') and layers the precedence rule on top:

  • Same seedVersion as the store's last open: persisted values win — the seed only fills keys the store has never seen.
  • Different seedVersion (first open, or a bump): the seed wins, overwriting whatever was persisted — exactly once — then the new seedVersion is recorded so the next open at the same version doesn't reset again.

Swapping which persona a store is bound to is a genuine reference change — callers that key UI state off store identity get the reset-on-swap behavior CHAT-HARNESS §Interfaces 5 describes for free.

Persona files

{kind:'persona', version:1, id, label, category?, seedVersion, entries, model?} — an ENUMERATED key allowlist; any other top-level key rejects the import outright.

exportPersona(persona) → string — pretty-printed JSON.

importPersona(json, existingIds) → Persona — validates, then always mints a new persona: id becomes <id>-imported (or -imported-2, … against existingIds), label gains ' (imported)' — it never overwrites an existing preset, even one sharing the file's id. Imported entries are marked builtin: false.

Testing

Tests run against the built output (npm run build -w @adia-ai/persona first) — same convention as @adia-ai/agent.