Two real GitHub ETL projects, cloned fresh and run through the full EKOS pipeline with nothing staged in advance — the terminal output, the MCP query/answer transcripts, and the gaps it found are all reproduced here, from a data engineer's point of view.
pih-pentaho is Partners In Health's production OpenMRS →
warehouse ETL — a live, actively maintained clinical-data pipeline. The AdventureWorks
project is a grad-school ETL exercise. Neither was touched or tuned before running EKOS
against it.
ekos init && ekos build && ekos recover && ekos resolve && ekos compile && ekos commitEKOS Doctor ──────────────────────────── [OK] Rust toolchain [OK] Working directory [OK] ekos.toml [OK] .ekos/ [OK] LLM provider claude (key: $ANTHROPIC_API_KEY ✓) ──────────────────────────── All checks passed.
Recover complete. SQL files analysed: 27 Git commits analysed: 403 Pentaho jobs analysed: 60 IR nodes (Pentaho): 312 total, 33% mapped IR nodes (SQL): 18 total, 100% mapped Passes run: 57
Object :0 (TransformNode) node_type: "Source" object_name: "omrs_obs" Object :1 (TransformNode) node_type: "Sink" object_name: "fact_patient_coded_value" columns: [patient_id, gender_id, age_id, date_id, ... coded_value_id]
The real Kettle steps, read straight from the file: Import Coded
Obs (TableInput) → Write Coded
Obs (TableOutput).
roxmltree), not generation — nothing here was guessed.
Asking about load-fact-coded-values.ktr surfaced its most
tightly co-changed files across 403 commits of git history — without anyone documenting
that relationship anywhere.
load-fact-numeric-values.ktr, load-fact-patient-event.ktr, reference-data setup transformsTodd Anderson and toddrobertanderson as the same person — recovered from git author metadata alone| Signal | pih-pentaho | adventureworks |
|---|---|---|
| Pentaho step mapping | 33% | 33% |
| SQL DDL mapping | 100% (18/18) | 0% (0/5) |
Every AdventureWorks SQL file failed to parse — MySQL #
comments and multi-statement scripts the generic SQL dialect can't handle. Zero tables were
fabricated to compensate; the pipeline logged the failure and moved on with an empty graph for
those files. A bonus finding: the localdocs observer also caught and
stripped an invisible, instruction-shaped payload hidden inside a course PDF in that same repo,
before it ever reached an LLM-backed pass.
ekos mcp serve — query in, evidenced answer out.→ tools/call ekos_search { "query": "omrs_obs" } ← result { "matches": [ { "id": "889b30d6-...", "name": "omrs_obs" }, { "id": "01e3d482-...", "name": "omrs_obs_group" }, { "id": "f7238521-...", "name": "import-into-omrs-obs.ktr:0" }, ... 34 more, ranked by relevance ] }
No LLM generation happened here — FTS-ranked retrieval, straight from the ledger, before the agent writes a single sentence.
→ tools/call ekos_impact { "id": "f7238521-...", "direction": "dependents", "max_hops": 5 } ← result { "count": 5, "hops": [ { "hop": 1, "name": "...ktr:4", "via": "FeedsInto" }, { "hop": 2, "name": "...ktr:6", "via": "FeedsInto" }, { "hop": 3, "name": "...ktr:8", "via": "FeedsInto" }, { "hop": 4, "name": "...ktr:7", "via": "FeedsInto" }, { "hop": 5, "name": "...ktr:3", "via": "FeedsInto" } ]}
The exact question a DE asks before editing an early step in a 12-step pipeline — answered without opening the file.
→ tools/call ekos_dependents { "id": "a77168f6-..." } ← result { "target": { "kind": "Table" }, "dependents_count": 0, "dependencies_count": 0 }
But §04 already showed load-fact-coded-values.ktr writes
exactly this table. The SQL Table object and the Pentaho
Sink node referencing it by name aren't yet resolved to the
same identity with a graph edge between them.
Worth knowing before relying on cross-format impact queries for SQL-defined tables touched only by Pentaho jobs.
Ask the ledger instead of reverse-engineering undocumented Kettle XML by hand.
ekos_impact/ekos_dependents answer "what breaks?" from the real dependency graph.
Moving Kettle to dbt/Airflow against an already-extracted Source→Sink shape, not a re-read of 40 XML files.
SQL-defined tables and Pentaho steps that reference them aren't linked yet — a real limit, not a hidden one.
# compile every .ktr/.kjb and SQL file once $ ekos build && ekos recover && ekos resolve && ekos compile && ekos commit # ask questions, or run deterministic queries $ ekos ask "what does fact_sales depend on?" $ ekos ekl "FIND Object WHERE kind = 'Table'" # serve it to any MCP client over stdio $ ekos mcp serve --workspace .
| MCP tool | Answers |
|---|---|
| ekos_impact | What breaks if I change this table, job, or step |
| ekos_dependents | What already depends on this object |
| ekos_diff | What changed in the ledger since a given time |