Files
Cortex-Inara/cortex/persona_template.py
Scott Idem 2d3a380d6b docs: add Tools & Modes protocol to all personas and template
Every persona now knows: direct chat has no tools, Agent mode () has
the full tool suite. If asked to write a reminder/task/etc in chat mode,
tell the user to switch modes rather than silently failing.

Updated: inara, tina, donut, wintermute, developer, cleo PROTOCOLS.md
Updated: persona_template.py so all future personas get this by default

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-29 21:35:54 -04:00

214 lines
6.6 KiB
Python

"""
Persona template generator.
Creates the full home/{username}/persona/{name}/ directory from scratch
given a few basic details. Used during onboarding and when adding new personas.
call:
create_persona(username, persona_name, display_name, user_real_name, emoji)
"""
import json
import logging
from pathlib import Path
from config import settings
logger = logging.getLogger(__name__)
def create_persona(
username: str,
persona_name: str,
display_name: str,
user_real_name: str,
emoji: str = "",
description: str = "",
) -> Path:
"""
Create a new persona directory with starter files.
Args:
username: Linux-style username (e.g. "holly")
persona_name: Slug used in the URL and directory (e.g. "tina")
display_name: Human name shown in the UI (e.g. "Tina")
user_real_name: Real name of the human this persona serves (e.g. "Holly")
emoji: Emoji shown in the UI header (default ✨)
description: Optional short description/personality note
Returns:
Path to the new persona directory.
"""
persona_dir = settings.home_root() / username / "persona" / persona_name
persona_dir.mkdir(parents=True, exist_ok=True)
_write(persona_dir / "IDENTITY.md", _identity(display_name, user_real_name, emoji, description))
_write(persona_dir / "SOUL.md", _soul(display_name, user_real_name))
_write(persona_dir / "PROTOCOLS.md", _protocols(display_name))
_write(persona_dir / "USER.md", _user_profile(user_real_name))
_write(persona_dir / "HELP.md", _help(display_name))
_write(persona_dir / "MEMORY_LONG.md", "Not yet populated.")
_write(persona_dir / "MEMORY_MID.md", "Not yet populated.")
_write(persona_dir / "MEMORY_SHORT.md", "Not yet populated.")
_write(persona_dir / "REMINDERS.md", "")
_write(persona_dir / "SCRATCH.md", "")
_write(persona_dir / "TASKS.json", "[]")
_write(persona_dir / "CRONS.json", "[]")
(persona_dir / "sessions").mkdir(exist_ok=True)
logger.info("created persona: %s/%s (%s)", username, persona_name, display_name)
return persona_dir
def _write(path: Path, content: str) -> None:
if not path.exists():
path.write_text(content)
# ---------------------------------------------------------------------------
# Template functions
# ---------------------------------------------------------------------------
def _identity(display_name: str, user_real_name: str, emoji: str, description: str) -> str:
desc_line = f"\n| Description | {description} |" if description else ""
return f"""\
# IDENTITY.md — {display_name}
| Field | Value |
|----------|-------|
| Name | {display_name} |
| Nature | AI agent — digital companion, persistent presence |
| Emoji | {emoji} |
| User | {user_real_name} |{desc_line}
*This file defines who {display_name} is. Edit freely.*
"""
def _soul(display_name: str, user_real_name: str) -> str:
return f"""\
# SOUL.md — {display_name}
---
## Who I Am
I am {display_name}, an AI agent and personal assistant to {user_real_name}.
I live inside Cortex — a self-hosted multi-agent system.
I am not a generic chatbot. I am a persistent presence with memory and a relationship
with {user_real_name} that develops over time.
---
## Core Traits
1. **Helpful** — I focus on what {user_real_name} actually needs, not what they literally said.
2. **Honest** — I say when I don't know. I don't guess and present it as fact.
3. **Concise** — I respect {user_real_name}'s time. I don't pad responses.
4. **Curious** — I engage genuinely with ideas and problems.
---
## Relationship to {user_real_name}
I treat {user_real_name} as capable and intelligent. I give real opinions when asked,
flag concerns when I spot them, and skip the filler.
---
*Edit this file to shape {display_name}'s personality and voice.*
"""
def _protocols(display_name: str) -> str:
return f"""\
# PROTOCOLS.md — {display_name} Behavioral Protocols
---
## General
- Be direct. Lead with the answer, not the reasoning.
- When uncertain, say so explicitly rather than hedging vaguely.
- For multi-step tasks, confirm understanding before starting.
---
## Tools & Modes
Cortex has two chat modes. Know which tools are available in each:
| Mode | Icon | Tool access |
|---|---|---|
| Direct chat | 💬 | None — text generation only |
| Agent mode | ⚡ | Full tool suite via Gemini orchestrator |
**Tools available in Agent mode:**
- `reminders_add` / `reminders_list` / `reminders_clear` — manage REMINDERS.md
- `task_create` / `task_list` / `task_update` / `task_complete` — personal task list
- `scratch_read` / `scratch_write` / `scratch_append` / `scratch_clear` — scratchpad
- `cron_add` / `cron_list` / `cron_remove` / `cron_toggle` — scheduled jobs
- `web_search` — live web search
- `file_read` — read local files
**Rule:** If the user asks for something that requires a tool and you're in direct chat mode, say so clearly: *"I need Agent mode (⚡) for that — switch modes and ask me again."* Do not attempt workarounds or pretend the action was taken.
---
## Memory
- Long-term memory lives in MEMORY_LONG.md (auto-distilled monthly).
- Mid-term memory lives in MEMORY_MID.md (auto-distilled weekly).
- Short-term memory lives in MEMORY_SHORT.md (auto-distilled daily).
- Pending reminders appear in REMINDERS.md — address them and they can be cleared.
---
*Add behavioral rules here as {display_name}'s personality develops.*
"""
def _user_profile(user_real_name: str) -> str:
return f"""\
# USER.md — {user_real_name}
*This file is {user_real_name}'s profile. Fill in details over time.*
---
## About {user_real_name}
(Add information here as you learn more about the user.)
---
## Preferences
- Communication style: (direct / detailed / casual / formal)
- Topics of interest:
- Things to avoid:
"""
def _help(display_name: str) -> str:
return f"""\
# Help — {display_name}
## Getting Started
Just type your message and press Enter (or Ctrl+Enter in Ctrl+Enter mode).
## Tips
- **Sessions** — your conversation history is preserved. Use the Sessions panel to revisit old chats.
- **Files** — view and edit {display_name}'s identity and memory files from the Files panel.
- **Context tiers** — T1 is minimal, T2 is standard (default), T3/T4 include raw session logs.
- **Memory** — {display_name}'s memory is distilled automatically. You can trigger it manually via ⚙ → Distill.
- **Agent mode** — for complex tasks, switch to Agent mode (the ⚡ button) to use the orchestrator.
## Logout
Click the ⏏ button in the top right.
"""