Skip to content
267 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.

Agents → Skills is the workspace's skill library in the open SKILL.md format: write a skill in g1t, import a SKILL.md or zip, link a repository whose .g1t/skills folders publish on every push, or save a finished session as a skill once a person reviews it; attach a skill to an agent, a team or the whole workspace, each attachment pinned to a version. Agents see each skill's name and when to use it, and read the rest with use_skill when a request needs it; a skill never adds a permission, and scripts wait for an agent's own computer. The agent skills guide says how.1/**
2 * A workspace's skill library (docs.g1t.sh/guides/agent-skills/): the
3 * skills it wrote, imported, saved from a session or follows from a
4 * repository, each a SKILL.md folder (skill-format.ts), every change a new
5 * version. A skill does nothing until it is attached: to one agent, to a
6 * team (every agent on it), or to the whole workspace. Each attachment
7 * pins the version its agents use, so an edit never reaches an agent until
8 * someone moves the pin ("update available").
9 *
10 * Who may do what:
11 *
12 * - **Everyone in the workspace** sees the library, and can save a draft
13 * from a session they can see.
14 * - **Team maintainers** write and import skills, edit the ones they
15 * wrote, publish drafts, and attach skills to the teams they maintain.
16 * - **Owners** do all of that for any skill, attach skills to agents and
17 * to the whole workspace, delete skills, and link the repository the
18 * library follows.
19 *
20 * Served by the agents service (`POST /rpc/<method>`); wire shapes are
21 * snake_case.
22 */
23import type { ServiceBinding } from "./clients";
24import type { User } from "./identity";
25import type { Result } from "./result";
26import type { SkillFile } from "./skill-format";
27
28/** Where a skill is attached. */
29export type SkillScope = "agent" | "team" | "workspace";
30
31export type SkillAttachment = {
32 id: string;
33 scope: SkillScope;
34 /** The agent's handle or the team's slug; null for the whole workspace. */
35 target: string | null;
36 /** How it reads: "@margo", "QA", "Every agent". */
37 label: string;
38 /** The version the agents it reaches use. */
39 version: number;
40 attached_by: string;
41 attached_at: string;
42 /** Whether the viewer may detach it or move its version. */
43 can_change: boolean;
44};
45
46/** Where a version came from. */
47export type SkillOrigin =
48 | { kind: "written" }
49 | { kind: "upload"; filename: string }
50 /** Read from a folder of a repository at one commit. */
51 | { kind: "repository"; repo: string; path: string; ref: string; commit: string }
52 /** Drafted by an agent from a finished session. */
53 | { kind: "session"; session_id: string; agent: string; title: string }
Merge branch 'customize' into main: Customize replaces the Marketplace, the Artifacts trash and spaces changes, the Security-free cleanup, with the desktop app's own title bar kept in the shell.54 /** From `.claude/skills/<name>/` in the repository the library follows. */
55 | { kind: "mirror"; repo: string; path: string; commit: string }
56 /** From a plugin installed from a marketplace (./claude-plugin.ts), at the commit it was read at. */
57 | { kind: "plugin"; plugin: string; marketplace: string; path: string; sha: string | null };
Agents → Skills is the workspace's skill library in the open SKILL.md format: write a skill in g1t, import a SKILL.md or zip, link a repository whose .g1t/skills folders publish on every push, or save a finished session as a skill once a person reviews it; attach a skill to an agent, a team or the whole workspace, each attachment pinned to a version. Agents see each skill's name and when to use it, and read the rest with use_skill when a request needs it; a skill never adds a permission, and scripts wait for an agent's own computer. The agent skills guide says how.58
59/** A draft is waiting for a person to review it; only published skills can be attached. */
60export type SkillStatus = "published" | "draft";
61
62export type LibrarySkill = {
63 id: string;
64 name: string;
Merge branch 'customize' into main: Customize replaces the Marketplace, the Artifacts trash and spaces changes, the Security-free cleanup, with the desktop app's own title bar kept in the shell.65 /** The plugin it came with (`name@marketplace`), or null for the workspace's own. */
66 plugin: string | null;
67 /** What agents and people call it: `plugin:name` for a plugin's skill, the name alone otherwise. */
68 qualified_name: string;
Agents → Skills is the workspace's skill library in the open SKILL.md format: write a skill in g1t, import a SKILL.md or zip, link a repository whose .g1t/skills folders publish on every push, or save a finished session as a skill once a person reviews it; attach a skill to an agent, a team or the whole workspace, each attachment pinned to a version. Agents see each skill's name and when to use it, and read the rest with use_skill when a request needs it; a skill never adds a permission, and scripts wait for an agent's own computer. The agent skills guide says how.69 /** When to use it. */
70 description: string;
71 status: SkillStatus;
72 /** The newest version. */
73 version: number;
74 tools: string[];
75 /** Needs the agent's own computer: marked, and its scripts aren't run, until agents have one. */
76 requires_computer: boolean;
77 /** Files besides SKILL.md. */
78 files: number;
79 bytes: number;
80 /** Where the newest version came from. */
81 origin: SkillOrigin;
82 /** Follows the repository the library is linked to: it is changed there, not here. */
83 mirrored: boolean;
84 attachments: SkillAttachment[];
85 created_by: string;
86 created_at: string;
87 updated_by: string;
88 updated_at: string;
89 /** Whether the viewer may edit it (or publish it, for a draft). */
90 can_edit: boolean;
91 /** Whether the viewer may delete it (or discard it, for a draft). */
92 can_delete: boolean;
93};
94
95/** One file of a version, as the skill's page shows it. */
96export type SkillFileEntry = {
97 path: string;
98 bytes: number;
99 encoding: "utf8" | "base64";
100 /** Text files' content, up to 200 KB; null for others. */
101 content: string | null;
102 /** Under `scripts/`: run only on an agent's computer. */
103 script: boolean;
104};
105
106export type SkillVersionEntry = {
107 version: number;
108 description: string;
109 note: string | null;
110 origin: SkillOrigin;
111 bytes: number;
112 files: number;
113 created_by: string;
114 created_at: string;
115};
116
117export type SkillDetail = {
118 skill: LibrarySkill;
119 /** The version shown: the newest unless another was asked for. */
120 shown: number;
121 skill_md: string;
122 /** The instructions: SKILL.md after its front-matter. */
123 instructions: string;
124 tools: string[];
125 requires_computer: boolean;
126 /** Front-matter keys g1t doesn't read, kept as written. */
127 extra: Record<string, unknown>;
128 files: SkillFileEntry[];
129 versions: SkillVersionEntry[];
130};
131
132/** The repository the library follows: `.g1t/skills/<name>/` on its default branch. */
133export type SkillMirror = {
134 /** `workspace/name`. */
135 repo: string;
136 branch: string;
137 /** The commit last read. */
138 commit: string | null;
139 synced_at: string | null;
140 /** What went wrong the last time it was read, if it did. */
141 error: string | null;
142 linked_by: string;
143 linked_at: string;
144};
145
146export type SkillLibrary = {
147 skills: LibrarySkill[];
148 mirror: SkillMirror | null;
149 /** May write and import skills: owners and team maintainers. */
150 can_write: boolean;
151 /** Owners: attach to agents and the whole workspace, delete any skill, link a repository. */
152 can_manage: boolean;
153 /** The teams the viewer may attach skills to. */
154 teams: { slug: string; name: string }[];
155 /** The agents an owner may attach skills to. */
156 agents: { handle: string; display_name: string }[];
157};
158
159/** A skill written or changed in the editor. */
160export type SkillInput = {
161 name: string;
162 /** When to use it. */
163 description: string;
164 /** The instructions, in Markdown. */
165 instructions: string;
166 tools?: string[];
167 requires_computer?: boolean;
168 /** Files to add, or to replace at the same path; the current version's others are kept. */
169 add_files?: SkillFile[] | null;
170 /** Paths of the current version's files to leave out. */
171 remove_files?: string[] | null;
172 /** What changed, shown in its history. */
173 note?: string | null;
174 /** Move every attachment the editor may change to the new version (the default). */
175 update_attachments?: boolean;
176};
177
178/** Where an imported skill comes from. */
179export type SkillImport =
180 /** A SKILL.md, or a zip of a skill's folder, as standard base64. */
181 | { kind: "upload"; filename: string; data_base64: string }
182 /** A folder in a repository the viewer can read, at a branch, tag or commit (the default branch when absent). */
183 | { kind: "repository"; repo: string; path: string; ref?: string | null };
184
185/** One skill an agent has, as its Skills tab lists it. */
186export type AgentSkillLine = {
187 /** A foundational skill's id, or a library skill's. */
188 id: string;
189 name: string;
Merge branch 'customize' into main: Customize replaces the Marketplace, the Artifacts trash and spaces changes, the Security-free cleanup, with the desktop app's own title bar kept in the shell.190 /** The plugin it came with, or null. */
191 plugin: string | null;
Agents → Skills is the workspace's skill library in the open SKILL.md format: write a skill in g1t, import a SKILL.md or zip, link a repository whose .g1t/skills folders publish on every push, or save a finished session as a skill once a person reviews it; attach a skill to an agent, a team or the whole workspace, each attachment pinned to a version. Agents see each skill's name and when to use it, and read the rest with use_skill when a request needs it; a skill never adds a permission, and scripts wait for an agent's own computer. The agent skills guide says how.192 description: string;
193 foundational: boolean;
194 /** Whether it is on for this agent (owners turn skills off per agent). */
195 on: boolean;
196 /** How the agent has it; null for a foundational skill. */
197 via: SkillScope | null;
198 via_label: string | null;
199 attachment_id: string | null;
200 /** The version it uses: a release like "2026.10" for foundational skills. */
201 version: string;
202 /** A newer published version, if there is one. */
203 update: number | null;
204 requires_computer: boolean;
205 tools: string[];
206 /** Whether the viewer may move this attachment's version or detach it. */
207 can_change: boolean;
208};
209
210export type AgentSkills = {
211 handle: string;
212 skills: AgentSkillLine[];
213 /** Library skills past the limit of 100, which the agent doesn't get. */
214 over_limit: number;
215};
216
217export interface SkillLibraryApi {
218 library(workspace: string, viewer: User): Promise<Result<SkillLibrary>>;
219 skill(workspace: string, viewer: User, name: string, version?: number | null): Promise<Result<SkillDetail>>;
220 /** A new skill (`name` null) or a new version of one; a draft is published by saving it. */
221 saveSkill(workspace: string, viewer: User, name: string | null, input: SkillInput): Promise<Result<SkillDetail>>;
222 /** A new skill, or with `replace` a new version of the one with its name. */
223 importSkill(workspace: string, viewer: User, source: SkillImport, replace?: boolean): Promise<Result<SkillDetail>>;
224 /** `target` is an agent's handle or a team's slug; null for the whole workspace. Pins the newest version. */
225 attachSkill(workspace: string, viewer: User, name: string, scope: SkillScope, target: string | null): Promise<Result<SkillDetail>>;
226 detachSkill(workspace: string, viewer: User, name: string, attachment: string): Promise<Result<SkillDetail>>;
227 /** Moves an attachment to another version: the newest when `version` is null. */
228 pinSkill(workspace: string, viewer: User, name: string, attachment: string, version: number | null): Promise<Result<SkillDetail>>;
229 /** Removes a skill and its attachments; for a draft, discards it. */
230 deleteSkill(workspace: string, viewer: User, name: string): Promise<Result<null>>;
231 /** An agent's skills: g1t's foundational ones and the library's that reach it. */
232 agentSkills(workspace: string, viewer: User, handle: string): Promise<Result<AgentSkills>>;
233 /** The session's agent drafts a skill from its transcript, billed as its work; a person reviews it before it is published. */
234 draftFromSession(workspace: string, viewer: User, session: string): Promise<Result<SkillDetail>>;
235 /** Links the repository the library follows (`workspace/name`), or unlinks it (null), and reads it. Owners. */
236 setMirror(workspace: string, viewer: User, repo: string | null): Promise<Result<{ mirror: SkillMirror | null; changed: string[]; problems: string[] }>>;
237 /** Reads the linked repository again. */
238 syncMirror(workspace: string, viewer: User): Promise<Result<{ mirror: SkillMirror | null; changed: string[]; problems: string[] }>>;
239}
240
241async function rpc<T>(service: ServiceBinding, method: string, args: object): Promise<T> {
242 const response = await service.fetch(`https://service/rpc/${method}`, {
243 method: "POST",
244 headers: { "content-type": "application/json" },
245 body: JSON.stringify(args),
246 });
247 if (!response.ok) throw new Error(`${method} failed with status ${response.status}`);
248 return (await response.json()) as T;
249}
250
251export function skillLibraryClient(service: ServiceBinding): SkillLibraryApi {
252 const call = <T>(method: string, args: object) => rpc<T>(service, method, args);
253 return {
254 library: (workspace, viewer) => call("skill_library", { workspace, viewer }),
255 skill: (workspace, viewer, name, version) => call("skill", { workspace, viewer, name, version: version ?? null }),
256 saveSkill: (workspace, viewer, name, input) => call("save_skill", { workspace, viewer, name, input }),
257 importSkill: (workspace, viewer, source, replace) => call("import_skill", { workspace, viewer, source, replace: replace === true }),
258 attachSkill: (workspace, viewer, name, scope, target) => call("attach_skill", { workspace, viewer, name, scope, target }),
259 detachSkill: (workspace, viewer, name, attachment) => call("detach_skill", { workspace, viewer, name, attachment }),
260 pinSkill: (workspace, viewer, name, attachment, version) => call("pin_skill", { workspace, viewer, name, attachment, version }),
261 deleteSkill: (workspace, viewer, name) => call("delete_skill", { workspace, viewer, name }),
262 agentSkills: (workspace, viewer, handle) => call("agent_skills", { workspace, viewer, handle }),
263 draftFromSession: (workspace, viewer, session) => call("draft_skill", { workspace, viewer, session }),
264 setMirror: (workspace, viewer, repo) => call("set_skill_mirror", { workspace, viewer, repo }),
265 syncMirror: (workspace, viewer) => call("sync_skill_mirror", { workspace, viewer }),
266 };
267}

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