Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 52 additions & 11 deletions .codex/config.toml
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
model = "gpt-5.2-codex"
sandbox_mode = "workspace-write"
model = "gpt-5.5"
model_reasoning_effort = "xhigh"
web_search = "live"
[sandbox_workspace_write]
network_access = true
[features]
rmcp_client = true
web_search_request = true

[mcp_servers.aws-docs]
command = "uvx"
Expand All @@ -25,27 +26,67 @@ args = ["-y", "next-devtools-mcp@latest"]
command = "npx"
args = ["@playwright/mcp@latest"]

[mcp_servers.o3]
command = "npx"
args = ["o3-search-mcp"]

[mcp_servers.o3.env]
OPENAI_API_KEY = "${OPENAI_API_KEY}"
REASONING_EFFORT = "medium"
SEARCH_CONTEXT_SIZE = "medium"

[mcp_servers.supabase]
url = "https://mcp.supabase.com/mcp"

[mcp_servers.supabase.http_headers]
Authorization = "Bearer ${SUPABASE_MCP_TOKEN}"
bearer_token_env_var = "SUPABASE_ACCESS_TOKEN"

[mcp_servers.vercel]
url = "https://mcp.vercel.com"
bearer_token_env_var = "VERCEL_TOKEN"

[mcp_servers.vercel.http_headers]
Authorization = "Bearer ${VERCEL_MCP_TOKEN}"
[mcp_servers.context7]
command = "npx"
args = ["-y", "@upstash/context7-mcp"]

[mcp_servers.linear]
url = "https://mcp.linear.app/mcp"

[mcp_servers.github]
url = "https://api.githubcopilot.com/mcp/"
[mcp_servers.doppler]
command = "npx"
args = ["-y", "@dopplerhq/mcp-server", "--read-only"]

[mcp_servers.github.http_headers]
Authorization = "Bearer ${GITHUB_COPILOT_MCP_TOKEN}"
[mcp_servers.doppler.env]
npm_config_cache = "/private/tmp/codex-npm-cache"

Comment on lines +53 to 59

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

macOS-specific path will fail in DevContainer/Linux environments.

/private/tmp/ is a macOS-specific path (where /tmp is a symlink to /private/tmp). On Linux systems, including the DevContainer which runs Ubuntu, this path doesn't exist and will cause the doppler MCP server to fail or behave unexpectedly.

Proposed fix
 [mcp_servers.doppler.env]
-npm_config_cache = "/private/tmp/codex-npm-cache"
+npm_config_cache = "/tmp/codex-npm-cache"
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
[mcp_servers.doppler]
command = "npx"
args = ["-y", "@dopplerhq/mcp-server", "--read-only"]
[mcp_servers.github.http_headers]
Authorization = "Bearer ${GITHUB_COPILOT_MCP_TOKEN}"
[mcp_servers.doppler.env]
npm_config_cache = "/private/tmp/codex-npm-cache"
[mcp_servers.doppler]
command = "npx"
args = ["-y", "`@dopplerhq/mcp-server`", "--read-only"]
[mcp_servers.doppler.env]
npm_config_cache = "/tmp/codex-npm-cache"
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.codex/config.toml around lines 53 - 59, The Docker/DevContainer config sets
npm_config_cache to a macOS-specific path "/private/tmp/codex-npm-cache" under
the [mcp_servers.doppler.env] block which will break on Linux; update the
npm_config_cache value to a cross-platform temp location (e.g., use
"/tmp/codex-npm-cache" or resolve from TMPDIR/TEMP environment variables) so the
doppler MCP server launched by the "command"/"args" (npx `@dopplerhq/mcp-server`)
works in DevContainer/Linux environments; change only the npm_config_cache env
value to use a portable path or an environment-derived fallback.

[notice]
hide_gpt5_1_migration_prompt = true
"hide_gpt-5.1-codex-max_migration_prompt" = true

[notice.model_migrations]
"gpt-5.1-codex-max" = "gpt-5.2-codex"

[plugins."google-calendar@openai-curated"]
enabled = true

[plugins."gmail@openai-curated"]
enabled = true

[plugins."vercel@openai-curated"]
enabled = true

[plugins."github@openai-curated"]
enabled = true

[plugins."google-drive@openai-curated"]
enabled = true

[plugins."browser@openai-bundled"]
enabled = true

[plugins."documents@openai-primary-runtime"]
enabled = true

[plugins."spreadsheets@openai-primary-runtime"]
enabled = true

[plugins."presentations@openai-primary-runtime"]
enabled = true
3 changes: 2 additions & 1 deletion .devcontainer/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
FROM mcr.microsoft.com/devcontainers/base:2.0-ubuntu-24.04

# Build arguments
ARG CLAUDE_CODE_OAUTH_TOKEN

Check warning on line 4 in .devcontainer/Dockerfile

View workflow job for this annotation

GitHub Actions / Generate SBOM

Sensitive data should not be used in the ARG or ENV commands

SecretsUsedInArgOrEnv: Do not use ARG or ENV instructions for sensitive data (ARG "CLAUDE_CODE_OAUTH_TOKEN") More info: https://docs.docker.com/go/dockerfile/rule/secrets-used-in-arg-or-env/

Check warning on line 4 in .devcontainer/Dockerfile

View workflow job for this annotation

GitHub Actions / Trivy Container Scan

Sensitive data should not be used in the ARG or ENV commands

SecretsUsedInArgOrEnv: Do not use ARG or ENV instructions for sensitive data (ARG "CLAUDE_CODE_OAUTH_TOKEN") More info: https://docs.docker.com/go/dockerfile/rule/secrets-used-in-arg-or-env/
ARG ANTHROPIC_API_KEY

Check warning on line 5 in .devcontainer/Dockerfile

View workflow job for this annotation

GitHub Actions / Generate SBOM

Sensitive data should not be used in the ARG or ENV commands

SecretsUsedInArgOrEnv: Do not use ARG or ENV instructions for sensitive data (ARG "ANTHROPIC_API_KEY") More info: https://docs.docker.com/go/dockerfile/rule/secrets-used-in-arg-or-env/

Check warning on line 5 in .devcontainer/Dockerfile

View workflow job for this annotation

GitHub Actions / Trivy Container Scan

Sensitive data should not be used in the ARG or ENV commands

SecretsUsedInArgOrEnv: Do not use ARG or ENV instructions for sensitive data (ARG "ANTHROPIC_API_KEY") More info: https://docs.docker.com/go/dockerfile/rule/secrets-used-in-arg-or-env/
ARG IMAGE_VERSION="dev"

# OCI Image Labels for version tracking
Expand Down Expand Up @@ -169,7 +169,8 @@
RUN chmod +x /usr/local/bin/setup-claude.sh /tmp/setup-claude-build.sh /tmp/install-skills.sh /usr/local/script/*.sh

# Install skills from skills.txt using npx skills add
# Skills are installed to ~/.agents/skills/ with symlinks in ~/.claude/skills/
# Skills are installed to ~/.agents/skills/ for all agents (Claude Code, Codex, Cursor, Gemini CLI)
# Custom skills from .claude/skills/*.md are also synced to ~/.agents/skills/
USER vscode
RUN env HOME=/home/vscode /tmp/install-skills.sh /home/vscode/.claude/skills/skills.txt || ( \
echo "[WARN] スキルのインストールに失敗しました" && \
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ report.log
.claude/skills/vercel-*
.claude/skills/web-design-*
.codex/skills/
.codex/prompts/
.cursor/skills/
.github/skills/

Expand Down
190 changes: 179 additions & 11 deletions script/install-skills.sh
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
#!/usr/bin/env bash
# ============================================================================
# Claude Code Skills Installer
# skills.txt からスキルをインストールするスクリプト
# Agent Skills Installer
# skills.txt からスキルを全エージェント向けにインストールするスクリプト
# 対象: Claude Code, Codex, Cursor, Gemini CLI
# ============================================================================

set -euo pipefail
Expand All @@ -18,8 +19,9 @@ else
fi

AGENTS_DIR="${HOME}/.agents/skills"
PROJECT_AGENTS_DIR="${PWD}/.agents/skills"

echo "[INFO] Claude スキルのインストールを開始します..."
echo "[INFO] エージェントスキルのインストールを開始します..."

# スキルリストが存在するか確認
if [[ -z "$SKILLS_FILE" ]] || [[ ! -f "$SKILLS_FILE" ]]; then
Expand All @@ -38,6 +40,12 @@ fi
# スキルディレクトリを作成
mkdir -p "$AGENTS_DIR"

# スキルの存在チェック(グローバルとプロジェクトの両方を確認)
skill_exists() {
local name="$1"
[[ -d "${AGENTS_DIR}/${name}" ]] || [[ -d "${PROJECT_AGENTS_DIR}/${name}" ]]
}

installed=0
failed=0
skipped=0
Expand All @@ -52,7 +60,7 @@ while IFS= read -r line || [[ -n "$line" ]]; do

echo "[INFO] チェック中: ${skill}"

# スキルがすでにインストールされているか npx skills list -g で確認
# スキルがすでにインストールされているか確認
# 既知のリポジトリとスキル名のマッピング
case "$skill" in
"vercel-labs/agent-skills")
Expand All @@ -65,21 +73,26 @@ while IFS= read -r line || [[ -n "$line" ]]; do
check_skills=("find-skills")
;;
"vercel-labs/agent-browser")
check_skills=("agent-browser" "skill-creator")
check_skills=("agent-browser")
;;
"intellectronica/agent-skills")
check_skills=("context7")
;;
*)
# 不明なリポジトリは basename を使用
check_skills=("$(basename "$skill")")
# @tag 付きエントリ: owner/repo@skill-name → skill-name
# @tag なしエントリ: owner/repo → basename (repo)
if [[ "$skill" == */*@* ]]; then
check_skills=("${skill##*@}")
else
check_skills=("$(basename "$skill")")
fi
;;
esac

# いずれかのスキルがインストールされているかチェック
all_installed=true
for check_skill in "${check_skills[@]}"; do
if [[ ! -d "${AGENTS_DIR}/${check_skill}" ]]; then
if ! skill_exists "$check_skill"; then
all_installed=false
break
fi
Expand All @@ -93,8 +106,8 @@ while IFS= read -r line || [[ -n "$line" ]]; do

echo "[INFO] インストール中: ${skill}"

# npx skills add でインストール(-y で自動確認、-g でグローバル)
if output=$(npx skills add "$skill" -y -g 2>&1); then
# npx skills add でインストール(-y で自動確認、-g でグローバル、-a '*' で全エージェント対応)
if output=$(npx skills add "$skill" -y -g -a '*' 2>&1); then
echo "[SUCCESS] 完了: ${skill}"
installed=$((installed + 1))
else
Expand All @@ -111,4 +124,159 @@ while IFS= read -r line || [[ -n "$line" ]]; do
done < "$SKILLS_FILE"

echo "[INFO] スキル: ${installed} インストール完了、${skipped} スキップ、${failed} 失敗"
echo "[SUCCESS] Claude スキルのインストールが完了しました"

# Claude Code のローカルファイルを SKILL.md 形式に変換して .agents/skills/ に同期する関数
# 引数: $1=ソースディレクトリ, $2=ラベル(ログ表示用)
sync_claude_to_agents() {
local src_dir="$1"
local label="$2"
local synced=0

[[ -d "$src_dir" ]] || return 0

for src_file in "$src_dir"/*.md; do
[[ -f "$src_file" ]] || continue
local name
name="$(basename "$src_file" .md)"
# README.md はスキップ
[[ "$name" == "README" ]] && continue

local target_dir="${PROJECT_AGENTS_DIR}/${name}"
local target_file="${target_dir}/SKILL.md"

# frontmatter の有無を判定
local has_frontmatter
has_frontmatter=$(head -1 "$src_file" | grep -c '^---$' || true)

local description body
if [[ "$has_frontmatter" -gt 0 ]]; then
# frontmatter から description を抽出
description=$(awk '/^---$/{n++; next} n==1 && /^description:/{sub(/^description: */, ""); print; exit}' "$src_file")
# frontmatter の後の本文を取得(2つ目の --- 以降)
body=$(awk 'BEGIN{n=0} /^---$/{n++; next} n>=2{print}' "$src_file")
# description が空なら本文の最初の見出しをフォールバック
if [[ -z "$description" ]]; then
description=$(echo "$body" | awk '/^#+ /{sub(/^#+ */, ""); print; exit}')
fi
else
# frontmatter なし: 最初の # 見出しを description として使用
description=$(awk '/^#+ /{sub(/^#+ */, ""); print; exit}' "$src_file")
body=$(cat "$src_file")
fi

# description が空の場合はスキル名をフォールバック
[[ -z "$description" ]] && description="$name"

mkdir -p "$target_dir"
printf '%s\n' "---" \
"name: ${name}" \
"description: ${description}" \
"metadata:" \
" author: keito4" \
" version: \"1.0.0\"" \
"---" > "$target_file"
printf '%s\n' "$body" >> "$target_file"
Comment on lines +171 to +178

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

YAML description field should be quoted to handle special characters.

If the extracted description contains YAML special characters (:, #, ", etc.), the generated SKILL.md will have malformed frontmatter. For example, a heading like "Fix: improve performance" would produce description: Fix: improve performance, which is ambiguous YAML.

Proposed fix
         mkdir -p "$target_dir"
+        # Escape double quotes and wrap in quotes for YAML safety
+        local safe_description="${description//\"/\\\"}"
         printf '%s\n' "---" \
             "name: ${name}" \
-            "description: ${description}" \
+            "description: \"${safe_description}\"" \
             "metadata:" \
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@script/install-skills.sh` around lines 171 - 178, The frontmatter writes
description unquoted which breaks YAML when description contains special
characters; update the printf that emits "description: ${description}" so the
description value is safely quoted/escaped (e.g., wrap the value in double
quotes and escape any inner quotes) before writing to "$target_file" — adjust
the printf invocation that uses variables name, description, target_file (and
keep the subsequent printf "$body" append) to emit a properly quoted/escaped
description string.


echo "[INFO] ${label}同期: ${name} → ${target_dir}"
synced=$((synced + 1))
done
echo "[INFO] ${label}: ${synced} 件同期完了"
}

# カスタムスキル(.claude/skills/*.md)を同期
CLAUDE_SKILLS_DIR=""
if [[ -n "$SKILLS_FILE" ]]; then
CLAUDE_SKILLS_DIR="$(dirname "$SKILLS_FILE")"
elif [[ -d "${PWD}/.claude/skills" ]]; then
CLAUDE_SKILLS_DIR="${PWD}/.claude/skills"
fi
sync_claude_to_agents "${CLAUDE_SKILLS_DIR:-}" "カスタムスキル"

# コマンド(.claude/commands/*.md)をスキルとして同期
CLAUDE_COMMANDS_DIR=""
if [[ -n "$CLAUDE_SKILLS_DIR" ]]; then
CLAUDE_COMMANDS_DIR="$(dirname "$CLAUDE_SKILLS_DIR")/commands"
elif [[ -d "${PWD}/.claude/commands" ]]; then
CLAUDE_COMMANDS_DIR="${PWD}/.claude/commands"
fi
sync_claude_to_agents "${CLAUDE_COMMANDS_DIR:-}" "コマンド"

# ルール(.claude/rules/*.md)をスキルとして同期
CLAUDE_RULES_DIR=""
if [[ -n "$CLAUDE_SKILLS_DIR" ]]; then
CLAUDE_RULES_DIR="$(dirname "$CLAUDE_SKILLS_DIR")/rules"
elif [[ -d "${PWD}/.claude/rules" ]]; then
CLAUDE_RULES_DIR="${PWD}/.claude/rules"
fi
sync_claude_to_agents "${CLAUDE_RULES_DIR:-}" "ルール"

# コマンドを Codex prompts(/command で呼び出し可能)にシンボリックリンク
# .codex/prompts/<name>.md → .claude/commands/<name>.md
CODEX_PROMPTS_DIR="${PWD}/.codex/prompts"
if [[ -n "${CLAUDE_COMMANDS_DIR:-}" && -d "$CLAUDE_COMMANDS_DIR" ]]; then
mkdir -p "$CODEX_PROMPTS_DIR"
prompts_synced=0
for cmd_file in "$CLAUDE_COMMANDS_DIR"/*.md; do
[[ -f "$cmd_file" ]] || continue
cmd_name="$(basename "$cmd_file")"
[[ "$cmd_name" == "README.md" ]] && continue
link_path="${CODEX_PROMPTS_DIR}/${cmd_name}"
[[ -e "$link_path" || -L "$link_path" ]] && continue
ln -s "../../.claude/commands/${cmd_name}" "$link_path"
prompts_synced=$((prompts_synced + 1))
done
echo "[INFO] Codex prompts: ${prompts_synced} 件リンク作成"
fi

# .agents/skills/ のスキルを各エージェントのスキルディレクトリにシンボリックリンク
# Codex (.codex/skills/), Cursor (.cursor/skills/), Gemini (.gemini/skills/) 等
# 対象: プロジェクトレベル (.agents/skills/) の全スキル + カスタムスキル
# グローバル (~/.agents/skills/) は skills.txt 外のスキルを含むため全量リンクしない
AGENT_SKILL_DIRS=(".codex/skills" ".cursor/skills" ".gemini/skills")
linked=0

# リンク対象スキル名を収集(プロジェクトレベル + カスタムスキル、重複排除)
declare -A all_skills
# プロジェクトレベルのスキル(npx skills add で project に入ったもの)
if [[ -d "$PROJECT_AGENTS_DIR" ]]; then
for skill_dir in "${PROJECT_AGENTS_DIR}"/*/; do
[[ -d "$skill_dir" ]] || continue
all_skills["$(basename "$skill_dir")"]=1
done
fi
# カスタムスキル + コマンド + ルール(プロジェクトに同期済み)
for src_dir in "${CLAUDE_SKILLS_DIR:-}" "${CLAUDE_COMMANDS_DIR:-}" "${CLAUDE_RULES_DIR:-}"; do
[[ -n "$src_dir" && -d "$src_dir" ]] || continue
for skill_file in "$src_dir"/*.md; do
[[ -f "$skill_file" ]] || continue
skill_name="$(basename "$skill_file" .md)"
[[ "$skill_name" == "README" ]] && continue
all_skills["$skill_name"]=1
done
done

for agent_dir in "${AGENT_SKILL_DIRS[@]}"; do
target_base="${PWD}/${agent_dir}"
mkdir -p "$target_base"
for skill_name in "${!all_skills[@]}"; do
link_path="${target_base}/${skill_name}"
# 既にリンクまたはディレクトリが存在する場合はスキップ(-L で壊れたリンクも検出)
if [[ -e "$link_path" || -L "$link_path" ]]; then
continue
fi
# プロジェクトレベルを優先、なければグローバルへリンク
# 相対パスはエージェントディレクトリが2階層深い前提(.codex/skills/, .cursor/skills/ 等)
if [[ -d "${PROJECT_AGENTS_DIR}/${skill_name}" ]]; then
ln -s "../../.agents/skills/${skill_name}" "$link_path"
elif [[ -d "${AGENTS_DIR}/${skill_name}" ]]; then
ln -s "${AGENTS_DIR}/${skill_name}" "$link_path"
else
continue
fi
echo "[INFO] リンク作成: ${agent_dir}/${skill_name}"
linked=$((linked + 1))
done
done
echo "[INFO] シンボリックリンク: ${linked} 件作成"

echo "[SUCCESS] エージェントスキルのインストールが完了しました"
Loading