# How to Configure Custom AI Prompts in Lifetrace: A Complete Guide

> Learn to configure custom AI prompts in Lifetrace. This guide shows how to create and manage YAML files for unique feature prompts, enhancing your workflow.

- Repository: [FreeU-group/lifetrace](https://github.com/freeu-group/lifetrace)
- Tags: how-to-guide
- Published: 2026-03-02

---

**To configure custom AI prompts in Lifetrace, create or edit YAML files in the `lifetrace/config/prompts/` directory, then retrieve them using the `get_prompt(category, key, **kwargs)` helper from [`lifetrace/util/prompt_loader.py`](https://github.com/freeu-group/lifetrace/blob/main/lifetrace/util/prompt_loader.py).**

Lifetrace centralizes all AI prompt management through a modular configuration system that supports both modern multi-file layouts and legacy single-file setups. By editing YAML definitions and leveraging the singleton `PromptLoader` class, you can customize AI behavior for transcription, RAG, planning, and custom features without modifying application source code. This guide explains how to configure custom AI prompts lifetrace using the actual implementation details from the freeu-group/lifetrace repository.

## Understanding the Prompt Loader Architecture

The prompt system relies on a **singleton `PromptLoader`** class defined in [`lifetrace/util/prompt_loader.py`](https://github.com/freeu-group/lifetrace/blob/main/lifetrace/util/prompt_loader.py) (lines 14-25). This design ensures that prompt dictionaries are loaded exactly once per process and cached for subsequent access.

When the application initializes, the loader determines the configuration directory by calling `get_config_dir()` from [`lifetrace/util/base_paths.py`](https://github.com/freeu-group/lifetrace/blob/main/lifetrace/util/base_paths.py) (lines 54-65). This function resolves paths differently for development environments versus PyInstaller production bundles, ensuring your custom prompts are discovered regardless of deployment context.

The `_load_prompts()` method (lines 30-66 of [`prompt_loader.py`](https://github.com/freeu-group/lifetrace/blob/main/prompt_loader.py)) implements a hierarchical loading strategy:

1. First, it scans `lifetrace/config/prompts/` for any `*.yaml` files (the new modular layout)
2. If found, it merges all YAML contents into the internal prompt dictionary
3. If the directory does not exist, it falls back to the legacy [`lifetrace/config/prompt.yaml`](https://github.com/freeu-group/lifetrace/blob/main/lifetrace/config/prompt.yaml) for backward compatibility

## Where to Store Custom AI Prompts

Lifetrace supports two configuration patterns. The modern approach uses a dedicated prompts directory, while the legacy approach uses a single file.

**Modular Layout (Recommended):**
Create individual YAML files under `lifetrace/config/prompts/`. Each file can contain multiple categories, allowing you to organize prompts by feature (e.g., [`todo.yaml`](https://github.com/freeu-group/lifetrace/blob/main/todo.yaml), [`rag.yaml`](https://github.com/freeu-group/lifetrace/blob/main/rag.yaml), [`transcription.yaml`](https://github.com/freeu-group/lifetrace/blob/main/transcription.yaml)).

**Legacy Fallback:**
If you prefer a single file or need to maintain older configurations, place all prompts in [`lifetrace/config/prompt.yaml`](https://github.com/freeu-group/lifetrace/blob/main/lifetrace/config/prompt.yaml). The loader automatically detects this file when the `prompts/` directory is absent.

## Creating Custom Prompt Files

To add custom prompts for a new feature, create a YAML file in the prompts directory with a top-level category key containing your prompt definitions.

```yaml

# lifetrace/config/prompts/custom_feature.yaml

custom_feature:
  system_prompt: |
    You are a specialized assistant for the Custom Feature module.
    Provide concise, structured responses in JSON format.
  user_prompt: |
    Process the following data and extract key entities:
    {input_data}

```

Use **category names** (like `custom_feature`) that match the feature identifier in your code. Define **keys** (like `system_prompt`, `user_prompt`) to distinguish different prompt contexts. Include placeholders like `{input_data}`—the loader applies Python's `str.format(**kwargs)` to substitute these at runtime.

## Retrieving and Using Prompts in Code

Access configured prompts through the `get_prompt` helper function exported from [`lifetrace/util/prompt_loader.py`](https://github.com/freeu-group/lifetrace/blob/main/lifetrace/util/prompt_loader.py).

```python
from lifetrace.util.prompt_loader import get_prompt

# Retrieve a static system prompt

system = get_prompt("custom_feature", "system_prompt")

# Retrieve a user prompt with dynamic data injection

user = get_prompt(
    "custom_feature",
    "user_prompt",
    input_data='{"entities": ["meeting", "deadline"]}'
)

```

The function signature is `get_prompt(category, key, **kwargs)`. The loader lazily initializes on first call, caching all subsequent requests. Dynamic values passed as keyword arguments replace the curly-brace placeholders in your YAML templates.

## Reloading Prompts Without Restarting

Because `PromptLoader` is a singleton, changes to YAML files on disk are not automatically reflected in running processes. To apply edits without restarting the service, explicitly trigger a reload:

```python
from lifetrace.util.prompt_loader import prompt_loader

# Force reload from disk

prompt_loader.reload()

```

This method re-executes `_load_prompts()`, re-scanning the `prompts/` directory or legacy file and updating the internal cache. Implement this in admin endpoints or development consoles to enable hot-reloading of AI behavior.

## Real-World Usage Examples

The Lifetrace codebase consistently uses `get_prompt` across services to maintain separation between AI logic and prompt content.

**Audio Transcription Service** ([`lifetrace/services/audio_service.py`](https://github.com/freeu-group/lifetrace/blob/main/lifetrace/services/audio_service.py), line 511):

```python
system_prompt = get_prompt("transcription_optimization", "system_assistant")
user_prompt = get_prompt(
    "transcription_optimization",
    "user_prompt",
    text=transcribed_text,
)

```

**RAG Service** ([`lifetrace/llm/rag_service.py`](https://github.com/freeu-group/lifetrace/blob/main/lifetrace/llm/rag_service.py), line 344):

```python
prompt = get_prompt("rag", "contextualization_prompt", context=document_chunks)

```

These examples demonstrate the standard pattern: import the helper, specify the category matching your YAML filename or top-level key, select the specific prompt key, and pass runtime variables as keyword arguments.

## Summary

- Lifetrace stores AI prompts in YAML files under `lifetrace/config/prompts/` (modular) or [`lifetrace/config/prompt.yaml`](https://github.com/freeu-group/lifetrace/blob/main/lifetrace/config/prompt.yaml) (legacy).
- The `PromptLoader` singleton in [`lifetrace/util/prompt_loader.py`](https://github.com/freeu-group/lifetrace/blob/main/lifetrace/util/prompt_loader.py) manages loading and caching via `get_config_dir()` resolution.
- Retrieve prompts in code using `get_prompt(category, key, **kwargs)` to inject dynamic values with Python string formatting.
- Call `prompt_loader.reload()` to refresh prompts from disk without application restart.
- Services like [`audio_service.py`](https://github.com/freeu-group/lifetrace/blob/main/audio_service.py) and [`rag_service.py`](https://github.com/freeu-group/lifetrace/blob/main/rag_service.py) demonstrate production usage of this configuration system.

## Frequently Asked Questions

### How does Lifetrace handle missing prompt directories?

If the `lifetrace/config/prompts/` directory does not exist, the `PromptLoader` automatically falls back to loading [`lifetrace/config/prompt.yaml`](https://github.com/freeu-group/lifetrace/blob/main/lifetrace/config/prompt.yaml). This backward-compatible behavior ensures existing single-file configurations continue to function while allowing migration to the modular layout.

### Can I use variables inside my YAML prompt templates?

Yes. Include Python format string placeholders like `{variable_name}` in your YAML values. When calling `get_prompt("category", "key", variable_name="value")`, the loader passes these kwargs to `str.format()`, replacing placeholders with runtime data before returning the final string.

### Why are my prompt changes not appearing in the application?

The `PromptLoader` caches prompts in memory as a singleton. Changes to YAML files require calling `prompt_loader.reload()` to re-read from disk, or you must restart the application process. This design optimizes performance by avoiding repeated file system access during normal operation.

### Where is the configuration directory located in production builds?

The `get_config_dir()` function in [`lifetrace/util/base_paths.py`](https://github.com/freeu-group/lifetrace/blob/main/lifetrace/util/base_paths.py) detects PyInstaller bundles and resolves the path relative to the executable location. In development, it uses the project root. This ensures `lifetrace/config/prompts/` is correctly discovered regardless of whether running from source or a compiled distribution.