personal memory agent
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Prompt Template System#

This document describes solstone's template variable system for personalizing prompts used in generators and agents. Templates enable dynamic substitution of owner identity, contextual information, and reusable prompt fragments.

Overview#

Prompts are stored as .md files with optional JSON frontmatter for metadata. The prompt content is loaded via load_prompt() from think/prompts.py, which uses Python's string.Template with safe_substitute. This means:

  • Variables use $name or ${name} syntax
  • Undefined variables are left as-is (no errors)
  • Use $$ to escape a literal dollar sign

The system supports three categories of variables with the following precedence (highest to lowest):

  1. Context variables - Passed by callers at runtime
  2. Identity variables - From journal configuration
  3. Template variables - From reusable template files

File Format#

Prompt files use JSON frontmatter with { and } as delimiters (braces on their own lines):

{
  "title": "Activity Synthesis",
  "color": "#00bcd4",
  "schedule": "segment"
}

$segment_preamble

# Segment Activity Synthesis

Your prompt content here...

Files without metadata can omit the frontmatter entirely - just write the prompt content directly.

Variable Categories#

Identity Variables#

Identity variables come from the identity block in config/journal.json. These are available in all prompts automatically.

Common variables:

  • $name - Full name
  • $preferred - Preferred name or nickname
  • $bio - Self-description
  • $timezone - IANA timezone identifier

Pronoun variables (flattened from nested structure):

  • $pronouns_subject - e.g., "he", "she", "they"
  • $pronouns_object - e.g., "him", "her", "them"
  • $pronouns_possessive - e.g., "his", "her", "their"
  • $pronouns_reflexive - e.g., "himself", "herself", "themselves"

Uppercase-first versions are automatically generated for all identity variables:

  • $Name, $Preferred, $Bio
  • $Pronouns_subject, $Pronouns_possessive, etc.

The flattening logic converts nested objects using underscore separators. For example, identity.pronouns.subject becomes $pronouns_subject.

References:

  • Identity configuration: config.md (identity section)
  • Flattening implementation: think/prompts.py_flatten_identity_to_template_vars()

Template Variables#

Template variables come from .md files in the think/templates/ directory. Each file's stem becomes a variable name containing its contents.

Current templates:

  • $daily_preamble - Preamble for full-day output analysis
  • $segment_preamble - Preamble for single-segment analysis
  • $activity_preamble - Preamble for activity-level analysis (uses $activity_* context variables)

Templates can themselves use identity and context variables, enabling composable prompt construction. For example, daily_preamble.md uses $preferred and $day.

Pattern: To add a new template variable, create think/templates/mytemplate.md and it becomes available as $mytemplate in all prompts.

Reference: think/templates/ directory

Context Variables#

Context variables are passed at runtime by the code calling load_prompt(). These are use-case specific and not globally available.

Common generator context:

  • $day - Human-readable date (e.g., "Friday, January 24, 2026")
  • $day_YYYYMMDD - Day in YYYYMMDD format (e.g., "20260124")
  • $facet - Focused facet name when the prompt is dispatched per-facet (bare name, e.g. work)
  • $activity_md_dir - Directory path containing per-activity narrative .md outputs for the focused facet/day, with trailing slash
  • $now - Current date and time with timezone (e.g., "Monday, February 3, 2025 at 10:30 AM PST")
  • $segment - Segment key (e.g., "143022_300")
  • $segment_start - Formatted start time (e.g., "2:30 PM")
  • $segment_end - Formatted end time (e.g., "2:35 PM")

Activity context (available for schedule: "activity" agents):

  • $activity_id - Activity record ID (e.g., "coding_095809_303")
  • $activity_type - Activity type (e.g., "coding", "meeting")
  • $activity_description - Description of the activity
  • $activity_level - Average engagement level (0-1)
  • $activity_entities - Comma-separated active entities
  • $activity_segments - Comma-separated segment keys
  • $activity_duration - Estimated duration in minutes

Context variables also get automatic uppercase-first versions ($Day, $Day_yyyymmdd, etc.).

References:

  • Generator context building: think/generate.py (search for prompt_context)
  • Other callers: observe/extract.py, observe/enrich.py

Usage Patterns#

For Generators#

Generator prompts typically compose a shared preamble with agent-specific instructions:

{
  "title": "My Generator",
  "color": "#4caf50",
  "schedule": "segment"
}

$segment_preamble

# Segment Activity Synthesis

Your specific instructions here...

The $segment_preamble or $daily_preamble template provides standardized context about what's being analyzed, while the rest of the prompt defines the specific analysis task.

Optional model configuration: Add max_output_tokens (response length limit) and thinking_budget (model thinking token budget) to override provider defaults.

Reference: talent/*.md for examples (files with schedule field but no tools field)

For Agents#

Agent prompts are .md files with configuration in frontmatter:

{
  "title": "My Agent",
  "tier": 2,
  "tools": "journal"
}

You are a helpful assistant...

Optional model configuration: Add max_output_tokens (response length limit) and thinking_budget (model thinking token budget) to override provider defaults. Note: OpenAI uses fixed reasoning and ignores thinking_budget.

Reference: think/talent.pyget_talent() for agent configuration loading

The load_prompt() Function#

load_prompt(
    name: str,                      # Prompt filename (without .md)
    base_dir: Path | None = None,   # Directory containing prompt
    context: dict | None = None,    # Runtime context variables
) -> PromptContent

Returns a PromptContent named tuple with text (substituted content), path (source file), and metadata (frontmatter dict).

Reference: think/prompts.pyload_prompt()

Adding New Variables#

Identity Variables#

Edit config/journal.json to add or modify identity fields. Nested objects are automatically flattened with underscore separators.

Template Variables#

Create a new .md file in think/templates/. The filename stem becomes the variable name.

Context Variables#

Pass via the context parameter when calling load_prompt():

load_prompt("myprompt", context={"custom_var": "value"})

Reference Index#

Category Authoritative Source
Identity config schema config.md (identity section)
Identity flattening think/prompts.py (_flatten_identity_to_template_vars)
Template loading think/prompts.py (_load_templates)
Core load function think/prompts.py (load_prompt)
Template files think/templates/*.md
Test coverage tests/test_template_substitution.py
Generator prompts talent/*.md (files with schedule field but no tools)
Agent prompts talent/*.md (files with tools field)