Kozen etl mk
Agentic Repository: Skills, Sub-Agents, Hooks, Context, etc.
npx -y skills add kozen-labs/agentic --skill kozen-etl-mkAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Reference skill for @kozen/etl-mk — a Kozen module that runs bi-directional ETL pipelines between MongoDB and Apache Kafka. Covers when and why to use this npm package, prerequisites, the MK (MongoDB→Kafka) and KM (Kafka→MongoDB) pipelines, the delegate pattern for transforming data in both directions, all CLI commands (etl-mk:start, etl-mk:validate, etl-mk:help), all environment variables, IoC service registrations, DLQ routing, retry logic, best practices for production, and how to build runnable demos using .env files and ESM delegate files.
SKILL.md
11.8 KB, as published. Nobody here has run it
@kozen/etl-mk — MongoDB ↔ Kafka ETL Module
What this package does
@kozen/etl-mk is an npm package for the Kozen framework that runs production-grade ETL
pipelines between MongoDB and Apache Kafka. You write only the transform logic (a delegate
file); the module handles connections, change streams, producer/consumer lifecycle, dead-letter
queuing, retries, and structured logging.
Two pipeline directions:
- MK (MongoDB → Kafka): watches a MongoDB collection via change stream, transforms each change event in a delegate, and publishes the result to a Kafka topic.
- KM (Kafka → MongoDB): consumes messages from a Kafka topic, transforms each message in a delegate, and writes the result to a MongoDB collection with at-least-once delivery.
Both directions can run concurrently in a single process.
When to use this package
Use @kozen/etl-mk when you need to move or replicate data between MongoDB and Kafka without
writing and maintaining pipeline boilerplate yourself.
| Scenario | Direction |
|---|---|
| Stream MongoDB document changes to downstream Kafka consumers | MK |
| Feed Kafka events into MongoDB for persistence, archiving, or analytics | KM |
| Keep a MongoDB collection in sync with an event-sourced Kafka topic | KM with writeMode=upsert |
| Mirror or replicate a MongoDB collection through Kafka to another MongoDB | MK + KM — two separate services |
| React to MongoDB changes and produce enriched or filtered Kafka messages | MK with transform delegate |
| Audit trail: persist all Kafka domain events into MongoDB for querying | KM |
Use MK when: MongoDB is your source of truth and downstream systems consume Kafka events.
Use KM when: Kafka is your event bus and MongoDB is the read/query store or archive.
Use two separate services (not bidirectional in one process) when you need both directions.
Running MK and KM as independent containers is the recommended deployment model — each service
can be scaled, restarted, or deployed independently without affecting the other. Both share the
same Docker image; what differs is the env file each container receives. See references/configuration.md
for the complete two-service Docker Compose pattern.
When NOT to use this package
- You need real-time OLAP or stream processing with aggregations, joins, or windowing — use Apache Flink, Kafka Streams, or Atlas Stream Processing instead.
- You need Kafka Connect with a managed connector (e.g., Debezium) —
@kozen/etl-mkis code-first; if you need a declarative, connector-managed pipeline, use Kafka Connect. - You need exactly-once semantics — this module guarantees at-least-once on the KM side; your delegate must be idempotent if deduplication matters.
- You do not have a Kozen framework project — this module requires
@kozen/engineas a peer.
Prerequisites
Before running any pipeline, verify these conditions:
MongoDB
- MongoDB instance is a replica set or sharded cluster — standalone instances do not support change streams (required by MK).
- The connection user has
readon the source collection andchangeStreamprivilege. - For Atlas: M10+ cluster tier (change streams not available on M0/M2/M5).
Kafka
- A running Kafka broker accessible from the process (local or remote).
- The target topic exists, or the broker is configured with
auto.create.topics.enable=true. - If SSL is required, set
KOZEN_ETL_MK_DESTINATION_SSL=true/KOZEN_ETL_KM_SOURCE_SSL=true.
Kozen project
-
@kozen/engineis installed as a peer dependency (npm install @kozen/engine). -
@kozen/etl-mkis installed (npm install @kozen/etl-mk). - Node.js ≥ 18 is running in the environment.
Routing table
| Signal | Reference |
|---|---|
| EtlModule, IEtlOptions, IMongoConfig, IKafkaConfig, IMongoToKafkaConfig, IKafkaToMongoConfig, IEtlMongoToKafkaTools, IKafkaDelegate, EtlPipelineService, MongoToKafkaService, KafkaToMongoService, KafkaProducerService, KafkaConsumerService, MongoWriterService, DelegateLoaderService, EtlCLIController, delegate pattern, MK pipeline, KM pipeline, bidirectional, DLQ, retry, at-least-once, etl-mk:start, etl-mk:validate, etl-mk:help, setMessageKey, setMessageHeaders, writeMode, insert upsert, onChange, onMessage, IoC registration, etl-mk:pipeline, etl-mk:kafka-producer, etl-mk:kafka-consumer, etl-mk:mongo-writer, etl-mk:mongo-to-kafka, etl-mk:kafka-to-mongo, ChangeStreamService | references/api.md |
| KOZEN_ETL_MK_SOURCE_URI, KOZEN_ETL_MK_SOURCE_DATABASE, KOZEN_ETL_MK_SOURCE_COLLECTION, KOZEN_ETL_MK_DESTINATION_BROKERS, KOZEN_ETL_MK_DESTINATION_TOPIC, KOZEN_ETL_KM_SOURCE_BROKERS, KOZEN_ETL_KM_SOURCE_TOPIC, KOZEN_ETL_KM_SOURCE_GROUP_ID, KOZEN_ETL_KM_DESTINATION_URI, KOZEN_ETL_KM_DESTINATION_DATABASE, KOZEN_ETL_KM_DESTINATION_COLLECTION, KOZEN_ETL_KM_DESTINATION_WRITE_MODE, KOZEN_ETL_DELEGATE_TYPE, DLQ topic, retry attempts, retry delay, SSL, .env file, .env.mk, .env.km, demo setup, two-service deployment, separate services, shared dockerfile, env file isolation, docker-compose, etl-mk service, etl-km service, KRaft kafka, kafka:9092, etl-net network, MongoDB replica set Docker, mongo-init, validate per service, PM2, validate config | references/configuration.md |
| delegate design, idempotency, at-least-once implications, error handling in delegates, Kafka message key strategy, consumer group ID, SSL production, DLQ monitoring, writeMode selection, ordering guarantees, silent failure patterns, structured logging, secrets in delegates | references/best-practices.md |
How to use this package — the 3-step model
Every usage of @kozen/etl-mk follows the same three steps regardless of direction:
Step 1 — Write a delegate file
The delegate is a .mjs (ESM) or .cjs (CommonJS) file that exports named async functions.
It contains only your business logic — no connection code, no Kafka SDK, no MongoDB driver.
// delegates/my-transform.mjs
export async function insert(change, tools) { // MK: called for each MongoDB insert
return { id: change.fullDocument._id.toString(), ...change.fullDocument };
}
export async function message(msg, tools) { // KM: called for each Kafka message
return { ...msg, savedAt: new Date() };
}
Step 2 — Configure via environment variables (or CLI flags)
# .env — minimum required for MK
KOZEN_ETL_MK_SOURCE_URI=mongodb+srv://user:[email protected]/
KOZEN_ETL_MK_SOURCE_DATABASE=mydb
KOZEN_ETL_MK_SOURCE_COLLECTION=orders
KOZEN_ETL_MK_DESTINATION_BROKERS=localhost:9092
KOZEN_ETL_MK_DESTINATION_TOPIC=orders.events
KOZEN_ETL_MK_DELEGATE_FILE=./delegates/my-transform.mjs
Step 3 — Validate, then start
# Always validate first
npx kozen --moduleLoad=@kozen/etl-mk --action=etl-mk:validate --envFile=.env
# Start the pipeline (long-running process)
npx kozen --moduleLoad=@kozen/etl-mk --action=etl-mk:start --envFile=.env
The process stays alive, listening for events. Send SIGINT (Ctrl+C) to stop gracefully.
Quick start — runnable examples
MongoDB → Kafka (MK)
npm install @kozen/etl-mk
# delegates/orders.mjs
cat > delegates/orders.mjs << 'EOF'
export async function insert(change, tools) {
const doc = change.fullDocument;
tools.setMessageKey(doc._id.toString());
return { id: doc._id.toString(), status: doc.status, amount: doc.amount };
}
export async function update(change, tools) {
const fields = change.updateDescription?.updatedFields;
if (!fields?.status) return null; // skip events we don't care about
tools.setMessageKey(change.documentKey._id.toString());
return { id: change.documentKey._id.toString(), status: fields.status };
}
EOF
export KOZEN_ETL_MK_SOURCE_URI=mongodb+srv://user:[email protected]/
export KOZEN_ETL_MK_SOURCE_DATABASE=mydb
export KOZEN_ETL_MK_SOURCE_COLLECTION=orders
export KOZEN_ETL_MK_DESTINATION_BROKERS=localhost:9092
export KOZEN_ETL_MK_DESTINATION_TOPIC=orders.events
export KOZEN_ETL_MK_DELEGATE_FILE=./delegates/orders.mjs
npx kozen --moduleLoad=@kozen/etl-mk --action=etl-mk:validate
npx kozen --moduleLoad=@kozen/etl-mk --action=etl-mk:start
Kafka → MongoDB (KM)
cat > delegates/archive.mjs << 'EOF'
export async function message(msg, tools) {
return { ...msg, archivedAt: new Date(), source: tools.collectionName };
}
EOF
export KOZEN_ETL_KM_SOURCE_BROKERS=localhost:9092
export KOZEN_ETL_KM_SOURCE_TOPIC=orders.events
export KOZEN_ETL_KM_DESTINATION_URI=mongodb+srv://user:[email protected]/
export KOZEN_ETL_KM_DESTINATION_DATABASE=archive
export KOZEN_ETL_KM_DESTINATION_COLLECTION=orders_archive
export KOZEN_ETL_KM_DELEGATE_FILE=./delegates/archive.mjs
npx kozen --moduleLoad=@kozen/etl-mk --action=etl-mk:validate
npx kozen --moduleLoad=@kozen/etl-mk --action=etl-mk:start
Validate configuration without connecting
npx kozen --moduleLoad=@kozen/etl-mk --action=etl-mk:validate
# Exit 0 = valid. Non-zero = logs each missing variable, then fails.
When to invoke this skill (AI usage)
Invoke this skill when the user is:
- Scaffolding a new MK or KM demo or pipeline from scratch
- Asking what delegate exports to write for a given use case
- Troubleshooting a missing env var, delegate not loading, or pipeline not activating
- Designing the writeMode, DLQ, or retry strategy for a KM pipeline
- Embedding
@kozen/etl-mkprogrammatically in a Kozen application - Asking about best practices for production ETL with this module
Do & Don't
Do:
- Always run
etl-mk:validatebeforeetl-mk:startin CI/CD — it exits non-zero on missing vars. - Set
KOZEN_ETL_MK_DELEGATE_FILEto activate MK; omit it entirely to disable MK silently. - Return
nullorundefinedfrom any delegate handler to skip that event without error. - Use
.mjsfor ESM delegates (recommended) and.cjsfor CommonJS — auto-detected by extension. - Set
writeMode=upsertand make delegates idempotent on KM — at-least-once means duplicates will occur. - Always set a meaningful
KOZEN_ETL_MK_DESTINATION_CLIENT_ID/KOZEN_ETL_KM_SOURCE_CLIENT_IDper environment. - Use a unique
KOZEN_ETL_KM_SOURCE_GROUP_IDper logical consumer group — sharing one group between pipelines causes missed messages. - Configure DLQ topics in production — failed messages vanish silently without them.
- Use
tools.logger(notconsole.log) inside delegates for structured, traceable output.
Don't:
- Never import KafkaJS, MongoClient, or other infrastructure SDKs directly in delegate files — use
tools. - Never use synchronous CPU-blocking code in delegates — all processing is event-loop-based.
- Never assume exactly-once delivery on KM — design your target collection schema and delegate for idempotency.
- Never omit
setMessageKey()on MK when ordering matters — without a key, Kafka distributes messages across partitions randomly. - Never share a consumer group ID across multiple running pipelines consuming the same topic — they will split the partition load unpredictably.
- Never run without a DLQ topic in production — an error without DLQ drops the message permanently after max retries.
- Never skip
etl-mk:validatewhen migrating between environments — missing vars produce silent, hard-to-diagnose failures.