record
The record commands send a security assessment from your machine to your
organization’s platform, so the threats a change introduced, what the team decided
about them, and whether the change was verified all end up in one place.
The assessment itself is produced by the ingrain-security
skill, which writes it to .ingrain-security/assessment-<branch>-<task>.md. The
skill knows nothing about the wire contract — this command is the only place that
does.
ingrain record design --assessment <path>ingrain record verification --assessment <path>One file, one flag. The org rules the review retrieved ride in the assessment’s
own ## Org rules section, so there is no second path to pass. (A --rules sidecar
was once required alongside; it is gone, and so is the failure it created — omitting
it produced a sync that silently recorded no rule at all.)
Two stages, two commands
Section titled “Two stages, two commands”They are deliberately not one call. They fire at different moments, carry different data, and fail differently — and either can happen without the other.
record design | record verification | |
|---|---|---|
| Fires at | design-time finalize, after the selection gates | verification finalize, after the code is written and judged |
| Carries | threats with their gate decisions, the gated org-rule set, risk, and the implementation guidance with the drivers each entry names | a robustness verdict per selected threat, an adherence verdict per selected rule |
| Targets | a new assessment revision for this unit of work | a new verification record bound to the revision it judged |
| Re-run | supersedes the prior revision; history is kept | supersedes the prior verdict set; the analysis is untouched |
| Alone? | yes — an unverified analysis is the normal mid-flight state | only against an existing revision |
design
Section titled “design”Sends the analysis as a new assessment revision.
ingrain record design \ --assessment .ingrain-security/assessment-feature-auth-add-rotation.mdWhat a design sync carries
Section titled “What a design sync carries”Two driver axes and one vessel between them.
- Threats, each with the decision made at the threat gate: act on it, or accept the risk. Excluded threats travel too — “we saw it and chose not to act” is exactly what a security record should preserve.
- Org rules, each with the decision made at the rule gate: it governs this change, or it was deemed inapplicable here. Both halves travel, for the same reason: an exclusion is a recorded decision the rule’s author gets to see, and filtering it out would make developer-side scoping silent.
- Implementation guidance — how a driver’s goal is reached. It carries no decision and no verdict of its own; its efficacy is read off the drivers beside it.
Every guidance entry names at least one driver — a threat it closes, a rule it implements, or both. Work that traces to no stated goal cannot be attributed, verified or governed, so an unanchored entry is refused rather than synced. One entry may serve several threats and several rules at once, and travels once naming them all.
A Rule refs id may only name a rule the gate accepted. Driving a rule that was
excluded, or one never gated, claims a mandate nobody granted — and the rule would be
unjudgeable at verification, where scope is the accepted set. Both are refused.
A change triaged as not security-relevant is recorded as such, and never replaces an assessment that already exists — the command skips the push and says so rather than overwriting a real analysis with an empty one.
verification
Section titled “verification”Sends the verdicts against the revision they judged.
ingrain record verification \ --assessment .ingrain-security/assessment-feature-auth-add-rotation.mdRequires a design sync to have run first: a verdict with no analysis to describe
is meaningless, so with no revision recorded this fails with a message telling you
to run record design rather than inventing one.
A verification has exactly two subjects: the threat and the rule. A robustness verdict per threat the threat gate selected, and an adherence verdict per rule the rule gate accepted — including a rule no guidance ended up implementing, which is precisely the case a security owner needs judged. A rule that was excluded is left unjudged: deemed inapplicable is a recorded decision, never a verdict.
Guidance is never a subject, so nothing is sent about it.
A partial verdict set is accepted. One verdict per accepted rule is the review’s own procedure, not a wire requirement — rejecting a mid-run pass would lose the verdicts it did conclude, and the platform reads an unjudged rule as exactly that.
How a task is identified
Section titled “How a task is identified”A unit of work is repository + branch + task title, normalised to a sync key:
<repository>/<branch>/<task>The repository comes from your git remote, the branch from git, and the task from
the assessment’s ## Task → Title. Each segment is lowercased and reduced to
[a-z0-9-], so Feature/Design_Sync and feature-design-sync name the same
branch — two developers working one branch converge on one record, which is the
intent.
If someone else records an assessment for the same unit of work while yours is syncing, the platform rejects the stale handle. The CLI re-pulls and retries once, then stops with a message naming the situation.
Configuration
Section titled “Configuration”record reads the same [context] section as context:
[context]syncUrl = "https://api.example.com/ingrain-agent-sync"ingrainApiToken = "ingrn_…"or INGRAIN_SYNC_URL / INGRAIN_API_TOKEN.
That section is resolved from your user-level conf.toml and the
environment — those two, wherever you run the command from. The environment is
trusted by design; see
Configuration overview for what that means.
Exit codes
Section titled “Exit codes”| Code | Meaning |
|---|---|
0 | Synced. |
1 | The assessment did not validate, or the sync failed. |
2 | Bad arguments — a missing --assessment, a retired flag, or a file that is not there. |
To see what is wrong with a file without needing credentials or a network, use
ingrain validate. It runs the same parser and the same
schemas, so a file it accepts is a file record will send.