Prologue Extractor
August 22, 2026 · View on GitHub
Prologue Extractor points at an existing ("brownfield") system and captures what changes, from several signals, to propose commands and the data changes they may have caused:
- Database change capture — watches SQL Server and PostgreSQL and records, per transaction, which tables and columns changed. Metadata only — never the actual data values.
- HTTP command capture — sits in front of the system as a YARP reverse proxy and records the
POST/PUT/DELETEoperations passing through (method, path, status, timing). - OpenTelemetry capture — acts as an OTLP proxy (HTTP on
4318, gRPC on4317). Point the monitored system's OTLP exporter at the extractor: it captures span metadata (name, kind, timing, trace/span ids, attribute keys, and the values of an allowlisted set of attributes) and forwards the telemetry unchanged to the upstream collector when one is configured. Traces carry the intent (commands) and the events they produce.
The streams are correlated by a time-window heuristic and by shared trace id, then sent to the configured output (the Prologue Receiver or rolling JSON files).
Architecture
SQL Server / PostgreSQL hosted services ─┐
HTTP reverse-proxy transform ├─► IObservationChannel ─► CorrelationWorker
OTLP HTTP and gRPC endpoints ┘ │
▼
TimeWindowCorrelator
│
▼
BufferedCaptureStore
│
▼
CaptureBuffer
│
▼
CaptureOutputWorker
├─► JSONL files
└─► Receiver API
Observationis the common unit each producer publishes: a source, timestamp, and polymorphic payload.IObservationChannelis the in-process producer/consumer boundary between the configured producers andCorrelationWorker.ICorrelatoris implemented byTimeWindowCorrelator, which groups settled observations into aCaptureusing trace identifiers where available and a configured time window otherwise.ICaptureStoreis implemented byBufferedCaptureStore. It enqueues captures so output I/O does not block observation capture.ICaptureOutputwrites rolling JSONL files throughJsonFileCaptureOutputor posts captures throughApiCaptureOutput, as selected by configuration.
The capture contract (Capture, Observation, payloads, and SourceKind) lives in
Cratis.Prologue.Contracts, shared by the Extractor, Receiver, storage, and Interpreter.
Adding another observation source
IObservationChannel is a useful in-process seam, but Prologue does not currently provide binary plug-in discovery
or an external source SDK. Source composition is explicit in Program.cs because the existing producers have
several hosting shapes: background services, a YARP transform, and mapped OTLP HTTP/gRPC endpoints.
A new source must be reviewed across the complete pipeline:
- define configuration and startup registration;
- publish bounded, classified metadata as
Observationinstances; - add any payload type to the canonical JSON discriminator set;
- define correlation behavior and failure/recovery semantics;
- verify JSON and MongoDB persistence compatibility;
- teach the Interpreter how to use or explicitly ignore the new evidence; and
- add denied-data, serialization, correlation, and interpretation specifications.
Do not force a new source into a relational table/column payload when its native semantics differ. Captured output is evidence for a provisional model, not automatic domain truth.
Configuration
The Extractor reads cratis-prologue.json from its working directory. Set PROLOGUE_CONFIG to use another path.
The file provides the baseline and environment variables override it using the normal double-underscore form.
Prologue.Output.KindselectsJsonorApioutput.Prologue.Output.Json.Directoryselects the JSONL capture directory.Prologue.Output.Api.Endpointselects the Receiver base address.Prologue.Correlation.WindowMillisecondssets the correlation window.Prologue.SqlServer[]/Prologue.Postgres[]configure databases to watch.SqlServer[].EnableChangeDataCapturedefaults totrue;SqlServer[].Tablesnarrows capture to named tables.Prologue.PrologueIdassociates captures with one interpretation session.Prologue.OpenTelemetryconfigures OTLP capture, filtering, allowlisted attribute values, and optional forwarding.ReverseProxyis the standard YARP route/cluster configuration for the monitored HTTP application.
HTTP observations include the query string, and OpenTelemetry observations can include values for explicitly allowlisted attributes. Treat configuration and capture output as sensitive, minimize the allowlist, and exclude credentials, personal data, and other unrestricted values.
Preparing the target databases
The extractor prepares the databases itself. A system being captured was built without knowing Prologue exists, so it must not have to carry setup code for the tool watching it — that is the whole point of being able to point Prologue at software that already exists. What is left for an operator is only what a database connection genuinely cannot do:
| The extractor does | You must do | |
|---|---|---|
| SQL Server | Enables CDC on the database and on every user table with a primary key, skipping what is already enabled (SqlServer[].EnableChangeDataCapture, on by default; narrow it with SqlServer[].Tables). Needs sysadmin. | Have SQL Server Agent running — CDC captures nothing without it. |
| PostgreSQL | Creates the publication and replication slot it consumes, and checks the server is actually usable before it starts. | Run the server with wal_level = logical (needs a restart) and give the connecting role the REPLICATION attribute. |
Neither of the remaining two can be changed over a normal connection, so the extractor detects them and says
exactly what is wrong rather than idling silently. If CDC cannot be enabled — no sysadmin, or a DBA has done it
already — the extractor logs a warning and watches whatever capture instances it finds;
sql/enable-sqlserver-cdc.sql is there for that case.
Running locally
The quickest way to see the extractor working is the Library sample in Samples/Library:
an ordinary ASP.NET + EF Core system with an Aspire composition that already wires everything up — the database
(PostgreSQL with wal_level=logical, or SQL Server with the Agent enabled for CDC), the extractor in front of the
system, the Receiver, and MongoDB. It also generates realistic load on demand.
cd Samples/Library && aspire run # PostgreSQL
cd Samples/Library && aspire run -- --database mssql # SQL Server
To wire it up by hand instead: run the Prologue Receiver, point the proxy's destination at your target system,
enable CDC on the SQL Server tables (sql/enable-sqlserver-cdc.sql), run the extractor, then issue
POST/PUT/DELETE requests through the proxy and inspect the captures collection in MongoDB.