The full upstream README, mirrored here for reference. Install config, tool schemas, adoption signals, and an original overview live on the Cejel listing page.
Cejel ("SEH-jel") — a trust certificate for your codebase.
Free, offline, no-signup CLI that scores the engineering signals that tell you whether to trust a repo — tests, secrets, isolation, claim-vs-reality, CI/audit discipline — and prints a trust certificate + badge. Especially valuable when AI wrote a lot of the code: that's exactly when you can't eyeball trust. Built on a deterministic, no-LLM scoring core — the free path makes zero network calls and requires no account.
Claim boundary: Cejel scores engineering-trust signals; it does not claim to detect software defects or prove that code is safe. Defect and vulnerability scanners remain evidence producers that Cejel can aggregate into a trust certificate.
Cejel is not another point scanner competing with the one you already run — it's the open, portable, offline trust certificate that aggregates them. Pipe in SARIF-compatible output (MunaTrust, Snyk, Semgrep, CodeQL, Codex) plus OpenSSF Scorecard, and get one shareable certificate + badge over all of them. See "Aggregate your scanners" below.
Cejel is used on Barg Labs’ own code. The public board labels publisher-owned snapshots separately from the ranked public repositories.
The public CLI default is witan-rubric-v17-2026-07-24, the last rubric to clear Cejel's
preregistered 200-repository untouched holdout. Published calibration figures apply only to that
exact rubric and frozen evaluation population. Later rubrics—including the current v18 through
v23 prospective series—are available only to explicit evaluation harnesses. Prospective rubrics
inherit none of v17's calibration figures; a bounded paired repair or corpus-delta result can
validate its stated construction without transferring precision, recall, or false-positive-rate
claims. Promoting a prospective rubric to the public default requires a fresh authenticated
untouched holdout, every preregistered gate to pass, and a separately recorded promotion decision.
Measured recall (bounded). Cejel publishes one cohort-level in-scope detection-recall figure, for the prospective v22 rubric, in
docs/calibration/v22-detection-recall/; no general figure exists, and the three quantities called recall are set side by side on cejel.dev/methodology. On a frozen, preregistered, in-scope held-out fixture set of 30 named defects, the released public default (v17, treea857f0b3) cited 16/30, two-sided 95% Wilson interval [36.1%, 69.8%]; the prospective v22 detector (commit8a289ea, tree10960a03) cited 24/30, two-sided 95% Wilson interval [62.7%, 90.5%]. Same fixtures, same partition, same controls in both runs. v22 is prospective and not the shipped default. Full preregistrations and results:docs/experiments/in-scope-detection-recall-v3-result-2026-08-09.mdanddocs/experiments/in-scope-detection-recall-v4-result-2026-08-11.md.
The defect-class census publishes the coverage-breadth boundary—which defect classes any shipped rule targets—and is explicitly not a recall claim.
No account, no key, no signup.
Single-file binary. One file. No Node, no npm, no node_modules, nothing installed.
Windows x86_64 (PowerShell).
Windows signing status:
cejel-Windows-x86_64.exeis intentionally unsigned in 0.4.10 and may trigger Microsoft SmartScreen. The release build removes Node's inherited signature before SEA injection and fails unless Windows reports the result asNotSigned; it does not ship an invalid signature. Before running it, verifySHA256SUMSand the GitHub build-provenance attestation. Each binary also has an attached SPDX SBOM and an own-platform verification receipt covering--version,--help, a real scan, source/binary parity, and a network-denied scan. If your policy requires Authenticode, use the npm package or the OCI image until a human-approved signing path is available.
Don't take the offline claim on trust — check it. Turn your network off, then run the binary. It will score your repository and write you a certificate anyway. That is the whole product, and you can falsify it in ten seconds:
npm.
Distribution note: Cejel
0.4.10is the coordinated release version for npm, standalone binaries, Docker/OCI, GitHub Action, Homebrew, and MCP Registry.
npx can reuse a stale cached package. Force the current npm release with the @latest
specifier above, and check the version that will run before comparing certificates:
If a root package.json still carries a template name, override only the certificate display
name while keeping the repository-derived stable slug:
From 0.4.5, use --product-name when two checkout directories must emit the
same identity fields. The supplied value sets both the display name and its slugified stable ID:
Product identity is caller context, not scored repository evidence, and is excluded from certificate byte-comparison claims.
The npm package is scoped as @cejel/cejel; its executable remains the short command cejel.
GitHub Action — score every PR and publish the badge:
For an executed public example that binds a release artifact to the same commit named by its Cejel certificate, see Certified releases with GitHub build provenance.
From source — it is AGPL and it runs offline, so reading it is rather the point:
Released binaries: cejel-Darwin-arm64, cejel-Darwin-x86_64, cejel-Linux-aarch64,
cejel-Linux-x86_64, and cejel-Windows-x86_64.exe. The release also carries
SHA256SUMS, a per-binary SPDX SBOM, and an own-platform verification receipt. Each binary
is executed against the source build and with networking denied before attachment. Releases
from v0.1.6 also carry a Sigstore bundle containing GitHub's signed build-provenance
attestation for the release set. Verify a downloaded binary with:
This is cryptographically signed provenance. It is distinct from Apple Developer ID or Microsoft Authenticode code-signing.
Docker / OCI. The current container release is 0.4.10:
The image defaults to cejel-mcp over stdio. To use the CLI instead:
The OCI image carries an SBOM, maximum-mode build provenance, and a signed registry attestation.
The Cejel OSS trust leaderboard is hosted on cejel.dev, which is the single current board. This repository no longer distributes a second copy of its scores or certificates. The board records its producing package version, rubric, run date, pinned public revisions, and reproduction instructions for that particular run. The private Alfred transparency snapshot is not independently reproducible.
The site's History section preserves the 2026-08-18 withdrawal: the earlier sealed-public-scorer reproducibility claim was false. The stale prospective-rubric copy previously linked here has been removed; it must not be treated as current evidence.
A path is published exactly when the reader can check it. Every public repository on the board cites full evidence paths and line numbers, everywhere, in every artifact — a certificate whose evidence you cannot open is not evidence. The private-repository entry (the studio monorepo's transparency snapshot) never cites a source path, anywhere, in any field or format — but the finding itself, its dimension, status, score, and content hash always survive; only the location is withheld, marked uniformly as "path withheld — private repository". Redaction removes a location, never a fact: a private repository failing its own check still shows up on its certificate, by name. The v3 repository scanner marks B1 and B5 not applicable for every repository, including ours; it does not accept structured substrate evidence for them. They remain defined for other rubric inputs, while the repository ranking excludes them fail-closed. Nobody is scored on evidence the public scanner cannot collect.
Calibrating a rubric against real, elite repositories surfaces mistakes; the record is part
of the trust claim, not something to bury. Two dimensions produced a punitive score for the
absence of a ratable surface rather than a real weakness, and both are fixed:
Django was flagged critical on dependency hygiene for using version ranges instead of exact
pins — normal, deliberate practice for a library, not an app; the rubric now scores
dependency hygiene against archetype-appropriate norms. OSSF Scorecard — Google's own
supply-chain security auditing tool — was flagged critical on audit-trail completeness for
publishing release notes via GitHub Releases instead of a committed CHANGELOG.md; a
repository with no ratable audit surface now returns "insufficient data" (excluded from the
composite) instead of a punitive score. The board also publishes a measured-coverage
indicator per row: a score reflects only its measured dimensions, and a row scored on fewer
than half of its applicable dimensions is shown as unranked rather than ordered against
better-evidenced rows.
scan scores the current directory with sensible defaults: no signup, fully offline. The
original ./cejel . form remains supported as a compatibility shorthand.
Prints a concise terminal certificate and writes to .cejel/:
report.json — the full structured report; scored runs carry numeric headline scores and a
score-band verdict, while abstained runs carry null scores and verdict: "insufficient_source"attestation.json — an unsigned in-toto statement binding the report digest, repository
revision, rubric, and scored-or-abstained outcome; ready for an external signercertificate.html — a self-contained HTML certificate (no external assets)badge.json — a shields.io endpoint payloadbadge.svg — a static, self-contained trust-score badgesummary.json — a compact digest (score, verdict, top findings)The attestation is deliberately explicit about its assurance level: Cejel creates the
statement, but it does not pretend to be an independent signer. Until a customer, reviewer,
or provenance system signs it, assurance.status is unsigned and issuer is
self-generated. An abstained scan carries only the refusal reason, never a numeric score.
Verify that an emitted report still matches its attestation:
This verifies the report schema and the report-to-attestation digest, repository, rubric, timestamp, and outcome binding. It does not verify a signature or signer identity; the command prints that boundary on every successful verification.
<path> — repo to score (default: current directory)--out <dir> — where to write report/certificate/badge files (default: .cejel;
--out-dir remains available as a compatibility alias)--min-score <n> — exit non-zero if the overall score is below n (0–4), or if Cejel
abstains and therefore cannot evaluate the threshold; used by the GitHub Action's optional
threshold gate--product-name <name> — Set both the caller-context
display name and slugified product ID so differently named checkouts can emit identical
certificates.--name <display> — override only the displayed project name while leaving the derived slug
unchanged; retained for compatibility--ingest <file|glob> — fold another scanner's output into the score (repeatable). Accepts
SARIF, OpenSSF Scorecard JSON, or the generic Cejel external-signal shape — format is
auto-detected. See "Aggregate your scanners" below.--rubric-pin <version> — Explicit opt-in only: pin an alternate rubric instead of the
calibrated public default. It
accepts the calibrated version or any published prospective rubric
(witan-rubric-v18-prospective-* through v23) and fails closed, naming what was accepted, on
anything else. v23 is prospective and uncalibrated, like every rubric after v17: the public
default (WITAN_LAST_CALIBRATED_RUBRIC_VERSION) is still witan-rubric-v17-2026-07-24, and v23
inherits none of v17's precision, recall, or false-positive-rate figures. It inherits v22
detector/scoring behavior and adds bounded A1 coverage-flag recognition (#276) plus per-signal
(rather than per-criterion) abstention for A1's coverage_percent/non_hollow_test_share
metrics (#278); every other criterion still abstains
criterion-wide under v23, same as v17/v22. Omit this flag for the calibrated result every
default scan produces — a prospective pin carries no precision/recall claim, and the terminal
certificate, HTML certificate, and Markdown report all state that plainly whenever one is used.--run-attempt <n> — record which CI run attempt produced this certificate, surfaced on the
human-readable certificate and as an additive-optional predicate.githubRunAttempt field on
attestation.json. The GitHub Action sets this automatically from GITHUB_RUN_ATTEMPT; omit it
for a local scan or any other CI — Cejel never fabricates or defaults a run attempt.--quiet — suppress the terminal certificate (files are still written)-h, --help — print usage and exit successfully-v, --version — print the version derived from the package manifest and exit successfullyCejel reads a repository's file tree, not its bytecode — it needs to recognise a file's source extension to say anything about it. It does not support every language, and it says so honestly rather than guessing:
unrecognised_ecosystem archetype, an explicit
insufficient_data criterion status, null headline scores, and an explicit machine verdict
of insufficient_source — never a numeric score-band verdict, and never the word
"Unverified" for the sole reason that cejel cannot read the language. The certificate states
plainly which of the 11 dimensions were and were not measured.This list will grow. It will never be "any codebase" — that claim is a promise the parser cannot keep, and an honest support matrix is worth more than a marketing line the code contradicts on the first unsupported repository someone runs it against.
Cejel doesn't compete with your AI-code scanner (MunaTrust, Snyk, Semgrep, CodeQL, Codex,
whatever runs in CI) — it sits on top of it. Feed a scanner's output in with --ingest and
Cejel folds those findings into the same rubric-scored, offline trust certificate, with the
contributing tools shown in the certificate and report as provenance:
Or drop files in .cejel/inputs/ and they're picked up automatically, no flag needed:
External findings only ever adjust a dimension score downward, and by a bounded amount —
they augment the native repo scan, they never replace it. Every ingested file is attributed
by name in certificate.html, report.json (consumedSignals), and the terminal output
("Incorporates findings from: ..."), so the certificate reads as a visible aggregation, not a
black box.
Three ways a scanner's output gets ingested:
SARIF — any SARIF 2.1.0-emitting tool (Semgrep, CodeQL, most commercial SAST/AI-code
scanners) works with zero configuration; --ingest auto-detects the runs array.
OpenSSF Scorecard — scorecard --repo=... --format=json > scorecard.json, then
--ingest scorecard.json; auto-detected by its checks array.
Generic JSON — for a tool that emits neither, map its output into the minimal shape
below (or write a small adapter mirroring
scorecard-adapter.ts if the format needs real
parsing):
dimension is one of the Witan rubric criterion ids (A1-A5, B1-B6); weight
(0–1, default 0.5) bounds how much this signal can move that dimension; severity is
critical | warning | info; location is optional.
The version field is required. Cejel rejects unversioned generic documents and unknown major versions rather than guessing. See the generic ingest contract, its published JSON Schema, and the synthetic CI heal-log mapping. Output-field stability and version routing are documented in format stability.
Endpoint JSON (host badge.json anywhere static — a repo file, a gist, GitHub Pages — and
point shields.io at it):
Or commit/link the static SVG directly:
See action/action.yml — runs Cejel on push/pull_request,
posts the score + top findings to the job summary, and can optionally fail the check below
a configurable min-score threshold. The scoring step makes no network calls and needs no
secrets.
The same package ships a second bin, cejel-mcp — a thin MCP (Model Context Protocol)
server over stdio, so any MCP client (Claude Code, Cowork, Cursor, Codex) can request a
trust certificate as a tool call. It wraps the exact same scan the CLI runs — same scores,
same verdict — and is listed on Smithery via the repo's smithery.yaml.
Add it to an MCP client config:
The server exposes one tool and two resources:
scan — input { path, format? }; scores the repository at path and returns the trust
cert as JSON (format: "summary", the default, is the compact digest; format: "json" is
the full report, identical to the CLI's report.json).cejel://last-scan/certificate.html and cejel://last-scan/badge.svg — the
HTML certificate and SVG badge for the most recent scan (the URI scheme derives from the
npm package name).Like the CLI, scoring over MCP is fully offline: no network calls, no telemetry, no signup, and the server writes no files.
Cejel is listed on the Smithery MCP registry via the repo's
smithery.yaml. Discovery needs no account:
Connecting through Smithery's own CLI is a separate step and requires a Smithery account:
smithery mcp add prompts to smithery login before it will create a connection, for every
caller, not just first-time ones.
If you'd rather not create a Smithery account, the generic MCP client config above needs no
login and no third-party CLI at all — it talks to the same cejel-mcp bin directly.
OpenClaw stores outbound MCP servers under mcp.servers. Add Cejel with the npm package's
shipped cejel-mcp bin:
The equivalent OpenClaw command is:
Pin openclaw@latest explicitly rather than running bare openclaw. The mcp add/mcp doctor subcommands need OpenClaw ≥2026.7.1-2, which itself needs Node ≥22.22.3 (also
≥24.15 or ≥25.9) — on an older-but-still-supported Node 22 patch, npm's own engines-aware
resolution silently serves an older OpenClaw release lacking these subcommands, and the
command above fails with error: unknown option '--command' instead of a version message.
The OCI image is an alternative when Docker is the preferred execution boundary. Replace the host path with the repository OpenClaw should allow Cejel to read:
Cejel is active in the Official MCP Registry as io.github.BargLabs/cejel. The explicit
OpenClaw configuration above works independently of catalog indexing.
Cejel scans code you point it at. This free adoption surface does not watch, intercept, or govern an agent's runtime actions. Runtime-action governance is a separate boundary for the future paid Agent Pack.
Scoring a repo — cejel scan . itself, and the Action's scoring step — makes zero network
calls: no telemetry, no signup, no model call. The scanner does invoke your local git
binary through one hardened subprocess chokepoint: fixed argv only (never a shell), an
explicit timeout and output bound, prompts and network transports disabled, proxy variables
removed, and repository-controlled filesystem monitoring neutralized. A static CI guard
allows node:child_process in that one module only and rejects direct network primitives
everywhere, while each release binary is also scanned with outbound networking denied.
Fetching the @cejel/cejel package the first time (like any npm-distributed CLI, including
this Action's own dependency install) does need network; that's a one-time install cost, not
part of the scoring guarantee. If the tracked-file inventory fails unexpectedly, the JSON,
HTML, and markdown certificates declare that the scanner used its bounded directory fallback
instead of silently presenting the two inventories as equivalent.
A certificate scores the repository tree at one pinned revision, and only that tree. That boundary is deliberate: a certificate that reached outside the pinned tree could not be reproduced by whoever receives it, and reproducibility is the entire product. Scoring only the pinned tree is correct — the gap was that nothing on the certificate itself told a reader which kind of statement they were holding. A repository whose regression suite lives in a separate repository, checked out and run by its own CI, is correctly reported as having zero test files against its source files. That statement is true about the tree and false about the system, and a reader with no other context cannot tell the difference.
Every certificate now carries a standing scope line, in the "How to read this certificate" section on every surface (HTML, Markdown, terminal), regardless of verdict: the certificate is a statement about the repository tree at the pinned revision, not about the system that tree belongs to, and evidence outside that tree is neither seen nor claimed to be absent. This is additive, not a hedge — a finding that says evidence was not found in this tree stays exactly as stated.
Four specific situations can make the tree's own conclusion misleading about the system it belongs to:
"test": "echo \"Error: no test specified\" && exit 1" placeholder being credited the same as a
real test runner. This was a detector defect, not a scope-disclosure gap — Cejel now checks the
test script's content against known test-runner invocations rather than crediting it by key
presence alone, so no separate disclosure line is needed for it.Cejel does not collect telemetry. External validation is therefore opt-in and inspectable:
Submit only public or redacted evidence. Never put credentials, proprietary strategy code, patient data, or protected health information in a GitHub issue.
We publish a trust board scoring a corpus of well-known open-source repositories alongside our own. Running a leaderboard on other people's code obliges us to be exact about how it works, so here is all of it.
What we redact, and on what basis. One rule: a path is published exactly when you can check it. For a public repository, every evidence path and line number is cited in full — a certificate whose evidence you cannot open is not evidence. For a private repository (ours), no source path is cited anywhere, in any field or format; an unverifiable path tells you nothing you can check while disclosing our file tree for free. Redaction removes a location, never a fact: the finding, its dimension, its status, its score, and its content hash all survive. Where a path is withheld you will see it said plainly. This is enforced structurally — the public artifacts are built from filtered data rather than rendered and then scrubbed — and a build that would emit a private path fails rather than publishes.
What we exclude from ranking. The v5 repository scanner does not evaluate B1 (dispatch trace completeness) or B5 (verified learning trace) for repository inputs, including ours: both are always not applicable in a repository certificate. They remain defined in the rubric for structured substrate evidence, but that evidence is not accepted by this scanner. The ranking excludes both dimensions fail-closed, including when it reads a legacy or separately produced structured report. We neither score you on evidence the public scanner cannot collect nor award ourselves points for evidence you cannot contest.
Where we were wrong. Calibrating this rubric against real repositories — and running the board itself like a stranger would — surfaced the errors below in our own tool, every one found by us and every one fixed. The list is its own count; we do not keep a tally in this sentence, because a number typed by hand beside a list that grows is exactly the kind of unchecked claim this tool exists to catch. We publish them because a scoring tool that has never been wrong is a scoring tool that has not been checked:
HEAD ancestry, so ambient branch state can no
longer add evidence or change coverage. The complete v4-to-v5 delta is published in the
rubric changelog.--help and --version as unknown flags, and read -h as a
directory path. Version 0.1.2 handles both aliases before positional-path parsing and
derives its printed version from the package manifest.0.0,
"Unverified". Every real legacy repository has a deploy script, so the fix that passed every
test was unreachable for essentially all of them. Recognised source must now be dominant,
not merely present. A fixture cleaner than reality proves nothing.test.js convention. A smoke test against
sindresorhus/slugify reported that a runner was configured but no concrete test files were
detected even though test.js was present at the repository root. That was a detection gap
in Cejel, not evidence about the repository. Rubric v6 recognizes AVA's test.js and
test-*.js conventions; a regression fixture preserves the correction.nyc. The detector looked only for standalone coverage files and framework configuration.
Version 0.1.10 also recognizes actual nyc, c8, and Istanbul commands or configuration in
package.json. An unused dependency is not treated as coverage evidence. This removes a false
finding without changing the measured coverage score.info finding severity could appear beside a critical dimension
band without naming the two different concepts. Version 0.1.10 prints the two lowest
contributing measurements, concrete next actions, finding severity, and dimension band
explicitly. It also explains when a requested scan target is gitignored instead of presenting
the target as a generic empty repository.Every one was a trust failure produced by us — false alarms about other people's code, silent omissions, inconsistent presentation, or a home-only scoring path — and we would rather you knew that than discovered it. If you believe the board scores your repository wrongly, open an issue — a rubric that cannot be corrected in public has no business being published in public.
No rubric change re-scores you silently. Every change to scoring behavior requires a
WITAN_RUBRIC_VERSION bump and a corpus-wide before/after delta published in
leaderboard/RUBRIC_CHANGELOG.md — score,
verdict, and rank for every repository, "no repository moved" stated explicitly when that is
the result. A build that changes scoring without both fails; see that file's v2 entry for
the home-field fix above as the first rubric change recorded this way.
cejel is free and licensed under AGPL-3.0-only, copyleft: any modified
version you distribute or run as a network service must also make its source available
under the same terms. A commercial license is available for teams that need to use or
modify cejel without those copyleft obligations.