No description
  • Python 71.8%
  • TypeScript 27.4%
  • CSS 0.3%
  • Dockerfile 0.2%
  • Shell 0.2%
  • Other 0.1%
Find a file
Kevin Heyer 8b5026f4a8
All checks were successful
CI / backend (push) Successful in 4m43s
CI / mcp-server (push) Successful in 39s
CI / frontend (push) Successful in 26s
Merge feature/mcp-server into dev
2026-10-07 19:50:18 +02:00
.forgejo/workflows Add MCP server for AI assistants and draft-only agent tokens 2026-10-07 19:29:57 +02:00
backend Add MCP server for AI assistants and draft-only agent tokens 2026-10-07 19:29:57 +02:00
dev/keycloak Add users, roles, single sign-on and audit trail 2026-10-07 10:20:04 +02:00
docs Add MCP server for AI assistants and draft-only agent tokens 2026-10-07 19:29:57 +02:00
frontend Add MCP server for AI assistants and draft-only agent tokens 2026-10-07 19:29:57 +02:00
mcp-server Add MCP server for AI assistants and draft-only agent tokens 2026-10-07 19:29:57 +02:00
.env.example Add MCP server for AI assistants and draft-only agent tokens 2026-10-07 19:29:57 +02:00
.gitignore Initial version of Normwerk 2026-10-07 08:04:02 +02:00
AGENTS.md Add users, roles, single sign-on and audit trail 2026-10-07 10:20:04 +02:00
CLAUDE.md Initial version of Normwerk 2026-10-07 08:04:02 +02:00
CONTRIBUTING.md Initial version of Normwerk 2026-10-07 08:04:02 +02:00
docker-compose.prod.yml Add MCP server for AI assistants and draft-only agent tokens 2026-10-07 19:29:57 +02:00
docker-compose.sso.yml Add users, roles, single sign-on and audit trail 2026-10-07 10:20:04 +02:00
docker-compose.yml Add MCP server for AI assistants and draft-only agent tokens 2026-10-07 19:29:57 +02:00
GEMINI.md Initial version of Normwerk 2026-10-07 08:04:02 +02:00
LICENSE Initial version of Normwerk 2026-10-07 08:04:02 +02:00
README.md Add MCP server for AI assistants and draft-only agent tokens 2026-10-07 19:29:57 +02:00
SECURITY.md Initial version of Normwerk 2026-10-07 08:04:02 +02:00

Normwerk

Open-Source Compliance Management

Self-hostable, AI-assisted compliance management. ISO 37301 is the baseline; the Harmonized Structure (clauses 4–10) is modelled once and reused by extension packs such as ISO/IEC 27001, ISO 9001 and ISO 14001. A guided interview asks plain-language questions, saves every answer immediately and turns it into reviewable draft records.

Status: early foundation (v0.1). Not yet production-ready.

Process map with process analysis

Features

  • Guided AI interview in plain business language (English and German). Every answer is saved immediately; an LLM turns it into draft records you review and approve.
  • Process map with management, core and support processes, subprocesses, custom swimlanes on every level (e.g. business areas within core processes) and hand-overs. Risks, controls, documents and KPIs are linked to the processes they belong to, and weak spots are flagged live.
  • One management system, many standards. Each record (risk, control, policy, audit, …) exists once and is mapped to the requirements of every enabled standard.
  • Coverage and gap analysis per clause of the Harmonized Structure, with an applicability decision (and justification) per requirement as the basis for a Statement of Applicability.
  • Review schedule (Wiedervorlage): assignees, review intervals and deadlines on every record; a daily job sends in-app reminders and an e-mail digest before things are due.
  • Self-hosted and model-agnostic. Docker Compose, local models via Ollama/vLLM or cloud APIs (Anthropic, OpenAI) via LiteLLM.
  • Users, roles and single sign-on: invitations, four roles, OpenID Connect (Keycloak, Authentik, Entra ID, …) with group → role mapping, personal API tokens and a full audit log.
  • English and German UI, light and dark mode.

Screenshots

Overview Guided interview
Coverage per clause Guided interview
Subprocess map with swimlanes (dark mode) Management system records
Subprocess map Risk register form
Gap analysis German UI
Gap analysis Prozesslandkarte

Quick start

cp .env.example .env              # set DJANGO_SECRET_KEY and the LLM settings
docker compose up -d              # postgres (pgvector), valkey, backend, celery, frontend
docker compose logs backend | grep "Generated password"   # initial admin password
  • App: http://localhost:5173. Sign in as DJANGO_SUPERUSER_USERNAME (default admin). If DJANGO_SUPERUSER_PASSWORD is empty, a random password is generated on first start and printed once in the backend log. It only appears on the first start; if you missed it: docker compose exec backend python manage.py changepassword admin.
  • API docs (OpenAPI): http://localhost:8000/api/docs
  • Django admin: http://localhost:8000/admin

When the backend starts, it runs the migrations, compiles translations, creates the admin user and loads the standard catalogue and the interview question bank.

Production: see docs/deployment.md (docker-compose.prod.yml: gunicorn, nginx, no development servers or bind mounts).

Demo data: to explore the app with a sample company (processes, risks, controls, an interview):

docker compose exec backend python manage.py seed_demo --user admin --language en   # or: de

AI models

The platform talks to models through LiteLLM, so local and cloud models are configured the same way:

Setup .env
Local (Ollama) LLM_MODEL=ollama/llama3.1, LLM_API_BASE=http://ollama:11434, then docker compose --profile ollama up -d and docker compose exec ollama ollama pull llama3.1
Anthropic Claude LLM_MODEL=anthropic/claude-sonnet-5-5, ANTHROPIC_API_KEY=…, LLM_API_BASE=
OpenAI LLM_MODEL=openai/gpt-4o, OPENAI_API_KEY=…, LLM_API_BASE=
No AI LLM_MODEL= (answers are stored, nothing is extracted)

Semantic requirement matching needs an embedding model (EMBEDDING_MODEL, e.g. ollama/nomic-embed-text). After configuring it, run docker compose exec backend python manage.py index_requirements.

Data protection: with a cloud model, interview answers are sent to that provider. Check your data processing agreement (GDPR), or use a local model for confidential information. Model weights (e.g. Llama) come with their own licenses.

Users, roles and single sign-on

Role Can do
Owner everything, incl. members, invitations and SSO settings
Compliance officer create and edit records, approve them, view the audit log
Contributor create and edit records (drafts, in review)
Auditor read everything incl. the audit log, change nothing

Every change (create, update, approve, delete, sign-ins, member and token changes) is recorded in the audit log with the field-level differences (Settings → Audit log).

Single sign-on (OpenID Connect):

  1. Register a confidential client at your identity provider with the redirect URI <APP_BASE_URL>/oidc/callback/ and a groups claim in the user info.
  2. Set OIDC_RP_CLIENT_ID, OIDC_RP_CLIENT_SECRET and OIDC_DISCOVERY_URL in .env and restart the backend.
  3. Map identity-provider groups to roles under Settings → Single sign-on.

Accounts are linked by issuer and subject, not by e-mail. Set LOCAL_LOGIN_ENABLED=false for SSO-only operation (administrators keep local access as a fallback). To try it locally with a prepared Keycloak:

docker compose -f docker-compose.yml -f docker-compose.sso.yml up -d
# sign in with sso-alice / sso-alice-dev-pw (dev credentials only)

API tokens (My account → API tokens), for scripts and AI assistants:

curl -H "Authorization: Bearer nw_…" http://localhost:8000/api/organizations/

Tokens have one of three access modes: read-only (never changes data), AI assistant (may only create and edit drafts, marked as AI-generated; approving and everything else is refused by the server) and full access.

AI assistants (MCP)

Normwerk includes an MCP server, so assistants such as Claude can read your management system and propose drafts. It runs as its own container and is served at /mcp (Streamable HTTP); locally at http://localhost:8100/mcp.

  1. Create a token with access AI assistant under My account → API tokens.

  2. Add the server to your MCP client, e.g. Claude Code:

    claude mcp add --transport http normwerk https://normwerk.example.com/mcp \
      --header "Authorization: Bearer nw_…"
    

Tools: organizations, coverage overview, process map (per level), gaps, due reviews and deadlines, requirement search with applicability, record types and their fields, list/get records, and create/update draft records. The assistant acts as you: it sees only your organizations, and every change appears in the audit log as "AI via (API token: …)". Drafts are approved by people in Normwerk.

Architecture

backend/                Django 5 + Django Ninja, Celery + Valkey, PostgreSQL + pgvector
  apps/core             tenancy (Organization, Membership), ComplianceRecord base, audit trail,
                        auth API
  apps/accounts         invitations, API tokens, OIDC single sign-on, SSO group mappings
  apps/standards        Standard → Clause → StandardRequirement catalogue, pack activation
    data/*.json         standard packs (paraphrased requirement summaries, EN/DE)
  apps/compliance       unified HS models for clauses 4–10, process map, generated CRUD API,
                        coverage, gap analysis, requirement mapping, AI policy drafting
  apps/interviews       question bank, sessions, answers, AI extraction into draft records
    question_bank/      plain-language interview questions (EN/DE)
  apps/ai               LiteLLM gateway, embeddings, pgvector retrieval, prompt templates
  locale/de/            German translations (gettext)
frontend/               React + TypeScript + Vite, Tailwind CSS v4, shadcn/ui, TanStack Query,
                        Zustand, React Flow
  src/components/ui     shadcn primitives
  src/features/*        dashboard, process map, interview, records, gaps, standards

Key design rule: there are no per-standard models. Each HS concept, such as ComplianceRisk, exists once per organization. It is linked to the StandardRequirements it covers through a many-to-many relation, so a single risk register serves ISO 37301 and ISO 27001 at the same time.

Process map

Every record can be linked to the business processes it belongs to (processes). The process map (/processes) shows management, core and support processes and the hand-overs between them. Double-click a process (or use “Open subprocess map”) to drill into its subprocesses. Sub-maps have swimlanes you define yourself, for example departments or roles. Subprocesses can hand over to processes on other maps: those appear in an extra lane, and on the top-level map the hand-over is shown dashed between the parent processes. Evidence linked to a subprocess also counts for its parents.

The map flags weak spots live: no owner, no assessed risks, risks without controls, no KPI, outsourced without a partner record, or a core process with no hand-overs. From the map you can start a process interview that asks the risk, control, partner and KPI questions for that one process and links everything it creates to the process.

Interview flow

  1. POST /api/interviews/{org}/sessions starts a session, either for one HS clause or for one process (process_id). Early on, the organization interview asks for the main workflows and creates BusinessProcess drafts.
  2. Each answer is saved straight away (InterviewAnswer, status saved).
  3. A Celery task asks the LLM to extract structured records for the question's target model. The results are validated against the model and stored as draft records with ai_generated=True.
  4. Records are linked to requirements: deterministically through evidence_models in the pack data, and semantically through pgvector if embeddings are available.
  5. Gap analysis (POST /api/compliance/{org}/gaps/run) lists requirements of the enabled standards that have no evidence, or only draft evidence.

Development

docker compose exec backend pytest                        # backend tests
docker compose exec backend ruff check . && docker compose exec backend ruff format .
docker compose exec backend python manage.py makemigrations
docker compose exec backend python manage.py makemessages -l de   # after adding strings
cd frontend && npm install && npm run build && npm run lint

See AGENTS.md for architecture and conventions and CONTRIBUTING.md for how to contribute. Report security issues privately, see SECURITY.md.

Disclaimer

This project is not affiliated with, endorsed by or certified by the International Organization for Standardization (ISO). "ISO" and standard names are used only to describe compatibility. The platform does not contain the text of any ISO standard; requirement summaries are our own paraphrases. To implement or certify against a standard you need the official standard document. Using this software does not guarantee certification or legal compliance.

License

Copyright (C) 2026 Kevin Heyer and contributors.

Licensed under the GNU Affero General Public License v3.0 or later. If you run a modified version as a network service, you must offer its source code to its users (AGPL §13). Set VITE_SOURCE_CODE_URL to your repository so the link in the app points to it.