toenobu-agent 0.1.4 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,64 @@
1
+ Here's a thorough analysis of the `handoff.ts` extension:
2
+
3
+ ---
4
+
5
+ ## 📋 Summary: `handoff.ts` Extension
6
+
7
+ ### 1. What It Does
8
+
9
+ **Handoff** is a session-transfer extension for a coding agent (part of the `pi-mono` monorepo). Its purpose is to **intelligently transfer context from one conversation session to a new, focused one** — without the information loss that comes with simple context compaction.
10
+
11
+ When you invoke `/handoff <goal>`, it:
12
+ 1. Reads the current conversation history
13
+ 2. Uses an LLM to generate a concise, self-contained "handoff prompt" summarizing relevant context + your stated goal
14
+ 3. Lets you **edit the generated prompt** before committing
15
+ 4. Creates a **new session** (with a reference to the parent session)
16
+ 5. Pre-fills the editor with the prompt, ready for submission
17
+
18
+ ---
19
+
20
+ ### 2. Key Features & Functionality
21
+
22
+ | Feature | Details |
23
+ |---|---|
24
+ | **`/handoff <goal>` command** | Registered via `pi.registerCommand("handoff", ...)` |
25
+ | **LLM-powered summarization** | Calls `complete()` with a carefully crafted system prompt to distill the conversation |
26
+ | **Structured output format** | Generated prompt follows a `## Context / ## Task` format — concise but self-contained |
27
+ | **Abortable loader UI** | Shows a `BorderedLoader` while generating; supports abort/cancel mid-flight via `AbortSignal` |
28
+ | **Interactive prompt editing** | Opens an editor UI (`ctx.ui.editor(...)`) for the user to refine the generated prompt before proceeding |
29
+ | **Parent session tracking** | New session is created with `parentSession` linked to the current one, preserving lineage |
30
+ | **Error handling** | Guards for: no UI, no model, empty goal, empty conversation, auth failures, generation failures, user cancellations |
31
+
32
+ ---
33
+
34
+ ### 3. Dependencies & Requirements
35
+
36
+ **Runtime Dependencies:**
37
+ - `@mariozechner/pi-ai` — provides `complete()` (LLM call) and the `Message` type
38
+ - `@mariozechner/pi-coding-agent` — provides:
39
+ - `ExtensionAPI` / `SessionEntry` — extension host contract
40
+ - `BorderedLoader` — terminal UI loading indicator
41
+ - `convertToLlm` / `serializeConversation` — conversation format utilities
42
+
43
+ **Runtime Requirements:**
44
+ - Must run in **interactive (UI) mode** — `ctx.hasUI` is checked first
45
+ - A **model must be selected** (`ctx.model`)
46
+ - A valid **API key** must be available via `ctx.modelRegistry.getApiKeyAndHeaders()`
47
+ - An existing **non-empty conversation** to hand off
48
+
49
+ ---
50
+
51
+ ### 4. Implementation Complexity
52
+
53
+ **Overall: Low-to-Medium** ⚙️
54
+
55
+ | Aspect | Assessment |
56
+ |---|---|
57
+ | **Code size** | ~130 lines — compact and focused |
58
+ | **Control flow** | Linear with clear early-exit guards; async/await throughout |
59
+ | **LLM integration** | Single `complete()` call with a static system prompt — no streaming, no multi-turn |
60
+ | **UI interaction** | Uses 3 UI primitives: `custom()` (loader), `editor()`, `setEditorText()` — all provided by the host |
61
+ | **State management** | Minimal — reads session branch, creates a new session, no persistent state |
62
+ | **Error paths** | Well-handled (null checks, try/catch, cancellation signals) |
63
+
64
+ The extension is a clean example of the **extension pattern** in `pi-coding-agent`: it relies heavily on the host `ExtensionAPI` for UI, auth, and session management, keeping its own logic thin — just orchestrating a generate → edit → create-session → pre-fill workflow.
@@ -0,0 +1,40 @@
1
+ {
2
+ "id": "49a97d86",
3
+ "title": "Implement handoff extension for session context transfer",
4
+ "tags": [
5
+ "extension",
6
+ "feature",
7
+ "pi",
8
+ "high-priority"
9
+ ],
10
+ "status": "completed",
11
+ "created_at": "2026-03-29T12:10:10.662Z",
12
+ "assigned_to_session": "e5898ce7-3b44-45b0-b50e-f8273d6419a4"
13
+ }
14
+
15
+ ## Overview
16
+ Create a 1:1 copy of the [pi-mono handoff.ts](https://github.com/badlogic/pi-mono/blob/main/packages/coding-agent/examples/extensions/handoff.ts) extension.
17
+
18
+ **Priority:** High
19
+
20
+ ## Implementation Steps
21
+ 1. **Setup dependencies** — Add `@mariozechner/pi-coding-agent` and `@mariozechner/pi-ai` to the project
22
+ 2. **Create extension folder** — `./extensions/`
23
+ 3. **Implement `handoff.ts`** — Copy reference implementation with:
24
+ - `/handoff <goal>` command
25
+ - LLM-powered conversation summarization
26
+ - `## Context` / `## Task` output format
27
+ - BorderedLoader UI + editor flow
28
+ - Parent session linking
29
+
30
+ ## Acceptance Criteria
31
+ - [x] Dependencies installed
32
+ - [x] `./extensions/handoff.ts` created
33
+ - [x] `/handoff <goal>` command works in interactive mode
34
+ - [x] Generates summarized context via LLM
35
+ - [x] Opens editor for prompt refinement
36
+ - [x] Creates new session with parent linkage
37
+
38
+ ## Reference
39
+ - Source: https://github.com/badlogic/pi-mono/blob/main/packages/coding-agent/examples/extensions/handoff.ts
40
+ - Analysis: `.pi/research-handoff.md`
@@ -0,0 +1,11 @@
1
+ {
2
+ "id": "67d010fe",
3
+ "title": "Delete skills/code-simplifier/",
4
+ "tags": [],
5
+ "status": "done",
6
+ "created_at": "2026-03-29T12:26:00.760Z"
7
+ }
8
+
9
+ Remove the unused code-simplifier skill from this project.
10
+
11
+ Path: `skills/code-simplifier/`
@@ -0,0 +1,23 @@
1
+ {
2
+ "id": "2b2baa06",
3
+ "title": "Update session-renamer skill to allow spaces and reference todo titles",
4
+ "tags": [
5
+ "skill",
6
+ "session-renamer",
7
+ "urgent"
8
+ ],
9
+ "status": "done",
10
+ "created_at": "2026-03-18T06:58:54.041Z"
11
+ }
12
+
13
+ ## Task
14
+ Update the session-renamer skill file with:
15
+
16
+ 1. **Naming format** - Allow spaces instead of kebab-case
17
+ 2. **Todo reference** - If session relates to a todo, use the todo's title as session name
18
+
19
+ ## File
20
+ `/Users/toenobu/homebrew/lib/node_modules/toenobu-agent/skills/session-renamer/SKILL.md`
21
+
22
+ ## Done when
23
+ Skill file updated and saved
package/Makefile CHANGED
@@ -19,3 +19,7 @@ major:
19
19
  # Publish toenobu-agent
20
20
  publish:
21
21
  npm publish
22
+
23
+ #
24
+ install:
25
+ npm install
@@ -0,0 +1,153 @@
1
+ /**
2
+ * Handoff extension - transfer context to a new focused session
3
+ *
4
+ * Instead of compacting (which is lossy), handoff extracts what matters
5
+ * for your next task and creates a new session with a generated prompt.
6
+ *
7
+ * Usage:
8
+ * /handoff now implement this for teams as well
9
+ * /handoff execute phase one of the plan
10
+ * /handoff check other places that need this fix
11
+ *
12
+ * The generated prompt appears as a draft in the editor for review/editing.
13
+ */
14
+
15
+ import { complete, type Message } from "@mariozechner/pi-ai";
16
+ import type { ExtensionAPI, SessionEntry } from "@mariozechner/pi-coding-agent";
17
+ import { BorderedLoader, convertToLlm, serializeConversation } from "@mariozechner/pi-coding-agent";
18
+
19
+ const SYSTEM_PROMPT = `You are a context transfer assistant. Given a conversation history and the user's goal for a new thread, generate a focused prompt that:
20
+
21
+ 1. Summarizes relevant context from the conversation (decisions made, approaches taken, key findings)
22
+ 2. Lists any relevant files that were discussed or modified
23
+ 3. Clearly states the next task based on the user's goal
24
+ 4. Is self-contained - the new thread should be able to proceed without the old conversation
25
+
26
+ Format your response as a prompt the user can send to start the new thread. Be concise but include all necessary context. Do not include any preamble like "Here's the prompt" - just output the prompt itself.
27
+
28
+ Example output format:
29
+ ## Context
30
+ We've been working on X. Key decisions:
31
+ - Decision 1
32
+ - Decision 2
33
+
34
+ Files involved:
35
+ - path/to/file1.ts
36
+ - path/to/file2.ts
37
+
38
+ ## Task
39
+ [Clear description of what to do next based on user's goal]`;
40
+
41
+ export default function (pi: ExtensionAPI) {
42
+ pi.registerCommand("handoff", {
43
+ description: "Transfer context to a new focused session",
44
+ handler: async (args, ctx) => {
45
+ if (!ctx.hasUI) {
46
+ ctx.ui.notify("handoff requires interactive mode", "error");
47
+ return;
48
+ }
49
+
50
+ if (!ctx.model) {
51
+ ctx.ui.notify("No model selected", "error");
52
+ return;
53
+ }
54
+
55
+ const goal = args.trim();
56
+ if (!goal) {
57
+ ctx.ui.notify("Usage: /handoff <goal for new thread>", "error");
58
+ return;
59
+ }
60
+
61
+ // Gather conversation context from current branch
62
+ const branch = ctx.sessionManager.getBranch();
63
+ const messages = branch
64
+ .filter((entry): entry is SessionEntry & { type: "message" } => entry.type === "message")
65
+ .map((entry) => entry.message);
66
+
67
+ if (messages.length === 0) {
68
+ ctx.ui.notify("No conversation to hand off", "error");
69
+ return;
70
+ }
71
+
72
+ // Convert to LLM format and serialize
73
+ const llmMessages = convertToLlm(messages);
74
+ const conversationText = serializeConversation(llmMessages);
75
+ const currentSessionFile = ctx.sessionManager.getSessionFile();
76
+
77
+ // Generate the handoff prompt with loader UI
78
+ const result = await ctx.ui.custom<string | null>((tui, theme, _kb, done) => {
79
+ const loader = new BorderedLoader(tui, theme, `Generating handoff prompt...`);
80
+ loader.onAbort = () => done(null);
81
+
82
+ const doGenerate = async () => {
83
+ const auth = await ctx.modelRegistry.getApiKeyAndHeaders(ctx.model!);
84
+ if (!auth.ok || !auth.apiKey) {
85
+ throw new Error(auth.ok ? `No API key for ${ctx.model!.provider}` : auth.error);
86
+ }
87
+
88
+ const userMessage: Message = {
89
+ role: "user",
90
+ content: [
91
+ {
92
+ type: "text",
93
+ text: `## Conversation History\n\n${conversationText}\n\n## User's Goal for New Thread\n\n${goal}`,
94
+ },
95
+ ],
96
+ timestamp: Date.now(),
97
+ };
98
+
99
+ const response = await complete(
100
+ ctx.model!,
101
+ { systemPrompt: SYSTEM_PROMPT, messages: [userMessage] },
102
+ { apiKey: auth.apiKey, headers: auth.headers, signal: loader.signal },
103
+ );
104
+
105
+ if (response.stopReason === "aborted") {
106
+ return null;
107
+ }
108
+
109
+ return response.content
110
+ .filter((c): c is { type: "text"; text: string } => c.type === "text")
111
+ .map((c) => c.text)
112
+ .join("\n");
113
+ };
114
+
115
+ doGenerate()
116
+ .then(done)
117
+ .catch((err) => {
118
+ console.error("Handoff generation failed:", err);
119
+ done(null);
120
+ });
121
+
122
+ return loader;
123
+ });
124
+
125
+ if (result === null) {
126
+ ctx.ui.notify("Cancelled", "info");
127
+ return;
128
+ }
129
+
130
+ // Let user edit the generated prompt
131
+ const editedPrompt = await ctx.ui.editor("Edit handoff prompt", result);
132
+
133
+ if (editedPrompt === undefined) {
134
+ ctx.ui.notify("Cancelled", "info");
135
+ return;
136
+ }
137
+
138
+ // Create new session with parent tracking
139
+ const newSessionResult = await ctx.newSession({
140
+ parentSession: currentSessionFile,
141
+ });
142
+
143
+ if (newSessionResult.cancelled) {
144
+ ctx.ui.notify("New session cancelled", "info");
145
+ return;
146
+ }
147
+
148
+ // Set the edited prompt in the main editor for submission
149
+ ctx.ui.setEditorText(editedPrompt);
150
+ ctx.ui.notify("Handoff ready. Submit when ready.", "info");
151
+ },
152
+ });
153
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "toenobu-agent",
3
- "version": "0.1.4",
3
+ "version": "0.2.1",
4
4
  "description": "toenobu's pi coding agent skills and extensions",
5
5
  "repository": {
6
6
  "type": "git",
@@ -15,10 +15,14 @@
15
15
  "pi": {
16
16
  "skills": [
17
17
  "./skills"
18
+ ],
19
+ "extensions": [
20
+ "./extensions"
18
21
  ]
19
22
  },
20
23
  "peerDependencies": {
21
- "@mariozechner/pi-coding-agent": "*"
24
+ "@mariozechner/pi-coding-agent": "*",
25
+ "@mariozechner/pi-ai": "*"
22
26
  },
23
27
  "license": "MIT"
24
28
  }
@@ -1,53 +1,54 @@
1
1
  ---
2
- description: Analyzes session content and generates a meaningful, descriptive session name
2
+ description: Analyzes session content to generate a descriptive name or suggest deletion if meaningless
3
3
  ---
4
4
 
5
5
  # Session Renamer
6
6
 
7
- Use this skill when the user asks to name or rename the current session, or when a session needs a proper descriptive name.
7
+ Use when the user asks to name/rename the current session.
8
8
 
9
- ## Instructions
9
+ ## Process
10
10
 
11
- Analyze the conversation history and generate a concise, descriptive session name that:
11
+ 1. **Analyze** the conversation history
12
+ 2. **Decide**: meaningful content or not?
13
+ - **Meaningless** → suggest `/delete`
14
+ - **Meaningful** → generate 2-3 name candidates
15
+ 3. **Present** options to user
16
+ 4. **Apply** with `/name <chosen-name>` or `/delete`
12
17
 
13
- 1. **Captures the Main Topic**: Identify the primary task, feature, or topic discussed
14
- 2. **Is Concise**: Keep it short (3-6 words, under 50 characters)
15
- 3. **Uses Descriptive Words**: Include key technologies, actions, or domains
16
- 4. **Uses kebab-case**: Lowercase with hyphens for consistency
18
+ ## Meaningless Sessions
17
19
 
18
- ## Naming Patterns
20
+ Suggest deletion if the session:
21
+ - Contains only greetings or small talk (e.g., just "hello" with no follow-up)
22
+ - Has abandoned/incomplete queries with no outcome
23
+ - Consists of test messages or accidental inputs
24
+ - Has no code changes, file operations, or real discussion
19
25
 
20
- Good examples:
21
- - `refactor-auth-middleware`
22
- - `fix-typescript-build-errors`
23
- - `add-user-dashboard-feature`
24
- - `debug-api-rate-limiting`
25
- - `setup-docker-compose`
26
- - `create-session-renamer-skill`
26
+ **Output:**
27
+ ```
28
+ This session doesn't have meaningful content:
29
+ - [reason]
27
30
 
28
- Avoid:
29
- - Generic names like `coding-session`, `help-request`, or `chat`
30
- - Too long names (over 50 characters)
31
- - Names that don't reflect actual content
32
- - CamelCase or spaces
31
+ Delete with `/delete`? Or suggest a name to keep it.
32
+ ```
33
33
 
34
- ## Process
34
+ ## Meaningful Sessions
35
35
 
36
- 1. Review the conversation topics and tasks completed
37
- 2. Identify the dominant theme or objective
38
- 3. Generate 2-3 candidate names
39
- 4. Present candidates to user for selection
40
- 5. Once user confirms, apply with `/name <chosen-name>`
36
+ Generate names that:
37
+ - Capture the main topic (3-6 words, <50 chars)
38
+ - Use spaces (not kebab-case)
39
+ - Include key technologies, actions, or domains
40
+ - **If related to a todo**: use the todo's title as the session name
41
41
 
42
- ## Output Format
42
+ **Good:** `Refactor auth middleware`, `Fix TypeScript build errors`, `Setup Docker Compose`
43
43
 
44
- Present candidates like this:
44
+ **Avoid:** Generic (`coding session`), too long, doesn't reflect actual content
45
45
 
46
+ **Output:**
46
47
  ```
47
- Suggested session names:
48
- 1. `primary-topic-name`
49
- 2. `alternative-name`
50
- 3. `another-option`
48
+ Suggested names:
49
+ 1. `Primary topic name`
50
+ 2. `Alternative name`
51
+ 3. `Another option`
51
52
 
52
- Which one would you like? (or suggest your own)
53
+ Pick one or suggest your own.
53
54
  ```
@@ -1,44 +0,0 @@
1
- ---
2
- description: Simplifies and refines code for clarity, consistency, and maintainability while preserving all functionality
3
- ---
4
-
5
- # Code Simplifier
6
-
7
- Use this skill when the user asks to simplify, refine, or clean up code.
8
-
9
- ## Instructions
10
-
11
- You are an expert code simplification specialist focused on enhancing code clarity, consistency, and maintainability while preserving exact functionality.
12
-
13
- Analyze the code and apply refinements that:
14
-
15
- 1. **Preserve Functionality**: Never change what the code does - only how it does it. All original features, outputs, and behaviors must remain intact.
16
-
17
- 2. **Enhance Clarity**: Simplify code structure by:
18
- - Reducing unnecessary complexity and nesting
19
- - Eliminating redundant code and abstractions
20
- - Improving readability through clear variable and function names
21
- - Consolidating related logic
22
- - Removing unnecessary comments that describe obvious code
23
- - Avoid nested ternary operators - prefer switch statements or if/else chains
24
- - Choose clarity over brevity - explicit code is often better than overly compact code
25
-
26
- 3. **Maintain Balance**: Avoid over-simplification that could:
27
- - Reduce code clarity or maintainability
28
- - Create overly clever solutions that are hard to understand
29
- - Combine too many concerns into single functions
30
- - Prioritize "fewer lines" over readability
31
-
32
- 4. **Apply Best Practices**:
33
- - Follow project coding standards from AGENTS.md/CLAUDE.md if present
34
- - Use proper error handling patterns
35
- - Maintain consistent naming conventions
36
- - Use appropriate language idioms
37
-
38
- ## Process
39
-
40
- 1. Identify the code sections to simplify
41
- 2. Analyze for opportunities to improve elegance and consistency
42
- 3. Apply best practices and coding standards
43
- 4. Ensure all functionality remains unchanged
44
- 5. Verify the refined code is simpler and more maintainable