diff --git a/.agents/AGENTS.md b/.agents/AGENTS.md
index d5f8f0bb6..06c215e10 100644
--- a/.agents/AGENTS.md
+++ b/.agents/AGENTS.md
@@ -4,7 +4,7 @@
## OVERVIEW
-Project-scope skills + slash commands under the new `.agents/` directory name. During the `oh-my-opencode` → `oh-my-openagent` rename transition, this directory is the **target** of the migration from `.opencode/`. It is a strict SUPERSET of `.opencode/` (5 -> 10 skills; 6 commands).
+Project-scope skills + slash commands under the new `.agents/` directory name. During the `oh-my-opencode` → `oh-my-openagent` rename transition, this directory is the **target** of the migration from `.opencode/`. It is a strict SUPERSET of `.opencode/` (5 -> 10 skills; 5 commands).
Loaded alongside `.opencode/` by [`src/features/opencode-skill-loader/`](file:///Users/yeongyu/local-workspaces/omo/src/features/opencode-skill-loader/). When both directories declare the same skill or command name, the higher-priority scope wins per the loader's deduplication rules.
@@ -25,7 +25,7 @@ Loaded alongside `.opencode/` by [`src/features/opencode-skill-loader/`](file://
The 5 "NEW" skills here are skill-format equivalents of slash commands that exist in BOTH `.opencode/command/` and `.agents/command/`. They allow the same instructions to be triggered either by an explicit `/command` invocation OR by skill auto-loading on matching prompts.
-## COMMANDS (6 slash commands)
+## COMMANDS (5 slash commands)
Identical set to `.opencode/command/`:
- `/get-unpublished-changes`
@@ -33,9 +33,6 @@ Identical set to `.opencode/command/`:
- `/publish`
- `/remove-deadcode`
- `/security-research`
-- `/security-review`
-
-`/security-review` is an alias command that loads the `security-research` skill.
## OTHER CONTENTS
diff --git a/.agents/command/security-review.md b/.agents/command/security-review.md
deleted file mode 100644
index 607b3a600..000000000
--- a/.agents/command/security-review.md
+++ /dev/null
@@ -1,16 +0,0 @@
----
-description: Alias for the Team Mode security-research audit
----
-
-
-Load and follow the `security-research` skill exactly.
-
-```text
-skill(name="security-research")
-```
-
-
-
-$ARGUMENTS
-
-
diff --git a/.opencode/AGENTS.md b/.opencode/AGENTS.md
index 9d08a2dc4..89c11df1d 100644
--- a/.opencode/AGENTS.md
+++ b/.opencode/AGENTS.md
@@ -4,9 +4,9 @@
## OVERVIEW
-Project-scope OpenCode configuration: 5 skills and 6 slash commands committed alongside the source. Picked up by [`src/features/opencode-skill-loader/`](file:///Users/yeongyu/local-workspaces/omo/src/features/opencode-skill-loader/) and the slash-command discovery pipeline.
+Project-scope OpenCode configuration: 5 skills and 5 slash commands committed alongside the source. Picked up by [`src/features/opencode-skill-loader/`](file:///Users/yeongyu/local-workspaces/omo/src/features/opencode-skill-loader/) and the slash-command discovery pipeline.
-**Relationship to `.agents/`:** `.agents/` is the migration target during the `oh-my-opencode` → `oh-my-openagent` rename. It is a SUPERSET of `.opencode/` (mirrors all 5 skills + adds 5 more, mirrors the 6 commands). Both directories load during the transition; consumers should prefer `.agents/`.
+**Relationship to `.agents/`:** `.agents/` is the migration target during the `oh-my-opencode` → `oh-my-openagent` rename. It is a SUPERSET of `.opencode/` (mirrors all 5 skills + adds 5 more, mirrors the 5 commands). Both directories load during the transition; consumers should prefer `.agents/`.
## SKILLS (5)
@@ -20,7 +20,7 @@ Project-scope OpenCode configuration: 5 skills and 6 slash commands committed al
Each skill follows the standard layout (`SKILL.md` + optional `scripts/`, `references/`, `assets/`).
-## COMMANDS (6 slash commands)
+## COMMANDS (5 slash commands)
| Command | Purpose |
|---------|---------|
@@ -29,7 +29,6 @@ Each skill follows the standard layout (`SKILL.md` + optional `scripts/`, `refer
| `/publish` | Publish via GitHub Actions workflow. Argument: ``. |
| `/remove-deadcode` | Remove unused code with LSP-verified safety + atomic commits. |
| `/security-research` | Run the Team Mode security-research audit with 3 vulnerability hunters and 2 PoC engineers. |
-| `/security-review` | Alias for `/security-research`. |
## OTHER CONTENTS
diff --git a/.opencode/command/security-review.md b/.opencode/command/security-review.md
deleted file mode 100644
index 607b3a600..000000000
--- a/.opencode/command/security-review.md
+++ /dev/null
@@ -1,16 +0,0 @@
----
-description: Alias for the Team Mode security-research audit
----
-
-
-Load and follow the `security-research` skill exactly.
-
-```text
-skill(name="security-research")
-```
-
-
-
-$ARGUMENTS
-
-
diff --git a/script/package-layout.test.ts b/script/package-layout.test.ts
index 83f146488..5f7c759f3 100644
--- a/script/package-layout.test.ts
+++ b/script/package-layout.test.ts
@@ -124,9 +124,7 @@ describe("published package layout", () => {
// given
const expectedAssetPaths = collectExpectedAssetPaths()
expect(expectedAssetPaths).toContain(".opencode/command/security-research.md")
- expect(expectedAssetPaths).toContain(".opencode/command/security-review.md")
expect(expectedAssetPaths).toContain(".agents/command/security-research.md")
- expect(expectedAssetPaths).toContain(".agents/command/security-review.md")
expect(expectedAssetPaths).toContain(".agents/skills/security-research/SKILL.md")
// when
diff --git a/src/features/AGENTS.md b/src/features/AGENTS.md
index 439782e85..1d2ec6c09 100644
--- a/src/features/AGENTS.md
+++ b/src/features/AGENTS.md
@@ -16,7 +16,7 @@ File counts are NON-TEST `.ts` files only (test files co-located but excluded fr
| **background-agent** | 30 / 1 subdir (spawner/) | HIGH | yes | Task lifecycle, concurrency (5/key), 3s polling, spawner pattern, circuit breaker. Newer files: `parent-wake-notifier.ts` (587 LOC), `loop-detector`, `error-classifier`, `fallback-retry-handler`, `process-cleanup`, `subagent-spawn-limits`, `session-status-classifier`, `compaction-aware-message-resolver`. |
| **tmux-subagent** | 27 | HIGH | yes | Tmux pane management, grid planning, session orchestration via `runTmuxCommand` |
| **opencode-skill-loader** | 25 / 1 subdir (merger/) | HIGH | yes | YAML frontmatter skill discovery from 4 scopes (project > opencode > user > global) |
-| **builtin-skills** | 18 / 5 subdirs | LOW–MED | yes | 10 built-in skill files (git-master, playwright, frontend-ui-ux, review-work, ai-slop-remover, dev-browser, playwright-cli, **team-mode**, …) |
+| **builtin-skills** | 19 / 5 subdirs | LOW–MED | yes | 11 built-in skill files (git-master, playwright, frontend-ui-ux, review-work, ai-slop-remover, security-review, dev-browser, playwright-cli, **team-mode**, …) |
| **skill-mcp-manager** | 11 | HIGH | yes | Tier-3 MCP client lifecycle per session (stdio + HTTP + OAuth) |
| **claude-code-plugin-loader** | 11 | MEDIUM | yes | Unified Claude Code plugin discovery (commands, agents, skills, hooks, MCPs) |
| **builtin-commands** | 11 / 1 subdir (templates/) | LOW | yes | Command templates: refactor, init-deep, handoff, ulw-loop, etc. |
@@ -70,7 +70,7 @@ Eligible members: sisyphus, atlas, sisyphus-junior, hephaestus only. See [`team-
State-first tmux integration. Centralized tmux command execution through `src/shared/tmux/runner.ts` (`runTmuxCommand`). Direct `Bun.spawn(["tmux", ...])` is FORBIDDEN — would drift from retry/timeout discipline.
-### builtin-skills (10 skills)
+### builtin-skills (11 skills)
| Skill | LOC | MCP | Notes |
|-------|-----|-----|-------|
@@ -80,6 +80,7 @@ State-first tmux integration. Centralized tmux command execution through `src/sh
| dev-browser | 221 | — | Persistent page state browser |
| review-work | ~500 | — | 5-agent post-implementation review orchestrator |
| ai-slop-remover | ~300 | — | Remove AI code patterns |
+| security-review | ~180 | — | Team Mode exploitability-driven security review |
| **team-mode** | — | — | Loaded only when `team_mode.enabled` (skill explains the 12 tools to agents) |
| frontend-ui-ux | 79 | — | Design-first UI development |
| (git-master-skill-metadata) | — | — | Companion to git-master |
diff --git a/src/features/builtin-skills/AGENTS.md b/src/features/builtin-skills/AGENTS.md
index 5083534ab..37e204ab8 100644
--- a/src/features/builtin-skills/AGENTS.md
+++ b/src/features/builtin-skills/AGENTS.md
@@ -1,4 +1,4 @@
-# src/features/builtin-skills/ — 10 Built-in Skill Files
+# src/features/builtin-skills/ — 11 Built-in Skill Files
**Generated:** 2026-05-15
@@ -11,7 +11,7 @@ Skills shipped inside the plugin (always available, no install). Registered via
```
builtin-skills/
├── index.ts # Barrel exports
-├── skills.ts # createBuiltinSkills() factory — registers all 10 below
+├── skills.ts # createBuiltinSkills() factory — registers all 11 below
├── types.ts # BuiltinSkill interface
├── skills/
│ ├── git-master.ts # 1111 LOC
@@ -23,6 +23,7 @@ builtin-skills/
│ ├── review-work.ts # 5-agent post-implementation review
│ ├── ai-slop-remover.ts # Remove AI-generated code patterns
│ ├── team-mode.ts # 12 team_* tool documentation (gated)
+│ ├── security-review.ts # Team Mode exploitability-driven security review
│ ├── git-master-sections/ # Git-master prompt sub-sections
│ └── index.ts # skill barrel
├── git-master/ # Resources for git-master skill
@@ -43,6 +44,7 @@ builtin-skills/
| `frontend-ui-ux` | 79 | — | Design-first UI development guidance |
| `review-work` | ~500 | — | Post-implementation review orchestrator (5 parallel agents) |
| `ai-slop-remover` | ~300 | — | Remove AI-generated code smells |
+| `security-review` | ~180 | — | Team Mode exploitability-driven security review |
| `team-mode` | — | — | **Conditional** — only loaded when `team_mode.enabled`; documents the 12 `team_*` tools and lifecycle |
## BROWSER VARIANT SELECTION
diff --git a/src/features/builtin-skills/skills.test.ts b/src/features/builtin-skills/skills.test.ts
index 5b17c6319..ab9614b60 100644
--- a/src/features/builtin-skills/skills.test.ts
+++ b/src/features/builtin-skills/skills.test.ts
@@ -1,3 +1,5 @@
+///
+
import { describe, test, expect } from "bun:test"
import { createBuiltinSkills } from "./skills"
@@ -83,7 +85,7 @@ describe("createBuiltinSkills", () => {
expect(agentBrowserSkill!.template).toContain("agent-browser snapshot")
})
- test("always includes frontend-ui-ux, git-master, review-work, and ai-slop-remover skills", () => {
+ test("always includes frontend-ui-ux, git-master, review-work, ai-slop-remover, and security-review skills", () => {
// given - both provider options
// when
@@ -97,10 +99,11 @@ describe("createBuiltinSkills", () => {
expect(skills.find((s) => s.name === "git-master")).toBeDefined()
expect(skills.find((s) => s.name === "review-work")).toBeDefined()
expect(skills.find((s) => s.name === "ai-slop-remover")).toBeDefined()
+ expect(skills.find((s) => s.name === "security-review")).toBeDefined()
}
})
- test("returns exactly 5 skills regardless of provider", () => {
+ test("returns exactly 6 skills regardless of provider", () => {
// given
// when
@@ -109,9 +112,9 @@ describe("createBuiltinSkills", () => {
const devBrowserSkills = createBuiltinSkills({ browserProvider: "dev-browser" })
// then
- expect(defaultSkills).toHaveLength(5)
- expect(agentBrowserSkills).toHaveLength(5)
- expect(devBrowserSkills).toHaveLength(5)
+ expect(defaultSkills).toHaveLength(6)
+ expect(agentBrowserSkills).toHaveLength(6)
+ expect(devBrowserSkills).toHaveLength(6)
})
test("should exclude playwright when it is in disabledSkills", () => {
@@ -128,7 +131,8 @@ describe("createBuiltinSkills", () => {
expect(skills.map((s) => s.name)).not.toContain("dev-browser")
expect(skills.map((s) => s.name)).toContain("review-work")
expect(skills.map((s) => s.name)).toContain("ai-slop-remover")
- expect(skills.length).toBe(4)
+ expect(skills.map((s) => s.name)).toContain("security-review")
+ expect(skills.length).toBe(5)
})
test("should exclude multiple skills when they are in disabledSkills", () => {
@@ -145,12 +149,13 @@ describe("createBuiltinSkills", () => {
expect(skills.map((s) => s.name)).not.toContain("dev-browser")
expect(skills.map((s) => s.name)).toContain("review-work")
expect(skills.map((s) => s.name)).toContain("ai-slop-remover")
- expect(skills.length).toBe(3)
+ expect(skills.map((s) => s.name)).toContain("security-review")
+ expect(skills.length).toBe(4)
})
test("should return an empty array when all skills are disabled", () => {
// #given
- const options = { disabledSkills: new Set(["playwright", "frontend-ui-ux", "git-master", "review-work", "ai-slop-remover"]) }
+ const options = { disabledSkills: new Set(["playwright", "frontend-ui-ux", "git-master", "review-work", "ai-slop-remover", "security-review"]) }
// #when
const skills = createBuiltinSkills(options)
@@ -167,7 +172,7 @@ describe("createBuiltinSkills", () => {
const skills = createBuiltinSkills(options)
// #then
- expect(skills.length).toBe(5)
+ expect(skills.length).toBe(6)
})
test("review-work skill has correct structure", () => {
@@ -216,6 +221,20 @@ describe("createBuiltinSkills", () => {
expect(aiSlopRemover!.template).toContain("SAFETY RULES")
})
+ test("security-review skill has correct structure", () => {
+ // #given - default options
+
+ // #when
+ const skills = createBuiltinSkills()
+ const securityReview = skills.find((skill) => skill.name === "security-review")
+
+ // #then
+ expect(securityReview?.description).toContain("security review")
+ expect(securityReview?.template).toContain("Team Mode Vulnerability Audit")
+ expect(securityReview?.template).toContain("team_create")
+ expect(securityReview?.template).toContain("Security Review Result")
+ })
+
test("returns playwright-cli skill when browserProvider is 'playwright-cli'", () => {
// given
const options = { browserProvider: "playwright-cli" as const }
diff --git a/src/features/builtin-skills/skills.ts b/src/features/builtin-skills/skills.ts
index 8c544e186..edd02853e 100644
--- a/src/features/builtin-skills/skills.ts
+++ b/src/features/builtin-skills/skills.ts
@@ -10,6 +10,7 @@ import {
devBrowserSkill,
reviewWorkSkill,
aiSlopRemoverSkill,
+ securityReviewSkill,
teamModeSkill,
} from "./skills/index"
@@ -33,7 +34,14 @@ export function createBuiltinSkills(options: CreateBuiltinSkillsOptions = {}): B
browserSkill = playwrightSkill
}
- const skills = [browserSkill, frontendUiUxSkill, gitMasterSkill, reviewWorkSkill, aiSlopRemoverSkill]
+ const skills = [
+ browserSkill,
+ frontendUiUxSkill,
+ gitMasterSkill,
+ reviewWorkSkill,
+ aiSlopRemoverSkill,
+ securityReviewSkill,
+ ]
if (teamModeEnabled && !disabledSkills?.has("team-mode")) {
skills.push(teamModeSkill)
diff --git a/src/features/builtin-skills/skills/index.ts b/src/features/builtin-skills/skills/index.ts
index 2990cf178..cbec60a18 100644
--- a/src/features/builtin-skills/skills/index.ts
+++ b/src/features/builtin-skills/skills/index.ts
@@ -5,4 +5,5 @@ export { gitMasterSkill } from "./git-master"
export { devBrowserSkill } from "./dev-browser"
export { reviewWorkSkill } from "./review-work"
export { aiSlopRemoverSkill } from "./ai-slop-remover"
+export { securityReviewSkill } from "./security-review"
export * from "./team-mode"
diff --git a/src/features/builtin-skills/skills/security-review.ts b/src/features/builtin-skills/skills/security-review.ts
new file mode 100644
index 000000000..695a27957
--- /dev/null
+++ b/src/features/builtin-skills/skills/security-review.ts
@@ -0,0 +1,206 @@
+import type { BuiltinSkill } from "../types"
+
+export const securityReviewSkill: BuiltinSkill = {
+ name: "security-review",
+ description:
+ "Team Mode security review skill. Orchestrates 3 vulnerability hunters and 2 PoC engineers to audit a codebase in parallel, prove exploitability, classify root causes, and calibrate severity by actual exploitability. Use for security review, vulnerability research, exploitability audit, pre-release security check, threat model validation, and `/security-review`. Triggers: 'security-review', 'security review', 'security research', 'vulnerability audit', 'exploitability audit', '보안 리뷰', '취약점 감사'.",
+ template: `# Security Review - Team Mode Vulnerability Audit
+
+Use this skill to run a parallel security audit that separates real exploitability from generic concern. The team has 3 vulnerability hunters and 2 PoC engineers.
+
+## Hard Preconditions
+
+Before starting, verify:
+
+1. \`team_*\` tools are available. If not, stop and tell the user:
+ \`security-review requires team-mode. Set team_mode.enabled: true in your oh-my-openagent config, restart opencode, then retry.\`
+2. You are in the main session, not a background subagent.
+3. You have a concrete target: repository, diff range, PR, release candidate, path list, or threat surface.
+
+If the user provided no target, audit the current repository and current branch diff against its upstream or merge base. If there is no diff, audit the security-sensitive surfaces in the working tree.
+
+## Severity Standard
+
+Use these references as the scoring frame:
+
+- CWE for root-cause weakness classification: https://cwe.mitre.org/
+- OWASP WSTG for test methodology: https://devguide.owasp.org/en/06-verification/01-guides/01-wstg/
+- OWASP ASVS for control verification: https://owasp.org/www-project-application-security-verification-standard/
+- CVSS v4.0 for exploitability and impact scoring: https://www.first.org/cvss/v4.0/specification-document
+
+Rules:
+
+- No severity without an attack path.
+- No critical or high finding without concrete exploit preconditions and impact.
+- Keep CWE category separate from severity.
+- Prefer a small, reproducible PoC over theoretical language.
+- Never run destructive exploits against real services or third-party systems.
+- Use local fixtures, toy payloads, dry runs, or static proof when real execution would be unsafe.
+
+## Team Roster
+
+Create one Team Mode run with these 5 members:
+
+| Member | Kind | Category | Role |
+|--------|------|----------|------|
+| \`surface-hunter\` | category | \`deep\` | Map entry points, trust boundaries, and reachable attack surfaces. |
+| \`auth-data-hunter\` | category | \`ultrabrain\` | Hunt auth, authorization, data isolation, injection, and secret handling flaws. |
+| \`runtime-supply-hunter\` | category | \`unspecified-high\` | Hunt filesystem, subprocess, archive, dependency, hook, MCP, and config risks. |
+| \`poc-engineer-a\` | category | \`unspecified-high\` | Build minimal PoCs for the strongest candidate findings. |
+| \`poc-engineer-b\` | category | \`deep\` | Independently reproduce, falsify, or downgrade candidate findings. |
+
+Call \`team_create\` with an inline spec:
+
+\`\`\`typescript
+team_create({
+ inline_spec: {
+ name: "security-review",
+ description: "Parallel exploitability-driven security review team.",
+ members: [
+ {
+ name: "surface-hunter",
+ kind: "category",
+ category: "deep",
+ prompt: "You map attack surface. Enumerate entry points, trust boundaries, attacker-controlled inputs, data sinks, privilege transitions, and sensitive assets. Return evidence with file paths and exact functions. Do not assign severity unless you can name an attack path."
+ },
+ {
+ name: "auth-data-hunter",
+ kind: "category",
+ category: "ultrabrain",
+ prompt: "You hunt auth, authorization, tenant/data isolation, injection, SSRF, credential exposure, and confused-deputy flaws. Reason from attacker capability to impact. Return only findings with concrete exploit preconditions, CWE candidates, and verification steps."
+ },
+ {
+ name: "runtime-supply-hunter",
+ kind: "category",
+ category: "unspecified-high",
+ prompt: "You hunt filesystem, subprocess, archive extraction, dependency, hook execution, MCP, config, and environment-variable risks. Check path traversal, command injection, unsafe downloads, permission boundaries, and supply-chain assumptions. Cite file paths and commands used."
+ },
+ {
+ name: "poc-engineer-a",
+ kind: "category",
+ category: "unspecified-high",
+ prompt: "You build minimal safe PoCs for candidate findings. Use toy inputs and local-only execution. Your job is to prove or disprove exploitability, not to broaden scope. Report exact reproduction steps and expected output."
+ },
+ {
+ name: "poc-engineer-b",
+ kind: "category",
+ category: "deep",
+ prompt: "You independently reproduce candidate findings and try to falsify them. Downgrade anything without a working path. If a PoC is unsafe to run, design a safe static or dry-run proof and explain the limit."
+ }
+ ]
+ }
+})
+\`\`\`
+
+If a category is unavailable, retry once by replacing only that category with \`unspecified-high\`. Do not reduce the team below 5 members.
+
+## Workflow
+
+### Phase 0: Scope and Baseline
+
+Collect:
+
+- Target scope and reason for audit.
+- Branch, base ref, diff, and changed files if this is a change review.
+- Security-sensitive directories and files if this is a full-repo audit.
+- Existing tests and commands that exercise relevant surfaces.
+- Any user-stated constraints, such as no network calls or no destructive tests.
+
+Use \`rg\`, \`git diff\`, \`git log\`, LSP, and existing tests before assigning work.
+
+### Phase 1: Independent Hunter Pass
+
+Send one prompt to the 3 hunters:
+
+\`\`\`text
+Audit target:
+{target summary}
+
+Context:
+{diff, file list, security-sensitive paths, known constraints}
+
+Task:
+Find candidate vulnerabilities in your assigned role. For each candidate include:
+- title
+- affected file/function
+- attacker capability
+- attack path
+- impact
+- CWE candidate
+- exact evidence
+- safe verification idea
+
+Reject generic hardening advice. Return only candidates with a plausible path.
+\`\`\`
+
+Wait for all hunters.
+
+### Phase 2: PoC Pass
+
+Deduplicate hunter candidates. Send the strongest candidates to both PoC engineers.
+
+Each PoC engineer must return:
+
+- Reproduced, falsified, or unsafe-to-run.
+- Exact commands, fixtures, or static proof.
+- Observed output or reason it fails.
+- Severity recommendation using exploitability and impact.
+- Downgrade rationale for anything not reproduced.
+
+### Phase 3: Cross-Check
+
+Send the PoC results back to all 5 members.
+
+Ask every member:
+
+- Which findings survive?
+- Which findings should be downgraded or removed?
+- What remediation is smallest and specific?
+- What regression test would prevent recurrence?
+
+### Phase 4: Final Report
+
+Produce this report:
+
+\`\`\`markdown
+## Security Review Result
+
+### Verdict
+PASS | PASS WITH FINDINGS | BLOCK
+
+### Scope
+- Target:
+- Base/diff:
+- Commands run:
+
+### Findings
+| Severity | Title | CWE | Exploitability | Impact | PoC | Fix |
+|----------|-------|-----|----------------|--------|-----|-----|
+
+### Finding Details
+For each finding:
+- Evidence:
+- Attack path:
+- PoC:
+- Severity rationale:
+- Minimal fix:
+- Regression check:
+
+### Downgraded or Rejected Candidates
+| Candidate | Reason |
+|-----------|--------|
+
+### Residual Risk
+- What was not tested and why.
+\`\`\`
+
+## Output Rules
+
+- Lead with the verdict.
+- Do not bury blocking issues.
+- Do not report speculative findings as vulnerabilities.
+- Do not claim CVSS precision unless you actually scored the metrics.
+- Include exact file paths and commands for every surviving finding.
+- If no findings survive PoC, say that plainly and list residual risk.
+`,
+}