Skip to content
245 linesCodeBlameRaw

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.

Merge rulesets: branch and tag rules, agent-first, enforced on push and merge1import type { RepoPath } from "./repos";
2import type { Result } from "./result";
3import type { User, Viewer } from "./identity";
4
5/**
6 * Rulesets: what may happen to a repository's branches and tags, and what a
7 * pull request needs before it merges. A ruleset belongs to a repository or
8 * to a workspace (and through it to the repositories it selects), targets
9 * branches or tags by name, is `active`, `evaluate` (a dry run that records
10 * what it would have refused) or `disabled`, lists who may bypass it, and
11 * holds rules. Rulesets stack: every rule of each holds.
12 *
13 * Mirrors `crates/contracts/src/rules.rs`. Rulesets travel in the shape the
14 * API shows them, `snake_case`, so an export imports anywhere unchanged.
15 */
16
17export const DEFAULT_BRANCH = "~DEFAULT_BRANCH";
18export const ALL = "~ALL";
19export const MAX_RULESETS = 75;
20
21export type Enforcement = "active" | "evaluate" | "disabled";
22export type Target = "branch" | "tag";
23export type Level = "repository" | "workspace";
24export type AppliesTo = "everyone" | "agents" | "people";
25export type BypassActorKind = "role" | "team" | "user" | "token" | "g1t";
26export type BypassMode = "always" | "pull_requests";
27export type MergeMethod = "merge" | "squash" | "rebase";
Merge checks: statuses and check runs on every commit28export type Integration = "actions" | "deployments" | "security" | "g1t" | "api";
Merge rulesets: branch and tag rules, agent-first, enforced on push and merge29export type PatternOperator = "starts_with" | "ends_with" | "contains" | "regex";
30
31export type Weekday = "mon" | "tue" | "wed" | "thu" | "fri" | "sat" | "sun";
32
33export type RefCondition = { include: string[]; exclude: string[] };
34export type RepositoryCondition = {
35 include: string[];
36 exclude: string[];
37 visibility: "any" | "public" | "private";
38 topics: string[];
39};
40export type Conditions = { ref_name: RefCondition; repository?: RepositoryCondition };
41export type BypassActor = { kind: BypassActorKind; value: string; mode: BypassMode };
42
43export type PullRequestParameters = {
44 required_approvals: number;
45 count_agent_approvals: boolean;
46 dismiss_stale_reviews_on_push: boolean;
47 require_code_owner_review: boolean;
48 require_last_push_approval: boolean;
49 allowed_merge_methods: MergeMethod[];
50 /** Only the ruleset made from branch protection that did not refuse pushes. */
51 allow_direct_pushes?: boolean;
52};
53export type RulesetCheck = { context: string; integration?: Integration };
54export type StatusChecksParameters = {
55 checks: RulesetCheck[];
56 strict: boolean;
57 paths: string[];
58 allow_bypass_on_merge: boolean;
59};
60export type MergeQueueParameters = {
61 merge_method: MergeMethod;
62 max_entries_to_build: number;
63 min_entries_to_merge: number;
64 min_entries_wait_minutes: number;
65 check_response_timeout_minutes: number;
66};
67export type PatternParameters = { name: string; operator: PatternOperator; pattern: string; negate: boolean };
68export type WeeklyWindow = { days: Weekday[]; start: string; end: string };
69export type Period = { start: string; end?: string | null; reason: string };
70export type MergeWindowParameters = {
71 time_zone: string;
72 windows: WeeklyWindow[];
73 freezes: Period[];
74 exceptions: Period[];
75};
76
77/** Every rule type, with its parameters. */
78export type Rule =
79 | { type: "creation"; parameters: Record<string, never> }
80 | { type: "update"; parameters: Record<string, never> }
81 | { type: "deletion"; parameters: Record<string, never> }
82 | { type: "non_fast_forward"; parameters: Record<string, never> }
83 | { type: "required_linear_history"; parameters: Record<string, never> }
84 | { type: "required_signatures"; parameters: Record<string, never> }
85 | { type: "pull_request"; parameters: PullRequestParameters }
86 | { type: "required_status_checks"; parameters: StatusChecksParameters }
87 | { type: "merge_queue"; parameters: MergeQueueParameters }
88 | { type: "required_deployments"; parameters: { environments: string[] } }
89 | { type: "commit_message_pattern"; parameters: PatternParameters }
90 | { type: "commit_author_email_pattern"; parameters: PatternParameters }
91 | { type: "committer_email_pattern"; parameters: PatternParameters }
92 | { type: "branch_name_pattern"; parameters: PatternParameters }
93 | { type: "tag_name_pattern"; parameters: PatternParameters }
94 | { type: "file_path_restriction"; parameters: { restricted_file_paths: string[] } }
95 | { type: "file_extension_restriction"; parameters: { restricted_file_extensions: string[] } }
96 | { type: "max_file_size"; parameters: { max_file_size_mb: number } }
97 | { type: "max_file_path_length"; parameters: { max_file_path_length: number } }
98 | { type: "max_files_changed"; parameters: { max_files: number } }
99 | { type: "secret_scanning"; parameters: Record<string, never> }
100 | { type: "path_review"; parameters: { paths: string[]; required_approvals: number; team?: string | null } }
101 | { type: "merge_window"; parameters: MergeWindowParameters }
The contracts no longer describe g1t's own agents, and workspaces can keep their AI providers. Every consumer had already stopped using them, so the TypeScript and Rust contracts drop the workspace-agent, ability, look, skill-library, context, runner-agent and mention modules, the chat and docs RPCs agents posted and read through, the folio agent methods, the agent_waiting notification, agent.asked and memory.changed events, AI credit, token and gateway billing types, model routes and sessions, team agents, agent tokens, plan, review, message and confidence types, command rules, cost caps and confidence rules. The agents:run and models:* scopes are no longer offered by any preset, OAuth default or permission form, but a stored token or grant that names them still reads; and the removed operations are gone from the scope table, so the API's check that every operation has exactly one scope is strict again. What stored data needs in order to parse (old run and credential kinds, an agent team lead, retired rules and webhook events, old guardrail and integration settings) still parses, and a run's token is still PrincipalKind::Agent, which now means a run's token and the @g1t rows written before. The customize, marketplace, skills and claude-plugin contracts stay only until the mobile app drops its Customize screens.102 | { type: "agent_auto_merge"; parameters: { allowed: boolean } };
103
104/**
105 * Rule types no longer offered, which were about g1t's own agents. A stored
106 * ruleset that has one still reads: the rule is left out. Mirrors
107 * `RETIRED_RULES` in `crates/contracts/src/rules.rs`.
108 */
109export const RETIRED_RULES: readonly string[] = ["confidence_threshold", "cost_cap"];
Merge rulesets: branch and tag rules, agent-first, enforced on push and merge110
111export type RuleType = Rule["type"];
112export type RuleEntry = Rule & { applies_to: AppliesTo };
113
114/** What a ruleset says: what is created, changed, exported and imported. */
115export type RulesetSpec = {
116 name: string;
117 enforcement: Enforcement;
118 target: Target;
119 conditions: Conditions;
120 bypass_actors: BypassActor[];
121 rules: RuleEntry[];
122};
123
124export type Ruleset = RulesetSpec & {
125 id: string;
126 level: Level;
127 workspace: string;
128 repo_id?: string;
129 repository?: string;
130 /** `branch_protection` for the one made from branch protection settings. */
131 source?: string;
132 created_by: string;
133 created_at: string;
134 updated_by: string;
135 updated_at: string;
136};
137
138export type RulesetSummary = {
139 id: string;
140 name: string;
141 level: Level;
142 enforcement: Enforcement;
143 bypass_actors: BypassActor[];
144};
145
146export type EffectiveRule = RuleEntry & {
147 ruleset_id: string;
148 ruleset_name: string;
149 level: Level;
150 enforcement: Enforcement;
151};
152
153export type EffectiveRules = {
154 name: string;
155 target: Target;
156 default_branch: boolean;
157 rules: EffectiveRule[];
158 rulesets: RulesetSummary[];
159};
160
161export type RuleVerdict = "pass" | "fail" | "bypass";
162export type Action = "push" | "merge" | "create_ref" | "delete_ref" | "rename_ref" | "commit";
163
164export type Violation = {
165 rule: string;
166 ruleset_id: string;
167 ruleset_name: string;
168 enforcement: Enforcement;
169 message: string;
170 remedy: string;
171};
172
173export type Evaluation = {
174 id: string;
175 repo_id: string;
176 workspace: string;
177 ruleset_id: string;
178 ruleset_name: string;
179 enforcement: Enforcement;
180 action: Action;
181 git_ref: string;
182 actor: string;
183 actor_kind: string;
184 verdict: RuleVerdict;
185 violations: Violation[];
186 number: number | null;
187 sha: string | null;
188 repository: string;
189 created_at: string;
190};
191
192export type Insights = {
193 days: number;
194 total: number;
195 passed: number;
196 blocked: number;
197 would_block: number;
198 bypassed: number;
199 by_ruleset: {
200 ruleset_id: string;
201 ruleset_name: string;
202 enforcement: Enforcement;
203 total: number;
204 blocked: number;
205 would_block: number;
206 bypassed: number;
207 }[];
208 by_rule: { rule: string; count: number }[];
209};
210
211export type EvaluationPage = { evaluations: Evaluation[]; next: string | null; insights: Insights };
212
213/** What a pull request's merge box shows of the rules of its base. */
214export type MergeRules = {
215 unmet: Violation[];
216 bypassable: Violation[];
217 evaluate: Violation[];
218 rulesets: RulesetSummary[];
219 merge_queue: boolean;
220 /** What the active rules ask, as they stack. */
221 required_approvals: number;
222 strict: boolean;
223 allow_bypass_on_merge: boolean;
224};
225
226/** Whose rulesets: a repository's or a workspace's. */
227export type RulesetOwner = { repo: RepoPath } | { workspace: string };
228
229export type EvaluationFilter = {
230 ruleset_id?: string;
231 verdict?: RuleVerdict;
232 problems_only?: boolean;
233 before?: string;
234 limit?: number;
235};
236
237export interface RulesApi {
238 listRulesets(owner: RulesetOwner, viewer: Viewer, includeParents?: boolean): Promise<Result<Ruleset[]>>;
239 getRuleset(owner: RulesetOwner, id: string, viewer: Viewer): Promise<Result<Ruleset>>;
240 /** Creates one (no `id`) or replaces one. */
241 saveRuleset(actor: User, owner: RulesetOwner, ruleset: RulesetSpec, id?: string): Promise<Result<Ruleset>>;
242 deleteRuleset(actor: User, owner: RulesetOwner, id: string): Promise<Result<boolean>>;
243 effectiveRules(repo: RepoPath, name: string, viewer: Viewer, target?: Target): Promise<Result<EffectiveRules>>;
244 ruleEvaluations(owner: RulesetOwner, viewer: Viewer, filter?: EvaluationFilter): Promise<Result<EvaluationPage>>;
245}

This file's history is long; its oldest lines are credited to the oldest commit read.