asopi tech
asopi techIndie Developer

Event Log Store

Alopex Trail

Storage that fits event logs

Trail is storage for event logs: user activity, incoming external notifications, and the inputs and outputs of tools called by an agent. Event logs differ from record to record and are not rewritten afterward. Trail is designed for those properties, so there is no need to decide their shape before writing.

A storage engine designed for event logs: store each record as it arrives, even when every event has a different shape.

DesignedOSS
What it stores
Event logs
Upfront schema definition
None

Key points

  • No schema to decide before writing
  • Ingestion continues when fields are added or types change
  • Choose the type when reading
observabilitydatabaserust

Challenge

Writing freely and reading quickly do not coexist

Storage that accepts any shape becomes slow to search after the fact. Storage that reads quickly asks you to decide the shape before writing. Trail aims to accept any shape at write time and read at columnar speed.

  • Products that accept any shape are slow to search after storage
  • Products that read quickly demand a schema before writing
  • When both are necessary, teams either give one up or maintain two systems

Event logs vary record by record and are not rewritten once they are written: user actions, incoming external notifications, and inputs and outputs of tools called by agents all work this way.

Relational storage asks for a shape before writing. Time-series storage assumes stable names and tags around numeric values. Document stores accept any shape but become slow to search after the fact.

Trail is designed around this nature of data. It accepts the arriving shape without requiring a schema at write time, and lets the reader choose a type at query time. It uses Skulk as its storage engine. Alopex OTel brings time-series and event logs together with dashboards.

Store data in the shape it arrives

Trail does not require a schema for writes. It accepts new fields and conflicting types as they arrive; interpretation happens when you read. That removes shaping code and the work of repairing it when it breaks.

  • Ingestion does not stop for type changes, avoiding missing records
  • Values do not need to be packed into JSON strings; they remain searchable
  • Read the same field as a number or a string, depending on the query
Transformation code
None
Schema changes
None

Use Cases

Three places it fits

What to put in Trail and how to read it later.

Keep a record of application events

Activity and audit logs

  • Store user actions, state transitions, errors, and external API results
  • Line up the records around an incident to reconstruct what happened
  • Keep writing when a new feature adds attributes, without changing definitions

Receive incoming event logs

Webhooks and integration notifications

  • Store webhooks and notifications whose structure changes outside your control
  • Keep them without conversion, then read the necessary attributes when they are known
  • Ingestion continues when an integration upgrades its API version

Keep records from agents and devices

Execution logs and IoT event logs

  • Store tool-call inputs and outputs, and device events with different attributes by model
  • Reproduce an execution one event at a time or select the same attribute across devices
  • Keep records intact even when their contents change every time

Features

Key features

What Trail provides to store and read event logs.

Schema-free writes

There is no need to decide the shape before writing. Continue writing when new fields appear without changing definitions.

Keep conflicting types

If the same field arrives as a number or a string, Trail retains both. Ingestion does not stop, so records are not lost.

Choose types when reading

Choose how to read a value at query time, supporting uses that need the same field treated as a number or as text.

No required timestamp

Accept records without a timestamp and event logs with an empty payload. No tag-versus-field distinction is required.

Parquet readable by external tools

Data stays in Parquet, so analysis needs no export step.

Tech Stack

Technology stack

Built directly on Skulk's storage engine.

Storage

Skulk engine (Apache Parquet)

Append-oriented storage designed for readsStored data remains readable by other tools

Durability

WAL and atomic file publication

Incomplete writes remain invisible after a crashUses the layer already running in Skulk v0.3.0

Implementation

Rust

Built on the same codebase as Skulk

Status

Development status

The design is ready for implementation. Versions v0.1 through v0.4 will add schema-free writes, storage, and Python bindings in order. Trail uses the storage engine already running in Skulk v0.3.0.

Public Resources

The latest documents, code, and community links in one place.

Get Involved

Do you have records that do not fit anywhere?

Records whose shape changes too much for relational storage and are not numeric enough for time-series storage—real examples help determine what to build first.