Documentation / Quality and governance
Quality contract
Quality rules live in a versioned file in the repository, not in the prompt, and apply equally to people and agents.
The quality contract is your project's .ai/contract.json file. It defines how much rigor the team requires: measurement thresholds, coverage, complexity, change size, protected paths and waivers.
It is applied by the engine gate, Git hooks, CI and agents. The result doesn't depend on who writes the code: a person, Yuli, Claude Code, Codex, Kiro or Antigravity.
If the file doesn't exist or isn't valid, Yuli uses the defaults (Business criticality). Every field is optional, so a partial contract also works.
Where to edit it
Open the Governance Center (right rail → More tools, or the command palette with Open the Governance Center) and go to the Contract tab.
When you save with Save and sign, Yuli records the change with your git config user.name. You can see every change in Contract history.
Criticality
Criticality selects a complete threshold profile. There are four levels:
| Value in the file | Label in Yuli | When to use it |
|---|---|---|
low |
Low | Prototypes, internal tools, experiments. |
business |
Business | Business applications. This is the default. |
regulated |
Regulated | Systems subject to audit or regulation. |
safety |
Safety-critical | Software where a failure has serious consequences. |
Profiles
| Threshold | Low | Business | Regulated | Safety-critical |
|---|---|---|---|---|
| Acceptance score | 80 | 90 | 92 | 95 |
| Measurement rounds | 2 | 3 | 4 | 5 |
| Minimum coverage | 50 % | 70 % | 80 % | 90 % |
| Max. cognitive complexity | 20 | 15 | 15 | 10 |
| Max. cyclomatic complexity | 15 | 10 | 10 | 8 |
| Minimum mutation score | 0 % | 0 % | 60 % | 75 % |
| Files per change | 60 | 40 | 25 | 15 |
| Lines per change | 2000 | 1000 | 600 | 400 |
| Independent review | No | No | Yes | Yes |
| Block test tampering | No | Yes | Yes | Yes |
| Strict enforcement | No | No | Yes | Yes |
You can override a specific threshold in gates. Only that field changes; the rest still comes from the profile. Block test tampering and Strict enforcement depend only on criticality and can't be overridden.
The contract's acceptance score and rounds override the local settings of the Measurement phase.
File structure
{
"schemaVersion": 1,
"criticality": "business",
"gates": { "minCoverage": 75, "maxCyclomatic": null },
"changeLimits": { "maxFiles": 40, "maxLines": 1000 },
"protectedPaths": ["db/migrations/**"],
"waivers": []
}
| Field | What it defines |
|---|---|
criticality |
low, business, regulated or safety. |
gates |
acceptanceScore, maxMeasureRounds, minCoverage, maxCognitive, maxCyclomatic, requireIndependentReview, minMutationScore. null takes the profile value. |
changeLimits |
maxFiles and maxLines per change. |
protectedPaths |
Extra globs, added to the default protected paths. |
waivers |
Waivers with an expiry date. |
architecture |
Layers (layers with name, paths, mayDependOn) and forbidCycles. |
slos |
Service objectives: latencyP95Ms, availability or errorRate. |
licensePolicy |
Allowed (allow) and forbidden (deny) licenses, by SPDX or by family, such as strong-copyleft. |
reviewer |
Independent reviewer: requireOtherFamily, provider, model. |
dataClassification |
Data patterns with their level: public, internal, confidential or restricted. |
finops |
Monthly budget per service and its owner. |
Change limits
The size of a change is measured with git diff --numstat. Lock files (package-lock.json, yarn.lock, Cargo.lock, go.sum and similar) count as files, but their lines don't.
Exceeding the limit blocks with strict enforcement (Regulated and Safety-critical). In the other profiles it's a warning.
Protected paths
An agent can't edit these files, even if asked to:
.ai/contract.json,.ai/quality.jsonand.ai/state/**.claude/settings.jsonand.claude/settings.local.json.githooks/**.github/workflows/**,.gitlab-ci.ymlandJenkinsfileCODEOWNERSand.github/CODEOWNERS
Matching is case-insensitive. Add your own paths in protectedPaths. A change to the contract saved from Yuli is recorded in the audit log and counts as approved.
Waivers
A waiver lets you skip a rule temporarily and with justification.
| Field | Contents |
|---|---|
id |
Waiver identifier. |
rule |
Rule being waived: secrets, protectedPaths, testIntegrity, a specific cheating type or *. |
path |
Glob it applies to. Empty means any path. |
reason |
Reason. |
approvedBy |
Who approved it. |
expires |
Expiry date, YYYY-MM-DD. |
ticket |
Optional reference. |
A waiver is valid through the expires date, inclusive. A missing or malformed date counts as expired. Once it expires, the rule applies again and the gate warns you.
In the interface, each waiver shows its status: Active, Expires soon, Expired or Invalid date.
testIntegrity waives every test-cheating detection at once. Use it with a narrow path and a near date.
Audit
Every save appends a line to .ai/state/contract-audit.jsonl with the date, the author, the SHA-256 hash and a summary (for example, “criticality business→regulated; waivers +1”).
The author is always a person: the name provided or your git config user.name. “Yuli” and “Yuli Code” are rejected as authors.
Next step
- Measuring against N−1: how the acceptance score and rounds are applied.
- Gate and Governance Center: how the contract is enforced on every commit.