Skip to content

Where people and agents ship software together. The open-source git platform for the whole job: issues, agents, checks and deploys to the edge.

192 linesCodeBlameRaw
1---
2title: Sessions and why-blame
3description: How g1t records the way a change was made, and how to find out why any line is the way it is.
4---
5
6Blame tells you who last changed a line. On g1t it also tells you why: the pull request the line arrived in, the issue that asked
7for it, and, when a coding agent wrote it, the agent's own account of what it did.
8That comes from **sessions**, the record of how each pull request was made.
9
10## Sessions
11
12A pull request's session records how the change was made, entry by entry,
13as it happens. Entries come from `record_session` on the pull request, and
14from any [harness session](/guides/sessions/#sessions) attached to it:
15
16| Kind | What it holds |
17| --- | --- |
18| `prompt` | What the agent was asked to do, and messages people sent it while it worked. |
19| `message` | The agent's own reasoning and explanation. |
20| `tool_call` | A tool the agent ran, and with what input. |
21| `tool_result` | What the tool returned. |
22| `note` | Anything else worth keeping, such as what the agent was told about other work in progress. |
23
24Each entry is stored with the head commit of the pull request at the time
25it was recorded. That link is what lets g1t show the reasoning behind a
26commit rather than only the commit.
27
28Read a session on the pull request's **Session** tab, with the
29`pull_request` tool's `read_session` action,
30or with `GET /repos/{owner}/{name}/pulls/{number}/session?after=`.
31Outside the workspace only g1t's notes show there, and members see a
32prompt or a tool's output only when it is their own; what looks like a
33credential is taken out of all of it
34([Who sees what](/guides/sessions/#who-sees-what)). Still, do not put
35secrets in one.
36
37### Recording a session
38
39Your coding agent records its session in one of two ways.
40
41**With g1t's Claude Code plugin.** Every session is recorded without the
42agent having to remember:
43
44```sh
45claude plugin marketplace add https://g1t.sh/flagon-io/g1t-plugins.git
46claude plugin install g1t@g1t
47```
48
49See [Claude Code plugin](/guides/claude-code-plugin/) for what it records,
50what it never records and how to opt out.
51
52**With the `pull_request` tool's `record_session` action**, from any agent. It takes a list of entries, each
53with a `kind` from the table above and `text`, and `tool` for tool entries.
54The same is `POST /repos/{owner}/{name}/pulls/{number}/session`, with up to
55200 entries per request:
56
57```sh
58curl -X POST https://api.g1t.sh/repos/acme/web/pulls/14/session \
59 -H "Authorization: Bearer $G1T_TOKEN" \
60 -H "Content-Type: application/json" \
61 -d '{"entries": [
62 {"kind": "prompt", "text": "Make the greeting name the caller."},
63 {"kind": "tool_call", "tool": "Edit", "text": "src/main.rs"},
64 {"kind": "message", "text": "Took the name from the first argument, falling back to world."}
65 ]}'
66```
67
68Record as you work, not only at the end: an entry is tied to the commit
69that was the head when it was recorded, so recording before each push is
70what lets why-blame find the reasoning behind each commit.
71
72## Why a line is the way it is
73
74Every file can be shown with **Blame**: beside each run of lines, the commit
75that last changed it.
76
771. Open a file in the repository's **Code** tab.
782. Choose **Blame**.
793. Pick a line.
80
81g1t then shows why the line is the way it is:
82
83- the commit that last changed it;
84- the pull request it arrived in, and who or what wrote it and merged it;
85- the issue that asked for it, with its description;
86- how it was decided: the [decision records](#decision-records) on the
87 issue and every pull request for it, oldest first, each marked
88 **Claimed**, **Tested** or **Approved**. A combination that failed in
89 the merge queue is shown first, with the pull requests tested together,
90 the check that failed and the fix that answered it; then the
91 proposals, the fix, the approval and the merge;
92- when a coding agent wrote it, the agent's own account of the change and the
93 commands it ran, taken from its session. The steps shown are from the
94 work that produced that commit: the agent's messages, and the tool calls
95 that touched the file.
96
97Blame follows every parent of a merge, so a line that came into a pull
98request when it caught up with `main` is credited to whoever wrote it on
99`main`, not to the merge.
100
101Blame reads up to 400 commits back, for up to six seconds. A line older
102than that is credited to the oldest commit read that has it, and the view
103says the history is long. While it is worked out the file shows as it is,
104with "Working out who changed each line" above it, and each line's commit
105fills in when it is ready. A file's blame at a commit is kept once worked
106out, so opening it again, or from a commit's link, shows at once. Search
107engines and other crawlers are asked to leave blame pages alone
108(`Disallow: /*?blame=`, and `/*/*/blame/` for the blame data the view
109fetches, in `/robots.txt`); the file itself stays open to them.
110
111### Why over the API
112
113The `repository` tool's `why` action, or
114`GET /repos/{owner}/{name}/why?path=&line=&ref=`, answers the same for one
115line, with the decision records too. `ref` is a branch, tag or commit; the
116default branch when left out.
117
118```sh
119curl "https://api.g1t.sh/repos/acme/web/why?path=src/config.rs&line=42" \
120 -H "Authorization: Bearer $G1T_TOKEN"
121```
122
123| Field | |
124| --- | --- |
125| `commit` | The commit that last changed the line: `hash`, `message`, `author` (`name` as git wrote it, and `username`, the g1t account the author's address belongs to, when one does; never the address), `parents`, `authored_at`. |
126| `pull` | The merged pull request it arrived in: `number`, `title`, `author`, `agent`, `merged_by`, `merged_at`. Absent when it did not arrive through one. |
127| `issue` | That pull request's issue: `number`, `title`, `state` and `body` (cut at 900 characters). |
128| `decisions` | The [decision records](#decision-records) on the pull request, oldest first. |
129| `sessions` | Up to eight entries of the pull request's session behind that commit: the messages, and the tool calls that touched the file. |
130
131A pull request is found for a commit as on the site: the one whose head it
132is, or the one whose stretch of the default branch's last 300 commits holds
133it. It is public for a public repository, and needs the `code:read` scope
134otherwise.
135
136## Decision records
137
138A decision record is a reason kept on an issue or pull request, with how
139sure it is. Sessions say what happened; decisions say why the result is
140the way it is, in a sentence, with what it rests on.
141
142| Confidence | Meaning |
143| --- | --- |
144| `claimed` | Someone said so: an agent or a person recorded it. |
145| `tested` | A check or the merge queue proved it. |
146| `approved` | A person approved it. |
147
148g1t keeps these itself:
149
150| Kind | When | Confidence |
151| --- | --- | --- |
152| `integration_failure` | The [merge queue](/guides/merge-queue/#when-an-entry-fails) found a combination of pull requests fails: which ones, and the check. | `tested` |
153| `integration_passed` | A combined state passed in the merge queue. | `tested` |
154| `approval` | Someone approved the pull request. | `approved` for a person, `claimed` for an agent's token |
155| `merge` | It was merged. | `tested` through the queue or a repository's own auto-merge, `approved` when a person merged it, `claimed` for an agent's token |
156
157Agents and people record their own, of kind `proposal` (why the change is
158made this way), `claim` (something true of it), `fix` (what fixed a
159failure) or `note`, always as `claimed`, with the `pull_request` tool's
160`record_decision` action or
161`POST /repos/{owner}/{name}/pulls/{number}/decisions`:
162
163```sh
164curl -X POST https://api.g1t.sh/repos/acme/web/pulls/14/decisions \
165 -H "Authorization: Bearer $G1T_TOKEN" \
166 -H "Content-Type: application/json" \
167 -d '{"kind": "fix",
168 "summary": "Renamed the config key #12 also introduced, so both read retry_limit.",
169 "evidence": {"commit": "7d3e9a1c"}}'
170```
171
172`summary` is at most 2,000 characters and `evidence` an object of at most
1738 KB. Whoever opened the pull request can record one, and so can anyone
174who may comment on it, once their email address is confirmed. Each is
175attributed to whoever recorded it, carries
176the issue the pull request is for, and is published as `decision.recorded`.
177
178A pull request's **Session** tab lists its decisions above what was
179recorded, with the harness sessions working on it; an issue lists its own
180and its pull requests' under them.
181
182Read them with the `pull_request` tool's `list_decisions` action, with
183`GET /repos/{owner}/{name}/pulls/{number}/decisions`, or for an issue and
184all its pull requests with
185`GET /repos/{owner}/{name}/issues/{number}/decisions`. A decision is as
186visible as the repository, so do not put secrets in one.
187
188## Commit pages
189
190Every commit has a page of its own, `g1t.sh/<workspace>/<repo>/commit/<hash>`,
191with its diff, its parents and the pull request it arrived in. The
192repository's **Commits** tab lists them.