Report your AI system from your build with klaritiq.yml
If your AI system is built from a repository, you can keep one small file in it, klaritiq.yml, that says which model, prompt files and datasets the system uses. A step in your deploy workflow reads that file, tells KlaritiQ what it says together with the commit being deployed, and then asks whether that version is signed off. Nobody types a version number, and a prompt file that changes is noticed because its content is hashed.
This page is for the engineer who owns the deploy workflow. For what a version is and how sign-offs attach to it, see Which AI Version Did You Approve?.
What it reports, and what it does not
- It reports what the file says, plus the commit. The code part is the repository and the first 7 characters of the commit being deployed, read from the CI job.
- It detects nothing on its own. It does not scan your code, call a model provider, read a model registry or look inside a dataset.
- Files are hashed, text is taken as written. A prompt file or a data file named by path is hashed, so editing it records a new version. A model id or a dataset version written as text is only as true as the file. If the deployed model changes and klaritiq.yml does not, KlaritiQ will not know.
- It replaces only what it sends. Each push replaces only the parts it lists. Parts reported by other tools, such as a model registry, the vendor register or Microsoft Entra, are carried forward untouched, and a deploy never removes the parts the vendor register or Microsoft Entra report.
The manifest
Create klaritiq.yml at the root of the repository. Every key is optional except version.
[[code]] version: 1 # required
model: # optional id: claude-sonnet-4-5-20250929 # required if model is present: the exact model or deployment id provider: anthropic # optional; used as the part's name unless name is given name: credit-scorer-llm # optional; defaults to provider, then "model"
prompts: # optional: files, each hashed - prompts/system.md - prompts/triage.md
data: # optional: a name and a version, or a path to hash - name: loan-applications-training version: "2026-09-snapshot" - path: data/eval-set.csv # the name defaults to the path
vendors: # optional: a name and a version, both text - name: Example Bureau version: contract 2026-04 [[/code]]
What each key becomes
| In the file | Part in KlaritiQ | Name | Version |
|---|---|---|---|
| (the CI job) | Code | The repository | First 7 characters of the commit |
| model | Model | name, else provider, else "model" | The id you wrote |
| prompts | Prompt, one per file | The file path | sha256: and the first 12 characters of the file's hash |
| data with a version | Data | The name you wrote | The version you wrote |
| data with a path | Data | The name, or the path | sha256: and the first 12 characters of the file's hash |
| vendors | Vendor | The name you wrote | The version you wrote |
The manifest can report Code, Model, Prompt, Data and Vendor. Configuration and Permissions are not in it. A manifest with only version: 1 reports the code alone. Each part also records where it came from, shown in the AI system card as the repository manifest.
Rules, all checked before anything is sent
- version: 1 is required. A key the format does not know is an error that lists the keys it does.
- Paths are relative to the manifest and must stay inside the repository. A prompt or data file that is a link (a symlink, or a file in a linked folder) is followed only when the real file is still inside the manifest's folder. A link that resolves anywhere else is refused, so nothing outside the repository is read.
- At most 20 entries in each list, 64 KB for the manifest, 50 MB for each hashed file, and 120 characters for each name or version.
- At most 40 parts in a version altogether, the code included.
- The same name twice under one part is an error.
- Every value is read as text. Lists or maps written on one line, anchors, multi-line strings and several documents in one file are refused with the line number. A klaritiq.json with the same keys is accepted too.
If the file is wrong, nothing is sent and the step stops with a message that names the line.
Set it up
- On the initiative's Governance tab, click Sources on the AI system card. Under Add a source, choose the part, choose Repository manifest (klaritiq.yml), name the key and click Create key. Copy the key straight away: it is shown once.
- Store it in your CI as a secret named KLARITIQ_PIPELINE_KEY. Prefer a secret of a protected environment (in GitHub: Settings, Environments) whose deployment branches are limited to your default branch, rather than a secret every workflow in the repository can read. If you limited the key to some parts, also set KLARITIQ_KINDS to the same parts, for example model or code,prompt, so the step reports only those.
- Add the reporting step to your deploy workflow. The step is one script, record.mjs, which needs Node 18 or later and nothing else. The examples below assume you keep it at tools/klaritiq-record/record.mjs in your repository.
- Run it once with --dry-run, which prints the request and sends nothing, to see what would be reported.
The key is read from the environment only. The script does not accept it as a command-line flag and never prints it.
GitHub Actions
[[code]] on: release: types: [published] workflow_dispatch:
jobs: record: runs-on: ubuntu-latest # environment: your-protected-environment # the environment that holds the key steps: - uses: actions/checkout@v4 with: persist-credentials: false - name: Report klaritiq.yml to KlaritiQ run: node tools/klaritiq-record/record.mjs env: KLARITIQ_PIPELINE_KEY: \${{ secrets.KLARITIQ_PIPELINE_KEY }} # KLARITIQ_KINDS: model,prompt # for a key limited to some parts [[/code]]
The script also ships as a composite action, .github/actions/klaritiq-record, which takes key, manifest, kinds, note, release-check and dry-run as inputs and gives version, unchanged and approved as outputs. It runs the same script.
Recording on deployments safely
GitHub's deployment events fire for every deployment, including preview deployments a hosting service creates for pull requests, some from forks, and for staging branches. Reporting those would present unreleased code as the live version, with your key. The example workflow, klaritiq-record-version.yml, is therefore deliberately narrow:
- It records on a deployment only when the repository variable KLARITIQ_RECORD_ENABLED is true, the deployment succeeded, and its environment is production. To use another environment name, set the repository variable KLARITIQ_RECORD_ENVIRONMENT.
- For a deployment it checks out your default branch and runs the script from there, never from the deployed commit.
- It refuses the deployment unless the deployed commit is already part of the default branch's history. Only then does it read that commit's klaritiq.yml and listed files, as data.
- Where the key lives matters most. GitHub reads the workflow file from the deployed commit, so a file cannot protect itself. Keep the key as a secret of a protected environment limited to the default branch, and name that environment in the job.
GitLab CI
klaritiq-record:
stage: deploy
image: node:20-alpine
rules:
- if: $CI_COMMIT_TAG
script:
- node tools/klaritiq-record/record.mjsAdd KLARITIQ_PIPELINE_KEY under Settings, CI/CD, Variables, and mark it Masked. The script reads the repository and commit from GitLab and reports the code with its origin as GitLab. GitLab has no GitHub source, so no commit link is attached.
Any other CI, or a shell
export KLARITIQ_PIPELINE_KEY="..." # from your CI's secret store, never written in a file
export KLARITIQ_REPOSITORY="your-repo" # needed outside GitHub Actions and GitLab CI
export KLARITIQ_COMMIT="$(git rev-parse HEAD)"
node tools/klaritiq-record/record.mjsOptions
| Flag | Environment | Default |
|---|---|---|
| --manifest | KLARITIQ_MANIFEST | klaritiq.yml, klaritiq.yaml or klaritiq.json in the working directory |
| --url | KLARITIQ_URL | https://klaritiq.in |
| --kinds | KLARITIQ_KINDS | Every part the manifest lists, plus the code |
| --note | KLARITIQ_NOTE | A note naming the CI and the manifest |
| --dry-run | KLARITIQ_DRY_RUN=true | Off |
| --no-release-check | KLARITIQ_RELEASE_CHECK=false | The check runs |
What the step does, and its exit codes
The step reads the manifest, records the version, and then asks KlaritiQ the same yes-or-no question as the release check: is the current version signed off? It fails the job when the answer is not a clear yes. An unreachable check, an error, or a page that is not KlaritiQ's answer fails the job too: it never reads as approved.
| Exit code | Meaning |
|---|---|
| 0 | Recorded, or nothing changed, and the version is signed off. Also when the check was skipped on purpose. |
| 1 | Recorded, but the version is not signed off. |
| 2 | The manifest or the options are wrong. Nothing was sent. |
| 3 | KlaritiQ did not record the version: unreachable, a refused key, a rejected push or an unexpected answer. |
| 4 | The release check could not be read. |
If nothing in the manifest or the commit has changed since the last run, nothing new is recorded and the answer says the version is still current.
Vendors in the manifest and the vendor register
If KlaritiQ's vendor register already reports this system's vendors (see Which AI Version Did You Approve?), you do not need vendors in the manifest. A push from the manifest does not remove the vendors the register reports. To drop a register vendor, unlink it in the register. A vendor in the manifest with the same name as a register vendor takes that part over, and vendors the register does not know are reported as written. Near the limit of 40 parts a deploy may be recorded without some register or Entra parts, and its change note names what was left out, starting "Not carried forward (limit of 40 parts)". Keep one source for each vendor, so it is clear where its version comes from.
Tips
- Pin line endings. A hash is of the exact bytes, so a runner that checks files out with Windows line endings hashes a prompt differently. Pin them for listed files in .gitattributes, for example prompts/** text eol=lf.
- Limited keys. A key limited to some parts can only report those. Asking it for another part is refused and nothing is recorded.
- Sign-offs. A new version that changes a part someone approved means that approval must be reviewed again. The step reports; it never signs anything off.
What this does not do
- It does not notice a change the file does not show. Only listed prompt and data files are hashed; a model id or a dataset version is taken as written.
- It does not check that a model id or a version you typed is true.
- It does not report Configuration or Permissions.
- It does not replace the sign-off. A person still reviews the version and signs.
Was this article helpful?
Community Questions (0)
No questions yet. Be the first to ask!
Still have questions?
Contact support
