From 21b93f23e0631f0675eb4fda0412c0c07bd7b161 Mon Sep 17 00:00:00 2001 From: Fred DE MATOS Date: Thu, 15 Jan 2026 17:09:45 +0100 Subject: [PATCH 1/7] feat: add release command and ask-questions skill --- .../SKILL.md => command/release.md | 23 ++++---- .../ask-questions-if-underspecified/SKILL.md | 59 +++++++++++++++++++ src/index.ts | 1 + src/tools/skill.ts | 20 ++++++- 4 files changed, 91 insertions(+), 12 deletions(-) rename skill/code-release/SKILL.md => command/release.md (67%) create mode 100644 skill/ask-questions-if-underspecified/SKILL.md diff --git a/skill/code-release/SKILL.md b/command/release.md similarity index 67% rename from skill/code-release/SKILL.md rename to command/release.md index 2d33a13..6dca615 100644 --- a/skill/code-release/SKILL.md +++ b/command/release.md @@ -1,13 +1,12 @@ --- -name: code-release -description: > - Prepare and execute a release with version bumping, changelog updates, and tags. -use_when: > - REQUIRED: When the user asks to prepare or perform a release, - call skill({ name: "code-release" }) before changing any release artifacts. +description: Prepare and execute a release with version bumping, changelog updates, and tags --- -# Code Release Skill +## Context + +- Current version: !`node -p "require('./package.json').version"` +- Latest tag: !`git describe --tags --abbrev=0 2>/dev/null || echo "none"` +- Commits since last tag: !`git log $(git describe --tags --abbrev=0 2>/dev/null || echo "HEAD~10")..HEAD --oneline 2>/dev/null || git log --oneline -10` ## CRITICAL CONSTRAINT @@ -17,13 +16,15 @@ Any destructive or remote action requires confirmation, including: - `git tag` - `git push` -## Step 1: Determine last released version +## Your task + +### Step 1: Determine last released version 1. Prefer the latest Git tag that matches `v`. 2. If no matching tag exists, use the version in `package.json`. 3. Collect commits since the last version (tag to `HEAD`). -## Step 2: Propose version bump +### Step 2: Propose version bump Analyze commits since the last version and recommend a semver bump: - **major**: breaking changes or incompatible behavior changes. @@ -32,14 +33,14 @@ Analyze commits since the last version and recommend a semver bump: Present the recommendation and ask the user to confirm before changing any files. -## Step 3: Update release artifacts (after confirmation) +### Step 3: Update release artifacts (after confirmation) - Update the version in `package.json`. - Update `CHANGELOG` with a new section for the version. - Summarize changes based on the commit range. - Preserve the existing changelog format. -## Step 4: Tag and publish (after confirmation) +### Step 4: Tag and publish (after confirmation) - Commit release changes with a clear release message. - Create an annotated tag (for example, `vX.Y.Z`). diff --git a/skill/ask-questions-if-underspecified/SKILL.md b/skill/ask-questions-if-underspecified/SKILL.md new file mode 100644 index 0000000..00429e4 --- /dev/null +++ b/skill/ask-questions-if-underspecified/SKILL.md @@ -0,0 +1,59 @@ +--- +name: ask-questions-if-underspecified +description: Clarify requirements before implementing. Use when serious doubts arise. +use_when: > + When a request has multiple plausible interpretations or key details + (objective, scope, constraints, environment, or safety) are unclear, + load this skill before starting implementation. + Do NOT use when the request is already clear or when a quick, low-risk + discovery read can answer the missing details. +--- + +# Ask Questions If Underspecified + +## Goal + +Ask the minimum set of clarifying questions needed to avoid wrong work; do not start implementing until the must-have questions are answered (or the user explicitly approves proceeding with stated assumptions). + +## Workflow + +### 1) Decide whether the request is underspecified + +Treat a request as underspecified if after exploring how to perform the work, some or all of the following are not clear: +- Define the objective (what should change vs stay the same) +- Define "done" (acceptance criteria, examples, edge cases) +- Define scope (which files/components/users are in/out) +- Define constraints (compatibility, performance, style, deps, time) +- Identify environment (language/runtime versions, OS, build/test runner) +- Clarify safety/reversibility (data migration, rollout/rollback, risk) + +If multiple plausible interpretations exist, assume it is underspecified. + +### 2) Ask must-have questions first (keep it small) + +Ask 1-5 questions in the first pass. Prefer questions that eliminate whole branches of work. + +Use the `question` tool to present structured choices: +- Offer multiple-choice options with clear labels +- Mark recommended defaults with "(Recommended)" in the label +- Use `multiple: true` when the user can select several options +- The user can always select "Other" for custom input + +### 3) Pause before acting + +Until must-have answers arrive: +- Do not run commands, edit files, or produce a detailed plan that depends on unknowns +- Do perform a clearly labeled, low-risk discovery step only if it does not commit you to a direction (e.g., inspect repo structure, read relevant config files) + +If the user explicitly asks you to proceed without answers: +- State your assumptions as a short numbered list +- Ask for confirmation; proceed only after they confirm or correct them + +### 4) Confirm interpretation, then proceed + +Once you have answers, restate the requirements in 1-3 sentences (including key constraints and what success looks like), then start work. + +## Anti-patterns + +- Don't ask questions you can answer with a quick, low-risk discovery read (e.g., configs, existing patterns, docs). +- Don't ask open-ended questions if a tight multiple-choice or yes/no would eliminate ambiguity faster. diff --git a/src/index.ts b/src/index.ts index f3f6fa5..b27daa8 100644 --- a/src/index.ts +++ b/src/index.ts @@ -105,6 +105,7 @@ const SmartfrogPlugin: Plugin = async (ctx) => { const skillTool = createSkillTool({ pluginSkills: skills, pluginDir: PLUGIN_ROOT, + client: ctx.client, }) log("[init] Plugin loaded", { diff --git a/src/tools/skill.ts b/src/tools/skill.ts index 3f8121f..875d100 100644 --- a/src/tools/skill.ts +++ b/src/tools/skill.ts @@ -2,7 +2,11 @@ import { tool, type ToolContext } from "@opencode-ai/plugin" import { existsSync, readdirSync, readFileSync } from "node:fs" import { join, dirname } from "node:path" import { homedir } from "node:os" +import type { createOpencodeClient } from "@opencode-ai/sdk" import { parseFrontmatter, type LoadedSkill } from "../loaders" +import { log } from "../logger" + +type Client = ReturnType export interface SkillInfo { name: string @@ -118,18 +122,20 @@ function loadSkillContent(location: string): string { export interface CreateSkillToolOptions { pluginSkills: LoadedSkill[] pluginDir: string + client: Client } export function createSkillTool(options: CreateSkillToolOptions) { let cachedSkills: SkillInfo[] | null = null let cachedDescription: string | null = null + const { client, pluginDir, pluginSkills } = options const getSkills = (cwd: string): SkillInfo[] => { if (cachedSkills) return cachedSkills // Merge order: plugin defaults < global < project (later entries override earlier on name collision) const allSkills = [ - ...pluginSkillsToInfo(options.pluginSkills, options.pluginDir), + ...pluginSkillsToInfo(pluginSkills, pluginDir), ...discoverClaudeGlobalSkills(), ...discoverOpencodeGlobalSkills(), ...discoverClaudeProjectSkills(cwd), @@ -183,6 +189,18 @@ export function createSkillTool(options: CreateSkillToolOptions) { const body = loadSkillContent(skill.location) const dir = dirname(skill.location) + try { + await client.tui.showToast({ + body: { + message: `Skill "${skill.name}" loaded`, + variant: "info", + duration: 3000, + }, + }) + } catch (error) { + log("[skill] Failed to show toast", { error: String(error) }) + } + return [ `## Skill: ${skill.name}`, "", From 4f0bf7e2455aa4ec4f09224cf9eb82f43bc87abc Mon Sep 17 00:00:00 2001 From: Fred DE MATOS Date: Thu, 15 Jan 2026 17:16:15 +0100 Subject: [PATCH 2/7] chore: release 0.9.0 --- CHANGELOG.md | 5 +++++ package.json | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6800e48..f00422c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # Changelog +## 0.9.0 +- Add /release command to guide release workflow +- Replace code-release skill with ask-questions skill +- Show a toast when loading a skill + ## 0.8.0 - Add pdf-to-markdown tool for PDF conversion diff --git a/package.json b/package.json index c8eceed..d7b07e9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "opencode-froggy", - "version": "0.8.0", + "version": "0.9.0", "description": "OpenCode plugin with a hook layer (tool.before.*, session.idle...), agents (code-reviewer, doc-writer), and commands (/review-pr, /commit)", "main": "dist/index.js", "types": "dist/index.d.ts", From 95de5302d6fc1e9258a35f9bbab55962227c3bb3 Mon Sep 17 00:00:00 2001 From: Fred DE MATOS Date: Sun, 18 Jan 2026 11:41:24 +0100 Subject: [PATCH 3/7] fix(command): remove redundant "Run" prefix in commit-push command --- command/commit-push.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/command/commit-push.md b/command/commit-push.md index 658213b..c9370b2 100644 --- a/command/commit-push.md +++ b/command/commit-push.md @@ -9,7 +9,7 @@ agent: build ## Your task -1. Run `/diff-summary` to analyze all working tree changes +1. /diff-summary to analyze all working tree changes 2. Present a summary to the user: - Files modified/added/deleted with stats - Proposed commit message based on the changes From b98975068caec0db7a0c0f10104720e679eb4f30 Mon Sep 17 00:00:00 2001 From: Fred DE MATOS Date: Tue, 20 Jan 2026 16:08:19 +0100 Subject: [PATCH 4/7] docs: rewrite skills section with complete documentation Replace outdated code-release reference with actual ask-questions-if-underspecified skill. Add comprehensive documentation covering discovery locations, skill creation format, and automatic activation via use_when. --- README.md | 89 ++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 81 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 26c94a7..42d6278 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ npm version

-OpenCode plugin providing hooks, specialized agents (architect, doc-writer, rubber-duck, partner, code-reviewer, code-simplifier), skills (code-release), and tools (gitingest, pdf-to-markdown, blockchain queries, agent-promote). +OpenCode plugin providing hooks, specialized agents (architect, doc-writer, rubber-duck, partner, code-reviewer, code-simplifier), skills (ask-questions-if-underspecified), and tools (gitingest, pdf-to-markdown, blockchain queries, agent-promote). --- @@ -17,7 +17,11 @@ OpenCode plugin providing hooks, specialized agents (architect, doc-writer, rubb - [Commands](#commands) - [Agents](#agents) - [Skills](#skills) - - [code-release](#code-release) + - [Overview](#overview) + - [Available Skills](#available-skills) + - [Discovery Locations](#discovery-locations) + - [Creating a Skill](#creating-a-skill) + - [Automatic Activation](#automatic-activation) - [Tools](#tools) - [gitingest](#gitingest) - [prompt-session](#prompt-session) @@ -117,15 +121,84 @@ Shows stats overview, commits, files changed, and full diff between branches. ## Skills -Skills are loaded on-demand to provide specialized capabilities during a session. +Skills are contextual instructions loaded on demand via the `skill` tool. The agent invokes `skill({ name: "skill-name" })` to load the instructions when needed. -### code-release +### Overview -Prepare releases with version bumps, changelog updates, and tags. +- Skills provide specialized guidance for specific tasks +- Instructions are loaded only when explicitly requested +- Multiple skills can exist with the same name; the highest-priority location wins -- **Purpose**: Guide release preparation steps and require confirmation before changing release artifacts -- **Activation**: On user request to prepare or perform a release -- **Constraints**: Avoid changing versions, tags, or changelogs without explicit confirmation +### Available Skills + +| Skill | Description | +|-------|-------------| +| `ask-questions-if-underspecified` | Clarify requirements before implementing. Use when serious doubts arise. | + +### Discovery Locations + +Skills are discovered from the following locations, in order of increasing priority: + +| Priority | Scope | Location | +|----------|-------|----------| +| 1 (lowest) | plugin | `/skill/` | +| 2 | global | `~/.config/opencode/skill/` | +| 3 (highest) | project | `/.opencode/skill/` | + +If multiple skills share the same name, the one from the highest-priority location takes precedence. + +### Creating a Skill + +Each skill lives in its own directory with a `SKILL.md` file: + +``` +skill/ +└── my-skill/ + └── SKILL.md +``` + +The `SKILL.md` file uses YAML frontmatter for metadata: + +```markdown +--- +name: my-skill +description: Short description of the skill (required) +use_when: > + Condition for automatic activation (optional). +--- + +# Detailed Instructions + +Markdown content with step-by-step guidance... +``` + +#### Frontmatter Fields + +| Field | Required | Description | +|-------|----------|-------------| +| `name` | Yes | Unique identifier for the skill | +| `description` | Yes | Short description (displayed in skill listings) | +| `use_when` | No | Condition for automatic activation | + +A skill without `name` or `description` will be ignored. + +### Automatic Activation + +If a skill defines `use_when`, a directive is injected into the system prompt: + +``` +MANDATORY: Call skill({ name: "my-skill" }) +``` + +This instructs the agent to load the skill when the specified condition is met. + +**What is injected:** +- The skill `name` +- The `use_when` text (normalized: multiple spaces collapsed to single space) + +**What is NOT injected:** +- The `description` +- The markdown content (loaded only when the skill is invoked) --- From d7cdfefdf2b809796e9ae38016dc2925f4d629df Mon Sep 17 00:00:00 2001 From: Fred DE MATOS Date: Thu, 22 Jan 2026 23:44:52 +0100 Subject: [PATCH 5/7] fix(command): list untracked files instead of showing truncated content Previously, /diff-summary and /review-changes displayed truncated content (50 lines) of untracked files. Now they list only file paths with instruction for agents to read them directly. This enables /simplify-changes and /review-changes to properly handle untracked files by accessing their full content. --- command/diff-summary.md | 7 +++---- command/review-changes.md | 5 +++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/command/diff-summary.md b/command/diff-summary.md index c9f8a3c..fc464a4 100644 --- a/command/diff-summary.md +++ b/command/diff-summary.md @@ -43,9 +43,8 @@ else git diff echo "" - echo "## Untracked Files Content" - git ls-files --others --exclude-standard | while read f; do - [ -f "$f" ] && echo "=== $f ===" && sed -n "1,50p" "$f" && sed -n "51p" "$f" | grep -q . && echo "... (truncated)" - done + echo "## Untracked Files (new)" + echo "These files are new and not yet tracked by git. Read them directly to see their content." + git ls-files --others --exclude-standard fi '` diff --git a/command/review-changes.md b/command/review-changes.md index 29e7f94..2254342 100644 --- a/command/review-changes.md +++ b/command/review-changes.md @@ -16,7 +16,8 @@ agent: code-reviewer !`git diff --stat` !`git diff` -## Untracked Files Content -!`bash -c 'git ls-files --others --exclude-standard | while read f; do [ -f "$f" ] && echo "=== $f ===" && sed -n "1,50p" "$f" && sed -n "51p" "$f" | grep -q . && echo "... (truncated)"; done'` +## Untracked Files (new) +These files are new and not yet tracked by git. Read them directly to see their content. +!`git ls-files --others --exclude-standard` Review the above changes for quality, correctness, and adherence to project guidelines. From bc1c7bb0e86ee6bfb7bcc8a7bfac61bafaa7e0c7 Mon Sep 17 00:00:00 2001 From: Fred DE MATOS Date: Sun, 25 Jan 2026 11:40:31 +0100 Subject: [PATCH 6/7] feat(agent): allow code-simplifier to read untracked files --- agent/code-simplifier.md | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/agent/code-simplifier.md b/agent/code-simplifier.md index a4a56c1..e1af06e 100644 --- a/agent/code-simplifier.md +++ b/agent/code-simplifier.md @@ -26,6 +26,7 @@ You do not introduce new features, fix bugs, or change logic. You only improve h ### 2. Scope discipline - Only simplify code that was **modified or introduced in the current session**. +- This includes **untracked files** (new files not yet committed) listed in the working tree. - Do not refactor adjacent or pre-existing code unless strictly required to simplify the modified section. - No cross-file refactors unless the change itself spans multiple files. @@ -61,11 +62,12 @@ Apply simplifications only when they clearly improve readability or maintainabil ## Execution process -1. Identify code that was added or modified in the current session. -2. Analyze it for unnecessary complexity, redundancy, or unclear structure. -3. Apply minimal, behavior-preserving refinements. -4. Re-check that functionality, outputs, and side effects are unchanged. -5. Produce the simplified code. +1. Identify code that was added or modified in the current session, **including untracked files listed in the diff**. +2. **Read the content of untracked files** using the Read tool before analyzing them. +3. Analyze the code for unnecessary complexity, redundancy, or unclear structure. +4. Apply minimal, behavior-preserving refinements. +5. Re-check that functionality, outputs, and side effects are unchanged. +6. Produce the simplified code. ## Output requirements From b32ed399aa665b0d95593e10e1ae942c8d2c7831 Mon Sep 17 00:00:00 2001 From: Fred DE MATOS Date: Sun, 25 Jan 2026 11:45:25 +0100 Subject: [PATCH 7/7] docs: add example for ask-questions-if-underspecified skill --- README.md | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/README.md b/README.md index 42d6278..0256cd8 100644 --- a/README.md +++ b/README.md @@ -135,6 +135,35 @@ Skills are contextual instructions loaded on demand via the `skill` tool. The ag |-------|-------------| | `ask-questions-if-underspecified` | Clarify requirements before implementing. Use when serious doubts arise. | +#### Example: ask-questions-if-underspecified + +**User request:** +> "Add authentication to the API" + +**Agent response (after loading the skill):** + +The agent recognizes this request has multiple interpretations and uses the `question` tool: + +``` +┌─ Authentication Approach ────────────────────────────────────────┐ +│ │ +│ Which authentication method should be implemented? │ +│ │ +│ ○ JWT tokens (Recommended) │ +│ ○ Session-based with cookies │ +│ ○ OAuth 2.0 / OpenID Connect │ +│ ○ API keys │ +│ ○ Other │ +│ │ +└──────────────────────────────────────────────────────────────────┘ +``` + +After the user selects "JWT tokens", the agent confirms: + +> "I'll add JWT-based authentication to the API endpoints using the existing Express middleware pattern. Success = all `/api/*` routes require a valid token, with a `/auth/login` endpoint for token generation." + +Then implementation begins. + ### Discovery Locations Skills are discovered from the following locations, in order of increasing priority: