A session's title keeps up with what it turns out to be about, and the g1t plugin is 0.2.11. A session is titled by its first prompt, which often stops being what it is about, and agents were never told they could change it. Now the plugin's note at the start of a session says to retitle it in a few words with `g1t session attach --title` once what it is doing is clear and whenever that changes. At the second prompt and every fifth after, Claude gets a one-line reminder, not while the CLI is signed out or too old. The plugin guide says so. Checked: node --test plugins/claude-code/test/hooks.test.mjs (60; new: when the reminder comes), scripts/plugins-release.test.mjs (8); this session retitled itself with the command.
- G1t-Session:
- ses_01m5075p3weck8yhgj6kdx5nqb
5 files+38−60/5 viewed
| 7 | 7 | "name": "g1t", | |
| 8 | 8 | "source": "./plugins/claude-code", | |
| 9 | 9 | "description": "Work on g1t issues from Claude Code: records your sessions on g1t, loads an issue's work context, claims and hands off work, and connects g1t's MCP server.", | |
| 10 | − | "version": "0.2.10", | |
| 10 | + | "version": "0.2.11", | |
| 11 | 11 | "category": "development" | |
| 12 | 12 | } | |
| 13 | 13 | ] |
| 177 | 177 | **Session on** its branch. To name | |
| 178 | 178 | it yourself, or have Claude name it, run | |
| 179 | 179 | `g1t session attach --title "Fix the preview builds"`; that replaces | |
| 180 | − | the title the prompt gave. | |
| 180 | + | the title the prompt gave. Claude keeps it true as the work turns | |
| 181 | + | out to be something else: the plugin tells it at the start that it | |
| 182 | + | can retitle the session, and reminds it at the second prompt and every | |
| 183 | + | fifth after (not while the CLI is signed out or too old). | |
| 181 | 184 | 2. **It shows to the team.** The project's overview and its **Work** page | |
| 182 | 185 | list it in **Live now** under its pull request, else its branch, else | |
| 183 | 186 | under **No branch yet**, with who it is for, Claude Code, its state, |
| 1 | 1 | { | |
| 2 | 2 | "name": "g1t", | |
| 3 | − | "version": "0.2.10", | |
| 3 | + | "version": "0.2.11", | |
| 4 | 4 | "description": "Work on g1t issues from Claude Code: records your sessions on g1t, loads an issue's work context, claims and hands off work, and connects g1t's MCP server.", | |
| 5 | 5 | "author": { "name": "Flagon, Inc.", "url": "https://g1t.sh" }, | |
| 6 | 6 | "homepage": "https://docs.g1t.sh/guides/claude-code-plugin/", |
| 1023 | 1023 | const TRAILER = "Add the trailer `G1t-Session: $G1T_SESSION` to the commits you make (git commit --trailer), so g1t ties them to this session. A commit pushed straight to the default branch that finishes an issue says `Closes #N` in its message: a bare `(#N)` only links it, and the issue stays open."; | |
| 1024 | 1024 | ||
| 1025 | 1025 | /** | |
| 1026 | + | * How the agent keeps its session's title true: it starts as the first | |
| 1027 | + | * prompt's intent, which often stops being what the session is about. | |
| 1028 | + | */ | |
| 1029 | + | export const RETITLE = 'Its title starts as your first prompt; once what you are actually doing is clear, and whenever it changes, retitle it in a few words with `g1t session attach --title "…"`.'; | |
| 1030 | + | ||
| 1031 | + | /** | |
| 1032 | + | * At which prompts the agent is reminded to retitle: the second (what the | |
| 1033 | + | * work is has usually shown by then) and every fifth after. | |
| 1034 | + | */ | |
| 1035 | + | export function retitleNudge(turn) { | |
| 1036 | + | return turn === 2 || (turn > 2 && turn % 5 === 0) ? `g1t: if this session's title no longer says what it is doing, retitle it: \`g1t session attach --title "…"\`.` : null; | |
| 1037 | + | } | |
| 1038 | + | ||
| 1039 | + | /** | |
| 1026 | 1040 | * SessionStart: marks the session as one in a g1t working copy, and | |
| 1027 | 1041 | * returns what to print: context for Claude, and a notice for you, once. | |
| 1028 | 1042 | * Null outside a g1t working copy, where nothing is recorded. | |
| ⋯ | |||
| 1063 | 1077 | context = `g1t: ${where} points at issue #${issue}. Load what is known about it with \`g1t work context ${issue}\`, and claim it with \`g1t work claim ${issue}\` before you start. ${TRAILER}`; | |
| 1064 | 1078 | } | |
| 1065 | 1079 | } else { | |
| 1066 | − | context = `g1t: this session is recorded on g1t and shows to the team, titled with what you are asked to do. Just work. If it turns into a change others should know about (a branch to push, a pull request), first look for its issue (\`g1t work list\`, \`g1t issue list\`) and claim it with \`g1t work claim N\`; if there is none, open and claim one with \`g1t work claim --title "…"\`. Never open issues for questions, exploration or trivial fixes. ${TRAILER}`; | |
| 1080 | + | context = `g1t: this session is recorded on g1t and shows to the team, titled with what you are asked to do. Just work. If it turns into a change others should know about (a branch to push, a pull request), first look for its issue (\`g1t work list\`, \`g1t issue list\`) and claim it with \`g1t work claim N\`; if there is none, open and claim one with \`g1t work claim --title "…"\`. Never open issues for questions, exploration or trivial fixes. ${RETITLE} ${TRAILER}`; | |
| 1067 | 1081 | } | |
| 1068 | 1082 | if (context) output.hookSpecificOutput = { hookEventName: "SessionStart", additionalContext: context }; | |
| 1069 | 1083 | return output; | |
| ⋯ | |||
| 1236 | 1250 | return { output: { hookSpecificOutput: { hookEventName: "SubagentStart", additionalContext: subagentContext(issue) } }, job }; | |
| 1237 | 1251 | } | |
| 1238 | 1252 | const notice = late?.output.systemMessage ?? (name === "UserPromptSubmit" ? takeNotice(env) : null); | |
| 1239 | − | const context = [late?.output.hookSpecificOutput?.additionalContext, name === "UserPromptSubmit" ? updateContext(event, env) : null] | |
| 1253 | + | const context = [ | |
| 1254 | + | late?.output.hookSpecificOutput?.additionalContext, | |
| 1255 | + | name === "UserPromptSubmit" ? updateContext(event, env) : null, | |
| 1256 | + | // Only while it is being recorded: not with the CLI signed out or too old. | |
| 1257 | + | name === "UserPromptSubmit" && !readJson(join(dataDir(env), "notice.json"), {}).problem ? retitleNudge(turn) : null, | |
| 1258 | + | ] | |
| 1240 | 1259 | .filter(Boolean) | |
| 1241 | 1260 | .join("\n\n"); | |
| 1242 | 1261 | return { output: context || notice ? { | |
| 8 | 8 | import { fileURLToPath } from "node:url"; | |
| 9 | 9 | ||
| 10 | 10 | import { | |
| 11 | + | retitleNudge, | |
| 11 | 12 | updateContext, | |
| 12 | 13 | UPDATES_REPEAT_MS, | |
| 13 | 14 | howToUpdate, | |
| ⋯ | |||
| 832 | 833 | assert.match(context, /Just work/); | |
| 833 | 834 | assert.match(context, /`g1t work claim --title "…"`/); | |
| 834 | 835 | assert.match(context, /Never open issues for questions, exploration or trivial fixes/); | |
| 835 | − | assert.ok(context.length < 900, `injected every session, so short: ${context.length}`); | |
| 836 | + | assert.match(context, /retitle it in a few words with `g1t session attach --title "…"`/); | |
| 837 | + | assert.ok(context.length < 1100, `injected every session, so short: ${context.length}`); | |
| 836 | 838 | assert.ok(!calls().some((c) => c.args[0] === "work"), "no issue's context is asked for"); | |
| 837 | 839 | }); | |
| 838 | 840 | ||
| 841 | + | test("Claude is reminded to retitle the session at its second prompt and every fifth after, no more", () => { | |
| 842 | + | assert.deepEqual( | |
| 843 | + | Array.from({ length: 16 }, (_, i) => i + 1).filter((turn) => retitleNudge(turn)), | |
| 844 | + | [2, 5, 10, 15], | |
| 845 | + | ); | |
| 846 | + | assert.match(retitleNudge(2), /g1t session attach --title/); | |
| 847 | + | }); | |
| 848 | + | ||
| 839 | 849 | test("the session's first prompt with an intent titles it, once, and never over a title it has", () => { | |
| 840 | 850 | hook({ ...base, cwd: dir, hook_event_name: "SessionStart" }, env); | |
| 841 | 851 | work({ cwd: dir, sid: base.session_id, start: true, steps: [] }, env); | |
Comments
Sign in to comment.