Skip to content

Session note schema

Stored under refs/notes/gitvow/<session-id> (gitvow 0.1 used the single ref refs/notes/sessions). First line gitvow-session, then JSON:

Field Type Meaning
session_id string the session id the agent assigns to the conversation
step int commit number within the session
committed_at string local time the note was written
assistant_turns_so_far int assistant messages in the transcript at commit time
tool_calls_so_far int tool invocations at commit time
tools_used string[] distinct tool names
last_stated_plan string last assistant text before the commit, redacted, at most 600 characters; read from Claude Code, Codex and Gemini CLI transcripts, empty for Cursor
files_in_commit string[] git show --stat lines, at most 50
files_written_by_agent_this_session string[] files in the commit that the agent edited or wrote via tools in this session
attribution object see below
usage object tokens by kind, models seen, estimated_cost_usd, pricing table used; see What each session cost
subagents object count and tool_calls of side conversations in the session
snapshot string or null the last snapshot ref taken before this commit, e.g. refs/gitvow/snapshots/<session>/7
decisions object[] the findings this commit carried and how they were answered; see below
intent object or null schema 8: what the task was for, in the person's words: text (redacted, at most 200 characters), by, source (stated from gitvow intent, prompt from the first message of the session), set_at, session_id, step; see State the intent
schema int note schema version, currently 9
transcript string always "kept local; see ledger"
redaction string statement of what redaction ran

attribution

Field Type Meaning
files_in_commit int files changed by the commit
touched_by_agent int of those, files the agent wrote or edited this session
lines_added_in_commit int sum of added lines over all files
lines_changed_by_human_after_agent int lines added or removed by a person after the agent's last write, over agent-touched files
agent_share float or null share of added lines that match the agent's version; null when the commit adds no lines or no agent-written blob was recorded
files[] object[] per file: path, agent_wrote, lines_added_in_commit, human_lines_added, human_lines_removed, agent_blob, committed_blob

decisions[]

Field Type Meaning
finding string the finding as it appears in the trailer, e.g. route /v1/x in src/api.py
kind string edit, route, route-removal, gate-file
subject string the path or route
path string the file the finding came from
reason string the rule's reason or the provider's summary
evidence string[] provider evidence, redacted, at most 8 lines
raised int how many tool calls raised the same finding in the session
answer string accepted, declined, referred, open, or observed (schema 7: an observe-tier rule recorded it and nobody was asked)
by string or null committer identity used in the trailer: email local part or name
authority string policy (named in decisions.authorities), commit-access (no list configured), none
scope string or null environment or branch the answer is limited to. A scoped answer is an exception, so it never counts towards a proposed rule
to string or null with answer: referred, who the question should go to; null when the person did not name anyone (schema 6)
note string or null the person's reason, redacted
decided_at string or null local time the answer was recorded
human_turns_after_card int or null user messages in the transcript between the card and the answer; 0 means the agent answered without a person speaking
proposed string or null what the record proposed on the card from earlier decisions on the same finding: accept, decline or null
intent_covered bool schema 8: the finding's subject shares a word with the session's stated intent (a term overlap, computed at card time; never an answer)
owner object or null schema 9: who owned the finding's path when it was raised: owners (as written in the ownership file, or the policy's authorities), source (<file>@<commit> or policy.authorities), pattern (the matching rule), unowned. Null for a finding that names no path, such as a command. See Who owns this path?
unowned bool schema 9: the path had no owner from any source

edits_outside_repository (schema 7)

An object keyed by the name of another checkout the agent edited during the session, each with count and up to 20 paths relative to that checkout. Empty when every edit stayed inside this repository. The gate evaluated those edits; this repository's note is the only record of them.

The schema is additive. New fields may appear; existing fields keep their meaning. Consumers should ignore unknown fields. Schema 9 added owner and unowned to decisions[]; schema 8 added intent and decisions[].intent_covered; schema 7 added observed as an answer and the edits_outside_repository object; schema 6 added to to decisions[]; a note written by an older gitvow reads the same as it always did.

The claim note

Stored under refs/notes/gitvow/claims on the empty commit gitvow claims confirm|reject writes. First line gitvow-claim, then JSON (schema 1): claim_id, verdict (confirmed or rejected), by, authority (speaker when the confirmer is the person who said it, else policy, commit-access or none), decided_at, text (as recorded), original_text (as extracted, verbatim), edited, paths, reach (repo), speaker, kind, source (a pointer: kind, file, message index; never the source content), said_at, classification (the extractor's opinion), reason. The trailer carries the id, the person, the bound paths and the first 120 characters; the note carries the rest. Person-reach preferences are never written to git; they live in ~/.gitvow/claims/preferences.jsonl on the speaker's own machine.

The outcome note

gitvow outcomes (0.31) grades each decision-bearing commit by what happened to it and writes the grade under refs/notes/gitvow/outcomes: its own ref, appended beside the decision, never rewriting the session note. First line gitvow-outcome, then JSON:

Field Type Meaning
schema int outcome note schema, currently 2
graded_at string UTC time the grade was written
window_days int the revert window the grade used (outcomes.revert_window_days)
verdict.kind string merged (a pull request merged it), closed (a pull request closed unmerged), open, direct (reachable from a production branch with no pull request), unknown
verdict.source string github when the forge answered, git when history alone spoke
verdict.pull_request, verdict.url int, string or null the pull request that carried the commit
verdict.landed_ts, verdict.landed_at int, string or null when it landed: the merge time, or the commit time for a direct landing
revert object or null sha of the reverting commit, after_seconds since landing, in_window
rework object or null schema 2: the earliest later commit by another author that rewrote lines this commit added, inside rework_window_days: sha, after_seconds, path, by_other
rework_window_days int schema 2: the rework window the grade used
decisions[] object[] per decision on the commit: finding, answer, outcome (held, not_held, reworked, overridden, pending)

See Did the decision hold? for the grading table.

The rule-decision note

Accepting or rejecting a proposed rule is itself a decision, so it is recorded the way decisions are. gitvow rules accept|reject writes an empty commit carrying the trailer and attaches a note under refs/notes/gitvow/rules — its own ref, because a rule decision is not a session. First line gitvow-rule-decision, then JSON:

Field Type Meaning
schema int rule-decision note schema, currently 1
verdict string accepted or rejected
by string the authority who decided
authority string policy or commit-access; never none, because a verdict by an unnamed person is refused rather than recorded
reason string or null the person's reason, redacted
decided_at string local time the verdict was recorded
threshold int decisions.rule_threshold in force when the verdict was made
rules[] object[] one per proposal in this verdict: finding, kind, answer, count, first, last, by[], evidence[], exceptions, exception_scopes[], expires

rules[].evidence[] is the run the proposal rested on, oldest first, at most 8 entries of date, by, answer and sha. It is stored at the moment of the verdict so the record says not only that a rule was accepted but what was in front of the person who accepted it.

Trailers

Gitvow-Session: <session id>
Gitvow-Step: <int>
Gitvow-Accepted: <finding> by <person>[ scope=<scope>][: <reason>]
Gitvow-Declined: <finding> by <person>[ scope=<scope>][: <reason>]
Gitvow-Referred: <finding> by <person>[ to=<person-or-team>][: <reason>]
Gitvow-Open: <finding>
Gitvow-Observed: <finding>
Gitvow-Revisits: <commit>
Gitvow-Rule-Accepted: <finding> by <person>[ answer=<accepted|declined>][: <reason>]
Gitvow-Rule-Rejected: <finding> by <person>[ answer=<accepted|declined>][: <reason>]
Gitvow-Claim-Confirmed: <claim-id> by <person>[ paths=<p1>,<p2>][: <verbatim text, first 120 chars>]
Gitvow-Claim-Rejected: <claim-id> by <person>[: <reason>]
Added by prepare-commit-msg when .git/gitvow-session.json holds a session id and a pending_commit timestamp younger than five minutes, which the PreToolUse gate sets when the agent runs git commit and PostToolUse clears afterwards. Idempotent: a message that already has Gitvow-Session: is left alone. A note is written only when the commit at HEAD carries the trailer.

Gitvow-Accepted, Gitvow-Declined and Gitvow-Referred are written for every finding decided with gitvow decide before the commit, on agent and human commits alike. Gitvow-Open is written for each finding nobody decided, on the agent's commit once the card has been shown and on a person's commit directly (policy decisions.mode open; in strict neither commit happens until every finding is decided). Gitvow-Observed is written for each finding an observe-tier rule recorded; it is neither debt nor an answer and never reaches the card. An immediate confirm nobody answered writes nothing: the command never ran. The post-commit hook clears the findings the commit carried. Gitvow-Revisits marks an empty commit written by gitvow revisit; its decision trailers answer the named commit's findings again. Gitvow-Rule-Accepted and Gitvow-Rule-Rejected mark an empty commit written by gitvow rules accept|reject; answer= says which run the verdict was about, so a later contradicting decision does not inherit it. See Decisions.

The grammar grows by new trailer names, never by new tail tokens on a name that has already shipped. Gitvow-Referred and its to= arrived together in 0.16: an older gitvow does not match the new name at all, so it reads the commit exactly as it would have before, which is the safe direction. Adding a token to a trailer that already exists is not safe, and the reason is in the pattern above — the finding is matched lazily and every suffix is optional, so an older parser that does not know the token backtracks it into the finding. Gitvow-Accepted: edit foo.go class=k7 by nikhil would parse on 0.15 as a decision about edit foo.go class=k7, silently forking the identity of every decision that carried it, with nothing anywhere reporting an error. Treat the token set of a released trailer as closed: a new fact belongs in a new trailer name, or in the note, which is versioned and genuinely additive. Within that constraint every part after the finding is optional, so a commit written by any earlier gitvow parses exactly as it did when it was made, and no existing trailer name has changed meaning. Gitvow-Rule-Accepted is deliberately not a Gitvow-Accepted: accepting a rule is not an answer to a finding on that commit, and a parser looking for decisions must not pick it up.