Skip to content

πŸ–₯️ 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
--no-cache Bypass local cache for remote catalogs and molds uses cache
# 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
    "body_size": 1234,      # response size in bytes
    "content_type": "application/json",
    "url": "https://example.com/api/data"
}
# 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 default build variant

HTTP input needs reqwest, which is included in the default build. Use FIMOD_VARIANT=slim (or cargo build --no-default-features) if you want to opt out.


πŸ“₯ 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> - URLs cannot carry a :alias suffix (the :// scheme separator collides with the alias delimiter, so URLs are always treated as bare entries). When mixing HTTP inputs with local files, list mode is the only option β€” access via data[0], data[1], … in input order.

# βž• 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.


βš™οΈ Setup

fimod setup <category> defaults installs the canonical configuration for a category. It's what the install scripts call after downloading the binary, but you can re-run it at any time.

fimod setup all defaults --yes          # πŸš€ registry + sandbox in one go
fimod setup registry defaults --yes     # community registries only
fimod setup sandbox defaults --yes      # sandbox policy only
Flag Description
--yes Non-interactive (required on CI / non-TTY).
--force Overwrite an existing sandbox.toml (ignored for registry).

What each target does:

  • registry β€” installs the community registries in ~/.config/fimod/sources.toml. Idempotent; safe to re-run. Same effect as the legacy fimod registry setup.
  • sandbox β€” writes the recommended sandbox policy to ~/.config/fimod/sandbox.toml. Refuses to overwrite without --force.
  • all β€” runs registry then sandbox, stopping at the first error.

See Sandbox policy for what the sandbox file controls and how it is resolved.


πŸ—‚οΈ 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 add my ~/molds/                          # βž• Add local registry
fimod registry add corp 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-priority corp 0                       # ⭐ Set P0 (highest priority)
fimod registry set-priority mycompany 1                  # πŸ“Œ Set priority P1
fimod registry set-priority mycompany --clear            # πŸ“Œ Clear priority
fimod registry build-catalog ./molds                     # πŸ“¦ Generate catalog.toml from a directory
fimod registry build-catalog --registry my               # πŸ“¦ Generate catalog.toml for a registered registry
fimod registry cache info                                # πŸ“Š Show cache location and usage
fimod registry cache clear                               # 🧹 Clear all cached catalogs and molds

Config stored in ~/.config/fimod/sources.toml. Cache stored in ~/.cache/fimod/.

registry setup β€” first-run onboarding

Deprecated in 0.5.0 β€” removed in 0.10.0

Use fimod setup registry defaults instead. The legacy form still works but prints a deprecation warning on stderr.

fimod registry setup adds the fimod example molds registry (P99) if not already present. It remains operational for backward compatibility but delegates to the new setup path internally.

fimod registry setup           # interactive β€” asks before adding
fimod registry setup --yes     # non-interactive / CI β€” skips the prompt

Behaviour:

  • Already configured (same URL found) β†’ no-op, prints "already configured".
  • Legacy "official" registry detected β†’ prompts to migrate it to "examples" (P99).
  • Fresh install β†’ adds "examples" at P99 (not default β€” your own registries take precedence).
  • Non-interactive (no TTY) β†’ skips silently unless --yes is passed.

Priority-based resolution

When you use @mold (without a registry prefix), fimod searches all configured registries in priority order until the mold is found:

Priority Source
P0 FIMOD_REGISTRY anonymous entries (env always wins)
P0, P1, P2, … Registries with a [priority] rank
β€” Remaining registries (file order, after all prioritized ones)
$ fimod registry list
  corp        [github]  github.com/org/fimod-powered       P0
  mycompany   [http]    registry.corp.com/fimod             P1
  internal    [local]   /home/user/molds                    P2
  examples    [github]  github.com/pytgaen/fimod            P99

With @registry/mold (explicit prefix), only that specific registry is searched.

set-priority β€” assign a priority rank

fimod registry set-priority mycompany 1    # Set mycompany to P1
fimod registry set-priority internal 2     # Set internal to P2
fimod registry set-priority mycompany --clear  # Remove priority

When the requested rank is already taken, the behaviour depends on context:

  • Swap (default) β€” if both registries already have a rank, they exchange positions:

    # Before: mycompany=P1, internal=P2
    $ fimod registry set-priority internal 1
    # After:  internal=P1, mycompany=P2
    
  • Cascade β€” if the source had no prior rank (or --cascade is passed), existing entries shift down:

    # Before: mycompany=P1, internal=P2
    $ fimod registry set-priority newreg 1
    # After:  newreg=P1, mycompany=P2, internal=P3
    

Use --cascade to force cascade behaviour even when both registries already have a rank.

sources.toml format

[priority]
corp = 0
mycompany = 1
internal = 2
examples = 99

[sources.corp]
type = "github"
url = "https://github.com/org/fimod-powered"

[sources.mycompany]
type = "http"
url = "https://registry.corp.com/fimod"

[sources.internal]
type = "local"
path = "/home/user/molds"

[sources.examples]
type = "github"
url = "https://github.com/pytgaen/fimod/tree/main/molds"

The [priority] section is optional. Without it, registries are searched in file order.

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          # searches all registries in priority order
fimod s -i messy.csv -m @my/cleanup       # explicit 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 all registries
fimod mold list examples     # list molds in a specific registry
fimod mold show pick_fields  # show metadata for a mold

Both mold list and mold show accept --output-format json for machine-readable output.

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:

fimod registry build-catalog ./molds         # scans directory and writes catalog.toml
fimod registry build-catalog --registry my   # same, resolving path from a registered registry

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:

"""Normalise field names to snake_case."""
def transform(data, args, env, headers):
    ...

Cache management

Remote catalogs and molds are cached locally in ~/.cache/fimod/ to avoid re-fetching on every invocation.

Catalog caching uses HTTP ETags: on subsequent requests, fimod sends If-None-Match and skips the download on 304 Not Modified.

Mold caching uses content hashes from the catalog: build-catalog computes a hash per mold directory, and the client only re-downloads when the hash changes.

fimod registry cache info              # show cache location and disk usage
fimod registry cache clear             # wipe all cached data
fimod registry cache clear @name       # wipe a specific mold (planned)
fimod s -i data.json -m @mold --no-cache  # bypass cache for this invocation

Override the cache directory with FIMOD_CACHE_DIR. For direct-URL molds (not registry-based), cache TTL is controlled by FIMOD_CACHE_TTL (minutes, default 360, 0 = infinite, negative = disabled).


πŸ›‘οΈ Sandbox policy

Every fimod s invocation runs the mold under a sandbox that limits what it can do on the host. A policy controls three things:

  • Clock access β€” whether datetime.now() / date.today() resolve to real values or raise.
  • Environment access β€” which os.getenv(KEY) calls are allowed (glob-matched).
  • Hard resource limits β€” wall-clock duration and peak memory.

Resolution

The policy is resolved in this order (first match wins):

  1. --sandbox-file <path> β€” CLI flag.
  2. $FIMOD_SANDBOX_FILE β€” environment variable.
  3. ~/.config/fimod/sandbox.toml β€” per-user canonical config.
  4. (none of the above) β€” zero-authorization defaults.

Special cases:

  • --sandbox-file="" (empty string) forces zero-authorization regardless of $FIMOD_SANDBOX_FILE or the canonical file. Portable across Linux/macOS/Windows.
  • If $FIMOD_SANDBOX_FILE points to a missing path, fimod errors out explicitly rather than falling back silently.

Bootstrap the canonical file with fimod setup sandbox defaults --yes.

Hard limits

Apply even with zero authorization:

Limit Default
max_duration 2m
max_memory 1GB

On violation, fimod exits with code 137 and a stderr message like:

sandbox exploded: max_duration exceeded (2m)
sandbox exploded: max_memory exceeded (1024 MB)

sandbox.toml schema

[sandbox]
allow_clock  = true              # allow datetime.now() / date.today()
max_duration = "2m"              # "30s", "2m", "unlimited"
max_memory   = "1GB"             # "500MB", "1GB", "unlimited"
allow_env    = ["LANG", "TZ_*"]  # glob patterns: "*", "PREFIX_*", "EXACT"

allow_env = [] (default) blocks every os.getenv() call. Patterns match the key name exactly, as a prefix (TZ_*), or anything (*).

Denied calls raise PermissionError inside the mold β€” catch it if you want a graceful fallback:

import os
lang = None
try:
    lang = os.getenv("LANG")
except PermissionError:
    pass  # sandbox forbids env access

πŸ“Š 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).
# πŸ”€ CSV β†’ TSV
fimod s -i data.csv -e 'data' --output-format csv --csv-output-delimiter '\t'

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.

For reusable transforms:

# cleanup.py
def transform(data, args, env, headers):
    for row in data:
        row["name"] = row["name"].strip().title()
    return data
fimod s -i messy.csv -m cleanup.py -o clean.json

Load from a URL:

fimod s -i data.json -m https://example.com/transforms/normalize.py

πŸŽ›οΈ 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

# πŸ“‘ Lines: one array element per line (shell-friendly lists)
fimod s -i users.json -e '[u["email"] for u in data]' --output-format lines

# πŸ“₯ 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):

fimod s -i data.json -m transform.py --debug

Output includes: input/output format, per-step identification (step N/M (label)), full script, input data, output data, phase timings (parse, execute, serialize, total).

Each step in a chain is logged with its 1-based index, the chain length, and a short label (the raw -m reference, or -e '<expr>' for inline expressions, truncated to ~50 chars). Steps injected at runtime via pipeline.insert_next / pipeline.append are annotated with injected by step P:

[debug] step 1/3 (./normalize.py)
[debug] step 2/3 (@common/flatten)
[debug] step 3/3 (-e 'data', injected by step 2)

The same identifier is prepended to runtime errors, so the failing step is always unambiguous:

Error: in step 2/3 (@common/flatten): Python error in mold:
KeyError: 'foo'

Timings are always emitted in seconds with millisecond precision (0.045s) for easy parsing:

[debug] parse: 0.002s
[debug] execute: 0.045s
[debug] serialize: 0.001s
[debug] total: 0.048s
# extract execute time of a run
fimod s -i big.json -m heavy.py --debug 2>&1 1>/dev/null \
  | awk '/\[debug\] execute:/ {print $3}'

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:

fimod s -i config.json -e '{"host": data["host"], "port": data["port"]}' --in-place

Requires -i. Incompatible with -o.


πŸ‘€ Watch mode (--watch / -w)

Re-runs the transform whenever the input file or a local mold script changes β€” handy for iterating on a mold while editing it in another window:

fimod s -i data.json -m cleanup.py -o out.json --watch

Output goes to the usual destination (-o file or stdout). Status messages stream on stderr, so piping still works:

fimod s -i data.json -m cleanup.py --watch | jq .name
# stderr: [watch] watching data.json, cleanup.py
# stderr: [watch] run #1 ok (42ms)
# stderr: [watch] run #2 ok (38ms)   (after editing cleanup.py)
# stdout: "alice"
# stdout: "alice"

A run that fails (Python error, parse error, missing file) is reported but does not exit the watch loop β€” fix the script and the next save triggers another run:

[watch] run #3 failed (12ms)
  in step 1/1 (cleanup.py): Python error in mold:
  NameError: name 'foo' is not defined

What is watched:

  • -i <file> (the input file, must be local β€” not stdin or HTTP).
  • Each -m <file.py> that points to a local file (registry molds @reg/name and inline -e expressions are not watched).

Refused combinations (each emits an explicit error):

Combo Reason
--watch + -i - (stdin) nothing to watch
--watch + -i http(s)://… HTTP inputs not supported
--watch + multiple -i (batch) watch is single-input only
--watch + --input-list input list mode unsupported
--watch + --no-input no input means no file to watch
--watch + --in-place feedback loop (we'd watch the file we write)
--watch + --output-format raw raw mode bypasses the transform pipeline

If the input is removed mid-watch (e.g. git checkout of a branch that deletes it, or a rm between two cp commands), the watcher logs:

[watch] warn: input removed, waiting for it to reappear...

and keeps running. The next time the file reappears, a normal re-run fires. Atomic saves (vim, VSCode tmp + rename pattern) stay silent β€” only sustained absence triggers the warning.

Implementation details: events go through a two-level debounce. The first level (150 ms, hard-coded) absorbs the multiple notify events a single :w produces. The second level (default 500 ms, override via FIMOD_WATCH_QUIET_MS=<ms>) waits for the filesystem to be quiet before firing the re-run β€” needed under WSL2 / inotify cross-process latency where event bursts can stretch beyond 400 ms. Parent directories are watched so atomic-rename editors (vim, VSCode) work correctly. The mold script is reloaded from disk on every iteration; no in-memory cache to invalidate.

Env var Default Purpose
FIMOD_WATCH_QUIET_MS 500 Quiet window before firing a re-run after an event.

The feature can be disabled at compile time with cargo build --no-default-features --features=reqwest (omits notify and ~25 transitive crates). A binary built without watch rejects the flag with a clear error.


πŸ”Œ 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 exit or ++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.


🐚 Shell completion

Fimod provides dynamic shell completions: subcommands, flags, format names, mold @references, and registry source names are all completed contextually.

Add one line to your shell rc β€” fimod setup completions prints the activation script on stdout, you eval it. The shell is auto-detected from $SHELL; pass --shell <SHELL> to override.

echo 'eval "$(fimod setup completions --shell bash)"' >> ~/.bashrc
echo 'eval "$(fimod setup completions --shell zsh)"' >> ~/.zshrc
fimod setup completions --shell fish > ~/.config/fish/completions/fimod.fish
echo 'eval (fimod setup completions --shell elvish | slurp)' >> ~/.elvish/rc.elv
Add-Content $PROFILE 'fimod setup completions --shell powershell | Out-String | Invoke-Expression'

Migrating from older snippets

If you previously added source <(COMPLETE=zsh fimod) (or the equivalent for your shell) to your rc, it still works β€” the underlying mechanism is unchanged. To switch to the new pattern, replace it with the eval "$(fimod setup completions ...)" line above.

What gets completed

You type ++tab++ completes
fimod Subcommands: shape, registry, mold, completions…
fimod shape -- All flags: --input, --mold, --debug…
fimod shape --input-format Format names: json, yaml, csv, ndjson, toml…
fimod shape --output-format Same format list
fimod shape -m @ Registry molds: @pick_fields, @examples/flatten_nested…
fimod registry show Configured source names
fimod registry remove Configured source names
fimod registry set-priority Configured source names
fimod registry build-catalog --registry Configured source names
fimod mold list Configured source names
fimod mold show --registry Configured source names
fimod setup completions --shell Shell names: bash, zsh, fish, elvish, powershell