Noru

Developers

One API key,the whole compliance record.

A documented REST API, an MCP endpoint your agents can already speak to, and manifests you push from CI. Everything the Noru app reads and writes is open to your own code — scoped to exactly what you grant it.

api.noru.techOpenAPI 3.1/v1/mcp

REST API

Documented, versioned, scope-limited.

The same organization-scoped data the app runs on. Read the spec, generate a client in whatever language you work in, and hold a key that can only do the things you granted it.

Base URL
https://api.noru.tech
Specification
OpenAPI 3.1 at /openapi, rendered as a browsable reference at the base URL.
For agents
The whole specification as Markdown at /llms.txt — point a coding agent at it and it can write the client itself.
Authentication
Authorization: Bearer noru_…
Keys
Organization-scoped, scope-limited, revocable, optionally expiring. Created under Settings → Developer.
Scopes
Twelve read scopes and eleven write ones. A call outside the key's grant returns 403 FORBIDDEN — it does not silently return less.
Versioning
Resources live under /v1 and /v2.
Pagination
limit of 1–100 (default 50) and offset, answered with { total, limit, offset }.
Errors
One envelope on every 4xx and 5xx: a machine-readable code and a human-readable message.
Rate limit
500 requests per 10 minutes per key, with X-RateLimit-Limit, -Remaining and -Reset on every response.

Ownership is principal-based: point at a user or a personnel record and Noru resolves the link. Discover valid principals with GET /v1/ownership-principals.

curl -X POST https://api.noru.tech/v1/risks \  -H "Authorization: Bearer $NORU_API_KEY" \  -H "Content-Type: application/json" \  -d '{    "title": "Unpatched critical vulnerabilities",    "description": "Critical CVEs on internet-facing hosts.",    "status": "identified",    "category": "technical",    "likelihood": "possible",    "impact": "major",    "owner": { "type": "personnel", "refId": "person_123" }  }'

Model Context Protocol

One endpoint your agents already know how to speak to.

The same organization-scoped data over MCP, at a single streamable HTTP endpoint. The tool surface is filtered by the scopes on the credential, so an agent can only reach what the key it was handed can reach.

Endpoint
https://api.noru.tech/v1/mcp
Transport
Streamable HTTP — JSON-RPC over POST, SSE over GET.
Authentication
The same bearer API key, or OAuth 2.1 with PKCE for clients that prefer to run a consent flow.
Discovery
Protected-resource metadata (RFC 9728), authorization-server metadata (RFC 8414) and dynamic client registration (RFC 7591), so a compliant client can connect with nothing but the URL.
Surface
Scope-filtered tools across controls, policies, risks, evidence, vendors, personnel, assets and the privacy data map — plus MCP resources and prompts.
A deliberate omission
Evidence file upload stays on REST. Tool arguments are JSON and cannot carry a multipart body, so pretending otherwise would only fail later.

One line, no local server to run and nothing to install. Cursor, ChatGPT, Copilot, Raycast and the rest take the same URL.

claude mcp add --transport http noru https://api.noru.tech/v1/mcp \  --header "Authorization: Bearer $NORU_API_KEY"
Per-client setup guides

In your pipeline

Push it from the job that produced it.

Manifests and artifacts land from the pipeline that made them, carrying the repository, commit and branch that vouch for them. Re-running the job does not create a second copy.

Idempotent
Assets and security findings upsert on source plus externalId — 201 the first time, 200 every time after. A retried job is not a duplicate.
Provenance
Data-map pushes carry slug, commitSha and branch. An unchanged manifest is recorded as a no-op rather than rewritten.
Verified in transit
Send the SHA-256 you computed as expectedDigest and a substituted or truncated upload is rejected with 400 before anything is stored — it never becomes evidence that merely looks valid.
Least privilege
The checks run with no credential at all. Only the job that lands the result gets a key, and it needs write:datamaps, or write:evidence, and nothing else — it cannot read the rest of the record.

The privacy-datamap piece reads your schemas and classifies what it recognises; a person resolves the rest and signs for it in the committed manifest, and an unresolved claim blocks the push. The checks need no credential and no network, so they are safe on a fork's pull request; only the job that writes gets a key, behind an environment gate.

name: complianceon:  pull_request:  push:    branches: [main]permissions:  contents: readjobs:  check:    runs-on: ubuntu-latest    steps:      - uses: actions/checkout@v4      - uses: actions/setup-node@v4        with:          node-version: "20"      # scan, validate, expiry, policy — the default steps, no credential      - uses: noru-tech/noru-grc-engineering/.github/actions/noru-ci@v0.4.0        with:          piece: privacy-datamap          mode: gate  land:    if: github.event_name == 'push'    needs: check    runs-on: ubuntu-latest    environment: compliance    steps:      - uses: actions/checkout@v4      - uses: actions/setup-node@v4        with:          node-version: "20"      - uses: noru-tech/noru-grc-engineering/.github/actions/noru-ci@v0.4.0        env:          NORU_API_KEY: ${{ secrets.NORU_API_KEY }}        with:          piece: privacy-datamap          mode: gate          steps: all          state: .noru/.cache/noru-state.json

Open source

The last mile runs where the work lives.

Some compliance work cannot be done from a server. It needs the repository, the pipeline, the laptop, or a person willing to say what they concluded and why. That is what the noru-grc-engineering pieces do — MIT licensed, running where the work lives, while Noru still holds the record.

Three commands
:scan collects locally into a committed .noru/<piece>.yml, :diff shows what would change without writing anything, :push lands it once. Reviewing the manifest in a pull request is the point.
Every claim is attributed
An interpretation block carries the owner, when they decided, when it expires and why — with file and line references. An unattributed claim is a validator error, not a warning.
Never a second register
A piece is an input to Noru and a record of provenance. There is no local risk register to reconcile before an audit.
Runs in CI
The same pieces run headless behind the shipped action — warning on drift or gating the build on it, with documented exit codes. That is the workflow above.
Barely handles a credential
In an editor the pieces delegate authentication to the MCP host and hold nothing themselves. Headless there is no host to delegate to, so the step that writes reads a key at the point of use — and only that step.

Installed as a plugin into Claude Code or Codex, then run in the repository you want covered.

/plugin marketplace add noru-tech/noru-grc-engineering/plugin install ai-inventory@noru-grc-engineering/ai-inventory:scan   # collect locally into .noru/ai-inventory.yml/ai-inventory:diff   # show what would change in Noru; writes nothing/ai-inventory:push   # land it, once, with provenance

Nine pieces, MIT licensed

  • ai-inventoryModel calls, agents, prompts and evals, found in the repo
  • evidence-pushLocal artifacts pushed against unmet evidence expectations
  • privacy-datamapSchema and personal-data categories mapped from source
  • iac-scanInfrastructure and pipeline configuration, read in place
  • change-controlSegregation of duties, proven from the change history
  • governance-recordsMeeting minutes, audit plans and decisions, recorded
  • review-signoffHuman attestation captured against machine output
  • audit-packArtifacts and workpapers bundled for one framework
  • noruThe hub — connect, doctor and context for every piece
Browse the pieces on GitHub

Trust, settled.

Every control, risk and artifact behind one documented API — and the last mile running where your work already lives.