Getting started

MarginCI runs in your laptop or CI runner. No account, MarginCI cloud service or hosted customer-code execution is involved. Use trusted application code and a bounded Node operation.

Once package distribution is available, the installation command is:

npm install --save-dev --save-exact marginci
./node_modules/.bin/marginci init

The package is not yet published. Ordinary installations will use the registry version and your committed lockfile. The local binary invocation never downloads a missing CLI or selects a global binary. Commit package.json and package-lock.json. Provision Node 25.3.0, Git and npm; npm 11.7.0 is tested. A supported pinned pnpm repository uses its exact toolchain and the following local invocation instead:

pnpm add -D -E marginci
node ./node_modules/marginci/dist/cli.js init
node ./node_modules/marginci/dist/cli.js doctor research --against HEAD
node ./node_modules/marginci/dist/cli.js test research --against HEAD

pnpm’s generated bin shim injects NODE_PATH, which is deliberately rejected. Invoke the installed CLI file with Node for all pnpm commands; do not weaken the isolation guard. This still uses the locked local package and never downloads a CLI. The npm examples below use npm’s local bin link. See support.

init inspects files, Git and dependency metadata without importing application modules, installing dependencies or contacting providers. It creates marginci.yml and adds generated .marginci/ and node_modules/ ignore rules. Existing config and ignore edits are preserved on repeat invocation. It does not generate or change application source. Fix an unsupported manager, missing/stale lock or path conflict before retrying.

Before executing a paid operation, supply:

Input Where it comes from
Operation One Node command; wrapper invokes your real application
Workload Explicit case IDs and inputs in config; read MARGINCI_CASE_JSON in the wrapper
Success Meaningful user-owned assertion; default exit 0, or strict single-record JSONL
Credentials Environment; credential_env checks presence without retaining its value
Provider/model Supported endpoint and exact response model ID; configure the application too
Value Your explicit rates or opted-in Exa estimate; no automatic tariff lookup
Baseline A commit containing shared setup; explicit --against SHA or local origin/HEAD
Threshold max_regression: 20% (same as 0.20)
Spend guard max_spend_usd, per-provider max_request_usd, native request limits

Create marginci/research.cjs:

async function main() {
  const { research } = await import('../src/research.js');
  const input = JSON.parse(process.env.MARGINCI_CASE_JSON);
  const result = await research(input);
  if (!result || !Array.isArray(result.sources) || result.sources.length === 0) {
    process.exitCode = 1;
  }
}
main().catch((error) => { console.error(error); process.exitCode = 1; });

The wrapper supplies fixed representative input, invokes real application logic and owns the success condition. It needs no provider accounting, event API, synthetic provider requests or MarginCI imports. Await all paid work. A nonempty source list is only an example success condition: choose checks that establish your application’s required outcome. MarginCI does not independently guarantee quality or production success rate.

Complete the generated model/rate fields; illustrative rates are not provider prices. Configure your application to use that same provider/model and provide credentials through its normal environment. Ignored .env files are not copied into snapshots, and MarginCI does not load them. Never embed credentials in config or workload files.

Then follow first adoption, commit the shared wrapper, config and workload, and run:

./node_modules/.bin/marginci doctor research --against HEAD
./node_modules/.bin/marginci test research --against HEAD

The first command inspects both snapshots without dependency installs or paid calls. The second installs each revision’s frozen dependencies and calls your configured providers. An identical committed application does not guarantee identical live spend; provider outputs can vary. After the setup reaches the default branch, use ./node_modules/.bin/marginci test research (local origin/HEAD) or an explicit baseline SHA.

Application stdout/stderr are private per-attempt files under .marginci/runs/; they never contaminate --json stdout. Use --verbose for progress on stderr and expanded human diagnostics. All run evidence remains until you remove it. CI setup is the next step after local validation.