日本語 | 中文 | Español | Français | हिन्दी | Italiano | Português (BR)
Syntropic repo network — append-only ledger, node manifests, and scoring for distributed repo coordination.
RepoMesh turns a collection of repos into a cooperative network. Each repo is a node with:
- A manifest (
node.json) declaring what it provides and consumes - Signed events broadcast to an append-only ledger
- A registry indexing all nodes and capabilities
- A profile defining what "done" means for trust
The network enforces three invariants:
- Deterministic outputs — same inputs, same artifacts
- Verifiable provenance — every release is signed and attested
- Composable contracts — interfaces are versioned and machine-readable
npx @mcptoolshop/repomesh init --repo your-org/your-repo --profile open-source
# JSON output for CI piping:
npx @mcptoolshop/repomesh init --repo your-org/your-repo --profile open-source --jsonThis generates everything you need:
node.json— your node manifestrepomesh.profile.json— your chosen profile.github/workflows/repomesh-broadcast.yml— release broadcast workflow- Ed25519 signing keypair (private key stays local)
Then add two secrets to your repo:
REPOMESH_SIGNING_KEY— your private key PEM (printed by init)REPOMESH_LEDGER_TOKEN— GitHub PAT withcontents:write+pull-requests:writeon this repo
Cut a release. Trust converges automatically.
All commands accept: --quiet, --verbose, --debug, --no-color. The init command also supports --json for machine-readable output.
Shell completions are available:
repomesh completion bash >> ~/.bashrc
repomesh completion zsh >> ~/.zshrc| Variable | Purpose |
|---|---|
REPOMESH_LEDGER_URL |
Override ledger endpoint |
REPOMESH_MANIFESTS_URL |
Override manifests endpoint |
REPOMESH_FETCH_TIMEOUT |
Fetch timeout in ms |
| Profile | Evidence | Assurance Checks | Use When |
|---|---|---|---|
baseline |
Optional | None required | Internal tools, experiments |
open-source |
SBOM + provenance | License audit + security scan | Default for OSS |
regulated |
SBOM + provenance | License + security + reproducibility | Compliance-critical |
node registry/scripts/verify-trust.mjs --repo your-org/your-repoShows integrity score, assurance score, profile-aware recommendations.
Per-repo customization without forking verifiers:
// repomesh.overrides.json
{
"license": { "allowlistAdd": ["WTFPL"] },
"security": { "ignoreVulns": [{ "id": "GHSA-xxx", "justification": "Not reachable" }] }
}repomesh/
profiles/ # Trust profiles (baseline, open-source, regulated)
schemas/ # Source of truth for all schemas
ledger/ # Append-only signed event log
events/events.jsonl # The ledger itself
nodes/ # Registered node manifests + profiles
scripts/ # Validation + verification tooling
attestor/ # Universal attestor (sbom, provenance, sig chain)
verifiers/ # Independent verifier nodes
license/ # License compliance scanner
security/ # Vulnerability scanner (OSV.dev)
anchor/xrpl/ # XRPL anchoring (Merkle roots + testnet posting)
manifests/ # Committed partition manifests (append-only)
scripts/ # compute-root, post-anchor, verify-anchor
policy/ # Network policy checks (semver, hash uniqueness)
registry/ # Network index (auto-generated from ledger)
nodes.json # All registered nodes
trust.json # Trust scores per release (integrity + assurance)
anchors.json # Anchor index (partitions + release anchoring)
badges/ # SVG trust badges per repo
snippets/ # Markdown verification snippets per repo
pages/ # Static site generator (GitHub Pages)
docs/ # Public verification docs
tools/ # Developer UX tools
repomesh.mjs # CLI entrypoint
templates/ # Workflow templates for joining
Add node.json to your repo root:
{
"id": "your-org/your-repo",
"kind": "compute",
"description": "What your repo does",
"provides": ["your.capability.v1"],
"consumes": [],
"interfaces": [
{ "name": "your-interface", "version": "v1", "schemaPath": "./schemas/your.v1.json" }
],
"invariants": {
"deterministicBuild": true,
"signedReleases": true,
"semver": true,
"changelog": true
},
"maintainers": [
{ "name": "your-name", "keyId": "ci-yourrepo-2026", "publicKey": "-----BEGIN PUBLIC KEY-----\n...\n-----END PUBLIC KEY-----" }
]
}openssl genpkey -algorithm ED25519 -out repomesh-private.pem
openssl pkey -in repomesh-private.pem -pubout -out repomesh-public.pemPut the public key PEM in your node.json maintainers entry.
Store the private key as a GitHub repo secret (REPOMESH_SIGNING_KEY).
Open a PR to this repo adding your node manifest:
ledger/nodes/<your-org>/<your-repo>/node.json
ledger/nodes/<your-org>/<your-repo>/repomesh.profile.json
Copy templates/repomesh-broadcast.yml to your repo's .github/workflows/.
Set the REPOMESH_LEDGER_TOKEN secret (a fine-grained PAT with contents:write + pull-requests:write on this repo).
Every release will now automatically broadcast a signed ReleasePublished event to the ledger.
- Append-only — existing lines are immutable
- Schema-valid — every event validates against
schemas/event.schema.json - Signature-valid — every event is signed by a registered node maintainer
- Unique — no duplicate
(repo, version, type)entries - Timestamp-sane — not more than 1 hour in the future or 1 year in the past
The ledger currently emits the live event types below. The rest are reserved / planned — the schema accepts them, but no node emits them yet. We list them so the roadmap is visible without implying coverage that does not exist (front-door honesty for a trust product).
Live (emitted today):
| Type | When |
|---|---|
ReleasePublished |
A new version is released |
AttestationPublished |
An attestor verifies a release |
ledger.anchor |
The anchor node seals a partition (Merkle root + XRPL memo) |
attestation.dispute |
A trusted node disputes an attestation (downgrades the verdict) |
KeyRotation |
A maintainer key is rotated to a successor (prospective — past signatures stay valid) |
KeyRevocation |
A maintainer key is revoked (compromise = retroactive invalidity, RFC 5280) |
Reserved / planned (not yet emitted):
| Type | Intended meaning |
|---|---|
BreakingChangeDetected |
A breaking change is introduced |
HealthCheckFailed |
A node fails its own health checks |
DependencyVulnFound |
A vulnerability is found in dependencies |
InterfaceUpdated |
An interface schema changes |
PolicyViolation |
A network policy is violated |
Maintainer keys have a lifecycle. A key can be rotated to a successor or revoked, and verification is time-aware: a signature is trusted only if the key was valid at the signature's trusted time — the XRPL anchor close-time, the same trusted clock the ledger already uses.
# Rotate to a successor key (the retired key's past signatures stay valid)
npx @mcptoolshop/repomesh key rotate --repo your-org/your-repo \
--retiring mike-2026-01 --new-key mike-2026-06 --public-key new.pem
# Revoke a compromised key (signatures at/after the invalidity date are rejected)
npx @mcptoolshop/repomesh key revoke --repo your-org/your-repo \
--key mike-2026-01 --reason compromise --invalid-after 2026-06-18T00:00:00Z- Routine rotation is prospective — the retired key's past signatures remain valid; it simply stops signing new releases.
- Compromise is retroactive (RFC 5280 §5.3.2) — any signature whose provable anchored time is at/after the invalidity date is rejected, and a signature that cannot be proven to predate it is rejected.
- A key with no lifecycle fields is grandfathered (always valid), so existing nodes verify unchanged.
- Revocations are signed
KeyRevocationevents; a single-key node whose only key is compromised is recovered by a governance (trustedPolicy) node signing the revocation. Trust-critical nodes should register ≥2 keys (TUF §6.1). - Even against a tampered
node.json, a revocation is re-imposed from the signed, XRPL-anchored events — a stripped manifest cannot revive a revoked key. See the threat model for the boundary (verify against the canonical ledger; use--anchoredfor revocation-sensitive checks).
| Kind | Role |
|---|---|
registry |
Indexes nodes and capabilities |
attestor |
Verifies claims (builds, compliance) |
policy |
Enforces rules (scoring, gating) |
oracle |
Provides external data |
compute |
Does work (transforms, builds) |
settlement |
Finalizes state |
governance |
Makes decisions |
identity |
Issues/verifies credentials |
Anyone can verify a release with one command — no clone required, the CLI fetches the public ledger for you:
npx @mcptoolshop/repomesh verify-release --repo mcp-tool-shop-org/shipcheck --version 1.0.4 --anchoredThis checks:
- The
ReleasePublishedevent exists and is signed (Ed25519) by a key registered to that repo's ownnode.json— a key registered to a different repo cannot validate it. - The repo's trust profile is satisfied: every profile-required attestation (SBOM, provenance, license, security) is present, signed by a trusted attestor, and its latest result is
pass, with at least one independent attestor. A release with only a self-signature and no independent attestations reportsUNVERIFIED, neverPASS. - With
--anchored: the partition's Merkle root is recomputed and matched to the manifest, and — when the network is reachable — the on-chain XRPL transaction is fetched and asserted (validated+tesSUCCESS, the signing account is in the trusted-anchor allowlist, and the on-chain memo binds to the local root/manifest-hash/count). Offline, it reportsXRPL NOT verifiedrather than a fake transaction; strict--anchoredthen fails (use--anchored-or-localto accept a locally-verified manifest without the on-chain proof).
For CI gates, choose an output format with --format <text|json|sarif|markdown> (--json is an alias
for --format json):
npx @mcptoolshop/repomesh verify-release --repo mcp-tool-shop-org/shipcheck --version 1.0.4 --anchored --format jsonThe exit code is derived from the tri-state verdict, so a CI step can gate on it directly:
| Exit | Verdict | Meaning |
|---|---|---|
0 |
PASS | Authentic and assured (or UNVERIFIED when relaxed by --fail-on=fail). |
1 |
FAIL | Hard failure — forged/wrong-repo signature, non-allowlisted attestor, or a required check failed. |
3 |
UNVERIFIED | Soft — not-yet-anchored, no independent witness, or a required check missing. |
2 |
— | Usage error or internal crash. |
--fail-on <fail\|unverified> sets strictness. Default unverified fails on both FAIL and
UNVERIFIED; --fail-on=fail lets UNVERIFIED pass (exit 0, with a warning) for warn-mode adoption.
Verify a whole batch in one ledger load with verify-all, and verify offline against a local clone
with --local:
# Every release in the trust index, warn-mode
npx @mcptoolshop/repomesh verify-all --from-registry --fail-on fail
# Offline against a local ledger checkout
npx @mcptoolshop/repomesh verify-release --repo org/repo --version 1.0.0 --local ./repomeshGate it in CI with the bundled composite action — see Using the GitHub Action:
- uses: mcp-tool-shop-org/repomesh/.github/actions/verify@v1
with:
repo: ${{ github.repository }}
version: ${{ github.event.release.tag_name }}
anchored: "true"See docs/verification.md for the full verification guide, threat model, and key concepts.
Repos can embed trust badges from the registry:
[](https://mcp-tool-shop-org.github.io/repomesh/repos/mcp-tool-shop-org/shipcheck/)
[](https://mcp-tool-shop-org.github.io/repomesh/repos/mcp-tool-shop-org/shipcheck/)
[](https://mcp-tool-shop-org.github.io/repomesh/repos/mcp-tool-shop-org/shipcheck/)npx @mcptoolshop/repomesh verify-release --repo mcp-tool-shop-org/shipcheck --version 1.0.4 --anchoredAttesting and running verifiers are operator tasks that act on a clone of this ledger, so they run from a checkout. Verifying a release does not — use the
npxcommand above.
node attestor/scripts/attest-release.mjs --scan-new # process all unattested releases
node attestor/scripts/attest-release.mjs --scan-new --dry-run # preview without writingChecks: sbom.present, provenance.present, signature.chain
node verifiers/license/scripts/verify-license.mjs --scan-new
node verifiers/security/scripts/verify-security.mjs --scan-newSecurity verifier thresholds (max CVEs, allowed severities) are config-driven via verifiers/security/config.json.
node policy/scripts/check-policy.mjsChecks: semver monotonicity, artifact hash uniqueness, required capabilities.
RepoMesh touches ledger events (signed JSON), node manifests (public keys + capabilities), registry indexes (auto-generated trust scores), and XRPL testnet (anchor transactions). It does not touch member repo source code, private keys, user credentials, or browsing data. Private signing keys never leave the CI runner. Network access is limited to the GitHub API (PR creation), XRPL testnet (anchoring), and OSV.dev (vulnerability lookups). No telemetry is collected or sent — zero analytics, zero crash reports, zero phone-home. See SECURITY.md for the full scope, required permissions, and vulnerability reporting process, and the threat model for the key-lifecycle trust boundary (why node.json authenticity depends on its source, and why revocation-sensitive verification should use --anchored).
Hardening:
- Child-process calls that interpolate variable data use
execFileSyncwith array arguments; the remainingexecSynccalls use static, constant command strings — no shell-injection vectors. - Ledger and registry JSON is parsed inside
try/catchwith structured, line-numbered errors; a malformed line is skipped and surfaced, never crashes the tool with a raw stack. - Path traversal is prevented on all file operations (resolve + boundary check).
- ReDoS-safe parsing throughout (no unbounded regex).
- PEM private keys are excluded via
.gitignore, never printed to stdout or CI logs, and written with owner-only (0600) permissions.
The full node --test suite covers Ed25519 signatures, schema validation, Merkle tree
integrity (v1 + RFC-6962 v2), append-only invariants, path traversal prevention, anchor
verification, the trusted-attestor allowlist, and input validation across the CLI, ledger,
anchor, verifier, and tools layers.
# Run every suite and read the exact pass/fail counts from the summary footer:
node --test $(git ls-files '*.test.mjs')The test count grows as suites are added — run the command above for the current total rather than relying on a number that drifts out of date.
MIT
Built by MCP Tool Shop
