Problem
Third-party Pi extensions that want to act on the current Pinet persona identity (agent name, emoji, traits) have no first-class way to discover it at runtime. The identity is generated by slack-bridge (generateAgentName / resolveAgentPersonality in slack-bridge/helpers.ts) and woven into the system prompt and Slack messages, but it is not exposed to other extensions via any documented surface.
Concrete example: I just built a voice extension (ElevenLabs TTS, plays every assistant reply through afplay) and want to give every Pinet persona a unique voice — Bear gets a warm/narrative voice, Fox gets a bright/punchy one, etc. Today the only way for that extension to learn its own persona is to regex the system prompt for the identity prefix line (`<name>` reporting from `<host>`). That works but is fragile to any future change in the prefix format.
Proposed solution
Have slack-bridge publish the current persona via two complementary mechanisms:
-
Pi event — emit a persona_changed (or pinet_persona) event on pi.events whenever the identity is resolved, refreshed, or restored from persisted state. Payload shape:
interface PinetPersonaEvent {
name: string; // "Radiant Rose Bear"
emoji: string; // "🐻"
role: "broker" | "worker";
descriptor?: string; // "Radiant"
color?: string; // "Rose"
animal?: string; // "Bear"
traits: string[]; // ["energetic","steady","expressive","resilient"]
stableId?: string; // for cache keys across restarts
}
Fire it once after session_start resolution completes, and again on any setAgentName(...) call.
-
Env var — export PINET_AGENT_NAME, PINET_AGENT_EMOJI, PINET_AGENT_ROLE, PINET_AGENT_TRAITS (comma-separated) in the child pi process environment, so non-extension consumers (skills, shell helpers) can see them too.
Both should be safe to add without breaking existing behaviour — they are additive.
Workaround in use today
In a voice extension I just shipped locally, I parse ctx.getSystemPrompt() in before_agent_start for the identity prefix line. Code sketch:
const m = systemPrompt.match(/'([^\s]+)\s+`([^`]+)`\s+reporting from\s+`([^`]+)`/);
if (m) {
const emoji = m[1];
const name = m[2];
// …pick voice from traits derived from name…
}
This is the same parsing the system prompt itself describes for the agent — fragile but functional. Happy to migrate the extension to a first-class event/env var the moment one exists.
Notes / open questions
- Should the event also include the
personalityGuidelines array, or just the raw traits? My instinct: raw traits + descriptor/animal, and let consumers re-derive any text they want.
- Worth caching the last fired payload so a late-loaded extension can subscribe and immediately receive a
replay via a method like pi.events.getLast("persona_changed").
- Is the
stableId safe to publish? It would help downstream caches like ~/.pi/agent/voice-personas.yaml key on something better than the display name.
Happy to send a PR if the direction is right — let me know which of (1)/(2)/both you want.
Problem
Third-party Pi extensions that want to act on the current Pinet persona identity (agent name, emoji, traits) have no first-class way to discover it at runtime. The identity is generated by
slack-bridge(generateAgentName/resolveAgentPersonalityinslack-bridge/helpers.ts) and woven into the system prompt and Slack messages, but it is not exposed to other extensions via any documented surface.Concrete example: I just built a voice extension (ElevenLabs TTS, plays every assistant reply through
afplay) and want to give every Pinet persona a unique voice — Bear gets a warm/narrative voice, Fox gets a bright/punchy one, etc. Today the only way for that extension to learn its own persona is to regex the system prompt for the identity prefix line (`<name>` reporting from `<host>`). That works but is fragile to any future change in the prefix format.Proposed solution
Have
slack-bridgepublish the current persona via two complementary mechanisms:Pi event — emit a
persona_changed(orpinet_persona) event onpi.eventswhenever the identity is resolved, refreshed, or restored from persisted state. Payload shape:Fire it once after
session_startresolution completes, and again on anysetAgentName(...)call.Env var — export
PINET_AGENT_NAME,PINET_AGENT_EMOJI,PINET_AGENT_ROLE,PINET_AGENT_TRAITS(comma-separated) in the child pi process environment, so non-extension consumers (skills, shell helpers) can see them too.Both should be safe to add without breaking existing behaviour — they are additive.
Workaround in use today
In a voice extension I just shipped locally, I parse
ctx.getSystemPrompt()inbefore_agent_startfor the identity prefix line. Code sketch:This is the same parsing the system prompt itself describes for the agent — fragile but functional. Happy to migrate the extension to a first-class event/env var the moment one exists.
Notes / open questions
personalityGuidelinesarray, or just the raw traits? My instinct: raw traits + descriptor/animal, and let consumers re-derive any text they want.replayvia a method likepi.events.getLast("persona_changed").stableIdsafe to publish? It would help downstream caches like~/.pi/agent/voice-personas.yamlkey on something better than the display name.Happy to send a PR if the direction is right — let me know which of (1)/(2)/both you want.