Chapter 05

CLI Reference

Four verbs in one binary: run, publish, mirror, bench. Same engine code path on every verb, so what you bench is what you ship.

dotnet run --project src/RuleForge.Cli -- <verb> [options]

verbs:
  run       Execute a rule against a request, in-process or via HTTP
  publish   Push a local rule snapshot into DocumentForge
  mirror    Copy collections between DocumentForge instances
  bench     Throughput + latency probe

run

Execute a rule against a request payload. Default is in-process; pass --http to talk to a deployed engine instead.

dotnet run --project src/RuleForge.Cli -- run \
  --endpoint /v1/ancillary/bag-policy \
  --request  '@fixtures/scenarios/s-bag-3pc-markup15.json' \
  --debug
FlagDescription
--endpoint <slug>Endpoint path, e.g. /v1/ancillary/bag-policy (required)
--request <json|@file>Inline JSON body, or @path/to/file.json (required)
--debugInclude the full per-node trace + envelope durationMs
--http <baseUrl>POST to a running engine instead of in-process
--dfUse a DocumentForge source (otherwise local files)
--env <name>DF environment to read bindings from (default: staging)
--df-base <url>DF base URL (default https://documentforge.onrender.com)
--df-api-key <k>DF bearer token (or env RULEFORGE_DF_API_KEY)
--fixtures <dir>Override local fixture directory (in-process mode)

publish

Push a local rule snapshot to DocumentForge. The verb is idempotent: if a ruleversions doc with the same {ruleId, version} already exists, it's replaced; otherwise inserted. The rules header's currentVersion is bumped, and environments[envName].ruleBindings[ruleId] is set to the version.

dotnet run --project src/RuleForge.Cli -- publish \
  --rule fixtures/rules/rule-bag-policy.v7.json \
  --env  staging
FlagDescription
--rule <path>Path to a local rule JSON (required)
--env <name>Environment to bind to (default: staging)
--api-key <k>DF bearer token (or env RULEFORGE_DF_API_KEY)
--df-base <url>DF base URL

Effects on DocumentForge

  1. ruleversions: insert (or replace) {id: "rv-{ruleId}-{version}", ruleId, version, snapshot, publishedAt, publishedBy}
  2. rules[ruleId]: bump currentVersion and set status: published
  3. environments[envName].ruleBindings[ruleId] = version

mirror

Copy collections from one DocumentForge instance to another. Idempotent: each source doc is matched to the target by logical id field — existing rows are replaced, new rows are inserted. Used to spin up a co-located dfdb that mirrors a hosted DF.

dotnet run --project src/RuleForge.Cli -- mirror \
  --from https://documentforge.onrender.com \
  --to   http://localhost:5000
FlagDescription
--from <url>Source DF base URL (required)
--to <url>Target DF base URL (required)
--from-key <k>Source bearer (or env RULEFORGE_DF_API_KEY)
--to-key <k>Target bearer
--collections <list>Comma-separated. Default: rules,ruleversions,environments,referencesets,referencesetversions,nodetemplates,scenarios,connections

bench

Run N evaluations with a fixed request and report p50 / p95 / p99 / mean / max latency plus throughput. Two modes:

dotnet run --project src/RuleForge.Cli -- bench \
  --endpoint /v1/ancillary/bag-policy \
  --request  '@fixtures/scenarios/s-bag-3pc-markup15.json' \
  --df --df-base http://localhost:5000 \
  --warmup 100 --iterations 10000 --concurrency 16
FlagDescription
--endpoint <slug>Endpoint to bench (required)
--request <json|@file>Request payload (required)
--iterations NHot-loop iterations after warmup (default 1000)
--warmup NPre-bench iterations (default 100)
--concurrency NParallel workers (default 1)
--coldBuild a fresh source per request (defeats the cache, surfaces DF round-trip)
--df · --env · --df-base · --df-api-keySame as run

Sample output

━━ bench ━━
  rule         : Bag policy · slice 3d (calc markup + lookup fee) (v7)
  source       : DocumentForge
  endpoint     : POST /v1/ancillary/bag-policy
  iterations   : 10000
  warmup       : 100
  concurrency  : 16
  cold         : False  (fresh source per request)

  sample run   : decision=Apply

  total wall   : 136 ms  (73529 req/s effective)
  per request  :
    p50        : 0.13 ms
    p95        : 0.23 ms
    p99        : 1.45 ms
    max        : 9.58 ms
    mean       : 0.18 ms