Skip to content

Installer — 60-second Quickstart

Audience: ERP integrators/installers who want to show a customer the value of RAG in under a minute, from any data in the customer's IT estate.


1. Prerequisites (once per workstation, 90 sec)

Install lm

lm builds from source (Go 1.24+) — today's official install path:

cd lm && go build -o lm ./cmd/lm
# then put ./lm on your PATH, e.g.:  sudo mv lm /usr/local/bin/

Pre-built binaries (GitHub Releases) and a Homebrew tap will arrive with the public opening — they are part of the publication ritual, not shipped yet.

Run lumnik

See the deploy docs (Docker Compose recommended for a single customer). The lumnik JVM must have LUMNIK_SECRET_MASTER_KEY set at startup (validated — the JVM refuses to start without it).

Already done by up.sh. If you came from the Deploy page, deploy/selfhost/up.sh generated LUMNIK_SECRET_MASTER_KEY into .env (mode 600) — do not regenerate it. The manual recipe below is only for the non-compose paths: - systemd: openssl rand -base64 32EnvironmentFile=/etc/lumnik/.env - Kubernetes: a Secret mounted as an env var

Point lm at the hub (once)

lm config set-context selfhost --server http://localhost:8080 \
    --oidc-issuer http://localhost:8180/realms/lumnik
lm config use-context selfhost
lm login   # prints a URL + device code — demo user: integrator / integrator

Every scenario below assumes this context: on the deployed stack, each lm call is Bearer-authenticated — without lm login, everything returns 401.


2. Scenario A — Stripe via OpenAPI (60 sec)

# 1. Register the API key (AES-256-encrypted in DB via pgcrypto)
lm secret set STRIPE_API_KEY sk_test_xxx

# 2. Generate + apply the manifest from Stripe's OpenAPI (one command)
lm source rest from-openapi https://api.stripe.com/openapi.json --name stripe --tag billing --apply

# 3. Enable the scheduler on an endpoint
lm endpoint enable stripe/charges

# 4. Talk to the data
lm ask "how many payments this month?"

3. Scenario B — one-shot CSV (30 sec)

lm csv ingest customers.csv --scope sales --tag demo
lm ask "who are my customers in the Var?" --scope sales

The ingest creates a dormant connector (enabled=false, no scheduler) + endpoint + an ext.<name> table + RAG chunks. Promotion to recurring ingestion: see §5.


4. Scenario C — combined (90 sec)

lm secret set STRIPE_API_KEY sk_test_xxx
lm source rest from-openapi https://api.stripe.com/openapi.json --name stripe --tag billing --apply
lm csv ingest contacts.csv --scope billing
lm endpoint enable stripe/charges
lm ask "list the customers who paid in May"

4bis. Scenario D — nightly SFTP export (90 sec)

The most common shape: a customer ERP exports to an SFTP server every night.

lm secret set ACME_SFTP_KEY -      # paste the private SSH key on stdin, Ctrl+D
lm csv ingest sftp://lumnik@sftp.acme.io/export/billing-latest.csv \
    --key-secret ACME_SFTP_KEY --scope billing --name acme-billing
lm ask "how many invoices in the latest export?" --scope billing

To switch to daily recurrence:

lm describe connector acme-billing > acme-nightly.yaml
# edit: transport.path: /export/*.csv, schedule: "0 6 * * *", after_process: move, archive_path: /archive/
lm validate -f acme-nightly.yaml
lm apply -f acme-nightly.yaml
lm connector resume acme-nightly   # or: lm endpoint enable acme-nightly/<endpoint>


4ter. Scenario E — S3 prefix (60 sec)

lm secret set AWS_S3_ACCESS_KEY AKIA...
lm secret set AWS_S3_SECRET_KEY ...
lm csv ingest s3://acme-exports/billing/ \
    --region eu-west-3 --suffix .csv --scope billing
lm ask "top 10 customers by invoiced amount?" --scope billing

For MinIO / Cloudflare R2 / GCS-S3-compat: add --endpoint https://....


5. From demo to production

Customize the generated manifest

lm describe connector stripe > stripe.yaml
$EDITOR stripe.yaml         # adjust default_schedule, promote columns, content_template, etc.
lm validate -f stripe.yaml  # optional but recommended — field-by-field errors before apply
lm apply -f stripe.yaml

Promote the CSV to recurring ingestion

Coming in v1.1 via lm source csv add --path /watched/*.csv --schedule "*/5 * * * *".

Until then, editing the dormant connector's YAML and lm apply -f is the escape hatch.

Enter a secret without a shell trace

lm secret set STRIPE_API_KEY -
# (then paste the value on stdin, end with Ctrl+D)

Keeps the value out of shell history and ps -ef.

Production security

  • Master-key rotation: planned for v1.1 (lm secret rotate-master-key)
  • Audit: every secret access emits platform.secret.{created,updated,deleted,read} events into the outbox (SOC 2)
  • RBAC: permission platform.secret.manage (granted to lm_admin)
  • No REST endpoint ever returns a secret's value — if the installer loses it, they rewrite it

6. Troubleshooting

Error Cause Fix
Bearer token unavailable (env=STRIPE_API_KEY) secret set neither in DB nor as an env var lm secret list then lm secret set STRIPE_API_KEY ...
connector "stripe" already exists on --apply double --apply with the same --name lm describe connector stripe then adjust, or lm connector pause stripe + updated apply
429 Too Many Requests from the vendor too many calls for the quota edit default_rate_limit: 50/s in the YAML, then lm apply -f
lumnik.secret.master-key is too short at JVM startup env var missing or < 16 chars regenerate with openssl rand -base64 32 + export; restart the JVM
secret with this name already exists on secret set transparent update not handled lm secret rm NAME --force then set; or the CLI already falls back to update on 409

For connector details: docs/connectors/rest-generic.md.