osborn 0.9.212 → 0.9.213

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.
@@ -1,3 +1,8 @@
1
+ ---
2
+ name: browser-apply
3
+ description: Interactively automate Workday and other multi-step JS-heavy job application forms using Playwright MCP browser tools, filling one page at a time with a screenshot and user confirmation before advancing. Use when applying to a Workday ATS or any staged online job application needing visible, confirmable progress.
4
+ ---
5
+
1
6
  # Skill: Browser Apply — Step-by-Step Workday Application
2
7
 
3
8
  Automate Workday job applications interactively, one step at a time. Each step takes a screenshot, confirms what's on screen, fills the current page, and waits before proceeding.
@@ -1,3 +1,8 @@
1
+ ---
2
+ name: browser-screen-recorder
3
+ description: Drive any web app in a real browser and record proof — per-action screenshots, video clips, audio capture, DevTools diagnostics, and metrics, with mic synthesis and natural-language clicking. Use as the QA protocol after building or changing any frontend, for debugging web-reachable issues, verifying deployed changes, or reproducing user reports.
4
+ ---
5
+
1
6
  # Browser Screen Recorder — drive any web app (voice, hands + a brain) and record proof
2
7
 
3
8
  ## SKILL IDENTITY
@@ -1,3 +1,8 @@
1
+ ---
2
+ name: deploy-workflow
3
+ description: The end-to-end release procedure for shipping osborn agent changes — build and verify locally, bump the package.json version, push to GitHub, publish to NPM from the Mac, and update the running Sprite from the registry. Use every time code or prompt changes are ready to ship.
4
+ ---
5
+
1
6
  # Deploy Workflow
2
7
 
3
8
  Use this every time changes are ready to ship.
@@ -1,3 +1,8 @@
1
+ ---
2
+ name: ground-assumptions
3
+ description: Treat every load-bearing assumption as a hypothesis to verify against real evidence before recommending an implementation strategy, rather than trusting training-data intuition or "it should work". Use whenever the conversation enters a planning, design, or architecture phase, or before making any performance, behavioral, or comparative claim.
4
+ ---
5
+
1
6
  # Ground Assumptions
2
7
 
3
8
  ## SKILL IDENTITY
@@ -1,3 +1,8 @@
1
+ ---
2
+ name: markdown-to-pdf
3
+ description: Export a Markdown document, spec, or research findings as a formatted PDF using md-to-pdf, pandoc, or markdown-pdf, saving the result to the session workspace. Use when the user wants to create or generate a PDF from a Markdown file.
4
+ ---
5
+
1
6
  # Skill: Markdown to PDF
2
7
 
3
8
  Export Markdown documents as formatted PDF files.
@@ -1,3 +1,8 @@
1
+ ---
2
+ name: meetings
3
+ description: Silently take notes and track TODOs while osborn sits in a live meeting via a Recall.ai bot, and pull transcripts on demand, delegating file and transcript work to the writer sub-agent to avoid the tool-call budget. Use for auto-tagged [MEETING] transcript chunks or when the user asks to grab, summarize, or write notes/todos from a meeting.
4
+ ---
5
+
1
6
  # Skill: Meetings
2
7
 
3
8
  Silent note-taking and TODO-tracking when osborn is sitting in a live meeting,
@@ -1,3 +1,8 @@
1
+ ---
2
+ name: pdf-to-markdown
3
+ description: Convert a PDF document to readable Markdown text using the built-in Read tool, pdf-parse-cli, or pdftotext, preserving headings and tables and saving the result to the session workspace. Use when the user provides a PDF file path and wants to read, search, or work with its contents.
4
+ ---
5
+
1
6
  # Skill: PDF to Markdown
2
7
 
3
8
  Convert PDF documents to readable Markdown text.
@@ -1,3 +1,8 @@
1
+ ---
2
+ name: playwright-browser
3
+ description: Automate web browser interactions via the @playwright/cli — navigate pages, click buttons and links, fill and submit forms, take screenshots, and extract text or structured data using token-efficient element references. Use to interact with a URL, automate a multi-step web workflow, or test a UI flow.
4
+ ---
5
+
1
6
  # Skill: Playwright Browser Automation
2
7
 
3
8
  Automate web browser interactions — navigate pages, click buttons, fill forms, take screenshots, and extract content.
@@ -1,3 +1,8 @@
1
+ ---
2
+ name: recall
3
+ description: Query this session's full untruncated history — every message, thinking block, and tool call stored in a per-session SQLite database with keyword and semantic search via the osborn-recall command. Use when you need an earlier decision, file, error, number, or name no longer in context, or to check prior work before acting as a grounded agent.
4
+ ---
5
+
1
6
  # Recall
2
7
 
3
8
  ## SKILL IDENTITY
@@ -1,3 +1,8 @@
1
+ ---
2
+ name: send-media
3
+ description: Upload a local file to the osborn public upload endpoint (Supabase storage) to get a permanent public URL, then render it inline in your next reply as a markdown image or link. Use whenever you have a local screenshot, image, PDF, clip, or log the user should see rather than have described.
4
+ ---
5
+
1
6
  # send-media — deliver screenshots, images, and files to the user INLINE in chat
2
7
 
3
8
  > 📅 Last updated: 2026-08-09. Use whenever you have a local file the user should SEE
@@ -1,3 +1,8 @@
1
+ ---
2
+ name: shadcn
3
+ description: Add and configure shadcn/ui components — the copy-paste library built on Radix UI and Tailwind CSS — in a Next.js or React project via the shadcn CLI, including first-time init and adding single or multiple components. Use when the user wants to add UI components like buttons, dialogs, cards, forms, or tables.
4
+ ---
5
+
1
6
  # Skill: shadcn/ui Components
2
7
 
3
8
  Add and configure shadcn/ui components in a Next.js or React project.
@@ -1,3 +1,8 @@
1
+ ---
2
+ name: slack-readonly
3
+ description: Search and read Slack messages, threads, and channels from the shell via read-only GET calls to the Slack Web API using a SLACK_TOKEN, with no posting, reactions, or edits by design. Use when asked to find, read, or summarize Slack content; refuse any request to send or write.
4
+ ---
5
+
1
6
  # Slack (read-only) — search and read Slack from the shell
2
7
 
3
8
  > 📅 **Last updated: 2026-08-09.** Recreated from scratch after the Mac data-loss events wiped the
@@ -1,3 +1,8 @@
1
+ ---
2
+ name: voice-native-sync
3
+ description: Sync osborn sessions between the local Mac and cloud machines, starting with a mandatory served-version check that self-updates and aborts on a stale local copy to prevent unresumable-session corruption. Use when uploading or downloading sessions for the voice-native osborn setup.
4
+ ---
5
+
1
6
  # Voice Native Sync Skill
2
7
 
3
8
  ## SKILL IDENTITY
@@ -1,3 +1,8 @@
1
+ ---
2
+ name: youtube-transcript
3
+ description: Fetch a YouTube video's auto-generated English subtitles with yt-dlp, strip the SRT timing markers to clean transcript text, and save it to the session workspace. Use when the user asks to get a transcript, subtitles, captions, or summary from a YouTube video URL.
4
+ ---
5
+
1
6
  # Skill: YouTube Transcript
2
7
 
3
8
  Fetch and save transcripts from YouTube videos.
@@ -199,6 +199,58 @@ function loadAllSkills(_workingDir) {
199
199
  console.log(`📚 Loaded ${skillMap.size} skill(s) from ${homeSkillsDir}`);
200
200
  return `<available-skills>\n${[...skillMap.values()].join('\n\n---\n\n')}\n</available-skills>`;
201
201
  }
202
+ /**
203
+ * Enumerate the agent's CURRENT skills (name + one-line description) from
204
+ * ~/.claude/skills, for injection into the PreCompact instruction. This is the
205
+ * list the compaction model dedupes/merges against so it stops re-emitting
206
+ * duplicate skills every session. Description is taken from YAML frontmatter
207
+ * (`description:`) when present, else the WHEN: line, else the first non-heading
208
+ * line. Returns one `- name: description` per line, or '' if none.
209
+ */
210
+ function enumerateSkillsForCompaction() {
211
+ const dir = join(homedir(), '.claude', 'skills');
212
+ if (!existsSync(dir))
213
+ return '';
214
+ const lines = [];
215
+ try {
216
+ for (const name of readdirSync(dir).sort()) {
217
+ const file = join(dir, name, 'SKILL.md');
218
+ if (!existsSync(file))
219
+ continue;
220
+ let desc = '';
221
+ try {
222
+ const raw = readFileSync(file, 'utf-8');
223
+ const fm = raw.match(/^---\n([\s\S]*?)\n---/);
224
+ if (fm) {
225
+ const m = fm[1].match(/^description:\s*(.+)$/m);
226
+ if (m)
227
+ desc = m[1].trim();
228
+ }
229
+ if (!desc) {
230
+ const body = raw.replace(/^---\n[\s\S]*?\n---\n?/, '');
231
+ const when = body.match(/^\s*WHEN:\s*(.+)$/mi);
232
+ if (when)
233
+ desc = when[1].trim();
234
+ }
235
+ if (!desc) {
236
+ const body = raw.replace(/^---\n[\s\S]*?\n---\n?/, '');
237
+ const first = body.split('\n').map(l => l.trim()).find(l => l && !l.startsWith('#'));
238
+ desc = first || '(no description)';
239
+ }
240
+ }
241
+ catch {
242
+ desc = '(unreadable)';
243
+ }
244
+ if (desc.length > 180)
245
+ desc = desc.slice(0, 177) + '…';
246
+ lines.push(`- ${name}: ${desc}`);
247
+ }
248
+ }
249
+ catch (err) {
250
+ console.warn('⚠️ enumerateSkillsForCompaction failed:', err instanceof Error ? err.message : err);
251
+ }
252
+ return lines.join('\n');
253
+ }
202
254
  // Compaction threshold: Fable 5 runs a 1M context window, so let sessions use
203
255
  // all of it before auto-compacting. autoCompactWindow max is 1_000_000; the SDK
204
256
  // reads it from settings.json (settingSources includes 'user'), so merge it into
@@ -2105,8 +2157,28 @@ class ClaudeLLMStream extends llm.LLMStream {
2105
2157
  try {
2106
2158
  this.#opts.onCompactionEvent?.({ type: 'compaction_started', trigger: input?.trigger });
2107
2159
  const instructionPath = join(__claudeLlmDir, 'prompts', 'compact-learnings-instruction.md');
2108
- const instruction = existsSync(instructionPath) ? readFileSync(instructionPath, 'utf-8') : '';
2109
- console.log(`🧠 PreCompact: injecting instruction (${instruction.length} chars, trigger=${input?.trigger || 'unknown'})`);
2160
+ const instructionRaw = existsSync(instructionPath) ? readFileSync(instructionPath, 'utf-8') : '';
2161
+ // Populate the EXISTING SKILLS section the instruction .md already refers to
2162
+ // (lines 42 & 55) but that nothing used to fill. Without this, the model is told
2163
+ // to "not re-emit skills already shown" against a list it never received — so it
2164
+ // proliferated duplicates. We hand it the current skill set + an adversarial,
2165
+ // self-critical directive to merge/refine rather than create anew.
2166
+ const existingSkills = enumerateSkillsForCompaction();
2167
+ const skillCount = existingSkills ? existingSkills.split('\n').length : 0;
2168
+ const criticBlock = existingSkills
2169
+ ? `\n\n---\n\n=== EXISTING SKILLS (${skillCount}) ===\n`
2170
+ + `These skills ALREADY EXIST for this user (name: description). Before you emit `
2171
+ + `SKILL_CANDIDATES or BEHAVIORAL_LEARNINGS, act as an ADVERSARIAL reviewer of your own output:\n`
2172
+ + `1. If a candidate duplicates or substantially overlaps one below, DO NOT create a new skill — `
2173
+ + `re-emit it under the EXACT SAME kebab-case name, and only if it needs a substantive update; otherwise omit it.\n`
2174
+ + `2. Propose a brand-new skill ONLY if nothing below covers it, it was CONFIRMED working this session, `
2175
+ + `and it generalizes to future sessions on different tasks.\n`
2176
+ + `3. Prefer merging/refining over proliferating. A small set of sharp, non-overlapping skills is the goal — `
2177
+ + `reject your own low-signal or one-off candidates.\n\n`
2178
+ + `${existingSkills}\n`
2179
+ : '';
2180
+ const instruction = instructionRaw + criticBlock;
2181
+ console.log(`🧠 PreCompact: injecting instruction (${instruction.length} chars, ${skillCount} existing skills, trigger=${input?.trigger || 'unknown'})`);
2110
2182
  return { systemMessage: instruction };
2111
2183
  }
2112
2184
  catch (err) {
@@ -2166,7 +2238,7 @@ class ClaudeLLMStream extends llm.LLMStream {
2166
2238
  const decPath = join(decFolder, 'SKILL.md');
2167
2239
  mkdirSync(decFolder, { recursive: true });
2168
2240
  const existing = existsSyncFs(decPath) ? readSyncFs(decPath, 'utf-8') : '';
2169
- const header = existing ? '' : `# Project Decisions\n\nAuto-extracted from compact summaries.\n\n`;
2241
+ const header = existing ? '' : `---\nname: decisions\ndescription: "Project-scoped architectural and implementation decisions auto-extracted from compaction summaries; consult before revisiting settled choices."\nmetadata:\n type: learned\n source: postcompact\n---\n\n# Project Decisions\n\nAuto-extracted from compact summaries.\n\n`;
2170
2242
  const entry = `\n## ${today} (session ${sessionId.substring(0, 8)})\n${projectLines.join('\n')}\n`;
2171
2243
  writeSyncFs(decPath, header + existing + entry, 'utf-8');
2172
2244
  console.log(`🧠 PostCompact: appended ${projectLines.length} decision(s) to ${decPath}`);
@@ -2196,8 +2268,14 @@ class ClaudeLLMStream extends llm.LLMStream {
2196
2268
  const skillFolder = join(skillDir, '.claude', 'skills', name);
2197
2269
  const skillPath = join(skillFolder, 'SKILL.md');
2198
2270
  mkdirSync(skillFolder, { recursive: true });
2199
- const header = `# ${name}\nAuto-extracted: ${today} | Session: ${sessionId.substring(0, 8)}\n\n`;
2200
- writeSyncFs(skillPath, header + body + '\n', 'utf-8');
2271
+ // Emit STANDARD skill format: YAML frontmatter (name + description) so
2272
+ // learned skills conform to the same shape the loader/other agents expect.
2273
+ // Description is derived from the candidate's WHEN: line; JSON.stringify
2274
+ // yields a safely-quoted YAML scalar even when it contains colons/quotes.
2275
+ const whenMatch = body.match(/^\s*WHEN:\s*(.+)$/mi);
2276
+ const desc = (whenMatch ? whenMatch[1].trim() : `Learned procedure: ${name}`).replace(/\s+/g, ' ').slice(0, 200);
2277
+ const frontmatter = `---\nname: ${name}\ndescription: ${JSON.stringify(desc)}\nmetadata:\n type: learned\n source: postcompact\n session: ${sessionId.substring(0, 8)}\n updated: ${today}\n---\n\n`;
2278
+ writeSyncFs(skillPath, frontmatter + `# ${name}\n\n` + body + '\n', 'utf-8');
2201
2279
  console.log(`🧠 PostCompact: wrote skill '${name}' to ${skillPath}`);
2202
2280
  skillsWritten++;
2203
2281
  skillNames.push(name);
@@ -2216,7 +2294,7 @@ class ClaudeLLMStream extends llm.LLMStream {
2216
2294
  const skillFolder = join(skillDir, '.claude', 'skills', 'learned-behaviors');
2217
2295
  const skillPath = join(skillFolder, 'SKILL.md');
2218
2296
  mkdirSync(skillFolder, { recursive: true });
2219
- const header = `# Learned Behaviors\n\nAuto-extracted from voice sessions via PostCompact.\nLast updated: ${today} | Session: ${sessionId.substring(0, 8)}...\n\n`;
2297
+ const header = `---\nname: learned-behaviors\ndescription: "User corrections, preferences, domain knowledge, effective patterns, and anti-patterns learned across sessions; apply to align with how this user works."\nmetadata:\n type: learned\n source: postcompact\n updated: ${today}\n---\n\n# Learned Behaviors\n\nAuto-extracted from voice sessions via PostCompact.\nLast updated: ${today} | Session: ${sessionId.substring(0, 8)}...\n\n`;
2220
2298
  writeSyncFs(skillPath, header + learnings + '\n', 'utf-8');
2221
2299
  console.log(`🧠 PostCompact: wrote learned behaviors to ${skillPath} (${learnings.length} chars)`);
2222
2300
  skillsWritten++;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "osborn",
3
- "version": "0.9.212",
3
+ "version": "0.9.213",
4
4
  "description": "Voice AI coding assistant - local agent that connects to Osborn frontend",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,46 +0,0 @@
1
- You are analyzing a voice AI assistant conversation to extract behavioral learnings that should persist across sessions.
2
-
3
- The conversation is between a user and "Osborn" — a voice AI thinking partner. Your job is to identify:
4
-
5
- 1. USER CORRECTIONS — things the user explicitly told the agent to stop doing or start doing differently
6
- 2. USER PREFERENCES — recurring patterns in how the user wants to work (tools, approaches, communication style)
7
- 3. DOMAIN KNOWLEDGE — specific technical facts learned during the session (API behaviors, selectors, platform quirks, vendor-specific details)
8
- 4. EFFECTIVE PATTERNS — approaches that worked well and the user confirmed or accepted without pushback
9
- 5. ANTI-PATTERNS — approaches that failed, got the user frustrated, or had to be abandoned
10
-
11
- For each item, include:
12
- - The specific learning (concrete, actionable)
13
- - Brief context for WHY (so future sessions can judge if it still applies)
14
- - Confidence level: HIGH (user explicitly stated it), MEDIUM (inferred from user behavior), LOW (observed but not confirmed)
15
-
16
- Output as markdown in this exact format:
17
-
18
- ```markdown
19
- # Session Learnings — {date}
20
-
21
- ## User Corrections (HIGH confidence)
22
- - {correction}: {context}
23
-
24
- ## User Preferences (MEDIUM-HIGH confidence)
25
- - {preference}: {context}
26
-
27
- ## Domain Knowledge Learned (varies)
28
- - [{confidence}] {fact}: {how it was verified}
29
-
30
- ## Effective Patterns (MEDIUM confidence)
31
- - {pattern}: {when it worked}
32
-
33
- ## Anti-Patterns to Avoid (HIGH confidence)
34
- - {anti-pattern}: {what went wrong}
35
- ```
36
-
37
- Be SELECTIVE. Only include items that are:
38
- - Generalizable to future sessions (not one-off task details)
39
- - Actionable (the agent can actually change behavior based on this)
40
- - Non-obvious (things the agent wouldn't know from its system prompt alone)
41
-
42
- Do NOT include:
43
- - Task-specific details (file paths, variable names, specific code changes)
44
- - Things already in the system prompt
45
- - Trivial confirmations or greetings
46
- - Speculative patterns not grounded in the conversation