commitwork

Domain model

commitwork

This page sets out commitwork's domain model: its subdomains, bounded contexts, context map and ubiquitous language. commitwork is a repository security scanner, local CI runner and scheduled monitor, with remediation and compliance-evidence tooling.

Domain

The domain is the security state of a set of repositories over time: which checks ran against which commit, what each check reported, how each finding was judged, and what was fixed. Every bounded context below reads or writes evidence about that state.

SubdomainTypeBounded context
Running checks and normalising their outputCoreCheck execution
Finding history, from first sighting to verified remediationCoreFleet monitoring
Judgement of findingsCoreAdjudication
Remediation work and its evidenceSupportingRemediation
Regulatory evidence for the EU CRA and SOC 2SupportingCompliance evidence
Public hostnames and their routingSupportingDeployment declaration
Access for operators and coding agentsSupportingPanel and MCP server
Scanning engines: Semgrep, CodeQL, gitleaks, TruffleHog, OSV, Trivy and othersGenericThird-party tools behind an anticorruption layer
Credential storageGenericThe OS keychain, referenced by pointer

Bounded contexts

  1. Structure:
  2. 1. Responsibility
  3. 2. Aggregates
  4. 3. Events
  5. 4. Terms

Check execution bin/commitwork.mjs manifests/

Responsibility
Runs checks against one repository, or every git repository under a root, as local commands, and writes one normalised report per check. A manifest maps each CI workflow to the local commands that perform the same checks.
Aggregates
Manifest: its checks, groups, requirements and the egress class each check declares.
Events
Check ran. Check skipped, with a skip record naming the requirement that was not met.
Terms
manifest, check, group, requirement, egress class, skip record, report

Fleet monitoring monitor/

Responsibility
Runs check groups on a schedule over declared areas, rolls each sweep into a slice, and tracks each finding from first sighting to verified remediation.
Aggregates
Area, with its projects and retention. Slice, with its findings and enrichment. Finding, identified by its place.
Events
Sweep intended (batch-manifest.json anchors each repository's commit before the run). Sweep completed (batch-verdict.json). Slice recorded in a hash-chained history. Finding born, persisting, resolved-fixed or unknown-not-scanned.
Terms
registry, root, project, area, sweep, rollup, slice, lane, lane kind, carried

Adjudication bin/annotate.mjs monitor/annotations.json

Responsibility
Records human judgement on findings and applies it to each slice as of that slice's timestamp. An annotated finding keeps its place in the slice, with the annotation attached.
Aggregates
Annotation. A scanner annotation matches every field of a finding's identity plus its repository; a dependency annotation matches the fields it names.
Events
Annotation applied, noMatch, expired, invalid or carried, published per slice. Ruling recorded.
Terms
annotation, ruling, fix type, incorrect-scan-result

Remediation monitor/issue-store.mjs monitor/ledger.mjs

Responsibility
Tracks findings that need work as issues with SLA clocks, records each verified fix with its evidence tier, and drafts fixes as triage prompts, agent hand-offs and diffs for git apply. Applying a fix is a human act.
Aggregates
Issue, keyed by a source key, with an append-only, hash-chained event trail. Remediation ledger entry.
Events
Issue minted, claimed, closed, and reopened under the same id when its finding returns. fix-authored, fix-verified, fix-disputed.
Terms
issue, source key, evidence tier, SLA clock, hardener

Compliance evidence cra/

Responsibility
Maps the monitor's evidence onto EU Cyber Resilience Act Article 14 obligations, CycloneDX SBOM and VEX, POA&M, SOC 2 and OSCAL. Every output is a draft, and submission to an authority is a human act.
Aggregates
Product, the unit the CRA regulates, spanning one or more repositories. Case, hash-chained.
Events
Case opened by the exploited-vulnerability watch (KEV × EPSS, every 30 minutes). early-warning, notification and final-report fall due on the 24-hour, 72-hour and 14-day clocks.
Terms
product, case, SBOM, VEX, POA&M, attestation

Deployment declaration bin/deploy.mjs

Responsibility
Renders a tunnel ingress fragment from the hostnames each area declares, and compares the declaration with reality on five axes: declared, routed, DNS, origin and TLS. It holds no credentials and applies no change.
Aggregates
Hostname declaration, with its public, requiresAuth and authAt fields.
Events
Drift found on an axis (exit 1).
Terms
declaration, ingress fragment, drift

Panel and MCP server admin/ mcp/

Responsibility
Publishes the evidence to operators through a web panel bound to loopback, and to coding agents through an MCP server. The panel authenticates with passwords, TOTP, passkeys and single sign-on for existing accounts.
Aggregates
Account and session in the panel. The MCP server holds none and forwards commands to the contexts that own them.
Events
Commands rather than events: run_checks into check execution, restricted to bundled manifests; issue_claim, issue_close and issue_judge into remediation.
Terms
section, workspace, count badge, tool, resource

Context map

UpstreamDownstreamRelationshipWhat crosses
Third-party scannersCheck executionAnticorruption layerEach tool's output, translated into the finding schema by its check wrapper and the monitor's extractors, with a declared lane kind
Check executionFleet monitoringCustomer and supplierNormalised reports per repository and commit, produced by commitwork run <group> inside each sweep
Fleet monitoringAdjudicationPartnershipFindings out; annotations back, applied as of each slice's timestamp
Fleet monitoringRemediationPublished languageFinding keys, as source keys; the issue tracker references the monitor's records and never copies them
Fleet monitoringCompliance evidenceCustomer and supplierFinding lifecycle and KEV/EPSS enrichment, as SBOM, VEX and case clocks
Fleet monitoringDeployment declarationCustomer and supplierAreas' declared hostnames
Every contextPanel and MCP serverOpen host serviceEvidence and commands, through the panel's routes and the MCP tool names
lib/Every contextShared kernelClock, HTML escaping, brand tokens and other primitives

Ubiquitous language

finding
One claim a check makes about a repository. Its identity is its place: repository, category and the category's identity fields, such as rule, file and package. A line number is never part of it.
lane
One check's findings as the monitor receives them.
lane kind
What a lane's findings claim: vulnerability, posture, integrity, policy or hygiene. A lane with no declared kind is reported as unclassified.
area
The declared unit of report output, retention, freshness and identity. Each registry entry belongs to one area by declaration.
sweep
One scheduled run of a check group over an area's repositories.
slice
A rollup recorded as a cut through the fleet at one time, with KEV and EPSS enrichment frozen as of that time.
lifecycle state
born, persisting, resolved-* or unknown-not-scanned. A finding resolves when its repository was scanned and its tool provably ran.
carried
A category that did not run in a sweep. Its previous counts and rows move forward, marked as carried.
undetermined
A severity field outside crit, high, med and low, holding rows whose claim cannot be read as a verdict, with the scanner's original claim preserved.
annotation
A human acceptance, applied to matching findings as of a slice's timestamp.
ruling, fix type
The two parts of a disposition: whether a finding is real, and how it was addressed.
evidence tier
The strength of proof that a fix happened: strong (a lockfile diff between two commits), medium (the fix version is known) or weak (not counted).
issue
A unit of remediation work, keyed by the source key of the finding or group it tracks.
product
The unit the EU CRA regulates, spanning one or more repositories.
case
A record of a reportable exploited vulnerability in a product, with its reporting clocks.
draft
Any output addressed to an outside party. Sending it is a human act.

Invariants

  1. Rule #1Fail closed. A parse failure or a permission error is an error, never an empty result; a missing file (ENOENT) is the one legitimate absence.
  2. Rule #2Key a finding's identity on its place, never its line number.
  3. Rule #3Same inputs give byte-identical outputs. Writes are atomic, and re-runs are idempotent.
  4. Rule #4Keep declaration apart from authority. Tools that describe deployments, DNS or tunnels hold no credentials and apply no changes.
  5. Rule #5Run no repository-local manifest (commitwork.json) without --trust-repo-manifest.
  6. Rule #6Leave applying a fix and submitting to an authority to a person.

Releases

Release notifications are published as an Atom feed at /releases.atom. It needs no token and no account.

Every commit carries a version: package.json's patch moves with each one. v0.5.0 is the first release, tagged on the public repository on 2026-10-08.

The versions and milestones so far and the target releases to 1.0.0 each have a page.

Versions are announced here rather than left to aggregators that resolve by name: asked about trufflehog, one returned an abandoned package four major versions behind the tool in use.