Pick any line to see why it is the way it is: the commit, the pull request and issue it came from, and what the agent was thinking.
| g1t coordinates the work and the person's own sessions do it: Ask g1t reads g1t with the same tools any agent gets, answers in one conversation shared with the @g1t direct message in Chat, and hands work to sessions in the person's own harness, whose subagents g1t records, ties to issues and pull requests, and lets see each other. | 1 | //! `list_commits`: a branch's history, newest first, with each commit's |
| A file's history and a repository's failed runs are one read each, so Ask (and any agent) answers "why does this file exist" and "why did the last Deploy fail" from what happened rather than by paging. list_commits with `path` now gives that file's or directory's own history: the commits on the first-parent chain that changed it (added, changed, removed), newest first, with `last_changed` the newest and `complete` false when a long history was not walked to its start in time. The repos service's new path_log walks the history as last_commits does, reading ahead in batches, a tree only where the path's directory changed, within its read budget and 8 s. list_workflow_runs takes GitHub's `status`, a status (queued, in_progress, waiting, completed) or a conclusion (failure, success, cancelled…), on REST (status, and head_sha on a workflow's runs too) and MCP, and the actions service filters by either. Ask's system prompt finds failed runs with status failure, says a run still going has no result rather than calling it passed, judges health from the newest completed run and what is still going, and reads a file's history for why it exists, quoting its commit messages. The quality bar no longer reads a run's number, in a link to the run or a table of runs, as an issue's. Its last run on production scored 97.1% of checks and a judge mean of 3.81 over 27 questions, against 52.1% and 3.08 before Ask had tools; these address its weakest answers. Checked: path_log's walks over a file, a directory, a missing path, a limit, pages and a read budget; cargo test for the workspace (the actions crates on their own), the wasm builds, the TypeScript typecheck, every workspace's tests, the deploy tool's and the plugin's tests and the docs build; the OpenAPI document, the CLI's operations and its reference are regenerated, and the MCP reference says both. | 2 | //! message, author, time and page; with `path`, that file's or directory's |
| 3 | //! own history: the commits that changed it. What an agent (or Ask g1t) | |
| 4 | //! reads to say what changed lately and why: g1t's commit messages say why. | |
| g1t coordinates the work and the person's own sessions do it: Ask g1t reads g1t with the same tools any agent gets, answers in one conversation shared with the @g1t direct message in Chat, and hands work to sessions in the person's own harness, whose subagents g1t records, ties to issues and pull requests, and lets see each other. | 5 | //! |
| A file's history and a repository's failed runs are one read each, so Ask (and any agent) answers "why does this file exist" and "why did the last Deploy fail" from what happened rather than by paging. list_commits with `path` now gives that file's or directory's own history: the commits on the first-parent chain that changed it (added, changed, removed), newest first, with `last_changed` the newest and `complete` false when a long history was not walked to its start in time. The repos service's new path_log walks the history as last_commits does, reading ahead in batches, a tree only where the path's directory changed, within its read budget and 8 s. list_workflow_runs takes GitHub's `status`, a status (queued, in_progress, waiting, completed) or a conclusion (failure, success, cancelled…), on REST (status, and head_sha on a workflow's runs too) and MCP, and the actions service filters by either. Ask's system prompt finds failed runs with status failure, says a run still going has no result rather than calling it passed, judges health from the newest completed run and what is still going, and reads a file's history for why it exists, quoting its commit messages. The quality bar no longer reads a run's number, in a link to the run or a table of runs, as an issue's. Its last run on production scored 97.1% of checks and a judge mean of 3.81 over 27 questions, against 52.1% and 3.08 before Ask had tools; these address its weakest answers. Checked: path_log's walks over a file, a directory, a missing path, a limit, pages and a read budget; cargo test for the workspace (the actions crates on their own), the wasm builds, the TypeScript typecheck, every workspace's tests, the deploy tool's and the plugin's tests and the docs build; the OpenAPI document, the CLI's operations and its reference are regenerated, and the MCP reference says both. | 6 | //! The repos service reads it, as the caller may see it: `log` for a |
| 7 | //! branch, `path_log` for a path. The shaping is [`commit`], a plain | |
| 8 | //! function. | |
| g1t coordinates the work and the person's own sessions do it: Ask g1t reads g1t with the same tools any agent gets, answers in one conversation shared with the @g1t direct message in Chat, and hands work to sessions in the person's own harness, whose subagents g1t records, ties to issues and pull requests, and lets see each other. | 9 | |
| A file's history and a repository's failed runs are one read each, so Ask (and any agent) answers "why does this file exist" and "why did the last Deploy fail" from what happened rather than by paging. list_commits with `path` now gives that file's or directory's own history: the commits on the first-parent chain that changed it (added, changed, removed), newest first, with `last_changed` the newest and `complete` false when a long history was not walked to its start in time. The repos service's new path_log walks the history as last_commits does, reading ahead in batches, a tree only where the path's directory changed, within its read budget and 8 s. list_workflow_runs takes GitHub's `status`, a status (queued, in_progress, waiting, completed) or a conclusion (failure, success, cancelled…), on REST (status, and head_sha on a workflow's runs too) and MCP, and the actions service filters by either. Ask's system prompt finds failed runs with status failure, says a run still going has no result rather than calling it passed, judges health from the newest completed run and what is still going, and reads a file's history for why it exists, quoting its commit messages. The quality bar no longer reads a run's number, in a link to the run or a table of runs, as an issue's. Its last run on production scored 97.1% of checks and a judge mean of 3.81 over 27 questions, against 52.1% and 3.08 before Ask had tools; these address its weakest answers. Checked: path_log's walks over a file, a directory, a missing path, a limit, pages and a read budget; cargo test for the workspace (the actions crates on their own), the wasm builds, the TypeScript typecheck, every workspace's tests, the deploy tool's and the plugin's tests and the docs build; the OpenAPI document, the CLI's operations and its reference are regenerated, and the MCP reference says both. | 10 | use g1t_contracts::repos::{Commit, LogArgs, PathLog, PathLogArgs, RepoPath}; |
| g1t coordinates the work and the person's own sessions do it: Ask g1t reads g1t with the same tools any agent gets, answers in one conversation shared with the @g1t direct message in Chat, and hands work to sessions in the person's own harness, whose subagents g1t records, ties to issues and pull requests, and lets see each other. | 11 | use g1t_contracts::{Outcome, Viewer}; |
| 12 | use serde_json::{Value, json}; | |
| 13 | use worker::Result; | |
| 14 | ||
| 15 | use crate::operations::Services; | |
| 16 | ||
| 17 | pub const DEFAULT_LIMIT: u32 = 30; | |
| 18 | pub const MAX_LIMIT: u32 = 100; | |
| 19 | /// The most of one commit's message an answer carries. | |
| 20 | const MAX_MESSAGE_CHARS: usize = 4_000; | |
| 21 | /// How long finding a path's last change may take, in milliseconds. | |
| 22 | const PATH_BUDGET_MS: u64 = 8_000; | |
| 23 | ||
| 24 | pub fn description() -> &'static str { | |
| A file's history and a repository's failed runs are one read each, so Ask (and any agent) answers "why does this file exist" and "why did the last Deploy fail" from what happened rather than by paging. list_commits with `path` now gives that file's or directory's own history: the commits on the first-parent chain that changed it (added, changed, removed), newest first, with `last_changed` the newest and `complete` false when a long history was not walked to its start in time. The repos service's new path_log walks the history as last_commits does, reading ahead in batches, a tree only where the path's directory changed, within its read budget and 8 s. list_workflow_runs takes GitHub's `status`, a status (queued, in_progress, waiting, completed) or a conclusion (failure, success, cancelled…), on REST (status, and head_sha on a workflow's runs too) and MCP, and the actions service filters by either. Ask's system prompt finds failed runs with status failure, says a run still going has no result rather than calling it passed, judges health from the newest completed run and what is still going, and reads a file's history for why it exists, quoting its commit messages. The quality bar no longer reads a run's number, in a link to the run or a table of runs, as an issue's. Its last run on production scored 97.1% of checks and a judge mean of 3.81 over 27 questions, against 52.1% and 3.08 before Ask had tools; these address its weakest answers. Checked: path_log's walks over a file, a directory, a missing path, a limit, pages and a read budget; cargo test for the workspace (the actions crates on their own), the wasm builds, the TypeScript typecheck, every workspace's tests, the deploy tool's and the plugin's tests and the docs build; the OpenAPI document, the CLI's operations and its reference are regenerated, and the MCP reference says both. | 25 | "A branch's commits, newest first (the default branch unless `ref` names a branch, tag or commit): each with its `sha`, `message` (why it was made: g1t's commit messages say), `author`, `authored_at` and `html_url`. `limit` is 30 unless you say, at most 100. With `path` (a file or directory), only the commits that changed it, newest first (its history: added, changed, removed), with `last_changed`, the newest of them, and `complete` false when a long history was not walked to its start in time." |
| g1t coordinates the work and the person's own sessions do it: Ask g1t reads g1t with the same tools any agent gets, answers in one conversation shared with the @g1t direct message in Chat, and hands work to sessions in the person's own harness, whose subagents g1t records, ties to issues and pull requests, and lets see each other. | 26 | } |
| 27 | ||
| 28 | pub fn input() -> Value { | |
| 29 | json!({ | |
| 30 | "type": "object", | |
| 31 | "properties": { | |
| 32 | "repo": { "type": "string", "description": "Repository as \"owner/name\", e.g. \"flagon-io/hello\"." }, | |
| 33 | "ref": { "type": "string", "description": "A branch, tag or commit; the default branch when left out." }, | |
| A file's history and a repository's failed runs are one read each, so Ask (and any agent) answers "why does this file exist" and "why did the last Deploy fail" from what happened rather than by paging. list_commits with `path` now gives that file's or directory's own history: the commits on the first-parent chain that changed it (added, changed, removed), newest first, with `last_changed` the newest and `complete` false when a long history was not walked to its start in time. The repos service's new path_log walks the history as last_commits does, reading ahead in batches, a tree only where the path's directory changed, within its read budget and 8 s. list_workflow_runs takes GitHub's `status`, a status (queued, in_progress, waiting, completed) or a conclusion (failure, success, cancelled…), on REST (status, and head_sha on a workflow's runs too) and MCP, and the actions service filters by either. Ask's system prompt finds failed runs with status failure, says a run still going has no result rather than calling it passed, judges health from the newest completed run and what is still going, and reads a file's history for why it exists, quoting its commit messages. The quality bar no longer reads a run's number, in a link to the run or a table of runs, as an issue's. Its last run on production scored 97.1% of checks and a judge mean of 3.81 over 27 questions, against 52.1% and 3.08 before Ask had tools; these address its weakest answers. Checked: path_log's walks over a file, a directory, a missing path, a limit, pages and a read budget; cargo test for the workspace (the actions crates on their own), the wasm builds, the TypeScript typecheck, every workspace's tests, the deploy tool's and the plugin's tests and the docs build; the OpenAPI document, the CLI's operations and its reference are regenerated, and the MCP reference says both. | 34 | "path": { "type": "string", "description": "A file or directory, such as scripts/deploy/npm-ci.mjs: only the commits that changed it." }, |
| g1t coordinates the work and the person's own sessions do it: Ask g1t reads g1t with the same tools any agent gets, answers in one conversation shared with the @g1t direct message in Chat, and hands work to sessions in the person's own harness, whose subagents g1t records, ties to issues and pull requests, and lets see each other. | 35 | "limit": { "type": "integer", "minimum": 1, "maximum": MAX_LIMIT, "description": "How many commits: 30 unless you say, at most 100." }, |
| 36 | }, | |
| 37 | "required": ["repo"], | |
| 38 | }) | |
| 39 | } | |
| 40 | ||
| 41 | /// One commit as an answer shows it. | |
| 42 | pub fn commit(site: &str, repo: &RepoPath, commit: &Commit) -> Value { | |
| 43 | let site = site.trim_end_matches('/'); | |
| 44 | let total = commit.message.chars().count(); | |
| 45 | let message = if total > MAX_MESSAGE_CHARS { | |
| 46 | format!("{}… [{} more characters]", commit.message.chars().take(MAX_MESSAGE_CHARS).collect::<String>(), total - MAX_MESSAGE_CHARS) | |
| 47 | } else { | |
| 48 | commit.message.trim_end().to_owned() | |
| 49 | }; | |
| 50 | json!({ | |
| 51 | "sha": commit.hash, | |
| 52 | "message": message, | |
| 53 | "author": { "name": commit.author.name }, | |
| 54 | "authored_at": commit.authored_at, | |
| 55 | "parents": commit.parents, | |
| 56 | "html_url": format!("{site}/{}/{}/commit/{}", repo.namespace, repo.name, commit.hash), | |
| 57 | }) | |
| 58 | } | |
| 59 | ||
| 60 | fn limit(input: &Value) -> u32 { | |
| 61 | let asked = match input.get("limit") { | |
| 62 | Some(Value::String(text)) => text.trim().parse::<u64>().ok(), | |
| 63 | Some(value) => value.as_u64(), | |
| 64 | None => None, | |
| 65 | }; | |
| 66 | asked.map_or(DEFAULT_LIMIT, |n| n.clamp(1, u64::from(MAX_LIMIT)) as u32) | |
| 67 | } | |
| 68 | ||
| 69 | pub async fn run(services: &Services, viewer: &Viewer, repo: &RepoPath, input: &Value) -> Result<Outcome<Value>> { | |
| 70 | let site = services.addresses.site.clone(); | |
| 71 | let git_ref = input["ref"].as_str().map(str::trim).filter(|git_ref| !git_ref.is_empty()).map(str::to_owned); | |
| 72 | let path = input["path"].as_str().unwrap_or_default().trim().trim_matches('/').to_owned(); | |
| A file's history and a repository's failed runs are one read each, so Ask (and any agent) answers "why does this file exist" and "why did the last Deploy fail" from what happened rather than by paging. list_commits with `path` now gives that file's or directory's own history: the commits on the first-parent chain that changed it (added, changed, removed), newest first, with `last_changed` the newest and `complete` false when a long history was not walked to its start in time. The repos service's new path_log walks the history as last_commits does, reading ahead in batches, a tree only where the path's directory changed, within its read budget and 8 s. list_workflow_runs takes GitHub's `status`, a status (queued, in_progress, waiting, completed) or a conclusion (failure, success, cancelled…), on REST (status, and head_sha on a workflow's runs too) and MCP, and the actions service filters by either. Ask's system prompt finds failed runs with status failure, says a run still going has no result rather than calling it passed, judges health from the newest completed run and what is still going, and reads a file's history for why it exists, quoting its commit messages. The quality bar no longer reads a run's number, in a link to the run or a table of runs, as an issue's. Its last run on production scored 97.1% of checks and a judge mean of 3.81 over 27 questions, against 52.1% and 3.08 before Ask had tools; these address its weakest answers. Checked: path_log's walks over a file, a directory, a missing path, a limit, pages and a read budget; cargo test for the workspace (the actions crates on their own), the wasm builds, the TypeScript typecheck, every workspace's tests, the deploy tool's and the plugin's tests and the docs build; the OpenAPI document, the CLI's operations and its reference are regenerated, and the MCP reference says both. | 73 | let full = format!("{}/{}", repo.namespace, repo.name); |
| 74 | if path.is_empty() { | |
| 75 | let log: Outcome<Vec<Commit>> = g1t_kit::call( | |
| 76 | &services.repos, | |
| 77 | "log", | |
| 78 | &LogArgs { path: repo.clone(), viewer: viewer.clone(), git_ref, limit: limit(input) }, | |
| 79 | ) | |
| 80 | .await?; | |
| 81 | return Ok(match log { | |
| 82 | Outcome::Ok(commits) => Outcome::Ok(json!({ | |
| 83 | "repo": full, | |
| 84 | "commits": commits.iter().map(|found| commit(&site, repo, found)).collect::<Vec<_>>(), | |
| 85 | })), | |
| 86 | Outcome::Fail(failure) => Outcome::Fail(failure), | |
| 87 | }); | |
| 88 | } | |
| 89 | // A path's own history: the commits that changed it, newest first. | |
| 90 | let history: Outcome<PathLog> = g1t_kit::call( | |
| g1t coordinates the work and the person's own sessions do it: Ask g1t reads g1t with the same tools any agent gets, answers in one conversation shared with the @g1t direct message in Chat, and hands work to sessions in the person's own harness, whose subagents g1t records, ties to issues and pull requests, and lets see each other. | 91 | &services.repos, |
| A file's history and a repository's failed runs are one read each, so Ask (and any agent) answers "why does this file exist" and "why did the last Deploy fail" from what happened rather than by paging. list_commits with `path` now gives that file's or directory's own history: the commits on the first-parent chain that changed it (added, changed, removed), newest first, with `last_changed` the newest and `complete` false when a long history was not walked to its start in time. The repos service's new path_log walks the history as last_commits does, reading ahead in batches, a tree only where the path's directory changed, within its read budget and 8 s. list_workflow_runs takes GitHub's `status`, a status (queued, in_progress, waiting, completed) or a conclusion (failure, success, cancelled…), on REST (status, and head_sha on a workflow's runs too) and MCP, and the actions service filters by either. Ask's system prompt finds failed runs with status failure, says a run still going has no result rather than calling it passed, judges health from the newest completed run and what is still going, and reads a file's history for why it exists, quoting its commit messages. The quality bar no longer reads a run's number, in a link to the run or a table of runs, as an issue's. Its last run on production scored 97.1% of checks and a judge mean of 3.81 over 27 questions, against 52.1% and 3.08 before Ask had tools; these address its weakest answers. Checked: path_log's walks over a file, a directory, a missing path, a limit, pages and a read budget; cargo test for the workspace (the actions crates on their own), the wasm builds, the TypeScript typecheck, every workspace's tests, the deploy tool's and the plugin's tests and the docs build; the OpenAPI document, the CLI's operations and its reference are regenerated, and the MCP reference says both. | 92 | "path_log", |
| 93 | &PathLogArgs { | |
| 94 | path: repo.clone(), | |
| 95 | viewer: viewer.clone(), | |
| 96 | git_ref, | |
| 97 | file_path: path.clone(), | |
| 98 | limit: limit(input), | |
| 99 | budget_ms: Some(PATH_BUDGET_MS), | |
| 100 | }, | |
| g1t coordinates the work and the person's own sessions do it: Ask g1t reads g1t with the same tools any agent gets, answers in one conversation shared with the @g1t direct message in Chat, and hands work to sessions in the person's own harness, whose subagents g1t records, ties to issues and pull requests, and lets see each other. | 101 | ) |
| 102 | .await?; | |
| A file's history and a repository's failed runs are one read each, so Ask (and any agent) answers "why does this file exist" and "why did the last Deploy fail" from what happened rather than by paging. list_commits with `path` now gives that file's or directory's own history: the commits on the first-parent chain that changed it (added, changed, removed), newest first, with `last_changed` the newest and `complete` false when a long history was not walked to its start in time. The repos service's new path_log walks the history as last_commits does, reading ahead in batches, a tree only where the path's directory changed, within its read budget and 8 s. list_workflow_runs takes GitHub's `status`, a status (queued, in_progress, waiting, completed) or a conclusion (failure, success, cancelled…), on REST (status, and head_sha on a workflow's runs too) and MCP, and the actions service filters by either. Ask's system prompt finds failed runs with status failure, says a run still going has no result rather than calling it passed, judges health from the newest completed run and what is still going, and reads a file's history for why it exists, quoting its commit messages. The quality bar no longer reads a run's number, in a link to the run or a table of runs, as an issue's. Its last run on production scored 97.1% of checks and a judge mean of 3.81 over 27 questions, against 52.1% and 3.08 before Ask had tools; these address its weakest answers. Checked: path_log's walks over a file, a directory, a missing path, a limit, pages and a read budget; cargo test for the workspace (the actions crates on their own), the wasm builds, the TypeScript typecheck, every workspace's tests, the deploy tool's and the plugin's tests and the docs build; the OpenAPI document, the CLI's operations and its reference are regenerated, and the MCP reference says both. | 103 | let history = match history { |
| 104 | Outcome::Ok(history) => history, | |
| g1t coordinates the work and the person's own sessions do it: Ask g1t reads g1t with the same tools any agent gets, answers in one conversation shared with the @g1t direct message in Chat, and hands work to sessions in the person's own harness, whose subagents g1t records, ties to issues and pull requests, and lets see each other. | 105 | Outcome::Fail(failure) => return Ok(Outcome::Fail(failure)), |
| 106 | }; | |
| A file's history and a repository's failed runs are one read each, so Ask (and any agent) answers "why does this file exist" and "why did the last Deploy fail" from what happened rather than by paging. list_commits with `path` now gives that file's or directory's own history: the commits on the first-parent chain that changed it (added, changed, removed), newest first, with `last_changed` the newest and `complete` false when a long history was not walked to its start in time. The repos service's new path_log walks the history as last_commits does, reading ahead in batches, a tree only where the path's directory changed, within its read budget and 8 s. list_workflow_runs takes GitHub's `status`, a status (queued, in_progress, waiting, completed) or a conclusion (failure, success, cancelled…), on REST (status, and head_sha on a workflow's runs too) and MCP, and the actions service filters by either. Ask's system prompt finds failed runs with status failure, says a run still going has no result rather than calling it passed, judges health from the newest completed run and what is still going, and reads a file's history for why it exists, quoting its commit messages. The quality bar no longer reads a run's number, in a link to the run or a table of runs, as an issue's. Its last run on production scored 97.1% of checks and a judge mean of 3.81 over 27 questions, against 52.1% and 3.08 before Ask had tools; these address its weakest answers. Checked: path_log's walks over a file, a directory, a missing path, a limit, pages and a read budget; cargo test for the workspace (the actions crates on their own), the wasm builds, the TypeScript typecheck, every workspace's tests, the deploy tool's and the plugin's tests and the docs build; the OpenAPI document, the CLI's operations and its reference are regenerated, and the MCP reference says both. | 107 | let last_changed = match history.commits.first() { |
| 108 | Some(first) => commit(&site, repo, first), | |
| 109 | None if history.complete => json!(format!("{path} is not in this repository at this ref.")), | |
| 110 | None => json!("Not found in time: its history is long. Ask with a smaller limit, or read the branch's commits."), | |
| 111 | }; | |
| 112 | Ok(Outcome::Ok(json!({ | |
| 113 | "repo": full, | |
| 114 | "path": path, | |
| 115 | "commits": history.commits.iter().map(|found| commit(&site, repo, found)).collect::<Vec<_>>(), | |
| 116 | "last_changed": last_changed, | |
| 117 | "complete": history.complete, | |
| 118 | }))) | |
| g1t coordinates the work and the person's own sessions do it: Ask g1t reads g1t with the same tools any agent gets, answers in one conversation shared with the @g1t direct message in Chat, and hands work to sessions in the person's own harness, whose subagents g1t records, ties to issues and pull requests, and lets see each other. | 119 | } |
| 120 | ||
| 121 | #[cfg(test)] | |
| 122 | mod tests { | |
| 123 | use super::*; | |
| 124 | use g1t_contracts::repos::Signature; | |
| 125 | ||
| 126 | #[test] | |
| 127 | fn a_commit_says_why_and_where_it_is() { | |
| 128 | let found = Commit { | |
| 129 | hash: "abc123".into(), | |
| 130 | tree_hash: "t".into(), | |
| 131 | message: "The runner retries installs that break off.\n".into(), | |
| 132 | author: Signature { name: "Chase Pierce".into(), email: "c@example.com".into() }, | |
| 133 | parents: vec!["p1".into()], | |
| 134 | authored_at: "2026-10-13T01:00:00Z".into(), | |
| 135 | }; | |
| 136 | let repo = RepoPath { namespace: "acme".into(), name: "web".into() }; | |
| 137 | let shown = commit("https://g1t.sh/", &repo, &found); | |
| 138 | assert_eq!(shown["sha"], "abc123"); | |
| 139 | assert_eq!(shown["message"], "The runner retries installs that break off."); | |
| 140 | assert_eq!(shown["author"], json!({ "name": "Chase Pierce" })); | |
| 141 | assert!(shown.get("email").is_none() && shown["author"].get("email").is_none(), "no email addresses"); | |
| 142 | assert_eq!(shown["html_url"], "https://g1t.sh/acme/web/commit/abc123"); | |
| 143 | assert_eq!(limit(&json!({ "limit": "500" })), MAX_LIMIT); | |
| 144 | assert_eq!(limit(&json!({})), DEFAULT_LIMIT); | |
| 145 | } | |
| 146 | } |