npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

witness-dao

v0.1.0

Published

Governance-evidence and compliance-reporting layer for DAOs and their legal wrappers. Seals governance-significant actions to tamper-evident, externally anchored records bound to the rule that governed them.

Downloads

40

Readme

Witness-DAO

Governance evidence for DAOs that survives contact with a regulator, an auditor, or a court.

Witness-DAO seals every governance-significant action — proposal, vote, multisig approval, treasury movement — to a tamper-evident, externally anchored record bound to the rule that authorised it, then turns that trail into artefacts humans actually rely on.

Built on VDA Witness (the evidence layer of Verified Digital Agents).


Why this exists

The blockchain already proves a vote happened. It does not produce:

  • a unified record spanning off-chain deliberation, Snapshot tallies, multisig approvals and treasury movements, each mapped to the ratified rule version;

  • proof of process followed — or of non-participation — for a named individual;

  • evidence a legal wrapper can put in front of an auditor or a supervisor when asked to demonstrate that its governance decisions followed its own ratified rules.

    That third bullet is deliberately narrow. This is not a MiCA report, not an AML report, and not a substitute for either — it produces evidence a human then interprets. MiCA obligations attach to issuers and to authorised CASPs and consist of authorisation, prudential safeguards, governance arrangements, record-keeping, complaints handling, conflicts of interest, custody segregation and market-abuse controls. Witness-DAO performs none of them. What it can honestly contribute is a tamper-evident evidence layer for the governance-arrangements and record-keeping limbs, if your counsel concludes that is useful to you. No AML capability exists at all; see governance-rules/treasury.transfer.md.

That third gap is the one with a buyer. After the CFTC's Ooki DAO action (a DAO treated as an unincorporated association, where voting your tokens can create personal liability) and the 2025 N.D. Cal. ruling treating Lido DAO as a general partnership (exposing token-holders and multisig signers personally), the people with real exposure are the named humans: core contributors, multisig signers, and the Wyoming / Marshall Islands LLC wrapping the DAO. For them, provable process and provable absence are defensible assets.

Witness-DAO is built for the wrapper, the signers, and their counsel — not for the anonymous token-holder.


The three disciplines this codebase enforces

These are not style preferences. They are the reason the output is worth anything.

1. Binding confidence is never laundered

A sealed record is only as truthful as the claim fed into it. Sealing an unverified assertion produces a beautifully tamper-evident lie. So every event states, in machine-readable form, how strongly it is tied to observable reality:

| Confidence | Meaning | |---|---| | onchain_confirmed | In a confirmed block — tx hash + block number + chain id | | signed_offchain | Backed by a verified off-chain signature (Snapshot EIP-712), not settled on-chain | | api_asserted | Read from a centralised API we cannot cryptographically check | | unbound | Operator assertion, no corroboration |

assertBindingIntegrity() structurally enforces that a claimed level actually has the identifiers it requires. No layer may upgrade a confidence level.

Concretely: Snapshot's tally is computed by their centralised server, so it is recorded as api_asserted — upgraded to signed_offchain only if we independently recompute it from the complete enumerated vote set. Divergence from the API's own numbers is recorded, never hidden.

2. "Verified" is not "asserted"

Anchoring reports verified only when something was cryptographically checked against pinned, independent material. Where we can confirm a proof asserts inclusion in Bitcoin block N but cannot confirm block N itself without a header source, the verdict is asserted_unverified — and the offline verifier will not reach ANCHORED_VALID on it. We do not upgrade ourselves on trust.

3. Evidence, not a certificate

Attestation is a human act. Reports carry a non-weakenable disclaimer. Records on the free, unanchored Sealed tier are blocked from reports by default (assertCompliancePosture) because that tier is terminal — it never becomes anchored, and presenting it as compliance-grade would be a material misrepresentation.


Architecture

ingest ──▶ bind ──▶ seal ──▶ anchor ──▶ verify ──▶ report
   │         │        │         │          │          │
Snapshot  binding  VDA       Bitcoin/   offline   governance
Safe      confid-  Witness   OTS +      (zero     evidence +
Governor  ence     (+rule)   Rekor +    VDA        liability
                             RFC-3161   calls)     defence

Two layers people constantly conflate — kept deliberately separate:

  • Binding (read) — the DAO's own chains, where governance actually happens. Not a choice; dictated by where each DAO lives. Ethereum L1 + Optimism/Arbitrum/Base + Snapshot + Safe.

  • Anchoring (write) — where we commit a Merkle root to prove tamper-evidence. This is a choice: Bitcoin for permanence and neutrality, Rekor + RFC-3161 timestamps from commercial TSAs for fast coverage of the window before Bitcoin confirms. Run in parallel, under a quorum policy — never instead of one another.

    On eIDAS, precisely. The default TSAs (DigiCert, Sectigo) are publicly-trusted commercial timestamping services under CA/Browser Forum requirements. They are not qualified trust service providers on any EU Member State Trusted List for timestamping. The difference is not cosmetic: eIDAS Art. 41(2) grants a presumption of accuracy of the date and time, and of integrity of the data, only to a qualified electronic time stamp. A non-qualified timestamp gets Art. 41(1) — it may not be denied legal effect or admissibility solely because it is electronic or non-qualified. Admissible: yes. Presumptively accurate: no; the party relying on it carries the evidential burden. Certificate-chain validation is not_checked by default (see LIMITATIONS.md §1). If you need the Art. 41(2) presumption, supply a QTSA endpoint and a chainValidator.

Cost follows cadence, not volume

Anchoring commits a Merkle root, not each record. One transaction covers an unbounded number of records, so on-chain cost tracks anchoring cadence (~730 tx/month hourly), not seal volume. Sealing 5,000 or 50,000,000 decisions costs the same on-chain. A private/permissioned chain is deliberately not supported as an anchor: something the vendor controls cannot back "provable even against the vendor."


Install

pnpm install --ignore-scripts
pnpm build
node dist/cli/index.js --version

Requires Node >= 22.6.0. Zero runtime dependencies — all crypto is node:crypto, all HTTP is fetch, RFC 8785 canonicalisation / Merkle trees / OTS binary format / DER encoding are implemented in-tree and unit-tested.

dist/ is the production entrypoint

Run node dist/cli/index.js (and node dist/mcp/server.js), or the published witness-dao bin, which points at the same file. The pnpm cli / pnpm mcp scripts run from source through --experimental-strip-types, an unstable Node flag whose semantics change between minor releases; they exist for the development loop and are not supported for anything you intend to rely on. engines.node is >=22.6.0 because that is the first release where those scripts work at all — an earlier declared floor could not run its own test suite.

A Dockerfile (multi-stage, pinned Node, non-root, dist/ only) and a GitHub Actions workflow ship in the repository. Operational procedures — scheduling, alerting, backup scope, incident response — are in RUNBOOK.md.

Configure

Secrets come from the environment only. A credential found in a config file is a hard error (CONFIG_SECRET_IN_FILE) — a key in a file is a key in git.

export WITNESS_API_KEY="wtn.<id>.<secret>"     # required to seal
export WITNESS_DAO_RULES_DIR="./governance-rules"
export WITNESS_DAO_RPC="1=https://…,10=https://…"   # optional, for Governor
export WITNESS_DAO_STATE_DIR=/var/lib/witness-dao   # durable state
export WITNESS_DAO_LOG_LEVEL=info                   # structured JSON on stderr

State is namespaced per account and per DAO under the state directory, so two DAOs never share a journal file.

Key lifecycle

Witness API keys are short-lived by design. Bind an Ed25519 controller key once, while the current key still works, and renew on a cadence — otherwise the key expires, every seal fails, and the failures sit in the journal until somebody notices.

openssl genpkey -algorithm ed25519 -out controller.pem && chmod 600 controller.pem
export WITNESS_DAO_CONTROLLER_KEY_FILE=$PWD/controller.pem

witness-dao keys bind-controller     # once
witness-dao keys renew               # on a cadence; also run before expiry

The renewal protocol is POST /api/witness/renew/challenge → sign vda.witness.renew/1|<accountId>|<nonce>POST /api/witness/renew. Only the public JWK and a signature ever leave the machine. A key file readable by anyone but its owner is refused, not warned about. For production, implement the ControllerSigner interface against your KMS or HSM rather than using a file — it is two methods, and the library never sees private key material.

Use — CLI

# Check the wiring without sealing anything or spending quota
witness-dao selftest

# What happened, and how well is it bound to reality?
witness-dao ingest --dao ens.eth --since 2026-01-01T00:00:00Z

# Full run: ingest → seal → anchor
witness-dao seal --dao ens.eth --since 2026-01-01T00:00:00Z
witness-dao seal --dao ens.eth --dry-run       # build requests, send nothing

# Replay seals that previously failed. NOT automatic — schedule it.
witness-dao seal --dao ens.eth --retry

# Independent verification — no network, no trust in the vendor
witness-dao verify --bundle ./proof-bundle.json

# The artefacts that matter
witness-dao report governance --dao ens.eth --format md --out evidence.md
witness-dao report liability --dao ens.eth --subject 0xabc… \
  --purpose "Defence of signer in matter 2026-114" --format md --out defence.md

# Promote pending Bitcoin anchors once they confirm (run on a schedule)
witness-dao anchor status
witness-dao anchor upgrade

# Data protection: erase a record body, and enforce the retention policy
witness-dao erase --record rec_01H... --reason "Art.17 request REQ-2026-0142" --confirm
witness-dao erase --list
witness-dao purge --max-age-days 730 --dry-run
witness-dao purge --max-age-days 730 --confirm

# Key lifecycle: bind once, renew on a cadence
witness-dao keys bind-controller
witness-dao keys renew

Four scheduled jobs, not one

Sealing is fail-open: an evidence-layer outage must not take down a governance pipeline, so a failed seal is stored complete in the journal instead of throwing. That is only safe because something drains the journal — and that something is seal --retry, which you must schedule. If you run only the window job, then once --since advances past a failed window those governance actions are absent from the trail permanently.

| Job | Cadence | Skip it and… | |---|---|---| | seal --dao <id> --since … | hourly/nightly | nothing is recorded | | seal --dao <id> --retry | every 15–30 min | failed seals are never replayed | | anchor upgrade | hourly | records stay SIGNED_PENDING forever | | keys renew | daily | the short-lived key expires and sealing stops |

systemd timers and Kubernetes CronJobs for all four are in RUNBOOK.md, along with the metrics worth alerting on.

Observability

WITNESS_DAO_LOG_LEVEL=info emits structured JSON logs on stderr (never stdout, which carries the result). WITNESS_DAO_METRICS=1 emits one JSON metric object per line, with a pluggable sink for Prometheus or OpenTelemetry — no dependency added. Instrumented: seal success/failure, journal backlog depth and age-of-oldest, anchor pending age, quorum-met rate, per-provider error rate and latency, remaining Witness quota, account tier, and key time-to-expiry. Every tolerated problem carries a machine-classifiable code alongside its prose in --json output.

Exit codes are meaningful (designed for CI):

| Code | Meaning | |---|---| | 0 | Success | | 1 | Failure, or a refusal to emit misleading evidence | | 2 | Usage / configuration error | | 3 | Verification returned BROKEN — possible tampering | | 4 | Incomplete run, or INSUFFICIENT_PROOF — a gap in the trail |

3 and 4 are split on purpose, mirroring the library's tampering-vs-missing-data distinction.

Use — library

import {
  WitnessClient, WitnessDaoPipeline, SnapshotProvider, SafeProvider,
  GitRulesResolver, DirectoryRuleResolver,
  MultiAnchorer, createOtsTarget, createRfc3161Target,
} from 'witness-dao';

const pipeline = new WitnessDaoPipeline({
  client: new WitnessClient({ apiKey: process.env.WITNESS_API_KEY }),
  ruleResolver: new DirectoryRuleResolver(
    new GitRulesResolver({ rulesDir: './governance-rules' }),
  ),
  providers: [
    new SnapshotProvider({ recomputeTally: true }),
    new SafeProvider({ chainId: 1 }),
  ],
  anchorer: new MultiAnchorer({ targets: [createOtsTarget(), createRfc3161Target()] }),
});

const run = await pipeline.run({ daoId: 'ens.eth', since: '2026-01-01T00:00:00Z' });
if (!run.complete) console.warn(run.problems);   // never ignore this

Use — MCP (for the DAO's own agents)

node dist/mcp/server.js     # JSON-RPC 2.0 over stdio

Read-only tools, always available: ingest_governance_events, verify_record, governance_evidence_report, anchor_status.

Mutating and bulk-export tools are disabled by default: seal_governance_events (writes durable records, spends the Witness allowance and the anchoring budget) and liability_defence_report (returns a named individual's entire participation history into the agent's context, and therefore into the transcript). Enable them deliberately, per deployment:

WITNESS_DAO_MCP_ALLOW_WRITES=1 node dist/mcp/server.js

The reason is specific rather than generic caution. MCP over stdio is unauthenticated by design, and this product's own premise is that a compliance copilot reads governance proposals — attacker-authored text that reaches the agent's context through ingest_governance_events. That is a live prompt-injection path into a money-spending tool. With writes enabled, seal_governance_events still defaults to dryRun: true and requires an explicit confirm: "<daoId>" echo, and third-party text in tool output is delimited as untrusted data.

Every result returns binding confidence, the closed verification verdict, and caveats — never a bare ok.


Governance rules ("git holds the rules")

Rules are markdown in a git directory. ruleVersion resolves to the git commit SHA that last touched the file, which is what makes charter-vs-code disputes resolvable: the sealed record proves which version of the rule text was in force.

Resolution is most-specific-first: snapshot.vote.castvote.castsnapshotdefault.

See governance-rules/ for a working example.

The rules directory is a trust boundary. Its contents are read, parsed and sealed verbatim into every matching record, and git metadata inside it is executed against. A .git/config placed there was an RCE vector. Treat that directory exactly as you treat source code: it must be write-restricted to the people entitled to change your governance, reviewed on change, and never pointed at a path a third party can write to. A rule file also asserts obligations inside your evidence — see governance-rules/treasury.transfer.md for what happens when a shipped example mandates a control the tool does not perform.

Network egress is default-deny. Requests to private, loopback and link-local address ranges are refused unless you opt in with allowPrivateNetwork (library) or WITNESS_DAO_ALLOW_PRIVATE_NETWORK=1 (environment). Enable it only for a self-hosted hub, RPC or Witness instance you control, and understand that doing so re-opens SSRF reachability from attacker-influenced URLs.


The evidence-strength calculus

Reports grade every line on a weakest-link basis, combining "is the record untamperable?" with "is it demonstrably about a real event?":

| verification ↓ / binding → | unbound | api_asserted | signed_offchain | onchain_confirmed | |---|---|---|---|---| | ANCHORED_VALID | UNSUPPORTED | WEAK | STRONG | PROVEN | | SIGNED_PENDING | UNSUPPORTED | WEAK | WEAK | STRONG | | INSUFFICIENT_PROOF | UNSUPPORTED | UNSUPPORTED | UNSUPPORTED | WEAK | | BROKEN | UNSUPPORTED | UNSUPPORTED | UNSUPPORTED | UNSUPPORTED |

Exactly one cell is PROVEN, and it requires both an anchored-valid record and an on-chain-confirmed binding. ANCHORED_VALID × api_asserted = WEAK is perfectly anchored hearsay: we prove what we were told and when, not that it happened.

Reaching the left-hand column at all requires an anchor verified against material you pinned in advance — a Bitcoin block-header source, Rekor's log key, or a trusted TSA root. None of that ships with the library, deliberately: a built-in "trusted" explorer or root would reintroduce exactly the vendor trust this layer exists to remove. Until you supply one, every record caps at SIGNED_PENDING and the report says which material is missing. RUNBOOK.md §7 has the three hooks.

Reports are reproducible offline

Every substantive claim in a report — who acted, what they did, when, and how strongly it is bound to reality — is read from each record's signed decision.inputs, not from a live re-fetch. Building a report therefore contacts no Snapshot, no Safe and no RPC: it needs your sealed records, the DID document, and the anchor attestations in your state directory. The same command over the same period produces the same reportDigest, which is the property that lets opposing counsel regenerate your document and get yours.

Proving a negative, honestly

The liability pack's core value is proof of non-participation — and you cannot prove a negative from an incomplete record set. So basis is explicit:

| Basis | Ceiling | Meaning | |---|---|---| | complete_tally_sealed | PROVEN | A sealed tally establishes the complete actor set; subject is absent from it | | enumerated_votes_sealed | STRONG | Every individual vote is sealed and the subject appears in none — but no sealed statement asserts the enumeration is complete | | inferred_absence | WEAK | We simply have no record of them acting. Always carries a caveat that absence of evidence is not evidence of absence. Never PROVEN. |

Reaching complete_tally_sealed — and why it does not require sealing the voter roll. The top tier needs a sealed statement of the complete participant set. Naively that means committing every voter's address to a permanent, externally anchored record, which is a data-maximisation incentive baked straight into the evidence calculus and points the opposite way from data-minimisation. So the bundled Snapshot provider does not seal the roll. When it has enumerated the vote set completely it seals a Merkle root over the sorted, de-duplicated participant set instead (detail.actorSetRoot, RFC 6962 leaves over sha256(lowercase-address)). The roll itself never enters a record and never reaches an anchor.

At report time you supply the roll from your own erasable store with --participant-set <file>; the report recomputes the root and relies on the tally only on an exact match, reporting the disagreement otherwise. Be clear about the limits: this is an ordinary ordered Merkle tree, so it supports inclusion proofs, not non-inclusion proofs. It does not let a third party verify "X is absent" from a short proof alone — they need the same roll. And it binds the set the collector held; whether the collector saw everybody remains an operational property, evidenced separately. Without a roll, the pack falls back to a weaker basis and says so in its caveats.


Testing

pnpm typecheck && pnpm test

Over a thousand tests, zero dependencies, no network access. Signature tests use real Ed25519 keypairs and real hash chains rather than mocks, so they catch real errors. The suite is deliberately adversarial about over-claiming — e.g. it asserts that an anchor supplied without an independent verifier stays SIGNED_PENDING and can never reach ANCHORED_VALID, and it reproduces each audit proof-of-concept (a pre-created credential path, a lost concurrent journal update, an oversized JSON-RPC frame) as a regression test.


Known limitations — read before relying on this

Honesty about limits is the point of the product, so they are documented rather than buried. See LIMITATIONS.md for the full list. The material ones:

  • Failed seals are replayed only when you run seal --retry. It is a scheduled job, not a background daemon. If it is not scheduled, a transient outage becomes a permanent hole in the trail.
  • Customer-held signing keys do not exist. All signing happens server-side at VDA Witness; there is no local-signing tier in this codebase. If you were told otherwise, you were told wrong — see LIMITATIONS.md §1.
  • PROVEN needs trust material you must supply. Out of the box no anchor can be independently verified (no pinned Bitcoin header source, Rekor log key or TSA root ships with the library), so records cap at SIGNED_PENDING. See RUNBOOK.md §7.
  • State is file-backed. Writes are atomic and fsynced and concurrent runs are refused by an advisory lock, but there is no replication and no multi-host coordination. Supply a DB-backed AnchorRunStore/SealJournal if you need either.
  • anchor-runs.json is the only copy of anchor proof material and must be backed up. Records and the DID document are re-fetchable from upstream; that file is not.
  • Rekor is off unless configured (it needs a signing key and a pinned log key), so the default quorum leans on RFC-3161 until Bitcoin confirms.
  • RFC-3161 CMS verification is not yet tested against a live TSA. It is conservative by design (an unusable certificate yields not_checked, never a false pass), but wants one integration test before production reliance.
  • Bitcoin attestations report asserted_unverified unless you supply a block-header lookup. This is correct, not a bug.
  • Snapshot enumeration caps out (~5000 votes); very large proposals cannot be fully enumerated, so the tally is never upgraded and voteSetTruncated is set.
  • Safe addresses must be EIP-55 checksummed (keccak-256 is unavailable in node:crypto and we ship no dependencies); a lowercase address yields an actionable SAFE_ADDRESS_NOT_CHECKSUMMED.
  • This is not legal advice. Every compliance claim needs counsel review before commercial use.
  • Data protection is a shared responsibility and half of it is yours. This product builds permanent, externally anchored behavioural records about identified natural persons. It now ships crypto-shredding, a retention policy, a minimisation gate, an enforced residency allowlist, supersession and dossier access logging — but it cannot supply your lawful basis, your DPIA, your processor contract, your limitation-period analysis or your privacy notice. Read DATA-PROTECTION.md before your first seal, not after.
  • The VDA SaaS has no delete endpoint. witness-dao erase destroys the local plaintext and suppresses the record everywhere this tool handles it, permanently and durably. It cannot delete the copy VDA holds. That gap is stated at the point of use and in every affected report.

Data protection

Read DATA-PROTECTION.md. In brief:

  • Only digests leave the building. OpenTimestamps, the RFC-3161 TSAs and Rekor receive a Merkle root or a hash of one — never a body, never an address, never a vote. Plaintext lives in exactly two erasable places: the VDA SaaS and your local journal. That is what makes crypto-shredding the right erasure strategy here rather than an impossibility.
  • Wallet addresses processed by this product are personal data. The liability pack is built for a named individual, so the customer holds the address-to-identity linkage by design — that linkage is the product. The pseudonymity argument does not survive the value proposition.
  • Free text is sealed as a digest by default (WITNESS_DAO_CONTENT_FREETEXT=hash-only). Set full deliberately, knowing that arbitrary third-party prose then becomes irreversible.
  • Erasure and retention are commands, not aspirations: witness-dao erase --record … --confirm crypto-shreds a record body while retaining bodyHash/prevHash/signature, so the record verifies as INSUFFICIENT_PROOF (missing data) and never BROKEN (tampering); witness-dao purge enforces WITNESS_DAO_RETENTION_DAYS over the local journal.
  • EU-only mode is enforced, not advisory. WITNESS_DAO_EU_ONLY=1 plus WITNESS_DAO_RESIDENCY_ALLOW_HOSTS refuses any endpoint you have not assessed, at startup. The allowlist ships empty on purpose: this library does not know where any third party processes data and will not guess for you.
  • A liability pack requires --purpose, records it in the artefact, and logs every generation to <state-dir>/…/dossier-access.log.

Licence

Apache-2.0. See LICENSE.