Recording a decision in the AI register
Working in the console
What a decision is, what an approval can carry, and what breaks one.
The register shows what AI tools are in use. A decision records what your organisation concluded about one: approved, not approved, or under review, with an owner and a date to revisit it.
You record decisions in the portal: every register card has an edit control, the wizard offers a baseline pass over the common tools, and each write is stamped into the audit trail with who made it. A YAML file in your repository is still a first-class way to keep them, reviewed the way the rest of your configuration is, and the two work together - a decision recorded in the portal wins, the file fills the gaps. This page covers the rules both share, then the file format.
Recording nothing is fine. Without any decisions the portal falls back to the registry's own approved flag, every tool reads as undecided, and the owner and review columns show as not set. Nothing else changes.
Why governance is separate from the registry
The registry answers what is this tool and how do I detect it. It ships with Nyxus, and it is the same for everyone.
Governance answers what did we decide about it. That is yours, and it is nobody else's to ship: an upstream project has no business implying that Claude is approved or that Engineering owns ChatGPT.
The separation is also physical. Approval used to be compiled into extension.json and scanner.json and sent to detectors that never read it. A browser extension has no use for your approval decisions, and now does not receive them.
Approval is not safety
Approval records a governance position. It does not change finding severity.
Severity is decided by the reporter at the point of detection and depends on the account domain. A personal account is a warn on any surface. The presence of a tool is info. Neither changes because you approved something.
So both of these are correct and normal:
The second is still the thing to act on, because the risky part is the account, not the tool. Approval must never quietly come to mean safe.
The file
The portal needs no file; everything below applies to it too, enforced on the write path. The file is for anyone who would rather their decisions went through the review their configuration already has:
Start from governance/governance.yaml.example, which has a worked entry for each state.
Fields
field | required | notes |
|---|---|---|
| yes |
|
| on |
|
| no | A team or a person. Not resolved against anything |
| no | Free text, shown with the decision |
review_due is required on an approval and not on a refusal because that is where the risk is. An approval with no expiry is the one that outlives the person who made it and the reason it was made. A decision not to use something does not rot in the same way.
Three states, not five
Restricted, Deprecated and Exception approved are all defensible, and none of them is needed to find out whether this model is useful. Start with three.
Expiry
An approval past its review_due reports as reviewing, with the reason and the previous decision alongside:
The record itself is never rewritten. A clock ticking over is not a decision, and the history has to keep saying what a human decided on a date. The stored status stays approved; only the derived status moves.
This is the same rule the platform already applies to detection sources. A collector that has stopped reporting is not evidence a machine is clean, and an approval nobody has revisited in eighteen months is not evidence a tool is safe. It is evidence that nobody looked.
Expiry is evaluated when the page is rendered. There is no job to run and no window where the stored value is right and the display is stale.
Tool ids
Keys are tool ids as they appear in the registry. They are also governance subjects, which is not quite the same thing: you can record a decision about a tool the registry has never heard of. That is deliberate, because the tool most urgently in need of a decision is often the one the register has just flagged as observed and not registered.
A decision naming an id the registry does not know is shown, not dropped:
Usually that is a typo. Occasionally it is an upstream rename that has quietly un-made an approval you recorded. Both look identical from here, and both need saying out loud: a decision that silently matches nothing is how an organisation believes it has decided something it has not.
Treat tool ids as stable keys for this reason. Display names and metadata can change; an id is what a decision is attached to.
Exceptions
A temporary departure from the general decision, for a stated scope and period.
Keyed on its own id, not on the tool. A tool can have more than one, for different teams or different reasons, and keying on the tool would allow exactly one and would discard the previous the moment a second was written. An exception is also a record with its own life: raised, applying, expired, and still visible afterwards.
It sits beside the decision, not in place of it
The register shows both. ollama reads as not approved with the Research exception underneath, because the general position has not been withdrawn. Showing the exception as the status would make a note about one team read as a decision about everybody.
expires is required
Unlike review_due on a decision, which is required only on an approval. A departure from the general position with no end is not an exception, it is an undocumented change of policy.
When it expires it simply stops applying. The underlying status is already what it was, so nothing becomes reviewing: that is the expired-approval rule, and applying it here would put a tool under review because a campaign finished.
Expired exceptions stay visible, quieter. One that has run its course is a record of something an organisation decided and then let lapse, which is worth seeing rather than losing.
scope
In the file, free-form keys such as team or project. The portal displays them and does not resolve them against anything. An exception granted in the portal is different: see below.
Fields
field | required | notes |
|---|---|---|
| yes | An id the registry does not know validates and is reported, same as a decision |
| yes |
|
| no | Free-form keys, displayed not enforced |
| no | Free text |
| no | A team or a person |
Exceptions granted in the portal
Governance > Exceptions, or the Exceptions section of a tool's record, grants one without editing a file. It is kept by the receiver, beside the file's exceptions, and differs from them in three ways:
Its scope is resolved. It names teams and people, not free text, and a person it names or a person a named team covers is not counted against the approval's conditions (below). At least one team or person is required.
It records who granted it, and when. Changing or revoking it is in the audit trail.
It can be revoked. An exception from the file is removed by editing the file; one granted in the portal has a Revoke button, and asks first.
expires is required in both, for the same reason. Deleting a team takes it off every exception that named it.
Conditions on an approval
An approval can say what it is for. Each condition narrows it; an approval with none is approved for everyone, as before.
Condition | Broken when |
|---|---|
Teams | Someone outside the approved teams uses the tool, and no active exception covers them or their team. Devices with no person attached are counted separately, not guessed at |
Seats | More people use the tool than the approval allows |
Work accounts only | Anyone uses it through a personal account |
Surfaces | It is used on a surface the approval does not include: web, desktop app, command line, IDE or MCP. Network and cloud are how use is seen, not a way of using a tool, so they never break this |
Conditions are recorded only on an approval; recording any other status clears them. They are checked when the register is read, over the reporting window, like expiry, and only for the organisation-wide view: a team's slice of the estate cannot say whether an approval for other teams is being kept.
A broken condition shows on the register as Conditions broken, in one notice on the tool's record listing each one, and in the review queue as a finding (remediation). Owners and admins are told once when it starts.
To let another team use a tool approved for one team, edit the conditions for a permanent change, or grant an exception with an end date for a temporary one.
Rules
A rule keeps checking the register. When every clause of a rule matches a tool, its actions apply. Governance > Rules builds them from a fixed vocabulary:
Field | Operators |
|---|---|
In the registry | is |
Category, risk tier | is, is not |
Vendor | is, contains |
Devices, people, personal accounts | at least, at most |
Surface | includes, excludes |
Decision (none, approved, reviewing, not approved) | is, is not |
Agents running on their own, agents nobody answers for | at least |
Conditions broken | is |
One to ten clauses, all of which must match. Actions, at least one:
Treat the tool as reviewing, or as not approved. Only where nobody has recorded a decision: a rule fills a gap and never overrides a person. Where two rules disagree, not approved wins. The register says the status was set by a rule, and names it; nothing is written to the decision record.
Raise a finding. The tool joins the review queue, where it can be given an owner and a due date.
Tell owners and admins. Once, when the rule starts matching a tool, by email and the webhook. A tool that stops matching and later matches again is told again.
The editor shows which tools a rule would match before it is saved. Turning a rule off stops it applying without deleting it.
Across companies
Where one deployment serves several companies, the company hosting it can set a baseline for all of them.
A decision for every company applies in each company that has not recorded its own decision on the tool. A company's own decision always wins, and removing it brings the shared one back. A shared approval cannot name teams, because each company has its own. Record one from a tool's register entry with Record it for every company.
A rule for every company runs in every company's register. Any company can turn it off for itself. Only the hosting company can edit it, turn it off for every company, or delete it.
Both are marked Every company in the register and on Governance > Rules. A company's own accounts can read them but cannot change them.
The governance file is read for every company too. A decision recorded in the portal, whether for one company or for all of them, wins over the file.
Validating
Exits non-zero on a schema error. Warns without failing on an id the registry does not know, and on an approval with no owner.
Write dates however you like. YAML parses a bare 2026-11-01 as a date rather than a string, and the validator normalises it, so quoting is optional rather than a trap.
Deploying
Kubernetes
Compose
Mount the file and point GOVERNANCE_PATH at it. The compose file supplied with your subscription has the mount commented out with a worked example beside it; uncomment both and restart.
The audit trail
A file has no write path. Decisions are edited in it, and it goes through whatever review your repository already has.
That is not a limitation to be apologised for. A merge request is signed, timestamped, reviewable, and carries a diff of exactly what changed and who approved the change. Most governance portals build something weaker and call it an audit log.
This document used to end: if, after living with it, the recurring thought is "I wish I could change this in the portal", that is evidence for a write path. That thought is now built: the register's cards carry an edit control, and the file is the other way of doing the same thing rather than the only one. A decision made there - status, owner, review date, reason - is held centrally in the receiver's state DB, every write is stamped with who and when in the receiver's event log, and the same rules the file's validator enforces apply on the write path - an approval without a review date is refused there too.
The two coexist per tool: a portal-recorded decision wins, the file fills the gaps, and the register labels which kind of decision it is showing ("set in the portal"). Exceptions - scoped, expiring departures - come from both as well: the file's, and those granted from a tool's entry in the register. The file stays first-class either way, so the argument above still holds for a deployment that would rather keep its decisions in a repository.