Package Exports
- opencode-froggy
- opencode-froggy/dist/index.js
This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (opencode-froggy) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.
Readme
Plugin providing Claude Code–style hooks, specialized agents (doc-writer, code reviewer, architect, partner, etc.), dedicated commands such as simplify-code and review-pr, and tools such as gitingest.
Table of Contents
Installation
From npm (recommended)
Add the plugin to your OpenCode configuration file (opencode.json):
{
"$schema": "https://opencode.ai/config.json",
"plugin": ["opencode-froggy"]
}From local files
Alternatively, clone or copy the plugin files to one of these directories:
- Project-local:
.opencode/plugin/opencode-froggy/ - Global:
~/.config/opencode/plugin/opencode-froggy/
Commands
| Command | Description | Agent |
|---|---|---|
/commit-push |
Stage, commit, and push changes with user confirmation | build |
/doc-changes |
Update documentation based on uncommitted changes (new features only) | doc-writer |
/review-changes |
Review uncommitted changes (staged + unstaged, including untracked files) | code-reviewer |
/review-pr <source> <target> |
Review changes from source branch into target branch | code-reviewer |
/send-to [agent] <message> |
Send a message to a child session (subagent) to continue the conversation | - |
/simplify-changes |
Simplify uncommitted changes (staged + unstaged, including untracked files) | code-simplifier |
/tests-coverage |
Run the full test suite with coverage report and suggest fixes for failures | build |
Agents
| Agent | Mode | Description |
|---|---|---|
architect |
subagent | Strategic technical advisor providing high-leverage guidance on architecture, code structure, and complex engineering trade-offs. Read-only. |
code-reviewer |
subagent | Reviews code for quality, correctness, and security. Read-only with restricted git access. |
code-simplifier |
subagent | Simplifies recently modified code for clarity and maintainability while strictly preserving behavior. |
doc-writer |
subagent | Technical writer that crafts clear, comprehensive documentation (README, API docs, architecture docs, user guides). |
partner |
subagent | Strategic ideation partner that breaks frames, expands solution spaces, and surfaces non-obvious strategic options. Read-only. |
rubber-duck |
subagent | Strategic thinking partner for exploratory dialogue. Challenges assumptions, asks pointed questions, and sharpens thinking through conversational friction. Read-only. |
Tools
gitingest
Fetch a GitHub repository's full content via gitingest.com. Returns summary, directory tree, and file contents optimized for LLM analysis. Use when you need to understand an external repository's structure or code.
Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
url |
string |
Yes | - | The GitHub repository URL to fetch |
maxFileSize |
number |
No | 50000 |
Maximum file size in bytes to include |
pattern |
string |
No | "" |
Glob pattern to filter files (e.g., *.ts, src/**/*.py) |
patternType |
"include" | "exclude" |
No | "exclude" |
Whether to include or exclude files matching the pattern |
Usage Examples
// Fetch entire repository
gitingest({ url: "https://github.com/user/repo" })
// Only TypeScript files
gitingest({
url: "https://github.com/user/repo",
pattern: "*.ts",
patternType: "include"
})
// Exclude test files
gitingest({
url: "https://github.com/user/repo",
pattern: "*.test.ts",
patternType: "exclude"
})
// Increase max file size to 100KB
gitingest({
url: "https://github.com/user/repo",
maxFileSize: 100000
})Limitations
- Content is truncated to 300k characters (server-side limit from gitingest.com)
- For large repositories, use pattern filtering to focus on relevant files
- The
maxFileSizeparameter controls individual file size, not total output size
diff-summary
Generate a structured summary of git diffs. Use for reviewing branch comparisons or working tree changes. Returns stats, commits, files changed, and full diff in a structured markdown format.
Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
source |
string |
No | - | Source branch to compare (e.g., feature-branch). If omitted, analyzes working tree changes. |
target |
string |
No | main |
Target branch to compare against |
remote |
string |
No | origin |
Git remote name |
Usage Examples
// Analyze working tree changes (staged, unstaged, and untracked files)
diffSummary({})
// Compare feature branch against main
diffSummary({ source: "feature-branch" })
// Compare feature branch against develop
diffSummary({
source: "feature-branch",
target: "develop"
})
// Compare branches on a different remote
diffSummary({
source: "feature-branch",
target: "main",
remote: "upstream"
})Output Structure
For branch comparisons:
- Stats Overview: Summary of changes (insertions, deletions)
- Commits to Review: List of commits in the range
- Files Changed: List of modified files
- Full Diff: Complete diff with context
For working tree changes:
- Status Overview: Git status output
- Staged Changes: Stats, files, and diff for staged changes
- Unstaged Changes: Stats, files, and diff for unstaged changes
- Untracked Files: List and diffs for new untracked files
Notes
- When comparing branches, the tool fetches from the remote before generating the diff
- Diffs include 5 lines of context and function context for better readability
prompt-session
Send a message to a child session (subagent) to continue the conversation. Useful for iterating with subagents without creating new sessions.
Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
message |
string |
Yes | - | The message to send to the child session |
sessionId |
string |
No | - | The child session ID to target. If omitted, targets the last child session. |
Usage Examples
// Send a message to the last child session
promptSession({ message: "Please also add unit tests for the new function" })
// Send a message to a specific child session
promptSession({
message: "Can you clarify the error handling approach?",
sessionId: "abc123"
})Behavior
- If
sessionIdis not provided, the tool automatically targets the most recently created child session - Returns the text response from the child session
- Returns an error message if no child session exists for the current session
list-child-sessions
List all child sessions (subagents) of the current session. Useful for finding specific sessions to target with prompt-session.
Parameters
This tool takes no parameters.
Usage Examples
// List all child sessions
listChildSessions()Output
Returns a formatted list of child sessions with:
- Session ID
- Session title
- Created and updated timestamps
Example output:
Child sessions (2):
1. [abc123] Code Review Session
Created: 2024-01-15T10:30:00Z | Updated: 2024-01-15T10:35:00Z
2. [def456] Architecture Discussion
Created: 2024-01-15T11:00:00Z | Updated: 2024-01-15T11:15:00ZHooks
Hooks run actions on session events. Configuration is loaded from standard OpenCode configuration directories.
Configuration Locations
Hooks are loaded from these locations (in order, merged together):
| Platform | Global | Project |
|---|---|---|
| Linux | ~/.config/opencode/hook/hooks.md |
<project>/.opencode/hook/hooks.md |
| macOS | ~/.config/opencode/hook/hooks.md |
<project>/.opencode/hook/hooks.md |
| Windows | ~/.config/opencode/hook/hooks.md or %APPDATA%/opencode/hook/hooks.md |
<project>/.opencode/hook/hooks.md |
On Windows, ~/.config is preferred for cross-platform consistency. If hooks exist in %APPDATA% but not in ~/.config, the %APPDATA% location is used.
Global hooks run first, then project hooks are added. Hooks from both sources are combined (not overridden).
Configuration File Format
- YAML frontmatter must include a
hookslist - Each hook defines
event,actions, and optionalconditions - Hooks for the same event run in declaration order
Example hooks.md:
---
hooks:
- event: session.idle
conditions: [hasCodeChange, isMainSession]
actions:
- command: simplify-changes
---Supported Events
| Event | Description |
|---|---|
session.idle |
Emitted when a session becomes idle and has files modified via write or edit in that session |
session.created |
Emitted when a session is created |
session.deleted |
Emitted when a session is deleted |
tool.before.* |
Emitted before any tool executes. Exit code 2 blocks the tool. |
tool.before.<name> |
Emitted before a specific tool (e.g., tool.before.write). Exit code 2 blocks the tool. |
tool.after.* |
Emitted after any tool executes |
tool.after.<name> |
Emitted after a specific tool (e.g., tool.after.edit) |
Tool Hook Execution Order
tool.before.*(all tools)tool.before.<name>(specific tool)- (tool executes)
tool.after.*(all tools)tool.after.<name>(specific tool)
Blocking Tools with Exit Code 2
For tool.before.* and tool.before.<name> hooks, a bash action returning exit code 2 will block the tool from executing. The stderr output is displayed to the user as the block reason.
Conditions
| Condition | Description |
|---|---|
isMainSession |
Run only for the main session (not sub-sessions) |
hasCodeChange |
Run only if at least one modified file looks like code |
All listed conditions must pass for the hook to run.
Code extensions treated as "code":
ts, tsx, js, jsx, mjs, cjs, json, yml, yaml, toml, css, scss, sass, less, html, vue, svelte, go, rs, c, h, cpp, cc, cxx, hpp, java, py, rb, php, sh, bash, kt, kts, swift, m, mm, cs, fs, scala, clj, hs, lua.
Supported Actions
Command Action
Execute a plugin command.
# Short form
- command: simplify-changes
# With arguments
- command:
name: review-pr
args: "main feature"If the command exists in config, the plugin reuses its agent and model.
Tool Action
Prompt the session to use a tool with specific arguments.
- tool:
name: bash
args: { command: "echo done" }Bash Action
Execute a shell command directly without involving the LLM. Useful for running linters, formatters, build scripts, or custom automation.
Configuration:
# Short form
- bash: "npm run lint"
# Long form with custom timeout
- bash:
command: "$OPENCODE_PROJECT_DIR/.opencode/hooks/init.sh"
timeout: 30000 # milliseconds (default: 60000)Environment Variables:
The plugin injects these variables into the child process environment:
| Variable | Value | Use case |
|---|---|---|
OPENCODE_PROJECT_DIR |
Absolute path to the project (e.g., /home/user/project) |
Reference project files from scripts located elsewhere |
OPENCODE_SESSION_ID |
The OpenCode session identifier | Logging, tracing, or conditioning actions based on session |
Stdin JSON Context:
The command receives a JSON object via stdin with session context:
{
"session_id": "abc123",
"event": "session.idle",
"cwd": "/path/to/project",
"files": ["src/index.ts", "src/utils.ts"]
}The files array is only present for session.idle events and contains paths modified via write or edit.
For tool hooks (tool.before.*, tool.after.*), additional fields are provided:
{
"session_id": "abc123",
"event": "tool.before.write",
"cwd": "/path/to/project",
"tool_name": "write",
"tool_args": { "filePath": "src/index.ts", "content": "..." }
}Environment Variables vs Stdin JSON:
- Environment variables: Direct access via
$VAR, convenient for simple values like paths and IDs - Stdin JSON: Contains richer context (event type, working directory, modified files), requires parsing with
jqor similar
Both mechanisms are complementary. Use environment variables for quick access to project path and session ID; use stdin JSON when you need event details or the list of modified files.
Exit Codes:
| Code | Behavior |
|---|---|
0 |
Success, continue to next action |
2 |
Blocking error, stop remaining actions in this hook |
| Other | Non-blocking error, log warning and continue |
Result Feedback:
Bash hook results are automatically sent back to your session:
[BASH HOOK ✓] npm run lint
Exit: 0 | Duration: 1234ms
Stdout: All files passed lintingThe feedback includes a status icon (✓ success, ✗ failure), exit code, execution duration, and stdout/stderr output (truncated to 500 characters). This message appears in your session but does not trigger a response from the assistant.
Execution Behavior
- Action errors are logged and do not stop later actions
session.idleonly fires if files were modified viawriteoredit; the session's modified file list is cleared after the hook runs- The main session is set on
session.createdwith no parent, or on the firstsession.idleif needed
Example Hook Configurations
Basic Multi-Hook Setup
---
hooks:
- event: session.idle
conditions: [hasCodeChange, isMainSession]
actions:
- bash: "npm run lint --fix"
- command: simplify-changes
- event: session.created
actions:
- bash:
command: "$OPENCODE_PROJECT_DIR/.opencode/hooks/init.sh"
timeout: 30000
- command:
name: review-pr
args: "main feature"
---Simple Lint-on-Idle Hook
hooks:
- event: session.idle
conditions: [hasCodeChange]
actions:
- bash: "npm run lint --fix"Custom Initialization Script
.opencode/hooks/init.sh:
#!/bin/bash
set -e
# Read JSON context from stdin
context=$(cat)
session_id=$(echo "$context" | jq -r '.session_id')
event=$(echo "$context" | jq -r '.event')
cwd=$(echo "$context" | jq -r '.cwd')
echo "Session $session_id triggered $event in $cwd"
# Use environment variables
echo "Project: $OPENCODE_PROJECT_DIR"
# Exit 0 for success, 2 to block remaining actions
exit 0Conditional Blocking Based on Lint Errors
#!/bin/bash
# Run linter and block if critical errors found
if ! npm run lint 2>&1 | grep -q "critical"; then
exit 0 # Success, continue
else
echo "Critical lint errors found, blocking further actions"
exit 2 # Block remaining actions
fiBlock Modifications to Sensitive Files
hooks:
- event: tool.before.write
actions:
- bash: |
file=$(cat | jq -r '.tool_args.filePath // .tool_args.file_path // .tool_args.path')
if echo "$file" | grep -qE '\.(env|pem|key)$'; then
echo "Cannot modify sensitive files: $file" >&2
exit 2
fi
- event: tool.before.edit
actions:
- bash: |
file=$(cat | jq -r '.tool_args.filePath // .tool_args.file_path // .tool_args.path')
if echo "$file" | grep -qE '\.(env|pem|key)$'; then
echo "Cannot modify sensitive files: $file" >&2
exit 2
fiAuto-Format TypeScript Files After Write
hooks:
- event: tool.after.write
actions:
- bash: |
file=$(cat | jq -r '.tool_args.filePath // .tool_args.file_path // .tool_args.path')
if echo "$file" | grep -qE '\.tsx?$'; then
npx prettier --write "$file"
fiLog All Tool Executions
hooks:
- event: tool.before.*
actions:
- bash: |
context=$(cat)
tool=$(echo "$context" | jq -r '.tool_name')
echo "[$(date)] Tool: $tool" >> /tmp/opencode-tools.logConfiguration Options
The plugin does not require additional configuration. Agents, commands, and skills are loaded automatically from the agent/, command/, and skill/ directories within the plugin. Hooks are loaded from the standard OpenCode configuration directories (see Hooks section).
Supported Code File Extensions
The hasCodeChange condition checks file extensions against the default set listed in the Conditions section. Hooks without any conditions still trigger on any modified file paths tracked via write or edit in the current session.
License
MIT