π₯οΈ CLI Reference
Usage
fimod s -i <INPUT> -m <MOLD> [OPTIONS]
fimod s -i <INPUT> -e '<EXPRESSION>' [OPTIONS]
fimod s --no-input -m <MOLD> [OPTIONS]
Note
Either -m or -e is required (but not both).
π― Core options
| Option | Short | Description | Default |
|---|---|---|---|
--input |
-i |
Input file path or URL (https://...) |
stdin |
--mold |
-m |
Path, URL, or registered name of the transform script | β |
--expression |
-e |
Inline Python expression (mutually exclusive with -m) |
β |
--output |
-o |
Output file path | stdout |
--in-place |
Modify input file in-place (requires -i, incompatible with -o and URLs) |
β | |
--slurp |
-s |
Read multiple JSON values into a single array | β |
--no-input |
Skip input β data = None in Python |
β | |
--check |
No stdout; exit 0 if result is truthy, 1 if falsy | β | |
--debug |
-d |
Print pipeline diagnostics to stderr | β |
π Format control
| Option | Description |
|---|---|
--input-format |
Explicitly set input format. Auto-detected from extension if omitted. |
--output-format |
Explicitly set output format. Defaults to input format if omitted. |
Supported values: json Β· json-compact Β· ndjson Β· yaml Β· toml Β· csv Β· txt Β· lines Β· raw (output-only) Β· http (input-only)
π Auto-detection
| Extension | Format |
|---|---|
.json |
JSON |
.ndjson, .jsonl |
NDJSON |
.yaml, .yml |
YAML |
.toml |
TOML |
.csv, .tsv |
CSV |
.txt, .text |
TXT |
| (none / stdin) | JSON (default) |
Lines is never auto-detected
Always use --input-format lines explicitly.
π₯ Your input can be an HTTPS request!
Awesome: the input can be an HTTPS request. The -i flag accepts URLs exactly like file paths β fimod fetches, parses, and transforms in a single command. No curl, no wget, no pipes.
# Fetch JSON from an API
fimod s -i https://api.github.com/repos/pytgaen/fimod -e 'data["name"]' --output-format txt
# Multiple URLs in batch mode
fimod s -i https://jsonplaceholder.typicode.com/users/1 https://jsonplaceholder.typicode.com/users/2 -e 'data' -o responses/
Format auto-detection: the response's Content-Type header is used as fallback when --input-format is not set (application/json β JSON, text/csv β CSV, etc.). You can always override explicitly.
--in-place is not allowed with URLs
HTTP options
| Option | Description | Default |
|---|---|---|
--header "Name: Value" |
Custom HTTP header (repeatable) | β |
--timeout <seconds> |
Request timeout | 30 |
--no-follow |
Don't follow HTTP redirects | follows redirects |
# Authenticated API
fimod s -i https://api.github.com/user \
--http-header "Authorization: Bearer $GITHUB_TOKEN" \
-e 'data["login"]' --output-format txt
# Disable redirects to inspect the Location header
fimod s -i https://github.com/pytgaen/fimod/releases/latest \
--input-format http --no-follow \
-e 'data["headers"]["location"]' --output-format txt
--input-format http β raw HTTP response
When you need the full HTTP response (status code, headers, body), use --input-format http. Instead of parsing the body, fimod gives you a dict:
data = {
"status": 200,
"headers": {"content-type": "application/json", "location": "..."},
"body": "..." # raw response body as a string
}
# Get the redirect target of a URL
fimod s -i https://github.com/pytgaen/fimod/releases/latest \
--input-format http --no-follow \
-e 'data["headers"]["location"].split("/")[-1]' --output-format txt
# β v0.3.0
# Combine with set_input_format() to re-parse the body
fimod s -i https://api.github.com/repos/pytgaen/fimod/releases/latest \
--input-format http \
-e 'set_input_format("json"); data["body"]' \
-e 'data["tag_name"]' --output-format txt
http is input-only
Using --output-format http will produce an error. HTTP is only meaningful as an input format.
Requires the full build variant
HTTP input needs reqwest, which is only included in FIMOD_VARIANT=full or cargo build --features full.
π₯ Slurp mode (--slurp / -s)
-s has two distinct uses depending on whether you pass a single input or multiple -i entries.
Single input β NDJSON / concatenated JSON
Reads multiple concatenated JSON values from a single source and collects them into an array.
# π Two separate JSON objects β array of two
printf '{"a":1}\n{"b":2}' | fimod s --slurp -e 'len(data)'
# β 2
# π Combine multiple JSON files via cat (JSON only)
cat file1.json file2.json | fimod s --slurp -e '[item for item in data if item.get("active")]'
For non-JSON formats, --slurp wraps the single parsed value in a one-element array.
Multiple inputs β multi-file slurp
When combined with two or more -i flags, -s switches to multi-file slurp mode: all files are parsed (each in their own format) and combined into a single data structure. The mold runs once against the combined result.
Two sub-modes controlled by the -i syntax:
| Syntax | Mode | data shape |
|---|---|---|
-i f1 -i f2 |
list | [parsed_f1, parsed_f2] |
-i f1: -i f2: |
named (auto stem) | {"f1": parsed_f1, "f2": parsed_f2} |
-i f1:alias -i f2:other |
named (explicit) | {"alias": parsed_f1, "other": parsed_f2} |
Rules:
- All entries must use : or none must (mixing β error)
- Auto stem uses the filename without extension; duplicate stems β error (use explicit aliases)
- Incompatible with --in-place and -o <directory>
# β List mode β access by index, cross-format (JSON + YAML)
fimod s -i base.json -i override.yaml -s -e 'data[1]["env"]'
# π·οΈ Named mode β auto stem as key
fimod s -i defaults.json: -i prod.toml: -s \
-e 'data["defaults"]["timeout"]'
# π·οΈ Named mode β explicit aliases (resolves stem collisions)
fimod s -i config/base.json:base -i other/base.json:fallback -s \
-e 'data["fallback"]["host"]'
# π Diff two files (with df_ helpers, once implemented)
fimod s -i before.json:old -i after.json:new -s \
-e 'df_diff(data["old"], data["new"])'
# πΎ Write result to a file
fimod s -i a.yaml -i b.yaml -s -e 'data[0]' -o merged.yaml
π« No-input mode (--no-input)
Skip input entirely β data is None in Python. Use to generate data from scratch.
Incompatible with
-i, --input-format, --in-place
fimod s --no-input -e '{"status": "ok", "ts": args["ts"]}' --arg ts="2024-01-01"
fimod s --no-input -m generate.py --arg count=5
# generate.py
def transform(data, args, env, headers):
n = int(args["count"])
return [{"id": i, "value": i * i} for i in range(n)]
β
Check mode (--check)
Suppresses stdout and uses the truthiness of the result as the exit code.
- Exit 0 β result is truthy
- Exit 1 β result is falsy
See Exit Codes for the full truthiness table.
# β
Validate a record
fimod s -i record.json -e 'data.get("email") and data.get("name")' --check
# π Use in a shell conditional
if fimod s -i config.json -m validate.py --check; then
echo "β
Config is valid"
else
echo "β Config has errors" >&2
exit 1
fi
Tip
When a mold calls set_exit(code), that code takes priority over --check truthiness.
ποΈ Mold registries
Registries are named collections of molds (local directories or remote repos).
Use @name or @registry/name with -m to reference a mold by name.
fimod registry setup # π First-run setup (official catalog)
fimod registry add my ~/molds/ # β Add local registry
fimod registry add official https://github.com/org/molds # β Add GitHub registry
fimod registry list # π List registries
fimod registry show my # π Show details
fimod registry remove my # ποΈ Remove
fimod registry set-default official # β Change default
fimod registry build-catalog my # π¦ Generate catalog.toml
Config stored in ~/.config/fimod/sources.toml.
registry setup β first-run onboarding
fimod registry setup adds the official fimod mold catalog if not already present. The install scripts call it automatically, but it is safe to run manually at any time (idempotent).
fimod registry setup # interactive β asks before adding
fimod registry setup --yes # non-interactive / CI β skips the prompt
fimod registry setup --force # promote official registry to default even if another default exists
Behaviour summary:
| Situation | Without --force |
With --force |
|---|---|---|
| Already configured | "already configured", no-op | same |
| No default registry yet | adds as default (fresh install) | same |
| Default already exists | adds without changing default | adds and promotes to default |
| Non-interactive (no TTY) | skips silently | skips silently |
FIMOD_REGISTRY β ephemeral registries for CI
In CI/CD or ephemeral environments, use the FIMOD_REGISTRY environment variable instead of fimod registry add. Comma-separated entries, optionally named:
# Anonymous β resolves @mold
FIMOD_REGISTRY=./molds fimod s -i data.json -m @clean
# Named β resolves @ci/mold and @mold
FIMOD_REGISTRY="ci=./molds,staging=https://github.com/org/molds" fimod s -i data.json -m @ci/clean
# Mixed anonymous + named
FIMOD_REGISTRY="ci=./molds,/opt/shared-molds" fimod s -i data.json -m @clean
FIMOD_REGISTRY takes priority over sources.toml (env overrides config, standard Unix convention). Named entries support @name/mold resolution.
# Register a local collection onceβ¦
fimod registry add my ~/molds/
# β¦then reference molds by name
fimod s -i messy.csv -m @cleanup # default registry
fimod s -i messy.csv -m @my/cleanup # named registry
Authentication β tokens are resolved automatically, or overridden per-registry:
| Source type | Default token |
|---|---|
github.com |
$GITHUB_TOKEN |
| GitLab | $GITLAB_TOKEN |
| Other HTTP (Gitea, Forgejo, β¦) | $FIMOD_DL_AUTH_TOKEN |
| Custom | --token-env MY_VAR at registry add time |
GitHub URL formats
fimod accepts different URL forms depending on the Git ref type you want to pin to:
| Ref type | URL to pass to registry add |
|---|---|
Branch (main, dev, β¦) |
https://github.com/org/repo/tree/main/molds |
Semver tag (v1.0.0, 2.3.4, β¦) |
https://github.com/org/repo/tree/v1.0.0/molds |
Other tag (stable, latest, β¦) |
https://raw.githubusercontent.com/org/repo/refs/tags/stable/molds |
| Commit SHA | https://github.com/org/repo/tree/abc1234.../molds |
For branches and semver tags, pass the standard github.com/tree/β¦ URL β fimod converts it to a raw URL automatically, using refs/heads/ for branches and refs/tags/ for semver-looking refs.
For non-semver tags (e.g. stable, latest), fimod cannot distinguish them from branch names based on the ref string alone. Pass the raw.githubusercontent.com URL with the full ref path instead:
# Branch β standard github.com URL
fimod registry add mylib https://github.com/org/repo/tree/main/molds
# Semver tag β standard github.com URL
fimod registry add mylib https://github.com/org/repo/tree/v1.2.0/molds
# Non-semver tag β raw URL required
fimod registry add mylib https://raw.githubusercontent.com/org/repo/refs/tags/stable/molds
Browsing available molds
fimod mold list # list molds in the default registry
fimod mold list official # list molds in a specific registry
For local registries, mold names and descriptions are discovered by scanning .py files.
For remote registries (GitHub, GitLab, HTTP), a catalog.toml must be present at the root of the registry.
Maintainers generate it with:
The catalog.toml is a simple TOML file committed alongside the molds:
[molds.normalize]
description = "Normalise field names to snake_case"
[molds.filter_active]
description = "Keep only active records"
Mold descriptions come from the module-level docstring at the top of each script:
π CSV options
| Option | Description |
|---|---|
--csv-delimiter <char> |
Separator character for input (default: ,). Use \t for tabs. |
--csv-output-delimiter <char> |
Separator for output (defaults to --csv-delimiter). |
--csv-no-input-header |
First line is data, not header. Columns: col0, col1, ... |
--csv-no-output-header |
Don't write header row in output. |
--csv-header "a,b,c" |
Explicit column names (implies no header in file). |
Column order is preserved
No alphabetical sorting through transforms.
When the input CSV has a header row, a headers global is automatically available in your script β see Mold Scripting β CSV headers.
β‘ Inline expressions vs scripts
Best for one-liners:
fimod s -i users.json -e '[u for u in data if u["active"]]'
fimod s -i data.json -e '{"name": data["first"].upper()}'
fimod s -i data.json -e 're_findall(r"\d+", data["text"])'
Multi-statement? Write def transform inside -e.
ποΈ Special output formats
Sometimes you need to control the output format for chaining with other tools, without changing the file extension:
# π¦ Compact JSON: one-line JSON for piping
fimod s -i data.json -e 'data' --output-format json-compact
# {"name":"Alice","age":30}
# π TXT: evaluate string without JSON quotes (ideal for shell variables)
NAME=$(fimod s -i data.json -e 'data["name"]' --output-format txt)
echo "Hello $NAME" # Hello Alice
# π₯ Raw: download binary streams or raw bytes (no parsing, bypass pipeline)
fimod shape -i https://example.com/file.bin --output-format raw -o file.bin
π Passing variables (--arg)
fimod s -i users.json --arg threshold=30 -e '
[u for u in data if u["age"] > int(args["threshold"])]
'
# Or via mold:
fimod s -i data.json -m filter.py --arg threshold=30 --arg prefix="A"
Access via args["key"] in the transform(data, args, env, headers) function.
π Format conversion
Pass-through expression for pure format conversion:
fimod s -i config.yaml -e 'data' -o config.toml
fimod s -i data.csv -e 'data' --output-format json
fimod s -i users.json -e 'data' --output-format lines
π Debug mode (--debug / -d)
Prints pipeline diagnostics to stderr (stdout stays clean for piping):
Output includes: input/output format, mold source, full script, input data, output data.
Tip
In debug mode, Python print() statements are also redirected to stderr.
π’ Message verbosity (--quiet / --msg-level)
Control which msg_* functions in mold scripts produce output:
fimod s -i data.json -m transform.py --quiet # errors only
fimod s -i data.json -m transform.py --msg-level=verbose # + msg_verbose()
fimod s -i data.json -m transform.py --msg-level=trace # + msg_trace()
--quiet and --msg-level are mutually exclusive. See built-ins reference for the full visibility table.
βοΈ In-place editing (--in-place)
Modify the input file directly:
Requires -i. Incompatible with -o.
π Stdin / stdout
# π₯ Read from stdin
cat data.json | fimod s -e '{"count": len(data)}'
# π Pipe chain
curl -s https://jsonplaceholder.typicode.com/todos | fimod s -e '[d for d in data if d["completed"]]' | jq .
π Monty REPL (fimod monty repl)
Start an interactive Python REPL powered by the embedded Monty engine β no system Python needed.
fimod monty repl
# Monty REPL v0.0.8 β fimod v0.1.0-alpha.1 (exit or Ctrl+D to quit)
# >>> 2 + 2
# 4
# >>> [x ** 2 for x in range(5)]
# [0, 1, 4, 9, 16]
# >>> exit
Features:
>>>/...prompts with automatic multi-line continuation (blocks, implicit line joins)- Command history (arrow keys, via rustyline)
- Exit with
exitor ++ctrl+d++
Same engine as fimod shape
The REPL runs the exact same Monty runtime used by fimod shape, so you can experiment with Python expressions and data structures before putting them into a mold.