toenobu-agent 0.2.0 → 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/`
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.2.0",
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,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
File without changes