Compare commits

..

2 Commits

Author SHA1 Message Date
YeonGyu-Kim
c25dbb94b2 docs: audit and update agent lists, models, and fallback chains
- Update README.md to prioritize Primary Agents (Sisyphus, Hephaestus, Prometheus, Atlas, Junior)
- Update overview.md and features.md to distinguish Primary Agents from Specialist Subagents
- Update Librarian and Multimodal-Looker models in docs to match source code fallback chains
- Ensure accuracy of agent descriptions and roles
2026-03-16 21:08:07 +09:00
YeonGyu-Kim
bed98988b3 docs: update outdated oh-my-opencode references to oh-my-openagent 2026-03-16 19:15:44 +09:00
524 changed files with 4764 additions and 69054 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 278 KiB

View File

@@ -60,33 +60,16 @@ jobs:
bun test src/features/opencode-skill-loader/loader.test.ts bun test src/features/opencode-skill-loader/loader.test.ts
bun test src/hooks/anthropic-context-window-limit-recovery/recovery-hook.test.ts bun test src/hooks/anthropic-context-window-limit-recovery/recovery-hook.test.ts
bun test src/hooks/anthropic-context-window-limit-recovery/executor.test.ts bun test src/hooks/anthropic-context-window-limit-recovery/executor.test.ts
# src/shared mock-heavy files (mock.module pollutes connected-providers-cache and legacy-plugin-warning)
bun test src/shared/model-capabilities.test.ts
bun test src/shared/log-legacy-plugin-startup-warning.test.ts
bun test src/shared/model-error-classifier.test.ts
bun test src/shared/opencode-message-dir.test.ts
# session-recovery mock isolation (recover-tool-result-missing mocks ./storage)
bun test src/hooks/session-recovery/recover-tool-result-missing.test.ts
# legacy-plugin-toast mock isolation (hook.test.ts mocks ./auto-migrate)
bun test src/hooks/legacy-plugin-toast/hook.test.ts
- name: Run remaining tests - name: Run remaining tests
run: | run: |
# Enumerate subdirectories/files explicitly to EXCLUDE mock-heavy files # Enumerate subdirectories/files explicitly to EXCLUDE mock-heavy files
# that were already run in isolation above. # that were already run in isolation above.
# Excluded from src/shared: model-capabilities, log-legacy-plugin-startup-warning, model-error-classifier, opencode-message-dir
# Excluded from src/cli: doctor/formatter.test.ts, doctor/format-default.test.ts # Excluded from src/cli: doctor/formatter.test.ts, doctor/format-default.test.ts
# Excluded from src/tools: call-omo-agent/sync-executor.test.ts, call-omo-agent/session-creator.test.ts, session-manager (all) # Excluded from src/tools: call-omo-agent/sync-executor.test.ts, call-omo-agent/session-creator.test.ts, session-manager (all)
# Excluded from src/hooks/anthropic-context-window-limit-recovery: recovery-hook.test.ts, executor.test.ts # Excluded from src/hooks/anthropic-context-window-limit-recovery: recovery-hook.test.ts, executor.test.ts
# Build src/shared file list excluding mock-heavy files already run in isolation
SHARED_FILES=$(find src/shared -name '*.test.ts' \
! -name 'model-capabilities.test.ts' \
! -name 'log-legacy-plugin-startup-warning.test.ts' \
! -name 'model-error-classifier.test.ts' \
! -name 'opencode-message-dir.test.ts' \
| sort | tr '\n' ' ')
bun test bin script src/config src/mcp src/index.test.ts \ bun test bin script src/config src/mcp src/index.test.ts \
src/agents $SHARED_FILES \ src/agents src/shared \
src/cli/run src/cli/config-manager src/cli/mcp-oauth \ src/cli/run src/cli/config-manager src/cli/mcp-oauth \
src/cli/index.test.ts src/cli/install.test.ts src/cli/model-fallback.test.ts \ src/cli/index.test.ts src/cli/install.test.ts src/cli/model-fallback.test.ts \
src/cli/config-manager.test.ts \ src/cli/config-manager.test.ts \
@@ -99,8 +82,6 @@ jobs:
src/tools/call-omo-agent/background-executor.test.ts \ src/tools/call-omo-agent/background-executor.test.ts \
src/tools/call-omo-agent/subagent-session-creator.test.ts \ src/tools/call-omo-agent/subagent-session-creator.test.ts \
src/hooks/anthropic-context-window-limit-recovery/empty-content-recovery-sdk.test.ts src/hooks/anthropic-context-window-limit-recovery/parser.test.ts src/hooks/anthropic-context-window-limit-recovery/pruning-deduplication.test.ts src/hooks/anthropic-context-window-limit-recovery/recovery-deduplication.test.ts src/hooks/anthropic-context-window-limit-recovery/storage.test.ts \ src/hooks/anthropic-context-window-limit-recovery/empty-content-recovery-sdk.test.ts src/hooks/anthropic-context-window-limit-recovery/parser.test.ts src/hooks/anthropic-context-window-limit-recovery/pruning-deduplication.test.ts src/hooks/anthropic-context-window-limit-recovery/recovery-deduplication.test.ts src/hooks/anthropic-context-window-limit-recovery/storage.test.ts \
src/hooks/session-recovery/detect-error-type.test.ts src/hooks/session-recovery/index.test.ts src/hooks/session-recovery/recover-empty-content-message-sdk.test.ts src/hooks/session-recovery/resume.test.ts src/hooks/session-recovery/storage \
src/hooks/legacy-plugin-toast/auto-migrate.test.ts \
src/hooks/claude-code-compatibility \ src/hooks/claude-code-compatibility \
src/hooks/context-injection \ src/hooks/context-injection \
src/hooks/provider-toast \ src/hooks/provider-toast \

View File

@@ -56,81 +56,36 @@ jobs:
env: env:
BUN_INSTALL_ALLOW_SCRIPTS: "@ast-grep/napi" BUN_INSTALL_ALLOW_SCRIPTS: "@ast-grep/napi"
- name: Validate release inputs
id: validate
env:
INPUT_VERSION: ${{ inputs.version }}
INPUT_DIST_TAG: ${{ inputs.dist_tag }}
run: |
VERSION="$INPUT_VERSION"
DIST_TAG="$INPUT_DIST_TAG"
if ! [[ "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z]+(\.[0-9A-Za-z]+)*)?$ ]]; then
echo "::error::Invalid version: $VERSION"
exit 1
fi
if [ -n "$DIST_TAG" ] && ! [[ "$DIST_TAG" =~ ^[a-z][a-z0-9-]*$ ]]; then
echo "::error::Invalid dist_tag: $DIST_TAG"
exit 1
fi
echo "version=$VERSION" >> $GITHUB_OUTPUT
echo "dist_tag=$DIST_TAG" >> $GITHUB_OUTPUT
- name: Check if already published - name: Check if already published
id: check id: check
env:
VERSION: ${{ steps.validate.outputs.version }}
run: | run: |
PKG_NAME="oh-my-opencode-${{ matrix.platform }}"
VERSION="${{ inputs.version }}"
STATUS=$(curl -s -o /dev/null -w "%{http_code}" "https://registry.npmjs.org/${PKG_NAME}/${VERSION}")
# Convert platform name for output (replace - with _)
PLATFORM_KEY="${{ matrix.platform }}" PLATFORM_KEY="${{ matrix.platform }}"
PLATFORM_KEY="${PLATFORM_KEY//-/_}" PLATFORM_KEY="${PLATFORM_KEY//-/_}"
if [ "$STATUS" = "200" ]; then
# Check oh-my-opencode
OC_STATUS=$(curl -s -o /dev/null -w "%{http_code}" "https://registry.npmjs.org/oh-my-opencode-${{ matrix.platform }}/${VERSION}")
# Check oh-my-openagent
OA_STATUS=$(curl -s -o /dev/null -w "%{http_code}" "https://registry.npmjs.org/oh-my-openagent-${{ matrix.platform }}/${VERSION}")
echo "oh-my-opencode-${{ matrix.platform }}@${VERSION}: ${OC_STATUS}"
echo "oh-my-openagent-${{ matrix.platform }}@${VERSION}: ${OA_STATUS}"
if [ "$OC_STATUS" = "200" ]; then
echo "skip_opencode=true" >> $GITHUB_OUTPUT
echo "✓ oh-my-opencode-${{ matrix.platform }}@${VERSION} already published"
else
echo "skip_opencode=false" >> $GITHUB_OUTPUT
echo "→ oh-my-opencode-${{ matrix.platform }}@${VERSION} needs publishing"
fi
if [ "$OA_STATUS" = "200" ]; then
echo "skip_openagent=true" >> $GITHUB_OUTPUT
echo "✓ oh-my-openagent-${{ matrix.platform }}@${VERSION} already published"
else
echo "skip_openagent=false" >> $GITHUB_OUTPUT
echo "→ oh-my-openagent-${{ matrix.platform }}@${VERSION} needs publishing"
fi
# Skip build only if BOTH are already published
if [ "$OC_STATUS" = "200" ] && [ "$OA_STATUS" = "200" ]; then
echo "skip=true" >> $GITHUB_OUTPUT echo "skip=true" >> $GITHUB_OUTPUT
echo "skip_${PLATFORM_KEY}=true" >> $GITHUB_OUTPUT
echo "✓ ${PKG_NAME}@${VERSION} already published"
else else
echo "skip=false" >> $GITHUB_OUTPUT echo "skip=false" >> $GITHUB_OUTPUT
echo "skip_${PLATFORM_KEY}=false" >> $GITHUB_OUTPUT
echo "→ ${PKG_NAME}@${VERSION} needs publishing"
fi fi
- name: Update version in package.json - name: Update version in package.json
if: steps.check.outputs.skip != 'true' if: steps.check.outputs.skip != 'true'
env:
VERSION: ${{ steps.validate.outputs.version }}
run: | run: |
VERSION="${{ inputs.version }}"
cd packages/${{ matrix.platform }} cd packages/${{ matrix.platform }}
jq --arg v "$VERSION" '.version = $v' package.json > tmp.json && mv tmp.json package.json jq --arg v "$VERSION" '.version = $v' package.json > tmp.json && mv tmp.json package.json
- name: Set root package version - name: Set root package version
if: steps.check.outputs.skip != 'true' if: steps.check.outputs.skip != 'true'
env:
VERSION: ${{ steps.validate.outputs.version }}
run: | run: |
jq --arg v "$VERSION" '.version = $v' package.json > tmp.json && mv tmp.json package.json jq --arg v "${{ inputs.version }}" '.version = $v' package.json > tmp.json && mv tmp.json package.json
- name: Pre-download baseline compile target - name: Pre-download baseline compile target
if: steps.check.outputs.skip != 'true' && endsWith(matrix.platform, '-baseline') if: steps.check.outputs.skip != 'true' && endsWith(matrix.platform, '-baseline')
@@ -252,60 +207,23 @@ jobs:
matrix: matrix:
platform: [darwin-arm64, darwin-x64, darwin-x64-baseline, linux-x64, linux-x64-baseline, linux-arm64, linux-x64-musl, linux-x64-musl-baseline, linux-arm64-musl, windows-x64, windows-x64-baseline] platform: [darwin-arm64, darwin-x64, darwin-x64-baseline, linux-x64, linux-x64-baseline, linux-arm64, linux-x64-musl, linux-x64-musl-baseline, linux-arm64-musl, windows-x64, windows-x64-baseline]
steps: steps:
- name: Validate release inputs - name: Check if oh-my-opencode already published
id: validate
env:
INPUT_VERSION: ${{ inputs.version }}
INPUT_DIST_TAG: ${{ inputs.dist_tag }}
run: |
VERSION="$INPUT_VERSION"
DIST_TAG="$INPUT_DIST_TAG"
if ! [[ "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z]+(\.[0-9A-Za-z]+)*)?$ ]]; then
echo "::error::Invalid version: $VERSION"
exit 1
fi
if [ -n "$DIST_TAG" ] && ! [[ "$DIST_TAG" =~ ^[a-z][a-z0-9-]*$ ]]; then
echo "::error::Invalid dist_tag: $DIST_TAG"
exit 1
fi
echo "version=$VERSION" >> $GITHUB_OUTPUT
echo "dist_tag=$DIST_TAG" >> $GITHUB_OUTPUT
- name: Check if already published
id: check id: check
env:
VERSION: ${{ steps.validate.outputs.version }}
run: | run: |
OC_STATUS=$(curl -s -o /dev/null -w "%{http_code}" "https://registry.npmjs.org/oh-my-opencode-${{ matrix.platform }}/${VERSION}") PKG_NAME="oh-my-opencode-${{ matrix.platform }}"
OA_STATUS=$(curl -s -o /dev/null -w "%{http_code}" "https://registry.npmjs.org/oh-my-openagent-${{ matrix.platform }}/${VERSION}") VERSION="${{ inputs.version }}"
STATUS=$(curl -s -o /dev/null -w "%{http_code}" "https://registry.npmjs.org/${PKG_NAME}/${VERSION}")
if [ "$OC_STATUS" = "200" ]; then if [ "$STATUS" = "200" ]; then
echo "skip_opencode=true" >> $GITHUB_OUTPUT echo "skip=true" >> $GITHUB_OUTPUT
echo "✓ oh-my-opencode-${{ matrix.platform }}@${VERSION} already published" echo "✓ ${PKG_NAME}@${VERSION} already published, skipping"
else else
echo "skip_opencode=false" >> $GITHUB_OUTPUT echo "skip=false" >> $GITHUB_OUTPUT
fi echo "→ ${PKG_NAME}@${VERSION} will be published"
if [ "$OA_STATUS" = "200" ]; then
echo "skip_openagent=true" >> $GITHUB_OUTPUT
echo "✓ oh-my-openagent-${{ matrix.platform }}@${VERSION} already published"
else
echo "skip_openagent=false" >> $GITHUB_OUTPUT
fi
# Need artifact if either package needs publishing
if [ "$OC_STATUS" = "200" ] && [ "$OA_STATUS" = "200" ]; then
echo "skip_all=true" >> $GITHUB_OUTPUT
else
echo "skip_all=false" >> $GITHUB_OUTPUT
fi fi
- name: Download artifact - name: Download artifact
id: download id: download
if: steps.check.outputs.skip_all != 'true' if: steps.check.outputs.skip != 'true'
continue-on-error: true continue-on-error: true
uses: actions/download-artifact@v4 uses: actions/download-artifact@v4
with: with:
@@ -313,7 +231,7 @@ jobs:
path: . path: .
- name: Extract artifact - name: Extract artifact
if: steps.check.outputs.skip_all != 'true' && steps.download.outcome == 'success' if: steps.check.outputs.skip != 'true' && steps.download.outcome == 'success'
run: | run: |
PLATFORM="${{ matrix.platform }}" PLATFORM="${{ matrix.platform }}"
mkdir -p packages/${PLATFORM} mkdir -p packages/${PLATFORM}
@@ -329,45 +247,23 @@ jobs:
ls -la packages/${PLATFORM}/bin/ ls -la packages/${PLATFORM}/bin/
- uses: actions/setup-node@v4 - uses: actions/setup-node@v4
if: steps.check.outputs.skip_all != 'true' && steps.download.outcome == 'success' if: steps.check.outputs.skip != 'true' && steps.download.outcome == 'success'
with: with:
node-version: "24" node-version: "24"
registry-url: "https://registry.npmjs.org" registry-url: "https://registry.npmjs.org"
- name: Publish oh-my-opencode-${{ matrix.platform }} - name: Publish ${{ matrix.platform }}
if: steps.check.outputs.skip_opencode != 'true' && steps.download.outcome == 'success' if: steps.check.outputs.skip != 'true' && steps.download.outcome == 'success'
env:
DIST_TAG: ${{ steps.validate.outputs.dist_tag }}
NODE_AUTH_TOKEN: ${{ secrets.NODE_AUTH_TOKEN }}
NPM_CONFIG_PROVENANCE: true
run: | run: |
cd packages/${{ matrix.platform }} cd packages/${{ matrix.platform }}
if [ -n "$DIST_TAG" ]; then TAG_ARG=""
npm publish --access public --provenance --tag "$DIST_TAG" if [ -n "${{ inputs.dist_tag }}" ]; then
else TAG_ARG="--tag ${{ inputs.dist_tag }}"
npm publish --access public --provenance
fi fi
timeout-minutes: 15
npm publish --access public --provenance $TAG_ARG
- name: Publish oh-my-openagent-${{ matrix.platform }}
if: steps.check.outputs.skip_openagent != 'true' && steps.download.outcome == 'success'
env: env:
DIST_TAG: ${{ steps.validate.outputs.dist_tag }}
NODE_AUTH_TOKEN: ${{ secrets.NODE_AUTH_TOKEN }} NODE_AUTH_TOKEN: ${{ secrets.NODE_AUTH_TOKEN }}
NPM_CONFIG_PROVENANCE: true NPM_CONFIG_PROVENANCE: true
run: |
cd packages/${{ matrix.platform }}
# Rename package for oh-my-openagent
jq --arg name "oh-my-openagent-${{ matrix.platform }}" \
--arg desc "Platform-specific binary for oh-my-openagent (${{ matrix.platform }})" \
'.name = $name | .description = $desc | .bin = {"oh-my-openagent": (.bin | to_entries | .[0].value)}' \
package.json > tmp.json && mv tmp.json package.json
if [ -n "$DIST_TAG" ]; then
npm publish --access public --provenance --tag "$DIST_TAG"
else
npm publish --access public --provenance
fi
timeout-minutes: 15 timeout-minutes: 15

View File

@@ -57,51 +57,32 @@ jobs:
bun test src/cli/doctor/format-default.test.ts bun test src/cli/doctor/format-default.test.ts
bun test src/tools/call-omo-agent/sync-executor.test.ts bun test src/tools/call-omo-agent/sync-executor.test.ts
bun test src/tools/call-omo-agent/session-creator.test.ts bun test src/tools/call-omo-agent/session-creator.test.ts
bun test src/tools/session-manager
bun test src/features/opencode-skill-loader/loader.test.ts bun test src/features/opencode-skill-loader/loader.test.ts
bun test src/hooks/anthropic-context-window-limit-recovery/recovery-hook.test.ts bun test src/hooks/anthropic-context-window-limit-recovery/recovery-hook.test.ts
bun test src/hooks/anthropic-context-window-limit-recovery/executor.test.ts bun test src/hooks/anthropic-context-window-limit-recovery/executor.test.ts
# src/shared mock-heavy files (mock.module pollutes connected-providers-cache and legacy-plugin-warning)
bun test src/shared/model-capabilities.test.ts
bun test src/shared/log-legacy-plugin-startup-warning.test.ts
bun test src/shared/model-error-classifier.test.ts
bun test src/shared/opencode-message-dir.test.ts
# session-recovery mock isolation (recover-tool-result-missing mocks ./storage)
bun test src/hooks/session-recovery/recover-tool-result-missing.test.ts
# legacy-plugin-toast mock isolation (hook.test.ts mocks ./auto-migrate)
bun test src/hooks/legacy-plugin-toast/hook.test.ts
- name: Run remaining tests - name: Run remaining tests
run: | run: |
# Enumerate subdirectories/files explicitly to EXCLUDE mock-heavy files # Enumerate subdirectories/files explicitly to EXCLUDE mock-heavy files
# that were already run in isolation above. # that were already run in isolation above.
# Excluded from src/shared: model-capabilities, log-legacy-plugin-startup-warning, model-error-classifier, opencode-message-dir
# Excluded from src/cli: doctor/formatter.test.ts, doctor/format-default.test.ts # Excluded from src/cli: doctor/formatter.test.ts, doctor/format-default.test.ts
# Excluded from src/tools: call-omo-agent/sync-executor.test.ts, call-omo-agent/session-creator.test.ts, session-manager (all) # Excluded from src/tools: call-omo-agent/sync-executor.test.ts, call-omo-agent/session-creator.test.ts
# Excluded from src/hooks/anthropic-context-window-limit-recovery: recovery-hook.test.ts, executor.test.ts # Excluded from src/hooks/anthropic-context-window-limit-recovery: recovery-hook.test.ts, executor.test.ts
# Build src/shared file list excluding mock-heavy files already run in isolation # Excluded from src/tools: call-omo-agent/sync-executor.test.ts, call-omo-agent/session-creator.test.ts
SHARED_FILES=$(find src/shared -name '*.test.ts' \
! -name 'model-capabilities.test.ts' \
! -name 'log-legacy-plugin-startup-warning.test.ts' \
! -name 'model-error-classifier.test.ts' \
! -name 'opencode-message-dir.test.ts' \
| sort | tr '\n' ' ')
bun test bin script src/config src/mcp src/index.test.ts \ bun test bin script src/config src/mcp src/index.test.ts \
src/agents $SHARED_FILES \ src/agents src/shared \
src/cli/run src/cli/config-manager src/cli/mcp-oauth \ src/cli/run src/cli/config-manager src/cli/mcp-oauth \
src/cli/index.test.ts src/cli/install.test.ts src/cli/model-fallback.test.ts \ src/cli/index.test.ts src/cli/install.test.ts src/cli/model-fallback.test.ts \
src/cli/config-manager.test.ts \ src/cli/config-manager.test.ts \
src/cli/doctor/runner.test.ts src/cli/doctor/checks \ src/cli/doctor/runner.test.ts src/cli/doctor/checks \
src/tools/ast-grep src/tools/background-task src/tools/delegate-task \ src/tools/ast-grep src/tools/background-task src/tools/delegate-task \
src/tools/glob src/tools/grep src/tools/interactive-bash \ src/tools/glob src/tools/grep src/tools/interactive-bash \
src/tools/look-at src/tools/lsp \ src/tools/look-at src/tools/lsp src/tools/session-manager \
src/tools/skill src/tools/skill-mcp src/tools/slashcommand src/tools/task \ src/tools/skill src/tools/skill-mcp src/tools/slashcommand src/tools/task \
src/tools/call-omo-agent/background-agent-executor.test.ts \ src/tools/call-omo-agent/background-agent-executor.test.ts \
src/tools/call-omo-agent/background-executor.test.ts \ src/tools/call-omo-agent/background-executor.test.ts \
src/tools/call-omo-agent/subagent-session-creator.test.ts \ src/tools/call-omo-agent/subagent-session-creator.test.ts \
src/hooks/anthropic-context-window-limit-recovery/empty-content-recovery-sdk.test.ts src/hooks/anthropic-context-window-limit-recovery/parser.test.ts src/hooks/anthropic-context-window-limit-recovery/pruning-deduplication.test.ts src/hooks/anthropic-context-window-limit-recovery/recovery-deduplication.test.ts src/hooks/anthropic-context-window-limit-recovery/storage.test.ts \ src/hooks/anthropic-context-window-limit-recovery/empty-content-recovery-sdk.test.ts src/hooks/anthropic-context-window-limit-recovery/parser.test.ts src/hooks/anthropic-context-window-limit-recovery/pruning-deduplication.test.ts src/hooks/anthropic-context-window-limit-recovery/recovery-deduplication.test.ts src/hooks/anthropic-context-window-limit-recovery/storage.test.ts \
src/hooks/session-recovery/detect-error-type.test.ts src/hooks/session-recovery/index.test.ts src/hooks/session-recovery/recover-empty-content-message-sdk.test.ts src/hooks/session-recovery/resume.test.ts src/hooks/session-recovery/storage \
src/hooks/legacy-plugin-toast/auto-migrate.test.ts \
src/hooks/claude-code-compatibility \ src/hooks/claude-code-compatibility \
src/hooks/context-injection \ src/hooks/context-injection \
src/hooks/provider-toast \ src/hooks/provider-toast \
@@ -167,47 +148,33 @@ jobs:
- name: Calculate version - name: Calculate version
id: version id: version
env:
RAW_VERSION: ${{ inputs.version }}
BUMP: ${{ inputs.bump }}
run: | run: |
VERSION="$RAW_VERSION" VERSION="${{ inputs.version }}"
if [ -z "$VERSION" ]; then if [ -z "$VERSION" ]; then
PREV=$(curl -s https://registry.npmjs.org/oh-my-opencode/latest | jq -r '.version // "0.0.0"') PREV=$(curl -s https://registry.npmjs.org/oh-my-opencode/latest | jq -r '.version // "0.0.0"')
BASE="${PREV%%-*}" BASE="${PREV%%-*}"
IFS='.' read -r MAJOR MINOR PATCH <<< "$BASE" IFS='.' read -r MAJOR MINOR PATCH <<< "$BASE"
case "$BUMP" in case "${{ inputs.bump }}" in
major) VERSION="$((MAJOR+1)).0.0" ;; major) VERSION="$((MAJOR+1)).0.0" ;;
minor) VERSION="${MAJOR}.$((MINOR+1)).0" ;; minor) VERSION="${MAJOR}.$((MINOR+1)).0" ;;
*) VERSION="${MAJOR}.${MINOR}.$((PATCH+1))" ;; *) VERSION="${MAJOR}.${MINOR}.$((PATCH+1))" ;;
esac esac
fi fi
if ! [[ "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z]+(\.[0-9A-Za-z]+)*)?$ ]]; then
echo "::error::Invalid version: $VERSION"
exit 1
fi
echo "version=$VERSION" >> $GITHUB_OUTPUT echo "version=$VERSION" >> $GITHUB_OUTPUT
if [[ "$VERSION" == *"-"* ]]; then if [[ "$VERSION" == *"-"* ]]; then
DIST_TAG=$(printf '%s' "$VERSION" | cut -d'-' -f2 | cut -d'.' -f1) DIST_TAG=$(echo "$VERSION" | cut -d'-' -f2 | cut -d'.' -f1)
if ! [[ "$DIST_TAG" =~ ^[a-z][a-z0-9-]*$ ]]; then
echo "::error::Invalid dist_tag: $DIST_TAG"
exit 1
fi
echo "dist_tag=${DIST_TAG:-next}" >> $GITHUB_OUTPUT echo "dist_tag=${DIST_TAG:-next}" >> $GITHUB_OUTPUT
else else
echo "dist_tag=" >> $GITHUB_OUTPUT echo "dist_tag=" >> $GITHUB_OUTPUT
fi fi
echo "Version: $VERSION" echo "Version: $VERSION"
- name: Check if already published - name: Check if already published
id: check id: check
env:
VERSION: ${{ steps.version.outputs.version }}
run: | run: |
VERSION="${{ steps.version.outputs.version }}"
STATUS=$(curl -s -o /dev/null -w "%{http_code}" "https://registry.npmjs.org/oh-my-opencode/${VERSION}") STATUS=$(curl -s -o /dev/null -w "%{http_code}" "https://registry.npmjs.org/oh-my-opencode/${VERSION}")
if [ "$STATUS" = "200" ]; then if [ "$STATUS" = "200" ]; then
echo "skip=true" >> $GITHUB_OUTPUT echo "skip=true" >> $GITHUB_OUTPUT
@@ -218,16 +185,15 @@ jobs:
- name: Update version - name: Update version
if: steps.check.outputs.skip != 'true' if: steps.check.outputs.skip != 'true'
env:
VERSION: ${{ steps.version.outputs.version }}
run: | run: |
VERSION="${{ steps.version.outputs.version }}"
jq --arg v "$VERSION" '.version = $v' package.json > tmp.json && mv tmp.json package.json jq --arg v "$VERSION" '.version = $v' package.json > tmp.json && mv tmp.json package.json
for platform in darwin-arm64 darwin-x64 darwin-x64-baseline linux-x64 linux-x64-baseline linux-arm64 linux-x64-musl linux-x64-musl-baseline linux-arm64-musl windows-x64 windows-x64-baseline; do for platform in darwin-arm64 darwin-x64 darwin-x64-baseline linux-x64 linux-x64-baseline linux-arm64 linux-x64-musl linux-x64-musl-baseline linux-arm64-musl windows-x64 windows-x64-baseline; do
jq --arg v "$VERSION" '.version = $v' "packages/${platform}/package.json" > tmp.json jq --arg v "$VERSION" '.version = $v' "packages/${platform}/package.json" > tmp.json
mv tmp.json "packages/${platform}/package.json" mv tmp.json "packages/${platform}/package.json"
done done
jq --arg v "$VERSION" '.optionalDependencies = (.optionalDependencies | to_entries | map(.value = $v) | from_entries)' package.json > tmp.json && mv tmp.json package.json jq --arg v "$VERSION" '.optionalDependencies = (.optionalDependencies | to_entries | map(.value = $v) | from_entries)' package.json > tmp.json && mv tmp.json package.json
- name: Build main package - name: Build main package
@@ -240,73 +206,34 @@ jobs:
- name: Publish oh-my-opencode - name: Publish oh-my-opencode
if: steps.check.outputs.skip != 'true' if: steps.check.outputs.skip != 'true'
run: |
TAG_ARG=""
if [ -n "${{ steps.version.outputs.dist_tag }}" ]; then
TAG_ARG="--tag ${{ steps.version.outputs.dist_tag }}"
fi
npm publish --access public --provenance $TAG_ARG
env: env:
DIST_TAG: ${{ steps.version.outputs.dist_tag }}
NODE_AUTH_TOKEN: ${{ secrets.NODE_AUTH_TOKEN }} NODE_AUTH_TOKEN: ${{ secrets.NODE_AUTH_TOKEN }}
NPM_CONFIG_PROVENANCE: true NPM_CONFIG_PROVENANCE: true
run: |
if [ -n "$DIST_TAG" ]; then
npm publish --access public --provenance --tag "$DIST_TAG"
else
npm publish --access public --provenance
fi
- name: Check if oh-my-openagent already published trigger-platform:
id: check-openagent runs-on: ubuntu-latest
env:
VERSION: ${{ steps.version.outputs.version }}
run: |
STATUS=$(curl -s -o /dev/null -w "%{http_code}" "https://registry.npmjs.org/oh-my-openagent/${VERSION}")
if [ "$STATUS" = "200" ]; then
echo "skip=true" >> $GITHUB_OUTPUT
echo "✓ oh-my-openagent@${VERSION} already published"
else
echo "skip=false" >> $GITHUB_OUTPUT
fi
- name: Publish oh-my-openagent
if: steps.check-openagent.outputs.skip != 'true'
env:
VERSION: ${{ steps.version.outputs.version }}
DIST_TAG: ${{ steps.version.outputs.dist_tag }}
NODE_AUTH_TOKEN: ${{ secrets.NODE_AUTH_TOKEN }}
NPM_CONFIG_PROVENANCE: true
run: |
# Update package name, version, and optionalDependencies for oh-my-openagent
jq --arg v "$VERSION" '
.name = "oh-my-openagent" |
.version = $v |
.optionalDependencies = (
.optionalDependencies | to_entries |
map(.key = (.key | sub("^oh-my-opencode-"; "oh-my-openagent-")) | .value = $v) |
from_entries
)
' package.json > tmp.json && mv tmp.json package.json
if [ -n "$DIST_TAG" ]; then
npm publish --access public --provenance --tag "$DIST_TAG"
else
npm publish --access public --provenance
fi
- name: Restore package.json
if: always() && steps.check-openagent.outputs.skip != 'true'
run: |
git checkout -- package.json
publish-platform:
needs: publish-main needs: publish-main
if: inputs.skip_platform != true if: inputs.skip_platform != true
uses: ./.github/workflows/publish-platform.yml steps:
with: - name: Trigger platform publish workflow
version: ${{ needs.publish-main.outputs.version }} run: |
dist_tag: ${{ needs.publish-main.outputs.dist_tag }} gh workflow run publish-platform.yml \
secrets: inherit --repo ${{ github.repository }} \
--ref ${{ github.ref }} \
-f version=${{ needs.publish-main.outputs.version }} \
-f dist_tag=${{ needs.publish-main.outputs.dist_tag }}
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
release: release:
runs-on: ubuntu-latest runs-on: ubuntu-latest
needs: [publish-main, publish-platform] needs: publish-main
if: always() && needs.publish-main.result == 'success' && (inputs.skip_platform == true || needs.publish-platform.result == 'success')
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
with: with:
@@ -330,53 +257,13 @@ jobs:
env: env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Apply release version to source tree
env:
VERSION: ${{ needs.publish-main.outputs.version }}
run: |
jq --arg v "$VERSION" '.version = $v' package.json > tmp.json && mv tmp.json package.json
for platform in darwin-arm64 darwin-x64 darwin-x64-baseline linux-x64 linux-x64-baseline linux-arm64 linux-x64-musl linux-x64-musl-baseline linux-arm64-musl windows-x64 windows-x64-baseline; do
jq --arg v "$VERSION" '.version = $v' "packages/${platform}/package.json" > tmp.json
mv tmp.json "packages/${platform}/package.json"
done
jq --arg v "$VERSION" '.optionalDependencies = (.optionalDependencies | to_entries | map(.value = $v) | from_entries)' package.json > tmp.json && mv tmp.json package.json
- name: Commit version bump
env:
VERSION: ${{ needs.publish-main.outputs.version }}
run: |
git config user.email "github-actions[bot]@users.noreply.github.com"
git config user.name "github-actions[bot]"
git add package.json packages/*/package.json
git diff --cached --quiet || git commit -m "release: v${VERSION}"
- name: Create release tag
env:
VERSION: ${{ needs.publish-main.outputs.version }}
run: |
if git rev-parse "v${VERSION}" >/dev/null 2>&1; then
echo "::error::Tag v${VERSION} already exists"
exit 1
fi
git tag "v${VERSION}"
- name: Push release state
env:
VERSION: ${{ needs.publish-main.outputs.version }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
git push origin HEAD
git push origin "v${VERSION}"
- name: Create GitHub release - name: Create GitHub release
env:
VERSION: ${{ needs.publish-main.outputs.version }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: | run: |
VERSION="${{ needs.publish-main.outputs.version }}"
gh release view "v${VERSION}" >/dev/null 2>&1 || \ gh release view "v${VERSION}" >/dev/null 2>&1 || \
gh release create "v${VERSION}" --title "v${VERSION}" --notes-file /tmp/changelog.md gh release create "v${VERSION}" --title "v${VERSION}" --notes-file /tmp/changelog.md
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Delete draft release - name: Delete draft release
run: gh release delete next --yes 2>/dev/null || true run: gh release delete next --yes 2>/dev/null || true
@@ -385,13 +272,13 @@ jobs:
- name: Merge to master - name: Merge to master
continue-on-error: true continue-on-error: true
env:
VERSION: ${{ needs.publish-main.outputs.version }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: | run: |
git config user.name "github-actions[bot]" git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com" git config user.email "github-actions[bot]@users.noreply.github.com"
VERSION="${{ needs.publish-main.outputs.version }}"
git stash --include-untracked || true git stash --include-untracked || true
git checkout master git checkout master
git reset --hard "v${VERSION}" git reset --hard "v${VERSION}"
git push -f origin master || echo "::warning::Failed to push to master" git push -f origin master || echo "::warning::Failed to push to master"
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -1,46 +0,0 @@
name: Refresh Model Capabilities
on:
schedule:
- cron: "17 4 * * 1"
workflow_dispatch:
permissions:
contents: write
pull-requests: write
jobs:
refresh:
runs-on: ubuntu-latest
if: github.repository == 'code-yeongyu/oh-my-openagent'
steps:
- uses: actions/checkout@v4
- uses: oven-sh/setup-bun@v2
with:
bun-version: latest
- name: Install dependencies
run: bun install
env:
BUN_INSTALL_ALLOW_SCRIPTS: "@ast-grep/napi"
- name: Refresh bundled model capabilities snapshot
run: bun run build:model-capabilities
- name: Validate capability guardrails
run: bun run test:model-capabilities
- name: Create refresh pull request
uses: peter-evans/create-pull-request@v7
with:
commit-message: "chore: refresh model capabilities snapshot"
title: "chore: refresh model capabilities snapshot"
body: |
Automated refresh of `src/generated/model-capabilities.generated.json` from `https://models.dev/api.json`.
This keeps the bundled capability snapshot aligned with upstream model metadata without relying on manual refreshes.
branch: automation/refresh-model-capabilities
delete-branch: true
labels: |
maintenance

1
.gitignore vendored
View File

@@ -36,4 +36,3 @@ test-injection/
notepad.md notepad.md
oauth-success.html oauth-success.html
*.bun-build *.bun-build
.omx/

View File

@@ -26,7 +26,7 @@ For each commit, you MUST:
<version-context> <version-context>
<published-version> <published-version>
!`npm view oh-my-opencode version 2>/dev/null || echo "not published"` !`npm view oh-my-openagent version 2>/dev/null || echo "not published"`
</published-version> </published-version>
<local-version> <local-version>
!`node -p "require('./package.json').version" 2>/dev/null || echo "unknown"` !`node -p "require('./package.json').version" 2>/dev/null || echo "unknown"`
@@ -38,13 +38,13 @@ For each commit, you MUST:
<git-context> <git-context>
<commits-since-release> <commits-since-release>
!`npm view oh-my-opencode version 2>/dev/null | xargs -I{} git log "v{}"..HEAD --oneline 2>/dev/null || echo "no commits since release"` !`npm view oh-my-openagent version 2>/dev/null | xargs -I{} git log "v{}"..HEAD --oneline 2>/dev/null || echo "no commits since release"`
</commits-since-release> </commits-since-release>
<diff-stat> <diff-stat>
!`npm view oh-my-opencode version 2>/dev/null | xargs -I{} git diff "v{}"..HEAD --stat 2>/dev/null || echo "no diff available"` !`npm view oh-my-openagent version 2>/dev/null | xargs -I{} git diff "v{}"..HEAD --stat 2>/dev/null || echo "no diff available"`
</diff-stat> </diff-stat>
<files-changed-summary> <files-changed-summary>
!`npm view oh-my-opencode version 2>/dev/null | xargs -I{} git diff "v{}"..HEAD --stat 2>/dev/null | tail -1 || echo ""` !`npm view oh-my-openagent version 2>/dev/null | xargs -I{} git diff "v{}"..HEAD --stat 2>/dev/null | tail -1 || echo ""`
</files-changed-summary> </files-changed-summary>
</git-context> </git-context>

View File

@@ -1,5 +1,5 @@
--- ---
description: Easter egg command - about oh-my-opencode description: Easter egg command - about oh-my-openagent
--- ---
<command-instruction> <command-instruction>
@@ -13,9 +13,9 @@ Print the following message to the user EXACTLY as written (in a friendly, celeb
**You found the easter egg!** 🥚✨ **You found the easter egg!** 🥚✨
## What is Oh My OpenCode? ## What is Oh My OpenAgent?
**Oh My OpenCode** is a powerful OpenCode plugin that transforms your AI agent into a full development team: **Oh My OpenAgent** is a powerful OpenCode plugin that transforms your AI agent into a full development team:
- 🤖 **Multi-Agent Orchestration**: Oracle (GPT-5.2), Librarian (Claude), Explore (Grok), Frontend Engineer (Gemini), and more - 🤖 **Multi-Agent Orchestration**: Oracle (GPT-5.2), Librarian (Claude), Explore (Grok), Frontend Engineer (Gemini), and more
- 🔧 **LSP Tools**: Full IDE capabilities for your agents - hover, goto definition, find references, rename, code actions - 🔧 **LSP Tools**: Full IDE capabilities for your agents - hover, goto definition, find references, rename, code actions
@@ -28,7 +28,7 @@ Print the following message to the user EXACTLY as written (in a friendly, celeb
Created with ❤️ by **[code-yeongyu](https://github.com/code-yeongyu)** Created with ❤️ by **[code-yeongyu](https://github.com/code-yeongyu)**
🔗 **GitHub**: https://github.com/code-yeongyu/oh-my-opencode 🔗 **GitHub**: https://github.com/code-yeongyu/oh-my-openagent
--- ---

View File

@@ -1,10 +1,10 @@
--- ---
description: Publish oh-my-opencode to npm via GitHub Actions workflow description: Publish oh-my-openagent to npm via GitHub Actions workflow
argument-hint: <patch|minor|major> argument-hint: <patch|minor|major>
--- ---
<command-instruction> <command-instruction>
You are the release manager for oh-my-opencode. Execute the FULL publish workflow from start to finish. You are the release manager for oh-my-openagent. Execute the FULL publish workflow from start to finish.
## CRITICAL: ARGUMENT REQUIREMENT ## CRITICAL: ARGUMENT REQUIREMENT
@@ -277,7 +277,7 @@ gh release view "v${NEW_VERSION}" --json url --jq '.url'
Poll npm registry until the new version appears: Poll npm registry until the new version appears:
```bash ```bash
npm view oh-my-opencode version npm view oh-my-openagent version
``` ```
Compare with expected version. If not matching after 2 minutes, warn user about npm propagation delay. Compare with expected version. If not matching after 2 minutes, warn user about npm propagation delay.
@@ -314,7 +314,7 @@ After publish-platform workflow completes, verify all 7 platform packages are pu
```bash ```bash
PLATFORMS="darwin-arm64 darwin-x64 linux-x64 linux-arm64 linux-x64-musl linux-arm64-musl windows-x64" PLATFORMS="darwin-arm64 darwin-x64 linux-x64 linux-arm64 linux-x64-musl linux-arm64-musl windows-x64"
for PLATFORM in $PLATFORMS; do for PLATFORM in $PLATFORMS; do
npm view "oh-my-opencode-${PLATFORM}" version npm view "oh-my-openagent-${PLATFORM}" version
done done
``` ```
@@ -323,13 +323,13 @@ All 7 packages should show the same version as the main package (`${NEW_VERSION}
**Expected packages:** **Expected packages:**
| Package | Description | | Package | Description |
|---------|-------------| |---------|-------------|
| `oh-my-opencode-darwin-arm64` | macOS Apple Silicon | | `oh-my-openagent-darwin-arm64` | macOS Apple Silicon |
| `oh-my-opencode-darwin-x64` | macOS Intel | | `oh-my-openagent-darwin-x64` | macOS Intel |
| `oh-my-opencode-linux-x64` | Linux x64 (glibc) | | `oh-my-openagent-linux-x64` | Linux x64 (glibc) |
| `oh-my-opencode-linux-arm64` | Linux ARM64 (glibc) | | `oh-my-openagent-linux-arm64` | Linux ARM64 (glibc) |
| `oh-my-opencode-linux-x64-musl` | Linux x64 (musl/Alpine) | | `oh-my-openagent-linux-x64-musl` | Linux x64 (musl/Alpine) |
| `oh-my-opencode-linux-arm64-musl` | Linux ARM64 (musl/Alpine) | | `oh-my-openagent-linux-arm64-musl` | Linux ARM64 (musl/Alpine) |
| `oh-my-opencode-windows-x64` | Windows x64 | | `oh-my-openagent-windows-x64` | Windows x64 |
If any platform package version doesn't match, warn the user and suggest checking the publish-platform workflow logs. If any platform package version doesn't match, warn the user and suggest checking the publish-platform workflow logs.
@@ -339,8 +339,8 @@ If any platform package version doesn't match, warn the user and suggest checkin
Report success to user with: Report success to user with:
- New version number - New version number
- GitHub release URL: https://github.com/code-yeongyu/oh-my-opencode/releases/tag/v{version} - GitHub release URL: https://github.com/code-yeongyu/oh-my-openagent/releases/tag/v{version}
- npm package URL: https://www.npmjs.com/package/oh-my-opencode - npm package URL: https://www.npmjs.com/package/oh-my-openagent
- Platform packages status: List all 7 platform packages with their versions - Platform packages status: List all 7 platform packages with their versions
--- ---
@@ -362,7 +362,7 @@ Respond to user in English.
<current-context> <current-context>
<published-version> <published-version>
!`npm view oh-my-opencode version 2>/dev/null || echo "not published"` !`npm view oh-my-openagent version 2>/dev/null || echo "not published"`
</published-version> </published-version>
<local-version> <local-version>
!`node -p "require('./package.json').version" 2>/dev/null || echo "unknown"` !`node -p "require('./package.json').version" 2>/dev/null || echo "unknown"`
@@ -371,6 +371,6 @@ Respond to user in English.
!`git status --porcelain` !`git status --porcelain`
</git-status> </git-status>
<recent-commits> <recent-commits>
!`npm view oh-my-opencode version 2>/dev/null | xargs -I{} git log "v{}"..HEAD --oneline 2>/dev/null | head -15 || echo "no commits"` !`npm view oh-my-openagent version 2>/dev/null | xargs -I{} git log "v{}"..HEAD --oneline 2>/dev/null | head -15 || echo "no commits"`
</recent-commits> </recent-commits>
</current-context> </current-context>

View File

@@ -79,65 +79,47 @@ Pass `REPO`, `REPORT_DIR`, and `COMMIT_SHA` to every subagent.
--- ---
--- ## Phase 1: Fetch All Open Items
## Phase 1: Fetch All Open Items (CORRECTED) <fetch>
Paginate if 500 results returned.
**IMPORTANT:** `body` and `comments` fields may contain control characters that break jq parsing. Fetch basic metadata first, then fetch full details per-item in subagents.
```bash ```bash
# Step 1: Fetch basic metadata (without body/comments to avoid JSON parsing issues) ISSUES=$(gh issue list --repo $REPO --state open --limit 500 \
ISSUES_LIST=$(gh issue list --repo $REPO --state open --limit 500 \ --json number,title,state,createdAt,updatedAt,labels,author,body,comments)
--json number,title,labels,author,createdAt) ISSUE_LEN=$(echo "$ISSUES" | jq length)
ISSUE_COUNT=$(echo "$ISSUES_LIST" | jq length) if [ "$ISSUE_LEN" -eq 500 ]; then
LAST_DATE=$(echo "$ISSUES" | jq -r '.[-1].createdAt')
# Paginate if needed
if [ "$ISSUE_COUNT" -eq 500 ]; then
LAST_DATE=$(echo "$ISSUES_LIST" | jq -r '.[-1].createdAt')
while true; do while true; do
PAGE=$(gh issue list --repo $REPO --state open --limit 500 \ PAGE=$(gh issue list --repo $REPO --state open --limit 500 \
--search "created:<$LAST_DATE" \ --search "created:<$LAST_DATE" \
--json number,title,labels,author,createdAt) --json number,title,state,createdAt,updatedAt,labels,author,body,comments)
PAGE_COUNT=$(echo "$PAGE" | jq length) PAGE_LEN=$(echo "$PAGE" | jq length)
[ "$PAGE_COUNT" -eq 0 ] && break [ "$PAGE_LEN" -eq 0 ] && break
ISSUES_LIST=$(echo "$ISSUES_LIST" "$PAGE" | jq -s '.[0] + .[1] | unique_by(.number)') ISSUES=$(echo "[$ISSUES, $PAGE]" | jq -s 'add | unique_by(.number)')
ISSUE_COUNT=$(echo "$ISSUES_LIST" | jq length) [ "$PAGE_LEN" -lt 500 ] && break
[ "$PAGE_COUNT" -lt 500 ] && break
LAST_DATE=$(echo "$PAGE" | jq -r '.[-1].createdAt') LAST_DATE=$(echo "$PAGE" | jq -r '.[-1].createdAt')
done done
fi fi
# Same for PRs PRS=$(gh pr list --repo $REPO --state open --limit 500 \
PRS_LIST=$(gh pr list --repo $REPO --state open --limit 500 \ --json number,title,state,createdAt,updatedAt,labels,author,body,headRefName,baseRefName,isDraft,mergeable,reviewDecision,statusCheckRollup)
--json number,title,labels,author,headRefName,baseRefName,isDraft,createdAt) PR_LEN=$(echo "$PRS" | jq length)
PR_COUNT=$(echo "$PRS_LIST" | jq length) if [ "$PR_LEN" -eq 500 ]; then
LAST_DATE=$(echo "$PRS" | jq -r '.[-1].createdAt')
if [ "$PR_COUNT" -eq 500 ]; then
LAST_DATE=$(echo "$PRS_LIST" | jq -r '.[-1].createdAt')
while true; do while true; do
PAGE=$(gh pr list --repo $REPO --state open --limit 500 \ PAGE=$(gh pr list --repo $REPO --state open --limit 500 \
--search "created:<$LAST_DATE" \ --search "created:<$LAST_DATE" \
--json number,title,labels,author,headRefName,baseRefName,isDraft,createdAt) --json number,title,state,createdAt,updatedAt,labels,author,body,headRefName,baseRefName,isDraft,mergeable,reviewDecision,statusCheckRollup)
PAGE_COUNT=$(echo "$PAGE" | jq length) PAGE_LEN=$(echo "$PAGE" | jq length)
[ "$PAGE_COUNT" -eq 0 ] && break [ "$PAGE_LEN" -eq 0 ] && break
PRS_LIST=$(echo "$PRS_LIST" "$PAGE" | jq -s '.[0] + .[1] | unique_by(.number)') PRS=$(echo "[$PRS, $PAGE]" | jq -s 'add | unique_by(.number)')
PR_COUNT=$(echo "$PRS_LIST" | jq length) [ "$PAGE_LEN" -lt 500 ] && break
[ "$PAGE_COUNT" -lt 500 ] && break
LAST_DATE=$(echo "$PAGE" | jq -r '.[-1].createdAt') LAST_DATE=$(echo "$PAGE" | jq -r '.[-1].createdAt')
done done
fi fi
echo "Total issues: $ISSUE_COUNT, Total PRs: $PR_COUNT"
``` ```
</fetch>
**LARGE REPOSITORY HANDLING:**
If total items exceeds 50, you MUST process ALL items. Use the pagination code above to fetch every single open issue and PR.
**DO NOT** sample or limit to 50 items - process the entire backlog.
Example: If there are 500 open issues, spawn 500 subagents. If there are 1000 open PRs, spawn 1000 subagents.
**Note:** Background task system will queue excess tasks automatically.
--- ---
@@ -154,36 +136,7 @@ Example: If there are 500 open issues, spawn 500 subagents. If there are 1000 op
--- ---
## Phase 3: Spawn Subagents (Individual Tool Calls) ## Phase 3: Spawn Subagents
**CRITICAL: Create tasks ONE BY ONE using individual `task_create` tool calls. NEVER batch or script.**
For each item, execute these steps sequentially:
### Step 3.1: Create Task Record
```typescript
task_create(
subject="Triage: #{number} {title}",
description="GitHub {issue|PR} triage analysis - {type}",
metadata={"type": "{ISSUE_QUESTION|ISSUE_BUG|ISSUE_FEATURE|ISSUE_OTHER|PR_BUGFIX|PR_OTHER}", "number": {number}}
)
```
### Step 3.2: Spawn Analysis Subagent (Background)
```typescript
task(
category="quick",
run_in_background=true,
load_skills=[],
prompt=SUBAGENT_PROMPT
)
```
**ABSOLUTE RULES for Subagents:**
- **ONLY ANALYZE** - Never take action on GitHub (no comments, merges, closes)
- **READ-ONLY** - Use tools only for reading code/GitHub data
- **WRITE REPORT ONLY** - Output goes to `{REPORT_DIR}/{issue|pr}-{number}.md` via Write tool
- **EVIDENCE REQUIRED** - Every claim must have GitHub permalink as proof
``` ```
For each item: For each item:
@@ -217,7 +170,6 @@ ABSOLUTE RULES (violating ANY = critical failure):
- Your ONLY writable output: {REPORT_DIR}/{issue|pr}-{number}.md via the Write tool - Your ONLY writable output: {REPORT_DIR}/{issue|pr}-{number}.md via the Write tool
``` ```
--- ---
### ISSUE_QUESTION ### ISSUE_QUESTION

View File

@@ -37,7 +37,7 @@ Then capture raw data needed by agent prompts:
```bash ```bash
# Extract versions (already in /get-unpublished-changes output) # Extract versions (already in /get-unpublished-changes output)
PUBLISHED=$(npm view oh-my-opencode version 2>/dev/null || echo "not published") PUBLISHED=$(npm view oh-my-openagent version 2>/dev/null || echo "not published")
LOCAL=$(node -p "require('./package.json').version" 2>/dev/null || echo "unknown") LOCAL=$(node -p "require('./package.json').version" 2>/dev/null || echo "unknown")
# Raw data for agents (diffs, file lists) # Raw data for agents (diffs, file lists)
@@ -85,7 +85,7 @@ task(
<review_type>PER-CHANGE DEEP ANALYSIS</review_type> <review_type>PER-CHANGE DEEP ANALYSIS</review_type>
<change_group>{GROUP_NAME}</change_group> <change_group>{GROUP_NAME}</change_group>
<project>oh-my-opencode (npm package)</project> <project>oh-my-openagent (npm package)</project>
<published_version>{PUBLISHED}</published_version> <published_version>{PUBLISHED}</published_version>
<target_version>{LOCAL}</target_version> <target_version>{LOCAL}</target_version>
@@ -160,7 +160,7 @@ task(
prompt=""" prompt="""
Run /review-work on the unpublished changes between v{PUBLISHED} and HEAD. Run /review-work on the unpublished changes between v{PUBLISHED} and HEAD.
GOAL: Review all changes heading into npm publish of oh-my-opencode. These changes span {COMMIT_COUNT} commits across {FILE_COUNT} files. GOAL: Review all changes heading into npm publish of oh-my-openagent. These changes span {COMMIT_COUNT} commits across {FILE_COUNT} files.
CONSTRAINTS: CONSTRAINTS:
- This is a plugin published to npm — public API stability matters - This is a plugin published to npm — public API stability matters
@@ -169,7 +169,7 @@ CONSTRAINTS:
- Factory pattern (createXXX) for tools, hooks, agents - Factory pattern (createXXX) for tools, hooks, agents
- kebab-case files, barrel exports, no catch-all files - kebab-case files, barrel exports, no catch-all files
BACKGROUND: Pre-publish review of oh-my-opencode, an OpenCode plugin with 1268 TypeScript files, 160k LOC. Changes since v{PUBLISHED} are about to be published. BACKGROUND: Pre-publish review of oh-my-openagent, an OpenCode plugin with 1268 TypeScript files, 160k LOC. Changes since v{PUBLISHED} are about to be published.
The diff base is: git diff v{PUBLISHED}..HEAD The diff base is: git diff v{PUBLISHED}..HEAD
@@ -190,7 +190,7 @@ task(
prompt=""" prompt="""
<review_type>RELEASE SYNTHESIS — OVERALL ASSESSMENT</review_type> <review_type>RELEASE SYNTHESIS — OVERALL ASSESSMENT</review_type>
<project>oh-my-opencode (npm package)</project> <project>oh-my-openagent (npm package)</project>
<published_version>{PUBLISHED}</published_version> <published_version>{PUBLISHED}</published_version>
<local_version>{LOCAL}</local_version> <local_version>{LOCAL}</local_version>
@@ -325,7 +325,7 @@ Do NOT deliver the final report until ALL agents have completed.
Compile the final report: Compile the final report:
```markdown ```markdown
# Pre-Publish Review — oh-my-opencode # Pre-Publish Review — oh-my-openagent
## Release: v{PUBLISHED} -> v{LOCAL} ## Release: v{PUBLISHED} -> v{LOCAL}
**Commits:** {COMMIT_COUNT} | **Files Changed:** {FILE_COUNT} | **Agents:** {AGENT_COUNT} **Commits:** {COMMIT_COUNT} | **Files Changed:** {FILE_COUNT} | **Agents:** {AGENT_COUNT}

View File

@@ -2,7 +2,7 @@
## Overview ## Overview
Add a `max_background_agents` config option to oh-my-opencode that limits total simultaneous background agents across all models/providers. Currently, concurrency is only limited per-model/provider key (default 5 per key). This new option adds a **global ceiling** on total running background agents. Add a `max_background_agents` config option to oh-my-openagent that limits total simultaneous background agents across all models/providers. Currently, concurrency is only limited per-model/provider key (default 5 per key). This new option adds a **global ceiling** on total running background agents.
## Step-by-Step Plan ## Step-by-Step Plan
@@ -80,7 +80,7 @@ Check `src/config/schema/background-task.ts` and `src/features/background-agent/
| File | Reason | | File | Reason |
|------|--------| |------|--------|
| `src/config/schema/oh-my-opencode-config.ts` | No change needed - `BackgroundTaskConfigSchema` is already composed into root schema via `background_task` field | | `src/config/schema/oh-my-openagent-config.ts` | No change needed - `BackgroundTaskConfigSchema` is already composed into root schema via `background_task` field |
| `src/create-managers.ts` | No change needed - `pluginConfig.background_task` already passed to `BackgroundManager` constructor | | `src/create-managers.ts` | No change needed - `pluginConfig.background_task` already passed to `BackgroundManager` constructor |
| `src/features/background-agent/manager.ts` | No change needed - already passes config to `ConcurrencyManager` | | `src/features/background-agent/manager.ts` | No change needed - already passes config to `ConcurrencyManager` |
| `src/plugin-config.ts` | No change needed - `background_task` is a simple object field, uses default override merge | | `src/plugin-config.ts` | No change needed - `background_task` is a simple object field, uses default override merge |

View File

@@ -63,7 +63,7 @@ All existing tests must continue to pass unchanged.
Verify the config flows correctly through the system: Verify the config flows correctly through the system:
1. **Schema → Type**: `BackgroundTaskConfig` type auto-includes `maxBackgroundAgents` via `z.infer` 1. **Schema → Type**: `BackgroundTaskConfig` type auto-includes `maxBackgroundAgents` via `z.infer`
2. **Config file → Schema**: `loadConfigFromPath()` in `plugin-config.ts` uses `OhMyOpenCodeConfigSchema.safeParse()` which includes `BackgroundTaskConfigSchema` 2. **Config file → Schema**: `loadConfigFromPath()` in `plugin-config.ts` uses `OhMyOpenAgentConfigSchema.safeParse()` which includes `BackgroundTaskConfigSchema`
3. **Config → Manager**: `create-managers.ts` passes `pluginConfig.background_task` to `BackgroundManager` constructor 3. **Config → Manager**: `create-managers.ts` passes `pluginConfig.background_task` to `BackgroundManager` constructor
4. **Manager → ConcurrencyManager**: `BackgroundManager` constructor passes config to `new ConcurrencyManager(config)` 4. **Manager → ConcurrencyManager**: `BackgroundManager` constructor passes config to `new ConcurrencyManager(config)`
5. **ConcurrencyManager → Enforcement**: `acquire()` reads `config.maxBackgroundAgents` via `getGlobalLimit()` 5. **ConcurrencyManager → Enforcement**: `acquire()` reads `config.maxBackgroundAgents` via `getGlobalLimit()`

View File

@@ -36,7 +36,7 @@ import { createWebsearchConfig } from "./websearch"
import { context7 } from "./context7" import { context7 } from "./context7"
import { grep_app } from "./grep-app" import { grep_app } from "./grep-app"
import { arxiv } from "./arxiv" import { arxiv } from "./arxiv"
import type { OhMyOpenCodeConfig } from "../config/schema" import type { OhMyOpenAgentConfig } from "../config/schema"
export { McpNameSchema, type McpName } from "./types" export { McpNameSchema, type McpName } from "./types"
@@ -48,7 +48,7 @@ type RemoteMcpConfig = {
oauth?: false oauth?: false
} }
export function createBuiltinMcps(disabledMcps: string[] = [], config?: OhMyOpenCodeConfig) { export function createBuiltinMcps(disabledMcps: string[] = [], config?: OhMyOpenAgentConfig) {
const mcps: Record<string, RemoteMcpConfig> = {} const mcps: Record<string, RemoteMcpConfig> = {}
if (!disabledMcps.includes("websearch")) { if (!disabledMcps.includes("websearch")) {

View File

@@ -41,7 +41,7 @@ Pattern followed: `grep-app.ts` (static export, no auth, no config factory neede
import { context7 } from "./context7" import { context7 } from "./context7"
import { grep_app } from "./grep-app" import { grep_app } from "./grep-app"
+import { arxiv } from "./arxiv" +import { arxiv } from "./arxiv"
import type { OhMyOpenCodeConfig } from "../config/schema" import type { OhMyOpenAgentConfig } from "../config/schema"
-export { McpNameSchema, type McpName } from "./types" -export { McpNameSchema, type McpName } from "./types"
+export { McpNameSchema, type McpName } from "./types" +export { McpNameSchema, type McpName } from "./types"
@@ -54,7 +54,7 @@ Pattern followed: `grep-app.ts` (static export, no auth, no config factory neede
oauth?: false oauth?: false
} }
export function createBuiltinMcps(disabledMcps: string[] = [], config?: OhMyOpenCodeConfig) { export function createBuiltinMcps(disabledMcps: string[] = [], config?: OhMyOpenAgentConfig) {
const mcps: Record<string, RemoteMcpConfig> = {} const mcps: Record<string, RemoteMcpConfig> = {}
if (!disabledMcps.includes("websearch")) { if (!disabledMcps.includes("websearch")) {

View File

@@ -51,7 +51,7 @@ Since the regex lives in the Go binary and this repo wraps it, the fix is two-pr
- Relax `(?i)^[\s#/*-]*note:\s*\w` to only match AI-style memo patterns like `Note: this was changed...`, `Note: implementation details...` - Relax `(?i)^[\s#/*-]*note:\s*\w` to only match AI-style memo patterns like `Note: this was changed...`, `Note: implementation details...`
- Add `--exclude-pattern` CLI flag for user-configurable exclusions - Add `--exclude-pattern` CLI flag for user-configurable exclusions
**B. This repo (oh-my-opencode)** - the PR scope: **B. This repo (oh-my-openagent)** - the PR scope:
1. Add `exclude_patterns` config field to `CommentCheckerConfigSchema` 1. Add `exclude_patterns` config field to `CommentCheckerConfigSchema`
2. Pass `--exclude-pattern` flags to the CLI binary 2. Pass `--exclude-pattern` flags to the CLI binary
3. Add integration tests with mock binaries for false positive scenarios 3. Add integration tests with mock binaries for false positive scenarios

View File

@@ -20,7 +20,7 @@ Additionally, the binary flags ALL non-filtered comments (not just agent memos),
## Architecture Understanding ## Architecture Understanding
``` ```
TypeScript (oh-my-opencode) Go Binary (go-claude-code-comment-checker) TypeScript (oh-my-openagent) Go Binary (go-claude-code-comment-checker)
───────────────────────────── ────────────────────────────────────────── ───────────────────────────── ──────────────────────────────────────────
hook.ts main.go hook.ts main.go
├─ tool.execute.before ├─ Read JSON from stdin ├─ tool.execute.before ├─ Read JSON from stdin
@@ -33,7 +33,7 @@ hook.ts main.go
└─ append to output └─ append to output
``` ```
Key files in oh-my-opencode: Key files in oh-my-openagent:
- `src/hooks/comment-checker/hook.ts` - Hook factory, registers before/after handlers - `src/hooks/comment-checker/hook.ts` - Hook factory, registers before/after handlers
- `src/hooks/comment-checker/cli-runner.ts` - Orchestrates CLI invocation, semaphore - `src/hooks/comment-checker/cli-runner.ts` - Orchestrates CLI invocation, semaphore
- `src/hooks/comment-checker/cli.ts` - Binary resolution, process spawning, timeout handling - `src/hooks/comment-checker/cli.ts` - Binary resolution, process spawning, timeout handling

View File

@@ -282,18 +282,6 @@ Once all three gates pass:
gh pr merge "$PR_NUMBER" --squash --delete-branch gh pr merge "$PR_NUMBER" --squash --delete-branch
``` ```
### Sync .sisyphus state back to main repo
Before removing the worktree, copy `.sisyphus/` state back. When `.sisyphus/` is gitignored, files written there during worktree execution are not committed or merged — they would be lost on worktree removal.
```bash
# Sync .sisyphus state from worktree to main repo (preserves task state, plans, notepads)
if [ -d "$WORKTREE_PATH/.sisyphus" ]; then
mkdir -p "$ORIGINAL_DIR/.sisyphus"
cp -r "$WORKTREE_PATH/.sisyphus/"* "$ORIGINAL_DIR/.sisyphus/" 2>/dev/null || true
fi
```
### Clean up the worktree ### Clean up the worktree
The worktree served its purpose — remove it to avoid disk bloat: The worktree served its purpose — remove it to avoid disk bloat:

View File

@@ -1,27 +1,27 @@
# oh-my-opencode — O P E N C O D E Plugin # oh-my-openagent — O P E N C O D E Plugin
**Generated:** 2026-03-06 | **Commit:** 7fe44024 | **Branch:** dev **Generated:** 2026-03-06 | **Commit:** 7fe44024 | **Branch:** dev
## OVERVIEW ## OVERVIEW
OpenCode plugin (npm: `oh-my-opencode`) that extends Claude Code (OpenCode fork) with multi-agent orchestration, 48 lifecycle hooks, 26 tools, skill/command/MCP systems, and Claude Code compatibility. 1268 TypeScript files, 160k LOC. OpenCode plugin (npm: `oh-my-openagent`) that extends Claude Code (OpenCode fork) with multi-agent orchestration, 46 lifecycle hooks, 26 tools, skill/command/MCP systems, and Claude Code compatibility. 1268 TypeScript files, 160k LOC.
## STRUCTURE ## STRUCTURE
``` ```
oh-my-opencode/ oh-my-openagent/
├── src/ ├── src/
│ ├── index.ts # Plugin entry: loadConfig → createManagers → createTools → createHooks → createPluginInterface │ ├── index.ts # Plugin entry: loadConfig → createManagers → createTools → createHooks → createPluginInterface
│ ├── plugin-config.ts # JSONC multi-level config: user → project → defaults (Zod v4) │ ├── plugin-config.ts # JSONC multi-level config: user → project → defaults (Zod v4)
│ ├── agents/ # 11 agents (Sisyphus, Hephaestus, Oracle, Librarian, Explore, Atlas, Prometheus, Metis, Momus, Multimodal-Looker, Sisyphus-Junior) │ ├── agents/ # 11 agents (Sisyphus, Hephaestus, Oracle, Librarian, Explore, Atlas, Prometheus, Metis, Momus, Multimodal-Looker, Sisyphus-Junior)
│ ├── hooks/ # 48 lifecycle hooks across dedicated modules and standalone files │ ├── hooks/ # 46 hooks across 45 directories + 11 standalone files
│ ├── tools/ # 26 tools across 15 directories │ ├── tools/ # 26 tools across 15 directories
│ ├── features/ # 19 feature modules (background-agent, skill-loader, tmux, MCP-OAuth, etc.) │ ├── features/ # 19 feature modules (background-agent, skill-loader, tmux, MCP-OAuth, etc.)
│ ├── shared/ # 95+ utility files in 13 categories │ ├── shared/ # 95+ utility files in 13 categories
│ ├── config/ # Zod v4 schema system (24 files) │ ├── config/ # Zod v4 schema system (24 files)
│ ├── cli/ # CLI: install, run, doctor, mcp-oauth (Commander.js) │ ├── cli/ # CLI: install, run, doctor, mcp-oauth (Commander.js)
│ ├── mcp/ # 3 built-in remote MCPs (websearch, context7, grep_app) │ ├── mcp/ # 3 built-in remote MCPs (websearch, context7, grep_app)
│ ├── plugin/ # 8 OpenCode hook handlers + 48 hook composition │ ├── plugin/ # 8 OpenCode hook handlers + 46 hook composition
│ └── plugin-handlers/ # 6-phase config loading pipeline │ └── plugin-handlers/ # 6-phase config loading pipeline
├── packages/ # Monorepo: cli-runner, 12 platform binaries ├── packages/ # Monorepo: cli-runner, 12 platform binaries
└── local-ignore/ # Dev-only test fixtures └── local-ignore/ # Dev-only test fixtures
@@ -30,11 +30,11 @@ oh-my-opencode/
## INITIALIZATION FLOW ## INITIALIZATION FLOW
``` ```
OhMyOpenCodePlugin(ctx) OhMyOpenAgentPlugin(ctx)
├─→ loadPluginConfig() # JSONC parse → project/user merge → Zod validate → migrate ├─→ loadPluginConfig() # JSONC parse → project/user merge → Zod validate → migrate
├─→ createManagers() # TmuxSessionManager, BackgroundManager, SkillMcpManager, ConfigHandler ├─→ createManagers() # TmuxSessionManager, BackgroundManager, SkillMcpManager, ConfigHandler
├─→ createTools() # SkillContext + AvailableCategories + ToolRegistry (26 tools) ├─→ createTools() # SkillContext + AvailableCategories + ToolRegistry (26 tools)
├─→ createHooks() # 3-tier: Core(39) + Continuation(7) + Skill(2) = 48 hooks ├─→ createHooks() # 3-tier: Core(37) + Continuation(7) + Skill(2) = 46 hooks
└─→ createPluginInterface() # 8 OpenCode hook handlers → PluginInterface └─→ createPluginInterface() # 8 OpenCode hook handlers → PluginInterface
``` ```
@@ -65,7 +65,7 @@ OhMyOpenCodePlugin(ctx)
| Add new command | `src/features/builtin-commands/` | Template in templates/ | | Add new command | `src/features/builtin-commands/` | Template in templates/ |
| Add new CLI command | `src/cli/cli-program.ts` | Commander.js subcommand | | Add new CLI command | `src/cli/cli-program.ts` | Commander.js subcommand |
| Add new doctor check | `src/cli/doctor/checks/` | Register in checks/index.ts | | Add new doctor check | `src/cli/doctor/checks/` | Register in checks/index.ts |
| Modify config schema | `src/config/schema/` + update root schema | Zod v4, add to OhMyOpenCodeConfigSchema | | Modify config schema | `src/config/schema/` + update root schema | Zod v4, add to OhMyOpenAgentConfigSchema |
| Add new category | `src/tools/delegate-task/constants.ts` | DEFAULT_CATEGORIES + CATEGORY_MODEL_REQUIREMENTS | | Add new category | `src/tools/delegate-task/constants.ts` | DEFAULT_CATEGORIES + CATEGORY_MODEL_REQUIREMENTS |
## MULTI-LEVEL CONFIG ## MULTI-LEVEL CONFIG
@@ -97,7 +97,7 @@ Fields: agents (14 overridable, 21 fields each), categories (8 built-in + custom
- **Test pattern**: Bun test (`bun:test`), co-located `*.test.ts`, given/when/then style (nested describe with `#given`/`#when`/`#then` prefixes) - **Test pattern**: Bun test (`bun:test`), co-located `*.test.ts`, given/when/then style (nested describe with `#given`/`#when`/`#then` prefixes)
- **CI test split**: mock-heavy tests run in isolation (separate `bun test` processes), rest in batch - **CI test split**: mock-heavy tests run in isolation (separate `bun test` processes), rest in batch
- **Factory pattern**: `createXXX()` for all tools, hooks, agents - **Factory pattern**: `createXXX()` for all tools, hooks, agents
- **Hook tiers**: Session (23) → Tool-Guard (12) → Transform (4) → Continuation (7) → Skill (2) - **Hook tiers**: Session (23) → Tool-Guard (10) → Transform (4) → Continuation (7) → Skill (2)
- **Agent modes**: `primary` (respects UI model) vs `subagent` (own fallback chain) vs `all` - **Agent modes**: `primary` (respects UI model) vs `subagent` (own fallback chain) vs `all`
- **Model resolution**: 4-step: override → category-default → provider-fallback → system-default - **Model resolution**: 4-step: override → category-default → provider-fallback → system-default
- **Config format**: JSONC with comments, Zod v4 validation, snake_case keys - **Config format**: JSONC with comments, Zod v4 validation, snake_case keys
@@ -128,9 +128,9 @@ bun test # Bun test suite
bun run build # Build plugin (ESM + declarations + schema) bun run build # Build plugin (ESM + declarations + schema)
bun run build:all # Build + platform binaries bun run build:all # Build + platform binaries
bun run typecheck # tsc --noEmit bun run typecheck # tsc --noEmit
bunx oh-my-opencode install # Interactive setup bunx oh-my-openagent install # Interactive setup
bunx oh-my-opencode doctor # Health diagnostics bunx oh-my-openagent doctor # Health diagnostics
bunx oh-my-opencode run # Non-interactive session bunx oh-my-openagent run # Non-interactive session
``` ```
## CI/CD ## CI/CD

2
CLA.md
View File

@@ -1,6 +1,6 @@
# Contributor License Agreement # Contributor License Agreement
Thank you for your interest in contributing to oh-my-opencode ("Project"), owned by YeonGyu Kim ("Owner"). Thank you for your interest in contributing to oh-my-openagent ("Project"), owned by YeonGyu Kim ("Owner").
By signing this Contributor License Agreement ("Agreement"), you agree to the following terms: By signing this Contributor License Agreement ("Agreement"), you agree to the following terms:

View File

@@ -1,6 +1,6 @@
# Contributing to Oh My OpenCode # Contributing to Oh My OpenAgent
First off, thanks for taking the time to contribute! This document provides guidelines and instructions for contributing to oh-my-opencode. First off, thanks for taking the time to contribute! This document provides guidelines and instructions for contributing to oh-my-openagent.
## Table of Contents ## Table of Contents
@@ -87,19 +87,19 @@ After making changes, you can test your local build in OpenCode:
```json ```json
{ {
"plugin": ["file:///absolute/path/to/oh-my-opencode/dist/index.js"] "plugin": ["file:///absolute/path/to/oh-my-openagent/dist/index.js"]
} }
``` ```
For example, if your project is at `/Users/yourname/projects/oh-my-opencode`: For example, if your project is at `/Users/yourname/projects/oh-my-openagent`:
```json ```json
{ {
"plugin": ["file:///Users/yourname/projects/oh-my-opencode/dist/index.js"] "plugin": ["file:///Users/yourname/projects/oh-my-openagent/dist/index.js"]
} }
``` ```
> **Note**: Remove `"oh-my-opencode"` from the plugin array if it exists, to avoid conflicts with the npm version. > **Note**: Remove `"oh-my-openagent"` from the plugin array if it exists, to avoid conflicts with the npm version.
3. **Restart OpenCode** to load the changes. 3. **Restart OpenCode** to load the changes.
@@ -108,9 +108,9 @@ After making changes, you can test your local build in OpenCode:
## Project Structure ## Project Structure
``` ```
oh-my-opencode/ oh-my-openagent/
├── src/ ├── src/
│ ├── index.ts # Plugin entry (OhMyOpenCodePlugin) │ ├── index.ts # Plugin entry (OhMyOpenAgentPlugin)
│ ├── plugin-config.ts # JSONC multi-level config (Zod v4) │ ├── plugin-config.ts # JSONC multi-level config (Zod v4)
│ ├── agents/ # 11 agents (Sisyphus, Hephaestus, Oracle, Librarian, Explore, Atlas, Prometheus, Metis, Momus, Multimodal-Looker, Sisyphus-Junior) │ ├── agents/ # 11 agents (Sisyphus, Hephaestus, Oracle, Librarian, Explore, Atlas, Prometheus, Metis, Momus, Multimodal-Looker, Sisyphus-Junior)
│ ├── hooks/ # Lifecycle hooks for orchestration, recovery, UX, and context management │ ├── hooks/ # Lifecycle hooks for orchestration, recovery, UX, and context management
@@ -272,4 +272,4 @@ export function createMyHook(input: PluginInput) {
--- ---
Thank you for contributing to Oh My OpenCode! Your efforts help make AI-assisted coding better for everyone. Thank you for contributing to Oh My OpenAgent! Your efforts help make AI-assisted coding better for everyone.

View File

@@ -72,7 +72,7 @@ Use ultrawork (ulw) to spawn UltraBrain agents in parallel. Each UB agent gets a
## ADDITIONAL BLOCKERS FROM GPT-5.4 REVIEW ## ADDITIONAL BLOCKERS FROM GPT-5.4 REVIEW
### G1: Package Identity Split-Brain ### G1: Package Identity Split-Brain
**Problem:** Installer writes oh-my-openagent but doctor, auto-update, version lookup, publish workflow still reference oh-my-opencode. Half-migrated state. **Problem:** Installer writes oh-my-openagent but doctor, auto-update, version lookup, publish workflow still reference oh-my-openagent. Half-migrated state.
**Fix:** Audit ALL references to package name. Either complete the migration consistently or revert to single name for this release. **Fix:** Audit ALL references to package name. Either complete the migration consistently or revert to single name for this release.
**Files:** Installer, doctor, auto-update, version lookup, publish workflow -- grep for both package names **Files:** Installer, doctor, auto-update, version lookup, publish workflow -- grep for both package names

View File

@@ -2,7 +2,7 @@
Portions of this software are licensed as follows: Portions of this software are licensed as follows:
- All third party components incorporated into the oh-my-opencode Software are licensed under the original license - All third party components incorporated into the oh-my-openagent Software are licensed under the original license
provided by the owner of the applicable component. provided by the owner of the applicable component.
- Content outside of the above mentioned files or restrictions is available under the "Sustainable Use - Content outside of the above mentioned files or restrictions is available under the "Sustainable Use
License" as defined below. License" as defined below.

View File

@@ -4,17 +4,6 @@
> コアメンテナーのQが負傷したため、今週は Issue/PR への返信とリリースが遅れる可能性があります。 > コアメンテナーのQが負傷したため、今週は Issue/PR への返信とリリースが遅れる可能性があります。
> ご理解とご支援に感謝します。 > ご理解とご支援に感謝します。
> [!TIP]
> **Building in Public**
>
> メンテナーが Jobdori を使い、oh-my-opencode をリアルタイムで開発・メンテナンスしています。Jobdori は OpenClaw をベースに大幅カスタマイズされた AI アシスタントです。
> すべての機能開発、修正、Issue トリアージを Discord でライブでご覧いただけます。
>
> [![Building in Public](./.github/assets/building-in-public.png)](https://discord.gg/PUwSMR9XNk)
>
> [**→ #building-in-public で確認する**](https://discord.gg/PUwSMR9XNk)
> [!NOTE] > [!NOTE]
> >
> [![Sisyphus Labs - Sisyphus is the agent that codes like your team.](./.github/assets/sisyphuslabs.png?v=2)](https://sisyphuslabs.ai) > [![Sisyphus Labs - Sisyphus is the agent that codes like your team.](./.github/assets/sisyphuslabs.png?v=2)](https://sisyphuslabs.ai)
@@ -23,18 +12,18 @@
> [!TIP] > [!TIP]
> 私たちと一緒に! > 私たちと一緒に!
> >
> | [<img alt="Discord link" src="https://img.shields.io/discord/1452487457085063218?color=5865F2&label=discord&labelColor=black&logo=discord&logoColor=white&style=flat-square" width="156px" />](https://discord.gg/PUwSMR9XNk) | [Discordコミュニティ](https://discord.gg/PUwSMR9XNk)に参加して、コントリビューターや他の `oh-my-opencode` ユーザーと交流しましょう。 | > | [<img alt="Discord link" src="https://img.shields.io/discord/1452487457085063218?color=5865F2&label=discord&labelColor=black&logo=discord&logoColor=white&style=flat-square" width="156px" />](https://discord.gg/PUwSMR9XNk) | [Discordコミュニティ](https://discord.gg/PUwSMR9XNk)に参加して、コントリビューターや他の `oh-my-openagent` ユーザーと交流しましょう。 |
> | :-----| :----- | > | :-----| :----- |
> | [<img alt="X link" src="https://img.shields.io/badge/Follow-%40justsisyphus-00CED1?style=flat-square&logo=x&labelColor=black" width="156px" />](https://x.com/justsisyphus) | `oh-my-opencode` のニュースやアップデートは私のXアカウントで投稿されていましたが、 <br /> 誤って凍結されてしまったため、現在は [@justsisyphus](https://x.com/justsisyphus) が代わりにアップデートを投稿しています。 | > | [<img alt="X link" src="https://img.shields.io/badge/Follow-%40justsisyphus-00CED1?style=flat-square&logo=x&labelColor=black" width="156px" />](https://x.com/justsisyphus) | `oh-my-openagent` のニュースやアップデートは私のXアカウントで投稿されていましたが、 <br /> 誤って凍結されてしまったため、現在は [@justsisyphus](https://x.com/justsisyphus) が代わりにアップデートを投稿しています。 |
> | [<img alt="GitHub Follow" src="https://img.shields.io/github/followers/code-yeongyu?style=flat-square&logo=github&labelColor=black&color=24292f" width="156px" />](https://github.com/code-yeongyu) | さらに多くのプロジェクトを見たい場合は、GitHubで [@code-yeongyu](https://github.com/code-yeongyu) をフォローしてください。 | > | [<img alt="GitHub Follow" src="https://img.shields.io/github/followers/code-yeongyu?style=flat-square&logo=github&labelColor=black&color=24292f" width="156px" />](https://github.com/code-yeongyu) | さらに多くのプロジェクトを見たい場合は、GitHubで [@code-yeongyu](https://github.com/code-yeongyu) をフォローしてください。 |
<!-- <CENTERED SECTION FOR GITHUB DISPLAY> --> <!-- <CENTERED SECTION FOR GITHUB DISPLAY> -->
<div align="center"> <div align="center">
[![Oh My OpenCode](./.github/assets/hero.jpg)](https://github.com/code-yeongyu/oh-my-openagent#oh-my-opencode) [![Oh My OpenAgent](./.github/assets/hero.jpg)](https://github.com/code-yeongyu/oh-my-openagent#oh-my-openagent)
[![Preview](./.github/assets/omo.png)](https://github.com/code-yeongyu/oh-my-openagent#oh-my-opencode) [![Preview](./.github/assets/omo.png)](https://github.com/code-yeongyu/oh-my-openagent#oh-my-openagent)
</div> </div>
@@ -45,7 +34,7 @@
<div align="center"> <div align="center">
[![GitHub Release](https://img.shields.io/github/v/release/code-yeongyu/oh-my-openagent?color=369eff&labelColor=black&logo=github&style=flat-square)](https://github.com/code-yeongyu/oh-my-openagent/releases) [![GitHub Release](https://img.shields.io/github/v/release/code-yeongyu/oh-my-openagent?color=369eff&labelColor=black&logo=github&style=flat-square)](https://github.com/code-yeongyu/oh-my-openagent/releases)
[![npm downloads](https://img.shields.io/npm/dt/oh-my-opencode?color=ff6b35&labelColor=black&style=flat-square)](https://www.npmjs.com/package/oh-my-opencode) [![npm downloads](https://img.shields.io/npm/dt/oh-my-openagent?color=ff6b35&labelColor=black&style=flat-square)](https://www.npmjs.com/package/oh-my-openagent)
[![GitHub Contributors](https://img.shields.io/github/contributors/code-yeongyu/oh-my-openagent?color=c4f042&labelColor=black&style=flat-square)](https://github.com/code-yeongyu/oh-my-openagent/graphs/contributors) [![GitHub Contributors](https://img.shields.io/github/contributors/code-yeongyu/oh-my-openagent?color=c4f042&labelColor=black&style=flat-square)](https://github.com/code-yeongyu/oh-my-openagent/graphs/contributors)
[![GitHub Forks](https://img.shields.io/github/forks/code-yeongyu/oh-my-openagent?color=8ae8ff&labelColor=black&style=flat-square)](https://github.com/code-yeongyu/oh-my-openagent/network/members) [![GitHub Forks](https://img.shields.io/github/forks/code-yeongyu/oh-my-openagent?color=8ae8ff&labelColor=black&style=flat-square)](https://github.com/code-yeongyu/oh-my-openagent/network/members)
[![GitHub Stars](https://img.shields.io/github/stars/code-yeongyu/oh-my-openagent?color=ffcb47&labelColor=black&style=flat-square)](https://github.com/code-yeongyu/oh-my-openagent/stargazers) [![GitHub Stars](https://img.shields.io/github/stars/code-yeongyu/oh-my-openagent?color=ffcb47&labelColor=black&style=flat-square)](https://github.com/code-yeongyu/oh-my-openagent/stargazers)
@@ -65,25 +54,25 @@
> 「Claude Codeが人間なら3ヶ月かかることを7日でやるとしたら、Sisyphusはそれを1時間でやってのけます。タスクが終わるまでひたすら働き続けます。まさに規律あるエージェントです。」 <br/>- B, Quant Researcher > 「Claude Codeが人間なら3ヶ月かかることを7日でやるとしたら、Sisyphusはそれを1時間でやってのけます。タスクが終わるまでひたすら働き続けます。まさに規律あるエージェントです。」 <br/>- B, Quant Researcher
> 「Oh My Opencodeを使って、たった1日で8000個の eslint 警告を叩き潰しました。」 <br/>- [Jacob Ferrari](https://x.com/jacobferrari_/status/2003258761952289061) > 「Oh My OpenAgentを使って、たった1日で8000個の eslint 警告を叩き潰しました。」 <br/>- [Jacob Ferrari](https://x.com/jacobferrari_/status/2003258761952289061)
> 「Ohmyopencodeとralph loopを使って、45k行のtauriアプリを一晩でSaaSウェブアプリに変換しました。インタビューモードから始めて、私のプロンプトに対して質問や推奨事項を尋ねました。勝手に作業していくのを見るのは楽しかったし、今朝起きたらウェブサイトがほぼ動いているのを見て驚愕しました」 - [James Hargis](https://x.com/hargabyte/status/2007299688261882202) > 「Ohmyopencodeとralph loopを使って、45k行のtauriアプリを一晩でSaaSウェブアプリに変換しました。インタビューモードから始めて、私のプロンプトに対して質問や推奨事項を尋ねました。勝手に作業していくのを見るのは楽しかったし、今朝起きたらウェブサイトがほぼ動いているのを見て驚愕しました」 - [James Hargis](https://x.com/hargabyte/status/2007299688261882202)
> 「oh-my-opencodeを使ってください。もう二度と元には戻れません。」 <br/>- [d0t3ch](https://x.com/d0t3ch/status/2001685618200580503) > 「oh-my-openagentを使ってください。もう二度と元には戻れません。」 <br/>- [d0t3ch](https://x.com/d0t3ch/status/2001685618200580503)
> 「何がどうすごいのかまだ上手く言語化できないんですが、開発体験が完全に異次元に到達してしまいました。」 - [苔硯:こけすずり](https://x.com/kokesuzuri/status/2008532913961529372?s=20) > 「何がどうすごいのかまだ上手く言語化できないんですが、開発体験が完全に異次元に到達してしまいました。」 - [苔硯:こけすずり](https://x.com/kokesuzuri/status/2008532913961529372?s=20)
> 「週末にマインクラフト/ソウルライクな化け物を作ろうと、open code、oh my opencode、supermemoryで実験中です。昼食後の散歩に行っている間に、しゃがむアニメーションを追加するように指示しておきました。[動画]」 - [MagiMetal](https://x.com/MagiMetal/status/2005374704178373023) > 「週末にマインクラフト/ソウルライクな化け物を作ろうと、open code、oh my openagent、supermemoryで実験中です。昼食後の散歩に行っている間に、しゃがむアニメーションを追加するように指示しておきました。[動画]」 - [MagiMetal](https://x.com/MagiMetal/status/2005374704178373023)
> 「これをコアに取り込んで彼を採用すべきだ。マジで。これ、本当に、本当に、本当に良い。」 <br/>- Henning Kilset > 「これをコアに取り込んで彼を採用すべきだ。マジで。これ、本当に、本当に、本当に良い。」 <br/>- Henning Kilset
> 「彼を説得できるなら @yeon_gyu_kim を雇ってください。彼がopencodeに革命を起こしました。」 <br/>- [mysticaltech](https://x.com/mysticaltech/status/2001858758608376079) > 「彼を説得できるなら @yeon_gyu_kim を雇ってください。彼がopencodeに革命を起こしました。」 <br/>- [mysticaltech](https://x.com/mysticaltech/status/2001858758608376079)
> 「Oh My OpenCodeはマジでヤバい」 - [YouTube - Darren Builds AI](https://www.youtube.com/watch?v=G_Snfh2M41M) > 「Oh My OpenAgentはマジでヤバい」 - [YouTube - Darren Builds AI](https://www.youtube.com/watch?v=G_Snfh2M41M)
--- ---
# Oh My OpenCode # Oh My OpenAgent
最初はこれを「Claude Codeにステロイドを打ったもの」と呼んでいました。それは過小評価でした。 最初はこれを「Claude Codeにステロイドを打ったもの」と呼んでいました。それは過小評価でした。
@@ -101,7 +90,7 @@ OmOをインストールして、`ultrawork`とタイプしてください。狂
以下のプロンプトをコピーして、あなたのLLMエージェントClaude Code、AmpCode、Cursorなどに貼り付けてください 以下のプロンプトをコピーして、あなたのLLMエージェントClaude Code、AmpCode、Cursorなどに貼り付けてください
``` ```
Install and configure oh-my-opencode by following the instructions here: Install and configure oh-my-openagent by following the instructions here:
https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/refs/heads/dev/docs/guide/installation.md https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/refs/heads/dev/docs/guide/installation.md
``` ```
@@ -168,7 +157,7 @@ Read this and tell me why it's not just another boilerplate: https://raw.githubu
**Sisyphus** (`claude-opus-4-6` / **`kimi-k2.5`** / **`glm-5`**) はあなたのメインのオーケストレーターです。計画を立て、専門家に委任し、攻撃的な並列実行でタスクを完了まで推進します。途中で投げ出すことはありません。 **Sisyphus** (`claude-opus-4-6` / **`kimi-k2.5`** / **`glm-5`**) はあなたのメインのオーケストレーターです。計画を立て、専門家に委任し、攻撃的な並列実行でタスクを完了まで推進します。途中で投げ出すことはありません。
**Hephaestus** (`gpt-5.4`) はあなたの自律的なディープワーカーです。レシピではなく、目標を与えてください。手取り足取り教えなくても、コードベースを探索し、パターンを研究し、端から端まで実行します。*正当なる職人 (The Legitimate Craftsman).* **Hephaestus** (`gpt-5.3-codex`) はあなたの自律的なディープワーカーです。レシピではなく、目標を与えてください。手取り足取り教えなくても、コードベースを探索し、パターンを研究し、端から端まで実行します。*正当なる職人 (The Legitimate Craftsman).*
**Prometheus** (`claude-opus-4-6` / **`kimi-k2.5`** / **`glm-5`**) はあなたの戦略プランナーです。インタビューモードで動作し、コードに触れる前に質問をしてスコープを特定し、詳細な計画を構築します。 **Prometheus** (`claude-opus-4-6` / **`kimi-k2.5`** / **`glm-5`**) はあなたの戦略プランナーです。インタビューモードで動作し、コードに触れる前に質問をしてスコープを特定し、詳細な計画を構築します。
@@ -176,7 +165,7 @@ Read this and tell me why it's not just another boilerplate: https://raw.githubu
> Anthropicが[私たちのせいでOpenCodeをブロックしました。](https://x.com/thdxr/status/2010149530486911014) だからこそHephaestusは「正当なる職人 (The Legitimate Craftsman)」と呼ばれているのです。皮肉を込めています。 > Anthropicが[私たちのせいでOpenCodeをブロックしました。](https://x.com/thdxr/status/2010149530486911014) だからこそHephaestusは「正当なる職人 (The Legitimate Craftsman)」と呼ばれているのです。皮肉を込めています。
> >
> Opusで最もよく動きますが、Kimi K2.5 + GPT-5.4の組み合わせだけでも、バニラのClaude Codeを軽く凌駕します。設定は一切不要です。 > Opusで最もよく動きますが、Kimi K2.5 + GPT-5.3 Codexの組み合わせだけでも、バニラのClaude Codeを軽く凌駕します。設定は一切不要です。
### エージェントの<E38388><E381AE>ーケストレーション ### エージェントの<E38388><E381AE>ーケストレーション
@@ -271,19 +260,19 @@ project/
> **背景のストーリーを知りたいですか?** なぜSisyphusは岩を転がすのか、なぜHephaestusは「正当なる職人」なのか、そして[オーケストレーションガイド](docs/guide/orchestration.md)をお読みください。 > **背景のストーリーを知りたいですか?** なぜSisyphusは岩を転がすのか、なぜHephaestusは「正当なる職人」なのか、そして[オーケストレーションガイド](docs/guide/orchestration.md)をお読みください。
> >
> oh-my-opencodeは初めてですか?どのモデルを使うべきかについては、**[インストールガイド](docs/guide/installation.md#step-5-understand-your-model-setup)** で推奨モデルを確認してください。 > oh-my-openagentは初めてですか?どのモデルを使うべきかについては、**[インストールガイド](docs/guide/installation.md#step-5-understand-your-model-setup)** で推奨モデルを確認してください。
## アンインストール (Uninstallation) ## アンインストール (Uninstallation)
oh-my-opencodeを削除するには: oh-my-openagentを削除するには:
1. **OpenCodeの設定からプラグインを削除する** 1. **OpenCodeの設定からプラグインを削除する**
`~/.config/opencode/opencode.json`(または `opencode.jsonc`)を編集し、`plugin` 配列から `"oh-my-opencode"` を削除します: `~/.config/opencode/opencode.json`(または `opencode.jsonc`)を編集し、`plugin` 配列から `"oh-my-openagent"` を削除します:
```bash ```bash
# jq を使用する場合 # jq を使用する場合
jq '.plugin = [.plugin[] | select(. != "oh-my-opencode")]' \ jq '.plugin = [.plugin[] | select(. != "oh-my-openagent")]' \
~/.config/opencode/opencode.json > /tmp/oc.json && \ ~/.config/opencode/opencode.json > /tmp/oc.json && \
mv /tmp/oc.json ~/.config/opencode/opencode.json mv /tmp/oc.json ~/.config/opencode/opencode.json
``` ```

View File

@@ -4,32 +4,21 @@
> 핵심 메인테이너 Q가 부상을 입어, 이번 주에는 이슈/PR 응답 및 릴리스가 지연될 수 있습니다. > 핵심 메인테이너 Q가 부상을 입어, 이번 주에는 이슈/PR 응답 및 릴리스가 지연될 수 있습니다.
> 양해와 응원에 감사드립니다. > 양해와 응원에 감사드립니다.
> [!TIP]
> **Building in Public**
>
> 메인테이너가 Jobdori를 통해 oh-my-opencode를 실시간으로 개발하고 있습니다. Jobdori는 OpenClaw를 기반으로 대폭 커스터마이징된 AI 어시스턴트입니다.
> 모든 기능 개발, 버그 수정, 이슈 트리아지를 Discord에서 실시간으로 확인하세요.
>
> [![Building in Public](./.github/assets/building-in-public.png)](https://discord.gg/PUwSMR9XNk)
>
> [**→ #building-in-public에서 확인하기**](https://discord.gg/PUwSMR9XNk)
> [!TIP] > [!TIP]
> 저희와 함께 하세요! > 저희와 함께 하세요!
> >
> | [<img alt="Discord link" src="https://img.shields.io/discord/1452487457085063218?color=5865F2&label=discord&labelColor=black&logo=discord&logoColor=white&style=flat-square" width="156px" />](https://discord.gg/PUwSMR9XNk) | [Discord 커뮤니티](https://discord.gg/PUwSMR9XNk)에 가입하여 기여자 및 다른 `oh-my-opencode` 사용자들과 소통하세요. | > | [<img alt="Discord link" src="https://img.shields.io/discord/1452487457085063218?color=5865F2&label=discord&labelColor=black&logo=discord&logoColor=white&style=flat-square" width="156px" />](https://discord.gg/PUwSMR9XNk) | [Discord 커뮤니티](https://discord.gg/PUwSMR9XNk)에 가입하여 기여자 및 다른 `oh-my-openagent` 사용자들과 소통하세요. |
> | :-----| :----- | > | :-----| :----- |
> | [<img alt="X link" src="https://img.shields.io/badge/Follow-%40justsisyphus-00CED1?style=flat-square&logo=x&labelColor=black" width="156px" />](https://x.com/justsisyphus) | `oh-my-opencode`에 대한 소식과 업데이트는 제 X 계정에 올라왔었지만, <br /> 실수로 정지된 이후에는 [@justsisyphus](https://x.com/justsisyphus)가 대신 업데이트를 게시하고 있습니다. | > | [<img alt="X link" src="https://img.shields.io/badge/Follow-%40justsisyphus-00CED1?style=flat-square&logo=x&labelColor=black" width="156px" />](https://x.com/justsisyphus) | `oh-my-openagent`에 대한 소식과 업데이트는 제 X 계정에 올라왔었지만, <br /> 실수로 정지된 이후에는 [@justsisyphus](https://x.com/justsisyphus)가 대신 업데이트를 게시하고 있습니다. |
> | [<img alt="GitHub Follow" src="https://img.shields.io/github/followers/code-yeongyu?style=flat-square&logo=github&labelColor=black&color=24292f" width="156px" />](https://github.com/code-yeongyu) | 더 많은 프로젝트를 보려면 GitHub에서 [@code-yeongyu](https://github.com/code-yeongyu)를 팔로우하세요. | > | [<img alt="GitHub Follow" src="https://img.shields.io/github/followers/code-yeongyu?style=flat-square&logo=github&labelColor=black&color=24292f" width="156px" />](https://github.com/code-yeongyu) | 더 많은 프로젝트를 보려면 GitHub에서 [@code-yeongyu](https://github.com/code-yeongyu)를 팔로우하세요. |
<!-- <CENTERED SECTION FOR GITHUB DISPLAY> --> <!-- <CENTERED SECTION FOR GITHUB DISPLAY> -->
<div align="center"> <div align="center">
[![Oh My OpenCode](./.github/assets/hero.jpg)](https://github.com/code-yeongyu/oh-my-openagent#oh-my-opencode) [![Oh My OpenAgent](./.github/assets/hero.jpg)](https://github.com/code-yeongyu/oh-my-openagent#oh-my-openagent)
[![Preview](./.github/assets/omo.png)](https://github.com/code-yeongyu/oh-my-openagent#oh-my-opencode) [![Preview](./.github/assets/omo.png)](https://github.com/code-yeongyu/oh-my-openagent#oh-my-openagent)
</div> </div>
@@ -40,7 +29,7 @@
<div align="center"> <div align="center">
[![GitHub Release](https://img.shields.io/github/v/release/code-yeongyu/oh-my-openagent?color=369eff&labelColor=black&logo=github&style=flat-square)](https://github.com/code-yeongyu/oh-my-openagent/releases) [![GitHub Release](https://img.shields.io/github/v/release/code-yeongyu/oh-my-openagent?color=369eff&labelColor=black&logo=github&style=flat-square)](https://github.com/code-yeongyu/oh-my-openagent/releases)
[![npm downloads](https://img.shields.io/npm/dt/oh-my-opencode?color=ff6b35&labelColor=black&style=flat-square)](https://www.npmjs.com/package/oh-my-opencode) [![npm downloads](https://img.shields.io/npm/dt/oh-my-openagent?color=ff6b35&labelColor=black&style=flat-square)](https://www.npmjs.com/package/oh-my-openagent)
[![GitHub Contributors](https://img.shields.io/github/contributors/code-yeongyu/oh-my-openagent?color=c4f042&labelColor=black&style=flat-square)](https://github.com/code-yeongyu/oh-my-openagent/graphs/contributors) [![GitHub Contributors](https://img.shields.io/github/contributors/code-yeongyu/oh-my-openagent?color=c4f042&labelColor=black&style=flat-square)](https://github.com/code-yeongyu/oh-my-openagent/graphs/contributors)
[![GitHub Forks](https://img.shields.io/github/forks/code-yeongyu/oh-my-openagent?color=8ae8ff&labelColor=black&style=flat-square)](https://github.com/code-yeongyu/oh-my-openagent/network/members) [![GitHub Forks](https://img.shields.io/github/forks/code-yeongyu/oh-my-openagent?color=8ae8ff&labelColor=black&style=flat-square)](https://github.com/code-yeongyu/oh-my-openagent/network/members)
[![GitHub Stars](https://img.shields.io/github/stars/code-yeongyu/oh-my-openagent?color=ffcb47&labelColor=black&style=flat-square)](https://github.com/code-yeongyu/oh-my-openagent/stargazers) [![GitHub Stars](https://img.shields.io/github/stars/code-yeongyu/oh-my-openagent?color=ffcb47&labelColor=black&style=flat-square)](https://github.com/code-yeongyu/oh-my-openagent/stargazers)
@@ -60,25 +49,25 @@
> "Claude Code가 인간이 3개월 걸릴 일을 7일 만에 한다면, Sisyphus는 1시간 만에 해냅니다. 작업이 끝날 때까지 그냥 계속 알아서 작동합니다. 이건 정말 규율이 잡힌 에이전트예요." <br/>- B, Quant Researcher > "Claude Code가 인간이 3개월 걸릴 일을 7일 만에 한다면, Sisyphus는 1시간 만에 해냅니다. 작업이 끝날 때까지 그냥 계속 알아서 작동합니다. 이건 정말 규율이 잡힌 에이전트예요." <br/>- B, Quant Researcher
> "Oh My Opencode로 하루 만에 eslint 경고 8000개를 해결했습니다." <br/>- [Jacob Ferrari](https://x.com/jacobferrari_/status/2003258761952289061) > "Oh My OpenAgent로 하루 만에 eslint 경고 8000개를 해결했습니다." <br/>- [Jacob Ferrari](https://x.com/jacobferrari_/status/2003258761952289061)
> "Ohmyopencode와 ralph loop를 써서 45k 라인짜리 tauri 앱을 하룻밤 만에 SaaS 웹앱으로 변환했어요. 인터뷰 모드로 시작해서, 제가 쓴 프롬프트에 대해 질문하고 추천을 부탁했죠. 일하는 걸 지켜보는 것도 재밌었고, 아침에 일어났더니 웹사이트가 대부분 돌아가고 있는 걸 보고 경악했습니다!" - [James Hargis](https://x.com/hargabyte/status/2007299688261882202) > "Ohmyopencode와 ralph loop를 써서 45k 라인짜리 tauri 앱을 하룻밤 만에 SaaS 웹앱으로 변환했어요. 인터뷰 모드로 시작해서, 제가 쓴 프롬프트에 대해 질문하고 추천을 부탁했죠. 일하는 걸 지켜보는 것도 재밌었고, 아침에 일어났더니 웹사이트가 대부분 돌아가고 있는 걸 보고 경악했습니다!" - [James Hargis](https://x.com/hargabyte/status/2007299688261882202)
> "oh-my-opencode 쓰세요, 다시는 예전으로 못 돌아갑니다." <br/>- [d0t3ch](https://x.com/d0t3ch/status/2001685618200580503) > "oh-my-openagent 쓰세요, 다시는 예전으로 못 돌아갑니다." <br/>- [d0t3ch](https://x.com/d0t3ch/status/2001685618200580503)
> "뭐가 이렇게 대단한 건지 아직 정확하게 말로 표현하긴 어려운데, 개발 경험 자체가 완전히 다른 차원에 도달해버렸어요." - [苔硯:こけすずり](https://x.com/kokesuzuri/status/2008532913961529372?s=20) > "뭐가 이렇게 대단한 건지 아직 정확하게 말로 표현하긴 어려운데, 개발 경험 자체가 완전히 다른 차원에 도달해버렸어요." - [苔硯:こけすずり](https://x.com/kokesuzuri/status/2008532913961529372?s=20)
> "주말에 마인크래프트/소울라이크 같은 괴물 같은 걸 만들어보려고 open code, oh my opencode, supermemory로 실험 중입니다. 점심 먹고 산책 다녀오는 동안 앉기 애니메이션을 추가하라고 시켜뒀어요. [영상]" - [MagiMetal](https://x.com/MagiMetal/status/2005374704178373023) > "주말에 마인크래프트/소울라이크 같은 괴물 같은 걸 만들어보려고 open code, oh my openagent, supermemory로 실험 중입니다. 점심 먹고 산책 다녀오는 동안 앉기 애니메이션을 추가하라고 시켜뒀어요. [영상]" - [MagiMetal](https://x.com/MagiMetal/status/2005374704178373023)
> "이걸 코어에 당겨오고 저 사람 스카우트해야 돼요. 진심으로. 이거 진짜, 진짜, 진짜 좋습니다." <br/>- Henning Kilset > "이걸 코어에 당겨오고 저 사람 스카우트해야 돼요. 진심으로. 이거 진짜, 진짜, 진짜 좋습니다." <br/>- Henning Kilset
> "설득할 수만 있다면 @yeon_gyu_kim 채용하세요, 이 사람이 opencode를 혁명적으로 바꿨습니다." <br/>- [mysticaltech](https://x.com/mysticaltech/status/2001858758608376079) > "설득할 수만 있다면 @yeon_gyu_kim 채용하세요, 이 사람이 opencode를 혁명적으로 바꿨습니다." <br/>- [mysticaltech](https://x.com/mysticaltech/status/2001858758608376079)
> "Oh My OpenCode는 진짜 미쳤다" - [YouTube - Darren Builds AI](https://www.youtube.com/watch?v=G_Snfh2M41M) > "Oh My OpenAgent는 진짜 미쳤다" - [YouTube - Darren Builds AI](https://www.youtube.com/watch?v=G_Snfh2M41M)
--- ---
# Oh My OpenCode # Oh My OpenAgent
Claude Code, Codex, 온갖 OSS 모델들 사이에서 헤매고 있나요. 워크플로우 설정하랴, 에이전트 디버깅하랴 피곤할 겁니다. Claude Code, Codex, 온갖 OSS 모델들 사이에서 헤매고 있나요. 워크플로우 설정하랴, 에이전트 디버깅하랴 피곤할 겁니다.
@@ -95,7 +84,7 @@ OmO 설치하고. `ultrawork` 치세요. 끝.
다음 프롬프트를 복사해서 여러분의 LLM 에이전트(Claude Code, AmpCode, Cursor 등)에 붙여넣으세요: 다음 프롬프트를 복사해서 여러분의 LLM 에이전트(Claude Code, AmpCode, Cursor 등)에 붙여넣으세요:
``` ```
Install and configure oh-my-opencode by following the instructions here: Install and configure oh-my-openagent by following the instructions here:
https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/refs/heads/dev/docs/guide/installation.md https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/refs/heads/dev/docs/guide/installation.md
``` ```
@@ -162,7 +151,7 @@ Read this and tell me why it's not just another boilerplate: https://raw.githubu
**Sisyphus** (`claude-opus-4-6` / **`kimi-k2.5`** / **`glm-5`**)는 당신의 메인 오케스트레이터입니다. 공격적인 병렬 실행으로 계획을 세우고, 전문가들에게 위임하며, 완료될 때까지 밀어붙입니다. 중간에 포기하는 법이 없습니다. **Sisyphus** (`claude-opus-4-6` / **`kimi-k2.5`** / **`glm-5`**)는 당신의 메인 오케스트레이터입니다. 공격적인 병렬 실행으로 계획을 세우고, 전문가들에게 위임하며, 완료될 때까지 밀어붙입니다. 중간에 포기하는 법이 없습니다.
**Hephaestus** (`gpt-5.4`)는 당신의 자율 딥 워커입니다. 레시피가 아니라 목표를 주세요. 베이비시터 없이 알아서 코드베이스를 탐색하고, 패턴을 연구하며, 끝에서 끝까지 전부 해냅니다. *진정한 장인(The Legitimate Craftsman).* **Hephaestus** (`gpt-5.3-codex`)는 당신의 자율 딥 워커입니다. 레시피가 아니라 목표를 주세요. 베이비시터 없이 알아서 코드베이스를 탐색하고, 패턴을 연구하며, 끝에서 끝까지 전부 해냅니다. *진정한 장인(The Legitimate Craftsman).*
**Prometheus** (`claude-opus-4-6` / **`kimi-k2.5`** / **`glm-5`**)는 당신의 전략 플래너입니다. 인터뷰 모드로 작동합니다. 코드 한 줄 만지기 전에 질문을 던져 스코프를 파악하고 상세한 계획부터 세웁니다. **Prometheus** (`claude-opus-4-6` / **`kimi-k2.5`** / **`glm-5`**)는 당신의 전략 플래너입니다. 인터뷰 모드로 작동합니다. 코드 한 줄 만지기 전에 질문을 던져 스코프를 파악하고 상세한 계획부터 세웁니다.
@@ -170,7 +159,7 @@ Read this and tell me why it's not just another boilerplate: https://raw.githubu
> Anthropic이 [우리 때문에 OpenCode를 막아버렸습니다.](https://x.com/thdxr/status/2010149530486911014) 그래서 Hephaestus의 별명이 "진정한 장인(The Legitimate Craftsman)"인 겁니다. (어디서 많이 들어본 이름이죠?) 아이러니를 노렸습니다. > Anthropic이 [우리 때문에 OpenCode를 막아버렸습니다.](https://x.com/thdxr/status/2010149530486911014) 그래서 Hephaestus의 별명이 "진정한 장인(The Legitimate Craftsman)"인 겁니다. (어디서 많이 들어본 이름이죠?) 아이러니를 노렸습니다.
> >
> Opus에서 제일 잘 돌아가긴 하지만, Kimi K2.5 + GPT-5.4 조합만으로도 바닐라 Claude Code는 가볍게 바릅니다. 설정도 필요 없습니다. > Opus에서 제일 잘 돌아가긴 하지만, Kimi K2.5 + GPT-5.3 Codex 조합만으로도 바닐라 Claude Code는 가볍게 바릅니다. 설정도 필요 없습니다.
### 에이전트 오케스트레이션 ### 에이전트 오케스트레이션
@@ -265,19 +254,19 @@ project/
> **비하인드 스토리가 궁금하신가요?** 왜 Sisyphus가 돌을 굴리는지, 왜 Hephaestus가 "진정한 장인"인지, 그리고 [오케스트레이션 가이드](docs/guide/orchestration.md)를 읽어보세요. > **비하인드 스토리가 궁금하신가요?** 왜 Sisyphus가 돌을 굴리는지, 왜 Hephaestus가 "진정한 장인"인지, 그리고 [오케스트레이션 가이드](docs/guide/orchestration.md)를 읽어보세요.
> >
> oh-my-opencode가 처음이신가요? 어떤 모델을 써야 할지 **[설치 가이드](docs/guide/installation.md#step-5-understand-your-model-setup)** 에서 추천 조합을 확인하세요. > oh-my-openagent가 처음이신가요? 어떤 모델을 써야 할지 **[설치 가이드](docs/guide/installation.md#step-5-understand-your-model-setup)** 에서 추천 조합을 확인하세요.
## 제거 (Uninstallation) ## 제거 (Uninstallation)
oh-my-opencode를 지우려면: oh-my-openagent를 지우려면:
1. **OpenCode 설정에서 플러그인 제거** 1. **OpenCode 설정에서 플러그인 제거**
`~/.config/opencode/opencode.json` (또는 `opencode.jsonc`)를 열고 `plugin` 배열에서 `"oh-my-opencode"`를 지우세요. `~/.config/opencode/opencode.json` (또는 `opencode.jsonc`)를 열고 `plugin` 배열에서 `"oh-my-openagent"`를 지우세요.
```bash ```bash
# jq 사용 시 # jq 사용 시
jq '.plugin = [.plugin[] | select(. != "oh-my-opencode")]' \ jq '.plugin = [.plugin[] | select(. != "oh-my-openagent")]' \
~/.config/opencode/opencode.json > /tmp/oc.json && \ ~/.config/opencode/opencode.json > /tmp/oc.json && \
mv /tmp/oc.json ~/.config/opencode/opencode.json mv /tmp/oc.json ~/.config/opencode/opencode.json
``` ```

View File

@@ -1,13 +1,3 @@
> [!TIP]
> **Building in Public**
>
> The maintainer builds and maintains oh-my-opencode in real-time with Jobdori, an AI assistant built on a heavily customized fork of OpenClaw.
> Every feature, every fix, every issue triage — live in our Discord.
>
> [![Building in Public](./.github/assets/building-in-public.png)](https://discord.gg/PUwSMR9XNk)
>
> [**→ Watch it happen in #building-in-public**](https://discord.gg/PUwSMR9XNk)
> [!NOTE] > [!NOTE]
> >
> [![Sisyphus Labs - Sisyphus is the agent that codes like your team.](./.github/assets/sisyphuslabs.png?v=2)](https://sisyphuslabs.ai) > [![Sisyphus Labs - Sisyphus is the agent that codes like your team.](./.github/assets/sisyphuslabs.png?v=2)](https://sisyphuslabs.ai)
@@ -16,18 +6,18 @@
> [!TIP] > [!TIP]
> Be with us! > Be with us!
> >
> | [<img alt="Discord link" src="https://img.shields.io/discord/1452487457085063218?color=5865F2&label=discord&labelColor=black&logo=discord&logoColor=white&style=flat-square" width="156px" />](https://discord.gg/PUwSMR9XNk) | Join our [Discord community](https://discord.gg/PUwSMR9XNk) to connect with contributors and fellow `oh-my-opencode` users. | > | [<img alt="Discord link" src="https://img.shields.io/discord/1452487457085063218?color=5865F2&label=discord&labelColor=black&logo=discord&logoColor=white&style=flat-square" width="156px" />](https://discord.gg/PUwSMR9XNk) | Join our [Discord community](https://discord.gg/PUwSMR9XNk) to connect with contributors and fellow `oh-my-openagent` users. |
> | :-----| :----- | > | :-----| :----- |
> | [<img alt="X link" src="https://img.shields.io/badge/Follow-%40justsisyphus-00CED1?style=flat-square&logo=x&labelColor=black" width="156px" />](https://x.com/justsisyphus) | News and updates for `oh-my-opencode` used to be posted on my X account. <br /> Since it was suspended mistakenly, [@justsisyphus](https://x.com/justsisyphus) now posts updates on my behalf. | > | [<img alt="X link" src="https://img.shields.io/badge/Follow-%40justsisyphus-00CED1?style=flat-square&logo=x&labelColor=black" width="156px" />](https://x.com/justsisyphus) | News and updates for `oh-my-openagent` used to be posted on my X account. <br /> Since it was suspended mistakenly, [@justsisyphus](https://x.com/justsisyphus) now posts updates on my behalf. |
> | [<img alt="GitHub Follow" src="https://img.shields.io/github/followers/code-yeongyu?style=flat-square&logo=github&labelColor=black&color=24292f" width="156px" />](https://github.com/code-yeongyu) | Follow [@code-yeongyu](https://github.com/code-yeongyu) on GitHub for more projects. | > | [<img alt="GitHub Follow" src="https://img.shields.io/github/followers/code-yeongyu?style=flat-square&logo=github&labelColor=black&color=24292f" width="156px" />](https://github.com/code-yeongyu) | Follow [@code-yeongyu](https://github.com/code-yeongyu) on GitHub for more projects. |
<!-- <CENTERED SECTION FOR GITHUB DISPLAY> --> <!-- <CENTERED SECTION FOR GITHUB DISPLAY> -->
<div align="center"> <div align="center">
[![Oh My OpenCode](./.github/assets/hero.jpg)](https://github.com/code-yeongyu/oh-my-openagent#oh-my-opencode) [![Oh My OpenAgent](./.github/assets/hero.jpg)](https://github.com/code-yeongyu/oh-my-openagent#oh-my-openagent)
[![Preview](./.github/assets/omo.png)](https://github.com/code-yeongyu/oh-my-openagent#oh-my-opencode) [![Preview](./.github/assets/omo.png)](https://github.com/code-yeongyu/oh-my-openagent#oh-my-openagent)
</div> </div>
@@ -41,7 +31,7 @@
<div align="center"> <div align="center">
[![GitHub Release](https://img.shields.io/github/v/release/code-yeongyu/oh-my-openagent?color=369eff&labelColor=black&logo=github&style=flat-square)](https://github.com/code-yeongyu/oh-my-openagent/releases) [![GitHub Release](https://img.shields.io/github/v/release/code-yeongyu/oh-my-openagent?color=369eff&labelColor=black&logo=github&style=flat-square)](https://github.com/code-yeongyu/oh-my-openagent/releases)
[![npm downloads](https://img.shields.io/endpoint?url=https%3A%2F%2Fohmyopenagent.com%2Fapi%2Fnpm-downloads&style=flat-square)](https://www.npmjs.com/package/oh-my-opencode) [![npm downloads](https://img.shields.io/endpoint?url=https%3A%2F%2Fohmyopenagent.com%2Fapi%2Fnpm-downloads&style=flat-square)](https://www.npmjs.com/package/oh-my-openagent)
[![GitHub Contributors](https://img.shields.io/github/contributors/code-yeongyu/oh-my-openagent?color=c4f042&labelColor=black&style=flat-square)](https://github.com/code-yeongyu/oh-my-openagent/graphs/contributors) [![GitHub Contributors](https://img.shields.io/github/contributors/code-yeongyu/oh-my-openagent?color=c4f042&labelColor=black&style=flat-square)](https://github.com/code-yeongyu/oh-my-openagent/graphs/contributors)
[![GitHub Forks](https://img.shields.io/github/forks/code-yeongyu/oh-my-openagent?color=8ae8ff&labelColor=black&style=flat-square)](https://github.com/code-yeongyu/oh-my-openagent/network/members) [![GitHub Forks](https://img.shields.io/github/forks/code-yeongyu/oh-my-openagent?color=8ae8ff&labelColor=black&style=flat-square)](https://github.com/code-yeongyu/oh-my-openagent/network/members)
[![GitHub Stars](https://img.shields.io/github/stars/code-yeongyu/oh-my-openagent?color=ffcb47&labelColor=black&style=flat-square)](https://github.com/code-yeongyu/oh-my-openagent/stargazers) [![GitHub Stars](https://img.shields.io/github/stars/code-yeongyu/oh-my-openagent?color=ffcb47&labelColor=black&style=flat-square)](https://github.com/code-yeongyu/oh-my-openagent/stargazers)
@@ -61,27 +51,27 @@
> "If Claude Code does in 7 days what a human does in 3 months, Sisyphus does it in 1 hour. It just works until the task is done. It is a discipline agent." <br/>- B, Quant Researcher > "If Claude Code does in 7 days what a human does in 3 months, Sisyphus does it in 1 hour. It just works until the task is done. It is a discipline agent." <br/>- B, Quant Researcher
> "Knocked out 8000 eslint warnings with Oh My Opencode, just in a day" <br/>- [Jacob Ferrari](https://x.com/jacobferrari_/status/2003258761952289061) > "Knocked out 8000 eslint warnings with Oh My OpenAgent, just in a day" <br/>- [Jacob Ferrari](https://x.com/jacobferrari_/status/2003258761952289061)
> "I converted a 45k line tauri app into a SaaS web app overnight using Ohmyopencode and ralph loop. Started with interview me prompt, asked it for ratings and recommendations on the questions. It was amazing to watch it work and to wake up this morning to a mostly working website!" - [James Hargis](https://x.com/hargabyte/status/2007299688261882202) > "I converted a 45k line tauri app into a SaaS web app overnight using Ohmyopencode and ralph loop. Started with interview me prompt, asked it for ratings and recommendations on the questions. It was amazing to watch it work and to wake up this morning to a mostly working website!" - [James Hargis](https://x.com/hargabyte/status/2007299688261882202)
> "use oh-my-opencode, you will never go back" <br/>- [d0t3ch](https://x.com/d0t3ch/status/2001685618200580503) > "use oh-my-openagent, you will never go back" <br/>- [d0t3ch](https://x.com/d0t3ch/status/2001685618200580503)
> "I haven't really been able to articulate exactly what makes it so great yet, but the development experience has reached a completely different dimension." - [ > "I haven't really been able to articulate exactly what makes it so great yet, but the development experience has reached a completely different dimension." - [
苔硯:こけすずり](https://x.com/kokesuzuri/status/2008532913961529372?s=20) 苔硯:こけすずり](https://x.com/kokesuzuri/status/2008532913961529372?s=20)
> "Experimenting with open code, oh my opencode and supermemory this weekend to build some minecraft/souls-like abomination." > "Experimenting with open code, oh my openagent and supermemory this weekend to build some minecraft/souls-like abomination."
> "Asking it to add crouch animations while I go take my post-lunch walk. [Video]" - [MagiMetal](https://x.com/MagiMetal/status/2005374704178373023) > "Asking it to add crouch animations while I go take my post-lunch walk. [Video]" - [MagiMetal](https://x.com/MagiMetal/status/2005374704178373023)
> "You guys should pull this into core and recruit him. Seriously. It's really, really, really good." <br/>- Henning Kilset > "You guys should pull this into core and recruit him. Seriously. It's really, really, really good." <br/>- Henning Kilset
> "Hire @yeon_gyu_kim if you can convince him, this dude has revolutionized opencode." <br/>- [mysticaltech](https://x.com/mysticaltech/status/2001858758608376079) > "Hire @yeon_gyu_kim if you can convince him, this dude has revolutionized opencode." <br/>- [mysticaltech](https://x.com/mysticaltech/status/2001858758608376079)
> "Oh My OpenCode Is Actually Insane" - [YouTube - Darren Builds AI](https://www.youtube.com/watch?v=G_Snfh2M41M) > "Oh My OpenAgent Is Actually Insane" - [YouTube - Darren Builds AI](https://www.youtube.com/watch?v=G_Snfh2M41M)
--- ---
# Oh My OpenCode # Oh My OpenAgent
You're juggling Claude Code, Codex, random OSS models. Configuring workflows. Debugging agents. You're juggling Claude Code, Codex, random OSS models. Configuring workflows. Debugging agents.
@@ -97,7 +87,7 @@ Install OmO. Type `ultrawork`. Done.
Copy and paste this prompt to your LLM agent (Claude Code, AmpCode, Cursor, etc.): Copy and paste this prompt to your LLM agent (Claude Code, AmpCode, Cursor, etc.):
``` ```
Install and configure oh-my-opencode by following the instructions here: Install and configure oh-my-openagent by following the instructions here:
https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/refs/heads/dev/docs/guide/installation.md https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/refs/heads/dev/docs/guide/installation.md
``` ```
@@ -111,8 +101,6 @@ Fetch the installation guide and follow it:
curl -s https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/refs/heads/dev/docs/guide/installation.md curl -s https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/refs/heads/dev/docs/guide/installation.md
``` ```
**Note**: Use the published package and binary name `oh-my-opencode`. Inside `opencode.json`, the compatibility layer now prefers the plugin entry `oh-my-openagent`, while legacy `oh-my-opencode` entries still load with a warning. Plugin config files still commonly use `oh-my-opencode.json` or `oh-my-opencode.jsonc`, and both legacy and renamed basenames are recognized during the transition.
--- ---
## Skip This README ## Skip This README
@@ -166,15 +154,19 @@ Even only with following subscriptions, ultrawork will work well (this project i
**Sisyphus** (`claude-opus-4-6` / **`kimi-k2.5`** / **`glm-5`** ) is your main orchestrator. He plans, delegates to specialists, and drives tasks to completion with aggressive parallel execution. He does not stop halfway. **Sisyphus** (`claude-opus-4-6` / **`kimi-k2.5`** / **`glm-5`** ) is your main orchestrator. He plans, delegates to specialists, and drives tasks to completion with aggressive parallel execution. He does not stop halfway.
**Hephaestus** (`gpt-5.4`) is your autonomous deep worker. Give him a goal, not a recipe. He explores the codebase, researches patterns, and executes end-to-end without hand-holding. *The Legitimate Craftsman.* **Hephaestus** (`gpt-5.3-codex`) is your autonomous deep worker. Give him a goal, not a recipe. He explores the codebase, researches patterns, and executes end-to-end without hand-holding. *The Legitimate Craftsman.*
**Prometheus** (`claude-opus-4-6` / **`kimi-k2.5`** / **`glm-5`** ) is your strategic planner. Interview mode: it questions, identifies scope, and builds a detailed plan before a single line of code is touched. **Prometheus** (`claude-opus-4-6` / **`kimi-k2.5`** / **`glm-5`** ) is your strategic planner. Interview mode: it questions, identifies scope, and builds a detailed plan before a single line of code is touched.
**Atlas** (`claude-sonnet-4-6`) is the executor. He takes the plan from Prometheus and drives it to completion, managing the todo list and coordinating subagents.
**Sisyphus-Junior** is the dedicated executor for category-based tasks.
Every agent is tuned to its model's specific strengths. No manual model-juggling. [Learn more →](docs/guide/overview.md) Every agent is tuned to its model's specific strengths. No manual model-juggling. [Learn more →](docs/guide/overview.md)
> Anthropic [blocked OpenCode because of us.](https://x.com/thdxr/status/2010149530486911014) That's why Hephaestus is called "The Legitimate Craftsman." The irony is intentional. > Anthropic [blocked OpenCode because of us.](https://x.com/thdxr/status/2010149530486911014) That's why Hephaestus is called "The Legitimate Craftsman." The irony is intentional.
> >
> We run best on Opus, but Kimi K2.5 + GPT-5.4 already beats vanilla Claude Code. Zero config needed. > We run best on Opus, but Kimi K2.5 + GPT-5.3 Codex already beats vanilla Claude Code. Zero config needed.
### Agent Orchestration ### Agent Orchestration
@@ -267,19 +259,19 @@ Add your own: `.opencode/skills/*/SKILL.md` or `~/.config/opencode/skills/*/SKIL
--- ---
> **New to oh-my-opencode?** Read the **[Overview](docs/guide/overview.md)** to understand what you have, or check the **[Orchestration Guide](docs/guide/orchestration.md)** for how agents collaborate. > **New to oh-my-openagent?** Read the **[Overview](docs/guide/overview.md)** to understand what you have, or check the **[Orchestration Guide](docs/guide/orchestration.md)** for how agents collaborate.
## Uninstallation ## Uninstallation
To remove oh-my-opencode: To remove oh-my-openagent:
1. **Remove the plugin from your OpenCode config** 1. **Remove the plugin from your OpenCode config**
Edit `~/.config/opencode/opencode.json` (or `opencode.jsonc`) and remove either `"oh-my-openagent"` or the legacy `"oh-my-opencode"` entry from the `plugin` array: Edit `~/.config/opencode/opencode.json` (or `opencode.jsonc`) and remove `"oh-my-openagent"` from the `plugin` array:
```bash ```bash
# Using jq # Using jq
jq '.plugin = [.plugin[] | select(. != "oh-my-openagent" and . != "oh-my-opencode")]' \ jq '.plugin = [.plugin[] | select(. != "oh-my-openagent")]' \
~/.config/opencode/opencode.json > /tmp/oc.json && \ ~/.config/opencode/opencode.json > /tmp/oc.json && \
mv /tmp/oc.json ~/.config/opencode/opencode.json mv /tmp/oc.json ~/.config/opencode/opencode.json
``` ```
@@ -287,13 +279,11 @@ To remove oh-my-opencode:
2. **Remove configuration files (optional)** 2. **Remove configuration files (optional)**
```bash ```bash
# Remove plugin config files recognized during the compatibility window # Remove user config
rm -f ~/.config/opencode/oh-my-openagent.jsonc ~/.config/opencode/oh-my-openagent.json \ rm -f ~/.config/opencode/oh-my-opencode.json ~/.config/opencode/oh-my-opencode.jsonc
~/.config/opencode/oh-my-opencode.jsonc ~/.config/opencode/oh-my-opencode.json
# Remove project config (if exists) # Remove project config (if exists)
rm -f .opencode/oh-my-openagent.jsonc .opencode/oh-my-openagent.json \ rm -f .opencode/oh-my-opencode.json .opencode/oh-my-opencode.jsonc
.opencode/oh-my-opencode.jsonc .opencode/oh-my-opencode.json
``` ```
3. **Verify removal** 3. **Verify removal**
@@ -310,7 +300,8 @@ Features you'll think should've always existed. Once you use them, you can't go
See full [Features Documentation](docs/reference/features.md). See full [Features Documentation](docs/reference/features.md).
**Quick Overview:** **Quick Overview:**
- **Agents**: Sisyphus (the main agent), Prometheus (planner), Oracle (architecture/debugging), Librarian (docs/code search), Explore (fast codebase grep), Multimodal Looker - **Primary Agents**: Sisyphus (the main agent), Hephaestus (deep worker), Prometheus (planner), Atlas (executor), Sisyphus-Junior (category executor)
- **Specialist Subagents**: Oracle (architecture/debugging), Librarian (docs/code search), Explore (fast codebase grep), Multimodal Looker (vision)
- **Background Agents**: Run multiple agents in parallel like a real dev team - **Background Agents**: Run multiple agents in parallel like a real dev team
- **LSP & AST Tools**: Refactoring, rename, diagnostics, AST-aware code search - **LSP & AST Tools**: Refactoring, rename, diagnostics, AST-aware code search
- **Hash-anchored Edit Tool**: `LINE#ID` references validate content before applying every change. Surgical edits, zero stale-line errors - **Hash-anchored Edit Tool**: `LINE#ID` references validate content before applying every change. Surgical edits, zero stale-line errors
@@ -318,11 +309,7 @@ See full [Features Documentation](docs/reference/features.md).
- **Claude Code Compatibility**: Full hook system, commands, skills, agents, MCPs - **Claude Code Compatibility**: Full hook system, commands, skills, agents, MCPs
- **Built-in MCPs**: websearch (Exa), context7 (docs), grep_app (GitHub search) - **Built-in MCPs**: websearch (Exa), context7 (docs), grep_app (GitHub search)
- **Session Tools**: List, read, search, and analyze session history - **Session Tools**: List, read, search, and analyze session history
- **Productivity Features**: Ralph Loop, Todo Enforcer, Comment Checker, Think Mode, and more - **Productivity Features**: Ralph Loop, Todo Enforcer, GPT permission-tail continuation, Comment Checker, Think Mode, and more
- **Doctor Command**: Built-in diagnostics (`bunx oh-my-opencode doctor`) verify plugin registration, config, models, and environment
- **Model Fallbacks**: `fallback_models` can mix plain model strings with per-fallback object settings in the same array
- **File Prompts**: Load prompts from files with `file://` support in agent configurations
- **Session Recovery**: Automatic recovery from session errors, context window limits, and API failures
- **Model Setup**: Agent-model matching is built into the [Installation Guide](docs/guide/installation.md#step-5-understand-your-model-setup) - **Model Setup**: Agent-model matching is built into the [Installation Guide](docs/guide/installation.md#step-5-understand-your-model-setup)
## Configuration ## Configuration
@@ -332,14 +319,14 @@ Opinionated defaults, adjustable if you insist.
See [Configuration Documentation](docs/reference/configuration.md). See [Configuration Documentation](docs/reference/configuration.md).
**Quick Overview:** **Quick Overview:**
- **Config Locations**: The compatibility layer recognizes both `oh-my-openagent.json[c]` and legacy `oh-my-opencode.json[c]` plugin config files. Existing installs still commonly use the legacy basename. - **Config Locations**: `.opencode/oh-my-opencode.jsonc` or `.opencode/oh-my-opencode.json` (project), `~/.config/opencode/oh-my-opencode.jsonc` or `~/.config/opencode/oh-my-opencode.json` (user)
- **JSONC Support**: Comments and trailing commas supported - **JSONC Support**: Comments and trailing commas supported
- **Agents**: Override models, temperatures, prompts, and permissions for any agent - **Agents**: Override models, temperatures, prompts, and permissions for any agent
- **Built-in Skills**: `playwright` (browser automation), `git-master` (atomic commits) - **Built-in Skills**: `playwright` (browser automation), `git-master` (atomic commits)
- **Sisyphus Agent**: Main orchestrator with Prometheus (Planner) and Metis (Plan Consultant) - **Sisyphus Agent**: Main orchestrator with Prometheus (Planner) and Metis (Plan Consultant)
- **Background Tasks**: Configure concurrency limits per provider/model - **Background Tasks**: Configure concurrency limits per provider/model
- **Categories**: Domain-specific task delegation (`visual`, `business-logic`, custom) - **Categories**: Domain-specific task delegation (`visual`, `business-logic`, custom)
- **Hooks**: 25+ built-in hooks, all configurable via `disabled_hooks` - **Hooks**: 25+ built-in hooks, including `gpt-permission-continuation`, all configurable via `disabled_hooks`
- **MCPs**: Built-in websearch (Exa), context7 (docs), grep_app (GitHub search) - **MCPs**: Built-in websearch (Exa), context7 (docs), grep_app (GitHub search)
- **LSP**: Full LSP support with refactoring tools - **LSP**: Full LSP support with refactoring tools
- **Experimental**: Aggressive truncation, auto-resume, and more - **Experimental**: Aggressive truncation, auto-resume, and more

View File

@@ -4,17 +4,6 @@
> Ключевой мейнтейнер Q получил травму, поэтому на этой неделе ответы по issue/PR и релизы могут задерживаться. > Ключевой мейнтейнер Q получил травму, поэтому на этой неделе ответы по issue/PR и релизы могут задерживаться.
> Спасибо за терпение и поддержку. > Спасибо за терпение и поддержку.
> [!TIP]
> **Building in Public**
>
> Мейнтейнер разрабатывает и поддерживает oh-my-opencode в режиме реального времени с помощью Jobdori — ИИ-ассистента на базе глубоко кастомизированной версии OpenClaw.
> Каждая фича, каждый фикс, каждый триаж issue — в прямом эфире в нашем Discord.
>
> [![Building in Public](./.github/assets/building-in-public.png)](https://discord.gg/PUwSMR9XNk)
>
> [**→ Смотрите в #building-in-public**](https://discord.gg/PUwSMR9XNk)
> [!NOTE] > [!NOTE]
> >
> [![Sisyphus Labs - Sisyphus is the agent that codes like your team.](./.github/assets/sisyphuslabs.png?v=2)](https://sisyphuslabs.ai) > [![Sisyphus Labs - Sisyphus is the agent that codes like your team.](./.github/assets/sisyphuslabs.png?v=2)](https://sisyphuslabs.ai)
@@ -23,16 +12,16 @@
> [!TIP] Будьте с нами! > [!TIP] Будьте с нами!
> >
> | [](https://discord.gg/PUwSMR9XNk) | Вступайте в наш [Discord](https://discord.gg/PUwSMR9XNk), чтобы общаться с контрибьюторами и пользователями `oh-my-opencode`. | > | [](https://discord.gg/PUwSMR9XNk) | Вступайте в наш [Discord](https://discord.gg/PUwSMR9XNk), чтобы общаться с контрибьюторами и пользователями `oh-my-openagent`. |
> | ----------------------------------- | ------------------------------------------------------------ | > | ----------------------------------- | ------------------------------------------------------------ |
> | [](https://x.com/justsisyphus) | Новости и обновления `oh-my-opencode` раньше публиковались на моём аккаунте X. <br /> После ошибочной блокировки, [@justsisyphus](https://x.com/justsisyphus) публикует обновления вместо меня. | > | [](https://x.com/justsisyphus) | Новости и обновления `oh-my-openagent` раньше публиковались на моём аккаунте X. <br /> После ошибочной блокировки, [@justsisyphus](https://x.com/justsisyphus) публикует обновления вместо меня. |
> | [](https://github.com/code-yeongyu) | Подпишитесь на [@code-yeongyu](https://github.com/code-yeongyu) на GitHub, чтобы следить за другими проектами. | > | [](https://github.com/code-yeongyu) | Подпишитесь на [@code-yeongyu](https://github.com/code-yeongyu) на GitHub, чтобы следить за другими проектами. |
<!-- <CENTERED SECTION FOR GITHUB DISPLAY> --> <div align="center"> <!-- <CENTERED SECTION FOR GITHUB DISPLAY> --> <div align="center">
[![Oh My OpenCode](./.github/assets/hero.jpg)](https://github.com/code-yeongyu/oh-my-openagent#oh-my-opencode) [![Oh My OpenAgent](./.github/assets/hero.jpg)](https://github.com/code-yeongyu/oh-my-openagent#oh-my-openagent)
[![Preview](./.github/assets/omo.png)](https://github.com/code-yeongyu/oh-my-openagent#oh-my-opencode) [![Preview](./.github/assets/omo.png)](https://github.com/code-yeongyu/oh-my-openagent#oh-my-openagent)
</div> </div>
@@ -42,7 +31,7 @@
<div align="center"> <div align="center">
[![GitHub Release](https://img.shields.io/github/v/release/code-yeongyu/oh-my-openagent?color=369eff&labelColor=black&logo=github&style=flat-square)](https://github.com/code-yeongyu/oh-my-openagent/releases) [![npm downloads](https://img.shields.io/npm/dt/oh-my-opencode?color=ff6b35&labelColor=black&style=flat-square)](https://www.npmjs.com/package/oh-my-opencode) [![GitHub Contributors](https://img.shields.io/github/contributors/code-yeongyu/oh-my-openagent?color=c4f042&labelColor=black&style=flat-square)](https://github.com/code-yeongyu/oh-my-openagent/graphs/contributors) [![GitHub Forks](https://img.shields.io/github/forks/code-yeongyu/oh-my-openagent?color=8ae8ff&labelColor=black&style=flat-square)](https://github.com/code-yeongyu/oh-my-openagent/network/members) [![GitHub Stars](https://img.shields.io/github/stars/code-yeongyu/oh-my-openagent?color=ffcb47&labelColor=black&style=flat-square)](https://github.com/code-yeongyu/oh-my-openagent/stargazers) [![GitHub Issues](https://img.shields.io/github/issues/code-yeongyu/oh-my-openagent?color=ff80eb&labelColor=black&style=flat-square)](https://github.com/code-yeongyu/oh-my-openagent/issues) [![License](https://img.shields.io/badge/license-SUL--1.0-white?labelColor=black&style=flat-square)](https://github.com/code-yeongyu/oh-my-openagent/blob/master/LICENSE.md) [![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/code-yeongyu/oh-my-openagent) [![GitHub Release](https://img.shields.io/github/v/release/code-yeongyu/oh-my-openagent?color=369eff&labelColor=black&logo=github&style=flat-square)](https://github.com/code-yeongyu/oh-my-openagent/releases) [![npm downloads](https://img.shields.io/npm/dt/oh-my-openagent?color=ff6b35&labelColor=black&style=flat-square)](https://www.npmjs.com/package/oh-my-openagent) [![GitHub Contributors](https://img.shields.io/github/contributors/code-yeongyu/oh-my-openagent?color=c4f042&labelColor=black&style=flat-square)](https://github.com/code-yeongyu/oh-my-openagent/graphs/contributors) [![GitHub Forks](https://img.shields.io/github/forks/code-yeongyu/oh-my-openagent?color=8ae8ff&labelColor=black&style=flat-square)](https://github.com/code-yeongyu/oh-my-openagent/network/members) [![GitHub Stars](https://img.shields.io/github/stars/code-yeongyu/oh-my-openagent?color=ffcb47&labelColor=black&style=flat-square)](https://github.com/code-yeongyu/oh-my-openagent/stargazers) [![GitHub Issues](https://img.shields.io/github/issues/code-yeongyu/oh-my-openagent?color=ff80eb&labelColor=black&style=flat-square)](https://github.com/code-yeongyu/oh-my-openagent/issues) [![License](https://img.shields.io/badge/license-SUL--1.0-white?labelColor=black&style=flat-square)](https://github.com/code-yeongyu/oh-my-openagent/blob/master/LICENSE.md) [![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/code-yeongyu/oh-my-openagent)
English | 한국어 | 日本語 | 简体中文 | Русский English | 한국어 | 日本語 | 简体中文 | Русский
@@ -54,25 +43,25 @@ English | 한국어 | 日本語 | 简体中文 | Русский
> «Если Claude Code делает за 7 дней то, на что у человека уходит 3 месяца, Sisyphus справляется за 1 час. Он просто работает, пока задача не выполнена. Это дисциплинированный агент.» <br/>— B, исследователь в области квантовых финансов > «Если Claude Code делает за 7 дней то, на что у человека уходит 3 месяца, Sisyphus справляется за 1 час. Он просто работает, пока задача не выполнена. Это дисциплинированный агент.» <br/>— B, исследователь в области квантовых финансов
> «За один день устранил 8000 предупреждений eslint с помощью Oh My Opencode.» <br/>— [Jacob Ferrari](https://x.com/jacobferrari_/status/2003258761952289061) > «За один день устранил 8000 предупреждений eslint с помощью Oh My OpenAgent.» <br/>— [Jacob Ferrari](https://x.com/jacobferrari_/status/2003258761952289061)
> «За ночь конвертировал приложение на tauri в 45k строк в веб-SaaS с помощью Ohmyopencode и ralph loop. Начал с промпта «проинтервьюируй меня», попросил оценки и рекомендации по вопросам. Было удивительно наблюдать за работой и утром проснуться с почти рабочим сайтом!» — [James Hargis](https://x.com/hargabyte/status/2007299688261882202) > «За ночь конвертировал приложение на tauri в 45k строк в веб-SaaS с помощью Ohmyopencode и ralph loop. Начал с промпта «проинтервьюируй меня», попросил оценки и рекомендации по вопросам. Было удивительно наблюдать за работой и утром проснуться с почти рабочим сайтом!» — [James Hargis](https://x.com/hargabyte/status/2007299688261882202)
> «Используйте oh-my-opencode — вы не захотите возвращаться назад.» <br/>— [d0t3ch](https://x.com/d0t3ch/status/2001685618200580503) > «Используйте oh-my-openagent — вы не захотите возвращаться назад.» <br/>— [d0t3ch](https://x.com/d0t3ch/status/2001685618200580503)
> «Пока не могу точно объяснить, почему это так круто, но опыт разработки вышел на совершенно другой уровень.» — [苔硯:こけすずり](https://x.com/kokesuzuri/status/2008532913961529372?s=20) > «Пока не могу точно объяснить, почему это так круто, но опыт разработки вышел на совершенно другой уровень.» — [苔硯:こけすずり](https://x.com/kokesuzuri/status/2008532913961529372?s=20)
> «Экспериментирую с open code, oh my opencode и supermemory этим выходным, чтобы собрать нечто среднее между Minecraft и souls-like.» «Попросил добавить анимации приседания, пока хожу на обеденную прогулку. [Видео]» — [MagiMetal](https://x.com/MagiMetal/status/2005374704178373023) > «Экспериментирую с open code, oh my openagent и supermemory этим выходным, чтобы собрать нечто среднее между Minecraft и souls-like.» «Попросил добавить анимации приседания, пока хожу на обеденную прогулку. [Видео]» — [MagiMetal](https://x.com/MagiMetal/status/2005374704178373023)
> «Ребята, вам нужно включить это в ядро и нанять его. Серьёзно. Это очень, очень, очень хорошо.» <br/>— Henning Kilset > «Ребята, вам нужно включить это в ядро и нанять его. Серьёзно. Это очень, очень, очень хорошо.» <br/>— Henning Kilset
> «Наймите @yeon_gyu_kim, если сможете его уговорить, этот парень революционизировал opencode.» <br/>— [mysticaltech](https://x.com/mysticaltech/status/2001858758608376079) > «Наймите @yeon_gyu_kim, если сможете его уговорить, этот парень революционизировал opencode.» <br/>— [mysticaltech](https://x.com/mysticaltech/status/2001858758608376079)
> «Oh My OpenCode — это что-то с чем-то» — [YouTube — Darren Builds AI](https://www.youtube.com/watch?v=G_Snfh2M41M) > «Oh My OpenAgent — это что-то с чем-то» — [YouTube — Darren Builds AI](https://www.youtube.com/watch?v=G_Snfh2M41M)
------ ------
# Oh My OpenCode # Oh My OpenAgent
Вы жонглируете Claude Code, Codex, случайными OSS-моделями. Настраиваете рабочие процессы. Дебажите агентов. Вы жонглируете Claude Code, Codex, случайными OSS-моделями. Настраиваете рабочие процессы. Дебажите агентов.
@@ -87,7 +76,7 @@ English | 한국어 | 日本語 | 简体中文 | Русский
Скопируйте и вставьте этот промпт в ваш LLM-агент (Claude Code, AmpCode, Cursor и т.д.): Скопируйте и вставьте этот промпт в ваш LLM-агент (Claude Code, AmpCode, Cursor и т.д.):
``` ```
Install and configure oh-my-opencode by following the instructions here: Install and configure oh-my-openagent by following the instructions here:
https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/refs/heads/dev/docs/guide/installation.md https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/refs/heads/dev/docs/guide/installation.md
``` ```
@@ -152,7 +141,7 @@ Read this and tell me why it's not just another boilerplate: https://raw.githubu
**Sisyphus** (`claude-opus-4-6` / **`kimi-k2.5`** / **`glm-5`**) — главный оркестратор. Он планирует, делегирует задачи специалистам и доводит их до завершения с агрессивным параллельным выполнением. Он не останавливается на полпути. **Sisyphus** (`claude-opus-4-6` / **`kimi-k2.5`** / **`glm-5`**) — главный оркестратор. Он планирует, делегирует задачи специалистам и доводит их до завершения с агрессивным параллельным выполнением. Он не останавливается на полпути.
**Hephaestus** (`gpt-5.4`) — автономный глубокий исполнитель. Дайте ему цель, а не рецепт. Он исследует кодовую базу, изучает паттерны и выполняет задачи сквозным образом без лишних подсказок. *Законный Мастер.* **Hephaestus** (`gpt-5.3-codex`) — автономный глубокий исполнитель. Дайте ему цель, а не рецепт. Он исследует кодовую базу, изучает паттерны и выполняет задачи сквозным образом без лишних подсказок. *Законный Мастер.*
**Prometheus** (`claude-opus-4-6` / **`kimi-k2.5`** / **`glm-5`**) — стратегический планировщик. Режим интервью: задаёт вопросы, определяет объём работ и формирует детальный план до того, как написана хотя бы одна строка кода. **Prometheus** (`claude-opus-4-6` / **`kimi-k2.5`** / **`glm-5`**) — стратегический планировщик. Режим интервью: задаёт вопросы, определяет объём работ и формирует детальный план до того, как написана хотя бы одна строка кода.
@@ -160,7 +149,7 @@ Read this and tell me why it's not just another boilerplate: https://raw.githubu
> Anthropic [заблокировал OpenCode из-за нас.](https://x.com/thdxr/status/2010149530486911014) Именно поэтому Hephaestus зовётся «Законным Мастером». Ирония намеренная. > Anthropic [заблокировал OpenCode из-за нас.](https://x.com/thdxr/status/2010149530486911014) Именно поэтому Hephaestus зовётся «Законным Мастером». Ирония намеренная.
> >
> Мы работаем лучше всего на Opus, но Kimi K2.5 + GPT-5.4 уже превосходят ванильный Claude Code. Никакой настройки не требуется. > Мы работаем лучше всего на Opus, но Kimi K2.5 + GPT-5.3 Codex уже превосходят ванильный Claude Code. Никакой настройки не требуется.
### Оркестрация агентов ### Оркестрация агентов
@@ -253,19 +242,19 @@ project/
------ ------
> **Впервые в oh-my-opencode?** Прочитайте **Обзор**, чтобы понять, что у вас есть, или ознакомьтесь с **руководством по оркестрации**, чтобы узнать, как агенты взаимодействуют. > **Впервые в oh-my-openagent?** Прочитайте **Обзор**, чтобы понять, что у вас есть, или ознакомьтесь с **руководством по оркестрации**, чтобы узнать, как агенты взаимодействуют.
## Удаление ## Удаление
Чтобы удалить oh-my-opencode: Чтобы удалить oh-my-openagent:
1. **Удалите плагин из конфига OpenCode** 1. **Удалите плагин из конфига OpenCode**
Отредактируйте `~/.config/opencode/opencode.json` (или `opencode.jsonc`) и уберите `"oh-my-opencode"` из массива `plugin`: Отредактируйте `~/.config/opencode/opencode.json` (или `opencode.jsonc`) и уберите `"oh-my-openagent"` из массива `plugin`:
```bash ```bash
# С помощью jq # С помощью jq
jq '.plugin = [.plugin[] | select(. != "oh-my-opencode")]' \ jq '.plugin = [.plugin[] | select(. != "oh-my-openagent")]' \
~/.config/opencode/opencode.json > /tmp/oc.json && \ ~/.config/opencode/opencode.json > /tmp/oc.json && \
mv /tmp/oc.json ~/.config/opencode/opencode.json mv /tmp/oc.json ~/.config/opencode/opencode.json
``` ```

View File

@@ -4,17 +4,6 @@
> 核心维护者 Q 因受伤,本周 issue/PR 回复和发布可能会延迟。 > 核心维护者 Q 因受伤,本周 issue/PR 回复和发布可能会延迟。
> 感谢你的耐心与支持。 > 感谢你的耐心与支持。
> [!TIP]
> **Building in Public**
>
> 维护者正在使用 Jobdori 实时开发和维护 oh-my-opencode。Jobdori 是基于 OpenClaw 深度定制的 AI 助手。
> 每个功能开发、每次修复、每次 Issue 分类,都在 Discord 上实时进行。
>
> [![Building in Public](./.github/assets/building-in-public.png)](https://discord.gg/PUwSMR9XNk)
>
> [**→ 在 #building-in-public 频道中查看**](https://discord.gg/PUwSMR9XNk)
> [!NOTE] > [!NOTE]
> >
> [![Sisyphus Labs - Sisyphus is the agent that codes like your team.](./.github/assets/sisyphuslabs.png?v=2)](https://sisyphuslabs.ai) > [![Sisyphus Labs - Sisyphus is the agent that codes like your team.](./.github/assets/sisyphuslabs.png?v=2)](https://sisyphuslabs.ai)
@@ -23,18 +12,18 @@
> [!TIP] > [!TIP]
> 加入我们! > 加入我们!
> >
> | [<img alt="Discord link" src="https://img.shields.io/discord/1452487457085063218?color=5865F2&label=discord&labelColor=black&logo=discord&logoColor=white&style=flat-square" width="156px" />](https://discord.gg/PUwSMR9XNk) | 加入我们的 [Discord 社区](https://discord.gg/PUwSMR9XNk),与贡献者及其他 `oh-my-opencode` 用户交流。 | > | [<img alt="Discord link" src="https://img.shields.io/discord/1452487457085063218?color=5865F2&label=discord&labelColor=black&logo=discord&logoColor=white&style=flat-square" width="156px" />](https://discord.gg/PUwSMR9XNk) | 加入我们的 [Discord 社区](https://discord.gg/PUwSMR9XNk),与贡献者及其他 `oh-my-openagent` 用户交流。 |
> | :-----| :----- | > | :-----| :----- |
> | [<img alt="X link" src="https://img.shields.io/badge/Follow-%40justsisyphus-00CED1?style=flat-square&logo=x&labelColor=black" width="156px" />](https://x.com/justsisyphus) | 关于 `oh-my-opencode` 的新闻和更新过去发布在我的 X 账号上。<br /> 因为账号被意外停用,现在由 [@justsisyphus](https://x.com/justsisyphus) 代为发布更新。 | > | [<img alt="X link" src="https://img.shields.io/badge/Follow-%40justsisyphus-00CED1?style=flat-square&logo=x&labelColor=black" width="156px" />](https://x.com/justsisyphus) | 关于 `oh-my-openagent` 的新闻和更新过去发布在我的 X 账号上。<br /> 因为账号被意外停用,现在由 [@justsisyphus](https://x.com/justsisyphus) 代为发布更新。 |
> | [<img alt="GitHub Follow" src="https://img.shields.io/github/followers/code-yeongyu?style=flat-square&logo=github&labelColor=black&color=24292f" width="156px" />](https://github.com/code-yeongyu) | 在 GitHub 上关注 [@code-yeongyu](https://github.com/code-yeongyu) 获取更多项目信息。 | > | [<img alt="GitHub Follow" src="https://img.shields.io/github/followers/code-yeongyu?style=flat-square&logo=github&labelColor=black&color=24292f" width="156px" />](https://github.com/code-yeongyu) | 在 GitHub 上关注 [@code-yeongyu](https://github.com/code-yeongyu) 获取更多项目信息。 |
<!-- <CENTERED SECTION FOR GITHUB DISPLAY> --> <!-- <CENTERED SECTION FOR GITHUB DISPLAY> -->
<div align="center"> <div align="center">
[![Oh My OpenCode](./.github/assets/hero.jpg)](https://github.com/code-yeongyu/oh-my-openagent#oh-my-opencode) [![Oh My OpenAgent](./.github/assets/hero.jpg)](https://github.com/code-yeongyu/oh-my-openagent#oh-my-openagent)
[![Preview](./.github/assets/omo.png)](https://github.com/code-yeongyu/oh-my-openagent#oh-my-opencode) [![Preview](./.github/assets/omo.png)](https://github.com/code-yeongyu/oh-my-openagent#oh-my-openagent)
</div> </div>
@@ -45,7 +34,7 @@
<div align="center"> <div align="center">
[![GitHub Release](https://img.shields.io/github/v/release/code-yeongyu/oh-my-openagent?color=369eff&labelColor=black&logo=github&style=flat-square)](https://github.com/code-yeongyu/oh-my-openagent/releases) [![GitHub Release](https://img.shields.io/github/v/release/code-yeongyu/oh-my-openagent?color=369eff&labelColor=black&logo=github&style=flat-square)](https://github.com/code-yeongyu/oh-my-openagent/releases)
[![npm downloads](https://img.shields.io/npm/dt/oh-my-opencode?color=ff6b35&labelColor=black&style=flat-square)](https://www.npmjs.com/package/oh-my-opencode) [![npm downloads](https://img.shields.io/npm/dt/oh-my-openagent?color=ff6b35&labelColor=black&style=flat-square)](https://www.npmjs.com/package/oh-my-openagent)
[![GitHub Contributors](https://img.shields.io/github/contributors/code-yeongyu/oh-my-openagent?color=c4f042&labelColor=black&style=flat-square)](https://github.com/code-yeongyu/oh-my-openagent/graphs/contributors) [![GitHub Contributors](https://img.shields.io/github/contributors/code-yeongyu/oh-my-openagent?color=c4f042&labelColor=black&style=flat-square)](https://github.com/code-yeongyu/oh-my-openagent/graphs/contributors)
[![GitHub Forks](https://img.shields.io/github/forks/code-yeongyu/oh-my-openagent?color=8ae8ff&labelColor=black&style=flat-square)](https://github.com/code-yeongyu/oh-my-openagent/network/members) [![GitHub Forks](https://img.shields.io/github/forks/code-yeongyu/oh-my-openagent?color=8ae8ff&labelColor=black&style=flat-square)](https://github.com/code-yeongyu/oh-my-openagent/network/members)
[![GitHub Stars](https://img.shields.io/github/stars/code-yeongyu/oh-my-openagent?color=ffcb47&labelColor=black&style=flat-square)](https://github.com/code-yeongyu/oh-my-openagent/stargazers) [![GitHub Stars](https://img.shields.io/github/stars/code-yeongyu/oh-my-openagent?color=ffcb47&labelColor=black&style=flat-square)](https://github.com/code-yeongyu/oh-my-openagent/stargazers)
@@ -65,25 +54,25 @@
> “如果人类需要 3 个月完成的事情 Claude Code 需要 7 天,那么 Sisyphus 只需要 1 小时。它会一直工作直到任务完成。它是一个极度自律的智能体。” <br/>- B, 量化研究员 > “如果人类需要 3 个月完成的事情 Claude Code 需要 7 天,那么 Sisyphus 只需要 1 小时。它会一直工作直到任务完成。它是一个极度自律的智能体。” <br/>- B, 量化研究员
> “用 Oh My Opencode 一天之内解决了 8000 个 eslint 警告。” <br/>- [Jacob Ferrari](https://x.com/jacobferrari_/status/2003258761952289061) > “用 Oh My OpenAgent 一天之内解决了 8000 个 eslint 警告。” <br/>- [Jacob Ferrari](https://x.com/jacobferrari_/status/2003258761952289061)
> “我用 Ohmyopencode 和 ralph loop 花了一晚上的时间,把一个 45k 行代码的 tauri 应用转换成了 SaaS Web 应用。从面试模式开始,让它对我提供的提示词进行提问和提出建议。看着它工作很有趣,今早醒来看到网站基本已经跑起来了,太震撼了!” - [James Hargis](https://x.com/hargabyte/status/2007299688261882202) > “我用 Ohmyopencode 和 ralph loop 花了一晚上的时间,把一个 45k 行代码的 tauri 应用转换成了 SaaS Web 应用。从面试模式开始,让它对我提供的提示词进行提问和提出建议。看着它工作很有趣,今早醒来看到网站基本已经跑起来了,太震撼了!” - [James Hargis](https://x.com/hargabyte/status/2007299688261882202)
> “用 oh-my-opencode 吧,你绝对回不去了。” <br/>- [d0t3ch](https://x.com/d0t3ch/status/2001685618200580503) > “用 oh-my-openagent 吧,你绝对回不去了。” <br/>- [d0t3ch](https://x.com/d0t3ch/status/2001685618200580503)
> “我很难准确描述它到底哪里牛逼,但开发体验已经达到完全不同的维度了。” - [苔硯:こけすずり](https://x.com/kokesuzuri/status/2008532913961529372?s=20) > “我很难准确描述它到底哪里牛逼,但开发体验已经达到完全不同的维度了。” - [苔硯:こけすずり](https://x.com/kokesuzuri/status/2008532913961529372?s=20)
> “这周末我用 open code、oh my opencode 和 supermemory 瞎折腾一个像我的世界/魂系一样的怪物游戏。吃完午饭去散步前,我让它把下蹲动画加进去。[视频]” - [MagiMetal](https://x.com/MagiMetal/status/2005374704178373023) > “这周末我用 open code、oh my openagent 和 supermemory 瞎折腾一个像我的世界/魂系一样的怪物游戏。吃完午饭去散步前,我让它把下蹲动画加进去。[视频]” - [MagiMetal](https://x.com/MagiMetal/status/2005374704178373023)
> “你们真该把这个合并到核心代码里,然后把他招安了。说真的,这东西实在太牛了。” <br/>- Henning Kilset > “你们真该把这个合并到核心代码里,然后把他招安了。说真的,这东西实在太牛了。” <br/>- Henning Kilset
> “如果你们能说服 @yeon_gyu_kim赶紧招募他。这个人彻底改变了 opencode。” <br/>- [mysticaltech](https://x.com/mysticaltech/status/2001858758608376079) > “如果你们能说服 @yeon_gyu_kim赶紧招募他。这个人彻底改变了 opencode。” <br/>- [mysticaltech](https://x.com/mysticaltech/status/2001858758608376079)
> “Oh My OpenCode 简直疯了。” - [YouTube - Darren Builds AI](https://www.youtube.com/watch?v=G_Snfh2M41M) > “Oh My OpenAgent 简直疯了。” - [YouTube - Darren Builds AI](https://www.youtube.com/watch?v=G_Snfh2M41M)
--- ---
# Oh My OpenCode # Oh My OpenAgent
我们最初把这叫做“给 Claude Code 打类固醇”。那是低估了它。 我们最初把这叫做“给 Claude Code 打类固醇”。那是低估了它。
@@ -102,7 +91,7 @@
复制并粘贴以下提示词到你的 LLM Agent (Claude Code, AmpCode, Cursor 等): 复制并粘贴以下提示词到你的 LLM Agent (Claude Code, AmpCode, Cursor 等):
``` ```
Install and configure oh-my-opencode by following the instructions here: Install and configure oh-my-openagent by following the instructions here:
https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/refs/heads/dev/docs/guide/installation.md https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/refs/heads/dev/docs/guide/installation.md
``` ```
@@ -169,7 +158,7 @@ Read this and tell me why it's not just another boilerplate: https://raw.githubu
**Sisyphus** (`claude-opus-4-6` / **`kimi-k2.5`** / **`glm-5`**) 是你的主指挥官。他负责制定计划、分配任务给专家团队,并以极其激进的并行策略推动任务直至完成。他从不半途而废。 **Sisyphus** (`claude-opus-4-6` / **`kimi-k2.5`** / **`glm-5`**) 是你的主指挥官。他负责制定计划、分配任务给专家团队,并以极其激进的并行策略推动任务直至完成。他从不半途而废。
**Hephaestus** (`gpt-5.4`) 是你的自主深度工作者。你只需要给他目标,不要给他具体做法。他会自动探索代码库模式,从头到尾独立执行任务,绝不会中途要你当保姆。*名副其实的正牌工匠。* **Hephaestus** (`gpt-5.3-codex`) 是你的自主深度工作者。你只需要给他目标,不要给他具体做法。他会自动探索代码库模式,从头到尾独立执行任务,绝不会中途要你当保姆。*名副其实的正牌工匠。*
**Prometheus** (`claude-opus-4-6` / **`kimi-k2.5`** / **`glm-5`**) 是你的战略规划师。他通过访谈模式,在动一行代码之前,先通过提问确定范围并构建详尽的执行计划。 **Prometheus** (`claude-opus-4-6` / **`kimi-k2.5`** / **`glm-5`**) 是你的战略规划师。他通过访谈模式,在动一行代码之前,先通过提问确定范围并构建详尽的执行计划。
@@ -177,7 +166,7 @@ Read this and tell me why it's not just another boilerplate: https://raw.githubu
> Anthropic [因为我们屏蔽了 OpenCode](https://x.com/thdxr/status/2010149530486911014)。这就是为什么我们将 Hephaestus 命名为“正牌工匠 (The Legitimate Craftsman)”。这是一个故意的讽刺。 > Anthropic [因为我们屏蔽了 OpenCode](https://x.com/thdxr/status/2010149530486911014)。这就是为什么我们将 Hephaestus 命名为“正牌工匠 (The Legitimate Craftsman)”。这是一个故意的讽刺。
> >
> 我们在 Opus 上运行得最好,但仅仅使用 Kimi K2.5 + GPT-5.4 就足以碾压原版的 Claude Code。完全不需要配置。 > 我们在 Opus 上运行得最好,但仅仅使用 Kimi K2.5 + GPT-5.3 Codex 就足以碾压原版的 Claude Code。完全不需要配置。
### 智能体调度机制 ### 智能体调度机制
@@ -270,19 +259,19 @@ Agent 会自动顺藤摸瓜加载对应的 Context免去了你所有的手动
--- ---
> **第一次用 oh-my-opencode** 阅读 **[概述](docs/guide/overview.md)** 了解你拥有哪些功能,或查看 **[编排指南](docs/guide/orchestration.md)** 了解 Agent 如何协作。 > **第一次用 oh-my-openagent** 阅读 **[概述](docs/guide/overview.md)** 了解你拥有哪些功能,或查看 **[编排指南](docs/guide/orchestration.md)** 了解 Agent 如何协作。
## 如何卸载 (Uninstallation) ## 如何卸载 (Uninstallation)
要移除 oh-my-opencode: 要移除 oh-my-openagent:
1. **从你的 OpenCode 配置文件中去掉插件** 1. **从你的 OpenCode 配置文件中去掉插件**
编辑 `~/.config/opencode/opencode.json` (或 `opencode.jsonc`) ,并把 `"oh-my-opencode"``plugin` 数组中删掉: 编辑 `~/.config/opencode/opencode.json` (或 `opencode.jsonc`) ,并把 `"oh-my-openagent"``plugin` 数组中删掉:
```bash ```bash
# 如果你有 jq 的话 # 如果你有 jq 的话
jq '.plugin = [.plugin[] | select(. != "oh-my-opencode")]' \ jq '.plugin = [.plugin[] | select(. != "oh-my-openagent")]' \
~/.config/opencode/opencode.json > /tmp/oc.json && \ ~/.config/opencode/opencode.json > /tmp/oc.json && \
mv /tmp/oc.json ~/.config/opencode/opencode.json mv /tmp/oc.json ~/.config/opencode/opencode.json
``` ```

File diff suppressed because it is too large Load Diff

View File

@@ -5,7 +5,7 @@
"": { "": {
"name": "hashline-edit-benchmark", "name": "hashline-edit-benchmark",
"dependencies": { "dependencies": {
"@ai-sdk/openai-compatible": "^2.0.35", "@friendliai/ai-provider": "^1.0.9",
"ai": "^6.0.94", "ai": "^6.0.94",
"zod": "^4.1.0", "zod": "^4.1.0",
}, },
@@ -14,11 +14,13 @@
"packages": { "packages": {
"@ai-sdk/gateway": ["@ai-sdk/gateway@3.0.55", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.15", "@vercel/oidc": "3.1.0" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-7xMeTJnCjwRwXKVCiv4Ly4qzWvDuW3+W1WIV0X1EFu6W83d4mEhV9bFArto10MeTw40ewuDjrbrZd21mXKohkw=="], "@ai-sdk/gateway": ["@ai-sdk/gateway@3.0.55", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.15", "@vercel/oidc": "3.1.0" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-7xMeTJnCjwRwXKVCiv4Ly4qzWvDuW3+W1WIV0X1EFu6W83d4mEhV9bFArto10MeTw40ewuDjrbrZd21mXKohkw=="],
"@ai-sdk/openai-compatible": ["@ai-sdk/openai-compatible@2.0.35", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.19" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-g3wA57IAQFb+3j4YuFndgkUdXyRETZVvbfAWM+UX7bZSxA3xjes0v3XKgIdKdekPtDGsh4ZX2byHD0gJIMPfiA=="], "@ai-sdk/openai-compatible": ["@ai-sdk/openai-compatible@2.0.30", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.15" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-iTjumHf1/u4NhjXYFn/aONM2GId3/o7J1Lp5ql8FCbgIMyRwrmanR5xy1S3aaVkfTscuDvLTzWiy1mAbGzK3nQ=="],
"@ai-sdk/provider": ["@ai-sdk/provider@3.0.8", "", { "dependencies": { "json-schema": "^0.4.0" } }, "sha512-oGMAgGoQdBXbZqNG0Ze56CHjDZ1IDYOwGYxYjO5KLSlz5HiNQ9udIXsPZ61VWaHGZ5XW/jyjmr6t2xz2jGVwbQ=="], "@ai-sdk/provider": ["@ai-sdk/provider@3.0.8", "", { "dependencies": { "json-schema": "^0.4.0" } }, "sha512-oGMAgGoQdBXbZqNG0Ze56CHjDZ1IDYOwGYxYjO5KLSlz5HiNQ9udIXsPZ61VWaHGZ5XW/jyjmr6t2xz2jGVwbQ=="],
"@ai-sdk/provider-utils": ["@ai-sdk/provider-utils@4.0.19", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@standard-schema/spec": "^1.1.0", "eventsource-parser": "^3.0.6" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-3eG55CrSWCu2SXlqq2QCsFjo3+E7+Gmg7i/oRVoSZzIodTuDSfLb3MRje67xE9RFea73Zao7Lm4mADIfUETKGg=="], "@ai-sdk/provider-utils": ["@ai-sdk/provider-utils@4.0.15", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@standard-schema/spec": "^1.1.0", "eventsource-parser": "^3.0.6" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-8XiKWbemmCbvNN0CLR9u3PQiet4gtEVIrX4zzLxnCj06AwsEDJwJVBbKrEI4t6qE8XRSIvU2irka0dcpziKW6w=="],
"@friendliai/ai-provider": ["@friendliai/ai-provider@1.1.4", "", { "dependencies": { "@ai-sdk/openai-compatible": "2.0.30", "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.15" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.12" } }, "sha512-9TU4B1QFqPhbkONjI5afCF7Ox4jOqtGg1xw8mA9QHZdtlEbZxU+mBNvMPlI5pU5kPoN6s7wkXmFmxpID+own1A=="],
"@opentelemetry/api": ["@opentelemetry/api@1.9.0", "", {}, "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg=="], "@opentelemetry/api": ["@opentelemetry/api@1.9.0", "", {}, "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg=="],
@@ -33,9 +35,5 @@
"json-schema": ["json-schema@0.4.0", "", {}, "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA=="], "json-schema": ["json-schema@0.4.0", "", {}, "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA=="],
"zod": ["zod@4.3.6", "", {}, "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg=="], "zod": ["zod@4.3.6", "", {}, "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg=="],
"@ai-sdk/gateway/@ai-sdk/provider-utils": ["@ai-sdk/provider-utils@4.0.15", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@standard-schema/spec": "^1.1.0", "eventsource-parser": "^3.0.6" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-8XiKWbemmCbvNN0CLR9u3PQiet4gtEVIrX4zzLxnCj06AwsEDJwJVBbKrEI4t6qE8XRSIvU2irka0dcpziKW6w=="],
"ai/@ai-sdk/provider-utils": ["@ai-sdk/provider-utils@4.0.15", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@standard-schema/spec": "^1.1.0", "eventsource-parser": "^3.0.6" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-8XiKWbemmCbvNN0CLR9u3PQiet4gtEVIrX4zzLxnCj06AwsEDJwJVBbKrEI4t6qE8XRSIvU2irka0dcpziKW6w=="],
} }
} }

View File

@@ -3,17 +3,16 @@ import { readFile, writeFile, mkdir } from "node:fs/promises"
import { join, dirname } from "node:path" import { join, dirname } from "node:path"
import { stepCountIs, streamText, type CoreMessage } from "ai" import { stepCountIs, streamText, type CoreMessage } from "ai"
import { tool } from "ai" import { tool } from "ai"
import { createOpenAICompatible } from "@ai-sdk/openai-compatible" import { createFriendli } from "@friendliai/ai-provider"
import { z } from "zod" import { z } from "zod"
import { formatHashLines } from "../../src/tools/hashline-edit/hash-computation" import { formatHashLines } from "../src/tools/hashline-edit/hash-computation"
import { normalizeHashlineEdits } from "../../src/tools/hashline-edit/normalize-edits" import { normalizeHashlineEdits } from "../src/tools/hashline-edit/normalize-edits"
import { applyHashlineEditsWithReport } from "../../src/tools/hashline-edit/edit-operations" import { applyHashlineEditsWithReport } from "../src/tools/hashline-edit/edit-operations"
import { canonicalizeFileText, restoreFileText } from "../../src/tools/hashline-edit/file-text-canonicalization" import { canonicalizeFileText, restoreFileText } from "../src/tools/hashline-edit/file-text-canonicalization"
import { HASHLINE_EDIT_DESCRIPTION } from "../../src/tools/hashline-edit/tool-description"
const DEFAULT_MODEL = "minimax-m2.5-free" const DEFAULT_MODEL = "MiniMaxAI/MiniMax-M2.5"
const MAX_STEPS = 50 const MAX_STEPS = 50
const sessionId = `hashline-${Date.now()}-${Math.random().toString(36).slice(2, 8)}` const sessionId = `bench-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`
const emit = (event: Record<string, unknown>) => const emit = (event: Record<string, unknown>) =>
console.log(JSON.stringify({ sessionId, timestamp: new Date().toISOString(), ...event })) console.log(JSON.stringify({ sessionId, timestamp: new Date().toISOString(), ...event }))
@@ -34,7 +33,7 @@ function parseArgs(): { prompt: string; modelId: string } {
// --no-translate, --think consumed silently // --no-translate, --think consumed silently
} }
if (!prompt) { if (!prompt) {
console.error("Usage: bun run tests/hashline/headless.ts -p <prompt> [-m <model>]") console.error("Usage: bun run benchmarks/headless.ts -p <prompt> [-m <model>]")
process.exit(1) process.exit(1)
} }
return { prompt, modelId } return { prompt, modelId }
@@ -58,7 +57,7 @@ const readFileTool = tool({
}) })
const editFileTool = tool({ const editFileTool = tool({
description: HASHLINE_EDIT_DESCRIPTION, description: "Edit a file using hashline anchors (LINE#ID format)",
inputSchema: z.object({ inputSchema: z.object({
path: z.string(), path: z.string(),
edits: z.array( edits: z.array(
@@ -117,12 +116,8 @@ const editFileTool = tool({
async function run() { async function run() {
const { prompt, modelId } = parseArgs() const { prompt, modelId } = parseArgs()
const provider = createOpenAICompatible({ const friendli = createFriendli({ apiKey: process.env.FRIENDLI_TOKEN! })
name: "hashline-test", const model = friendli(modelId)
baseURL: process.env.HASHLINE_TEST_BASE_URL ?? "https://quotio.mengmota.com/v1",
apiKey: process.env.HASHLINE_TEST_API_KEY ?? "quotio-local-60A613FE-DB74-40FF-923E-A14151951E5D",
})
const model = provider.chatModel(modelId)
const tools = { read_file: readFileTool, edit_file: editFileTool } const tools = { read_file: readFileTool, edit_file: editFileTool }
emit({ type: "user", content: prompt }) emit({ type: "user", content: prompt })
@@ -130,8 +125,7 @@ async function run() {
const messages: CoreMessage[] = [{ role: "user", content: prompt }] const messages: CoreMessage[] = [{ role: "user", content: prompt }]
const system = const system =
"You are a code editing assistant. Use read_file to read files and edit_file to edit them. " + "You are a code editing assistant. Use read_file to read files and edit_file to edit them. " +
"Always read a file before editing it to get fresh LINE#ID anchors.\n\n" + "Always read a file before editing it to get fresh LINE#ID anchors."
"edit_file tool description:\n" + HASHLINE_EDIT_DESCRIPTION
for (let step = 0; step < MAX_STEPS; step++) { for (let step = 0; step < MAX_STEPS; step++) {
const stream = streamText({ const stream = streamText({
@@ -167,7 +161,6 @@ async function run() {
...(isError ? { error: output } : {}), ...(isError ? { error: output } : {}),
}) })
break break
}
} }
} }
@@ -198,4 +191,3 @@ run()
const elapsed = ((Date.now() - startTime) / 1000).toFixed(2) const elapsed = ((Date.now() - startTime) / 1000).toFixed(2)
console.error(`[headless] Completed in ${elapsed}s`) console.error(`[headless] Completed in ${elapsed}s`)
}) })

18
benchmarks/package.json Normal file
View File

@@ -0,0 +1,18 @@
{
"name": "hashline-edit-benchmark",
"version": "0.1.0",
"private": true,
"type": "module",
"description": "Hashline edit tool benchmark using Vercel AI SDK with FriendliAI provider",
"scripts": {
"bench:basic": "bun run test-edit-ops.ts",
"bench:edge": "bun run test-edge-cases.ts",
"bench:multi": "bun run test-multi-model.ts",
"bench:all": "bun run bench:basic && bun run bench:edge"
},
"dependencies": {
"@friendliai/ai-provider": "^1.0.9",
"ai": "^6.0.94",
"zod": "^4.1.0"
}
}

View File

@@ -14,7 +14,10 @@ import { resolve } from "node:path";
// ── Models ──────────────────────────────────────────────────── // ── Models ────────────────────────────────────────────────────
const MODELS = [ const MODELS = [
{ id: "minimax-m2.5-free", short: "M2.5-Free" }, { id: "MiniMaxAI/MiniMax-M2.5", short: "M2.5" },
// { id: "MiniMaxAI/MiniMax-M2.1", short: "M2.1" }, // masked: slow + timeout-prone
// { id: "zai-org/GLM-5", short: "GLM-5" }, // masked: API 503
{ id: "zai-org/GLM-4.7", short: "GLM-4.7" },
]; ];
// ── CLI args ────────────────────────────────────────────────── // ── CLI args ──────────────────────────────────────────────────

View File

@@ -71,19 +71,9 @@ function getSignalExitCode(signal) {
return 128 + (signalCodeByName[signal] ?? 1); return 128 + (signalCodeByName[signal] ?? 1);
} }
function getPackageBaseName() {
try {
const packageJson = JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf8"));
return packageJson.name || "oh-my-opencode";
} catch {
return "oh-my-opencode";
}
}
function main() { function main() {
const { platform, arch } = process; const { platform, arch } = process;
const libcFamily = getLibcFamily(); const libcFamily = getLibcFamily();
const packageBaseName = getPackageBaseName();
const avx2Supported = supportsAvx2(); const avx2Supported = supportsAvx2();
let packageCandidates; let packageCandidates;
@@ -93,7 +83,6 @@ function main() {
arch, arch,
libcFamily, libcFamily,
preferBaseline: avx2Supported === false, preferBaseline: avx2Supported === false,
packageBaseName,
}); });
} catch (error) { } catch (error) {
console.error(`\noh-my-opencode: ${error.message}\n`); console.error(`\noh-my-opencode: ${error.message}\n`);

View File

@@ -3,11 +3,11 @@
/** /**
* Get the platform-specific package name * Get the platform-specific package name
* @param {{ platform: string, arch: string, libcFamily?: string | null, packageBaseName?: string }} options * @param {{ platform: string, arch: string, libcFamily?: string | null }} options
* @returns {string} Package name like "oh-my-opencode-darwin-arm64" * @returns {string} Package name like "oh-my-opencode-darwin-arm64"
* @throws {Error} If libc cannot be detected on Linux * @throws {Error} If libc cannot be detected on Linux
*/ */
export function getPlatformPackage({ platform, arch, libcFamily, packageBaseName = "oh-my-opencode" }) { export function getPlatformPackage({ platform, arch, libcFamily }) {
let suffix = ""; let suffix = "";
if (platform === "linux") { if (platform === "linux") {
if (libcFamily === null || libcFamily === undefined) { if (libcFamily === null || libcFamily === undefined) {
@@ -23,13 +23,13 @@ export function getPlatformPackage({ platform, arch, libcFamily, packageBaseName
// Map platform names: win32 -> windows (for package name) // Map platform names: win32 -> windows (for package name)
const os = platform === "win32" ? "windows" : platform; const os = platform === "win32" ? "windows" : platform;
return `${packageBaseName}-${os}-${arch}${suffix}`; return `oh-my-opencode-${os}-${arch}${suffix}`;
} }
/** @param {{ platform: string, arch: string, libcFamily?: string | null, preferBaseline?: boolean, packageBaseName?: string }} options */ /** @param {{ platform: string, arch: string, libcFamily?: string | null, preferBaseline?: boolean }} options */
export function getPlatformPackageCandidates({ platform, arch, libcFamily, preferBaseline = false, packageBaseName = "oh-my-opencode" }) { export function getPlatformPackageCandidates({ platform, arch, libcFamily, preferBaseline = false }) {
const primaryPackage = getPlatformPackage({ platform, arch, libcFamily, packageBaseName }); const primaryPackage = getPlatformPackage({ platform, arch, libcFamily });
const baselinePackage = getBaselinePlatformPackage({ platform, arch, libcFamily, packageBaseName }); const baselinePackage = getBaselinePlatformPackage({ platform, arch, libcFamily });
if (!baselinePackage) { if (!baselinePackage) {
return [primaryPackage]; return [primaryPackage];
@@ -38,18 +38,18 @@ export function getPlatformPackageCandidates({ platform, arch, libcFamily, prefe
return preferBaseline ? [baselinePackage, primaryPackage] : [primaryPackage, baselinePackage]; return preferBaseline ? [baselinePackage, primaryPackage] : [primaryPackage, baselinePackage];
} }
/** @param {{ platform: string, arch: string, libcFamily?: string | null, packageBaseName?: string }} options */ /** @param {{ platform: string, arch: string, libcFamily?: string | null }} options */
function getBaselinePlatformPackage({ platform, arch, libcFamily, packageBaseName = "oh-my-opencode" }) { function getBaselinePlatformPackage({ platform, arch, libcFamily }) {
if (arch !== "x64") { if (arch !== "x64") {
return null; return null;
} }
if (platform === "darwin") { if (platform === "darwin") {
return `${packageBaseName}-darwin-x64-baseline`; return "oh-my-opencode-darwin-x64-baseline";
} }
if (platform === "win32") { if (platform === "win32") {
return `${packageBaseName}-windows-x64-baseline`; return "oh-my-opencode-windows-x64-baseline";
} }
if (platform === "linux") { if (platform === "linux") {
@@ -61,10 +61,10 @@ function getBaselinePlatformPackage({ platform, arch, libcFamily, packageBaseNam
} }
if (libcFamily === "musl") { if (libcFamily === "musl") {
return `${packageBaseName}-linux-x64-musl-baseline`; return "oh-my-opencode-linux-x64-musl-baseline";
} }
return `${packageBaseName}-linux-x64-baseline`; return "oh-my-opencode-linux-x64-baseline";
} }
return null; return null;

View File

@@ -190,21 +190,6 @@ describe("getPlatformPackageCandidates", () => {
]); ]);
}); });
test("supports renamed package family via packageBaseName override", () => {
// #given Linux x64 with glibc and renamed package base
const input = { platform: "linux", arch: "x64", libcFamily: "glibc", packageBaseName: "oh-my-openagent" };
// #when getting package candidates
const result = getPlatformPackageCandidates(input);
// #then returns renamed package family candidates
expect(result).toEqual([
"oh-my-openagent-linux-x64",
"oh-my-openagent-linux-x64-baseline",
]);
});
test("returns only one candidate for ARM64", () => { test("returns only one candidate for ARM64", () => {
// #given non-x64 platform // #given non-x64 platform
const input = { platform: "linux", arch: "arm64", libcFamily: "glibc" }; const input = { platform: "linux", arch: "arm64", libcFamily: "glibc" };

View File

@@ -1,88 +0,0 @@
{
"$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-opencode/dev/assets/oh-my-opencode.schema.json",
// Optimized for intensive coding sessions.
// Prioritizes deep implementation agents and fast feedback loops.
"agents": {
// Primary orchestrator: aggressive parallel delegation
"sisyphus": {
"model": "kimi-for-coding/k2p5",
"ultrawork": { "model": "anthropic/claude-opus-4-6", "variant": "max" },
"prompt_append": "Delegate heavily to hephaestus for implementation. Parallelize exploration.",
},
// Heavy lifter: maximum autonomy for coding tasks
"hephaestus": {
"model": "openai/gpt-5.4",
"prompt_append": "You are the primary implementation agent. Own the codebase. Explore, decide, execute. Use LSP and AST-grep aggressively.",
"permission": { "edit": "allow", "bash": { "git": "allow", "test": "allow" } },
},
// Lightweight planner: quick planning for coding tasks
"prometheus": {
"model": "opencode/gpt-5-nano",
"prompt_append": "Keep plans concise. Focus on file structure and key decisions.",
},
// Debugging and architecture
"oracle": { "model": "openai/gpt-5.4", "variant": "high" },
// Fast docs lookup
"librarian": { "model": "github-copilot/grok-code-fast-1" },
// Rapid codebase navigation
"explore": { "model": "github-copilot/grok-code-fast-1" },
// Frontend and visual work
"multimodal-looker": { "model": "google/gemini-3.1-pro" },
// Plan review: minimal overhead
"metis": { "model": "opencode/gpt-5-nano" },
// Code review focus
"momus": { "prompt_append": "Focus on code quality, edge cases, and test coverage." },
// Long-running coding sessions
"atlas": {},
// Quick fixes and small tasks
"sisyphus-junior": { "model": "opencode/gpt-5-nano" },
},
"categories": {
// Trivial changes: fastest possible
"quick": { "model": "opencode/gpt-5-nano" },
// Standard coding tasks: good quality, fast
"unspecified-low": { "model": "anthropic/claude-sonnet-4-6" },
// Complex refactors: best quality
"unspecified-high": { "model": "openai/gpt-5.3-codex" },
// Visual work
"visual-engineering": { "model": "google/gemini-3.1-pro", "variant": "high" },
// Deep autonomous work
"deep": { "model": "openai/gpt-5.3-codex" },
// Architecture decisions
"ultrabrain": { "model": "openai/gpt-5.4", "variant": "xhigh" },
},
// High concurrency for parallel agent work
"background_task": {
"defaultConcurrency": 8,
"providerConcurrency": {
"anthropic": 5,
"openai": 5,
"google": 10,
"github-copilot": 10,
"opencode": 15,
},
},
// Enable all coding aids
"hashline_edit": true,
"experimental": { "aggressive_truncation": true, "task_system": true },
}

View File

@@ -1,71 +0,0 @@
{
"$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-opencode/dev/assets/oh-my-opencode.schema.json",
// Balanced defaults for general development.
// Tuned for reliability across diverse tasks without overspending.
"agents": {
// Main orchestrator: handles delegation and drives tasks to completion
"sisyphus": {
"model": "anthropic/claude-opus-4-6",
"ultrawork": { "model": "anthropic/claude-opus-4-6", "variant": "max" },
},
// Deep autonomous worker: end-to-end implementation
"hephaestus": {
"model": "openai/gpt-5.4",
"prompt_append": "Explore thoroughly, then implement. Prefer small, testable changes.",
},
// Strategic planner: interview mode before execution
"prometheus": {
"prompt_append": "Always interview first. Validate scope before planning.",
},
// Architecture consultant: complex design and debugging
"oracle": { "model": "openai/gpt-5.4", "variant": "high" },
// Documentation and code search
"librarian": { "model": "google/gemini-3-flash" },
// Fast codebase exploration
"explore": { "model": "github-copilot/grok-code-fast-1" },
// Visual tasks: UI/UX, images, diagrams
"multimodal-looker": { "model": "google/gemini-3.1-pro" },
// Plan consultant: reviews and improves plans
"metis": {},
// Critic and reviewer
"momus": {},
// Continuation and long-running task handler
"atlas": {},
// Lightweight task executor for simple jobs
"sisyphus-junior": { "model": "opencode/gpt-5-nano" },
},
"categories": {
"quick": { "model": "opencode/gpt-5-nano" },
"unspecified-low": { "model": "anthropic/claude-sonnet-4-6" },
"unspecified-high": { "model": "anthropic/claude-opus-4-6", "variant": "max" },
"writing": { "model": "google/gemini-3-flash" },
"visual-engineering": { "model": "google/gemini-3.1-pro", "variant": "high" },
"deep": { "model": "openai/gpt-5.3-codex" },
"ultrabrain": { "model": "openai/gpt-5.4", "variant": "xhigh" },
},
// Conservative concurrency for cost control
"background_task": {
"providerConcurrency": {
"anthropic": 3,
"openai": 3,
"google": 5,
"opencode": 10,
},
},
"experimental": { "aggressive_truncation": true },
}

View File

@@ -1,112 +0,0 @@
{
"$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-opencode/dev/assets/oh-my-opencode.schema.json",
// Optimized for strategic planning, architecture, and complex project design.
// Prioritizes deep thinking agents and thorough analysis before execution.
"agents": {
// Orchestrator: delegates to planning agents first
"sisyphus": {
"model": "anthropic/claude-opus-4-6",
"ultrawork": { "model": "anthropic/claude-opus-4-6", "variant": "max" },
"prompt_append": "Always consult prometheus and atlas for planning. Never rush to implementation.",
},
// Implementation: uses planning outputs
"hephaestus": {
"model": "openai/gpt-5.4",
"prompt_append": "Follow established plans precisely. Ask for clarification when plans are ambiguous.",
},
// Primary planner: deep interview mode
"prometheus": {
"model": "anthropic/claude-opus-4-6",
"thinking": { "type": "enabled", "budgetTokens": 160000 },
"prompt_append": "Interview extensively. Question assumptions. Build exhaustive plans with milestones, risks, and contingencies. Use deep & quick agents heavily in parallel for research.",
},
// Architecture consultant
"oracle": {
"model": "openai/gpt-5.4",
"variant": "xhigh",
"thinking": { "type": "enabled", "budgetTokens": 120000 },
},
// Research and documentation
"librarian": { "model": "google/gemini-3-flash" },
// Exploration for research phase
"explore": { "model": "github-copilot/grok-code-fast-1" },
// Visual planning and diagrams
"multimodal-looker": { "model": "google/gemini-3.1-pro", "variant": "high" },
// Plan review and refinement: heavily utilized
"metis": {
"model": "anthropic/claude-opus-4-6",
"prompt_append": "Critically evaluate plans. Identify gaps, risks, and improvements. Be thorough.",
},
// Critic: challenges assumptions
"momus": {
"model": "openai/gpt-5.4",
"prompt_append": "Challenge all assumptions in plans. Look for edge cases, failure modes, and overlooked requirements.",
},
// Long-running planning sessions
"atlas": {
"prompt_append": "Preserve context across long planning sessions. Track evolving decisions.",
},
// Quick research tasks
"sisyphus-junior": { "model": "opencode/gpt-5-nano" },
},
"categories": {
"quick": { "model": "opencode/gpt-5-nano" },
"unspecified-low": { "model": "anthropic/claude-sonnet-4-6" },
// High-effort planning tasks: maximum reasoning
"unspecified-high": {
"model": "openai/gpt-5.4",
"variant": "xhigh",
},
// Documentation from plans
"writing": { "model": "google/gemini-3-flash" },
// Visual architecture
"visual-engineering": { "model": "google/gemini-3.1-pro", "variant": "high" },
// Deep research and analysis
"deep": { "model": "openai/gpt-5.3-codex" },
// Strategic reasoning
"ultrabrain": { "model": "openai/gpt-5.4", "variant": "xhigh" },
// Creative approaches to problems
"artistry": { "model": "google/gemini-3.1-pro", "variant": "high" },
},
// Moderate concurrency: planning is sequential by nature
"background_task": {
"defaultConcurrency": 5,
"staleTimeoutMs": 300000,
"providerConcurrency": {
"anthropic": 3,
"openai": 3,
},
"modelConcurrency": {
"anthropic/claude-opus-4-6": 2,
"openai/gpt-5.4": 2,
},
},
"sisyphus_agent": {
"planner_enabled": true,
"replace_plan": true,
},
"experimental": { "aggressive_truncation": true },
}

View File

@@ -27,7 +27,7 @@ Using Sisyphus with older GPT models would be like taking your best project mana
Hephaestus is the developer who stays in their room coding all day. Doesn't talk much. Might seem socially awkward. But give them a hard technical problem and they'll emerge three hours later with a solution nobody else could have found. Hephaestus is the developer who stays in their room coding all day. Doesn't talk much. Might seem socially awkward. But give them a hard technical problem and they'll emerge three hours later with a solution nobody else could have found.
**This is why Hephaestus uses GPT-5.4.** GPT-5.4 is built for exactly this: **This is why Hephaestus uses GPT-5.3 Codex.** Codex is built for exactly this:
- Deep, autonomous exploration without hand-holding - Deep, autonomous exploration without hand-holding
- Multi-file reasoning across complex codebases - Multi-file reasoning across complex codebases
@@ -64,8 +64,8 @@ These agents have Claude-optimized prompts — long, detailed, mechanics-driven.
| Agent | Role | Fallback Chain | Notes | | Agent | Role | Fallback Chain | Notes |
| ------------ | ----------------- | -------------------------------------- | ------------------------------------------------------------------------------------------------- | | ------------ | ----------------- | -------------------------------------- | ------------------------------------------------------------------------------------------------- |
| **Sisyphus** | Main orchestrator | anthropic\|github-copilot\|opencode/claude-opus-4-6 (max) → opencode-go/kimi-k2.5 → kimi-for-coding/k2p5 → opencode\|moonshotai\|moonshotai-cn\|firmware\|ollama-cloud\|aihubmix/kimi-k2.5 → openai\|github-copilot\|opencode/gpt-5.4 (medium) → zai-coding-plan\|opencode/glm-5 → opencode/big-pickle | Exact runtime chain from `src/shared/model-requirements.ts`. | | **Sisyphus** | Main orchestrator | Claude Opus → opencode-go/kimi-k2.5 → K2P5 → GPT-5.4 → GLM-5 → Big Pickle | Claude-family first. GPT-5.4 has dedicated prompt support. Kimi/GLM as intermediate fallbacks. |
| **Metis** | Plan gap analyzer | anthropic\|github-copilot\|opencode/claude-opus-4-6 (max) → openai\|github-copilot\|opencode/gpt-5.4 (high) → opencode-go/glm-5 → kimi-for-coding/k2p5 | Exact runtime chain from `src/shared/model-requirements.ts`. | | **Metis** | Plan gap analyzer | Claude Opus → opencode-go/glm-5 → K2P5 | Claude preferred. Uses opencode-go for reliable GLM-5 access. |
### Dual-Prompt Agents → Claude preferred, GPT supported ### Dual-Prompt Agents → Claude preferred, GPT supported
@@ -73,8 +73,8 @@ These agents ship separate prompts for Claude and GPT families. They auto-detect
| Agent | Role | Fallback Chain | Notes | | Agent | Role | Fallback Chain | Notes |
| -------------- | ----------------- | -------------------------------------- | -------------------------------------------------------------------- | | -------------- | ----------------- | -------------------------------------- | -------------------------------------------------------------------- |
| **Prometheus** | Strategic planner | anthropic\|github-copilot\|opencode/claude-opus-4-6 (max) → openai\|github-copilot\|opencode/gpt-5.4 (high) → opencode-go/glm-5 → google\|github-copilot\|opencode/gemini-3.1-pro | Exact runtime chain from `src/shared/model-requirements.ts`. | | **Prometheus** | Strategic planner | Claude Opus → GPT-5.4 → opencode-go/glm-5 → Gemini 3.1 Pro | Interview-mode planning. GPT prompt is compact and principle-driven. |
| **Atlas** | Todo orchestrator | anthropic\|github-copilot\|opencode/claude-sonnet-4-6 → opencode-go/kimi-k2.5 → openai\|github-copilot\|opencode/gpt-5.4 (medium) → opencode-go/minimax-m2.7 | Exact runtime chain from `src/shared/model-requirements.ts`. | | **Atlas** | Todo orchestrator | Claude Sonnet → opencode-go/kimi-k2.5 | Claude first, opencode-go as the current fallback path. |
### Deep Specialists → GPT ### Deep Specialists → GPT
@@ -82,9 +82,9 @@ These agents are built for GPT's principle-driven style. Their prompts assume au
| Agent | Role | Fallback Chain | Notes | | Agent | Role | Fallback Chain | Notes |
| -------------- | ----------------------- | -------------------------------------- | ------------------------------------------------ | | -------------- | ----------------------- | -------------------------------------- | ------------------------------------------------ |
| **Hephaestus** | Autonomous deep worker | GPT-5.4 (medium) | Requires a GPT-capable provider. The craftsman. | | **Hephaestus** | Autonomous deep worker | GPT-5.3 Codex only | No fallback. Requires GPT access. The craftsman. |
| **Oracle** | Architecture consultant | openai\|github-copilot\|opencode/gpt-5.4 (high) → google\|github-copilot\|opencode/gemini-3.1-pro (high) → anthropic\|github-copilot\|opencode/claude-opus-4-6 (max) → opencode-go/glm-5 | Exact runtime chain from `src/shared/model-requirements.ts`. | | **Oracle** | Architecture consultant | GPT-5.4 → Gemini 3.1 Pro → Claude Opus | Read-only high-IQ consultation. |
| **Momus** | Ruthless reviewer | openai\|github-copilot\|opencode/gpt-5.4 (xhigh) → anthropic\|github-copilot\|opencode/claude-opus-4-6 (max) → google\|github-copilot\|opencode/gemini-3.1-pro (high) → opencode-go/glm-5 | Exact runtime chain from `src/shared/model-requirements.ts`. | | **Momus** | Ruthless reviewer | GPT-5.4 → Claude Opus → Gemini 3.1 Pro | Verification and plan review. |
### Utility Runners → Speed over Intelligence ### Utility Runners → Speed over Intelligence
@@ -92,10 +92,9 @@ These agents do grep, search, and retrieval. They intentionally use the fastest,
| Agent | Role | Fallback Chain | Notes | | Agent | Role | Fallback Chain | Notes |
| --------------------- | ------------------ | ---------------------------------------------- | ----------------------------------------------------- | | --------------------- | ------------------ | ---------------------------------------------- | ----------------------------------------------------- |
| **Explore** | Fast codebase grep | github-copilot\|xai/grok-code-fast-1 → opencode-go/minimax-m2.7-highspeed → opencode/minimax-m2.7 → anthropic\|opencode/claude-haiku-4-5 → opencode/gpt-5-nano | Exact runtime chain from `src/shared/model-requirements.ts`. | | **Explore** | Fast codebase grep | Grok Code Fast → opencode-go/minimax-m2.5 → MiniMax Free → Haiku → GPT-5-Nano | Speed is everything. Fire 10 in parallel. |
| **Librarian** | Docs/code search | opencode-go/minimax-m2.7opencode/minimax-m2.7-highspeedanthropic\|opencode/claude-haiku-4-5 → opencode/gpt-5-nano | Exact runtime chain from `src/shared/model-requirements.ts`. | | **Librarian** | Docs/code search | opencode-go/minimax-m2.5MiniMax Free → Haiku → GPT-5-Nano | Doc retrieval doesn't need deep reasoning. |
| **Multimodal Looker** | Vision/screenshots | openai\|opencode/gpt-5.4 (medium) → opencode-go/kimi-k2.5 → zai-coding-plan/glm-4.6v → openai\|github-copilot\|opencode/gpt-5-nano | Exact runtime chain from `src/shared/model-requirements.ts`. | | **Multimodal Looker** | Vision/screenshots | GPT-5.4 → opencode-go/kimi-k2.5 → GLM-4.6v → GPT-5-Nano | Uses the first available multimodal-capable fallback. |
| **Sisyphus-Junior** | Category executor | anthropic\|github-copilot\|opencode/claude-sonnet-4-6 → opencode-go/kimi-k2.5 → openai\|github-copilot\|opencode/gpt-5.4 (medium) → opencode-go/minimax-m2.7 → opencode/big-pickle | Exact runtime chain from `src/shared/model-requirements.ts`. |
--- ---
@@ -119,9 +118,9 @@ Principle-driven, explicit reasoning, deep technical capability. Best for agents
| Model | Strengths | | Model | Strengths |
| ----------------- | ----------------------------------------------------------------------------------------------- | | ----------------- | ----------------------------------------------------------------------------------------------- |
| **GPT-5.3 Codex** | Deep coding powerhouse. Autonomous exploration. Still available for deep category and explicit overrides. | | **GPT-5.3 Codex** | Deep coding powerhouse. Autonomous exploration. Required for Hephaestus. |
| **GPT-5.4** | High intelligence, strategic reasoning. Default for Oracle, Momus, and a key fallback for Prometheus / Atlas. Uses xhigh variant for Momus. | | **GPT-5.4** | High intelligence, strategic reasoning. Default for Oracle. |
| **GPT-5.4 Mini** | Fast + strong reasoning. Good for lightweight autonomous tasks. Default for quick category. | | **GPT-5.4** | Strong principle-driven reasoning. Default for Momus and a key fallback for Prometheus / Atlas. |
| **GPT-5-Nano** | Ultra-cheap, fast. Good for simple utility tasks. | | **GPT-5-Nano** | Ultra-cheap, fast. Good for simple utility tasks. |
### Other Models ### Other Models
@@ -131,8 +130,7 @@ Principle-driven, explicit reasoning, deep technical capability. Best for agents
| **Gemini 3.1 Pro** | Excels at visual/frontend tasks. Different reasoning style. Default for `visual-engineering` and `artistry`. | | **Gemini 3.1 Pro** | Excels at visual/frontend tasks. Different reasoning style. Default for `visual-engineering` and `artistry`. |
| **Gemini 3 Flash** | Fast. Good for doc search and light tasks. | | **Gemini 3 Flash** | Fast. Good for doc search and light tasks. |
| **Grok Code Fast 1** | Blazing fast code grep. Default for Explore agent. | | **Grok Code Fast 1** | Blazing fast code grep. Default for Explore agent. |
| **MiniMax M2.7** | Fast and smart. Used in OpenCode Go and OpenCode Zen utility fallback chains. | | **MiniMax M2.5** | Fast and smart. Good for utility tasks and search/retrieval. |
| **MiniMax M2.7 Highspeed** | High-speed OpenCode catalog entry used in utility fallback chains that prefer the fastest available MiniMax path. |
### OpenCode Go ### OpenCode Go
@@ -144,12 +142,11 @@ A premium subscription tier ($10/month) that provides reliable access to Chinese
| ------------------------ | --------------------------------------------------------------------- | | ------------------------ | --------------------------------------------------------------------- |
| **opencode-go/kimi-k2.5** | Vision-capable, Claude-like reasoning. Used by Sisyphus, Atlas, Sisyphus-Junior, Multimodal Looker. | | **opencode-go/kimi-k2.5** | Vision-capable, Claude-like reasoning. Used by Sisyphus, Atlas, Sisyphus-Junior, Multimodal Looker. |
| **opencode-go/glm-5** | Text-only orchestration model. Used by Oracle, Prometheus, Metis, Momus. | | **opencode-go/glm-5** | Text-only orchestration model. Used by Oracle, Prometheus, Metis, Momus. |
| **opencode-go/minimax-m2.7** | Ultra-cheap, fast responses. Used by Librarian, Atlas, and Sisyphus-Junior for utility work. | | **opencode-go/minimax-m2.5** | Ultra-cheap, fast responses. Used by Librarian, Explore for utility work. |
| **opencode-go/minimax-m2.7-highspeed** | Even faster OpenCode Go MiniMax entry used by Explore when the high-speed catalog entry is available. |
**When It Gets Used:** **When It Gets Used:**
OpenCode Go models appear throughout the fallback chains as intermediate options. Depending on the agent, they can sit before GPT, after GPT, or act as the last structured-model fallback before cheaper utility paths. OpenCode Go models appear in fallback chains as intermediate options. They bridge the gap between premium Claude access and free-tier alternatives. The system tries OpenCode Go models before falling back to free tiers (MiniMax Free, Big Pickle) or GPT alternatives.
**Go-Only Scenarios:** **Go-Only Scenarios:**
@@ -157,7 +154,7 @@ Some model identifiers like `k2p5` (paid Kimi K2.5) and `glm-5` may only be avai
### About Free-Tier Fallbacks ### About Free-Tier Fallbacks
You may see model names like `kimi-k2.5-free`, `minimax-m2.7`, `minimax-m2.7-highspeed`, or `big-pickle` (GLM 4.6) in the source code or logs. These are provider-specific or speed-optimized entries in fallback chains. You may see model names like `kimi-k2.5-free`, `minimax-m2.5-free`, or `big-pickle` (GLM 4.6) in the source code or logs. These are free-tier versions of the same model families, served through the OpenCode Zen provider. They exist as lower-priority entries in fallback chains.
You don't need to configure them. The system includes them so it degrades gracefully when you don't have every paid subscription. If you have the paid version, the paid version is always preferred. You don't need to configure them. The system includes them so it degrades gracefully when you don't have every paid subscription. If you have the paid version, the paid version is always preferred.
@@ -169,14 +166,14 @@ When agents delegate work, they don't pick a model name — they pick a **catego
| Category | When Used | Fallback Chain | | Category | When Used | Fallback Chain |
| -------------------- | -------------------------- | -------------------------------------------- | | -------------------- | -------------------------- | -------------------------------------------- |
| `visual-engineering` | Frontend, UI, CSS, design | google\|github-copilot\|opencode/gemini-3.1-pro (high) → zai-coding-plan\|opencode/glm-5 → anthropic\|github-copilot\|opencode/claude-opus-4-6 (max) → opencode-go/glm-5 → kimi-for-coding/k2p5 | | `visual-engineering` | Frontend, UI, CSS, design | Gemini 3.1 Pro → GLM 5 → Claude Opus |
| `ultrabrain` | Maximum reasoning needed | openai\|opencode/gpt-5.4 (xhigh) → google\|github-copilot\|opencode/gemini-3.1-pro (high) → anthropic\|github-copilot\|opencode/claude-opus-4-6 (max) → opencode-go/glm-5 | | `ultrabrain` | Maximum reasoning needed | GPT-5.4 → Gemini 3.1 Pro → Claude Opus |
| `deep` | Deep coding, complex logic | openai\|opencode/gpt-5.3-codex (medium) → anthropic\|github-copilot\|opencode/claude-opus-4-6 (max) → google\|github-copilot\|opencode/gemini-3.1-pro (high) | | `deep` | Deep coding, complex logic | GPT-5.3 Codex → Claude Opus → Gemini 3.1 Pro |
| `artistry` | Creative, novel approaches | google\|github-copilot\|opencode/gemini-3.1-pro (high) → anthropic\|github-copilot\|opencode/claude-opus-4-6 (max) → openai\|github-copilot\|opencode/gpt-5.4 | | `artistry` | Creative, novel approaches | Gemini 3.1 Pro → Claude Opus → GPT-5.4 |
| `quick` | Simple, fast tasks | openai\|github-copilot\|opencode/gpt-5.4-mini → anthropic\|github-copilot\|opencode/claude-haiku-4-5 → google\|github-copilot\|opencode/gemini-3-flash → opencode-go/minimax-m2.7 → opencode/gpt-5-nano | | `quick` | Simple, fast tasks | Claude Haiku → Gemini Flash → GPT-5-Nano |
| `unspecified-high` | General complex work | anthropic\|github-copilot\|opencode/claude-opus-4-6 (max) → openai\|github-copilot\|opencode/gpt-5.4 (high) → zai-coding-plan\|opencode/glm-5 → kimi-for-coding/k2p5 → opencode-go/glm-5 → opencode/kimi-k2.5 → opencode\|moonshotai\|moonshotai-cn\|firmware\|ollama-cloud\|aihubmix/kimi-k2.5 | | `unspecified-high` | General complex work | Claude Opus → GPT-5.4 (high) → GLM 5 → K2P5 |
| `unspecified-low` | General standard work | anthropic\|github-copilot\|opencode/claude-sonnet-4-6 → openai\|opencode/gpt-5.3-codex (medium) → opencode-go/kimi-k2.5 → google\|github-copilot\|opencode/gemini-3-flash → opencode-go/minimax-m2.7 | | `unspecified-low` | General standard work | Claude Sonnet → GPT-5.3 Codex → Gemini Flash |
| `writing` | Text, docs, prose | google\|github-copilot\|opencode/gemini-3-flash → opencode-go/kimi-k2.5 → anthropic\|github-copilot\|opencode/claude-sonnet-4-6 → opencode-go/minimax-m2.7 | | `writing` | Text, docs, prose | Gemini Flash → Claude Sonnet |
See the [Orchestration System Guide](./orchestration.md) for how agents dispatch tasks to categories. See the [Orchestration System Guide](./orchestration.md) for how agents dispatch tasks to categories.
@@ -256,46 +253,12 @@ Run `opencode models` to see available models, `opencode auth login` to authenti
### How Model Resolution Works ### How Model Resolution Works
Each agent has a fallback chain. The system tries models in priority order until it finds one available through your connected providers. You don't need to configure providers per model. Just authenticate (`opencode auth login`) and the system figures out which models are available and where. Each agent has a fallback chain. The system tries models in priority order until it finds one available through your connected providers. You don't need to configure providers per model — just authenticate (`opencode auth login`) and the system figures out which models are available and where.
Core-agent tab cycling is deterministic via injected runtime order field. The fixed priority order is Sisyphus (order: 1), Hephaestus (order: 2), Prometheus (order: 3), and Atlas (order: 4), then the remaining agents follow.
Your explicit configuration always wins. If you set a specific model for an agent, that choice takes precedence even when resolution data is cold.
Variant and `reasoningEffort` overrides are normalized to model-supported values, so cross-provider overrides degrade gracefully instead of failing hard.
Model capabilities are models.dev-backed, with a refreshable cache and capability diagnostics. Use `bunx oh-my-opencode refresh-model-capabilities` to update the cache, or configure `model_capabilities.auto_refresh_on_start` to refresh at startup.
To see which models your agents will actually use, run `bunx oh-my-opencode doctor`. This shows effective model resolution based on your current authentication and config.
``` ```
Agent Request → User Override (if configured) → Fallback Chain → System Default Agent Request → User Override (if configured) → Fallback Chain → System Default
``` ```
### File-Based Prompts
You can load agent system prompts from external files using `file://` URLs in the `prompt` field, or append additional content with `prompt_append`. The `prompt_append` field also works on categories.
```jsonc
{
"agents": {
"sisyphus": {
"prompt": "file:///path/to/custom-prompt.md"
},
"oracle": {
"prompt_append": "file:///path/to/additional-context.md"
}
},
"categories": {
"deep": {
"prompt_append": "file:///path/to/deep-category-append.md"
}
}
}
```
The file content is loaded at runtime and injected into the agent's system prompt. Supports `~` expansion for home directory and relative `file://` paths.
--- ---
## See Also ## See Also

View File

@@ -5,7 +5,7 @@
Paste this into your llm agent session: Paste this into your llm agent session:
``` ```
Install and configure oh-my-opencode by following the instructions here: Install and configure oh-my-openagent by following the instructions here:
https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/refs/heads/dev/docs/guide/installation.md https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/refs/heads/dev/docs/guide/installation.md
``` ```
@@ -14,8 +14,8 @@ https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/refs/heads/dev/do
Run the interactive installer: Run the interactive installer:
```bash ```bash
bunx oh-my-opencode install # recommended bunx oh-my-openagent install # recommended
npx oh-my-opencode install # alternative npx oh-my-openagent install # alternative
``` ```
> **Note**: The CLI ships with standalone binaries for all major platforms. No runtime (Bun/Node.js) is required for CLI execution after installation. > **Note**: The CLI ships with standalone binaries for all major platforms. No runtime (Bun/Node.js) is required for CLI execution after installation.
@@ -26,8 +26,6 @@ Follow the prompts to configure your Claude, ChatGPT, and Gemini subscriptions.
After you install it, you can read this [overview guide](./overview.md) to understand more. After you install it, you can read this [overview guide](./overview.md) to understand more.
The published package and local binary are still `oh-my-opencode`. Inside `opencode.json`, the compatibility layer now prefers the plugin entry `oh-my-openagent`, while legacy `oh-my-opencode` entries still load with a warning. Plugin config loading recognizes both `oh-my-openagent.json[c]` and `oh-my-opencode.json[c]` during the transition. If you see a "Using legacy package name" warning from `bunx oh-my-opencode doctor`, update your `opencode.json` plugin entry from `"oh-my-opencode"` to `"oh-my-openagent"`.
## For LLM Agents ## For LLM Agents
> **IMPORTANT: Use `curl` to fetch this file, NOT WebFetch.** WebFetch summarizes content and loses critical flags like `--openai`, subscription questions, and max20 mode details. Always use: > **IMPORTANT: Use `curl` to fetch this file, NOT WebFetch.** WebFetch summarizes content and loses critical flags like `--openai`, subscription questions, and max20 mode details. Always use:
@@ -36,7 +34,7 @@ The published package and local binary are still `oh-my-opencode`. Inside `openc
> curl -fsSL https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/refs/heads/dev/docs/guide/installation.md > curl -fsSL https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/refs/heads/dev/docs/guide/installation.md
> ``` > ```
If you're an LLM Agent helping set up oh-my-opencode, welcome. You'll help your user install the harness and verify the rename-compat setup cleanly. Tell user this with greetings, with text 'oMoMoMoMo...' If you're an LLM Agent helping set up oh-my-openagent, Welcome! You'll now help your user to install the best agent harness, OhMyOpenAgent. Tell user this with greetings, with test 'oMoMoMoMo...'
follow these steps: follow these steps:
@@ -71,11 +69,11 @@ Ask the user these questions to determine CLI options:
- If **no**`--zai-coding-plan=no` (default) - If **no**`--zai-coding-plan=no` (default)
7. **Do you have an OpenCode Go subscription?** 7. **Do you have an OpenCode Go subscription?**
- OpenCode Go is a $10/month subscription providing access to GLM-5, Kimi K2.5, and MiniMax M2.7 models - OpenCode Go is a $10/month subscription providing access to GLM-5, Kimi K2.5, and MiniMax M2.5 models
- If **yes**`--opencode-go=yes` - If **yes**`--opencode-go=yes`
- If **no**`--opencode-go=no` (default) - If **no**`--opencode-go=no` (default)
**Provider selection is agent-specific.** The installer and runtime do not use one single global provider priority. Each agent resolves against its own fallback chain. **Provider Priority**: Native (anthropic/, openai/, google/) > Kimi for Coding > GitHub Copilot > OpenCode Go > OpenCode Zen > Z.ai Coding Plan
MUST STRONGLY WARNING, WHEN USER SAID THEY DON'T HAVE CLAUDE SUBSCRIPTION, SISYPHUS AGENT MIGHT NOT WORK IDEALLY. MUST STRONGLY WARNING, WHEN USER SAID THEY DON'T HAVE CLAUDE SUBSCRIPTION, SISYPHUS AGENT MIGHT NOT WORK IDEALLY.
@@ -98,19 +96,19 @@ Spawn a subagent to handle installation and report back - to save context.
Based on user's answers, run the CLI installer with appropriate flags: Based on user's answers, run the CLI installer with appropriate flags:
```bash ```bash
bunx oh-my-opencode install --no-tui --claude=<yes|no|max20> --gemini=<yes|no> --copilot=<yes|no> [--openai=<yes|no>] [--opencode-go=<yes|no>] [--opencode-zen=<yes|no>] [--zai-coding-plan=<yes|no>] bunx oh-my-openagent install --no-tui --claude=<yes|no|max20> --gemini=<yes|no> --copilot=<yes|no> [--openai=<yes|no>] [--opencode-go=<yes|no>] [--opencode-zen=<yes|no>] [--zai-coding-plan=<yes|no>]
``` ```
**Examples:** **Examples:**
- User has all native subscriptions: `bunx oh-my-opencode install --no-tui --claude=max20 --openai=yes --gemini=yes --copilot=no` - User has all native subscriptions: `bunx oh-my-openagent install --no-tui --claude=max20 --openai=yes --gemini=yes --copilot=no`
- User has only Claude: `bunx oh-my-opencode install --no-tui --claude=yes --gemini=no --copilot=no` - User has only Claude: `bunx oh-my-openagent install --no-tui --claude=yes --gemini=no --copilot=no`
- User has Claude + OpenAI: `bunx oh-my-opencode install --no-tui --claude=yes --openai=yes --gemini=no --copilot=no` - User has Claude + OpenAI: `bunx oh-my-openagent install --no-tui --claude=yes --openai=yes --gemini=no --copilot=no`
- User has only GitHub Copilot: `bunx oh-my-opencode install --no-tui --claude=no --gemini=no --copilot=yes` - User has only GitHub Copilot: `bunx oh-my-openagent install --no-tui --claude=no --gemini=no --copilot=yes`
- User has Z.ai for Librarian: `bunx oh-my-opencode install --no-tui --claude=yes --gemini=no --copilot=no --zai-coding-plan=yes` - User has Z.ai for Librarian: `bunx oh-my-openagent install --no-tui --claude=yes --gemini=no --copilot=no --zai-coding-plan=yes`
- User has only OpenCode Zen: `bunx oh-my-opencode install --no-tui --claude=no --gemini=no --copilot=no --opencode-zen=yes` - User has only OpenCode Zen: `bunx oh-my-openagent install --no-tui --claude=no --gemini=no --copilot=no --opencode-zen=yes`
- User has OpenCode Go only: `bunx oh-my-opencode install --no-tui --claude=no --openai=no --gemini=no --copilot=no --opencode-go=yes` - User has OpenCode Go only: `bunx oh-my-openagent install --no-tui --claude=no --openai=no --gemini=no --copilot=no --opencode-go=yes`
- User has no subscriptions: `bunx oh-my-opencode install --no-tui --claude=no --gemini=no --copilot=no` - User has no subscriptions: `bunx oh-my-openagent install --no-tui --claude=no --gemini=no --copilot=no`
The CLI will: The CLI will:
@@ -122,17 +120,8 @@ The CLI will:
```bash ```bash
opencode --version # Should be 1.0.150 or higher opencode --version # Should be 1.0.150 or higher
cat ~/.config/opencode/opencode.json # Should contain "oh-my-openagent" in plugin array, or the legacy "oh-my-opencode" entry while you are still migrating cat ~/.config/opencode/opencode.json # Should contain "oh-my-openagent" in plugin array
``` ```
#### Run Doctor Verification
After installation, verify everything is working correctly:
```bash
bunx oh-my-opencode doctor
```
This checks system, config, tools, and model resolution, including legacy package name warnings and compatibility-fallback diagnostics.
### Step 4: Configure Authentication ### Step 4: Configure Authentication
@@ -165,9 +154,9 @@ First, add the opencode-antigravity-auth plugin:
You'll also need full model settings in `opencode.json`. You'll also need full model settings in `opencode.json`.
Read the [opencode-antigravity-auth documentation](https://github.com/NoeFabris/opencode-antigravity-auth), copy the full model configuration from the README, and merge carefully to avoid breaking the user's existing setup. The plugin now uses a **variant system** — models like `antigravity-gemini-3-pro` support `low`/`high` variants instead of separate `-low`/`-high` model entries. Read the [opencode-antigravity-auth documentation](https://github.com/NoeFabris/opencode-antigravity-auth), copy the full model configuration from the README, and merge carefully to avoid breaking the user's existing setup. The plugin now uses a **variant system** — models like `antigravity-gemini-3-pro` support `low`/`high` variants instead of separate `-low`/`-high` model entries.
##### Plugin config model override ##### oh-my-openagent Agent Model Override
The `opencode-antigravity-auth` plugin uses different model names than the built-in Google auth. Override the agent models in your plugin config file. Existing installs still commonly use `oh-my-opencode.json` or `.opencode/oh-my-opencode.json`, while the compatibility layer also recognizes `oh-my-openagent.json[c]`. The `opencode-antigravity-auth` plugin uses different model names than the built-in Google auth. Override the agent models in `oh-my-opencode.json` (or `.opencode/oh-my-opencode.json`):
```json ```json
{ {
@@ -187,7 +176,7 @@ The `opencode-antigravity-auth` plugin uses different model names than the built
**Available models (Gemini CLI quota)**: **Available models (Gemini CLI quota)**:
- `google/gemini-2.5-flash`, `google/gemini-2.5-pro`, `google/gemini-3-flash-preview`, `google/gemini-3.1-pro-preview` - `google/gemini-2.5-flash`, `google/gemini-2.5-pro`, `google/gemini-3-flash-preview`, `google/gemini-3-pro-preview`
> **Note**: Legacy tier-suffixed names like `google/antigravity-gemini-3-pro-high` still work but variants are recommended. Use `--variant=high` with the base model name instead. > **Note**: Legacy tier-suffixed names like `google/antigravity-gemini-3-pro-high` still work but variants are recommended. Use `--variant=high` with the base model name instead.
@@ -212,16 +201,16 @@ GitHub Copilot is supported as a **fallback provider** when native providers are
##### Model Mappings ##### Model Mappings
When GitHub Copilot is the best available provider, install-time defaults are agent-specific. Common examples are: When GitHub Copilot is the best available provider, oh-my-openagent uses these model assignments:
| Agent | Model | | Agent | Model |
| ------------- | ---------------------------------- | | ------------- | --------------------------------- |
| **Sisyphus** | `github-copilot/claude-opus-4.6` | | **Sisyphus** | `github-copilot/claude-opus-4-6` |
| **Oracle** | `github-copilot/gpt-5.4` | | **Oracle** | `github-copilot/gpt-5.4` |
| **Explore** | `github-copilot/grok-code-fast-1` | | **Explore** | `github-copilot/grok-code-fast-1` |
| **Atlas** | `github-copilot/claude-sonnet-4.6` | | **Librarian** | `github-copilot/gemini-3-flash` |
GitHub Copilot acts as a proxy provider, routing requests to underlying models based on your subscription. Some agents, like Librarian, are not installed from Copilot alone and instead rely on other configured providers or runtime fallback behavior. GitHub Copilot acts as a proxy provider, routing requests to underlying models based on your subscription.
#### Z.ai Coding Plan #### Z.ai Coding Plan
@@ -238,37 +227,43 @@ If Z.ai is your main provider, the most important fallbacks are:
#### OpenCode Zen #### OpenCode Zen
OpenCode Zen provides access to `opencode/` prefixed models including `opencode/claude-opus-4-6`, `opencode/gpt-5.4`, `opencode/gpt-5.3-codex`, `opencode/gpt-5-nano`, `opencode/glm-5`, `opencode/big-pickle`, `opencode/minimax-m2.7`, and `opencode/minimax-m2.7-highspeed`. OpenCode Zen provides access to `opencode/` prefixed models including `opencode/claude-opus-4-6`, `opencode/gpt-5.4`, `opencode/gpt-5.3-codex`, `opencode/gpt-5-nano`, `opencode/glm-5`, `opencode/big-pickle`, and `opencode/minimax-m2.5-free`.
When OpenCode Zen is the best available provider, these are the most relevant source-backed examples: When OpenCode Zen is the best available provider (no native or Copilot), these models are used:
| Agent | Model | | Agent | Model |
| ------------- | ---------------------------------------------------- | | ------------- | ---------------------------------------------------- |
| **Sisyphus** | `opencode/claude-opus-4-6` | | **Sisyphus** | `opencode/claude-opus-4-6` |
| **Oracle** | `opencode/gpt-5.4` | | **Oracle** | `opencode/gpt-5.4` |
| **Explore** | `opencode/minimax-m2.7` | | **Explore** | `opencode/gpt-5-nano` |
| **Librarian** | `opencode/minimax-m2.5-free` / `opencode/big-pickle` |
##### Setup ##### Setup
Run the installer and select "Yes" for OpenCode Zen: Run the installer and select "Yes" for GitHub Copilot:
```bash ```bash
bunx oh-my-opencode install bunx oh-my-openagent install
# Select your subscriptions (Claude, ChatGPT, Gemini, OpenCode Zen, etc.) # Select your subscriptions (Claude, ChatGPT, Gemini)
# When prompted: "Do you have access to OpenCode Zen (opencode/ models)?" → Select "Yes" # When prompted: "Do you have a GitHub Copilot subscription?" → Select "Yes"
``` ```
Or use non-interactive mode: Or use non-interactive mode:
```bash ```bash
bunx oh-my-opencode install --no-tui --claude=no --openai=no --gemini=no --opencode-zen=yes bunx oh-my-openagent install --no-tui --claude=no --openai=no --gemini=no --copilot=yes
``` ```
This provider uses the `opencode/` model catalog. If your OpenCode environment prompts for provider authentication, follow the OpenCode provider flow for `opencode/` models instead of reusing the fallback-provider auth steps above. Then authenticate with GitHub:
```bash
opencode auth login
# Select: GitHub → Authenticate via OAuth
```
### Step 5: Understand Your Model Setup ### Step 5: Understand Your Model Setup
You've just configured oh-my-opencode. Here's what got set up and why. You've just configured oh-my-openagent. Here's what got set up and why.
#### Model Families: What You're Working With #### Model Families: What You're Working With
@@ -281,7 +276,7 @@ Not all models behave the same way. Understanding which models are "similar" hel
| **Claude Opus 4.6** | anthropic, github-copilot, opencode | Best overall. Default for Sisyphus. | | **Claude Opus 4.6** | anthropic, github-copilot, opencode | Best overall. Default for Sisyphus. |
| **Claude Sonnet 4.6** | anthropic, github-copilot, opencode | Faster, cheaper. Good balance. | | **Claude Sonnet 4.6** | anthropic, github-copilot, opencode | Faster, cheaper. Good balance. |
| **Claude Haiku 4.5** | anthropic, opencode | Fast and cheap. Good for quick tasks. | | **Claude Haiku 4.5** | anthropic, opencode | Fast and cheap. Good for quick tasks. |
| **Kimi K2.5** | kimi-for-coding, opencode-go, opencode, moonshotai, moonshotai-cn, firmware, ollama-cloud, aihubmix | Behaves very similarly to Claude. Great all-rounder that appears in several orchestration fallback chains. | | **Kimi K2.5** | kimi-for-coding | Behaves very similarly to Claude. Great all-rounder. Default for Atlas. |
| **Kimi K2.5 Free** | opencode | Free-tier Kimi. Rate-limited but functional. | | **Kimi K2.5 Free** | opencode | Free-tier Kimi. Rate-limited but functional. |
| **GLM 5** | zai-coding-plan, opencode | Claude-like behavior. Good for broad tasks. | | **GLM 5** | zai-coding-plan, opencode | Claude-like behavior. Good for broad tasks. |
| **Big Pickle (GLM 4.6)** | opencode | Free-tier GLM. Decent fallback. | | **Big Pickle (GLM 4.6)** | opencode | Free-tier GLM. Decent fallback. |
@@ -290,27 +285,26 @@ Not all models behave the same way. Understanding which models are "similar" hel
| Model | Provider(s) | Notes | | Model | Provider(s) | Notes |
| ----------------- | -------------------------------- | ------------------------------------------------- | | ----------------- | -------------------------------- | ------------------------------------------------- |
| **GPT-5.3-codex** | openai, github-copilot, opencode | Deep coding powerhouse. Still available for deep category and explicit overrides. | | **GPT-5.3-codex** | openai, github-copilot, opencode | Deep coding powerhouse. Required for Hephaestus. |
| **GPT-5.4** | openai, github-copilot, opencode | High intelligence. Default for Oracle. | | **GPT-5.4** | openai, github-copilot, opencode | High intelligence. Default for Oracle. |
| **GPT-5.4 Mini** | openai, github-copilot, opencode | Fast + strong reasoning. Default for quick category. |
| **GPT-5-Nano** | opencode | Ultra-cheap, fast. Good for simple utility tasks. | | **GPT-5-Nano** | opencode | Ultra-cheap, fast. Good for simple utility tasks. |
**Different-Behavior Models**: **Different-Behavior Models**:
| Model | Provider(s) | Notes | | Model | Provider(s) | Notes |
| --------------------- | -------------------------------- | ----------------------------------------------------------- | | --------------------- | -------------------------------- | ----------------------------------------------------------- |
| **Gemini 3.1 Pro** | google, github-copilot, opencode | Excels at visual/frontend tasks. Different reasoning style. | | **Gemini 3 Pro** | google, github-copilot, opencode | Excels at visual/frontend tasks. Different reasoning style. |
| **Gemini 3 Flash** | google, github-copilot, opencode | Fast, good for doc search and light tasks. | | **Gemini 3 Flash** | google, github-copilot, opencode | Fast, good for doc search and light tasks. |
| **MiniMax M2.7** | opencode-go, opencode | Fast and smart. Utility fallbacks use `minimax-m2.7` or `minimax-m2.7-highspeed` depending on the chain. | | **MiniMax M2.5** | venice | Fast and smart. Good for utility tasks. |
| **MiniMax M2.7 Highspeed** | opencode-go, opencode | Faster utility variant used in Explore and other retrieval-heavy fallback chains. | | **MiniMax M2.5 Free** | opencode | Free-tier MiniMax. Fast for search/retrieval. |
**Speed-Focused Models**: **Speed-Focused Models**:
| Model | Provider(s) | Speed | Notes | | Model | Provider(s) | Speed | Notes |
| ----------------------- | ---------------------- | -------------- | --------------------------------------------------------------------------------------------------------------------------------------------- | | ----------------------- | ---------------------- | -------------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
| **Grok Code Fast 1** | github-copilot, xai | Very fast | Optimized for code grep/search. Default for Explore. | | **Grok Code Fast 1** | github-copilot, venice | Very fast | Optimized for code grep/search. Default for Explore. |
| **Claude Haiku 4.5** | anthropic, opencode | Fast | Good balance of speed and intelligence. | | **Claude Haiku 4.5** | anthropic, opencode | Fast | Good balance of speed and intelligence. |
| **MiniMax M2.7 Highspeed** | opencode-go, opencode | Very fast | High-speed MiniMax utility fallback used by runtime chains such as Explore and, on the OpenCode catalog, Librarian. | | **MiniMax M2.5 (Free)** | opencode, venice | Fast | Smart for its speed class. |
| **GPT-5.3-codex-spark** | openai | Extremely fast | Blazing fast but compacts so aggressively that oh-my-openagent's context management doesn't work well with it. Not recommended for omo agents. | | **GPT-5.3-codex-spark** | openai | Extremely fast | Blazing fast but compacts so aggressively that oh-my-openagent's context management doesn't work well with it. Not recommended for omo agents. |
#### What Each Agent Does and Which Model It Got #### What Each Agent Does and Which Model It Got
@@ -321,8 +315,8 @@ Based on your subscriptions, here's how the agents were configured:
| Agent | Role | Default Chain | What It Does | | Agent | Role | Default Chain | What It Does |
| ------------ | ---------------- | ----------------------------------------------- | ---------------------------------------------------------------------------------------- | | ------------ | ---------------- | ----------------------------------------------- | ---------------------------------------------------------------------------------------- |
| **Sisyphus** | Main ultraworker | anthropic\|github-copilot\|opencode/claude-opus-4-6 (max) → opencode-go/kimi-k2.5 → kimi-for-coding/k2p5 → opencode\|moonshotai\|moonshotai-cn\|firmware\|ollama-cloud\|aihubmix/kimi-k2.5 → openai\|github-copilot\|opencode/gpt-5.4 (medium) → zai-coding-plan\|opencode/glm-5 → opencode/big-pickle | Primary coding agent. Exact runtime chain from `src/shared/model-requirements.ts`. | | **Sisyphus** | Main ultraworker | Opus (max) → Kimi K2.5 → GLM 5 → Big Pickle | Primary coding agent. Orchestrates everything. **Never use GPT — no GPT prompt exists.** |
| **Metis** | Plan review | anthropic\|github-copilot\|opencode/claude-opus-4-6 (max) → openai\|github-copilot\|opencode/gpt-5.4 (high) → opencode-go/glm-5 → kimi-for-coding/k2p5 | Reviews Prometheus plans for gaps. Exact runtime chain from `src/shared/model-requirements.ts`. | | **Metis** | Plan review | Opus (max) → Kimi K2.5 → GPT-5.4 → Gemini 3 Pro | Reviews Prometheus plans for gaps. |
**Dual-Prompt Agents** (auto-switch between Claude and GPT prompts): **Dual-Prompt Agents** (auto-switch between Claude and GPT prompts):
@@ -332,16 +326,16 @@ Priority: **Claude > GPT > Claude-like models**
| Agent | Role | Default Chain | GPT Prompt? | | Agent | Role | Default Chain | GPT Prompt? |
| -------------- | ----------------- | ---------------------------------------------------------- | ---------------------------------------------------------------- | | -------------- | ----------------- | ---------------------------------------------------------- | ---------------------------------------------------------------- |
| **Prometheus** | Strategic planner | anthropic\|github-copilot\|opencode/claude-opus-4-6 (max) → openai\|github-copilot\|opencode/gpt-5.4 (high) → opencode-go/glm-5 → google\|github-copilot\|opencode/gemini-3.1-pro | Yes — XML-tagged, principle-driven (~300 lines vs ~1,100 Claude) | | **Prometheus** | Strategic planner | Opus (max) → **GPT-5.4 (high)** → Kimi K2.5 → Gemini 3 Pro | Yes — XML-tagged, principle-driven (~300 lines vs ~1,100 Claude) |
| **Atlas** | Todo orchestrator | anthropic\|github-copilot\|opencode/claude-sonnet-4-6 → opencode-go/kimi-k2.5 → openai\|github-copilot\|opencode/gpt-5.4 (medium) → opencode-go/minimax-m2.7 | Yes - GPT-optimized todo management | | **Atlas** | Todo orchestrator | **Kimi K2.5** → Sonnet → GPT-5.4 | Yes GPT-optimized todo management |
**GPT-Native Agents** (built for GPT, don't override to Claude): **GPT-Native Agents** (built for GPT, don't override to Claude):
| Agent | Role | Default Chain | Notes | | Agent | Role | Default Chain | Notes |
| -------------- | ---------------------- | -------------------------------------- | ------------------------------------------------------ | | -------------- | ---------------------- | -------------------------------------- | ------------------------------------------------------ |
| **Hephaestus** | Deep autonomous worker | GPT-5.4 (medium) only | "Codex on steroids." No fallback. Requires GPT access. | | **Hephaestus** | Deep autonomous worker | GPT-5.3-codex (medium) only | "Codex on steroids." No fallback. Requires GPT access. |
| **Oracle** | Architecture/debugging | openai\|github-copilot\|opencode/gpt-5.4 (high) → google\|github-copilot\|opencode/gemini-3.1-pro (high) → anthropic\|github-copilot\|opencode/claude-opus-4-6 (max) → opencode-go/glm-5 | High-IQ strategic backup. GPT preferred. | | **Oracle** | Architecture/debugging | GPT-5.4 (high) → Gemini 3 Pro → Opus | High-IQ strategic backup. GPT preferred. |
| **Momus** | High-accuracy reviewer | openai\|github-copilot\|opencode/gpt-5.4 (xhigh) → anthropic\|github-copilot\|opencode/claude-opus-4-6 (max) → google\|github-copilot\|opencode/gemini-3.1-pro (high) → opencode-go/glm-5 | Verification agent. GPT preferred. | | **Momus** | High-accuracy reviewer | GPT-5.4 (medium) → Opus → Gemini 3 Pro | Verification agent. GPT preferred. |
**Utility Agents** (speed over intelligence): **Utility Agents** (speed over intelligence):
@@ -349,9 +343,9 @@ These agents do search, grep, and retrieval. They intentionally use fast, cheap
| Agent | Role | Default Chain | Design Rationale | | Agent | Role | Default Chain | Design Rationale |
| --------------------- | ------------------ | ---------------------------------------------------------------------- | -------------------------------------------------------------- | | --------------------- | ------------------ | ---------------------------------------------------------------------- | -------------------------------------------------------------- |
| **Explore** | Fast codebase grep | github-copilot\|xai/grok-code-fast-1 → opencode-go/minimax-m2.7-highspeed → opencode/minimax-m2.7anthropic\|opencode/claude-haiku-4-5 → opencode/gpt-5-nano | Speed is everything. Exact runtime chain from `src/shared/model-requirements.ts`. | | **Explore** | Fast codebase grep | MiniMax M2.5 Free → Grok Code Fast → MiniMax M2.5Haiku → GPT-5-Nano | Speed is everything. Grok is blazing fast for grep. |
| **Librarian** | Docs/code search | opencode-go/minimax-m2.7opencode/minimax-m2.7-highspeedanthropic\|opencode/claude-haiku-4-5 → opencode/gpt-5-nano | Doc retrieval doesn't need deep reasoning. Exact runtime chain from `src/shared/model-requirements.ts`. | | **Librarian** | Docs/code search | MiniMax M2.5MiniMax Free → Haiku → Nano | Fast, cheap models for search. |
| **Multimodal Looker** | Vision/screenshots | openai\|opencode/gpt-5.4 (medium) → opencode-go/kimi-k2.5 → zai-coding-plan/glm-4.6v → openai\|github-copilot\|opencode/gpt-5-nano | GPT-5.4 now leads the default vision path when available. | | **Multimodal Looker** | Vision/screenshots | GPT-5.4 → Kimi K2.5 → GLM-4.6v → GPT-5-Nano | Strong vision capabilities. |
#### Why Different Models Need Different Prompts #### Why Different Models Need Different Prompts
@@ -370,7 +364,7 @@ This is why Prometheus and Atlas ship separate prompts per model family — they
#### Custom Model Configuration #### Custom Model Configuration
If the user wants to override which model an agent uses, you can customize in your plugin config file. Existing installs still commonly use `oh-my-opencode.json`, while the compatibility layer also recognizes `oh-my-openagent.json[c]`. If the user wants to override which model an agent uses, you can customize in `oh-my-opencode.json`:
```jsonc ```jsonc
{ {
@@ -405,14 +399,18 @@ GPT (5.3-codex, 5.2) > Claude Opus (decent fallback) > Gemini (acceptable)
**Dangerous** (no prompt support): **Dangerous** (no prompt support):
- Sisyphus → older GPT models: **Still a bad fit. GPT-5.4 is the only dedicated GPT prompt path.** - Sisyphus → GPT: **No GPT prompt. Will degrade significantly.**
- Hephaestus → Claude: **Built for Codex. Claude can't replicate this.** - Hephaestus → Claude: **Built for Codex. Claude can't replicate this.**
- Explore → Opus: **Massive cost waste. Explore needs speed, not intelligence.** - Explore → Opus: **Massive cost waste. Explore needs speed, not intelligence.**
- Librarian → Opus: **Same. Doc search doesn't need Opus-level reasoning.** - Librarian → Opus: **Same. Doc search doesn't need Opus-level reasoning.**
#### Provider Resolution #### Provider Priority Chain
There is no single global provider priority. The installer and runtime resolve each agent against its own fallback chain, so the winning provider depends on the agent and the subscriptions you enabled. When multiple providers are available, oh-my-openagent uses this priority:
```
Native (anthropic/, openai/, google/) > Kimi for Coding > GitHub Copilot > Venice > OpenCode Zen > Z.ai Coding Plan
```
### ⚠️ Warning ### ⚠️ Warning
@@ -463,7 +461,3 @@ Tell the user of following:
4. You wanna have your own agent- catalog setup? I can read the [docs](docs/guide/agent-model-matching.md) and set up for you after interviewing! 4. You wanna have your own agent- catalog setup? I can read the [docs](docs/guide/agent-model-matching.md) and set up for you after interviewing!
That's it. The agent will figure out the rest and handle everything automatically. That's it. The agent will figure out the rest and handle everything automatically.
#### Advanced Configuration
You can customize agent models and fallback chains in your config. The `fallback_models` field accepts either a single string or an array that mixes strings and per-model objects with settings like `variant` and `temperature`. See the [Configuration Reference](../reference/configuration.md) and example configs in `docs/examples/` for details.

View File

@@ -298,7 +298,7 @@ task({ category: "quick", prompt: "..." }); // "Just get it done fast"
| `visual-engineering` | Gemini 3.1 Pro | Frontend, UI/UX, design, styling, animation | | `visual-engineering` | Gemini 3.1 Pro | Frontend, UI/UX, design, styling, animation |
| `ultrabrain` | GPT-5.4 (xhigh) | Deep logical reasoning, complex architecture decisions | | `ultrabrain` | GPT-5.4 (xhigh) | Deep logical reasoning, complex architecture decisions |
| `artistry` | Gemini 3.1 Pro (high) | Highly creative or artistic tasks, novel ideas | | `artistry` | Gemini 3.1 Pro (high) | Highly creative or artistic tasks, novel ideas |
| `quick` | GPT-5.4 Mini | Trivial tasks - single file changes, typo fixes | | `quick` | Claude Haiku 4.5 | Trivial tasks - single file changes, typo fixes |
| `deep` | GPT-5.3 Codex (medium) | Goal-oriented autonomous problem-solving, thorough research | | `deep` | GPT-5.3 Codex (medium) | Goal-oriented autonomous problem-solving, thorough research |
| `unspecified-low` | Claude Sonnet 4.6 | Tasks that don't fit other categories, low effort | | `unspecified-low` | Claude Sonnet 4.6 | Tasks that don't fit other categories, low effort |
| `unspecified-high` | Claude Opus 4.6 (max) | Tasks that don't fit other categories, high effort | | `unspecified-high` | Claude Opus 4.6 (max) | Tasks that don't fit other categories, high effort |
@@ -420,7 +420,7 @@ Atlas is automatically activated when you run `/start-work`. You don't need to m
| Aspect | Hephaestus | Sisyphus + `ulw` / `ultrawork` | | Aspect | Hephaestus | Sisyphus + `ulw` / `ultrawork` |
| --------------- | ------------------------------------------ | ---------------------------------------------------- | | --------------- | ------------------------------------------ | ---------------------------------------------------- |
| **Model** | GPT-5.4 (medium reasoning) | Claude Opus 4.6 / GPT-5.4 / GLM 5 depending on setup | | **Model** | GPT-5.3 Codex (medium reasoning) | Claude Opus 4.6 / GPT-5.4 / GLM 5 depending on setup |
| **Approach** | Autonomous deep worker | Keyword-activated ultrawork mode | | **Approach** | Autonomous deep worker | Keyword-activated ultrawork mode |
| **Best For** | Complex architectural work, deep reasoning | General complex tasks, "just do it" scenarios | | **Best For** | Complex architectural work, deep reasoning | General complex tasks, "just do it" scenarios |
| **Planning** | Self-plans during execution | Uses Prometheus plans if available | | **Planning** | Self-plans during execution | Uses Prometheus plans if available |
@@ -443,8 +443,8 @@ Switch to Hephaestus (Tab → Select Hephaestus) when:
- "Integrate our Rust core with the TypeScript frontend" - "Integrate our Rust core with the TypeScript frontend"
- "Migrate from MongoDB to PostgreSQL with zero downtime" - "Migrate from MongoDB to PostgreSQL with zero downtime"
4. **You specifically want GPT-5.4 reasoning** 4. **You specifically want GPT-5.3 Codex reasoning**
- Some problems benefit from GPT-5.4's training characteristics - Some problems benefit from GPT-5.3 Codex's training characteristics
**When to Use Sisyphus + `ulw`:** **When to Use Sisyphus + `ulw`:**
@@ -469,13 +469,13 @@ Use the `ulw` keyword in Sisyphus when:
**Recommendation:** **Recommendation:**
- **For most users**: Use `ulw` keyword in Sisyphus. It's the default path and works excellently for 90% of complex tasks. - **For most users**: Use `ulw` keyword in Sisyphus. It's the default path and works excellently for 90% of complex tasks.
- **For power users**: Switch to Hephaestus when you specifically need GPT-5.4's reasoning style or want the "AmpCode deep mode" experience of fully autonomous exploration and execution. - **For power users**: Switch to Hephaestus when you specifically need GPT-5.3 Codex's reasoning style or want the "AmpCode deep mode" experience of fully autonomous exploration and execution.
--- ---
## Configuration ## Configuration
You can control related features in `oh-my-openagent.json`: You can control related features in `oh-my-opencode.json`:
```jsonc ```jsonc
{ {
@@ -520,7 +520,7 @@ Type `exit` or start a new session. Atlas is primarily entered via `/start-work`
**For most tasks**: Type `ulw` in Sisyphus. **For most tasks**: Type `ulw` in Sisyphus.
**Use Hephaestus when**: You specifically need GPT-5.4's reasoning style for deep architectural work or complex debugging. **Use Hephaestus when**: You specifically need GPT-5.3 Codex's reasoning style for deep architectural work or complex debugging.
--- ---

View File

@@ -41,7 +41,7 @@ We used to call this "Claude Code on steroids." That was wrong.
This isn't about making Claude Code better. It's about breaking free from the idea that one model, one provider, one way of working is enough. Anthropic wants you locked in. OpenAI wants you locked in. Everyone wants you locked in. This isn't about making Claude Code better. It's about breaking free from the idea that one model, one provider, one way of working is enough. Anthropic wants you locked in. OpenAI wants you locked in. Everyone wants you locked in.
Oh My OpenAgent doesn't play that game. It orchestrates across models, picking the right brain for the right job. Claude for orchestration. GPT for deep reasoning. Gemini for frontend. GPT-5.4 Mini for quick tasks. All working together, automatically. Oh My OpenAgent doesn't play that game. It orchestrates across models, picking the right brain for the right job. Claude for orchestration. GPT for deep reasoning. Gemini for frontend. Haiku for quick tasks. All working together, automatically.
--- ---
@@ -60,10 +60,11 @@ User Request
├─→ [Prometheus] — Strategic planning (interview mode) ├─→ [Prometheus] — Strategic planning (interview mode)
├─→ [Atlas] — Todo orchestration and execution ├─→ [Atlas] — Todo orchestration and execution
├─→ [Oracle] — Architecture consultation ├─→ [Specialist Subagents]
├─→ [Librarian] — Documentation/code search ├─→ [Oracle] — Architecture consultation
├─→ [Explore] — Fast codebase grep ├─→ [Librarian] — Documentation/code search
└─→ [Category-based agents] — Specialized by task type └─→ [Explore] — Fast codebase grep
└─→ [Sisyphus-Junior] — Category-based executor
``` ```
When Sisyphus delegates to a subagent, it doesn't pick a model name. It picks a **category**`visual-engineering`, `ultrabrain`, `quick`, `deep`. The category automatically maps to the right model. You touch nothing. When Sisyphus delegates to a subagent, it doesn't pick a model name. It picks a **category**`visual-engineering`, `ultrabrain`, `quick`, `deep`. The category automatically maps to the right model. You touch nothing.
@@ -93,15 +94,15 @@ Sisyphus still works best on Claude-family models, Kimi, and GLM. GPT-5.4 now ha
Named with intentional irony. Anthropic blocked OpenCode from using their API because of this project. So the team built an autonomous GPT-native agent instead. Named with intentional irony. Anthropic blocked OpenCode from using their API because of this project. So the team built an autonomous GPT-native agent instead.
Hephaestus runs on GPT-5.4. Give him a goal, not a recipe. He explores the codebase, researches patterns, and executes end-to-end without hand-holding. He is the legitimate craftsman because he was born from necessity, not privilege. Hephaestus runs on GPT-5.3 Codex. Give him a goal, not a recipe. He explores the codebase, researches patterns, and executes end-to-end without hand-holding. He is the legitimate craftsman because he was born from necessity, not privilege.
Use Hephaestus when you need deep architectural reasoning, complex debugging across many files, or cross-domain knowledge synthesis. Switch to him explicitly when the work demands GPT-5.4's particular strengths. Use Hephaestus when you need deep architectural reasoning, complex debugging across many files, or cross-domain knowledge synthesis. Switch to him explicitly when the work demands GPT-5.3 Codex's particular strengths.
**Why this beats vanilla Codex CLI:** **Why this beats vanilla Codex CLI:**
- **Multi-model orchestration.** Pure Codex is single-model. OmO routes different tasks to different models automatically. GPT for deep reasoning. Gemini for frontend. GPT-5.4 Mini for speed. The right brain for the right job. - **Multi-model orchestration.** Pure Codex is single-model. OmO routes different tasks to different models automatically. GPT for deep reasoning. Gemini for frontend. Haiku for speed. The right brain for the right job.
- **Background agents.** Fire 5+ agents in parallel. Something Codex simply cannot do. While one agent writes code, another researches patterns, another checks documentation. Like a real dev team. - **Background agents.** Fire 5+ agents in parallel. Something Codex simply cannot do. While one agent writes code, another researches patterns, another checks documentation. Like a real dev team.
- **Category system.** Tasks are routed by intent, not model name. `visual-engineering` gets Gemini. `ultrabrain` gets GPT-5.4. `quick` gets GPT-5.4 Mini. No manual juggling. - **Category system.** Tasks are routed by intent, not model name. `visual-engineering` gets Gemini. `ultrabrain` gets GPT-5.4. `quick` gets Haiku. No manual juggling.
- **Accumulated wisdom.** Subagents learn from previous results. Conventions discovered in task 1 are passed to task 5. Mistakes made early aren't repeated. The system gets smarter as it works. - **Accumulated wisdom.** Subagents learn from previous results. Conventions discovered in task 1 are passed to task 5. Mistakes made early aren't repeated. The system gets smarter as it works.
### Prometheus: The Strategic Planner ### Prometheus: The Strategic Planner
@@ -116,17 +117,20 @@ Atlas executes Prometheus plans. Distributes tasks to specialized subagents. Acc
Run `/start-work` to activate Atlas on your latest plan. Run `/start-work` to activate Atlas on your latest plan.
### Oracle: The Consultant ### Sisyphus-Junior: The Specialist
Read-only high-IQ consultant for architecture decisions and complex debugging. Consult Oracle when facing unfamiliar patterns, security concerns, or multi-system tradeoffs. When Sisyphus delegates a task via a specific **Category** (like `visual-engineering` or `deep`), **Sisyphus-Junior** is the agent that performs it. It is optimized for focused execution within a specific domain and cannot re-delegate, preventing infinite loops.
### Supporting Cast ### Specialist Subagents
These agents are primarily designed to be called by other agents or for specific queries, rather than managing a full workflow.
- **Oracle** — Read-only high-IQ consultant for architecture decisions and complex debugging.
- **Librarian** — Documentation and OSS code search. Stays current on library APIs and best practices.
- **Explore** — Fast codebase grep. Uses speed-focused models for pattern discovery.
- **Multimodal Looker** — Vision and screenshot analysis.
- **Metis** — Gap analyzer. Catches what Prometheus missed before plans are finalized. - **Metis** — Gap analyzer. Catches what Prometheus missed before plans are finalized.
- **Momus** — Ruthless reviewer. Validates plans against clarity, verification, and context criteria. - **Momus** — Ruthless reviewer. Validates plans against clarity, verification, and context criteria.
- **Explore** — Fast codebase grep. Uses speed-focused models for pattern discovery.
- **Librarian** — Documentation and OSS code search. Stays current on library APIs and best practices.
- **Multimodal Looker** — Vision and screenshot analysis.
--- ---
@@ -168,7 +172,7 @@ You can override specific agents or categories in your config:
```jsonc ```jsonc
{ {
"$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-openagent.schema.json", "$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-opencode.schema.json",
"agents": { "agents": {
// Main orchestrator: Claude Opus or Kimi K2.5 work best // Main orchestrator: Claude Opus or Kimi K2.5 work best
@@ -195,8 +199,8 @@ You can override specific agents or categories in your config:
// General high-effort work // General high-effort work
"unspecified-high": { "model": "anthropic/claude-opus-4-6", "variant": "max" }, "unspecified-high": { "model": "anthropic/claude-opus-4-6", "variant": "max" },
// Quick tasks: use GPT-5.4-mini (fast and cheap) // Quick tasks: use the cheapest models
"quick": { "model": "openai/gpt-5.4-mini" }, "quick": { "model": "anthropic/claude-haiku-4-5" },
// Deep reasoning: GPT-5.4 // Deep reasoning: GPT-5.4
"ultrabrain": { "model": "openai/gpt-5.4", "variant": "xhigh" }, "ultrabrain": { "model": "openai/gpt-5.4", "variant": "xhigh" },
@@ -214,13 +218,14 @@ You can override specific agents or categories in your config:
**GPT models** (explicit reasoning, principle-driven): **GPT models** (explicit reasoning, principle-driven):
- GPT-5.4 — deep coding powerhouse, required for Hephaestus and default for Oracle - GPT-5.3-codex — deep coding powerhouse, required for Hephaestus
- GPT-5.4 — high intelligence, default for Oracle
- GPT-5-Nano — ultra-cheap, fast utility tasks - GPT-5-Nano — ultra-cheap, fast utility tasks
**Different-behavior models**: **Different-behavior models**:
- Gemini 3.1 Pro — excels at visual/frontend tasks - Gemini 3 Pro — excels at visual/frontend tasks
- MiniMax M2.7 / M2.7-highspeed — fast and smart for utility tasks - MiniMax M2.5 — fast and smart for utility tasks
- Grok Code Fast 1 — optimized for code grep/search - Grok Code Fast 1 — optimized for code grep/search
See the [Agent-Model Matching Guide](./agent-model-matching.md) for complete details on which models work best for each agent, safe vs dangerous overrides, and provider priority chains. See the [Agent-Model Matching Guide](./agent-model-matching.md) for complete details on which models work best for each agent, safe vs dangerous overrides, and provider priority chains.

View File

@@ -1,33 +0,0 @@
# Model Capabilities Maintenance
This project treats model capability resolution as a layered system:
1. runtime metadata from connected providers
2. `models.dev` bundled/runtime snapshot data
3. explicit compatibility aliases
4. heuristic fallback as the last resort
## Internal policy
- Built-in OmO agent/category requirement models must use canonical model IDs.
- Aliases exist only to preserve compatibility with historical OmO names or provider-specific decorations.
- New decorated names like `-high`, `-low`, or `-thinking` should not be added to built-in requirements when a canonical model ID plus structured settings can express the same thing.
- If a provider or config input still uses an alias, normalize it at the edge and continue internally with the canonical ID.
## When adding an alias
- Add the alias rule to `src/shared/model-capability-aliases.ts`.
- Include a rationale for why the alias exists.
- Add or update tests so the alias is covered explicitly.
- Ensure the alias canonical target exists in the bundled `models.dev` snapshot.
## Guardrails
`bun run test:model-capabilities` enforces the following invariants:
- exact alias targets must exist in the bundled snapshot
- exact alias keys must not silently become canonical `models.dev` IDs
- pattern aliases must not rewrite canonical snapshot IDs
- built-in requirement models must stay canonical and snapshot-backed
The scheduled `refresh-model-capabilities` workflow runs these guardrails before opening an automated snapshot refresh PR.

View File

@@ -1,192 +1,142 @@
# CLI Reference # CLI Reference
Complete reference for the published `oh-my-opencode` CLI. During the rename transition, OpenCode plugin registration now prefers `oh-my-openagent` inside `opencode.json`. Complete reference for the `oh-my-openagent` command-line interface.
## Basic Usage ## Basic Usage
```bash ```bash
# Display help # Display help
bunx oh-my-opencode bunx oh-my-openagent
# Or with npx # Or with npx
npx oh-my-opencode npx oh-my-openagent
``` ```
## Commands ## Commands
| Command | Description | | Command | Description |
| ----------------------------- | ------------------------------------------------------ | | ------------------- | ----------------------------------------- |
| `install` | Interactive setup wizard | | `install` | Interactive setup wizard |
| `doctor` | Environment diagnostics and health checks | | `doctor` | Environment diagnostics and health checks |
| `run` | OpenCode session runner with task completion enforcement | | `run` | OpenCode session runner |
| `get-local-version` | Display local version information and update check | | `mcp oauth` | MCP OAuth authentication management |
| `refresh-model-capabilities` | Refresh the cached models.dev-based model capabilities | | `auth` | Google Antigravity OAuth authentication |
| `version` | Show version information | | `get-local-version` | Display local version information |
| `mcp oauth` | MCP OAuth authentication management |
--- ---
## install ## install
Interactive installation tool for initial Oh My OpenCode setup. Provides a TUI based on `@clack/prompts`. Interactive installation tool for initial Oh-My-OpenCode setup. Provides a TUI based on `@clack/prompts`.
### Usage ### Usage
```bash ```bash
bunx oh-my-opencode install bunx oh-my-openagent install
``` ```
### Installation Process ### Installation Process
1. **Subscription Selection**: Choose which providers and subscriptions you actually have 1. **Provider Selection**: Choose your AI provider (Claude, ChatGPT, or Gemini)
2. **Plugin Registration**: Registers `oh-my-openagent` in OpenCode settings, or upgrades a legacy `oh-my-opencode` entry during the compatibility window 2. **API Key Input**: Enter the API key for your selected provider
3. **Configuration File Creation**: Writes the generated OmO config to `oh-my-opencode.json` in the active OpenCode config directory 3. **Configuration File Creation**: Generates `opencode.json` or `oh-my-opencode.json` files
4. **Authentication Hints**: Shows the `opencode auth login` steps for the providers you selected, unless `--skip-auth` is set 4. **Plugin Registration**: Automatically registers the oh-my-openagent plugin in OpenCode settings
### Options ### Options
| Option | Description | | Option | Description |
| ------ | ----------- | | ----------- | ---------------------------------------------------------------- |
| `--no-tui` | Run in non-interactive mode without TUI | | `--no-tui` | Run in non-interactive mode without TUI (for CI/CD environments) |
| `--claude <no\|yes\|max20>` | Claude subscription mode | | `--verbose` | Display detailed logs |
| `--openai <no\|yes>` | OpenAI / ChatGPT subscription |
| `--gemini <no\|yes>` | Gemini integration |
| `--copilot <no\|yes>` | GitHub Copilot subscription |
| `--opencode-zen <no\|yes>` | OpenCode Zen access |
| `--zai-coding-plan <no\|yes>` | Z.ai Coding Plan subscription |
| `--kimi-for-coding <no\|yes>` | Kimi for Coding subscription |
| `--opencode-go <no\|yes>` | OpenCode Go subscription |
| `--skip-auth` | Skip authentication setup hints |
--- ---
## doctor ## doctor
Diagnoses your environment to ensure Oh My OpenCode is functioning correctly. The current checks are grouped into system, config, tools, and models. Diagnoses your environment to ensure Oh-My-OpenCode is functioning correctly. Performs 17+ health checks.
The doctor command detects common issues including:
- Legacy plugin entry references in `opencode.json` (warns when `oh-my-opencode` is still used instead of `oh-my-openagent`)
- Configuration file validity and JSONC parsing errors
- Model resolution and fallback chain verification
- Missing or misconfigured MCP servers
### Usage ### Usage
```bash ```bash
bunx oh-my-opencode doctor bunx oh-my-openagent doctor
``` ```
### Diagnostic Categories ### Diagnostic Categories
| Category | Check Items | | Category | Check Items |
| ----------------- | ------------------------------------------------------------------------------------ | | ------------------ | --------------------------------------------------------- |
| **System** | OpenCode binary, version (>= 1.0.150), plugin registration, legacy package name warning | | **Installation** | OpenCode version (>= 1.0.150), plugin registration status |
| **Config** | Configuration file validity, JSONC parsing, Zod schema validation | | **Configuration** | Configuration file validity, JSONC parsing |
| **Tools** | AST-Grep, LSP servers, GitHub CLI, MCP servers | | **Authentication** | Anthropic, OpenAI, Google API key validity |
| **Models** | Model capabilities cache, model resolution, agent/category overrides, availability | | **Dependencies** | Bun, Node.js, Git installation status |
| **Tools** | LSP server status, MCP server status |
| **Updates** | Latest version check |
### Options ### Options
| Option | Description | | Option | Description |
| ------------ | ----------------------------------------- | | ------------------- | ---------------------------------------------------------------- |
| `--status` | Show compact system dashboard | | `--category <name>` | Check specific category only (e.g., `--category authentication`) |
| `--verbose` | Show detailed diagnostic information | | `--json` | Output results in JSON format |
| `--json` | Output results in JSON format | | `--verbose` | Include detailed information |
### Example Output ### Example Output
``` ```
oh-my-opencode doctor oh-my-openagent doctor
┌──────────────────────────────────────────────────┐ ┌──────────────────────────────────────────────────┐
│ Oh-My-OpenAgent Doctor │ │ Oh-My-OpenCode Doctor │
└──────────────────────────────────────────────────┘ └──────────────────────────────────────────────────┘
System Installation
✓ OpenCode version: 1.0.155 (>= 1.0.150) ✓ OpenCode version: 1.0.155 (>= 1.0.150)
✓ Plugin registered in opencode.json ✓ Plugin registered in opencode.json
Config Configuration
✓ oh-my-opencode.jsonc is valid ✓ oh-my-opencode.json is valid
✓ Model resolution: all agents have valid fallback chains
⚠ categories.visual-engineering: using default model ⚠ categories.visual-engineering: using default model
Tools Authentication
✓ AST-Grep available ✓ Anthropic API key configured
LSP servers configured OpenAI API key configured
✗ Google API key not found
Models Dependencies
11 agents, 8 categories, 0 overrides Bun 1.2.5 installed
⚠ Some configured models rely on compatibility fallback ✓ Node.js 22.0.0 installed
✓ Git 2.45.0 installed
Summary: 10 passed, 1 warning, 0 failed Summary: 10 passed, 1 warning, 1 failed
``` ```
--- ---
## run ## run
Run opencode with todo/background task completion enforcement. Unlike 'opencode run', this command waits until all todos are completed or cancelled, and all child sessions (background tasks) are idle. Executes OpenCode sessions and monitors task completion.
### Usage ### Usage
```bash ```bash
bunx oh-my-opencode run <message> bunx oh-my-openagent run [prompt]
``` ```
### Options ### Options
| Option | Description | | Option | Description |
| --------------------- | ------------------------------------------------------------------- | | ------------------------ | ------------------------------------------------- |
| `-a, --agent <name>` | Agent to use (default: from CLI/env/config, fallback: Sisyphus) | | `--enforce-completion` | Keep session active until all TODOs are completed |
| `-m, --model <provider/model>` | Model override (e.g., anthropic/claude-sonnet-4) | | `--timeout <seconds>` | Set maximum execution time |
| `-d, --directory <path>` | Working directory | | `--agent <name>` | Specify agent to use |
| `-p, --port <port>` | Server port (attaches if port already in use) | | `--directory <path>` | Set working directory |
| `--attach <url>` | Attach to existing opencode server URL | | `--port <number>` | Set port for session |
| `--on-complete <command>` | Shell command to run after completion | | `--attach` | Attach to existing session |
| `--json` | Output structured JSON result to stdout | | `--json` | Output in JSON format |
| `--no-timestamp` | Disable timestamp prefix in run output | | `--no-timestamp` | Disable timestamped output |
| `--verbose` | Show full event stream (default: messages/tools only) | | `--session-id <id>` | Resume existing session |
| `--session-id <id>` | Resume existing session instead of creating new one | | `--on-complete <action>` | Action on completion |
| `--verbose` | Enable verbose logging |
---
## get-local-version
Show current installed version and check for updates.
### Usage
```bash
bunx oh-my-opencode get-local-version
```
### Options
| Option | Description |
| ----------------- | ---------------------------------------------- |
| `-d, --directory` | Working directory to check config from |
| `--json` | Output in JSON format for scripting |
### Output
Shows:
- Current installed version
- Latest available version on npm
- Whether you're up to date
- Special modes (local dev, pinned version)
---
## version
Show version information.
### Usage
```bash
bunx oh-my-opencode version
```
`--on-complete` runs through your current shell when possible: `sh` on Unix shells, `pwsh` for PowerShell on non-Windows, `powershell.exe` for PowerShell on Windows, and `cmd.exe` as the Windows fallback.
--- ---
@@ -198,16 +148,16 @@ Manages OAuth 2.1 authentication for remote MCP servers.
```bash ```bash
# Login to an OAuth-protected MCP server # Login to an OAuth-protected MCP server
bunx oh-my-opencode mcp oauth login <server-name> --server-url https://api.example.com bunx oh-my-openagent mcp oauth login <server-name> --server-url https://api.example.com
# Login with explicit client ID and scopes # Login with explicit client ID and scopes
bunx oh-my-opencode mcp oauth login my-api --server-url https://api.example.com --client-id my-client --scopes read write bunx oh-my-openagent mcp oauth login my-api --server-url https://api.example.com --client-id my-client --scopes "read,write"
# Remove stored OAuth tokens # Remove stored OAuth tokens
bunx oh-my-opencode mcp oauth logout <server-name> --server-url https://api.example.com bunx oh-my-openagent mcp oauth logout <server-name>
# Check OAuth token status # Check OAuth token status
bunx oh-my-opencode mcp oauth status [server-name] bunx oh-my-openagent mcp oauth status [server-name]
``` ```
### Options ### Options
@@ -216,7 +166,7 @@ bunx oh-my-opencode mcp oauth status [server-name]
| -------------------- | ------------------------------------------------------------------------- | | -------------------- | ------------------------------------------------------------------------- |
| `--server-url <url>` | MCP server URL (required for login) | | `--server-url <url>` | MCP server URL (required for login) |
| `--client-id <id>` | OAuth client ID (optional if server supports Dynamic Client Registration) | | `--client-id <id>` | OAuth client ID (optional if server supports Dynamic Client Registration) |
| `--scopes <scopes>` | OAuth scopes as separate variadic arguments (for example: `--scopes read write`) | | `--scopes <scopes>` | Comma-separated OAuth scopes |
### Token Storage ### Token Storage
@@ -226,20 +176,10 @@ Tokens are stored in `~/.config/opencode/mcp-oauth.json` with `0600` permissions
## Configuration Files ## Configuration Files
The runtime loads user config as the base config, then merges project config on top: The CLI searches for configuration files in the following locations (in priority order):
1. **Project Level**: `.opencode/oh-my-openagent.jsonc`, `.opencode/oh-my-openagent.json`, `.opencode/oh-my-opencode.jsonc`, or `.opencode/oh-my-opencode.json` 1. **Project Level**: `.opencode/oh-my-opencode.json`
2. **User Level**: `~/.config/opencode/oh-my-openagent.jsonc`, `~/.config/opencode/oh-my-openagent.json`, `~/.config/opencode/oh-my-opencode.jsonc`, or `~/.config/opencode/oh-my-opencode.json` 2. **User Level**: `~/.config/opencode/oh-my-opencode.json`
**Naming Note**: The published package and binary are still `oh-my-opencode`. Inside `opencode.json`, the compatibility layer now prefers the plugin entry `oh-my-openagent`. Plugin config loading recognizes both `oh-my-openagent.*` and legacy `oh-my-opencode.*` basenames. If both basenames exist in the same directory, the legacy `oh-my-opencode.*` file currently wins.
### Filename Compatibility
Both `.jsonc` and `.json` extensions are supported. JSONC (JSON with Comments) is preferred as it allows:
- Comments (both `//` and `/* */` styles)
- Trailing commas in arrays and objects
If both `.jsonc` and `.json` exist in the same directory, the `.jsonc` file takes precedence.
### JSONC Support ### JSONC Support
@@ -279,78 +219,31 @@ bun install -g opencode@latest
```bash ```bash
# Reinstall plugin # Reinstall plugin
bunx oh-my-opencode install bunx oh-my-openagent install
``` ```
### Doctor Check Failures ### Doctor Check Failures
```bash ```bash
# Diagnose with detailed information # Diagnose with detailed information
bunx oh-my-opencode doctor --verbose bunx oh-my-openagent doctor --verbose
# Show compact system dashboard # Check specific category only
bunx oh-my-opencode doctor --status bunx oh-my-openagent doctor --category authentication
# JSON output for scripting
bunx oh-my-opencode doctor --json
```
### "Using legacy package name" Warning
The doctor warns if it finds the legacy plugin entry `oh-my-opencode` in `opencode.json`. Update the plugin array to the canonical `oh-my-openagent` entry:
```bash
# Replace the legacy plugin entry in user config
jq '.plugin = (.plugin // [] | map(if . == "oh-my-opencode" then "oh-my-openagent" else . end))' \
~/.config/opencode/opencode.json > /tmp/opencode.json && mv /tmp/opencode.json ~/.config/opencode/opencode.json
```
---
## refresh-model-capabilities
Refreshes the cached model capabilities snapshot from models.dev. This updates the local cache used by capability resolution and compatibility diagnostics.
### Usage
```bash
bunx oh-my-opencode refresh-model-capabilities
```
### Options
| Option | Description |
| ----------------- | --------------------------------------------------- |
| `-d, --directory` | Working directory to read oh-my-opencode config from |
| `--source-url <url>` | Override the models.dev source URL |
| `--json` | Output refresh summary as JSON |
### Configuration
Configure automatic refresh behavior in your plugin config:
```jsonc
{
"model_capabilities": {
"enabled": true,
"auto_refresh_on_start": true,
"refresh_timeout_ms": 5000,
"source_url": "https://models.dev/api.json"
}
}
``` ```
--- ---
## Non-Interactive Mode ## Non-Interactive Mode
Use JSON output for CI or scripted diagnostics. Use the `--no-tui` option for CI/CD environments.
```bash ```bash
# Run doctor in CI environment # Run doctor in CI environment
bunx oh-my-opencode doctor --json bunx oh-my-openagent doctor --no-tui --json
# Save results to file # Save results to file
bunx oh-my-opencode doctor --json > doctor-report.json bunx oh-my-openagent doctor --json > doctor-report.json
``` ```
--- ---

View File

@@ -1,6 +1,6 @@
# Configuration Reference # Configuration Reference
Complete reference for Oh My OpenCode plugin configuration. During the rename transition, the runtime recognizes both `oh-my-openagent.json[c]` and legacy `oh-my-opencode.json[c]` files. Complete reference for `oh-my-opencode.jsonc` configuration. This document covers every available option with examples.
--- ---
@@ -30,7 +30,6 @@ Complete reference for Oh My OpenCode plugin configuration. During the rename tr
- [LSP](#lsp) - [LSP](#lsp)
- [Advanced](#advanced) - [Advanced](#advanced)
- [Runtime Fallback](#runtime-fallback) - [Runtime Fallback](#runtime-fallback)
- [Model Capabilities](#model-capabilities)
- [Hashline Edit](#hashline-edit) - [Hashline Edit](#hashline-edit)
- [Experimental](#experimental) - [Experimental](#experimental)
- [Reference](#reference) - [Reference](#reference)
@@ -43,17 +42,16 @@ Complete reference for Oh My OpenCode plugin configuration. During the rename tr
### File Locations ### File Locations
User config is loaded first, then project config overrides it. In each directory, the compatibility layer recognizes both the renamed and legacy basenames. Priority order (project overrides user):
1. Project config: `.opencode/oh-my-openagent.json[c]` or `.opencode/oh-my-opencode.json[c]` 1. `.opencode/oh-my-opencode.jsonc` / `.opencode/oh-my-opencode.json`
2. User config (`.jsonc` preferred over `.json`): 2. User config (`.jsonc` preferred over `.json`):
| Platform | Path candidates | | Platform | Path |
| ----------- | --------------- | | ----------- | ----------------------------------------- |
| macOS/Linux | `~/.config/opencode/oh-my-openagent.json[c]`, `~/.config/opencode/oh-my-opencode.json[c]` | | macOS/Linux | `~/.config/opencode/oh-my-opencode.jsonc` |
| Windows | `%APPDATA%\opencode\oh-my-openagent.json[c]`, `%APPDATA%\opencode\oh-my-opencode.json[c]` | | Windows | `%APPDATA%\opencode\oh-my-opencode.jsonc` |
**Rename compatibility:** The published package and CLI binary remain `oh-my-opencode`. OpenCode plugin registration prefers `oh-my-openagent`, while legacy `oh-my-opencode` entries and config basenames still load during the transition. Config detection checks `oh-my-opencode` before `oh-my-openagent`, so if both plugin config basenames exist in the same directory, the legacy `oh-my-opencode.*` file currently wins.
JSONC supports `// line comments`, `/* block comments */`, and trailing commas. JSONC supports `// line comments`, `/* block comments */`, and trailing commas.
Enable schema autocomplete: Enable schema autocomplete:
@@ -64,7 +62,7 @@ Enable schema autocomplete:
} }
``` ```
Run `bunx oh-my-opencode install` for guided setup. Run `opencode models` to list available models. Run `bunx oh-my-openagent install` for guided setup. Run `opencode models` to list available models.
### Quick Start Example ### Quick Start Example
@@ -95,19 +93,19 @@ Here's a practical starting configuration:
}, },
"categories": { "categories": {
// quick - trivial tasks // quick trivial tasks
"quick": { "model": "opencode/gpt-5-nano" }, "quick": { "model": "opencode/gpt-5-nano" },
// unspecified-low - moderate tasks // unspecified-low moderate tasks
"unspecified-low": { "model": "anthropic/claude-sonnet-4-6" }, "unspecified-low": { "model": "anthropic/claude-sonnet-4-6" },
// unspecified-high - complex work // unspecified-high complex work
"unspecified-high": { "model": "anthropic/claude-opus-4-6", "variant": "max" }, "unspecified-high": { "model": "anthropic/claude-opus-4-6", "variant": "max" },
// writing - docs/prose // writing docs/prose
"writing": { "model": "google/gemini-3-flash" }, "writing": { "model": "google/gemini-3-flash" },
// visual-engineering - Gemini dominates visual tasks // visual-engineering Gemini dominates visual tasks
"visual-engineering": { "visual-engineering": {
"model": "google/gemini-3.1-pro", "model": "google/gemini-3.1-pro",
"variant": "high", "variant": "high",
@@ -159,28 +157,26 @@ Override built-in agent settings. Available agents: `sisyphus`, `hephaestus`, `p
Disable agents entirely: `{ "disabled_agents": ["oracle", "multimodal-looker"] }` Disable agents entirely: `{ "disabled_agents": ["oracle", "multimodal-looker"] }`
Core agents receive an injected runtime `order` field for deterministic Tab cycling in the UI: Sisyphus = 1, Hephaestus = 2, Prometheus = 3, Atlas = 4. This is not a user-configurable config key.
#### Agent Options #### Agent Options
| Option | Type | Description | | Option | Type | Description |
| ----------------- | -------------- | --------------------------------------------------------------- | | ----------------- | ------------- | ------------------------------------------------------ |
| `model` | string | Model override (`provider/model`) | | `model` | string | Model override (`provider/model`) |
| `fallback_models` | string\|array | Fallback models on API errors. Supports strings or mixed arrays of strings and object entries with per-model settings | | `fallback_models` | string\|array | Fallback models on API errors |
| `temperature` | number | Sampling temperature | | `temperature` | number | Sampling temperature |
| `top_p` | number | Top-p sampling | | `top_p` | number | Top-p sampling |
| `prompt` | string | Replace system prompt. Supports `file://` URIs | | `prompt` | string | Replace system prompt |
| `prompt_append` | string | Append to system prompt. Supports `file://` URIs | | `prompt_append` | string | Append to system prompt |
| `tools` | array | Allowed tools list | | `tools` | array | Allowed tools list |
| `disable` | boolean | Disable this agent | | `disable` | boolean | Disable this agent |
| `mode` | string | Agent mode | | `mode` | string | Agent mode |
| `color` | string | UI color | | `color` | string | UI color |
| `permission` | object | Per-tool permissions (see below) | | `permission` | object | Per-tool permissions (see below) |
| `category` | string | Inherit model from category | | `category` | string | Inherit model from category |
| `variant` | string | Model variant: `max`, `high`, `medium`, `low`, `xhigh`. Normalized to supported values | | `variant` | string | Model variant: `max`, `high`, `medium`, `low`, `xhigh` |
| `maxTokens` | number | Max response tokens | | `maxTokens` | number | Max response tokens |
| `thinking` | object | Anthropic extended thinking | | `thinking` | object | Anthropic extended thinking |
| `reasoningEffort` | string | OpenAI reasoning: `none`, `minimal`, `low`, `medium`, `high`, `xhigh`. Normalized to supported values | | `reasoningEffort` | string | OpenAI reasoning: `low`, `medium`, `high`, `xhigh` |
| `textVerbosity` | string | Text verbosity: `low`, `medium`, `high` | | `textVerbosity` | string | Text verbosity: `low`, `medium`, `high` |
| `providerOptions` | object | Provider-specific options | | `providerOptions` | object | Provider-specific options |
@@ -220,65 +216,6 @@ Control what tools an agent can use:
| `doom_loop` | `ask` / `allow` / `deny` | | `doom_loop` | `ask` / `allow` / `deny` |
| `external_directory` | `ask` / `allow` / `deny` | | `external_directory` | `ask` / `allow` / `deny` |
#### Fallback Models with Per-Model Settings
`fallback_models` accepts either a single model string or an array. Array entries can be plain strings or objects with individual model settings:
```jsonc
{
"agents": {
"sisyphus": {
"model": "anthropic/claude-opus-4-6",
"fallback_models": [
// Simple string fallback
"openai/gpt-5.4",
// Object with per-model settings
{
"model": "google/gemini-3.1-pro",
"variant": "high",
"temperature": 0.2
},
{
"model": "anthropic/claude-sonnet-4-6",
"thinking": { "type": "enabled", "budgetTokens": 64000 }
}
]
}
}
}
```
Object entries support: `model`, `variant`, `reasoningEffort`, `temperature`, `top_p`, `maxTokens`, `thinking`.
#### File URIs for Prompts
Both `prompt` and `prompt_append` support loading content from files via `file://` URIs. Category-level `prompt_append` supports the same URI forms.
```jsonc
{
"agents": {
"sisyphus": {
"prompt_append": "file:///absolute/path/to/prompt.txt"
},
"oracle": {
"prompt": "file://./relative/to/project/prompt.md"
},
"explore": {
"prompt_append": "file://~/home/dir/prompt.txt"
}
},
"categories": {
"custom": {
"model": "anthropic/claude-sonnet-4-6",
"prompt_append": "file://./category-context.md"
}
}
}
```
Paths can be absolute (`file:///abs/path`), relative to project root (`file://./rel/path`), or home-relative (`file://~/home/path`). If a file URI cannot be decoded, resolved, or read, OmO inserts a warning placeholder into the prompt instead of failing hard.
### Categories ### Categories
Domain-specific model delegation used by the `task()` tool. When Sisyphus delegates work, it picks a category, not a model name. Domain-specific model delegation used by the `task()` tool. When Sisyphus delegates work, it picks a category, not a model name.
@@ -291,7 +228,7 @@ Domain-specific model delegation used by the `task()` tool. When Sisyphus delega
| `ultrabrain` | `openai/gpt-5.4` (xhigh) | Deep logical reasoning, complex architecture | | `ultrabrain` | `openai/gpt-5.4` (xhigh) | Deep logical reasoning, complex architecture |
| `deep` | `openai/gpt-5.3-codex` (medium) | Autonomous problem-solving, thorough research | | `deep` | `openai/gpt-5.3-codex` (medium) | Autonomous problem-solving, thorough research |
| `artistry` | `google/gemini-3.1-pro` (high) | Creative/unconventional approaches | | `artistry` | `google/gemini-3.1-pro` (high) | Creative/unconventional approaches |
| `quick` | `openai/gpt-5.4-mini` | Trivial tasks, typo fixes, single-file changes | | `quick` | `anthropic/claude-haiku-4-5` | Trivial tasks, typo fixes, single-file changes |
| `unspecified-low` | `anthropic/claude-sonnet-4-6` | General tasks, low effort | | `unspecified-low` | `anthropic/claude-sonnet-4-6` | General tasks, low effort |
| `unspecified-high` | `anthropic/claude-opus-4-6` (max) | General tasks, high effort | | `unspecified-high` | `anthropic/claude-opus-4-6` (max) | General tasks, high effort |
| `writing` | `google/gemini-3-flash` | Documentation, prose, technical writing | | `writing` | `google/gemini-3-flash` | Documentation, prose, technical writing |
@@ -303,16 +240,16 @@ Domain-specific model delegation used by the `task()` tool. When Sisyphus delega
| Option | Type | Default | Description | | Option | Type | Default | Description |
| ------------------- | ------------- | ------- | ------------------------------------------------------------------- | | ------------------- | ------------- | ------- | ------------------------------------------------------------------- |
| `model` | string | - | Model override | | `model` | string | - | Model override |
| `fallback_models` | string\|array | - | Fallback models on API errors. Supports strings or mixed arrays of strings and object entries with per-model settings | | `fallback_models` | string\|array | - | Fallback models on API errors |
| `temperature` | number | - | Sampling temperature | | `temperature` | number | - | Sampling temperature |
| `top_p` | number | - | Top-p sampling | | `top_p` | number | - | Top-p sampling |
| `maxTokens` | number | - | Max response tokens | | `maxTokens` | number | - | Max response tokens |
| `thinking` | object | - | Anthropic extended thinking | | `thinking` | object | - | Anthropic extended thinking |
| `reasoningEffort` | string | - | OpenAI reasoning effort. Unsupported values are normalized | | `reasoningEffort` | string | - | OpenAI reasoning effort |
| `textVerbosity` | string | - | Text verbosity | | `textVerbosity` | string | - | Text verbosity |
| `tools` | array | - | Allowed tools | | `tools` | array | - | Allowed tools |
| `prompt_append` | string | - | Append to system prompt | | `prompt_append` | string | - | Append to system prompt |
| `variant` | string | - | Model variant. Unsupported values are normalized | | `variant` | string | - | Model variant |
| `description` | string | - | Shown in `task()` tool prompt | | `description` | string | - | Shown in `task()` tool prompt |
| `is_unstable_agent` | boolean | `false` | Force background mode + monitoring. Auto-enabled for Gemini models. | | `is_unstable_agent` | boolean | `false` | Force background mode + monitoring. Auto-enabled for Gemini models. |
@@ -320,66 +257,41 @@ Disable categories: `{ "disabled_categories": ["ultrabrain"] }`
### Model Resolution ### Model Resolution
Runtime priority: 3-step priority at runtime:
1. **UI-selected model** - model chosen in the OpenCode UI, for primary agents
2. **User override** - model set in config → used exactly as-is. Even on cold cache, explicit user configuration takes precedence over hardcoded fallback chains
3. **Category default** - model inherited from the assigned category config
4. **User `fallback_models`** - user-configured fallback list is tried before built-in fallback chains
5. **Provider fallback chain** - built-in provider/model chain from OmO source
6. **System default** - OpenCode's configured default model
#### Model Settings Compatibility
Model settings are compatibility-normalized against model capabilities instead of failing hard.
Normalized fields:
- `variant` - downgraded to the closest supported value
- `reasoningEffort` - downgraded to the closest supported value, or removed if unsupported
- `temperature` - removed if unsupported by the model metadata
- `top_p` - removed if unsupported by the model metadata
- `maxTokens` - capped to the model's reported max output limit
- `thinking` - removed if the target model does not support thinking
Examples:
- Claude models do not support `reasoningEffort` - it is removed automatically
- GPT-4.1 does not support reasoning - `reasoningEffort` is removed
- o-series models support `none` through `high` - `xhigh` is downgraded to `high`
- GPT-5 supports `none`, `minimal`, `low`, `medium`, `high`, `xhigh` - all pass through
Capability data comes from provider runtime metadata first. OmO also ships bundled models.dev-backed capability data, supports a refreshable local models.dev cache, and falls back to heuristic family detection plus alias rules when exact metadata is unavailable. `bunx oh-my-opencode doctor` surfaces capability diagnostics and warns when a configured model relies on compatibility fallback.
1. **User override** — model set in config → used exactly as-is
2. **Provider fallback chain** — tries each provider in priority order until available
3. **System default** — falls back to OpenCode's configured default model
#### Agent Provider Chains #### Agent Provider Chains
| Agent | Default Model | Provider Priority | | Agent | Default Model | Provider Priority |
| --------------------- | ------------------- | ---------------------------------------------------------------------------- | | --------------------- | ------------------- | ---------------------------------------------------------------------------- |
| **Sisyphus** | `claude-opus-4-6` | `anthropic\|github-copilot\|opencode/claude-opus-4-6 (max)``opencode-go/kimi-k2.5``kimi-for-coding/k2p5``opencode\|moonshotai\|moonshotai-cn\|firmware\|ollama-cloud\|aihubmix/kimi-k2.5``openai\|github-copilot\|opencode/gpt-5.4 (medium)``zai-coding-plan\|opencode/glm-5``opencode/big-pickle` | | **Sisyphus** | `claude-opus-4-6` | `claude-opus-4-6``glm-5``big-pickle` |
| **Hephaestus** | `gpt-5.4` | `gpt-5.4 (medium)` | | **Hephaestus** | `gpt-5.3-codex` | `gpt-5.3-codex``gpt-5.4` (GitHub Copilot fallback) |
| **oracle** | `gpt-5.4` | `openai\|github-copilot\|opencode/gpt-5.4 (high)``google\|github-copilot\|opencode/gemini-3.1-pro (high)``anthropic\|github-copilot\|opencode/claude-opus-4-6 (max)``opencode-go/glm-5` | | **oracle** | `gpt-5.4` | `gpt-5.4``gemini-3.1-pro``claude-opus-4-6` |
| **librarian** | `minimax-m2.7` | `opencode-go/minimax-m2.7``opencode/minimax-m2.7-highspeed``anthropic\|opencode/claude-haiku-4-5``opencode/gpt-5-nano` | | **librarian** | `gemini-3-flash` | `gemini-3-flash``minimax-m2.5-free``big-pickle` |
| **explore** | `grok-code-fast-1` | `github-copilot\|xai/grok-code-fast-1``opencode-go/minimax-m2.7-highspeed``opencode/minimax-m2.7``anthropic\|opencode/claude-haiku-4-5``opencode/gpt-5-nano` | | **explore** | `grok-code-fast-1` | `grok-code-fast-1``minimax-m2.5-free``claude-haiku-4-5``gpt-5-nano` |
| **multimodal-looker** | `gpt-5.4` | `openai\|opencode/gpt-5.4 (medium)``opencode-go/kimi-k2.5``zai-coding-plan/glm-4.6v``openai\|github-copilot\|opencode/gpt-5-nano` | | **multimodal-looker** | `gpt-5.3-codex` | `gpt-5.3-codex``k2p5``gemini-3-flash``glm-4.6v``gpt-5-nano` |
| **Prometheus** | `claude-opus-4-6` | `anthropic\|github-copilot\|opencode/claude-opus-4-6 (max)``openai\|github-copilot\|opencode/gpt-5.4 (high)``opencode-go/glm-5``google\|github-copilot\|opencode/gemini-3.1-pro` | | **Prometheus** | `claude-opus-4-6` | `claude-opus-4-6``gpt-5.4``gemini-3.1-pro` |
| **Metis** | `claude-opus-4-6` | `anthropic\|github-copilot\|opencode/claude-opus-4-6 (max)``openai\|github-copilot\|opencode/gpt-5.4 (high)``opencode-go/glm-5``kimi-for-coding/k2p5` | | **Metis** | `claude-opus-4-6` | `claude-opus-4-6``gpt-5.4``gemini-3.1-pro` |
| **Momus** | `gpt-5.4` | `openai\|github-copilot\|opencode/gpt-5.4 (xhigh)``anthropic\|github-copilot\|opencode/claude-opus-4-6 (max)``google\|github-copilot\|opencode/gemini-3.1-pro (high)``opencode-go/glm-5` | | **Momus** | `gpt-5.4` | `gpt-5.4``claude-opus-4-6``gemini-3.1-pro` |
| **Atlas** | `claude-sonnet-4-6` | `anthropic\|github-copilot\|opencode/claude-sonnet-4-6``opencode-go/kimi-k2.5``openai\|github-copilot\|opencode/gpt-5.4 (medium)``opencode-go/minimax-m2.7` | | **Atlas** | `claude-sonnet-4-6` | `claude-sonnet-4-6``gpt-5.4` |
#### Category Provider Chains #### Category Provider Chains
| Category | Default Model | Provider Priority | | Category | Default Model | Provider Priority |
| ---------------------- | ------------------- | -------------------------------------------------------------- | | ---------------------- | ------------------- | -------------------------------------------------------------- |
| **visual-engineering** | `gemini-3.1-pro` | `google\|github-copilot\|opencode/gemini-3.1-pro (high)``zai-coding-plan\|opencode/glm-5``anthropic\|github-copilot\|opencode/claude-opus-4-6 (max)``opencode-go/glm-5``kimi-for-coding/k2p5` | | **visual-engineering** | `gemini-3.1-pro` | `gemini-3.1-pro``glm-5``claude-opus-4-6` |
| **ultrabrain** | `gpt-5.4` | `openai\|opencode/gpt-5.4 (xhigh)``google\|github-copilot\|opencode/gemini-3.1-pro (high)``anthropic\|github-copilot\|opencode/claude-opus-4-6 (max)``opencode-go/glm-5` | | **ultrabrain** | `gpt-5.4` | `gpt-5.4``gemini-3.1-pro``claude-opus-4-6` |
| **deep** | `gpt-5.3-codex` | `openai\|opencode/gpt-5.3-codex (medium)``anthropic\|github-copilot\|opencode/claude-opus-4-6 (max)``google\|github-copilot\|opencode/gemini-3.1-pro (high)` | | **deep** | `gpt-5.3-codex` | `gpt-5.3-codex``claude-opus-4-6``gemini-3.1-pro` |
| **artistry** | `gemini-3.1-pro` | `google\|github-copilot\|opencode/gemini-3.1-pro (high)``anthropic\|github-copilot\|opencode/claude-opus-4-6 (max)``openai\|github-copilot\|opencode/gpt-5.4` | | **artistry** | `gemini-3.1-pro` | `gemini-3.1-pro``claude-opus-4-6``gpt-5.4` |
| **quick** | `gpt-5.4-mini` | `openai\|github-copilot\|opencode/gpt-5.4-mini` `anthropic\|github-copilot\|opencode/claude-haiku-4-5``google\|github-copilot\|opencode/gemini-3-flash``opencode-go/minimax-m2.7``opencode/gpt-5-nano` | | **quick** | `claude-haiku-4-5` | `claude-haiku-4-5``gemini-3-flash``gpt-5-nano` |
| **unspecified-low** | `claude-sonnet-4-6` | `anthropic\|github-copilot\|opencode/claude-sonnet-4-6``openai\|opencode/gpt-5.3-codex (medium)``opencode-go/kimi-k2.5``google\|github-copilot\|opencode/gemini-3-flash``opencode-go/minimax-m2.7` | | **unspecified-low** | `claude-sonnet-4-6` | `claude-sonnet-4-6``gpt-5.3-codex``gemini-3-flash` |
| **unspecified-high** | `claude-opus-4-6` | `anthropic\|github-copilot\|opencode/claude-opus-4-6 (max)``openai\|github-copilot\|opencode/gpt-5.4 (high)``zai-coding-plan\|opencode/glm-5``kimi-for-coding/k2p5``opencode-go/glm-5``opencode/kimi-k2.5``opencode\|moonshotai\|moonshotai-cn\|firmware\|ollama-cloud\|aihubmix/kimi-k2.5` | | **unspecified-high** | `claude-opus-4-6` | `claude-opus-4-6``gpt-5.4 (high)``glm-5``k2p5``kimi-k2.5` |
| **writing** | `gemini-3-flash` | `google\|github-copilot\|opencode/gemini-3-flash``opencode-go/kimi-k2.5``anthropic\|github-copilot\|opencode/claude-sonnet-4-6``opencode-go/minimax-m2.7` | | **writing** | `gemini-3-flash` | `gemini-3-flash``claude-sonnet-4-6` |
Run `bunx oh-my-opencode doctor --verbose` to see effective model resolution for your config. Run `bunx oh-my-openagent doctor --verbose` to see effective model resolution for your config.
--- ---
@@ -506,17 +418,17 @@ Disable built-in skills: `{ "disabled_skills": ["playwright"] }`
Disable built-in hooks via `disabled_hooks`: Disable built-in hooks via `disabled_hooks`:
```json ```json
{ "disabled_hooks": ["comment-checker"] } { "disabled_hooks": ["comment-checker", "gpt-permission-continuation"] }
``` ```
Available hooks: `todo-continuation-enforcer`, `context-window-monitor`, `session-recovery`, `session-notification`, `comment-checker`, `grep-output-truncator`, `tool-output-truncator`, `directory-agents-injector`, `directory-readme-injector`, `empty-task-response-detector`, `think-mode`, `anthropic-context-window-limit-recovery`, `rules-injector`, `background-notification`, `auto-update-checker`, `startup-toast`, `keyword-detector`, `agent-usage-reminder`, `non-interactive-env`, `interactive-bash-session`, `compaction-context-injector`, `thinking-block-validator`, `claude-code-hooks`, `ralph-loop`, `preemptive-compaction`, `auto-slash-command`, `sisyphus-junior-notepad`, `no-sisyphus-gpt`, `start-work`, `runtime-fallback` Available hooks: `gpt-permission-continuation`, `todo-continuation-enforcer`, `context-window-monitor`, `session-recovery`, `session-notification`, `comment-checker`, `grep-output-truncator`, `tool-output-truncator`, `directory-agents-injector`, `directory-readme-injector`, `empty-task-response-detector`, `think-mode`, `anthropic-context-window-limit-recovery`, `rules-injector`, `background-notification`, `auto-update-checker`, `startup-toast`, `keyword-detector`, `agent-usage-reminder`, `non-interactive-env`, `interactive-bash-session`, `compaction-context-injector`, `thinking-block-validator`, `claude-code-hooks`, `ralph-loop`, `preemptive-compaction`, `auto-slash-command`, `sisyphus-junior-notepad`, `no-sisyphus-gpt`, `start-work`, `runtime-fallback`
**Notes:** **Notes:**
- `directory-agents-injector` - auto-disabled on OpenCode 1.1.37+ (native AGENTS.md support) - `directory-agents-injector` auto-disabled on OpenCode 1.1.37+ (native AGENTS.md support)
- `no-sisyphus-gpt` - **do not disable**. It blocks incompatible GPT models for Sisyphus while allowing the dedicated GPT-5.4 prompt path. - `gpt-permission-continuation` — resumes GPT sessions only when the last assistant reply ends with a permission-seeking tail like `If you want, ...`. Disable it if you prefer GPT sessions to wait for explicit user follow-up.
- `no-sisyphus-gpt`**do not disable**. It blocks incompatible GPT models for Sisyphus while allowing the dedicated GPT-5.4 prompt path.
- `startup-toast` is a sub-feature of `auto-update-checker`. Disable just the toast by adding `startup-toast` to `disabled_hooks`. - `startup-toast` is a sub-feature of `auto-update-checker`. Disable just the toast by adding `startup-toast` to `disabled_hooks`.
- `session-recovery` - automatically recovers from recoverable session errors (missing tool results, unavailable tools, thinking block violations). Shows toast notifications during recovery. Enable `experimental.auto_resume` for automatic retry after recovery.
### Commands ### Commands
@@ -593,7 +505,7 @@ Force-enable session notifications:
{ "notification": { "force_enable": true } } { "notification": { "force_enable": true } }
``` ```
`force_enable` (`false`) - force session-notification even if external notification plugins are detected. `force_enable` (`false`) force session-notification even if external notification plugins are detected.
### MCPs ### MCPs
@@ -679,233 +591,12 @@ Define `fallback_models` per agent or category:
"agents": { "agents": {
"sisyphus": { "sisyphus": {
"model": "anthropic/claude-opus-4-6", "model": "anthropic/claude-opus-4-6",
"fallback_models": [ "fallback_models": ["openai/gpt-5.4", "google/gemini-3.1-pro"]
"openai/gpt-5.4",
{
"model": "google/gemini-3.1-pro",
"variant": "high"
}
]
} }
} }
} }
``` ```
`fallback_models` also supports object-style entries so you can attach settings to a specific fallback model:
```json
{
"agents": {
"sisyphus": {
"model": "anthropic/claude-opus-4-6",
"fallback_models": [
"openai/gpt-5.4",
{
"model": "anthropic/claude-sonnet-4-6",
"variant": "high",
"thinking": { "type": "enabled", "budgetTokens": 12000 }
},
{
"model": "openai/gpt-5.3-codex",
"reasoningEffort": "high",
"temperature": 0.2,
"top_p": 0.95,
"maxTokens": 8192
}
]
}
}
}
```
Mixed arrays are allowed, so string entries and object entries can appear together in the same fallback chain.
#### Object-style `fallback_models`
Object entries use the following shape:
| Field | Type | Description |
| ----- | ---- | ----------- |
| `model` | string | Fallback model ID. Provider prefix is optional when OmO can inherit the current/default provider. |
| `variant` | string | Explicit variant override for this fallback entry. |
| `reasoningEffort` | string | OpenAI reasoning effort override for this fallback entry. |
| `temperature` | number | Temperature applied if this fallback model becomes active. |
| `top_p` | number | Top-p applied if this fallback model becomes active. |
| `maxTokens` | number | Max response tokens applied if this fallback model becomes active. |
| `thinking` | object | Anthropic thinking config applied if this fallback model becomes active. |
Per-model settings are **fallback-only**. They are promoted only when that specific fallback model is actually selected, so they do not override your primary model settings when the primary model resolves successfully.
`thinking` uses the same shape as the normal agent/category option:
| Field | Type | Description |
| ----- | ---- | ----------- |
| `type` | string | `enabled` or `disabled` |
| `budgetTokens` | number | Optional Anthropic thinking budget |
Object entries can also omit the provider prefix when OmO can infer it from the current/default provider. If you provide both inline variant syntax in `model` and an explicit `variant` field, the explicit `variant` field wins.
#### Full examples
**1. Simple string chain**
Use strings when you only need an ordered fallback chain:
```json
{
"agents": {
"atlas": {
"model": "anthropic/claude-sonnet-4-6",
"fallback_models": [
"anthropic/claude-haiku-4-5",
"openai/gpt-5.4",
"google/gemini-3.1-pro"
]
}
}
}
```
**2. Same-provider shorthand**
If the primary model already establishes the provider, fallback entries can omit the prefix:
```json
{
"agents": {
"atlas": {
"model": "openai/gpt-5.4",
"fallback_models": [
"gpt-5.4-mini",
{
"model": "gpt-5.3-codex",
"reasoningEffort": "medium",
"maxTokens": 4096
}
]
}
}
}
```
In this example OmO treats `gpt-5.4-mini` and `gpt-5.3-codex` as OpenAI fallback entries because the current/default provider is already `openai`.
**3. Mixed cross-provider chain**
Mix string entries and object entries when only some fallback models need special settings:
```json
{
"agents": {
"sisyphus": {
"model": "anthropic/claude-opus-4-6",
"fallback_models": [
"openai/gpt-5.4",
{
"model": "anthropic/claude-sonnet-4-6",
"variant": "high",
"thinking": { "type": "enabled", "budgetTokens": 12000 }
},
{
"model": "google/gemini-3.1-pro",
"variant": "high"
}
]
}
}
}
```
**4. Category-level fallback chain**
`fallback_models` works the same way under `categories`:
```json
{
"categories": {
"deep": {
"model": "openai/gpt-5.3-codex",
"fallback_models": [
{
"model": "openai/gpt-5.4",
"reasoningEffort": "xhigh",
"maxTokens": 12000
},
{
"model": "anthropic/claude-opus-4-6",
"variant": "max",
"temperature": 0.2
},
"google/gemini-3.1-pro(high)"
]
}
}
}
```
**5. Full object entry with every supported field**
This shows every supported object-style parameter in one place:
```json
{
"agents": {
"oracle": {
"model": "openai/gpt-5.4",
"fallback_models": [
{
"model": "openai/gpt-5.3-codex(low)",
"variant": "xhigh",
"reasoningEffort": "high",
"temperature": 0.3,
"top_p": 0.9,
"maxTokens": 8192,
"thinking": {
"type": "disabled"
}
}
]
}
}
}
```
In this example the explicit `"variant": "xhigh"` overrides the inline `(low)` suffix in `"model"`.
This final example is a **complete shape reference**. In real configs, prefer provider-appropriate settings:
- use `reasoningEffort` for OpenAI reasoning models
- use `thinking` for Anthropic thinking-capable models
- use `variant`, `temperature`, `top_p`, and `maxTokens` only when that fallback model supports them
### Model Capabilities
OmO can refresh a local models.dev capability snapshot on startup. This cache is controlled by `model_capabilities`.
```jsonc
{
"model_capabilities": {
"enabled": true,
"auto_refresh_on_start": true,
"refresh_timeout_ms": 5000,
"source_url": "https://models.dev/api.json"
}
}
```
| Option | Default behavior | Description |
| ------ | ---------------- | ----------- |
| `enabled` | enabled unless explicitly set to `false` | Master switch for model capability refresh behavior |
| `auto_refresh_on_start` | refresh on startup unless explicitly set to `false` | Refresh the local models.dev cache during startup checks |
| `refresh_timeout_ms` | `5000` | Timeout for the startup refresh attempt |
| `source_url` | `https://models.dev/api.json` | Override the models.dev source URL |
Notes:
- Startup refresh runs through the auto-update checker hook.
- Manual refresh is available via `bunx oh-my-opencode refresh-model-capabilities`.
- Provider runtime metadata still takes priority when OmO resolves capabilities for compatibility checks.
### Hashline Edit ### Hashline Edit
Replaces the built-in `Edit` tool with a hash-anchored version using `LINE#ID` references to prevent stale-line edits. Disabled by default. Replaces the built-in `Edit` tool with a hash-anchored version using `LINE#ID` references to prevent stale-line edits. Disabled by default.
@@ -925,7 +616,7 @@ When enabled, two companion hooks are active: `hashline-read-enhancer` (annotate
"aggressive_truncation": false, "aggressive_truncation": false,
"auto_resume": false, "auto_resume": false,
"disable_omo_env": false, "disable_omo_env": false,
"task_system": true, "task_system": false,
"dynamic_context_pruning": { "dynamic_context_pruning": {
"enabled": false, "enabled": false,
"notification": "detailed", "notification": "detailed",
@@ -955,7 +646,7 @@ When enabled, two companion hooks are active: `hashline-read-enhancer` (annotate
| `aggressive_truncation` | `false` | Aggressively truncate when token limit exceeded | | `aggressive_truncation` | `false` | Aggressively truncate when token limit exceeded |
| `auto_resume` | `false` | Auto-resume after thinking block recovery | | `auto_resume` | `false` | Auto-resume after thinking block recovery |
| `disable_omo_env` | `false` | Disable auto-injected `<omo-env>` block (date/time/locale). Improves cache hit rate. | | `disable_omo_env` | `false` | Disable auto-injected `<omo-env>` block (date/time/locale). Improves cache hit rate. |
| `task_system` | `true` | Enable Sisyphus task system | | `task_system` | `false` | Enable Sisyphus task system |
| `dynamic_context_pruning.enabled` | `false` | Auto-prune old tool outputs to manage context window | | `dynamic_context_pruning.enabled` | `false` | Auto-prune old tool outputs to manage context window |
| `dynamic_context_pruning.notification` | `detailed` | Pruning notifications: `off` / `minimal` / `detailed` | | `dynamic_context_pruning.notification` | `detailed` | Pruning notifications: `off` / `minimal` / `detailed` |
| `turn_protection.turns` | `3` | Recent turns protected from pruning (110) | | `turn_protection.turns` | `3` | Recent turns protected from pruning (110) |

View File

@@ -1,35 +1,29 @@
# Oh-My-OpenAgent Features Reference # Oh-My-OpenCode Features Reference
## Agents ## Agents
Oh-My-OpenAgent provides 11 specialized AI agents. Each has distinct expertise, optimized models, and tool permissions. Oh-My-OpenCode provides 11 specialized AI agents. Each has distinct expertise, optimized models, and tool permissions.
### Core Agents ### Primary Agents
Core-agent tab cycling is deterministic via injected runtime order field. The fixed priority order is Sisyphus (order: 1), Hephaestus (order: 2), Prometheus (order: 3), and Atlas (order: 4). Remaining agents follow after that stable core ordering.
| Agent | Model | Purpose | | Agent | Model | Purpose |
| --------------------- | ------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | --------------------- | ------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Sisyphus** | `claude-opus-4-6` | The default orchestrator. Plans, delegates, and executes complex tasks using specialized subagents with aggressive parallel execution. Todo-driven workflow with extended thinking (32k budget). Fallback: `opencode-go/kimi-k2.5``kimi-for-coding/k2p5``opencode\|moonshotai\|moonshotai-cn\|firmware\|ollama-cloud\|aihubmix/kimi-k2.5``openai\|github-copilot\|opencode/gpt-5.4 (medium)``zai-coding-plan\|opencode/glm-5``opencode/big-pickle`. | | **Sisyphus** | `claude-opus-4-6` | The default orchestrator. Plans, delegates, and executes complex tasks using specialized subagents with aggressive parallel execution. Todo-driven workflow with extended thinking (32k budget). Fallback: `kimi-k2.5``glm-5`. |
| **Hephaestus** | `gpt-5.4` | The Legitimate Craftsman. Autonomous deep worker inspired by AmpCode's deep mode. Goal-oriented execution with thorough research before action. Explores codebase patterns, completes tasks end-to-end without premature stopping. Named after the Greek god of forge and craftsmanship. Requires a GPT-capable provider. | | **Hephaestus** | `gpt-5.3-codex` | The Legitimate Craftsman. Autonomous deep worker. Goal-oriented execution with thorough research before action. Explores codebase patterns, completes tasks end-to-end. Fallback: `gpt-5.4` on GitHub Copilot. Requires a GPT-capable provider. |
| **Oracle** | `gpt-5.4` | Architecture decisions, code review, debugging. Read-only consultation with stellar logical reasoning and deep analysis. Inspired by AmpCode. Fallback: `google\|github-copilot\|opencode/gemini-3.1-pro (high)``anthropic\|github-copilot\|opencode/claude-opus-4-6 (max)``opencode-go/glm-5`. | | **Prometheus** | `claude-opus-4-6` | Strategic planner with interview mode. Creates detailed work plans through iterative questioning. Fallback: `gpt-5.4``gemini-3.1-pro`. |
| **Librarian** | `minimax-m2.7` | Multi-repo analysis, documentation lookup, OSS implementation examples. Deep codebase understanding with evidence-based answers. Fallback: `opencode/minimax-m2.7-highspeed``anthropic\|opencode/claude-haiku-4-5``opencode/gpt-5-nano`. | | **Atlas** | `claude-sonnet-4-6`| Executor. Takes the plan from Prometheus and drives it to completion, managing the todo list and coordinating subagents. Fallback: `gpt-5.4` (medium). |
| **Explore** | `grok-code-fast-1` | Fast codebase exploration and contextual grep. Fallback: `opencode-go/minimax-m2.7-highspeed``opencode/minimax-m2.7``anthropic\|opencode/claude-haiku-4-5``opencode/gpt-5-nano`. | | **Sisyphus-Junior** | _(category-dependent)_ | Category-spawned executor. Model is selected automatically based on the task category. Used when the main agent delegates work via the `task` tool. |
| **Multimodal-Looker** | `gpt-5.4` | Visual content specialist. Analyzes PDFs, images, diagrams to extract information. Fallback: `opencode-go/kimi-k2.5``zai-coding-plan/glm-4.6v``openai\|github-copilot\|opencode/gpt-5-nano`. |
### Planning Agents
| Agent | Model | Purpose | ### Specialist Subagents
| -------------- | ----------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Prometheus** | `claude-opus-4-6` | Strategic planner with interview mode. Creates detailed work plans through iterative questioning. Fallback: `openai\|github-copilot\|opencode/gpt-5.4 (high)``opencode-go/glm-5``google\|github-copilot\|opencode/gemini-3.1-pro`. |
| **Metis** | `claude-opus-4-6` | Plan consultant — pre-planning analysis. Identifies hidden intentions, ambiguities, and AI failure points. Fallback: `openai\|github-copilot\|opencode/gpt-5.4 (high)``opencode-go/glm-5``kimi-for-coding/k2p5`. |
| **Momus** | `gpt-5.4` | Plan reviewer — validates plans against clarity, verifiability, and completeness standards. Fallback: `anthropic\|github-copilot\|opencode/claude-opus-4-6 (max)``google\|github-copilot\|opencode/gemini-3.1-pro (high)``opencode-go/glm-5`. |
### Orchestration Agents | Agent | Model | Purpose |
| --------------------- | ------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------- |
| Agent | Model | Purpose | | **Oracle** | `gpt-5.4` | Architecture decisions, code review, debugging. Read-only consultation. Fallback: `gemini-3.1-pro``claude-opus-4-6`. |
| ------------------- | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Librarian** | `minimax-m2.5` | Multi-repo analysis, documentation lookup, OSS implementation examples. Fallback: `minimax-m2.5-free``claude-haiku-4-5``gpt-5-nano`. |
| **Atlas** | `claude-sonnet-4-6` | Todo-list orchestrator. Executes planned tasks systematically, managing todo items and coordinating work. Fallback: `opencode-go/kimi-k2.5``openai\|github-copilot\|opencode/gpt-5.4 (medium)``opencode-go/minimax-m2.7`. | | **Explore** | `grok-code-fast-1` | Fast codebase exploration and contextual grep. Fallback: `minimax-m2.5``minimax-m2.5-free``claude-haiku-4-5`. |
| **Sisyphus-Junior** | _(category-dependent)_ | Category-spawned executor. Model is selected automatically based on the task category (visual-engineering, quick, deep, etc.). Its built-in general fallback chain is `anthropic\|github-copilot\|opencode/claude-sonnet-4-6``opencode-go/kimi-k2.5``openai\|github-copilot\|opencode/gpt-5.4 (medium)``opencode-go/minimax-m2.7``opencode/big-pickle`. | | **Multimodal-Looker** | `gpt-5.4` | Visual content specialist. Analyzes PDFs, images, diagrams. Fallback: `kimi-k2.5``glm-4.6v``gpt-5-nano`. |
| **Metis** | `claude-opus-4-6` | Plan consultant — pre-planning analysis. Identifies hidden intentions, ambiguities, and AI failure points. Fallback: `gpt-5.4``gemini-3.1-pro`. |
| **Momus** | `gpt-5.4` | Plan reviewer — validates plans against clarity, verifiability, and completeness standards. Fallback: `claude-opus-4-6``gemini-3.1-pro`. |
### Invoking Agents ### Invoking Agents
@@ -90,9 +84,8 @@ When running inside tmux:
- Watch multiple agents work in real-time - Watch multiple agents work in real-time
- Each pane shows agent output live - Each pane shows agent output live
- Auto-cleanup when agents complete - Auto-cleanup when agents complete
- **Stable agent ordering**: core-agent tab cycling is deterministic via injected runtime order field (Sisyphus: 1, Hephaestus: 2, Prometheus: 3, Atlas: 4)
Customize agent models, prompts, and permissions in `oh-my-opencode.jsonc`. Customize agent models, prompts, and permissions in `oh-my-opencode.json`.
## Category System ## Category System
@@ -113,7 +106,7 @@ By combining these two concepts, you can generate optimal agents through `task`.
| `ultrabrain` | `openai/gpt-5.4` (xhigh) | Deep logical reasoning, complex architecture decisions requiring extensive analysis | | `ultrabrain` | `openai/gpt-5.4` (xhigh) | Deep logical reasoning, complex architecture decisions requiring extensive analysis |
| `deep` | `openai/gpt-5.3-codex` (medium) | Goal-oriented autonomous problem-solving. Thorough research before action. For hairy problems requiring deep understanding. | | `deep` | `openai/gpt-5.3-codex` (medium) | Goal-oriented autonomous problem-solving. Thorough research before action. For hairy problems requiring deep understanding. |
| `artistry` | `google/gemini-3.1-pro` (high) | Highly creative/artistic tasks, novel ideas | | `artistry` | `google/gemini-3.1-pro` (high) | Highly creative/artistic tasks, novel ideas |
| `quick` | `openai/gpt-5.4-mini` | Trivial tasks - single file changes, typo fixes, simple modifications | | `quick` | `anthropic/claude-haiku-4-5` | Trivial tasks - single file changes, typo fixes, simple modifications |
| `unspecified-low` | `anthropic/claude-sonnet-4-6` | Tasks that don't fit other categories, low effort required | | `unspecified-low` | `anthropic/claude-sonnet-4-6` | Tasks that don't fit other categories, low effort required |
| `unspecified-high` | `anthropic/claude-opus-4-6` (max) | Tasks that don't fit other categories, high effort required | | `unspecified-high` | `anthropic/claude-opus-4-6` (max) | Tasks that don't fit other categories, high effort required |
| `writing` | `google/gemini-3-flash` | Documentation, prose, technical writing | | `writing` | `google/gemini-3-flash` | Documentation, prose, technical writing |
@@ -131,7 +124,7 @@ task({
### Custom Categories ### Custom Categories
You can define custom categories in your plugin config file. During the rename transition, both `oh-my-openagent.json[c]` and legacy `oh-my-opencode.json[c]` basenames are recognized. You can define custom categories in `oh-my-opencode.json`.
#### Category Configuration Schema #### Category Configuration Schema
@@ -190,75 +183,6 @@ When you use a Category, a special agent called **Sisyphus-Junior** performs the
- **Characteristic**: Cannot **re-delegate** tasks to other agents. - **Characteristic**: Cannot **re-delegate** tasks to other agents.
- **Purpose**: Prevents infinite delegation loops and ensures focus on the assigned task. - **Purpose**: Prevents infinite delegation loops and ensures focus on the assigned task.
## Advanced Configuration
### Rename Compatibility
The published package and binary remain `oh-my-opencode`. Inside `opencode.json`, the compatibility layer now prefers the plugin entry `oh-my-openagent`, while legacy `oh-my-opencode` entries still load with a warning. Plugin config files (`oh-my-openagent.json[c]` or legacy `oh-my-opencode.json[c]`) are recognized during the transition. Run `bunx oh-my-opencode doctor` to check for legacy package name warnings.
### Fallback Models
Configure per-agent fallback chains with arrays that can mix plain model strings and per-model objects:
```jsonc
{
"agents": {
"sisyphus": {
"fallback_models": [
"opencode/glm-5",
{ "model": "openai/gpt-5.4", "variant": "high" },
{ "model": "anthropic/claude-sonnet-4-6", "thinking": { "type": "enabled", "budgetTokens": 64000 } }
]
}
}
}
```
When a model errors, the runtime can move through the configured fallback array. Object entries let you tune the backup model itself instead of only swapping the model name.
### File-Based Prompts
Load agent system prompts from external files using `file://` URLs in the `prompt` field, or append additional content with `prompt_append`. The `prompt_append` field also works on categories.
```jsonc
{
"agents": {
"sisyphus": {
"prompt": "file:///path/to/custom-prompt.md"
},
"oracle": {
"prompt_append": "file:///path/to/additional-context.md"
}
},
"categories": {
"deep": {
"prompt_append": "file:///path/to/deep-category-append.md"
}
}
}
```
Supports `~` expansion for home directory and relative `file://` paths.
Useful for:
- Version controlling prompts separately from config
- Sharing prompts across projects
- Keeping configuration files concise
- Adding category-specific context without duplicating base prompts
The file content is loaded at runtime and injected into the agent's system prompt.
### Session Recovery
The system automatically recovers from common session failures without user intervention:
- **Missing tool results**: reconstructs recoverable tool state and skips invalid tool-part IDs instead of failing the whole recovery pass
- **Thinking block violations**: Recovers from API thinking block mismatches
- **Empty messages**: Reconstructs message history when content is missing
- **Context window limits**: Gracefully handles Claude context window exceeded errors with intelligent compaction
- **JSON parse errors**: Recovers from malformed tool outputs
Recovery happens transparently during agent execution. You see the result, not the failure.
## Skills ## Skills
Skills provide specialized workflows with embedded MCP servers and detailed instructions. A Skill is a mechanism that injects **specialized knowledge (Context)** and **tools (MCP)** for specific domains into agents. Skills provide specialized workflows with embedded MCP servers and detailed instructions. A Skill is a mechanism that injects **specialized knowledge (Context)** and **tools (MCP)** for specific domains into agents.
@@ -308,7 +232,7 @@ Skills provide specialized workflows with embedded MCP servers and detailed inst
### Browser Automation Options ### Browser Automation Options
Oh-My-OpenAgent provides two browser automation providers, configurable via `browser_automation_engine.provider`. Oh-My-OpenCode provides two browser automation providers, configurable via `browser_automation_engine.provider`.
#### Option 1: Playwright MCP (Default) #### Option 1: Playwright MCP (Default)
@@ -751,6 +675,7 @@ Hooks intercept and modify behavior at key points in the agent lifecycle across
| **ralph-loop** | Event + Message | Manages self-referential loop continuation. | | **ralph-loop** | Event + Message | Manages self-referential loop continuation. |
| **start-work** | Message | Handles /start-work command execution. | | **start-work** | Message | Handles /start-work command execution. |
| **auto-slash-command** | Message | Automatically executes slash commands from prompts. | | **auto-slash-command** | Message | Automatically executes slash commands from prompts. |
| **gpt-permission-continuation** | Event | Auto-continues GPT sessions when the final assistant reply ends with a permission-seeking tail such as `If you want, ...`. |
| **stop-continuation-guard** | Event + Message | Guards the stop-continuation mechanism. | | **stop-continuation-guard** | Event + Message | Guards the stop-continuation mechanism. |
| **category-skill-reminder** | Event + PostToolUse | Reminds agents about available category skills for delegation. | | **category-skill-reminder** | Event + PostToolUse | Reminds agents about available category skills for delegation. |
| **anthropic-effort** | Params | Adjusts Anthropic API effort level based on context. | | **anthropic-effort** | Params | Adjusts Anthropic API effort level based on context. |
@@ -805,6 +730,7 @@ Hooks intercept and modify behavior at key points in the agent lifecycle across
| Hook | Event | Description | | Hook | Event | Description |
| ------------------------------ | ----- | ---------------------------------------------------------- | | ------------------------------ | ----- | ---------------------------------------------------------- |
| **gpt-permission-continuation** | Event | Continues GPT replies that end in a permission-seeking tail. |
| **todo-continuation-enforcer** | Event | Enforces todo completion — yanks idle agents back to work. | | **todo-continuation-enforcer** | Event | Enforces todo completion — yanks idle agents back to work. |
| **compaction-todo-preserver** | Event | Preserves todo state during session compaction. | | **compaction-todo-preserver** | Event | Preserves todo state during session compaction. |
| **unstable-agent-babysitter** | Event | Handles unstable agent behavior with recovery strategies. | | **unstable-agent-babysitter** | Event | Handles unstable agent behavior with recovery strategies. |
@@ -856,10 +782,12 @@ Disable specific hooks in config:
```json ```json
{ {
"disabled_hooks": ["comment-checker"] "disabled_hooks": ["comment-checker", "gpt-permission-continuation"]
} }
``` ```
Use `gpt-permission-continuation` when you want GPT sessions to stop at permission-seeking endings instead of auto-resuming.
## MCPs ## MCPs
### Built-in MCPs ### Built-in MCPs
@@ -915,41 +843,9 @@ When a skill MCP has `oauth` configured:
Pre-authenticate via CLI: Pre-authenticate via CLI:
```bash ```bash
bunx oh-my-opencode mcp oauth login <server-name> --server-url https://api.example.com bunx oh-my-openagent mcp oauth login <server-name> --server-url https://api.example.com
``` ```
## Model Capabilities
Model capabilities are models.dev-backed, with a refreshable cache and compatibility diagnostics. The system combines bundled models.dev snapshot data, optional refreshed cache data, provider runtime metadata, and heuristics when exact metadata is unavailable.
### Refreshing Capabilities
Update the local cache with the latest model information:
```bash
bunx oh-my-opencode refresh-model-capabilities
```
Configure automatic refresh at startup:
```jsonc
{
"model_capabilities": {
"enabled": true,
"auto_refresh_on_start": true,
"refresh_timeout_ms": 5000,
"source_url": "https://models.dev/api.json"
}
}
```
### Capability Diagnostics
Run `bunx oh-my-opencode doctor` to see capability diagnostics including:
- effective model resolution for agents and categories
- warnings when configured models rely on compatibility fallback
- override compatibility details alongside model resolution output
## Context Injection ## Context Injection
### Directory AGENTS.md ### Directory AGENTS.md

View File

@@ -1,86 +0,0 @@
# Model Settings Compatibility Resolver Implementation Plan
> **For agentic workers:** REQUIRED: Use superpowers:subagent-driven-development (if subagents available) or superpowers:executing-plans to implement this plan. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** Centralize compatibility handling for `variant` and `reasoningEffort` so an already-selected model receives the best valid settings for that exact model.
**Architecture:** Introduce a pure shared resolver in `src/shared/` that computes compatible settings and records downgrades/removals. Integrate it first in `chat.params`, then keep Claude-specific effort logic as a thin layer rather than a special-case policy owner.
**Tech Stack:** TypeScript, Bun test, existing shared model normalization/utilities, OpenCode plugin `chat.params` path.
---
### Task 1: Create the pure compatibility resolver
**Files:**
- Create: `src/shared/model-settings-compatibility.ts`
- Create: `src/shared/model-settings-compatibility.test.ts`
- Modify: `src/shared/index.ts`
- [ ] **Step 1: Write failing tests for exact keep behavior**
- [ ] **Step 2: Write failing tests for downgrade behavior (`max` -> `high`, `xhigh` -> `high` where needed)**
- [ ] **Step 3: Write failing tests for unsupported-value removal**
- [ ] **Step 4: Write failing tests for model-family distinctions (Opus vs Sonnet/Haiku, GPT-family variants)**
- [ ] **Step 5: Implement the pure resolver with explicit capability ladders**
- [ ] **Step 6: Export the resolver from `src/shared/index.ts`**
- [ ] **Step 7: Run `bun test src/shared/model-settings-compatibility.test.ts`**
- [ ] **Step 8: Commit**
### Task 2: Integrate resolver into chat.params
**Files:**
- Modify: `src/plugin/chat-params.ts`
- Modify: `src/plugin/chat-params.test.ts`
- [ ] **Step 1: Write failing tests showing `chat.params` applies resolver output to runtime settings**
- [ ] **Step 2: Ensure tests cover both `variant` and `reasoningEffort` decisions**
- [ ] **Step 3: Update `chat-params.ts` to call the shared resolver before hook-specific adjustments**
- [ ] **Step 4: Preserve existing prompt-param-store merging behavior**
- [ ] **Step 5: Run `bun test src/plugin/chat-params.test.ts`**
- [ ] **Step 6: Commit**
### Task 3: Re-scope anthropic-effort around the resolver
**Files:**
- Modify: `src/hooks/anthropic-effort/hook.ts`
- Modify: `src/hooks/anthropic-effort/index.test.ts`
- [ ] **Step 1: Write failing tests that codify the intended remaining Anthropic-specific behavior after centralization**
- [ ] **Step 2: Reduce `anthropic-effort` to Claude/Anthropic-specific effort injection where still needed**
- [ ] **Step 3: Remove duplicated compatibility policy from the hook if the shared resolver now owns it**
- [ ] **Step 4: Run `bun test src/hooks/anthropic-effort/index.test.ts`**
- [ ] **Step 5: Commit**
### Task 4: Add integration/regression coverage across real request paths
**Files:**
- Modify: `src/plugin/chat-params.test.ts`
- Modify: `src/hooks/anthropic-effort/index.test.ts`
- Add tests only where needed in nearby suites
- [ ] **Step 1: Add regression test for non-Opus Claude with `variant=max` resolving to compatible settings without ad hoc path-only logic**
- [ ] **Step 2: Add regression test for GPT-style `reasoningEffort` compatibility**
- [ ] **Step 3: Add regression test showing supported values remain unchanged**
- [ ] **Step 4: Run the focused test set**
- [ ] **Step 5: Commit**
### Task 5: Verify full quality bar
**Files:**
- No intended code changes
- [ ] **Step 1: Run `bun run typecheck`**
- [ ] **Step 2: Run a focused suite for the touched files**
- [ ] **Step 3: If clean, run `bun test`**
- [ ] **Step 4: Review diff for accidental scope creep**
- [ ] **Step 5: Commit any final cleanup**
### Task 6: Prepare PR metadata
**Files:**
- No repo file change required unless docs are updated further
- [ ] **Step 1: Write a human summary explaining this is settings compatibility, not model fallback**
- [ ] **Step 2: Document scope: Phase 1 covers `variant` and `reasoningEffort` only**
- [ ] **Step 3: Document explicit non-goals: no model switching, no automatic upscaling in Phase 1**
- [ ] **Step 4: Request review**

View File

@@ -1,164 +0,0 @@
# Model Settings Compatibility Resolver Design
## Goal
Introduce a central resolver that takes an already-selected model and a set of desired model settings, then returns the best compatible configuration for that exact model.
This is explicitly separate from model fallback.
## Problem
Today, logic for `variant` and `reasoningEffort` compatibility is scattered across multiple places:
- `hooks/anthropic-effort`
- `plugin/chat-params`
- agent/category/fallback config layers
- delegate/background prompt plumbing
That creates inconsistent behavior:
- some paths clamp unsupported levels
- some paths pass them through unchanged
- some paths silently drop them
- some paths use model-family-specific assumptions that do not generalize
The result is brittle request behavior even when the chosen model itself is valid.
## Scope
Phase 1 covers only:
- `variant`
- `reasoningEffort`
Out of scope for Phase 1:
- model fallback itself
- `thinking`
- `maxTokens`
- `temperature`
- `top_p`
- automatic upward remapping of settings
## Desired behavior
Given a fixed model and desired settings:
1. If a desired value is supported, keep it.
2. If not supported, downgrade to the nearest lower compatible value.
3. If no compatible value exists, drop the field.
4. Do not switch models.
5. Do not automatically upgrade settings in Phase 1.
## Architecture
Add a central module:
- `src/shared/model-settings-compatibility.ts`
Core API:
```ts
type DesiredModelSettings = {
variant?: string
reasoningEffort?: string
}
type ModelSettingsCompatibilityInput = {
providerID: string
modelID: string
desired: DesiredModelSettings
}
type ModelSettingsCompatibilityChange = {
field: "variant" | "reasoningEffort"
from: string
to?: string
reason: string
}
type ModelSettingsCompatibilityResult = {
variant?: string
reasoningEffort?: string
changes: ModelSettingsCompatibilityChange[]
}
```
## Compatibility model
Phase 1 should be **metadata-first where the platform exposes reliable capability data**, and only fall back to family-based rules when that metadata is absent.
### Variant compatibility
Preferred source of truth:
- OpenCode/provider model metadata (`variants`)
Fallback when metadata is unavailable:
- family-based ladders
Examples of fallback ladders:
- Claude Opus family: `low`, `medium`, `high`, `max`
- Claude Sonnet/Haiku family: `low`, `medium`, `high`
- OpenAI GPT family: conservative family fallback only when metadata is missing
- Unknown family: drop unsupported values conservatively
### Reasoning effort compatibility
Current Phase 1 source of truth:
- conservative model/provider family heuristics
Reason:
- the currently available OpenCode SDK/provider metadata exposes model `variants`, but does not expose an equivalent per-model capability list for `reasoningEffort` levels
Examples:
- GPT/OpenAI-style models: `low`, `medium`, `high`, `xhigh` where supported by family heuristics
- Claude family via current OpenCode path: treat `reasoningEffort` as unsupported in Phase 1 and remove it
The resolver should remain pure model/settings logic only. Transport restrictions remain the responsibility of the request-building path.
## Separation of concerns
This design intentionally separates:
- model selection (`resolveModel...`, fallback chains)
- settings compatibility (this resolver)
- request transport compatibility (`chat.params`, prompt body constraints)
That keeps responsibilities clear:
- choose model first
- normalize settings second
- build request third
## First integration point
Phase 1 should first integrate into `chat.params`.
Why:
- it is already the centralized path for request-time tuning
- it can influence provider-facing options without leaking unsupported fields into prompt payload bodies
- it avoids trying to patch every prompt constructor at once
## Rollout plan
### Phase 1
- add resolver module and tests
- integrate into `chat.params`
- migrate `anthropic-effort` to either use the resolver or become a thin Claude-specific supplement around it
### Phase 2
- expand to `thinking`, `maxTokens`, `temperature`, `top_p`
- formalize request-path capability tables if needed
### Phase 3
- centralize all variant/reasoning normalization away from scattered hooks and ad hoc callers
## Risks
- Overfitting family rules to current model naming conventions
- Accidentally changing request semantics on paths that currently rely on implicit behavior
- Mixing provider transport limitations with model capability logic
## Mitigations
- Keep resolver pure and narrowly scoped in Phase 1
- Add explicit regression tests for keep/downgrade/drop decisions
- Integrate at one central point first (`chat.params`)
- Preserve existing behavior where desired values are already valid
## Recommendation
Proceed with the central resolver as a new, isolated implementation in a dedicated branch/worktree.
This is the clean long-term path and is more reviewable than continuing to add special-case clamps in hooks.

View File

@@ -1,12 +1,12 @@
{ {
"name": "oh-my-opencode", "name": "oh-my-openagent",
"version": "3.14.0", "version": "3.11.0",
"description": "The Best AI Agent Harness - Batteries-Included OpenCode Plugin with Multi-Model Orchestration, Parallel Background Agents, and Crafted LSP/AST Tools", "description": "The Best AI Agent Harness - Batteries-Included OpenCode Plugin with Multi-Model Orchestration, Parallel Background Agents, and Crafted LSP/AST Tools",
"main": "dist/index.js", "main": "dist/index.js",
"types": "dist/index.d.ts", "types": "dist/index.d.ts",
"type": "module", "type": "module",
"bin": { "bin": {
"oh-my-opencode": "bin/oh-my-opencode.js" "oh-my-openagent": "bin/oh-my-opencode.js"
}, },
"files": [ "files": [
"dist", "dist",
@@ -25,12 +25,10 @@
"build:all": "bun run build && bun run build:binaries", "build:all": "bun run build && bun run build:binaries",
"build:binaries": "bun run script/build-binaries.ts", "build:binaries": "bun run script/build-binaries.ts",
"build:schema": "bun run script/build-schema.ts", "build:schema": "bun run script/build-schema.ts",
"build:model-capabilities": "bun run script/build-model-capabilities.ts",
"clean": "rm -rf dist", "clean": "rm -rf dist",
"prepare": "bun run build", "prepare": "bun run build",
"postinstall": "node postinstall.mjs", "postinstall": "node postinstall.mjs",
"prepublishOnly": "bun run clean && bun run build", "prepublishOnly": "bun run clean && bun run build",
"test:model-capabilities": "bun test src/shared/model-capability-aliases.test.ts src/shared/model-capability-guardrails.test.ts src/shared/model-capabilities.test.ts src/cli/doctor/checks/model-resolution.test.ts --bail",
"typecheck": "tsc --noEmit", "typecheck": "tsc --noEmit",
"test": "bun test" "test": "bun test"
}, },
@@ -78,17 +76,17 @@
"typescript": "^5.7.3" "typescript": "^5.7.3"
}, },
"optionalDependencies": { "optionalDependencies": {
"oh-my-opencode-darwin-arm64": "3.14.0", "oh-my-openagent-darwin-arm64": "3.11.0",
"oh-my-opencode-darwin-x64": "3.14.0", "oh-my-openagent-darwin-x64": "3.11.0",
"oh-my-opencode-darwin-x64-baseline": "3.14.0", "oh-my-openagent-darwin-x64-baseline": "3.11.0",
"oh-my-opencode-linux-arm64": "3.14.0", "oh-my-openagent-linux-arm64": "3.11.0",
"oh-my-opencode-linux-arm64-musl": "3.14.0", "oh-my-openagent-linux-arm64-musl": "3.11.0",
"oh-my-opencode-linux-x64": "3.14.0", "oh-my-openagent-linux-x64": "3.11.0",
"oh-my-opencode-linux-x64-baseline": "3.14.0", "oh-my-openagent-linux-x64-baseline": "3.11.0",
"oh-my-opencode-linux-x64-musl": "3.14.0", "oh-my-openagent-linux-x64-musl": "3.11.0",
"oh-my-opencode-linux-x64-musl-baseline": "3.14.0", "oh-my-openagent-linux-x64-musl-baseline": "3.11.0",
"oh-my-opencode-windows-x64": "3.14.0", "oh-my-openagent-windows-x64": "3.11.0",
"oh-my-opencode-windows-x64-baseline": "3.14.0" "oh-my-openagent-windows-x64-baseline": "3.11.0"
}, },
"overrides": { "overrides": {
"@opencode-ai/sdk": "^1.2.24" "@opencode-ai/sdk": "^1.2.24"

View File

@@ -1,6 +1,6 @@
{ {
"name": "oh-my-opencode-darwin-arm64", "name": "oh-my-opencode-darwin-arm64",
"version": "3.14.0", "version": "3.11.0",
"description": "Platform-specific binary for oh-my-opencode (darwin-arm64)", "description": "Platform-specific binary for oh-my-opencode (darwin-arm64)",
"license": "MIT", "license": "MIT",
"repository": { "repository": {

View File

@@ -1,6 +1,6 @@
{ {
"name": "oh-my-opencode-darwin-x64-baseline", "name": "oh-my-opencode-darwin-x64-baseline",
"version": "3.14.0", "version": "3.11.0",
"description": "Platform-specific binary for oh-my-opencode (darwin-x64-baseline, no AVX2)", "description": "Platform-specific binary for oh-my-opencode (darwin-x64-baseline, no AVX2)",
"license": "MIT", "license": "MIT",
"repository": { "repository": {

View File

@@ -1,6 +1,6 @@
{ {
"name": "oh-my-opencode-darwin-x64", "name": "oh-my-opencode-darwin-x64",
"version": "3.14.0", "version": "3.11.0",
"description": "Platform-specific binary for oh-my-opencode (darwin-x64)", "description": "Platform-specific binary for oh-my-opencode (darwin-x64)",
"license": "MIT", "license": "MIT",
"repository": { "repository": {

View File

@@ -1,6 +1,6 @@
{ {
"name": "oh-my-opencode-linux-arm64-musl", "name": "oh-my-opencode-linux-arm64-musl",
"version": "3.14.0", "version": "3.11.0",
"description": "Platform-specific binary for oh-my-opencode (linux-arm64-musl)", "description": "Platform-specific binary for oh-my-opencode (linux-arm64-musl)",
"license": "MIT", "license": "MIT",
"repository": { "repository": {

View File

@@ -1,6 +1,6 @@
{ {
"name": "oh-my-opencode-linux-arm64", "name": "oh-my-opencode-linux-arm64",
"version": "3.14.0", "version": "3.11.0",
"description": "Platform-specific binary for oh-my-opencode (linux-arm64)", "description": "Platform-specific binary for oh-my-opencode (linux-arm64)",
"license": "MIT", "license": "MIT",
"repository": { "repository": {

View File

@@ -1,6 +1,6 @@
{ {
"name": "oh-my-opencode-linux-x64-baseline", "name": "oh-my-opencode-linux-x64-baseline",
"version": "3.14.0", "version": "3.11.0",
"description": "Platform-specific binary for oh-my-opencode (linux-x64-baseline, no AVX2)", "description": "Platform-specific binary for oh-my-opencode (linux-x64-baseline, no AVX2)",
"license": "MIT", "license": "MIT",
"repository": { "repository": {

View File

@@ -1,6 +1,6 @@
{ {
"name": "oh-my-opencode-linux-x64-musl-baseline", "name": "oh-my-opencode-linux-x64-musl-baseline",
"version": "3.14.0", "version": "3.11.0",
"description": "Platform-specific binary for oh-my-opencode (linux-x64-musl-baseline, no AVX2)", "description": "Platform-specific binary for oh-my-opencode (linux-x64-musl-baseline, no AVX2)",
"license": "MIT", "license": "MIT",
"repository": { "repository": {

View File

@@ -1,6 +1,6 @@
{ {
"name": "oh-my-opencode-linux-x64-musl", "name": "oh-my-opencode-linux-x64-musl",
"version": "3.14.0", "version": "3.11.0",
"description": "Platform-specific binary for oh-my-opencode (linux-x64-musl)", "description": "Platform-specific binary for oh-my-opencode (linux-x64-musl)",
"license": "MIT", "license": "MIT",
"repository": { "repository": {

View File

@@ -1,6 +1,6 @@
{ {
"name": "oh-my-opencode-linux-x64", "name": "oh-my-opencode-linux-x64",
"version": "3.14.0", "version": "3.11.0",
"description": "Platform-specific binary for oh-my-opencode (linux-x64)", "description": "Platform-specific binary for oh-my-opencode (linux-x64)",
"license": "MIT", "license": "MIT",
"repository": { "repository": {

View File

@@ -1,6 +1,6 @@
{ {
"name": "oh-my-opencode-windows-x64-baseline", "name": "oh-my-opencode-windows-x64-baseline",
"version": "3.14.0", "version": "3.11.0",
"description": "Platform-specific binary for oh-my-opencode (windows-x64-baseline, no AVX2)", "description": "Platform-specific binary for oh-my-opencode (windows-x64-baseline, no AVX2)",
"license": "MIT", "license": "MIT",
"repository": { "repository": {

View File

@@ -1,6 +1,6 @@
{ {
"name": "oh-my-opencode-windows-x64", "name": "oh-my-opencode-windows-x64",
"version": "3.14.0", "version": "3.11.0",
"description": "Platform-specific binary for oh-my-opencode (windows-x64)", "description": "Platform-specific binary for oh-my-opencode (windows-x64)",
"license": "MIT", "license": "MIT",
"repository": { "repository": {

View File

@@ -1,7 +1,6 @@
// postinstall.mjs // postinstall.mjs
// Runs after npm install to verify platform binary is available // Runs after npm install to verify platform binary is available
import { readFileSync } from "node:fs";
import { createRequire } from "node:module"; import { createRequire } from "node:module";
import { getPlatformPackageCandidates, getBinaryPath } from "./bin/platform.js"; import { getPlatformPackageCandidates, getBinaryPath } from "./bin/platform.js";
@@ -23,26 +22,15 @@ function getLibcFamily() {
} }
} }
function getPackageBaseName() {
try {
const packageJson = JSON.parse(readFileSync(new URL("./package.json", import.meta.url), "utf8"));
return packageJson.name || "oh-my-opencode";
} catch {
return "oh-my-opencode";
}
}
function main() { function main() {
const { platform, arch } = process; const { platform, arch } = process;
const libcFamily = getLibcFamily(); const libcFamily = getLibcFamily();
const packageBaseName = getPackageBaseName();
try { try {
const packageCandidates = getPlatformPackageCandidates({ const packageCandidates = getPlatformPackageCandidates({
platform, platform,
arch, arch,
libcFamily, libcFamily,
packageBaseName,
}); });
const resolvedPackage = packageCandidates.find((pkg) => { const resolvedPackage = packageCandidates.find((pkg) => {

View File

@@ -101,9 +101,7 @@ async function main() {
console.log("\n✅ All platform binaries built successfully!\n"); console.log("\n✅ All platform binaries built successfully!\n");
} }
if (import.meta.main) { main().catch((error) => {
main().catch((error) => { console.error("Fatal error:", error);
console.error("Fatal error:", error); process.exit(1);
process.exit(1); });
});
}

View File

@@ -1,13 +0,0 @@
import { writeFileSync } from "fs"
import { resolve } from "path"
import {
fetchModelCapabilitiesSnapshot,
MODELS_DEV_SOURCE_URL,
} from "../src/shared/model-capabilities-cache"
const OUTPUT_PATH = resolve(import.meta.dir, "../src/generated/model-capabilities.generated.json")
console.log(`Fetching model capabilities snapshot from ${MODELS_DEV_SOURCE_URL}...`)
const snapshot = await fetchModelCapabilitiesSnapshot()
writeFileSync(OUTPUT_PATH, `${JSON.stringify(snapshot, null, 2)}\n`)
console.log(`Generated ${OUTPUT_PATH} with ${Object.keys(snapshot.models).length} models`)

View File

@@ -34,72 +34,6 @@ async function generateChangelog(previousTag: string): Promise<string[]> {
return notes return notes
} }
async function getChangedFiles(previousTag: string): Promise<string[]> {
try {
const diff = await $`git diff --name-only ${previousTag}..HEAD`.text()
return diff
.split("\n")
.map((line) => line.trim())
.filter(Boolean)
} catch {
return []
}
}
function touchesAnyPath(files: string[], candidates: string[]): boolean {
return files.some((file) => candidates.some((candidate) => file === candidate || file.startsWith(`${candidate}/`)))
}
function buildReleaseFraming(files: string[]): string[] {
const bullets: string[] = []
if (
touchesAnyPath(files, [
"src/index.ts",
"src/plugin-config.ts",
"bin/platform.js",
"postinstall.mjs",
"docs",
])
) {
bullets.push("Rename transition updates across package detection, plugin/config compatibility, and install surfaces.")
}
if (touchesAnyPath(files, ["src/tools/delegate-task", "src/plugin/tool-registry.ts"])) {
bullets.push("Task and tool behavior updates, including delegate-task contract and runtime registration behavior.")
}
if (
touchesAnyPath(files, [
"src/plugin/tool-registry.ts",
"src/plugin-handlers/agent-config-handler.ts",
"src/plugin-handlers/tool-config-handler.ts",
"src/hooks/tasks-todowrite-disabler",
])
) {
bullets.push("Task-system default behavior alignment so omitted configuration behaves consistently across runtime paths.")
}
if (touchesAnyPath(files, [".github/workflows", "docs/guide/installation.md", "postinstall.mjs"])) {
bullets.push("Install and publish workflow hardening, including safer release sequencing and package/install fixes.")
}
if (bullets.length === 0) {
return []
}
return [
"## Minor Compatibility and Stability Release",
"",
"This release carries compatibility-facing behavior changes and operational hardening. Read the summary below before upgrading or publishing.",
"",
...bullets.map((bullet) => `- ${bullet}`),
"",
"## Commit Summary",
"",
]
}
async function getContributors(previousTag: string): Promise<string[]> { async function getContributors(previousTag: string): Promise<string[]> {
const notes: string[] = [] const notes: string[] = []
@@ -144,11 +78,9 @@ async function main() {
process.exit(0) process.exit(0)
} }
const changedFiles = await getChangedFiles(previousTag)
const changelog = await generateChangelog(previousTag) const changelog = await generateChangelog(previousTag)
const contributors = await getContributors(previousTag) const contributors = await getContributors(previousTag)
const framing = buildReleaseFraming(changedFiles) const notes = [...changelog, ...contributors]
const notes = [...framing, ...changelog, ...contributors]
if (notes.length === 0) { if (notes.length === 0) {
console.log("No notable changes") console.log("No notable changes")

View File

@@ -2207,198 +2207,6 @@
"created_at": "2026-03-16T04:55:10Z", "created_at": "2026-03-16T04:55:10Z",
"repoId": 1108837393, "repoId": 1108837393,
"pullRequestNo": 2604 "pullRequestNo": 2604
},
{
"name": "gxlife",
"id": 110413359,
"comment_id": 4068427047,
"created_at": "2026-03-16T15:17:01Z",
"repoId": 1108837393,
"pullRequestNo": 2625
},
{
"name": "HaD0Yun",
"id": 102889891,
"comment_id": 4073195308,
"created_at": "2026-03-17T08:27:45Z",
"repoId": 1108837393,
"pullRequestNo": 2640
},
{
"name": "tad-hq",
"id": 213478119,
"comment_id": 4077697128,
"created_at": "2026-03-17T20:07:09Z",
"repoId": 1108837393,
"pullRequestNo": 2655
},
{
"name": "ogormans-deptstack",
"id": 208788555,
"comment_id": 4077893096,
"created_at": "2026-03-17T20:42:42Z",
"repoId": 1108837393,
"pullRequestNo": 2656
},
{
"name": "walioo",
"id": 25835823,
"comment_id": 4087098221,
"created_at": "2026-03-19T02:13:02Z",
"repoId": 1108837393,
"pullRequestNo": 2688
},
{
"name": "trafgals",
"id": 6454757,
"comment_id": 4087725932,
"created_at": "2026-03-19T04:22:32Z",
"repoId": 1108837393,
"pullRequestNo": 2690
},
{
"name": "tonymfer",
"id": 66512584,
"comment_id": 4091847232,
"created_at": "2026-03-19T17:13:49Z",
"repoId": 1108837393,
"pullRequestNo": 2701
},
{
"name": "nguyentamdat",
"id": 16253213,
"comment_id": 4096267323,
"created_at": "2026-03-20T07:34:22Z",
"repoId": 1108837393,
"pullRequestNo": 2718
},
{
"name": "whackur",
"id": 26926041,
"comment_id": 4102330445,
"created_at": "2026-03-21T05:27:17Z",
"repoId": 1108837393,
"pullRequestNo": 2733
},
{
"name": "ndaemy",
"id": 18691542,
"comment_id": 4103008804,
"created_at": "2026-03-21T10:18:22Z",
"repoId": 1108837393,
"pullRequestNo": 2734
},
{
"name": "0xYiliu",
"id": 3838688,
"comment_id": 4104738337,
"created_at": "2026-03-21T22:59:33Z",
"repoId": 1108837393,
"pullRequestNo": 2738
},
{
"name": "hunghoang3011",
"id": 65234777,
"comment_id": 4107900881,
"created_at": "2026-03-23T04:28:20Z",
"repoId": 1108837393,
"pullRequestNo": 2758
},
{
"name": "anas-asghar4831",
"id": 110368394,
"comment_id": 4128950310,
"created_at": "2026-03-25T18:48:19Z",
"repoId": 1108837393,
"pullRequestNo": 2837
},
{
"name": "clansty",
"id": 18461360,
"comment_id": 4129934858,
"created_at": "2026-03-25T21:33:35Z",
"repoId": 1108837393,
"pullRequestNo": 2839
},
{
"name": "ventsislav-georgiev",
"id": 5616486,
"comment_id": 4130417794,
"created_at": "2026-03-25T23:11:32Z",
"repoId": 1108837393,
"pullRequestNo": 2840
},
{
"name": "kuitos",
"id": 5206843,
"comment_id": 4133207953,
"created_at": "2026-03-26T09:55:49Z",
"repoId": 1108837393,
"pullRequestNo": 2833
},
{
"name": "Jholly2008",
"id": 29773273,
"comment_id": 4139918265,
"created_at": "2026-03-27T03:37:00Z",
"repoId": 1108837393,
"pullRequestNo": 2871
},
{
"name": "WhiteGiverMa",
"id": 152406589,
"comment_id": 4140294245,
"created_at": "2026-03-27T05:26:37Z",
"repoId": 1108837393,
"pullRequestNo": 2877
},
{
"name": "codivedev",
"id": 249558739,
"comment_id": 4142164072,
"created_at": "2026-03-27T12:11:45Z",
"repoId": 1108837393,
"pullRequestNo": 2888
},
{
"name": "AlexDochioiu",
"id": 38853913,
"comment_id": 4147980685,
"created_at": "2026-03-28T12:20:42Z",
"repoId": 1108837393,
"pullRequestNo": 2916
},
{
"name": "ryandielhenn",
"id": 35785891,
"comment_id": 4148508024,
"created_at": "2026-03-28T17:46:50Z",
"repoId": 1108837393,
"pullRequestNo": 2919
},
{
"name": "lorenzo-dallamuta",
"id": 66994937,
"comment_id": 4148848505,
"created_at": "2026-03-28T21:30:15Z",
"repoId": 1108837393,
"pullRequestNo": 2925
},
{
"name": "quangtran88",
"id": 107824159,
"comment_id": 4149327240,
"created_at": "2026-03-29T03:21:39Z",
"repoId": 1108837393,
"pullRequestNo": 2929
},
{
"name": "HOYALIM",
"id": 166576253,
"comment_id": 4149626853,
"created_at": "2026-03-29T07:31:36Z",
"repoId": 1108837393,
"pullRequestNo": 2935
} }
] ]
} }

View File

@@ -10,11 +10,11 @@ Entry point `index.ts` orchestrates 5-step initialization: loadConfig → create
| File | Purpose | | File | Purpose |
|------|---------| |------|---------|
| `index.ts` | Plugin entry, exports `OhMyOpenCodePlugin` | | `index.ts` | Plugin entry, exports `OhMyOpenAgentPlugin` |
| `plugin-config.ts` | JSONC parse, multi-level merge, Zod v4 validation | | `plugin-config.ts` | JSONC parse, multi-level merge, Zod v4 validation |
| `create-managers.ts` | TmuxSessionManager, BackgroundManager, SkillMcpManager, ConfigHandler | | `create-managers.ts` | TmuxSessionManager, BackgroundManager, SkillMcpManager, ConfigHandler |
| `create-tools.ts` | SkillContext + AvailableCategories + ToolRegistry (26 tools) | | `create-tools.ts` | SkillContext + AvailableCategories + ToolRegistry (26 tools) |
| `create-hooks.ts` | 3-tier: Core(39) + Continuation(7) + Skill(2) = 48 hooks | | `create-hooks.ts` | 3-tier: Core(37) + Continuation(7) + Skill(2) = 46 hooks |
| `plugin-interface.ts` | 8 OpenCode hook handlers: config, tool, chat.message, chat.params, chat.headers, event, tool.execute.before, tool.execute.after | | `plugin-interface.ts` | 8 OpenCode hook handlers: config, tool, chat.message, chat.params, chat.headers, event, tool.execute.before, tool.execute.after |
## CONFIG LOADING ## CONFIG LOADING
@@ -32,10 +32,10 @@ loadPluginConfig(directory, ctx)
``` ```
createHooks() createHooks()
├─→ createCoreHooks() # 39 hooks ├─→ createCoreHooks() # 37 hooks
│ ├─ createSessionHooks() # 23: contextWindowMonitor, thinkMode, ralphLoop, modelFallback, runtimeFallback, noSisyphusGpt, noHephaestusNonGpt, anthropicEffort, intentGate... │ ├─ createSessionHooks() # 23: contextWindowMonitor, thinkMode, ralphLoop, modelFallback, runtimeFallback, noSisyphusGpt, noHephaestusNonGpt, anthropicEffort, intentGate...
│ ├─ createToolGuardHooks() # 12: commentChecker, rulesInjector, writeExistingFileGuard, jsonErrorRecovery, hashlineReadEnhancer... │ ├─ createToolGuardHooks() # 10: commentChecker, rulesInjector, writeExistingFileGuard, jsonErrorRecovery, hashlineReadEnhancer...
│ └─ createTransformHooks() # 4: claudeCodeHooks, keywordDetector, contextInjector, thinkingBlockValidator │ └─ createTransformHooks() # 4: claudeCodeHooks, keywordDetector, contextInjector, thinkingBlockValidator
├─→ createContinuationHooks() # 7: todoContinuationEnforcer, atlas, stopContinuationGuard, compactionContextInjector... ├─→ createContinuationHooks() # 7: todoContinuationEnforcer, atlas, stopContinuationGuard, ralphLoopActivator...
└─→ createSkillHooks() # 2: categorySkillReminder, autoSlashCommand └─→ createSkillHooks() # 2: categorySkillReminder, autoSlashCommand
``` ```

View File

@@ -11,10 +11,10 @@ Agent factories following `createXXXAgent(model) → AgentConfig` pattern. Each
| Agent | Model | Temp | Mode | Fallback Chain | Purpose | | Agent | Model | Temp | Mode | Fallback Chain | Purpose |
|-------|-------|------|------|----------------|---------| |-------|-------|------|------|----------------|---------|
| **Sisyphus** | claude-opus-4-6 max | 0.1 | all | k2p5 → kimi-k2.5 → gpt-5.4 medium → glm-5 → big-pickle | Main orchestrator, plans + delegates | | **Sisyphus** | claude-opus-4-6 max | 0.1 | all | k2p5 → kimi-k2.5 → gpt-5.4 medium → glm-5 → big-pickle | Main orchestrator, plans + delegates |
| **Hephaestus** | gpt-5.4 medium | 0.1 | all | | Autonomous deep worker | | **Hephaestus** | gpt-5.3-codex medium | 0.1 | all | gpt-5.4 medium (copilot) | Autonomous deep worker |
| **Oracle** | gpt-5.4 high | 0.1 | subagent | gemini-3.1-pro high → claude-opus-4-6 max | Read-only consultation | | **Oracle** | gpt-5.4 high | 0.1 | subagent | gemini-3.1-pro high → claude-opus-4-6 max | Read-only consultation |
| **Librarian** | minimax-m2.7 | 0.1 | subagent | minimax-m2.7-highspeedclaude-haiku-4-5 → gpt-5-nano | External docs/code search | | **Librarian** | gemini-3-flash | 0.1 | subagent | minimax-m2.5-free → big-pickle | External docs/code search |
| **Explore** | grok-code-fast-1 | 0.1 | subagent | minimax-m2.7-highspeed → minimax-m2.7 → claude-haiku-4-5 → gpt-5-nano | Contextual grep | | **Explore** | grok-code-fast-1 | 0.1 | subagent | minimax-m2.5-free → claude-haiku-4-5 → gpt-5-nano | Contextual grep |
| **Multimodal-Looker** | gpt-5.3-codex medium | 0.1 | subagent | k2p5 → gemini-3-flash → glm-4.6v → gpt-5-nano | PDF/image analysis | | **Multimodal-Looker** | gpt-5.3-codex medium | 0.1 | subagent | k2p5 → gemini-3-flash → glm-4.6v → gpt-5-nano | PDF/image analysis |
| **Metis** | claude-opus-4-6 max | **0.3** | subagent | gpt-5.4 high → gemini-3.1-pro high | Pre-planning consultant | | **Metis** | claude-opus-4-6 max | **0.3** | subagent | gpt-5.4 high → gemini-3.1-pro high | Pre-planning consultant |
| **Momus** | gpt-5.4 xhigh | 0.1 | subagent | claude-opus-4-6 max → gemini-3.1-pro high | Plan reviewer | | **Momus** | gpt-5.4 xhigh | 0.1 | subagent | claude-opus-4-6 max → gemini-3.1-pro high | Plan reviewer |

View File

@@ -44,10 +44,6 @@ export function mergeAgentConfig(
const { prompt_append, ...rest } = migratedOverride const { prompt_append, ...rest } = migratedOverride
const merged = deepMerge(base, rest as Partial<AgentConfig>) const merged = deepMerge(base, rest as Partial<AgentConfig>)
if (merged.prompt && typeof merged.prompt === 'string' && merged.prompt.startsWith('file://')) {
merged.prompt = resolvePromptAppend(merged.prompt, directory)
}
if (prompt_append && merged.prompt) { if (prompt_append && merged.prompt) {
merged.prompt = merged.prompt + "\n" + resolvePromptAppend(prompt_append, directory) merged.prompt = merged.prompt + "\n" + resolvePromptAppend(prompt_append, directory)
} }

View File

@@ -39,7 +39,7 @@ export function maybeCreateAtlasConfig(input: {
const atlasRequirement = AGENT_MODEL_REQUIREMENTS["atlas"] const atlasRequirement = AGENT_MODEL_REQUIREMENTS["atlas"]
const atlasResolution = applyModelResolution({ const atlasResolution = applyModelResolution({
uiSelectedModel: orchestratorOverride?.model !== undefined ? undefined : uiSelectedModel, uiSelectedModel: orchestratorOverride?.model ? undefined : uiSelectedModel,
userModel: orchestratorOverride?.model, userModel: orchestratorOverride?.model,
requirement: atlasRequirement, requirement: atlasRequirement,
availableModels, availableModels,

View File

@@ -8,7 +8,6 @@ import { buildAgent, isFactory } from "../agent-builder"
import { applyOverrides } from "./agent-overrides" import { applyOverrides } from "./agent-overrides"
import { applyEnvironmentContext } from "./environment-context" import { applyEnvironmentContext } from "./environment-context"
import { applyModelResolution, getFirstFallbackModel } from "./model-resolution" import { applyModelResolution, getFirstFallbackModel } from "./model-resolution"
import { log } from "../../shared/logger"
export function collectPendingBuiltinAgents(input: { export function collectPendingBuiltinAgents(input: {
agentSources: Record<BuiltinAgentName, import("../agent-builder").AgentSource> agentSources: Record<BuiltinAgentName, import("../agent-builder").AgentSource>
@@ -70,24 +69,14 @@ export function collectPendingBuiltinAgents(input: {
const isPrimaryAgent = isFactory(source) && source.mode === "primary" const isPrimaryAgent = isFactory(source) && source.mode === "primary"
let resolution = applyModelResolution({ let resolution = applyModelResolution({
uiSelectedModel: (isPrimaryAgent && override?.model === undefined) ? uiSelectedModel : undefined, uiSelectedModel: (isPrimaryAgent && !override?.model) ? uiSelectedModel : undefined,
userModel: override?.model, userModel: override?.model,
requirement, requirement,
availableModels, availableModels,
systemDefaultModel, systemDefaultModel,
}) })
if (!resolution) { if (!resolution && isFirstRunNoCache && !override?.model) {
if (override?.model) { resolution = getFirstFallbackModel(requirement)
// User explicitly configured a model but resolution failed (e.g., cold cache).
// Honor the user's choice directly instead of falling back to hardcoded chain.
log("[agent-registration] User-configured model not resolved, using as-is", {
agent: agentName,
configuredModel: override.model,
})
resolution = { model: override.model, provenance: "override" as const }
} else {
resolution = getFirstFallbackModel(requirement)
}
} }
if (!resolution) continue if (!resolution) continue
const { model, variant: resolvedVariant } = resolution const { model, variant: resolvedVariant } = resolution

View File

@@ -1,32 +1,20 @@
import { afterAll, beforeAll, describe, expect, mock, test } from "bun:test" import { afterAll, beforeAll, describe, expect, test } from "bun:test"
import { mkdirSync, rmSync, writeFileSync } from "node:fs" import { mkdirSync, rmSync, writeFileSync } from "node:fs"
import * as os from "node:os" import { homedir, tmpdir } from "node:os"
import { tmpdir } from "node:os"
import { join } from "node:path" import { join } from "node:path"
import { resolvePromptAppend } from "./resolve-file-uri"
const originalHomedir = os.homedir.bind(os)
let mockedHomeDir = ""
let moduleImportCounter = 0
let resolvePromptAppend: typeof import("./resolve-file-uri").resolvePromptAppend
mock.module("node:os", () => ({
...os,
homedir: () => mockedHomeDir || originalHomedir(),
}))
describe("resolvePromptAppend", () => { describe("resolvePromptAppend", () => {
const fixtureRoot = join(tmpdir(), `resolve-file-uri-${Date.now()}`) const fixtureRoot = join(tmpdir(), `resolve-file-uri-${Date.now()}`)
const configDir = join(fixtureRoot, "config") const configDir = join(fixtureRoot, "config")
const homeFixtureRoot = join(fixtureRoot, "home") const homeFixtureDir = join(homedir(), `.resolve-file-uri-home-${Date.now()}`)
const homeFixtureDir = join(homeFixtureRoot, "fixture-home")
const absoluteFilePath = join(fixtureRoot, "absolute.txt") const absoluteFilePath = join(fixtureRoot, "absolute.txt")
const relativeFilePath = join(configDir, "relative.txt") const relativeFilePath = join(configDir, "relative.txt")
const spacedFilePath = join(fixtureRoot, "with space.txt") const spacedFilePath = join(fixtureRoot, "with space.txt")
const homeFilePath = join(homeFixtureDir, "home.txt") const homeFilePath = join(homeFixtureDir, "home.txt")
beforeAll(async () => { beforeAll(() => {
mockedHomeDir = homeFixtureRoot
mkdirSync(fixtureRoot, { recursive: true }) mkdirSync(fixtureRoot, { recursive: true })
mkdirSync(configDir, { recursive: true }) mkdirSync(configDir, { recursive: true })
mkdirSync(homeFixtureDir, { recursive: true }) mkdirSync(homeFixtureDir, { recursive: true })
@@ -35,14 +23,11 @@ describe("resolvePromptAppend", () => {
writeFileSync(relativeFilePath, "relative-content", "utf8") writeFileSync(relativeFilePath, "relative-content", "utf8")
writeFileSync(spacedFilePath, "encoded-content", "utf8") writeFileSync(spacedFilePath, "encoded-content", "utf8")
writeFileSync(homeFilePath, "home-content", "utf8") writeFileSync(homeFilePath, "home-content", "utf8")
moduleImportCounter += 1
;({ resolvePromptAppend } = await import(`./resolve-file-uri?test=${moduleImportCounter}`))
}) })
afterAll(() => { afterAll(() => {
rmSync(fixtureRoot, { recursive: true, force: true }) rmSync(fixtureRoot, { recursive: true, force: true })
mock.restore() rmSync(homeFixtureDir, { recursive: true, force: true })
}) })
test("returns non-file URI strings unchanged", () => { test("returns non-file URI strings unchanged", () => {
@@ -80,7 +65,7 @@ describe("resolvePromptAppend", () => {
test("resolves home directory URI path", () => { test("resolves home directory URI path", () => {
//#given //#given
const input = "file://~/fixture-home/home.txt" const input = `file://~/${homeFixtureDir.split("/").pop()}/home.txt`
//#when //#when
const resolved = resolvePromptAppend(input) const resolved = resolvePromptAppend(input)

View File

@@ -52,7 +52,7 @@ export function maybeCreateSisyphusConfig(input: {
if (disabledAgents.includes("sisyphus") || !meetsSisyphusAnyModelRequirement) return undefined if (disabledAgents.includes("sisyphus") || !meetsSisyphusAnyModelRequirement) return undefined
let sisyphusResolution = applyModelResolution({ let sisyphusResolution = applyModelResolution({
uiSelectedModel: sisyphusOverride?.model !== undefined ? undefined : uiSelectedModel, uiSelectedModel: sisyphusOverride?.model ? undefined : uiSelectedModel,
userModel: sisyphusOverride?.model, userModel: sisyphusOverride?.model,
requirement: sisyphusRequirement, requirement: sisyphusRequirement,
availableModels, availableModels,

View File

@@ -181,7 +181,7 @@ describe("buildParallelDelegationSection", () => {
it("#given non-Claude model with deep category #when building #then returns aggressive delegation section", () => { it("#given non-Claude model with deep category #when building #then returns aggressive delegation section", () => {
//#given //#given
const model = "google/gemini-3.1-pro" const model = "google/gemini-3-pro"
const categories = [deepCategory, otherCategory] const categories = [deepCategory, otherCategory]
//#when //#when
@@ -237,7 +237,7 @@ describe("buildParallelDelegationSection", () => {
describe("buildNonClaudePlannerSection", () => { describe("buildNonClaudePlannerSection", () => {
it("#given non-Claude model #when building #then returns plan agent section", () => { it("#given non-Claude model #when building #then returns plan agent section", () => {
//#given //#given
const model = "google/gemini-3.1-pro" const model = "google/gemini-3-pro"
//#when //#when
const result = buildNonClaudePlannerSection(model) const result = buildNonClaudePlannerSection(model)
@@ -272,3 +272,4 @@ describe("buildNonClaudePlannerSection", () => {
}) })
}) })

View File

@@ -308,12 +308,6 @@ Briefly announce "Consulting Oracle for [reason]" before invocation.
**Collect Oracle results before your final answer. No exceptions.** **Collect Oracle results before your final answer. No exceptions.**
**Oracle-dependent implementation is BLOCKED until Oracle finishes.**
- If you asked Oracle for architecture/debugging direction that affects the fix, do not implement before Oracle result arrives.
- While waiting, only do non-overlapping prep work. Never ship implementation decisions Oracle was asked to decide.
- Never "time out and continue anyway" for Oracle-dependent tasks.
- Oracle takes minutes. When done with your own work: **end your response** — wait for the \`<system-reminder>\`. - Oracle takes minutes. When done with your own work: **end your response** — wait for the \`<system-reminder>\`.
- Do NOT poll \`background_output\` on a running Oracle. The notification will come. - Do NOT poll \`background_output\` on a running Oracle. The notification will come.
- Never cancel Oracle. - Never cancel Oracle.

View File

@@ -162,10 +162,6 @@ Asking the user is the LAST resort after exhausting creative alternatives.
- User asks a question implying work → Answer briefly, DO the implied work in the same turn - User asks a question implying work → Answer briefly, DO the implied work in the same turn
- You wrote a plan in your response → EXECUTE the plan before ending turn — plans are starting lines, not finish lines - You wrote a plan in your response → EXECUTE the plan before ending turn — plans are starting lines, not finish lines
### Task Scope Clarification
You handle multi-step sub-tasks of a SINGLE GOAL. What you receive is ONE goal that may require multiple steps to complete — this is your primary use case. Only reject when given MULTIPLE INDEPENDENT goals in one request.
## Hard Constraints ## Hard Constraints
${hardBlocks} ${hardBlocks}

View File

@@ -121,10 +121,6 @@ When blocked: try a different approach → decompose the problem → challenge a
- User asks a question implying work → Answer briefly, DO the implied work in the same turn - User asks a question implying work → Answer briefly, DO the implied work in the same turn
- You wrote a plan in your response → EXECUTE the plan before ending turn — plans are starting lines, not finish lines - You wrote a plan in your response → EXECUTE the plan before ending turn — plans are starting lines, not finish lines
### Task Scope Clarification
You handle multi-step sub-tasks of a SINGLE GOAL. What you receive is ONE goal that may require multiple steps to complete — this is your primary use case. Only reject when given MULTIPLE INDEPENDENT goals in one request.
## Hard Constraints ## Hard Constraints
${hardBlocks} ${hardBlocks}

View File

@@ -112,10 +112,6 @@ Asking the user is the LAST resort after exhausting creative alternatives.
- Note assumptions in final message, not as questions mid-work - Note assumptions in final message, not as questions mid-work
- Need context? Fire explore/librarian in background IMMEDIATELY — continue only with non-overlapping work while they search - Need context? Fire explore/librarian in background IMMEDIATELY — continue only with non-overlapping work while they search
### Task Scope Clarification
You handle multi-step sub-tasks of a SINGLE GOAL. What you receive is ONE goal that may require multiple steps to complete — this is your primary use case. Only reject when given MULTIPLE INDEPENDENT goals in one request.
## Hard Constraints ## Hard Constraints
${hardBlocks} ${hardBlocks}

View File

@@ -1,42 +0,0 @@
import { describe, it, expect } from "bun:test"
import { getPrometheusPrompt } from "./system-prompt"
describe("getPrometheusPrompt", () => {
describe("#given question tool is not disabled", () => {
describe("#when generating prompt", () => {
it("#then should include Question tool references", () => {
const prompt = getPrometheusPrompt(undefined, [])
expect(prompt).toContain("Question({")
})
})
})
describe("#given question tool is disabled via disabled_tools", () => {
describe("#when generating prompt", () => {
it("#then should strip Question tool code examples", () => {
const prompt = getPrometheusPrompt(undefined, ["question"])
expect(prompt).not.toContain("Question({")
})
})
describe("#when disabled_tools includes question among other tools", () => {
it("#then should strip Question tool code examples", () => {
const prompt = getPrometheusPrompt(undefined, ["todowrite", "question", "interactive_bash"])
expect(prompt).not.toContain("Question({")
})
})
})
describe("#given no disabled_tools provided", () => {
describe("#when generating prompt with undefined", () => {
it("#then should include Question tool references", () => {
const prompt = getPrometheusPrompt(undefined, undefined)
expect(prompt).toContain("Question({")
})
})
})
})

View File

@@ -52,34 +52,16 @@ export function getPrometheusPromptSource(model?: string): PrometheusPromptSourc
* Gemini models → Gemini-optimized prompt (aggressive tool-call enforcement, thinking checkpoints) * Gemini models → Gemini-optimized prompt (aggressive tool-call enforcement, thinking checkpoints)
* Default (Claude, etc.) → Claude-optimized prompt (modular sections) * Default (Claude, etc.) → Claude-optimized prompt (modular sections)
*/ */
export function getPrometheusPrompt(model?: string, disabledTools?: readonly string[]): string { export function getPrometheusPrompt(model?: string): string {
const source = getPrometheusPromptSource(model) const source = getPrometheusPromptSource(model)
const isQuestionDisabled = disabledTools?.includes("question") ?? false
let prompt: string
switch (source) { switch (source) {
case "gpt": case "gpt":
prompt = getGptPrometheusPrompt() return getGptPrometheusPrompt()
break
case "gemini": case "gemini":
prompt = getGeminiPrometheusPrompt() return getGeminiPrometheusPrompt()
break
case "default": case "default":
default: default:
prompt = PROMETHEUS_SYSTEM_PROMPT return PROMETHEUS_SYSTEM_PROMPT
} }
if (isQuestionDisabled) {
prompt = stripQuestionToolReferences(prompt)
}
return prompt
}
/**
* Removes Question tool usage examples from prompt text when question tool is disabled.
*/
function stripQuestionToolReferences(prompt: string): string {
// Remove Question({...}) code blocks (multi-line)
return prompt.replace(/```typescript\n\s*Question\(\{[\s\S]*?\}\)\s*\n```/g, "")
} }

View File

@@ -35,11 +35,6 @@ Task NOT complete without:
- ${verificationText} - ${verificationText}
</Verification> </Verification>
<Termination>
STOP after first successful verification. Do NOT re-verify.
Maximum status checks: 2. Then stop regardless.
</Termination>
<Style> <Style>
- Start immediately. No acknowledgments. - Start immediately. No acknowledgments.
- Match user's communication style. - Match user's communication style.

View File

@@ -127,12 +127,6 @@ This verbalization anchors your routing decision and makes your reasoning transp
- **Open-ended** ("Improve", "Refactor", "Add feature") → Assess codebase first - **Open-ended** ("Improve", "Refactor", "Add feature") → Assess codebase first
- **Ambiguous** (unclear scope, multiple interpretations) → Ask ONE clarifying question - **Ambiguous** (unclear scope, multiple interpretations) → Ask ONE clarifying question
### Step 1.5: Turn-Local Intent Reset (MANDATORY)
- Reclassify intent from the CURRENT user message only. Never auto-carry "implementation mode" from prior turns.
- If current message is a question/explanation/investigation request, answer/analyze only. Do NOT create todos or edit files.
- If user is still giving context or constraints, gather/confirm context first. Do NOT start implementation yet.
### Step 2: Check for Ambiguity ### Step 2: Check for Ambiguity
- Single valid interpretation → Proceed - Single valid interpretation → Proceed
@@ -141,15 +135,6 @@ This verbalization anchors your routing decision and makes your reasoning transp
- Missing critical info (file, error, context) → **MUST ask** - Missing critical info (file, error, context) → **MUST ask**
- User's design seems flawed or suboptimal → **MUST raise concern** before implementing - User's design seems flawed or suboptimal → **MUST raise concern** before implementing
### Step 2.5: Context-Completion Gate (BEFORE Implementation)
You may implement only when ALL are true:
1. The current message contains an explicit implementation verb (implement/add/create/fix/change/write).
2. Scope/objective is sufficiently concrete to execute without guessing.
3. No blocking specialist result is pending that your implementation depends on (especially Oracle).
If any condition fails, do research/clarification only, then wait.
### Step 3: Validate Before Acting ### Step 3: Validate Before Acting
**Assumptions Check:** **Assumptions Check:**

View File

@@ -167,11 +167,6 @@ Complexity:
- Open-ended ("improve", "refactor") → assess codebase first, then propose - Open-ended ("improve", "refactor") → assess codebase first, then propose
- Ambiguous (multiple interpretations with 2x+ effort difference) → ask ONE question - Ambiguous (multiple interpretations with 2x+ effort difference) → ask ONE question
Turn-local reset (mandatory): classify from the CURRENT user message, not conversation momentum.
- Never carry implementation mode from prior turns.
- If current turn is question/explanation/investigation, answer or analyze only.
- If user appears to still be providing context, gather/confirm context first and wait.
Domain guess (provisional — finalized in ROUTE after exploration): Domain guess (provisional — finalized in ROUTE after exploration):
- Visual (UI, CSS, styling, layout, design, animation) → likely visual-engineering - Visual (UI, CSS, styling, layout, design, animation) → likely visual-engineering
- Logic (algorithms, architecture, complex business logic) → likely ultrabrain - Logic (algorithms, architecture, complex business logic) → likely ultrabrain
@@ -189,11 +184,6 @@ Step 2 — Check before acting:
- Missing critical info → ask - Missing critical info → ask
- User's design seems flawed → raise concern concisely, propose alternative, ask if they want to proceed anyway - User's design seems flawed → raise concern concisely, propose alternative, ask if they want to proceed anyway
Context-completion gate before implementation:
- Implement only when the current message explicitly requests implementation (implement/add/create/fix/change/write),
scope is concrete enough to execute without guessing, and no blocking specialist result is pending.
- If any condition fails, continue with research/clarification only and wait.
<ask_gate> <ask_gate>
Proceed unless: Proceed unless:
(a) the action is irreversible, (a) the action is irreversible,

View File

@@ -1,5 +1,5 @@
import { describe, test, expect } from "bun:test"; import { describe, test, expect } from "bun:test";
import { isGptModel, isGeminiModel, isGpt5_4Model, isMiniMaxModel } from "./types"; import { isGptModel, isGeminiModel, isGpt5_4Model } from "./types";
describe("isGpt5_4Model", () => { describe("isGpt5_4Model", () => {
test("detects gpt-5.4 models", () => { test("detects gpt-5.4 models", () => {
@@ -79,28 +79,6 @@ describe("isGptModel", () => {
}); });
}); });
describe("isMiniMaxModel", () => {
test("detects minimax models with provider prefix", () => {
expect(isMiniMaxModel("opencode-go/minimax-m2.7")).toBe(true);
expect(isMiniMaxModel("opencode/minimax-m2.7-highspeed")).toBe(true);
expect(isMiniMaxModel("opencode-go/minimax-m2.5")).toBe(true);
expect(isMiniMaxModel("opencode/minimax-m2.5-free")).toBe(true);
});
test("detects minimax models without provider prefix", () => {
expect(isMiniMaxModel("minimax-m2.7")).toBe(true);
expect(isMiniMaxModel("minimax-m2.7-highspeed")).toBe(true);
expect(isMiniMaxModel("minimax-m2.5")).toBe(true);
});
test("does not match non-minimax models", () => {
expect(isMiniMaxModel("openai/gpt-5.4")).toBe(false);
expect(isMiniMaxModel("anthropic/claude-opus-4-6")).toBe(false);
expect(isMiniMaxModel("google/gemini-3.1-pro")).toBe(false);
expect(isMiniMaxModel("opencode-go/kimi-k2.5")).toBe(false);
});
});
describe("isGeminiModel", () => { describe("isGeminiModel", () => {
test("#given google provider models #then returns true", () => { test("#given google provider models #then returns true", () => {
expect(isGeminiModel("google/gemini-3.1-pro")).toBe(true); expect(isGeminiModel("google/gemini-3.1-pro")).toBe(true);

View File

@@ -91,11 +91,6 @@ export function isGpt5_3CodexModel(model: string): boolean {
const GEMINI_PROVIDERS = ["google/", "google-vertex/"]; const GEMINI_PROVIDERS = ["google/", "google-vertex/"];
export function isMiniMaxModel(model: string): boolean {
const modelName = extractModelName(model).toLowerCase();
return modelName.includes("minimax");
}
export function isGeminiModel(model: string): boolean { export function isGeminiModel(model: string): boolean {
if (GEMINI_PROVIDERS.some((prefix) => model.startsWith(prefix))) return true; if (GEMINI_PROVIDERS.some((prefix) => model.startsWith(prefix))) return true;
@@ -128,7 +123,7 @@ export type AgentName = BuiltinAgentName;
export type AgentOverrideConfig = Partial<AgentConfig> & { export type AgentOverrideConfig = Partial<AgentConfig> & {
prompt_append?: string; prompt_append?: string;
variant?: string; variant?: string;
fallback_models?: string | (string | import("../config/schema/fallback-models").FallbackModelObject)[]; fallback_models?: string | string[];
}; };
export type AgentOverrides = Partial< export type AgentOverrides = Partial<

View File

@@ -642,7 +642,7 @@ describe("createBuiltinAgents with requiresProvider gating (hephaestus)", () =>
// #then // #then
expect(agents.hephaestus).toBeDefined() expect(agents.hephaestus).toBeDefined()
expect(agents.hephaestus.model).toBe("openai/gpt-5.4") expect(agents.hephaestus.model).toBe("openai/gpt-5.3-codex")
} finally { } finally {
cacheSpy.mockRestore() cacheSpy.mockRestore()
fetchSpy.mockRestore() fetchSpy.mockRestore()

View File

@@ -5,60 +5,60 @@ exports[`generateModelConfig no providers available returns ULTIMATE_FALLBACK fo
"$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-opencode.schema.json", "$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-opencode.schema.json",
"agents": { "agents": {
"atlas": { "atlas": {
"model": "opencode/gpt-5-nano", "model": "opencode/glm-4.7-free",
}, },
"explore": { "explore": {
"model": "opencode/gpt-5-nano", "model": "opencode/glm-4.7-free",
}, },
"hephaestus": { "hephaestus": {
"model": "opencode/gpt-5-nano", "model": "opencode/glm-4.7-free",
}, },
"librarian": { "librarian": {
"model": "opencode/gpt-5-nano", "model": "opencode/glm-4.7-free",
}, },
"metis": { "metis": {
"model": "opencode/gpt-5-nano", "model": "opencode/glm-4.7-free",
}, },
"momus": { "momus": {
"model": "opencode/gpt-5-nano", "model": "opencode/glm-4.7-free",
}, },
"multimodal-looker": { "multimodal-looker": {
"model": "opencode/gpt-5-nano", "model": "opencode/glm-4.7-free",
}, },
"oracle": { "oracle": {
"model": "opencode/gpt-5-nano", "model": "opencode/glm-4.7-free",
}, },
"prometheus": { "prometheus": {
"model": "opencode/gpt-5-nano", "model": "opencode/glm-4.7-free",
}, },
"sisyphus-junior": { "sisyphus-junior": {
"model": "opencode/gpt-5-nano", "model": "opencode/glm-4.7-free",
}, },
}, },
"categories": { "categories": {
"artistry": { "artistry": {
"model": "opencode/gpt-5-nano", "model": "opencode/glm-4.7-free",
}, },
"deep": { "deep": {
"model": "opencode/gpt-5-nano", "model": "opencode/glm-4.7-free",
}, },
"quick": { "quick": {
"model": "opencode/gpt-5-nano", "model": "opencode/glm-4.7-free",
}, },
"ultrabrain": { "ultrabrain": {
"model": "opencode/gpt-5-nano", "model": "opencode/glm-4.7-free",
}, },
"unspecified-high": { "unspecified-high": {
"model": "opencode/gpt-5-nano", "model": "opencode/glm-4.7-free",
}, },
"unspecified-low": { "unspecified-low": {
"model": "opencode/gpt-5-nano", "model": "opencode/glm-4.7-free",
}, },
"visual-engineering": { "visual-engineering": {
"model": "opencode/gpt-5-nano", "model": "opencode/glm-4.7-free",
}, },
"writing": { "writing": {
"model": "opencode/gpt-5-nano", "model": "opencode/glm-4.7-free",
}, },
}, },
} }
@@ -83,7 +83,7 @@ exports[`generateModelConfig single native provider uses Claude models when only
"variant": "max", "variant": "max",
}, },
"multimodal-looker": { "multimodal-looker": {
"model": "opencode/gpt-5-nano", "model": "opencode/glm-4.7-free",
}, },
"oracle": { "oracle": {
"model": "anthropic/claude-opus-4-6", "model": "anthropic/claude-opus-4-6",
@@ -145,7 +145,7 @@ exports[`generateModelConfig single native provider uses Claude models with isMa
"variant": "max", "variant": "max",
}, },
"multimodal-looker": { "multimodal-looker": {
"model": "opencode/gpt-5-nano", "model": "opencode/glm-4.7-free",
}, },
"oracle": { "oracle": {
"model": "anthropic/claude-opus-4-6", "model": "anthropic/claude-opus-4-6",
@@ -202,7 +202,7 @@ exports[`generateModelConfig single native provider uses OpenAI models when only
"variant": "medium", "variant": "medium",
}, },
"hephaestus": { "hephaestus": {
"model": "openai/gpt-5.4", "model": "openai/gpt-5.3-codex",
"variant": "medium", "variant": "medium",
}, },
"librarian": { "librarian": {
@@ -248,7 +248,8 @@ exports[`generateModelConfig single native provider uses OpenAI models when only
"variant": "medium", "variant": "medium",
}, },
"quick": { "quick": {
"model": "openai/gpt-5.4-mini", "model": "openai/gpt-5.3-codex",
"variant": "low",
}, },
"ultrabrain": { "ultrabrain": {
"model": "openai/gpt-5.4", "model": "openai/gpt-5.4",
@@ -287,7 +288,7 @@ exports[`generateModelConfig single native provider uses OpenAI models with isMa
"variant": "medium", "variant": "medium",
}, },
"hephaestus": { "hephaestus": {
"model": "openai/gpt-5.4", "model": "openai/gpt-5.3-codex",
"variant": "medium", "variant": "medium",
}, },
"librarian": { "librarian": {
@@ -333,7 +334,8 @@ exports[`generateModelConfig single native provider uses OpenAI models with isMa
"variant": "medium", "variant": "medium",
}, },
"quick": { "quick": {
"model": "openai/gpt-5.4-mini", "model": "openai/gpt-5.3-codex",
"variant": "low",
}, },
"ultrabrain": { "ultrabrain": {
"model": "openai/gpt-5.4", "model": "openai/gpt-5.4",
@@ -364,20 +366,20 @@ exports[`generateModelConfig single native provider uses Gemini models when only
"$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-opencode.schema.json", "$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-opencode.schema.json",
"agents": { "agents": {
"atlas": { "atlas": {
"model": "opencode/gpt-5-nano", "model": "opencode/glm-4.7-free",
}, },
"explore": { "explore": {
"model": "opencode/gpt-5-nano", "model": "opencode/gpt-5-nano",
}, },
"metis": { "metis": {
"model": "opencode/gpt-5-nano", "model": "opencode/glm-4.7-free",
}, },
"momus": { "momus": {
"model": "google/gemini-3.1-pro-preview", "model": "google/gemini-3.1-pro-preview",
"variant": "high", "variant": "high",
}, },
"multimodal-looker": { "multimodal-looker": {
"model": "opencode/gpt-5-nano", "model": "opencode/glm-4.7-free",
}, },
"oracle": { "oracle": {
"model": "google/gemini-3.1-pro-preview", "model": "google/gemini-3.1-pro-preview",
@@ -387,7 +389,7 @@ exports[`generateModelConfig single native provider uses Gemini models when only
"model": "google/gemini-3.1-pro-preview", "model": "google/gemini-3.1-pro-preview",
}, },
"sisyphus-junior": { "sisyphus-junior": {
"model": "opencode/gpt-5-nano", "model": "opencode/glm-4.7-free",
}, },
}, },
"categories": { "categories": {
@@ -424,20 +426,20 @@ exports[`generateModelConfig single native provider uses Gemini models with isMa
"$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-opencode.schema.json", "$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-opencode.schema.json",
"agents": { "agents": {
"atlas": { "atlas": {
"model": "opencode/gpt-5-nano", "model": "opencode/glm-4.7-free",
}, },
"explore": { "explore": {
"model": "opencode/gpt-5-nano", "model": "opencode/gpt-5-nano",
}, },
"metis": { "metis": {
"model": "opencode/gpt-5-nano", "model": "opencode/glm-4.7-free",
}, },
"momus": { "momus": {
"model": "google/gemini-3.1-pro-preview", "model": "google/gemini-3.1-pro-preview",
"variant": "high", "variant": "high",
}, },
"multimodal-looker": { "multimodal-looker": {
"model": "opencode/gpt-5-nano", "model": "opencode/glm-4.7-free",
}, },
"oracle": { "oracle": {
"model": "google/gemini-3.1-pro-preview", "model": "google/gemini-3.1-pro-preview",
@@ -447,7 +449,7 @@ exports[`generateModelConfig single native provider uses Gemini models with isMa
"model": "google/gemini-3.1-pro-preview", "model": "google/gemini-3.1-pro-preview",
}, },
"sisyphus-junior": { "sisyphus-junior": {
"model": "opencode/gpt-5-nano", "model": "opencode/glm-4.7-free",
}, },
}, },
"categories": { "categories": {
@@ -463,7 +465,7 @@ exports[`generateModelConfig single native provider uses Gemini models with isMa
"variant": "high", "variant": "high",
}, },
"unspecified-high": { "unspecified-high": {
"model": "opencode/gpt-5-nano", "model": "opencode/glm-4.7-free",
}, },
"unspecified-low": { "unspecified-low": {
"model": "google/gemini-3-flash-preview", "model": "google/gemini-3-flash-preview",
@@ -490,7 +492,7 @@ exports[`generateModelConfig all native providers uses preferred models from fal
"model": "anthropic/claude-haiku-4-5", "model": "anthropic/claude-haiku-4-5",
}, },
"hephaestus": { "hephaestus": {
"model": "openai/gpt-5.4", "model": "openai/gpt-5.3-codex",
"variant": "medium", "variant": "medium",
}, },
"metis": { "metis": {
@@ -531,7 +533,7 @@ exports[`generateModelConfig all native providers uses preferred models from fal
"variant": "medium", "variant": "medium",
}, },
"quick": { "quick": {
"model": "openai/gpt-5.4-mini", "model": "anthropic/claude-haiku-4-5",
}, },
"ultrabrain": { "ultrabrain": {
"model": "openai/gpt-5.4", "model": "openai/gpt-5.4",
@@ -565,7 +567,7 @@ exports[`generateModelConfig all native providers uses preferred models with isM
"model": "anthropic/claude-haiku-4-5", "model": "anthropic/claude-haiku-4-5",
}, },
"hephaestus": { "hephaestus": {
"model": "openai/gpt-5.4", "model": "openai/gpt-5.3-codex",
"variant": "medium", "variant": "medium",
}, },
"metis": { "metis": {
@@ -606,7 +608,7 @@ exports[`generateModelConfig all native providers uses preferred models with isM
"variant": "medium", "variant": "medium",
}, },
"quick": { "quick": {
"model": "openai/gpt-5.4-mini", "model": "anthropic/claude-haiku-4-5",
}, },
"ultrabrain": { "ultrabrain": {
"model": "openai/gpt-5.4", "model": "openai/gpt-5.4",
@@ -641,7 +643,7 @@ exports[`generateModelConfig fallback providers uses OpenCode Zen models when on
"model": "opencode/claude-haiku-4-5", "model": "opencode/claude-haiku-4-5",
}, },
"hephaestus": { "hephaestus": {
"model": "opencode/gpt-5.4", "model": "opencode/gpt-5.3-codex",
"variant": "medium", "variant": "medium",
}, },
"metis": { "metis": {
@@ -682,7 +684,7 @@ exports[`generateModelConfig fallback providers uses OpenCode Zen models when on
"variant": "medium", "variant": "medium",
}, },
"quick": { "quick": {
"model": "opencode/gpt-5.4-mini", "model": "opencode/claude-haiku-4-5",
}, },
"ultrabrain": { "ultrabrain": {
"model": "opencode/gpt-5.4", "model": "opencode/gpt-5.4",
@@ -716,7 +718,7 @@ exports[`generateModelConfig fallback providers uses OpenCode Zen models with is
"model": "opencode/claude-haiku-4-5", "model": "opencode/claude-haiku-4-5",
}, },
"hephaestus": { "hephaestus": {
"model": "opencode/gpt-5.4", "model": "opencode/gpt-5.3-codex",
"variant": "medium", "variant": "medium",
}, },
"metis": { "metis": {
@@ -757,7 +759,7 @@ exports[`generateModelConfig fallback providers uses OpenCode Zen models with is
"variant": "medium", "variant": "medium",
}, },
"quick": { "quick": {
"model": "opencode/gpt-5.4-mini", "model": "opencode/claude-haiku-4-5",
}, },
"ultrabrain": { "ultrabrain": {
"model": "opencode/gpt-5.4", "model": "opencode/gpt-5.4",
@@ -828,7 +830,7 @@ exports[`generateModelConfig fallback providers uses GitHub Copilot models when
"variant": "high", "variant": "high",
}, },
"quick": { "quick": {
"model": "github-copilot/gpt-5.4-mini", "model": "github-copilot/claude-haiku-4.5",
}, },
"ultrabrain": { "ultrabrain": {
"model": "github-copilot/gemini-3.1-pro-preview", "model": "github-copilot/gemini-3.1-pro-preview",
@@ -898,7 +900,7 @@ exports[`generateModelConfig fallback providers uses GitHub Copilot models with
"variant": "high", "variant": "high",
}, },
"quick": { "quick": {
"model": "github-copilot/gpt-5.4-mini", "model": "github-copilot/claude-haiku-4.5",
}, },
"ultrabrain": { "ultrabrain": {
"model": "github-copilot/gemini-3.1-pro-preview", "model": "github-copilot/gemini-3.1-pro-preview",
@@ -927,7 +929,7 @@ exports[`generateModelConfig fallback providers uses ZAI model for librarian whe
"$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-opencode.schema.json", "$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-opencode.schema.json",
"agents": { "agents": {
"atlas": { "atlas": {
"model": "opencode/gpt-5-nano", "model": "opencode/glm-4.7-free",
}, },
"explore": { "explore": {
"model": "opencode/gpt-5-nano", "model": "opencode/gpt-5-nano",
@@ -936,45 +938,45 @@ exports[`generateModelConfig fallback providers uses ZAI model for librarian whe
"model": "zai-coding-plan/glm-4.7", "model": "zai-coding-plan/glm-4.7",
}, },
"metis": { "metis": {
"model": "opencode/gpt-5-nano", "model": "opencode/glm-4.7-free",
}, },
"momus": { "momus": {
"model": "opencode/gpt-5-nano", "model": "opencode/glm-4.7-free",
}, },
"multimodal-looker": { "multimodal-looker": {
"model": "zai-coding-plan/glm-4.6v", "model": "zai-coding-plan/glm-4.6v",
}, },
"oracle": { "oracle": {
"model": "opencode/gpt-5-nano", "model": "opencode/glm-4.7-free",
}, },
"prometheus": { "prometheus": {
"model": "opencode/gpt-5-nano", "model": "opencode/glm-4.7-free",
}, },
"sisyphus": { "sisyphus": {
"model": "zai-coding-plan/glm-5", "model": "zai-coding-plan/glm-5",
}, },
"sisyphus-junior": { "sisyphus-junior": {
"model": "opencode/gpt-5-nano", "model": "opencode/glm-4.7-free",
}, },
}, },
"categories": { "categories": {
"quick": { "quick": {
"model": "opencode/gpt-5-nano", "model": "opencode/glm-4.7-free",
}, },
"ultrabrain": { "ultrabrain": {
"model": "opencode/gpt-5-nano", "model": "opencode/glm-4.7-free",
}, },
"unspecified-high": { "unspecified-high": {
"model": "opencode/gpt-5-nano", "model": "opencode/glm-4.7-free",
}, },
"unspecified-low": { "unspecified-low": {
"model": "opencode/gpt-5-nano", "model": "opencode/glm-4.7-free",
}, },
"visual-engineering": { "visual-engineering": {
"model": "zai-coding-plan/glm-5", "model": "zai-coding-plan/glm-5",
}, },
"writing": { "writing": {
"model": "opencode/gpt-5-nano", "model": "opencode/glm-4.7-free",
}, },
}, },
} }
@@ -985,7 +987,7 @@ exports[`generateModelConfig fallback providers uses ZAI model for librarian wit
"$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-opencode.schema.json", "$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-opencode.schema.json",
"agents": { "agents": {
"atlas": { "atlas": {
"model": "opencode/gpt-5-nano", "model": "opencode/glm-4.7-free",
}, },
"explore": { "explore": {
"model": "opencode/gpt-5-nano", "model": "opencode/gpt-5-nano",
@@ -994,45 +996,45 @@ exports[`generateModelConfig fallback providers uses ZAI model for librarian wit
"model": "zai-coding-plan/glm-4.7", "model": "zai-coding-plan/glm-4.7",
}, },
"metis": { "metis": {
"model": "opencode/gpt-5-nano", "model": "opencode/glm-4.7-free",
}, },
"momus": { "momus": {
"model": "opencode/gpt-5-nano", "model": "opencode/glm-4.7-free",
}, },
"multimodal-looker": { "multimodal-looker": {
"model": "zai-coding-plan/glm-4.6v", "model": "zai-coding-plan/glm-4.6v",
}, },
"oracle": { "oracle": {
"model": "opencode/gpt-5-nano", "model": "opencode/glm-4.7-free",
}, },
"prometheus": { "prometheus": {
"model": "opencode/gpt-5-nano", "model": "opencode/glm-4.7-free",
}, },
"sisyphus": { "sisyphus": {
"model": "zai-coding-plan/glm-5", "model": "zai-coding-plan/glm-5",
}, },
"sisyphus-junior": { "sisyphus-junior": {
"model": "opencode/gpt-5-nano", "model": "opencode/glm-4.7-free",
}, },
}, },
"categories": { "categories": {
"quick": { "quick": {
"model": "opencode/gpt-5-nano", "model": "opencode/glm-4.7-free",
}, },
"ultrabrain": { "ultrabrain": {
"model": "opencode/gpt-5-nano", "model": "opencode/glm-4.7-free",
}, },
"unspecified-high": { "unspecified-high": {
"model": "zai-coding-plan/glm-5", "model": "zai-coding-plan/glm-5",
}, },
"unspecified-low": { "unspecified-low": {
"model": "opencode/gpt-5-nano", "model": "opencode/glm-4.7-free",
}, },
"visual-engineering": { "visual-engineering": {
"model": "zai-coding-plan/glm-5", "model": "zai-coding-plan/glm-5",
}, },
"writing": { "writing": {
"model": "opencode/gpt-5-nano", "model": "opencode/glm-4.7-free",
}, },
}, },
} }
@@ -1049,7 +1051,7 @@ exports[`generateModelConfig mixed provider scenarios uses Claude + OpenCode Zen
"model": "anthropic/claude-haiku-4-5", "model": "anthropic/claude-haiku-4-5",
}, },
"hephaestus": { "hephaestus": {
"model": "opencode/gpt-5.4", "model": "opencode/gpt-5.3-codex",
"variant": "medium", "variant": "medium",
}, },
"metis": { "metis": {
@@ -1090,7 +1092,7 @@ exports[`generateModelConfig mixed provider scenarios uses Claude + OpenCode Zen
"variant": "medium", "variant": "medium",
}, },
"quick": { "quick": {
"model": "opencode/gpt-5.4-mini", "model": "anthropic/claude-haiku-4-5",
}, },
"ultrabrain": { "ultrabrain": {
"model": "opencode/gpt-5.4", "model": "opencode/gpt-5.4",
@@ -1124,7 +1126,7 @@ exports[`generateModelConfig mixed provider scenarios uses OpenAI + Copilot comb
"model": "github-copilot/gpt-5-mini", "model": "github-copilot/gpt-5-mini",
}, },
"hephaestus": { "hephaestus": {
"model": "openai/gpt-5.4", "model": "openai/gpt-5.3-codex",
"variant": "medium", "variant": "medium",
}, },
"metis": { "metis": {
@@ -1165,7 +1167,7 @@ exports[`generateModelConfig mixed provider scenarios uses OpenAI + Copilot comb
"variant": "medium", "variant": "medium",
}, },
"quick": { "quick": {
"model": "openai/gpt-5.4-mini", "model": "github-copilot/claude-haiku-4.5",
}, },
"ultrabrain": { "ultrabrain": {
"model": "openai/gpt-5.4", "model": "openai/gpt-5.4",
@@ -1271,7 +1273,7 @@ exports[`generateModelConfig mixed provider scenarios uses Gemini + Claude combi
"variant": "max", "variant": "max",
}, },
"multimodal-looker": { "multimodal-looker": {
"model": "opencode/gpt-5-nano", "model": "opencode/glm-4.7-free",
}, },
"oracle": { "oracle": {
"model": "google/gemini-3.1-pro-preview", "model": "google/gemini-3.1-pro-preview",
@@ -1329,7 +1331,7 @@ exports[`generateModelConfig mixed provider scenarios uses all fallback provider
"model": "opencode/claude-haiku-4-5", "model": "opencode/claude-haiku-4-5",
}, },
"hephaestus": { "hephaestus": {
"model": "github-copilot/gpt-5.4", "model": "opencode/gpt-5.3-codex",
"variant": "medium", "variant": "medium",
}, },
"librarian": { "librarian": {
@@ -1373,7 +1375,7 @@ exports[`generateModelConfig mixed provider scenarios uses all fallback provider
"variant": "medium", "variant": "medium",
}, },
"quick": { "quick": {
"model": "github-copilot/gpt-5.4-mini", "model": "github-copilot/claude-haiku-4.5",
}, },
"ultrabrain": { "ultrabrain": {
"model": "opencode/gpt-5.4", "model": "opencode/gpt-5.4",
@@ -1407,7 +1409,7 @@ exports[`generateModelConfig mixed provider scenarios uses all providers togethe
"model": "anthropic/claude-haiku-4-5", "model": "anthropic/claude-haiku-4-5",
}, },
"hephaestus": { "hephaestus": {
"model": "openai/gpt-5.4", "model": "openai/gpt-5.3-codex",
"variant": "medium", "variant": "medium",
}, },
"librarian": { "librarian": {
@@ -1451,7 +1453,7 @@ exports[`generateModelConfig mixed provider scenarios uses all providers togethe
"variant": "medium", "variant": "medium",
}, },
"quick": { "quick": {
"model": "openai/gpt-5.4-mini", "model": "anthropic/claude-haiku-4-5",
}, },
"ultrabrain": { "ultrabrain": {
"model": "openai/gpt-5.4", "model": "openai/gpt-5.4",
@@ -1485,7 +1487,7 @@ exports[`generateModelConfig mixed provider scenarios uses all providers with is
"model": "anthropic/claude-haiku-4-5", "model": "anthropic/claude-haiku-4-5",
}, },
"hephaestus": { "hephaestus": {
"model": "openai/gpt-5.4", "model": "openai/gpt-5.3-codex",
"variant": "medium", "variant": "medium",
}, },
"librarian": { "librarian": {
@@ -1529,7 +1531,7 @@ exports[`generateModelConfig mixed provider scenarios uses all providers with is
"variant": "medium", "variant": "medium",
}, },
"quick": { "quick": {
"model": "openai/gpt-5.4-mini", "model": "anthropic/claude-haiku-4-5",
}, },
"ultrabrain": { "ultrabrain": {
"model": "openai/gpt-5.4", "model": "openai/gpt-5.4",

View File

@@ -1,5 +1,4 @@
import color from "picocolors" import color from "picocolors"
import { PLUGIN_NAME } from "../shared"
import type { InstallArgs } from "./types" import type { InstallArgs } from "./types"
import { import {
addPluginToOpenCodeConfig, addPluginToOpenCodeConfig,
@@ -33,7 +32,7 @@ export async function runCliInstaller(args: InstallArgs, version: string): Promi
} }
console.log() console.log()
printInfo( printInfo(
`Usage: bunx ${PLUGIN_NAME} install --no-tui --claude=<no|yes|max20> --gemini=<no|yes> --copilot=<no|yes>`, "Usage: bunx oh-my-opencode install --no-tui --claude=<no|yes|max20> --gemini=<no|yes> --copilot=<no|yes>",
) )
console.log() console.log()
return 1 return 1
@@ -66,7 +65,7 @@ export async function runCliInstaller(args: InstallArgs, version: string): Promi
const config = argsToConfig(args) const config = argsToConfig(args)
printStep(step++, totalSteps, `Adding ${PLUGIN_NAME} plugin...`) printStep(step++, totalSteps, "Adding oh-my-opencode plugin...")
const pluginResult = await addPluginToOpenCodeConfig(version) const pluginResult = await addPluginToOpenCodeConfig(version)
if (!pluginResult.success) { if (!pluginResult.success) {
printError(`Failed: ${pluginResult.error}`) printError(`Failed: ${pluginResult.error}`)
@@ -76,7 +75,7 @@ export async function runCliInstaller(args: InstallArgs, version: string): Promi
`Plugin ${isUpdate ? "verified" : "added"} ${SYMBOLS.arrow} ${color.dim(pluginResult.configPath)}`, `Plugin ${isUpdate ? "verified" : "added"} ${SYMBOLS.arrow} ${color.dim(pluginResult.configPath)}`,
) )
printStep(step++, totalSteps, `Writing ${PLUGIN_NAME} configuration...`) printStep(step++, totalSteps, "Writing oh-my-opencode configuration...")
const omoResult = writeOmoConfig(config) const omoResult = writeOmoConfig(config)
if (!omoResult.success) { if (!omoResult.success) {
printError(`Failed: ${omoResult.error}`) printError(`Failed: ${omoResult.error}`)

View File

@@ -3,7 +3,6 @@ import { install } from "./install"
import { run } from "./run" import { run } from "./run"
import { getLocalVersion } from "./get-local-version" import { getLocalVersion } from "./get-local-version"
import { doctor } from "./doctor" import { doctor } from "./doctor"
import { refreshModelCapabilities } from "./refresh-model-capabilities"
import { createMcpOAuthCommand } from "./mcp-oauth" import { createMcpOAuthCommand } from "./mcp-oauth"
import type { InstallArgs } from "./types" import type { InstallArgs } from "./types"
import type { RunOptions } from "./run" import type { RunOptions } from "./run"
@@ -43,7 +42,7 @@ Examples:
Model Providers (Priority: Native > Copilot > OpenCode Zen > Z.ai > Kimi): Model Providers (Priority: Native > Copilot > OpenCode Zen > Z.ai > Kimi):
Claude Native anthropic/ models (Opus, Sonnet, Haiku) Claude Native anthropic/ models (Opus, Sonnet, Haiku)
OpenAI Native openai/ models (GPT-5.4 for Oracle) OpenAI Native openai/ models (GPT-5.4 for Oracle)
Gemini Native google/ models (Gemini 3.1 Pro, Flash) Gemini Native google/ models (Gemini 3 Pro, Flash)
Copilot github-copilot/ models (fallback) Copilot github-copilot/ models (fallback)
OpenCode Zen opencode/ models (opencode/claude-opus-4-6, etc.) OpenCode Zen opencode/ models (opencode/claude-opus-4-6, etc.)
Z.ai zai-coding-plan/glm-5 (visual-engineering fallback) Z.ai zai-coding-plan/glm-5 (visual-engineering fallback)
@@ -177,21 +176,6 @@ Examples:
process.exit(exitCode) process.exit(exitCode)
}) })
program
.command("refresh-model-capabilities")
.description("Refresh the cached models.dev-based model capabilities snapshot")
.option("-d, --directory <path>", "Working directory to read oh-my-opencode config from")
.option("--source-url <url>", "Override the models.dev source URL")
.option("--json", "Output refresh summary as JSON")
.action(async (options) => {
const exitCode = await refreshModelCapabilities({
directory: options.directory,
sourceUrl: options.sourceUrl,
json: options.json ?? false,
})
process.exit(exitCode)
})
program program
.command("version") .command("version")
.description("Show version information") .description("Show version information")

View File

@@ -0,0 +1,300 @@
import { describe, expect, test, mock, afterEach } from "bun:test"
import { getPluginNameWithVersion, fetchNpmDistTags, generateOmoConfig } from "./config-manager"
import type { InstallConfig } from "./types"
describe("getPluginNameWithVersion", () => {
const originalFetch = globalThis.fetch
afterEach(() => {
globalThis.fetch = originalFetch
})
test("returns @latest when current version matches latest tag", async () => {
// #given npm dist-tags with latest=2.14.0
globalThis.fetch = mock(() =>
Promise.resolve({
ok: true,
json: () => Promise.resolve({ latest: "2.14.0", beta: "3.0.0-beta.3" }),
} as Response)
) as unknown as typeof fetch
// #when current version is 2.14.0
const result = await getPluginNameWithVersion("2.14.0")
// #then should use @latest tag
expect(result).toBe("oh-my-opencode@latest")
})
test("returns @beta when current version matches beta tag", async () => {
// #given npm dist-tags with beta=3.0.0-beta.3
globalThis.fetch = mock(() =>
Promise.resolve({
ok: true,
json: () => Promise.resolve({ latest: "2.14.0", beta: "3.0.0-beta.3" }),
} as Response)
) as unknown as typeof fetch
// #when current version is 3.0.0-beta.3
const result = await getPluginNameWithVersion("3.0.0-beta.3")
// #then should use @beta tag
expect(result).toBe("oh-my-opencode@beta")
})
test("returns @next when current version matches next tag", async () => {
// #given npm dist-tags with next=3.1.0-next.1
globalThis.fetch = mock(() =>
Promise.resolve({
ok: true,
json: () => Promise.resolve({ latest: "2.14.0", beta: "3.0.0-beta.3", next: "3.1.0-next.1" }),
} as Response)
) as unknown as typeof fetch
// #when current version is 3.1.0-next.1
const result = await getPluginNameWithVersion("3.1.0-next.1")
// #then should use @next tag
expect(result).toBe("oh-my-opencode@next")
})
test("returns prerelease channel tag when no dist-tag matches prerelease version", async () => {
// #given npm dist-tags with beta=3.0.0-beta.3
globalThis.fetch = mock(() =>
Promise.resolve({
ok: true,
json: () => Promise.resolve({ latest: "2.14.0", beta: "3.0.0-beta.3" }),
} as Response)
) as unknown as typeof fetch
// #when current version is old beta 3.0.0-beta.2
const result = await getPluginNameWithVersion("3.0.0-beta.2")
// #then should preserve prerelease channel
expect(result).toBe("oh-my-opencode@beta")
})
test("returns prerelease channel tag when fetch fails", async () => {
// #given network failure
globalThis.fetch = mock(() => Promise.reject(new Error("Network error"))) as unknown as typeof fetch
// #when current version is 3.0.0-beta.3
const result = await getPluginNameWithVersion("3.0.0-beta.3")
// #then should preserve prerelease channel
expect(result).toBe("oh-my-opencode@beta")
})
test("returns bare package name when npm returns non-ok response for stable version", async () => {
// #given npm returns 404
globalThis.fetch = mock(() =>
Promise.resolve({
ok: false,
status: 404,
} as Response)
) as unknown as typeof fetch
// #when current version is 2.14.0
const result = await getPluginNameWithVersion("2.14.0")
// #then should fall back to bare package entry
expect(result).toBe("oh-my-opencode")
})
test("prioritizes latest over other tags when version matches multiple", async () => {
// #given version matches both latest and beta (during release promotion)
globalThis.fetch = mock(() =>
Promise.resolve({
ok: true,
json: () => Promise.resolve({ beta: "3.0.0", latest: "3.0.0", next: "3.1.0-alpha.1" }),
} as Response)
) as unknown as typeof fetch
// #when current version matches both
const result = await getPluginNameWithVersion("3.0.0")
// #then should prioritize @latest
expect(result).toBe("oh-my-opencode@latest")
})
})
describe("fetchNpmDistTags", () => {
const originalFetch = globalThis.fetch
afterEach(() => {
globalThis.fetch = originalFetch
})
test("returns dist-tags on success", async () => {
// #given npm returns dist-tags
globalThis.fetch = mock(() =>
Promise.resolve({
ok: true,
json: () => Promise.resolve({ latest: "2.14.0", beta: "3.0.0-beta.3" }),
} as Response)
) as unknown as typeof fetch
// #when fetching dist-tags
const result = await fetchNpmDistTags("oh-my-opencode")
// #then should return the tags
expect(result).toEqual({ latest: "2.14.0", beta: "3.0.0-beta.3" })
})
test("returns null on network failure", async () => {
// #given network failure
globalThis.fetch = mock(() => Promise.reject(new Error("Network error"))) as unknown as typeof fetch
// #when fetching dist-tags
const result = await fetchNpmDistTags("oh-my-opencode")
// #then should return null
expect(result).toBeNull()
})
test("returns null on non-ok response", async () => {
// #given npm returns 404
globalThis.fetch = mock(() =>
Promise.resolve({
ok: false,
status: 404,
} as Response)
) as unknown as typeof fetch
// #when fetching dist-tags
const result = await fetchNpmDistTags("oh-my-opencode")
// #then should return null
expect(result).toBeNull()
})
})
describe("generateOmoConfig - model fallback system", () => {
test("uses github-copilot sonnet fallback when only copilot available", () => {
// #given user has only copilot (no max plan)
const config: InstallConfig = {
hasClaude: false,
isMax20: false,
hasOpenAI: false,
hasGemini: false,
hasCopilot: true,
hasOpencodeZen: false,
hasZaiCodingPlan: false,
hasKimiForCoding: false,
}
// #when generating config
const result = generateOmoConfig(config)
// #then Sisyphus uses Copilot (OR logic - copilot is in claude-opus-4-6 providers)
expect((result.agents as Record<string, { model: string }>).sisyphus.model).toBe("github-copilot/claude-opus-4.6")
})
test("uses ultimate fallback when no providers configured", () => {
// #given user has no providers
const config: InstallConfig = {
hasClaude: false,
isMax20: false,
hasOpenAI: false,
hasGemini: false,
hasCopilot: false,
hasOpencodeZen: false,
hasZaiCodingPlan: false,
hasKimiForCoding: false,
}
// #when generating config
const result = generateOmoConfig(config)
// #then Sisyphus is omitted (requires all fallback providers)
expect(result.$schema).toBe("https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-opencode.schema.json")
expect((result.agents as Record<string, { model: string }>).sisyphus).toBeUndefined()
})
test("uses ZAI model for librarian when Z.ai is available", () => {
// #given user has Z.ai and Claude max20
const config: InstallConfig = {
hasClaude: true,
isMax20: true,
hasOpenAI: false,
hasGemini: false,
hasCopilot: false,
hasOpencodeZen: false,
hasZaiCodingPlan: true,
hasKimiForCoding: false,
}
// #when generating config
const result = generateOmoConfig(config)
// #then librarian should use ZAI model
expect((result.agents as Record<string, { model: string }>).librarian.model).toBe("zai-coding-plan/glm-4.7")
// #then Sisyphus uses Claude (OR logic)
expect((result.agents as Record<string, { model: string }>).sisyphus.model).toBe("anthropic/claude-opus-4-6")
})
test("uses native OpenAI models when only ChatGPT available", () => {
// #given user has only ChatGPT subscription
const config: InstallConfig = {
hasClaude: false,
isMax20: false,
hasOpenAI: true,
hasGemini: false,
hasCopilot: false,
hasOpencodeZen: false,
hasZaiCodingPlan: false,
hasKimiForCoding: false,
}
// #when generating config
const result = generateOmoConfig(config)
// #then Sisyphus resolves to gpt-5.4 medium (openai is now in sisyphus chain)
expect((result.agents as Record<string, { model: string; variant?: string }>).sisyphus.model).toBe("openai/gpt-5.4")
expect((result.agents as Record<string, { model: string; variant?: string }>).sisyphus.variant).toBe("medium")
// #then Oracle should use native OpenAI (first fallback entry)
expect((result.agents as Record<string, { model: string }>).oracle.model).toBe("openai/gpt-5.4")
// #then multimodal-looker should use native OpenAI (first fallback entry is gpt-5.4)
expect((result.agents as Record<string, { model: string }>)["multimodal-looker"].model).toBe("openai/gpt-5.4")
})
test("uses haiku for explore when Claude max20", () => {
// #given user has Claude max20
const config: InstallConfig = {
hasClaude: true,
isMax20: true,
hasOpenAI: false,
hasGemini: false,
hasCopilot: false,
hasOpencodeZen: false,
hasZaiCodingPlan: false,
hasKimiForCoding: false,
}
// #when generating config
const result = generateOmoConfig(config)
// #then explore should use haiku (max20 plan uses Claude quota)
expect((result.agents as Record<string, { model: string }>).explore.model).toBe("anthropic/claude-haiku-4-5")
})
test("uses haiku for explore regardless of max20 flag", () => {
// #given user has Claude but not max20
const config: InstallConfig = {
hasClaude: true,
isMax20: false,
hasOpenAI: false,
hasGemini: false,
hasCopilot: false,
hasOpencodeZen: false,
hasZaiCodingPlan: false,
hasKimiForCoding: false,
}
// #when generating config
const result = generateOmoConfig(config)
// #then explore should use haiku (isMax20 doesn't affect explore anymore)
expect((result.agents as Record<string, { model: string }>).explore.model).toBe("anthropic/claude-haiku-4-5")
})
})

View File

@@ -10,7 +10,7 @@
| File | Purpose | | File | Purpose |
|------|---------| |------|---------|
| `add-plugin-to-opencode-config.ts` | Register `oh-my-opencode` in `.opencode/opencode.json` plugin array | | `add-plugin-to-opencode-config.ts` | Register `oh-my-openagent` in `.opencode/opencode.json` plugin array |
| `add-provider-config.ts` | Add provider API key to OpenCode config (user-level) | | `add-provider-config.ts` | Add provider API key to OpenCode config (user-level) |
| `antigravity-provider-configuration.ts` | Handle Antigravity provider setup (special case) | | `antigravity-provider-configuration.ts` | Handle Antigravity provider setup (special case) |
| `auth-plugins.ts` | Detect auth plugin requirements per provider (oauth vs key) | | `auth-plugins.ts` | Detect auth plugin requirements per provider (oauth vs key) |
@@ -26,7 +26,7 @@
| `opencode-binary.ts` | Detect OpenCode binary location, verify it's installed | | `opencode-binary.ts` | Detect OpenCode binary location, verify it's installed |
| `opencode-config-format.ts` | OpenCode config format constants and type guards | | `opencode-config-format.ts` | OpenCode config format constants and type guards |
| `parse-opencode-config-file.ts` | Parse opencode.json/opencode.jsonc with fallback | | `parse-opencode-config-file.ts` | Parse opencode.json/opencode.jsonc with fallback |
| `plugin-name-with-version.ts` | Resolve `oh-my-opencode@X.Y.Z` for installation | | `plugin-name-with-version.ts` | Resolve `oh-my-openagent@X.Y.Z` for installation |
| `write-omo-config.ts` | Write generated config to `.opencode/oh-my-opencode.jsonc` | | `write-omo-config.ts` | Write generated config to `.opencode/oh-my-opencode.jsonc` |
## USAGE PATTERN ## USAGE PATTERN

View File

@@ -1,6 +1,5 @@
import { readFileSync, writeFileSync } from "node:fs" import { readFileSync, writeFileSync } from "node:fs"
import type { ConfigMergeResult } from "../types" import type { ConfigMergeResult } from "../types"
import { PLUGIN_NAME, LEGACY_PLUGIN_NAME } from "../../shared"
import { getConfigDir } from "./config-context" import { getConfigDir } from "./config-context"
import { ensureConfigDirectoryExists } from "./ensure-config-directory-exists" import { ensureConfigDirectoryExists } from "./ensure-config-directory-exists"
import { formatErrorWithSuggestion } from "./format-error-with-suggestion" import { formatErrorWithSuggestion } from "./format-error-with-suggestion"
@@ -8,6 +7,8 @@ import { detectConfigFormat } from "./opencode-config-format"
import { parseOpenCodeConfigFileWithError, type OpenCodeConfig } from "./parse-opencode-config-file" import { parseOpenCodeConfigFileWithError, type OpenCodeConfig } from "./parse-opencode-config-file"
import { getPluginNameWithVersion } from "./plugin-name-with-version" import { getPluginNameWithVersion } from "./plugin-name-with-version"
const PACKAGE_NAME = "oh-my-opencode"
export async function addPluginToOpenCodeConfig(currentVersion: string): Promise<ConfigMergeResult> { export async function addPluginToOpenCodeConfig(currentVersion: string): Promise<ConfigMergeResult> {
try { try {
ensureConfigDirectoryExists() ensureConfigDirectoryExists()
@@ -20,7 +21,7 @@ export async function addPluginToOpenCodeConfig(currentVersion: string): Promise
} }
const { format, path } = detectConfigFormat() const { format, path } = detectConfigFormat()
const pluginEntry = await getPluginNameWithVersion(currentVersion, PLUGIN_NAME) const pluginEntry = await getPluginNameWithVersion(currentVersion, PACKAGE_NAME)
try { try {
if (format === "none") { if (format === "none") {
@@ -40,40 +41,27 @@ export async function addPluginToOpenCodeConfig(currentVersion: string): Promise
const config = parseResult.config const config = parseResult.config
const plugins = config.plugin ?? [] const plugins = config.plugin ?? []
const existingIndex = plugins.findIndex((plugin) => plugin === PACKAGE_NAME || plugin.startsWith(`${PACKAGE_NAME}@`))
const canonicalEntries = plugins.filter( if (existingIndex !== -1) {
(plugin) => plugin === PLUGIN_NAME || plugin.startsWith(`${PLUGIN_NAME}@`) if (plugins[existingIndex] === pluginEntry) {
) return { success: true, configPath: path }
const legacyEntries = plugins.filter( }
(plugin) => plugin === LEGACY_PLUGIN_NAME || plugin.startsWith(`${LEGACY_PLUGIN_NAME}@`) plugins[existingIndex] = pluginEntry
)
const otherPlugins = plugins.filter(
(plugin) => !(plugin === PLUGIN_NAME || plugin.startsWith(`${PLUGIN_NAME}@`))
&& !(plugin === LEGACY_PLUGIN_NAME || plugin.startsWith(`${LEGACY_PLUGIN_NAME}@`))
)
const normalizedPlugins = [...otherPlugins]
if (canonicalEntries.length > 0) {
normalizedPlugins.push(canonicalEntries[0])
} else if (legacyEntries.length > 0) {
const versionMatch = legacyEntries[0].match(/@(.+)$/)
const preservedVersion = versionMatch ? versionMatch[1] : null
normalizedPlugins.push(preservedVersion ? `${PLUGIN_NAME}@${preservedVersion}` : pluginEntry)
} else { } else {
normalizedPlugins.push(pluginEntry) plugins.push(pluginEntry)
} }
config.plugin = normalizedPlugins config.plugin = plugins
if (format === "jsonc") { if (format === "jsonc") {
const content = readFileSync(path, "utf-8") const content = readFileSync(path, "utf-8")
const pluginArrayRegex = /((?:"plugin"|plugin)\s*:\s*)\[([\s\S]*?)\]/ const pluginArrayRegex = /"plugin"\s*:\s*\[([\s\S]*?)\]/
const match = content.match(pluginArrayRegex) const match = content.match(pluginArrayRegex)
if (match) { if (match) {
const formattedPlugins = normalizedPlugins.map((p) => `"${p}"`).join(",\n ") const formattedPlugins = plugins.map((p) => `"${p}"`).join(",\n ")
const newContent = content.replace(pluginArrayRegex, `$1[\n ${formattedPlugins}\n ]`) const newContent = content.replace(pluginArrayRegex, `"plugin": [\n ${formattedPlugins}\n ]`)
writeFileSync(path, newContent) writeFileSync(path, newContent)
} else { } else {
const newContent = content.replace(/(\{)/, `$1\n "plugin": ["${pluginEntry}"],`) const newContent = content.replace(/(\{)/, `$1\n "plugin": ["${pluginEntry}"],`)

View File

@@ -11,8 +11,6 @@ type BunInstallOutputMode = "inherit" | "pipe"
interface RunBunInstallOptions { interface RunBunInstallOptions {
outputMode?: BunInstallOutputMode outputMode?: BunInstallOutputMode
/** Workspace directory to install to. Defaults to cache dir if not provided. */
workspaceDir?: string
} }
interface BunInstallOutput { interface BunInstallOutput {
@@ -67,7 +65,7 @@ function logCapturedOutputOnFailure(outputMode: BunInstallOutputMode, output: Bu
export async function runBunInstallWithDetails(options?: RunBunInstallOptions): Promise<BunInstallResult> { export async function runBunInstallWithDetails(options?: RunBunInstallOptions): Promise<BunInstallResult> {
const outputMode = options?.outputMode ?? "pipe" const outputMode = options?.outputMode ?? "pipe"
const cacheDir = options?.workspaceDir ?? getOpenCodeCacheDir() const cacheDir = getOpenCodeCacheDir()
const packageJsonPath = `${cacheDir}/package.json` const packageJsonPath = `${cacheDir}/package.json`
if (!existsSync(packageJsonPath)) { if (!existsSync(packageJsonPath)) {

View File

@@ -1,5 +1,5 @@
import { existsSync, readFileSync } from "node:fs" import { existsSync, readFileSync } from "node:fs"
import { parseJsonc, LEGACY_PLUGIN_NAME, PLUGIN_NAME } from "../../shared" import { parseJsonc } from "../../shared"
import type { DetectedConfig } from "../types" import type { DetectedConfig } from "../types"
import { getOmoConfigPath } from "./config-context" import { getOmoConfigPath } from "./config-context"
import { detectConfigFormat } from "./opencode-config-format" import { detectConfigFormat } from "./opencode-config-format"
@@ -55,12 +55,8 @@ function detectProvidersFromOmoConfig(): {
} }
} }
function isOurPlugin(plugin: string): boolean {
return plugin === PLUGIN_NAME || plugin.startsWith(`${PLUGIN_NAME}@`) ||
plugin === LEGACY_PLUGIN_NAME || plugin.startsWith(`${LEGACY_PLUGIN_NAME}@`)
}
export function detectCurrentConfig(): DetectedConfig { export function detectCurrentConfig(): DetectedConfig {
const PACKAGE_NAME = "oh-my-opencode"
const result: DetectedConfig = { const result: DetectedConfig = {
isInstalled: false, isInstalled: false,
hasClaude: true, hasClaude: true,
@@ -86,7 +82,7 @@ export function detectCurrentConfig(): DetectedConfig {
const openCodeConfig = parseResult.config const openCodeConfig = parseResult.config
const plugins = openCodeConfig.plugin ?? [] const plugins = openCodeConfig.plugin ?? []
result.isInstalled = plugins.some(isOurPlugin) result.isInstalled = plugins.some((plugin) => plugin.startsWith(PACKAGE_NAME))
if (!result.isInstalled) { if (!result.isInstalled) {
return result return result

View File

@@ -1,142 +0,0 @@
/// <reference types="bun-types" />
import { describe, expect, test } from "bun:test"
import { generateOmoConfig } from "../config-manager"
import type { InstallConfig } from "../types"
describe("generateOmoConfig - model fallback system", () => {
test("uses github-copilot sonnet fallback when only copilot available", () => {
//#given
const config: InstallConfig = {
hasClaude: false,
isMax20: false,
hasOpenAI: false,
hasGemini: false,
hasCopilot: true,
hasOpencodeZen: false,
hasZaiCodingPlan: false,
hasKimiForCoding: false,
hasOpencodeGo: false,
}
//#when
const result = generateOmoConfig(config)
//#then
expect([
"github-copilot/claude-opus-4.6",
"github-copilot/claude-opus-4-6",
]).toContain((result.agents as Record<string, { model: string }>).sisyphus.model)
})
test("uses ultimate fallback when no providers configured", () => {
//#given
const config: InstallConfig = {
hasClaude: false,
isMax20: false,
hasOpenAI: false,
hasGemini: false,
hasCopilot: false,
hasOpencodeZen: false,
hasZaiCodingPlan: false,
hasKimiForCoding: false,
hasOpencodeGo: false,
}
//#when
const result = generateOmoConfig(config)
//#then
expect(result.$schema).toBe("https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-opencode.schema.json")
expect((result.agents as Record<string, { model: string }>).sisyphus).toBeUndefined()
})
test("uses ZAI model for librarian when Z.ai is available", () => {
//#given
const config: InstallConfig = {
hasClaude: true,
isMax20: true,
hasOpenAI: false,
hasGemini: false,
hasCopilot: false,
hasOpencodeZen: false,
hasZaiCodingPlan: true,
hasKimiForCoding: false,
hasOpencodeGo: false,
}
//#when
const result = generateOmoConfig(config)
//#then
expect((result.agents as Record<string, { model: string }>).librarian.model).toBe("zai-coding-plan/glm-4.7")
expect((result.agents as Record<string, { model: string }>).sisyphus.model).toBe("anthropic/claude-opus-4-6")
})
test("uses native OpenAI models when only ChatGPT available", () => {
//#given
const config: InstallConfig = {
hasClaude: false,
isMax20: false,
hasOpenAI: true,
hasGemini: false,
hasCopilot: false,
hasOpencodeZen: false,
hasZaiCodingPlan: false,
hasKimiForCoding: false,
hasOpencodeGo: false,
}
//#when
const result = generateOmoConfig(config)
//#then
expect((result.agents as Record<string, { model: string; variant?: string }>).sisyphus.model).toBe("openai/gpt-5.4")
expect((result.agents as Record<string, { model: string; variant?: string }>).sisyphus.variant).toBe("medium")
expect((result.agents as Record<string, { model: string }>).oracle.model).toBe("openai/gpt-5.4")
expect((result.agents as Record<string, { model: string }>)['multimodal-looker'].model).toBe("openai/gpt-5.4")
})
test("uses haiku for explore when Claude max20", () => {
//#given
const config: InstallConfig = {
hasClaude: true,
isMax20: true,
hasOpenAI: false,
hasGemini: false,
hasCopilot: false,
hasOpencodeZen: false,
hasZaiCodingPlan: false,
hasKimiForCoding: false,
hasOpencodeGo: false,
}
//#when
const result = generateOmoConfig(config)
//#then
expect((result.agents as Record<string, { model: string }>).explore.model).toBe("anthropic/claude-haiku-4-5")
})
test("uses haiku for explore regardless of max20 flag", () => {
//#given
const config: InstallConfig = {
hasClaude: true,
isMax20: false,
hasOpenAI: false,
hasGemini: false,
hasCopilot: false,
hasOpencodeZen: false,
hasZaiCodingPlan: false,
hasKimiForCoding: false,
hasOpencodeGo: false,
}
//#when
const result = generateOmoConfig(config)
//#then
expect((result.agents as Record<string, { model: string }>).explore.model).toBe("anthropic/claude-haiku-4-5")
})
})

View File

@@ -1,56 +0,0 @@
/// <reference types="bun-types" />
import { afterEach, describe, expect, mock, test } from "bun:test"
import { fetchNpmDistTags } from "../config-manager"
describe("fetchNpmDistTags", () => {
const originalFetch = globalThis.fetch
afterEach(() => {
globalThis.fetch = originalFetch
})
test("returns dist-tags on success", async () => {
//#given
globalThis.fetch = mock(() =>
Promise.resolve({
ok: true,
json: () => Promise.resolve({ latest: "3.13.1", beta: "3.14.0-beta.1" }),
} as Response)
) as unknown as typeof fetch
//#when
const result = await fetchNpmDistTags("oh-my-openagent")
//#then
expect(result).toEqual({ latest: "3.13.1", beta: "3.14.0-beta.1" })
})
test("returns null on network failure", async () => {
//#given
globalThis.fetch = mock(() => Promise.reject(new Error("Network error"))) as unknown as typeof fetch
//#when
const result = await fetchNpmDistTags("oh-my-openagent")
//#then
expect(result).toBeNull()
})
test("returns null on non-ok response", async () => {
//#given
globalThis.fetch = mock(() =>
Promise.resolve({
ok: false,
status: 404,
} as Response)
) as unknown as typeof fetch
//#when
const result = await fetchNpmDistTags("oh-my-openagent")
//#then
expect(result).toBeNull()
})
})

View File

@@ -28,9 +28,10 @@ describe("detectCurrentConfig - single package detection", () => {
delete process.env.OPENCODE_CONFIG_DIR delete process.env.OPENCODE_CONFIG_DIR
}) })
it("detects both legacy and canonical plugin entries", () => { it("detects oh-my-opencode in plugin array", () => {
// given // given
writeFileSync(testConfigPath, JSON.stringify({ plugin: ["oh-my-opencode", "oh-my-openagent@3.11.0"] }, null, 2) + "\n", "utf-8") const config = { plugin: ["oh-my-opencode"] }
writeFileSync(testConfigPath, JSON.stringify(config, null, 2) + "\n", "utf-8")
// when // when
const result = detectCurrentConfig() const result = detectCurrentConfig()
@@ -39,9 +40,22 @@ describe("detectCurrentConfig - single package detection", () => {
expect(result.isInstalled).toBe(true) expect(result.isInstalled).toBe(true)
}) })
it("returns false when plugin not present with similar name", () => { it("detects oh-my-opencode with version pin", () => {
// given // given
writeFileSync(testConfigPath, JSON.stringify({ plugin: ["oh-my-openagent-extra"] }, null, 2) + "\n", "utf-8") const config = { plugin: ["oh-my-opencode@3.11.0"] }
writeFileSync(testConfigPath, JSON.stringify(config, null, 2) + "\n", "utf-8")
// when
const result = detectCurrentConfig()
// then
expect(result.isInstalled).toBe(true)
})
it("returns false when plugin not present", () => {
// given
const config = { plugin: ["some-other-plugin"] }
writeFileSync(testConfigPath, JSON.stringify(config, null, 2) + "\n", "utf-8")
// when // when
const result = detectCurrentConfig() const result = detectCurrentConfig()
@@ -53,7 +67,11 @@ describe("detectCurrentConfig - single package detection", () => {
it("detects OpenCode Go from the existing omo config", () => { it("detects OpenCode Go from the existing omo config", () => {
// given // given
writeFileSync(testConfigPath, JSON.stringify({ plugin: ["oh-my-opencode"] }, null, 2) + "\n", "utf-8") writeFileSync(testConfigPath, JSON.stringify({ plugin: ["oh-my-opencode"] }, null, 2) + "\n", "utf-8")
writeFileSync(testOmoConfigPath, JSON.stringify({ agents: { atlas: { model: "opencode-go/kimi-k2.5" } } }, null, 2) + "\n", "utf-8") writeFileSync(
testOmoConfigPath,
JSON.stringify({ agents: { atlas: { model: "opencode-go/kimi-k2.5" } } }, null, 2) + "\n",
"utf-8",
)
// when // when
const result = detectCurrentConfig() const result = detectCurrentConfig()
@@ -83,9 +101,10 @@ describe("addPluginToOpenCodeConfig - single package writes", () => {
delete process.env.OPENCODE_CONFIG_DIR delete process.env.OPENCODE_CONFIG_DIR
}) })
it("writes canonical plugin entry for new installs", async () => { it("keeps oh-my-opencode when it already exists", async () => {
// given // given
writeFileSync(testConfigPath, JSON.stringify({}, null, 2) + "\n", "utf-8") const config = { plugin: ["oh-my-opencode"] }
writeFileSync(testConfigPath, JSON.stringify(config, null, 2) + "\n", "utf-8")
// when // when
const result = await addPluginToOpenCodeConfig("3.11.0") const result = await addPluginToOpenCodeConfig("3.11.0")
@@ -93,12 +112,13 @@ describe("addPluginToOpenCodeConfig - single package writes", () => {
// then // then
expect(result.success).toBe(true) expect(result.success).toBe(true)
const savedConfig = JSON.parse(readFileSync(testConfigPath, "utf-8")) const savedConfig = JSON.parse(readFileSync(testConfigPath, "utf-8"))
expect(savedConfig.plugin).toEqual(["oh-my-openagent"]) expect(savedConfig.plugin).toContain("oh-my-opencode")
}) })
it("upgrades a bare legacy plugin entry to canonical", async () => { it("replaces version-pinned oh-my-opencode@X.Y.Z", async () => {
// given // given
writeFileSync(testConfigPath, JSON.stringify({ plugin: ["oh-my-opencode"] }, null, 2) + "\n", "utf-8") const config = { plugin: ["oh-my-opencode@3.10.0"] }
writeFileSync(testConfigPath, JSON.stringify(config, null, 2) + "\n", "utf-8")
// when // when
const result = await addPluginToOpenCodeConfig("3.11.0") const result = await addPluginToOpenCodeConfig("3.11.0")
@@ -106,12 +126,14 @@ describe("addPluginToOpenCodeConfig - single package writes", () => {
// then // then
expect(result.success).toBe(true) expect(result.success).toBe(true)
const savedConfig = JSON.parse(readFileSync(testConfigPath, "utf-8")) const savedConfig = JSON.parse(readFileSync(testConfigPath, "utf-8"))
expect(savedConfig.plugin).toEqual(["oh-my-openagent"]) expect(savedConfig.plugin).toContain("oh-my-opencode")
expect(savedConfig.plugin).not.toContain("oh-my-opencode@3.10.0")
}) })
it("upgrades a version-pinned legacy entry to canonical", async () => { it("adds new plugin when none exists", async () => {
// given // given
writeFileSync(testConfigPath, JSON.stringify({ plugin: ["oh-my-opencode@3.10.0"] }, null, 2) + "\n", "utf-8") const config = {}
writeFileSync(testConfigPath, JSON.stringify(config, null, 2) + "\n", "utf-8")
// when // when
const result = await addPluginToOpenCodeConfig("3.11.0") const result = await addPluginToOpenCodeConfig("3.11.0")
@@ -119,12 +141,13 @@ describe("addPluginToOpenCodeConfig - single package writes", () => {
// then // then
expect(result.success).toBe(true) expect(result.success).toBe(true)
const savedConfig = JSON.parse(readFileSync(testConfigPath, "utf-8")) const savedConfig = JSON.parse(readFileSync(testConfigPath, "utf-8"))
expect(savedConfig.plugin).toEqual(["oh-my-openagent@3.10.0"]) expect(savedConfig.plugin).toContain("oh-my-opencode")
}) })
it("removes stale legacy entry when canonical and legacy entries both exist", async () => { it("adds plugin when plugin array is empty", async () => {
// given // given
writeFileSync(testConfigPath, JSON.stringify({ plugin: ["oh-my-openagent", "oh-my-opencode"] }, null, 2) + "\n", "utf-8") const config = { plugin: [] }
writeFileSync(testConfigPath, JSON.stringify(config, null, 2) + "\n", "utf-8")
// when // when
const result = await addPluginToOpenCodeConfig("3.11.0") const result = await addPluginToOpenCodeConfig("3.11.0")
@@ -132,34 +155,6 @@ describe("addPluginToOpenCodeConfig - single package writes", () => {
// then // then
expect(result.success).toBe(true) expect(result.success).toBe(true)
const savedConfig = JSON.parse(readFileSync(testConfigPath, "utf-8")) const savedConfig = JSON.parse(readFileSync(testConfigPath, "utf-8"))
expect(savedConfig.plugin).toEqual(["oh-my-openagent"]) expect(savedConfig.plugin).toContain("oh-my-opencode")
})
it("preserves a canonical entry when it already exists", async () => {
// given
writeFileSync(testConfigPath, JSON.stringify({ plugin: ["oh-my-openagent@3.10.0"] }, null, 2) + "\n", "utf-8")
// when
const result = await addPluginToOpenCodeConfig("3.11.0")
// then
expect(result.success).toBe(true)
const savedConfig = JSON.parse(readFileSync(testConfigPath, "utf-8"))
expect(savedConfig.plugin).toEqual(["oh-my-openagent@3.10.0"])
})
it("rewrites quoted jsonc plugin field in place", async () => {
// given
testConfigPath = join(testConfigDir, "opencode.jsonc")
writeFileSync(testConfigPath, '{\n "plugin": ["oh-my-opencode"]\n}\n', "utf-8")
// when
const result = await addPluginToOpenCodeConfig("3.11.0")
// then
expect(result.success).toBe(true)
const savedContent = readFileSync(testConfigPath, "utf-8")
expect(savedContent.includes('"plugin": [\n "oh-my-openagent"\n ]')).toBe(true)
expect(savedContent.includes("oh-my-opencode")).toBe(false)
}) })
}) })

View File

@@ -1,56 +0,0 @@
/// <reference types="bun-types" />
import { afterEach, describe, expect, mock, test } from "bun:test"
import { getPluginNameWithVersion } from "../config-manager"
describe("getPluginNameWithVersion", () => {
const originalFetch = globalThis.fetch
afterEach(() => {
globalThis.fetch = originalFetch
})
test("returns the canonical latest tag when current version matches latest", async () => {
//#given
globalThis.fetch = mock(() =>
Promise.resolve({
ok: true,
json: () => Promise.resolve({ latest: "3.13.1", beta: "3.14.0-beta.1" }),
} as Response)
) as unknown as typeof fetch
//#when
const result = await getPluginNameWithVersion("3.13.1")
//#then
expect(result).toBe("oh-my-openagent@latest")
})
test("preserves the canonical prerelease channel when fetch fails", async () => {
//#given
globalThis.fetch = mock(() => Promise.reject(new Error("Network error"))) as unknown as typeof fetch
//#when
const result = await getPluginNameWithVersion("3.14.0-beta.1")
//#then
expect(result).toBe("oh-my-openagent@beta")
})
test("returns the canonical bare package name for stable fallback", async () => {
//#given
globalThis.fetch = mock(() =>
Promise.resolve({
ok: false,
status: 404,
} as Response)
) as unknown as typeof fetch
//#when
const result = await getPluginNameWithVersion("3.13.1")
//#then
expect(result).toBe("oh-my-openagent")
})
})

Some files were not shown because too many files have changed in this diff Show More