Last updated: April 17, 2026
Article 11 of the EU AI Act requires providers of high-risk AI systems to create and maintain technical documentation that demonstrates compliance before the system is placed on the market. This is not a Word document with outdated screenshots. It is a living record of system design, risk management, testing results, and post-deployment behavior that regulators can audit. If you ship AI in the EU after August 2, 2026, you need this documentation locked in before launch.
After building documentation pipelines for three compliance scanning tools, the biggest lesson is this: teams that treat documentation as code pass audits. Teams that treat it as a quarterly chore fail. This guide walks through what Article 11 actually requires, what Annex IV spells out in detail, and how to build documentation programmatically in Python so it stays synchronized with your actual system.
Article 11 mandates that before deployment, providers of high-risk AI systems must have technical documentation covering seven areas: system description, design specifications, development process, risk management measures, monitoring and testing plans, change history, and compliance cross-references to other articles. The documentation must be kept up to date throughout the system's operational lifetime - it is not a one-time deliverable.
The specifics break down into these required elements:
The key insight: this is not documentation about compliance. It is documentation that proves compliance. Every requirement from Articles 9 through 15 should map to a specific section in your technical file.
Annex IV of the EU AI Act lists the exact items that must appear in your technical documentation. Regulators use this as their checklist. If an item is missing, the audit fails regardless of how good your code is. The table below maps each item to the article it satisfies.
| Documentation Item | What to Include | Maps to Article |
|---|---|---|
| 1. System description | Purpose, intended use, users affected | 11 |
| 2. Data description | Training data provenance, characteristics, labeling methodology, bias assessment | 10 |
| 3. Model architecture | Model type, algorithm, version, dependencies | 11 |
| 4. Risk management file | Identified risks and mitigation measures | 9 |
| 5. Performance testing | Accuracy, robustness, fairness metrics on test sets and real-world data | 15 |
| 6. Monitoring system | How you detect performance degradation, drift, misuse | 12 |
| 7. Logging capability | What events are recorded, how, for how long | 12 |
| 8. User documentation | How to use the system correctly, limitations, failure modes | 13 |
| 9. Incident response | What happens when the system fails, who to notify, how to recover | 9, 14 |
| 10. Governance records | Who approved deployment, when, based on what evidence | 14 |
Each item should be updated during development and maintained throughout the system's operational lifetime. The August 2026 enforcement deadline applies to systems deployed after that date.
A model card is a structured summary of what a model does, what data trained it, and how it performs. Defining it as a Python dataclass satisfies Annex IV items 2 (data description), 3 (model architecture), and 5 (performance testing) in a single version-controlled artifact. When the model changes, the dataclass changes with it - no separate document to update.
from dataclasses import dataclass
from typing import Optional
import json
@dataclass
class ModelCard:
# System identification
system_name: str
system_version: str
intended_use: str
# Data
training_data_source: str
training_data_size: int
labeling_methodology: str
known_biases: list[str]
# Model
model_type: str
framework: str
# Performance
accuracy_test_set: float
accuracy_real_world: float
fairness_metrics: dict
failure_modes: list[str]
# Risk
identified_risks: list[str]
mitigation_measures: dict
# Monitoring
monitoring_frequency: str
alert_thresholds: dict
def to_markdown(self) -> str:
"""Export as markdown for compliance documentation."""
lines = [
f"# {self.system_name} v{self.system_version}",
f"\n## System Description\n{self.intended_use}",
f"\n## Training Data\n- Source: {self.training_data_source}",
f"- Size: {self.training_data_size:,} samples",
f"- Labeling: {self.labeling_methodology}",
f"- Known biases: {', '.join(self.known_biases)}",
f"\n## Model\n- Type: {self.model_type}",
f"- Framework: {self.framework}",
f"\n## Performance\n- Test accuracy: {self.accuracy_test_set:.2%}",
f"- Real-world accuracy: {self.accuracy_real_world:.2%}",
f"- Fairness: {json.dumps(self.fairness_metrics, indent=2)}",
f"\n## Failure Modes\n" + "\n".join(
[f"- {mode}" for mode in self.failure_modes]
),
f"\n## Risks and Mitigations\n" + "\n".join(
[f"- {risk}: {self.mitigation_measures[risk]}"
for risk in self.identified_risks]
),
]
return "\n".join(lines)
Populate this card once during development and version it alongside your model:
card = ModelCard(
system_name="CreditRisk-v2",
system_version="2.3.1",
intended_use="Assess creditworthiness for loan applications in EU markets",
training_data_source="Internal loan database 2018-2025",
training_data_size=125000,
labeling_methodology="Default status after 90 days",
known_biases=["Overrepresented: prime-age males in tech hubs",
"Underrepresented: rural applicants, older workers"],
model_type="Gradient boosting (XGBoost)",
framework="xgboost==2.0.1",
accuracy_test_set=0.87,
accuracy_real_world=0.84, # Real-world is lower (normal)
fairness_metrics={
"demographic_parity_difference": 0.12,
"equal_opportunity_difference": 0.08
},
failure_modes=[
"Model underperforms for self-employed applicants (< 60% accuracy)",
"Drift detected when interest rates change rapidly"
],
identified_risks=[
"Fairness: Model bias against certain age groups",
"Robustness: Performance degrades with economic shock",
"Transparency: Black-box model obscures decision logic"
],
mitigation_measures={
"Fairness: Model bias against certain age groups":
"Monitored monthly, threshold 0.15 triggers retraining review",
"Robustness: Performance degrades with economic shock":
"Real-time monitoring on economic indicators, auto-disable if GDP growth < -2%",
"Transparency: Black-box model obscures decision logic":
"SHAP explanations for every denial, audit trail per Article 12"
},
monitoring_frequency="Daily",
alert_thresholds={
"accuracy_drop": 0.03,
"fairness_gap": 0.20,
"drift_detected": True
}
)
# Save and version with model
with open("docs/model_card.md", "w") as f:
f.write(card.to_markdown())
This single dataclass becomes your Annex IV items 2, 3, and 5. It is version-controlled, auditable, and automatically formatted for regulators.
Running a compliance scanner on your codebase produces a report that maps directly to Article 11 requirements. Instead of writing architecture documentation by hand and watching it drift within weeks, extract the report and build your architecture documentation from the scan results. This keeps documentation synchronized with actual system behavior.
from air_compliance import scan_project
# Scan your codebase
report = scan_project("./my_ai_system")
# Generate architecture documentation from scan results
arch_doc = f"""
# System Architecture
## Components Identified
{report.components_summary}
## Risk Assessment (Article 9)
{report.article_9_findings}
## Data Governance (Article 10)
{report.article_10_findings}
## High-Risk Zones
- {chr(10).join([f"- {zone['name']}: {zone['risk_level']}"
for zone in report.high_risk_areas])}
## Dependencies
{report.dependency_audit}
## Compliance Score
{report.overall_score}/100
## Required Actions
{report.remediation_steps}
"""
with open("docs/architecture.md", "w") as f:
f.write(arch_doc)
Run this in CI/CD on every commit to catch compliance drift before it reaches production.
Article 11 documentation does not stand alone. Regulators expect a unified technical file where every claim cross-references the article that governs it. A risk identified under Article 9 must have a corresponding mitigation shown in Article 11 code. A monitoring claim must link to an Article 12 audit trail. If the cross-references are missing, the documentation fails even if individual components are strong.
The integration points are:
identified_risks directly to Article 9 risk IDs.Example cross-reference format:
# In your Article 11 technical file:
## Risk: Model Bias Against Certain Demographics
- **Article 9 ID:** RISK-032
- **Severity:** High
- **Mitigation:** Monthly fairness audits, bias threshold 0.15
- **Article 12 Link:** Fairness metrics logged daily to audit chain
- **Article 14 Link:** Bias alert triggers manual review by Data Ethics Officer
- **Article 15 Link:** Tested against NIST bias taxonomy, 94% of cases within tolerance
Treat documentation generation as a CI/CD step, not a quarterly chore. The most common reason Article 11 audits fail is documentation drift - the technical file says one thing and the code does another. Automating the pipeline eliminates this gap by generating documentation from authoritative sources (code, config, scan results) on every deployment.
from air_compliance import scan_project, generate_documentation
import json
from datetime import datetime
# Run compliance scan
report = scan_project("./src")
# Load your model card
with open("model_card.json") as f:
card = json.load(f)
# Generate complete technical file
tech_file = generate_documentation(
report=report,
model_card=card,
article_9_risks=load_risk_register(),
article_10_data=load_data_audit(),
article_12_logs=load_recent_audit_logs(),
article_14_approvals=load_approval_chain(),
article_15_tests=load_test_results(),
generated_at=datetime.now().isoformat()
)
# Write as HTML and PDF for regulators
with open(f"compliance/{report.version}/technical_file.html", "w") as f:
f.write(tech_file.to_html())
tech_file.to_pdf(
f"compliance/{report.version}/technical_file.pdf"
)
This generates a complete, auditable technical file with version control, timestamps, and cross-references. Every artifact is backed by source code and scan results.
Documentation written by hand drifts. After scanning dozens of AI systems for Article 11 compliance, the pattern is consistent: teams with hand-written technical files have an average documentation accuracy of 60-70% within six months of deployment. Teams using documentation-as-code maintain 95%+ accuracy because the pipeline catches every change.
Documentation-as-code means:
air-compliance on every commit - if code changes but documentation is not updated, the build failsThe result is documentation that regulators trust because every claim can be traced back to source.
Five documentation gaps cause the majority of Article 11 audit failures. Each has a straightforward fix, but you need to address them before the August 2026 deadline - not after a regulator flags them.
No versioning. You update your model, but the technical file is still v1.0 from last year. Fix: link version numbers to Git tags and generate documentation per release.
No risk assessment linkage. Your Article 9 risk register is separate from Article 11 documentation. Regulators see the risks but not how you mitigated them in your actual system. Fix: every risk in Article 9 must have a corresponding mitigation in Article 11 (code, test, monitoring rule).
No lifecycle updates. Documentation frozen at deployment while the real system changes - data drifts, models get retrained, configs evolve. Fix: quarterly documentation reviews and automated monitoring for changes that require doc updates.
Performance data from dev, not production. Your accuracy is 92% in tests but 84% in production. If regulators find a gap, credibility dies. Fix: include both test-set performance and real-world performance, and explain the gap.
Monitoring plans with no implementation. You document that you will monitor accuracy drift, but nothing actually does it. Fix: documentation should link to actual monitoring code - if you say you will alert on drift > 3%, show the code that does it.
Article 11 requires providers of high-risk AI systems to create and maintain comprehensive technical documentation demonstrating compliance before the system is placed on the market. This documentation must cover system design, development process, risk management, testing results, monitoring procedures, and evidence of compliance with Articles 9, 10, 12, 14, and 15.
Technically yes, but practically it fails audits. Regulators want auditable, traceable documentation. If your document claims 91% model accuracy but the code trains a different model, you have failed. Treat documentation as code: version it in Git, generate it from scans and configs, test it in CI/CD, and link every claim to source.
No. Regulators expect a unified technical file, not five separate documents. Your Article 11 file should cross-reference and integrate information from all other articles. Every risk identified in Article 9 should have a mitigation shown in Article 11 code. Every monitoring requirement from Article 12 should link to Article 11 monitoring procedures.
During development, not after deployment. Document during the design phase, update as you build, integrate documentation generation into your CI/CD pipeline so it stays current, and maintain it throughout the system's lifecycle. The August 2, 2026 enforcement deadline applies to all high-risk AI systems deployed after that date.
Article 11 documentation requirements map closely to ISO 42001 Clause 7.5 (documented information) and NIST AI RMF GOVERN 1.5 (documentation practices). If you are already compliant with ISO 42001, approximately 70% of Article 11 requirements are covered. The gap is typically in the AI-specific elements: model cards, training data provenance, and automated compliance evidence. See the Articles 9-15 standards crosswalk for the full mapping.
Generate Article 11 technical documentation automatically:
pip install air-compliance