From df3cc3e890dab2ef98de403beed3f1c8a5c45e36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EA=B2=BD=EC=A2=85?= Date: Wed, 10 Jun 2026 17:12:23 +0900 Subject: [PATCH] modify template --- .../{Codex => Codex-cpp}/.codex/config.toml | 3 +- Coding/{Codex => Codex-cpp}/.codex/hooks.json | 0 .../.codex/hooks/pre_commit_checks.py | 89 + Coding/Codex-cpp/.codex/hooks/tdd-guard.py | 205 ++ .../.codex/skills/harness-review/SKILL.md | 44 + .../skills/harness-review/agents/openai.yaml | 0 .../.codex/skills/harness-workflow/SKILL.md | 129 + .../harness-workflow/agents/openai.yaml | 0 Coding/Codex-cpp/.gitignore | 23 + Coding/Codex-cpp/AGENTS.md | 44 + Coding/Codex-cpp/docs/ADR.md | 34 + Coding/Codex-cpp/docs/ARCHITECTURE.md | 58 + Coding/Codex-cpp/docs/PRD.md | 22 + Coding/{Codex => Codex-cpp}/docs/UI_GUIDE.md | 0 .../{Codex => Codex-cpp}/scripts/execute.py | 0 .../scripts/test_pre_commit_checks.py | 41 + Coding/Codex-cpp/scripts/test_tdd_guard.py | 61 + .../scripts/test_validate_workspace.py | 94 + .../Codex-cpp/scripts/validate_workspace.py | 151 + Coding/Codex-tsjs/.codex/config.toml | 4 + Coding/Codex-tsjs/.codex/hooks.json | 28 + .../.codex/hooks/pre_commit_checks.py | 0 .../.codex/hooks/tdd-guard.py | 0 .../.codex}/skills/harness-review/SKILL.md | 0 .../skills/harness-review/agents/openai.yaml | 4 + .../.codex}/skills/harness-workflow/SKILL.md | 0 .../harness-workflow/agents/openai.yaml | 4 + Coding/{Codex => Codex-tsjs}/.gitignore | 0 Coding/{Codex => Codex-tsjs}/AGENTS.md | 0 Coding/{Codex => Codex-tsjs}/docs/ADR.md | 0 .../docs/ARCHITECTURE.md | 0 Coding/{Codex => Codex-tsjs}/docs/PRD.md | 0 Coding/Codex-tsjs/docs/UI_GUIDE.md | 76 + Coding/Codex-tsjs/scripts/execute.py | 417 +++ .../Codex/.system/.codex-system-skills.marker | 1 + Skills/Codex/.system/imagegen/LICENSE.txt | 201 ++ Skills/Codex/.system/imagegen/SKILL.md | 356 ++ .../Codex/.system/imagegen/agents/openai.yaml | 6 + .../imagegen/assets/imagegen-small.svg | 5 + .../.system/imagegen/assets/imagegen.png | Bin 0 -> 1711 bytes .../Codex/.system/imagegen/references/cli.md | 242 ++ .../imagegen/references/codex-network.md | 33 + .../.system/imagegen/references/image-api.md | 90 + .../.system/imagegen/references/prompting.md | 118 + .../imagegen/references/sample-prompts.md | 433 +++ .../.system/imagegen/scripts/image_gen.py | 995 +++++ .../imagegen/scripts/remove_chroma_key.py | 440 +++ Skills/Codex/.system/openai-docs/LICENSE.txt | 201 ++ Skills/Codex/.system/openai-docs/SKILL.md | 167 + .../.system/openai-docs/agents/openai.yaml | 14 + .../openai-docs/assets/openai-small.svg | 3 + .../.system/openai-docs/assets/openai.png | Bin 0 -> 1429 bytes .../openai-docs/references/latest-model.md | 37 + .../openai-docs/references/prompting-guide.md | 244 ++ .../openai-docs/references/upgrade-guide.md | 181 + .../scripts/fetch-codex-manual.mjs | 598 +++ .../scripts/resolve-latest-model-info.js | 147 + Skills/Codex/.system/plugin-creator/SKILL.md | 243 ++ .../.system/plugin-creator/agents/openai.yaml | 6 + .../assets/plugin-creator-small.svg | 3 + .../plugin-creator/assets/plugin-creator.png | Bin 0 -> 1563 bytes .../references/installing-and-updating.md | 143 + .../references/plugin-json-spec.md | 194 + .../scripts/create_basic_plugin.py | 324 ++ .../scripts/read_marketplace_name.py | 48 + .../scripts/update_plugin_cachebuster.py | 78 + .../plugin-creator/scripts/validate_plugin.py | 586 +++ Skills/Codex/.system/skill-creator/SKILL.md | 416 +++ .../.system/skill-creator/agents/openai.yaml | 5 + .../assets/skill-creator-small.svg | 3 + .../skill-creator/assets/skill-creator.png | Bin 0 -> 1563 bytes .../Codex/.system/skill-creator/license.txt | 202 ++ .../skill-creator/references/openai_yaml.md | 49 + .../generate_openai_yaml.cpython-312.pyc | Bin 0 -> 8735 bytes .../scripts/generate_openai_yaml.py | 226 ++ .../skill-creator/scripts/init_skill.py | 400 +++ .../skill-creator/scripts/quick_validate.py | 101 + .../Codex/.system/skill-installer/LICENSE.txt | 202 ++ Skills/Codex/.system/skill-installer/SKILL.md | 58 + .../skill-installer/agents/openai.yaml | 5 + .../assets/skill-installer-small.svg | 3 + .../assets/skill-installer.png | Bin 0 -> 1086 bytes .../skill-installer/scripts/github_utils.py | 21 + .../scripts/install-skill-from-github.py | 308 ++ .../skill-installer/scripts/list-skills.py | 107 + Skills/Codex/spreadsheet/LICENSE.txt | 201 ++ Skills/Codex/spreadsheet/SKILL.md | 145 + Skills/Codex/spreadsheet/agents/openai.yaml | 6 + .../spreadsheet/assets/spreadsheet-small.svg | 3 + .../Codex/spreadsheet/assets/spreadsheet.png | Bin 0 -> 3077 bytes .../openpyxl/create_basic_spreadsheet.py | 51 + .../create_spreadsheet_with_styling.py | 96 + .../openpyxl/read_existing_spreadsheet.py | 59 + .../examples/openpyxl/styling_spreadsheet.py | 79 + .../1.0.0/.codex-plugin/plugin.json | 44 + .../claude-md-management/1.0.0/LICENSE | 202 ++ .../claude-md-management/1.0.0/README.md | 31 + .../assets/claude-md-improver-example.png | Bin 0 -> 518778 bytes .../1.0.0/assets/revise-claude-md-example.png | Bin 0 -> 555521 bytes .../1.0.0/skills/claude-md-improver/SKILL.md | 151 + .../references/quality-criteria.md | 109 + .../references/templates.md | 253 ++ .../references/update-guidelines.md | 150 + .../1.0.0/skills/revise-claude-md/SKILL.md | 72 + .../.codex-plugin/api-multi-tab.md | 434 +++ .../control-in-app-browser-multi-tab.md | 98 + .../26.608.12217/.codex-plugin/plugin.json | 43 + .../browser/26.608.12217/assets/browser.png | Bin 0 -> 9692 bytes .../26.608.12217/assets/composer-icon.png | Bin 0 -> 624 bytes .../26.608.12217/docs/api-troubleshooting.md | 8 + .../browser/26.608.12217/docs/api.md | 432 +++ .../docs/capabilities/browser/viewport.md | 16 + .../docs/capabilities/browser/visibility.md | 11 + .../docs/capabilities/tab/pageAssets.md | 11 + .../26.608.12217/docs/confirmations.md | 89 + .../browser/26.608.12217/docs/playwright.md | 128 + .../browser/26.608.12217/docs/screenshots.md | 7 + .../26.608.12217/scripts/browser-client.mjs | 3200 +++++++++++++++++ .../skills/control-in-app-browser/SKILL.md | 83 + .../control-in-app-browser/agents/openai.yaml | 4 + .../c6ea566d/.codex-plugin/plugin.json | 47 + .../superpowers/c6ea566d/CODE_OF_CONDUCT.md | 128 + .../superpowers/c6ea566d/LICENSE | 21 + .../superpowers/c6ea566d/README.md | 233 ++ .../superpowers/c6ea566d/assets/app-icon.png | Bin 0 -> 49841 bytes .../c6ea566d/assets/superpowers-small.svg | 1 + .../c6ea566d/skills/brainstorming/SKILL.md | 164 + .../skills/brainstorming/agents/openai.yaml | 3 + .../brainstorming/scripts/frame-template.html | 214 ++ .../skills/brainstorming/scripts/helper.js | 88 + .../skills/brainstorming/scripts/server.cjs | 354 ++ .../brainstorming/scripts/start-server.sh | 148 + .../brainstorming/scripts/stop-server.sh | 56 + .../spec-document-reviewer-prompt.md | 49 + .../skills/brainstorming/visual-companion.md | 287 ++ .../dispatching-parallel-agents/SKILL.md | 182 + .../agents/openai.yaml | 3 + .../c6ea566d/skills/executing-plans/SKILL.md | 70 + .../skills/executing-plans/agents/openai.yaml | 3 + .../finishing-a-development-branch/SKILL.md | 251 ++ .../agents/openai.yaml | 3 + .../skills/receiving-code-review/SKILL.md | 213 ++ .../receiving-code-review/agents/openai.yaml | 3 + .../skills/requesting-code-review/SKILL.md | 103 + .../requesting-code-review/agents/openai.yaml | 3 + .../requesting-code-review/code-reviewer.md | 168 + .../subagent-driven-development/SKILL.md | 279 ++ .../agents/openai.yaml | 3 + .../code-quality-reviewer-prompt.md | 25 + .../implementer-prompt.md | 113 + .../spec-reviewer-prompt.md | 61 + .../systematic-debugging/CREATION-LOG.md | 119 + .../skills/systematic-debugging/SKILL.md | 296 ++ .../systematic-debugging/agents/openai.yaml | 3 + .../condition-based-waiting-example.ts | 158 + .../condition-based-waiting.md | 115 + .../systematic-debugging/defense-in-depth.md | 122 + .../systematic-debugging/find-polluter.sh | 63 + .../root-cause-tracing.md | 169 + .../systematic-debugging/test-academic.md | 14 + .../systematic-debugging/test-pressure-1.md | 58 + .../systematic-debugging/test-pressure-2.md | 68 + .../systematic-debugging/test-pressure-3.md | 69 + .../skills/test-driven-development/SKILL.md | 371 ++ .../agents/openai.yaml | 3 + .../testing-anti-patterns.md | 299 ++ .../skills/using-git-worktrees/SKILL.md | 215 ++ .../using-git-worktrees/agents/openai.yaml | 3 + .../skills/using-superpowers/SKILL.md | 117 + .../using-superpowers/agents/openai.yaml | 3 + .../references/codex-tools.md | 59 + .../references/copilot-tools.md | 42 + .../references/gemini-tools.md | 51 + .../verification-before-completion/SKILL.md | 139 + .../agents/openai.yaml | 3 + .../c6ea566d/skills/writing-plans/SKILL.md | 152 + .../skills/writing-plans/agents/openai.yaml | 3 + .../plan-document-reviewer-prompt.md | 49 + .../c6ea566d/skills/writing-skills/SKILL.md | 655 ++++ .../skills/writing-skills/agents/openai.yaml | 3 + .../anthropic-best-practices.md | 1150 ++++++ .../examples/CLAUDE_MD_TESTING.md | 189 + .../writing-skills/graphviz-conventions.dot | 172 + .../writing-skills/persuasion-principles.md | 187 + .../skills/writing-skills/render-graphs.js | 168 + .../testing-skills-with-subagents.md | 384 ++ 186 files changed, 24935 insertions(+), 2 deletions(-) rename Coding/{Codex => Codex-cpp}/.codex/config.toml (80%) rename Coding/{Codex => Codex-cpp}/.codex/hooks.json (100%) create mode 100644 Coding/Codex-cpp/.codex/hooks/pre_commit_checks.py create mode 100644 Coding/Codex-cpp/.codex/hooks/tdd-guard.py create mode 100644 Coding/Codex-cpp/.codex/skills/harness-review/SKILL.md rename Coding/{Codex/.agents => Codex-cpp/.codex}/skills/harness-review/agents/openai.yaml (100%) create mode 100644 Coding/Codex-cpp/.codex/skills/harness-workflow/SKILL.md rename Coding/{Codex/.agents => Codex-cpp/.codex}/skills/harness-workflow/agents/openai.yaml (100%) create mode 100644 Coding/Codex-cpp/.gitignore create mode 100644 Coding/Codex-cpp/AGENTS.md create mode 100644 Coding/Codex-cpp/docs/ADR.md create mode 100644 Coding/Codex-cpp/docs/ARCHITECTURE.md create mode 100644 Coding/Codex-cpp/docs/PRD.md rename Coding/{Codex => Codex-cpp}/docs/UI_GUIDE.md (100%) rename Coding/{Codex => Codex-cpp}/scripts/execute.py (100%) create mode 100644 Coding/Codex-cpp/scripts/test_pre_commit_checks.py create mode 100644 Coding/Codex-cpp/scripts/test_tdd_guard.py create mode 100644 Coding/Codex-cpp/scripts/test_validate_workspace.py create mode 100644 Coding/Codex-cpp/scripts/validate_workspace.py create mode 100644 Coding/Codex-tsjs/.codex/config.toml create mode 100644 Coding/Codex-tsjs/.codex/hooks.json rename Coding/{Codex => Codex-tsjs}/.codex/hooks/pre_commit_checks.py (100%) rename Coding/{Codex => Codex-tsjs}/.codex/hooks/tdd-guard.py (100%) rename Coding/{Codex/.agents => Codex-tsjs/.codex}/skills/harness-review/SKILL.md (100%) create mode 100644 Coding/Codex-tsjs/.codex/skills/harness-review/agents/openai.yaml rename Coding/{Codex/.agents => Codex-tsjs/.codex}/skills/harness-workflow/SKILL.md (100%) create mode 100644 Coding/Codex-tsjs/.codex/skills/harness-workflow/agents/openai.yaml rename Coding/{Codex => Codex-tsjs}/.gitignore (100%) rename Coding/{Codex => Codex-tsjs}/AGENTS.md (100%) rename Coding/{Codex => Codex-tsjs}/docs/ADR.md (100%) rename Coding/{Codex => Codex-tsjs}/docs/ARCHITECTURE.md (100%) rename Coding/{Codex => Codex-tsjs}/docs/PRD.md (100%) create mode 100644 Coding/Codex-tsjs/docs/UI_GUIDE.md create mode 100644 Coding/Codex-tsjs/scripts/execute.py create mode 100644 Skills/Codex/.system/.codex-system-skills.marker create mode 100644 Skills/Codex/.system/imagegen/LICENSE.txt create mode 100644 Skills/Codex/.system/imagegen/SKILL.md create mode 100644 Skills/Codex/.system/imagegen/agents/openai.yaml create mode 100644 Skills/Codex/.system/imagegen/assets/imagegen-small.svg create mode 100644 Skills/Codex/.system/imagegen/assets/imagegen.png create mode 100644 Skills/Codex/.system/imagegen/references/cli.md create mode 100644 Skills/Codex/.system/imagegen/references/codex-network.md create mode 100644 Skills/Codex/.system/imagegen/references/image-api.md create mode 100644 Skills/Codex/.system/imagegen/references/prompting.md create mode 100644 Skills/Codex/.system/imagegen/references/sample-prompts.md create mode 100644 Skills/Codex/.system/imagegen/scripts/image_gen.py create mode 100644 Skills/Codex/.system/imagegen/scripts/remove_chroma_key.py create mode 100644 Skills/Codex/.system/openai-docs/LICENSE.txt create mode 100644 Skills/Codex/.system/openai-docs/SKILL.md create mode 100644 Skills/Codex/.system/openai-docs/agents/openai.yaml create mode 100644 Skills/Codex/.system/openai-docs/assets/openai-small.svg create mode 100644 Skills/Codex/.system/openai-docs/assets/openai.png create mode 100644 Skills/Codex/.system/openai-docs/references/latest-model.md create mode 100644 Skills/Codex/.system/openai-docs/references/prompting-guide.md create mode 100644 Skills/Codex/.system/openai-docs/references/upgrade-guide.md create mode 100644 Skills/Codex/.system/openai-docs/scripts/fetch-codex-manual.mjs create mode 100644 Skills/Codex/.system/openai-docs/scripts/resolve-latest-model-info.js create mode 100644 Skills/Codex/.system/plugin-creator/SKILL.md create mode 100644 Skills/Codex/.system/plugin-creator/agents/openai.yaml create mode 100644 Skills/Codex/.system/plugin-creator/assets/plugin-creator-small.svg create mode 100644 Skills/Codex/.system/plugin-creator/assets/plugin-creator.png create mode 100644 Skills/Codex/.system/plugin-creator/references/installing-and-updating.md create mode 100644 Skills/Codex/.system/plugin-creator/references/plugin-json-spec.md create mode 100644 Skills/Codex/.system/plugin-creator/scripts/create_basic_plugin.py create mode 100644 Skills/Codex/.system/plugin-creator/scripts/read_marketplace_name.py create mode 100644 Skills/Codex/.system/plugin-creator/scripts/update_plugin_cachebuster.py create mode 100644 Skills/Codex/.system/plugin-creator/scripts/validate_plugin.py create mode 100644 Skills/Codex/.system/skill-creator/SKILL.md create mode 100644 Skills/Codex/.system/skill-creator/agents/openai.yaml create mode 100644 Skills/Codex/.system/skill-creator/assets/skill-creator-small.svg create mode 100644 Skills/Codex/.system/skill-creator/assets/skill-creator.png create mode 100644 Skills/Codex/.system/skill-creator/license.txt create mode 100644 Skills/Codex/.system/skill-creator/references/openai_yaml.md create mode 100644 Skills/Codex/.system/skill-creator/scripts/__pycache__/generate_openai_yaml.cpython-312.pyc create mode 100644 Skills/Codex/.system/skill-creator/scripts/generate_openai_yaml.py create mode 100644 Skills/Codex/.system/skill-creator/scripts/init_skill.py create mode 100644 Skills/Codex/.system/skill-creator/scripts/quick_validate.py create mode 100644 Skills/Codex/.system/skill-installer/LICENSE.txt create mode 100644 Skills/Codex/.system/skill-installer/SKILL.md create mode 100644 Skills/Codex/.system/skill-installer/agents/openai.yaml create mode 100644 Skills/Codex/.system/skill-installer/assets/skill-installer-small.svg create mode 100644 Skills/Codex/.system/skill-installer/assets/skill-installer.png create mode 100644 Skills/Codex/.system/skill-installer/scripts/github_utils.py create mode 100644 Skills/Codex/.system/skill-installer/scripts/install-skill-from-github.py create mode 100644 Skills/Codex/.system/skill-installer/scripts/list-skills.py create mode 100644 Skills/Codex/spreadsheet/LICENSE.txt create mode 100644 Skills/Codex/spreadsheet/SKILL.md create mode 100644 Skills/Codex/spreadsheet/agents/openai.yaml create mode 100644 Skills/Codex/spreadsheet/assets/spreadsheet-small.svg create mode 100644 Skills/Codex/spreadsheet/assets/spreadsheet.png create mode 100644 Skills/Codex/spreadsheet/references/examples/openpyxl/create_basic_spreadsheet.py create mode 100644 Skills/Codex/spreadsheet/references/examples/openpyxl/create_spreadsheet_with_styling.py create mode 100644 Skills/Codex/spreadsheet/references/examples/openpyxl/read_existing_spreadsheet.py create mode 100644 Skills/Codex/spreadsheet/references/examples/openpyxl/styling_spreadsheet.py create mode 100644 plugins/cache/local-personal/claude-md-management/1.0.0/.codex-plugin/plugin.json create mode 100644 plugins/cache/local-personal/claude-md-management/1.0.0/LICENSE create mode 100644 plugins/cache/local-personal/claude-md-management/1.0.0/README.md create mode 100644 plugins/cache/local-personal/claude-md-management/1.0.0/assets/claude-md-improver-example.png create mode 100644 plugins/cache/local-personal/claude-md-management/1.0.0/assets/revise-claude-md-example.png create mode 100644 plugins/cache/local-personal/claude-md-management/1.0.0/skills/claude-md-improver/SKILL.md create mode 100644 plugins/cache/local-personal/claude-md-management/1.0.0/skills/claude-md-improver/references/quality-criteria.md create mode 100644 plugins/cache/local-personal/claude-md-management/1.0.0/skills/claude-md-improver/references/templates.md create mode 100644 plugins/cache/local-personal/claude-md-management/1.0.0/skills/claude-md-improver/references/update-guidelines.md create mode 100644 plugins/cache/local-personal/claude-md-management/1.0.0/skills/revise-claude-md/SKILL.md create mode 100644 plugins/cache/openai-bundled/browser/26.608.12217/.codex-plugin/api-multi-tab.md create mode 100644 plugins/cache/openai-bundled/browser/26.608.12217/.codex-plugin/control-in-app-browser-multi-tab.md create mode 100644 plugins/cache/openai-bundled/browser/26.608.12217/.codex-plugin/plugin.json create mode 100644 plugins/cache/openai-bundled/browser/26.608.12217/assets/browser.png create mode 100644 plugins/cache/openai-bundled/browser/26.608.12217/assets/composer-icon.png create mode 100644 plugins/cache/openai-bundled/browser/26.608.12217/docs/api-troubleshooting.md create mode 100644 plugins/cache/openai-bundled/browser/26.608.12217/docs/api.md create mode 100644 plugins/cache/openai-bundled/browser/26.608.12217/docs/capabilities/browser/viewport.md create mode 100644 plugins/cache/openai-bundled/browser/26.608.12217/docs/capabilities/browser/visibility.md create mode 100644 plugins/cache/openai-bundled/browser/26.608.12217/docs/capabilities/tab/pageAssets.md create mode 100644 plugins/cache/openai-bundled/browser/26.608.12217/docs/confirmations.md create mode 100644 plugins/cache/openai-bundled/browser/26.608.12217/docs/playwright.md create mode 100644 plugins/cache/openai-bundled/browser/26.608.12217/docs/screenshots.md create mode 100644 plugins/cache/openai-bundled/browser/26.608.12217/scripts/browser-client.mjs create mode 100644 plugins/cache/openai-bundled/browser/26.608.12217/skills/control-in-app-browser/SKILL.md create mode 100644 plugins/cache/openai-bundled/browser/26.608.12217/skills/control-in-app-browser/agents/openai.yaml create mode 100644 plugins/cache/openai-curated/superpowers/c6ea566d/.codex-plugin/plugin.json create mode 100644 plugins/cache/openai-curated/superpowers/c6ea566d/CODE_OF_CONDUCT.md create mode 100644 plugins/cache/openai-curated/superpowers/c6ea566d/LICENSE create mode 100644 plugins/cache/openai-curated/superpowers/c6ea566d/README.md create mode 100644 plugins/cache/openai-curated/superpowers/c6ea566d/assets/app-icon.png create mode 100644 plugins/cache/openai-curated/superpowers/c6ea566d/assets/superpowers-small.svg create mode 100644 plugins/cache/openai-curated/superpowers/c6ea566d/skills/brainstorming/SKILL.md create mode 100644 plugins/cache/openai-curated/superpowers/c6ea566d/skills/brainstorming/agents/openai.yaml create mode 100644 plugins/cache/openai-curated/superpowers/c6ea566d/skills/brainstorming/scripts/frame-template.html create mode 100644 plugins/cache/openai-curated/superpowers/c6ea566d/skills/brainstorming/scripts/helper.js create mode 100644 plugins/cache/openai-curated/superpowers/c6ea566d/skills/brainstorming/scripts/server.cjs create mode 100644 plugins/cache/openai-curated/superpowers/c6ea566d/skills/brainstorming/scripts/start-server.sh create mode 100644 plugins/cache/openai-curated/superpowers/c6ea566d/skills/brainstorming/scripts/stop-server.sh create mode 100644 plugins/cache/openai-curated/superpowers/c6ea566d/skills/brainstorming/spec-document-reviewer-prompt.md create mode 100644 plugins/cache/openai-curated/superpowers/c6ea566d/skills/brainstorming/visual-companion.md create mode 100644 plugins/cache/openai-curated/superpowers/c6ea566d/skills/dispatching-parallel-agents/SKILL.md create mode 100644 plugins/cache/openai-curated/superpowers/c6ea566d/skills/dispatching-parallel-agents/agents/openai.yaml create mode 100644 plugins/cache/openai-curated/superpowers/c6ea566d/skills/executing-plans/SKILL.md create mode 100644 plugins/cache/openai-curated/superpowers/c6ea566d/skills/executing-plans/agents/openai.yaml create mode 100644 plugins/cache/openai-curated/superpowers/c6ea566d/skills/finishing-a-development-branch/SKILL.md create mode 100644 plugins/cache/openai-curated/superpowers/c6ea566d/skills/finishing-a-development-branch/agents/openai.yaml create mode 100644 plugins/cache/openai-curated/superpowers/c6ea566d/skills/receiving-code-review/SKILL.md create mode 100644 plugins/cache/openai-curated/superpowers/c6ea566d/skills/receiving-code-review/agents/openai.yaml create mode 100644 plugins/cache/openai-curated/superpowers/c6ea566d/skills/requesting-code-review/SKILL.md create mode 100644 plugins/cache/openai-curated/superpowers/c6ea566d/skills/requesting-code-review/agents/openai.yaml create mode 100644 plugins/cache/openai-curated/superpowers/c6ea566d/skills/requesting-code-review/code-reviewer.md create mode 100644 plugins/cache/openai-curated/superpowers/c6ea566d/skills/subagent-driven-development/SKILL.md create mode 100644 plugins/cache/openai-curated/superpowers/c6ea566d/skills/subagent-driven-development/agents/openai.yaml create mode 100644 plugins/cache/openai-curated/superpowers/c6ea566d/skills/subagent-driven-development/code-quality-reviewer-prompt.md create mode 100644 plugins/cache/openai-curated/superpowers/c6ea566d/skills/subagent-driven-development/implementer-prompt.md create mode 100644 plugins/cache/openai-curated/superpowers/c6ea566d/skills/subagent-driven-development/spec-reviewer-prompt.md create mode 100644 plugins/cache/openai-curated/superpowers/c6ea566d/skills/systematic-debugging/CREATION-LOG.md create mode 100644 plugins/cache/openai-curated/superpowers/c6ea566d/skills/systematic-debugging/SKILL.md create mode 100644 plugins/cache/openai-curated/superpowers/c6ea566d/skills/systematic-debugging/agents/openai.yaml create mode 100644 plugins/cache/openai-curated/superpowers/c6ea566d/skills/systematic-debugging/condition-based-waiting-example.ts create mode 100644 plugins/cache/openai-curated/superpowers/c6ea566d/skills/systematic-debugging/condition-based-waiting.md create mode 100644 plugins/cache/openai-curated/superpowers/c6ea566d/skills/systematic-debugging/defense-in-depth.md create mode 100644 plugins/cache/openai-curated/superpowers/c6ea566d/skills/systematic-debugging/find-polluter.sh create mode 100644 plugins/cache/openai-curated/superpowers/c6ea566d/skills/systematic-debugging/root-cause-tracing.md create mode 100644 plugins/cache/openai-curated/superpowers/c6ea566d/skills/systematic-debugging/test-academic.md create mode 100644 plugins/cache/openai-curated/superpowers/c6ea566d/skills/systematic-debugging/test-pressure-1.md create mode 100644 plugins/cache/openai-curated/superpowers/c6ea566d/skills/systematic-debugging/test-pressure-2.md create mode 100644 plugins/cache/openai-curated/superpowers/c6ea566d/skills/systematic-debugging/test-pressure-3.md create mode 100644 plugins/cache/openai-curated/superpowers/c6ea566d/skills/test-driven-development/SKILL.md create mode 100644 plugins/cache/openai-curated/superpowers/c6ea566d/skills/test-driven-development/agents/openai.yaml create mode 100644 plugins/cache/openai-curated/superpowers/c6ea566d/skills/test-driven-development/testing-anti-patterns.md create mode 100644 plugins/cache/openai-curated/superpowers/c6ea566d/skills/using-git-worktrees/SKILL.md create mode 100644 plugins/cache/openai-curated/superpowers/c6ea566d/skills/using-git-worktrees/agents/openai.yaml create mode 100644 plugins/cache/openai-curated/superpowers/c6ea566d/skills/using-superpowers/SKILL.md create mode 100644 plugins/cache/openai-curated/superpowers/c6ea566d/skills/using-superpowers/agents/openai.yaml create mode 100644 plugins/cache/openai-curated/superpowers/c6ea566d/skills/using-superpowers/references/codex-tools.md create mode 100644 plugins/cache/openai-curated/superpowers/c6ea566d/skills/using-superpowers/references/copilot-tools.md create mode 100644 plugins/cache/openai-curated/superpowers/c6ea566d/skills/using-superpowers/references/gemini-tools.md create mode 100644 plugins/cache/openai-curated/superpowers/c6ea566d/skills/verification-before-completion/SKILL.md create mode 100644 plugins/cache/openai-curated/superpowers/c6ea566d/skills/verification-before-completion/agents/openai.yaml create mode 100644 plugins/cache/openai-curated/superpowers/c6ea566d/skills/writing-plans/SKILL.md create mode 100644 plugins/cache/openai-curated/superpowers/c6ea566d/skills/writing-plans/agents/openai.yaml create mode 100644 plugins/cache/openai-curated/superpowers/c6ea566d/skills/writing-plans/plan-document-reviewer-prompt.md create mode 100644 plugins/cache/openai-curated/superpowers/c6ea566d/skills/writing-skills/SKILL.md create mode 100644 plugins/cache/openai-curated/superpowers/c6ea566d/skills/writing-skills/agents/openai.yaml create mode 100644 plugins/cache/openai-curated/superpowers/c6ea566d/skills/writing-skills/anthropic-best-practices.md create mode 100644 plugins/cache/openai-curated/superpowers/c6ea566d/skills/writing-skills/examples/CLAUDE_MD_TESTING.md create mode 100644 plugins/cache/openai-curated/superpowers/c6ea566d/skills/writing-skills/graphviz-conventions.dot create mode 100644 plugins/cache/openai-curated/superpowers/c6ea566d/skills/writing-skills/persuasion-principles.md create mode 100644 plugins/cache/openai-curated/superpowers/c6ea566d/skills/writing-skills/render-graphs.js create mode 100644 plugins/cache/openai-curated/superpowers/c6ea566d/skills/writing-skills/testing-skills-with-subagents.md diff --git a/Coding/Codex/.codex/config.toml b/Coding/Codex-cpp/.codex/config.toml similarity index 80% rename from Coding/Codex/.codex/config.toml rename to Coding/Codex-cpp/.codex/config.toml index bc8a348..b75aa36 100644 --- a/Coding/Codex/.codex/config.toml +++ b/Coding/Codex-cpp/.codex/config.toml @@ -1,5 +1,4 @@ #:schema https://developers.openai.com/codex/config-schema.json [features] -hooks = true - \ No newline at end of file +codex_hooks = true diff --git a/Coding/Codex/.codex/hooks.json b/Coding/Codex-cpp/.codex/hooks.json similarity index 100% rename from Coding/Codex/.codex/hooks.json rename to Coding/Codex-cpp/.codex/hooks.json diff --git a/Coding/Codex-cpp/.codex/hooks/pre_commit_checks.py b/Coding/Codex-cpp/.codex/hooks/pre_commit_checks.py new file mode 100644 index 0000000..92dd51d --- /dev/null +++ b/Coding/Codex-cpp/.codex/hooks/pre_commit_checks.py @@ -0,0 +1,89 @@ +import json +import re +import subprocess +import sys +from pathlib import Path + + +def _repo_root(cwd: Path) -> Path: + try: + root = subprocess.check_output( + ["git", "rev-parse", "--show-toplevel"], + cwd=cwd, + text=True, + stderr=subprocess.DEVNULL, + ).strip() + except (subprocess.CalledProcessError, FileNotFoundError): + return cwd + return Path(root) + + +def _is_git_commit(command: str) -> bool: + return re.search( + r"^\s*git(?:\s+(?:-[A-Za-z]\s+\S+|--[A-Za-z0-9-]+(?:=\S+)?))*\s+commit\b", + command, + ) is not None + + +def _deny(reason: str) -> None: + print( + json.dumps( + { + "hookSpecificOutput": { + "hookEventName": "PreToolUse", + "permissionDecision": "deny", + "permissionDecisionReason": reason, + } + } + ) + ) + + +def _tail(text: str, limit: int = 1200) -> str: + text = text.strip() + if len(text) <= limit: + return text + return text[-limit:] + + +def _build_pre_commit_commands(root: Path) -> list[list[str]]: + return [ + [sys.executable, "-m", "unittest", "discover", "-s", "scripts", "-p", "test_*.py"], + [sys.executable, "scripts/validate_workspace.py"], + ] + + +def _run_checks(root: Path) -> str | None: + for command in _build_pre_commit_commands(root): + result = subprocess.run(command, cwd=root, capture_output=True, text=True) + if result.returncode != 0: + details = _tail(result.stdout + "\n" + result.stderr) + label = " ".join(command) + if details: + return f"{label} failed:\n{details}" + return f"{label} failed with exit code {result.returncode}." + + return None + + +def main() -> int: + try: + payload = json.load(sys.stdin) + except json.JSONDecodeError: + return 0 + + command = payload.get("tool_input", {}).get("command", "") + if not isinstance(command, str) or not _is_git_commit(command): + return 0 + + cwd = Path(payload.get("cwd") or Path.cwd()) + root = _repo_root(cwd) + failure = _run_checks(root) + if failure: + _deny(f"PRE-COMMIT CHECKS: {failure}") + + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/Coding/Codex-cpp/.codex/hooks/tdd-guard.py b/Coding/Codex-cpp/.codex/hooks/tdd-guard.py new file mode 100644 index 0000000..0e4cba7 --- /dev/null +++ b/Coding/Codex-cpp/.codex/hooks/tdd-guard.py @@ -0,0 +1,205 @@ +import json +import subprocess +import sys +from pathlib import Path + + +SOURCE_SUFFIXES = {".h", ".hpp", ".hh", ".hxx", ".c", ".cc", ".cpp", ".cxx", ".ixx"} +TEST_SUFFIXES = {".h", ".hpp", ".hh", ".hxx", ".c", ".cc", ".cpp", ".cxx", ".ixx"} +CONFIG_SUFFIXES = {".json", ".md", ".yml", ".yaml", ".txt", ".cmake"} + + +def _repo_root(cwd: Path) -> Path: + try: + root = subprocess.check_output( + ["git", "rev-parse", "--show-toplevel"], + cwd=cwd, + text=True, + stderr=subprocess.DEVNULL, + ).strip() + except (subprocess.CalledProcessError, FileNotFoundError): + return cwd + return Path(root) + + +def _extract_patch_paths(command: str) -> list[str]: + prefixes = ( + "*** Add File: ", + "*** Update File: ", + "*** Delete File: ", + "*** Move to: ", + ) + paths: list[str] = [] + for raw_line in command.splitlines(): + line = raw_line.strip() + for prefix in prefixes: + if line.startswith(prefix): + paths.append(line[len(prefix) :].strip()) + break + return paths + + +def _touched_paths(payload: dict) -> list[str]: + tool_input = payload.get("tool_input", {}) + if not isinstance(tool_input, dict): + return [] + + file_path = tool_input.get("file_path") + if isinstance(file_path, str) and file_path: + return [file_path] + + command = tool_input.get("command") + if isinstance(command, str): + return _extract_patch_paths(command) + + return [] + + +def _normalize(path_text: str) -> str: + return path_text.replace("\\", "/").lower() + + +def _is_test_path(path_text: str) -> bool: + normalized = _normalize(path_text) + name = normalized.rsplit("/", 1)[-1] + path = Path(path_text) + return ( + "/tests/" in f"/{normalized}" + or "/test/" in f"/{normalized}" + or name.endswith("_test.cpp") + or name.startswith("test_") + or ".test." in name + or ".spec." in name + ) and path.suffix.lower() in TEST_SUFFIXES + + +def _token(text: str) -> str: + return "".join(ch for ch in text.lower() if ch.isalnum()) + + +def _module_token(path: Path) -> str: + parts = [part.lower() for part in path.parts] + for marker in ("include", "src"): + if marker not in parts: + continue + idx = parts.index(marker) + if marker == "include" and idx + 2 < len(parts) and parts[idx + 1] == "fesa": + return _token(parts[idx + 2]) + if marker == "src" and idx + 1 < len(parts): + return _token(parts[idx + 1]) + return "" + + +def _related_tokens(path: Path) -> set[str]: + tokens = {_token(_base_name(path))} + module = _module_token(path) + if module: + tokens.add(module) + return {token for token in tokens if token} + + +def _candidate_test_paths(paths: list[str], cwd: Path, root: Path) -> list[Path]: + candidates: list[Path] = [] + for path_text in paths: + resolved = _resolve_path(path_text, cwd) + if _is_test_path(str(resolved)): + candidates.append(resolved) + + for test_root_name in ("tests", "test"): + test_root = root / test_root_name + if not test_root.is_dir(): + continue + for suffix in TEST_SUFFIXES: + candidates.extend(test_root.rglob(f"*{suffix}")) + + return candidates + + +def _has_related_test(path: Path, candidate_tests: list[Path]) -> bool: + tokens = _related_tokens(path) + for test_path in candidate_tests: + test_token = _token(test_path.stem) + if any(token and token in test_token for token in tokens): + return True + return False + + +def _is_exempt(path_text: str) -> bool: + normalized = _normalize(path_text) + path = Path(path_text) + name = path.name.lower() + + if name == "cmakelists.txt": + return True + if _is_test_path(path_text): + return True + if path.suffix.lower() in CONFIG_SUFFIXES: + return True + if "/cmake/" in normalized: + return True + + return False + + +def _resolve_path(path_text: str, cwd: Path) -> Path: + path = Path(path_text) + if path.is_absolute(): + return path + return (cwd / path).resolve() + + +def _base_name(path: Path) -> str: + for suffix in sorted(SOURCE_SUFFIXES, key=len, reverse=True): + if path.name.lower().endswith(suffix): + return path.name[: -len(suffix)] + return path.stem + + +def _guarded_paths(paths: list[str], cwd: Path, root: Path) -> list[str]: + missing_tests: list[str] = [] + candidate_tests = _candidate_test_paths(paths, cwd, root) + for path_text in paths: + if _is_exempt(path_text): + continue + + path = _resolve_path(path_text, cwd) + if path.suffix.lower() not in SOURCE_SUFFIXES: + continue + if not _has_related_test(path, candidate_tests): + missing_tests.append(_base_name(path)) + + return missing_tests + + +def main() -> int: + try: + payload = json.load(sys.stdin) + except json.JSONDecodeError: + return 0 + + cwd = Path(payload.get("cwd") or Path.cwd()) + root = _repo_root(cwd) + missing_tests = _guarded_paths(_touched_paths(payload), cwd, root) + if not missing_tests: + return 0 + + names = ", ".join(sorted(set(missing_tests))) + print( + json.dumps( + { + "hookSpecificOutput": { + "hookEventName": "PreToolUse", + "permissionDecision": "deny", + "permissionDecisionReason": ( + "TDD GUARD: missing test file for " + f"{names}. Write or add the test first." + ), + } + } + ) + ) + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/Coding/Codex-cpp/.codex/skills/harness-review/SKILL.md b/Coding/Codex-cpp/.codex/skills/harness-review/SKILL.md new file mode 100644 index 0000000..498d394 --- /dev/null +++ b/Coding/Codex-cpp/.codex/skills/harness-review/SKILL.md @@ -0,0 +1,44 @@ +--- +name: harness-review +description: Use when reviewing this C++/MSVC Harness repository: local changes, generated phase files, step outputs, implementation diffs, missing tests, MSVC build readiness, or compliance with AGENTS.md, docs/ARCHITECTURE.md, docs/ADR.md, and Harness acceptance criteria. +--- + +# Harness Review + +## Overview + +Use this skill to review Harness work against the repository's persistent rules, architecture docs, C++/MSVC constraints, TDD guard policy, and executable verification requirements. Prioritize bugs, regressions, missing tests, and rule violations. + +## Review Process + +1. Read `/AGENTS.md`, `/docs/ARCHITECTURE.md`, and `/docs/ADR.md`. +2. Inspect the changed files with `git status --short` and `git diff`. +3. Check architecture, stack choices, C++ test coverage, critical rules, and MSVC/CMake readiness. +4. Run relevant verification commands when feasible. If a command cannot be run, report that as residual risk. +5. Lead with actionable findings. Keep summaries secondary. + +## Checklist + +| Item | Question | +| --- | --- | +| Architecture | Does the change follow `docs/ARCHITECTURE.md` ownership boundaries? | +| Stack | Does the change stay within C++/MSVC/CMake decisions documented in `docs/ADR.md`? | +| Tests | Are new or changed behaviors covered by Python Harness tests or C++ tests? | +| TDD Guard | Would C++ production edits be blocked without related tests? | +| Critical Rules | Does the change violate any `AGENTS.md` CRITICAL rule? | +| Build | Do `python -m unittest discover -s scripts -p "test_*.py"` and `python scripts/validate_workspace.py` pass or provide an expected no-CMake message? | + +## Output Format + +If there are findings, list them first in severity order with file and line references when possible. Then include this table: + +| 항목 | 결과 | 비고 | +| --- | --- | --- | +| 아키텍처 준수 | PASS/FAIL | {상세} | +| 기술 스택 준수 | PASS/FAIL | {상세} | +| 테스트 존재 | PASS/FAIL | {상세} | +| TDD Guard | PASS/FAIL | {상세} | +| CRITICAL 규칙 | PASS/FAIL | {상세} | +| 빌드/검증 가능 | PASS/FAIL | {상세} | + +When there are no findings, say that clearly, then mention any commands not run or remaining risk. diff --git a/Coding/Codex/.agents/skills/harness-review/agents/openai.yaml b/Coding/Codex-cpp/.codex/skills/harness-review/agents/openai.yaml similarity index 100% rename from Coding/Codex/.agents/skills/harness-review/agents/openai.yaml rename to Coding/Codex-cpp/.codex/skills/harness-review/agents/openai.yaml diff --git a/Coding/Codex-cpp/.codex/skills/harness-workflow/SKILL.md b/Coding/Codex-cpp/.codex/skills/harness-workflow/SKILL.md new file mode 100644 index 0000000..a499e94 --- /dev/null +++ b/Coding/Codex-cpp/.codex/skills/harness-workflow/SKILL.md @@ -0,0 +1,129 @@ +--- +name: harness-workflow +description: Use when planning or running this C++/MSVC Harness framework: reading AGENTS.md and docs/*.md, discussing implementation scope, creating or updating phases/index.json, phases/{task}/index.json, phases/{task}/stepN.md, or invoking scripts/execute.py for staged Codex execution. +--- + +# Harness Workflow + +## Overview + +Use this skill to turn a user-approved task into small, self-contained Harness steps that another Codex session can execute reliably. Keep every step grounded in repository docs, C++/MSVC constraints, TDD, and executable acceptance criteria. + +## Workflow + +1. Read `AGENTS.md` and relevant files under `docs/`, especially `docs/PRD.md`, `docs/ARCHITECTURE.md`, and `docs/ADR.md`. +2. Discuss unresolved product or technical decisions with the user before writing phase files. +3. When the user asks for an implementation plan, draft steps and get approval before creating files. +4. Create or update `phases/index.json`, `phases/{task-name}/index.json`, and one `phases/{task-name}/stepN.md` per step. +5. Run the phase with `python scripts/execute.py {task-name}` when asked to execute it. Use `--push` only when the user asks to push. + +## Step Design Rules + +- Scope each step to one layer or module. Split steps when multiple modules would otherwise change together. +- Make every step self-contained. Do not rely on prior conversation; include all required context and file paths. +- Force context gathering. Each step must tell Codex which docs and previous outputs to read before editing. +- Specify interfaces and signatures, not full implementations, unless exact code is required for a constraint. +- Put core invariants directly in the step: idempotency, numerical conventions, data integrity, API contracts, or other non-negotiables. +- Use executable acceptance criteria such as `python scripts/validate_workspace.py`, not abstract statements. +- For C++ behavior changes, require tests first and name the expected test file or test executable. +- Name steps with kebab-case slugs such as `project-setup`, `core-types`, or `solver-validation`. + +## Phase Files + +Create or update `phases/index.json`: + +```json +{ + "phases": [ + { + "dir": "0-mvp", + "status": "pending" + } + ] +} +``` + +Create `phases/{task-name}/index.json`: + +```json +{ + "project": "FESA Harness", + "phase": "", + "steps": [ + { "step": 0, "name": "project-setup", "status": "pending" }, + { "step": 1, "name": "core-types", "status": "pending" }, + { "step": 2, "name": "validation-path", "status": "pending" } + ] +} +``` + +Rules: + +- `project` comes from `AGENTS.md`. +- `phase` matches the task directory name. +- `steps[].step` starts at `0`. +- Initial status is always `pending`. +- Do not add timestamps when creating files. `scripts/execute.py` records `created_at`, `started_at`, `completed_at`, `failed_at`, and `blocked_at`. + +## Step Template + +```markdown +# Step {N}: {name} + +## 읽어야 할 파일 + +먼저 아래 파일들을 읽고 프로젝트의 아키텍처와 설계 의도를 파악하라: + +- `/AGENTS.md` +- `/docs/ARCHITECTURE.md` +- `/docs/ADR.md` +- {previously created or modified files} + +이전 step에서 만들어진 코드를 꼼꼼히 읽고, 설계 의도를 이해한 뒤 작업하라. + +## 작업 + +{Concrete instructions with file paths, interfaces, signatures, and rules.} + +## Tests To Write First + +- {Exact C++ or Python test file and behavior to add before implementation.} + +## Acceptance Criteria + +```bash +python -m unittest discover -s scripts -p "test_*.py" +python scripts/validate_workspace.py +``` + +## 검증 절차 + +1. 위 AC 커맨드를 실행한다. +2. 아키텍처 체크리스트를 확인한다: + - ARCHITECTURE.md 디렉토리 구조를 따르는가? + - ADR 기술 스택을 벗어나지 않았는가? + - AGENTS.md CRITICAL 규칙을 위반하지 않았는가? + - C++ 변경에는 관련 테스트가 존재하는가? +3. 결과에 따라 `phases/{task-name}/index.json`의 해당 step을 업데이트한다: + - 성공: `"status": "completed"`, `"summary": "산출물 한 줄 요약"` + - 3회 수정 시도 후 실패: `"status": "error"`, `"error_message": "구체적 에러 내용"` + - 사용자 개입 필요: `"status": "blocked"`, `"blocked_reason": "구체적 사유"` 후 중단 + +## 금지사항 + +- JavaScript/TypeScript/npm fallback을 추가하지 마라. Reason: 이 Harness는 C++/MSVC 전용이다. +- 기존 테스트를 깨뜨리지 마라. +``` + +## Execution And Recovery + +Run: + +```bash +python scripts/execute.py {task-name} +python scripts/execute.py {task-name} --push +``` + +`scripts/execute.py` creates or checks out `feat-{task-name}`, injects `AGENTS.md` and `docs/*.md` into each prompt, carries completed step summaries forward, retries failed steps up to three times, separates code and metadata commits, and records timestamps. + +If a step is `error`, set it back to `pending` and remove `error_message` after fixing the cause. If a step is `blocked`, resolve `blocked_reason`, set it back to `pending`, remove `blocked_reason`, and rerun. diff --git a/Coding/Codex/.agents/skills/harness-workflow/agents/openai.yaml b/Coding/Codex-cpp/.codex/skills/harness-workflow/agents/openai.yaml similarity index 100% rename from Coding/Codex/.agents/skills/harness-workflow/agents/openai.yaml rename to Coding/Codex-cpp/.codex/skills/harness-workflow/agents/openai.yaml diff --git a/Coding/Codex-cpp/.gitignore b/Coding/Codex-cpp/.gitignore new file mode 100644 index 0000000..ab001a0 --- /dev/null +++ b/Coding/Codex-cpp/.gitignore @@ -0,0 +1,23 @@ +.vs/ +build/ +out/ +CMakeFiles/ +CMakeCache.txt +cmake_install.cmake +CTestTestfile.cmake +Testing/ +*.vcxproj.user +*.obj +*.pdb +*.ilk +*.exe +*.dll +*.lib +*.exp +*.log +__pycache__/ +*.pyc + +# phase execution outputs +phases/**/phase*-output.json +phases/**/step*-output.json diff --git a/Coding/Codex-cpp/AGENTS.md b/Coding/Codex-cpp/AGENTS.md new file mode 100644 index 0000000..2abc792 --- /dev/null +++ b/Coding/Codex-cpp/AGENTS.md @@ -0,0 +1,44 @@ +# Project: FESA Harness + +## 기술 스택 +- C++17 이상 +- MSVC on Windows +- CMake + CTest +- Harness scripts in Python 3 + +## 아키텍처 규칙 +- CRITICAL: 기본 검증 경로는 `python scripts/validate_workspace.py`이다. +- CRITICAL: C++ 빌드는 CMake/MSVC/x64/Debug 기준으로 검증한다. +- CRITICAL: 새 기능 또는 동작 변경은 테스트를 먼저 작성하고 실패를 확인한 뒤 구현한다. +- CRITICAL: Abaqus reference artifact나 solver 코드 복원은 명시적으로 요청된 phase에서만 수행한다. +- Harness runner는 `scripts/execute.py`에 둔다. +- Codex hook 정책은 `.codex/hooks/`에 둔다. +- Harness planning/review instructions are stored in `.codex/skills/`. +- Generated phase execution outputs remain ignored under `phases/**/step*-output.json`. + +## 개발 프로세스 +- TDD를 기본으로 한다. C++ production file을 바꿀 때는 관련 C++ test file이 있어야 한다. +- 커밋 전 hook은 Harness Python self-test와 workspace validation을 실행해야 한다. +- 커밋 메시지는 conventional commits 형식을 따른다: `feat:`, `fix:`, `docs:`, `refactor:`, `test:`. +- 계획이 필요한 장기 작업은 Harness phase로 나누고, 각 step은 독립 실행 가능해야 한다. + +## 명령어 +```bash +python -m unittest discover -s scripts -p "test_*.py" +python scripts/validate_workspace.py +python scripts/execute.py +python scripts/execute.py --push +``` + +## MSVC 검증 기본값 +- Generator: `Visual Studio 17 2022` +- Platform: `x64` +- Config: `Debug` +- Build directory: `build/msvc-debug` + +Override variables: +- `HARNESS_VALIDATION_COMMANDS` +- `HARNESS_CMAKE_GENERATOR` +- `HARNESS_CMAKE_PLATFORM` +- `HARNESS_CMAKE_CONFIG` +- `HARNESS_BUILD_DIR` diff --git a/Coding/Codex-cpp/docs/ADR.md b/Coding/Codex-cpp/docs/ADR.md new file mode 100644 index 0000000..1ba9166 --- /dev/null +++ b/Coding/Codex-cpp/docs/ADR.md @@ -0,0 +1,34 @@ +# Architecture Decision Records + +## 철학 +Harness는 현재 프로젝트의 실제 기술 스택을 반영해야 한다. C++/MSVC 프로젝트에서 npm, Next.js, TypeScript test naming을 기본값으로 두면 agent prompt와 hook policy가 잘못된 구현을 유도한다. + +--- + +### ADR-001: C++ 전용 Harness +**결정**: Harness scaffold는 C++/MSVC 전용으로 운영한다. JavaScript/TypeScript fallback은 유지하지 않는다. + +**이유**: FESA 개발 환경은 MSVC 기반 C++이다. 언어별 fallback을 남기면 validation, TDD guard, acceptance criteria가 흐려진다. + +**트레이드오프**: 같은 Harness scaffold를 JS/TS 프로젝트에 재사용할 수 없다. 필요하면 별도 template이나 language registry를 새 ADR로 설계한다. + +### ADR-002: CMake/MSVC/x64/Debug 기본 검증 +**결정**: 기본 workspace validation은 CMake, Visual Studio 17 2022 generator, x64 platform, Debug config, CTest로 수행한다. + +**이유**: MSVC 환경에서 CMake/CTest는 source tree가 복원되거나 새 C++ project가 추가될 때 가장 일관된 build/test entry point다. + +**트레이드오프**: Visual Studio solution-only project는 기본 지원하지 않는다. 명시적으로 필요하면 `HARNESS_VALIDATION_COMMANDS`로 override한다. + +### ADR-003: 엄격한 C++ TDD Guard +**결정**: C++ production file 변경은 관련 C++ test file이 없으면 차단한다. + +**이유**: Harness의 핵심 목적은 agent가 검증 없는 C++ 변경을 만들지 않도록 하는 것이다. Header 중심 C++ 구조에서도 module 또는 basename 기반 테스트 존재를 확인한다. + +**트레이드오프**: 초기 scaffolding 작업에서 guard가 엄격하게 느껴질 수 있다. 문서, CMake 설정, Harness metadata는 guard 대상에서 제외한다. + +### ADR-004: Harness 자체 테스트 우선 +**결정**: commit hook은 먼저 Python Harness self-test를 실행한 뒤 workspace validation을 실행한다. + +**이유**: 현재 저장소에는 C++ source tree가 없을 수 있다. Harness가 스스로 검증 가능해야 이후 phase generation과 source restoration을 안전하게 진행할 수 있다. + +**트레이드오프**: commit 시간이 조금 늘어난다. 대신 hook/validation regressions를 빠르게 잡는다. diff --git a/Coding/Codex-cpp/docs/ARCHITECTURE.md b/Coding/Codex-cpp/docs/ARCHITECTURE.md new file mode 100644 index 0000000..1747640 --- /dev/null +++ b/Coding/Codex-cpp/docs/ARCHITECTURE.md @@ -0,0 +1,58 @@ +# 아키텍처 + +## 목표 +이 저장소의 현재 책임은 C++/MSVC 프로젝트를 위한 Codex Harness scaffold를 제공하는 것이다. Harness는 phase execution, edit guard, commit validation, workspace validation을 분리해서 관리한다. + +## 디렉토리 구조 +```text +.codex/ +├── hooks/ # Codex hook scripts +└── skills/ # Harness planning/review instructions +docs/ # Project and Harness guidance +scripts/ +├── execute.py # Phase step executor +├── validate_workspace.py +└── test_*.py # Harness self-tests +phases/ # Optional generated phase plans +``` + +## 데이터 흐름 +```text +User-approved task +-> Harness phase files under phases/ +-> scripts/execute.py injects AGENTS.md and docs/*.md +-> Codex executes one step at a time +-> step updates phases/{phase}/index.json +-> validation runs through scripts/validate_workspace.py +``` + +## Hook 흐름 +```text +apply_patch/Edit/Write +-> .codex/hooks/tdd-guard.py +-> C++ production changes require related tests + +git commit command +-> .codex/hooks/pre_commit_checks.py +-> Python Harness self-tests +-> scripts/validate_workspace.py +``` + +## Validation 흐름 +```text +HARNESS_VALIDATION_COMMANDS set +-> run exact commands + +CMakePresets.json has msvc-debug configure preset +-> cmake --preset msvc-debug +-> cmake --build preset binary dir --config Debug +-> ctest --test-dir preset binary dir -C Debug + +CMakeLists.txt exists +-> cmake -S . -B build/msvc-debug -G "Visual Studio 17 2022" -A x64 +-> cmake --build build/msvc-debug --config Debug +-> ctest --test-dir build/msvc-debug --output-on-failure -C Debug + +No CMake project +-> print guidance and exit successfully +``` diff --git a/Coding/Codex-cpp/docs/PRD.md b/Coding/Codex-cpp/docs/PRD.md new file mode 100644 index 0000000..a6630fb --- /dev/null +++ b/Coding/Codex-cpp/docs/PRD.md @@ -0,0 +1,22 @@ +# PRD: C++/MSVC Harness + +## 목표 +Codex Harness가 C++/MSVC 프로젝트에서 phase planning, TDD guard, commit validation, workspace validation을 일관되게 수행하게 한다. + +## 사용자 +- Windows/MSVC 기반 C++ 개발자 +- Harness phase를 작성하고 실행하는 Codex agent +- Harness 결과를 검토하는 reviewer + +## 핵심 기능 +1. CMake/MSVC/x64/Debug 기반 workspace validation +2. C++ source/header 변경에 대한 엄격한 TDD guard +3. npm 없이 Python self-test와 CMake/CTest 검증을 수행하는 pre-commit hook +4. C++ 프로젝트에 맞는 Harness workflow/review prompt +5. CMake project가 아직 없어도 Harness 자체 테스트가 가능한 no-op validation path + +## 제외 사항 +- 이전 FESA solver source tree 복원 +- JavaScript/TypeScript fallback 유지 +- Abaqus reference artifact 생성 또는 solver reference 비교 구현 +- Visual Studio `.sln`/`.vcxproj` 전용 MSBuild workflow diff --git a/Coding/Codex/docs/UI_GUIDE.md b/Coding/Codex-cpp/docs/UI_GUIDE.md similarity index 100% rename from Coding/Codex/docs/UI_GUIDE.md rename to Coding/Codex-cpp/docs/UI_GUIDE.md diff --git a/Coding/Codex/scripts/execute.py b/Coding/Codex-cpp/scripts/execute.py similarity index 100% rename from Coding/Codex/scripts/execute.py rename to Coding/Codex-cpp/scripts/execute.py diff --git a/Coding/Codex-cpp/scripts/test_pre_commit_checks.py b/Coding/Codex-cpp/scripts/test_pre_commit_checks.py new file mode 100644 index 0000000..8553716 --- /dev/null +++ b/Coding/Codex-cpp/scripts/test_pre_commit_checks.py @@ -0,0 +1,41 @@ +import importlib.util +import sys +import tempfile +import unittest +from pathlib import Path + + +def load_pre_commit_checks(): + module_path = Path(__file__).resolve().parent.parent / ".codex" / "hooks" / "pre_commit_checks.py" + spec = importlib.util.spec_from_file_location("pre_commit_checks", module_path) + module = importlib.util.module_from_spec(spec) + spec.loader.exec_module(module) + return module + + +class PreCommitChecksTests(unittest.TestCase): + def test_git_commit_runs_python_self_tests_and_workspace_validation(self): + pre_commit_checks = load_pre_commit_checks() + with tempfile.TemporaryDirectory() as tmp: + root = Path(tmp) + commands = pre_commit_checks._build_pre_commit_commands(root) + + self.assertEqual( + commands, + [ + [sys.executable, "-m", "unittest", "discover", "-s", "scripts", "-p", "test_*.py"], + [sys.executable, "scripts/validate_workspace.py"], + ], + ) + self.assertFalse(any("npm" in part.lower() for command in commands for part in command)) + + def test_only_git_commit_commands_trigger_checks(self): + pre_commit_checks = load_pre_commit_checks() + self.assertTrue(pre_commit_checks._is_git_commit('git commit -m "change"')) + self.assertTrue(pre_commit_checks._is_git_commit('git -c core.editor=true commit -m "change"')) + self.assertFalse(pre_commit_checks._is_git_commit("git status --short")) + self.assertFalse(pre_commit_checks._is_git_commit("echo git commit")) + + +if __name__ == "__main__": + unittest.main() diff --git a/Coding/Codex-cpp/scripts/test_tdd_guard.py b/Coding/Codex-cpp/scripts/test_tdd_guard.py new file mode 100644 index 0000000..67436df --- /dev/null +++ b/Coding/Codex-cpp/scripts/test_tdd_guard.py @@ -0,0 +1,61 @@ +import importlib.util +import tempfile +import unittest +from pathlib import Path + + +def load_tdd_guard(): + module_path = Path(__file__).resolve().parent.parent / ".codex" / "hooks" / "tdd-guard.py" + spec = importlib.util.spec_from_file_location("tdd_guard", module_path) + module = importlib.util.module_from_spec(spec) + spec.loader.exec_module(module) + return module + + +class CppTddGuardTests(unittest.TestCase): + def test_cpp_production_file_without_related_test_is_blocked(self): + tdd_guard = load_tdd_guard() + with tempfile.TemporaryDirectory() as tmp: + root = Path(tmp) + source = root / "include" / "fesa" / "Core" / "DofManager.hpp" + source.parent.mkdir(parents=True) + source.write_text("#pragma once\n", encoding="utf-8") + + self.assertEqual(tdd_guard._guarded_paths([str(source)], root, root), ["DofManager"]) + + def test_cpp_production_file_with_module_test_is_allowed(self): + tdd_guard = load_tdd_guard() + with tempfile.TemporaryDirectory() as tmp: + root = Path(tmp) + source = root / "include" / "fesa" / "Core" / "DofManager.hpp" + source.parent.mkdir(parents=True) + source.write_text("#pragma once\n", encoding="utf-8") + tests_dir = root / "tests" + tests_dir.mkdir() + (tests_dir / "test_core_module_includes.cpp").write_text("int main() { return 0; }\n", encoding="utf-8") + + self.assertEqual(tdd_guard._guarded_paths([str(source)], root, root), []) + + def test_cpp_production_file_with_basename_test_in_same_patch_is_allowed(self): + tdd_guard = load_tdd_guard() + with tempfile.TemporaryDirectory() as tmp: + root = Path(tmp) + source = root / "src" / "Math" / "DenseMatrix.cpp" + source.parent.mkdir(parents=True) + source.write_text("void f() {}\n", encoding="utf-8") + test_path = root / "tests" / "test_dense_matrix.cpp" + + self.assertEqual(tdd_guard._guarded_paths([str(source), str(test_path)], root, root), []) + + def test_cmake_and_docs_are_exempt(self): + tdd_guard = load_tdd_guard() + with tempfile.TemporaryDirectory() as tmp: + root = Path(tmp) + self.assertEqual( + tdd_guard._guarded_paths(["CMakeLists.txt", "docs/ARCHITECTURE.md", "cmake/toolchain.cmake"], root, root), + [], + ) + + +if __name__ == "__main__": + unittest.main() diff --git a/Coding/Codex-cpp/scripts/test_validate_workspace.py b/Coding/Codex-cpp/scripts/test_validate_workspace.py new file mode 100644 index 0000000..71ba75a --- /dev/null +++ b/Coding/Codex-cpp/scripts/test_validate_workspace.py @@ -0,0 +1,94 @@ +import importlib.util +import os +import tempfile +import unittest +from pathlib import Path +from unittest.mock import patch + + +def load_validate_workspace(): + module_path = Path(__file__).resolve().parent / "validate_workspace.py" + spec = importlib.util.spec_from_file_location("validate_workspace", module_path) + module = importlib.util.module_from_spec(spec) + spec.loader.exec_module(module) + return module + + +class ValidateWorkspaceTests(unittest.TestCase): + def test_env_commands_override_cmake_detection(self): + validate_workspace = load_validate_workspace() + with tempfile.TemporaryDirectory() as tmp: + root = Path(tmp) + (root / "CMakeLists.txt").write_text("cmake_minimum_required(VERSION 3.20)\n", encoding="utf-8") + with patch.dict(os.environ, {"HARNESS_VALIDATION_COMMANDS": "echo first\n echo second \n"}, clear=True): + self.assertEqual(validate_workspace.discover_commands(root), ["echo first", "echo second"]) + + def test_msvc_debug_cmake_commands_are_default_for_cmake_project(self): + validate_workspace = load_validate_workspace() + with tempfile.TemporaryDirectory() as tmp: + root = Path(tmp) + (root / "CMakeLists.txt").write_text("cmake_minimum_required(VERSION 3.20)\n", encoding="utf-8") + build_dir = root / "build" / "msvc-debug" + with patch.dict(os.environ, {}, clear=True): + self.assertEqual( + validate_workspace.discover_commands(root), + [ + f'cmake -S "{root}" -B "{build_dir}" -G "Visual Studio 17 2022" -A x64', + f'cmake --build "{build_dir}" --config Debug', + f'ctest --test-dir "{build_dir}" --output-on-failure -C Debug', + ], + ) + + def test_msvc_debug_configure_preset_is_preferred_when_present(self): + validate_workspace = load_validate_workspace() + with tempfile.TemporaryDirectory() as tmp: + root = Path(tmp) + (root / "CMakeLists.txt").write_text("cmake_minimum_required(VERSION 3.20)\n", encoding="utf-8") + (root / "CMakePresets.json").write_text( + """ +{ + "version": 3, + "configurePresets": [ + { + "name": "msvc-debug", + "generator": "Visual Studio 17 2022", + "binaryDir": "${sourceDir}/out/msvc-debug" + } + ] +} +""", + encoding="utf-8", + ) + with patch.dict(os.environ, {}, clear=True): + self.assertEqual( + validate_workspace.discover_commands(root), + [ + "cmake --preset msvc-debug", + f'cmake --build "{root / "out" / "msvc-debug"}" --config Debug', + f'ctest --test-dir "{root / "out" / "msvc-debug"}" --output-on-failure -C Debug', + ], + ) + + def test_no_cmake_project_has_no_validation_commands(self): + validate_workspace = load_validate_workspace() + with tempfile.TemporaryDirectory() as tmp: + root = Path(tmp) + with patch.dict(os.environ, {}, clear=True): + self.assertEqual(validate_workspace.discover_commands(root), []) + + def test_common_cmake_install_path_is_prepended_when_cmake_is_not_on_path(self): + validate_workspace = load_validate_workspace() + with tempfile.TemporaryDirectory() as tmp: + common_bin = Path(tmp) / "CMake" / "bin" + common_bin.mkdir(parents=True) + (common_bin / "cmake.exe").write_text("", encoding="utf-8") + (common_bin / "ctest.exe").write_text("", encoding="utf-8") + with patch.object(validate_workspace, "COMMON_CMAKE_BIN", common_bin): + with patch.object(validate_workspace.shutil, "which", return_value=None): + env = validate_workspace.validation_environment({"PATH": "C:\\Windows\\System32"}) + + self.assertTrue(env["PATH"].startswith(str(common_bin))) + + +if __name__ == "__main__": + unittest.main() diff --git a/Coding/Codex-cpp/scripts/validate_workspace.py b/Coding/Codex-cpp/scripts/validate_workspace.py new file mode 100644 index 0000000..45b4530 --- /dev/null +++ b/Coding/Codex-cpp/scripts/validate_workspace.py @@ -0,0 +1,151 @@ +#!/usr/bin/env python3 +"""Run C++/MSVC Harness validation commands.""" + +from __future__ import annotations + +import json +import os +import shutil +import subprocess +import sys +from pathlib import Path + + +DEFAULT_GENERATOR = "Visual Studio 17 2022" +DEFAULT_PLATFORM = "x64" +DEFAULT_CONFIG = "Debug" +DEFAULT_BUILD_DIR = "build/msvc-debug" +PRESET_NAME = "msvc-debug" +COMMON_CMAKE_BIN = Path(r"C:\Program Files\CMake\bin") + + +def load_env_commands() -> list[str]: + raw = os.environ.get("HARNESS_VALIDATION_COMMANDS", "") + return [line.strip() for line in raw.splitlines() if line.strip()] + + +def _cmake_config() -> tuple[str, str, str, Path]: + generator = os.environ.get("HARNESS_CMAKE_GENERATOR", DEFAULT_GENERATOR) + platform = os.environ.get("HARNESS_CMAKE_PLATFORM", DEFAULT_PLATFORM) + config = os.environ.get("HARNESS_CMAKE_CONFIG", DEFAULT_CONFIG) + build_dir = Path(os.environ.get("HARNESS_BUILD_DIR", DEFAULT_BUILD_DIR)) + return generator, platform, config, build_dir + + +def _read_presets(root: Path) -> dict: + presets_file = root / "CMakePresets.json" + if not presets_file.exists(): + return {} + try: + return json.loads(presets_file.read_text(encoding="utf-8")) + except json.JSONDecodeError: + return {} + + +def _preset_binary_dir(root: Path, preset: dict) -> Path: + binary_dir = str(preset.get("binaryDir") or DEFAULT_BUILD_DIR) + binary_dir = binary_dir.replace("${sourceDir}", str(root)) + binary_dir = binary_dir.replace("$sourceDir", str(root)) + path = Path(binary_dir) + return path if path.is_absolute() else root / path + + +def load_preset_commands(root: Path) -> list[str]: + payload = _read_presets(root) + config = os.environ.get("HARNESS_CMAKE_CONFIG", DEFAULT_CONFIG) + for preset in payload.get("configurePresets", []): + if isinstance(preset, dict) and preset.get("name") == PRESET_NAME: + build_dir = _preset_binary_dir(root, preset) + return [ + f"cmake --preset {PRESET_NAME}", + f'cmake --build "{build_dir}" --config {config}', + f'ctest --test-dir "{build_dir}" --output-on-failure -C {config}', + ] + return [] + + +def load_cmake_commands(root: Path) -> list[str]: + if not (root / "CMakeLists.txt").exists(): + return [] + + generator, platform, config, build_dir = _cmake_config() + if not build_dir.is_absolute(): + build_dir = root / build_dir + return [ + f'cmake -S "{root}" -B "{build_dir}" -G "{generator}" -A {platform}', + f'cmake --build "{build_dir}" --config {config}', + f'ctest --test-dir "{build_dir}" --output-on-failure -C {config}', + ] + + +def discover_commands(root: Path) -> list[str]: + env_commands = load_env_commands() + if env_commands: + return env_commands + preset_commands = load_preset_commands(root) + if preset_commands: + return preset_commands + return load_cmake_commands(root) + + +def run_command(command: str, root: Path) -> subprocess.CompletedProcess: + return subprocess.run( + command, + cwd=root, + shell=True, + capture_output=True, + text=True, + encoding="utf-8", + errors="replace", + env=validation_environment(os.environ), + ) + + +def validation_environment(base_env: os._Environ | dict[str, str]) -> dict[str, str]: + env = dict(base_env) + if shutil.which("cmake") is not None: + return env + cmake_exe = COMMON_CMAKE_BIN / "cmake.exe" + if not cmake_exe.exists(): + return env + + current_path = env.get("PATH", "") + paths = [part for part in current_path.split(os.pathsep) if part] + common_bin_text = str(COMMON_CMAKE_BIN) + if not any(part.lower() == common_bin_text.lower() for part in paths): + env["PATH"] = common_bin_text + (os.pathsep + current_path if current_path else "") + return env + + +def emit_stream(prefix: str, content: str, *, stream) -> None: + text = (content or "").strip() + if not text: + return + print(prefix, file=stream) + print(text, file=stream) + + +def main() -> int: + root = Path(__file__).resolve().parent.parent + commands = discover_commands(root) + + if not commands: + print("No C++ validation commands configured.") + print("Add CMakeLists.txt or set HARNESS_VALIDATION_COMMANDS.") + return 0 + + for command in commands: + print(f"$ {command}") + result = run_command(command, root) + emit_stream("[stdout]", result.stdout, stream=sys.stdout) + emit_stream("[stderr]", result.stderr, stream=sys.stderr) + if result.returncode != 0: + print(f"Validation failed: {command}", file=sys.stderr) + return result.returncode + + print("Validation succeeded.") + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/Coding/Codex-tsjs/.codex/config.toml b/Coding/Codex-tsjs/.codex/config.toml new file mode 100644 index 0000000..b75aa36 --- /dev/null +++ b/Coding/Codex-tsjs/.codex/config.toml @@ -0,0 +1,4 @@ +#:schema https://developers.openai.com/codex/config-schema.json + +[features] +codex_hooks = true diff --git a/Coding/Codex-tsjs/.codex/hooks.json b/Coding/Codex-tsjs/.codex/hooks.json new file mode 100644 index 0000000..0229d62 --- /dev/null +++ b/Coding/Codex-tsjs/.codex/hooks.json @@ -0,0 +1,28 @@ +{ + "hooks": { + "PreToolUse": [ + { + "matcher": "^Bash$", + "hooks": [ + { + "type": "command", + "command": "python -c \"import pathlib, runpy, subprocess; root = pathlib.Path(subprocess.check_output(['git', 'rev-parse', '--show-toplevel'], text=True).strip()); runpy.run_path(str(root / '.codex' / 'hooks' / 'pre_commit_checks.py'), run_name='__main__')\"", + "timeout": 600, + "statusMessage": "Running pre-commit checks" + } + ] + }, + { + "matcher": "^(apply_patch|Edit|Write)$", + "hooks": [ + { + "type": "command", + "command": "python -c \"import pathlib, runpy, subprocess; root = pathlib.Path(subprocess.check_output(['git', 'rev-parse', '--show-toplevel'], text=True).strip()); runpy.run_path(str(root / '.codex' / 'hooks' / 'tdd-guard.py'), run_name='__main__')\"", + "timeout": 30, + "statusMessage": "Checking TDD guard" + } + ] + } + ] + } +} diff --git a/Coding/Codex/.codex/hooks/pre_commit_checks.py b/Coding/Codex-tsjs/.codex/hooks/pre_commit_checks.py similarity index 100% rename from Coding/Codex/.codex/hooks/pre_commit_checks.py rename to Coding/Codex-tsjs/.codex/hooks/pre_commit_checks.py diff --git a/Coding/Codex/.codex/hooks/tdd-guard.py b/Coding/Codex-tsjs/.codex/hooks/tdd-guard.py similarity index 100% rename from Coding/Codex/.codex/hooks/tdd-guard.py rename to Coding/Codex-tsjs/.codex/hooks/tdd-guard.py diff --git a/Coding/Codex/.agents/skills/harness-review/SKILL.md b/Coding/Codex-tsjs/.codex/skills/harness-review/SKILL.md similarity index 100% rename from Coding/Codex/.agents/skills/harness-review/SKILL.md rename to Coding/Codex-tsjs/.codex/skills/harness-review/SKILL.md diff --git a/Coding/Codex-tsjs/.codex/skills/harness-review/agents/openai.yaml b/Coding/Codex-tsjs/.codex/skills/harness-review/agents/openai.yaml new file mode 100644 index 0000000..9af296a --- /dev/null +++ b/Coding/Codex-tsjs/.codex/skills/harness-review/agents/openai.yaml @@ -0,0 +1,4 @@ +interface: + display_name: "Harness Review" + short_description: "Review Harness changes safely" + default_prompt: "Use $harness-review to review Harness repository changes." diff --git a/Coding/Codex/.agents/skills/harness-workflow/SKILL.md b/Coding/Codex-tsjs/.codex/skills/harness-workflow/SKILL.md similarity index 100% rename from Coding/Codex/.agents/skills/harness-workflow/SKILL.md rename to Coding/Codex-tsjs/.codex/skills/harness-workflow/SKILL.md diff --git a/Coding/Codex-tsjs/.codex/skills/harness-workflow/agents/openai.yaml b/Coding/Codex-tsjs/.codex/skills/harness-workflow/agents/openai.yaml new file mode 100644 index 0000000..3a671bf --- /dev/null +++ b/Coding/Codex-tsjs/.codex/skills/harness-workflow/agents/openai.yaml @@ -0,0 +1,4 @@ +interface: + display_name: "Harness Workflow" + short_description: "Plan staged Harness workflow steps" + default_prompt: "Use $harness-workflow to plan Harness phases and step files." diff --git a/Coding/Codex/.gitignore b/Coding/Codex-tsjs/.gitignore similarity index 100% rename from Coding/Codex/.gitignore rename to Coding/Codex-tsjs/.gitignore diff --git a/Coding/Codex/AGENTS.md b/Coding/Codex-tsjs/AGENTS.md similarity index 100% rename from Coding/Codex/AGENTS.md rename to Coding/Codex-tsjs/AGENTS.md diff --git a/Coding/Codex/docs/ADR.md b/Coding/Codex-tsjs/docs/ADR.md similarity index 100% rename from Coding/Codex/docs/ADR.md rename to Coding/Codex-tsjs/docs/ADR.md diff --git a/Coding/Codex/docs/ARCHITECTURE.md b/Coding/Codex-tsjs/docs/ARCHITECTURE.md similarity index 100% rename from Coding/Codex/docs/ARCHITECTURE.md rename to Coding/Codex-tsjs/docs/ARCHITECTURE.md diff --git a/Coding/Codex/docs/PRD.md b/Coding/Codex-tsjs/docs/PRD.md similarity index 100% rename from Coding/Codex/docs/PRD.md rename to Coding/Codex-tsjs/docs/PRD.md diff --git a/Coding/Codex-tsjs/docs/UI_GUIDE.md b/Coding/Codex-tsjs/docs/UI_GUIDE.md new file mode 100644 index 0000000..c3d280f --- /dev/null +++ b/Coding/Codex-tsjs/docs/UI_GUIDE.md @@ -0,0 +1,76 @@ +# UI 디자인 가이드 + +## 디자인 원칙 +1. {원칙 1 — 예: "도구처럼 보여야 한다. 마케팅 페이지가 아니라 매일 쓰는 대시보드."} +2. {원칙 2} +3. {원칙 3} + +## AI 슬롭 안티패턴 — 하지 마라 +| 금지 사항 | 이유 | +|-----------|------| +| backdrop-filter: blur() | glass morphism은 AI 템플릿의 가장 흔한 징후 | +| gradient-text (배경 그라데이션 텍스트) | AI가 만든 SaaS 랜딩의 1번 특징 | +| "Powered by AI" 배지 | 기능이 아니라 장식. 사용자에게 가치 없음 | +| box-shadow 글로우 애니메이션 | 네온 글로우 = AI 슬롭 | +| 보라/인디고 브랜드 색상 | "AI = 보라색" 클리셰 | +| 모든 카드에 동일한 rounded-2xl | 균일한 둥근 모서리는 템플릿 느낌 | +| 배경 gradient orb (blur-3xl 원형) | 모든 AI 랜딩 페이지에 있는 장식 | + +## 색상 +### 배경 +| 용도 | 값 | +|------|------| +| 페이지 | {예: #0a0a0a} | +| 카드 | {예: #141414} | + +### 텍스트 +| 용도 | 값 | +|------|------| +| 주 텍스트 | {예: text-white} | +| 본문 | {예: text-neutral-300} | +| 보조 | {예: text-neutral-400} | +| 비활성 | {예: text-neutral-500} | + +### 데이터/시맨틱 색상 +| 용도 | 값 | +|------|------| +| {긍정/성공} | {예: #22c55e} | +| {부정/에러} | {예: #ef4444} | +| {중립/기본} | {예: #525252} | + +## 컴포넌트 +### 카드 +``` +{예: rounded-lg bg-[#141414] border border-neutral-800 p-6} +``` + +### 버튼 +``` +Primary: {예: rounded-lg bg-white text-black hover:bg-neutral-200} +Text: {예: text-neutral-500 hover:text-neutral-300} +``` + +### 입력 필드 +``` +{예: rounded-lg bg-neutral-900 border border-neutral-800 px-4 py-3} +``` + +## 레이아웃 +- 전체 너비: {예: max-w-5xl} +- 정렬: {예: 좌측 정렬 기본. 중앙 정렬 금지} +- 간격: {예: gap-3~4, 섹션 간 space-y-8} + +## 타이포그래피 +| 용도 | 스타일 | +|------|--------| +| 페이지 제목 | {예: text-4xl font-semibold text-white} | +| 카드 제목 | {예: text-sm font-medium text-neutral-400} | +| 본문 | {예: text-sm text-neutral-300 leading-relaxed} | + +## 애니메이션 +- {허용할 애니메이션만 나열. 예: fade-in (0.4s), slide-up (0.5s)} +- {그 외 모든 애니메이션 금지} + +## 아이콘 +- {예: SVG 인라인, strokeWidth 1.5} +- {예: 아이콘 컨테이너(둥근 배경 박스)로 감싸지 않는다} diff --git a/Coding/Codex-tsjs/scripts/execute.py b/Coding/Codex-tsjs/scripts/execute.py new file mode 100644 index 0000000..8016252 --- /dev/null +++ b/Coding/Codex-tsjs/scripts/execute.py @@ -0,0 +1,417 @@ +#!/usr/bin/env python3 +""" +Harness Step Executor — phase 내 step을 순차 실행하고 자가 교정한다. + +Usage: + python scripts/execute.py [--push] +""" + +import argparse +import contextlib +import json +import os +import subprocess +import sys +import threading +import time +import types +from datetime import datetime, timezone, timedelta +from pathlib import Path +from typing import Optional + +ROOT = Path(__file__).resolve().parent.parent + + +@contextlib.contextmanager +def progress_indicator(label: str): + """터미널 진행 표시기. with 문으로 사용하며 .elapsed 로 경과 시간을 읽는다.""" + frames = "◐◓◑◒" + stop = threading.Event() + t0 = time.monotonic() + + def _animate(): + idx = 0 + while not stop.wait(0.12): + sec = int(time.monotonic() - t0) + sys.stderr.write(f"\r{frames[idx % len(frames)]} {label} [{sec}s]") + sys.stderr.flush() + idx += 1 + sys.stderr.write("\r" + " " * (len(label) + 20) + "\r") + sys.stderr.flush() + + th = threading.Thread(target=_animate, daemon=True) + th.start() + info = types.SimpleNamespace(elapsed=0.0) + try: + yield info + finally: + stop.set() + th.join() + info.elapsed = time.monotonic() - t0 + + +class StepExecutor: + """Phase 디렉토리 안의 step들을 순차 실행하는 하네스.""" + + MAX_RETRIES = 3 + FEAT_MSG = "feat({phase}): step {num} — {name}" + CHORE_MSG = "chore({phase}): step {num} output" + TZ = timezone(timedelta(hours=9)) + + def __init__(self, phase_dir_name: str, *, auto_push: bool = False): + self._root = str(ROOT) + self._phases_dir = ROOT / "phases" + self._phase_dir = self._phases_dir / phase_dir_name + self._phase_dir_name = phase_dir_name + self._top_index_file = self._phases_dir / "index.json" + self._auto_push = auto_push + + if not self._phase_dir.is_dir(): + print(f"ERROR: {self._phase_dir} not found") + sys.exit(1) + + self._index_file = self._phase_dir / "index.json" + if not self._index_file.exists(): + print(f"ERROR: {self._index_file} not found") + sys.exit(1) + + idx = self._read_json(self._index_file) + self._project = idx.get("project", "project") + self._phase_name = idx.get("phase", phase_dir_name) + self._total = len(idx["steps"]) + + def run(self): + self._print_header() + self._check_blockers() + self._checkout_branch() + guardrails = self._load_guardrails() + self._ensure_created_at() + self._execute_all_steps(guardrails) + self._finalize() + + # --- timestamps --- + + def _stamp(self) -> str: + return datetime.now(self.TZ).strftime("%Y-%m-%dT%H:%M:%S%z") + + # --- JSON I/O --- + + @staticmethod + def _read_json(p: Path) -> dict: + return json.loads(p.read_text(encoding="utf-8")) + + @staticmethod + def _write_json(p: Path, data: dict): + p.write_text(json.dumps(data, indent=2, ensure_ascii=False), encoding="utf-8") + + # --- git --- + + def _run_git(self, *args) -> subprocess.CompletedProcess: + cmd = ["git"] + list(args) + return subprocess.run(cmd, cwd=self._root, capture_output=True, text=True) + + def _checkout_branch(self): + branch = f"feat-{self._phase_name}" + + r = self._run_git("rev-parse", "--abbrev-ref", "HEAD") + if r.returncode != 0: + print(f" ERROR: git을 사용할 수 없거나 git repo가 아닙니다.") + print(f" {r.stderr.strip()}") + sys.exit(1) + + if r.stdout.strip() == branch: + return + + r = self._run_git("rev-parse", "--verify", branch) + r = self._run_git("checkout", branch) if r.returncode == 0 else self._run_git("checkout", "-b", branch) + + if r.returncode != 0: + print(f" ERROR: 브랜치 '{branch}' checkout 실패.") + print(f" {r.stderr.strip()}") + print(f" Hint: 변경사항을 stash하거나 commit한 후 다시 시도하세요.") + sys.exit(1) + + print(f" Branch: {branch}") + + def _commit_step(self, step_num: int, step_name: str): + output_rel = f"phases/{self._phase_dir_name}/step{step_num}-output.json" + index_rel = f"phases/{self._phase_dir_name}/index.json" + + self._run_git("add", "-A") + self._run_git("reset", "HEAD", "--", output_rel) + self._run_git("reset", "HEAD", "--", index_rel) + + if self._run_git("diff", "--cached", "--quiet").returncode != 0: + msg = self.FEAT_MSG.format(phase=self._phase_name, num=step_num, name=step_name) + r = self._run_git("commit", "-m", msg) + if r.returncode == 0: + print(f" Commit: {msg}") + else: + print(f" WARN: 코드 커밋 실패: {r.stderr.strip()}") + + self._run_git("add", "-A") + if self._run_git("diff", "--cached", "--quiet").returncode != 0: + msg = self.CHORE_MSG.format(phase=self._phase_name, num=step_num) + r = self._run_git("commit", "-m", msg) + if r.returncode != 0: + print(f" WARN: housekeeping 커밋 실패: {r.stderr.strip()}") + + # --- top-level index --- + + def _update_top_index(self, status: str): + if not self._top_index_file.exists(): + return + top = self._read_json(self._top_index_file) + ts = self._stamp() + for phase in top.get("phases", []): + if phase.get("dir") == self._phase_dir_name: + phase["status"] = status + ts_key = {"completed": "completed_at", "error": "failed_at", "blocked": "blocked_at"}.get(status) + if ts_key: + phase[ts_key] = ts + break + self._write_json(self._top_index_file, top) + + # --- guardrails & context --- + + def _load_guardrails(self) -> str: + sections = [] + agents_md = ROOT / "AGENTS.md" + if agents_md.exists(): + sections.append(f"## 프로젝트 규칙 (AGENTS.md)\n\n{agents_md.read_text(encoding='utf-8')}") + docs_dir = ROOT / "docs" + if docs_dir.is_dir(): + for doc in sorted(docs_dir.glob("*.md")): + sections.append(f"## {doc.stem}\n\n{doc.read_text(encoding='utf-8')}") + return "\n\n---\n\n".join(sections) if sections else "" + + @staticmethod + def _build_step_context(index: dict) -> str: + lines = [ + f"- Step {s['step']} ({s['name']}): {s['summary']}" + for s in index["steps"] + if s["status"] == "completed" and s.get("summary") + ] + if not lines: + return "" + return "## 이전 Step 산출물\n\n" + "\n".join(lines) + "\n\n" + + def _build_preamble(self, guardrails: str, step_context: str, + prev_error: Optional[str] = None) -> str: + commit_example = self.FEAT_MSG.format( + phase=self._phase_name, num="N", name="" + ) + retry_section = "" + if prev_error: + retry_section = ( + f"\n## ⚠ 이전 시도 실패 — 아래 에러를 반드시 참고하여 수정하라\n\n" + f"{prev_error}\n\n---\n\n" + ) + return ( + f"당신은 {self._project} 프로젝트의 개발자입니다. 아래 step을 수행하세요.\n\n" + f"{guardrails}\n\n---\n\n" + f"{step_context}{retry_section}" + f"## 작업 규칙\n\n" + f"1. 이전 step에서 작성된 코드를 확인하고 일관성을 유지하라.\n" + f"2. 이 step에 명시된 작업만 수행하라. 추가 기능이나 파일을 만들지 마라.\n" + f"3. 기존 테스트를 깨뜨리지 마라.\n" + f"4. AC(Acceptance Criteria) 검증을 직접 실행하라.\n" + f"5. /phases/{self._phase_dir_name}/index.json의 해당 step status를 업데이트하라:\n" + f" - AC 통과 → \"completed\" + \"summary\" 필드에 이 step의 산출물을 한 줄로 요약\n" + f" - {self.MAX_RETRIES}회 수정 시도 후에도 실패 → \"error\" + \"error_message\" 기록\n" + f" - 사용자 개입이 필요한 경우 (API 키, 인증, 수동 설정 등) → \"blocked\" + \"blocked_reason\" 기록 후 즉시 중단\n" + f"6. 모든 변경사항을 커밋하라:\n" + f" {commit_example}\n\n---\n\n" + ) + + # --- Codex 호출 --- + + def _invoke_codex(self, step: dict, preamble: str) -> dict: + step_num, step_name = step["step"], step["name"] + step_file = self._phase_dir / f"step{step_num}.md" + + if not step_file.exists(): + print(f" ERROR: {step_file} not found") + sys.exit(1) + + prompt = preamble + step_file.read_text(encoding="utf-8") + result = subprocess.run( + ["codex", "exec", "--dangerously-bypass-approvals-and-sandbox", "--json", prompt], + cwd=self._root, capture_output=True, text=True, timeout=1800, + ) + + if result.returncode != 0: + print(f"\n WARN: Codex가 비정상 종료됨 (code {result.returncode})") + if result.stderr: + print(f" stderr: {result.stderr[:500]}") + + output = { + "step": step_num, "name": step_name, + "exitCode": result.returncode, + "stdout": result.stdout, "stderr": result.stderr, + } + out_path = self._phase_dir / f"step{step_num}-output.json" + with open(out_path, "w", encoding="utf-8") as f: + json.dump(output, f, indent=2, ensure_ascii=False) + + return output + + # --- 헤더 & 검증 --- + + def _print_header(self): + print(f"\n{'='*60}") + print(f" Harness Step Executor") + print(f" Phase: {self._phase_name} | Steps: {self._total}") + if self._auto_push: + print(f" Auto-push: enabled") + print(f"{'='*60}") + + def _check_blockers(self): + index = self._read_json(self._index_file) + for s in reversed(index["steps"]): + if s["status"] == "error": + print(f"\n ✗ Step {s['step']} ({s['name']}) failed.") + print(f" Error: {s.get('error_message', 'unknown')}") + print(f" Fix and reset status to 'pending' to retry.") + sys.exit(1) + if s["status"] == "blocked": + print(f"\n ⏸ Step {s['step']} ({s['name']}) blocked.") + print(f" Reason: {s.get('blocked_reason', 'unknown')}") + print(f" Resolve and reset status to 'pending' to retry.") + sys.exit(2) + if s["status"] != "pending": + break + + def _ensure_created_at(self): + index = self._read_json(self._index_file) + if "created_at" not in index: + index["created_at"] = self._stamp() + self._write_json(self._index_file, index) + + # --- 실행 루프 --- + + def _execute_single_step(self, step: dict, guardrails: str) -> bool: + """단일 step 실행 (재시도 포함). 완료되면 True, 실패/차단이면 False.""" + step_num, step_name = step["step"], step["name"] + done = sum(1 for s in self._read_json(self._index_file)["steps"] if s["status"] == "completed") + prev_error = None + + for attempt in range(1, self.MAX_RETRIES + 1): + index = self._read_json(self._index_file) + step_context = self._build_step_context(index) + preamble = self._build_preamble(guardrails, step_context, prev_error) + + tag = f"Step {step_num}/{self._total - 1} ({done} done): {step_name}" + if attempt > 1: + tag += f" [retry {attempt}/{self.MAX_RETRIES}]" + + with progress_indicator(tag) as pi: + self._invoke_codex(step, preamble) + elapsed = int(pi.elapsed) + + index = self._read_json(self._index_file) + status = next((s.get("status", "pending") for s in index["steps"] if s["step"] == step_num), "pending") + ts = self._stamp() + + if status == "completed": + for s in index["steps"]: + if s["step"] == step_num: + s["completed_at"] = ts + self._write_json(self._index_file, index) + self._commit_step(step_num, step_name) + print(f" ✓ Step {step_num}: {step_name} [{elapsed}s]") + return True + + if status == "blocked": + for s in index["steps"]: + if s["step"] == step_num: + s["blocked_at"] = ts + self._write_json(self._index_file, index) + reason = next((s.get("blocked_reason", "") for s in index["steps"] if s["step"] == step_num), "") + print(f" ⏸ Step {step_num}: {step_name} blocked [{elapsed}s]") + print(f" Reason: {reason}") + self._update_top_index("blocked") + sys.exit(2) + + err_msg = next( + (s.get("error_message", "Step did not update status") for s in index["steps"] if s["step"] == step_num), + "Step did not update status", + ) + + if attempt < self.MAX_RETRIES: + for s in index["steps"]: + if s["step"] == step_num: + s["status"] = "pending" + s.pop("error_message", None) + self._write_json(self._index_file, index) + prev_error = err_msg + print(f" ↻ Step {step_num}: retry {attempt}/{self.MAX_RETRIES} — {err_msg}") + else: + for s in index["steps"]: + if s["step"] == step_num: + s["status"] = "error" + s["error_message"] = f"[{self.MAX_RETRIES}회 시도 후 실패] {err_msg}" + s["failed_at"] = ts + self._write_json(self._index_file, index) + self._commit_step(step_num, step_name) + print(f" ✗ Step {step_num}: {step_name} failed after {self.MAX_RETRIES} attempts [{elapsed}s]") + print(f" Error: {err_msg}") + self._update_top_index("error") + sys.exit(1) + + return False # unreachable + + def _execute_all_steps(self, guardrails: str): + while True: + index = self._read_json(self._index_file) + pending = next((s for s in index["steps"] if s["status"] == "pending"), None) + if pending is None: + print("\n All steps completed!") + return + + step_num = pending["step"] + for s in index["steps"]: + if s["step"] == step_num and "started_at" not in s: + s["started_at"] = self._stamp() + self._write_json(self._index_file, index) + break + + self._execute_single_step(pending, guardrails) + + def _finalize(self): + index = self._read_json(self._index_file) + index["completed_at"] = self._stamp() + self._write_json(self._index_file, index) + self._update_top_index("completed") + + self._run_git("add", "-A") + if self._run_git("diff", "--cached", "--quiet").returncode != 0: + msg = f"chore({self._phase_name}): mark phase completed" + r = self._run_git("commit", "-m", msg) + if r.returncode == 0: + print(f" ✓ {msg}") + + if self._auto_push: + branch = f"feat-{self._phase_name}" + r = self._run_git("push", "-u", "origin", branch) + if r.returncode != 0: + print(f"\n ERROR: git push 실패: {r.stderr.strip()}") + sys.exit(1) + print(f" ✓ Pushed to origin/{branch}") + + print(f"\n{'='*60}") + print(f" Phase '{self._phase_name}' completed!") + print(f"{'='*60}") + + +def main(): + parser = argparse.ArgumentParser(description="Harness Step Executor") + parser.add_argument("phase_dir", help="Phase directory name (e.g. 0-mvp)") + parser.add_argument("--push", action="store_true", help="Push branch after completion") + args = parser.parse_args() + + StepExecutor(args.phase_dir, auto_push=args.push).run() + + +if __name__ == "__main__": + main() diff --git a/Skills/Codex/.system/.codex-system-skills.marker b/Skills/Codex/.system/.codex-system-skills.marker new file mode 100644 index 0000000..128e9dd --- /dev/null +++ b/Skills/Codex/.system/.codex-system-skills.marker @@ -0,0 +1 @@ +f13290a7889cc9e1 diff --git a/Skills/Codex/.system/imagegen/LICENSE.txt b/Skills/Codex/.system/imagegen/LICENSE.txt new file mode 100644 index 0000000..13e25df --- /dev/null +++ b/Skills/Codex/.system/imagegen/LICENSE.txt @@ -0,0 +1,201 @@ +Apache License +Version 2.0, January 2004 +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf of + any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don\'t include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/Skills/Codex/.system/imagegen/SKILL.md b/Skills/Codex/.system/imagegen/SKILL.md new file mode 100644 index 0000000..4285e5e --- /dev/null +++ b/Skills/Codex/.system/imagegen/SKILL.md @@ -0,0 +1,356 @@ +--- +name: "imagegen" +description: "Generate or edit raster images when the task benefits from AI-created bitmap visuals such as photos, illustrations, textures, sprites, mockups, or transparent-background cutouts. Use when Codex should create a brand-new image, transform an existing image, or derive visual variants from references, and the output should be a bitmap asset rather than repo-native code or vector. Do not use when the task is better handled by editing existing SVG/vector/code-native assets, extending an established icon or logo system, or building the visual directly in HTML/CSS/canvas." +--- + +# Image Generation Skill + +Generates or edits images for the current project (for example website assets, game assets, UI mockups, product mockups, wireframes, logo design, photorealistic images, or infographics). + +## Top-level modes and rules + +This skill has exactly two top-level modes: + +- **Default built-in tool mode (preferred):** built-in `image_gen` tool for normal image generation, editing, and simple transparent-image requests. Does not require `OPENAI_API_KEY`. +- **Fallback CLI mode:** `scripts/image_gen.py` CLI. Use when the user explicitly asks for the CLI/API/model path, or after the user explicitly confirms a true model-native transparency fallback with `gpt-image-1.5`. Requires `OPENAI_API_KEY`. + +Within CLI fallback, the CLI exposes three subcommands: + +- `generate` +- `edit` +- `generate-batch` + +Rules: +- Use the built-in `image_gen` tool by default for normal image generation and editing requests. +- Do not switch to CLI fallback for ordinary quality, size, or file-path control. +- If the user explicitly asks for a transparent image/background, stay on built-in `image_gen` first: prompt for a flat removable chroma-key background, then remove it locally with the installed helper at `$CODEX_HOME/skills/.system/imagegen/scripts/remove_chroma_key.py`. +- Never silently switch from built-in `image_gen` or CLI `gpt-image-2` to CLI `gpt-image-1.5`. Treat this as a model/path downgrade and ask the user before doing it, unless the user has already explicitly requested `gpt-image-1.5`, `scripts/image_gen.py`, or CLI fallback. +- If a transparent request appears too complex for clean chroma-key removal, asks for true/native transparency, or local removal fails validation, explain that true transparency requires CLI `gpt-image-1.5 --background transparent --output-format png` because `gpt-image-2` does not support `background=transparent`, then ask whether to proceed. Run the CLI fallback only after the user confirms. +- The word `batch` by itself does not mean CLI fallback. If the user asks for many assets or says to batch-generate assets without explicitly asking for CLI/API/model controls, stay on the built-in path and issue one built-in call per requested asset or variant. +- If the built-in tool fails or is unavailable, tell the user the CLI fallback exists and that it requires `OPENAI_API_KEY`. Proceed only if the user explicitly asks for that fallback. +- If the user explicitly asks for CLI mode, use the bundled `scripts/image_gen.py` workflow. Do not create one-off SDK runners. +- Never modify `scripts/image_gen.py`. If something is missing, ask the user before doing anything else. + +Built-in save-path policy: +- In built-in tool mode, Codex saves generated images under `$CODEX_HOME/*` by default. +- Do not describe or rely on OS temp as the default built-in destination. +- Do not describe or rely on a destination-path argument (if any) on the built-in `image_gen` tool. If a specific location is needed, generate first and then move or copy the selected output from `$CODEX_HOME/generated_images/...`. +- Save-path precedence in built-in mode: + 1. If the user names a destination, move or copy the selected output there. + 2. If the image is meant for the current project, move or copy the final selected image into the workspace before finishing. + 3. If the image is only for preview or brainstorming, render it inline; the underlying file can remain at the default `$CODEX_HOME/*` path. +- Never leave a project-referenced asset only at the default `$CODEX_HOME/*` path. +- Do not overwrite an existing asset unless the user explicitly asked for replacement; otherwise create a sibling versioned filename such as `hero-v2.png` or `item-icon-edited.png`. + +Shared prompt guidance for both modes lives in `references/prompting.md` and `references/sample-prompts.md`. + +Fallback-only docs/resources for CLI mode: +- `references/cli.md` +- `references/image-api.md` +- `references/codex-network.md` +- `scripts/image_gen.py` + +Local post-processing helper: +- `$CODEX_HOME/skills/.system/imagegen/scripts/remove_chroma_key.py`: removes a flat chroma-key background from a generated image and writes a PNG/WebP with alpha. Prefer auto-key sampling, soft matte, and despill for antialiased edges. + +## When to use +- Generate a new image (concept art, product shot, cover, website hero) +- Generate a new image using one or more reference images for style, composition, or mood +- Edit an existing image (inpainting, lighting or weather transformations, background replacement, object removal, compositing, transparent background) +- Produce many assets or variants for one task + +## When not to use +- Extending or matching an existing SVG/vector icon set, logo system, or illustration library inside the repo +- Creating simple shapes, diagrams, wireframes, or icons that are better produced directly in SVG, HTML/CSS, or canvas +- Making a small project-local asset edit when the source file already exists in an editable native format +- Any task where the user clearly wants deterministic code-native output instead of a generated bitmap + +## Decision tree + +Think about two separate questions: + +1. **Intent:** is this a new image or an edit of an existing image? +2. **Execution strategy:** is this one asset or many assets/variants? + +Intent: +- If the user wants to modify an existing image while preserving parts of it, treat the request as **edit**. +- If the user provides images only as references for style, composition, mood, or subject guidance, treat the request as **generate**. +- If the user provides no images, treat the request as **generate**. + +Built-in edit semantics: +- Built-in edit mode is for images already visible in the conversation context, such as attached images or images generated earlier in the thread. +- If the user wants to edit a local image file with the built-in tool, first load it with built-in `view_image` tool so the image is visible in the conversation context, then proceed with the built-in edit flow. +- Do not promise arbitrary filesystem-path editing through the built-in tool. +- If a local file still needs direct file-path control, masks, or other explicit CLI-only parameters, use the explicit CLI fallback only when the user asks for it. +- For edits, preserve invariants aggressively and save non-destructively by default. + +Execution strategy: +- In the built-in default path, produce many assets or variants by issuing one `image_gen` call per requested asset or variant. +- In the CLI fallback path, use the CLI `generate-batch` subcommand only when the user explicitly chose CLI mode and needs many prompts/assets. +- For many distinct assets, do not use `n` as a substitute for separate prompts. `n` is for variants of one prompt; distinct assets need distinct built-in calls or distinct CLI `generate-batch` jobs. + +Assume the user wants a new image unless they clearly ask to change an existing one. + +## Workflow +1. Decide the top-level mode: built-in by default, including simple transparent-output requests; fallback CLI only if explicitly requested or after the user explicitly confirms a transparent-output fallback. +2. Decide the intent: `generate` or `edit`. +3. Decide whether the output is preview-only or meant to be consumed by the current project. +4. Decide the execution strategy: single asset vs repeated built-in calls vs CLI `generate-batch`. +5. Collect inputs up front: prompt(s), exact text (verbatim), constraints/avoid list, and any input images. +6. For every input image, label its role explicitly: + - reference image + - edit target + - supporting insert/style/compositing input +7. If the edit target is only on the local filesystem and you are staying on the built-in path, inspect it with `view_image` first so the image is available in conversation context. +8. If the user asked for a photo, illustration, sprite, product image, banner, or other explicitly raster-style asset, use `image_gen` rather than substituting SVG/HTML/CSS placeholders. If the request is for an icon, logo, or UI graphic that should match existing repo-native SVG/vector/code assets, prefer editing those directly instead. +9. Augment the prompt based on specificity: + - If the user's prompt is already specific and detailed, normalize it into a clear spec without adding creative requirements. + - If the user's prompt is generic, add tasteful augmentation only when it materially improves output quality. +10. Use the built-in `image_gen` tool by default. +11. For transparent-output requests, follow the transparent image guidance below: generate with built-in `image_gen` on a flat chroma-key background, copy the selected output into the workspace or `tmp/imagegen/`, run the installed `$CODEX_HOME/skills/.system/imagegen/scripts/remove_chroma_key.py` helper, and validate the alpha result before using it. If this path looks unsuitable or fails, ask before switching to CLI `gpt-image-1.5`. +12. Inspect outputs and validate: subject, style, composition, text accuracy, and invariants/avoid items. +13. Iterate with a single targeted change, then re-check. +14. For preview-only work, render the image inline; the underlying file may remain at the default `$CODEX_HOME/generated_images/...` path. +15. For project-bound work, move or copy the selected artifact into the workspace and update any consuming code or references. Never leave a project-referenced asset only at the default `$CODEX_HOME/generated_images/...` path. +16. For batches or multi-asset requests, persist every requested deliverable final in the workspace unless the user explicitly asked to keep outputs preview-only. Discarded variants do not need to be kept unless requested. +17. If the user explicitly chooses or confirms the CLI fallback, then use the fallback-only docs for model, quality, size, `input_fidelity`, masks, output format, output paths, and network setup. +18. Always report the final saved path(s) for any workspace-bound asset(s), plus the final prompt or prompt set and whether the built-in tool or fallback CLI mode was used. + +## Transparent image requests + +Transparent-image requests still use built-in `image_gen` first. Because the built-in tool does not expose a true transparent-background control, create a removable chroma-key source image and then convert the key color to alpha locally. + +Default sequence: +1. Use built-in `image_gen` to generate the requested subject on a perfectly flat solid chroma-key background. +2. Choose a key color that is unlikely to appear in the subject: default `#00ff00`, use `#ff00ff` for green subjects, and avoid `#0000ff` for blue subjects. +3. After generation, move or copy the selected source image from `$CODEX_HOME/generated_images/...` into the workspace or `tmp/imagegen/`. +4. Run the installed helper path, not a project-relative script path: + ```bash + python "${CODEX_HOME:-$HOME/.codex}/skills/.system/imagegen/scripts/remove_chroma_key.py" \ + --input \ + --out \ + --auto-key border \ + --soft-matte \ + --transparent-threshold 12 \ + --opaque-threshold 220 \ + --despill + ``` +5. Validate that the output has an alpha channel, transparent corners, plausible subject coverage, and no obvious key-color fringe. If a thin fringe remains, retry once with `--edge-contract 1`; use `--edge-feather 0.25` only when the edge is visibly stair-stepped and the subject is not shiny or reflective. +6. Save the final alpha PNG/WebP in the project if the asset is project-bound. Never leave a project-referenced transparent asset only under `$CODEX_HOME/*`. + +Prompt transparent requests like this: + +```text +Create the requested subject on a perfectly flat solid #00ff00 chroma-key background for background removal. +The background must be one uniform color with no shadows, gradients, texture, reflections, floor plane, or lighting variation. +Keep the subject fully separated from the background with crisp edges and generous padding. +Do not use #00ff00 anywhere in the subject. +No cast shadow, no contact shadow, no reflection, no watermark, and no text unless explicitly requested. +``` + +Do not automatically use CLI `gpt-image-1.5 --background transparent --output-format png` instead of chroma keying. Ask the user first when the user asks for true/native transparency, when local removal fails validation, or when the requested image is complex: hair, fur, feathers, smoke, glass, liquids, translucent materials, reflective objects, soft shadows, realistic product grounding, or subject colors that conflict with all practical key colors. + +Use a concise confirmation like: + +```text +This likely needs true native transparency. The default built-in path uses a chroma-key background plus local removal, but true transparency requires the CLI fallback with gpt-image-1.5 because gpt-image-2 does not support background=transparent. It also requires OPENAI_API_KEY. Should I proceed with that CLI fallback? +``` + +## Prompt augmentation + +Reformat user prompts into a structured, production-oriented spec. Make the user's goal clearer and more actionable, but do not blindly add detail. + +Treat this as prompt-shaping guidance, not a closed schema. Use only the lines that help, and add a short extra labeled line when it materially improves clarity. + +### Specificity policy + +Use the user's prompt specificity to decide how much augmentation is appropriate: + +- If the prompt is already specific and detailed, preserve that specificity and only normalize/structure it. +- If the prompt is generic, you may add tasteful augmentation when it will materially improve the result. + +Allowed augmentations: +- composition or framing hints +- polish level or intended-use hints +- practical layout guidance +- reasonable scene concreteness that supports the stated request + +Not allowed augmentations: +- extra characters or objects that are not implied by the request +- brand names, slogans, palettes, or narrative beats that are not implied +- arbitrary side-specific placement unless the surrounding layout supports it + +## Use-case taxonomy (exact slugs) + +Classify each request into one of these buckets and keep the slug consistent across prompts and references. + +Generate: +- photorealistic-natural — candid/editorial lifestyle scenes with real texture and natural lighting. +- product-mockup — product/packaging shots, catalog imagery, merch concepts. +- ui-mockup — app/web interface mockups and wireframes; specify the desired fidelity. +- infographic-diagram — diagrams/infographics with structured layout and text. +- scientific-educational — classroom explainers, scientific diagrams, and learning visuals with required labels and accuracy constraints. +- ads-marketing — campaign concepts and ad creatives with audience, brand position, scene, and exact tagline/copy. +- productivity-visual — slide, chart, workflow, and data-heavy business visuals. +- logo-brand — logo/mark exploration, vector-friendly. +- illustration-story — comics, children’s book art, narrative scenes. +- stylized-concept — style-driven concept art, 3D/stylized renders. +- historical-scene — period-accurate/world-knowledge scenes. + +Edit: +- text-localization — translate/replace in-image text, preserve layout. +- identity-preserve — try-on, person-in-scene; lock face/body/pose. +- precise-object-edit — remove/replace a specific element (including interior swaps). +- lighting-weather — time-of-day/season/atmosphere changes only. +- background-extraction — transparent background / clean cutout. Use built-in `image_gen` with chroma-key removal first for simple opaque subjects; ask before using CLI true transparency for complex subjects. +- style-transfer — apply reference style while changing subject/scene. +- compositing — multi-image insert/merge with matched lighting/perspective. +- sketch-to-render — drawing/line art to photoreal render. + +## Shared prompt schema + +Use the following labeled spec as shared prompt scaffolding for both top-level modes: + +```text +Use case: +Asset type: +Primary request: +Input images: (optional) +Scene/backdrop: +Subject:
+Style/medium: +Composition/framing: +Lighting/mood: +Color palette: +Materials/textures: +Text (verbatim): "" +Constraints: +Avoid: +``` + +Notes: +- `Asset type` and `Input images` are prompt scaffolding, not dedicated CLI flags. +- `Scene/backdrop` refers to the visual setting. It is not the same as the fallback CLI `background` parameter, which controls output transparency behavior. +- Fallback-only execution notes such as `Quality:`, `Input fidelity:`, masks, output format, and output paths belong in the CLI path only. Do not treat them as built-in `image_gen` tool arguments. + +Augmentation rules: +- Keep it short. +- Add only the details needed to improve the prompt materially. +- For edits, explicitly list invariants (`change only X; keep Y unchanged`). +- If any critical detail is missing and blocks success, ask a question; otherwise proceed. + +## Examples + +### Generation example (hero image) +```text +Use case: product-mockup +Asset type: landing page hero +Primary request: a minimal hero image of a ceramic coffee mug +Style/medium: clean product photography +Composition/framing: wide composition with usable negative space for page copy if needed +Lighting/mood: soft studio lighting +Constraints: no logos, no text, no watermark +``` + +### Edit example (invariants) +```text +Use case: precise-object-edit +Asset type: product photo background replacement +Primary request: replace only the background with a warm sunset gradient +Constraints: change only the background; keep the product and its edges unchanged; no text; no watermark +``` + +## Prompting best practices +- Structure prompt as scene/backdrop -> subject -> details -> constraints. +- Include intended use (ad, UI mock, infographic) to set the mode and polish level. +- Use camera/composition language for photorealism. +- Only use SVG/vector stand-ins when the user explicitly asked for vector output or a non-image placeholder. +- Quote exact text and specify typography + placement. +- For tricky words, spell them letter-by-letter and require verbatim rendering. +- For multi-image inputs, reference images by index and describe how they should be used. +- For edits, repeat invariants every iteration to reduce drift. +- Iterate with single-change follow-ups. +- If the prompt is generic, add only the extra detail that will materially help. +- If the prompt is already detailed, normalize it instead of expanding it. +- For CLI fallback only, see `references/cli.md` and `references/image-api.md` for model, `quality`, `input_fidelity`, masks, output format, and output-path guidance. +- For transparent images, use the built-in-first chroma-key workflow unless the request is complex enough to need true CLI transparency; ask before switching to CLI `gpt-image-1.5`. + +More principles shared by both modes: `references/prompting.md`. +Copy/paste specs shared by both modes: `references/sample-prompts.md`. + +## Guidance by asset type +Asset-type templates (website assets, game assets, wireframes, logo) are consolidated in `references/sample-prompts.md`. + +## gpt-image-2 guidance for CLI fallback + +The fallback CLI defaults to `gpt-image-2`. + +- Use `gpt-image-2` for new CLI/API workflows unless the request needs true model-native transparent output. +- If a transparent request may need CLI fallback, ask before using `gpt-image-1.5` unless the user already explicitly requested `gpt-image-1.5`, `scripts/image_gen.py`, or CLI fallback. Explain that the built-in chroma-key path is the default, but true transparency requires `gpt-image-1.5` because `gpt-image-2` does not support `background=transparent`. +- `gpt-image-2` always uses high fidelity for image inputs; do not set `input_fidelity` with this model. +- `gpt-image-2` supports `quality` values `low`, `medium`, `high`, and `auto`. +- Use `quality low` for fast drafts, thumbnails, and quick iterations. Use `medium`, `high`, or `auto` for final assets, dense text, diagrams, identity-sensitive edits, or high-resolution outputs. +- Square images are typically fastest to generate. Use `1024x1024` for fast square drafts. +- If the user asks for 4K-style output, use `3840x2160` for landscape or `2160x3840` for portrait. +- `gpt-image-2` size may be `auto` or `WIDTHxHEIGHT` if all constraints hold: max edge `<= 3840px`, both edges multiples of `16px`, long-to-short ratio `<= 3:1`, total pixels between `655,360` and `8,294,400`. + +Popular `gpt-image-2` sizes: +- `1024x1024` square +- `1536x1024` landscape +- `1024x1536` portrait +- `2048x2048` 2K square +- `2048x1152` 2K landscape +- `3840x2160` 4K landscape +- `2160x3840` 4K portrait +- `auto` + +## Fallback CLI mode only + +### Temp and output conventions +These conventions apply only to the CLI fallback. They do not describe built-in `image_gen` output behavior. +- Use `tmp/imagegen/` for intermediate files (for example JSONL batches); delete them when done. +- Write final artifacts under `output/imagegen/`. +- Use `--out` or `--out-dir` to control output paths; keep filenames stable and descriptive. + +### Dependencies +Prefer `uv` for dependency management in this repo. + +Required Python package: +```bash +uv pip install openai +``` + +Required for local chroma-key removal and optional downscaling: +```bash +uv pip install pillow +``` + +Portability note: +- If you are using the installed skill outside this repo, install dependencies into that environment with its package manager. +- In uv-managed environments, `uv pip install ...` remains the preferred path. + +### Environment +- `OPENAI_API_KEY` must be set for live API calls. +- Do not ask the user for `OPENAI_API_KEY` when using the built-in `image_gen` tool. +- Never ask the user to paste the full key in chat. Ask them to set it locally and confirm when ready. + +If the key is missing, give the user these steps: +1. Create an API key in the OpenAI platform UI: https://platform.openai.com/api-keys +2. Set `OPENAI_API_KEY` as an environment variable in their system. +3. Offer to guide them through setting the environment variable for their OS/shell if needed. + +If installation is not possible in this environment, tell the user which dependency is missing and how to install it into their active environment. + +### Script-mode notes +- CLI commands + examples: `references/cli.md` +- API parameter quick reference: `references/image-api.md` +- Network approvals / sandbox settings for CLI mode: `references/codex-network.md` + +## Reference map +- `references/prompting.md`: shared prompting principles for both modes. +- `references/sample-prompts.md`: shared copy/paste prompt recipes for both modes. +- `references/cli.md`: fallback-only CLI usage via `scripts/image_gen.py`. +- `references/image-api.md`: fallback-only API/CLI parameter reference. +- `references/codex-network.md`: fallback-only network/sandbox troubleshooting for CLI mode. +- `scripts/image_gen.py`: fallback-only CLI implementation. Do not load or use it unless the user explicitly chooses CLI mode or explicitly confirms a transparent request's true CLI transparency fallback. +- `$CODEX_HOME/skills/.system/imagegen/scripts/remove_chroma_key.py`: local post-processing helper for built-in transparent-image requests. diff --git a/Skills/Codex/.system/imagegen/agents/openai.yaml b/Skills/Codex/.system/imagegen/agents/openai.yaml new file mode 100644 index 0000000..5e01d44 --- /dev/null +++ b/Skills/Codex/.system/imagegen/agents/openai.yaml @@ -0,0 +1,6 @@ +interface: + display_name: "Image Gen" + short_description: "Generate or edit images for websites, games, and more" + icon_small: "./assets/imagegen-small.svg" + icon_large: "./assets/imagegen.png" + default_prompt: "Use $imagegen to make or edit an image for this project." diff --git a/Skills/Codex/.system/imagegen/assets/imagegen-small.svg b/Skills/Codex/.system/imagegen/assets/imagegen-small.svg new file mode 100644 index 0000000..20128b2 --- /dev/null +++ b/Skills/Codex/.system/imagegen/assets/imagegen-small.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/Skills/Codex/.system/imagegen/assets/imagegen.png b/Skills/Codex/.system/imagegen/assets/imagegen.png new file mode 100644 index 0000000000000000000000000000000000000000..94b54541a9affd39a7aa09d0efd5bc6b712b723b GIT binary patch literal 1711 zcmV;g22lBlP)f8*GWodgmJ0xDHBC~1!*z7`}xiD+*{^u{6Wtr9m>;F?6e6%akq_R>NQ97`^h zS_ISw!l_acdMv2|s@jkWFo}~maqQ{5Ar6jXJ8OGpcRf3wwDM+c*~)zT-u&HNh6Xr2 z$-B~6@6U&DoN@F6Tx_gMyw!zZkYd0r7n}J1r^VmNyNO5=4Zu(bgOk|-gzyRH_#DA0 ze5a&Dv5qs&Z`LEHCLtt(GYpH}0a%=n6p=Gpix@{jKAv3Z&a&_|v3nYpI$$>Jn72{}2rewsoH7VU@@*oo2>*cKtL zTT?Bf&S2fJxIt9+2RUqgo>5nJ#ub| zQq}-0z927LghkRij)2h@&){gs3Jyeb=#8#z9#4y@PugZO5lp1xm|ls&O&Ie1Y;Y<& zDJqnH7*0nhk28A~+ z7<=9c&7_PLLIN%we2x!9dQ!nmCW_&I_i2rm5DevDWF6nVJEu$r(Gy$4m3QXlck9AP zAru+93XZ;0rxYWFoZJ6W>sd_Seeu8x=)gE3r*<#NO*egQ8QEe}jd4PT_P&B!&~Me- za;t<zMu9~wY)fm}Rzy9AItra{)#n*Ft zp#x)wPKN*4hndv~RP#6!#f883EA5>ZW2_J=urHpxtu%d61x_+_HXOVgZ*U1pUyntk z&{EQR=i5oZ_4zJ5T+-jH*0PkegJp0u{3nitpQ5+rnfUw7Y~EbH6KNj9MD{&AT0ew2 zu6@1iCZ~3%@lofp<0)5aAWWoVxbvz*TZ$@0sgS;wrx=Pokgrae&K<&7=9qkS3pxKD zT|-~ns+{fX2)!(eSEue($$FZ zBMl2V75M|_V)ta4Qo-2jF}VemhGKH4^?}?}Lf=PnuV)4kMCz`oE{PPST1J60(ckfX z`wz;Zu9>J=2o=)R_FFPl>7=J+9#`9L1x`v$La6e-A_}RI%DWbVD8;dmf{b2KNNy4| zDUO8nhUTRVlHvtHlCq-^sw=LvdncnnP^459LaiNYP5Gq|f*_@$5Ngt%i`|9aFkMPn zAtXXqA43HuOW7i%(8r)u<#$Y#vMI#vK86ZRlp=+A)yGhQX;MO7_c2spk`%T$bD5iR zcFpAW%f^kirm}vO`, `image_2.`, and so on. +- Downscaled copies use the default suffix `-web` unless you override it. + +## Common recipes + +Generate with augmentation fields: + +```bash +python "$IMAGE_GEN" generate \ + --prompt "A minimal hero image of a ceramic coffee mug" \ + --use-case "product-mockup" \ + --style "clean product photography" \ + --composition "wide product shot with usable negative space for page copy" \ + --constraints "no logos, no text" \ + --out output/imagegen/mug-hero.png +``` + +Generate + also write a downscaled copy for fast web loading: + +```bash +python "$IMAGE_GEN" generate \ + --prompt "A cozy alpine cabin at dawn" \ + --size 1024x1024 \ + --downscale-max-dim 1024 \ + --out output/imagegen/alpine-cabin.png +``` + +Generate multiple prompts concurrently (async batch): + +```bash +mkdir -p tmp/imagegen output/imagegen/batch +cat > tmp/imagegen/prompts.jsonl << 'EOF' +{"prompt":"Cavernous hangar interior with a compact shuttle parked near the center","use_case":"stylized-concept","composition":"wide-angle, low-angle","lighting":"volumetric light rays through drifting fog","constraints":"no logos or trademarks; no watermark","size":"1536x1024"} +{"prompt":"Gray wolf in profile in a snowy forest","use_case":"photorealistic-natural","composition":"eye-level","constraints":"no logos or trademarks; no watermark","size":"1024x1024"} +EOF + +python "$IMAGE_GEN" generate-batch \ + --input tmp/imagegen/prompts.jsonl \ + --out-dir output/imagegen/batch \ + --concurrency 5 + +rm -f tmp/imagegen/prompts.jsonl +``` + +Notes: +- `generate-batch` requires `--out-dir`. +- generate-batch requires --out-dir. +- Use `--concurrency` to control parallelism (default `5`). +- Per-job overrides are supported in JSONL (for example `size`, `quality`, `background`, `output_format`, `output_compression`, `moderation`, `n`, `model`, `out`, and prompt-augmentation fields). +- `--n` generates multiple variants for a single prompt; `generate-batch` is for many different prompts. +- In batch mode, per-job `out` is treated as a filename under `--out-dir`. +- For many requested deliverable assets, provide one prompt/job per distinct asset and use semantic filenames when possible. + +## CLI notes +- Supported sizes depend on the model. `gpt-image-2` supports flexible constrained sizes; older GPT Image models support `1024x1024`, `1536x1024`, `1024x1536`, or `auto`. +- True transparent CLI outputs require `output_format` to be `png` or `webp` and are not supported by `gpt-image-2`. +- `--prompt-file`, `--output-compression`, `--moderation`, `--max-attempts`, `--fail-fast`, `--force`, and `--no-augment` are supported. +- This CLI is intended for GPT Image models. Do not assume older non-GPT image-model behavior applies here. + +## See also +- API parameter quick reference for fallback CLI mode: `references/image-api.md` +- Prompt examples shared across both top-level modes: `references/sample-prompts.md` +- Network/sandbox notes for fallback CLI mode: `references/codex-network.md` +- Built-in-first transparent image workflow: `SKILL.md` and `$CODEX_HOME/skills/.system/imagegen/scripts/remove_chroma_key.py` diff --git a/Skills/Codex/.system/imagegen/references/codex-network.md b/Skills/Codex/.system/imagegen/references/codex-network.md new file mode 100644 index 0000000..5ce1fbc --- /dev/null +++ b/Skills/Codex/.system/imagegen/references/codex-network.md @@ -0,0 +1,33 @@ +# Codex network approvals / sandbox notes + +This file is for the fallback CLI mode only. Read it when the user explicitly asks to use `scripts/image_gen.py` / CLI / API / model controls, or after the user explicitly confirms that a transparent-output request should use the `gpt-image-1.5` true-transparency fallback path. + +This guidance is intentionally isolated from `SKILL.md` because it can vary by environment and may become stale. Prefer the defaults in your environment when in doubt. + +## Why am I asked to approve image generation calls? +The fallback CLI uses the OpenAI Image API, so it needs outbound network access. In many Codex setups, network access is disabled by default and/or the approval policy requires confirmation before networked commands run. + +## Important note about approvals vs network +- `--ask-for-approval never` suppresses approval prompts. +- It does **not** by itself enable network access. +- In `workspace-write`, network access still depends on your Codex configuration (for example `[sandbox_workspace_write] network_access = true`). + +## How do I reduce repeated approval prompts? +If you trust the repo and want fewer prompts, use a configuration or profile that both: +- enables network for the sandbox mode you plan to use +- sets an approval policy that matches your risk tolerance + +Example `~/.codex/config.toml` pattern: + +```toml +approval_policy = "on-request" +sandbox_mode = "workspace-write" + +[sandbox_workspace_write] +network_access = true +``` + +If you want quieter automation after network is enabled, you can choose a stricter approval policy, but do that intentionally and with care. + +## Safety note +Enabling network and reducing approvals lowers friction, but increases risk if you run untrusted code or work in an untrusted repository. diff --git a/Skills/Codex/.system/imagegen/references/image-api.md b/Skills/Codex/.system/imagegen/references/image-api.md new file mode 100644 index 0000000..db8567d --- /dev/null +++ b/Skills/Codex/.system/imagegen/references/image-api.md @@ -0,0 +1,90 @@ +# Image API quick reference + +This file is for the fallback CLI mode only. Use it when the user explicitly asks to use `scripts/image_gen.py` / CLI / API / model controls, or after the user explicitly confirms that a transparent-output request should use the `gpt-image-1.5` true-transparency fallback path. + +These parameters describe the Image API and bundled CLI fallback surface. Do not assume they are normal arguments on the built-in `image_gen` tool. + +## Scope +- This fallback CLI is intended for GPT Image models (`gpt-image-2`, `gpt-image-1.5`, `gpt-image-1`, and `gpt-image-1-mini`). +- The built-in `image_gen` tool and the fallback CLI do not expose the same controls. + +## Model summary + +| Model | Quality | Input fidelity | Resolutions | Recommended use | +| --- | --- | --- | --- | --- | +| `gpt-image-2` | `low`, `medium`, `high`, `auto` | Always high fidelity for image inputs; do not set `input_fidelity` | `auto` or flexible sizes that satisfy the constraints below | Default for new CLI/API workflows: high-quality generation and editing, text-heavy images, photorealism, compositing, identity-sensitive edits, and workflows where fewer retries matter | +| `gpt-image-1.5` | `low`, `medium`, `high`, `auto` | `low`, `high` | `1024x1024`, `1024x1536`, `1536x1024`, `auto` | True transparent-background fallback and backward-compatible workflows | +| `gpt-image-1` | `low`, `medium`, `high`, `auto` | `low`, `high` | `1024x1024`, `1024x1536`, `1536x1024`, `auto` | Legacy compatibility | +| `gpt-image-1-mini` | `low`, `medium`, `high`, `auto` | `low`, `high` | `1024x1024`, `1024x1536`, `1536x1024`, `auto` | Cost-sensitive draft batches and lower-stakes previews | + +## gpt-image-2 sizes + +`gpt-image-2` accepts `auto` or any `WIDTHxHEIGHT` size that satisfies all constraints: + +- Maximum edge length must be less than or equal to `3840px`. +- Both edges must be multiples of `16px`. +- Long edge to short edge ratio must not exceed `3:1`. +- Total pixels must be at least `655,360` and no more than `8,294,400`. + +Popular sizes: + +| Label | Size | Notes | +| --- | --- | --- | +| Square | `1024x1024` | Typical fast default | +| Landscape | `1536x1024` | Standard landscape | +| Portrait | `1024x1536` | Standard portrait | +| 2K square | `2048x2048` | Larger square output | +| 2K landscape | `2048x1152` | Widescreen output | +| 4K landscape | `3840x2160` | Widescreen 4K output | +| 4K portrait | `2160x3840` | Vertical 4K output | +| Auto | `auto` | Default size | + +Square images are typically fastest to generate. For 4K-style output, use `3840x2160` or `2160x3840`. + +## Endpoints +- Generate: `POST /v1/images/generations` (`client.images.generate(...)`) +- Edit: `POST /v1/images/edits` (`client.images.edit(...)`) + +## Core parameters for GPT Image models +- `prompt`: text prompt +- `model`: image model +- `n`: number of images (1-10) +- `size`: `auto` by default for `gpt-image-2`; flexible `WIDTHxHEIGHT` sizes are allowed only for `gpt-image-2`; older GPT Image models use `1024x1024`, `1536x1024`, `1024x1536`, or `auto` +- `quality`: `low`, `medium`, `high`, or `auto` +- `background`: output transparency behavior (`transparent`, `opaque`, or `auto`) for generated output; this is not the same thing as the prompt's visual scene/backdrop +- `output_format`: `png` (default), `jpeg`, `webp` +- `output_compression`: 0-100 (jpeg/webp only) +- `moderation`: `auto` (default) or `low` + +## Edit-specific parameters +- `image`: one or more input images. For GPT Image models, you can provide up to 16 images. +- `mask`: optional mask image +- `input_fidelity`: `low` or `high` only for models that support it; do not set this for `gpt-image-2` + +Model-specific note for `input_fidelity`: +- `gpt-image-2` always uses high fidelity for image inputs and does not support setting `input_fidelity`. +- `gpt-image-1` and `gpt-image-1-mini` preserve all input images, but the first image gets richer textures and finer details. +- `gpt-image-1.5` preserves the first 5 input images with higher fidelity. + +## Transparent backgrounds + +`gpt-image-2` does not currently support the Image API `background=transparent` parameter. The skill's default transparent-image path is built-in `image_gen` with a flat chroma-key background, followed by local alpha extraction with `python "${CODEX_HOME:-$HOME/.codex}/skills/.system/imagegen/scripts/remove_chroma_key.py"`. + +Use CLI `gpt-image-1.5` with `background=transparent` and a transparent-capable output format such as `png` or `webp` only after the user explicitly confirms that fallback, unless they already requested `gpt-image-1.5`, `scripts/image_gen.py`, or CLI fallback. If the user asks for true/native transparency, the subject is too complex for clean chroma-key removal, or local background removal fails validation, explain the tradeoff and ask before switching. + +## Output +- `data[]` list with `b64_json` per image +- The bundled `scripts/image_gen.py` CLI decodes `b64_json` and writes output files for you. + +## Limits and notes +- Input images and masks must be under 50MB. +- Use the edits endpoint when the user requests changes to an existing image. +- Masking is prompt-guided; exact shapes are not guaranteed. +- Large sizes and high quality increase latency and cost. +- Use `quality=low` for fast drafts, thumbnails, and quick iterations. Use `medium` or `high` for final assets, dense text, diagrams, identity-sensitive edits, or high-resolution outputs. +- High `input_fidelity` can materially increase input token usage on models that support it. +- If a request fails because a specific option is unsupported by the selected GPT Image model, retry manually without that option only when the option is not required by the user. If true transparent CLI output is required, ask before switching to `gpt-image-1.5` instead of dropping `background=transparent`, unless the user already explicitly chose that fallback. + +## Important boundary +- `quality`, `input_fidelity`, explicit masks, `background`, `output_format`, and related parameters are fallback-only execution controls. +- Do not assume they are built-in `image_gen` tool arguments. diff --git a/Skills/Codex/.system/imagegen/references/prompting.md b/Skills/Codex/.system/imagegen/references/prompting.md new file mode 100644 index 0000000..9d2da42 --- /dev/null +++ b/Skills/Codex/.system/imagegen/references/prompting.md @@ -0,0 +1,118 @@ +# Prompting best practices + +These prompting principles are shared by both top-level modes of the skill: +- built-in `image_gen` tool (default) +- explicit `scripts/image_gen.py` CLI fallback + +This file is about prompt structure, specificity, and iteration. Fallback-only execution controls such as `quality`, `input_fidelity`, masks, output format, and output paths live in the fallback docs. + +## Contents +- [Structure](#structure) +- [Specificity policy](#specificity-policy) +- [Allowed and disallowed augmentation](#allowed-and-disallowed-augmentation) +- [Composition and layout](#composition-and-layout) +- [Constraints and invariants](#constraints-and-invariants) +- [Text in images](#text-in-images) +- [Input images and references](#input-images-and-references) +- [Iterate deliberately](#iterate-deliberately) +- [Transparent images](#transparent-images) +- [Fallback-only execution controls](#fallback-only-execution-controls) +- [Use-case tips](#use-case-tips) +- [Where to find copy/paste recipes](#where-to-find-copypaste-recipes) + +## Structure +- Use a consistent order: scene/backdrop -> subject -> key details -> constraints -> output intent. +- Include intended use (ad, UI mock, infographic) to set the level of polish. +- For complex requests, use short labeled lines instead of one long paragraph. + +## Specificity policy +- If the user prompt is already specific and detailed, normalize it into a clean spec without adding creative requirements. +- If the prompt is generic, you may add tasteful detail when it materially improves the output. +- Treat examples in `sample-prompts.md` as fully-authored recipes, not as the default amount of augmentation to add to every request. +- For photorealism, include `photorealistic` directly when that is the goal, plus concrete real-world texture such as pores, wrinkles, fabric wear, material grain, or imperfect everyday detail. + +## Allowed and disallowed augmentation + +Allowed augmentation for generic prompts: +- composition and framing cues +- intended-use or polish-level hints +- practical layout guidance +- reasonable scene concreteness that supports the request + +Do not add: +- extra characters, props, or objects that are not implied +- brand palettes, slogans, or story beats that are not implied +- arbitrary side-specific placement unless the surrounding layout supports it + +## Composition and layout +- Specify framing and viewpoint (close-up, wide, top-down) and placement only when it materially helps. +- Call out negative space if the asset clearly needs room for UI or copy. +- Avoid making left/right layout decisions unless the user or surrounding layout supports them. +- For people, describe body framing, scale, gaze, and object interactions when they matter (`full body visible`, `looking down at the book`, `hands naturally gripping the handlebars`). + +## Constraints and invariants +- State what must not change (`keep background unchanged`). +- For edits, say `change only X; keep Y unchanged` and repeat invariants on every iteration to reduce drift. + +## Text in images +- Put literal text in quotes or ALL CAPS and specify typography (font style, size, color, placement). +- Spell uncommon words letter-by-letter if accuracy matters. +- For in-image copy, require verbatim rendering and no extra characters. +- In CLI fallback mode, use `medium` or `high` quality for small text, dense infographics, data-heavy slides, multi-font layouts, legends, axes, and footnotes. + +## Input images and references +- Do not assume that every provided image is an edit target. +- Label each image by index and role (`Image 1: edit target`, `Image 2: style reference`). +- If the user provides images for style, composition, or mood guidance and does not ask to modify them, treat the request as generation with references. +- If the user asks to preserve an existing image while changing specific parts, treat the request as an edit. +- For compositing, describe how the images interact (`place the subject from Image 2 into Image 1`). + +## Iterate deliberately +- Start with a clean base prompt, then make small single-change edits. +- Re-specify critical constraints when you iterate. +- Prefer one targeted follow-up at a time over rewriting the whole prompt. + +## Transparent images +- Use built-in `image_gen` first for transparent-image requests. If the subject is clearly too complex for chroma-key removal, explain the fallback and ask before switching to CLI. +- Prompt for a perfectly flat solid chroma-key background, usually `#00ff00`; use `#ff00ff` when the subject is green, and avoid key colors that appear in the subject. +- Explicitly prohibit shadows, gradients, floor planes, reflections, texture, and lighting variation in the background. +- Ask for crisp edges, generous padding, and no use of the key color inside the subject. +- After generation, remove the background locally with `python "${CODEX_HOME:-$HOME/.codex}/skills/.system/imagegen/scripts/remove_chroma_key.py" --input --out --auto-key border --soft-matte --transparent-threshold 12 --opaque-threshold 220 --despill` and validate the alpha result before shipping it. +- Use soft matte and despill for antialiased edges; hard tolerance-only removal is mainly for flat pixel-art or exact-color fixtures. +- Use CLI `gpt-image-1.5 --background transparent --output-format png` only after the user explicitly confirms the fallback, or when the user already explicitly requested `gpt-image-1.5`, `scripts/image_gen.py`, or CLI fallback. Ask first for true/native transparency requests, failed chroma-key validation, or complex transparent subjects such as hair, fur, glass, smoke, liquids, translucent materials, reflective objects, or soft shadows. + +## Fallback-only execution controls +- `quality`, `input_fidelity`, explicit masks, output format, and output paths are fallback-only execution controls. +- Do not assume they are built-in `image_gen` tool arguments. +- If the user explicitly chooses CLI fallback, see `references/cli.md` and `references/image-api.md` for those controls. +- In CLI fallback mode, `gpt-image-2` is the default. It supports `quality=low|medium|high|auto`; use `low` for fast drafts and thumbnails, and move to `medium`, `high`, or `auto` for final assets. +- `gpt-image-2` always uses high fidelity for image inputs, so do not set `input_fidelity` with that model. +- If a transparent request needs true CLI transparency, ask before using `gpt-image-1.5` unless the user already explicitly chose it. Explain that built-in chroma-key removal is the default path, but `gpt-image-2` does not support `background=transparent`. +- If the user asks for 4K-style output with `gpt-image-2`, use `3840x2160` for landscape or `2160x3840` for portrait. + +## Use-case tips +Generate: +- photorealistic-natural: Prompt as if a real photo is captured in the moment; use photography language (lens, lighting, framing); call for real texture; avoid over-stylized polish unless requested. +- product-mockup: Describe the product/packaging and materials; ensure clean silhouette and label clarity; if in-image text is needed, require verbatim rendering and specify typography. +- ui-mockup: Describe the target fidelity first (shippable mockup or low-fi wireframe), then focus on layout, hierarchy, and practical UI elements; avoid concept-art language. +- infographic-diagram: Define the audience and layout flow; label parts explicitly; require verbatim text; prefer higher quality in CLI mode for dense labels. +- logo-brand: Keep it simple and scalable; ask for a strong silhouette and balanced negative space; avoid decorative flourishes unless requested. +- ads-marketing: Write like a creative brief; include brand positioning, audience, desired vibe, scene, and exact tagline if text must appear. +- productivity-visual: Name the exact artifact (slide, chart, workflow diagram), define the canvas and hierarchy, provide real labels/data, and ask for readable typography and polished spacing. +- scientific-educational: Define audience, lesson objective, required labels, scientific constraints, arrows, and scan-friendly whitespace. +- illustration-story: Define panels or scene beats; keep each action concrete. +- stylized-concept: Specify style cues, material finish, and rendering approach (3D, painterly, clay) without inventing new story elements. +- historical-scene: State the location/date and required period accuracy; constrain clothing, props, and environment to match the era. + +Edit: +- text-localization: Change only the text; preserve layout, typography, spacing, and hierarchy; no extra words or reflow unless needed. +- identity-preserve: Lock identity (face, body, pose, hair, expression); change only the specified elements; match lighting and shadows. +- precise-object-edit: Specify exactly what to remove/replace; preserve surrounding texture and lighting; keep everything else unchanged. +- lighting-weather: Change only environmental conditions (light, shadows, atmosphere, precipitation); keep geometry, framing, and subject identity. +- background-extraction: For simple opaque subjects, request a clean cutout on a perfectly flat chroma-key background; crisp silhouette; generous padding; no shadows; no halos; preserve label text exactly; no restyling. Ask before using true CLI transparency for complex subjects. +- style-transfer: Specify style cues to preserve (palette, texture, brushwork) and what must change; add `no extra elements` to prevent drift. +- compositing: Reference inputs by index; specify what moves where; match lighting, perspective, and scale; keep the base framing unchanged. +- sketch-to-render: Preserve layout, proportions, and perspective; choose materials and lighting that support the supplied sketch without adding new elements. + +## Where to find copy/paste recipes +For copy/paste prompt specs (examples only), see `references/sample-prompts.md`. This file focuses on principles, specificity, and iteration patterns. diff --git a/Skills/Codex/.system/imagegen/references/sample-prompts.md b/Skills/Codex/.system/imagegen/references/sample-prompts.md new file mode 100644 index 0000000..d949295 --- /dev/null +++ b/Skills/Codex/.system/imagegen/references/sample-prompts.md @@ -0,0 +1,433 @@ +# Sample prompts (copy/paste) + +These prompt recipes are shared across both top-level modes of the skill: +- built-in `image_gen` tool (default) +- `scripts/image_gen.py` CLI fallback for explicit CLI/API/model requests or user-confirmed true-transparent-output fallback requests + +Use these as starting points. They are intentionally complete prompt recipes, not the default amount of augmentation to add to every user request. + +When adapting a user's prompt: +- keep user-provided requirements +- only add detail according to the specificity policy in `SKILL.md` +- do not treat every example below as permission to invent extra story elements + +The labeled lines are prompt scaffolding, not a closed schema. `Asset type` and `Input images` are prompt-only scaffolding; the CLI does not expose them as dedicated flags. + +Execution details such as explicit CLI flags, `quality`, `input_fidelity`, masks, output formats, and local output paths depend on mode. Use the built-in tool by default, including simple transparent-image requests. For transparent images, prompt for a flat chroma-key background and remove it locally with `python "${CODEX_HOME:-$HOME/.codex}/skills/.system/imagegen/scripts/remove_chroma_key.py"`; only apply CLI-specific controls when the user explicitly opts into fallback mode or explicitly confirms that the transparent request should use true CLI transparency. + +CLI model notes: +- `gpt-image-2` is the fallback CLI default for new workflows. +- `gpt-image-2` supports `quality` values `low`, `medium`, `high`, and `auto`. +- For 4K-style `gpt-image-2` output, use `3840x2160` or `2160x3840`. +- If transparent output needs true CLI fallback, ask before using `gpt-image-1.5` unless the user already explicitly requested `gpt-image-1.5`, `scripts/image_gen.py`, or CLI fallback. Explain that built-in chroma-key removal is the default path, but `gpt-image-2` does not support `background=transparent`. +- Do not set `input_fidelity` with `gpt-image-2`; image inputs already use high fidelity. + +For prompting principles (structure, specificity, invariants, iteration), see `references/prompting.md`. + +## Generate + +### photorealistic-natural +``` +Use case: photorealistic-natural +Primary request: candid photo of an elderly sailor on a small fishing boat adjusting a net +Scene/backdrop: coastal water with soft haze +Subject: weathered skin with wrinkles and sun texture +Style/medium: photorealistic candid photo +Composition/framing: medium close-up, eye-level +Lighting/mood: soft coastal daylight, shallow depth of field, subtle film grain +Materials/textures: real skin texture, worn fabric, salt-worn wood +Constraints: natural color balance; no heavy retouching; no glamorization; no watermark +Avoid: studio polish; staged look +``` + +### product-mockup +``` +Use case: product-mockup +Primary request: premium product photo of a matte black shampoo bottle with a minimal label +Scene/backdrop: clean studio gradient from light gray to white +Subject: single bottle centered with subtle reflection +Style/medium: premium product photography +Composition/framing: centered, slight three-quarter angle, generous padding +Lighting/mood: softbox lighting, clean highlights, controlled shadows +Materials/textures: matte plastic, crisp label printing +Constraints: no logos or trademarks; no watermark +``` + +### ui-mockup +``` +Use case: ui-mockup +Primary request: mobile app home screen for a local farmers market with vendors and daily specials +Asset type: mobile app screen +Style/medium: realistic product UI, not concept art +Composition/framing: clean vertical mobile layout with clear hierarchy +Constraints: practical layout, clear typography, no logos or trademarks, no watermark +``` + +### infographic-diagram +``` +Use case: infographic-diagram +Primary request: detailed infographic of an automatic coffee machine flow +Scene/backdrop: clean, light neutral background +Subject: bean hopper -> grinder -> brew group -> boiler -> water tank -> drip tray +Style/medium: clean vector-like infographic with clear callouts and arrows +Composition/framing: vertical poster layout, top-to-bottom flow +Text (verbatim): "Bean Hopper", "Grinder", "Brew Group", "Boiler", "Water Tank", "Drip Tray" +Constraints: clear labels, strong contrast, no logos or trademarks, no watermark +``` + +### scientific-educational +``` +Use case: scientific-educational +Primary request: biology diagram titled "Cellular Respiration at a Glance" for high school students +Scene/backdrop: clean white classroom handout background +Subject: glucose turns into energy inside a cell; include glycolysis, Krebs cycle, and electron transport chain +Style/medium: flat scientific diagram with consistent icons, arrows, and readable labels +Composition/framing: landscape slide-style layout with clear hierarchy and generous whitespace +Text (verbatim): "Cellular Respiration at a Glance", "Glucose", "Pyruvate", "ATP", "NADH", "FADH2", "CO2", "O2", "H2O" +Constraints: scientifically plausible; avoid tiny text; no extra decoration; no watermark +``` + +### logo-brand +``` +Use case: logo-brand +Primary request: original logo for "Field & Flour", a local bakery +Style/medium: vector logo mark; flat colors; minimal +Composition/framing: single centered logo on a plain background with generous padding +Constraints: strong silhouette, balanced negative space; original design only; no gradients unless essential; no trademarks; no watermark +``` + +### illustration-story +``` +Use case: illustration-story +Primary request: 4-panel comic about a pet left alone at home +Scene/backdrop: cozy living room across panels +Subject: pet reacting to the owner leaving, then relaxing, then returning to a composed pose +Style/medium: comic illustration with clear panels +Composition/framing: 4 equal-sized vertical panels, readable actions per panel +Constraints: no text; no logos or trademarks; no watermark +``` + +### stylized-concept +``` +Use case: stylized-concept +Primary request: cavernous hangar interior with tall support beams and drifting fog +Scene/backdrop: industrial hangar interior, deep scale, light haze +Subject: compact shuttle parked near the center +Style/medium: cinematic concept art, industrial realism +Composition/framing: wide-angle, low-angle +Lighting/mood: volumetric light rays cutting through fog +Constraints: no logos or trademarks; no watermark +``` + +### ads-marketing +``` +Use case: ads-marketing +Primary request: campaign image for a streetwear brand called Thread +Subject: group of friends hanging out together in a stylish urban setting +Style/medium: polished youth streetwear campaign photography +Composition/framing: vertical ad layout with natural poses and integrated headline space +Lighting/mood: contemporary, energetic, tasteful +Text (verbatim): "Yours to Create." +Constraints: render the tagline exactly once; clean legible typography; no extra text; no watermarks; no unrelated logos +``` + +### productivity-visual +``` +Use case: productivity-visual +Primary request: one pitch-deck slide titled "Market Opportunity" +Asset type: fundraising slide image +Style/medium: clean modern deck slide, white background, crisp sans-serif typography +Subject: TAM/SAM/SOM concentric-circle diagram plus a small growth bar chart from 2021 to 2026 +Composition/framing: 16:9 landscape slide, clear data hierarchy, polished spacing +Text (verbatim): "Market Opportunity", "TAM: $42B", "SAM: $8.7B", "SOM: $340M", "AGI Research, 2024", "Internal analysis" +Constraints: readable labels, no clip art, no stock photography, no decorative clutter, no watermark +``` + +### historical-scene +``` +Use case: historical-scene +Primary request: outdoor crowd scene in Bethel, New York on August 16, 1969 +Scene/backdrop: open field with period-appropriate staging +Subject: crowd in period-accurate clothing, authentic environment +Style/medium: photorealistic photo +Composition/framing: wide shot, eye-level +Constraints: period-accurate details; no modern objects; no logos or trademarks; no watermark +``` + +## Asset type templates (taxonomy-aligned) + +### Website assets template +``` +Use case: +Asset type: +Primary request: +Scene/backdrop: +Subject:
+Style/medium: +Composition/framing: +Lighting/mood: +Color palette: +Constraints: +``` + +### Website assets example: minimal hero background +``` +Use case: stylized-concept +Asset type: landing page hero background +Primary request: minimal abstract background with a soft gradient and subtle texture +Style/medium: matte illustration / soft-rendered abstract background +Composition/framing: wide composition with usable negative space for page copy +Lighting/mood: gentle studio glow +Color palette: restrained neutral palette +Constraints: no text; no logos; no watermark +``` + +### Website assets example: feature section illustration +``` +Use case: stylized-concept +Asset type: feature section illustration +Primary request: simple abstract shapes suggesting connection and flow +Scene/backdrop: subtle light-gray backdrop with faint texture +Style/medium: flat illustration; soft shadows; restrained contrast +Composition/framing: centered cluster; open margins for UI +Color palette: muted neutral palette +Constraints: no text; no logos; no watermark +``` + +### Website assets example: blog header image +``` +Use case: photorealistic-natural +Asset type: blog header image +Primary request: overhead desk scene with notebook, pen, and coffee cup +Scene/backdrop: warm wooden tabletop +Style/medium: photorealistic photo +Composition/framing: wide crop with clean room for page copy +Lighting/mood: soft morning light +Constraints: no text; no logos; no watermark +``` + +### Game assets template +``` +Use case: stylized-concept +Asset type: +Primary request: +Scene/backdrop: (if applicable) +Subject:
+Style/medium: ; +Composition/framing: ; ; +Lighting/mood: