Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

10 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

pic1

Oh My Kiro Plugin for OpenCode

Oh My Kiro is a spec-driven, multi-agent coding plugin for OpenCode.

Kiro is great, Spec-Driven Development works, but the subscription credits are too limited, and the context window is too small for serious use. So I reverse-engineered Kiro and built oh-my-kiro — an open-source alternative with the same capabilities and better UX, no more worrying about context limits, and full freedom to configure the underlying model.

Features

  • Spec-Driven Development: Enforces Requirements → Design → Tasks → Implementation workflow
  • Dynamic Task Graph: Supports branching, loops, and parallel execution in task workflows
  • Multi-Agent Architecture: Specialized subagents for different tasks (exploration, execution, analysis)
  • Background Tasks: Run subagents in parallel without blocking the main conversation
  • AST-based Search: Structural code search and refactoring using ast-grep
  • Code Execution: Stateful JavaScript execution in Jupyter kernels for browser automation and workflows
  • Browser Automation: Built-in support for Stagehand and browser-use skills
  • Multimodal Support: Image and document analysis via configurable vision models
  • LSP Integration: Get diagnostics and rename symbols using Language Server Protocol

Agents

Agent Mode Purpose
kiro (orchestrator) primary Main orchestrator that coordinates all subagents
requirements-first-workflow subagent Build and refine specs (requirements → design → tasks)
spec-task-execution subagent Execute a single task from a spec's tasks.md
kiroExplore subagent Deep codebase exploration
context-gatherer subagent Gather focused code context
general-task-execution subagent General implementation work
multimodal-looker subagent Image/document understanding

Tools

Category Tools Description
Kiro-specific prework, kiroSpecTaskStatus Spec workflow management
Background tasks backgroundTask, backgroundTaskStatus, getTaskOutput, backgroundTaskCancel, listBackgroundTasks, waitForBackgroundTasks, listAllTaskSessions Parallel subagent execution
AST-grep astGrepSearch, astGrepReplace Structural code search and refactoring
Code execution execute_code, list_code_sessions, close_code_session Stateful JavaScript in Jupyter kernels
Multimodal lookAt Image/PDF analysis (optional)
LSP kiroGetDiagnostics, kiroRenameSymbol Language Server integration
Clipboard listClipboardFiles Access pasted images queue

Built-in Commands

Command Description
/spec Spec-driven development workflow - Requirements → Design → Tasks → Implementation
/skill Trigger agent to use a skill (e.g., browser automation)
/session-reuse Reuse existing subagent sessions
/general Trigger general-task-execution for implementation work

Note: /spec is optional—Kiro operates in spec-driven mode by default. The command serves as a helper/reminder.

Installation

Edit ~/.config/opencode/opencode.jsonc:

{
  "plugin": ["@oh-my-kiro/oh-my-kiro"],
}
# 1. Install Jupyter
pip install jupyter

# 2. Install jslab kernel (JavaScript kernel based on tslab)
npm install -g tslab
tslab install

# 3. (Optional) Start Jupyter server manually
jupyter server --no-browser --port=8888 --IdentityProvider.token=your-token --ServerApp.allow_origin='*' --KernelManager.autorestart=False --MappingKernelManager.kernel_info_timeout=60

# Or let Kiro auto-spawn one (no manual setup needed)

Configuration

Oh My Kiro reads config from ~/.config/opencode/kiro/kiro.json:

{
  "lookAt": {
    "enable": true,
    "model": "openai/gpt-5.3-codex"
  },
  "codeExecution": {
    "script_dir": ".kiro/scripts",
    "jupyter": {
      "baseUrl": "http://localhost:8888",
      "token": "your-token"
    },
    "env": {
      "BROWSER_LLM_API_KEY": "your-api-key",
      "BROWSER_LLM_BASE_URL": "https://api.openai.com/v1",
      "BROWSER_LLM_MODEL": "gpt-5.3-codex"
    }
  }
}

Configuration Options

Key Type Default Description
lookAt.enable boolean false Enable/disable multimodal tool
lookAt.model string - Vision model for lookAt (e.g., openai/gpt-4o)
codeExecution.script_dir string .kiro/scripts Directory for execution notebooks
codeExecution.jupyter object - Jupyter server config (auto-spawn if not provided)
codeExecution.env object - Environment variables for execute_code sessions

Technical Deep Dive

1. Dynamic Task Graph

Tasks.md supports a task graph syntax that enables branching, loops, and parallel execution:

Task Types

Marker Type Description
[ ]^ Start Entry point - can have multiple start nodes
[ ] Regular Standard implementation task
[ ]? Branch Point Decision point - returns conclusions for routing
[ ]$ Terminal Execution ends here

Task Status

Status Syntax Description
Not started [ ] Task not yet begun
In progress [-] Currently executing
Queued [/] Waiting to execute
Completed [x] Done
Failed [!] Error occurred

Iteration Support (Loops)

For retry/polling workflows, cycles are permitted. Iteration count is tracked:

- [ ]^ 1. Initialize        → [x]   (1st completion)
- [ ]  2. Poll for result   → [/1]  (queued, 1 prior completion)
                          → [-1]  (in_progress, 1 prior)
                          → [x2]  (2nd completion)

Example 1: Database Migration with Validation Gates

# Implementation Plan: Database Migration Workflow

- [ ]^ 1. Analyze current schema and migration request
  - [ ] 1.1 Use execute_code to query DB schema, establish baseline
  - _Requirements: 1.1_

- [ ] 2. Create non-destructive schema migration
  - [ ] 2.1 Generate SQL to add NEW tables/columns ONLY (no DROP)
  - _Requirements: 1.2_

- [ ]? 3. Execute migration in staging (dry-run first)
  - [ ] 3.1 Run migration with --dry-run flag
  - [ ]? 3.2 If dry-run fails, jump to 8; if successful, jump to 4
  - _Requirements: 2.1_

- [ ] 4. Write data backfill script
  - [ ] 4.1 Create batch-processing script for old→new schema mapping
  - _Requirements: 2.2_

- [ ]? 5. Execute backfill and verify data integrity
  - [ ] 5.1 Run backfill, compare row counts and sample data
  - [ ]? 5.2 If mismatch > 0%, jump to 6; if 100% match, jump to 7
  - _Requirements: 3.1_

- [ ] 6. Rollback and refine backfill (self-correction loop)
  - [ ] 6.1 Truncate new columns, analyze logs
  - [ ]? 6.2 Jump back to 4
  - _Requirements: 3.2_

- [ ] 7. Generate cleanup migration
  - [ ] 7.1 Create final SQL to safely drop deprecated columns/tables
  - _Requirements: 4.1_

- [ ]$ 8. Terminal: Migration blocked, revert staging, save error trace for human review

- [ ]$ 9. Terminal: Migration PRs ready, output 3 PRs: Expand Schema, Data Backfill, Cleanup

Example 2: Compilation-Driven Code Translation (with loops)

# Implementation Plan: Python to Rust Translation Workflow

- [ ]^ 1. Source analysis and initial translation
  - [ ] 1.1 Parse Python, generate initial Rust, initialize cargo
  - [ ] 1.2 Use execute_code to store: compile_retry_count = 0
  - _Requirements: 1.1_

- [ ] 2. Execute strict compiler check (loop anchor)
  - [ ] 2.1 Run cargo check --message-format=json
  - _Requirements: 1.2_

- [ ]? 3. Evaluate compilation results
  - [ ]? 3.1 If 0 errors, jump to 6
  - [ ]? 3.2 If errors AND compile_retry_count < 5, jump to 4
  - [ ]? 3.3 If errors AND compile_retry_count >= 5, jump to 8
  - _Requirements: 2.1_

- [ ] 4. Deep analysis of compiler errors
  - [ ] 4.1 Extract error codes (E0382, E0597), formulate patch strategy
  - _Requirements: 2.2_

- [ ] 5. Apply patch and retry
  - [ ] 5.1 Modify .rs files
  - [ ] 5.2 Use execute_code to increment compile_retry_count
  - [ ]? 5.3 Jump back to 2
  - _Requirements: 2.3_

- [ ]? 6. Semantic testing evaluation
  - [ ]? 6.1 If cargo test passes, jump to 9; if fails, jump to 7
  - _Requirements: 3.1_

- [ ] 7. Logic error remediation
  - [ ] 7.1 Fix business logic
  - [ ]? 7.2 Jump back to 2 (logic changes may break compilation)
  - _Requirements: 3.2_

- [ ]$ 8. Terminal: Translation failed, output errors, request human intervention

- [ ]$ 9. Terminal: Translation complete, commit compilable, tested Rust project

Example 3: Multi-Entry Code Review Workflow (convergent workflow)

# Implementation Plan: Code Review and Improvement Workflow

- [ ]^ 1. Entry A: Pull Request Review
  - [ ] 1.1 Fetch PR diff, changed files, author context
  - [ ]? 1.2 Jump to 4 (convergence point)
  - _Requirements: 1.1_

- [ ]^ 2. Entry B: Pre-Commit Hook Analysis
  - [ ] 2.1 Run linter, type checker, collect violations
  - [ ]? 2.2 Jump to 4
  - _Requirements: 1.2_

- [ ]^ 3. Entry C: Manual Code Improvement Request
  - [ ] 3.1 Parse improvement request, identify target files/modules
  - [ ]? 3.2 Jump to 4
  - _Requirements: 1.3_

- [ ] 4. Context aggregation and analysis (convergence)
  - [ ] 4.1 Analyze code patterns, identify improvement opportunities
  - [ ] 4.2 Use execute_code to store: entry_point = 'A' | 'B' | 'C'
  - _Requirements: 2.1_

- [ ] 5. Generate improvement suggestions
  - [ ] 5.1 Create detailed recommendations with code examples
  - _Requirements: 2.2_

- [ ]? 6. Apply improvements and verify
  - [ ]? 6.1 If changes break tests, jump back to 5; if pass, jump to 7
  - _Requirements: 3.1_

- [ ]? 7. Output strategy decision
  - [ ] 7.1 Read entry_point from execute_code
  - [ ]? 7.2 If entry_point == 'A', jump to 8
  - [ ]? 7.3 If entry_point == 'B' or 'C', jump to 9
  - _Requirements: 3.2_

- [ ]$ 8. Terminal: Post PR review comments with suggested improvements

- [ ]$ 9. Terminal: Apply auto-fixable changes, commit with descriptive message

Example 4: Full-Stack Parallel Development (fan-out pattern)

# Implementation Plan: Full-Stack Feature Parallel Development

- [ ]^ 1. Analyze request and define API contract (entry)
  - [ ] 1.1 Parse requirements, draft OpenAPI/Swagger schema
  - [ ]? 1.2 Trigger 2, 3, 4 simultaneously (parallel fan-out)
  - _Requirements: 1.1_

- [ ] 2. Branch A: Backend implementation (parallel)
  - [ ] 2.1 Generate migrations, ORM models, API controllers
  - [ ]? 2.2 Jump to 5 when complete
  - _Requirements: 2.1_

- [ ] 3. Branch B: Frontend implementation (parallel)
  - [ ] 3.1 Auto-generate API client from OpenAPI spec
  - [ ] 3.2 Build UI components, wire up state
  - [ ]? 3.3 Jump to 5 when complete
  - _Requirements: 2.2_

- [ ] 4. Branch C: E2E test generation (parallel)
  - [ ] 4.1 Write Cypress/Playwright tests based on contract
  - [ ]? 4.2 Jump to 5 when complete
  - _Requirements: 2.3_

- [ ] 5. Integration and environment spin-up (convergence/fan-in)
  - [ ] 5.1 Wait for branches A, B, C to report complete
  - [ ] 5.2 Build and launch docker-compose stack
  - _Requirements: 3.1_

- [ ]? 6. Execute E2E suite
  - [ ] 6.1 Run tests (from Branch C) against live stack (from 5)
  - [ ]? 6.2 If pass, jump to 8; if fail, jump to 7
  - _Requirements: 4.1_

- [ ] 7. Cross-stack debugging (feedback loop)
  - [ ] 7.1 Analyze failure logs, identify bug location
  - [ ]? 7.2 If backend bug, jump to 2; if frontend bug, jump to 3
  - _Requirements: 4.2_

- [ ]$ 8. Terminal: All tests pass, feature complete, ready for PR

- [ ]$ 9. Terminal: Max retries exceeded, escalate for human review

Example 5: API Polling with Retry (iteration tracking)

# Implementation Plan: API Polling Workflow

- [ ]^ 1. Initialize polling state
  - [ ] 1.1 Use execute_code to set: poll_count = 0, max_polls = 5
  - _Requirements: 1.1_

- [ ] 2. Check API status
  - [ ] 2.1 Increment poll_count via execute_code
  - [ ] 2.2 Call API endpoint, store response status
  - _Requirements: 1.2_

- [ ]? 3. Evaluate polling result
  - [ ] 3.1 Read poll_count and status from execute_code
  - [ ]? 3.2 If status is 'complete', jump to 5
  - [ ]? 3.3 If status is 'pending' AND poll_count < max_polls, jump to 2
  - [ ]? 3.4 If max polls reached, jump to 4
  - _Requirements: 2.1_

- [ ]$ 4. Terminal: Polling timeout, operation did not complete

- [ ]$ 5. Terminal: Success, operation completed

After execution with 2 polling attempts, task status would show:

- [x]^ 1. Initialize polling state
- [x2] 2. Check API status # Completed twice
- [x]? 3. Evaluate polling result # Final: status is 'complete'
- [ ]$ 4. Terminal: Polling timeout
- [x]$ 5. Terminal: Success

Execution Algorithm

  1. Static Mode (no markers): Queue all tasks, execute sequentially
  2. Dynamic Mode (has ^? $):
    • Queue tasks from START to FIRST branch point only
    • Execute queued tasks
    • When branch point completes, evaluate conditions and route to appropriate branch
    • Continue until terminal node or no more tasks

Routing Syntax

Branch points use natural language routing rules in sub-tasks:

Pattern Example
Conditional If [condition], jump to [task]
Multiple conditions If X, jump to 3; if Y, jump to 4; if Z, jump to 5
Unconditional Jump to 4
Loop back Jump back to 2
Parallel trigger Trigger 2, 3, 4 simultaneously

Example 6: Codebase Modernization (parallel branches from analysis)

When a branch point detects multiple independent issues, it can trigger parallel remediation branches:

# Implementation Plan: Codebase Modernization Workflow

- [ ]^ 1. Run codebase analysis
  - [ ] 1.1 Use execute_code to run static analysis (ESLint, TypeScript strict mode, etc.)
  - [ ] 1.2 Store results: improvements = ["Type safety", "Promise handling", "Error handling"]
  - _Requirements: 1.1_

- [ ]? 2. Analyze improvement areas and dispatch modernization tasks
  - [ ] 2.1 Read improvements from execute_code
  - [ ]? 2.2 For each area, trigger parallel branch: Type safety → 3, Promise handling → 4, Error handling → 5
  - _Requirements: 1.2_

- [ ] 3. Branch A: Improve type safety (parallel)
  - [ ] 3.1 Identify all `any` types and implicit any usages
  - [ ] 3.2 Replace with proper TypeScript types, add interfaces
  - [ ] 3.3 Store fix summary in execute_code: type_fixes = {count, files}
  - [ ]? 3.4 Jump to 6 when complete
  - _Requirements: 2.1_

- [ ] 4. Branch B: Modernize promise handling (parallel)
  - [ ] 4.1 Find all callback patterns and `.then()` chains
  - [ ] 4.2 Convert to async/await syntax with proper error handling
  - [ ] 4.3 Store fix summary in execute_code: promise_fixes = {count, files}
  - [ ]? 4.4 Jump to 6 when complete
  - _Requirements: 2.2_

- [ ] 5. Branch C: Improve error handling (parallel)
  - [ ] 5.1 Identify all unhandled promise rejections and try-catch gaps
  - [ ] 5.2 Add proper error boundaries and logging
  - [ ] 5.3 Store fix summary in execute_code: error_fixes = {count, files}
  - [ ]? 5.4 Jump to 6 when complete
  - _Requirements: 2.3_

- [ ] 6. Convergence: Generate modernization report (fan-in)
  - [ ] 6.1 Wait for all branches (3, 4, 5) to report complete
  - [ ] 6.2 Read type_fixes, promise_fixes, error_fixes from execute_code
  - [ ] 6.3 Compile comprehensive modernization report
  - _Requirements: 3.1_

- [ ]? 7. Verify changes with test suite
  - [ ] 7.1 Run full test suite
  - [ ]? 7.2 If tests fail, jump to 2; if all pass, jump to 8
  - _Requirements: 3.2_

- [ ]$ 8. Terminal: Modernization complete, all improvements applied, PR ready

- [ ]$ 9. Terminal: Max retry attempts exceeded, escalate for manual review

Execution flow when 3 improvement areas are found:

  1. Task 2 branch point returns ["Type safety", "Promise handling", "Error handling"]
  2. Agent launches tasks 3, 4, 5 simultaneously via backgroundTask
  3. Each branch works independently on its improvement area
  4. waitForBackgroundTasks blocks until all branches complete
  5. Task 6 merges results and continues sequentially

---

### 2. Code Execution Architecture

The `execute_code` tool runs JavaScript in **Jupyter kernels**, enabling stateful workflows.

#### How It Works

 ┌─────────────────────────────────────┐
 │         OpenCode / Kiro             │
 │                                     │
 │  execute_code({ notebook_file,     │
 │                code })              │
 │              │                      │
 │              ▼                      │
 │  ┌───────────────────────────────┐  │
 │  │      SessionManager           │  │
 │  │  (SQLite metadata + runtime)  │  │
 │  └──────────────┬────────────────┘  │
 │                 │                   │
 │    ┌────────────┴────────────┐        │
 │    ▼                         ▼       │
 │ ┌──────────┐          ┌──────────┐   │
 │ │ REST API │◄────────►│ WebSocket│   │
 │ └────┬─────┘          └────┬─────┘   │
 │      │                      │         │
 │      └──────────┬───────────┘         │
 │                 ▼                      │
 │    ┌─────────────────────────────┐    │
 │    │      Jupyter Server         │    │
 │    └─────────────┬───────────────┘    │
 │                  │                      │
 │                  ▼                      │
 │    ┌─────────────────────────────┐    │
 │    │       KernelClient          │    │
 │    │      (WebSocket)            │    │
 │    └─────────────┬───────────────┘    │
 │                  │                      │
 │                  ▼                      │
 │    ┌─────────────────────────────┐    │
 │    │       jslab kernel          │    │
 │    │   (JavaScript / Node.js)    │    │
 │    └─────────────────────────────┘    │
 └─────────────────────────────────────┘

**Key Components:**

1. **Jupyter Server**: REST API for kernel lifecycle, WebSocket for code execution
2. **jslab Kernel**: JavaScript kernel based on tslab, provides Node.js runtime
3. **SessionManager**: SQLite-backed session persistence, runtime kernel connections
4. **Notebook Storage**: `.ipynb` files preserve execution history and state

#### State Persistence

Variables persist across calls when using the same `notebook_file`:

```typescript
// First call - initialize
execute_code({
  notebook_file: "/workspace/.kiro/scripts/session.ipynb",
  code: "const data = await fetch(url).then(r => r.json());",
})

// Later call - data still exists!
execute_code({
  notebook_file: "/workspace/.kiro/scripts/session.ipynb", // SAME path
  code: "console.log(data.filter(x => x.active));",
})

Package Loading

kiro.require() loads npm packages from multiple paths:

// Search order:
// 1. .kiro/scripts/node_modules (project-local)
// 2. npm global (system)

const stagehand = kiro.require("@browserbasehq/stagehand")

Setup Requirements

# 1. Install Jupyter
pip install jupyter

# 2. Install jslab kernel (JavaScript kernel based on tslab)
npm install -g tslab
tslab install

# 3. (Optional) Start Jupyter server manually
jupyter server --no-browser --port=8888 --IdentityProvider.token=your-token --ServerApp.allow_origin='*' --KernelManager.autorestart=False --MappingKernelManager.kernel_info_timeout=60

# Or let Kiro auto-spawn one (no manual setup needed)

3. Browser Automation

Oh My Kiro supports browser automation through the execute_code tool with Stagehand.

Architecture

┌───────────────────────────────────────────────────────────┐
│  browser-use related request                               │
│         │                                                  │
│         ▼                                                  │
│  Agent loads skill context                                 │
│         │                                                  │
│         ▼                                                  │
│  execute_code({                                            │
│    path: ".kiro/scripts/browser.ipynb",                   │
│    code: `                                                 │
│      const stagehand = kiro.require("@browserbasehq/...");│
│      const browser = new Stagehand({                      │
│        llmClient: new CustomOpenAIClient({                │
│          modelName: process.env.BROWSER_LLM_MODEL,        │
│          client: new OpenAI({                             │
│            apiKey: process.env.BROWSER_LLM_API_KEY,       │
│            baseURL: process.env.BROWSER_LLM_BASE_URL,     │
│          })                                                │
│        })                                                  │
│      });                                                   │
│      await stagehand.init();                              │
│    `                                                       │
│  })                                                        │
│         │                                                  │
│         ▼                                                  │
│  jslab kernel executes in Node.js runtime                 │
│         │                                                  │
│         ▼                                                  │
│  Stagehand controls browser via CDP                       │
└───────────────────────────────────────────────────────────┘

Usage Example

// Step 1: initialize once (stateful kernel session)
execute_code({
  notebook_file: "/workspace/.kiro/scripts/browser.ipynb",
  description: "Initialize Stagehand and open target page",
  code: `
const { Stagehand, CustomOpenAIClient } = kiro.require("@browserbasehq/stagehand")
const OpenAI = kiro.require("openai").default

const stagehand = new Stagehand({
  env: "LOCAL",
  llmClient: new CustomOpenAIClient({
    modelName: process.env.BROWSER_LLM_MODEL,
    client: new OpenAI({
      apiKey: process.env.BROWSER_LLM_API_KEY,
      baseURL: process.env.BROWSER_LLM_BASE_URL,
    }),
  }),
})

await stagehand.init()
const page = stagehand.context.pages()[0]
await page.goto("https://demo.site/login")
console.log("Stagehand ready")
`,
})

// Step 2: Variables persist, reuse existing variables in the same notebook_file
execute_code({
  notebook_file: "/workspace/.kiro/scripts/browser.ipynb",
  description: "Perform actions and extract structured result",
  code: `
await stagehand.act("type user@example.com into email input")
await stagehand.act("type correct-password into password input")
await stagehand.act("click sign in button")

const result = await stagehand.extract(
  "extract current page title and whether login succeeded",
  {
    type: "object",
    properties: {
      title: { type: "string" },
      login_success: { type: "boolean" },
    },
    required: ["title", "login_success"],
  }
)

console.log(result)
`,
})

Install Dependencies

# The agent load packages from ${script_dir}/node_modules, by default, it is .kiro/scripts/node_modules
# In your project's .kiro/scripts directory
cd .kiro/scripts
npm init -y
npm install @browserbasehq/stagehand

Spec-Driven Development

Specs are stored in .kiro/specs/<feature>/:

.kiro/specs/
└── my-feature/
    ├── requirements.md   # What to build
    ├── design.md         # How to build it
    └── tasks.md          # Implementation steps (supports task graph syntax)

Spec Workflow

  1. Requirements: Define what you're building
  2. Design: Plan the architecture and approach
  3. Tasks: Break down into actionable steps (use task graph for complex flows)
  4. Implementation: Execute tasks via spec-task-execution subagent

Background Tasks

Run subagents in parallel without blocking:

// Start background exploration
backgroundTask({
  subagent_type: "kiroExplore",
  description: "Explore auth flow",
  prompt: "Find all authentication-related code",
})

// Check status
backgroundTaskStatus({ taskId: "task-uuid" })

// Get results when complete
getTaskOutput({ taskId: "task-uuid" })

Clipboard Files Queue

Oh My Kiro automatically saves pasted images to a persistent queue (~/.local/share/opencode/kiro/clipboard-files-queue/{sessionID}/{datetime}.png), enabling image analysis even with non-vision models:

User: [pastes screenshot]
Agent: [calls lookAt with index=-1 to analyze most recent image]

Acknowledgments

  • Kiro - Original spec-driven development inspiration
  • OpenCode - The platform this plugin runs on
  • tslab - JavaScript kernel for Jupyter
  • Stagehand - AI-powered browser automation

About

Spec-Driven Development (SDD) plugin for OpenCode, Graph-based spec execution, Stateful JavaScript runtime

Resources

Stars

35 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors