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

voice-persona

v0.2.0

Published

Reference parser, validator, and types for the voice.persona spec — Apache-2.0.

Readme

voice.persona

A file format for voices that have a point of view — identity, idiolect, scene modulation, and refusals in one versioned artifact.

voice.persona is the spec; this package is the reference parser, validator, and TypeScript types. Apache-2.0. The runtime that compiles personas onto a TTS backend is separate (and not Apache-2.0); the spec is.

The full spec lives in SPEC.md.

Why

Most TTS treats voice as a timbre. A character whispering at 2am and rallying allies in a fight ends up sounding identical. voice.persona makes the point of view — values, idiolect, scene-aware delivery — first-class, versioned, and forkable.

Hello world

spec_version: "0.2"
id: "you/first_persona"
version: "0.1.0"
name: "First Persona"
locale: "en-US"

identity:
  tagline: "A calm, curious listener."
  archetype: "confidant"

idiolect:
  signatures: ["Okay. Tell me more."]
  warmth: "high"
  directness: "mid"

voice:
  timbre: { warmth: "high", pitch: "mid", texture: "soft" }
  prosody: { rate: "steady", energy: "low", arousal: "low", valence: "positive" }

safety:
  age_gate: "13+"

author: { handle: "you", url: "https://example.com" }
license: "CC-BY-4.0"

Fifteen lines of signal. Everything else in SPEC.md is optional refinement.

Install

npm install voice-persona

Use

import { parseVoicePersona } from "voice-persona";
import { readFileSync } from "node:fs";

const persona = parseVoicePersona(readFileSync("warm_confidant.persona.yaml", "utf8"));
console.log(persona.identity.tagline);

The package is pure — no file I/O of its own. Wrap with whatever runtime gives you bytes (Node fs, Deno, Bun, fetch in a browser, an edge runtime).

For JSON personas, the parser auto-detects:

parseVoicePersona('{"spec_version": "0.2", "id": "you/x", ... }');

Or force the format explicitly:

parseVoicePersona(text, { format: "yaml" });

Validation

parseVoicePersona runs the validator before returning. Bad input throws PersonaValidationError with a path-prefixed message ($.identity.tagline: expected non-empty string). Validate without parsing:

import { validateVoicePersona } from "voice-persona";
validateVoicePersona(alreadyParsedObject); // throws on bad shape

Importing from Tavern Card v2

voice.persona ships a CCv2 importer for the chub.ai / SillyTavern character card format. The mapping is lossy by design — CCv2 carries a character as free-form prose; v0.2 expects structured idiolect, voice, and scene fields. The importer fills what it can and surfaces what it can't via a warnings array. No LLM. No prosody guessing.

import { importTavernCard } from "voice-persona";
import { readFileSync } from "node:fs";
import { stringify as yamlStringify } from "yaml";

const card = JSON.parse(readFileSync("seraphina.card.json", "utf8"));
const { persona, warnings } = importTavernCard(card);

console.log(yamlStringify(persona));        // ready to commit
console.warn(warnings.join("\n"));          // what to review

Mapping

| CCv2 field | voice.persona target | |-------------------------------|---------------------------------------------------| | data.name | name, slug → id as imported/<slug> | | data.description | identity.description | | data.personality | identity.tagline (first sentence, ≤100 chars) | | data.first_mes | greetings[0] | | data.alternate_greetings[] | greetings[1..] | | data.mes_example | examples[] (one per <START> block) | | data.creator | author.handle | | data.character_version | version (default 1.0.0) | | data.creator_notes | extensions["chub.ai/creator_notes"] | | data.tags[] | extensions["chub.ai/tags"] | | data.extensions.* | extensions["chub.ai/*"] (preserved verbatim) | | data.scenario | dropped (per-chat, not per-character) | | data.system_prompt | dropped (runtime concern) | | data.post_history_instructions | dropped (runtime concern) | | data.character_book | dropped (lorebook — preserved when v0.3 lands) |

Defaults applied when the card doesn't carry the field: locale: "en-US", safety.age_gate: "13+", license: "NOASSERTION" (SPDX standard for "unknown provenance"), no voice, no idiolect, no scenes. The importer always warns "idiolect, voice, scenes are empty — fill them in or this persona will sound generic." Treat the imported file as a first draft, not a finished persona.

Examples

examples/starters/ ships the 8 canonical starter personas — Apache-2.0, fork them. Drop them into your runtime and call them by id (himaia/warm_confidant, himaia/skeptical_buyer, etc.) or copy the file and rename for your own roster.

Status

v0.2.0 — first public release. The spec is stable enough to ship against but expect minor refinements as real authors push on it. See CHANGELOG.md for the version policy.

Contributing

Spec issues and clarifications: open a GitHub issue. Reference parser bugs: same. Major changes (new fields, new merge operators, breaking shifts) require a written spec RFC in the issues — discuss before sending a PR.

License

Apache-2.0. See LICENSE. The spec, the reference implementation, and the example starters are all Apache-2.0. Any persona file you author is yours; the example starters carry CC-BY-4.0 attribution per author / license fields in each file.

Made by himaia · © Fuse Link Inc.