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/4] 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/4] 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/4] 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/4] 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 @@
-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)
---