Skip to main content
The JournalStore is the central persistence authority for the Palyra daemon. It implements an event-sourcing architecture backed by SQLite, responsible for recording every interaction, tool execution, and state change within the system. Beyond simple logging, it manages complex relational data for agent sessions, cron schedules, and a vector-enabled memory subsystem for RAG (Retrieval-Augmented Generation).

1. Architecture and Event Sourcing

The system utilizes an event-sourcing pattern where the state of a “Run” or “Session” is derived from a sequence of immutable events. Each event is assigned a unique ULID and is associated with a specific session_id and run_id.

Hash-Chaining and Integrity

To ensure the auditability of the journal, Palyra supports hash-chaining for specific export types, such as approvals. This creates a cryptographic link between records, starting from a known seed.

Key Entities Mapping

The following diagram bridges the high-level persistence concepts to the underlying code entities. Diagram: Persistence Layer Entity Mapping Sources: crates/palyra-daemon/src/journal.rs#68-71, crates/palyra-daemon/src/gateway.rs#56-71

2. Data Flow: Recording an Event

When the gateway receives a request to append an event via gRPC AppendEvent, it validates the protocol version and the canonical IDs before committing to the JournalStore.

Execution Flow

  1. gRPC Entry: GatewayServiceImpl::append_event receives AppendEventRequest crates/palyra-daemon/src/transport/grpc/services/gateway/service.rs#117-120.
  2. Validation: Checks CANONICAL_PROTOCOL_MAJOR and validates ULIDs crates/palyra-daemon/src/transport/grpc/services/gateway/service.rs#125-142.
  3. Journal Dispatch: Calls state.record_journal_event which wraps JournalStore::append crates/palyra-daemon/src/transport/grpc/services/gateway/service.rs#155-168.
  4. Persistence: The JournalStore executes a SQL INSERT into the journal_events table within a transaction crates/palyra-daemon/src/journal.rs#13-13.

Constraints and Budgets

The system enforces strict latency and size constraints to ensure performance:
ConstraintValueSource
Journal Write Latency Budget25msgateway.rs#92
Max Recent Events Cache100gateway.rs#89
Max Tape Entries per Run1,024gateway.rs#103
Sources: crates/palyra-daemon/src/gateway.rs#89-103, crates/palyra-daemon/src/transport/grpc/services/gateway/service.rs#117-170

3. Canvas State and Compaction

The “Canvas” represents the persistent UI state shared between the agent and the user. Instead of storing the full state every time, Palyra uses a combination of snapshots and JSON patches. Functions like apply_patch_document and build_replace_root_patch from the palyra-a2ui crate are used to manage these transitions crates/palyra-daemon/src/gateway.rs#13-15. Sources: crates/palyra-daemon/src/gateway.rs#13-60, crates/palyra-daemon/src/journal.rs#12-12

4. Memory Subsystem (RAG)

The Memory subsystem provides the daemon with long-term retrieval capabilities. It supports vector search (semantic) and tag-based filtering.

Embedding Pipeline

The JournalStore integrates with a MemoryEmbeddingProvider. By default, it uses a HashMemoryEmbeddingProvider for deterministic testing, but it is designed to interface with model providers like OpenAI or Anthropic for production use. Diagram: Memory Search and Retrieval Flow Sources: crates/palyra-daemon/src/journal.rs#64-100, crates/palyra-daemon/src/cron.rs#56-58, crates/palyra-daemon/src/gateway.rs#66-66

5. Session and Run Lifecycle Persistence

The JournalStore tracks the lifecycle of every agent interaction through the OrchestratorSessionRecord and CronRunRecord.

Session States

Sessions transition through various states, often influenced by the RunStateMachine crates/palyra-daemon/src/gateway.rs#77-77.

Data Retention and Cleanup

Retention is configured via FileMemoryRetentionConfig crates/palyra-common/src/daemon_config_schema.rs#199-205. The daemon supports: Sources: crates/palyra-daemon/src/journal.rs#130-192, crates/palyra-daemon/src/gateway/messages.rs#5-38, crates/palyra-common/src/daemon_config_schema.rs#183-205