JSPM

  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 59
  • Score
    100M100P100Q71475F
  • License MIT

OpenCode plugin with a hook layer (tool.before.*, session.idle...), agents (code-reviewer, doc-writer), and commands (/review-pr, /commit)

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

opencode-froggy logo

CI npm version

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

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 maxFileSize parameter controls individual file size, not total output size

diff-summary

Command that displays a structured summary of git working tree changes (staged, unstaged, and untracked files). Injects git diff output directly into the prompt using bash commands.

Usage

/diff-summary

What it shows

  • Git status (porcelain format)
  • Staged changes (stats and full diff)
  • Unstaged changes (stats and full diff)
  • Untracked files content (first 50 lines of each file)

Implementation

This command uses OpenCode's !`...`` syntax to inject bash command output directly into the prompt, avoiding the 2000-line truncation limit that affects tools.

See command/diff-summary.md for the full implementation.

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 sessionId is 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:00Z

Blockchain

Tools for querying Ethereum and EVM-compatible blockchains via Etherscan APIs.

All blockchain tools support multiple chains via the chainId parameter:

Chain ID Network
1 Ethereum (default)
137 Polygon
56 BSC
42161 Arbitrum
10 Optimism
8453 Base
43114 Avalanche
250 Fantom
324 zkSync

Configuration

The blockchain tools use Etherscan-compatible APIs. An API key is optional but recommended.

Environment Variable:

Variable Required Description
ETHERSCAN_API_KEY No API key for Etherscan and compatible explorers

Without an API key: Requests are rate-limited (typically 1 request per 5 seconds).

With an API key: Higher rate limits and more reliable access.

Getting an API key:

  1. Create a free account at etherscan.io
  2. Navigate to API Keys in your account settings
  3. Generate a new API key

Setting the environment variable:

export ETHERSCAN_API_KEY="your-api-key-here"

eth-transaction

Get Ethereum transaction details by transaction hash. Returns status, block, addresses, gas costs in JSON format. Use optional parameters to include internal transactions, token transfers, and decoded event logs.

Parameters
Parameter Type Required Default Description
hash string Yes - Transaction hash (0x...)
chainId string No "1" Chain ID (see table above)
includeInternalTxs boolean No false Include internal transactions (ETH transfers between contracts)
includeTokenTransfers boolean No false Include ERC-20 token transfers
decodeLogs boolean No false Decode event logs (Transfer, Approval, Deposit, Withdrawal)
Usage Examples
// Get basic transaction details on Ethereum mainnet
ethTransaction({ hash: "0x123abc..." })

// Get transaction on Polygon
ethTransaction({ 
  hash: "0x123abc...",
  chainId: "137"
})

// Get transaction with internal transactions and token transfers
ethTransaction({ 
  hash: "0x123abc...",
  includeInternalTxs: true,
  includeTokenTransfers: true
})

// Get full transaction details with decoded event logs
ethTransaction({ 
  hash: "0x123abc...",
  includeInternalTxs: true,
  includeTokenTransfers: true,
  decodeLogs: true
})
Output Structure

The tool returns JSON with labeled addresses (contract names resolved via Etherscan):

{
  "hash": "0x123...",
  "status": "success",
  "block": 12345678,
  "from": { "address": "0xabc...", "label": "Uniswap V3: Router" },
  "to": { "address": "0xdef...", "label": "WETH" },
  "value": "0",
  "gas": { "used": 150000, "price": "20000000000", "cost": "0.003" }
}

With includeInternalTxs: true:

{
  "internalTransactions": [
    {
      "from": { "address": "0x...", "label": "Uniswap V3: Router" },
      "to": { "address": "0x...", "label": null },
      "value": "1.5",
      "type": "call"
    }
  ]
}

With includeTokenTransfers: true:

{
  "tokenTransfers": [
    {
      "token": { "address": "0x...", "name": "Wrapped Ether", "symbol": "WETH", "decimals": 18 },
      "from": { "address": "0x...", "label": null },
      "to": { "address": "0x...", "label": "Uniswap V3: Router" },
      "value": "1.5"
    }
  ]
}

With decodeLogs: true:

{
  "decodedEvents": [
    {
      "name": "Transfer",
      "address": { "address": "0x...", "label": "WETH" },
      "params": { "from": "0x...", "to": "0x...", "value": "1500000000000000000" }
    }
  ],
  "undecodedEventsCount": 2
}
Supported Decoded Events
Event Description
Transfer ERC-20 token transfer
Approval ERC-20 approval for spending
Deposit WETH deposit (ETH → WETH)
Withdrawal WETH withdrawal (WETH → ETH)

eth-address-balance

Get the ETH balance of an Ethereum address. Returns balance in both ETH and Wei.

Parameters
Parameter Type Required Default Description
address string Yes - Ethereum address (0x...)
chainId string No "1" Chain ID (see table above)
Usage Examples
// Get balance on Ethereum mainnet
ethAddressBalance({ address: "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045" })

// Get balance on Arbitrum
ethAddressBalance({ 
  address: "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
  chainId: "42161"
})

eth-address-txs

List Ethereum transactions for an address. Shows incoming and outgoing transactions with values, timestamps, and status.

Parameters
Parameter Type Required Default Description
address string Yes - Ethereum address (0x...)
limit number No 20 Maximum number of transactions to return
chainId string No "1" Chain ID (see table above)
Usage Examples
// List recent transactions on Ethereum mainnet
ethAddressTxs({ address: "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045" })

// List last 50 transactions on Base
ethAddressTxs({ 
  address: "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
  limit: 50,
  chainId: "8453"
})

eth-token-transfers

List ERC-20 token transfers for an Ethereum address. Shows token names, symbols, values, and transaction details.

Parameters
Parameter Type Required Default Description
address string Yes - Ethereum address (0x...)
limit number No 20 Maximum number of transfers to return
chainId string No "1" Chain ID (see table above)
Usage Examples
// List recent token transfers on Ethereum mainnet
ethTokenTransfers({ address: "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045" })

// List last 100 token transfers on Optimism
ethTokenTransfers({ 
  address: "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
  limit: 100,
  chainId: "10"
})

Hooks

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 hooks list
  • Each hook defines event, actions, and optional conditions
  • 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

  1. tool.before.* (all tools)
  2. tool.before.<name> (specific tool)
  3. (tool executes)
  4. tool.after.* (all tools)
  5. 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 jq or 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 linting

The 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.idle only fires if files were modified via write or edit; the session's modified file list is cleared after the hook runs
  • The main session is set on session.created with no parent, or on the first session.idle if 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 0

Conditional 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
fi

Block 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
          fi

Auto-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"
          fi

Log 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.log

Configuration 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