Standalone Usage
metapod works as a standalone tool — no remote platform required. Extract metadata locally, inspect the JSON output, pipe it to your own systems, or use it in CI/CD.
Local file mode (default)
Every metapod run command writes JSON to ./output/:
metapod run "oracle.metadata.*" --config config.yaml --output ./output
# Output structure:
# ./output/
# oracle/
# metadata/
# tables.json
# columns.json
# views.json
# source_code.json
# ...
No push step required. The JSON files are the product.
Output format
Each probe writes one JSON file — a ProbeResult envelope:
{
"probe": "oracle.metadata.tables",
"source": {
"type": "oracle",
"id": "prod-db:1521/ORCLPDB1/RISK_MGMT"
},
"timestamp": "2026-03-29T12:00:00+00:00",
"records": [
{
"table_name": "CUSTOMERS",
"owner": "RISK_MGMT",
"row_count": 15000,
"created": "2025-06-15 10:30:00",
"modified": "2026-03-28 08:45:00"
},
{
"table_name": "ORDERS",
"owner": "RISK_MGMT",
"row_count": 842000,
"created": "2025-06-15 10:31:00",
"modified": "2026-03-29 02:15:00"
}
],
"record_count": 2,
"duration_ms": 234,
"error": null
}
Fields:
probe— fully qualified probe namesource.type— connector type (oracle, postgres, azure_sql, …)source.id— connection identifier (host, port, service, schema)records— array of extracted metadata records (shape varies by probe)record_count— length of records arrayduration_ms— execution time in millisecondserror— null on success, error message on failure
Reading output in Python
import json
from pathlib import Path
# Load all probe results
for jf in Path("./output").rglob("*.json"):
data = json.load(jf.open())
print(f"{data['probe']}: {data['record_count']} records")
for record in data["records"]:
print(f" {record}")
Converting to CSV
# Quick one-liner: tables to CSV
python3 -c "
import json, csv, sys
data = json.load(open('output/oracle/metadata/tables.json'))
w = csv.DictWriter(sys.stdout, fieldnames=data['records'][0].keys())
w.writeheader()
w.writerows(data['records'])
" > tables.csv
Converting to pandas DataFrame
import json
import pandas as pd
data = json.load(open("output/oracle/metadata/columns.json"))
df = pd.DataFrame(data["records"])
print(df.head())
# Filter to a specific table
print(df[df["table_name"] == "CUSTOMERS"])
Comparing extractions (diff)
Run probes twice and compare:
# First extraction
metapod run "oracle.metadata.*" --output ./output
# Later...
mv ./output ./output.prev
metapod run "oracle.metadata.*" --output ./output
# Compare
metapod diff --current ./output --previous ./output.prev
Output shows added, removed, and changed records per probe.
Incremental extraction (delta mode)
Skip unchanged resources on re-runs:
# First run — extracts everything
metapod run "oracle.metadata.*" --delta --output ./output
# Second run — only changed tables/columns emitted
metapod run "oracle.metadata.*" --delta --output ./output
See Delta Engine for details on change detection strategies.
Daemon mode (pull)
Serve probe results via HTTP — other tools call metapod on demand:
metapod serve --config config.yaml --port 9090
# From any consumer:
curl http://localhost:9090/probes/oracle.metadata.tables
curl http://localhost:9090/catalog
curl http://localhost:9090/health
Optional: push to a remote platform
If you use Dataflix, DataHub, or a custom API, push results after extraction:
# To Dataflix
metapod push --target https://dataflix.example.com --project my-project
# To any REST API (custom script)
python3 push_to_datahub.py --input ./output
See Platform Integrations for platform-specific guides.
Scheduling extractions
Run probes on a cron schedule (blocks forever):
metapod schedule "oracle.metadata.*" --cron "0 6 * * *" --config config.yaml
For production, prefer a container scheduler (Kubernetes CronJob, Airflow DAG). See Docker & CI/CD.