RiskForge produces structured, hash-chained evidence for the EU AI Act Article 9 risk management system and the description of it that Annex IV point 5 asks for. Apache 2.0, provided AS IS.
RiskForge turns Article 9 risk management into a developer workflow and writes a Risk Management File whose digest, signatures and audit chain anyone can check. It is an engineering tool that produces evidence; it is not a notified body, and its output is not a legal certification.
The Problem
Under the EU AI Act (Regulation (EU) 2024/1689), providers of high-risk AI systems (Article 6, Annexes I and III) must establish, implement, document and maintain a continuous Risk Management System (Article 9) throughout the entire AI lifecycle.
- Application Dates: The high-risk requirements and obligations in Chapter III, Sections 1 to 3 (including Article 9) apply from 2 December 2027 for systems under Article 6(2) and Annex III, and from 2 August 2028 for those under Article 6(1) and Annex I (Article 113, third paragraph, point (c), as amended by Regulation (EU) 2026/1744, in force since 27 July 2026).
- Penalties: breaches of the provider obligations can be fined up to €15,000,000 or, for an undertaking, 3% of its total worldwide annual turnover for the preceding financial year, whichever is higher (Article 99(4)); for SMEs, including start-ups, and for small mid-cap enterprises, whichever is lower (Article 99(6) and (6a)).
- The bottleneck: Article 9(2) makes risk management a continuous iterative process, run throughout the lifecycle with regular systematic review and updating, and advisory engagements are not built for that pace.
RiskForge is built around one question, asked in your terminal or CI/CD pipeline:
"How do we assess and mitigate Article 9 risks continuously, and keep evidence of it that an auditor can check, without blocking product velocity?"
Run through a guided, 37-question assessment across 8 risk dimensions. RiskForge produces a tamper-evident Risk Management File (JSON, PDF, or Markdown) backed by a SHA-256 hash chain, optional Ed25519 signatures, and cross-references to ISO/IEC 42001 and the NIST AI RMF. It runs offline, with zero telemetry.
Built by AI Exponent LLC. Apache 2.0. Runs entirely offline after pip install.
Quick Start
pip install riskforge
# 1. Register your AI system (prints the system id that every later command takes)
riskforge init \
--name "Loan Scoring Model" \
--sys-version "2.1" \
--purpose "Automated credit scoring for retail loan applications." \
--provider "Acme Financial Services" \
--category essential_services
# 2. Record your Article 6(2) Annex III self-classification (required before export)
riskforge system classify <system-id> --confirm
# 3. Run the guided 8-dimension risk assessment: 37 questions
riskforge assess <system-id> \
--assessor-name "Alice Chen" \
--assessor-role "AI Governance Lead"
# For CI or reproducible fixtures, run it from a YAML answers file. Running it again
# updates the items it created and never adds duplicates:
# riskforge assess <system-id> -a "Alice Chen" -r "AI Governance Lead" --answers answers.yaml
# 4. Record mitigations and accept residual risk (gate G3 fails until every risk whose
# residual score is above the appetite threshold is re-scored at or below it, or accepted)
riskforge risk list <system-id>
riskforge risk mitigate <system-id> <risk-id> \
-m "Remove postcode feature; add demographic parity monitoring" \
-c preventive --owner "ML Platform" --residual-likelihood 2 --residual-severity 3 \
--by "Dr. Lena Fischer, AI Governance Lead"
riskforge risk accept <system-id> <risk-id> --rationale "Residual within appetite after controls." \
--by "Dr. Lena Fischer, AI Governance Lead"
# 5. Derive Article 9(6) to (8) test requirements for knowledge-gap risks and risks scoring 9 or more, and save them
# on the register (the export carries them; gate G4 warns until every knowledge gap has one)
riskforge tests generate <system-id>
# 6. Check completeness before export (exit 1 if a FAIL gate is unmet)
riskforge validate <system-id>
# 7. Create an Ed25519 signing key once, outside the project (keygen never overwrites a file)
mkdir -p ~/.config/riskforge
riskforge keygen --output ~/.config/riskforge/signing.pem
# 8. Export your Article 9 Risk Management File, signing the JSON
riskforge export <system-id> --format json --output rmf.json --sign ~/.config/riskforge/signing.pem
riskforge export <system-id> --format pdf --output rmf.pdf
# 9. Take a receipt and keep it where the project's editors cannot change it
mkdir -p ~/riskforge-receipts
riskforge receipt <system-id> --output ~/riskforge-receipts/loan-scoring.json
# 10. Verify any time (exit 2 on integrity findings; plain verify misses a log rewritten to match its head file, --receipt catches it up to the receipt)
riskforge verify
riskforge verify --file rmf.json --trusted-key ~/.config/riskforge/signing.pem.pub
riskforge verify --receipt ~/riskforge-receipts/loan-scoring.json
Why RiskForge
| Evaluation Method | Cost | Deterministic / Repeatable? | Offline / Zero-Telemetry? |
|---|---|---|---|
| Big 4 Consulting | Paid engagement per system | ❌ No (Advisory opinion) | ⚠️ Depends on the engagement |
| Enterprise GRC Platforms | Annual license | ⚠️ Partial | ⚠️ Depends on the product and deployment |
| Internal Spreadsheets | "Free" | ❌ No (Human error) | ⚠️ Manual |
| RiskForge | Free (Apache 2.0) | ✅ Yes (Deterministic hash) | ✅ Yes (100% offline, zero network) |
System Architecture
RiskForge has four layers with CI-enforced import boundaries (ADR-02):
graph TB
subgraph UI ["1. Interface Layer"]
CLI["CLI (Typer)<br/><code>riskforge init / assess / validate / export / verify</code>"]
end
subgraph Core ["2. Decoupled Engine Layer"]
ENG["AuditEngine · RiskEngine · SystemEngine · ValidateEngine<br/>AssessEngine · ExportEngine · TestDerivationEngine"]
end
subgraph Persistence ["3. Pluggable Storage Layer"]
STORE["StorageBackend ABC · FileStore<br/><code>YAML + JSONL · chmod 600/700 · file lock · atomic writes</code>"]
end
subgraph Extensibility ["4. Integration Adapters"]
ADAPT["RAGBenchmarkingAdapter · Ecosystem Adapters<br/><em>Discovered via Python entry_points</em>"]
end
CLI -->|"calls engine functions"| ENG
ENG -->|"reads/writes via StorageBackend ABC"| STORE
ENG -->|"adapter pattern, no hard imports"| ADAPT
style UI fill:#F5F4EF,stroke:#E4E2DC,color:#0F1419
style Core fill:#E6F4F1,stroke:#0D5463,color:#0D5463
style Persistence fill:#FAF0E6,stroke:#B68A2E,color:#0F1419
style Extensibility fill:#F5F4EF,stroke:#E4E2DC,color:#0F1419
State on disk:
your-project/
├── riskforge.yaml project manifest (chmod 600)
├── .riskforge/ (chmod 700)
│ ├── audit.jsonl append-only hash-chained audit log
│ ├── audit.head.json sequence number and hash of the last entry
│ ├── audit.lock serializes writers across processes
│ ├── txn.json exists only while a change is being committed
│ ├── .nodelete deletion sentinel
│ └── systems/<system-id>/
│ ├── system.yaml
│ ├── register.yaml
│ └── mitigations.yaml
└── rmf-<id>-<export>.json exports land where --output says (default: the project directory)
Plain YAML plus JSONL: readable by regulators without RiskForge installed, and diff-able in GitHub PRs.
AI Exponent Governance Toolchain
RiskForge is the Article 9 tool in the open-source AI Exponent governance toolchain:
graph LR
LIT["litmusai<br/><i>(Art. 5 Prohibited AI)</i><br/><code>SARIF / JSON</code>"]
LCC["license-compliance-checker<br/><i>(Art. 53 GPAI & Models)</i><br/><code>CycloneDX / JSON</code>"]
RAG["rag-benchmarking<br/><i>(Art. 15 Accuracy & Robustness)</i><br/><code>BenchmarkReport JSON</code>"]
RF["riskforge<br/><i>(Art. 9 Risk Management)</i><br/><b>Signed rmf.json / PDF</b>"]
ADA["agentic-document-analyser<br/><i>(Art. 9 / Annex IV)</i><br/><code>Audit Blocks / Layout JSON</code>"]
LIT -.->|"prohibited practice clearance"| RF
LCC -.->|"model & training risk"| RF
RAG -->|"benchmark_report.json"| RF
RF -->|"rmf.json / rmf.pdf"| ADA
style RF fill:#E6F4F1,stroke:#0D5463,color:#0D5463,stroke-width:2px
style LIT fill:#F5F4EF,stroke:#E4E2DC,color:#0F1419
style LCC fill:#F5F4EF,stroke:#E4E2DC,color:#0F1419
style RAG fill:#F5F4EF,stroke:#E4E2DC,color:#0F1419
style ADA fill:#F5F4EF,stroke:#E4E2DC,color:#0F1419
All interactions occur via plain JSON artifacts on disk. RiskForge never calls external cloud APIs.
EU AI Act Article 9 Coverage
graph LR
A9_1["Art. 9(1)<br/>Establish RMS"] --> REG["Register lifecycle<br/>Version history<br/>Audit log"]
A9_2a["Art. 9(2)(a)<br/>Identify risks"] --> QB["Guided question bank<br/>8 dimensions · 37 questions"]
A9_2b["Art. 9(2)(b)<br/>Estimate and evaluate risks<br/>(intended use, foreseeable misuse)"] --> PAT["Risk patterns<br/>6 Annex III points, 1 Annex I route"]
A9_2d_5["Art. 9(2)(d), 9(5)<br/>Risk measures"] --> MIT["Mitigation docs<br/>Vague-detection"]
A9_6_8["Art. 9(6) to (8)<br/>Testing requirements"] --> TEST["riskforge tests generate<br/>Per-risk metric hints"]
A9_9["Art. 9(9)<br/>Vulnerable groups"] --> VG["Dedicated questions<br/>Mandatory flag"]
A9_1D["Art. 9(1)<br/>Documented"] --> AUD["Append-only JSONL<br/>SHA-256 hash chain"]
style A9_1 fill:#E6F4F1,stroke:#0D5463,color:#0D5463
style A9_2a fill:#E6F4F1,stroke:#0D5463,color:#0D5463
style A9_2b fill:#E6F4F1,stroke:#0D5463,color:#0D5463
style A9_2d_5 fill:#E6F4F1,stroke:#0D5463,color:#0D5463
style A9_6_8 fill:#E6F4F1,stroke:#0D5463,color:#0D5463
style A9_9 fill:#E6F4F1,stroke:#0D5463,color:#0D5463
style A9_1D fill:#E6F4F1,stroke:#0D5463,color:#0D5463
Cross-maps to:
- NIST AI RMF 1.0:
GOVERN,MAP,MEASURE,MANAGE - ISO/IEC 42001:2023: Clauses 6.1 and 9.1, and Annex A.6, A.7 and A.9
- Colorado AI Act: SB 24-205, repealed and reenacted by SB 26-189 (signed 14 May 2026)
- Texas Responsible Artificial Intelligence Governance Act: Texas HB 149 (TRAIGA), in effect since 1 January 2026
Validation Gates
Before every export, riskforge validate runs 8 automated gates:
| Gate | Check |
|---|---|
| G1 | All 8 risk dimensions have at least one entry |
| G2 | Article 6(2) Annex III self-classification documented |
| G3 | Every risk whose residual score is above the appetite threshold is re-scored at or below it, or accepted with a rationale |
| G4 | Knowledge gaps have test requirements |
| G5 | System metadata complete |
| G6 | Assessor identity recorded |
| G7 | Risk score distribution plausible (warns if all scores are low) |
| G8 | No vague mitigation language detected |
Interactive Artifact Previews
📄 View a starter system.yaml
The system record riskforge init writes to .riskforge/systems/<system-id>/system.yaml,
after riskforge system classify --confirm.
id: 634ca9f5-b64f-4275-8469-fc4ddc8ddc14
name: Loan Scoring Model
version: '2.1'
purpose: Automated credit scoring for retail loan applications.
intended_users: []
inputs: []
outputs: []
deployment_context: ''
annex_iii_category: essential_services
annex_iii_self_classification_documented: true
provider_name: Acme Financial Services
provider_contact: ''
created_at: '2026-10-17T20:47:38.653899Z'
schema_version: 1.0.0
🔍 View an exported rmf.json (one risk item, schema 1.1.0, signed)
A complete export from a one-risk project, signed with a throwaway key from riskforge keygen
and made with --force because a real assessment covers all eight dimensions.
tests/contract/test_readme_samples.py checks that it validates against the schema and that
its digest, signature, chain proof and receipt verify.
{
"id": "27c60766-0e97-4df0-8b47-6b2600d9e55e",
"rmf_schema_version": "1.1.0",
"register": {
"id": "1452ba9b-7f05-4173-8ca7-46b5d42e5556",
"system": {
"id": "634ca9f5-b64f-4275-8469-fc4ddc8ddc14",
"name": "Loan Scoring Model",
"version": "2.1",
"purpose": "Automated credit scoring for retail loan applications.",
"intended_users": [],
"inputs": [],
"outputs": [],
"deployment_context": "",
"annex_iii_category": "essential_services",
"annex_iii_self_classification_documented": true,
"provider_name": "Acme Financial Services",
"provider_contact": "",
"created_at": "2026-10-17T20:47:38.653899Z",
"schema_version": "1.0.0"
},
"items": [
{
"id": "4e5d7138-e939-4a88-97c4-e06a7a0b8f08",
"dimension": "discrimination",
"title": "Has the training dataset been audited for representation imbalances across protected characteristics (gender, ethnicity,",
"description": "Biased training data produces biased outputs. Article 10(2)(f) requires data governance measures to address biases.",
"source": "question_bank",
"likelihood": 4,
"severity": 5,
"mitigations": [],
"residual_likelihood": 4,
"residual_severity": 5,
"accepted": true,
"acceptance_rationale": "Residual within appetite after documented controls.",
"accepted_by": "Alice Chen, AI Governance Lead",
"identified_at": "2026-10-17T20:47:39.000441Z",
"article_refs": [
"Art.10(2)(f)",
"Art.9(2)(a)"
],
"nist_rmf_refs": [],
"iso42001_refs": [],
"nist_rmf_ref": "MEASURE 2.11",
"iso42001_ref": "Annex A.7",
"regulatory_status": "settled",
"knowledge_gap": false,
"knowledge_gap_reason": "",
"source_ref": "",
"tags": [
"DI-001"
],
"notes": "",
"risk_score": 20,
"residual_risk_score": 20,
"risk_band": "critical",
"residual_risk_band": "critical"
}
],
"risk_appetite_threshold": 9,
"assessor_name": "Alice Chen",
"assessor_role": "AI Governance Lead",
"assessment_date": "2026-10-17T20:47:38.982512Z",
"review_date": "2027-10-12T20:47:38.982512Z",
"question_bank_version": "1.0.0",
"schema_version": "1.0.0",
"test_requirements": [
{
"id": "36ce0868-6eff-5c10-a6cc-3432fbfcb064",
"risk_item_id": "4e5d7138-e939-4a88-97c4-e06a7a0b8f08",
"description": "Validate 'Has the training dataset been audited for representation imbalances across protected characteristics (gender, ethnicity,' via demographic_parity measurement. Target: <= 0.10.",
"metric_type": "demographic_parity",
"threshold_range": "<= 0.10",
"article_ref": "Art.9(8)",
"nist_rmf_ref": ""
}
]
},
"test_requirements": [
{
"id": "36ce0868-6eff-5c10-a6cc-3432fbfcb064",
"risk_item_id": "4e5d7138-e939-4a88-97c4-e06a7a0b8f08",
"description": "Validate 'Has the training dataset been audited for representation imbalances across protected characteristics (gender, ethnicity,' via demographic_parity measurement. Target: <= 0.10.",
"metric_type": "demographic_parity",
"threshold_range": "<= 0.10",
"article_ref": "Art.9(8)",
"nist_rmf_ref": ""
}
],
"cross_references": [
{
"article_ref": "Art.10(2)(f)",
"risk_item_ids": [
"4e5d7138-e939-4a88-97c4-e06a7a0b8f08"
],
"nist_rmf_ref": "MEASURE 2.11",
"iso42001_ref": "Annex A.7"
},
{
"article_ref": "Art.9(2)(a)",
"risk_item_ids": [
"4e5d7138-e939-4a88-97c4-e06a7a0b8f08"
],
"nist_rmf_ref": "MEASURE 2.11",
"iso42001_ref": "Annex A.7"
}
],
"generated_at": "2026-10-17T20:47:39.725511Z",
"sha256_hash": "03cbec63a205057eb5a0c43efac12951e7bd70204a9b94c4fcd9a00df5f76e36",
"disclosure": "This document was produced using RiskForge v2.0.0, question bank version 1.0.0. It represents the team's documented risk assessment and has not been reviewed by a qualified legal professional. It does not constitute legal advice under the EU AI Act or any other regulation.",
"signoffs": [],
"signatures": [
{
"key_id": "ed25519:b7b5c4a19a859133",
"algorithm": "ed25519",
"signed_at": "2026-10-17T20:47:39.726225Z",
"signature": "p/CVwcq2mcTC8wp3NiJ4En4eeWrvTldbJM+ndkZjeFUUBW7RKPcJlRBqjyJWSmDlNOzM0Y2/bQOWIszDQ83VAA=="
}
],
"public_keys": [
{
"key_id": "ed25519:b7b5c4a19a859133",
"algorithm": "ed25519",
"public_key": "MBbJzWXjm7pX/63P8jUIMByQJTMgg8W7yAj9QCciCYQ="
}
],
"chain_proof": {
"scope": "project",
"entries": [
{
"seq": 0,
"event": "system.created",
"timestamp": "2026-10-17T20:47:38.664225Z",
"actor": {
"type": "human",
"identity": "cli"
},
"system_id": "634ca9f5-b64f-4275-8469-fc4ddc8ddc14",
"payload": {
"name": "Loan Scoring Model",
"version": "2.1",
"annex_iii_category": "essential_services"
},
"prev_hash": "0000000000",
"entry_hash": "96ffca43be322700b3ee97ad1927af4e349adc6ca337c2cc17c104bbf7be300e"
},
{
"seq": 1,
"event": "system.classified",
"timestamp": "2026-10-17T20:47:38.823841Z",
"actor": {
"type": "human",
"identity": "cli"
},
"system_id": "634ca9f5-b64f-4275-8469-fc4ddc8ddc14",
"payload": {
"annex_iii_self_classification_documented": true,
"annex_iii_category": "essential_services"
},
"prev_hash": "96ffca43be322700b3ee97ad1927af4e349adc6ca337c2cc17c104bbf7be300e",
"entry_hash": "920f2989222a6e951b06d482931141a50b5a93b0f3e46795938a5fb4cda49fd0"
},
{
"seq": 2,
"event": "register.created",
"timestamp": "2026-10-17T20:47:38.984641Z",
"actor": {
"type": "human",
"identity": "Alice Chen"
},
"system_id": "634ca9f5-b64f-4275-8469-fc4ddc8ddc14",
"payload": {
"assessor_name": "Alice Chen",
"assessor_role": "AI Governance Lead",
"review_date": "2027-10-12T20:47:38.982512+00:00"
},
"prev_hash": "920f2989222a6e951b06d482931141a50b5a93b0f3e46795938a5fb4cda49fd0",
"entry_hash": "e3bab0ed097b6956ab6b0f309dbc3a29a0b65153aeff44f6b4befd37a54609d0",
"register_fingerprint": "3ec4a2883d344d097c849f6c2da0cdee493f4b111b53fc4f9d927efbffe25dd7"
},
{
"seq": 3,
"event": "risk_item.created",
"timestamp": "2026-10-17T20:47:39.003418Z",
"actor": {
"type": "human",
"identity": "Alice Chen"
},
"system_id": "634ca9f5-b64f-4275-8469-fc4ddc8ddc14",
"payload": {
"risk_item_id": "4e5d7138-e939-4a88-97c4-e06a7a0b8f08",
"dimension": "discrimination",
"score": 20
},
"prev_hash": "e3bab0ed097b6956ab6b0f309dbc3a29a0b65153aeff44f6b4befd37a54609d0",
"entry_hash": "27471302726ce8051f99a5e67d086c05e940002a14ecf229114848dea846b6de",
"register_fingerprint": "6eed24a18c7e1634024236f409443743d7f77a48e22e06244dbfb5035191eb2a"
},
{
"seq": 4,
"event": "risk.accepted",
"timestamp": "2026-10-17T20:47:39.191413Z",
"actor": {
"type": "human",
"identity": "Alice Chen, AI Governance Lead"
},
"system_id": "634ca9f5-b64f-4275-8469-fc4ddc8ddc14",
"payload": {
"risk_item_id": "4e5d7138-e939-4a88-97c4-e06a7a0b8f08",
"old_accepted": false,
"rationale_hash": "72e990650636afae",
"actor": "Alice Chen, AI Governance Lead"
},
"prev_hash": "27471302726ce8051f99a5e67d086c05e940002a14ecf229114848dea846b6de",
"entry_hash": "f9cedd0ef74f00f98df9209f3069b5680985059867f47ba2758f6573c3425ef5",
"register_fingerprint": "3cdea27d907dc2a1029e376d906910bd2d393a3735b924bff601d3fb6e9f6652"
},
{
"seq": 5,
"event": "tests.generated",
"timestamp": "2026-10-17T20:47:39.356442Z",
"actor": {
"type": "human",
"identity": "cli"
},
"system_id": "634ca9f5-b64f-4275-8469-fc4ddc8ddc14",
"payload": {
"count": 1,
"risk_item_ids": [
"4e5d7138-e939-4a88-97c4-e06a7a0b8f08"
]
},
"prev_hash": "f9cedd0ef74f00f98df9209f3069b5680985059867f47ba2758f6573c3425ef5",
"entry_hash": "5a4df81458b3e929170150d0c45a47e9d279538f58b3469cb6e502d24e9cc279",
"register_fingerprint": "dc93c4b03aa10f1010424b6df2941b31c282e20712036dab15b2973d12e73f06"
}
]
},
"receipt": {
"receipt_version": "1",
"system_id": "634ca9f5-b64f-4275-8469-fc4ddc8ddc14",
"seq": 5,
"entry_hash": "5a4df81458b3e929170150d0c45a47e9d279538f58b3469cb6e502d24e9cc279",
"register_fingerprint": "dc93c4b03aa10f1010424b6df2941b31c282e20712036dab15b2973d12e73f06",
"issued_at": "2026-10-17T20:47:39.725779Z",
"key_id": "ed25519:b7b5c4a19a859133",
"public_key": "MBbJzWXjm7pX/63P8jUIMByQJTMgg8W7yAj9QCciCYQ=",
"signature": "LMd7wAVJG28NUwc82b5MRrtc/OYfCxbqnxYAZ5qilSEQOKPJgBJhBf/CUmuW/UuIxZe+MIcQ5k8MxHae0nOHAg=="
}
}
CI/CD Integration & Exit Codes
Add RiskForge to your GitHub Actions pipeline as an automated completeness and integrity check:
# .github/workflows/article9-gate.yml
name: EU AI Act Article 9 register checks
on: [pull_request, push]
jobs:
rmf-gate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/setup-python@v6
with:
python-version: "3.11"
- name: Install RiskForge
run: pip install riskforge
- name: Validate Article 9 Gates
run: riskforge validate <system-id>
- name: Verify Audit Chain Integrity
run: riskforge verify --strict
This job checks a project committed to the repository. The files in .riskforge/ hold
your risk assessment, so do this only in a private repository, and never in a public one.
Exit Code Contract
RiskForge implements deterministic UNIX exit codes for automated CI/CD gating:
| Exit Code | Meaning | CI Behavior |
|---|---|---|
0 |
PASS / VALID | Success: the command succeeded, or what it checked is intact. |
1 |
GATE FAILURE | One or more validation gates failed (unmitigated high risks, missing assessor, unclassified system). Also exits 1: verify or validate finding a change in progress or unfinished, a command that waited more than 120 seconds for another riskforge process to release the project, and an unexpected crash (prints a traceback). |
2 |
TAMPER DETECTED | Integrity failure: the audit chain is corrupt or tampered, a register or system file was changed outside RiskForge, the log was deleted or cut off, or an exported RMF file fails verify --file (its digest, a signature, its chain proof or its receipt). verify exits 2 (with --strict, also on any integrity warning), and every command that changes or exports data exits 2 on such a project without changing it. |
3 |
USAGE / INPUT ERROR | Usage or input error: unknown option or command, missing required option, bad option value, missing or malformed input file, unknown system or risk ID, no project in the directory, no risk register yet, project already exists, system classify without --confirm, an export --sign or --public-key value that is not a usable Ed25519 key file, an export output directory that is missing or cannot be written, verify --strict with --file, a receipt file that is not a receipt, a --trusted-key file that is not an Ed25519 public key, a keygen or receipt --output file that already exists, or interactive assess without a terminal. Prints one line saying what to do. |
CLI Command Reference
| Command | Description |
|---|---|
riskforge init |
Create a project and register the AI system; prints the system id. |
riskforge system show <id> |
Print the system record. |
riskforge system classify <id> |
Document and confirm Article 6(2) Annex III self-classification. |
riskforge assess <id> |
Run the interactive 8-dimension guided assessment (supports --answers). |
riskforge risk mitigate <id> <risk-id> --by NAME |
Document preventive/corrective mitigation controls and re-score residual risk. --by (or RISKFORGE_ACTOR) names who recorded it; the name is self-declared and not verified. |
riskforge risk accept <id> <risk-id> --by NAME |
Formally accept residual risk with documented business/technical rationale. --by (or RISKFORGE_ACTOR) names who accepted it; the name is self-declared and not verified. |
riskforge tests generate <id> |
Generate Article 9(6) to (8) testing requirements for knowledge-gap risks and risks whose inherent score is 9 or more, and save them on the register (exported with the RMF). |
riskforge validate <id> |
Execute the 8 completeness and quality gates before report generation. |
riskforge export <id> |
Export the Risk Management File to pdf, json, or markdown; --sign KEY signs it with an Ed25519 key. |
riskforge verify |
Check the project (audit chain, head file, register fingerprints, system files); --strict also fails on warnings. |
riskforge verify --file rmf.json |
Check one exported file: schema, digest, signatures, sign-offs, chain proof and receipt; --trusted-key KEY.pub pins the signer. |
riskforge verify --receipt FILE |
Also check that the audit log still holds the entry a receipt names. |
riskforge keygen --output KEY |
Create an Ed25519 key pair: KEY (mode 600 on Linux and macOS, not encrypted) and KEY.pub. |
riskforge receipt <id> |
Print or save (--output FILE) a receipt for the last audit entry, to keep outside the project. |
riskforge diff <id> OLD.json NEW.json |
Show risk items added, removed, and changed between two exports. |
riskforge import <id> -a ADAPTER -r REPORT |
Import findings from a rag-benchmarking or TraceForge report. |
riskforge risk list <id> |
List the risk items with their scores, bands and acceptance. |
riskforge --version |
Print the version, licence and telemetry status. |
Features
| Feature | Detail |
|---|---|
| Offline-first | Zero outbound calls after pip install, enforced by pytest-socket CI gate |
| Hash-chained audit | Every change and its audit entry are committed together under a file lock, with a fingerprint of the register; riskforge verify exits 2 when the chain, a register or a file was altered, unless the chain and head file were recomputed to match; a receipt catches that for the entries it covers |
| Signed exports and receipts | Ed25519 keys from riskforge keygen; verify --file checks the digest, signatures and chain proof; a receipt kept outside the project catches a rewrite of any entry up to the receipt's entry |
| Schema-validated exports | Every export is validated against the bundled RMF schema 1.1.0 ($id https://aiexponent.com/schemas/riskforge/rmf/1.1.0.json) before it is written |
| PDF export | WeasyPrint + Jinja2, no LibreOffice or wkhtmltopdf required |
| Pattern matching | 7 pre-built risk patterns, each tied to its high-risk route. Six name the Annex III point they cover: credit scoring (5(b)), recruitment and CV screening (4(a)), remote biometric identification (1(a)), assessment of learning outcomes (3(b)), asylum, visa and residence applications (7(c)), and offending risk assessment (6(d)). One covers medical diagnosis and clinical decision support, high-risk under Art. 6(1) where the AI system is, or is a safety component of, a medical device covered by Annex I that must undergo a third-party conformity assessment |
| Plugin extensible | Add question banks, exporters, adapters via pip install, no config edit required |
| Git-friendly state | YAML + JSONL files, human-readable and diff-able. One writer at a time: merging two branches' audit logs breaks the chain, and verify reports it |
Contributing
The easiest contribution requires zero Python: edit a YAML file and open a PR.
Add a question to an existing dimension:
# src/riskforge/_data/question_bank/privacy.yaml
- id: PRIV-007
text: "Does the system process special category data under GDPR Article 9?"
guidance: "Special category data includes data revealing racial or ethnic origin or political opinions, health data, and biometric data processed to uniquely identify a person (GDPR Article 9(1))."
annex_iii_categories: [essential_services, employment]
default_likelihood_hint: 3
default_severity_hint: 5
article_refs: ["Art.9(2)(a)", "Art.4a(1)"]
nist_rmf_ref: "MEASURE 2.10"
iso42001_ref: "Annex A.7"
regulatory_status: settled
Add a risk pattern: edit src/riskforge/_data/patterns/patterns.yaml.
Fix a bug or add a feature: see CONTRIBUTING.md.
git clone https://github.com/aiexponent/riskforge
cd riskforge
make dev-setup # pip install -e ".[dev]" + pre-commit install
make test # the full suite; all tests must pass
make lint # ruff check + format
Documentation
- User Guide: the CLI workflow, answers files, signing, receipts, CI use, and mitigations.
- Article 9 Mapping: what RiskForge does and does not do for each part of Article 9, and how the question bank lines up with it.
- Audit Chain Design: the hash chain, register fingerprints, signatures, receipts, and their limits.
- Architecture Decision Records (ADRs): design principles, boundaries, and technical decisions.
- Contributing Guide: how to contribute questions, patterns, and code.
Important Disclaimers
Technical Documentation & Legal Status
REGULATORY EVIDENCE GENERATOR, NOT A NOTIFIED BODY
RiskForge produces documented evidence and audit logs for the EU AI Act Article 9 risk management system, and the description of that system that Annex IV point 5 asks for. It is a technical workflow tool for engineering and governance teams. A complete RiskForge file shows that the risk management steps were documented; it does not show that the AI system complies with Article 9 or any other provision.
RiskForge does not constitute legal advice and is not a notified body. Using RiskForge does not replace mandatory third-party conformity assessment where required under Article 43 of the EU AI Act.
Privacy & Zero-Network Guarantee
RiskForge makes zero outbound network connections in CLI mode. Your risk registers, architecture descriptions, mitigation plans, and audit logs remain strictly on your local machine.
RiskForge v2.0.0 | Apache 2.0 | Zero telemetry | aiexponent.com
Zero-network guarantee enforced in automated CI via pytest-socket --disable-socket.
Releases
| Version | Highlights |
|---|---|
| v2.0.0 | Interactive assess works; verify catches edited registers, cut or deleted logs and deleted files; atomic writes under one project lock; Ed25519 signing, receipts and RMF schema 1.1.0; a styled PDF with the full structure; one-line errors with exit code 3; a supported Python API and storage contract suite. Breaking: GPG signing, the serve command and the Docker image are gone. RiskForge 1.x reports a project 2.0.0 has changed as tampered (exit 2), and verify --file in 1.1.x reports a 2.0.0 JSON export the same way: upgrade every machine and every reviewer together, do not downgrade, and see the upgrade note in CHANGELOG.md. |
| v1.1.3 | Resilient dependency ranges, multi-OS CI runner matrix (Ubuntu/macOS) with WeasyPrint test coverage, 5-tool reciprocal ecosystem footer, flat-square badges & Dependabot. |
| v1.1.2 | Documentation now points at the in-repo guides (full user guide, Article 9 mapping, audit-chain design with diagrams); the PyPI docs link is absolute and a docs/ index was added. |
| v1.1.1 | Schema hardening: the mandatory not-legal-advice disclosure is now enforced by the RMF JSON Schema (required, non-empty), not only injected at export. |
| v1.1.0 | Release-hardening pass: six correctness fixes, O(n) audit append, worked examples with a determinism check, a full user guide, benchmarks, and single-source versioning. |
| v1.0.0 | First Production/Stable release. Click 8.3 regression fixed; LICENSE realigned to canonical SPDX; scope amended to ship reality (37 questions, 6 patterns); coverage floor 24→55. |
| v0.1.4 | CI fixes: lint version compat, format alignment, --sys-version rename |
| v0.1.3 | Superseded by v0.1.4 (ruff format alignment) |
| v0.1.2 | OSS hardening: LICENSE, CONTRIBUTING, SECURITY, issue templates, full integration tests |
| v0.1.1 | riskforge assess fully implemented; PDF exporter fix; audit chain integrity fixes |
| v0.1.0 | Initial release |
License
Apache 2.0, free to use, modify, and distribute.
Built by AI Exponent LLC, hello@aiexponent.com
Part of the AI Exponent open-source AI governance toolchain:
litmusai (Art. 5) ·
license-compliance-checker (Art. 53) ·
rag-benchmarking (Art. 15) ·
riskforge (Art. 9) ·
agentic-document-analyser (Art. 9 / Annex IV)
Metadata
Release files for riskforge 2.0.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| riskforge-2.0.0.tar.gz | 791.2 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| riskforge-2.0.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 972.1 kB
Release files / riskforge-2.0.0.tar.gz
| Download URL | riskforge-2.0.0.tar.gz |
|---|---|
| Size | 791.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
ec33388bc93e8853bae7f598a54c51f043ad93324cde56f0880d2d354b9e79eb
|
|
BLAKE2b-256 checksum How to use checksums |
98e097b661e7030f780338727b281b17ae75477b9ad97b9cd55aaae89f3fad6b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 18, 2026.
Transparency logRelease files / riskforge-2.0.0-py3-none-any.whl
| Download URL | riskforge-2.0.0-py3-none-any.whl |
|---|---|
| Size | 180.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
88c39e5bac9b59f4bc8c3f94bbafaf87ff746ccfd7e7bac8ea7ce748fd529dd8
|
|
BLAKE2b-256 checksum How to use checksums |
648369bd1c1f4fbb188278c2dd0b370a5e1e8684a7e367b8e4397e2c16e4b496
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 18, 2026.
Transparency log