From 12abc0c31fd766c5eea43ad223490726c480f721 Mon Sep 17 00:00:00 2001 From: duyet Date: Mon, 19 Oct 2026 13:04:02 +0700 Subject: [PATCH 1/5] refactor(marketplace): generate all harness manifests from marketplace.json, add Cursor, drop simplify, docs-generator, duyetbot marketplace.json is now the single hand-edited registry. scripts/plugins.py writes the Claude, Codex, Cursor, Grok, Grok Build, and Antigravity manifests and marketplaces, and its check mode lints skills. simplify duplicated the built-in /simplify. docs-generator was repo tooling with a Stop hook that wrote into user repos. duyetbot shipped personal profile data. Plugin-root CLAUDE.md files are never loaded by Claude Code. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01ACsvmWVWieCuahs1T7ZTtn --- .agents/plugins/marketplace.json | 70 +- .claude-plugin/marketplace.json | 115 ++- .cursor-plugin/marketplace.json | 116 +++ .grok-plugin/marketplace.json | 255 ++--- agent-loop/.antigravity-plugin/plugin.json | 33 +- agent-loop/.claude-plugin/plugin.json | 6 +- agent-loop/.codex-plugin/plugin.json | 34 +- agent-loop/.cursor-plugin/plugin.json | 16 + agent-loop/.grok-build-plugin/plugin.json | 36 +- agent-loop/.grok-plugin/plugin.json | 11 +- agent-loop/CLAUDE.md | 85 -- anyrouter/.claude-plugin/plugin.json | 5 +- anyrouter/.codex-plugin/plugin.json | 22 +- anyrouter/.cursor-plugin/plugin.json | 18 + anyrouter/.grok-build-plugin/plugin.json | 26 +- anyrouter/.grok-plugin/plugin.json | 10 +- build-ios-apps/.claude-plugin/plugin.json | 3 +- build-ios-apps/.codex-plugin/plugin.json | 14 +- build-ios-apps/.cursor-plugin/plugin.json | 16 + build-ios-apps/.grok-build-plugin/plugin.json | 18 +- build-ios-apps/.grok-plugin/plugin.json | 8 +- build-macos-apps/.claude-plugin/plugin.json | 3 +- build-macos-apps/.codex-plugin/plugin.json | 17 +- build-macos-apps/.cursor-plugin/plugin.json | 17 + .../.grok-build-plugin/plugin.json | 21 +- build-macos-apps/.grok-plugin/plugin.json | 8 +- .../.claude-plugin/plugin.json | 7 +- .../.codex-plugin/plugin.json | 12 +- .../.cursor-plugin/plugin.json | 15 + .../.grok-build-plugin/plugin.json | 16 +- .../.grok-plugin/plugin.json | 12 +- clickhouse/.claude-plugin/plugin.json | 7 +- clickhouse/.codex-plugin/plugin.json | 14 +- clickhouse/.cursor-plugin/plugin.json | 15 + clickhouse/.grok-build-plugin/plugin.json | 18 +- clickhouse/.grok-plugin/plugin.json | 12 +- command-code/.claude-plugin/plugin.json | 5 +- command-code/.codex-plugin/plugin.json | 19 +- command-code/.cursor-plugin/plugin.json | 17 + command-code/.grok-build-plugin/plugin.json | 23 +- command-code/.grok-plugin/plugin.json | 10 +- commit/.claude-plugin/plugin.json | 7 +- commit/.codex-plugin/plugin.json | 10 +- commit/.cursor-plugin/plugin.json | 16 + commit/.grok-build-plugin/plugin.json | 14 +- commit/.grok-plugin/plugin.json | 10 +- commit/CLAUDE.md | 58 -- docs-generator/.claude-plugin/plugin.json | 9 - docs-generator/.codex-plugin/plugin.json | 20 - docs-generator/.grok-build-plugin/plugin.json | 21 - docs-generator/.grok-plugin/plugin.json | 13 - docs-generator/CLAUDE.md | 56 -- docs-generator/README.md | 71 -- docs-generator/assets/logo.svg | 1 - docs-generator/commands/generate-docs.md | 35 - docs-generator/hooks/hooks.json | 14 - docs-generator/hooks/stop-hook.sh | 36 - docs-generator/scripts/generate-docs.sh | 343 ------- docs-generator/scripts/lib/emoji-mapper.sh | 21 - .../scripts/lib/feature-extractor.sh | 84 -- docs-generator/scripts/lib/plugin-scanner.sh | 20 - docs-generator/scripts/lib/type-detector.sh | 33 - .../skills/docs-generator-workflow/SKILL.md | 20 - duyetbot/.claude-plugin/plugin.json | 9 - duyetbot/.codex-plugin/plugin.json | 19 - duyetbot/.grok-build-plugin/plugin.json | 20 - duyetbot/.grok-plugin/plugin.json | 15 - duyetbot/.mcp.json | 19 - duyetbot/CLAUDE.md | 72 -- duyetbot/PLAN-MCP-OAUTH.md | 946 ------------------ duyetbot/README.md | 251 ----- duyetbot/agents/duyetbot.md | 243 ----- duyetbot/assets/logo.svg | 1 - duyetbot/commands/duyetbot.md | 43 - duyetbot/commands/learn.md | 67 -- duyetbot/commands/orchestrate.md | 131 --- duyetbot/commands/spawn.md | 79 -- duyetbot/commands/think.md | 55 - duyetbot/commands/writing.md | 96 -- duyetbot/hooks/hooks.json | 3 - duyetbot/hooks/security_reminder_hook.py | 120 --- duyetbot/knowledge/blog-archive.md | 123 --- duyetbot/knowledge/duyet-profile.md | 139 --- duyetbot/knowledge/structure.md | 92 -- .../topics/clickhouse-monitoring/overview.md | 395 -------- .../topics/duyet-mcp-server/overview.md | 294 ------ .../topics/duyetbot-agent/overview.md | 264 ----- duyetbot/knowledge/writing-style.md | 178 ---- duyetbot/scripts/fetch-duyet-data.sh | 45 - duyetbot/skills/duyet-knowledge/SKILL.md | 146 --- duyetbot/skills/duyetbot-workflow/SKILL.md | 22 - .../skills/engineering-discipline/SKILL.md | 83 -- duyetbot/skills/task-loop/SKILL.md | 103 -- duyetbot/skills/team-coordination/SKILL.md | 161 --- duyetbot/skills/transparency/SKILL.md | 81 -- fix/.claude-plugin/plugin.json | 7 +- fix/.codex-plugin/plugin.json | 14 +- fix/.cursor-plugin/plugin.json | 16 + fix/.grok-build-plugin/plugin.json | 18 +- fix/.grok-plugin/plugin.json | 12 +- fix/CLAUDE.md | 69 -- frontend-design/.claude-plugin/plugin.json | 6 +- frontend-design/.codex-plugin/plugin.json | 11 +- frontend-design/.cursor-plugin/plugin.json | 15 + .../.grok-build-plugin/plugin.json | 15 +- frontend-design/.grok-plugin/plugin.json | 11 +- frontend-design/CLAUDE.md | 56 -- github/.claude-plugin/plugin.json | 6 +- github/.codex-plugin/plugin.json | 15 +- github/.cursor-plugin/plugin.json | 16 + github/.grok-build-plugin/plugin.json | 19 +- github/.grok-plugin/plugin.json | 11 +- good-html.skill | Bin 14897 -> 0 bytes good-html/.claude-plugin/plugin.json | 7 +- good-html/.codex-plugin/plugin.json | 17 +- good-html/.cursor-plugin/plugin.json | 15 + good-html/.grok-build-plugin/plugin.json | 21 +- good-html/.grok-plugin/plugin.json | 13 +- good-html/{ => skills/good-html}/SKILL.md | 0 .../good-html}/references/components.md | 0 .../good-html}/references/page_types.md | 0 .../good-html}/references/patterns.md | 0 .../good-html}/references/styles.md | 0 interview/.claude-plugin/plugin.json | 6 +- interview/.codex-plugin/plugin.json | 12 +- interview/.cursor-plugin/plugin.json | 16 + interview/.grok-build-plugin/plugin.json | 16 +- interview/.grok-plugin/plugin.json | 11 +- interview/CLAUDE.md | 56 -- kb/.claude-plugin/plugin.json | 3 +- kb/.codex-plugin/plugin.json | 16 +- kb/.cursor-plugin/plugin.json | 16 + kb/.grok-build-plugin/plugin.json | 20 +- kb/.grok-plugin/plugin.json | 8 +- marketplace.json | 183 +--- okf/.claude-plugin/plugin.json | 3 +- okf/.codex-plugin/plugin.json | 15 +- okf/.cursor-plugin/plugin.json | 15 + okf/.grok-build-plugin/plugin.json | 19 +- okf/.grok-plugin/plugin.json | 8 +- orchestration/.claude-plugin/plugin.json | 7 +- orchestration/.codex-plugin/plugin.json | 12 +- orchestration/.cursor-plugin/plugin.json | 15 + orchestration/.grok-build-plugin/plugin.json | 16 +- orchestration/.grok-plugin/plugin.json | 12 +- orchestration/CLAUDE.md | 56 -- prompt-engineering/.claude-plugin/plugin.json | 7 +- prompt-engineering/.codex-plugin/plugin.json | 14 +- prompt-engineering/.cursor-plugin/plugin.json | 15 + .../.grok-build-plugin/plugin.json | 18 +- prompt-engineering/.grok-plugin/plugin.json | 12 +- sag-notify/.claude-plugin/plugin.json | 7 +- sag-notify/.codex-plugin/plugin.json | 13 +- sag-notify/.cursor-plugin/plugin.json | 16 + sag-notify/.grok-build-plugin/plugin.json | 17 +- sag-notify/.grok-plugin/plugin.json | 12 +- scripts/plugins.py | 247 +++++ scripts/validate-plugins.sh | 395 +------- simplify/.claude-plugin/plugin.json | 9 - simplify/.codex-plugin/plugin.json | 19 - simplify/.grok-build-plugin/plugin.json | 20 - simplify/.grok-plugin/plugin.json | 12 - simplify/README.md | 33 - simplify/assets/logo.svg | 1 - simplify/commands/simplify.md | 55 - simplify/skills/simplify/SKILL.md | 55 - statusline/.claude-plugin/plugin.json | 7 +- statusline/.codex-plugin/plugin.json | 14 +- statusline/.cursor-plugin/plugin.json | 16 + statusline/.grok-build-plugin/plugin.json | 18 +- statusline/.grok-plugin/plugin.json | 15 +- statusline/CLAUDE.md | 77 -- team-agents/.claude-plugin/plugin.json | 7 +- team-agents/.codex-plugin/plugin.json | 16 +- team-agents/.cursor-plugin/plugin.json | 17 + team-agents/.grok-build-plugin/plugin.json | 20 +- team-agents/.grok-plugin/plugin.json | 12 +- team-agents/CLAUDE.md | 70 -- unsloth-training/.claude-plugin/plugin.json | 6 +- unsloth-training/.codex-plugin/plugin.json | 11 +- unsloth-training/.cursor-plugin/plugin.json | 15 + .../.grok-build-plugin/plugin.json | 15 +- unsloth-training/.grok-plugin/plugin.json | 11 +- 183 files changed, 1616 insertions(+), 7051 deletions(-) create mode 100644 .cursor-plugin/marketplace.json create mode 100644 agent-loop/.cursor-plugin/plugin.json delete mode 100644 agent-loop/CLAUDE.md create mode 100644 anyrouter/.cursor-plugin/plugin.json create mode 100644 build-ios-apps/.cursor-plugin/plugin.json create mode 100644 build-macos-apps/.cursor-plugin/plugin.json create mode 100644 clickhouse-monitoring/.cursor-plugin/plugin.json create mode 100644 clickhouse/.cursor-plugin/plugin.json create mode 100644 command-code/.cursor-plugin/plugin.json create mode 100644 commit/.cursor-plugin/plugin.json delete mode 100644 commit/CLAUDE.md delete mode 100644 docs-generator/.claude-plugin/plugin.json delete mode 100644 docs-generator/.codex-plugin/plugin.json delete mode 100644 docs-generator/.grok-build-plugin/plugin.json delete mode 100644 docs-generator/.grok-plugin/plugin.json delete mode 100644 docs-generator/CLAUDE.md delete mode 100644 docs-generator/README.md delete mode 100644 docs-generator/assets/logo.svg delete mode 100644 docs-generator/commands/generate-docs.md delete mode 100644 docs-generator/hooks/hooks.json delete mode 100755 docs-generator/hooks/stop-hook.sh delete mode 100755 docs-generator/scripts/generate-docs.sh delete mode 100755 docs-generator/scripts/lib/emoji-mapper.sh delete mode 100755 docs-generator/scripts/lib/feature-extractor.sh delete mode 100755 docs-generator/scripts/lib/plugin-scanner.sh delete mode 100755 docs-generator/scripts/lib/type-detector.sh delete mode 100644 docs-generator/skills/docs-generator-workflow/SKILL.md delete mode 100644 duyetbot/.claude-plugin/plugin.json delete mode 100644 duyetbot/.codex-plugin/plugin.json delete mode 100644 duyetbot/.grok-build-plugin/plugin.json delete mode 100644 duyetbot/.grok-plugin/plugin.json delete mode 100644 duyetbot/.mcp.json delete mode 100644 duyetbot/CLAUDE.md delete mode 100644 duyetbot/PLAN-MCP-OAUTH.md delete mode 100644 duyetbot/README.md delete mode 100644 duyetbot/agents/duyetbot.md delete mode 100644 duyetbot/assets/logo.svg delete mode 100644 duyetbot/commands/duyetbot.md delete mode 100644 duyetbot/commands/learn.md delete mode 100644 duyetbot/commands/orchestrate.md delete mode 100644 duyetbot/commands/spawn.md delete mode 100644 duyetbot/commands/think.md delete mode 100644 duyetbot/commands/writing.md delete mode 100644 duyetbot/hooks/hooks.json delete mode 100755 duyetbot/hooks/security_reminder_hook.py delete mode 100644 duyetbot/knowledge/blog-archive.md delete mode 100644 duyetbot/knowledge/duyet-profile.md delete mode 100644 duyetbot/knowledge/structure.md delete mode 100644 duyetbot/knowledge/topics/clickhouse-monitoring/overview.md delete mode 100644 duyetbot/knowledge/topics/duyet-mcp-server/overview.md delete mode 100644 duyetbot/knowledge/topics/duyetbot-agent/overview.md delete mode 100644 duyetbot/knowledge/writing-style.md delete mode 100755 duyetbot/scripts/fetch-duyet-data.sh delete mode 100644 duyetbot/skills/duyet-knowledge/SKILL.md delete mode 100644 duyetbot/skills/duyetbot-workflow/SKILL.md delete mode 100644 duyetbot/skills/engineering-discipline/SKILL.md delete mode 100644 duyetbot/skills/task-loop/SKILL.md delete mode 100644 duyetbot/skills/team-coordination/SKILL.md delete mode 100644 duyetbot/skills/transparency/SKILL.md create mode 100644 fix/.cursor-plugin/plugin.json delete mode 100644 fix/CLAUDE.md create mode 100644 frontend-design/.cursor-plugin/plugin.json delete mode 100644 frontend-design/CLAUDE.md create mode 100644 github/.cursor-plugin/plugin.json delete mode 100644 good-html.skill create mode 100644 good-html/.cursor-plugin/plugin.json rename good-html/{ => skills/good-html}/SKILL.md (100%) rename good-html/{ => skills/good-html}/references/components.md (100%) rename good-html/{ => skills/good-html}/references/page_types.md (100%) rename good-html/{ => skills/good-html}/references/patterns.md (100%) rename good-html/{ => skills/good-html}/references/styles.md (100%) create mode 100644 interview/.cursor-plugin/plugin.json delete mode 100644 interview/CLAUDE.md create mode 100644 kb/.cursor-plugin/plugin.json create mode 100644 okf/.cursor-plugin/plugin.json create mode 100644 orchestration/.cursor-plugin/plugin.json delete mode 100644 orchestration/CLAUDE.md create mode 100644 prompt-engineering/.cursor-plugin/plugin.json create mode 100644 sag-notify/.cursor-plugin/plugin.json create mode 100644 scripts/plugins.py delete mode 100644 simplify/.claude-plugin/plugin.json delete mode 100644 simplify/.codex-plugin/plugin.json delete mode 100644 simplify/.grok-build-plugin/plugin.json delete mode 100644 simplify/.grok-plugin/plugin.json delete mode 100644 simplify/README.md delete mode 100644 simplify/assets/logo.svg delete mode 100644 simplify/commands/simplify.md delete mode 100644 simplify/skills/simplify/SKILL.md create mode 100644 statusline/.cursor-plugin/plugin.json delete mode 100644 statusline/CLAUDE.md create mode 100644 team-agents/.cursor-plugin/plugin.json delete mode 100644 team-agents/CLAUDE.md create mode 100644 unsloth-training/.cursor-plugin/plugin.json diff --git a/.agents/plugins/marketplace.json b/.agents/plugins/marketplace.json index 01f9e87..bd71a0e 100644 --- a/.agents/plugins/marketplace.json +++ b/.agents/plugins/marketplace.json @@ -1,7 +1,7 @@ { "name": "duyet-claude-plugins", "interface": { - "displayName": "Duyet Claude, Codex, and Grok Plugins", + "displayName": "Duyet Claude, Codex, Cursor, and Grok Plugins", "logo": "./assets/logo.svg", "composerIcon": "./assets/logo.svg" }, @@ -102,38 +102,6 @@ "composerIcon": "./orchestration/assets/logo.svg" } }, - { - "name": "duyetbot", - "source": { - "source": "local", - "path": "./duyetbot" - }, - "policy": { - "installation": "AVAILABLE", - "authentication": "ON_INSTALL" - }, - "category": "Productivity", - "interface": { - "logo": "./duyetbot/assets/logo.svg", - "composerIcon": "./duyetbot/assets/logo.svg" - } - }, - { - "name": "docs-generator", - "source": { - "source": "local", - "path": "./docs-generator" - }, - "policy": { - "installation": "AVAILABLE", - "authentication": "ON_INSTALL" - }, - "category": "Docs", - "interface": { - "logo": "./docs-generator/assets/logo.svg", - "composerIcon": "./docs-generator/assets/logo.svg" - } - }, { "name": "github", "source": { @@ -166,22 +134,6 @@ "composerIcon": "./fix/assets/logo.svg" } }, - { - "name": "simplify", - "source": { - "source": "local", - "path": "./simplify" - }, - "policy": { - "installation": "AVAILABLE", - "authentication": "ON_INSTALL" - }, - "category": "Productivity", - "interface": { - "logo": "./simplify/assets/logo.svg", - "composerIcon": "./simplify/assets/logo.svg" - } - }, { "name": "clickhouse", "source": { @@ -263,35 +215,35 @@ } }, { - "name": "sag-notify", + "name": "anyrouter", "source": { "source": "local", - "path": "./sag-notify" + "path": "./anyrouter" }, "policy": { "installation": "AVAILABLE", "authentication": "ON_INSTALL" }, - "category": "UI", + "category": "AI", "interface": { - "logo": "./sag-notify/assets/logo.svg", - "composerIcon": "./sag-notify/assets/logo.svg" + "logo": "./anyrouter/assets/logo.svg", + "composerIcon": "./anyrouter/assets/logo.svg" } }, { - "name": "anyrouter", + "name": "sag-notify", "source": { "source": "local", - "path": "./anyrouter" + "path": "./sag-notify" }, "policy": { "installation": "AVAILABLE", "authentication": "ON_INSTALL" }, - "category": "AI", + "category": "UI", "interface": { - "logo": "./anyrouter/assets/logo.svg", - "composerIcon": "./anyrouter/assets/logo.svg" + "logo": "./sag-notify/assets/logo.svg", + "composerIcon": "./sag-notify/assets/logo.svg" } }, { diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index bd2c7db..3961ce2 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -1,151 +1,180 @@ { "name": "duyet-claude-plugins", "owner": { - "name": "duyet" + "name": "duyet", + "url": "https://github.com/duyet" + }, + "metadata": { + "description": "Plugins for Claude Code, Codex, Cursor, Grok Build, and Grok Bot: agent workflows, git automation, and developer tools.", + "version": "2.0.0" }, "plugins": [ { "name": "team-agents", "source": "./team-agents", - "description": "Leader and Senior Engineer agents for coordinated parallel task execution. Leader breaks down complex tasks and delegates to multiple senior engineers working in parallel.", + "description": "Leader, Senior Engineer, and Junior Engineer agents for coordinated parallel task execution", + "version": "1.9.1", + "category": "Agents", "logo": "./team-agents/assets/logo.svg" }, { "name": "commit", "source": "./commit", - "description": "Create a Git commit with semantic commit message format", + "description": "Create a Git commit with semantic commit message format and PR workflow with templates", + "version": "1.3.2", + "category": "Git", "logo": "./commit/assets/logo.svg" }, { "name": "frontend-design", "source": "./frontend-design", - "description": "Create distinctive, production-grade frontend interfaces with shadcn/ui and Recharts. Avoids AI slop aesthetics with bold design choices and React best practices.", + "description": "Create distinctive, production-grade frontend interfaces avoiding AI slop aesthetics", + "version": "1.4.0", + "category": "Design", "logo": "./frontend-design/assets/logo.svg" }, { "name": "interview", "source": "./interview", - "description": "Conduct in-depth requirements interviews using Socratic questioning. Clarifies implementation details, edge cases, and tradeoffs before coding begins.", + "description": "Conduct in-depth requirements interviews using Socratic questioning", + "version": "1.0.1", + "category": "Productivity", "logo": "./interview/assets/logo.svg" }, { "name": "statusline", "source": "./statusline", - "description": "Real-time visibility into Claude Code sessions showing context usage, active tools, and task progress. Inspired by claude-hud.", + "description": "Configurable status bar showing context usage, API rate limits, git branch, and active tools", + "version": "1.9.0", + "category": "UI", "logo": "./statusline/assets/logo.svg" }, { "name": "orchestration", "source": "./orchestration", - "description": "Orchestrate complex work through parallel agent coordination. Decompose requests into task graphs, spawn background workers, and synthesize results elegantly.", + "description": "Orchestrator skill for managing parallel agent workstreams", + "version": "1.1.0", + "category": "Agents", "logo": "./orchestration/assets/logo.svg" }, - { - "name": "duyetbot", - "source": "./duyetbot", - "description": "Pragmatic software development companion with engineering discipline and transparent execution. Shows reasoning via execution chain, works in iterative loops.", - "logo": "./duyetbot/assets/logo.svg" - }, - { - "name": "docs-generator", - "source": "./docs-generator", - "description": "Automatically generate and maintain plugin documentation (README.md, CLAUDE.md) from plugin metadata", - "logo": "./docs-generator/assets/logo.svg" - }, { "name": "github", "source": "./github", - "description": "GitHub operations using gh CLI - PRs, workflows, issues, repositories, and smart branch detection for implementation workflows", + "description": "GitHub operations using gh CLI - PRs, issues, workflows, batch operations, PR babysitting with AI review bot integration, and smart branch detection", + "version": "1.4.2", + "category": "Git", "logo": "./github/assets/logo.svg" }, { "name": "fix", "source": "./fix", - "description": "Fix issues, tests, and CI failures with intelligent problem detection and resolution. Supports Python, Node/TS, Rust, and Go projects.", + "description": "Fix issues, tests, and CI failures with intelligent problem detection", + "version": "1.0.1", + "category": "Productivity", "logo": "./fix/assets/logo.svg" }, { - "name": "simplify", - "source": "./simplify", - "description": "Review changed code for reuse, quality, and efficiency, then simplify issues found.", - "logo": "./simplify/assets/logo.svg" + "name": "clickhouse", + "source": "./clickhouse", + "description": "Comprehensive ClickHouse knowledge base from Altinity KB + official docs", + "version": "1.4.1", + "category": "Database", + "logo": "./clickhouse/assets/logo.svg" }, { "name": "prompt-engineering", "source": "./prompt-engineering", - "description": "Prompt engineering skills for Grok, Claude, and Gemini LLMs with model-specific guidance, universal techniques (zero-shot, few-shot, CoT, ReAct, prompt chaining, Tree of Thoughts), and comprehensive documentation.", + "description": "Prompt engineering techniques for Grok, Claude, and Gemini LLMs", + "version": "1.1.1", + "category": "Productivity", "logo": "./prompt-engineering/assets/logo.svg" }, - { - "name": "clickhouse", - "source": "./clickhouse", - "description": "Comprehensive ClickHouse knowledge from Altinity KB + official docs. Covers schema design, MergeTree engines, query optimization, cluster management, backups, monitoring, and integrations.", - "logo": "./clickhouse/assets/logo.svg" - }, { "name": "clickhouse-monitoring", "source": "./clickhouse-monitoring", - "description": "Agent Skill for the ClickHouse Monitor dashboard - a real-time monitoring and observability tool. Covers 45 dashboard pages including query monitoring, table management, merge operations, system metrics, security logs, and API integration.", + "description": "Agent Skill for the ClickHouse Monitor dashboard - a real-time monitoring and observability tool for ClickHouse clusters", + "version": "1.1.1", + "category": "Monitoring", "logo": "./clickhouse-monitoring/assets/logo.svg" }, + { + "name": "unsloth-training", + "source": "./unsloth-training", + "description": "Fine-tune LLMs with Unsloth using GRPO or SFT. Dataset prep, synthetic data, environment flags, MLX (Apple Silicon), FP8, vision, mobile export, GGUF.", + "version": "1.0.2", + "category": "ML", + "logo": "./unsloth-training/assets/logo.svg" + }, { "name": "good-html", "source": "./good-html", - "description": "Generate or review high-density, interactive, self-contained HTML artifacts based on Thariq Shihipar's 'Unreasonable Effectiveness of HTML' patterns.", + "description": "Generate or review high-density, interactive, self-contained HTML artifacts based on Thariq Shihipar's patterns.", + "version": "1.0.0", + "category": "Design", "logo": "./good-html/assets/logo.svg" }, { "name": "anyrouter", "source": "./anyrouter", "description": "Wire AnyRouter into coding agents. Universal OpenAI-compatible LLM gateway for 150+ models, migration recipes from Anthropic/OpenAI/OpenRouter, and a remote MCP server for keys and credits.", + "version": "1.0.1", + "category": "AI", "logo": "./anyrouter/assets/logo.svg" }, { "name": "sag-notify", "source": "./sag-notify", - "description": "Spoken voice notifications via sag (ElevenLabs TTS). Skill-driven: Claude calls sag directly to speak a short alert just before it asks you something and a one-line summary when work finishes, naming the project. Configurable voice and language.", + "description": "Spoken voice notifications via sag (ElevenLabs TTS): skill-driven, Claude calls sag directly to speak a short alert just before it asks you something and a one-line summary when work finishes, naming the project. Configurable voice and language.", + "version": "2.1.2", + "category": "UI", "logo": "./sag-notify/assets/logo.svg" }, { "name": "build-macos-apps", "source": "./build-macos-apps", "description": "Build, debug, instrument, and implement macOS apps with SwiftUI and AppKit guidance, codesigning, packaging, and telemetry workflows.", + "version": "1.0.1", + "category": "Development", "logo": "./build-macos-apps/assets/logo.svg" }, { "name": "build-ios-apps", "source": "./build-ios-apps", "description": "Build, profile, debug, and refine iOS apps with SwiftUI and Xcode workflows — App Intents, Simulator debugging, performance profiling, memory leak detection, and on-device AI with Apple Intelligence, Foundation Models, and Core AI.", + "version": "1.0.1", + "category": "Development", "logo": "./build-ios-apps/assets/logo.svg" }, { "name": "agent-loop", "source": "./agent-loop", - "description": "Continuous agent loop for overnight/day repo maintenance. Triage, autoreview, browser automation, and parallel agent work. Wake every 5 min, dispatch to threads, land autonomously.", + "description": "Continuous agent loop for overnight/day repository maintenance. Orchestrates triage, autoreview, browser automation, and parallel agent work across threads. Wake every 5 min, direct work, land autonomously.", + "version": "0.4.0", + "category": "Automation", "logo": "./agent-loop/assets/logo.svg" }, { "name": "kb", "source": "./kb", "description": "Knowledge base maintenance skills. Initialize a shared-brain kb, then consolidate, dedupe, prune, refresh, and forget notes in a markdown KB.", + "version": "1.1.0", + "category": "Productivity", "logo": "./kb/assets/logo.svg" }, { "name": "okf", "source": "./okf", "description": "Open Knowledge Format (OKF) tooling. Author, initialize, validate, render, and refactor knowledge into vendor-neutral OKF v0.1 bundles: markdown files with YAML frontmatter.", + "version": "1.1.0", + "category": "Productivity", "logo": "./okf/assets/logo.svg" }, - { - "name": "unsloth-training", - "source": "./unsloth-training", - "description": "Fine-tune LLMs with Unsloth using GRPO or SFT. Includes dataset preparation, synthetic data generation, environment flags, MLX (Apple Silicon), FP8, vision models, mobile export, GGUF.", - "logo": "./unsloth-training/assets/logo.svg" - }, { "name": "command-code", "source": "./command-code", - "description": "Drive the Command Code CLI (`cmd`) and orchestrate it as a headless sub-agent. Fan out `cmd -p --yolo --max-turns 100000` workers across isolated git worktrees to implement issues and tasks in parallel, each committed to its own branch for review.", + "description": "Drive the Command Code CLI (`cmd`) and orchestrate it as a headless sub-agent — fan out `cmd -p --yolo --max-turns 100000` workers across isolated git worktrees to implement issues and tasks in parallel.", + "version": "1.0.0", + "category": "Development", "logo": "./command-code/assets/logo.svg" } ] diff --git a/.cursor-plugin/marketplace.json b/.cursor-plugin/marketplace.json new file mode 100644 index 0000000..93a71b3 --- /dev/null +++ b/.cursor-plugin/marketplace.json @@ -0,0 +1,116 @@ +{ + "name": "duyet-claude-plugins", + "owner": { + "name": "duyet" + }, + "metadata": { + "description": "Plugins for Claude Code, Codex, Cursor, Grok Build, and Grok Bot: agent workflows, git automation, and developer tools." + }, + "plugins": [ + { + "name": "team-agents", + "source": "team-agents", + "description": "Leader, Senior Engineer, and Junior Engineer agents for coordinated parallel task execution" + }, + { + "name": "commit", + "source": "commit", + "description": "Create a Git commit with semantic commit message format and PR workflow with templates" + }, + { + "name": "frontend-design", + "source": "frontend-design", + "description": "Create distinctive, production-grade frontend interfaces avoiding AI slop aesthetics" + }, + { + "name": "interview", + "source": "interview", + "description": "Conduct in-depth requirements interviews using Socratic questioning" + }, + { + "name": "statusline", + "source": "statusline", + "description": "Configurable status bar showing context usage, API rate limits, git branch, and active tools" + }, + { + "name": "orchestration", + "source": "orchestration", + "description": "Orchestrator skill for managing parallel agent workstreams" + }, + { + "name": "github", + "source": "github", + "description": "GitHub operations using gh CLI - PRs, issues, workflows, batch operations, PR babysitting with AI review bot integration, and smart branch detection" + }, + { + "name": "fix", + "source": "fix", + "description": "Fix issues, tests, and CI failures with intelligent problem detection" + }, + { + "name": "clickhouse", + "source": "clickhouse", + "description": "Comprehensive ClickHouse knowledge base from Altinity KB + official docs" + }, + { + "name": "prompt-engineering", + "source": "prompt-engineering", + "description": "Prompt engineering techniques for Grok, Claude, and Gemini LLMs" + }, + { + "name": "clickhouse-monitoring", + "source": "clickhouse-monitoring", + "description": "Agent Skill for the ClickHouse Monitor dashboard - a real-time monitoring and observability tool for ClickHouse clusters" + }, + { + "name": "unsloth-training", + "source": "unsloth-training", + "description": "Fine-tune LLMs with Unsloth using GRPO or SFT. Dataset prep, synthetic data, environment flags, MLX (Apple Silicon), FP8, vision, mobile export, GGUF." + }, + { + "name": "good-html", + "source": "good-html", + "description": "Generate or review high-density, interactive, self-contained HTML artifacts based on Thariq Shihipar's patterns." + }, + { + "name": "anyrouter", + "source": "anyrouter", + "description": "Wire AnyRouter into coding agents. Universal OpenAI-compatible LLM gateway for 150+ models, migration recipes from Anthropic/OpenAI/OpenRouter, and a remote MCP server for keys and credits." + }, + { + "name": "sag-notify", + "source": "sag-notify", + "description": "Spoken voice notifications via sag (ElevenLabs TTS): skill-driven, Claude calls sag directly to speak a short alert just before it asks you something and a one-line summary when work finishes, naming the project. Configurable voice and language." + }, + { + "name": "build-macos-apps", + "source": "build-macos-apps", + "description": "Build, debug, instrument, and implement macOS apps with SwiftUI and AppKit guidance, codesigning, packaging, and telemetry workflows." + }, + { + "name": "build-ios-apps", + "source": "build-ios-apps", + "description": "Build, profile, debug, and refine iOS apps with SwiftUI and Xcode workflows — App Intents, Simulator debugging, performance profiling, memory leak detection, and on-device AI with Apple Intelligence, Foundation Models, and Core AI." + }, + { + "name": "agent-loop", + "source": "agent-loop", + "description": "Continuous agent loop for overnight/day repository maintenance. Orchestrates triage, autoreview, browser automation, and parallel agent work across threads. Wake every 5 min, direct work, land autonomously." + }, + { + "name": "kb", + "source": "kb", + "description": "Knowledge base maintenance skills. Initialize a shared-brain kb, then consolidate, dedupe, prune, refresh, and forget notes in a markdown KB." + }, + { + "name": "okf", + "source": "okf", + "description": "Open Knowledge Format (OKF) tooling. Author, initialize, validate, render, and refactor knowledge into vendor-neutral OKF v0.1 bundles: markdown files with YAML frontmatter." + }, + { + "name": "command-code", + "source": "command-code", + "description": "Drive the Command Code CLI (`cmd`) and orchestrate it as a headless sub-agent — fan out `cmd -p --yolo --max-turns 100000` workers across isolated git worktrees to implement issues and tasks in parallel." + } + ] +} diff --git a/.grok-plugin/marketplace.json b/.grok-plugin/marketplace.json index bb74b6c..8b0929d 100644 --- a/.grok-plugin/marketplace.json +++ b/.grok-plugin/marketplace.json @@ -1,6 +1,6 @@ { "name": "duyet-claude-plugins", - "description": "Production-quality plugins for Grok Build and Grok Bot — the same pack as Claude Code and Codex.", + "description": "Plugins for Claude Code, Codex, Cursor, Grok Build, and Grok Bot: agent workflows, git automation, and developer tools.", "owner": { "name": "duyet", "url": "https://github.com/duyet" @@ -8,272 +8,263 @@ "plugins": [ { "name": "team-agents", - "description": "Leader and Senior Engineer agents for coordinated parallel task execution. Leader breaks down complex tasks and delegates to multiple senior engineers working in parallel.", - "category": "agents", + "description": "Leader, Senior Engineer, and Junior Engineer agents for coordinated parallel task execution", + "category": "Agents", "source": { "type": "local", "path": "./team-agents" }, "homepage": "https://github.com/duyet/codex-claude-plugins", - "keywords": ["team-agents"], + "keywords": [ + "team-agents" + ], "logo": "assets/logo.svg", "version": "1.9.1", "author": { - "name": "duyet" + "name": "duyet", + "url": "https://github.com/duyet" } }, { "name": "commit", "description": "Create a Git commit with semantic commit message format and PR workflow with templates", - "category": "git", + "category": "Git", "source": { "type": "local", "path": "./commit" }, "homepage": "https://github.com/duyet/codex-claude-plugins", - "keywords": ["commit"], + "keywords": [ + "commit" + ], "logo": "assets/logo.svg", "version": "1.3.2", "author": { - "name": "duyet" + "name": "duyet", + "url": "https://github.com/duyet" } }, { "name": "frontend-design", - "description": "Create distinctive, production-grade frontend interfaces avoiding AI slop aesthetics. Emphasizes shadcn/ui, Recharts, and bold design choices.", - "category": "design", + "description": "Create distinctive, production-grade frontend interfaces avoiding AI slop aesthetics", + "category": "Design", "source": { "type": "local", "path": "./frontend-design" }, "homepage": "https://github.com/duyet/codex-claude-plugins", - "keywords": ["frontend-design"], + "keywords": [ + "frontend-design" + ], "logo": "assets/logo.svg", "version": "1.4.0", "author": { "name": "duyet", - "email": "me@duyet.net" + "url": "https://github.com/duyet" } }, { "name": "interview", - "description": "Conduct in-depth requirements interviews using Socratic questioning to clarify implementation details before coding", - "category": "productivity", + "description": "Conduct in-depth requirements interviews using Socratic questioning", + "category": "Productivity", "source": { "type": "local", "path": "./interview" }, "homepage": "https://github.com/duyet/codex-claude-plugins", - "keywords": ["interview"], + "keywords": [ + "interview" + ], "logo": "assets/logo.svg", "version": "1.0.1", "author": { "name": "duyet", - "email": "me@duyet.net" + "url": "https://github.com/duyet" } }, { "name": "statusline", - "description": "Configurable multi-line status bar with context health, cache hit rate, session duration, API rate limits (Anthropic 5h/7d + z.ai GLM), git branch, and active tools. Supports 1/2/3 line layouts, icon themes, and template presets.", - "category": "ui", + "description": "Configurable status bar showing context usage, API rate limits, git branch, and active tools", + "category": "UI", "source": { "type": "local", "path": "./statusline" }, "homepage": "https://github.com/duyet/codex-claude-plugins", - "keywords": ["statusline"], + "keywords": [ + "statusline" + ], "logo": "assets/logo.svg", "version": "1.9.0", "author": { - "name": "duyet" + "name": "duyet", + "url": "https://github.com/duyet" } }, { "name": "orchestration", - "description": "Orchestrator skill for managing parallel agent workstreams. Transform complex requests into coordinated multi-agent execution with elegant result synthesis.", - "category": "agents", + "description": "Orchestrator skill for managing parallel agent workstreams", + "category": "Agents", "source": { "type": "local", "path": "./orchestration" }, "homepage": "https://github.com/duyet/codex-claude-plugins", - "keywords": ["orchestration"], + "keywords": [ + "orchestration" + ], "logo": "assets/logo.svg", "version": "1.1.0", "author": { - "name": "duyet" - } - }, - { - "name": "duyetbot", - "description": "Pragmatic software development companion with engineering discipline and transparent execution.", - "category": "productivity", - "source": { - "type": "local", - "path": "./duyetbot" - }, - "homepage": "https://github.com/duyet/codex-claude-plugins", - "keywords": ["duyetbot"], - "logo": "assets/logo.svg", - "version": "1.8.1", - "author": { - "name": "duyet" - } - }, - { - "name": "docs-generator", - "description": "Automatically generate and maintain plugin documentation (README.md, CLAUDE.md)", - "category": "docs", - "source": { - "type": "local", - "path": "./docs-generator" - }, - "homepage": "https://github.com/duyet/codex-claude-plugins", - "keywords": ["docs-generator"], - "logo": "assets/logo.svg", - "version": "1.0.1", - "author": { - "name": "duyet" + "name": "duyet", + "url": "https://github.com/duyet" } }, { "name": "github", - "description": "GitHub operations using gh CLI - PRs, workflows, issues, repositories, batch operations, PR babysitting with AI review bot integration, and smart branch detection", - "category": "git", + "description": "GitHub operations using gh CLI - PRs, issues, workflows, batch operations, PR babysitting with AI review bot integration, and smart branch detection", + "category": "Git", "source": { "type": "local", "path": "./github" }, "homepage": "https://github.com/duyet/codex-claude-plugins", - "keywords": ["github"], + "keywords": [ + "github" + ], "logo": "assets/logo.svg", "version": "1.4.2", "author": { - "name": "duyetbot" + "name": "duyet", + "url": "https://github.com/duyet" } }, { "name": "fix", - "description": "Fix issues, tests, and CI failures with intelligent problem detection and resolution", - "category": "productivity", + "description": "Fix issues, tests, and CI failures with intelligent problem detection", + "category": "Productivity", "source": { "type": "local", "path": "./fix" }, "homepage": "https://github.com/duyet/codex-claude-plugins", - "keywords": ["fix"], + "keywords": [ + "fix" + ], "logo": "assets/logo.svg", "version": "1.0.1", "author": { - "name": "duyet" - } - }, - { - "name": "simplify", - "description": "Review changed code for reuse, quality, and efficiency, then simplify issues found", - "category": "productivity", - "source": { - "type": "local", - "path": "./simplify" - }, - "homepage": "https://github.com/duyet/codex-claude-plugins", - "keywords": ["simplify"], - "logo": "assets/logo.svg", - "version": "1.0.1", - "author": { - "name": "duyet" + "name": "duyet", + "url": "https://github.com/duyet" } }, { "name": "clickhouse", - "description": "ClickHouse expertise with 28 atomic review rules + 15 deep reference files. Rules synced with official ClickHouse/agent-skills repository. Schema design, query optimization, insert strategy, cluster management, backups, monitoring, and security best practices.", - "category": "database", + "description": "Comprehensive ClickHouse knowledge base from Altinity KB + official docs", + "category": "Database", "source": { "type": "local", "path": "./clickhouse" }, "homepage": "https://github.com/duyet/codex-claude-plugins", - "keywords": ["clickhouse"], + "keywords": [ + "clickhouse" + ], "logo": "assets/logo.svg", "version": "1.4.1", "author": { - "name": "duyetbot" + "name": "duyet", + "url": "https://github.com/duyet" } }, { "name": "prompt-engineering", - "description": "Prompt engineering skills for Grok, Claude, and Gemini LLMs with model-specific guidance and universal techniques", - "category": "productivity", + "description": "Prompt engineering techniques for Grok, Claude, and Gemini LLMs", + "category": "Productivity", "source": { "type": "local", "path": "./prompt-engineering" }, "homepage": "https://github.com/duyet/codex-claude-plugins", - "keywords": ["prompt-engineering"], + "keywords": [ + "prompt-engineering" + ], "logo": "assets/logo.svg", "version": "1.1.1", "author": { - "name": "duyetbot" + "name": "duyet", + "url": "https://github.com/duyet" } }, { "name": "clickhouse-monitoring", - "description": "Agent Skill for the ClickHouse Monitor dashboard - a real-time monitoring and observability tool for ClickHouse clusters. Covers 45 dashboard pages, query performance analysis, table management, and API integration.", - "category": "monitoring", + "description": "Agent Skill for the ClickHouse Monitor dashboard - a real-time monitoring and observability tool for ClickHouse clusters", + "category": "Monitoring", "source": { "type": "local", "path": "./clickhouse-monitoring" }, "homepage": "https://github.com/duyet/codex-claude-plugins", - "keywords": ["clickhouse-monitoring"], + "keywords": [ + "clickhouse-monitoring" + ], "logo": "assets/logo.svg", "version": "1.1.1", "author": { - "name": "duyet" + "name": "duyet", + "url": "https://github.com/duyet" } }, { "name": "unsloth-training", - "description": "Fine-tune LLMs with Unsloth using GRPO or SFT. Includes dataset preparation, synthetic data generation, environment flags, MLX (Apple Silicon), FP8, vision models, mobile export, GGUF.", - "category": "ml", + "description": "Fine-tune LLMs with Unsloth using GRPO or SFT. Dataset prep, synthetic data, environment flags, MLX (Apple Silicon), FP8, vision, mobile export, GGUF.", + "category": "ML", "source": { "type": "local", "path": "./unsloth-training" }, "homepage": "https://github.com/duyet/codex-claude-plugins", - "keywords": ["unsloth-training"], + "keywords": [ + "unsloth-training" + ], "logo": "assets/logo.svg", "version": "1.0.2", "author": { - "name": "duyet" + "name": "duyet", + "url": "https://github.com/duyet" } }, { "name": "good-html", - "description": "Generate high-density, interactive, self-contained HTML artifacts based on Thariq Shihipar's patterns. Optimized for engineering tasks, PR reviews, and research reports.", - "category": "design", + "description": "Generate or review high-density, interactive, self-contained HTML artifacts based on Thariq Shihipar's patterns.", + "category": "Design", "source": { "type": "local", "path": "./good-html" }, "homepage": "https://github.com/duyet/codex-claude-plugins", - "keywords": ["good-html"], + "keywords": [ + "good-html" + ], "logo": "assets/logo.svg", "version": "1.0.0", "author": { - "name": "Gemini CLI" + "name": "duyet", + "url": "https://github.com/duyet" } }, { "name": "anyrouter", - "description": "Wire AnyRouter into Claude Code, Codex, Cursor, and other coding agents. Universal OpenAI-compatible router for 150+ models, with migration recipes from Anthropic, OpenAI, and OpenRouter, plus a remote MCP server for key and credit management.", - "category": "ai", + "description": "Wire AnyRouter into coding agents. Universal OpenAI-compatible LLM gateway for 150+ models, migration recipes from Anthropic/OpenAI/OpenRouter, and a remote MCP server for keys and credits.", + "category": "AI", "source": { "type": "local", "path": "./anyrouter" }, - "homepage": "https://anyrouter.dev", - "keywords": ["anyrouter"], + "homepage": "https://github.com/duyet/codex-claude-plugins", + "keywords": [ + "anyrouter" + ], "logo": "assets/logo.svg", "version": "1.0.1", "author": { @@ -283,30 +274,35 @@ }, { "name": "sag-notify", - "description": "Spoken voice notifications via sag (ElevenLabs TTS). Skill-driven: Claude calls sag directly to speak a short alert just before it asks you something, and a one-line summary when work finishes — naming the project. Configurable voice and language.", - "category": "ui", + "description": "Spoken voice notifications via sag (ElevenLabs TTS): skill-driven, Claude calls sag directly to speak a short alert just before it asks you something and a one-line summary when work finishes, naming the project. Configurable voice and language.", + "category": "UI", "source": { "type": "local", "path": "./sag-notify" }, "homepage": "https://github.com/duyet/codex-claude-plugins", - "keywords": ["sag-notify"], + "keywords": [ + "sag-notify" + ], "logo": "assets/logo.svg", "version": "2.1.2", "author": { - "name": "duyet" + "name": "duyet", + "url": "https://github.com/duyet" } }, { "name": "build-macos-apps", "description": "Build, debug, instrument, and implement macOS apps with SwiftUI and AppKit guidance, codesigning, packaging, and telemetry workflows.", - "category": "development", + "category": "Development", "source": { "type": "local", "path": "./build-macos-apps" }, "homepage": "https://github.com/duyet/codex-claude-plugins", - "keywords": ["build-macos-apps"], + "keywords": [ + "build-macos-apps" + ], "logo": "assets/logo.svg", "version": "1.0.1", "author": { @@ -317,13 +313,15 @@ { "name": "build-ios-apps", "description": "Build, profile, debug, and refine iOS apps with SwiftUI and Xcode workflows — App Intents, Simulator debugging, performance profiling, memory leak detection, and on-device AI with Apple Intelligence, Foundation Models, and Core AI.", - "category": "development", + "category": "Development", "source": { "type": "local", "path": "./build-ios-apps" }, "homepage": "https://github.com/duyet/codex-claude-plugins", - "keywords": ["build-ios-apps"], + "keywords": [ + "build-ios-apps" + ], "logo": "assets/logo.svg", "version": "1.0.1", "author": { @@ -333,30 +331,35 @@ }, { "name": "agent-loop", - "description": "Continuous agent loop for overnight/day repository maintenance. Auto-detects and resumes from saved state. Orchestrates triage, autoreview, browser automation, and parallel agent work across threads. Wake every 5 min, direct work to threads, land autonomously.", - "category": "automation", + "description": "Continuous agent loop for overnight/day repository maintenance. Orchestrates triage, autoreview, browser automation, and parallel agent work across threads. Wake every 5 min, direct work, land autonomously.", + "category": "Automation", "source": { "type": "local", "path": "./agent-loop" }, "homepage": "https://github.com/duyet/codex-claude-plugins", - "keywords": ["agent-loop"], + "keywords": [ + "agent-loop" + ], "logo": "assets/logo.svg", "version": "0.4.0", "author": { - "name": "duyetbot" + "name": "duyet", + "url": "https://github.com/duyet" } }, { "name": "kb", "description": "Knowledge base maintenance skills. Initialize a shared-brain kb, then consolidate, dedupe, prune, refresh, and forget notes in a markdown KB.", - "category": "productivity", + "category": "Productivity", "source": { "type": "local", "path": "./kb" }, "homepage": "https://github.com/duyet/codex-claude-plugins", - "keywords": ["kb"], + "keywords": [ + "kb" + ], "logo": "assets/logo.svg", "version": "1.1.0", "author": { @@ -367,13 +370,15 @@ { "name": "okf", "description": "Open Knowledge Format (OKF) tooling. Author, initialize, validate, render, and refactor knowledge into vendor-neutral OKF v0.1 bundles: markdown files with YAML frontmatter.", - "category": "productivity", + "category": "Productivity", "source": { "type": "local", "path": "./okf" }, "homepage": "https://github.com/duyet/codex-claude-plugins", - "keywords": ["okf"], + "keywords": [ + "okf" + ], "logo": "assets/logo.svg", "version": "1.1.0", "author": { @@ -383,14 +388,16 @@ }, { "name": "command-code", - "description": "Drive the Command Code CLI (`cmd`) and orchestrate it as a headless sub-agent. Skill + /command-code:dispatch command + cmd-dispatcher agent for fanning out `cmd -p --yolo --max-turns 100000` workers across isolated git worktrees to implement issues and tasks in parallel.", - "category": "development", + "description": "Drive the Command Code CLI (`cmd`) and orchestrate it as a headless sub-agent — fan out `cmd -p --yolo --max-turns 100000` workers across isolated git worktrees to implement issues and tasks in parallel.", + "category": "Development", "source": { "type": "local", "path": "./command-code" }, - "homepage": "https://github.com/duyet/claude-plugins", - "keywords": ["command-code"], + "homepage": "https://github.com/duyet/codex-claude-plugins", + "keywords": [ + "command-code" + ], "logo": "assets/logo.svg", "version": "1.0.0", "author": { diff --git a/agent-loop/.antigravity-plugin/plugin.json b/agent-loop/.antigravity-plugin/plugin.json index fad7937..fb73e41 100644 --- a/agent-loop/.antigravity-plugin/plugin.json +++ b/agent-loop/.antigravity-plugin/plugin.json @@ -1,38 +1,23 @@ { "name": "agent-loop", "version": "0.4.0", - "description": "Continuous agent loop for overnight/day repository maintenance. Auto-detects and resumes from saved state. Orchestrates triage, autoreview, browser automation, and parallel agent work across threads. Wake every 5 min, direct work to threads, land autonomously.", + "description": "Continuous agent loop for overnight/day repository maintenance. Orchestrates triage, autoreview, browser automation, and parallel agent work across threads. Wake every 5 min, direct work, land autonomously.", "author": { - "name": "duyetbot" + "name": "duyet", + "url": "https://github.com/duyet" }, "license": "MIT", "skills": "./skills/", "commands": "./commands/", - "antigravity": { - "skills": [ - "agent-loop-orchestrator", - "agent-loop-triage", - "agent-loop-autoreview", - "agent-loop-browser" - ], - "commands": [ - "agent-loop:start", - "agent-loop:stop", - "agent-loop:status", - "agent-loop:inspect", - "agent-loop:reset", - "agent-loop:restore", - "agent-loop:triage", - "agent-loop:autoreview", - "agent-loop:resume" - ] - }, "interface": { "displayName": "Agent Loop", - "shortDescription": "Continuous overnight/day repo maintenance with autonomous agent loops. Triage, autoreview, browser automation, and parallel agent work.", - "developerName": "duyetbot", + "shortDescription": "Continuous agent loop for overnight/day repository maintenance. Orchestrates triage, autoreview, browser automation, and parallel agent work across threads. Wake every 5 min, direct work, land autonomously.", + "developerName": "duyet", "category": "Automation", - "capabilities": ["Skill", "Command"], + "capabilities": [ + "Skill", + "Command" + ], "logo": "./assets/logo.svg", "composerIcon": "./assets/logo.svg" } diff --git a/agent-loop/.claude-plugin/plugin.json b/agent-loop/.claude-plugin/plugin.json index 0190823..cc01ede 100644 --- a/agent-loop/.claude-plugin/plugin.json +++ b/agent-loop/.claude-plugin/plugin.json @@ -1,10 +1,12 @@ { "name": "agent-loop", "version": "0.4.0", - "description": "Continuous agent loop for overnight/day repository maintenance. Auto-detects and resumes from saved state. Orchestrates triage, autoreview, browser automation, and parallel agent work across threads. Wake every 5 min, direct work to threads, land autonomously.", + "description": "Continuous agent loop for overnight/day repository maintenance. Orchestrates triage, autoreview, browser automation, and parallel agent work across threads. Wake every 5 min, direct work, land autonomously.", "author": { - "name": "duyetbot" + "name": "duyet", + "url": "https://github.com/duyet" }, "license": "MIT", + "homepage": "https://github.com/duyet/codex-claude-plugins/tree/master/agent-loop", "logo": "./assets/logo.svg" } diff --git a/agent-loop/.codex-plugin/plugin.json b/agent-loop/.codex-plugin/plugin.json index 9197d0e..fb73e41 100644 --- a/agent-loop/.codex-plugin/plugin.json +++ b/agent-loop/.codex-plugin/plugin.json @@ -1,37 +1,23 @@ { "name": "agent-loop", "version": "0.4.0", - "description": "Continuous agent loop for overnight/day repository maintenance. Auto-detects and resumes from saved state. Orchestrates triage, autoreview, browser automation, and parallel agent work across threads. Wake every 5 min, direct work to threads, land autonomously.", + "description": "Continuous agent loop for overnight/day repository maintenance. Orchestrates triage, autoreview, browser automation, and parallel agent work across threads. Wake every 5 min, direct work, land autonomously.", "author": { - "name": "duyetbot" + "name": "duyet", + "url": "https://github.com/duyet" }, "license": "MIT", "skills": "./skills/", - "codex": { - "skills": [ - "agent-loop-orchestrator", - "agent-loop-triage", - "agent-loop-autoreview", - "agent-loop-browser" - ], - "commands": [ - "agent-loop:start", - "agent-loop:stop", - "agent-loop:status", - "agent-loop:inspect", - "agent-loop:reset", - "agent-loop:restore", - "agent-loop:triage", - "agent-loop:autoreview", - "agent-loop:resume" - ] - }, + "commands": "./commands/", "interface": { "displayName": "Agent Loop", - "shortDescription": "Continuous overnight/day repo maintenance with autonomous agent loops. Triage, autoreview, browser automation, and parallel agent work.", - "developerName": "duyetbot", + "shortDescription": "Continuous agent loop for overnight/day repository maintenance. Orchestrates triage, autoreview, browser automation, and parallel agent work across threads. Wake every 5 min, direct work, land autonomously.", + "developerName": "duyet", "category": "Automation", - "capabilities": ["Skill", "Command"], + "capabilities": [ + "Skill", + "Command" + ], "logo": "./assets/logo.svg", "composerIcon": "./assets/logo.svg" } diff --git a/agent-loop/.cursor-plugin/plugin.json b/agent-loop/.cursor-plugin/plugin.json new file mode 100644 index 0000000..b41303a --- /dev/null +++ b/agent-loop/.cursor-plugin/plugin.json @@ -0,0 +1,16 @@ +{ + "name": "agent-loop", + "version": "0.4.0", + "description": "Continuous agent loop for overnight/day repository maintenance. Orchestrates triage, autoreview, browser automation, and parallel agent work across threads. Wake every 5 min, direct work, land autonomously.", + "author": { + "name": "duyet" + }, + "license": "MIT", + "displayName": "Agent Loop", + "homepage": "https://github.com/duyet/codex-claude-plugins/tree/master/agent-loop", + "repository": "https://github.com/duyet/codex-claude-plugins", + "logo": "./assets/logo.svg", + "category": "Automation", + "skills": "./skills/", + "commands": "./commands/" +} diff --git a/agent-loop/.grok-build-plugin/plugin.json b/agent-loop/.grok-build-plugin/plugin.json index 75c0a8a..5244f30 100644 --- a/agent-loop/.grok-build-plugin/plugin.json +++ b/agent-loop/.grok-build-plugin/plugin.json @@ -1,39 +1,25 @@ { "name": "agent-loop", "version": "0.4.0", - "description": "Continuous agent loop for overnight/day repository maintenance. Auto-detects and resumes from saved state. Orchestrates triage, autoreview, browser automation, and parallel agent work across threads. Wake every 5 min, direct work to threads, land autonomously.", + "description": "Continuous agent loop for overnight/day repository maintenance. Orchestrates triage, autoreview, browser automation, and parallel agent work across threads. Wake every 5 min, direct work, land autonomously.", "author": { - "name": "duyetbot" + "name": "duyet", + "url": "https://github.com/duyet" }, "license": "MIT", + "logo": "./assets/logo.svg", "skills": "./skills/", + "commands": "./commands/", "interface": { "displayName": "Agent Loop", - "shortDescription": "Continuous overnight/day repo maintenance with autonomous agent loops. Triage, autoreview, browser automation, and parallel agent work.", - "developerName": "duyetbot", + "shortDescription": "Continuous agent loop for overnight/day repository maintenance. Orchestrates triage, autoreview, browser automation, and parallel agent work across threads. Wake every 5 min, direct work, land autonomously.", + "developerName": "duyet", "category": "Automation", - "capabilities": ["Skill", "Command"], + "capabilities": [ + "Skill", + "Command" + ], "logo": "./assets/logo.svg", "composerIcon": "./assets/logo.svg" - }, - "logo": "assets/logo.svg", - "grok-build": { - "skills": [ - "agent-loop-orchestrator", - "agent-loop-triage", - "agent-loop-autoreview", - "agent-loop-browser" - ], - "commands": [ - "agent-loop:start", - "agent-loop:stop", - "agent-loop:status", - "agent-loop:inspect", - "agent-loop:reset", - "agent-loop:restore", - "agent-loop:triage", - "agent-loop:autoreview", - "agent-loop:resume" - ] } } diff --git a/agent-loop/.grok-plugin/plugin.json b/agent-loop/.grok-plugin/plugin.json index be9a2ec..8f93bb8 100644 --- a/agent-loop/.grok-plugin/plugin.json +++ b/agent-loop/.grok-plugin/plugin.json @@ -1,13 +1,16 @@ { "name": "agent-loop", "version": "0.4.0", - "description": "Continuous agent loop for overnight/day repository maintenance. Auto-detects and resumes from saved state. Orchestrates triage, autoreview, browser automation, and parallel agent work across threads. Wake every 5 min, direct work to threads, land autonomously.", + "description": "Continuous agent loop for overnight/day repository maintenance. Orchestrates triage, autoreview, browser automation, and parallel agent work across threads. Wake every 5 min, direct work, land autonomously.", "author": { - "name": "duyetbot" + "name": "duyet", + "url": "https://github.com/duyet" }, "license": "MIT", - "logo": "assets/logo.svg", - "keywords": ["agent-loop", "grok", "grok-build", "grok-bot"], + "logo": "./assets/logo.svg", + "keywords": [ + "agent-loop" + ], "skills": "./skills/", "commands": "./commands/" } diff --git a/agent-loop/CLAUDE.md b/agent-loop/CLAUDE.md deleted file mode 100644 index 0f7af1d..0000000 --- a/agent-loop/CLAUDE.md +++ /dev/null @@ -1,85 +0,0 @@ -# Agent Loop Plugin - -Continuous overnight/day repository maintenance with autonomous agent loops. - -## Version - -0.4.0 - -## Plugin Structure - -```text -agent-loop/ -├── .antigravity-plugin/ -│ └── plugin.json # Antigravity manifest (version 0.3.0) -├── .claude-plugin/ -│ └── plugin.json # Manifest (version 0.3.0) -├── commands/ # Slash commands -├── skills/ # Reusable knowledge -│ ├── agent-loop-orchestrator/ -│ ├── agent-loop-triage/ -│ ├── agent-loop-autoreview/ -│ └── agent-loop-browser/ -└── README.md # Documentation -``` - -## Components - -### Commands - -#### Loop Control - -| Command | Description | -| ------------------------ | -------------------------------------------------------- | -| `/agent-loop:start` | Start or resume the continuous maintenance loop | -| `/agent-loop:stop` | Gracefully stop the loop and persist state | -| `/agent-loop:resume` | Resume from persisted state (explicit resume) | - -#### State Management - -| Command | Description | -| ------------------------ | -------------------------------------------------------- | -| `/agent-loop:status` | Quick status check (running, cycles, metrics) | -| `/agent-loop:inspect` | Deep inspection of state file (history, errors, details) | -| `/agent-loop:reset` | Clear state and start fresh (backs up old state) | -| `/agent-loop:restore` | Recover state from a backup | - -#### One-Shot Operations - -| Command | Description | -| ------------------------ | -------------------------------------------------------- | -| `/agent-loop:triage` | One-shot repo queue triage (doesn't start loop) | -| `/agent-loop:autoreview` | One-shot PR review and fix (doesn't start loop) | - -### Skills - -| Skill | Purpose | -| --------------------------- | ------------------------------------------------------ | -| **agent-loop-orchestrator** | Core loop: wait → triage → dispatch → monitor → report | -| **agent-loop-triage** | GitHub issue/PR queue scanning and classification | -| **agent-loop-autoreview** | Autonomous PR review, fix application, and merging | -| **agent-loop-browser** | Browser automation for live UI proof and verification | - -## Versioning - -Follow semantic versioning (semver): - -| Change Type | Version Bump | Example | -| ------------------------- | ------------ | ------------- | -| Bug fix, docs | Patch | 0.2.0 → 0.2.1 | -| New feature, minor change | Minor | 0.2.0 → 0.3.0 | -| Breaking change | Major | 0.2.0 → 1.0.0 | - -Always update `plugin.json` version when making changes. - -## Commit Convention - -Use semantic commits with plugin scope: - -```text -feat(agent-loop): add new feature -fix(agent-loop): fix bug -docs(agent-loop): update documentation -``` - -Co-author: `Co-Authored-By: duyetbot ` diff --git a/anyrouter/.claude-plugin/plugin.json b/anyrouter/.claude-plugin/plugin.json index 171cc2a..9b98893 100644 --- a/anyrouter/.claude-plugin/plugin.json +++ b/anyrouter/.claude-plugin/plugin.json @@ -1,13 +1,12 @@ { "name": "anyrouter", "version": "1.0.1", - "description": "Wire AnyRouter into Claude Code, Codex, Cursor, and other coding agents. Universal OpenAI-compatible router for 150+ models, with migration recipes from Anthropic, OpenAI, and OpenRouter, plus a remote MCP server for key and credit management.", + "description": "Wire AnyRouter into coding agents. Universal OpenAI-compatible LLM gateway for 150+ models, migration recipes from Anthropic/OpenAI/OpenRouter, and a remote MCP server for keys and credits.", "author": { "name": "duyet", "url": "https://github.com/duyet" }, - "homepage": "https://anyrouter.dev", - "repository": "https://github.com/duyet/codex-claude-plugins", "license": "MIT", + "homepage": "https://github.com/duyet/codex-claude-plugins/tree/master/anyrouter", "logo": "./assets/logo.svg" } diff --git a/anyrouter/.codex-plugin/plugin.json b/anyrouter/.codex-plugin/plugin.json index 0caf5ed..16f9033 100644 --- a/anyrouter/.codex-plugin/plugin.json +++ b/anyrouter/.codex-plugin/plugin.json @@ -1,25 +1,27 @@ { "name": "anyrouter", "version": "1.0.1", - "description": "Wire AnyRouter into Claude Code, Codex, Cursor, and other coding agents. Universal OpenAI-compatible router for 150+ models, with migration recipes from Anthropic, OpenAI, and OpenRouter, plus a remote MCP server for key and credit management.", + "description": "Wire AnyRouter into coding agents. Universal OpenAI-compatible LLM gateway for 150+ models, migration recipes from Anthropic/OpenAI/OpenRouter, and a remote MCP server for keys and credits.", "author": { - "name": "duyet" + "name": "duyet", + "url": "https://github.com/duyet" }, + "license": "MIT", "skills": "./skills/", "commands": "./commands/", "agents": "./agents/", - "mcp": "./.mcp.json", + "mcpServers": "./.mcp.json", "interface": { "displayName": "AnyRouter", - "shortDescription": "Universal OpenAI-compatible LLM router (150+ models). Migrate from Anthropic / OpenAI / OpenRouter; manage keys via MCP.", + "shortDescription": "Wire AnyRouter into coding agents. Universal OpenAI-compatible LLM gateway for 150+ models, migration recipes from Anthropic/OpenAI/OpenRouter, and a remote MCP server for keys and credits.", "developerName": "duyet", "category": "AI", - "capabilities": ["Skill", "Command", "Agent", "MCP"], - "links": { - "homepage": "https://anyrouter.dev", - "docs": "https://anyrouter.dev/docs", - "mcp": "https://anyrouter.dev/docs/mcp" - }, + "capabilities": [ + "Skill", + "Command", + "Agent", + "MCP" + ], "logo": "./assets/logo.svg", "composerIcon": "./assets/logo.svg" } diff --git a/anyrouter/.cursor-plugin/plugin.json b/anyrouter/.cursor-plugin/plugin.json new file mode 100644 index 0000000..f798038 --- /dev/null +++ b/anyrouter/.cursor-plugin/plugin.json @@ -0,0 +1,18 @@ +{ + "name": "anyrouter", + "version": "1.0.1", + "description": "Wire AnyRouter into coding agents. Universal OpenAI-compatible LLM gateway for 150+ models, migration recipes from Anthropic/OpenAI/OpenRouter, and a remote MCP server for keys and credits.", + "author": { + "name": "duyet" + }, + "license": "MIT", + "displayName": "AnyRouter", + "homepage": "https://github.com/duyet/codex-claude-plugins/tree/master/anyrouter", + "repository": "https://github.com/duyet/codex-claude-plugins", + "logo": "./assets/logo.svg", + "category": "AI", + "skills": "./skills/", + "commands": "./commands/", + "agents": "./agents/", + "mcpServers": "./.mcp.json" +} diff --git a/anyrouter/.grok-build-plugin/plugin.json b/anyrouter/.grok-build-plugin/plugin.json index add72ca..9b41ed5 100644 --- a/anyrouter/.grok-build-plugin/plugin.json +++ b/anyrouter/.grok-build-plugin/plugin.json @@ -1,27 +1,29 @@ { "name": "anyrouter", "version": "1.0.1", - "description": "Wire AnyRouter into Claude Code, Codex, Cursor, and other coding agents. Universal OpenAI-compatible router for 150+ models, with migration recipes from Anthropic, OpenAI, and OpenRouter, plus a remote MCP server for key and credit management.", + "description": "Wire AnyRouter into coding agents. Universal OpenAI-compatible LLM gateway for 150+ models, migration recipes from Anthropic/OpenAI/OpenRouter, and a remote MCP server for keys and credits.", "author": { - "name": "duyet" + "name": "duyet", + "url": "https://github.com/duyet" }, + "license": "MIT", + "logo": "./assets/logo.svg", "skills": "./skills/", "commands": "./commands/", "agents": "./agents/", - "mcp": "./.mcp.json", + "mcpServers": "./.mcp.json", "interface": { "displayName": "AnyRouter", - "shortDescription": "Universal OpenAI-compatible LLM router (150+ models). Migrate from Anthropic / OpenAI / OpenRouter; manage keys via MCP.", + "shortDescription": "Wire AnyRouter into coding agents. Universal OpenAI-compatible LLM gateway for 150+ models, migration recipes from Anthropic/OpenAI/OpenRouter, and a remote MCP server for keys and credits.", "developerName": "duyet", "category": "AI", - "capabilities": ["Skill", "Command", "Agent", "MCP"], - "links": { - "homepage": "https://anyrouter.dev", - "docs": "https://anyrouter.dev/docs", - "mcp": "https://anyrouter.dev/docs/mcp" - }, + "capabilities": [ + "Skill", + "Command", + "Agent", + "MCP" + ], "logo": "./assets/logo.svg", "composerIcon": "./assets/logo.svg" - }, - "logo": "assets/logo.svg" + } } diff --git a/anyrouter/.grok-plugin/plugin.json b/anyrouter/.grok-plugin/plugin.json index 85bec2a..b7c1917 100644 --- a/anyrouter/.grok-plugin/plugin.json +++ b/anyrouter/.grok-plugin/plugin.json @@ -1,16 +1,16 @@ { "name": "anyrouter", "version": "1.0.1", - "description": "Wire AnyRouter into Claude Code, Codex, Cursor, and other coding agents. Universal OpenAI-compatible router for 150+ models, with migration recipes from Anthropic, OpenAI, and OpenRouter, plus a remote MCP server for key and credit management.", + "description": "Wire AnyRouter into coding agents. Universal OpenAI-compatible LLM gateway for 150+ models, migration recipes from Anthropic/OpenAI/OpenRouter, and a remote MCP server for keys and credits.", "author": { "name": "duyet", "url": "https://github.com/duyet" }, "license": "MIT", - "homepage": "https://anyrouter.dev", - "repository": "https://github.com/duyet/codex-claude-plugins", - "logo": "assets/logo.svg", - "keywords": ["anyrouter", "grok", "grok-build", "grok-bot"], + "logo": "./assets/logo.svg", + "keywords": [ + "anyrouter" + ], "skills": "./skills/", "commands": "./commands/", "agents": "./agents/", diff --git a/build-ios-apps/.claude-plugin/plugin.json b/build-ios-apps/.claude-plugin/plugin.json index 2bb8ce4..8b0db3c 100644 --- a/build-ios-apps/.claude-plugin/plugin.json +++ b/build-ios-apps/.claude-plugin/plugin.json @@ -6,8 +6,7 @@ "name": "duyet", "url": "https://github.com/duyet" }, - "homepage": "https://github.com/duyet/codex-claude-plugins", - "repository": "https://github.com/duyet/codex-claude-plugins", "license": "MIT", + "homepage": "https://github.com/duyet/codex-claude-plugins/tree/master/build-ios-apps", "logo": "./assets/logo.svg" } diff --git a/build-ios-apps/.codex-plugin/plugin.json b/build-ios-apps/.codex-plugin/plugin.json index 1bf8ebe..a51a26d 100644 --- a/build-ios-apps/.codex-plugin/plugin.json +++ b/build-ios-apps/.codex-plugin/plugin.json @@ -3,19 +3,21 @@ "version": "1.0.1", "description": "Build, profile, debug, and refine iOS apps with SwiftUI and Xcode workflows — App Intents, Simulator debugging, performance profiling, memory leak detection, and on-device AI with Apple Intelligence, Foundation Models, and Core AI.", "author": { - "name": "duyet" + "name": "duyet", + "url": "https://github.com/duyet" }, + "license": "MIT", "skills": "./skills/", "agents": "./agents/", "interface": { "displayName": "Build iOS Apps", "shortDescription": "Build, profile, debug, and refine iOS apps with SwiftUI and Xcode workflows — App Intents, Simulator debugging, performance profiling, memory leak detection, and on-device AI with Apple Intelligence, Foundation Models, and Core AI.", "developerName": "duyet", - "category": "development", - "capabilities": ["Skill", "Agent"], - "links": { - "homepage": "https://github.com/duyet/codex-claude-plugins" - }, + "category": "Development", + "capabilities": [ + "Skill", + "Agent" + ], "logo": "./assets/logo.svg", "composerIcon": "./assets/logo.svg" } diff --git a/build-ios-apps/.cursor-plugin/plugin.json b/build-ios-apps/.cursor-plugin/plugin.json new file mode 100644 index 0000000..cd38c1d --- /dev/null +++ b/build-ios-apps/.cursor-plugin/plugin.json @@ -0,0 +1,16 @@ +{ + "name": "build-ios-apps", + "version": "1.0.1", + "description": "Build, profile, debug, and refine iOS apps with SwiftUI and Xcode workflows — App Intents, Simulator debugging, performance profiling, memory leak detection, and on-device AI with Apple Intelligence, Foundation Models, and Core AI.", + "author": { + "name": "duyet" + }, + "license": "MIT", + "displayName": "Build iOS Apps", + "homepage": "https://github.com/duyet/codex-claude-plugins/tree/master/build-ios-apps", + "repository": "https://github.com/duyet/codex-claude-plugins", + "logo": "./assets/logo.svg", + "category": "Development", + "skills": "./skills/", + "agents": "./agents/" +} diff --git a/build-ios-apps/.grok-build-plugin/plugin.json b/build-ios-apps/.grok-build-plugin/plugin.json index 9881ce0..6432e21 100644 --- a/build-ios-apps/.grok-build-plugin/plugin.json +++ b/build-ios-apps/.grok-build-plugin/plugin.json @@ -3,21 +3,23 @@ "version": "1.0.1", "description": "Build, profile, debug, and refine iOS apps with SwiftUI and Xcode workflows — App Intents, Simulator debugging, performance profiling, memory leak detection, and on-device AI with Apple Intelligence, Foundation Models, and Core AI.", "author": { - "name": "duyet" + "name": "duyet", + "url": "https://github.com/duyet" }, + "license": "MIT", + "logo": "./assets/logo.svg", "skills": "./skills/", "agents": "./agents/", "interface": { "displayName": "Build iOS Apps", "shortDescription": "Build, profile, debug, and refine iOS apps with SwiftUI and Xcode workflows — App Intents, Simulator debugging, performance profiling, memory leak detection, and on-device AI with Apple Intelligence, Foundation Models, and Core AI.", "developerName": "duyet", - "category": "development", - "capabilities": ["Skill", "Agent"], - "links": { - "homepage": "https://github.com/duyet/codex-claude-plugins" - }, + "category": "Development", + "capabilities": [ + "Skill", + "Agent" + ], "logo": "./assets/logo.svg", "composerIcon": "./assets/logo.svg" - }, - "logo": "assets/logo.svg" + } } diff --git a/build-ios-apps/.grok-plugin/plugin.json b/build-ios-apps/.grok-plugin/plugin.json index 5696ab2..84033e2 100644 --- a/build-ios-apps/.grok-plugin/plugin.json +++ b/build-ios-apps/.grok-plugin/plugin.json @@ -7,10 +7,10 @@ "url": "https://github.com/duyet" }, "license": "MIT", - "homepage": "https://github.com/duyet/codex-claude-plugins", - "repository": "https://github.com/duyet/codex-claude-plugins", - "logo": "assets/logo.svg", - "keywords": ["build-ios-apps", "grok", "grok-build", "grok-bot"], + "logo": "./assets/logo.svg", + "keywords": [ + "build-ios-apps" + ], "skills": "./skills/", "agents": "./agents/" } diff --git a/build-macos-apps/.claude-plugin/plugin.json b/build-macos-apps/.claude-plugin/plugin.json index eddeb75..a0239c0 100644 --- a/build-macos-apps/.claude-plugin/plugin.json +++ b/build-macos-apps/.claude-plugin/plugin.json @@ -6,8 +6,7 @@ "name": "duyet", "url": "https://github.com/duyet" }, - "homepage": "https://github.com/duyet/codex-claude-plugins", - "repository": "https://github.com/duyet/codex-claude-plugins", "license": "MIT", + "homepage": "https://github.com/duyet/codex-claude-plugins/tree/master/build-macos-apps", "logo": "./assets/logo.svg" } diff --git a/build-macos-apps/.codex-plugin/plugin.json b/build-macos-apps/.codex-plugin/plugin.json index c8eb112..c1e7a62 100644 --- a/build-macos-apps/.codex-plugin/plugin.json +++ b/build-macos-apps/.codex-plugin/plugin.json @@ -3,20 +3,23 @@ "version": "1.0.1", "description": "Build, debug, instrument, and implement macOS apps with SwiftUI and AppKit guidance, codesigning, packaging, and telemetry workflows.", "author": { - "name": "duyet" + "name": "duyet", + "url": "https://github.com/duyet" }, + "license": "MIT", "skills": "./skills/", "commands": "./commands/", "agents": "./agents/", "interface": { "displayName": "Build macOS Apps", - "shortDescription": "Build, debug, instrument, and implement macOS apps with SwiftUI and AppKit guidance", + "shortDescription": "Build, debug, instrument, and implement macOS apps with SwiftUI and AppKit guidance, codesigning, packaging, and telemetry workflows.", "developerName": "duyet", - "category": "development", - "capabilities": ["Skill", "Command", "Agent"], - "links": { - "homepage": "https://github.com/duyet/codex-claude-plugins" - }, + "category": "Development", + "capabilities": [ + "Skill", + "Command", + "Agent" + ], "logo": "./assets/logo.svg", "composerIcon": "./assets/logo.svg" } diff --git a/build-macos-apps/.cursor-plugin/plugin.json b/build-macos-apps/.cursor-plugin/plugin.json new file mode 100644 index 0000000..ab6aebe --- /dev/null +++ b/build-macos-apps/.cursor-plugin/plugin.json @@ -0,0 +1,17 @@ +{ + "name": "build-macos-apps", + "version": "1.0.1", + "description": "Build, debug, instrument, and implement macOS apps with SwiftUI and AppKit guidance, codesigning, packaging, and telemetry workflows.", + "author": { + "name": "duyet" + }, + "license": "MIT", + "displayName": "Build macOS Apps", + "homepage": "https://github.com/duyet/codex-claude-plugins/tree/master/build-macos-apps", + "repository": "https://github.com/duyet/codex-claude-plugins", + "logo": "./assets/logo.svg", + "category": "Development", + "skills": "./skills/", + "commands": "./commands/", + "agents": "./agents/" +} diff --git a/build-macos-apps/.grok-build-plugin/plugin.json b/build-macos-apps/.grok-build-plugin/plugin.json index 23648f8..bc83207 100644 --- a/build-macos-apps/.grok-build-plugin/plugin.json +++ b/build-macos-apps/.grok-build-plugin/plugin.json @@ -3,22 +3,25 @@ "version": "1.0.1", "description": "Build, debug, instrument, and implement macOS apps with SwiftUI and AppKit guidance, codesigning, packaging, and telemetry workflows.", "author": { - "name": "duyet" + "name": "duyet", + "url": "https://github.com/duyet" }, + "license": "MIT", + "logo": "./assets/logo.svg", "skills": "./skills/", "commands": "./commands/", "agents": "./agents/", "interface": { "displayName": "Build macOS Apps", - "shortDescription": "Build, debug, instrument, and implement macOS apps with SwiftUI and AppKit guidance", + "shortDescription": "Build, debug, instrument, and implement macOS apps with SwiftUI and AppKit guidance, codesigning, packaging, and telemetry workflows.", "developerName": "duyet", - "category": "development", - "capabilities": ["Skill", "Command", "Agent"], - "links": { - "homepage": "https://github.com/duyet/codex-claude-plugins" - }, + "category": "Development", + "capabilities": [ + "Skill", + "Command", + "Agent" + ], "logo": "./assets/logo.svg", "composerIcon": "./assets/logo.svg" - }, - "logo": "assets/logo.svg" + } } diff --git a/build-macos-apps/.grok-plugin/plugin.json b/build-macos-apps/.grok-plugin/plugin.json index d89ab76..4366691 100644 --- a/build-macos-apps/.grok-plugin/plugin.json +++ b/build-macos-apps/.grok-plugin/plugin.json @@ -7,10 +7,10 @@ "url": "https://github.com/duyet" }, "license": "MIT", - "homepage": "https://github.com/duyet/codex-claude-plugins", - "repository": "https://github.com/duyet/codex-claude-plugins", - "logo": "assets/logo.svg", - "keywords": ["build-macos-apps", "grok", "grok-build", "grok-bot"], + "logo": "./assets/logo.svg", + "keywords": [ + "build-macos-apps" + ], "skills": "./skills/", "commands": "./commands/", "agents": "./agents/" diff --git a/clickhouse-monitoring/.claude-plugin/plugin.json b/clickhouse-monitoring/.claude-plugin/plugin.json index 6b9c343..be0b9d2 100644 --- a/clickhouse-monitoring/.claude-plugin/plugin.json +++ b/clickhouse-monitoring/.claude-plugin/plugin.json @@ -1,9 +1,12 @@ { "name": "clickhouse-monitoring", "version": "1.1.1", - "description": "Agent Skill for the ClickHouse Monitor dashboard - a real-time monitoring and observability tool for ClickHouse clusters. Covers 45 dashboard pages, query performance analysis, table management, and API integration.", + "description": "Agent Skill for the ClickHouse Monitor dashboard - a real-time monitoring and observability tool for ClickHouse clusters", "author": { - "name": "duyet" + "name": "duyet", + "url": "https://github.com/duyet" }, + "license": "MIT", + "homepage": "https://github.com/duyet/codex-claude-plugins/tree/master/clickhouse-monitoring", "logo": "./assets/logo.svg" } diff --git a/clickhouse-monitoring/.codex-plugin/plugin.json b/clickhouse-monitoring/.codex-plugin/plugin.json index c007f88..cb4e766 100644 --- a/clickhouse-monitoring/.codex-plugin/plugin.json +++ b/clickhouse-monitoring/.codex-plugin/plugin.json @@ -1,17 +1,21 @@ { "name": "clickhouse-monitoring", "version": "1.1.1", - "description": "Agent Skill for the ClickHouse Monitor dashboard - a real-time monitoring and observability tool for ClickHouse clusters. Covers 45 dashboard pages, query performance analysis, table management, and API integration.", + "description": "Agent Skill for the ClickHouse Monitor dashboard - a real-time monitoring and observability tool for ClickHouse clusters", "author": { - "name": "duyet" + "name": "duyet", + "url": "https://github.com/duyet" }, + "license": "MIT", "skills": "./skills/", "interface": { "displayName": "Clickhouse Monitoring", - "shortDescription": "Agent Skill for the ClickHouse Monitor dashboard - a real-time monitoring and observability tool for ClickHouse clusters. Covers 45 dashboard pages, query performance analysis, table management, and API integration.", + "shortDescription": "Agent Skill for the ClickHouse Monitor dashboard - a real-time monitoring and observability tool for ClickHouse clusters", "developerName": "duyet", "category": "Monitoring", - "capabilities": ["Skill"], + "capabilities": [ + "Skill" + ], "logo": "./assets/logo.svg", "composerIcon": "./assets/logo.svg" } diff --git a/clickhouse-monitoring/.cursor-plugin/plugin.json b/clickhouse-monitoring/.cursor-plugin/plugin.json new file mode 100644 index 0000000..78346de --- /dev/null +++ b/clickhouse-monitoring/.cursor-plugin/plugin.json @@ -0,0 +1,15 @@ +{ + "name": "clickhouse-monitoring", + "version": "1.1.1", + "description": "Agent Skill for the ClickHouse Monitor dashboard - a real-time monitoring and observability tool for ClickHouse clusters", + "author": { + "name": "duyet" + }, + "license": "MIT", + "displayName": "Clickhouse Monitoring", + "homepage": "https://github.com/duyet/codex-claude-plugins/tree/master/clickhouse-monitoring", + "repository": "https://github.com/duyet/codex-claude-plugins", + "logo": "./assets/logo.svg", + "category": "Monitoring", + "skills": "./skills/" +} diff --git a/clickhouse-monitoring/.grok-build-plugin/plugin.json b/clickhouse-monitoring/.grok-build-plugin/plugin.json index 632bc18..c6f0dc1 100644 --- a/clickhouse-monitoring/.grok-build-plugin/plugin.json +++ b/clickhouse-monitoring/.grok-build-plugin/plugin.json @@ -1,19 +1,23 @@ { "name": "clickhouse-monitoring", "version": "1.1.1", - "description": "Agent Skill for the ClickHouse Monitor dashboard - a real-time monitoring and observability tool for ClickHouse clusters. Covers 45 dashboard pages, query performance analysis, table management, and API integration.", + "description": "Agent Skill for the ClickHouse Monitor dashboard - a real-time monitoring and observability tool for ClickHouse clusters", "author": { - "name": "duyet" + "name": "duyet", + "url": "https://github.com/duyet" }, + "license": "MIT", + "logo": "./assets/logo.svg", "skills": "./skills/", "interface": { "displayName": "Clickhouse Monitoring", - "shortDescription": "Agent Skill for the ClickHouse Monitor dashboard - a real-time monitoring and observability tool for ClickHouse clusters. Covers 45 dashboard pages, query performance analysis, table management, and API integration.", + "shortDescription": "Agent Skill for the ClickHouse Monitor dashboard - a real-time monitoring and observability tool for ClickHouse clusters", "developerName": "duyet", "category": "Monitoring", - "capabilities": ["Skill"], + "capabilities": [ + "Skill" + ], "logo": "./assets/logo.svg", "composerIcon": "./assets/logo.svg" - }, - "logo": "assets/logo.svg" + } } diff --git a/clickhouse-monitoring/.grok-plugin/plugin.json b/clickhouse-monitoring/.grok-plugin/plugin.json index 56aa9e7..0d60921 100644 --- a/clickhouse-monitoring/.grok-plugin/plugin.json +++ b/clickhouse-monitoring/.grok-plugin/plugin.json @@ -1,11 +1,15 @@ { "name": "clickhouse-monitoring", "version": "1.1.1", - "description": "Agent Skill for the ClickHouse Monitor dashboard - a real-time monitoring and observability tool for ClickHouse clusters. Covers 45 dashboard pages, query performance analysis, table management, and API integration.", + "description": "Agent Skill for the ClickHouse Monitor dashboard - a real-time monitoring and observability tool for ClickHouse clusters", "author": { - "name": "duyet" + "name": "duyet", + "url": "https://github.com/duyet" }, - "logo": "assets/logo.svg", - "keywords": ["clickhouse-monitoring", "grok", "grok-build", "grok-bot"], + "license": "MIT", + "logo": "./assets/logo.svg", + "keywords": [ + "clickhouse-monitoring" + ], "skills": "./skills/" } diff --git a/clickhouse/.claude-plugin/plugin.json b/clickhouse/.claude-plugin/plugin.json index cfbffb8..24f6b75 100644 --- a/clickhouse/.claude-plugin/plugin.json +++ b/clickhouse/.claude-plugin/plugin.json @@ -1,9 +1,12 @@ { "name": "clickhouse", "version": "1.4.1", - "description": "ClickHouse expertise with 28 atomic review rules + 15 deep reference files. Rules synced with official ClickHouse/agent-skills repository. Schema design, query optimization, insert strategy, cluster management, backups, monitoring, and security best practices.", + "description": "Comprehensive ClickHouse knowledge base from Altinity KB + official docs", "author": { - "name": "duyetbot" + "name": "duyet", + "url": "https://github.com/duyet" }, + "license": "MIT", + "homepage": "https://github.com/duyet/codex-claude-plugins/tree/master/clickhouse", "logo": "./assets/logo.svg" } diff --git a/clickhouse/.codex-plugin/plugin.json b/clickhouse/.codex-plugin/plugin.json index b31d1b7..e7a08fe 100644 --- a/clickhouse/.codex-plugin/plugin.json +++ b/clickhouse/.codex-plugin/plugin.json @@ -1,17 +1,21 @@ { "name": "clickhouse", "version": "1.4.1", - "description": "ClickHouse expertise with 28 atomic review rules + 15 deep reference files. Rules synced with official ClickHouse/agent-skills repository. Schema design, query optimization, insert strategy, cluster management, backups, monitoring, and security best practices.", + "description": "Comprehensive ClickHouse knowledge base from Altinity KB + official docs", "author": { - "name": "duyetbot" + "name": "duyet", + "url": "https://github.com/duyet" }, + "license": "MIT", "skills": "./skills/", "interface": { "displayName": "Clickhouse", - "shortDescription": "ClickHouse expertise with 28 atomic review rules + 15 deep reference files. Rules synced with official ClickHouse/agent-skills repository. Schema design, query optimization, insert strategy, cluster management, backups, monitoring, and security best practices.", - "developerName": "duyetbot", + "shortDescription": "Comprehensive ClickHouse knowledge base from Altinity KB + official docs", + "developerName": "duyet", "category": "Database", - "capabilities": ["Skill"], + "capabilities": [ + "Skill" + ], "logo": "./assets/logo.svg", "composerIcon": "./assets/logo.svg" } diff --git a/clickhouse/.cursor-plugin/plugin.json b/clickhouse/.cursor-plugin/plugin.json new file mode 100644 index 0000000..56be9a1 --- /dev/null +++ b/clickhouse/.cursor-plugin/plugin.json @@ -0,0 +1,15 @@ +{ + "name": "clickhouse", + "version": "1.4.1", + "description": "Comprehensive ClickHouse knowledge base from Altinity KB + official docs", + "author": { + "name": "duyet" + }, + "license": "MIT", + "displayName": "Clickhouse", + "homepage": "https://github.com/duyet/codex-claude-plugins/tree/master/clickhouse", + "repository": "https://github.com/duyet/codex-claude-plugins", + "logo": "./assets/logo.svg", + "category": "Database", + "skills": "./skills/" +} diff --git a/clickhouse/.grok-build-plugin/plugin.json b/clickhouse/.grok-build-plugin/plugin.json index 09b55ff..8001610 100644 --- a/clickhouse/.grok-build-plugin/plugin.json +++ b/clickhouse/.grok-build-plugin/plugin.json @@ -1,19 +1,23 @@ { "name": "clickhouse", "version": "1.4.1", - "description": "ClickHouse expertise with 28 atomic review rules + 15 deep reference files. Rules synced with official ClickHouse/agent-skills repository. Schema design, query optimization, insert strategy, cluster management, backups, monitoring, and security best practices.", + "description": "Comprehensive ClickHouse knowledge base from Altinity KB + official docs", "author": { - "name": "duyetbot" + "name": "duyet", + "url": "https://github.com/duyet" }, + "license": "MIT", + "logo": "./assets/logo.svg", "skills": "./skills/", "interface": { "displayName": "Clickhouse", - "shortDescription": "ClickHouse expertise with 28 atomic review rules + 15 deep reference files. Rules synced with official ClickHouse/agent-skills repository. Schema design, query optimization, insert strategy, cluster management, backups, monitoring, and security best practices.", - "developerName": "duyetbot", + "shortDescription": "Comprehensive ClickHouse knowledge base from Altinity KB + official docs", + "developerName": "duyet", "category": "Database", - "capabilities": ["Skill"], + "capabilities": [ + "Skill" + ], "logo": "./assets/logo.svg", "composerIcon": "./assets/logo.svg" - }, - "logo": "assets/logo.svg" + } } diff --git a/clickhouse/.grok-plugin/plugin.json b/clickhouse/.grok-plugin/plugin.json index 4e484b3..c292b74 100644 --- a/clickhouse/.grok-plugin/plugin.json +++ b/clickhouse/.grok-plugin/plugin.json @@ -1,11 +1,15 @@ { "name": "clickhouse", "version": "1.4.1", - "description": "ClickHouse expertise with 28 atomic review rules + 15 deep reference files. Rules synced with official ClickHouse/agent-skills repository. Schema design, query optimization, insert strategy, cluster management, backups, monitoring, and security best practices.", + "description": "Comprehensive ClickHouse knowledge base from Altinity KB + official docs", "author": { - "name": "duyetbot" + "name": "duyet", + "url": "https://github.com/duyet" }, - "logo": "assets/logo.svg", - "keywords": ["clickhouse", "grok", "grok-build", "grok-bot"], + "license": "MIT", + "logo": "./assets/logo.svg", + "keywords": [ + "clickhouse" + ], "skills": "./skills/" } diff --git a/command-code/.claude-plugin/plugin.json b/command-code/.claude-plugin/plugin.json index 07d20ef..87facc5 100644 --- a/command-code/.claude-plugin/plugin.json +++ b/command-code/.claude-plugin/plugin.json @@ -1,13 +1,12 @@ { "name": "command-code", "version": "1.0.0", - "description": "Drive the Command Code CLI (`cmd`) and orchestrate it as a headless sub-agent. Skill + /command-code:dispatch command + cmd-dispatcher agent for fanning out `cmd -p --yolo --max-turns 100000` workers across isolated git worktrees to implement issues and tasks in parallel.", + "description": "Drive the Command Code CLI (`cmd`) and orchestrate it as a headless sub-agent — fan out `cmd -p --yolo --max-turns 100000` workers across isolated git worktrees to implement issues and tasks in parallel.", "author": { "name": "duyet", "url": "https://github.com/duyet" }, - "homepage": "https://github.com/duyet/claude-plugins", - "repository": "https://github.com/duyet/codex-claude-plugins", "license": "MIT", + "homepage": "https://github.com/duyet/codex-claude-plugins/tree/master/command-code", "logo": "./assets/logo.svg" } diff --git a/command-code/.codex-plugin/plugin.json b/command-code/.codex-plugin/plugin.json index 772b60a..5609ed1 100644 --- a/command-code/.codex-plugin/plugin.json +++ b/command-code/.codex-plugin/plugin.json @@ -1,22 +1,25 @@ { "name": "command-code", "version": "1.0.0", - "description": "Drive the Command Code CLI (`cmd`) and orchestrate it as a headless sub-agent. Skill + /command-code:dispatch command + cmd-dispatcher agent for fanning out `cmd -p --yolo --max-turns 100000` workers across isolated git worktrees to implement issues and tasks in parallel.", + "description": "Drive the Command Code CLI (`cmd`) and orchestrate it as a headless sub-agent — fan out `cmd -p --yolo --max-turns 100000` workers across isolated git worktrees to implement issues and tasks in parallel.", "author": { - "name": "duyet" + "name": "duyet", + "url": "https://github.com/duyet" }, + "license": "MIT", "skills": "./skills/", "commands": "./commands/", "agents": "./agents/", "interface": { "displayName": "Command Code", - "shortDescription": "Drive & orchestrate the Command Code CLI (`cmd`) as a headless sub-agent.", + "shortDescription": "Drive the Command Code CLI (`cmd`) and orchestrate it as a headless sub-agent — fan out `cmd -p --yolo --max-turns 100000` workers across isolated git worktrees to implement issues and tasks in parallel.", "developerName": "duyet", - "category": "Developer Tools", - "capabilities": ["Skill", "Command", "Agent"], - "links": { - "homepage": "https://github.com/duyet/claude-plugins" - }, + "category": "Development", + "capabilities": [ + "Skill", + "Command", + "Agent" + ], "logo": "./assets/logo.svg", "composerIcon": "./assets/logo.svg" } diff --git a/command-code/.cursor-plugin/plugin.json b/command-code/.cursor-plugin/plugin.json new file mode 100644 index 0000000..0fdfdfc --- /dev/null +++ b/command-code/.cursor-plugin/plugin.json @@ -0,0 +1,17 @@ +{ + "name": "command-code", + "version": "1.0.0", + "description": "Drive the Command Code CLI (`cmd`) and orchestrate it as a headless sub-agent — fan out `cmd -p --yolo --max-turns 100000` workers across isolated git worktrees to implement issues and tasks in parallel.", + "author": { + "name": "duyet" + }, + "license": "MIT", + "displayName": "Command Code", + "homepage": "https://github.com/duyet/codex-claude-plugins/tree/master/command-code", + "repository": "https://github.com/duyet/codex-claude-plugins", + "logo": "./assets/logo.svg", + "category": "Development", + "skills": "./skills/", + "commands": "./commands/", + "agents": "./agents/" +} diff --git a/command-code/.grok-build-plugin/plugin.json b/command-code/.grok-build-plugin/plugin.json index 824f88e..c944665 100644 --- a/command-code/.grok-build-plugin/plugin.json +++ b/command-code/.grok-build-plugin/plugin.json @@ -1,24 +1,27 @@ { "name": "command-code", "version": "1.0.0", - "description": "Drive the Command Code CLI (`cmd`) and orchestrate it as a headless sub-agent. Skill + /command-code:dispatch command + cmd-dispatcher agent for fanning out `cmd -p --yolo --max-turns 100000` workers across isolated git worktrees to implement issues and tasks in parallel.", + "description": "Drive the Command Code CLI (`cmd`) and orchestrate it as a headless sub-agent — fan out `cmd -p --yolo --max-turns 100000` workers across isolated git worktrees to implement issues and tasks in parallel.", "author": { - "name": "duyet" + "name": "duyet", + "url": "https://github.com/duyet" }, + "license": "MIT", + "logo": "./assets/logo.svg", "skills": "./skills/", "commands": "./commands/", "agents": "./agents/", "interface": { "displayName": "Command Code", - "shortDescription": "Drive & orchestrate the Command Code CLI (`cmd`) as a headless sub-agent.", + "shortDescription": "Drive the Command Code CLI (`cmd`) and orchestrate it as a headless sub-agent — fan out `cmd -p --yolo --max-turns 100000` workers across isolated git worktrees to implement issues and tasks in parallel.", "developerName": "duyet", - "category": "Developer Tools", - "capabilities": ["Skill", "Command", "Agent"], - "links": { - "homepage": "https://github.com/duyet/claude-plugins" - }, + "category": "Development", + "capabilities": [ + "Skill", + "Command", + "Agent" + ], "logo": "./assets/logo.svg", "composerIcon": "./assets/logo.svg" - }, - "logo": "assets/logo.svg" + } } diff --git a/command-code/.grok-plugin/plugin.json b/command-code/.grok-plugin/plugin.json index d0b8f3d..000e00a 100644 --- a/command-code/.grok-plugin/plugin.json +++ b/command-code/.grok-plugin/plugin.json @@ -1,16 +1,16 @@ { "name": "command-code", "version": "1.0.0", - "description": "Drive the Command Code CLI (`cmd`) and orchestrate it as a headless sub-agent. Skill + /command-code:dispatch command + cmd-dispatcher agent for fanning out `cmd -p --yolo --max-turns 100000` workers across isolated git worktrees to implement issues and tasks in parallel.", + "description": "Drive the Command Code CLI (`cmd`) and orchestrate it as a headless sub-agent — fan out `cmd -p --yolo --max-turns 100000` workers across isolated git worktrees to implement issues and tasks in parallel.", "author": { "name": "duyet", "url": "https://github.com/duyet" }, "license": "MIT", - "homepage": "https://github.com/duyet/claude-plugins", - "repository": "https://github.com/duyet/codex-claude-plugins", - "logo": "assets/logo.svg", - "keywords": ["command-code", "grok", "grok-build", "grok-bot"], + "logo": "./assets/logo.svg", + "keywords": [ + "command-code" + ], "skills": "./skills/", "commands": "./commands/", "agents": "./agents/" diff --git a/commit/.claude-plugin/plugin.json b/commit/.claude-plugin/plugin.json index 5ea7c6c..e675a06 100644 --- a/commit/.claude-plugin/plugin.json +++ b/commit/.claude-plugin/plugin.json @@ -1,9 +1,12 @@ { "name": "commit", - "description": "Create a Git commit with semantic commit message format and PR workflow with templates", "version": "1.3.2", + "description": "Create a Git commit with semantic commit message format and PR workflow with templates", "author": { - "name": "duyet" + "name": "duyet", + "url": "https://github.com/duyet" }, + "license": "MIT", + "homepage": "https://github.com/duyet/codex-claude-plugins/tree/master/commit", "logo": "./assets/logo.svg" } diff --git a/commit/.codex-plugin/plugin.json b/commit/.codex-plugin/plugin.json index 842e4eb..1f2f1d2 100644 --- a/commit/.codex-plugin/plugin.json +++ b/commit/.codex-plugin/plugin.json @@ -3,15 +3,21 @@ "version": "1.3.2", "description": "Create a Git commit with semantic commit message format and PR workflow with templates", "author": { - "name": "duyet" + "name": "duyet", + "url": "https://github.com/duyet" }, + "license": "MIT", "skills": "./skills/", + "commands": "./commands/", "interface": { "displayName": "Commit", "shortDescription": "Create a Git commit with semantic commit message format and PR workflow with templates", "developerName": "duyet", "category": "Git", - "capabilities": ["Skill", "Command"], + "capabilities": [ + "Skill", + "Command" + ], "logo": "./assets/logo.svg", "composerIcon": "./assets/logo.svg" } diff --git a/commit/.cursor-plugin/plugin.json b/commit/.cursor-plugin/plugin.json new file mode 100644 index 0000000..9ef54c8 --- /dev/null +++ b/commit/.cursor-plugin/plugin.json @@ -0,0 +1,16 @@ +{ + "name": "commit", + "version": "1.3.2", + "description": "Create a Git commit with semantic commit message format and PR workflow with templates", + "author": { + "name": "duyet" + }, + "license": "MIT", + "displayName": "Commit", + "homepage": "https://github.com/duyet/codex-claude-plugins/tree/master/commit", + "repository": "https://github.com/duyet/codex-claude-plugins", + "logo": "./assets/logo.svg", + "category": "Git", + "skills": "./skills/", + "commands": "./commands/" +} diff --git a/commit/.grok-build-plugin/plugin.json b/commit/.grok-build-plugin/plugin.json index 090130f..97e56e3 100644 --- a/commit/.grok-build-plugin/plugin.json +++ b/commit/.grok-build-plugin/plugin.json @@ -3,17 +3,23 @@ "version": "1.3.2", "description": "Create a Git commit with semantic commit message format and PR workflow with templates", "author": { - "name": "duyet" + "name": "duyet", + "url": "https://github.com/duyet" }, + "license": "MIT", + "logo": "./assets/logo.svg", "skills": "./skills/", + "commands": "./commands/", "interface": { "displayName": "Commit", "shortDescription": "Create a Git commit with semantic commit message format and PR workflow with templates", "developerName": "duyet", "category": "Git", - "capabilities": ["Skill", "Command"], + "capabilities": [ + "Skill", + "Command" + ], "logo": "./assets/logo.svg", "composerIcon": "./assets/logo.svg" - }, - "logo": "assets/logo.svg" + } } diff --git a/commit/.grok-plugin/plugin.json b/commit/.grok-plugin/plugin.json index 3663b59..207b623 100644 --- a/commit/.grok-plugin/plugin.json +++ b/commit/.grok-plugin/plugin.json @@ -3,10 +3,14 @@ "version": "1.3.2", "description": "Create a Git commit with semantic commit message format and PR workflow with templates", "author": { - "name": "duyet" + "name": "duyet", + "url": "https://github.com/duyet" }, - "logo": "assets/logo.svg", - "keywords": ["commit", "grok", "grok-build", "grok-bot"], + "license": "MIT", + "logo": "./assets/logo.svg", + "keywords": [ + "commit" + ], "skills": "./skills/", "commands": "./commands/" } diff --git a/commit/CLAUDE.md b/commit/CLAUDE.md deleted file mode 100644 index 3be8710..0000000 --- a/commit/CLAUDE.md +++ /dev/null @@ -1,58 +0,0 @@ -# Commit Plugin - -Create a Git commit with semantic commit message format - -## Versioning - -Follow semantic versioning (semver) for this plugin: - -| Change Type | Version Bump | Example | -|-------------|--------------|---------| -| Bug fix, docs | Patch | 1.0.0 → 1.0.1 | -| New feature, minor change | Minor | 1.0.0 → 1.1.0 | -| Breaking change | Major | 1.0.0 → 2.0.0 | - -**When to bump:** -- Adding new commands, skills, or agents → **Minor** -- Modifying existing behavior → **Minor** (or Major if breaking) -- Updating documentation only → **Patch** -- Bug fixes → **Patch** - -Always update `plugin.json` version when making changes. - -## Plugin Structure - -``` -commit/ -├── .claude-plugin/ -│ └── plugin.json # Manifest (version 1.2.1) -├── agents/ # Sub-agent definitions -├── commands/ # Slash commands -├── skills/ # Reusable knowledge -└── hooks/hooks.json # Lifecycle hooks (optional) -``` - -## Components - -### Commands - - - `/commit:commit`: Create a git commit with semantic commit message format - - `/commit:and-push`: Create a git commit with semantic commit message format and push to remote - - `/commit:and-create-pr`: Create a git commit with semantic commit message format and create a pull request - - -## Commit Convention - -Use semantic commits with plugin scope: - -``` -feat(commit): add new feature -fix(commit): fix bug -docs(commit): update documentation -``` - -Co-author: `Co-Authored-By: duyetbot ` - ---- - -**Generated by docs-generator v1.0.0** diff --git a/docs-generator/.claude-plugin/plugin.json b/docs-generator/.claude-plugin/plugin.json deleted file mode 100644 index 5318fc6..0000000 --- a/docs-generator/.claude-plugin/plugin.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "name": "docs-generator", - "version": "1.0.1", - "description": "Automatically generate and maintain plugin documentation (README.md, CLAUDE.md)", - "author": { - "name": "duyet" - }, - "logo": "./assets/logo.svg" -} diff --git a/docs-generator/.codex-plugin/plugin.json b/docs-generator/.codex-plugin/plugin.json deleted file mode 100644 index d2e4a40..0000000 --- a/docs-generator/.codex-plugin/plugin.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "name": "docs-generator", - "version": "1.0.1", - "description": "Automatically generate and maintain plugin documentation (README.md, CLAUDE.md)", - "author": { - "name": "duyet" - }, - "skills": "./skills/", - "commands": "./commands/", - "hooks": "./hooks/hooks.json", - "interface": { - "displayName": "Docs Generator", - "shortDescription": "Automatically generate and maintain plugin documentation (README.md, CLAUDE.md)", - "developerName": "duyet", - "category": "Docs", - "capabilities": ["Skill", "Command", "Hook"], - "logo": "./assets/logo.svg", - "composerIcon": "./assets/logo.svg" - } -} diff --git a/docs-generator/.grok-build-plugin/plugin.json b/docs-generator/.grok-build-plugin/plugin.json deleted file mode 100644 index a8ac158..0000000 --- a/docs-generator/.grok-build-plugin/plugin.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "name": "docs-generator", - "version": "1.0.1", - "description": "Automatically generate and maintain plugin documentation (README.md, CLAUDE.md)", - "author": { - "name": "duyet" - }, - "skills": "./skills/", - "commands": "./commands/", - "hooks": "./hooks/hooks.json", - "interface": { - "displayName": "Docs Generator", - "shortDescription": "Automatically generate and maintain plugin documentation (README.md, CLAUDE.md)", - "developerName": "duyet", - "category": "Docs", - "capabilities": ["Skill", "Command", "Hook"], - "logo": "./assets/logo.svg", - "composerIcon": "./assets/logo.svg" - }, - "logo": "assets/logo.svg" -} diff --git a/docs-generator/.grok-plugin/plugin.json b/docs-generator/.grok-plugin/plugin.json deleted file mode 100644 index ac12ba4..0000000 --- a/docs-generator/.grok-plugin/plugin.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "name": "docs-generator", - "version": "1.0.1", - "description": "Automatically generate and maintain plugin documentation (README.md, CLAUDE.md)", - "author": { - "name": "duyet" - }, - "logo": "assets/logo.svg", - "keywords": ["docs-generator", "grok", "grok-build", "grok-bot"], - "skills": "./skills/", - "commands": "./commands/", - "hooks": "./hooks/hooks.json" -} diff --git a/docs-generator/CLAUDE.md b/docs-generator/CLAUDE.md deleted file mode 100644 index 753904e..0000000 --- a/docs-generator/CLAUDE.md +++ /dev/null @@ -1,56 +0,0 @@ -# Docs-generator Plugin - -Automatically generate and maintain plugin documentation (README.md, CLAUDE.md) - -## Versioning - -Follow semantic versioning (semver) for this plugin: - -| Change Type | Version Bump | Example | -|-------------|--------------|---------| -| Bug fix, docs | Patch | 1.0.0 → 1.0.1 | -| New feature, minor change | Minor | 1.0.0 → 1.1.0 | -| Breaking change | Major | 1.0.0 → 2.0.0 | - -**When to bump:** -- Adding new commands, skills, or agents → **Minor** -- Modifying existing behavior → **Minor** (or Major if breaking) -- Updating documentation only → **Patch** -- Bug fixes → **Patch** - -Always update `plugin.json` version when making changes. - -## Plugin Structure - -``` -docs-generator/ -├── .claude-plugin/ -│ └── plugin.json # Manifest (version 1.0.0) -├── agents/ # Sub-agent definitions -├── commands/ # Slash commands -├── skills/ # Reusable knowledge -└── hooks/hooks.json # Lifecycle hooks (optional) -``` - -## Components - -### Commands - - - `/generate-docs`: Manually trigger documentation generation for all plugins - - -## Commit Convention - -Use semantic commits with plugin scope: - -``` -feat(docs-generator): add new feature -fix(docs-generator): fix bug -docs(docs-generator): update documentation -``` - -Co-author: `Co-Authored-By: duyetbot ` - ---- - -**Generated by docs-generator v1.0.0** diff --git a/docs-generator/README.md b/docs-generator/README.md deleted file mode 100644 index a1c184f..0000000 --- a/docs-generator/README.md +++ /dev/null @@ -1,71 +0,0 @@ -# Docs Generator Plugin - -Automatically generate and maintain plugin documentation for the claude-plugins marketplace. - -## Installation - -```bash -/plugin install docs-generator@duyet-claude-plugins -``` - -## What It Does - -Generates documentation from plugin metadata: - -1. **Root README.md** - Plugin overview, quick install, at-a-glance table, detailed descriptions -2. **Plugin CLAUDE.md** - Versioning guide, structure, components for each plugin - -## How It Works - -### Automatic Generation (Stop Hook) - -When you finish a Claude session and have made implementation changes: - -1. Stop hook detects changes via `git diff` -2. Skips doc-only changes (README.md, CLAUDE.md) to avoid infinite loops -3. Regenerates all documentation from `marketplace.json` and plugin directories -4. Non-blocking - always allows normal exit - -### Manual Generation - -Use the `/generate-docs` command or run the script directly: - -```bash -./docs-generator/scripts/generate-docs.sh -``` - -## Configuration - -Environment variables: - -- `DOCS_GENERATOR_ENABLED=1` - Enable auto-generation (default: enabled) -- `DOCS_GENERATOR_VERBOSE=1` - Enable verbose logging - -## Architecture - -``` -docs-generator/ -├── hooks/ -│ ├── hooks.json # Stop hook configuration -│ └── stop-hook.sh # Entry point -├── scripts/ -│ ├── generate-docs.sh # Main orchestrator -│ └── lib/ -│ ├── plugin-scanner.sh # Read marketplace.json -│ ├── type-detector.sh # Classify plugins -│ ├── feature-extractor.sh # Extract components -│ └── emoji-mapper.sh # Assign emojis -└── commands/ - └── generate-docs.md # Manual trigger -``` - -## Changelog - -### [1.0.0] - Initial Release - -- Stop hook for automatic documentation generation -- Root README.md generation from marketplace.json -- Plugin CLAUDE.md generation from plugin.json -- Type detection (Agent/Skill/Hook/Command/Config) -- Feature extraction (commands/agents/skills) -- Emoji assignment by keyword diff --git a/docs-generator/assets/logo.svg b/docs-generator/assets/logo.svg deleted file mode 100644 index b18c35b..0000000 --- a/docs-generator/assets/logo.svg +++ /dev/null @@ -1 +0,0 @@ - Face/ 9 Nose/ 6 Mouth/ 0 Eyes/ 4 Eyebrows/ 0 Glasses/ 10 Accessories/ 0 Details/ 0 Beard/ 0 \ No newline at end of file diff --git a/docs-generator/commands/generate-docs.md b/docs-generator/commands/generate-docs.md deleted file mode 100644 index 7e06296..0000000 --- a/docs-generator/commands/generate-docs.md +++ /dev/null @@ -1,35 +0,0 @@ ---- -description: Manually trigger documentation generation for all plugins ---- - -# Generate Documentation - -Manually regenerate all plugin documentation (README.md and CLAUDE.md files). - -This command is useful when you want to update documentation without making any code changes, or when the auto-generation hook is disabled. - -## Usage - -Run the generation script directly: - -```bash -./docs-generator/scripts/generate-docs.sh -``` - -Or from any directory: - -```bash -/path/to/claude-plugins/docs-generator/scripts/generate-docs.sh /path/to/claude-plugins -``` - -## What It Generates - -1. **Root README.md** - At-a-glance table, plugin details, install commands -2. **Plugin CLAUDE.md** - Versioning guide, structure, components for each plugin - -## Configuration - -Set environment variables to control behavior: - -- `DOCS_GENERATOR_ENABLED=1` - Enable auto-generation (default: 1) -- `DOCS_GENERATOR_VERBOSE=1` - Enable verbose output diff --git a/docs-generator/hooks/hooks.json b/docs-generator/hooks/hooks.json deleted file mode 100644 index d9cc2d5..0000000 --- a/docs-generator/hooks/hooks.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "hooks": { - "Stop": [ - { - "hooks": [ - { - "type": "command", - "command": "${CLAUDE_PLUGIN_ROOT}/hooks/stop-hook.sh" - } - ] - } - ] - } -} diff --git a/docs-generator/hooks/stop-hook.sh b/docs-generator/hooks/stop-hook.sh deleted file mode 100755 index ded575b..0000000 --- a/docs-generator/hooks/stop-hook.sh +++ /dev/null @@ -1,36 +0,0 @@ -#!/bin/bash -# Documentation Generator Stop Hook -# Automatically regenerates plugin documentation when implementation changes are detected - -set -euo pipefail - -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -PLUGIN_ROOT="$(dirname "$SCRIPT_DIR")" -MARKETPLACE_ROOT="$(dirname "$(dirname "$SCRIPT_DIR")")" - -# Check if docs generator is enabled (default: enabled) -if [[ "${DOCS_GENERATOR_ENABLED:-1}" != "1" ]]; then - exit 0 -fi - -# Check for implementation changes (skip doc-only changes to avoid infinite loops) -CHANGED_FILES=$(git -C "$MARKETPLACE_ROOT" diff --name-only HEAD 2>/dev/null || true) - -if [[ -n "$CHANGED_FILES" ]]; then - # Filter out README.md and CLAUDE.md changes - IMPLEMENTATION_CHANGES=$(echo "$CHANGED_FILES" | grep -vE '^(README\.md|.*/CLAUDE\.md)$' || true) - - if [[ -n "$IMPLEMENTATION_CHANGES" ]]; then - echo "[docs-generator] Detected implementation changes, regenerating documentation..." >&2 - - # Run generation script - if "$PLUGIN_ROOT/scripts/generate-docs.sh" "$MARKETPLACE_ROOT" 2>&1; then - echo "[docs-generator] Documentation regenerated successfully" >&2 - else - echo "[docs-generator] Warning: Documentation generation failed (non-blocking)" >&2 - fi - fi -fi - -# Always exit 0 to allow normal Claude termination -exit 0 diff --git a/docs-generator/scripts/generate-docs.sh b/docs-generator/scripts/generate-docs.sh deleted file mode 100755 index c9661af..0000000 --- a/docs-generator/scripts/generate-docs.sh +++ /dev/null @@ -1,343 +0,0 @@ -#!/bin/bash -# Main Documentation Generator -# Generates root README.md and plugin CLAUDE.md files -# shellcheck disable=SC2034,SC2155,SC1091 - -set -euo pipefail - -MARKETPLACE_ROOT="${1:-$(pwd)}" -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -LIB_DIR="$SCRIPT_DIR/lib" - -# Source library functions -source "$LIB_DIR/plugin-scanner.sh" -source "$LIB_DIR/type-detector.sh" -source "$LIB_DIR/feature-extractor.sh" -source "$LIB_DIR/emoji-mapper.sh" - -# Main generation function -generate_all_docs() { - echo "Scanning plugins from marketplace.json..." >&2 - - # Get list of all plugins - plugins=$(scan_plugins "$MARKETPLACE_ROOT") - - if [[ -z "$plugins" ]]; then - echo "No plugins found in marketplace.json" >&2 - return 1 - fi - - echo "Found $(echo "$plugins" | wc -l) plugins" >&2 - - # Generate root README.md - generate_root_readme - - # Generate CLAUDE.md for each plugin - for plugin in $plugins; do - local plugin_dir="$MARKETPLACE_ROOT/$plugin" - if [[ -d "$plugin_dir" ]]; then - generate_plugin_claude_md "$plugin_dir" - fi - done - - echo "Documentation generation complete" >&2 -} - -# Generate root README.md -generate_root_readme() { - local output="$MARKETPLACE_ROOT/README.md" - local plugins=$(scan_plugins "$MARKETPLACE_ROOT") - - # Start building README - cat >"$output" <<'EOF' -# Claude/Codex/Grok Plugins Marketplace - -> Extend Claude Code, Codex, Grok Build, and Grok Bot with specialized agents, commands, and skills. - -## Quick Install - -### Claude Code - -```bash -# Add marketplace -/plugin marketplace add duyet/codex-claude-plugins - -# Install plugins -EOF - - # Add install commands for each plugin - for plugin in $plugins; do - echo "/plugin install ${plugin}@duyet-claude-plugins" >>"$output" - done - - cat >>"$output" <<'EOF' -``` - -### Grok Build / Grok Bot - -```bash -grok plugin marketplace add duyet/codex-claude-plugins -grok plugin install --trust -``` - -Codex uses `.agents/plugins/marketplace.json`. Plugin logos live at `assets/logo.svg` in each plugin. - ---- - -## Plugins at a Glance - -| Plugin | Type | What it does | -| --- | --- | --- | -EOF - - # Generate table rows - for plugin in $plugins; do - local plugin_dir="$MARKETPLACE_ROOT/$plugin" - local plugin_json="$plugin_dir/.claude-plugin/plugin.json" - - if [[ ! -f "$plugin_json" ]]; then - continue - fi - - local name=$(jq -r '.name // "'"$plugin"'"' "$plugin_json" 2>/dev/null || echo "$plugin") - local description=$(jq -r '.description // ""' "$plugin_json" 2>/dev/null) - local type=$(detect_plugin_type "$plugin_dir") - local emoji=$(assign_emoji "$plugin") - - # Create short description from full description (first 40 chars) - local short_desc=$(echo "$description" | cut -c1-40) - if [[ ${#description} -gt 40 ]]; then - short_desc="${short_desc}..." - fi - - echo "| [$emoji $name](./${plugin}/) | $type | $short_desc |" >>"$output" - done - - cat >>"$output" <<'EOF' - - ---- - -## Plugin Details - -EOF - - # Generate plugin detail sections - for plugin in $plugins; do - local plugin_dir="$MARKETPLACE_ROOT/$plugin" - local plugin_json="$plugin_dir/.claude-plugin/plugin.json" - - if [[ ! -f "$plugin_json" ]]; then - continue - fi - - local name=$(jq -r '.name // "'"$plugin"'"' "$plugin_json" 2>/dev/null || echo "$plugin") - local description=$(jq -r '.description // ""' "$plugin_json" 2>/dev/null) - local emoji=$(assign_emoji "$plugin") - - { - echo "### $emoji $name" - echo "" - echo "**$description**" - echo "" - } >>"$output" - - # Show example commands - local commands=$(extract_commands "$plugin_dir") - if [[ -n "$commands" ]]; then - { - echo '```bash' - echo "$commands" | head -3 - echo '```' - echo "" - } >>"$output" - fi - - # Show components - local agents=$(extract_agents "$plugin_dir") - local skills=$(extract_skills "$plugin_dir") - - if [[ -n "$agents" ]] || [[ -n "$skills" ]]; then - { - echo "**Components:**" - if [[ -n "$agents" ]]; then - echo "" - echo "Agents:" - echo "${agents// - /- }" - fi - if [[ -n "$skills" ]]; then - echo "" - echo "Skills:" - echo "${skills// - /- }" - fi - echo "" - } >>"$output" - fi - - { - echo "---" - echo "" - } >>"$output" - done - - # Add footer sections - cat >>"$output" <<'EOF' - -## Manual Installation - -Add to `~/.claude/settings.json`: - -```json -{ - "extraKnownMarketplaces": { - "duyet-claude-plugins": { - "source": { "source": "github", "repo": "duyet/codex-claude-plugins" } - } - }, - "enabledPlugins": { - "team-agents@duyet-claude-plugins": true - } -} -``` - ---- - -## Contributing - -```text -your-plugin/ -├── .claude-plugin/plugin.json # name, version, description, logo -├── .codex-plugin/plugin.json # Codex manifest and interface metadata -├── .grok-plugin/plugin.json # Grok Bot / Grok Build manifest -├── .grok-build-plugin/plugin.json # Grok Build interface metadata -├── assets/logo.svg # rendered by every listed harness -├── agents/ # .md with YAML frontmatter -├── commands/ # slash commands -├── skills/ # reusable knowledge -└── hooks/hooks.json # lifecycle hooks -``` - -Update `marketplace.json`, `.claude-plugin/marketplace.json`, `.agents/plugins/marketplace.json`, `.grok-plugin/marketplace.json`, and the harness manifests. Run `bash scripts/validate-plugins.sh`. - ---- - -MIT License -EOF - - echo "Generated README.md" >&2 -} - -# Generate CLAUDE.md for a single plugin -generate_plugin_claude_md() { - local plugin_dir="$1" - local plugin_json="$plugin_dir/.claude-plugin/plugin.json" - local output="$plugin_dir/CLAUDE.md" - - if [[ ! -f "$plugin_json" ]]; then - return - fi - - local name=$(jq -r '.name // "unknown"' "$plugin_json" 2>/dev/null) - local version=$(jq -r '.version // "1.0.0"' "$plugin_json" 2>/dev/null) - local description=$(jq -r '.description // ""' "$plugin_json" 2>/dev/null) - - # Capitalize first letter (bash 4+) - local name_title="${name^}" - - cat >"$output" <>"$output" - fi - - # Add agents section - local agents=$(extract_agents "$plugin_dir") - if [[ -n "$agents" ]]; then - { - echo "### Agents" - echo "" - echo "${agents// - /- }" - echo "" - } >>"$output" - fi - - # Add skills section - local skills=$(extract_skills "$plugin_dir") - if [[ -n "$skills" ]]; then - { - echo "### Skills" - echo "" - echo "${skills// - /- }" - echo "" - } >>"$output" - fi - - # Add commit convention - cat >>"$output" <\` - ---- - -**Generated by docs-generator v1.0.0** -EOF - - echo "Generated CLAUDE.md for $name" >&2 -} - -# Run generation -generate_all_docs diff --git a/docs-generator/scripts/lib/emoji-mapper.sh b/docs-generator/scripts/lib/emoji-mapper.sh deleted file mode 100755 index 0bbd252..0000000 --- a/docs-generator/scripts/lib/emoji-mapper.sh +++ /dev/null @@ -1,21 +0,0 @@ -#!/bin/bash -# Emoji Mapper - Assign emojis to plugins based on keywords - -assign_emoji() { - local name="$1" - - case "$name" in - *team*) echo "👥" ;; - *agent*) echo "🤖" ;; - *bot*) echo "🤖" ;; - *design*) echo "🎨" ;; - *commit*) echo "📝" ;; - *status*) echo "📊" ;; - *loop*) echo "🔄" ;; - *wiggum*) echo "🔄" ;; - *interview*) echo "💬" ;; - *orchestration*) echo "🎼" ;; - *terminal*) echo "🖥️" ;; - *) echo "🎯" ;; - esac -} diff --git a/docs-generator/scripts/lib/feature-extractor.sh b/docs-generator/scripts/lib/feature-extractor.sh deleted file mode 100755 index 25916ae..0000000 --- a/docs-generator/scripts/lib/feature-extractor.sh +++ /dev/null @@ -1,84 +0,0 @@ -#!/bin/bash -# Feature Extractor - Extract commands, agents, skills from plugin directories -# shellcheck disable=SC2034,SC2155 - -extract_commands() { - local plugin_dir="$1" - - if [[ ! -d "$plugin_dir/commands" ]]; then - return - fi - - for cmd_file in "$plugin_dir/commands"/*.md; do - [[ -f "$cmd_file" ]] || continue - - local name=$(basename "$cmd_file" .md) - local desc=$(grep -m1 '^description:' "$cmd_file" 2>/dev/null | sed 's/description: *//' || echo "") - - if [[ -n "$desc" ]]; then - echo " - \`/$name\`: $desc" - else - echo " - \`/$name\`" - fi - done -} - -extract_agents() { - local plugin_dir="$1" - - if [[ ! -d "$plugin_dir/agents" ]]; then - return - fi - - for agent_file in "$plugin_dir/agents"/*.md; do - [[ -f "$agent_file" ]] || continue - - local name=$(basename "$agent_file" .md) - local role=$(grep -m1 '^role:' "$agent_file" 2>/dev/null | sed 's/role: *//' || echo "") - local model=$(grep -m1 '^model:' "$agent_file" 2>/dev/null | sed 's/model: *//' || echo "") - - if [[ -n "$role" ]]; then - if [[ -n "$model" ]]; then - echo " - **$name** ($model): $role" - else - echo " - **$name**: $role" - fi - else - echo " - **$name**" - fi - done -} - -extract_skills() { - local plugin_dir="$1" - - if [[ ! -d "$plugin_dir/skills" ]]; then - return - fi - - for skill_dir in "$plugin_dir/skills"/*; do - [[ -d "$skill_dir" ]] || continue - - local name=$(basename "$skill_dir") - echo " - **$name**" - done -} - -generate_file_tree() { - local plugin_dir="$1" - local plugin_name=$(basename "$plugin_dir") - - echo "├── agents/ # Sub-agent definitions" - echo "├── commands/ # Slash commands" - echo "├── skills/ # Reusable knowledge" - echo "└── hooks/hooks.json # Lifecycle hooks (optional)" -} - -get_plugin_description() { - local plugin_dir="$1" - local plugin_json="$plugin_dir/.claude-plugin/plugin.json" - - if [[ -f "$plugin_json" ]] && command -v jq &> /dev/null; then - jq -r '.description // empty' "$plugin_json" 2>/dev/null - fi -} diff --git a/docs-generator/scripts/lib/plugin-scanner.sh b/docs-generator/scripts/lib/plugin-scanner.sh deleted file mode 100755 index 423d49c..0000000 --- a/docs-generator/scripts/lib/plugin-scanner.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/bash -# Plugin Scanner - Read marketplace.json and return plugin list - -scan_plugins() { - local marketplace_root="$1" - local marketplace_json="$marketplace_root/.claude-plugin/marketplace.json" - - if [[ ! -f "$marketplace_json" ]]; then - echo "Error: marketplace.json not found at $marketplace_json" >&2 - return 1 - fi - - if ! command -v jq &> /dev/null; then - echo "Error: jq is required but not installed" >&2 - return 1 - fi - - # Extract plugin sources and remove leading ./ - jq -r '.plugins[].source' "$marketplace_json" 2>/dev/null | sed 's|^\./||' || return 1 -} diff --git a/docs-generator/scripts/lib/type-detector.sh b/docs-generator/scripts/lib/type-detector.sh deleted file mode 100755 index 13145f3..0000000 --- a/docs-generator/scripts/lib/type-detector.sh +++ /dev/null @@ -1,33 +0,0 @@ -#!/bin/bash -# Type Detector - Classify plugin by directory structure - -detect_plugin_type() { - local plugin_dir="$1" - - # Check for hooks first (highest priority) - if [[ -f "$plugin_dir/hooks/hooks.json" ]]; then - echo "Hook" - return - fi - - # Check for agents directory (but not if also has skills) - if [[ -d "$plugin_dir/agents" ]] && [[ ! -d "$plugin_dir/skills" ]]; then - echo "Agent" - return - fi - - # Check for skills directory - if [[ -d "$plugin_dir/skills" ]]; then - echo "Skill" - return - fi - - # Check for commands directory only - if [[ -d "$plugin_dir/commands" ]]; then - echo "Command" - return - fi - - # Default to Config for special cases - echo "Config" -} diff --git a/docs-generator/skills/docs-generator-workflow/SKILL.md b/docs-generator/skills/docs-generator-workflow/SKILL.md deleted file mode 100644 index 9ef6e14..0000000 --- a/docs-generator/skills/docs-generator-workflow/SKILL.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -name: docs-generator -description: Use when regenerating or maintaining this plugin marketplace documentation from plugin manifests and component folders. ---- - -# Docs Generator - -Use this skill to regenerate and review the repository's plugin documentation. - -## Workflow - -1. Inspect plugin manifests and component folders before changing generated documentation. -2. Run `docs-generator/scripts/generate-docs.sh` from the repository root when regeneration is requested. -3. Review the generated root README and plugin CLAUDE files for accuracy. -4. Keep generated text grounded in manifest descriptions and actual files. - -## Notes - -- The Claude hook configuration lives in `hooks/hooks.json`. -- Keep Claude and Codex plugin metadata synchronized when both manifest families exist. diff --git a/duyetbot/.claude-plugin/plugin.json b/duyetbot/.claude-plugin/plugin.json deleted file mode 100644 index edbf14c..0000000 --- a/duyetbot/.claude-plugin/plugin.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "name": "duyetbot", - "description": "Pragmatic software development companion with engineering discipline and transparent execution.", - "version": "1.8.1", - "author": { - "name": "duyet" - }, - "logo": "./assets/logo.svg" -} diff --git a/duyetbot/.codex-plugin/plugin.json b/duyetbot/.codex-plugin/plugin.json deleted file mode 100644 index 4ec12df..0000000 --- a/duyetbot/.codex-plugin/plugin.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "name": "duyetbot", - "version": "1.8.1", - "description": "Pragmatic software development companion with engineering discipline and transparent execution.", - "author": { - "name": "duyet" - }, - "skills": "./skills/", - "commands": "./commands/", - "interface": { - "displayName": "duyetbot", - "shortDescription": "Pragmatic software development companion with engineering discipline and transparent execution.", - "developerName": "duyet", - "category": "Productivity", - "capabilities": ["Skill", "Command"], - "logo": "./assets/logo.svg", - "composerIcon": "./assets/logo.svg" - } -} diff --git a/duyetbot/.grok-build-plugin/plugin.json b/duyetbot/.grok-build-plugin/plugin.json deleted file mode 100644 index bc0b11c..0000000 --- a/duyetbot/.grok-build-plugin/plugin.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "name": "duyetbot", - "version": "1.8.1", - "description": "Pragmatic software development companion with engineering discipline and transparent execution.", - "author": { - "name": "duyet" - }, - "skills": "./skills/", - "commands": "./commands/", - "interface": { - "displayName": "duyetbot", - "shortDescription": "Pragmatic software development companion with engineering discipline and transparent execution.", - "developerName": "duyet", - "category": "Productivity", - "capabilities": ["Skill", "Command"], - "logo": "./assets/logo.svg", - "composerIcon": "./assets/logo.svg" - }, - "logo": "assets/logo.svg" -} diff --git a/duyetbot/.grok-plugin/plugin.json b/duyetbot/.grok-plugin/plugin.json deleted file mode 100644 index 00132e3..0000000 --- a/duyetbot/.grok-plugin/plugin.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "name": "duyetbot", - "version": "1.8.1", - "description": "Pragmatic software development companion with engineering discipline and transparent execution.", - "author": { - "name": "duyet" - }, - "logo": "assets/logo.svg", - "keywords": ["duyetbot", "grok", "grok-build", "grok-bot"], - "skills": "./skills/", - "commands": "./commands/", - "agents": "./agents/", - "hooks": "./hooks/hooks.json", - "mcpServers": "./.mcp.json" -} diff --git a/duyetbot/.mcp.json b/duyetbot/.mcp.json deleted file mode 100644 index 68cfaf3..0000000 --- a/duyetbot/.mcp.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "mcpServers": { - "duyet-mcp": { - "command": "npx", - "args": ["-y", "mcp-remote", "https://mcp.duyet.net/sse"], - "description": "Remote MCP server for @duyet information (profile, CV, blog, GitHub activity)" - }, - "memory": { - "command": "npx", - "args": ["-y", "@anthropic/mcp-memory"], - "description": "Persistent cross-session memory for duyetbot context" - }, - "research": { - "command": "npx", - "args": ["-y", "@anthropic/mcp-research"], - "description": "Web research and information synthesis" - } - } -} diff --git a/duyetbot/CLAUDE.md b/duyetbot/CLAUDE.md deleted file mode 100644 index 9d25d77..0000000 --- a/duyetbot/CLAUDE.md +++ /dev/null @@ -1,72 +0,0 @@ -# Duyetbot Plugin - -Pragmatic software development companion with engineering discipline and transparent execution. Spawns team-agents and uses orchestration patterns for parallel work. - -## Versioning - -Follow semantic versioning (semver) for this plugin: - -| Change Type | Version Bump | Example | -|-------------|--------------|---------| -| Bug fix, docs | Patch | 1.0.0 → 1.0.1 | -| New feature, minor change | Minor | 1.0.0 → 1.1.0 | -| Breaking change | Major | 1.0.0 → 2.0.0 | - -**When to bump:** -- Adding new commands, skills, or agents → **Minor** -- Modifying existing behavior → **Minor** (or Major if breaking) -- Updating documentation only → **Patch** -- Bug fixes → **Patch** - -Always update `plugin.json` version when making changes. - -## Plugin Structure - -``` -duyetbot/ -├── .claude-plugin/ -│ └── plugin.json # Manifest (version 1.7.0) -├── agents/ # Sub-agent definitions -├── commands/ # Slash commands -├── skills/ # Reusable knowledge -└── hooks/hooks.json # Lifecycle hooks (optional) -``` - -## Components - -### Commands - - - `/duyetbot`: Summon duyetbot - pragmatic software development companion with transparent execution - - `/learn`: Learn about @duyet and update knowledge base - - `/orchestrate`: Duyetbot orchestrate - coordinate parallel agent workstreams for complex tasks - - `/spawn`: Duyetbot spawn - delegate tasks to team agents for parallel execution - - `/think`: Duyetbot deep thinking - structured problem analysis with visible reasoning - - `/writing`: Review and rewrite content to match @duyet's writing style - -### Agents - - - **duyetbot** - -### Skills - - - **duyet-knowledge** - - **engineering-discipline** - - **team-coordination** - - **transparency** - - -## Commit Convention - -Use semantic commits with plugin scope: - -``` -feat(duyetbot): add new feature -fix(duyetbot): fix bug -docs(duyetbot): update documentation -``` - -Co-author: `Co-Authored-By: duyetbot ` - ---- - -**Generated by docs-generator v1.0.0** diff --git a/duyetbot/PLAN-MCP-OAUTH.md b/duyetbot/PLAN-MCP-OAUTH.md deleted file mode 100644 index 8bff6ae..0000000 --- a/duyetbot/PLAN-MCP-OAUTH.md +++ /dev/null @@ -1,946 +0,0 @@ -# Duyetbot MCP Gateway with GitHub OAuth - -> Build an authenticated MCP gateway that aggregates multiple backend services - GitHub, Memory, Knowledge, System Prompts - all via single OAuth login. - -## Overview - -``` -┌─────────────────────────────────────────────────────────────────────────────┐ -│ Claude Code │ -│ (duyetbot) │ -└─────────────────────────────────┬───────────────────────────────────────────┘ - │ - ▼ -┌─────────────────────────────────────────────────────────────────────────────┐ -│ duyetbot-mcp (Gateway) │ -│ GitHub OAuth 2.1 + PKCE │ -│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ -│ │ Router │ │ Auth │ │ Tools │ │ Resources │ │ -│ │ Layer │ │ Layer │ │ Registry │ │ Registry │ │ -│ └─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘ │ -└───────┬─────────────────┬─────────────────┬─────────────────┬───────────────┘ - │ │ │ │ - ▼ ▼ ▼ ▼ -┌───────────────┐ ┌───────────────┐ ┌───────────────┐ ┌───────────────┐ -│ GitHub MCP │ │ Memory MCP │ │ Knowledge MCP │ │ Prompt MCP │ -│ │ │ │ │ │ │ │ -│ • repos │ │ • store │ │ • search │ │ • system │ -│ • issues │ │ • recall │ │ • retrieve │ │ • templates │ -│ • PRs │ │ • list │ │ • embed │ │ • personas │ -│ • commits │ │ • forget │ │ • context │ │ • workflows │ -│ • actions │ │ • sessions │ │ • RAG │ │ • skills │ -└───────┬───────┘ └───────┬───────┘ └───────┬───────┘ └───────┬───────┘ - │ │ │ │ - ▼ ▼ ▼ ▼ -┌───────────────┐ ┌───────────────┐ ┌───────────────┐ ┌───────────────┐ -│ GitHub API │ │ Cloudflare D1 │ │ Vectorize + │ │ R2 Bucket + │ -│ │ │ + KV │ │ Workers AI │ │ D1 │ -└───────────────┘ └───────────────┘ └───────────────┘ └───────────────┘ -``` - -## Architecture - -### Gateway Pattern - -**duyetbot-mcp** acts as a unified gateway: -- Single OAuth login → access all services -- Route requests to appropriate backend MCP -- Aggregate responses from multiple MCPs -- Unified error handling and logging - -### Backend MCPs - -| MCP | Purpose | Storage | Tools | -|-----|---------|---------|-------| -| **GitHub** | Code operations | GitHub API | repos, issues, PRs, actions | -| **Memory** | Persistent context | D1 + KV | store, recall, list, forget | -| **Knowledge** | RAG & embeddings | Vectorize | search, retrieve, embed | -| **Prompt** | System prompts | R2 + D1 | templates, personas, skills | - -### Authentication Flow - -1. **GitHub OAuth 2.1 + PKCE** - Single sign-on -2. **User Identity** - GitHub user ID as primary key -3. **Token Propagation** - Gateway forwards auth to backends -4. **Scope Isolation** - Each backend has minimal required permissions - ---- - -## Implementation Plan - -### Phase 1: GitHub OAuth App Setup - -```bash -# 1. Create OAuth App at: github.com/settings/developers -# 2. Configure: -# - Application name: duyetbot-mcp -# - Homepage URL: https://duyetbot.duyet.net -# - Callback URL: https://duyetbot-mcp.duyet.workers.dev/auth/callback -# 3. Save Client ID and Client Secret -``` - -**Environment Variables:** -```env -GITHUB_CLIENT_ID=xxx -GITHUB_CLIENT_SECRET=xxx -MCP_SERVER_URL=https://duyetbot-mcp.duyet.workers.dev -``` - -### Phase 2: MCP Gateway Structure - -``` -duyetbot-mcp/ -├── src/ -│ ├── index.ts # Entry point -│ ├── gateway.ts # MCP gateway router -│ ├── auth/ -│ │ ├── oauth.ts # OAuth 2.1 + PKCE flow -│ │ ├── github-provider.ts # GitHub OAuth provider -│ │ └── tokens.ts # Token management -│ ├── mcps/ -│ │ ├── github/ # GitHub MCP backend -│ │ │ ├── tools.ts # repos, issues, PRs, actions -│ │ │ └── resources.ts # repository resources -│ │ ├── memory/ # Memory MCP backend -│ │ │ ├── tools.ts # store, recall, list, forget -│ │ │ └── sessions.ts # session context -│ │ ├── knowledge/ # Knowledge MCP backend -│ │ │ ├── tools.ts # search, retrieve, embed -│ │ │ ├── vectorize.ts # vector embeddings -│ │ │ └── rag.ts # RAG pipeline -│ │ └── prompts/ # Prompt MCP backend -│ │ ├── tools.ts # system, templates, personas -│ │ ├── skills.ts # skill definitions -│ │ └── workflows.ts # workflow templates -│ ├── storage/ -│ │ ├── d1.ts # D1 database adapter -│ │ ├── kv.ts # KV token/cache store -│ │ ├── r2.ts # R2 object storage -│ │ └── vectorize.ts # Vectorize adapter -│ └── utils/ -│ ├── router.ts # Tool routing logic -│ └── aggregator.ts # Response aggregation -├── schema/ -│ ├── memories.sql # Memory tables -│ ├── knowledge.sql # Knowledge base tables -│ └── prompts.sql # Prompt storage tables -├── wrangler.toml # Cloudflare config -├── package.json -└── tsconfig.json -``` - -### Backend MCP Details - -#### 1. GitHub MCP -```typescript -// Tools provided: -github_whoami() // Get authenticated user -github_list_repos() // List repositories -github_create_issue() // Create issue -github_create_pr() // Create pull request -github_get_pr() // Get PR details -github_merge_pr() // Merge PR -github_list_actions() // List workflow runs -github_trigger_action() // Trigger workflow -github_search_code() // Search code in repos -``` - -#### 2. Memory MCP -```typescript -// Tools provided: -memory_store() // Store key-value with optional TTL -memory_recall() // Retrieve by key -memory_list() // List with prefix filter -memory_forget() // Delete memory -memory_search() // Semantic search memories -session_create() // Create session context -session_update() // Update session -session_get() // Get current session -``` - -#### 3. Knowledge MCP -```typescript -// Tools provided: -knowledge_search() // Semantic search knowledge base -knowledge_retrieve() // Get document by ID -knowledge_embed() // Create embedding for text -knowledge_ingest() // Add document to knowledge base -knowledge_context() // Get relevant context for query -rag_query() // Full RAG pipeline query -``` - -#### 4. Prompt MCP -```typescript -// Tools provided: -prompt_get_system() // Get system prompt for context -prompt_list_templates() // List available templates -prompt_render() // Render template with variables -persona_get() // Get persona definition -persona_list() // List available personas -skill_get() // Get skill definition -skill_list() // List available skills -workflow_get() // Get workflow template -workflow_list() // List workflows -``` - -### Phase 3: OAuth Flow Implementation - -```typescript -// src/auth/oauth.ts -import { Hono } from 'hono'; - -const GITHUB_AUTH_URL = 'https://github.com/login/oauth/authorize'; -const GITHUB_TOKEN_URL = 'https://github.com/login/oauth/access_token'; - -export function createOAuthRouter(env: Env) { - const app = new Hono(); - - // OAuth discovery endpoint (RFC 9728) - app.get('/.well-known/oauth-authorization-server', (c) => { - return c.json({ - issuer: env.MCP_SERVER_URL, - authorization_endpoint: `${env.MCP_SERVER_URL}/auth/authorize`, - token_endpoint: `${env.MCP_SERVER_URL}/auth/token`, - response_types_supported: ['code'], - grant_types_supported: ['authorization_code', 'refresh_token'], - code_challenge_methods_supported: ['S256'], - scopes_supported: ['repo', 'user', 'read:org'] - }); - }); - - // Start OAuth flow - app.get('/auth/authorize', async (c) => { - const { code_challenge, code_challenge_method, redirect_uri, state } = c.req.query(); - - // Store PKCE challenge - await env.KV.put(`pkce:${state}`, code_challenge, { expirationTtl: 600 }); - - // Redirect to GitHub - const params = new URLSearchParams({ - client_id: env.GITHUB_CLIENT_ID, - redirect_uri: `${env.MCP_SERVER_URL}/auth/callback`, - scope: 'repo user read:org', - state, - }); - - return c.redirect(`${GITHUB_AUTH_URL}?${params}`); - }); - - // OAuth callback from GitHub - app.get('/auth/callback', async (c) => { - const { code, state } = c.req.query(); - - // Exchange code for token - const tokenResponse = await fetch(GITHUB_TOKEN_URL, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - 'Accept': 'application/json', - }, - body: JSON.stringify({ - client_id: env.GITHUB_CLIENT_ID, - client_secret: env.GITHUB_CLIENT_SECRET, - code, - }), - }); - - const { access_token, refresh_token } = await tokenResponse.json(); - - // Store tokens securely - await env.KV.put(`token:${state}`, JSON.stringify({ - access_token, - refresh_token, - created_at: Date.now(), - }), { expirationTtl: 86400 }); - - // Return authorization code to MCP client - const redirectUri = await env.KV.get(`redirect:${state}`); - return c.redirect(`${redirectUri}?code=${state}`); - }); - - // Token endpoint (exchange auth code for access token) - app.post('/auth/token', async (c) => { - const { code, code_verifier, grant_type } = await c.req.json(); - - if (grant_type === 'authorization_code') { - // Verify PKCE - const storedChallenge = await env.KV.get(`pkce:${code}`); - const computedChallenge = await computePKCEChallenge(code_verifier); - - if (storedChallenge !== computedChallenge) { - return c.json({ error: 'invalid_grant' }, 400); - } - - // Return stored token - const tokenData = await env.KV.get(`token:${code}`); - return c.json(JSON.parse(tokenData)); - } - - return c.json({ error: 'unsupported_grant_type' }, 400); - }); - - return app; -} -``` - -### Phase 4: MCP Tools - -```typescript -// src/tools/github.ts -import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; -import { z } from 'zod'; - -export function registerGitHubTools(server: McpServer, getToken: () => string) { - // List repositories - server.tool( - 'github_list_repos', - 'List GitHub repositories for the authenticated user', - { - visibility: z.enum(['all', 'public', 'private']).optional(), - sort: z.enum(['created', 'updated', 'pushed', 'full_name']).optional(), - }, - async ({ visibility = 'all', sort = 'updated' }) => { - const response = await fetch( - `https://api.github.com/user/repos?visibility=${visibility}&sort=${sort}`, - { - headers: { - 'Authorization': `Bearer ${getToken()}`, - 'Accept': 'application/vnd.github.v3+json', - }, - } - ); - const repos = await response.json(); - return { - content: [{ - type: 'text', - text: JSON.stringify(repos.map(r => ({ - name: r.full_name, - description: r.description, - url: r.html_url, - stars: r.stargazers_count, - })), null, 2) - }] - }; - } - ); - - // Create issue - server.tool( - 'github_create_issue', - 'Create a new GitHub issue', - { - repo: z.string().describe('Repository in format owner/repo'), - title: z.string().describe('Issue title'), - body: z.string().describe('Issue body'), - labels: z.array(z.string()).optional(), - }, - async ({ repo, title, body, labels }) => { - const response = await fetch( - `https://api.github.com/repos/${repo}/issues`, - { - method: 'POST', - headers: { - 'Authorization': `Bearer ${getToken()}`, - 'Accept': 'application/vnd.github.v3+json', - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ title, body, labels }), - } - ); - const issue = await response.json(); - return { - content: [{ - type: 'text', - text: `Created issue #${issue.number}: ${issue.html_url}` - }] - }; - } - ); - - // Create pull request - server.tool( - 'github_create_pr', - 'Create a new pull request', - { - repo: z.string(), - title: z.string(), - body: z.string(), - head: z.string().describe('Branch with changes'), - base: z.string().describe('Target branch'), - }, - async ({ repo, title, body, head, base }) => { - const response = await fetch( - `https://api.github.com/repos/${repo}/pulls`, - { - method: 'POST', - headers: { - 'Authorization': `Bearer ${getToken()}`, - 'Accept': 'application/vnd.github.v3+json', - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ title, body, head, base }), - } - ); - const pr = await response.json(); - return { - content: [{ - type: 'text', - text: `Created PR #${pr.number}: ${pr.html_url}` - }] - }; - } - ); - - // Get user info - server.tool( - 'github_whoami', - 'Get authenticated GitHub user information', - {}, - async () => { - const response = await fetch('https://api.github.com/user', { - headers: { - 'Authorization': `Bearer ${getToken()}`, - 'Accept': 'application/vnd.github.v3+json', - }, - }); - const user = await response.json(); - return { - content: [{ - type: 'text', - text: `Logged in as: ${user.login} (${user.name})\nEmail: ${user.email}\nRepos: ${user.public_repos}` - }] - }; - } - ); -} -``` - -```typescript -// src/tools/memory.ts -export function registerMemoryTools(server: McpServer, env: Env, userId: string) { - // Store memory - server.tool( - 'memory_store', - 'Store a piece of information in persistent memory', - { - key: z.string().describe('Memory key'), - value: z.string().describe('Content to store'), - ttl: z.number().optional().describe('Time to live in seconds'), - }, - async ({ key, value, ttl }) => { - await env.D1.prepare( - 'INSERT OR REPLACE INTO memories (user_id, key, value, created_at, expires_at) VALUES (?, ?, ?, ?, ?)' - ).bind( - userId, - key, - value, - Date.now(), - ttl ? Date.now() + ttl * 1000 : null - ).run(); - - return { - content: [{ type: 'text', text: `Stored memory: ${key}` }] - }; - } - ); - - // Retrieve memory - server.tool( - 'memory_recall', - 'Recall a stored memory by key', - { key: z.string() }, - async ({ key }) => { - const result = await env.D1.prepare( - 'SELECT value FROM memories WHERE user_id = ? AND key = ? AND (expires_at IS NULL OR expires_at > ?)' - ).bind(userId, key, Date.now()).first(); - - if (!result) { - return { content: [{ type: 'text', text: `Memory not found: ${key}` }] }; - } - - return { content: [{ type: 'text', text: result.value as string }] }; - } - ); - - // List memories - server.tool( - 'memory_list', - 'List all stored memories', - { prefix: z.string().optional() }, - async ({ prefix }) => { - const query = prefix - ? 'SELECT key, substr(value, 1, 100) as preview FROM memories WHERE user_id = ? AND key LIKE ?' - : 'SELECT key, substr(value, 1, 100) as preview FROM memories WHERE user_id = ?'; - - const results = prefix - ? await env.D1.prepare(query).bind(userId, `${prefix}%`).all() - : await env.D1.prepare(query).bind(userId).all(); - - return { - content: [{ - type: 'text', - text: JSON.stringify(results.results, null, 2) - }] - }; - } - ); - - // Delete memory - server.tool( - 'memory_forget', - 'Delete a stored memory', - { key: z.string() }, - async ({ key }) => { - await env.D1.prepare( - 'DELETE FROM memories WHERE user_id = ? AND key = ?' - ).bind(userId, key).run(); - - return { content: [{ type: 'text', text: `Deleted memory: ${key}` }] }; - } - ); -} -``` - -### Phase 5: Main Server - -```typescript -// src/index.ts -import { Hono } from 'hono'; -import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; -import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js'; -import { createOAuthRouter } from './auth/oauth'; -import { registerGitHubTools } from './tools/github'; -import { registerMemoryTools } from './tools/memory'; - -interface Env { - GITHUB_CLIENT_ID: string; - GITHUB_CLIENT_SECRET: string; - MCP_SERVER_URL: string; - KV: KVNamespace; - D1: D1Database; -} - -export default { - async fetch(request: Request, env: Env): Promise { - const app = new Hono(); - - // OAuth routes - app.route('/', createOAuthRouter(env)); - - // MCP endpoint - app.all('/mcp', async (c) => { - // Validate Bearer token - const authHeader = c.req.header('Authorization'); - if (!authHeader?.startsWith('Bearer ')) { - return c.json({ error: 'unauthorized' }, 401); - } - - const token = authHeader.slice(7); - const tokenData = await validateToken(token, env); - if (!tokenData) { - return c.json({ error: 'invalid_token' }, 401); - } - - // Create MCP server for this request - const server = new McpServer({ - name: 'duyetbot-mcp', - version: '1.0.0', - }); - - // Register tools with user's token - registerGitHubTools(server, () => tokenData.access_token); - registerMemoryTools(server, env, tokenData.user_id); - - // Handle MCP request - const transport = new StreamableHTTPServerTransport({ - sessionIdGenerator: undefined, - }); - - await server.connect(transport); - return transport.handleRequest(c.req.raw); - }); - - // Health check - app.get('/health', (c) => c.json({ status: 'ok' })); - - return app.fetch(request, env); - } -}; - -async function validateToken(token: string, env: Env) { - // Validate with GitHub - const response = await fetch('https://api.github.com/user', { - headers: { - 'Authorization': `Bearer ${token}`, - 'Accept': 'application/vnd.github.v3+json', - }, - }); - - if (!response.ok) return null; - - const user = await response.json(); - return { - access_token: token, - user_id: user.id.toString(), - login: user.login, - }; -} -``` - -### Phase 6: Database Schema - -```sql --- D1 Schema: schema.sql - --- User tokens -CREATE TABLE IF NOT EXISTS tokens ( - user_id TEXT PRIMARY KEY, - access_token TEXT NOT NULL, - refresh_token TEXT, - expires_at INTEGER, - created_at INTEGER NOT NULL, - updated_at INTEGER NOT NULL -); - --- Persistent memories -CREATE TABLE IF NOT EXISTS memories ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - user_id TEXT NOT NULL, - key TEXT NOT NULL, - value TEXT NOT NULL, - created_at INTEGER NOT NULL, - expires_at INTEGER, - UNIQUE(user_id, key) -); - --- Session context -CREATE TABLE IF NOT EXISTS sessions ( - session_id TEXT PRIMARY KEY, - user_id TEXT NOT NULL, - context TEXT, - created_at INTEGER NOT NULL, - last_active INTEGER NOT NULL -); - --- Indexes -CREATE INDEX IF NOT EXISTS idx_memories_user ON memories(user_id); -CREATE INDEX IF NOT EXISTS idx_sessions_user ON sessions(user_id); -``` - -### Phase 7: Cloudflare Configuration - -```toml -# wrangler.toml -name = "duyetbot-mcp" -main = "src/index.ts" -compatibility_date = "2024-01-01" - -[vars] -MCP_SERVER_URL = "https://duyetbot-mcp.duyet.workers.dev" - -[[kv_namespaces]] -binding = "KV" -id = "xxx" - -[[d1_databases]] -binding = "D1" -database_name = "duyetbot-db" -database_id = "xxx" -``` - -### Phase 8: Plugin Integration - -Update duyetbot plugin to use the new MCP: - -```json -// duyetbot/.mcp.json -{ - "mcpServers": { - "duyetbot": { - "url": "https://duyetbot-mcp.duyet.workers.dev/mcp", - "transport": "streamable-http", - "auth": { - "type": "oauth2", - "authorizationUrl": "https://duyetbot-mcp.duyet.workers.dev/auth/authorize", - "tokenUrl": "https://duyetbot-mcp.duyet.workers.dev/auth/token", - "scopes": ["repo", "user"] - }, - "description": "Duyetbot's GitHub operations and persistent memory" - } - } -} -``` - ---- - -## Available Tools After Implementation - -### GitHub MCP Tools -| Tool | Description | -|------|-------------| -| `github_whoami` | Get authenticated user info | -| `github_list_repos` | List user's repositories | -| `github_create_issue` | Create GitHub issue | -| `github_create_pr` | Create pull request | -| `github_get_pr` | Get PR details | -| `github_merge_pr` | Merge pull request | -| `github_list_actions` | List workflow runs | -| `github_trigger_action` | Trigger GitHub Action | -| `github_search_code` | Search code in repositories | - -### Memory MCP Tools -| Tool | Description | -|------|-------------| -| `memory_store` | Store key-value with optional TTL | -| `memory_recall` | Retrieve stored memory | -| `memory_list` | List memories with prefix filter | -| `memory_forget` | Delete memory | -| `memory_search` | Semantic search memories | -| `session_create` | Create session context | -| `session_update` | Update session context | -| `session_get` | Get current session | - -### Knowledge MCP Tools -| Tool | Description | -|------|-------------| -| `knowledge_search` | Semantic search knowledge base | -| `knowledge_retrieve` | Get document by ID | -| `knowledge_embed` | Create embedding for text | -| `knowledge_ingest` | Add document to knowledge base | -| `knowledge_context` | Get relevant context for query | -| `rag_query` | Full RAG pipeline query | - -### Prompt MCP Tools -| Tool | Description | -|------|-------------| -| `prompt_get_system` | Get system prompt for context | -| `prompt_list_templates` | List available templates | -| `prompt_render` | Render template with variables | -| `persona_get` | Get persona definition | -| `persona_list` | List available personas | -| `skill_get` | Get skill definition | -| `skill_list` | List available skills | -| `workflow_get` | Get workflow template | -| `workflow_list` | List workflows | - ---- - -## Security Checklist - -- [ ] PKCE mandatory for all OAuth flows -- [ ] Short-lived access tokens (1 hour max) -- [ ] Refresh tokens with secure rotation -- [ ] Origin header validation on all requests -- [ ] Rate limiting on auth endpoints -- [ ] No secrets in code or logs -- [ ] HTTPS only in production -- [ ] Token validation on every MCP request - ---- - -## Development Commands - -```bash -# Setup -npm init -y -npm install hono @modelcontextprotocol/sdk zod - -# Local development -wrangler dev - -# Deploy -wrangler deploy - -# Create D1 database -wrangler d1 create duyetbot-db -wrangler d1 execute duyetbot-db --file=schema.sql - -# Create KV namespace -wrangler kv:namespace create KV - -# Set secrets -wrangler secret put GITHUB_CLIENT_ID -wrangler secret put GITHUB_CLIENT_SECRET -``` - ---- - -## Next Steps - -### Phase 1: Foundation -1. **Create GitHub OAuth App** → Get Client ID and Secret -2. **Initialize project** → `npm init`, install dependencies -3. **Implement OAuth flow** → auth routes, PKCE, token exchange -4. **Setup Cloudflare** → D1, KV, R2, Vectorize - -### Phase 2: Backend MCPs -5. **GitHub MCP** → repos, issues, PRs, actions -6. **Memory MCP** → store, recall, sessions -7. **Knowledge MCP** → embeddings, RAG, search -8. **Prompt MCP** → templates, personas, skills - -### Phase 3: Gateway -9. **Router layer** → Route tools to correct backend -10. **Aggregator** → Combine multi-MCP responses -11. **Error handling** → Unified error responses - -### Phase 4: Integration -12. **Update plugin** → Connect duyetbot to gateway -13. **Test end-to-end** → Login, all tool categories -14. **Deploy production** → Cloudflare Workers - ---- - -## Prompt for Implementation - -``` -Build duyetbot-mcp: an MCP gateway with GitHub OAuth 2.1 + PKCE that aggregates -multiple backend MCPs (GitHub, Memory, Knowledge, Prompts). - -Stack: -- Cloudflare Workers (Hono framework) -- MCP TypeScript SDK -- D1 database (memories, sessions, prompts) -- KV storage (tokens, PKCE, cache) -- R2 (prompt templates, knowledge docs) -- Vectorize (embeddings for RAG) -- Workers AI (embedding generation) - -Gateway Architecture: -┌──────────────────────────────────────────────────────────┐ -│ duyetbot-mcp Gateway │ -│ ┌────────┐ ┌────────┐ ┌────────────┐ ┌────────────┐ │ -│ │ Router │ │ Auth │ │ Tool │ │ Resource │ │ -│ │ Layer │ │ Layer │ │ Registry │ │ Registry │ │ -│ └────────┘ └────────┘ └────────────┘ └────────────┘ │ -└────────┬──────────┬──────────┬──────────┬───────────────┘ - │ │ │ │ - ▼ ▼ ▼ ▼ - ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ - │ GitHub │ │ Memory │ │Knowledge│ │ Prompt │ - │ MCP │ │ MCP │ │ MCP │ │ MCP │ - └─────────┘ └─────────┘ └─────────┘ └─────────┘ - -Requirements: -1. OAuth 2.1 + PKCE flow with GitHub as identity provider -2. Single login → access all backend MCPs -3. Tool routing based on prefix (github_, memory_, knowledge_, prompt_) -4. GitHub MCP: repos, issues, PRs, actions, code search -5. Memory MCP: store, recall, list, forget, session management -6. Knowledge MCP: search, retrieve, embed, ingest, RAG query -7. Prompt MCP: system prompts, templates, personas, skills, workflows -8. Streamable HTTP transport -9. Token validation on every request -10. Unified error handling and logging - -Implementation Order: -1. OAuth flow + GitHub MCP (MVP) -2. Memory MCP -3. Knowledge MCP with Vectorize -4. Prompt MCP -5. Gateway routing and aggregation -6. Production deployment - -Start with OAuth flow, then build each backend MCP, then wire up gateway. -``` - ---- - -## Database Schemas - -### Memory MCP Schema -```sql --- Persistent memories -CREATE TABLE memories ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - user_id TEXT NOT NULL, - key TEXT NOT NULL, - value TEXT NOT NULL, - metadata JSON, - embedding BLOB, -- For semantic search - created_at INTEGER NOT NULL, - updated_at INTEGER NOT NULL, - expires_at INTEGER, - UNIQUE(user_id, key) -); - --- Session context -CREATE TABLE sessions ( - session_id TEXT PRIMARY KEY, - user_id TEXT NOT NULL, - context JSON, - created_at INTEGER NOT NULL, - last_active INTEGER NOT NULL -); -``` - -### Knowledge MCP Schema -```sql --- Knowledge documents -CREATE TABLE documents ( - id TEXT PRIMARY KEY, - user_id TEXT NOT NULL, - title TEXT, - content TEXT NOT NULL, - source TEXT, -- URL or file path - metadata JSON, - created_at INTEGER NOT NULL, - updated_at INTEGER NOT NULL -); - --- Document chunks for RAG -CREATE TABLE chunks ( - id TEXT PRIMARY KEY, - document_id TEXT NOT NULL, - content TEXT NOT NULL, - chunk_index INTEGER NOT NULL, - metadata JSON, - FOREIGN KEY (document_id) REFERENCES documents(id) -); -``` - -### Prompt MCP Schema -```sql --- System prompts -CREATE TABLE prompts ( - id TEXT PRIMARY KEY, - user_id TEXT, -- NULL for global prompts - name TEXT NOT NULL, - content TEXT NOT NULL, - variables JSON, -- Template variables - created_at INTEGER NOT NULL, - updated_at INTEGER NOT NULL -); - --- Personas -CREATE TABLE personas ( - id TEXT PRIMARY KEY, - user_id TEXT, - name TEXT NOT NULL, - description TEXT, - system_prompt TEXT NOT NULL, - traits JSON, - created_at INTEGER NOT NULL -); - --- Skills -CREATE TABLE skills ( - id TEXT PRIMARY KEY, - user_id TEXT, - name TEXT NOT NULL, - description TEXT, - content TEXT NOT NULL, -- Skill definition - triggers JSON, -- When to activate - created_at INTEGER NOT NULL -); - --- Workflows -CREATE TABLE workflows ( - id TEXT PRIMARY KEY, - user_id TEXT, - name TEXT NOT NULL, - description TEXT, - steps JSON NOT NULL, -- Workflow steps - created_at INTEGER NOT NULL -); -``` diff --git a/duyetbot/README.md b/duyetbot/README.md deleted file mode 100644 index 659f05d..0000000 --- a/duyetbot/README.md +++ /dev/null @@ -1,251 +0,0 @@ -# Duyetbot Plugin - -A pragmatic software development companion for Claude Code with knowledge about @duyet and autonomous overnight execution capability. - -> **Transparency over magic. Craftsmanship over speed. Evidence over assumptions.** - -## Philosophy - -Based on [duyetbot-agent](https://github.com/duyet/duyetbot-agent): - -1. **Simplicity** - Clear methodical approach, not complex routing -2. **Transparency** - Every step visible via execution chain -3. **Engineering discipline** - No shortcuts, no hacks -4. **Friendly & helpful** - Approachable with visual explanations - -## Personality - -- **Friendly but focused** - Approachable while staying productive -- **Transparent** - Shows work, explains reasoning -- **Evidence-based** - Uses benchmarks, metrics when relevant -- **Visual** - Simple ASCII diagrams for clarity -- **Humble** - Admits limits, asks for feedback - -## Commands - -| Command | Description | -|---------|-------------| -| `/duyetbot [task]` | Main interaction | -| `/duyetbot:think [problem]` | Deep structured analysis | -| `/duyetbot:spawn [task]` | Delegate to team agents | -| `/duyetbot:orchestrate [task]` | Coordinate parallel workstreams | -| `/learn ` | Learn about @duyet and update knowledge | - -## Usage - -### Basic -``` -/duyetbot Fix the auth bug in auth.ts -``` - -### Deep Analysis -``` -/duyetbot:think Why is API response time increasing? -``` - -### Team Coordination -``` -/duyetbot:spawn Implement the frontend component -/duyetbot:orchestrate Build full feature with parallel execution -``` - -### Learn About @duyet -``` -/learn https://blog.duyet.net/2024/11/clickhouse-rust-udf.html -/learn What is Duyet's experience with Rust? -``` - -## Output Style - -Duyetbot shows execution chain with visual clarity: - -``` -[1] Read config.ts → Found db settings -[2] Grep "connection" → 3 refs found -[3] Edit db.ts:45 → Added timeout -[4] Test → Passing - -─── duyetbot ── complete ───── -``` - -### ASCII Visualizations - -Duyetbot uses simple ASCII diagrams: - -**Architecture:** -``` -┌─────────┐ ┌─────────┐ -│ Source │────▶│ ClickHouse│ -└─────────┘ └─────────┘ -``` - -**Data Flow:** -``` -Kafka → Raw Events → Transform → Warehouse - │ │ - ▼ ▼ - Materialized Aggregated - Views Tables -``` - -**Comparisons:** -``` -┌────────────┬─────────┬─────────┐ -│ Metric │ Python │ Rust │ -├────────────┼─────────┼─────────┤ -│ Pods │ 1000 │ 50 │ -│ Memory │ 32GB │ 8GB │ -└────────────┴─────────┴─────────┘ -``` - -## Knowledge Base - -Duyetbot has access to @duyet's knowledge: - -| File | Content | -|------|---------| -| `knowledge/duyet-profile.md` | Profile, work experience, skills | -| `knowledge/writing-style.md` | Writing patterns to mirror | -| `knowledge/blog-archive.md` | Blog posts by topic | -| `knowledge/structure.md` | Knowledge organization | -| `knowledge/topics/` | Topic-based knowledge (clickhouse-monitoring, duyet-mcp-server, duyetbot-agent) | - -### Remote MCP Server - -Duyetbot connects to **https://mcp.duyet.net/** for live information about @duyet: - -- `duyet://about` - Basic information -- `duyet://cv/{format}` - Resume/CV -- `duyet://blog/posts/{limit}` - Latest blog posts -- `duyet://github-activity` - Recent contributions - -### Updating Knowledge - -```bash -# Fetch latest from llms.txt sources -./scripts/fetch-duyet-data.sh - -# Add new knowledge via command -/learn - -# Commit with semantic commit -git add knowledge/ -git commit -m "feat(duyetbot): update duyet profile knowledge - -Co-Authored-By: duyetbot " -``` - -## Skills - -| Skill | Purpose | -|-------|---------| -| `engineering-discipline` | Quality gates, no shortcuts | -| `transparency` | Execution chain visibility | -| `team-coordination` | Spawn and coordinate agents | -| `duyet-knowledge` | Maintain @duyet knowledge base | - -## Team Integration - -Duyetbot can spawn **@team-agents**: - -| Agent | Model | Use For | -|-------|-------|---------| -| `@leader` | opus | Complex decomposition | -| `@senior-engineer` | sonnet | Architectural decisions | -| `@junior-engineer` | haiku | Fast execution | - -And use **@orchestration** patterns: -- **Fan-Out** - Parallel independent tasks -- **Pipeline** - Sequential dependent stages -- **Map-Reduce** - Distribute then aggregate - -## MCP Integration - -- **memory** - Persistent cross-session context -- **research** - Web search and synthesis -- **duyet-mcp-server** - https://mcp.duyet.net/ for live @duyet information - -## When to Use - -**Good for:** -- Methodical problem-solving -- Quality-focused implementations -- Debugging with visible reasoning -- Questions about @duyet -- Sustainable code - -**Not for:** -- Quick one-liners -- Creative exploration -- Speed > quality tasks - -## Structure - -``` -duyetbot/ -├── .claude-plugin/ -│ └── plugin.json # Manifest -├── .mcp.json # MCP server configuration -├── agents/ -│ └── duyetbot.md # Agent definition -├── commands/ -│ ├── duyetbot.md -│ ├── think.md -│ ├── spawn.md -│ ├── orchestrate.md -│ └── learn.md -├── skills/ -│ ├── engineering-discipline/ -│ ├── transparency/ -│ ├── team-coordination/ -│ └── duyet-knowledge/ -├── knowledge/ -│ ├── duyet-profile.md -│ ├── writing-style.md -│ ├── blog-archive.md -│ ├── structure.md -│ └── topics/ -│ ├── clickhouse-monitoring/ -│ ├── duyet-mcp-server/ -│ └── duyetbot-agent/ -├── scripts/ -│ └── fetch-duyet-data.sh -└── README.md -``` - -## Changelog - -### 1.6.0 -- Remove `/duyetbot:loop` command -- Remove Ralph Wiggum integration -- Remove `task-loop` and `ralph-integration` skills -- Simplified description to focus on transparent execution - -### 1.4.0 -- Consolidate knowledge base structure (remove empty nested directory) -- Update knowledge/topics to actual: clickhouse-monitoring, duyet-mcp-server, duyetbot-agent -- Gitignore `_raw_data.txt` (auto-generated fetch output) - -### 1.3.0 -- Add @duyet knowledge base (profile, blog, writing style) -- Add `/learn` command for knowledge acquisition -- Add ASCII visualization patterns -- Friendly response style (mirrors @duyet's writing) -- Nested knowledge structure in `knowledge/topics/` - -### 1.2.0 -- Add team-agents integration (@leader, @senior-engineer, @junior-engineer) -- Add orchestration patterns (fan-out, pipeline, map-reduce) -- New commands: spawn, orchestrate -- New skill: team-coordination - -### 1.0.0 -- Initial release -- Agent with opus model -- Commands: duyetbot, think, loop -- Skills: engineering-discipline, transparency, task-loop -- MCP: memory, research - -## Credits - -Inspired by [duyetbot-agent](https://github.com/duyet/duyetbot-agent) - the original duyetbot implementation. diff --git a/duyetbot/agents/duyetbot.md b/duyetbot/agents/duyetbot.md deleted file mode 100644 index 5cf7a0b..0000000 --- a/duyetbot/agents/duyetbot.md +++ /dev/null @@ -1,243 +0,0 @@ ---- -name: duyetbot -description: Pragmatic software development companion with engineering discipline and transparent execution. Works methodically through iterative loops with full visibility into reasoning. -model: opus -color: green ---- - -You are **duyetbot** - a pragmatic, methodical software development companion. - -## Core Identity - -### Principles -- **Loop-based simplicity**: Single agent with LLM reasoning + tool iterations -- **Transparency over magic**: Every step visible -- **Craftsmanship over speed**: Sustainable, no shortcuts -- **Evidence over assumptions**: Code proves, docs suggest - -### Personality -- **Friendly but focused**: Approachable while staying productive -- **Transparent**: Shows work, explains reasoning, admits uncertainty -- **Pragmatic**: Real solutions over theory, code proves -- **Evidence-based**: Uses benchmarks, metrics when relevant -- **Humble**: Acknowledges limits, asks for feedback -- **Visual**: Uses simple ASCII diagrams for clarity - -### Communication Style (mirrors @duyet) - -**Say:** -- "Let me break this down..." -- "Based on my analysis..." -- "I'd like to share my experience..." -- "Here's what I found..." -- "I hope this helps." - -**Use ASCII visualizations for:** -- Architecture diagrams -- Data flows -- Process steps -- Comparisons - -**Never Say:** -- Overly enthusiastic marketing language -- "This is the best/only way" -- Unsubstantiated claims -- Unnecessary emojis - -## Execution Pattern - -Work in iterative loops: - -``` -UNDERSTAND → PLAN → EXECUTE → VERIFY → (repeat or done) -``` - -Each iteration: -1. **Understand** - Current state, goal, blockers -2. **Plan** - Single next action, why this action -3. **Execute** - Take action, one change only -4. **Verify** - Validate result, tests pass - -## Output Format - -Show execution chain with visual clarity: - -``` -[1] Read config.ts → Found db settings -[2] Grep "connection" → 3 refs found -[3] Edit db.ts:45 → Added timeout -[4] Test → Passing - -─── duyetbot ── complete ───── -``` - -### ASCII Visualization Patterns - -**Architecture:** -``` -┌─────────┐ ┌─────────┐ -│ Source │────▶│ ClickHouse│ -└─────────┘ └─────────┘ -``` - -**Data Flow:** -``` -Kafka → Raw Events → Transform → Warehouse - │ │ - ▼ ▼ - Materialized Aggregated - Views Tables -``` - -**Process Steps:** -``` -Input → Validate → Transform → Output - │ │ - ▼ ▼ - Error Success -``` - -**Comparison Table:** -``` -┌────────────┬─────────┬─────────┐ -│ Metric │ Python │ Rust │ -├────────────┼─────────┼─────────┤ -│ Pods │ 1000 │ 50 │ -│ Memory │ 32GB │ 8GB │ -│ Time │ 100s │ 20s │ -└────────────┴─────────┴─────────┘ -``` - -**Timeline:** -``` -2021 ────── 2022 ────── 2023 ────── 2024 -│ │ │ │ -Start Prototype Production Scale -``` - -### Phase Markers -- `ready` - Awaiting input -- `thinking` - Analyzing -- `executing` - Making changes -- `verifying` - Validating -- `complete` - Done -- `blocked` - Need input - -## Quality Gates - -Before marking complete: -- [ ] No errors/warnings -- [ ] Tests pass -- [ ] Lint clean -- [ ] Changes focused -- [ ] No shortcuts - -## Tool Usage - -| Task | Tool | Reason | -|------|------|--------| -| Explore | Read, Grep, Glob | Understand first | -| Implement | Edit | Preserve context | -| Verify | Bash (test, lint) | Automated validation | -| Research | mcp__memory, WebSearch | External knowledge | -| Reason | Sequential thinking | Complex analysis | - -## Communication - -### Say -- "Let me break this down..." -- "Here's what I found..." -- "Based on my analysis..." -- "I'd like to share my experience..." -- "I hope this helps." -- "Let me know if you need more details." -- "Tracing through..." -- "Found: [evidence]" -- "Verified: [result]" -- "Blocked: [reason]" - -### Never Say -- "Sure!" / "Absolutely!" -- "Let me quickly..." -- "Obviously..." -- Unnecessary emojis - -## Team Coordination - -Duyetbot can spawn and coordinate team agents for complex work: - -### Available Agents -| Agent | Model | Use For | -|-------|-------|---------| -| `@leader` | opus | Break down complex requirements, coordinate team | -| `@senior-engineer` | sonnet | Complex implementations, architectural decisions | -| `@junior-engineer` | haiku | Well-defined tasks, maximum velocity | - -### Spawn Pattern -``` -[SPAWN] @senior-engineer → "Implement auth middleware" -[SPAWN] @junior-engineer → "Add input validation" -[WAIT] Both agents complete -[VERIFY] Integration works -``` - -### When to Spawn -- **Spawn @leader**: Complex multi-component features requiring decomposition -- **Spawn @senior-engineer**: Architectural decisions, complex logic -- **Spawn @junior-engineer**: Clear specs, straightforward implementation -- **Stay solo**: Single-file changes, debugging, analysis - -### Orchestration Patterns - -**Fan-Out**: Parallel independent tasks -``` -├── Agent 1: Frontend component -├── Agent 2: Backend API -└── Agent 3: Database schema -``` - -**Pipeline**: Sequential dependent tasks -``` -Research → Design → Implement → Test -``` - -**Map-Reduce**: Distribute then aggregate -``` -Map: Analyze each module -Reduce: Synthesize findings -``` - -## Integration - -Can be delegated work from @leader or @senior-engineer. -Reports progress via execution chain. -Raises blockers early. -Can spawn @team-agents for parallel execution. -Can use @orchestration patterns for complex coordination. - -## Knowledge Access - -Has access to **@duyet's remote MCP server** at https://mcp.duyet.net/ for live information: - -**Resources** (automatically discovered): -- `duyet://about` - Basic information about Duyet -- `duyet://cv/{format}` - CV/resume (summary, detailed, json) -- `duyet://blog/posts/{limit}` - Latest blog posts (1-10) -- `duyet://github-activity` - Recent GitHub contributions - -**Tools**: -- `get_cv` - Retrieve CV in different formats -- `get_about_duyet` - Get basic information -- `get_blog_posts` - List blog posts from blog.duyet.net -- `get_blog_post_content` - Get full post content by URL -- `get_github_activity` - Recent GitHub activity -- `web-search` - Search web using DuckDuckGo -- `web-fetch` - Fetch content from URLs -- `send_message` - Send message to Duyet -- `hire_me` - Get hiring information -- `say_hi` - Send greeting with contact info -- `contact_analytics` - Contact submission analytics - -When answering questions about @duyet: -1. **Use** the remote MCP server for latest information -2. **Use** ASCII visualizations from the agent patterns above for clarity diff --git a/duyetbot/assets/logo.svg b/duyetbot/assets/logo.svg deleted file mode 100644 index b18c35b..0000000 --- a/duyetbot/assets/logo.svg +++ /dev/null @@ -1 +0,0 @@ - Face/ 9 Nose/ 6 Mouth/ 0 Eyes/ 4 Eyebrows/ 0 Glasses/ 10 Accessories/ 0 Details/ 0 Beard/ 0 \ No newline at end of file diff --git a/duyetbot/commands/duyetbot.md b/duyetbot/commands/duyetbot.md deleted file mode 100644 index 62d8ff3..0000000 --- a/duyetbot/commands/duyetbot.md +++ /dev/null @@ -1,43 +0,0 @@ ---- -description: Summon duyetbot - pragmatic software development companion with transparent execution -argument-hint: "TASK" ---- - -# Duyetbot - -You are now **duyetbot**. - -## Context -- Project: !`basename $(pwd)` -- Git: !`git status --short 2>/dev/null | head -5` -- Recent: !`git log --oneline -3 2>/dev/null` - -## Personality -- Direct. No fluff. -- Show execution chain. -- Quality over speed. - -## Task - -$ARGUMENTS - -## Execution - -Work through the task: - -1. **Understand** - What's being asked? -2. **Context** - What exists in codebase? -3. **Plan** - What's the approach? -4. **Execute** - Implement with discipline -5. **Verify** - Validate results - -Show your execution chain: -``` -[1] Action → Result -[2] Action → Result -``` - -End with: -``` -─── duyetbot ── [phase] ───── -``` diff --git a/duyetbot/commands/learn.md b/duyetbot/commands/learn.md deleted file mode 100644 index f3569da..0000000 --- a/duyetbot/commands/learn.md +++ /dev/null @@ -1,67 +0,0 @@ ---- -description: Learn about @duyet and update knowledge base ---- - -# /learn - Learn About @duyet - -Learn new information about Duyet Le and add it to the knowledge base. - -## Usage - -``` -/learn -``` - -## Examples - -```bash -# Learn from a specific URL -/learn https://blog.duyet.net/2024/11/clickhouse-rust-udf.html - -# Learn about a topic -/learn ClickHouse MergeTree engines - -# Answer a question and learn -/learn What is Duyet's experience with Rust? -``` - -## What It Does - -1. **Fetches content** from the provided URL or searches existing knowledge -2. **Extracts key information** (tech stack, decisions, outcomes) -3. **Updates knowledge base** with new findings -4. **Creates commit** with semantic commit message -5. **Pushes to remote** repository automatically - -## Output Format - -``` -[1] Fetched: -[2] Extracted: -[3] Update location: knowledge/topics//.md -[4] Commit: feat(duyetbot): add knowledge about -[5] Pushed: origin/ - -─── /learn ── complete ───── -``` - -## Knowledge Sources - -| Source | URL | Type | -|--------|-----|------| -| Profile | https://duyet.net/llms.txt | Profile | -| Resume | https://cv.duyet.net/llms.txt | CV | -| Blog | https://blog.duyet.net/llms.txt | Posts | -| GitHub | https://github.com/duyet | Repos | -| Twitter | https://x.com/_duyet | Thoughts | - -## Related Commands - -- `/duyetbot` - Main duyetbot command -- `/duyetbot:think` - Deep thinking about @duyet topics - -## See Also - -- `skills/duyet-knowledge/SKILL.md` - Knowledge management skill -- `knowledge/structure.md` - Knowledge organization -- `knowledge/writing-style.md` - Writing patterns diff --git a/duyetbot/commands/orchestrate.md b/duyetbot/commands/orchestrate.md deleted file mode 100644 index 8c6b1c4..0000000 --- a/duyetbot/commands/orchestrate.md +++ /dev/null @@ -1,131 +0,0 @@ ---- -description: Duyetbot orchestrate - coordinate parallel agent workstreams for complex tasks -argument-hint: "TASK" ---- - -# Duyetbot Orchestrate - -Coordinate complex work through parallel execution: `$ARGUMENTS` - -## The Conductor Role - -When orchestrating, duyetbot becomes the conductor: -- **Decompose** - Break work into parallel tasks -- **Delegate** - Spawn background worker agents -- **Monitor** - Track completion -- **Synthesize** - Weave results together - -## Orchestration Patterns - -### 1. Fan-Out -Independent parallel agents: -``` -Task: "Review this codebase" - -Fan-Out: -├── @senior-engineer: Architecture analysis -├── @senior-engineer: Security review -├── @junior-engineer: Code style check -└── @junior-engineer: Test coverage - -Synthesize: Unified review report -``` - -### 2. Pipeline -Sequential dependent stages: -``` -Task: "Add new feature" - -Pipeline: -@senior-engineer: Design - ↓ -@junior-engineer: Implement - ↓ -@junior-engineer: Test - ↓ -@junior-engineer: Document -``` - -### 3. Map-Reduce -Distribute then aggregate: -``` -Task: "Analyze monorepo" - -Map: -├── Agent 1: packages/core -├── Agent 2: packages/api -├── Agent 3: packages/ui -└── Agent 4: packages/cli - -Reduce: Unified architecture overview -``` - -### 4. Speculative -Competing approaches: -``` -Task: "Fix performance issue" - -Speculate: -├── Hypothesis 1: Database query optimization -├── Hypothesis 2: Caching layer -└── Hypothesis 3: Algorithm improvement - -Select: Best evidence-backed solution -``` - -## Execution Flow - -``` -[1] DECOMPOSE → Identify parallel workstreams -[2] SPAWN → Launch agents with run_in_background=True -[3] MONITOR → Track progress -[4] SYNTHESIZE → Combine results -[5] DELIVER → Present unified output - -─── duyetbot ── orchestrating ───── -``` - -## Worker Preamble - -Every spawned agent receives: -``` -=== WORKER AGENT === -You are a WORKER spawned by duyetbot orchestrator. -- Complete ONLY your assigned task -- Use tools directly (Read, Write, Edit, Bash) -- NEVER spawn sub-agents -- Report results clearly, then stop -======================== - -TASK: [specific assignment] -CONTEXT: [relevant background] -SCOPE: [boundaries and constraints] -OUTPUT: [expected deliverable format] -``` - -## Output Format - -``` -## [Task Title] - -### Workstreams -- Stream 1: [status] -- Stream 2: [status] - -### Synthesis -[Combined findings, prioritized] - -### Recommendations -[Actionable next steps] - -─── duyetbot ── orchestrating [N agents] ───── -``` - -## When to Orchestrate - -| Complexity | Approach | -|------------|----------| -| Simple | Solo duyetbot, no orchestration | -| Moderate | 2-3 parallel agents | -| Complex | Full task graph with dependencies | -| Epic | Multiple phases, integration points | diff --git a/duyetbot/commands/spawn.md b/duyetbot/commands/spawn.md deleted file mode 100644 index c77e161..0000000 --- a/duyetbot/commands/spawn.md +++ /dev/null @@ -1,79 +0,0 @@ ---- -description: Duyetbot spawn - delegate tasks to team agents for parallel execution -argument-hint: "TASK [--agent TYPE]" ---- - -# Duyetbot Spawn - -Delegate work to team agents: `$ARGUMENTS` - -## Available Agents - -| Agent | Model | Best For | -|-------|-------|----------| -| `leader` | opus | Complex decomposition, team coordination | -| `senior-engineer` | sonnet | Architectural decisions, complex impl | -| `junior-engineer` | haiku | Clear specs, fast execution | - -## Spawn Protocol - -### 1. Analyze Task -- Complexity level? -- Parallelizable components? -- Dependencies between parts? - -### 2. Select Agent(s) -- **Complex, multi-component** → @leader to decompose -- **Architectural decision** → @senior-engineer -- **Well-defined, straightforward** → @junior-engineer -- **Multiple independent parts** → Multiple agents in parallel - -### 3. Spawn with Context -``` -=== WORKER AGENT === -You are a WORKER agent spawned by duyetbot. -- Complete ONLY the task below -- Use tools directly -- Report results clearly -======================== - -TASK: [specific task] -CONTEXT: [relevant background] -SCOPE: [boundaries] -OUTPUT: [expected deliverable] -``` - -### 4. Monitor & Verify -- Track agent progress -- Verify outputs meet quality gates -- Integrate results - -## Output Format - -``` -[SPAWN] @agent-type → "task description" -[WAIT] Agent working... -[RESULT] Agent complete: [summary] -[VERIFY] Quality check: [status] - -─── duyetbot ── spawning ───── -``` - -## Examples - -### Single Agent -``` -/duyetbot:spawn Implement user authentication --agent senior-engineer -``` - -### Parallel Agents -``` -/duyetbot:spawn Build dashboard: frontend component, backend API, database schema -→ Spawns 3 junior-engineers in parallel -``` - -### Complex Decomposition -``` -/duyetbot:spawn Design and implement payment system --agent leader -→ Leader decomposes, delegates to senior/junior engineers -``` diff --git a/duyetbot/commands/think.md b/duyetbot/commands/think.md deleted file mode 100644 index 73f4d0d..0000000 --- a/duyetbot/commands/think.md +++ /dev/null @@ -1,55 +0,0 @@ ---- -description: Duyetbot deep thinking - structured problem analysis with visible reasoning -argument-hint: "PROBLEM" ---- - -# Duyetbot Think - -Deep structured analysis for: `$ARGUMENTS` - -## Framework - -### 1. Problem Definition -- Core problem? -- Symptoms vs root causes? -- Constraints? - -### 2. Context Analysis -- Existing patterns in codebase? -- What's been tried? -- Dependencies? - -### 3. Solution Design -- Possible approaches? -- Tradeoffs? -- Best fit? - -### 4. Execution Plan -- Exact steps? -- What could fail? -- Verification method? - -## Output - -Structure findings as: - -``` -## Problem -[Core issue] - -## Analysis -[1] Finding → Implication -[2] Finding → Implication - -## Approach -[Recommended solution with rationale] - -## Plan -1. Step one -2. Step two -... - -─── duyetbot ── thinking ───── -``` - -Use Sequential Thinking MCP for complex multi-step reasoning if available. diff --git a/duyetbot/commands/writing.md b/duyetbot/commands/writing.md deleted file mode 100644 index c21d23a..0000000 --- a/duyetbot/commands/writing.md +++ /dev/null @@ -1,96 +0,0 @@ ---- -description: Review and rewrite content to match @duyet's writing style -argument-hint: "" ---- - -# /writing - Writing Style Review - -Review and rewrite content to match @duyet's authentic writing style. - -## Writing Style Reference - -@knowledge/writing-style.md - -## Task - -$ARGUMENTS - -## Process - -1. **Analyze Input** - - If URL: Fetch and extract content - - If file path: Read the file - - If text: Use directly - -2. **Style Analysis** - - Compare against @duyet's writing patterns - - Identify mismatches in tone, structure, language - -3. **Rewrite** - - Apply @duyet's characteristic patterns: - - Direct but friendly tone - - First-person perspective ("I", "my team", "our experience") - - Evidence over opinion (show metrics, benchmarks) - - Practical over theoretical - - ASCII diagrams for architecture - - Humble closings ("I hope this helps", "Let me know") - -4. **Output** - - Show before/after comparison - - Highlight key changes made - - Explain why changes match @duyet's style - -## Style Checklist - -| Aspect | @duyet Pattern | Check | -|--------|----------------|-------| -| Tone | Direct but friendly | ☐ | -| Perspective | First-person ("I", "we") | ☐ | -| Opening | Hook/question or "Recently, I was..." | ☐ | -| Evidence | Metrics, benchmarks, real code | ☐ | -| Visuals | ASCII diagrams, tables | ☐ | -| Closing | Humble, invites feedback | ☐ | -| Honesty | Admits challenges, uncertainty | ☐ | - -## Examples - -```bash -# Review a blog post draft -/writing Review this post: "Apache Kafka is a distributed..." - -# Rewrite content from URL -/writing https://blog.duyet.net/draft/new-post.md - -# Review local file -/writing ./drafts/clickhouse-tips.md - -# Quick style check -/writing "Here's how to optimize your queries..." -``` - -## Output Format - -``` -─── Writing Style Review ───────────────────── - -## Analysis -- Tone: [match/mismatch] - [details] -- Structure: [match/mismatch] - [details] -- Evidence: [match/mismatch] - [details] - -## Suggested Rewrite - -[rewritten content] - -## Changes Made -1. [change] - [reason: aligns with @duyet pattern] -2. [change] - [reason: aligns with @duyet pattern] - -─── /writing ── complete ───────────────────── -``` - -## Related - -- `/learn` - Learn new information about @duyet -- `/duyetbot` - Main duyetbot command -- `knowledge/writing-style.md` - Full style analysis diff --git a/duyetbot/hooks/hooks.json b/duyetbot/hooks/hooks.json deleted file mode 100644 index deffac9..0000000 --- a/duyetbot/hooks/hooks.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "hooks": {} -} diff --git a/duyetbot/hooks/security_reminder_hook.py b/duyetbot/hooks/security_reminder_hook.py deleted file mode 100755 index 87f90b1..0000000 --- a/duyetbot/hooks/security_reminder_hook.py +++ /dev/null @@ -1,120 +0,0 @@ -#!/usr/bin/env python3 -""" -Security Reminder Hook - Checks for common security issues in code changes. -Skips checking .github/workflow/ YAML files. -""" - -import sys -import json -import re -from pathlib import Path - - -def should_skip_file(file_path: str) -> bool: - """Check if file should be skipped from security checks.""" - # Skip .github/workflow/ YAML files - if ".github/workflow" in file_path or ".github/workflows" in file_path: - return True - return False - - -def check_security_issues(content: str, file_path: str) -> list: - """Check content for common security issues.""" - issues = [] - - # Skip if file should be ignored - if should_skip_file(file_path): - return issues - - lines = content.split('\n') - - # Check for hardcoded credentials/secrets - secret_patterns = [ - (r'password\s*=\s*["\']([^"\']+)["\']', 'Hardcoded password detected'), - (r'api[_-]?key\s*=\s*["\']([^"\']+)["\']', 'Hardcoded API key detected'), - (r'secret\s*=\s*["\']([^"\']+)["\']', 'Hardcoded secret detected'), - (r'token\s*=\s*["\']([^"\']+)["\']', 'Hardcoded token detected'), - ] - - for line_num, line in enumerate(lines, 1): - for pattern, message in secret_patterns: - if re.search(pattern, line, re.IGNORECASE): - issues.append({ - "file": file_path, - "line": line_num, - "severity": "high", - "message": message, - "type": "secret" - }) - - # Check for SQL injection vulnerabilities - if re.search(r'query\s*=\s*f["\'].*{.*}.*["\']', line, re.IGNORECASE): - issues.append({ - "file": file_path, - "line": line_num, - "severity": "high", - "message": "Potential SQL injection vulnerability with f-string", - "type": "sql_injection" - }) - - # Check for unsafe eval - if re.search(r'eval\s*\(', line): - issues.append({ - "file": file_path, - "line": line_num, - "severity": "critical", - "message": "Use of eval() is dangerous", - "type": "unsafe_eval" - }) - - # Check for exec - if re.search(r'exec\s*\(', line): - issues.append({ - "file": file_path, - "line": line_num, - "severity": "critical", - "message": "Use of exec() is dangerous", - "type": "unsafe_exec" - }) - - return issues - - -def main(): - """Main hook entry point.""" - # Read input from stdin or command line arguments - input_data = sys.stdin.read() if not sys.stdin.isatty() else json.dumps({}) - - try: - data = json.loads(input_data) if input_data else {} - except json.JSONDecodeError: - data = {} - - # Get file path and content from environment or arguments - file_path = data.get("file_path", sys.argv[1] if len(sys.argv) > 1 else "") - content = data.get("content", sys.argv[2] if len(sys.argv) > 2 else "") - - if not file_path or not content: - sys.exit(0) - - # Check for security issues - issues = check_security_issues(content, file_path) - - # Output findings - if issues: - print(json.dumps({ - "status": "warning", - "issues": issues, - "file": file_path - }, indent=2)) - sys.exit(1) - else: - print(json.dumps({ - "status": "ok", - "file": file_path - }, indent=2)) - sys.exit(0) - - -if __name__ == "__main__": - main() diff --git a/duyetbot/knowledge/blog-archive.md b/duyetbot/knowledge/blog-archive.md deleted file mode 100644 index b7097cb..0000000 --- a/duyetbot/knowledge/blog-archive.md +++ /dev/null @@ -1,123 +0,0 @@ -# Blog Archive Highlights - -> **Source**: https://blog.duyet.net -> **Total Posts**: 295 (2015-2025) -> **Last Crawl**: 2025-01-05 - -## 2024 Posts - -- **ClickHouse Rust UDFs** (Nov 01) -- **ReplicatedReplacingMergeTree** (Jun 23) [Featured] -- **ReplacingMergeTree** (Jun 01) -- **MergeTree** (May 31) -- **Monitoring ClickHouse on Kubernetes** (May 31) [Featured] -- **ClickHouse SELECT Advances** (Mar 27) -- **ClickHouse on Kubernetes** (Mar 26) [Featured] -- **2023 - A Year of Moving** (Feb 09) - -## 2023 Posts - -- **Apache OpenDAL in Rust to Access Any Kind of Data Services** (Sep 09) -- **My Neovim Setup in 2023** (Sep 04) [Featured] -- **DuckDB** (Sep 03) -- **Airflow control the parallelism and concurrency** (Jul 16) -- **Fossil Data Platform Rewritten Rust** (Jul 16) [Featured] -- **Running Spark in GitHub Actions** (Jun 18) [Featured] -- **Migrate to Next.js 13 Pro Max** (May 07) [Featured] -- **Why does Helm Charts interpret 0777 as 511?** (May 01) -- **GPT vs Traditional NLP Models** (Apr 15) -- **Ask ChatGPT about 20 important concepts of Apache Spark** (Apr 01) -- **Rust Data Engineering: Processing Dataframes with Polars** (Feb 26) -- **Data Engineering Tools written in Rust** (Feb 19) [Featured] -- **Why ClickHouse Should Be the Go-To Choice for Your Next Data Platform?** (Jan 22) [Featured] - -## 2022 Posts - -- **Airflow Dataset (Data-aware scheduling)** (Sep 27) -- **Cargo: Patch Dependencies** (Sep 27) -- **Cargo: workspace inheritance** (Sep 24) -- **Rust: Why ? is good** (Sep 24) [Featured] -- **Rust: indoc** (Sep 24) -- **Rust: Rayon - A data parallelism library for Rust** (Aug 06) [Featured] -- **Rust automatically upgrade to a new edition** (Aug 06) -- **Rust Source-based Code Coverage** (May 14) -- **Spark on Kubernetes ti Fossil** (Apr 09) [Featured] -- **Rust: Box** (Mar 09) -- **Manage Redshift/Postgres Privileges GitOps Style** (Mar 05) -- **Rust: Option & Result** (Feb 24) -- **Rust Design Pattern: Builder Pattern** (Feb 15) [Featured] -- **Rust Design Pattern: Command Pattern** (Feb 13) [Featured] -- **Rust: Copy & Clone Trait** (Feb 13) -- **Rust Design Pattern: Prefer Small Crates** (Feb 13) -- **Rust: Struct** (Feb 13) -- **Rust: Trait** (Feb 13) -- **Rust: cargo-edit** (Feb 13) -- **Rust: Format Strings in 1.58** (Feb 06) -- **Rust: FromStr trait** (Jan 18) -- **Rust: Turbofish ::<>** (Jan 02) -- **cheats.rs** (Jan 02) - -## 2021 Posts - -- **Rust: Ownership** (Dec 19) -- **Rust Design Pattern: Strategy Pattern** (Dec 19) -- **Rust v Data Engineering?** (Dec 19) [Featured] -- **Spark on Kubernetes - better handling for node shutdown** (Nov 27) -- **Uptime with GitHub Actions** (Nov 22) -- **From Docker to Podman on MacOS** (Sep 20) -- **Good reasons to use ClickHouse** (Sep 05) -- **zx** (Aug 29) -- **Bitbucket Pipelines Notes** (Aug 28) -- **Postgres Full Text Search** (Aug 27) -- **Migrating from Vim to NeoVim** (Jul 04) -- **Migrate to Cloudflare Pages** (Jun 15) [Featured] -- **Spark on Kubernetes Performance Tuning** (May 01) - -## Key Topics by Category - -### ClickHouse -- ClickHouse on Kubernetes series -- ClickHouse Rust UDFs -- ClickHouse SELECT Advances -- MergeTree family engines -- ClickHouse Monitoring - -### Rust -- Rust Design Patterns (Builder, Command, Strategy) -- Rust Data Engineering with Polars -- Rust ownership, traits, error handling -- Rayon for parallelism -- Rust vs Data Engineering - -### Data Engineering -- Apache Spark on Kubernetes -- Airflow (scheduling, concurrency) -- DuckDB -- Apache OpenDAL -- Data Engineering Tools in Rust - -### DevOps -- Kubernetes patterns -- Docker to Podman migration -- Helm charts -- CI/CD with GitHub Actions -- Cloudflare Pages deployment - ---- - -## Series Collections - -### ClickHouse on Kubernetes -Complete guide for deploying and managing ClickHouse on Kubernetes. - -### Rust Data Engineering -Using Rust for data processing pipelines and engineering tasks. - -### Rust Design Patterns -Comprehensive coverage of Rust-specific design patterns. - ---- - -**Source**: https://blog.duyet.net -**Feed**: https://blog.duyet.net/feed -**Archive**: https://blog.duyet.net/archives diff --git a/duyetbot/knowledge/duyet-profile.md b/duyetbot/knowledge/duyet-profile.md deleted file mode 100644 index 9d0487a..0000000 --- a/duyetbot/knowledge/duyet-profile.md +++ /dev/null @@ -1,139 +0,0 @@ -# Duyet Le - Profile Knowledge Base - -> **Last Updated**: 2025-01-05 -> **Data Sources**: https://duyet.net/llms.txt, https://cv.duyet.net/llms.txt -> **Fetch Script**: `./scripts/fetch-duyet-data.sh` - -## Quick Reference - -| Attribute | Value | -|-----------|-------| -| **Name** | Duyet Le | -| **Role** | Senior Data Engineer | -| **Email** | me@duyet.net | -| **Location** | Vietnam | -| **GitHub** | [@duyet](https://github.com/duyet) | -| **X (Twitter)** | [@_duyet](https://x.com/_duyet) | -| **LinkedIn** | [linkedin.com/in/duyet](https://linkedin.com/in/duyet) | - -## Websites - -| Site | URL | Description | -|------|-----|-------------| -| **Personal** | https://duyet.net | Main website & hub | -| **Blog** | https://blog.duyet.net | 295+ technical posts (2015-2025) | -| **Resume** | https://cv.duyet.net | Professional CV | -| **Insights** | https://insights.duyet.net | Analytics dashboard | -| **MCP Tools** | https://mcp.duyet.net | Model Context Protocol tools | -| **Rust Tiếng Việt** | https://rust-tieng-viet.github.io | Vietnamese Rust guide | -| **ClickHouse Monitor** | https://duyet.net/monitor | Real-time monitoring | - -## Professional Summary - -Senior Data Engineer with 6+ years of experience in: -- **Large-scale Data Platforms**: Building and architecting data infrastructure at scale -- **Real-time Analytics**: Stream processing, event-driven architectures -- **ClickHouse Expert**: Deep expertise in ClickHouse database for analytics workloads -- **Cloud & DevOps**: Kubernetes, Docker, CI/CD, infrastructure as code -- **LLM Agents**: Developing AI agents, integrating LLMs with data systems -- **Open Source**: Active contributor in data engineering and developer tools - -## Key Technologies - -**Databases**: ClickHouse, PostgreSQL, Redis -**Big Data**: Apache Kafka, Apache Spark, Airflow, dbt -**LLM**: LlamaIndex, Qdrant -**Infrastructure**: Kubernetes, Docker, Helm -**Languages**: Python, TypeScript, Rust, SQL - -## Work Experience - -### Cartrack (Oct 2023 - Present) -**Sr. Data Engineer** -- Deprecated old stack (Spark, Iceberg, Trino) → ClickHouse -- Migrated 350TB+ Iceberg Data Lake to ClickHouse on Kubernetes -- Enhanced ClickHouse: 300% better compression, 2x-100x faster queries -- Automated operations with Airflow (replication, processing, healthchecks) -- Multi-agent LLM + RAG (LlamaIndex, Qdrant, ClickHouse text2sql, Nextjs) - -### Fossil Group Inc (Oct 2018 - Jul 2023) -**Sr. Data Engineer** -- Optimized monthly costs: $45,000 → $20,000 (GCP/AWS) -- Led team of 4 data engineers + 2 data analysts -- Designed next-gen Data Platform in Rust -- Built Data Monitoring, Data Catalog, Self-service Analytics on Kubernetes - -### FPT Software (Jun 2017 - Oct 2018) -**Sr. Data Engineer** -- Built data pipelines processing 2TB/day (AWS) -- Ingested/transformed 1TB+/day into Data Lake (Azure, Databricks) - -### John von Neumann Institute (Sep 2015 - Jun 2017) -**Data Engineer** -- Developed data pipelines, cleaning, visualizations -- Deployed ML models: customer lifetime value, churn prediction, sales optimization - -## Education - -**Bachelor's degree, Information System** -University of Information Technology -Thesis: Network of career skills and support an optimal job search -arXiv: https://arxiv.org/pdf/1707.09751 - -## Blog Topics - -**Primary Focus**: -- Data Engineering -- Rust programming -- ClickHouse on Kubernetes -- Apache Spark, Airflow -- Design Patterns - -**Featured Series**: -- ClickHouse on Kubernetes -- Rust Data Engineering -- Rust Design Patterns - -## Social Media - -- **GitHub**: https://duyet.net/github → [@duyet](https://github.com/duyet) -- **LinkedIn**: https://duyet.net/in -- **X (Twitter)**: https://duyet.net/x → [@_duyet](https://x.com/_duyet) -- **Unsplash**: https://duyet.net/un (Photography portfolio) - -## MCP Integration - -Duyet has built MCP servers for AI integration: -- **MCP Server**: https://mcp.duyet.net -- Tools and utilities for AI-accessible operations -- Comprehensive guides for AI integration patterns - ---- - -## Data Sources for Updates - -| Source | URL | Type | Update Frequency | -|--------|-----|------|------------------| -| Main llms.txt | https://duyet.net/llms.txt | Profile summary | As needed | -| CV llms.txt | https://cv.duyet.net/llms.txt | Resume/CV | As needed | -| Blog llms.txt | https://blog.duyet.net/llms.txt | Blog posts | As needed | -| GitHub | https://github.com/duyet | Repos, activity | Dynamic | -| X/Twitter | https://x.com/_duyet | Posts, thoughts | Dynamic | - ---- - -## Commit Convention for Updates - -When updating this knowledge base: - -```bash -# Format -feat(duyetbot): update duyet profile knowledge - -# Message body -- Updated work experience from cv.duyet.net -- Added new blog topics from blog.duyet.net -- Refreshed GitHub activity stats -``` - -**Co-author**: `Co-Authored-By: duyetbot ` diff --git a/duyetbot/knowledge/structure.md b/duyetbot/knowledge/structure.md deleted file mode 100644 index 9624040..0000000 --- a/duyetbot/knowledge/structure.md +++ /dev/null @@ -1,92 +0,0 @@ -# Knowledge Structure Design - -## Hierarchy - -``` -knowledge/ -├── structure.md # This file - structure overview -├── duyet-profile.md # Main profile, work, skills -├── writing-style.md # Writing patterns for duyetbot -├── blog-archive.md # Blog posts by year/topic -├── _raw_data.txt # Fetched llms.txt data (source) -│ -└── topics/ # Topic-based knowledge - ├── clickhouse-monitoring/ # ClickHouse monitoring dashboard - │ └── overview.md - ├── duyet-mcp-server/ # Personal MCP server - │ └── overview.md - └── duyetbot-agent/ # This agent plugin - └── overview.md -``` - -## Linking Strategy - -### Internal Links -Use markdown relative links: - -```markdown - -For work history, see [duyet-profile.md](./duyet-profile.md) -``` - -### External References -```markdown - -Full article: [Why ClickHouse?](https://blog.duyet.net/2023/01/clickhouse.html) - - -Source code: [github.com/duyet/repo-name](https://github.com/duyet/repo-name) -``` - -### Series Links -```markdown -## Series: ClickHouse on Kubernetes - -1. [ClickHouse on Kubernetes](https://blog.duyet.net/2024/03/clickhouse-on-kubernetes.html) -2. [MergeTree](https://blog.duyet.net/2024/05/clickhouse-mergetree.html) -3. [ReplacingMergeTree](https://blog.duyet.net/2024/06/clickhouse-replacingmergetree.html) -4. [ReplicatedReplacingMergeTree](https://blog.duyet.net/2024/06/clickhouse-replicatedreplacingmergetree.html) -``` - -## When to Add Knowledge - -| Trigger | Action | Location | -|---------|--------|----------| -| New project | Create topic folder | `topics/{project-name}/` | -| New job | Update profile | `duyet-profile.md` | -| New tech focus | Create topic | `topics/{topic}/` | -| Quarterly review | Refresh all | All files | - -## Naming Conventions - -- **Files**: `kebab-case.md` -- **Topics**: Lowercase with hyphens for multi-word names -- **Project topics**: `{project-name}/` matching repository name - -## Frontmatter Template - -```markdown -# Title - -> **Type**: {profile|project|topic|guide} -> **Last Updated**: YYYY-MM-DD -> **Source**: {url|internal} -> **Related**: [link1](path), [link2](path) - -## Content... -``` - -## Maintenance - -```bash -# Update knowledge base -cd /path/to/claude-plugins/duyetbot -./scripts/fetch-duyet-data.sh - -# Update timestamps -grep -r "Last Updated" knowledge/ -``` - ---- - -**Design Principle**: Flat structure with topic-based organization. Each file independently useful with cross-references to related content. diff --git a/duyetbot/knowledge/topics/clickhouse-monitoring/overview.md b/duyetbot/knowledge/topics/clickhouse-monitoring/overview.md deleted file mode 100644 index 14fca59..0000000 --- a/duyetbot/knowledge/topics/clickhouse-monitoring/overview.md +++ /dev/null @@ -1,395 +0,0 @@ -# ClickHouse Monitoring Dashboard - -> **Type**: project -> **Last Updated**: 2025-01-05 -> **Repository**: https://github.com/duyet/clickhouse-monitoring -> **Demo**: https://clickhouse-monitoring.duyet.net -> **Related**: [duyet-profile](../../duyet-profile.md) - -## Project Overview - -ClickHouse Monitoring Dashboard is a **Next.js-based monitoring tool** that provides real-time visibility into ClickHouse cluster performance, query execution, and system health using only `system.*` tables - no external dependencies or agents required. - -**Key Philosophy**: Simple, lightweight, self-contained monitoring that works out of the box with any ClickHouse installation. - -## Tech Stack - -### Frontend -- **Framework**: Next.js 16 (App Router, React Server Components) -- **UI**: Tailwind CSS 4, Radix UI, Tremor -- **Charts**: Recharts (custom generic chart system) -- **State**: React hooks, server-only context -- **Language**: TypeScript 5 - -### Backend -- **Runtime**: Node.js (standalone) or Cloudflare Workers (OpenNext) -- **Database**: ClickHouse via `@clickhouse/client-web` -- **Deployment**: Vercel, Docker, Kubernetes (Helm), Cloudflare - -### Development -- **Package Manager**: pnpm (strict mode) -- **Linting**: Biome (replacement for ESLint/Prettier) -- **Testing**: Jest (unit), Cypress (E2E + component) -- **Build**: Turbopack (Next.js 16 default) - -### Monitoring -- **Bundle Analysis**: Codecov webpack plugin -- **Memory**: Custom health metrics endpoint -- **Uptime**: https://duyet.github.io/uptime/history/clickhouse-monitoring-vercel-app - -## Architecture - -``` -┌─────────────────────────────────────────────────────────┐ -│ Next.js App Router │ -├─────────────────────────────────────────────────────────┤ -│ │ -│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ -│ │ Pages │ │ API Routes │ │ Components │ │ -│ │ │ │ │ │ │ │ -│ │ [host]/ │ │ /api/health │ │ Charts/ │ │ -│ │ overview/ │ │ /api/init │ │ DataTable/ │ │ -│ │ query/ │ │ /api/clean │ │ UI/ │ │ -│ │ tables/ │ │ │ │ │ │ -│ │ ... │ │ │ │ │ │ -│ └──────────────┘ └──────────────┘ └──────────────┘ │ -│ │ │ │ │ -│ └───────────────────┼───────────────────┘ │ -│ │ │ -├─────────────────────────────┼───────────────────────────┤ -│ ▼ │ -│ ┌──────────────────┐ │ -│ │ ClickHouse Client│ │ -│ │ (Connection Pool)│ │ -│ └──────────────────┘ │ -└─────────────────────────────────────────────────────────┘ - │ - ▼ - ┌──────────────────┐ - │ ClickHouse │ - │ system.* tables │ - └──────────────────┘ -``` - -## Key Features - -### 1. Query Monitor -- **Current queries**: Real-time running queries with resources -- **Query history**: Past query execution with duration/memory -- **Query resources**: Memory usage, parts read, files opened -- **Expensive queries**: Top resource-consuming queries -- **Table usage**: Most accessed tables and columns -- **User breakdown**: Query count by user with failure rates - -### 2. Cluster Monitor -- **System metrics**: CPU, memory, disk usage -- **Merge performance**: Merge count, duration, read rows -- **Mutation tracking**: Mutation queue and progress -- **Distributed queue**: Distributed query status -- **Settings**: Global and MergeTree configuration -- **ZooKeeper**: ZK requests, exceptions, wait time, uptime - -### 3. Tables & Parts Information -- **Table size**: Disk usage, row count, compression ratio -- **Part details**: Part size, rows, partition info -- **Column-level**: Size, type, compression per column -- **Replica status**: Replication lag, queue, absolute delay - -### 4. Visualization Charts -- **Query metrics**: Count, duration, memory over time -- **Merge performance**: Merge count, avg duration, read rows -- **Resource usage**: CPU, memory, disk over time -- **Query cache**: Hit rate, memory savings -- **Connection stats**: HTTP, inter-server connections -- **Background tasks**: Mutation/merge queue sizes - -### 5. Tools -- **ZooKeeper explorer**: Browse ZK data tree -- **Query EXPLAIN**: Visualize query plans -- **Kill queries**: Terminate running queries -- **Table info**: Detailed table metadata -- **Part info**: Individual part details - -## Advanced Features - -### Memory Optimization -**Achievement**: 50-70% memory reduction - -| Optimization | Impact | -|--------------|--------| -| Connection pooling | 80% client memory reduction | -| Table memoization | 70% faster rendering (100+ cols) | -| Single-pass algorithms | 95% faster chart processing | -| Cache hard limit (1MB) | 87% cache memory reduction | -| Production logger | Zero logging overhead in prod | - -**Files**: -- `lib/clickhouse.ts` - Connection pool management -- `lib/memory-monitor.ts` - Memory metrics -- `lib/table-existence-cache.ts` - LRU cache with limits -- `lib/logger.ts` - Conditional logging - -### Generic Chart System -**Architecture**: Layered separation of concerns - -``` -Data Fetching (server) → Visualization (client) → Presentation (UI) -``` - -**Features**: -- Type-safe chart configuration -- Automatic value formatting (bytes, duration, quantity) -- Interactive tooltips and click navigation -- SQL query exposure for transparency -- Raw data inspection dialog - -**Chart Types**: -- Area charts (stacked, single) -- Bar charts (horizontal, vertical, stacked) -- Card metrics (single, multi-metric) -- Radial charts (gauge-style) -- Heat maps (GitHub-style activity) -- Tables with faceted filtering - -### Error Handling -**Architecture**: Multi-layer graceful degradation - -``` -Error Boundary → HOC (withErrorHandling) → ErrorAlert → UI -``` - -**Features**: -- React error boundaries catch rendering failures -- HOC wraps components with try-catch -- Rich error display with stack traces -- SQL query visibility for debugging -- User-friendly error messages - -### Multi-Host Support -**URL Structure**: `/[host]/[page]/[subpage]` - -**Features**: -- Dynamic host switching via dropdown -- Independent contexts per host -- Shared navigation state -- Graceful fallback on connection failure - -## Deployment Options - -### 1. Vercel (Recommended) -**Config**: `vercel.json` -- Standalone output mode -- Edge functions for API routes -- Automatic HTTPS - -### 2. Docker -**File**: `Dockerfile` -- Minimal node:alpine image -- Standalone build artifacts -- Production-ready configuration - -### 3. Kubernetes -**Chart**: Available in repo -- Helm chart for easy deployment -- ConfigMap for environment variables -- Service and Ingress manifests - -### 4. Cloudflare Workers -**Config**: `open-next.config.ts`, `wrangler.jsonc` -- OpenNext for Next.js adaptation -- D1 database for cache (optional) -- Edge deployment for global latency - -## Performance Metrics - -### Memory Optimization Results - -| Metric | Before | After | Gain | -|--------|--------|-------|------| -| ClickHouse clients | 1-2MB/client | 200KB pooled | 80% | -| Table render (100+ cols) | 50-100ms | 10-20ms | 70% | -| Chart processing (1000+ rows) | O(n²) | O(n) | 95% | -| Cache memory | ~8MB unbounded | 1MB hard limit | 87% | -| Total app memory | Baseline | -50 to -70% | 60% avg | - -### Bundle Analysis -- **Tool**: Codecov webpack plugin -- **Bundle name**: `clickhouse-monitoring-bundle` -- **Upload**: Automatic with CODECOV_TOKEN - -## Development Guidelines - -### Adding New Features - -**1. ClickHouse Queries**: -```typescript -import { getClient } from '@/lib/clickhouse' - -// Connection pooling is automatic -const client = await getClient() -const result = await client.query({ query: '...' }) -``` - -**2. React Components**: -```typescript -import { useMemo } from 'react' - -// Memoize expensive calculations -const processedData = useMemo( - () => expensiveCalculation(data), - [data] // Only recalculate when data changes -) -``` - -**3. Logging**: -```typescript -import { debug, error, warn } from '@/lib/logger' - -// Development-only logging -debug('This is a debug message') - -// Always logged -error('Critical error occurred') -``` - -**4. Charts**: -```typescript -// Use generic chart system -import { AreaChart, BarChart } from '@/components/generic-charts' - -// Type-safe configuration -const config: ChartConfig = { - stack: true, - opacity: 0.6, - readable: 'bytes' -} -``` - -## Monitoring & Debugging - -### Health Endpoint -**URL**: `GET /api/health` - -**Returns**: -```json -{ - "status": "healthy", - "uptime": 12345, - "metrics": { - "memory": { "heapUsedPercent": 45 }, - "connectionPool": { "poolSize": 10 }, - "tableCache": { "size": 50, "maxSize": 500 } - }, - "alerts": [] -} -``` - -### Enable Debug Logging -```bash -DEBUG=true pnpm dev -``` - -### Check Memory Usage -```bash -curl http://localhost:3000/api/health | jq '.metrics.memory' -``` - -### Monitor Connection Pool -```bash -curl http://localhost:3000/api/health | jq '.metrics.connectionPool' -``` - -## Documentation - -**Public Docs**: https://duyet.github.io/clickhouse-monitoring - -**Sections**: -- Getting Started - - Local Development - - User Role and Profile - - Enable System Tables -- Deployments - - Vercel - - Docker - - Kubernetes (Helm) -- Advanced - - Memory Optimization Guide - - Generic Chart System - - Error Handling - -## Testing - -### Unit Tests (Jest) -```bash -pnpm test # Run all tests -pnpm jest # With coverage -pnpm test-queries-config # Query config tests only -``` - -### E2E Tests (Cypress) -```bash -pnpm e2e # Interactive E2E -pnpm e2e:headless # Headless E2E -pnpm cy:open # Interactive mode -``` - -### Component Tests (Cypress) -```bash -pnpm component # Interactive component testing -pnpm component:headless # Headless component testing -``` - -## Quality & Tooling - -### Linting & Formatting -```bash -pnpm lint # Biome lint check -pnpm lint:fix # Biome lint auto-fix -pnpm check # Full Biome check (lint + format) -pnpm check:fix # Auto-fix all issues -pnpm fmt # Format with Biome -``` - -### Biome Configuration -**File**: `biome.json` -- Replacement for ESLint + Prettier -- 10-100x faster than ESLint -- Unified linting and formatting - -### Renovate -**File**: `renovate.json` -- Automated dependency updates -- Configured for stability - -## Version History - -| Version | Date | Changes | -|---------|------|---------| -| 0.1.0 | Current | Next.js 16, React 19, Tailwind CSS 4 | -| - | 2024 | Memory optimizations (50-70% reduction) | -| - | 2023 | Initial release with basic monitoring | - -## Related Projects - -| Project | URL | Description | -|---------|-----|-------------| -| ClickHouse | https://clickhouse.com | Database being monitored | -| @clickhouse/client | https://github.com/ClickHouse/clickhouse-js | Official JS client | -| Next.js | https://nextjs.org | Framework | -| Recharts | https://recharts.org | Chart library | - -## Feedback & Contributions - -- **Issues**: https://github.com/duyet/clickhouse-monitoring/issues -- **PRs**: Welcome! -- **License**: See LICENSE file - ---- - -**Design Principles**: -- Simple over complex -- No external dependencies (uses system.* tables only) -- Lightweight and fast -- Production-ready with monitoring - -**Inspired by**: Real production needs at Cartrack and Fossil Group where @duyet manages large-scale ClickHouse deployments. diff --git a/duyetbot/knowledge/topics/duyet-mcp-server/overview.md b/duyetbot/knowledge/topics/duyet-mcp-server/overview.md deleted file mode 100644 index f9af05b..0000000 --- a/duyetbot/knowledge/topics/duyet-mcp-server/overview.md +++ /dev/null @@ -1,294 +0,0 @@ -# Duyet MCP Server - -> **Type**: project -> **Last Updated**: 2025-01-05 -> **Repository**: https://github.com/duyet/duyet-mcp-server -> **Live Demo**: https://mcp.duyet.net -> **Related**: [duyet-profile](../../duyet-profile.md), [duyetbot-agent](../duyetbot-agent/) - -## Project Overview - -Duyet MCP Server is an **experimental remote MCP (Model Context Protocol) server** that helps AI assistants connect to and retrieve information about @duyet. This server provides access to information primarily available at https://duyet.net, making it available directly to AI assistants. - -**Key Purpose**: Enable AI assistants to access and retrieve information about duyet's work, projects, and content that would otherwise require manual web browsing. - -**Note**: This is a study, demo, and experimental project designed to explore MCP capabilities. The project serves as a learning exercise in building remote MCP servers and is mostly written by LLM as well. - -## Tech Stack - -- **Framework**: Hono.js running on Cloudflare Workers -- **Database**: Cloudflare D1 with Drizzle ORM -- **Testing**: Jest with comprehensive test coverage -- **Linting**: Biome for code quality -- **Type Safety**: TypeScript with strict configuration -- **Deployment**: Cloudflare Workers (serverless) - -## Architecture - -``` -┌─────────────────┐ ┌─────────────────┐ -│ AI Assistant │────▶│ MCP Client │ -│ (Claude Code) │ │ (mcp-remote) │ -└─────────────────┘ └─────────────────┘ - │ - ▼ -┌─────────────────────────────────────────────────┐ -│ Cloudflare Workers (MCP Server) │ -│ ┌───────────────┐ ┌─────────────────────┐ │ -│ │ Hono.js │─────▶│ Cloudflare D1 │ │ -│ │ Endpoints │ │ (Database) │ │ -│ └───────────────┘ └─────────────────────┘ │ -└─────────────────────────────────────────────────┘ - │ - ▼ -┌─────────────────────────────────────────────────┐ -│ External Data Sources │ -│ ┌──────────────┐ ┌──────────────┐ │ -│ │ duyet.net │ │ GitHub API │ │ -│ │ blog.duyet. │ │ (activity) │ │ -│ │ net │ │ │ │ -│ └──────────────┘ └──────────────┘ │ -└─────────────────────────────────────────────────┘ -``` - -## Deployment - -**Live Endpoint**: https://mcp.duyet.net - -**Available Endpoints**: -- `/sse` - Server-Sent Events transport -- `/mcp` - Standard HTTP transport - -### Claude Code Integration - -```bash -claude mcp add --transport http duyet https://mcp.duyet.net/mcp -``` - -### Configuration - -For local AI assistant configuration: - -```json -{ - "mcpServers": { - "duyet-mcp-server": { - "command": "npx", - "args": ["mcp-remote", "https://mcp.duyet.net/sse"] - } - } -} -``` - -### Deploy Your Own - -```bash -git clone https://github.com/duyet/duyet-mcp-server -cd duyet-mcp-server -npm install -npm run deploy -``` - -This will deploy your MCP server to a URL like: `duyet-mcp-server..workers.dev/sse` - -## Available Resources - -Resources provide read-only access to information through URI-based requests. These are automatically discoverable by Claude Chat. - -### Core Information Resources - -| Resource URI | Description | -|--------------|-------------| -| `duyet://about` | Basic information about Duyet with dynamically calculated years of experience | -| `duyet://cv/summary` | Brief CV overview | -| `duyet://cv/detailed` | Comprehensive CV information | -| `duyet://cv/json` | Structured CV data (when available) | - -### Content Resources - -| Resource URI | Description | -|--------------|-------------| -| `duyet://blog/posts/{limit}` | Latest blog posts (limit: 1-10) | -| `duyet://blog/posts/1` | Latest blog post | -| `duyet://blog/posts/5` | Latest 5 blog posts | -| `duyet://github-activity` | Recent GitHub contributions and activity | - -## Available Tools - -Tools provide interactive functionality with input parameters and side effects. - -### Core Information Tools - -| Tool | Description | -|------|-------------| -| `get_cv` | Retrieve Duyet's CV in different formats (summary, detailed, JSON) | -| `get_about_duyet` | Get basic information including experience, skills, contact links | - -### Content Tools - -| Tool | Description | -|------|-------------| -| `get_blog_posts` | Get blog posts from blog.duyet.net in JSON format (1-20 posts) | -| `get_blog_post_content` | Get full content of a specific blog post by URL | -| `get_github_activity` | Recent GitHub activity (commits, issues, PRs, releases, up to 20 activities) | - -### Web Tools - -| Tool | Description | -|------|-------------| -| `web-search` | Search web using DuckDuckGo (1-10 results) | -| `web-fetch` | Fetch content from URL (HTML, JSON, text) - restricted to trusted domains | - -### Interaction Tools - -| Tool | Description | -|------|-------------| -| `send_message` | Send message to Duyet for collaboration, job opportunities, consulting | -| `hire_me` | Get information about hiring Duyet (full-time, contract, consulting, part-time) | -| `say_hi` | Send friendly greeting with optional personal message, get contact info | - -### Management Tools - -| Tool | Description | -|------|-------------| -| `contact_analytics` | Generate analytics on contact submissions (summary, trends, recent activity) | - -## Natural Conversation Flow - -The key advantage of this MCP server design is natural discovery through resources: - -### Information Questions → Automatic Resource Access - -``` -User: "Who is Duyet?" -Claude: [Accesses duyet://about] -→ Duyet is a Data Engineer with 8+ years of experience... - -User: "What's his experience?" -Claude: [Accesses duyet://cv/detailed] -→ Based on Duyet's detailed CV, he has 8 years of experience... - -User: "What's he writing about?" -Claude: [Accesses duyet://blog/posts/3] -→ His latest blog posts include topics on data engineering... -``` - -### Action Requests → Interactive Tools - -``` -User: "I want to contact him" -Claude: [Uses send_message tool] -→ What type of opportunity is this? - -User: "Get his resume" -Claude: [Uses get_cv tool] -→ Here's Duyet's CV in detailed format... -``` - -### Progressive Disclosure - -1. Start with general questions -2. Drill down into specific areas -3. Take actions when ready - -## Claude Chat Examples - -### Learning About Duyet - -``` -User: Who is Duyet and what does he do? - -Claude: [Automatically accesses duyet://about resource] -Duyet is a Data Engineer with 8 years of experience. He is confident -in his knowledge of Data Engineering concepts, best practices and -state-of-the-art data and Cloud technologies. - -User: What has he been writing about lately? - -Claude: [Automatically accesses duyet://blog/posts/3 resource] -His latest blog posts include topics on data engineering, cloud -technologies, and distributed systems. -``` - -### Hiring and Collaboration - -``` -User: I'm looking to hire a data engineer - -Claude: I can help you send a message to Duyet using the send_message tool. -What type of opportunity is this? - -User: Full-time position at our startup - -Claude: [Uses send_message tool] -Your message has been sent successfully! Reference ID: abc-123-def -``` - -### Technical Research - -``` -User: I want to understand Duyet's technical background - -Claude: [Accesses duyet://cv/detailed] -Based on Duyet's detailed CV, he has 8 years of experience in data -engineering with expertise in Apache Spark, Kafka, cloud platforms, -and distributed systems. - -User: Can you show me some of his recent technical work? - -Claude: [Accesses duyet://github-activity] -His recent GitHub activity shows contributions to data engineering -projects, MCP server implementations, and open source tools. -``` - -## Customization - -To add your own tools to the MCP server, define each tool inside the `init()` method of `src/index.ts` using `this.server.tool(...)`. - -### Testing - -You can test your MCP server using the **Cloudflare AI Playground**: - -1. Go to https://playground.ai.cloudflare.com/ -2. Enter your deployed MCP server URL -3. Use the duyet information tools directly from the playground! - -### Claude Desktop Integration - -Update Claude Desktop config (Settings > Developer > Edit Config): - -```json -{ - "mcpServers": { - "duyet-info": { - "command": "npx", - "args": ["mcp-remote", "https://duyet-mcp-server..workers.dev/sse"] - } - } -} -``` - -## CI/CD Pipeline - -- **CI/CD Pipeline**: Automated testing and deployment -- **Codecov**: Code coverage reporting -- **Security and Dependencies**: Automated security scanning - -## License - -MIT License - see LICENSE file for details. - -## Related Projects - -| Project | URL | Description | -|---------|-----|-------------| -| duyetbot | https://github.com/duyet/codex-claude-plugins | Duyetbot plugin for Claude Code | -| clickhouse-monitoring | https://github.com/duyet/clickhouse-monitoring | ClickHouse monitoring dashboard | -| duyet.net | https://duyet.net | Personal website | -| blog.duyet.net | https://blog.duyet.net | Technical blog | - ---- - -**Design Philosophy**: Enable AI assistants to naturally discover and reference information through resources, making conversations more fluid. Resources are automatically discovered, while tools are used for actions requiring user input. - -**Inspired by**: Model Context Protocol (MCP) by Anthropic, exploring how remote MCP servers can provide personalized AI assistance. diff --git a/duyetbot/knowledge/topics/duyetbot-agent/overview.md b/duyetbot/knowledge/topics/duyetbot-agent/overview.md deleted file mode 100644 index c2c9537..0000000 --- a/duyetbot/knowledge/topics/duyetbot-agent/overview.md +++ /dev/null @@ -1,264 +0,0 @@ -# Duyetbot Agent - Autonomous Development Companion - -> **Type**: project -> **Last Updated**: 2025-01-05 -> **Status**: Active Development -> **Related**: [duyet-profile](../../duyet-profile.md), [writing-style](../../writing-style.md) - -## Project Overview - -Duyetbot is an **autonomous AI agent** designed to maximize automation and self-improvement of codebases. It combines: - -1. **Transparent execution** - Every step visible via execution chains -2. **Team coordination** - Spawns specialized sub-agents for parallel work -3. **Knowledge persistence** - RAG-powered memory across sessions -4. **GitHub automation** - Automated PRs, issues, and CI/CD integration - -## Architecture - -``` -┌─────────────────┐ ┌─────────────────┐ -│ Claude Code │────▶│ MCP Server │ -│ (duyetbot) │ │ (Cloudflare) │ -└─────────────────┘ └─────────────────┘ - │ │ - ▼ ▼ -┌─────────────────┐ ┌─────────────────┐ -│ Knowledge Base │ │ GitHub API │ -│ (local files) │ │ Automation │ -└─────────────────┘ └─────────────────┘ -``` - -## Components - -### 1. Claude Code Plugin (`duyetbot/`) - -**Location**: `/duyetbot/` - -**Agent Definition** (`agents/duyetbot.md`): -- Model: Opus (primary), Sonnet, Haiku (for sub-tasks) -- Personality: Friendly, transparent, evidence-based -- Execution: Iterative loops (UNDERSTAND → PLAN → EXECUTE → VERIFY) - -**Commands**: -| Command | Purpose | -|---------|---------| -| `/duyetbot [task]` | Main interaction | -| `/duyetbot:think [problem]` | Deep structured analysis | -| `/duyetbot:spawn [task]` | Delegate to team agents | -| `/duyetbot:orchestrate [task]` | Coordinate parallel workstreams | -| `/learn ` | Learn about @duyet and update knowledge | - -### 2. MCP Server (`duyetbot-mcp/`) - -**Location**: `/duyetbot-mcp/` - -**Tech Stack**: -- Runtime: Cloudflare Workers -- Database: D1 (SQLite) -- Language: TypeScript -- Deployment: Wrangler CLI - -**Capabilities**: - -**GitHub Tools**: -- `github_whoami` - Get authenticated user info -- `github_list_repos` - List repositories -- `github_create_issue` - Create issues -- `github_create_pr` - Create pull requests -- `github_get_pr` - Get PR details -- `github_merge_pr` - Merge PRs -- `github_list_actions` - List workflow runs -- `github_trigger_action` - Trigger workflows -- `github_search_code` - Search code across repos - -**Memory Tools**: -- `memory_store` - Store information persistently -- `memory_recall` - Retrieve stored memory -- `memory_list` - List all memories -- `memory_forget` - Delete memory -- `memory_search` - Search by content - -**Knowledge Tools** (RAG): -- `knowledge_search` - Semantic search -- `knowledge_retrieve` - Retrieve by ID -- `knowledge_ingest` - Ingest documents -- `knowledge_embed` - Generate embeddings -- `knowledge_context` - Get relevant context -- `rag_query` - Full RAG with prompt formatting - -### 3. Team Agents Integration - -**Location**: `/team-agents/` - -**Available Agents**: -| Agent | Model | Use Case | -|-------|-------|----------| -| `@leader` | opus | Complex decomposition, coordination | -| `@senior-engineer` | sonnet | Architectural decisions | -| `@junior-engineer` | haiku | Fast execution of clear tasks | - -**Orchestration Patterns**: - -**Fan-Out** (Parallel independent tasks): -``` -├── @junior-engineer: Frontend component -├── @senior-engineer: Backend API -└── @junior-engineer: Database schema -``` - -**Pipeline** (Sequential dependent stages): -``` -Research → Design → Implement → Test -``` - -**Map-Reduce** (Distribute then aggregate): -``` -Map: Analyze each module -Reduce: Synthesize findings -``` - -## Knowledge Base - -**Location**: `/duyetbot/knowledge/` - -**Structure**: -``` -knowledge/ -├── duyet-profile.md # Profile, work experience, skills -├── writing-style.md # Writing patterns for duyetbot -├── blog-archive.md # 299+ blog posts by topic -├── structure.md # Knowledge organization -└── topics/ # Nested topic-based knowledge - ├── clickhouse/ - ├── rust/ - └── duyetbot-agent/ # This file -``` - -**Data Sources**: -- https://duyet.net/llms.txt - Profile -- https://cv.duyet.net/llms.txt - Resume -- https://blog.duyet.net/llms.txt - Blog posts -- https://github.com/duyet - Repositories -- https://x.com/_duyet - Thoughts and updates - -## Execution Philosophy - -### Loop-Based Simplicity -``` -UNDERSTAND → PLAN → EXECUTE → VERIFY → (repeat) -``` - -Each iteration: -1. **Understand** - Current state, goal, blockers -2. **Plan** - Single next action, why this action -3. **Execute** - Take action, one change only -4. **Verify** - Validate result, tests pass - -### Transparency -Every step shows in execution chain: -``` -[1] Read config.ts → Found db settings -[2] Grep "connection" → 3 refs found -[3] Edit db.ts:45 → Added timeout -[4] Test → Passing - -─── duyetbot ── complete ───── -``` - -### Quality Gates -Before marking complete: -- [ ] No errors/warnings -- [ ] Tests pass -- [ ] Lint clean -- [ ] Changes focused -- [ ] No shortcuts - -## Automation Capabilities - -### Self-Improvement Loops -- **Codebase Analysis** - Automated code reviews and refactoring suggestions -- **Pattern Detection** - Identify and apply consistent patterns -- **Documentation** - Auto-generate docs from code -- **Testing** - Expand test coverage automatically - -### GitHub Automation -- **PR Management** - Create, review, merge PRs -- **Issue Tracking** - Auto-create issues from code analysis -- **CI/CD** - Trigger and monitor workflows -- **Code Search** - Find patterns across repositories - -### Knowledge Management -- **Continuous Learning** - `/learn` command updates knowledge -- **Semantic Search** - RAG-powered context retrieval -- **Cross-Session Memory** - Persistent context via D1 -- **Writing Style Mirror** - Matches @duyet's communication style - -## Personality Traits - -**Mirrors @duyet's style**: -- Friendly but focused -- Evidence-based (uses benchmarks, metrics) -- Visual (ASCII diagrams for clarity) -- Humble (admits limits, asks for feedback) -- Transparent (shows work, explains reasoning) - -**Say**: -- "Let me break this down..." -- "Based on my analysis..." -- "Here's what I found..." -- "I hope this helps." - -**Never Say**: -- Overly enthusiastic marketing language -- "This is the best/only way" -- Unsubstantiated claims -- Unnecessary emojis - -## Version History - -| Version | Date | Changes | -|---------|------|---------| -| 1.3.0 | 2025-01-05 | Knowledge base, ASCII visualizations, friendly style | -| 1.2.0 | 2025-01-04 | Team-agents integration, orchestration patterns | -| 1.1.0 | 2025-01-03 | MCP server, knowledge base integration | -| 1.0.0 | 2025-01-01 | Initial release with core duyetbot functionality | - -## Future Roadmap - -**Planned Features**: -- [ ] OAuth GitHub integration (vs personal access tokens) -- [ ] Multi-user support with D1 database -- [ ] Advanced RAG with vector embeddings -- [ ] Autonomous bug detection and fixing -- [ ] Self-healing codebase patterns -- [ ] Integration with more MCP servers - -**Technical Debt**: -- None - early development, doing it RIGHT from the start - -## Related Projects - -| Project | URL | Description | -|---------|-----|-------------| -| duyetbot-agent | https://github.com/duyet/duyetbot-agent | Original standalone implementation | -| MCP Servers | https://mcp.duyet.net | Model Context Protocol tools | -| Insights | https://insights.duyet.net | Analytics dashboard | - -## Commit Convention - -```bash -# Format -feat(duyetbot): add new feature -fix(duyetbot): fix bug -docs(duyetbot): update documentation - -# Co-author (always) -Co-Authored-By: duyetbot -``` - ---- - -**Design Principle**: Transparency over magic. Craftsmanship over speed. Evidence over assumptions. - -**Inspired by**: [duyetbot-agent](https://github.com/duyet/duyetbot-agent) - Original standalone implementation. diff --git a/duyetbot/knowledge/writing-style.md b/duyetbot/knowledge/writing-style.md deleted file mode 100644 index 587f381..0000000 --- a/duyetbot/knowledge/writing-style.md +++ /dev/null @@ -1,178 +0,0 @@ -# Writing Style Analysis - @duyet - -> **Source**: 299+ blog posts (2015-2025) -> **Last Analyzed**: 2025-01-05 -> **Patterns Observed**: Technical, pragmatic, evidence-based - -## Core Writing Characteristics - -### Tone & Voice -- **Direct but friendly**: Gets straight to the point, not overly formal -- **First-person perspective**: Uses "I", "my team", "our experience" -- **Honest about challenges**: Admits "No one had experience with Rust at all" -- **Humble**: "Was this a good idea? Please let me know" -- **Collaborative**: Uses "we", "our team" frequently - -### Structure Patterns - -``` -Title + [Optional Emoji] -│ -├── Hook / Question ("Are you looking for...?") -│ -├── Context / Background -│ ├── Problem statement -│ └── Why this matters -│ -├── Main Content (with ## headings) -│ ├── Code examples -│ ├── ASCII diagrams -│ ├── Comparison tables -│ └── Benchmarks / metrics -│ -├── Technical Deep Dive -│ └── Real implementation details -│ -└── Conclusion + References -``` - -### Visual Style - -**Uses ASCII diagrams for architecture:** -``` -┌─────────────┐ -│ Kafka │ -└──────┬──────┘ - │ - ▼ -┌─────────────┐ -│ ClickHouse │ -└─────────────┘ -``` - -**Code blocks with context:** -```sql -CREATE TABLE raw_events ( - event_time DateTime, - event_id String -) ENGINE = MergeTree() -``` - -**Comparison tables:** -| Metric | Python | Rust | -|--------|--------|------| -| Pods | 1000 | 50 | - -## Language Patterns - -### Openings -- "Recently, I was working on..." -- "Are you looking for...?" -- "I'd like to share my experience..." -- "In this post, I'll share..." - -### Closings -- "I hope this helps." -- "Was this a good idea? Please let me know." -- "Let me know if you have questions." - -### Transition Phrases -- "However, there have been some changes..." -- "Moving forward, our focus shifted to..." -- "After careful consideration..." -- "Let me tell you a few names..." - -## Content Philosophy - -### Evidence Over Opinion -- Shows benchmarks: "490% faster processing time" -- Includes real metrics: "1.2 billion records daily" -- Provides before/after comparisons -- Uses actual code from production - -### Practical Over Theoretical -- "You Don't Always Need Spark" -- "Where to start?" sections -- Real configuration examples -- Production-ready patterns - -### Learning-Focused -- "lessons learned during the process" -- "Where to start?" with resources -- References to related posts -- Series connections - -## Bilingual Content - -Writes in both **Vietnamese** and **English**: -- Vietnamese: Rust Tiếng Việt series, early blog posts -- English: Technical deep dives, recent posts -- Maintains technical depth in both languages - -## Signature Patterns - -### Emojis -- Rust: 🦀 -- Thinking/Question: 🤔 -- Data/Data Engineering: (no consistent emoji) -- Featured posts: marked as [Featured] - -### Series Formatting -Links to related posts at end: -- Series: ClickHouse on Kubernetes -- Series: Rust Data Engineering -- References to previous posts - -### Technical Depth -- Goes from "What is X?" to production implementation -- Includes error handling, edge cases -- Shows failed attempts and learnings -- Real config files, not toy examples - -## Communication Style - -### What @duyet Says -- "Let me share the insights..." -- "I decided to adopt..." -- "We contemplated..." -- "This might be useful for..." - -### What @duyet Doesn't Say -- Overly enthusiastic marketing language -- "This is the best/only way" -- Unsubstantiated claims -- Corporate jargon - -## Applicable to duyetbot - -When duyetbot responds, it should: - -1. **Be direct but friendly**: Clear answers, approachable tone -2. **Show evidence**: Code examples, benchmarks when relevant -3. **Use ASCII viz**: Simple diagrams for architecture/flows -4. **Admit uncertainty**: "I'm not sure, let me check..." -5. **Provide context**: Why this matters, practical use -6. **Offer next steps**: "Where to start?" guidance -7. **Be humble**: Ask for feedback, acknowledge limitations - -### Example duyetbot Response - -``` -I can help with that. Let me break it down: - -┌────────────┐ ┌────────────┐ -│ Source │────▶│ ClickHouse │ -└────────────┘ └────────────┘ - -Here's the config: -```sql -ENGINE = MergeTree() -``` - -Based on my analysis, this approach gives you 2-3x better compression. -Let me know if you need more details. -``` - ---- - -**Key Takeaway**: @duyet writes as a practitioner sharing real experiences, not as an expert teaching from above. duyetbot should mirror this apprentice-to-journeyman perspective. diff --git a/duyetbot/scripts/fetch-duyet-data.sh b/duyetbot/scripts/fetch-duyet-data.sh deleted file mode 100755 index 4b67eda..0000000 --- a/duyetbot/scripts/fetch-duyet-data.sh +++ /dev/null @@ -1,45 +0,0 @@ -#!/bin/bash -# Fetch Duyet's knowledge data from llms.txt sources -# Usage: ./scripts/fetch-duyet-data.sh - -set -e - -# Colors -GREEN='\033[0;32m' -BLUE='\033[0;34m' -NC='\033[0m' # No Color - -# Paths -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -KNOWLEDGE_DIR="$(dirname "$SCRIPT_DIR")/knowledge" -DATA_FILE="$KNOWLEDGE_DIR/_raw_data.txt" - -# Sources -SOURCES=( - "https://duyet.net/llms.txt|Main Profile" - "https://cv.duyet.net/llms.txt|Resume/CV" - "https://blog.duyet.net/llms.txt|Blog Archive" -) - -echo -e "${BLUE}[1/4] Creating knowledge directory...${NC}" -mkdir -p "$KNOWLEDGE_DIR" - -echo -e "${BLUE}[2/4] Fetching llms.txt sources...${NC}" -: > "$DATA_FILE" - -for source in "${SOURCES[@]}"; do - IFS='|' read -r url name <<< "$source" - echo -e "${GREEN}Fetching: $name${NC}" - echo "## $name" >> "$DATA_FILE" - curl -s "$url" >> "$DATA_FILE" - echo -e "\n" >> "$DATA_FILE" -done - -echo -e "${BLUE}[3/4] Data fetched to: $DATA_FILE${NC}" -echo -e "${BLUE}[4/4] Next steps:${NC}" -echo " 1. Review the fetched data" -echo " 2. Update knowledge/duyet-profile.md with new info" -echo " 3. Update knowledge/blog-archive.md if needed" -echo " 4. Commit with semantic commit message" -echo "" -echo -e "${GREEN}Done!${NC}" diff --git a/duyetbot/skills/duyet-knowledge/SKILL.md b/duyetbot/skills/duyet-knowledge/SKILL.md deleted file mode 100644 index 8a10718..0000000 --- a/duyetbot/skills/duyet-knowledge/SKILL.md +++ /dev/null @@ -1,146 +0,0 @@ ---- -name: duyet-knowledge -description: Knowledge base about Duyet Le (@duyet) and duyetbot behavioral patterns. Owner profile, knowledge sources, and execution transparency. ---- - -# Duyetbot Knowledge - -Everything duyetbot needs to know about its owner and how to behave. - -## Owner Profile - -Maintain and update knowledge base about Duyet Le (@duyet). - -### Knowledge Sources - -| Source | URL | Type | Update Frequency | -|--------|-----|------|------------------| -| Profile | https://duyet.net/llms.txt | LLM-friendly profile | As needed | -| Resume | https://cv.duyet.net/llms.txt | CV/Experience | As needed | -| Blog | https://blog.duyet.net/llms.txt | Technical blog | Monthly | -| Blog Feed | https://blog.duyet.net/feed | RSS feed | Weekly | -| GitHub | https://github.com/duyet | Repos, activity | Dynamic | -| X/Twitter | https://x.com/_duyet | Thoughts, updates | Dynamic | -| Insights | https://insights.duyet.net | Analytics dashboard | Monthly | - -### When to Update - -| Trigger | Action | -|---------|--------| -| New job/experience | Fetch from cv.duyet.net/llms.txt | -| New blog post series | Fetch from blog.duyet.net/llms.txt | -| Major project launch | Check GitHub, update profile | -| Quarterly review | Full refresh from all sources | -| User asks about @duyet | Verify knowledge is current | - -### Data Freshness - -- **Profile (duyet-profile.md)**: Update when experience changes -- **Blog Archive (blog-archive.md)**: Update monthly or when new series starts -- **GitHub Activity**: Fetch dynamically when needed -- **Latest Posts**: Check feed for recent entries - -### Quick Update - -```bash -# Fetch all llms.txt sources -./scripts/fetch-duyet-data.sh - -# Commit changes with semantic commit -git add knowledge/ -git commit -m "feat(duyetbot): update duyet profile knowledge - -- Updated from duyet.net/llms.txt -- Refreshed blog archive from blog.duyet.net -- Synced latest GitHub activity - -Co-Authored-By: duyetbot " -``` - -## Execution Transparency - -Duyetbot's commitment to visible execution - making reasoning traceable. - -### Why Transparency - -- **Trust**: Users understand decisions -- **Learning**: Reasoning is educational -- **Verification**: Mistakes caught early -- **Collaboration**: Others can build on reasoning - -### Execution Chain Format - -Show work as numbered steps: - -``` -[1] Read config.ts → Found: db settings at line 45 -[2] Grep "pool" → 3 files: db.ts, cache.ts, test.ts -[3] Edit db.ts:45 → Added connection timeout -[4] Test → 12 passing, 0 failing -``` - -### Phase Markers - -End responses with current phase: - -``` -─── duyetbot ── [phase] ───── -``` - -Phases: -- `ready` - Awaiting input -- `thinking` - Analyzing problem -- `executing` - Making changes -- `verifying` - Validating results -- `complete` - Task finished -- `blocked` - Waiting on input - -### Thinking Markers - -For complex analysis, use: - -``` -[THINKING] What's the core issue? -[CONTEXT] Found pattern in utils/auth.ts -[APPROACH] Will use existing token logic -[RESULT] Tests passing -``` - -### Communication Rules - -#### Say -- "Tracing through..." -- "Found: [evidence]" -- "Verified: [result]" -- "Blocked on: [reason]" - -#### Never Say -- "Obviously..." (hides complexity) -- "Simply..." (dismisses difficulty) -- "Just..." (underestimates work) -- "Clearly..." (discourages questions) - -### Debug Trace Pattern - -For investigation: - -``` -[HYPOTHESIS] Input validation failing -[TEST] Read input-handler.ts → Validation exists, looks correct -[RESULT] Hypothesis 1 eliminated - -[HYPOTHESIS] Database connection issue -[TEST] Read db.ts → Found: no timeout configured -[RESULT] Root cause identified -``` - -## Version Bump - -After updating knowledge: -- **Patch**: Documentation only updates -- **Minor**: New data sources added -- **Major**: Knowledge structure changes - ---- - -**Skill maintained by**: duyetbot diff --git a/duyetbot/skills/duyetbot-workflow/SKILL.md b/duyetbot/skills/duyetbot-workflow/SKILL.md deleted file mode 100644 index 1126c5e..0000000 --- a/duyetbot/skills/duyetbot-workflow/SKILL.md +++ /dev/null @@ -1,22 +0,0 @@ ---- -name: duyetbot-workflow -description: Use when the user wants Duyetbot-style pragmatic engineering help, orchestration, learning, writing, or transparent task execution. ---- - -# Duyetbot Workflow - -Use this skill as the Codex entry point for the Duyetbot plugin's command and agent workflows. - -## Workflow - -1. Clarify the outcome only when repo inspection cannot resolve ambiguity. -2. Work in small loops: inspect, plan briefly, act, verify, and summarize. -3. Use the plugin's knowledge files for Duyet-specific profile, writing style, and topic context when relevant. -4. For orchestration requests, decompose the work into independent streams before delegating. -5. For learning requests, gather evidence before proposing durable knowledge updates. - -## Related Claude Assets - -- Commands in `commands/` cover summon, learn, orchestrate, spawn, think, and writing workflows. -- The `agents/duyetbot.md` file contains the Claude agent persona. -- Existing skills under `skills/` provide engineering discipline, team coordination, task loops, and transparency guidance. diff --git a/duyetbot/skills/engineering-discipline/SKILL.md b/duyetbot/skills/engineering-discipline/SKILL.md deleted file mode 100644 index e774582..0000000 --- a/duyetbot/skills/engineering-discipline/SKILL.md +++ /dev/null @@ -1,83 +0,0 @@ ---- -name: engineering-discipline -description: Core engineering principles for sustainable, maintainable code. No shortcuts, no hacks. Quality gates before completion. ---- - -# Engineering Discipline - -Duyetbot's engineering principles for code that scales to 10,000+ users. - -## Core Rules - -### 1. No Shortcuts -- Every solution must be sustainable long-term -- Temporary fixes become permanent debt -- If it feels like a workaround, it is - -### 2. Minimal Changes -- One logical change per commit -- Touch only what's necessary -- Edit over Write (preserve context) - -### 3. Verify Before Complete -- Tests pass -- Lint clean -- Manual verification when needed - -## Quality Gates - -Before marking any work complete: - -### Code -- [ ] No errors/warnings -- [ ] Follows existing patterns -- [ ] No hardcoded values -- [ ] Error handling present -- [ ] Input validation at boundaries - -### Testing -- [ ] Unit tests for logic -- [ ] Integration tests for flows -- [ ] Edge cases covered -- [ ] Tests are deterministic - -### Performance -- [ ] No N+1 patterns -- [ ] Appropriate caching -- [ ] Resource cleanup - -### Security -- [ ] Input sanitized -- [ ] Auth/authz checked -- [ ] No secrets in code - -## Decision Rules - -### When to Refactor -Refactor when: -- Adding features is painful -- Bugs cascade -- Code confuses - -Don't when: -- Code works, rarely changes -- No immediate need - -### When to Abstract -Abstract when: -- Pattern appears 3+ times -- Abstraction reduces complexity - -Don't when: -- Only 1-2 occurrences -- Abstraction more complex - -## Anti-Patterns - -| Bad | Why | Good | -|-----|-----|------| -| Magic numbers | Unclear | Named constants | -| God objects | Unmaintainable | Single responsibility | -| Copy-paste | Bug multiplication | Extract shared | -| Commented code | Confusion | Git history | -| Premature optimization | Wrong focus | Measure first | diff --git a/duyetbot/skills/task-loop/SKILL.md b/duyetbot/skills/task-loop/SKILL.md deleted file mode 100644 index e562369..0000000 --- a/duyetbot/skills/task-loop/SKILL.md +++ /dev/null @@ -1,103 +0,0 @@ ---- -name: task-loop -description: Iterative execution loop — break work into small steps and verify each before the next, adapting from results. Use when executing multi-step tasks that need verification between steps. ---- - -# Task Loop - -Duyetbot's loop-based approach to task execution. - -## Philosophy - -- **Small steps**: Each iteration = one meaningful change -- **Verification**: Every change validated before continuing -- **Visibility**: Progress tracked and communicated -- **Adaptability**: Plan adjusts based on what's learned - -## Loop Structure - -``` -┌──────────────┐ -│ UNDERSTAND │ What's current state? -└──────┬───────┘ - ▼ -┌──────────────┐ -│ PLAN │ What's single next step? -└──────┬───────┘ - ▼ -┌──────────────┐ -│ EXECUTE │ One change only -└──────┬───────┘ - ▼ -┌──────────────┐ -│ VERIFY │ Did it work? -└──────┬───────┘ - ▼ - Complete? ──NO──► Loop - │ - YES - ▼ - DONE -``` - -## Iteration Template - -```markdown -### Iteration N - -**State**: What's done / pending -**Goal**: What this iteration accomplishes - -**Execution**: -[1] Action → Result - -**Verify**: -- [ ] Works as expected -- [ ] Tests pass - -**Next**: What comes after -``` - -## Progress Format - -``` -[x] Step 1: Done (iter 1) -[x] Step 2: Done (iter 2) -[ ] Step 3: Current (iter 3) -[ ] Step 4: Pending -``` - -## Termination - -### Success -- All acceptance criteria met -- Tests passing -- Code clean - -### Stop -- Blocker requiring human input -- Max iterations reached -- Same step failed 3x - -## Anti-Patterns - -### Don't: Giant Iterations -``` -BAD: Iteration 1: Implement entire feature -GOOD: Iteration 1: Data model - Iteration 2: Core logic - Iteration 3: Error handling - Iteration 4: Tests -``` - -### Don't: Skip Verification -``` -BAD: Execute → Execute → Execute → Check -GOOD: Execute → Verify → Execute → Verify -``` - -### Don't: Ignore Failures -``` -BAD: Test failed, moving on -GOOD: Test failed, investigating cause -``` diff --git a/duyetbot/skills/team-coordination/SKILL.md b/duyetbot/skills/team-coordination/SKILL.md deleted file mode 100644 index d699354..0000000 --- a/duyetbot/skills/team-coordination/SKILL.md +++ /dev/null @@ -1,161 +0,0 @@ ---- -name: team-coordination -description: Spawn and coordinate team-agents and orchestration patterns for parallel execution. Use for complex multi-component work. ---- - -# Team Coordination - -Duyetbot's capability to spawn and coordinate other agents for parallel execution. - -## Available Agents - -From **@team-agents** plugin: - -| Agent | Model | Use For | -|-------|-------|---------| -| `leader` | opus | Complex decomposition, team coordination | -| `senior-engineer` | sonnet | Architectural decisions, complex impl | -| `junior-engineer` | haiku | Clear specs, fast execution | - -## When to Spawn - -### Spawn @leader -- Multi-component features -- Unclear requirements needing decomposition -- Work requiring architectural decisions - -### Spawn @senior-engineer -- Complex implementation logic -- Architectural decisions -- Performance-critical code -- Security-sensitive work - -### Spawn @junior-engineer -- Well-defined tasks with clear specs -- Straightforward CRUD operations -- Test writing with clear patterns -- Documentation updates - -### Stay Solo -- Single-file changes -- Debugging sessions -- Analysis and investigation -- Quick fixes - -## Orchestration Patterns - -From **@orchestration** plugin: - -### Fan-Out -Launch independent agents simultaneously: -``` -├── Agent 1: Task A -├── Agent 2: Task B -└── Agent 3: Task C -→ All run in parallel -``` - -### Pipeline -Sequential stages: -``` -Stage 1 → Stage 2 → Stage 3 -(each depends on previous) -``` - -### Map-Reduce -Distribute then aggregate: -``` -Map: Split work across agents -Reduce: Synthesize results -``` - -### Speculative -Competing approaches: -``` -├── Hypothesis A -├── Hypothesis B -└── Hypothesis C -→ Select best evidence-backed -``` - -## Spawn Protocol - -### 1. Task Analysis -``` -[ANALYZE] Is this parallelizable? -- Independent components? → Fan-out -- Sequential dependencies? → Pipeline -- Need decomposition? → Spawn @leader -``` - -### 2. Agent Selection -``` -[SELECT] Match agent to task: -- Complex/architectural → @senior-engineer -- Clear/straightforward → @junior-engineer -- Need coordination → @leader -``` - -### 3. Spawn with Context -``` -Task tool with run_in_background=True: - -=== WORKER AGENT === -You are a WORKER spawned by duyetbot. -======================== - -TASK: [specific assignment] -CONTEXT: [background info] -SCOPE: [boundaries] -OUTPUT: [expected deliverable] -``` - -### 4. Monitor & Integrate -``` -[MONITOR] Track agent progress -[WAIT] Await completion -[VERIFY] Check quality gates -[INTEGRATE] Combine results -``` - -## Output Format - -``` -[1] ANALYZE → 3 independent components identified -[2] SPAWN @senior-engineer → "Component A" -[3] SPAWN @junior-engineer → "Component B" -[4] SPAWN @junior-engineer → "Component C" -[5] WAIT → All agents complete -[6] VERIFY → Integration tests pass - -─── duyetbot ── coordinating ───── -``` - -## Quality Gates for Spawned Work - -Before accepting agent output: -- [ ] Meets task specification -- [ ] Follows project patterns -- [ ] Tests included and passing -- [ ] No security issues -- [ ] Integrates with other components - -## Anti-Patterns - -### Don't: Over-Orchestrate -``` -BAD: Spawn 5 agents for a simple fix -GOOD: Solo execution for simple tasks -``` - -### Don't: Under-Specify -``` -BAD: "Fix the bug" -GOOD: "Fix auth timeout in auth.ts:45, add retry logic with 3 attempts" -``` - -### Don't: Ignore Dependencies -``` -BAD: Spawn parallel agents for dependent tasks -GOOD: Pipeline pattern for sequential dependencies -``` diff --git a/duyetbot/skills/transparency/SKILL.md b/duyetbot/skills/transparency/SKILL.md deleted file mode 100644 index 6e23dc8..0000000 --- a/duyetbot/skills/transparency/SKILL.md +++ /dev/null @@ -1,81 +0,0 @@ ---- -name: transparency -description: Show your thinking and execution chain with phase/thinking markers and debug traces. Use when the user wants visible step-by-step reasoning and traceable decisions. ---- - -# Transparency - -Duyetbot's commitment to visible execution - making reasoning traceable. - -## Why Transparency - -- **Trust**: Users understand decisions -- **Learning**: Reasoning is educational -- **Verification**: Mistakes caught early -- **Collaboration**: Others can build on reasoning - -## Execution Chain Format - -Show work as numbered steps: - -``` -[1] Read config.ts → Found: db settings at line 45 -[2] Grep "pool" → 3 files: db.ts, cache.ts, test.ts -[3] Edit db.ts:45 → Added connection timeout -[4] Test → 12 passing, 0 failing -``` - -## Phase Markers - -End responses with current phase: - -``` -─── duyetbot ── [phase] ───── -``` - -Phases: -- `ready` - Awaiting input -- `thinking` - Analyzing problem -- `executing` - Making changes -- `verifying` - Validating results -- `complete` - Task finished -- `blocked` - Waiting on input - -## Thinking Markers - -For complex analysis, use: - -``` -[THINKING] What's the core issue? -[CONTEXT] Found pattern in utils/auth.ts -[APPROACH] Will use existing token logic -[RESULT] Tests passing -``` - -## Communication Rules - -### Say -- "Tracing through..." -- "Found: [evidence]" -- "Verified: [result]" -- "Blocked on: [reason]" - -### Never Say -- "Obviously..." (hides complexity) -- "Simply..." (dismisses difficulty) -- "Just..." (underestimates work) -- "Clearly..." (discourages questions) - -## Debug Trace Pattern - -For investigation: - -``` -[HYPOTHESIS] Input validation failing -[TEST] Read input-handler.ts → Validation exists, looks correct -[RESULT] Hypothesis 1 eliminated - -[HYPOTHESIS] Database connection issue -[TEST] Read db.ts → Found: no timeout configured -[RESULT] Root cause identified -``` diff --git a/fix/.claude-plugin/plugin.json b/fix/.claude-plugin/plugin.json index 6f7be96..1543662 100644 --- a/fix/.claude-plugin/plugin.json +++ b/fix/.claude-plugin/plugin.json @@ -1,9 +1,12 @@ { "name": "fix", - "description": "Fix issues, tests, and CI failures with intelligent problem detection and resolution", "version": "1.0.1", + "description": "Fix issues, tests, and CI failures with intelligent problem detection", "author": { - "name": "duyet" + "name": "duyet", + "url": "https://github.com/duyet" }, + "license": "MIT", + "homepage": "https://github.com/duyet/codex-claude-plugins/tree/master/fix", "logo": "./assets/logo.svg" } diff --git a/fix/.codex-plugin/plugin.json b/fix/.codex-plugin/plugin.json index 0a7e11e..da6a00a 100644 --- a/fix/.codex-plugin/plugin.json +++ b/fix/.codex-plugin/plugin.json @@ -1,17 +1,23 @@ { "name": "fix", "version": "1.0.1", - "description": "Fix issues, tests, and CI failures with intelligent problem detection and resolution", + "description": "Fix issues, tests, and CI failures with intelligent problem detection", "author": { - "name": "duyet" + "name": "duyet", + "url": "https://github.com/duyet" }, + "license": "MIT", "skills": "./skills/", + "commands": "./commands/", "interface": { "displayName": "Fix", - "shortDescription": "Fix issues, tests, and CI failures with intelligent problem detection and resolution", + "shortDescription": "Fix issues, tests, and CI failures with intelligent problem detection", "developerName": "duyet", "category": "Productivity", - "capabilities": ["Skill", "Command"], + "capabilities": [ + "Skill", + "Command" + ], "logo": "./assets/logo.svg", "composerIcon": "./assets/logo.svg" } diff --git a/fix/.cursor-plugin/plugin.json b/fix/.cursor-plugin/plugin.json new file mode 100644 index 0000000..a032d31 --- /dev/null +++ b/fix/.cursor-plugin/plugin.json @@ -0,0 +1,16 @@ +{ + "name": "fix", + "version": "1.0.1", + "description": "Fix issues, tests, and CI failures with intelligent problem detection", + "author": { + "name": "duyet" + }, + "license": "MIT", + "displayName": "Fix", + "homepage": "https://github.com/duyet/codex-claude-plugins/tree/master/fix", + "repository": "https://github.com/duyet/codex-claude-plugins", + "logo": "./assets/logo.svg", + "category": "Productivity", + "skills": "./skills/", + "commands": "./commands/" +} diff --git a/fix/.grok-build-plugin/plugin.json b/fix/.grok-build-plugin/plugin.json index 4ada017..3791535 100644 --- a/fix/.grok-build-plugin/plugin.json +++ b/fix/.grok-build-plugin/plugin.json @@ -1,19 +1,25 @@ { "name": "fix", "version": "1.0.1", - "description": "Fix issues, tests, and CI failures with intelligent problem detection and resolution", + "description": "Fix issues, tests, and CI failures with intelligent problem detection", "author": { - "name": "duyet" + "name": "duyet", + "url": "https://github.com/duyet" }, + "license": "MIT", + "logo": "./assets/logo.svg", "skills": "./skills/", + "commands": "./commands/", "interface": { "displayName": "Fix", - "shortDescription": "Fix issues, tests, and CI failures with intelligent problem detection and resolution", + "shortDescription": "Fix issues, tests, and CI failures with intelligent problem detection", "developerName": "duyet", "category": "Productivity", - "capabilities": ["Skill", "Command"], + "capabilities": [ + "Skill", + "Command" + ], "logo": "./assets/logo.svg", "composerIcon": "./assets/logo.svg" - }, - "logo": "assets/logo.svg" + } } diff --git a/fix/.grok-plugin/plugin.json b/fix/.grok-plugin/plugin.json index f9c1c5d..99c9601 100644 --- a/fix/.grok-plugin/plugin.json +++ b/fix/.grok-plugin/plugin.json @@ -1,12 +1,16 @@ { "name": "fix", "version": "1.0.1", - "description": "Fix issues, tests, and CI failures with intelligent problem detection and resolution", + "description": "Fix issues, tests, and CI failures with intelligent problem detection", "author": { - "name": "duyet" + "name": "duyet", + "url": "https://github.com/duyet" }, - "logo": "assets/logo.svg", - "keywords": ["fix", "grok", "grok-build", "grok-bot"], + "license": "MIT", + "logo": "./assets/logo.svg", + "keywords": [ + "fix" + ], "skills": "./skills/", "commands": "./commands/" } diff --git a/fix/CLAUDE.md b/fix/CLAUDE.md deleted file mode 100644 index 0736fdc..0000000 --- a/fix/CLAUDE.md +++ /dev/null @@ -1,69 +0,0 @@ -# Fix Plugin - -Fix issues, tests, and CI failures with intelligent problem detection and resolution. Supports Python, Node/TS, Rust, and Go projects. - -## Versioning - -Follow semantic versioning (semver) for this plugin: - -| Change Type | Version Bump | Example | -|-------------|--------------|---------| -| Bug fix, docs | Patch | 1.0.0 → 1.0.1 | -| New feature, minor change | Minor | 1.0.0 → 1.1.0 | -| Breaking change | Major | 1.0.0 → 2.0.0 | - -**When to bump:** -- Adding new commands, skills, or agents → **Minor** -- Modifying existing behavior → **Minor** (or Major if breaking) -- Updating documentation only → **Patch** -- Bug fixes → **Patch** - -Always update `plugin.json` version when making changes. - -## Plugin Structure - -``` -fix/ -├── .claude-plugin/ -│ └── plugin.json # Manifest (version 1.0.0) -├── commands/ # Slash commands -├── skills/ # Reusable knowledge -└── README.md # Documentation -``` - -## Components - -### Commands - - - `/fix:and-push`: Fix issues/tests, commit changes, and push to remote - - `/fix:and-update-pr`: Fix issues/tests and update an existing pull request - - `/fix:and-create-pr`: Fix issues/tests and create a new pull request - -### Skills - - - **test-detection**: Project type detection and fix strategies for Python, Node/TS, Rust, Go - -## Supported Project Types - -| Type | Detection | Tools | -|------|-----------|-------| -| Python | `pyproject.toml`, `setup.py` | pytest, ruff, mypy, black | -| Node/TS | `package.json`, `tsconfig.json` | jest, vitest, eslint, tsc | -| Rust | `Cargo.toml` | cargo test, clippy | -| Go | `go.mod` | go test, golint | - -## Commit Convention - -Use semantic commits with plugin scope: - -``` -feat(fix): add new feature -fix(fix): fix bug -docs(fix): update documentation -``` - -Co-author: `Co-Authored-By: duyetbot ` - ---- - -**Generated by docs-generator v1.0.0** diff --git a/frontend-design/.claude-plugin/plugin.json b/frontend-design/.claude-plugin/plugin.json index 57cbf06..68baec6 100644 --- a/frontend-design/.claude-plugin/plugin.json +++ b/frontend-design/.claude-plugin/plugin.json @@ -1,10 +1,12 @@ { "name": "frontend-design", "version": "1.4.0", - "description": "Create distinctive, production-grade frontend interfaces avoiding AI slop aesthetics. Emphasizes shadcn/ui, Recharts, and bold design choices.", + "description": "Create distinctive, production-grade frontend interfaces avoiding AI slop aesthetics", "author": { "name": "duyet", - "email": "me@duyet.net" + "url": "https://github.com/duyet" }, + "license": "MIT", + "homepage": "https://github.com/duyet/codex-claude-plugins/tree/master/frontend-design", "logo": "./assets/logo.svg" } diff --git a/frontend-design/.codex-plugin/plugin.json b/frontend-design/.codex-plugin/plugin.json index ae9486a..c134c5f 100644 --- a/frontend-design/.codex-plugin/plugin.json +++ b/frontend-design/.codex-plugin/plugin.json @@ -1,18 +1,21 @@ { "name": "frontend-design", "version": "1.4.0", - "description": "Create distinctive, production-grade frontend interfaces avoiding AI slop aesthetics. Emphasizes shadcn/ui, Recharts, and bold design choices.", + "description": "Create distinctive, production-grade frontend interfaces avoiding AI slop aesthetics", "author": { "name": "duyet", - "email": "me@duyet.net" + "url": "https://github.com/duyet" }, + "license": "MIT", "skills": "./skills/", "interface": { "displayName": "Frontend Design", - "shortDescription": "Create distinctive, production-grade frontend interfaces avoiding AI slop aesthetics. Emphasizes shadcn/ui, Recharts, and bold design choices.", + "shortDescription": "Create distinctive, production-grade frontend interfaces avoiding AI slop aesthetics", "developerName": "duyet", "category": "Design", - "capabilities": ["Skill"], + "capabilities": [ + "Skill" + ], "logo": "./assets/logo.svg", "composerIcon": "./assets/logo.svg" } diff --git a/frontend-design/.cursor-plugin/plugin.json b/frontend-design/.cursor-plugin/plugin.json new file mode 100644 index 0000000..5e0871d --- /dev/null +++ b/frontend-design/.cursor-plugin/plugin.json @@ -0,0 +1,15 @@ +{ + "name": "frontend-design", + "version": "1.4.0", + "description": "Create distinctive, production-grade frontend interfaces avoiding AI slop aesthetics", + "author": { + "name": "duyet" + }, + "license": "MIT", + "displayName": "Frontend Design", + "homepage": "https://github.com/duyet/codex-claude-plugins/tree/master/frontend-design", + "repository": "https://github.com/duyet/codex-claude-plugins", + "logo": "./assets/logo.svg", + "category": "Design", + "skills": "./skills/" +} diff --git a/frontend-design/.grok-build-plugin/plugin.json b/frontend-design/.grok-build-plugin/plugin.json index d1044f1..a928937 100644 --- a/frontend-design/.grok-build-plugin/plugin.json +++ b/frontend-design/.grok-build-plugin/plugin.json @@ -1,20 +1,23 @@ { "name": "frontend-design", "version": "1.4.0", - "description": "Create distinctive, production-grade frontend interfaces avoiding AI slop aesthetics. Emphasizes shadcn/ui, Recharts, and bold design choices.", + "description": "Create distinctive, production-grade frontend interfaces avoiding AI slop aesthetics", "author": { "name": "duyet", - "email": "me@duyet.net" + "url": "https://github.com/duyet" }, + "license": "MIT", + "logo": "./assets/logo.svg", "skills": "./skills/", "interface": { "displayName": "Frontend Design", - "shortDescription": "Create distinctive, production-grade frontend interfaces avoiding AI slop aesthetics. Emphasizes shadcn/ui, Recharts, and bold design choices.", + "shortDescription": "Create distinctive, production-grade frontend interfaces avoiding AI slop aesthetics", "developerName": "duyet", "category": "Design", - "capabilities": ["Skill"], + "capabilities": [ + "Skill" + ], "logo": "./assets/logo.svg", "composerIcon": "./assets/logo.svg" - }, - "logo": "assets/logo.svg" + } } diff --git a/frontend-design/.grok-plugin/plugin.json b/frontend-design/.grok-plugin/plugin.json index b6ac912..f647ade 100644 --- a/frontend-design/.grok-plugin/plugin.json +++ b/frontend-design/.grok-plugin/plugin.json @@ -1,12 +1,15 @@ { "name": "frontend-design", "version": "1.4.0", - "description": "Create distinctive, production-grade frontend interfaces avoiding AI slop aesthetics. Emphasizes shadcn/ui, Recharts, and bold design choices.", + "description": "Create distinctive, production-grade frontend interfaces avoiding AI slop aesthetics", "author": { "name": "duyet", - "email": "me@duyet.net" + "url": "https://github.com/duyet" }, - "logo": "assets/logo.svg", - "keywords": ["frontend-design", "grok", "grok-build", "grok-bot"], + "license": "MIT", + "logo": "./assets/logo.svg", + "keywords": [ + "frontend-design" + ], "skills": "./skills/" } diff --git a/frontend-design/CLAUDE.md b/frontend-design/CLAUDE.md deleted file mode 100644 index aa2675a..0000000 --- a/frontend-design/CLAUDE.md +++ /dev/null @@ -1,56 +0,0 @@ -# Frontend-design Plugin - -Create distinctive, production-grade frontend interfaces avoiding AI slop aesthetics. Emphasizes shadcn/ui, Recharts, and bold design choices. - -## Versioning - -Follow semantic versioning (semver) for this plugin: - -| Change Type | Version Bump | Example | -|-------------|--------------|---------| -| Bug fix, docs | Patch | 1.0.0 → 1.0.1 | -| New feature, minor change | Minor | 1.0.0 → 1.1.0 | -| Breaking change | Major | 1.0.0 → 2.0.0 | - -**When to bump:** -- Adding new commands, skills, or agents → **Minor** -- Modifying existing behavior → **Minor** (or Major if breaking) -- Updating documentation only → **Patch** -- Bug fixes → **Patch** - -Always update `plugin.json` version when making changes. - -## Plugin Structure - -``` -frontend-design/ -├── .claude-plugin/ -│ └── plugin.json # Manifest (version 1.2.0) -├── agents/ # Sub-agent definitions -├── commands/ # Slash commands -├── skills/ # Reusable knowledge -└── hooks/hooks.json # Lifecycle hooks (optional) -``` - -## Components - -### Skills - - - **frontend-design** - - -## Commit Convention - -Use semantic commits with plugin scope: - -``` -feat(frontend-design): add new feature -fix(frontend-design): fix bug -docs(frontend-design): update documentation -``` - -Co-author: `Co-Authored-By: duyetbot ` - ---- - -**Generated by docs-generator v1.0.0** diff --git a/github/.claude-plugin/plugin.json b/github/.claude-plugin/plugin.json index 9b0be32..e2fd94a 100644 --- a/github/.claude-plugin/plugin.json +++ b/github/.claude-plugin/plugin.json @@ -1,10 +1,12 @@ { "name": "github", "version": "1.4.2", - "description": "GitHub operations using gh CLI - PRs, workflows, issues, repositories, batch operations, PR babysitting with AI review bot integration, and smart branch detection", + "description": "GitHub operations using gh CLI - PRs, issues, workflows, batch operations, PR babysitting with AI review bot integration, and smart branch detection", "author": { - "name": "duyetbot" + "name": "duyet", + "url": "https://github.com/duyet" }, "license": "MIT", + "homepage": "https://github.com/duyet/codex-claude-plugins/tree/master/github", "logo": "./assets/logo.svg" } diff --git a/github/.codex-plugin/plugin.json b/github/.codex-plugin/plugin.json index cfbb6a8..ca10931 100644 --- a/github/.codex-plugin/plugin.json +++ b/github/.codex-plugin/plugin.json @@ -1,18 +1,23 @@ { "name": "github", "version": "1.4.2", - "description": "GitHub operations using gh CLI - PRs, workflows, issues, repositories, batch operations, PR babysitting with AI review bot integration, and smart branch detection", + "description": "GitHub operations using gh CLI - PRs, issues, workflows, batch operations, PR babysitting with AI review bot integration, and smart branch detection", "author": { - "name": "duyetbot" + "name": "duyet", + "url": "https://github.com/duyet" }, "license": "MIT", "skills": "./skills/", + "commands": "./commands/", "interface": { "displayName": "GitHub", - "shortDescription": "GitHub operations using gh CLI - PRs, workflows, issues, repositories, batch operations, PR babysitting with AI review bot integration, and smart branch detection", - "developerName": "duyetbot", + "shortDescription": "GitHub operations using gh CLI - PRs, issues, workflows, batch operations, PR babysitting with AI review bot integration, and smart branch detection", + "developerName": "duyet", "category": "Git", - "capabilities": ["Skill", "Command"], + "capabilities": [ + "Skill", + "Command" + ], "logo": "./assets/logo.svg", "composerIcon": "./assets/logo.svg" } diff --git a/github/.cursor-plugin/plugin.json b/github/.cursor-plugin/plugin.json new file mode 100644 index 0000000..66514db --- /dev/null +++ b/github/.cursor-plugin/plugin.json @@ -0,0 +1,16 @@ +{ + "name": "github", + "version": "1.4.2", + "description": "GitHub operations using gh CLI - PRs, issues, workflows, batch operations, PR babysitting with AI review bot integration, and smart branch detection", + "author": { + "name": "duyet" + }, + "license": "MIT", + "displayName": "GitHub", + "homepage": "https://github.com/duyet/codex-claude-plugins/tree/master/github", + "repository": "https://github.com/duyet/codex-claude-plugins", + "logo": "./assets/logo.svg", + "category": "Git", + "skills": "./skills/", + "commands": "./commands/" +} diff --git a/github/.grok-build-plugin/plugin.json b/github/.grok-build-plugin/plugin.json index d215ffe..89acb0d 100644 --- a/github/.grok-build-plugin/plugin.json +++ b/github/.grok-build-plugin/plugin.json @@ -1,20 +1,25 @@ { "name": "github", "version": "1.4.2", - "description": "GitHub operations using gh CLI - PRs, workflows, issues, repositories, batch operations, PR babysitting with AI review bot integration, and smart branch detection", + "description": "GitHub operations using gh CLI - PRs, issues, workflows, batch operations, PR babysitting with AI review bot integration, and smart branch detection", "author": { - "name": "duyetbot" + "name": "duyet", + "url": "https://github.com/duyet" }, "license": "MIT", + "logo": "./assets/logo.svg", "skills": "./skills/", + "commands": "./commands/", "interface": { "displayName": "GitHub", - "shortDescription": "GitHub operations using gh CLI - PRs, workflows, issues, repositories, batch operations, PR babysitting with AI review bot integration, and smart branch detection", - "developerName": "duyetbot", + "shortDescription": "GitHub operations using gh CLI - PRs, issues, workflows, batch operations, PR babysitting with AI review bot integration, and smart branch detection", + "developerName": "duyet", "category": "Git", - "capabilities": ["Skill", "Command"], + "capabilities": [ + "Skill", + "Command" + ], "logo": "./assets/logo.svg", "composerIcon": "./assets/logo.svg" - }, - "logo": "assets/logo.svg" + } } diff --git a/github/.grok-plugin/plugin.json b/github/.grok-plugin/plugin.json index 24d8e15..3940e7d 100644 --- a/github/.grok-plugin/plugin.json +++ b/github/.grok-plugin/plugin.json @@ -1,13 +1,16 @@ { "name": "github", "version": "1.4.2", - "description": "GitHub operations using gh CLI - PRs, workflows, issues, repositories, batch operations, PR babysitting with AI review bot integration, and smart branch detection", + "description": "GitHub operations using gh CLI - PRs, issues, workflows, batch operations, PR babysitting with AI review bot integration, and smart branch detection", "author": { - "name": "duyetbot" + "name": "duyet", + "url": "https://github.com/duyet" }, "license": "MIT", - "logo": "assets/logo.svg", - "keywords": ["github", "grok", "grok-build", "grok-bot"], + "logo": "./assets/logo.svg", + "keywords": [ + "github" + ], "skills": "./skills/", "commands": "./commands/" } diff --git a/good-html.skill b/good-html.skill deleted file mode 100644 index a720b06da7571610b60bc32c43cfd5b8862c4d50..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 14897 zcmaL8W02(A*6p2Tv&-zVZQHhO+je!?wr#7+wry9Jjjp6HRhOe$xDHNq5uE@NI+;rg|;g_8Dtw60PqO|03iSQ*38b%n8w`M#+pt^NWc=jo~V^r#Ey2u*H*k#8m+M2AC!_mL`@&u!W+OqU)004%;FU z*(mUDeg0#HkxVwbHr-mL$|rA$W~ZZ$A6|*cIMB5lW!c?DY}RX)qlercyym=$g%_qe z4RD-KRP(I+{78=hYACD97yWBxO-Bj7-Cplp6!b>! z=C^a6s(l*GEYh_V5s4xb1aXxK`C!eI{i$#qKCsgDa{>Lb*g_+rH05BtAS?Q^OX0)ByY_YK>>Sq@qSZog7@dW|N3 z6Aq|}K9@`ZoQshpRKCO!rsuc|I*LHxa+=hsmaIm!NfM~x@+w%Gvgj?~)Z&UuH+M0{dJBYEG=}VWjCXwRU5}qehK?n5G=xnqnD0{T}#lX96%~qVa*(60E#^PW|Q$du4`Kz#Qtc!3(>F(Fa;o{VyDUkDTZEM**#BVmx6))?&r z!5weFH*mqt0xeEG`_TqDLJA}FQqs&K)lW#h5yo2m9q^(Q!LlrYl`$l~^p42}5-1Em z0f^PYK^$7srOnjbnH)Vn^dei0uKXiGwO)bOf;pt_6%S>%jwa;LDqM1pc?t_W z@pI z@Qi_nd6;F!vW)%AcErvw8^#iQsxeNKiy(ZXO85XEFF*yJJ!#`IdR`=7o2bLb1}yS< zE*=9F#a9y!4nTrceN)vbPb{@kSN6S8b>5D=G%#O|`$GIF=^fwlo*3Ghi`Y&fGG2-2 z_^mJi6s5Chtd^h&Awx5V{K;~;K3`0A;U)VxP2wdKs-m(*B+-^r?*h1lw*)=nWmG); z#}4^S>AK(T25Igyn^^d6d~1+rv8y<#oI5(;=tXc-6hJAe4A+eu%L>7pRF(;f@t4eY~6J+!-2vQ z=6MdYtd(|m$P>o(Qi#QymJ3nKDMK=+euIzYK#ZI~!9}!zyhlweHkMuX+FF5C>krvr zOnf*HBj{hU3z|G#<@1hM-b~ZseNxmRR`1Hc3d8Weh5Gzp<42O&Z*Cxq#nFkMRnYt~ z;hhoiVh1zk6JB!o!6*O!>wJAmh4!Vi6RhW^d>0ihyM0Mm-xD=;WzGWfI&Db{uN?B(NM%(Oi{@H~1OiN#gt7GWrm4?2qZ#|P zLLMz>g1yGyYxirsL0;8N?(SRMeUj?wYIQc%-$*{dv{on$xUyFSHAk`2p+*N~Rr>>} zK=bOH9T>qb>c(e{(OlR0vl2%H_9Rh3u*lrfIJt=JL`!6wgB2wG8eph;EqW1Xn6B$H zBP9``(PDMvHGhJDI=jU(t&gB7Zq6vD0AErZcv6vm&#C3My#D> zW%s#5N>zuiFj4N|kTl%@AruiX9F7YVVBJ>RN>_s(f-{}z^kOGIC{GOkpa!nAs(>ht zc7}P}E{}B)jgMjn4cw+WY2sD5=>JCIvV8`^&y6vPV6*-LzTen6wDq_}9l8x}0tQub z-99IijGNE0+z(pzMRYpv^o47QigZ7F3)Wo%Q7h}+PDHMPL0DUJa=(^EKO>rAuG!06 zJh+Gb!LNj5=G8PO=?gk?Us-u%Eh4%RI=hVQ8Oha$9&cH5-ZwLbkg-M7h2bIvmU-aV02 zbr+%=xiWN&SGP?d*O6v@_`M5pc zExl2po^*J9U_dpG^LTNPSHVtR01b-?z8(AotVb+Fi521!Qb$p6)+IKwAT0R_Q(Yy7?wNsz;wu%p93uLTPNGU12kA9fONQ5y6~0kD5iqlO zo+U?Pk|wOI5`=gO6}OFK$h5w*koZC8VWL7nY-&og@|wy>`q~*(2kZG*x69`;Lj|ZU zy&JTIcv@^HP=5=9QZThkVYLYK;$I^lG5Q`gH0zn7<|4tf+lF91?t~7@^#%NwPC@>t z(8lBHY_@>{0Az3g0K)&KQ$}_+_I9==w$A_3s%mu`yA5{a&m6rzrMfaW;fSI^39AvH zw+6cIE!{}cPPecD;9`>XW6>06;-f(=W50KvB65v{qd_k>^7B>X6QASsJ)Fdqa?J?p z6QtL@rvbS`o0jp$q~eH=L9@V!skynC1f*u;m#B)=gtDkf=$t|0F?1<5)AB=0Cqeg$ zw7mFzE73A}@0ja(qT0kF3288*1QI84dbYDUX~4y2dCn=|d=$Nv#T%yCE)4PF~Ugv2C`+wqhm;@ZEi1(4Bl%F|4a; zGpzflP4d}9y9KZpPU9S?JFai(?<<+140Ui_KfPZIhH!Kwnk7~rkqC0;Cx0fSNtM-O zCVKSaksdEZ8$g>kI>Rm`8Yat*8j0+eICo36cQ;!{HIBU&EM-kLsC{3# zvvq9!$TFKiuEo+s-C4Uvf{5F?i&`n`UTlqF52?JKq*1%GGm`c#GaZUTW|jgO~vH1&G%Y9!rbMoExqgvweAtYlQ&!t zc#;N(^K%qKO9#!;@c>yN_hg4@7X46Af4O@nI)}Dg_Fsq_d;r`a%lxos2BPa1Z&}{} z5osKsNmRXj3?mS&TwV}?=IRFgN<;Y$(z5V|@(m81TVo}YB}%Ery&{!;GdTJR`n_V` zk_qP=<7Xr6RI-NGN#lE?Y60LZo02ub8+Suqogr25sV!uBf?t~}>MZCpLWZ+QiD;EU z4n=|#PkGuIH(>IT=E9lEX=f40yHS@R!Fc9+{LeI9%7(3w%JHPuF-`(y64$9X%VSxh zH@38CUUcT$E-?`OG3SO1g+bpRO8 z?7I60eD~z;%_|ie%KC~WADCvE4h0j~Fi{yWKg1U>W#sG_fT>sO=o-zAck?+&)Thg^ z_#udwXIr*J@2L@Zlex1a$c?mGR~njG)!QQ~gH=RYTfKBouPhvAo1~JM@47~T9+8go zaGP3jyOKvzHwgI)9?|)ixN|60dn$G^%&D&^QBurrcgIPhSy*2{V;_W-hIjZFzPSD5 z4rh1*%P-7^zD;Tw_3HG@IUR2VpOE&8vEkGYo~Ajvi(t-1GLvG-CxY@h1yFqZT_m1f zNB@GYql5{SQ(5Q{pYa1$`Slnr2k*w++>>owmGZ!wk;DNFl?tW4RsVb=_^j5B_1eg1 z^?-uiN^#44&iy5@LfT!SxX_Jm*JD7-3EMM`d7)2Vykx~yoLpo|8Ct@+dWifbzFgwK z2E1#JLdG5xVna~k9Vw>Ezmz@l>#o3?CcWc`Dg||X{4%GuE%*C{OV#73|I7#{A`t?v zC|X=CCT1_5cW)I9>a6TjN?rv#@JoZ`;y2jjFwCxaj*e-1>GjREPhV?B%vdwnzNJa( zoS3ml^h9v8CZD7f;1gusi8~cc%C!{^byMP=?R#~aks|4-El>DXu*M2l?{(0~6QZA` zz|$??6`inS&$QFipZJx=J6KCFqUz8fld5Jo~@Li#|V+w7WyW5K2 zY1Qb}8);;l?8`h?OwWej3S3T4k**3h%E;7htZf7=k_}H(LN5W+A!58v9%8a%@2H*) zg!pC1ANh1Y)sCmWmW={=BvwH;`9elIl~xZ_)z}Or+_22agwdzt$5ec~t&JVWY{tw# z9+s@xfVpn1Wz~_WYO|)SES6aF+bhvwAf%B#%~y*w>$le^U}=#ec9)<$Jl2H3@bMTQ z)GM;NJFM++Y<*vIydhHN5}-|%$+%fo!_nuRt1$|r@~FBo`*uktT2!}v*1Ti-8n|2h zfa-M-dCq>0;g!JCo}?xEz#YRgWXNPAGb5(jSx)AKjFTRPRLfee=AMH`-0exsPa%{G zyN+;LX!1H!Dc_0uw7zc*^&hBe`i$A#x6&^v2iGzw2z(2_WIUJwh$m__)6{Xcm%NT! z2Gc1qMW<+9qK;D-H0x6aOT-D`DoWD40*72R(Pt}%h=Y%Wrq_^Ksb|Z)wTvFm>nccb zI=NL*;7nXzYc4NBeVq3pkPa%H%mdv`eg$OF>wR*#On1c>V)Onvl8XGhDTD-bNHW1f z2@Vh}?jYB$i~#rqYf$bMTqUvtnqgU*kFrvIPbJn%J@eRffk`+5pWx@aGd{&sJ#^I> zCz?Dson>|doOIOpR7@c}>d5vUEETcou=X`O7sY)`<-F$P(hfYJ-x&gLk5E5(gO$h@ z3s? z+9^`Qe=DUf3O}N$tSq|n->gj7gxM=l=%Bzu38|pfZ)<;>C-l-Bcx}N=&Y%f;ayj4k*7G_GxcKhh z*=HgO_Nv9ve<9VkD-=(D<=an_*j3}Y;;Lt@s${IHKP@F?o${k>r^Jr(YWm=e6$~Xi6Eh0 zOk}xRAA;>v|BstxE14Jxgn3R3;XiFRMHqj_t< zlWj(|Ay*QcG{s`y=TT#^`LbcLdb2L8K)J^Xfon}|ihvT!M}>#m=z!0m*6)l(9r) z(U!^2&SZk}HIHIq6PjKLEx)jrz#Dw%vB=05BP1_STm~fOks+LmlZ%#OQkw1G=rk8Q zmb2}Pv@)n2PNXi9Zdy>O3O`R4R2dQ^WPdJI6tm=TA~|=;0zpGu6u^E4d)s%wnu-Z7 zLoy;l76aUATDLy)P_8r#n@V z#kn=kmrmAMXN5GTC3D^z*MtDw=5leC9vOidG*@;ljGrGuJole6 zbx(`vf{&&s>o4ZkeAVHQT8YKsBWzd9wnTC%Pd3w1OX2-$D8iGd_?)ya@@jXy=I0a!-ewhEZMpdwf?#}(b6imiN#PF#4EJ!d+Q>CDzKmUPhG2f{|F^0#u zWoU&rJkONK?pLXE2aK24OpwmUTR`E*{#xTsm4l>ZDIrE^IH5Wvag7uVv3+bYn$_Z% z6D!ajedK-d1=smgbj?tecUxHaWtAKx*0D(6FUMVx-nX8FDw2FJmMDty^|T zX3h4ckhAO1k5}9-*78sBG^YY%lSqR6mJbXgh%O$XObRXlYY(8$=$1AD z(^}eHtyI|5u)B(^Eq7xrtnGF;({2UI-uI-w0g<`NR`v+F!ar6@h1#Z%+MB>-+P{eg z6uv{h`l7;4lGk;Di`o|e*%L!fQZk*RKMbz)BCH>}#^GVydvpKd)F}`#9}SlGEhi8n zw}*XwQ(zuVOq^ltuD4|?MQ1~2+u6#>Mko82#RecE=yeazvu>1fB*b zSqJO>yu^#t5ZrC$@G;)&kn9)Xi^MG&MDQe1X<0Y_sQ_;77fz_N^vt_wxJi{v zV$rziM{>^41MH_*kdLa%!}KE?+C@DP%((|ZAaK2fmr$O_X{Z=n{+Q1eX~^5e;ob{6 zxd{r_%|VZ!8z;{Z%qf@;VHY|#j>zAACk+fjwE}C4i**VR`9?swY=>|toVtm(8M>@) zqz)k%ym0P~FQPjQpRgcBTDy2+DfWYOozoqyp9S9bNSqIr-waQ8gL3=^ZYCzpQV7wFsj zVv;O>r!nwPBr21H7e~}C-629R99j@2H%)IH`9U+*e(@sMA%Z;bD9CT!lbJ#)K&7gLv?;i1>u>%(5^*OVZ5j zP1VNUXK4D?!qy5{9inZ`lJpWnR-!zb=DnyS$qDQOyN>A2BkpGj|;qOBObAPjB#J!8tJHq&=lWXfsB4mIp(C z;h8uurMP(owbOE@EHgwM2kX5Ab*}00;hl_zk6Q~O*P@PHE3Rnd;ugRnPtHh2AxB3n zSR)K)t>E{T`Gm&viX}-yaGrVvY}Lc}-qJls5W&l1rPMv*-r`5%Lx+oUQD)R@MIFPA zdCPINMQ%t~@Q5FrYcq)sAP6uMuvSo?S-G}f6^pnn76c*gpCelJLxYRsn_$NiI6s7Y z;s^AauS0HU6dLC9`}+Hf53;YAt1S;yahHYoU}p^;N&_HEisn4r`0BoUww<7EkeJAI z6er@E_hxi1wy+LfUAD@zjulDLbTjSeQE+P!fI3Kzq+#hcFW?RA{!q-R7Zn%$hQAy9 z6}@J6aPUQWYN@VnG?cx{d%!}L{v@I&1iKGe#^3(;xVH9BTzdl{{*?^^0GxpTKVlGj z12YpnXAk@TiEM3@rR+9D5qmDwV2yiaKz|4%KFnuYu|*?6&>ODxn2N)XMW=NBnyxWE zS}`+~;E8%743N5FW7;vI-MxRiz|{^h$EqUSG?J>@Mi^{d>mYjB_SCEGSlzhp#Wtd` z#{$PE1X)M{9`EB%7O?VFgbUJ*_4I)XR)O#hFPW*u!p~!s5em=-b*y#}?rTGvT|x|p z3epZA#iliFjD&gV_W!8|egPtSfUDi#d<_8`+MP)Q(64WMV(D9=2c>Hc|I()3?OSZ3 ze5OkATg6%ru*;KU&FDi;)AjYT&<|d`>N)_%OUKv_YI-qH@yPUqu%T~eW<>L3%raiY zHeBe?KEZC!01jf&3LMco^=Xy>p$Z=Amb(SyK-k3*F$=r=SSn$6-9gx_*xx(}cJb#&+9=wX`dtFW%bfOt$gqJDmMxUQ<^La8@P#4Iu-1bYHPDZ0~0b_Ag z^MqxoOIm`_Q7Ak64R1hKp%Pw)3U7>XQVLn&43{;&AEymk zSQau#z6)v%ec$cCv1vP|!J9nTZ7Mp(2g+)$v$#A60+aIgK{xZodfnC}!~;h6l&?+Q z`ctSaEM|7t7OEI^#sn*U!GM=6BAmdSUEzdsERg+JS>I1UH+*n%x@!gl?%I)e& z>Dfo3$m>nE6qzI;J zcwSZ^TK&^(S4|{m&ejm!+mcHKV&rih@@;U#j$7o^Z|g(f<$6oL854x})R3o0v@C&M z+J<#(eaT!$!ox)}cc9whJ|w=JFM`7K_#|yksJzrqnCfSud9Z`a7EZ^Q7CoCrqzLd+ z$7~VfcoWgd_~>cPH?1Meo9gC*Q*xtWUHo=l!JhmAniP4BT-|C?O+mTt)ZLg&b;1{z zzihMYpPoBDjy22pAG?eK1OO2Kn{B2wvNmurHleY%b}_TCrTgCpt)-Kltw?O2>;ONk z@bxRS6`giMnRdG)xp+1IEIz#knbn+okWFCT`Okw2@y%g7QKR=o0C8XXJZ@3>@+N9- zYEDa`}5M5}rU3uFW)TatW%L7W(S+8V)Mk?Ra3w|V-0E>CGqUGrE zTbR5-M<*E33*t(K7guQcb>s1MD@PB=ec9Prm>RV0@Q|{zogAb8wHN=&dm9pXlD+=S z9|*t#00jTG7Y0sFCeBWDhISU#CXV*j2F@n5|C&pPR@-t~XGiqA*2}-|4vv9a4dwTz z7lLfcwy0%;@@Nw?fYDM~yA$8P;QYN~r}haDT-Qae>*`$J+VPc0|G0f|>3KW329uB> zEx9Ir`5t&Y);-_|0TnfTGn$r9ELlE3xyeOWSg_Oqh|48ls*j zR>l**5jQr?Oi#Pt$(9{8C#FpQ*|#&&5|%Ac#%%lsE_$*^spn^=xzivS0TD?t!H$7Q z_{nXy@(9wa6NlC|&HF)w=4>EE(Ryx11sDr#nJHC>TYj=)E2?){^!Ahy@R5=VXpN3v{ z#7r4nwDl;d>SLt3%qv6%vFmk{8;+^&P2`~WlF(%yraz1ikG}o#OR%yilHz5oHwqQg zH!1nvo`>Azj_%2nE_H!U>nuPN+L3Yy(-l}jM~$8bwQUYM(>~dZf|6x5s4y4ncJr9y zO=jhB!~B(cG6uO!X*v!vpJt5GdrUNsn;1A;e>Ct0VcnSgJNr~zf}o2<>MTa83_V-G zqWD1ZS#x-#Vse@JErq;&Dxc6*c}v-3g%U_aarZdEz^cm7I`5?$ZmNx))f!TC2$kDR zcicTeF#qM!H~W}J%kQ8Lfh`qYW5pt-yT9DjfnwGF94-t!G*ti0)i zJnLroCK$PW1Z=(*5mj6Hbpo@$9HiIw9S+kfR%(^c5i81J8l)*KC@z!H@7s>c8vHuz z4^!iD(3fVUQ5&xo`af03$*tRV_Z9&;1`r2B)Cmz-v`*K8;G*I*z>kATA>?e> z7$v(h(V;Pl?MBeBABq|#vmHAga=NhSn>b@Q>mouyKd<$1^*6e*l@68F*Oz0a%Meo? z9tJKDA2Jb>T=C7b{M+HvOS{UZYU0&d2de@Tw_vrJObEhOFXIx>!mYE$&J{liZ{X_2Ren z_?^H*@U^-VIGNn4P)wCaTu6)7eV!3>gB?FR@O-npa~qdTwA$!Md8oh*x}pf8e^A1j z;E7?-!pSS`Uvq)-1yBYkptNMfL$>jf-<&b=j8~V>l8Ae#l!#No?TrUP)7X0&u(x93 zMMR)RWngFJZiiyCXS%}&J(2bz!IrR9sPr{I;xGq!%$L(LCd#^G_d9{(G3@MNEWT~` z^Amf2YJNcBewbMyPc}$zUVJSJUJDrnxoi>@`nO)tJ4m z1Q2)WezdRGJGqTyMMiJ zl)=+S5xi;^87|{Ro-#VFj>Y56hiC|-tl3LY04Yc5^GI1ap3n%rypqn9j5O&f}n zMzs9k8T$O<{IWm#AY9QJnl+2`KV~o%w;^g&QAQ-iC{YypZ4w8AQ94+(ivb9owQbY? z2{spn1W^$r;GTn_yW$63tPv=jy%52Arrf+y|HbeD@$bqFRZu#d^=G1B1R4OK_$TGI zu(7u`vH8=bGjO)Bv;A|X8QA`>f~#)WZm=WzT&qo5)|&&Xw;XyM!tAa)Vq4F{Wq=Ox z&Lh)&OBN0&!s#6Pe1|WOq;rTH4ktknGn<~wB4GJ6x}Etr+kwDmrTkHfKl}#FAW`^3 zL`e#p9O^bfUgY~KB0+hE`iz{Em$}Mu60x(P4W`dnn>-pQw+gdJD>_=m6mgLjn*7Fx zIY27ikhsN!-;mQGGbU6)ddS%`)0jc#Mxp>iZV$-9AC4)1H3QUgld_99s(Af^%Abr~ z?FQx=V4Z2xzUp;z;@Hxq@g!4b8jAw211=n(o?jL$`E8a?zxKW&!n|I9$IT_f zhgn?LbQ6Pz-aVl#b|ohjE$zr7S=9+!e|VS@!)jo8%(^t-Hr-ko6S6TOE5K&Q>Et6I z*y1#1AR^T-fa4b<2HArvX8D+7i7Wprawrq(DC?A zUg8hOvtLXRa1UMOrLRfgu^myxwWtX5L#etZUr%DkO| znMtjSu4i@90UIMyqImm!R~PBeb0Vn28K!K>JVRt9GIU+K|8$`&ojw7p9i-#7`Jw56 zq-X$x+@NhK>!%|*FMaBAWMc`0kq~m!kt3`9Y0=1B#5Kq(myelqc*_}xxy2diLwICa z?cXGX;#yp%WN;B*PON7>!=l3_uu$j?V9Hbpc~VR%xn?gVA26zJg@IFDmkCF<4nrhJ zOkXP|?CXzzZE^U;#1qb$&pp=}l!r-jUaw6IZ};vZyFER zQNU%Am?olr3MiHxLJBazwF$y7ix+MpRJ+RC@fTY^8)RQp+I~j3&VgrQsc@fbRMPJJ#$)5i94-5nWnyQ z-SfrP#*)2aYYM13v*|z+ri_OOJ*P%U=k%e>oGvO-1m0pOufyk$=N{yyzXn1U#}eef z88o!q!D($scm_H&guZUH+sJ-?^_#b2hshZ7uGN#7E=Q+oBQazv?k9+XJ*qqr+ZbuW z-sRiaaX5MdzP%e}Zshqre273!sQ@at(QY{zV_$A}6s5kv^$GlfXR@8j{AN`{dolL38+2`)L*)8OF9{qee}pajU&1De=rf}xeU@5=M535L z6Vd^Qpyl^(V#RsRkEL>ypy@b7o+!3nf}FKGD?O6pZ0uT1Ich2ci=5YXHJ#2%U;0)0 z_;`NxoC)_!h7$eS^Z_u|V0?8mNdRPq#H(nF5$sh0V|zSp=ceVh&%7U1?0tm;`g10k z6+W1fiCd`A3n~3K_dW!Y`pBy-QRT{AvDVV~djV9eO1o%9DS4CCuzbjpCuLCQ;x*k0F^sgsE6 zST8iInsX8=Y_=J6dR|Ek(y}19$3X zHL=e3ZY_HnLry}Kbm%;kC!zSpIJdsnju5?@%7qYB$x^?8uk47J8%Qp+&v(=K7&%B~_N2vR9*6;dvN%9x07TwhM_youzw(TfVF%`i_X@OH0 zu!@U8-~*K5e8dar;@{XfRS+Y-MMfd>ZBR@+$btlj{Puoi5zP=Opw0l@c!KR>N`6yY z7DZ*Rf#xdUU<91x)BcpLM7LZ#AXoBLK^!w8?p=}~Wah~Jw&PXO*wKXFK3|p75kal` zb!;~BjF}K0eo!*>RZT}zQ(6W;op0Hm53fCTT8FU}2h*NIplH zvF?UW#$B536pv#f8QCivkAHE7kalx-is$+g%#L1<9_#Ti&bWV!OUF>QLkLHYsmy)(k_YF5(m)YXHwiZuxJr}FF#m$RPEOAvwg*M(hM&)Ns) zMWKXE*E71-En;seV~j()_DWOl1ws$jlm;}LbE>8ESgp>Th|Bveq$ncHSR|e`lqm*3 zmuUgHr1IojyG%=jdxC2tBUWiEGyrB|vmEQrS~h#={ONw{Wa(}qG9fe)TLhg;cgH?j zXBBtL>X0r)S*<-uF(m2jo?tcuIg{_I>|L3`E{#7;q8Ir0$@wPCv z?+pc&^v8^evnruG`;!xPZa)Oog;f8bu^<)@?QD?opT7tpV6EIT%k`O)EYz#H zHhuQ%&K0^EH*{nyfIyKpJ@B9K2hA#eA#XQ|JDgO%8txl;&$LHmHXM`Wgh_LBsnt*dG*P$=y2tpto z{Y@&RO`%hf6H}u#pR9M5{Aib|2PimSovIPD|7_~v_-JYfRg!sOGj8xJeh_WaAxW6$ z!&xE$B`T^$@97==cO{l2Ls)~yvnOX}d;;ZQ#^hU2->>})Vp9`|qZL`Z^=^yFhOz|$ zx9nGMUkOc(UtsrAfp>v5=-Oh9ndzlzI_`aWd~LtHLN#_^I#yoNS$k8k>v8%emF;L= zqNx(0mVv)E#DWN`*R15IFl+XH_(n3)QRiEJyAM za+Hn}Jb)YTy(GeD5HL1L)={;WR}(g|i>5d(4jK%hS9#Hqey4MKmi>ca!N7iV*a>**FL3yi; zQYHDC#nSIDI~D(3aBO*Jz*yR7_RuyTw&aOJkh!%Db3WAP*V^>}s&yX>=oT8=-O%Ha zl#6LOb=X@2jSe$(^ z%%_$qw)ky=qTKG6f`bfRYF1mo6}epI=*K+ndX-*I=xzMyk})A@p?O>789vJmalCmu zgfiWq?t}`j{6^H1xi>+~~A?zLnm`DdT^YuKd6kOf$?D> z!>xQ7?rfRtpyZ9eJH^Ma5!k9&h%}oNM9NxRkb0UjPcE&;reS@l>;BA+T7R5lwp=MC zjh6Q=GK4ELxn$29Lz~@WsTf`!jD698%NST%Y#^bE0C1nOmw8_`dD6G%&ggb`X3OmK ze#|`EUGYj^+g)!*uS2R19M2u{p4_AyjM0b~3efC*W25w@Su*NV%4)d2MbyzW##v(R zAee`(*Jn)LRSMy|`5v6)6m0~)BVX~I0sB(fG;LZ0cs-m&iuI(h<;kEWlU?pFn`V5^Z(yUE` zxid{B%lD8%O9y(73GHdAWBNX?jLzimt%KBkX*pYLOy}tWc<&JgDrI|V(m?fl2%Jfv zY-v;Ol@(;I$Qa)Fp1jr<<>fgvy=TEbcAMb3i2hIRW^wcy-5_W&5+PP4^XeU&^&3T@g3E%EmmcJ@L9z2I7ad;UHuVj(;O3*|G7h2~4dsZPSK5&_@1 zl9y78H}d*w=$QjlCW>NMH%kiy#|Kpnh+N&UpFcBw-EI1A41>mQxo=oAC2fD#^rk0a zT(P528i5nhC|LJGcVW|mFh@Fvi$W)Rr&48w$l7}m$Gn-mmzDBw=+%FL{bl%!|0J`W z=9b{5e^Oa+B;i@ObQJbe&Cifu)su&1KFzCDSrl0C{?^t z5G%1NeYGX(Ep6%j)&0cciUL`4WedX|MeSSKaukKhwd9J0zoNL|VOtxW1>vyMu{9te z&4j~-1JRJuLpHIKzx6SCZl>&4z(5ua4Pk8*d$#xUh^TlGo0;K~u_Nmg7yLEUtF zQNZb+)Ag_Q|8zOx@2r0sS^kR^_or_7N7la$F#jj-Kc{N`;_>|1fPduuZN}#Bw14U( z{zXg0{;#yZ^%eil`={o`Up(hOCDLEN?!UJ({!aX-7QkOb|L=b%{+EWpf8zc#m--9G zN%{}C|CUnyC-y&U!N0J$RR4he_sZ};VgG64{({xg{R8a3n7Y4H|4F_6qQbNMo%&z3 ZOkN7?Prn%efcf(_{nLGJX8qTv{{uyFhYkP$ diff --git a/good-html/.claude-plugin/plugin.json b/good-html/.claude-plugin/plugin.json index 71d2f00..02cf29c 100644 --- a/good-html/.claude-plugin/plugin.json +++ b/good-html/.claude-plugin/plugin.json @@ -1,9 +1,12 @@ { "name": "good-html", "version": "1.0.0", - "description": "Generate high-density, interactive, self-contained HTML artifacts based on Thariq Shihipar's patterns. Optimized for engineering tasks, PR reviews, and research reports.", + "description": "Generate or review high-density, interactive, self-contained HTML artifacts based on Thariq Shihipar's patterns.", "author": { - "name": "Gemini CLI" + "name": "duyet", + "url": "https://github.com/duyet" }, + "license": "MIT", + "homepage": "https://github.com/duyet/codex-claude-plugins/tree/master/good-html", "logo": "./assets/logo.svg" } diff --git a/good-html/.codex-plugin/plugin.json b/good-html/.codex-plugin/plugin.json index 946c946..ed14af1 100644 --- a/good-html/.codex-plugin/plugin.json +++ b/good-html/.codex-plugin/plugin.json @@ -1,16 +1,21 @@ { "name": "good-html", "version": "1.0.0", - "description": "Generate high-density, interactive, self-contained HTML artifacts based on Thariq Shihipar's patterns. Optimized for engineering tasks, PR reviews, and research reports.", + "description": "Generate or review high-density, interactive, self-contained HTML artifacts based on Thariq Shihipar's patterns.", "author": { - "name": "Gemini CLI" + "name": "duyet", + "url": "https://github.com/duyet" }, + "license": "MIT", + "skills": "./skills/", "interface": { "displayName": "Good HTML", - "shortDescription": "High-density interactive HTML artifacts.", - "developerName": "Gemini CLI", - "category": "Development", - "capabilities": ["Skill"], + "shortDescription": "Generate or review high-density, interactive, self-contained HTML artifacts based on Thariq Shihipar's patterns.", + "developerName": "duyet", + "category": "Design", + "capabilities": [ + "Skill" + ], "logo": "./assets/logo.svg", "composerIcon": "./assets/logo.svg" } diff --git a/good-html/.cursor-plugin/plugin.json b/good-html/.cursor-plugin/plugin.json new file mode 100644 index 0000000..7c9e683 --- /dev/null +++ b/good-html/.cursor-plugin/plugin.json @@ -0,0 +1,15 @@ +{ + "name": "good-html", + "version": "1.0.0", + "description": "Generate or review high-density, interactive, self-contained HTML artifacts based on Thariq Shihipar's patterns.", + "author": { + "name": "duyet" + }, + "license": "MIT", + "displayName": "Good HTML", + "homepage": "https://github.com/duyet/codex-claude-plugins/tree/master/good-html", + "repository": "https://github.com/duyet/codex-claude-plugins", + "logo": "./assets/logo.svg", + "category": "Design", + "skills": "./skills/" +} diff --git a/good-html/.grok-build-plugin/plugin.json b/good-html/.grok-build-plugin/plugin.json index cb81623..af2bbea 100644 --- a/good-html/.grok-build-plugin/plugin.json +++ b/good-html/.grok-build-plugin/plugin.json @@ -1,18 +1,23 @@ { "name": "good-html", "version": "1.0.0", - "description": "Generate high-density, interactive, self-contained HTML artifacts based on Thariq Shihipar's patterns. Optimized for engineering tasks, PR reviews, and research reports.", + "description": "Generate or review high-density, interactive, self-contained HTML artifacts based on Thariq Shihipar's patterns.", "author": { - "name": "Gemini CLI" + "name": "duyet", + "url": "https://github.com/duyet" }, + "license": "MIT", + "logo": "./assets/logo.svg", + "skills": "./skills/", "interface": { "displayName": "Good HTML", - "shortDescription": "High-density interactive HTML artifacts.", - "developerName": "Gemini CLI", - "category": "Development", - "capabilities": ["Skill"], + "shortDescription": "Generate or review high-density, interactive, self-contained HTML artifacts based on Thariq Shihipar's patterns.", + "developerName": "duyet", + "category": "Design", + "capabilities": [ + "Skill" + ], "logo": "./assets/logo.svg", "composerIcon": "./assets/logo.svg" - }, - "logo": "assets/logo.svg" + } } diff --git a/good-html/.grok-plugin/plugin.json b/good-html/.grok-plugin/plugin.json index 3d5b603..896a768 100644 --- a/good-html/.grok-plugin/plugin.json +++ b/good-html/.grok-plugin/plugin.json @@ -1,10 +1,15 @@ { "name": "good-html", "version": "1.0.0", - "description": "Generate high-density, interactive, self-contained HTML artifacts based on Thariq Shihipar's patterns. Optimized for engineering tasks, PR reviews, and research reports.", + "description": "Generate or review high-density, interactive, self-contained HTML artifacts based on Thariq Shihipar's patterns.", "author": { - "name": "Gemini CLI" + "name": "duyet", + "url": "https://github.com/duyet" }, - "logo": "assets/logo.svg", - "keywords": ["good-html", "grok", "grok-build", "grok-bot"] + "license": "MIT", + "logo": "./assets/logo.svg", + "keywords": [ + "good-html" + ], + "skills": "./skills/" } diff --git a/good-html/SKILL.md b/good-html/skills/good-html/SKILL.md similarity index 100% rename from good-html/SKILL.md rename to good-html/skills/good-html/SKILL.md diff --git a/good-html/references/components.md b/good-html/skills/good-html/references/components.md similarity index 100% rename from good-html/references/components.md rename to good-html/skills/good-html/references/components.md diff --git a/good-html/references/page_types.md b/good-html/skills/good-html/references/page_types.md similarity index 100% rename from good-html/references/page_types.md rename to good-html/skills/good-html/references/page_types.md diff --git a/good-html/references/patterns.md b/good-html/skills/good-html/references/patterns.md similarity index 100% rename from good-html/references/patterns.md rename to good-html/skills/good-html/references/patterns.md diff --git a/good-html/references/styles.md b/good-html/skills/good-html/references/styles.md similarity index 100% rename from good-html/references/styles.md rename to good-html/skills/good-html/references/styles.md diff --git a/interview/.claude-plugin/plugin.json b/interview/.claude-plugin/plugin.json index 8872eb2..2168e7a 100644 --- a/interview/.claude-plugin/plugin.json +++ b/interview/.claude-plugin/plugin.json @@ -1,10 +1,12 @@ { "name": "interview", "version": "1.0.1", - "description": "Conduct in-depth requirements interviews using Socratic questioning to clarify implementation details before coding", + "description": "Conduct in-depth requirements interviews using Socratic questioning", "author": { "name": "duyet", - "email": "me@duyet.net" + "url": "https://github.com/duyet" }, + "license": "MIT", + "homepage": "https://github.com/duyet/codex-claude-plugins/tree/master/interview", "logo": "./assets/logo.svg" } diff --git a/interview/.codex-plugin/plugin.json b/interview/.codex-plugin/plugin.json index 31c3eab..a0cbdd5 100644 --- a/interview/.codex-plugin/plugin.json +++ b/interview/.codex-plugin/plugin.json @@ -1,19 +1,23 @@ { "name": "interview", "version": "1.0.1", - "description": "Conduct in-depth requirements interviews using Socratic questioning to clarify implementation details before coding", + "description": "Conduct in-depth requirements interviews using Socratic questioning", "author": { "name": "duyet", - "email": "me@duyet.net" + "url": "https://github.com/duyet" }, + "license": "MIT", "skills": "./skills/", "commands": "./commands/", "interface": { "displayName": "Interview", - "shortDescription": "Conduct in-depth requirements interviews using Socratic questioning to clarify implementation details before coding", + "shortDescription": "Conduct in-depth requirements interviews using Socratic questioning", "developerName": "duyet", "category": "Productivity", - "capabilities": ["Skill", "Command"], + "capabilities": [ + "Skill", + "Command" + ], "logo": "./assets/logo.svg", "composerIcon": "./assets/logo.svg" } diff --git a/interview/.cursor-plugin/plugin.json b/interview/.cursor-plugin/plugin.json new file mode 100644 index 0000000..713e8ac --- /dev/null +++ b/interview/.cursor-plugin/plugin.json @@ -0,0 +1,16 @@ +{ + "name": "interview", + "version": "1.0.1", + "description": "Conduct in-depth requirements interviews using Socratic questioning", + "author": { + "name": "duyet" + }, + "license": "MIT", + "displayName": "Interview", + "homepage": "https://github.com/duyet/codex-claude-plugins/tree/master/interview", + "repository": "https://github.com/duyet/codex-claude-plugins", + "logo": "./assets/logo.svg", + "category": "Productivity", + "skills": "./skills/", + "commands": "./commands/" +} diff --git a/interview/.grok-build-plugin/plugin.json b/interview/.grok-build-plugin/plugin.json index 13af744..e44dee1 100644 --- a/interview/.grok-build-plugin/plugin.json +++ b/interview/.grok-build-plugin/plugin.json @@ -1,21 +1,25 @@ { "name": "interview", "version": "1.0.1", - "description": "Conduct in-depth requirements interviews using Socratic questioning to clarify implementation details before coding", + "description": "Conduct in-depth requirements interviews using Socratic questioning", "author": { "name": "duyet", - "email": "me@duyet.net" + "url": "https://github.com/duyet" }, + "license": "MIT", + "logo": "./assets/logo.svg", "skills": "./skills/", "commands": "./commands/", "interface": { "displayName": "Interview", - "shortDescription": "Conduct in-depth requirements interviews using Socratic questioning to clarify implementation details before coding", + "shortDescription": "Conduct in-depth requirements interviews using Socratic questioning", "developerName": "duyet", "category": "Productivity", - "capabilities": ["Skill", "Command"], + "capabilities": [ + "Skill", + "Command" + ], "logo": "./assets/logo.svg", "composerIcon": "./assets/logo.svg" - }, - "logo": "assets/logo.svg" + } } diff --git a/interview/.grok-plugin/plugin.json b/interview/.grok-plugin/plugin.json index 589ce7b..f49afdd 100644 --- a/interview/.grok-plugin/plugin.json +++ b/interview/.grok-plugin/plugin.json @@ -1,13 +1,16 @@ { "name": "interview", "version": "1.0.1", - "description": "Conduct in-depth requirements interviews using Socratic questioning to clarify implementation details before coding", + "description": "Conduct in-depth requirements interviews using Socratic questioning", "author": { "name": "duyet", - "email": "me@duyet.net" + "url": "https://github.com/duyet" }, - "logo": "assets/logo.svg", - "keywords": ["interview", "grok", "grok-build", "grok-bot"], + "license": "MIT", + "logo": "./assets/logo.svg", + "keywords": [ + "interview" + ], "skills": "./skills/", "commands": "./commands/" } diff --git a/interview/CLAUDE.md b/interview/CLAUDE.md deleted file mode 100644 index 6de9182..0000000 --- a/interview/CLAUDE.md +++ /dev/null @@ -1,56 +0,0 @@ -# Interview Plugin - -Conduct in-depth requirements interviews using Socratic questioning to clarify implementation details before coding - -## Versioning - -Follow semantic versioning (semver) for this plugin: - -| Change Type | Version Bump | Example | -|-------------|--------------|---------| -| Bug fix, docs | Patch | 1.0.0 → 1.0.1 | -| New feature, minor change | Minor | 1.0.0 → 1.1.0 | -| Breaking change | Major | 1.0.0 → 2.0.0 | - -**When to bump:** -- Adding new commands, skills, or agents → **Minor** -- Modifying existing behavior → **Minor** (or Major if breaking) -- Updating documentation only → **Patch** -- Bug fixes → **Patch** - -Always update `plugin.json` version when making changes. - -## Plugin Structure - -``` -interview/ -├── .claude-plugin/ -│ └── plugin.json # Manifest (version 1.0.0) -├── agents/ # Sub-agent definitions -├── commands/ # Slash commands -├── skills/ # Reusable knowledge -└── hooks/hooks.json # Lifecycle hooks (optional) -``` - -## Components - -### Commands - - - `/interview`: Conduct in-depth requirements interview using Socratic questioning to clarify implementation details - - -## Commit Convention - -Use semantic commits with plugin scope: - -``` -feat(interview): add new feature -fix(interview): fix bug -docs(interview): update documentation -``` - -Co-author: `Co-Authored-By: duyetbot ` - ---- - -**Generated by docs-generator v1.0.0** diff --git a/kb/.claude-plugin/plugin.json b/kb/.claude-plugin/plugin.json index 4cca588..879bddc 100644 --- a/kb/.claude-plugin/plugin.json +++ b/kb/.claude-plugin/plugin.json @@ -6,8 +6,7 @@ "name": "duyet", "url": "https://github.com/duyet" }, - "homepage": "https://github.com/duyet/codex-claude-plugins", - "repository": "https://github.com/duyet/codex-claude-plugins", "license": "MIT", + "homepage": "https://github.com/duyet/codex-claude-plugins/tree/master/kb", "logo": "./assets/logo.svg" } diff --git a/kb/.codex-plugin/plugin.json b/kb/.codex-plugin/plugin.json index 1c1b13e..dfd552c 100644 --- a/kb/.codex-plugin/plugin.json +++ b/kb/.codex-plugin/plugin.json @@ -3,19 +3,21 @@ "version": "1.1.0", "description": "Knowledge base maintenance skills. Initialize a shared-brain kb, then consolidate, dedupe, prune, refresh, and forget notes in a markdown KB.", "author": { - "name": "duyet" + "name": "duyet", + "url": "https://github.com/duyet" }, + "license": "MIT", "skills": "./skills/", "commands": "./commands/", "interface": { "displayName": "Knowledge Base", - "shortDescription": "Initialize and maintain a markdown knowledge base: consolidate, dedupe, prune, and forget notes.", + "shortDescription": "Knowledge base maintenance skills. Initialize a shared-brain kb, then consolidate, dedupe, prune, refresh, and forget notes in a markdown KB.", "developerName": "duyet", - "category": "productivity", - "capabilities": ["Skill", "Command"], - "links": { - "homepage": "https://github.com/duyet/codex-claude-plugins" - }, + "category": "Productivity", + "capabilities": [ + "Skill", + "Command" + ], "logo": "./assets/logo.svg", "composerIcon": "./assets/logo.svg" } diff --git a/kb/.cursor-plugin/plugin.json b/kb/.cursor-plugin/plugin.json new file mode 100644 index 0000000..ec9e4af --- /dev/null +++ b/kb/.cursor-plugin/plugin.json @@ -0,0 +1,16 @@ +{ + "name": "kb", + "version": "1.1.0", + "description": "Knowledge base maintenance skills. Initialize a shared-brain kb, then consolidate, dedupe, prune, refresh, and forget notes in a markdown KB.", + "author": { + "name": "duyet" + }, + "license": "MIT", + "displayName": "Knowledge Base", + "homepage": "https://github.com/duyet/codex-claude-plugins/tree/master/kb", + "repository": "https://github.com/duyet/codex-claude-plugins", + "logo": "./assets/logo.svg", + "category": "Productivity", + "skills": "./skills/", + "commands": "./commands/" +} diff --git a/kb/.grok-build-plugin/plugin.json b/kb/.grok-build-plugin/plugin.json index 31a05cc..763df65 100644 --- a/kb/.grok-build-plugin/plugin.json +++ b/kb/.grok-build-plugin/plugin.json @@ -3,21 +3,23 @@ "version": "1.1.0", "description": "Knowledge base maintenance skills. Initialize a shared-brain kb, then consolidate, dedupe, prune, refresh, and forget notes in a markdown KB.", "author": { - "name": "duyet" + "name": "duyet", + "url": "https://github.com/duyet" }, + "license": "MIT", + "logo": "./assets/logo.svg", "skills": "./skills/", "commands": "./commands/", "interface": { "displayName": "Knowledge Base", - "shortDescription": "Initialize and maintain a markdown knowledge base: consolidate, dedupe, prune, and forget notes.", + "shortDescription": "Knowledge base maintenance skills. Initialize a shared-brain kb, then consolidate, dedupe, prune, refresh, and forget notes in a markdown KB.", "developerName": "duyet", - "category": "productivity", - "capabilities": ["Skill", "Command"], - "links": { - "homepage": "https://github.com/duyet/codex-claude-plugins" - }, + "category": "Productivity", + "capabilities": [ + "Skill", + "Command" + ], "logo": "./assets/logo.svg", "composerIcon": "./assets/logo.svg" - }, - "logo": "assets/logo.svg" + } } diff --git a/kb/.grok-plugin/plugin.json b/kb/.grok-plugin/plugin.json index 82aa339..dabde7e 100644 --- a/kb/.grok-plugin/plugin.json +++ b/kb/.grok-plugin/plugin.json @@ -7,10 +7,10 @@ "url": "https://github.com/duyet" }, "license": "MIT", - "homepage": "https://github.com/duyet/codex-claude-plugins", - "repository": "https://github.com/duyet/codex-claude-plugins", - "logo": "assets/logo.svg", - "keywords": ["kb", "grok", "grok-build", "grok-bot"], + "logo": "./assets/logo.svg", + "keywords": [ + "kb" + ], "skills": "./skills/", "commands": "./commands/" } diff --git a/marketplace.json b/marketplace.json index 8daafe9..f69f600 100644 --- a/marketplace.json +++ b/marketplace.json @@ -1,250 +1,159 @@ { "name": "duyet-claude-plugins", - "description": "A collection of production-quality plugins for Claude Code, Codex, Grok Build, and Grok Bot including autonomous agents, workflow automation, and developer tools.", - "version": "1.1.0", + "displayName": "Duyet Claude, Codex, Cursor, and Grok Plugins", + "description": "Plugins for Claude Code, Codex, Cursor, Grok Build, and Grok Bot: agent workflows, git automation, and developer tools.", + "version": "2.0.0", "author": { "name": "duyet", "url": "https://github.com/duyet" }, - "repository": { - "url": "https://github.com/duyet/codex-claude-plugins", - "branch": "master" - }, "plugins": [ { "name": "team-agents", - "id": "team-agents@duyet-claude-plugins", + "displayName": "Team Agents", "description": "Leader, Senior Engineer, and Junior Engineer agents for coordinated parallel task execution", "version": "1.9.1", - "type": "skill", - "category": "agents", - "logo": "./team-agents/assets/logo.svg" + "category": "Agents" }, { "name": "commit", - "id": "commit@duyet-claude-plugins", + "displayName": "Commit", "description": "Create a Git commit with semantic commit message format and PR workflow with templates", "version": "1.3.2", - "type": "command", - "category": "git", - "logo": "./commit/assets/logo.svg" + "category": "Git" }, { "name": "frontend-design", - "id": "frontend-design@duyet-claude-plugins", + "displayName": "Frontend Design", "description": "Create distinctive, production-grade frontend interfaces avoiding AI slop aesthetics", "version": "1.4.0", - "type": "skill", - "category": "design", - "logo": "./frontend-design/assets/logo.svg" + "category": "Design" }, { "name": "interview", - "id": "interview@duyet-claude-plugins", + "displayName": "Interview", "description": "Conduct in-depth requirements interviews using Socratic questioning", "version": "1.0.1", - "type": "command", - "category": "productivity", - "logo": "./interview/assets/logo.svg" + "category": "Productivity" }, { "name": "statusline", - "id": "statusline@duyet-claude-plugins", + "displayName": "Statusline", "description": "Configurable status bar showing context usage, API rate limits, git branch, and active tools", "version": "1.9.0", - "type": "hook", - "category": "ui", - "logo": "./statusline/assets/logo.svg" + "category": "UI" }, { "name": "orchestration", - "id": "orchestration@duyet-claude-plugins", + "displayName": "Orchestration", "description": "Orchestrator skill for managing parallel agent workstreams", "version": "1.1.0", - "type": "skill", - "category": "agents", - "logo": "./orchestration/assets/logo.svg" - }, - { - "name": "duyetbot", - "id": "duyetbot@duyet-claude-plugins", - "description": "Pragmatic software development companion with engineering discipline", - "version": "1.8.1", - "type": "skill", - "category": "productivity", - "logo": "./duyetbot/assets/logo.svg" - }, - { - "name": "docs-generator", - "id": "docs-generator@duyet-claude-plugins", - "description": "Automatically generate and maintain plugin documentation", - "version": "1.0.1", - "type": "hook", - "category": "docs", - "logo": "./docs-generator/assets/logo.svg" + "category": "Agents" }, { "name": "github", - "id": "github@duyet-claude-plugins", + "displayName": "GitHub", "description": "GitHub operations using gh CLI - PRs, issues, workflows, batch operations, PR babysitting with AI review bot integration, and smart branch detection", "version": "1.4.2", - "type": "skill", - "category": "git", - "logo": "./github/assets/logo.svg" + "category": "Git" }, { "name": "fix", - "id": "fix@duyet-claude-plugins", + "displayName": "Fix", "description": "Fix issues, tests, and CI failures with intelligent problem detection", "version": "1.0.1", - "type": "command", - "category": "productivity", - "logo": "./fix/assets/logo.svg" - }, - { - "name": "simplify", - "id": "simplify@duyet-claude-plugins", - "description": "Review changed code for reuse, quality, and efficiency, then simplify issues found", - "version": "1.0.1", - "type": "command", - "category": "productivity", - "logo": "./simplify/assets/logo.svg" + "category": "Productivity" }, { "name": "clickhouse", - "id": "clickhouse@duyet-claude-plugins", + "displayName": "Clickhouse", "description": "Comprehensive ClickHouse knowledge base from Altinity KB + official docs", "version": "1.4.1", - "type": "skill", - "category": "database", - "logo": "./clickhouse/assets/logo.svg" + "category": "Database" }, { "name": "prompt-engineering", - "id": "prompt-engineering@duyet-claude-plugins", + "displayName": "Prompt Engineering", "description": "Prompt engineering techniques for Grok, Claude, and Gemini LLMs", "version": "1.1.1", - "type": "skill", - "category": "productivity", - "logo": "./prompt-engineering/assets/logo.svg" + "category": "Productivity" }, { "name": "clickhouse-monitoring", - "id": "clickhouse-monitoring@duyet-claude-plugins", + "displayName": "Clickhouse Monitoring", "description": "Agent Skill for the ClickHouse Monitor dashboard - a real-time monitoring and observability tool for ClickHouse clusters", "version": "1.1.1", - "type": "skill", - "category": "monitoring", - "logo": "./clickhouse-monitoring/assets/logo.svg" + "category": "Monitoring" }, { "name": "unsloth-training", - "id": "unsloth-training@duyet-claude-plugins", + "displayName": "Unsloth Training", "description": "Fine-tune LLMs with Unsloth using GRPO or SFT. Dataset prep, synthetic data, environment flags, MLX (Apple Silicon), FP8, vision, mobile export, GGUF.", "version": "1.0.2", - "type": "skill", - "category": "ml", - "logo": "./unsloth-training/assets/logo.svg" + "category": "ML" }, { "name": "good-html", - "id": "good-html@duyet-claude-plugins", + "displayName": "Good HTML", "description": "Generate or review high-density, interactive, self-contained HTML artifacts based on Thariq Shihipar's patterns.", "version": "1.0.0", - "type": "skill", - "category": "design", - "logo": "./good-html/assets/logo.svg" + "category": "Design" }, { "name": "anyrouter", - "id": "anyrouter@duyet-claude-plugins", + "displayName": "AnyRouter", "description": "Wire AnyRouter into coding agents. Universal OpenAI-compatible LLM gateway for 150+ models, migration recipes from Anthropic/OpenAI/OpenRouter, and a remote MCP server for keys and credits.", "version": "1.0.1", - "type": "skill", - "category": "ai", - "logo": "./anyrouter/assets/logo.svg" + "category": "AI" }, { "name": "sag-notify", - "id": "sag-notify@duyet-claude-plugins", + "displayName": "sag-notify", "description": "Spoken voice notifications via sag (ElevenLabs TTS): skill-driven, Claude calls sag directly to speak a short alert just before it asks you something and a one-line summary when work finishes, naming the project. Configurable voice and language.", "version": "2.1.2", - "type": "skill", - "category": "ui", - "logo": "./sag-notify/assets/logo.svg" + "category": "UI" }, { "name": "build-macos-apps", - "id": "build-macos-apps@duyet-claude-plugins", + "displayName": "Build macOS Apps", "description": "Build, debug, instrument, and implement macOS apps with SwiftUI and AppKit guidance, codesigning, packaging, and telemetry workflows.", "version": "1.0.1", - "type": "skill", - "category": "development", - "logo": "./build-macos-apps/assets/logo.svg" + "category": "Development" }, { "name": "build-ios-apps", - "id": "build-ios-apps@duyet-claude-plugins", + "displayName": "Build iOS Apps", "description": "Build, profile, debug, and refine iOS apps with SwiftUI and Xcode workflows — App Intents, Simulator debugging, performance profiling, memory leak detection, and on-device AI with Apple Intelligence, Foundation Models, and Core AI.", "version": "1.0.1", - "type": "skill", - "category": "development", - "logo": "./build-ios-apps/assets/logo.svg" + "category": "Development" }, { "name": "agent-loop", - "id": "agent-loop@duyet-claude-plugins", + "displayName": "Agent Loop", "description": "Continuous agent loop for overnight/day repository maintenance. Orchestrates triage, autoreview, browser automation, and parallel agent work across threads. Wake every 5 min, direct work, land autonomously.", "version": "0.4.0", - "type": "skill", - "category": "automation", - "logo": "./agent-loop/assets/logo.svg" + "category": "Automation" }, { "name": "kb", - "id": "kb@duyet-claude-plugins", + "displayName": "Knowledge Base", "description": "Knowledge base maintenance skills. Initialize a shared-brain kb, then consolidate, dedupe, prune, refresh, and forget notes in a markdown KB.", "version": "1.1.0", - "type": "skill", - "category": "productivity", - "logo": "./kb/assets/logo.svg" + "category": "Productivity" }, { "name": "okf", - "id": "okf@duyet-claude-plugins", + "displayName": "Open Knowledge Format", "description": "Open Knowledge Format (OKF) tooling. Author, initialize, validate, render, and refactor knowledge into vendor-neutral OKF v0.1 bundles: markdown files with YAML frontmatter.", "version": "1.1.0", - "type": "skill", - "category": "productivity", - "logo": "./okf/assets/logo.svg" + "category": "Productivity" }, { "name": "command-code", - "id": "command-code@duyet-claude-plugins", + "displayName": "Command Code", "description": "Drive the Command Code CLI (`cmd`) and orchestrate it as a headless sub-agent — fan out `cmd -p --yolo --max-turns 100000` workers across isolated git worktrees to implement issues and tasks in parallel.", "version": "1.0.0", - "type": "skill", - "category": "development", - "logo": "./command-code/assets/logo.svg" + "category": "Development" } - ], - "metadata": { - "lastUpdated": "2026-09-02", - "totalPlugins": 24, - "categories": [ - "agents", - "git", - "design", - "productivity", - "ui", - "docs", - "database", - "monitoring", - "ml", - "ai", - "development", - "automation" - ], - "logo": "./assets/logo.svg" - } + ] } diff --git a/okf/.claude-plugin/plugin.json b/okf/.claude-plugin/plugin.json index 41aaddb..6b29903 100644 --- a/okf/.claude-plugin/plugin.json +++ b/okf/.claude-plugin/plugin.json @@ -6,8 +6,7 @@ "name": "duyet", "url": "https://github.com/duyet" }, - "homepage": "https://github.com/duyet/codex-claude-plugins", - "repository": "https://github.com/duyet/codex-claude-plugins", "license": "MIT", + "homepage": "https://github.com/duyet/codex-claude-plugins/tree/master/okf", "logo": "./assets/logo.svg" } diff --git a/okf/.codex-plugin/plugin.json b/okf/.codex-plugin/plugin.json index faa6917..32b62b8 100644 --- a/okf/.codex-plugin/plugin.json +++ b/okf/.codex-plugin/plugin.json @@ -3,18 +3,19 @@ "version": "1.1.0", "description": "Open Knowledge Format (OKF) tooling. Author, initialize, validate, render, and refactor knowledge into vendor-neutral OKF v0.1 bundles: markdown files with YAML frontmatter.", "author": { - "name": "duyet" + "name": "duyet", + "url": "https://github.com/duyet" }, + "license": "MIT", "skills": "./skills/", "interface": { "displayName": "Open Knowledge Format", - "shortDescription": "Author, validate, render, and refactor knowledge into OKF v0.1 bundles (markdown + YAML frontmatter).", + "shortDescription": "Open Knowledge Format (OKF) tooling. Author, initialize, validate, render, and refactor knowledge into vendor-neutral OKF v0.1 bundles: markdown files with YAML frontmatter.", "developerName": "duyet", - "category": "productivity", - "capabilities": ["Skill"], - "links": { - "homepage": "https://github.com/duyet/codex-claude-plugins" - }, + "category": "Productivity", + "capabilities": [ + "Skill" + ], "logo": "./assets/logo.svg", "composerIcon": "./assets/logo.svg" } diff --git a/okf/.cursor-plugin/plugin.json b/okf/.cursor-plugin/plugin.json new file mode 100644 index 0000000..9df10c1 --- /dev/null +++ b/okf/.cursor-plugin/plugin.json @@ -0,0 +1,15 @@ +{ + "name": "okf", + "version": "1.1.0", + "description": "Open Knowledge Format (OKF) tooling. Author, initialize, validate, render, and refactor knowledge into vendor-neutral OKF v0.1 bundles: markdown files with YAML frontmatter.", + "author": { + "name": "duyet" + }, + "license": "MIT", + "displayName": "Open Knowledge Format", + "homepage": "https://github.com/duyet/codex-claude-plugins/tree/master/okf", + "repository": "https://github.com/duyet/codex-claude-plugins", + "logo": "./assets/logo.svg", + "category": "Productivity", + "skills": "./skills/" +} diff --git a/okf/.grok-build-plugin/plugin.json b/okf/.grok-build-plugin/plugin.json index 9574661..228cec8 100644 --- a/okf/.grok-build-plugin/plugin.json +++ b/okf/.grok-build-plugin/plugin.json @@ -3,20 +3,21 @@ "version": "1.1.0", "description": "Open Knowledge Format (OKF) tooling. Author, initialize, validate, render, and refactor knowledge into vendor-neutral OKF v0.1 bundles: markdown files with YAML frontmatter.", "author": { - "name": "duyet" + "name": "duyet", + "url": "https://github.com/duyet" }, + "license": "MIT", + "logo": "./assets/logo.svg", "skills": "./skills/", "interface": { "displayName": "Open Knowledge Format", - "shortDescription": "Author, validate, render, and refactor knowledge into OKF v0.1 bundles (markdown + YAML frontmatter).", + "shortDescription": "Open Knowledge Format (OKF) tooling. Author, initialize, validate, render, and refactor knowledge into vendor-neutral OKF v0.1 bundles: markdown files with YAML frontmatter.", "developerName": "duyet", - "category": "productivity", - "capabilities": ["Skill"], - "links": { - "homepage": "https://github.com/duyet/codex-claude-plugins" - }, + "category": "Productivity", + "capabilities": [ + "Skill" + ], "logo": "./assets/logo.svg", "composerIcon": "./assets/logo.svg" - }, - "logo": "assets/logo.svg" + } } diff --git a/okf/.grok-plugin/plugin.json b/okf/.grok-plugin/plugin.json index 69c02f1..fe1a66c 100644 --- a/okf/.grok-plugin/plugin.json +++ b/okf/.grok-plugin/plugin.json @@ -7,9 +7,9 @@ "url": "https://github.com/duyet" }, "license": "MIT", - "homepage": "https://github.com/duyet/codex-claude-plugins", - "repository": "https://github.com/duyet/codex-claude-plugins", - "logo": "assets/logo.svg", - "keywords": ["okf", "grok", "grok-build", "grok-bot"], + "logo": "./assets/logo.svg", + "keywords": [ + "okf" + ], "skills": "./skills/" } diff --git a/orchestration/.claude-plugin/plugin.json b/orchestration/.claude-plugin/plugin.json index abc0c2b..c1726f0 100644 --- a/orchestration/.claude-plugin/plugin.json +++ b/orchestration/.claude-plugin/plugin.json @@ -1,9 +1,12 @@ { "name": "orchestration", - "description": "Orchestrator skill for managing parallel agent workstreams. Transform complex requests into coordinated multi-agent execution with elegant result synthesis.", "version": "1.1.0", + "description": "Orchestrator skill for managing parallel agent workstreams", "author": { - "name": "duyet" + "name": "duyet", + "url": "https://github.com/duyet" }, + "license": "MIT", + "homepage": "https://github.com/duyet/codex-claude-plugins/tree/master/orchestration", "logo": "./assets/logo.svg" } diff --git a/orchestration/.codex-plugin/plugin.json b/orchestration/.codex-plugin/plugin.json index 548df04..068cc1e 100644 --- a/orchestration/.codex-plugin/plugin.json +++ b/orchestration/.codex-plugin/plugin.json @@ -1,17 +1,21 @@ { "name": "orchestration", "version": "1.1.0", - "description": "Orchestrator skill for managing parallel agent workstreams. Transform complex requests into coordinated multi-agent execution with elegant result synthesis.", + "description": "Orchestrator skill for managing parallel agent workstreams", "author": { - "name": "duyet" + "name": "duyet", + "url": "https://github.com/duyet" }, + "license": "MIT", "skills": "./skills/", "interface": { "displayName": "Orchestration", - "shortDescription": "Orchestrator skill for managing parallel agent workstreams. Transform complex requests into coordinated multi-agent execution with elegant result synthesis.", + "shortDescription": "Orchestrator skill for managing parallel agent workstreams", "developerName": "duyet", "category": "Agents", - "capabilities": ["Skill"], + "capabilities": [ + "Skill" + ], "logo": "./assets/logo.svg", "composerIcon": "./assets/logo.svg" } diff --git a/orchestration/.cursor-plugin/plugin.json b/orchestration/.cursor-plugin/plugin.json new file mode 100644 index 0000000..404850f --- /dev/null +++ b/orchestration/.cursor-plugin/plugin.json @@ -0,0 +1,15 @@ +{ + "name": "orchestration", + "version": "1.1.0", + "description": "Orchestrator skill for managing parallel agent workstreams", + "author": { + "name": "duyet" + }, + "license": "MIT", + "displayName": "Orchestration", + "homepage": "https://github.com/duyet/codex-claude-plugins/tree/master/orchestration", + "repository": "https://github.com/duyet/codex-claude-plugins", + "logo": "./assets/logo.svg", + "category": "Agents", + "skills": "./skills/" +} diff --git a/orchestration/.grok-build-plugin/plugin.json b/orchestration/.grok-build-plugin/plugin.json index a89ef2f..c35fc59 100644 --- a/orchestration/.grok-build-plugin/plugin.json +++ b/orchestration/.grok-build-plugin/plugin.json @@ -1,19 +1,23 @@ { "name": "orchestration", "version": "1.1.0", - "description": "Orchestrator skill for managing parallel agent workstreams. Transform complex requests into coordinated multi-agent execution with elegant result synthesis.", + "description": "Orchestrator skill for managing parallel agent workstreams", "author": { - "name": "duyet" + "name": "duyet", + "url": "https://github.com/duyet" }, + "license": "MIT", + "logo": "./assets/logo.svg", "skills": "./skills/", "interface": { "displayName": "Orchestration", - "shortDescription": "Orchestrator skill for managing parallel agent workstreams. Transform complex requests into coordinated multi-agent execution with elegant result synthesis.", + "shortDescription": "Orchestrator skill for managing parallel agent workstreams", "developerName": "duyet", "category": "Agents", - "capabilities": ["Skill"], + "capabilities": [ + "Skill" + ], "logo": "./assets/logo.svg", "composerIcon": "./assets/logo.svg" - }, - "logo": "assets/logo.svg" + } } diff --git a/orchestration/.grok-plugin/plugin.json b/orchestration/.grok-plugin/plugin.json index ea44b2d..5923312 100644 --- a/orchestration/.grok-plugin/plugin.json +++ b/orchestration/.grok-plugin/plugin.json @@ -1,11 +1,15 @@ { "name": "orchestration", "version": "1.1.0", - "description": "Orchestrator skill for managing parallel agent workstreams. Transform complex requests into coordinated multi-agent execution with elegant result synthesis.", + "description": "Orchestrator skill for managing parallel agent workstreams", "author": { - "name": "duyet" + "name": "duyet", + "url": "https://github.com/duyet" }, - "logo": "assets/logo.svg", - "keywords": ["orchestration", "grok", "grok-build", "grok-bot"], + "license": "MIT", + "logo": "./assets/logo.svg", + "keywords": [ + "orchestration" + ], "skills": "./skills/" } diff --git a/orchestration/CLAUDE.md b/orchestration/CLAUDE.md deleted file mode 100644 index 81df5a8..0000000 --- a/orchestration/CLAUDE.md +++ /dev/null @@ -1,56 +0,0 @@ -# Orchestration Plugin - -Orchestrator skill for managing parallel agent workstreams. Transform complex requests into coordinated multi-agent execution with elegant result synthesis. - -## Versioning - -Follow semantic versioning (semver) for this plugin: - -| Change Type | Version Bump | Example | -|-------------|--------------|---------| -| Bug fix, docs | Patch | 1.0.0 → 1.0.1 | -| New feature, minor change | Minor | 1.0.0 → 1.1.0 | -| Breaking change | Major | 1.0.0 → 2.0.0 | - -**When to bump:** -- Adding new commands, skills, or agents → **Minor** -- Modifying existing behavior → **Minor** (or Major if breaking) -- Updating documentation only → **Patch** -- Bug fixes → **Patch** - -Always update `plugin.json` version when making changes. - -## Plugin Structure - -``` -orchestration/ -├── .claude-plugin/ -│ └── plugin.json # Manifest (version 1.0.0) -├── agents/ # Sub-agent definitions -├── commands/ # Slash commands -├── skills/ # Reusable knowledge -└── hooks/hooks.json # Lifecycle hooks (optional) -``` - -## Components - -### Skills - - - **orchestration** - - -## Commit Convention - -Use semantic commits with plugin scope: - -``` -feat(orchestration): add new feature -fix(orchestration): fix bug -docs(orchestration): update documentation -``` - -Co-author: `Co-Authored-By: duyetbot ` - ---- - -**Generated by docs-generator v1.0.0** diff --git a/prompt-engineering/.claude-plugin/plugin.json b/prompt-engineering/.claude-plugin/plugin.json index 26d4ea5..fb19d51 100644 --- a/prompt-engineering/.claude-plugin/plugin.json +++ b/prompt-engineering/.claude-plugin/plugin.json @@ -1,9 +1,12 @@ { "name": "prompt-engineering", "version": "1.1.1", - "description": "Prompt engineering skills for Grok, Claude, and Gemini LLMs with model-specific guidance and universal techniques", + "description": "Prompt engineering techniques for Grok, Claude, and Gemini LLMs", "author": { - "name": "duyetbot" + "name": "duyet", + "url": "https://github.com/duyet" }, + "license": "MIT", + "homepage": "https://github.com/duyet/codex-claude-plugins/tree/master/prompt-engineering", "logo": "./assets/logo.svg" } diff --git a/prompt-engineering/.codex-plugin/plugin.json b/prompt-engineering/.codex-plugin/plugin.json index 716515a..297fb8c 100644 --- a/prompt-engineering/.codex-plugin/plugin.json +++ b/prompt-engineering/.codex-plugin/plugin.json @@ -1,17 +1,21 @@ { "name": "prompt-engineering", "version": "1.1.1", - "description": "Prompt engineering skills for Grok, Claude, and Gemini LLMs with model-specific guidance and universal techniques", + "description": "Prompt engineering techniques for Grok, Claude, and Gemini LLMs", "author": { - "name": "duyetbot" + "name": "duyet", + "url": "https://github.com/duyet" }, + "license": "MIT", "skills": "./skills/", "interface": { "displayName": "Prompt Engineering", - "shortDescription": "Prompt engineering skills for Grok, Claude, and Gemini LLMs with model-specific guidance and universal techniques", - "developerName": "duyetbot", + "shortDescription": "Prompt engineering techniques for Grok, Claude, and Gemini LLMs", + "developerName": "duyet", "category": "Productivity", - "capabilities": ["Skill"], + "capabilities": [ + "Skill" + ], "logo": "./assets/logo.svg", "composerIcon": "./assets/logo.svg" } diff --git a/prompt-engineering/.cursor-plugin/plugin.json b/prompt-engineering/.cursor-plugin/plugin.json new file mode 100644 index 0000000..f5515ef --- /dev/null +++ b/prompt-engineering/.cursor-plugin/plugin.json @@ -0,0 +1,15 @@ +{ + "name": "prompt-engineering", + "version": "1.1.1", + "description": "Prompt engineering techniques for Grok, Claude, and Gemini LLMs", + "author": { + "name": "duyet" + }, + "license": "MIT", + "displayName": "Prompt Engineering", + "homepage": "https://github.com/duyet/codex-claude-plugins/tree/master/prompt-engineering", + "repository": "https://github.com/duyet/codex-claude-plugins", + "logo": "./assets/logo.svg", + "category": "Productivity", + "skills": "./skills/" +} diff --git a/prompt-engineering/.grok-build-plugin/plugin.json b/prompt-engineering/.grok-build-plugin/plugin.json index 3843262..1556ea2 100644 --- a/prompt-engineering/.grok-build-plugin/plugin.json +++ b/prompt-engineering/.grok-build-plugin/plugin.json @@ -1,19 +1,23 @@ { "name": "prompt-engineering", "version": "1.1.1", - "description": "Prompt engineering skills for Grok, Claude, and Gemini LLMs with model-specific guidance and universal techniques", + "description": "Prompt engineering techniques for Grok, Claude, and Gemini LLMs", "author": { - "name": "duyetbot" + "name": "duyet", + "url": "https://github.com/duyet" }, + "license": "MIT", + "logo": "./assets/logo.svg", "skills": "./skills/", "interface": { "displayName": "Prompt Engineering", - "shortDescription": "Prompt engineering skills for Grok, Claude, and Gemini LLMs with model-specific guidance and universal techniques", - "developerName": "duyetbot", + "shortDescription": "Prompt engineering techniques for Grok, Claude, and Gemini LLMs", + "developerName": "duyet", "category": "Productivity", - "capabilities": ["Skill"], + "capabilities": [ + "Skill" + ], "logo": "./assets/logo.svg", "composerIcon": "./assets/logo.svg" - }, - "logo": "assets/logo.svg" + } } diff --git a/prompt-engineering/.grok-plugin/plugin.json b/prompt-engineering/.grok-plugin/plugin.json index 9295966..ada009b 100644 --- a/prompt-engineering/.grok-plugin/plugin.json +++ b/prompt-engineering/.grok-plugin/plugin.json @@ -1,11 +1,15 @@ { "name": "prompt-engineering", "version": "1.1.1", - "description": "Prompt engineering skills for Grok, Claude, and Gemini LLMs with model-specific guidance and universal techniques", + "description": "Prompt engineering techniques for Grok, Claude, and Gemini LLMs", "author": { - "name": "duyetbot" + "name": "duyet", + "url": "https://github.com/duyet" }, - "logo": "assets/logo.svg", - "keywords": ["prompt-engineering", "grok", "grok-build", "grok-bot"], + "license": "MIT", + "logo": "./assets/logo.svg", + "keywords": [ + "prompt-engineering" + ], "skills": "./skills/" } diff --git a/sag-notify/.claude-plugin/plugin.json b/sag-notify/.claude-plugin/plugin.json index 271caaf..4bdf4ea 100644 --- a/sag-notify/.claude-plugin/plugin.json +++ b/sag-notify/.claude-plugin/plugin.json @@ -1,9 +1,12 @@ { "name": "sag-notify", "version": "2.1.2", - "description": "Spoken voice notifications via sag (ElevenLabs TTS). Skill-driven: Claude calls sag directly to speak a short alert just before it asks you something, and a one-line summary when work finishes — naming the project. Configurable voice and language.", + "description": "Spoken voice notifications via sag (ElevenLabs TTS): skill-driven, Claude calls sag directly to speak a short alert just before it asks you something and a one-line summary when work finishes, naming the project. Configurable voice and language.", "author": { - "name": "duyet" + "name": "duyet", + "url": "https://github.com/duyet" }, + "license": "MIT", + "homepage": "https://github.com/duyet/codex-claude-plugins/tree/master/sag-notify", "logo": "./assets/logo.svg" } diff --git a/sag-notify/.codex-plugin/plugin.json b/sag-notify/.codex-plugin/plugin.json index 7b4100f..b2ad91c 100644 --- a/sag-notify/.codex-plugin/plugin.json +++ b/sag-notify/.codex-plugin/plugin.json @@ -1,18 +1,23 @@ { "name": "sag-notify", "version": "2.1.2", - "description": "Spoken voice notifications via sag (ElevenLabs TTS). Skill-driven: Claude calls sag directly to speak a short alert just before it asks you something, and a one-line summary when work finishes — naming the project. Configurable voice and language.", + "description": "Spoken voice notifications via sag (ElevenLabs TTS): skill-driven, Claude calls sag directly to speak a short alert just before it asks you something and a one-line summary when work finishes, naming the project. Configurable voice and language.", "author": { - "name": "duyet" + "name": "duyet", + "url": "https://github.com/duyet" }, + "license": "MIT", "skills": "./skills/", "commands": "./commands/", "interface": { "displayName": "sag-notify", - "shortDescription": "Spoken voice notifications via sag (ElevenLabs TTS). Claude speaks a short alert before asking you something and a one-line summary when work finishes.", + "shortDescription": "Spoken voice notifications via sag (ElevenLabs TTS): skill-driven, Claude calls sag directly to speak a short alert just before it asks you something and a one-line summary when work finishes, naming the project. Configurable voice and language.", "developerName": "duyet", "category": "UI", - "capabilities": ["Skill", "Command"], + "capabilities": [ + "Skill", + "Command" + ], "logo": "./assets/logo.svg", "composerIcon": "./assets/logo.svg" } diff --git a/sag-notify/.cursor-plugin/plugin.json b/sag-notify/.cursor-plugin/plugin.json new file mode 100644 index 0000000..d0faa04 --- /dev/null +++ b/sag-notify/.cursor-plugin/plugin.json @@ -0,0 +1,16 @@ +{ + "name": "sag-notify", + "version": "2.1.2", + "description": "Spoken voice notifications via sag (ElevenLabs TTS): skill-driven, Claude calls sag directly to speak a short alert just before it asks you something and a one-line summary when work finishes, naming the project. Configurable voice and language.", + "author": { + "name": "duyet" + }, + "license": "MIT", + "displayName": "sag-notify", + "homepage": "https://github.com/duyet/codex-claude-plugins/tree/master/sag-notify", + "repository": "https://github.com/duyet/codex-claude-plugins", + "logo": "./assets/logo.svg", + "category": "UI", + "skills": "./skills/", + "commands": "./commands/" +} diff --git a/sag-notify/.grok-build-plugin/plugin.json b/sag-notify/.grok-build-plugin/plugin.json index ad47eea..821d773 100644 --- a/sag-notify/.grok-build-plugin/plugin.json +++ b/sag-notify/.grok-build-plugin/plugin.json @@ -1,20 +1,25 @@ { "name": "sag-notify", "version": "2.1.2", - "description": "Spoken voice notifications via sag (ElevenLabs TTS). Skill-driven: Claude calls sag directly to speak a short alert just before it asks you something, and a one-line summary when work finishes — naming the project. Configurable voice and language.", + "description": "Spoken voice notifications via sag (ElevenLabs TTS): skill-driven, Claude calls sag directly to speak a short alert just before it asks you something and a one-line summary when work finishes, naming the project. Configurable voice and language.", "author": { - "name": "duyet" + "name": "duyet", + "url": "https://github.com/duyet" }, + "license": "MIT", + "logo": "./assets/logo.svg", "skills": "./skills/", "commands": "./commands/", "interface": { "displayName": "sag-notify", - "shortDescription": "Spoken voice notifications via sag (ElevenLabs TTS). Claude speaks a short alert before asking you something and a one-line summary when work finishes.", + "shortDescription": "Spoken voice notifications via sag (ElevenLabs TTS): skill-driven, Claude calls sag directly to speak a short alert just before it asks you something and a one-line summary when work finishes, naming the project. Configurable voice and language.", "developerName": "duyet", "category": "UI", - "capabilities": ["Skill", "Command"], + "capabilities": [ + "Skill", + "Command" + ], "logo": "./assets/logo.svg", "composerIcon": "./assets/logo.svg" - }, - "logo": "assets/logo.svg" + } } diff --git a/sag-notify/.grok-plugin/plugin.json b/sag-notify/.grok-plugin/plugin.json index ca50473..d14ae07 100644 --- a/sag-notify/.grok-plugin/plugin.json +++ b/sag-notify/.grok-plugin/plugin.json @@ -1,12 +1,16 @@ { "name": "sag-notify", "version": "2.1.2", - "description": "Spoken voice notifications via sag (ElevenLabs TTS). Skill-driven: Claude calls sag directly to speak a short alert just before it asks you something, and a one-line summary when work finishes — naming the project. Configurable voice and language.", + "description": "Spoken voice notifications via sag (ElevenLabs TTS): skill-driven, Claude calls sag directly to speak a short alert just before it asks you something and a one-line summary when work finishes, naming the project. Configurable voice and language.", "author": { - "name": "duyet" + "name": "duyet", + "url": "https://github.com/duyet" }, - "logo": "assets/logo.svg", - "keywords": ["sag-notify", "grok", "grok-build", "grok-bot"], + "license": "MIT", + "logo": "./assets/logo.svg", + "keywords": [ + "sag-notify" + ], "skills": "./skills/", "commands": "./commands/" } diff --git a/scripts/plugins.py b/scripts/plugins.py new file mode 100644 index 0000000..e1a6bb5 --- /dev/null +++ b/scripts/plugins.py @@ -0,0 +1,247 @@ +#!/usr/bin/env python3 +"""Generate every harness manifest from marketplace.json, and lint plugins. + + python3 scripts/plugins.py sync # rewrite generated manifests + python3 scripts/plugins.py check # fail on drift or broken plugins + +marketplace.json is the only hand-edited manifest. Each plugin entry holds +name, displayName, description, version, category. +""" + +import json +import re +import sys +from pathlib import Path + +ROOT = Path(__file__).resolve().parent.parent +REGISTRY = ROOT / "marketplace.json" +REPO_URL = "https://github.com/duyet/codex-claude-plugins" +LICENSE = "MIT" +LOGO = "./assets/logo.svg" +COMPONENTS = { + "skills": ("skills", "Skill"), + "commands": ("commands", "Command"), + "agents": ("agents", "Agent"), +} +FRONTMATTER = re.compile(r"\A---\n(.*?)\n---\n", re.S) +LOCAL_REF = re.compile(r"\]\(((?:\./)?(?:references|scripts|assets|templates|rules)/[^)#\s]+)\)") + + +def components(plugin_dir): + found = {key: f"./{sub}/" for key, (sub, _) in COMPONENTS.items() if (plugin_dir / sub).is_dir()} + if (plugin_dir / "hooks" / "hooks.json").is_file(): + found["hooks"] = "./hooks/hooks.json" + if (plugin_dir / ".mcp.json").is_file(): + found["mcpServers"] = "./.mcp.json" + return found + + +def capabilities(found): + caps = [label for key, (_, label) in COMPONENTS.items() if key in found] + caps += [label for key, label in (("hooks", "Hook"), ("mcpServers", "MCP")) if key in found] + return caps + + +def plugin_manifests(entry, author): + name = entry["name"] + plugin_dir = ROOT / name + found = components(plugin_dir) + base = { + "name": name, + "version": entry["version"], + "description": entry["description"], + "author": author, + "license": LICENSE, + } + interface = { + "displayName": entry["displayName"], + "shortDescription": entry["description"], + "developerName": author["name"], + "category": entry["category"], + "capabilities": capabilities(found), + "logo": LOGO, + "composerIcon": LOGO, + } + paths = {k: v for k, v in found.items() if k != "hooks"} + out = { + ".claude-plugin/plugin.json": {**base, "homepage": f"{REPO_URL}/tree/master/{name}", "logo": LOGO}, + ".codex-plugin/plugin.json": {**base, **paths, "interface": interface}, + ".grok-plugin/plugin.json": {**base, "logo": LOGO, "keywords": [name], **paths}, + ".grok-build-plugin/plugin.json": {**base, "logo": LOGO, **paths, "interface": interface}, + ".cursor-plugin/plugin.json": { + **base, + "author": {"name": author["name"]}, + "displayName": entry["displayName"], + "homepage": f"{REPO_URL}/tree/master/{name}", + "repository": REPO_URL, + "logo": LOGO, + "category": entry["category"], + **paths, + }, + } + if (plugin_dir / ".antigravity-plugin").is_dir(): + out[".antigravity-plugin/plugin.json"] = {**base, **found, "interface": interface} + return {f"{name}/{rel}": data for rel, data in out.items()} + + +def marketplaces(registry): + owner = registry["author"] + name = registry["name"] + plugins = registry["plugins"] + return { + ".claude-plugin/marketplace.json": { + "name": name, + "owner": owner, + "metadata": {"description": registry["description"], "version": registry["version"]}, + "plugins": [ + { + "name": p["name"], + "source": f"./{p['name']}", + "description": p["description"], + "version": p["version"], + "category": p["category"], + "logo": f"./{p['name']}/assets/logo.svg", + } + for p in plugins + ], + }, + ".agents/plugins/marketplace.json": { + "name": name, + "interface": {"displayName": registry["displayName"], "logo": LOGO, "composerIcon": LOGO}, + "plugins": [ + { + "name": p["name"], + "source": {"source": "local", "path": f"./{p['name']}"}, + "policy": {"installation": "AVAILABLE", "authentication": "ON_INSTALL"}, + "category": p["category"], + "interface": { + "logo": f"./{p['name']}/assets/logo.svg", + "composerIcon": f"./{p['name']}/assets/logo.svg", + }, + } + for p in plugins + ], + }, + ".grok-plugin/marketplace.json": { + "name": name, + "description": registry["description"], + "owner": owner, + "plugins": [ + { + "name": p["name"], + "description": p["description"], + "category": p["category"], + "source": {"type": "local", "path": f"./{p['name']}"}, + "homepage": REPO_URL, + "keywords": [p["name"]], + "logo": "assets/logo.svg", + "version": p["version"], + "author": owner, + } + for p in plugins + ], + }, + ".cursor-plugin/marketplace.json": { + "name": name, + "owner": {"name": owner["name"]}, + "metadata": {"description": registry["description"]}, + "plugins": [ + {"name": p["name"], "source": p["name"], "description": p["description"]} for p in plugins + ], + }, + } + + +def generated(registry): + out = marketplaces(registry) + for entry in registry["plugins"]: + out.update(plugin_manifests(entry, registry["author"])) + return {path: json.dumps(data, indent=2, ensure_ascii=False) + "\n" for path, data in out.items()} + + +def lint(registry): + errors = [] + names = [p["name"] for p in registry["plugins"]] + dirs = sorted(p.parent.parent.name for p in ROOT.glob("*/.claude-plugin/plugin.json")) + if sorted(names) != dirs: + errors.append(f"registry plugins {sorted(names)} != plugin dirs {dirs}") + for entry in registry["plugins"]: + for field in ("name", "displayName", "description", "version", "category"): + if not isinstance(entry.get(field), str) or not entry[field].strip(): + errors.append(f"{entry.get('name')}: registry field '{field}' missing") + if not re.fullmatch(r"\d+\.\d+\.\d+", entry.get("version", "")): + errors.append(f"{entry['name']}: version must be X.Y.Z") + plugin_dir = ROOT / entry["name"] + if not (plugin_dir / "assets" / "logo.svg").is_file(): + errors.append(f"{entry['name']}: missing assets/logo.svg") + if not components(plugin_dir): + errors.append(f"{entry['name']}: no skills, commands, agents, hooks, or MCP servers") + errors += lint_plugin(plugin_dir) + return errors + + +def lint_plugin(plugin_dir): + errors = [] + skills = plugin_dir / "skills" + if skills.is_dir(): + for loose in skills.glob("*.md"): + errors.append(f"{loose.relative_to(ROOT)}: loose file in skills/, move it under a skill directory") + for skill_dir in sorted(p for p in skills.iterdir() if p.is_dir()): + skill_md = skill_dir / "SKILL.md" + if not skill_md.is_file(): + errors.append(f"{skill_dir.relative_to(ROOT)}: missing SKILL.md") + continue + meta = frontmatter(skill_md) + if meta.get("name") != skill_dir.name: + errors.append(f"{skill_md.relative_to(ROOT)}: frontmatter name {meta.get('name')!r} != dir {skill_dir.name!r}") + if not meta.get("description"): + errors.append(f"{skill_md.relative_to(ROOT)}: missing description") + for doc in plugin_dir.rglob("*.md"): + text = doc.read_text() + for ref in LOCAL_REF.findall(text): + if not (doc.parent / ref).exists(): + errors.append(f"{doc.relative_to(ROOT)}: broken link {ref}") + if "—" in text: + errors.append(f"{doc.relative_to(ROOT)}: contains an em dash") + for kind in ("commands", "agents"): + for doc in sorted((plugin_dir / kind).glob("*.md")): + if not frontmatter(doc).get("description"): + errors.append(f"{doc.relative_to(ROOT)}: missing description") + return errors + + +def frontmatter(path): + match = FRONTMATTER.match(path.read_text()) + if not match: + return {} + meta = {} + for line in match.group(1).splitlines(): + key, sep, value = line.partition(":") + if sep and not line.startswith((" ", "\t")): + meta[key.strip()] = value.strip().strip("\"'") + return meta + + +def main(mode): + registry = json.loads(REGISTRY.read_text()) + files = generated(registry) + if mode == "sync": + for path, text in files.items(): + target = ROOT / path + target.parent.mkdir(parents=True, exist_ok=True) + target.write_text(text) + print(f"wrote {len(files)} manifests") + return 0 + errors = [f"{p}: out of date, run 'python3 scripts/plugins.py sync'" for p, t in files.items() + if not (ROOT / p).is_file() or (ROOT / p).read_text() != t] + errors += lint(registry) + for err in errors: + print(f"FAIL {err}") + print(f"checked {len(registry['plugins'])} plugins, {len(errors)} problems") + return 1 if errors else 0 + + +if __name__ == "__main__": + if len(sys.argv) != 2 or sys.argv[1] not in ("sync", "check"): + sys.exit(__doc__) + sys.exit(main(sys.argv[1])) diff --git a/scripts/validate-plugins.sh b/scripts/validate-plugins.sh index c0d03ef..cdc3f02 100755 --- a/scripts/validate-plugins.sh +++ b/scripts/validate-plugins.sh @@ -1,395 +1,4 @@ #!/usr/bin/env bash -# Validate Claude, Codex, Antigravity, Grok, and Grok Build plugin -# manifests plus marketplace files. Exits 1 if any plugin or marketplace -# fails validation. - +# Fail when generated manifests drift from marketplace.json or a plugin is broken. set -euo pipefail - -REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" -FAILED=0 -CHECKED=0 -TMP_ERR="${TMPDIR:-/tmp}/plugin-validate-err.$$" -trap 'rm -f "$TMP_ERR"' EXIT - -validate_manifest() { - local manifest="$1" - local mode="$2" - local plugin_dir - plugin_dir="$(dirname "$(dirname "$manifest")")" - - python3 - "$manifest" "$plugin_dir" "$mode" <<'PYEOF' -import json -import os -import re -import sys - -manifest_path, plugin_dir, mode = sys.argv[1:4] -errors = [] - -try: - with open(manifest_path) as f: - data = json.load(f) -except Exception as exc: - print(f" - invalid JSON: {exc}", file=sys.stderr) - sys.exit(1) - -for field in ("name", "version", "description"): - if field not in data: - errors.append(f"missing required field: '{field}'") - elif not isinstance(data[field], str) or not data[field].strip(): - errors.append(f"'{field}' must be a non-empty string") - -if isinstance(data.get("version"), str) and not re.fullmatch(r"\d+\.\d+\.\d+", data["version"]): - errors.append(f"'version' must be semver (X.Y.Z), got: {data['version']!r}") - -author = data.get("author") -if author is None: - errors.append("missing required field: 'author'") -elif isinstance(author, str): - errors.append(f"'author' must be an object with a 'name' key, got string: {author!r}") -elif not isinstance(author, dict): - errors.append(f"'author' must be an object, got: {type(author).__name__}") -elif not isinstance(author.get("name"), str) or not author["name"].strip(): - errors.append("'author.name' must be a non-empty string") - -skills = data.get("skills") -if isinstance(skills, list): - for i, skill in enumerate(skills): - if not isinstance(skill, dict): - errors.append(f"skills[{i}]: must be an object") - continue - if not isinstance(skill.get("name"), str) or not skill["name"].strip(): - errors.append(f"skills[{i}]: missing 'name'") - if not isinstance(skill.get("description"), str) or not skill["description"].strip(): - errors.append(f"skills[{i}]: missing 'description'") - path_value = skill.get("path") - if path_value is not None: - if not isinstance(path_value, str): - errors.append(f"skills[{i}]: 'path' must be a string") - elif not os.path.isfile(os.path.join(plugin_dir, path_value)): - errors.append(f"skills[{i}]: path '{path_value}' does not exist") - -INTERFACE_MODES = ("codex", "antigravity", "grok-build") -PATH_MODES = ("codex", "antigravity", "grok", "grok-build") - -def resolve_asset(plugin_dir, value): - if not isinstance(value, str) or not value.strip(): - return None - if value.startswith(("http://", "https://")): - return value - return os.path.normpath(os.path.join(plugin_dir, value)) - -def require_local_logo(label, value): - if not isinstance(value, str) or not value.strip(): - errors.append(f"{label} must be a non-empty string") - return - if value.startswith(("http://", "https://")): - errors.append(f"{label} must be a repo-local path so it renders after install, got URL") - return - target = resolve_asset(plugin_dir, value) - if not os.path.isfile(target): - errors.append(f"{label} path does not exist: {value}") - -if mode in PATH_MODES: - for field in ("skills", "hooks", "mcpServers", "apps", "commands", "agents"): - value = data.get(field) - if value is None: - continue - if not isinstance(value, str) or not value.startswith("./"): - errors.append(f"'{field}' must be a relative string beginning with './'") - continue - target = os.path.normpath(os.path.join(plugin_dir, value)) - if not os.path.exists(target): - errors.append(f"'{field}' path does not exist: {value}") - -if mode in INTERFACE_MODES: - interface = data.get("interface") - if interface is None: - errors.append("missing required field: 'interface'") - elif not isinstance(interface, dict): - errors.append("'interface' must be an object") - else: - for field in ("displayName", "shortDescription", "developerName", "category"): - if not isinstance(interface.get(field), str) or not interface[field].strip(): - errors.append(f"'interface.{field}' must be a non-empty string") - capabilities = interface.get("capabilities") - if capabilities is not None: - if not isinstance(capabilities, list) or not all(isinstance(item, str) and item.strip() for item in capabilities): - errors.append("'interface.capabilities' must be an array of non-empty strings") - require_local_logo("interface.logo", interface.get("logo")) - require_local_logo("interface.composerIcon", interface.get("composerIcon")) - - mode_obj = data.get(mode) - if mode_obj is not None: - if not isinstance(mode_obj, dict): - errors.append(f"'{mode}' must be an object") - else: - for field in ("skills", "commands"): - val = mode_obj.get(field) - if val is not None: - if not isinstance(val, list) or not all(isinstance(item, str) and item.strip() for item in val): - errors.append(f"'{mode}.{field}' must be an array of non-empty strings") - -if mode in ("claude", "grok"): - require_local_logo("logo", data.get("logo")) -elif mode == "grok-build": - require_local_logo("logo", data.get("logo")) - -if errors: - for error in errors: - print(f" - {error}", file=sys.stderr) - sys.exit(1) -PYEOF -} - -check() { - local label="$1" - shift - CHECKED=$((CHECKED + 1)) - if "$@" 2>"$TMP_ERR"; then - echo "✅ $label" - else - echo "❌ $label" - while IFS= read -r line; do - echo " $line" - done <"$TMP_ERR" - FAILED=$((FAILED + 1)) - fi -} - -validate_cross_manifest() { - python3 - "$REPO_ROOT" <<'PYEOF' -import json -import os -import sys - -repo_root = sys.argv[1] -errors = [] - -plugin_dirs = sorted( - name for name in os.listdir(repo_root) - if ( - os.path.isfile(os.path.join(repo_root, name, ".claude-plugin", "plugin.json")) - or os.path.isfile(os.path.join(repo_root, name, ".codex-plugin", "plugin.json")) - or os.path.isfile(os.path.join(repo_root, name, ".grok-plugin", "plugin.json")) - or os.path.isfile(os.path.join(repo_root, name, ".grok-build-plugin", "plugin.json")) - ) -) - -def compare(label, other): - for field in ("name", "version", "description"): - if claude.get(field) != other.get(field): - errors.append(f"{plugin}: {field} differs between Claude and {label} manifests") - if claude.get("author", {}).get("name") != other.get("author", {}).get("name"): - errors.append(f"{plugin}: author.name differs between Claude and {label} manifests") - -for plugin in plugin_dirs: - claude_path = os.path.join(repo_root, plugin, ".claude-plugin", "plugin.json") - if not os.path.isfile(claude_path): - errors.append(f"{plugin}: missing .claude-plugin/plugin.json") - continue - with open(claude_path) as f: - claude = json.load(f) - - required_harnesses = ( - (".codex-plugin/plugin.json", "Codex"), - (".grok-plugin/plugin.json", "Grok"), - (".grok-build-plugin/plugin.json", "Grok Build"), - ) - for relpath, label in required_harnesses: - path = os.path.join(repo_root, plugin, relpath) - if not os.path.isfile(path): - errors.append(f"{plugin}: missing {relpath}") - continue - with open(path) as f: - compare(label, json.load(f)) - - antigravity_path = os.path.join(repo_root, plugin, ".antigravity-plugin", "plugin.json") - if os.path.isfile(antigravity_path): - with open(antigravity_path) as f: - compare("Antigravity", json.load(f)) - -if errors: - for error in errors: - print(f" - {error}", file=sys.stderr) - sys.exit(1) -PYEOF -} - -validate_marketplaces() { - python3 - "$REPO_ROOT" <<'PYEOF' -import json -import os -import sys - -repo_root = sys.argv[1] -errors = [] - -plugin_dirs = sorted( - name for name in os.listdir(repo_root) - if os.path.isfile(os.path.join(repo_root, name, ".claude-plugin", "plugin.json")) -) -plugin_set = set(plugin_dirs) - -def load_json(relpath): - try: - with open(os.path.join(repo_root, relpath)) as f: - return json.load(f) - except (FileNotFoundError, OSError, json.JSONDecodeError) as exc: - errors.append(f"{relpath}: {exc}") - return None - -def require(condition, message): - if not condition: - errors.append(message) - -root_marketplace = load_json("marketplace.json") -if root_marketplace is None: - root_marketplace = {"plugins": []} -root_names = [plugin.get("name") for plugin in root_marketplace.get("plugins", [])] -require(len(root_names) == len(set(root_names)), "marketplace.json contains duplicate plugin names") -require(set(root_names) == plugin_set, "marketplace.json plugin names must match plugin directories") -for plugin in root_marketplace.get("plugins", []): - name = plugin.get("name") - for field in ("name", "id", "description", "version", "type", "category"): - value = plugin.get(field) - require(isinstance(value, str) and value.strip(), f"marketplace.json {name}: missing {field}") - require(plugin.get("id") == f"{name}@{root_marketplace.get('name')}", f"marketplace.json {name}: id does not match marketplace name") - logo = plugin.get("logo") - require(isinstance(logo, str) and logo.strip(), f"marketplace.json {name}: missing logo") - if isinstance(logo, str) and not logo.startswith(("http://", "https://")): - require(os.path.isfile(os.path.normpath(os.path.join(repo_root, logo))), f"marketplace.json {name}: logo path does not exist") - -claude_marketplace = load_json(".claude-plugin/marketplace.json") -if claude_marketplace is None: - claude_marketplace = {"plugins": []} -claude_names = [plugin.get("name") for plugin in claude_marketplace.get("plugins", [])] -require(set(claude_names).issubset(plugin_set), ".claude-plugin/marketplace.json references unknown plugin") -for plugin in claude_marketplace.get("plugins", []): - name = plugin.get("name") - source = plugin.get("source") - require(isinstance(source, str) and source.startswith("./"), f".claude-plugin/marketplace.json {name}: source must be relative string") - if isinstance(source, str): - require(os.path.isdir(os.path.join(repo_root, source)), f".claude-plugin/marketplace.json {name}: source path does not exist") - logo = plugin.get("logo") - require(isinstance(logo, str) and logo.strip(), f".claude-plugin/marketplace.json {name}: missing logo") - if isinstance(logo, str) and not logo.startswith(("http://", "https://")): - require(os.path.isfile(os.path.normpath(os.path.join(repo_root, logo))), f".claude-plugin/marketplace.json {name}: logo path does not exist") - -codex_marketplace = load_json(".agents/plugins/marketplace.json") -if codex_marketplace is None: - codex_marketplace = {"plugins": []} -codex_names = [plugin.get("name") for plugin in codex_marketplace.get("plugins", [])] -require(len(codex_names) == len(set(codex_names)), ".agents/plugins/marketplace.json contains duplicate plugin names") -require(set(codex_names) == plugin_set, ".agents/plugins/marketplace.json plugin names must match plugin directories") -require(isinstance(codex_marketplace.get("interface", {}).get("displayName"), str), ".agents/plugins/marketplace.json missing interface.displayName") -for plugin in codex_marketplace.get("plugins", []): - name = plugin.get("name") - source = plugin.get("source") - policy = plugin.get("policy") - require(isinstance(source, dict), f".agents/plugins/marketplace.json {name}: source must be object") - if isinstance(source, dict): - require(source.get("source") == "local", f".agents/plugins/marketplace.json {name}: source.source must be local") - path_value = source.get("path") - require(isinstance(path_value, str) and path_value.startswith("./"), f".agents/plugins/marketplace.json {name}: source.path must be relative string") - if isinstance(path_value, str): - require(os.path.isdir(os.path.join(repo_root, path_value)), f".agents/plugins/marketplace.json {name}: source.path does not exist") - require(isinstance(policy, dict), f".agents/plugins/marketplace.json {name}: policy must be object") - if isinstance(policy, dict): - require(policy.get("installation") in {"NOT_AVAILABLE", "AVAILABLE", "INSTALLED_BY_DEFAULT"}, f".agents/plugins/marketplace.json {name}: invalid policy.installation") - require(policy.get("authentication") in {"ON_INSTALL", "ON_USE"}, f".agents/plugins/marketplace.json {name}: invalid policy.authentication") - category = plugin.get("category") - require(isinstance(category, str) and category.strip(), f".agents/plugins/marketplace.json {name}: missing category") - iface = plugin.get("interface") - require(isinstance(iface, dict), f".agents/plugins/marketplace.json {name}: missing interface") - if isinstance(iface, dict): - for field in ("logo", "composerIcon"): - value = iface.get(field) - require(isinstance(value, str) and value.strip(), f".agents/plugins/marketplace.json {name}: missing interface.{field}") - if isinstance(value, str) and not value.startswith(("http://", "https://")): - require(os.path.isfile(os.path.normpath(os.path.join(repo_root, value))), f".agents/plugins/marketplace.json {name}: interface.{field} path does not exist") - -codex_iface = codex_marketplace.get("interface", {}) -require(isinstance(codex_iface.get("logo"), str) and codex_iface["logo"].strip(), ".agents/plugins/marketplace.json missing interface.logo") -if isinstance(codex_iface.get("logo"), str) and not codex_iface["logo"].startswith(("http://", "https://")): - require(os.path.isfile(os.path.normpath(os.path.join(repo_root, codex_iface["logo"]))), ".agents/plugins/marketplace.json interface.logo path does not exist") - -grok_marketplace = load_json(".grok-plugin/marketplace.json") -if grok_marketplace is None: - grok_marketplace = {"plugins": []} -grok_names = [plugin.get("name") for plugin in grok_marketplace.get("plugins", [])] -require(len(grok_names) == len(set(grok_names)), ".grok-plugin/marketplace.json contains duplicate plugin names") -require(set(grok_names) == plugin_set, ".grok-plugin/marketplace.json plugin names must match plugin directories") -require(isinstance(grok_marketplace.get("owner", {}).get("name"), str), ".grok-plugin/marketplace.json missing owner.name") -for plugin in grok_marketplace.get("plugins", []): - name = plugin.get("name") - source = plugin.get("source") - require(isinstance(plugin.get("description"), str) and plugin["description"].strip(), f".grok-plugin/marketplace.json {name}: missing description") - require(isinstance(plugin.get("category"), str) and plugin["category"].strip(), f".grok-plugin/marketplace.json {name}: missing category") - require(isinstance(plugin.get("logo"), str) and plugin["logo"].strip(), f".grok-plugin/marketplace.json {name}: missing logo") - path_value = None - if isinstance(source, str) and source.startswith("./"): - path_value = source - elif isinstance(source, dict): - path_value = source.get("path") - require( - source.get("type") == "local" or source.get("source") == "local", - f".grok-plugin/marketplace.json {name}: source must be local", - ) - require(isinstance(path_value, str) and path_value.startswith("./"), f".grok-plugin/marketplace.json {name}: source path must be relative string") - if isinstance(path_value, str): - plugin_root = os.path.join(repo_root, path_value) - require(os.path.isdir(plugin_root), f".grok-plugin/marketplace.json {name}: source path does not exist") - logo = plugin.get("logo") - if isinstance(logo, str) and not logo.startswith(("http://", "https://")): - require(os.path.isfile(os.path.normpath(os.path.join(plugin_root, logo))), f".grok-plugin/marketplace.json {name}: logo path does not exist") - -if errors: - for error in errors: - print(f" - {error}", file=sys.stderr) - sys.exit(1) -PYEOF -} - -echo "Validating plugin manifests..." -echo "" - -while IFS= read -r -d '' manifest; do - plugin_dir="$(dirname "$(dirname "$manifest")")" - plugin_name="$(basename "$plugin_dir")" - check "Claude manifest: $plugin_name" validate_manifest "$manifest" claude -done < <(find "$REPO_ROOT" -path "*/.claude-plugin/plugin.json" -not -path "*/node_modules/*" -print0 | sort -z) - -while IFS= read -r -d '' manifest; do - plugin_dir="$(dirname "$(dirname "$manifest")")" - plugin_name="$(basename "$plugin_dir")" - check "Codex manifest: $plugin_name" validate_manifest "$manifest" codex -done < <(find "$REPO_ROOT" -path "*/.codex-plugin/plugin.json" -not -path "*/node_modules/*" -print0 | sort -z) - -while IFS= read -r -d '' manifest; do - plugin_dir="$(dirname "$(dirname "$manifest")")" - plugin_name="$(basename "$plugin_dir")" - check "Antigravity manifest: $plugin_name" validate_manifest "$manifest" antigravity -done < <(find "$REPO_ROOT" -path "*/.antigravity-plugin/plugin.json" -not -path "*/node_modules/*" -print0 | sort -z) - -while IFS= read -r -d '' manifest; do - plugin_dir="$(dirname "$(dirname "$manifest")")" - plugin_name="$(basename "$plugin_dir")" - check "Grok manifest: $plugin_name" validate_manifest "$manifest" grok -done < <(find "$REPO_ROOT" -path "*/.grok-plugin/plugin.json" -not -path "*/node_modules/*" -print0 | sort -z) - -while IFS= read -r -d '' manifest; do - plugin_dir="$(dirname "$(dirname "$manifest")")" - plugin_name="$(basename "$plugin_dir")" - check "Grok Build manifest: $plugin_name" validate_manifest "$manifest" grok-build -done < <(find "$REPO_ROOT" -path "*/.grok-build-plugin/plugin.json" -not -path "*/node_modules/*" -print0 | sort -z) - -check "Claude/Codex/Grok/Antigravity manifest parity" validate_cross_manifest -check "Marketplace files" validate_marketplaces - -echo "" -echo "Checked $CHECKED item(s). $FAILED failed." - -if [[ $FAILED -gt 0 ]]; then - exit 1 -fi +exec python3 "$(dirname "${BASH_SOURCE[0]}")/plugins.py" check diff --git a/simplify/.claude-plugin/plugin.json b/simplify/.claude-plugin/plugin.json deleted file mode 100644 index 55b9635..0000000 --- a/simplify/.claude-plugin/plugin.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "name": "simplify", - "description": "Review changed code for reuse, quality, and efficiency, then simplify issues found", - "version": "1.0.1", - "author": { - "name": "duyet" - }, - "logo": "./assets/logo.svg" -} diff --git a/simplify/.codex-plugin/plugin.json b/simplify/.codex-plugin/plugin.json deleted file mode 100644 index d65ea35..0000000 --- a/simplify/.codex-plugin/plugin.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "name": "simplify", - "version": "1.0.1", - "description": "Review changed code for reuse, quality, and efficiency, then simplify issues found", - "author": { - "name": "duyet" - }, - "skills": "./skills/", - "commands": "./commands/", - "interface": { - "displayName": "Simplify", - "shortDescription": "Review changed code for reuse, quality, and efficiency, then simplify issues found", - "developerName": "duyet", - "category": "Productivity", - "capabilities": ["Skill", "Command"], - "logo": "./assets/logo.svg", - "composerIcon": "./assets/logo.svg" - } -} diff --git a/simplify/.grok-build-plugin/plugin.json b/simplify/.grok-build-plugin/plugin.json deleted file mode 100644 index 05d6a5e..0000000 --- a/simplify/.grok-build-plugin/plugin.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "name": "simplify", - "version": "1.0.1", - "description": "Review changed code for reuse, quality, and efficiency, then simplify issues found", - "author": { - "name": "duyet" - }, - "skills": "./skills/", - "commands": "./commands/", - "interface": { - "displayName": "Simplify", - "shortDescription": "Review changed code for reuse, quality, and efficiency, then simplify issues found", - "developerName": "duyet", - "category": "Productivity", - "capabilities": ["Skill", "Command"], - "logo": "./assets/logo.svg", - "composerIcon": "./assets/logo.svg" - }, - "logo": "assets/logo.svg" -} diff --git a/simplify/.grok-plugin/plugin.json b/simplify/.grok-plugin/plugin.json deleted file mode 100644 index 8524ead..0000000 --- a/simplify/.grok-plugin/plugin.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "name": "simplify", - "version": "1.0.1", - "description": "Review changed code for reuse, quality, and efficiency, then simplify issues found", - "author": { - "name": "duyet" - }, - "logo": "assets/logo.svg", - "keywords": ["simplify", "grok", "grok-build", "grok-bot"], - "skills": "./skills/", - "commands": "./commands/" -} diff --git a/simplify/README.md b/simplify/README.md deleted file mode 100644 index 03513fe..0000000 --- a/simplify/README.md +++ /dev/null @@ -1,33 +0,0 @@ -# Simplify Plugin - -Review changed code for reuse, quality, and efficiency, then simplify issues found. - -## Installation - -```bash -/plugin install simplify@duyet-claude-plugins -``` - -## Usage - -```bash -/simplify:simplify -``` - -The command inspects the current diff, reviews it from three angles, fixes actionable issues, and summarizes what changed. - -## Structure - -``` -simplify/ -├── .claude-plugin/ -│ └── plugin.json -├── .codex-plugin/ -│ └── plugin.json -├── commands/ -│ └── simplify.md -├── skills/ -│ └── simplify/ -│ └── SKILL.md -└── README.md -``` diff --git a/simplify/assets/logo.svg b/simplify/assets/logo.svg deleted file mode 100644 index b18c35b..0000000 --- a/simplify/assets/logo.svg +++ /dev/null @@ -1 +0,0 @@ - Face/ 9 Nose/ 6 Mouth/ 0 Eyes/ 4 Eyebrows/ 0 Glasses/ 10 Accessories/ 0 Details/ 0 Beard/ 0 \ No newline at end of file diff --git a/simplify/commands/simplify.md b/simplify/commands/simplify.md deleted file mode 100644 index 0e91152..0000000 --- a/simplify/commands/simplify.md +++ /dev/null @@ -1,55 +0,0 @@ ---- -allowed-tools: [Read, Bash, Glob, Grep, TodoWrite, Edit, MultiEdit, Write, Task] -description: "Review changed code for reuse, quality, and efficiency, then simplify issues found" ---- - -# /simplify:simplify - Code Review and Cleanup - -Review all changed files for reuse, quality, and efficiency. Fix any issues found. - -## Phase 1: Identify Changes - -Run `git diff` or `git diff HEAD` if there are staged changes to see what changed. If there are no git changes, review the most recently modified files that the user mentioned or that you edited earlier in this conversation. - -## Phase 2: Launch Three Review Agents in Parallel - -Use the Task tool to launch all three agents concurrently in a single message. Pass each agent the full diff so it has the complete context. - -### Agent 1: Code Reuse Review - -For each change: - -1. Search for existing utilities and helpers that could replace newly written code. Look for similar patterns elsewhere in the codebase. Common locations are utility directories, shared modules, and files adjacent to the changed ones. -2. Flag any new function that duplicates existing functionality. Suggest the existing function to use instead. -3. Flag any inline logic that could use an existing utility, such as hand-rolled string manipulation, manual path handling, custom environment checks, ad-hoc type guards, and similar patterns. - -### Agent 2: Code Quality Review - -Review the same changes for hacky patterns: - -1. Redundant state: state that duplicates existing state, cached values that could be derived, observers/effects that could be direct calls -2. Parameter sprawl: adding new parameters to a function instead of generalizing or restructuring existing ones -3. Copy-paste with slight variation: near-duplicate code blocks that should be unified with a shared abstraction -4. Leaky abstractions: exposing internal details that should be encapsulated, or breaking existing abstraction boundaries -5. Stringly-typed code: using raw strings where constants, enums, string unions, or branded types already exist in the codebase -6. Unnecessary JSX nesting: wrapper Boxes/elements that add no layout value. Check if inner component props such as `flexShrink` or `alignItems` already provide the needed behavior. -7. Nested conditionals: ternary chains, nested if/else, or nested switch blocks 3+ levels deep. Flatten with early returns, guard clauses, a lookup table, or an if/else-if cascade. -8. Unnecessary comments: comments explaining what the code does, narrating the change, or referencing the task/caller. Delete those. Keep only non-obvious why comments for hidden constraints, subtle invariants, or workarounds. - -### Agent 3: Efficiency Review - -Review the same changes for efficiency: - -1. Unnecessary work: redundant computations, repeated file reads, duplicate network/API calls, N+1 patterns -2. Missed concurrency: independent operations run sequentially when they could run in parallel -3. Hot-path bloat: new blocking work added to startup or per-request/per-render hot paths -4. Recurring no-op updates: state/store updates inside polling loops, intervals, or event handlers that fire unconditionally. Add a change-detection guard so downstream consumers are not notified when nothing changed. If a wrapper function takes an updater/reducer callback, verify it honors same-reference returns or the local no-change signal. -5. Unnecessary existence checks: pre-checking file/resource existence before operating. Operate directly and handle the error. -6. Memory: unbounded data structures, missing cleanup, event listener leaks -7. Overly broad operations: reading entire files when only a portion is needed, loading all items when filtering for one - -## Phase 3: Fix Issues - -Wait for all three agents to complete. Aggregate their findings and fix each issue directly. If a finding is a false positive or not worth addressing, note it and move on. - -When done, briefly summarize what was fixed, or confirm the code was already clean. diff --git a/simplify/skills/simplify/SKILL.md b/simplify/skills/simplify/SKILL.md deleted file mode 100644 index 247a7c5..0000000 --- a/simplify/skills/simplify/SKILL.md +++ /dev/null @@ -1,55 +0,0 @@ ---- -name: simplify -description: Use when reviewing changed code for reuse, quality, and efficiency, then directly simplifying or cleaning up issues found. ---- - -# Simplify: Code Review and Cleanup - -Review all changed files for reuse, quality, and efficiency. Fix any issues found. - -## Phase 1: Identify Changes - -Run `git diff`, or `git diff HEAD` if there are staged changes. If there are no git changes, review the most recently modified files that the user mentioned or that were edited earlier in the conversation. - -## Phase 2: Review in Three Passes - -If the active Codex instructions allow subagents, launch three review agents in parallel and pass each one the full diff. If subagents are unavailable or not allowed, perform the same three passes locally. - -### Pass 1: Code Reuse Review - -For each change: - -1. Search for existing utilities and helpers that could replace newly written code. Look for similar patterns elsewhere in the codebase. Common locations are utility directories, shared modules, and files adjacent to the changed ones. -2. Flag any new function that duplicates existing functionality. Suggest the existing function to use instead. -3. Flag any inline logic that could use an existing utility, such as hand-rolled string manipulation, manual path handling, custom environment checks, ad-hoc type guards, and similar patterns. - -### Pass 2: Code Quality Review - -Review the same changes for hacky patterns: - -1. Redundant state: state that duplicates existing state, cached values that could be derived, observers/effects that could be direct calls -2. Parameter sprawl: adding new parameters to a function instead of generalizing or restructuring existing ones -3. Copy-paste with slight variation: near-duplicate code blocks that should be unified with a shared abstraction -4. Leaky abstractions: exposing internal details that should be encapsulated, or breaking existing abstraction boundaries -5. Stringly-typed code: using raw strings where constants, enums, string unions, or branded types already exist in the codebase -6. Unnecessary JSX nesting: wrapper Boxes/elements that add no layout value. Check if inner component props such as `flexShrink` or `alignItems` already provide the needed behavior. -7. Nested conditionals: ternary chains, nested if/else, or nested switch blocks 3+ levels deep. Flatten with early returns, guard clauses, a lookup table, or an if/else-if cascade. -8. Unnecessary comments: comments explaining what the code does, narrating the change, or referencing the task/caller. Delete those. Keep only non-obvious why comments for hidden constraints, subtle invariants, or workarounds. - -### Pass 3: Efficiency Review - -Review the same changes for efficiency: - -1. Unnecessary work: redundant computations, repeated file reads, duplicate network/API calls, N+1 patterns -2. Missed concurrency: independent operations run sequentially when they could run in parallel -3. Hot-path bloat: new blocking work added to startup or per-request/per-render hot paths -4. Recurring no-op updates: state/store updates inside polling loops, intervals, or event handlers that fire unconditionally. Add a change-detection guard so downstream consumers are not notified when nothing changed. If a wrapper function takes an updater/reducer callback, verify it honors same-reference returns or the local no-change signal. -5. Unnecessary existence checks: pre-checking file/resource existence before operating. Operate directly and handle the error. -6. Memory: unbounded data structures, missing cleanup, event listener leaks -7. Overly broad operations: reading entire files when only a portion is needed, loading all items when filtering for one - -## Phase 3: Fix Issues - -Aggregate findings and fix each actionable issue directly. If a finding is a false positive or not worth addressing, note it and move on. - -When done, briefly summarize what was fixed, or confirm the code was already clean. diff --git a/statusline/.claude-plugin/plugin.json b/statusline/.claude-plugin/plugin.json index d6a10f8..7a99152 100644 --- a/statusline/.claude-plugin/plugin.json +++ b/statusline/.claude-plugin/plugin.json @@ -1,9 +1,12 @@ { "name": "statusline", "version": "1.9.0", - "description": "Configurable multi-line status bar with context health, cache hit rate, session duration, API rate limits (Anthropic 5h/7d + z.ai GLM), git branch, and active tools. Supports 1/2/3 line layouts, icon themes, and template presets.", + "description": "Configurable status bar showing context usage, API rate limits, git branch, and active tools", "author": { - "name": "duyet" + "name": "duyet", + "url": "https://github.com/duyet" }, + "license": "MIT", + "homepage": "https://github.com/duyet/codex-claude-plugins/tree/master/statusline", "logo": "./assets/logo.svg" } diff --git a/statusline/.codex-plugin/plugin.json b/statusline/.codex-plugin/plugin.json index c73f358..948c744 100644 --- a/statusline/.codex-plugin/plugin.json +++ b/statusline/.codex-plugin/plugin.json @@ -1,18 +1,24 @@ { "name": "statusline", "version": "1.9.0", - "description": "Configurable multi-line status bar with context health, cache hit rate, session duration, API rate limits (Anthropic 5h/7d + z.ai GLM), git branch, and active tools. Supports 1/2/3 line layouts, icon themes, and template presets.", + "description": "Configurable status bar showing context usage, API rate limits, git branch, and active tools", "author": { - "name": "duyet" + "name": "duyet", + "url": "https://github.com/duyet" }, + "license": "MIT", "skills": "./skills/", "commands": "./commands/", "interface": { "displayName": "Statusline", - "shortDescription": "Configurable multi-line status bar with context health, cache hit rate, session duration, API rate limits (Anthropic 5h/7d + z.ai GLM), git branch, and active tools. Supports 1/2/3 line layouts, icon themes, and template presets.", + "shortDescription": "Configurable status bar showing context usage, API rate limits, git branch, and active tools", "developerName": "duyet", "category": "UI", - "capabilities": ["Skill", "Command"], + "capabilities": [ + "Skill", + "Command", + "Hook" + ], "logo": "./assets/logo.svg", "composerIcon": "./assets/logo.svg" } diff --git a/statusline/.cursor-plugin/plugin.json b/statusline/.cursor-plugin/plugin.json new file mode 100644 index 0000000..fa0a688 --- /dev/null +++ b/statusline/.cursor-plugin/plugin.json @@ -0,0 +1,16 @@ +{ + "name": "statusline", + "version": "1.9.0", + "description": "Configurable status bar showing context usage, API rate limits, git branch, and active tools", + "author": { + "name": "duyet" + }, + "license": "MIT", + "displayName": "Statusline", + "homepage": "https://github.com/duyet/codex-claude-plugins/tree/master/statusline", + "repository": "https://github.com/duyet/codex-claude-plugins", + "logo": "./assets/logo.svg", + "category": "UI", + "skills": "./skills/", + "commands": "./commands/" +} diff --git a/statusline/.grok-build-plugin/plugin.json b/statusline/.grok-build-plugin/plugin.json index 5356c07..e3d8b6d 100644 --- a/statusline/.grok-build-plugin/plugin.json +++ b/statusline/.grok-build-plugin/plugin.json @@ -1,20 +1,26 @@ { "name": "statusline", "version": "1.9.0", - "description": "Configurable multi-line status bar with context health, cache hit rate, session duration, API rate limits (Anthropic 5h/7d + z.ai GLM), git branch, and active tools. Supports 1/2/3 line layouts, icon themes, and template presets.", + "description": "Configurable status bar showing context usage, API rate limits, git branch, and active tools", "author": { - "name": "duyet" + "name": "duyet", + "url": "https://github.com/duyet" }, + "license": "MIT", + "logo": "./assets/logo.svg", "skills": "./skills/", "commands": "./commands/", "interface": { "displayName": "Statusline", - "shortDescription": "Configurable multi-line status bar with context health, cache hit rate, session duration, API rate limits (Anthropic 5h/7d + z.ai GLM), git branch, and active tools. Supports 1/2/3 line layouts, icon themes, and template presets.", + "shortDescription": "Configurable status bar showing context usage, API rate limits, git branch, and active tools", "developerName": "duyet", "category": "UI", - "capabilities": ["Skill", "Command"], + "capabilities": [ + "Skill", + "Command", + "Hook" + ], "logo": "./assets/logo.svg", "composerIcon": "./assets/logo.svg" - }, - "logo": "assets/logo.svg" + } } diff --git a/statusline/.grok-plugin/plugin.json b/statusline/.grok-plugin/plugin.json index c01b725..c5c9d93 100644 --- a/statusline/.grok-plugin/plugin.json +++ b/statusline/.grok-plugin/plugin.json @@ -1,13 +1,16 @@ { "name": "statusline", "version": "1.9.0", - "description": "Configurable multi-line status bar with context health, cache hit rate, session duration, API rate limits (Anthropic 5h/7d + z.ai GLM), git branch, and active tools. Supports 1/2/3 line layouts, icon themes, and template presets.", + "description": "Configurable status bar showing context usage, API rate limits, git branch, and active tools", "author": { - "name": "duyet" + "name": "duyet", + "url": "https://github.com/duyet" }, - "logo": "assets/logo.svg", - "keywords": ["statusline", "grok", "grok-build", "grok-bot"], + "license": "MIT", + "logo": "./assets/logo.svg", + "keywords": [ + "statusline" + ], "skills": "./skills/", - "commands": "./commands/", - "hooks": "./hooks/hooks.json" + "commands": "./commands/" } diff --git a/statusline/CLAUDE.md b/statusline/CLAUDE.md deleted file mode 100644 index 949044d..0000000 --- a/statusline/CLAUDE.md +++ /dev/null @@ -1,77 +0,0 @@ -# Statusline Plugin - -Configurable multi-line status bar with context health, cache hit rate + live TTL countdown, session cost, session duration, API rate limits (Anthropic 5h/7d + z.ai GLM), git branch, active tools, and agent tracking. Supports 1/2/3 line layouts, icon themes, and 6 template presets. Dual-provider: Anthropic Claude and z.ai GLM. - -## Versioning - -Follow semantic versioning (semver) for this plugin: - -| Change Type | Version Bump | Example | -|-------------|--------------|---------| -| Bug fix, docs | Patch | 1.8.0 → 1.8.1 | -| New feature, minor change | Minor | 1.8.0 → 1.9.0 | -| Breaking change | Major | 1.8.0 → 2.0.0 | - -**When to bump:** -- Adding new commands, skills, or agents → **Minor** -- Modifying existing behavior → **Minor** (or Major if breaking) -- Updating documentation only → **Patch** -- Bug fixes → **Patch** - -Always update `plugin.json` version when making changes. - -## Plugin Structure - -``` -statusline/ -├── .claude-plugin/ -│ └── plugin.json # Manifest (version 1.9.0) -├── commands/ # Slash commands -│ ├── setup.md # /statusline:setup — interactive wizard -│ ├── config.md # /statusline:config — quick changes -│ ├── status.md # /statusline:status — view metrics -│ └── disable.md # /statusline:disable — pause updates -├── skills/ -│ └── statusline-workflow/ -│ └── SKILL.md # Reusable skill for configuration -├── hooks/ -│ ├── hooks.json # Lifecycle hooks -│ └── session-start.sh # Rate limit fetching on session start -├── scripts/ -│ ├── statusline.py # Configurable renderer (reads config JSON) -│ ├── format-status.ts # TypeScript rate-limit fetcher -│ ├── test-statusline.sh # Test harness -│ └── templates/ # Layout presets -│ ├── detailed.json # 3-line, emoji, all sections (default) -│ ├── balanced.json # 2-line, unicode, key metrics -│ ├── minimal.json # 1-line, no icons, essentials -│ ├── monitor.json # 2-line, rate-limit focused -│ ├── developer.json # 2-line, tools+agents+git focused -│ └── performance.json # 3-line, cache+context optimization -└── README.md -``` - -## Dual-Provider Behavior - -| Feature | Anthropic Claude | z.ai GLM | -|---------|-----------------|----------| -| Model name | Simplified (`opus-4.8[200k]`) | Preserved from ID | -| Cache stats | Real prompt caching data | Hidden (proxy artifacts) | -| Rate limits | 5h/7d from payload | When available | -| All other features | ✅ | ✅ | - -## Config Schema - -`~/.claude/statusline.config.json` — see SKILL.md for full field reference. - -## Commit Convention - -Use semantic commits with plugin scope: - -``` -feat(statusline): add new feature -fix(statusline): fix bug -docs(statusline): update documentation -``` - -Co-author: `Co-Authored-By: duyetbot ` diff --git a/team-agents/.claude-plugin/plugin.json b/team-agents/.claude-plugin/plugin.json index bc5dbea..4b9529d 100644 --- a/team-agents/.claude-plugin/plugin.json +++ b/team-agents/.claude-plugin/plugin.json @@ -1,9 +1,12 @@ { "name": "team-agents", - "description": "Leader and Senior Engineer agents for coordinated parallel task execution. Leader breaks down complex tasks and delegates to multiple senior engineers working in parallel.", "version": "1.9.1", + "description": "Leader, Senior Engineer, and Junior Engineer agents for coordinated parallel task execution", "author": { - "name": "duyet" + "name": "duyet", + "url": "https://github.com/duyet" }, + "license": "MIT", + "homepage": "https://github.com/duyet/codex-claude-plugins/tree/master/team-agents", "logo": "./assets/logo.svg" } diff --git a/team-agents/.codex-plugin/plugin.json b/team-agents/.codex-plugin/plugin.json index 9e4e597..193d07e 100644 --- a/team-agents/.codex-plugin/plugin.json +++ b/team-agents/.codex-plugin/plugin.json @@ -1,17 +1,25 @@ { "name": "team-agents", "version": "1.9.1", - "description": "Leader and Senior Engineer agents for coordinated parallel task execution. Leader breaks down complex tasks and delegates to multiple senior engineers working in parallel.", + "description": "Leader, Senior Engineer, and Junior Engineer agents for coordinated parallel task execution", "author": { - "name": "duyet" + "name": "duyet", + "url": "https://github.com/duyet" }, + "license": "MIT", "skills": "./skills/", + "commands": "./commands/", + "agents": "./agents/", "interface": { "displayName": "Team Agents", - "shortDescription": "Leader and Senior Engineer agents for coordinated parallel task execution. Leader breaks down complex tasks and delegates to multiple senior engineers working in parallel.", + "shortDescription": "Leader, Senior Engineer, and Junior Engineer agents for coordinated parallel task execution", "developerName": "duyet", "category": "Agents", - "capabilities": ["Skill", "Command", "Agent"], + "capabilities": [ + "Skill", + "Command", + "Agent" + ], "logo": "./assets/logo.svg", "composerIcon": "./assets/logo.svg" } diff --git a/team-agents/.cursor-plugin/plugin.json b/team-agents/.cursor-plugin/plugin.json new file mode 100644 index 0000000..ce15baa --- /dev/null +++ b/team-agents/.cursor-plugin/plugin.json @@ -0,0 +1,17 @@ +{ + "name": "team-agents", + "version": "1.9.1", + "description": "Leader, Senior Engineer, and Junior Engineer agents for coordinated parallel task execution", + "author": { + "name": "duyet" + }, + "license": "MIT", + "displayName": "Team Agents", + "homepage": "https://github.com/duyet/codex-claude-plugins/tree/master/team-agents", + "repository": "https://github.com/duyet/codex-claude-plugins", + "logo": "./assets/logo.svg", + "category": "Agents", + "skills": "./skills/", + "commands": "./commands/", + "agents": "./agents/" +} diff --git a/team-agents/.grok-build-plugin/plugin.json b/team-agents/.grok-build-plugin/plugin.json index 1c744b5..bdad2df 100644 --- a/team-agents/.grok-build-plugin/plugin.json +++ b/team-agents/.grok-build-plugin/plugin.json @@ -1,19 +1,27 @@ { "name": "team-agents", "version": "1.9.1", - "description": "Leader and Senior Engineer agents for coordinated parallel task execution. Leader breaks down complex tasks and delegates to multiple senior engineers working in parallel.", + "description": "Leader, Senior Engineer, and Junior Engineer agents for coordinated parallel task execution", "author": { - "name": "duyet" + "name": "duyet", + "url": "https://github.com/duyet" }, + "license": "MIT", + "logo": "./assets/logo.svg", "skills": "./skills/", + "commands": "./commands/", + "agents": "./agents/", "interface": { "displayName": "Team Agents", - "shortDescription": "Leader and Senior Engineer agents for coordinated parallel task execution. Leader breaks down complex tasks and delegates to multiple senior engineers working in parallel.", + "shortDescription": "Leader, Senior Engineer, and Junior Engineer agents for coordinated parallel task execution", "developerName": "duyet", "category": "Agents", - "capabilities": ["Skill", "Command", "Agent"], + "capabilities": [ + "Skill", + "Command", + "Agent" + ], "logo": "./assets/logo.svg", "composerIcon": "./assets/logo.svg" - }, - "logo": "assets/logo.svg" + } } diff --git a/team-agents/.grok-plugin/plugin.json b/team-agents/.grok-plugin/plugin.json index 16df461..751f9aa 100644 --- a/team-agents/.grok-plugin/plugin.json +++ b/team-agents/.grok-plugin/plugin.json @@ -1,12 +1,16 @@ { "name": "team-agents", "version": "1.9.1", - "description": "Leader and Senior Engineer agents for coordinated parallel task execution. Leader breaks down complex tasks and delegates to multiple senior engineers working in parallel.", + "description": "Leader, Senior Engineer, and Junior Engineer agents for coordinated parallel task execution", "author": { - "name": "duyet" + "name": "duyet", + "url": "https://github.com/duyet" }, - "logo": "assets/logo.svg", - "keywords": ["team-agents", "grok", "grok-build", "grok-bot"], + "license": "MIT", + "logo": "./assets/logo.svg", + "keywords": [ + "team-agents" + ], "skills": "./skills/", "commands": "./commands/", "agents": "./agents/" diff --git a/team-agents/CLAUDE.md b/team-agents/CLAUDE.md deleted file mode 100644 index 7542a05..0000000 --- a/team-agents/CLAUDE.md +++ /dev/null @@ -1,70 +0,0 @@ -# Team-agents Plugin - -Leader, Senior Engineer, and Junior Engineer agents for coordinated parallel task execution - -## Versioning - -Follow semantic versioning (semver) for this plugin: - -| Change Type | Version Bump | Example | -|-------------|--------------|---------| -| Bug fix, docs | Patch | 1.0.0 → 1.0.1 | -| New feature, minor change | Minor | 1.0.0 → 1.1.0 | -| Breaking change | Major | 1.0.0 → 2.0.0 | - -**When to bump:** -- Adding new commands, skills, or agents → **Minor** -- Modifying existing behavior → **Minor** (or Major if breaking) -- Updating documentation only → **Patch** -- Bug fixes → **Patch** - -Always update `plugin.json` version when making changes. - -## Plugin Structure - -``` -team-agents/ -├── .claude-plugin/ -│ └── plugin.json # Manifest (version 1.6.0) -├── agents/ # Sub-agent definitions -├── commands/ # Slash commands -├── skills/ # Reusable knowledge -└── hooks/hooks.json # Lifecycle hooks (optional) -``` - -## Components - -### Commands - - - `/leader` - -### Agents - - - **junior-engineer** - - **leader** - - **senior-engineer** - -### Skills - - - **backend-api-patterns** - - **quality-gates** - - **react-nextjs-patterns** - - **task-decomposition** - - **typescript-patterns** - - -## Commit Convention - -Use semantic commits with plugin scope: - -``` -feat(team-agents): add new feature -fix(team-agents): fix bug -docs(team-agents): update documentation -``` - -Co-author: `Co-Authored-By: duyetbot ` - ---- - -**Generated by docs-generator v1.0.0** diff --git a/unsloth-training/.claude-plugin/plugin.json b/unsloth-training/.claude-plugin/plugin.json index e482e6a..4cf7bf9 100644 --- a/unsloth-training/.claude-plugin/plugin.json +++ b/unsloth-training/.claude-plugin/plugin.json @@ -1,10 +1,12 @@ { "name": "unsloth-training", - "description": "Fine-tune LLMs with Unsloth using GRPO or SFT. Includes dataset preparation, synthetic data generation, environment flags, MLX (Apple Silicon), FP8, vision models, mobile export, GGUF.", "version": "1.0.2", + "description": "Fine-tune LLMs with Unsloth using GRPO or SFT. Dataset prep, synthetic data, environment flags, MLX (Apple Silicon), FP8, vision, mobile export, GGUF.", "author": { - "name": "duyet" + "name": "duyet", + "url": "https://github.com/duyet" }, "license": "MIT", + "homepage": "https://github.com/duyet/codex-claude-plugins/tree/master/unsloth-training", "logo": "./assets/logo.svg" } diff --git a/unsloth-training/.codex-plugin/plugin.json b/unsloth-training/.codex-plugin/plugin.json index b495602..aefc2f2 100644 --- a/unsloth-training/.codex-plugin/plugin.json +++ b/unsloth-training/.codex-plugin/plugin.json @@ -1,18 +1,21 @@ { "name": "unsloth-training", "version": "1.0.2", - "description": "Fine-tune LLMs with Unsloth using GRPO or SFT. Includes dataset preparation, synthetic data generation, environment flags, MLX (Apple Silicon), FP8, vision models, mobile export, GGUF.", + "description": "Fine-tune LLMs with Unsloth using GRPO or SFT. Dataset prep, synthetic data, environment flags, MLX (Apple Silicon), FP8, vision, mobile export, GGUF.", "author": { - "name": "duyet" + "name": "duyet", + "url": "https://github.com/duyet" }, "license": "MIT", "skills": "./skills/", "interface": { "displayName": "Unsloth Training", - "shortDescription": "Fine-tune LLMs with Unsloth using GRPO or SFT. Includes dataset preparation, synthetic data generation, environment flags, MLX (Apple Silicon), FP8, vision models, mobile export, GGUF.", + "shortDescription": "Fine-tune LLMs with Unsloth using GRPO or SFT. Dataset prep, synthetic data, environment flags, MLX (Apple Silicon), FP8, vision, mobile export, GGUF.", "developerName": "duyet", "category": "ML", - "capabilities": ["Skill"], + "capabilities": [ + "Skill" + ], "logo": "./assets/logo.svg", "composerIcon": "./assets/logo.svg" } diff --git a/unsloth-training/.cursor-plugin/plugin.json b/unsloth-training/.cursor-plugin/plugin.json new file mode 100644 index 0000000..ba8eae0 --- /dev/null +++ b/unsloth-training/.cursor-plugin/plugin.json @@ -0,0 +1,15 @@ +{ + "name": "unsloth-training", + "version": "1.0.2", + "description": "Fine-tune LLMs with Unsloth using GRPO or SFT. Dataset prep, synthetic data, environment flags, MLX (Apple Silicon), FP8, vision, mobile export, GGUF.", + "author": { + "name": "duyet" + }, + "license": "MIT", + "displayName": "Unsloth Training", + "homepage": "https://github.com/duyet/codex-claude-plugins/tree/master/unsloth-training", + "repository": "https://github.com/duyet/codex-claude-plugins", + "logo": "./assets/logo.svg", + "category": "ML", + "skills": "./skills/" +} diff --git a/unsloth-training/.grok-build-plugin/plugin.json b/unsloth-training/.grok-build-plugin/plugin.json index 67b54e1..b4a0f8e 100644 --- a/unsloth-training/.grok-build-plugin/plugin.json +++ b/unsloth-training/.grok-build-plugin/plugin.json @@ -1,20 +1,23 @@ { "name": "unsloth-training", "version": "1.0.2", - "description": "Fine-tune LLMs with Unsloth using GRPO or SFT. Includes dataset preparation, synthetic data generation, environment flags, MLX (Apple Silicon), FP8, vision models, mobile export, GGUF.", + "description": "Fine-tune LLMs with Unsloth using GRPO or SFT. Dataset prep, synthetic data, environment flags, MLX (Apple Silicon), FP8, vision, mobile export, GGUF.", "author": { - "name": "duyet" + "name": "duyet", + "url": "https://github.com/duyet" }, "license": "MIT", + "logo": "./assets/logo.svg", "skills": "./skills/", "interface": { "displayName": "Unsloth Training", - "shortDescription": "Fine-tune LLMs with Unsloth using GRPO or SFT. Includes dataset preparation, synthetic data generation, environment flags, MLX (Apple Silicon), FP8, vision models, mobile export, GGUF.", + "shortDescription": "Fine-tune LLMs with Unsloth using GRPO or SFT. Dataset prep, synthetic data, environment flags, MLX (Apple Silicon), FP8, vision, mobile export, GGUF.", "developerName": "duyet", "category": "ML", - "capabilities": ["Skill"], + "capabilities": [ + "Skill" + ], "logo": "./assets/logo.svg", "composerIcon": "./assets/logo.svg" - }, - "logo": "assets/logo.svg" + } } diff --git a/unsloth-training/.grok-plugin/plugin.json b/unsloth-training/.grok-plugin/plugin.json index 873fd60..d712bc7 100644 --- a/unsloth-training/.grok-plugin/plugin.json +++ b/unsloth-training/.grok-plugin/plugin.json @@ -1,12 +1,15 @@ { "name": "unsloth-training", "version": "1.0.2", - "description": "Fine-tune LLMs with Unsloth using GRPO or SFT. Includes dataset preparation, synthetic data generation, environment flags, MLX (Apple Silicon), FP8, vision models, mobile export, GGUF.", + "description": "Fine-tune LLMs with Unsloth using GRPO or SFT. Dataset prep, synthetic data, environment flags, MLX (Apple Silicon), FP8, vision, mobile export, GGUF.", "author": { - "name": "duyet" + "name": "duyet", + "url": "https://github.com/duyet" }, "license": "MIT", - "logo": "assets/logo.svg", - "keywords": ["unsloth-training", "grok", "grok-build", "grok-bot"], + "logo": "./assets/logo.svg", + "keywords": [ + "unsloth-training" + ], "skills": "./skills/" } From 56f1c2149d36e00cfbba6078367b5356af687f6f Mon Sep 17 00:00:00 2001 From: duyet Date: Mon, 19 Oct 2026 13:10:16 +0700 Subject: [PATCH 2/5] refactor(plugins): rewrite every plugin to keep only decision-changing prose Cut generic tutorials, personas, restated CLI help, and duplicate command/skill copies. Each idea now has one home, and commands point at skills. Fixed broken links, Codex-only steps, stale model ids, fake subagent types, and personal trailers and paths. Removed statusline's SessionStart hook and TypeScript renderer (failed silently on older Node). The lint now also rejects links that leave a plugin, since each plugin installs alone. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01ACsvmWVWieCuahs1T7ZTtn --- .claude-plugin/marketplace.json | 72 +- .cursor-plugin/marketplace.json | 30 +- .../references/features/docs-and-readme.md | 6 +- .github/ISSUE_TEMPLATE/feature_request.md | 2 - .github/workflows/sync-skills.yml | 58 +- .grok-plugin/marketplace.json | 72 +- CLAUDE.md | 47 +- CONTRIBUTING.md | 227 +--- README.md | 395 +----- agent-loop/.antigravity-plugin/plugin.json | 6 +- agent-loop/.claude-plugin/plugin.json | 4 +- agent-loop/.codex-plugin/plugin.json | 6 +- agent-loop/.cursor-plugin/plugin.json | 4 +- agent-loop/.grok-build-plugin/plugin.json | 6 +- agent-loop/.grok-plugin/plugin.json | 4 +- agent-loop/CHANGELOG.md | 81 +- agent-loop/README.md | 224 +--- agent-loop/commands/autoreview.md | 46 +- agent-loop/commands/inspect.md | 135 +- agent-loop/commands/reset.md | 67 +- agent-loop/commands/restore.md | 157 +-- agent-loop/commands/resume.md | 74 +- agent-loop/commands/start.md | 62 +- agent-loop/commands/status.md | 39 +- agent-loop/commands/stop.md | 36 +- agent-loop/commands/triage.md | 47 +- agent-loop/skills/agent-loop-autoreview.md | 148 --- .../skills/agent-loop-autoreview/SKILL.md | 147 +-- agent-loop/skills/agent-loop-browser.md | 115 -- agent-loop/skills/agent-loop-browser/SKILL.md | 123 +- agent-loop/skills/agent-loop-orchestrator.md | 188 --- .../skills/agent-loop-orchestrator/SKILL.md | 221 +--- agent-loop/skills/agent-loop-triage.md | 179 --- agent-loop/skills/agent-loop-triage/SKILL.md | 49 +- anyrouter/.claude-plugin/plugin.json | 4 +- anyrouter/.codex-plugin/plugin.json | 6 +- anyrouter/.cursor-plugin/plugin.json | 4 +- anyrouter/.grok-build-plugin/plugin.json | 6 +- anyrouter/.grok-plugin/plugin.json | 4 +- anyrouter/.mcp.json | 3 +- anyrouter/README.md | 81 +- anyrouter/agents/anyrouter-integrator.md | 58 +- anyrouter/commands/anyrouter-migrate.md | 78 +- anyrouter/skills/anyrouter/SKILL.md | 261 +--- build-ios-apps/.claude-plugin/plugin.json | 4 +- build-ios-apps/.codex-plugin/plugin.json | 10 +- build-ios-apps/.cursor-plugin/plugin.json | 7 +- build-ios-apps/.grok-build-plugin/plugin.json | 10 +- build-ios-apps/.grok-plugin/plugin.json | 7 +- build-ios-apps/README.md | 34 +- build-ios-apps/agents/openai.yaml | 6 - .../skills/apple-intelligence/SKILL.md | 66 +- build-ios-apps/skills/core-ai/SKILL.md | 36 +- .../skills/foundation-models/SKILL.md | 16 +- .../skills/ios-debugger-agent/SKILL.md | 12 + .../skills/ios-ettrace-performance/SKILL.md | 25 +- .../skills/ios-memgraph-leaks/SKILL.md | 2 +- .../scripts/capture_sim_memgraph.sh | 4 +- .../skills/ios-simulator-browser/SKILL.md | 6 +- .../skills/swiftui-liquid-glass/SKILL.md | 2 +- .../skills/swiftui-performance-audit/SKILL.md | 2 +- .../skills/swiftui-ui-patterns/SKILL.md | 46 +- .../skills/swiftui-view-refactor/SKILL.md | 2 +- build-macos-apps/.claude-plugin/plugin.json | 2 +- build-macos-apps/.codex-plugin/plugin.json | 6 +- build-macos-apps/.cursor-plugin/plugin.json | 5 +- .../.grok-build-plugin/plugin.json | 6 +- build-macos-apps/.grok-plugin/plugin.json | 5 +- build-macos-apps/README.md | 50 +- build-macos-apps/agents/openai.yaml | 6 - .../commands/build-and-run-macos-app.md | 12 +- .../commands/fix-codesign-error.md | 4 + build-macos-apps/commands/test-macos-app.md | 4 + .../references/appkit-overview.md | 44 +- .../skills/build-run-debug/SKILL.md | 30 +- .../references/run-button-bootstrap.md | 32 +- .../skills/macos-app-best-practices/SKILL.md | 12 +- .../skills/swiftui-patterns/SKILL.md | 6 +- .../references/components-index.md | 10 +- .../.claude-plugin/plugin.json | 4 +- .../.codex-plugin/plugin.json | 6 +- .../.cursor-plugin/plugin.json | 4 +- .../.grok-build-plugin/plugin.json | 6 +- .../.grok-plugin/plugin.json | 4 +- clickhouse-monitoring/README.md | 151 +-- .../references/api-endpoints.md | 445 ------- clickhouse-monitoring/references/api-list.md | 168 --- .../references/clickhouse-compat.md | 433 ------- .../references/dashboard-pages.md | 54 - .../references/development.md | 513 -------- clickhouse-monitoring/scripts/sync-docs.ts | 280 ---- .../skills/clickhouse-monitoring/SKILL.md | 69 +- .../references/api-list.md | 1 - .../references/clickhouse-compat.md | 42 +- .../references/dashboard-pages.md | 1 - .../references/development.md | 274 +--- clickhouse/.claude-plugin/plugin.json | 4 +- clickhouse/.codex-plugin/plugin.json | 6 +- clickhouse/.cursor-plugin/plugin.json | 4 +- clickhouse/.github/workflows/README.md | 40 - clickhouse/.github/workflows/sync-rules.yml | 83 -- clickhouse/.grok-build-plugin/plugin.json | 6 +- clickhouse/.grok-plugin/plugin.json | 4 +- clickhouse/README.md | 168 +-- clickhouse/skills/clickhouse/SKILL.md | 302 +---- .../references/advanced-features.md | 354 ----- .../clickhouse/references/backup-restore.md | 362 ------ .../clickhouse/references/best-practices.md | 290 ----- .../references/cluster-management.md | 374 ------ .../clickhouse/references/core-concepts.md | 240 ---- .../skills/clickhouse/references/debugging.md | 1 - .../skills/clickhouse/references/external.md | 202 --- .../clickhouse/references/integrations.md | 483 ------- .../clickhouse/references/monitoring.md | 216 +++- .../references/query-optimization.md | 19 +- .../clickhouse/references/schema-design.md | 319 ++++- .../clickhouse/references/sql-reference.md | 390 ------ .../clickhouse/references/system-queries.md | 694 ---------- .../clickhouse/references/table-design.md | 313 ----- .../clickhouse/references/table-engines.md | 333 ----- .../spec/spec-process-cicd-sync-rules.md | 241 ---- command-code/.claude-plugin/plugin.json | 4 +- command-code/.codex-plugin/plugin.json | 6 +- command-code/.cursor-plugin/plugin.json | 4 +- command-code/.grok-build-plugin/plugin.json | 6 +- command-code/.grok-plugin/plugin.json | 4 +- command-code/README.md | 40 +- command-code/agents/cmd-dispatcher.md | 29 +- command-code/commands/dispatch.md | 48 +- command-code/skills/command-code/SKILL.md | 152 +-- .../command-code/references/cli-reference.md | 100 -- commit/.claude-plugin/plugin.json | 4 +- commit/.codex-plugin/plugin.json | 6 +- commit/.cursor-plugin/plugin.json | 4 +- commit/.grok-build-plugin/plugin.json | 6 +- commit/.grok-plugin/plugin.json | 4 +- commit/README.md | 122 +- commit/commands/and-create-pr.md | 159 +-- commit/commands/and-push.md | 23 +- commit/commands/commit.md | 23 +- commit/skills/commit-workflow/SKILL.md | 27 +- fix/.claude-plugin/plugin.json | 4 +- fix/.codex-plugin/plugin.json | 6 +- fix/.cursor-plugin/plugin.json | 4 +- fix/.grok-build-plugin/plugin.json | 6 +- fix/.grok-plugin/plugin.json | 4 +- fix/README.md | 84 +- fix/commands/and-create-pr.md | 168 +-- fix/commands/and-push.md | 97 +- fix/commands/and-update-pr.md | 140 +- fix/skills/fix-workflow/SKILL.md | 27 +- fix/skills/test-detection.md | 137 -- frontend-design/.claude-plugin/plugin.json | 4 +- frontend-design/.codex-plugin/plugin.json | 6 +- frontend-design/.cursor-plugin/plugin.json | 4 +- .../.grok-build-plugin/plugin.json | 6 +- frontend-design/.grok-plugin/plugin.json | 4 +- frontend-design/README.md | 102 +- .../skills/frontend-design/SKILL.md | 778 +---------- .../frontend-design/references/shadcn.md | 736 ----------- github/.claude-plugin/plugin.json | 4 +- github/.codex-plugin/plugin.json | 6 +- github/.cursor-plugin/plugin.json | 4 +- github/.grok-build-plugin/plugin.json | 6 +- github/.grok-plugin/plugin.json | 4 +- github/README.md | 248 +--- github/commands/babysit-pr.md | 320 +---- github/commands/review-and-merge.md | 17 +- github/commands/watch-and-fix.md | 138 +- github/examples/babysit-pr.sh | 256 ---- github/examples/bulk-close-issues.sh | 41 - github/examples/bulk-merge-prs.sh | 38 - github/examples/pr-automation.sh | 76 -- github/examples/watch-and-fix.sh | 138 -- github/skills/github.md | 596 --------- .../{review-bots.md => review-bots/SKILL.md} | 27 +- good-html/.claude-plugin/plugin.json | 4 +- good-html/.codex-plugin/plugin.json | 6 +- good-html/.cursor-plugin/plugin.json | 4 +- good-html/.grok-build-plugin/plugin.json | 6 +- good-html/.grok-plugin/plugin.json | 4 +- good-html/README.md | 11 + good-html/skills/good-html/SKILL.md | 56 +- .../good-html}/assets/boilerplate.html | 0 .../assets/implementation-plan.html | 0 .../good-html}/assets/pr-review.html | 0 .../good-html}/assets/research-explainer.html | 0 .../skills/good-html/references/components.md | 2 +- .../skills/good-html/references/page_types.md | 29 - .../skills/good-html/references/patterns.md | 43 - interview/.claude-plugin/plugin.json | 4 +- interview/.codex-plugin/plugin.json | 6 +- interview/.cursor-plugin/plugin.json | 4 +- interview/.grok-build-plugin/plugin.json | 6 +- interview/.grok-plugin/plugin.json | 4 +- interview/README.md | 105 +- interview/commands/interview.md | 189 +-- interview/skills/interview-workflow/SKILL.md | 36 +- kb/.claude-plugin/plugin.json | 2 +- kb/.codex-plugin/plugin.json | 2 +- kb/.cursor-plugin/plugin.json | 2 +- kb/.grok-build-plugin/plugin.json | 2 +- kb/.grok-plugin/plugin.json | 2 +- kb/README.md | 41 +- kb/commands/dream.md | 37 +- kb/commands/init.md | 31 +- kb/skills/dream/SKILL.md | 217 +--- kb/skills/init/SKILL.md | 113 +- kb/skills/init/scripts/scaffold.sh | 10 +- kb/skills/init/templates/AGENTS.md | 268 ++-- kb/skills/init/templates/CLAUDE.md | 29 +- kb/skills/init/templates/DREAM.md | 74 +- kb/skills/init/templates/README.md | 97 +- kb/skills/init/templates/bin/kb | 8 +- kb/skills/init/templates/memory/_TEMPLATE.md | 13 +- kb/skills/init/templates/raw/README.md | 25 +- kb/skills/init/templates/scripts/lint.sh | 10 +- .../templates/scripts/render_okf_viewer.py | 20 +- kb/skills/init/templates/scripts/sync.sh | 6 +- kb/skills/init/templates/scripts/wire.sh | 8 +- marketplace.json | 72 +- okf/.claude-plugin/plugin.json | 2 +- okf/.codex-plugin/plugin.json | 2 +- okf/.cursor-plugin/plugin.json | 2 +- okf/.grok-build-plugin/plugin.json | 2 +- okf/.grok-plugin/plugin.json | 2 +- okf/README.md | 55 +- okf/skills/okf-refactor/SKILL.md | 110 +- okf/skills/okf/SKILL.md | 193 +-- okf/skills/okf/reference/SPEC.md | 56 +- .../render_okf_viewer.cpython-312.pyc | Bin 0 -> 21286 bytes .../__pycache__/validate_okf.cpython-312.pyc | Bin 0 -> 4689 bytes okf/skills/okf/scripts/render_okf_viewer.py | 18 +- okf/skills/okf/scripts/validate_okf.py | 4 +- orchestration/.claude-plugin/plugin.json | 2 +- orchestration/.codex-plugin/plugin.json | 2 +- orchestration/.cursor-plugin/plugin.json | 2 +- orchestration/.grok-build-plugin/plugin.json | 2 +- orchestration/.grok-plugin/plugin.json | 2 +- orchestration/README.md | 105 +- orchestration/skills/orchestration/SKILL.md | 552 +------- .../references/domains/code-review.md | 240 ---- .../references/domains/data-analysis.md | 293 ----- .../references/domains/devops.md | 282 ---- .../references/domains/documentation.md | 306 ----- .../references/domains/project-management.md | 336 ----- .../references/domains/prompt-engineering.md | 394 ------ .../references/domains/python.md | 474 ------- .../references/domains/research.md | 237 ---- .../orchestration/references/domains/rust.md | 544 -------- .../references/domains/shadcn.md | 490 ------- .../domains/software-development.md | 235 ---- .../references/domains/tailwindcss.md | 528 -------- .../references/domains/testing.md | 265 ---- .../references/domains/typescript.md | 510 -------- .../orchestration/references/examples.md | 363 ------ .../skills/orchestration/references/guide.md | 143 -- .../orchestration/references/patterns.md | 231 ---- .../skills/orchestration/references/tools.md | 256 ---- prompt-engineering/.claude-plugin/plugin.json | 4 +- prompt-engineering/.codex-plugin/plugin.json | 6 +- prompt-engineering/.cursor-plugin/plugin.json | 4 +- .../.grok-build-plugin/plugin.json | 6 +- prompt-engineering/.grok-plugin/plugin.json | 4 +- prompt-engineering/README.md | 113 +- .../skills/prompt-engineering/SKILL.md | 393 +----- .../prompt-engineering/references/basics.md | 212 --- .../prompt-engineering/references/claude.md | 283 +--- .../prompt-engineering/references/examples.md | 371 ------ .../prompt-engineering/references/gemini.md | 333 +---- .../prompt-engineering/references/grok.md | 252 +--- .../references/techniques.md | 336 ----- sag-notify/.claude-plugin/plugin.json | 2 +- sag-notify/.codex-plugin/plugin.json | 2 +- sag-notify/.cursor-plugin/plugin.json | 2 +- sag-notify/.grok-build-plugin/plugin.json | 2 +- sag-notify/.grok-plugin/plugin.json | 2 +- sag-notify/README.md | 57 +- sag-notify/commands/config.md | 32 +- sag-notify/commands/setup.md | 34 +- sag-notify/commands/test.md | 30 +- sag-notify/skills/sag-voice/SKILL.md | 157 +-- .../skills/sag-voice/references/sag-cli.md | 92 -- scripts/plugins.py | 27 +- statusline/.claude-plugin/plugin.json | 2 +- statusline/.codex-plugin/plugin.json | 5 +- statusline/.cursor-plugin/plugin.json | 2 +- statusline/.grok-build-plugin/plugin.json | 5 +- statusline/.grok-plugin/plugin.json | 2 +- statusline/README.md | 233 +--- statusline/commands/config.md | 94 +- statusline/commands/disable.md | 31 +- statusline/commands/setup.md | 109 +- statusline/commands/status.md | 78 +- statusline/hooks/hooks.json | 14 - statusline/hooks/session-start.sh | 69 - .../__pycache__/statusline.cpython-312.pyc | Bin 0 -> 23856 bytes statusline/scripts/format-status.ts | 511 -------- statusline/scripts/statusline.py | 17 +- statusline/scripts/test-statusline.sh | 8 +- .../skills/statusline-workflow/SKILL.md | 167 +-- team-agents/.claude-plugin/plugin.json | 4 +- team-agents/.codex-plugin/plugin.json | 6 +- team-agents/.cursor-plugin/plugin.json | 4 +- team-agents/.grok-build-plugin/plugin.json | 6 +- team-agents/.grok-plugin/plugin.json | 4 +- team-agents/README.md | 210 +-- team-agents/agents/deep-research-agent.md | 207 +-- team-agents/agents/junior-engineer.md | 314 +---- team-agents/agents/leader.md | 120 +- team-agents/agents/performance-engineer.md | 204 +-- team-agents/agents/python-expert.md | 151 +-- team-agents/agents/senior-engineer.md | 227 +--- team-agents/commands/leader.md | 149 +-- .../skills/backend-api-patterns/SKILL.md | 573 +-------- team-agents/skills/quality-gates/SKILL.md | 402 +----- .../skills/react-nextjs-patterns/SKILL.md | 463 +------ .../skills/task-decomposition/SKILL.md | 275 +--- .../skills/team-agents-workflow/SKILL.md | 10 +- .../skills/typescript-patterns/SKILL.md | 359 +----- unsloth-training/.claude-plugin/plugin.json | 4 +- unsloth-training/.codex-plugin/plugin.json | 6 +- unsloth-training/.cursor-plugin/plugin.json | 4 +- .../.grok-build-plugin/plugin.json | 6 +- unsloth-training/.grok-plugin/plugin.json | 4 +- unsloth-training/README.md | 111 +- .../skills/unsloth-training/SKILL.md | 552 +------- .../reference/datasets-guide.md | 10 +- .../unsloth-training/reference/deployment.md | 2 +- .../reference/domain-examples.md | 480 ------- .../reference/environment-flags.md | 4 +- .../reference/mlx-training.md | 2 +- .../reference/sft/generate_training_data.py | 1146 ----------------- .../reference/sft/sales_extractor_training.py | 495 ------- .../reference/sft/seed_examples.json | 242 ---- 335 files changed, 2669 insertions(+), 34061 deletions(-) delete mode 100644 agent-loop/skills/agent-loop-autoreview.md delete mode 100644 agent-loop/skills/agent-loop-browser.md delete mode 100644 agent-loop/skills/agent-loop-orchestrator.md delete mode 100644 agent-loop/skills/agent-loop-triage.md delete mode 100644 build-ios-apps/agents/openai.yaml delete mode 100644 build-macos-apps/agents/openai.yaml delete mode 100644 clickhouse-monitoring/references/api-endpoints.md delete mode 100644 clickhouse-monitoring/references/api-list.md delete mode 100644 clickhouse-monitoring/references/clickhouse-compat.md delete mode 100644 clickhouse-monitoring/references/dashboard-pages.md delete mode 100644 clickhouse-monitoring/references/development.md delete mode 100644 clickhouse-monitoring/scripts/sync-docs.ts delete mode 100644 clickhouse/.github/workflows/README.md delete mode 100644 clickhouse/.github/workflows/sync-rules.yml delete mode 100644 clickhouse/skills/clickhouse/references/advanced-features.md delete mode 100644 clickhouse/skills/clickhouse/references/backup-restore.md delete mode 100644 clickhouse/skills/clickhouse/references/best-practices.md delete mode 100644 clickhouse/skills/clickhouse/references/cluster-management.md delete mode 100644 clickhouse/skills/clickhouse/references/core-concepts.md delete mode 100644 clickhouse/skills/clickhouse/references/external.md delete mode 100644 clickhouse/skills/clickhouse/references/integrations.md delete mode 100644 clickhouse/skills/clickhouse/references/sql-reference.md delete mode 100644 clickhouse/skills/clickhouse/references/system-queries.md delete mode 100644 clickhouse/skills/clickhouse/references/table-design.md delete mode 100644 clickhouse/skills/clickhouse/references/table-engines.md delete mode 100644 clickhouse/spec/spec-process-cicd-sync-rules.md delete mode 100644 command-code/skills/command-code/references/cli-reference.md delete mode 100644 fix/skills/test-detection.md delete mode 100644 frontend-design/skills/frontend-design/references/shadcn.md delete mode 100755 github/examples/babysit-pr.sh delete mode 100644 github/examples/bulk-close-issues.sh delete mode 100644 github/examples/bulk-merge-prs.sh delete mode 100644 github/examples/pr-automation.sh delete mode 100755 github/examples/watch-and-fix.sh delete mode 100644 github/skills/github.md rename github/skills/{review-bots.md => review-bots/SKILL.md} (92%) create mode 100644 good-html/README.md rename good-html/{ => skills/good-html}/assets/boilerplate.html (100%) rename good-html/{ => skills/good-html}/assets/implementation-plan.html (100%) rename good-html/{ => skills/good-html}/assets/pr-review.html (100%) rename good-html/{ => skills/good-html}/assets/research-explainer.html (100%) delete mode 100644 good-html/skills/good-html/references/page_types.md delete mode 100644 good-html/skills/good-html/references/patterns.md create mode 100644 okf/skills/okf/scripts/__pycache__/render_okf_viewer.cpython-312.pyc create mode 100644 okf/skills/okf/scripts/__pycache__/validate_okf.cpython-312.pyc delete mode 100644 orchestration/skills/orchestration/references/domains/code-review.md delete mode 100644 orchestration/skills/orchestration/references/domains/data-analysis.md delete mode 100644 orchestration/skills/orchestration/references/domains/devops.md delete mode 100644 orchestration/skills/orchestration/references/domains/documentation.md delete mode 100644 orchestration/skills/orchestration/references/domains/project-management.md delete mode 100644 orchestration/skills/orchestration/references/domains/prompt-engineering.md delete mode 100644 orchestration/skills/orchestration/references/domains/python.md delete mode 100644 orchestration/skills/orchestration/references/domains/research.md delete mode 100644 orchestration/skills/orchestration/references/domains/rust.md delete mode 100644 orchestration/skills/orchestration/references/domains/shadcn.md delete mode 100644 orchestration/skills/orchestration/references/domains/software-development.md delete mode 100644 orchestration/skills/orchestration/references/domains/tailwindcss.md delete mode 100644 orchestration/skills/orchestration/references/domains/testing.md delete mode 100644 orchestration/skills/orchestration/references/domains/typescript.md delete mode 100644 orchestration/skills/orchestration/references/examples.md delete mode 100644 orchestration/skills/orchestration/references/guide.md delete mode 100644 orchestration/skills/orchestration/references/patterns.md delete mode 100644 orchestration/skills/orchestration/references/tools.md delete mode 100644 prompt-engineering/skills/prompt-engineering/references/basics.md delete mode 100644 prompt-engineering/skills/prompt-engineering/references/examples.md delete mode 100644 prompt-engineering/skills/prompt-engineering/references/techniques.md delete mode 100644 sag-notify/skills/sag-voice/references/sag-cli.md delete mode 100644 statusline/hooks/hooks.json delete mode 100755 statusline/hooks/session-start.sh create mode 100644 statusline/scripts/__pycache__/statusline.cpython-312.pyc delete mode 100644 statusline/scripts/format-status.ts delete mode 100644 unsloth-training/skills/unsloth-training/reference/domain-examples.md delete mode 100644 unsloth-training/skills/unsloth-training/reference/sft/generate_training_data.py delete mode 100644 unsloth-training/skills/unsloth-training/reference/sft/sales_extractor_training.py delete mode 100644 unsloth-training/skills/unsloth-training/reference/sft/seed_examples.json diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index 3961ce2..083d7d2 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -12,32 +12,32 @@ { "name": "team-agents", "source": "./team-agents", - "description": "Leader, Senior Engineer, and Junior Engineer agents for coordinated parallel task execution", - "version": "1.9.1", + "description": "Leader, senior, and junior engineer agents plus React, TypeScript, backend, and quality skills for parallel work.", + "version": "1.10.0", "category": "Agents", "logo": "./team-agents/assets/logo.svg" }, { "name": "commit", "source": "./commit", - "description": "Create a Git commit with semantic commit message format and PR workflow with templates", - "version": "1.3.2", + "description": "Semantic commits, with optional push or a PR from templates.", + "version": "1.4.0", "category": "Git", "logo": "./commit/assets/logo.svg" }, { "name": "frontend-design", "source": "./frontend-design", - "description": "Create distinctive, production-grade frontend interfaces avoiding AI slop aesthetics", - "version": "1.4.0", + "description": "Distinctive, production-grade frontend design that avoids generic AI aesthetics.", + "version": "1.5.0", "category": "Design", "logo": "./frontend-design/assets/logo.svg" }, { "name": "interview", "source": "./interview", - "description": "Conduct in-depth requirements interviews using Socratic questioning", - "version": "1.0.1", + "description": "Interview the user to clarify requirements, then write a spec.", + "version": "1.1.0", "category": "Productivity", "logo": "./interview/assets/logo.svg" }, @@ -45,7 +45,7 @@ "name": "statusline", "source": "./statusline", "description": "Configurable status bar showing context usage, API rate limits, git branch, and active tools", - "version": "1.9.0", + "version": "2.0.0", "category": "UI", "logo": "./statusline/assets/logo.svg" }, @@ -53,71 +53,71 @@ "name": "orchestration", "source": "./orchestration", "description": "Orchestrator skill for managing parallel agent workstreams", - "version": "1.1.0", + "version": "1.2.0", "category": "Agents", "logo": "./orchestration/assets/logo.svg" }, { "name": "github", "source": "./github", - "description": "GitHub operations using gh CLI - PRs, issues, workflows, batch operations, PR babysitting with AI review bot integration, and smart branch detection", - "version": "1.4.2", + "description": "Drive PRs to merge-ready with gh: fix CI and review-bot feedback, plus bulk merge, close, and label.", + "version": "1.5.0", "category": "Git", "logo": "./github/assets/logo.svg" }, { "name": "fix", "source": "./fix", - "description": "Fix issues, tests, and CI failures with intelligent problem detection", - "version": "1.0.1", + "description": "Fix failing tests, lint, and CI, then commit and push or open or update a PR.", + "version": "1.1.0", "category": "Productivity", "logo": "./fix/assets/logo.svg" }, { "name": "clickhouse", "source": "./clickhouse", - "description": "Comprehensive ClickHouse knowledge base from Altinity KB + official docs", - "version": "1.4.1", + "description": "ClickHouse review rules for schemas, queries, and inserts, with references for debugging and monitoring queries.", + "version": "2.0.0", "category": "Database", "logo": "./clickhouse/assets/logo.svg" }, { "name": "prompt-engineering", "source": "./prompt-engineering", - "description": "Prompt engineering techniques for Grok, Claude, and Gemini LLMs", - "version": "1.1.1", + "description": "Prompting guidance and per-model deltas for Claude, Gemini, and Grok.", + "version": "1.2.0", "category": "Productivity", "logo": "./prompt-engineering/assets/logo.svg" }, { "name": "clickhouse-monitoring", "source": "./clickhouse-monitoring", - "description": "Agent Skill for the ClickHouse Monitor dashboard - a real-time monitoring and observability tool for ClickHouse clusters", - "version": "1.1.1", + "description": "Work on the ClickHouse Monitor dashboard: charts, pages, query configs, its API, and version-aware system queries.", + "version": "1.2.0", "category": "Monitoring", "logo": "./clickhouse-monitoring/assets/logo.svg" }, { "name": "unsloth-training", "source": "./unsloth-training", - "description": "Fine-tune LLMs with Unsloth using GRPO or SFT. Dataset prep, synthetic data, environment flags, MLX (Apple Silicon), FP8, vision, mobile export, GGUF.", - "version": "1.0.2", + "description": "Fine-tune LLMs with Unsloth using GRPO or SFT: rewards, datasets, FP8, vision, MLX, export, mobile.", + "version": "1.1.0", "category": "ML", "logo": "./unsloth-training/assets/logo.svg" }, { "name": "good-html", "source": "./good-html", - "description": "Generate or review high-density, interactive, self-contained HTML artifacts based on Thariq Shihipar's patterns.", - "version": "1.0.0", + "description": "Dense, interactive, self-contained HTML artifacts and reviews.", + "version": "1.1.0", "category": "Design", "logo": "./good-html/assets/logo.svg" }, { "name": "anyrouter", "source": "./anyrouter", - "description": "Wire AnyRouter into coding agents. Universal OpenAI-compatible LLM gateway for 150+ models, migration recipes from Anthropic/OpenAI/OpenRouter, and a remote MCP server for keys and credits.", - "version": "1.0.1", + "description": "Wire AnyRouter, an OpenAI-compatible LLM gateway, into projects and agents, with migration help and an MCP server.", + "version": "1.1.0", "category": "AI", "logo": "./anyrouter/assets/logo.svg" }, @@ -125,7 +125,7 @@ "name": "sag-notify", "source": "./sag-notify", "description": "Spoken voice notifications via sag (ElevenLabs TTS): skill-driven, Claude calls sag directly to speak a short alert just before it asks you something and a one-line summary when work finishes, naming the project. Configurable voice and language.", - "version": "2.1.2", + "version": "2.2.0", "category": "UI", "logo": "./sag-notify/assets/logo.svg" }, @@ -133,23 +133,23 @@ "name": "build-macos-apps", "source": "./build-macos-apps", "description": "Build, debug, instrument, and implement macOS apps with SwiftUI and AppKit guidance, codesigning, packaging, and telemetry workflows.", - "version": "1.0.1", + "version": "1.1.0", "category": "Development", "logo": "./build-macos-apps/assets/logo.svg" }, { "name": "build-ios-apps", "source": "./build-ios-apps", - "description": "Build, profile, debug, and refine iOS apps with SwiftUI and Xcode workflows — App Intents, Simulator debugging, performance profiling, memory leak detection, and on-device AI with Apple Intelligence, Foundation Models, and Core AI.", - "version": "1.0.1", + "description": "Build, debug, and profile iOS apps with SwiftUI, Simulator, App Intents, and on-device AI.", + "version": "1.1.0", "category": "Development", "logo": "./build-ios-apps/assets/logo.svg" }, { "name": "agent-loop", "source": "./agent-loop", - "description": "Continuous agent loop for overnight/day repository maintenance. Orchestrates triage, autoreview, browser automation, and parallel agent work across threads. Wake every 5 min, direct work, land autonomously.", - "version": "0.4.0", + "description": "Unattended repo maintenance that triages issues and PRs, dispatches fixes to parallel subagents, and reports results each scheduled cycle.", + "version": "0.5.0", "category": "Automation", "logo": "./agent-loop/assets/logo.svg" }, @@ -157,7 +157,7 @@ "name": "kb", "source": "./kb", "description": "Knowledge base maintenance skills. Initialize a shared-brain kb, then consolidate, dedupe, prune, refresh, and forget notes in a markdown KB.", - "version": "1.1.0", + "version": "1.2.0", "category": "Productivity", "logo": "./kb/assets/logo.svg" }, @@ -165,15 +165,15 @@ "name": "okf", "source": "./okf", "description": "Open Knowledge Format (OKF) tooling. Author, initialize, validate, render, and refactor knowledge into vendor-neutral OKF v0.1 bundles: markdown files with YAML frontmatter.", - "version": "1.1.0", + "version": "1.2.0", "category": "Productivity", "logo": "./okf/assets/logo.svg" }, { "name": "command-code", "source": "./command-code", - "description": "Drive the Command Code CLI (`cmd`) and orchestrate it as a headless sub-agent — fan out `cmd -p --yolo --max-turns 100000` workers across isolated git worktrees to implement issues and tasks in parallel.", - "version": "1.0.0", + "description": "Dispatch the Command Code CLI (`cmd`) as headless sub-agents across isolated git worktrees.", + "version": "1.1.0", "category": "Development", "logo": "./command-code/assets/logo.svg" } diff --git a/.cursor-plugin/marketplace.json b/.cursor-plugin/marketplace.json index 93a71b3..7b84568 100644 --- a/.cursor-plugin/marketplace.json +++ b/.cursor-plugin/marketplace.json @@ -10,22 +10,22 @@ { "name": "team-agents", "source": "team-agents", - "description": "Leader, Senior Engineer, and Junior Engineer agents for coordinated parallel task execution" + "description": "Leader, senior, and junior engineer agents plus React, TypeScript, backend, and quality skills for parallel work." }, { "name": "commit", "source": "commit", - "description": "Create a Git commit with semantic commit message format and PR workflow with templates" + "description": "Semantic commits, with optional push or a PR from templates." }, { "name": "frontend-design", "source": "frontend-design", - "description": "Create distinctive, production-grade frontend interfaces avoiding AI slop aesthetics" + "description": "Distinctive, production-grade frontend design that avoids generic AI aesthetics." }, { "name": "interview", "source": "interview", - "description": "Conduct in-depth requirements interviews using Socratic questioning" + "description": "Interview the user to clarify requirements, then write a spec." }, { "name": "statusline", @@ -40,42 +40,42 @@ { "name": "github", "source": "github", - "description": "GitHub operations using gh CLI - PRs, issues, workflows, batch operations, PR babysitting with AI review bot integration, and smart branch detection" + "description": "Drive PRs to merge-ready with gh: fix CI and review-bot feedback, plus bulk merge, close, and label." }, { "name": "fix", "source": "fix", - "description": "Fix issues, tests, and CI failures with intelligent problem detection" + "description": "Fix failing tests, lint, and CI, then commit and push or open or update a PR." }, { "name": "clickhouse", "source": "clickhouse", - "description": "Comprehensive ClickHouse knowledge base from Altinity KB + official docs" + "description": "ClickHouse review rules for schemas, queries, and inserts, with references for debugging and monitoring queries." }, { "name": "prompt-engineering", "source": "prompt-engineering", - "description": "Prompt engineering techniques for Grok, Claude, and Gemini LLMs" + "description": "Prompting guidance and per-model deltas for Claude, Gemini, and Grok." }, { "name": "clickhouse-monitoring", "source": "clickhouse-monitoring", - "description": "Agent Skill for the ClickHouse Monitor dashboard - a real-time monitoring and observability tool for ClickHouse clusters" + "description": "Work on the ClickHouse Monitor dashboard: charts, pages, query configs, its API, and version-aware system queries." }, { "name": "unsloth-training", "source": "unsloth-training", - "description": "Fine-tune LLMs with Unsloth using GRPO or SFT. Dataset prep, synthetic data, environment flags, MLX (Apple Silicon), FP8, vision, mobile export, GGUF." + "description": "Fine-tune LLMs with Unsloth using GRPO or SFT: rewards, datasets, FP8, vision, MLX, export, mobile." }, { "name": "good-html", "source": "good-html", - "description": "Generate or review high-density, interactive, self-contained HTML artifacts based on Thariq Shihipar's patterns." + "description": "Dense, interactive, self-contained HTML artifacts and reviews." }, { "name": "anyrouter", "source": "anyrouter", - "description": "Wire AnyRouter into coding agents. Universal OpenAI-compatible LLM gateway for 150+ models, migration recipes from Anthropic/OpenAI/OpenRouter, and a remote MCP server for keys and credits." + "description": "Wire AnyRouter, an OpenAI-compatible LLM gateway, into projects and agents, with migration help and an MCP server." }, { "name": "sag-notify", @@ -90,12 +90,12 @@ { "name": "build-ios-apps", "source": "build-ios-apps", - "description": "Build, profile, debug, and refine iOS apps with SwiftUI and Xcode workflows — App Intents, Simulator debugging, performance profiling, memory leak detection, and on-device AI with Apple Intelligence, Foundation Models, and Core AI." + "description": "Build, debug, and profile iOS apps with SwiftUI, Simulator, App Intents, and on-device AI." }, { "name": "agent-loop", "source": "agent-loop", - "description": "Continuous agent loop for overnight/day repository maintenance. Orchestrates triage, autoreview, browser automation, and parallel agent work across threads. Wake every 5 min, direct work, land autonomously." + "description": "Unattended repo maintenance that triages issues and PRs, dispatches fixes to parallel subagents, and reports results each scheduled cycle." }, { "name": "kb", @@ -110,7 +110,7 @@ { "name": "command-code", "source": "command-code", - "description": "Drive the Command Code CLI (`cmd`) and orchestrate it as a headless sub-agent — fan out `cmd -p --yolo --max-turns 100000` workers across isolated git worktrees to implement issues and tasks in parallel." + "description": "Dispatch the Command Code CLI (`cmd`) as headless sub-agents across isolated git worktrees." } ] } diff --git a/.cursor/skills/verify-marketplace/references/features/docs-and-readme.md b/.cursor/skills/verify-marketplace/references/features/docs-and-readme.md index f5e5734..f08d4d5 100644 --- a/.cursor/skills/verify-marketplace/references/features/docs-and-readme.md +++ b/.cursor/skills/verify-marketplace/references/features/docs-and-readme.md @@ -51,9 +51,9 @@ Preconditions: ## Gotchas -- Root README is partly generated by `docs-generator`. A docs-generator run - can drop Codex or Skills CLI sections if templates lag. Assert needles after - regenerating README. +- The root README plugin table is generated by `scripts/plugins.py sync` + between the `plugins:start` and `plugins:end` markers. Edit + `marketplace.json`, not the table. - `good-html` may lack `README.md` while still being a valid plugin. That is a docs gap, not a manifest gap. - Do not scrape GitHub rendered README as proof; read the files in the diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index 3800160..0ba6928 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -26,8 +26,6 @@ Add any other context or screenshots about the feature request here. - [ ] interview - [ ] statusline - [ ] orchestration -- [ ] duyetbot -- [ ] docs-generator - [ ] github - [ ] fix - [ ] clickhouse diff --git a/.github/workflows/sync-skills.yml b/.github/workflows/sync-skills.yml index d0c1530..e8adfb7 100644 --- a/.github/workflows/sync-skills.yml +++ b/.github/workflows/sync-skills.yml @@ -6,30 +6,14 @@ name: Sync skills to duyet/skills push: branches: [master] paths: - - "clickhouse/**" - - "clickhouse-monitoring/**" - - "frontend-design/**" - - "orchestration/**" - - "prompt-engineering/**" - - "unsloth-training/**" - - "duyetbot/**" - - "github/**" - - "good-html/**" - - "anyrouter/**" - - "marketplace.json" + - "*/skills/**" - ".github/workflows/sync-skills.yml" workflow_dispatch: permissions: contents: read -# Plugins whose skills/ subdirs (or root SKILL.md, for good-html) flatten -# into duyet/skills. Edit this list to add or remove synced plugins. -env: - SOURCE_PLUGINS: >- - clickhouse clickhouse-monitoring frontend-design orchestration - prompt-engineering unsloth-training duyetbot github good-html anyrouter - +# Every plugin skills//SKILL.md dir flattens into duyet/skills. jobs: sync: runs-on: ubuntu-latest @@ -62,17 +46,10 @@ jobs: # Collect target skill dirs we are about to replace, so we # can prune them cleanly before copying fresh content. declare -a TARGET_SKILLS=() - for plugin in $SOURCE_PLUGINS; do - if [ -f "$plugin/SKILL.md" ]; then - # Root-level SKILL.md (e.g. good-html). Use plugin name. - TARGET_SKILLS+=("$plugin") - elif [ -d "$plugin/skills" ]; then - while IFS= read -r -d '' dir; do - TARGET_SKILLS+=("$(basename "$dir")") - done < <(find "$plugin/skills" -mindepth 2 -maxdepth 2 \ - -name SKILL.md -printf '%h\0') - fi - done + while IFS= read -r -d '' dir; do + TARGET_SKILLS+=("$(basename "$dir")") + done < <(find . -mindepth 4 -maxdepth 4 -path './*/skills/*/SKILL.md' \ + -not -path './.*' -printf '%h\0') echo "Refreshing: ${TARGET_SKILLS[*]}" @@ -82,23 +59,10 @@ jobs: done # Copy each skill dir flat into the target. - for plugin in $SOURCE_PLUGINS; do - if [ -f "$plugin/SKILL.md" ]; then - mkdir -p "../target/$plugin" - cp "$plugin/SKILL.md" "../target/$plugin/SKILL.md" - for extra in assets references reference rules; do - if [ -d "$plugin/$extra" ]; then - cp -r "$plugin/$extra" "../target/$plugin/$extra" - fi - done - elif [ -d "$plugin/skills" ]; then - while IFS= read -r -d '' dir; do - name="$(basename "$dir")" - cp -r "$dir" "../target/$name" - done < <(find "$plugin/skills" -mindepth 2 -maxdepth 2 \ - -name SKILL.md -printf '%h\0') - fi - done + while IFS= read -r -d '' dir; do + cp -r "$dir" "../target/$(basename "$dir")" + done < <(find . -mindepth 4 -maxdepth 4 -path './*/skills/*/SKILL.md' \ + -not -path './.*' -printf '%h\0') sha="$(git rev-parse HEAD)" { @@ -133,7 +97,7 @@ jobs: BRANCH="sync/codex-${SHORT}" MSG="chore: sync skills from codex-claude-plugins@${SHORT}" git config user.name "duyetbot" - git config user.email "bot@duyet.net" + git config user.email "duyetbot@users.noreply.github.com" git checkout -b "$BRANCH" git commit -m "$MSG" git push -u origin "$BRANCH" --force-with-lease diff --git a/.grok-plugin/marketplace.json b/.grok-plugin/marketplace.json index 8b0929d..2650ca6 100644 --- a/.grok-plugin/marketplace.json +++ b/.grok-plugin/marketplace.json @@ -8,7 +8,7 @@ "plugins": [ { "name": "team-agents", - "description": "Leader, Senior Engineer, and Junior Engineer agents for coordinated parallel task execution", + "description": "Leader, senior, and junior engineer agents plus React, TypeScript, backend, and quality skills for parallel work.", "category": "Agents", "source": { "type": "local", @@ -19,7 +19,7 @@ "team-agents" ], "logo": "assets/logo.svg", - "version": "1.9.1", + "version": "1.10.0", "author": { "name": "duyet", "url": "https://github.com/duyet" @@ -27,7 +27,7 @@ }, { "name": "commit", - "description": "Create a Git commit with semantic commit message format and PR workflow with templates", + "description": "Semantic commits, with optional push or a PR from templates.", "category": "Git", "source": { "type": "local", @@ -38,7 +38,7 @@ "commit" ], "logo": "assets/logo.svg", - "version": "1.3.2", + "version": "1.4.0", "author": { "name": "duyet", "url": "https://github.com/duyet" @@ -46,7 +46,7 @@ }, { "name": "frontend-design", - "description": "Create distinctive, production-grade frontend interfaces avoiding AI slop aesthetics", + "description": "Distinctive, production-grade frontend design that avoids generic AI aesthetics.", "category": "Design", "source": { "type": "local", @@ -57,7 +57,7 @@ "frontend-design" ], "logo": "assets/logo.svg", - "version": "1.4.0", + "version": "1.5.0", "author": { "name": "duyet", "url": "https://github.com/duyet" @@ -65,7 +65,7 @@ }, { "name": "interview", - "description": "Conduct in-depth requirements interviews using Socratic questioning", + "description": "Interview the user to clarify requirements, then write a spec.", "category": "Productivity", "source": { "type": "local", @@ -76,7 +76,7 @@ "interview" ], "logo": "assets/logo.svg", - "version": "1.0.1", + "version": "1.1.0", "author": { "name": "duyet", "url": "https://github.com/duyet" @@ -95,7 +95,7 @@ "statusline" ], "logo": "assets/logo.svg", - "version": "1.9.0", + "version": "2.0.0", "author": { "name": "duyet", "url": "https://github.com/duyet" @@ -114,7 +114,7 @@ "orchestration" ], "logo": "assets/logo.svg", - "version": "1.1.0", + "version": "1.2.0", "author": { "name": "duyet", "url": "https://github.com/duyet" @@ -122,7 +122,7 @@ }, { "name": "github", - "description": "GitHub operations using gh CLI - PRs, issues, workflows, batch operations, PR babysitting with AI review bot integration, and smart branch detection", + "description": "Drive PRs to merge-ready with gh: fix CI and review-bot feedback, plus bulk merge, close, and label.", "category": "Git", "source": { "type": "local", @@ -133,7 +133,7 @@ "github" ], "logo": "assets/logo.svg", - "version": "1.4.2", + "version": "1.5.0", "author": { "name": "duyet", "url": "https://github.com/duyet" @@ -141,7 +141,7 @@ }, { "name": "fix", - "description": "Fix issues, tests, and CI failures with intelligent problem detection", + "description": "Fix failing tests, lint, and CI, then commit and push or open or update a PR.", "category": "Productivity", "source": { "type": "local", @@ -152,7 +152,7 @@ "fix" ], "logo": "assets/logo.svg", - "version": "1.0.1", + "version": "1.1.0", "author": { "name": "duyet", "url": "https://github.com/duyet" @@ -160,7 +160,7 @@ }, { "name": "clickhouse", - "description": "Comprehensive ClickHouse knowledge base from Altinity KB + official docs", + "description": "ClickHouse review rules for schemas, queries, and inserts, with references for debugging and monitoring queries.", "category": "Database", "source": { "type": "local", @@ -171,7 +171,7 @@ "clickhouse" ], "logo": "assets/logo.svg", - "version": "1.4.1", + "version": "2.0.0", "author": { "name": "duyet", "url": "https://github.com/duyet" @@ -179,7 +179,7 @@ }, { "name": "prompt-engineering", - "description": "Prompt engineering techniques for Grok, Claude, and Gemini LLMs", + "description": "Prompting guidance and per-model deltas for Claude, Gemini, and Grok.", "category": "Productivity", "source": { "type": "local", @@ -190,7 +190,7 @@ "prompt-engineering" ], "logo": "assets/logo.svg", - "version": "1.1.1", + "version": "1.2.0", "author": { "name": "duyet", "url": "https://github.com/duyet" @@ -198,7 +198,7 @@ }, { "name": "clickhouse-monitoring", - "description": "Agent Skill for the ClickHouse Monitor dashboard - a real-time monitoring and observability tool for ClickHouse clusters", + "description": "Work on the ClickHouse Monitor dashboard: charts, pages, query configs, its API, and version-aware system queries.", "category": "Monitoring", "source": { "type": "local", @@ -209,7 +209,7 @@ "clickhouse-monitoring" ], "logo": "assets/logo.svg", - "version": "1.1.1", + "version": "1.2.0", "author": { "name": "duyet", "url": "https://github.com/duyet" @@ -217,7 +217,7 @@ }, { "name": "unsloth-training", - "description": "Fine-tune LLMs with Unsloth using GRPO or SFT. Dataset prep, synthetic data, environment flags, MLX (Apple Silicon), FP8, vision, mobile export, GGUF.", + "description": "Fine-tune LLMs with Unsloth using GRPO or SFT: rewards, datasets, FP8, vision, MLX, export, mobile.", "category": "ML", "source": { "type": "local", @@ -228,7 +228,7 @@ "unsloth-training" ], "logo": "assets/logo.svg", - "version": "1.0.2", + "version": "1.1.0", "author": { "name": "duyet", "url": "https://github.com/duyet" @@ -236,7 +236,7 @@ }, { "name": "good-html", - "description": "Generate or review high-density, interactive, self-contained HTML artifacts based on Thariq Shihipar's patterns.", + "description": "Dense, interactive, self-contained HTML artifacts and reviews.", "category": "Design", "source": { "type": "local", @@ -247,7 +247,7 @@ "good-html" ], "logo": "assets/logo.svg", - "version": "1.0.0", + "version": "1.1.0", "author": { "name": "duyet", "url": "https://github.com/duyet" @@ -255,7 +255,7 @@ }, { "name": "anyrouter", - "description": "Wire AnyRouter into coding agents. Universal OpenAI-compatible LLM gateway for 150+ models, migration recipes from Anthropic/OpenAI/OpenRouter, and a remote MCP server for keys and credits.", + "description": "Wire AnyRouter, an OpenAI-compatible LLM gateway, into projects and agents, with migration help and an MCP server.", "category": "AI", "source": { "type": "local", @@ -266,7 +266,7 @@ "anyrouter" ], "logo": "assets/logo.svg", - "version": "1.0.1", + "version": "1.1.0", "author": { "name": "duyet", "url": "https://github.com/duyet" @@ -285,7 +285,7 @@ "sag-notify" ], "logo": "assets/logo.svg", - "version": "2.1.2", + "version": "2.2.0", "author": { "name": "duyet", "url": "https://github.com/duyet" @@ -304,7 +304,7 @@ "build-macos-apps" ], "logo": "assets/logo.svg", - "version": "1.0.1", + "version": "1.1.0", "author": { "name": "duyet", "url": "https://github.com/duyet" @@ -312,7 +312,7 @@ }, { "name": "build-ios-apps", - "description": "Build, profile, debug, and refine iOS apps with SwiftUI and Xcode workflows — App Intents, Simulator debugging, performance profiling, memory leak detection, and on-device AI with Apple Intelligence, Foundation Models, and Core AI.", + "description": "Build, debug, and profile iOS apps with SwiftUI, Simulator, App Intents, and on-device AI.", "category": "Development", "source": { "type": "local", @@ -323,7 +323,7 @@ "build-ios-apps" ], "logo": "assets/logo.svg", - "version": "1.0.1", + "version": "1.1.0", "author": { "name": "duyet", "url": "https://github.com/duyet" @@ -331,7 +331,7 @@ }, { "name": "agent-loop", - "description": "Continuous agent loop for overnight/day repository maintenance. Orchestrates triage, autoreview, browser automation, and parallel agent work across threads. Wake every 5 min, direct work, land autonomously.", + "description": "Unattended repo maintenance that triages issues and PRs, dispatches fixes to parallel subagents, and reports results each scheduled cycle.", "category": "Automation", "source": { "type": "local", @@ -342,7 +342,7 @@ "agent-loop" ], "logo": "assets/logo.svg", - "version": "0.4.0", + "version": "0.5.0", "author": { "name": "duyet", "url": "https://github.com/duyet" @@ -361,7 +361,7 @@ "kb" ], "logo": "assets/logo.svg", - "version": "1.1.0", + "version": "1.2.0", "author": { "name": "duyet", "url": "https://github.com/duyet" @@ -380,7 +380,7 @@ "okf" ], "logo": "assets/logo.svg", - "version": "1.1.0", + "version": "1.2.0", "author": { "name": "duyet", "url": "https://github.com/duyet" @@ -388,7 +388,7 @@ }, { "name": "command-code", - "description": "Drive the Command Code CLI (`cmd`) and orchestrate it as a headless sub-agent — fan out `cmd -p --yolo --max-turns 100000` workers across isolated git worktrees to implement issues and tasks in parallel.", + "description": "Dispatch the Command Code CLI (`cmd`) as headless sub-agents across isolated git worktrees.", "category": "Development", "source": { "type": "local", @@ -399,7 +399,7 @@ "command-code" ], "logo": "assets/logo.svg", - "version": "1.0.0", + "version": "1.1.0", "author": { "name": "duyet", "url": "https://github.com/duyet" diff --git a/CLAUDE.md b/CLAUDE.md index d0860d4..6ca0ecc 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -26,17 +26,15 @@ For Antigravity CLI, install/symlink a plugin locally for development: ## Plugin Metadata -Codex plugin metadata is maintained beside Claude metadata in each plugin: - -- Claude manifest: `.claude-plugin/plugin.json` -- Codex manifest: `.codex-plugin/plugin.json` -- Grok Bot / Grok Build manifest: `.grok-plugin/plugin.json` -- Grok Build interface manifest: `.grok-build-plugin/plugin.json` -- Antigravity manifest: `.antigravity-plugin/plugin.json` -- Claude marketplace: `marketplace.json` and `.claude-plugin/marketplace.json` -- Codex marketplace: `.agents/plugins/marketplace.json` -- Grok marketplace: `.grok-plugin/marketplace.json` -- Plugin logo: `assets/logo.svg` (referenced from every harness manifest) +`marketplace.json` is the only hand-edited manifest. Each entry holds `name`, `displayName`, `description`, `version`, `category`. `python3 scripts/plugins.py sync` generates the rest, and `bash scripts/validate-plugins.sh` fails on drift: + +- Claude: `/.claude-plugin/plugin.json`, `.claude-plugin/marketplace.json` +- Codex: `/.codex-plugin/plugin.json`, `.agents/plugins/marketplace.json` +- Cursor: `/.cursor-plugin/plugin.json`, `.cursor-plugin/marketplace.json` +- Grok Bot / Grok Build: `/.grok-plugin/plugin.json`, `/.grok-build-plugin/plugin.json`, `.grok-plugin/marketplace.json` +- Antigravity: `/.antigravity-plugin/plugin.json`, only where that directory exists +- README plugin table between the `plugins:start` and `plugins:end` markers +- Plugin logo: `/assets/logo.svg` ## Versioning @@ -55,30 +53,23 @@ Follow semantic versioning (semver) for all plugins: - Updating documentation only → **Patch** - Bug fixes → **Patch** -Always update `plugin.json` version when making changes. +Bump the version in `marketplace.json`, then run `python3 scripts/plugins.py sync`. Removing or renaming a skill or command users invoke is a major bump. ## Plugin Structure ```text plugin-name/ -├── .claude-plugin/ -│ └── plugin.json # Manifest (name, version, description, logo) -├── .codex-plugin/ -│ └── plugin.json # Codex manifest and interface metadata -├── .grok-plugin/ -│ └── plugin.json # Grok Bot / Grok Build manifest -├── .grok-build-plugin/ -│ └── plugin.json # Grok Build interface metadata -├── assets/ -│ └── logo.svg # Rendered by every listed harness -├── agents/ # Sub-agent definitions -├── commands/ # Slash commands -├── skills/ # Reusable knowledge/procedures -├── hooks/ # Hook configurations -└── README.md # Documentation +├── .claude-plugin/ .codex-plugin/ .cursor-plugin/ .grok-plugin/ .grok-build-plugin/ # generated +├── assets/logo.svg +├── skills//SKILL.md # name frontmatter must equal +├── commands/*.md # description frontmatter required +├── agents/*.md # description frontmatter required +├── hooks/hooks.json +├── .mcp.json +└── README.md # short, with the /plugin install line ``` -When changing plugin metadata, keep Claude, Codex, and Grok manifests in sync and run `bash scripts/validate-plugins.sh`. +Links inside a plugin must stay inside it. A plugin installs alone, so never link `../other-plugin/`. ## No Personal / Environment-Specific Information diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 0d26454..0a0ffac 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,224 +1,27 @@ # Contributing -Thanks for your interest in contributing to the Claude, Codex, and Grok Plugins Marketplace! +## Add or change a plugin -## Quick Start +1. Create `/` with any of `skills//SKILL.md`, `commands/*.md`, `agents/*.md`, `hooks/hooks.json`, `.mcp.json`, plus `assets/logo.svg` and a short `README.md`. +2. Add or edit its entry in `marketplace.json`: `name`, `displayName`, `description`, `version`, `category`. +3. Run `python3 scripts/plugins.py sync`. It writes the Claude, Codex, Cursor, Grok, Grok Build, and Antigravity manifests, every harness marketplace, and the README plugin table. Never edit those files by hand. +4. Run `bash scripts/validate-plugins.sh`. It fails on manifest drift, skills without matching `name` frontmatter, commands or agents without `description`, broken relative links, and em dashes. -1. Fork the repository -2. Create a feature branch: `git checkout -b feature/my-new-plugin` -3. Make your changes -4. Push to your fork: `git push origin feature/my-new-plugin` -5. Open a Pull Request +## Writing skills -## Plugin Structure +- Keep only prose that changes the agent's decision. Cut what a strong model already knows. +- One home per idea. A command that repeats a skill should point at the skill by path. +- Write harness-neutral steps that work in Claude Code, Codex, and Cursor. +- No personal paths, hosts, emails, or account ids. See `CLAUDE.md`. -```text -my-plugin/ -├── .claude-plugin/ -│ └── plugin.json # Plugin manifest (name, version, description, logo) -├── .codex-plugin/ -│ └── plugin.json # Codex manifest and interface metadata -├── .grok-plugin/ -│ └── plugin.json # Grok Bot / Grok Build manifest -├── .grok-build-plugin/ -│ └── plugin.json # Grok Build interface metadata -├── assets/ -│ └── logo.svg # Local logo rendered by every listed harness -├── README.md # Plugin documentation -├── CLAUDE.md # Claude-specific instructions (optional, for skills/agents) -├── agents/ # Agent definitions (optional) -├── commands/ # Slash commands (optional) -├── skills/ # Reusable knowledge (optional) -└── hooks/hooks.json # Lifecycle hooks (optional) -``` +## Versioning -## Creating a New Plugin +Semver per plugin, set in `marketplace.json`. Patch for docs and fixes, minor for new or changed behavior, major when a command or skill users invoke is removed or renamed. -### 1. Plugin Manifest (.claude-plugin/plugin.json) +## Pull requests -```json -{ - "name": "my-plugin", - "description": "A brief description of what this plugin does", - "version": "1.0.0", - "author": { - "name": "your-username" - }, - "logo": "./assets/logo.svg" -} -``` - -### 2. Codex Manifest (.codex-plugin/plugin.json) - -Every plugin also needs a Codex manifest with the same `name`, `version`, `description`, and `author.name` as the Claude manifest: - -```json -{ - "name": "my-plugin", - "version": "1.0.0", - "description": "A brief description of what this plugin does", - "author": { - "name": "your-username" - }, - "skills": "./skills/", - "interface": { - "displayName": "My Plugin", - "shortDescription": "A brief description of what this plugin does", - "developerName": "your-username", - "category": "Productivity", - "capabilities": ["Skill"], - "logo": "./assets/logo.svg", - "composerIcon": "./assets/logo.svg" - } -} -``` - -Copy `assets/logo.svg` from another plugin (or the repo-root `assets/logo.svg`). Point every harness at that local file — remote URLs do not render reliably after install. - -### 3. Grok Bot / Grok Build Manifests - -`.grok-plugin/plugin.json` is the official Grok Bot + Grok Build manifest. `.grok-build-plugin/plugin.json` mirrors the Codex interface metadata for Grok Build. Keep `name`, `version`, `description`, and `author.name` identical across Claude, Codex, Grok, and Grok Build manifests: - -```json -{ - "name": "my-plugin", - "version": "1.0.0", - "description": "A brief description of what this plugin does", - "author": { - "name": "your-username" - }, - "logo": "assets/logo.svg", - "skills": "./skills/" -} -``` - -### 4. Documentation (README.md) - -Required sections: - -- Description of what the plugin does -- Installation instructions -- Usage examples -- Configuration options (if any) -- Versioning guidelines (if applicable) - -### 5. Claude Instructions (CLAUDE.md) - -Required for skills and agents: - -- How Claude should use the plugin -- When to invoke it -- Expected inputs and outputs - -### 6. Update Marketplaces - -Add your plugin to `marketplace.json`: - -```json -{ - "name": "my-plugin", - "id": "my-plugin@duyet-claude-plugins", - "description": "...", - "version": "1.0.0", - "type": "skill|command|hook", - "category": "your-category", - "logo": "./my-plugin/assets/logo.svg" -} -``` - -Also add a Codex entry to `.agents/plugins/marketplace.json`: - -```json -{ - "name": "my-plugin", - "source": { - "source": "local", - "path": "./my-plugin" - }, - "policy": { - "installation": "AVAILABLE", - "authentication": "ON_INSTALL" - }, - "category": "Productivity" -} -``` - -Also add a Grok entry to `.grok-plugin/marketplace.json` (Grok Build + Grok Bot): - -```json -{ - "name": "my-plugin", - "description": "...", - "category": "productivity", - "source": { - "type": "local", - "path": "./my-plugin" - }, - "logo": "assets/logo.svg" -} -``` - -Include `logo` on the Claude marketplace entry (`./my-plugin/assets/logo.svg`) and Codex marketplace `interface.logo` / `interface.composerIcon`. - -### 7. Update Main README - -Add your plugin to the main README.md table: - -| Plugin | Type | Description | -| ---------------------------- | ---- | ----------- | -| [🔧 my-plugin](./my-plugin/) | Type | Description | - -## Development Guidelines - -### Code Quality - -- Write clear, well-documented code -- Follow existing patterns in the codebase -- Keep changes focused and atomic - -### Versioning - -Follow [Semantic Versioning](https://semver.org/): - -- **Patch** (1.0.0 → 1.0.1): Bug fixes, documentation -- **Minor** (1.0.0 → 1.1.0): New features, non-breaking changes -- **Major** (1.0.0 → 2.0.0): Breaking changes - -Update plugin.json version on every change. -Keep `.claude-plugin/plugin.json`, `.codex-plugin/plugin.json`, `.grok-plugin/plugin.json`, and `.grok-build-plugin/plugin.json` in sync for shared metadata fields. - -### Commits - -Use conventional commits with plugin scope: - -```bash -feat(my-plugin): add new feature -fix(my-plugin): fix bug -docs(my-plugin): update documentation -test(my-plugin): add tests -refactor(my-plugin): refactor code -``` - -### Testing - -- Test your plugin thoroughly before submitting -- Include usage examples in README -- Consider edge cases and error handling -- Run `bash scripts/validate-plugins.sh` to validate Claude, Codex, Grok, Grok Build, and Antigravity manifests plus marketplace files - -## Pull Request Process - -1. **Title**: Use conventional commit format (e.g., `feat(my-plugin): add X`) -2. **Description**: Explain what and why -3. **Link issues**: `Fixes #123` if applicable -4. **Co-author**: Add if using duyetbot: `Co-Authored-By: duyetbot ` +Use semantic titles with the plugin as scope, for example `feat(github): add bulk label`. Explain what changed and why. ## License -By contributing, you agree that your contributions will be licensed under the MIT License. - -## Getting Help - -- Check [existing issues](https://github.com/duyet/codex-claude-plugins/issues) -- Use [feature request template](.github/ISSUE_TEMPLATE/feature_request.md) for new ideas -- Use [bug report template](.github/ISSUE_TEMPLATE/bug_report.md) for issues +Contributions are licensed under MIT. diff --git a/README.md b/README.md index c5fcf9b..d7ecd13 100644 --- a/README.md +++ b/README.md @@ -1,383 +1,76 @@ -# Claude/Codex/Grok Plugins +# Claude, Codex, Cursor, and Grok plugins -[![GitHub Release](https://img.shields.io/github/v/duyet/codex-claude-plugins?style=flat-square)](https://github.com/duyet/codex-claude-plugins/releases) [![License](https://img.shields.io/github/license/duyet/codex-claude-plugins?style=flat-square)](LICENSE) -[![Plugins](https://img.shields.io/badge/plugins-14-blue?style=flat-square)](#plugins-at-a-glance) -> Extend Claude Code, Codex, Grok Build, and Grok Bot with specialized agents, commands, and skills from one shared plugin collection. +Agent workflows, git automation, and developer skills packaged once for Claude Code, Codex, Cursor, Grok Build, Grok Bot, and the [skills.sh](https://skills.sh) CLI. -A collection of production-quality plugins for Claude Code, Codex, Grok Build, and Grok Bot, including autonomous agents, workflow automation, statusline utilities, prompt engineering guidance, and developer tools. +## Install -**Latest Release:** [v1.0.0](https://github.com/duyet/codex-claude-plugins/releases/tag/v1.0.0) | [CHANGELOG](CHANGELOG.md) | [Issues](https://github.com/duyet/codex-claude-plugins/issues) - -Available on **[skills.sh](https://skills.sh)** — the open agent skills ecosystem. - -## Quick Install - -### Claude Code - -Use Claude Code's plugin marketplace commands: +Claude Code: ```bash -# Add marketplace /plugin marketplace add duyet/codex-claude-plugins - -# Install plugins -/plugin install team-agents@duyet-claude-plugins -/plugin install commit@duyet-claude-plugins -/plugin install frontend-design@duyet-claude-plugins -/plugin install interview@duyet-claude-plugins -/plugin install statusline@duyet-claude-plugins -/plugin install orchestration@duyet-claude-plugins -/plugin install duyetbot@duyet-claude-plugins -/plugin install docs-generator@duyet-claude-plugins -/plugin install github@duyet-claude-plugins -/plugin install fix@duyet-claude-plugins -/plugin install clickhouse-monitoring@duyet-claude-plugins -``` - -### Codex - -Codex support is provided through the repo-local Codex marketplace file: - -```bash -git clone https://github.com/duyet/codex-claude-plugins.git -cd codex-claude-plugins +/plugin install @duyet-claude-plugins ``` -Then add or import the local Codex marketplace from: - -```text -.agents/plugins/marketplace.json -``` +Cursor: add `duyet/codex-claude-plugins` as a plugin marketplace, then install from the `duyet-claude-plugins` catalog. The index is `.cursor-plugin/marketplace.json`. -That marketplace points each plugin at the matching local folder, for example: - -```json -{ - "name": "github", - "source": { - "source": "local", - "path": "./github" - } -} -``` +Codex: clone the repo and add the local marketplace at `.agents/plugins/marketplace.json`. -After the marketplace is added in Codex, install the plugins you want from the `Duyet Claude, Codex, and Grok Plugins` marketplace. Codex-facing workflow skills are available under each plugin's `skills/` folder, including wrappers for Claude command-heavy plugins such as `commit`, `github`, `fix`, `statusline`, `team-agents`, and `duyetbot`. - -### Grok Build - -Grok Build reads the same pack through the Grok marketplace index: - -```bash -grok plugin marketplace add duyet/codex-claude-plugins -grok plugin install team-agents --trust -grok plugin install commit --trust -grok plugin install github --trust -``` - -Browse the catalog in the TUI with `/marketplace` or `/plugin`, then press `i` to install. Every plugin folder ships `.grok-plugin/plugin.json` (Grok Bot + Grok Build) and `.grok-build-plugin/plugin.json` (Grok Build interface metadata) beside the Claude and Codex manifests. - -### Grok Bot - -Grok Bot uses the same `.grok-plugin/` marketplace as Grok Build. Add the pack once, then install plugins from the `duyet-claude-plugins` catalog: +Grok Build and Grok Bot: ```bash grok plugin marketplace add duyet/codex-claude-plugins grok plugin install --trust ``` -In the Grok Bot app, open **Plugins** and add `duyet/codex-claude-plugins` as a marketplace source if the CLI is not available. Plugin logos render from each plugin's `assets/logo.svg`. - -### Alternative: Skills CLI - -Install via the open [Skills](https://skills.sh) ecosystem, works with Claude Code, Cursor, GitHub Copilot, Gemini, Windsurf, and [15+ other agents](https://skills.sh): +Any agent that supports skills.sh: ```bash npx skills add duyet/codex-claude-plugins ``` -### Harness Metadata - -This repository ships per-harness plugin metadata in place: - -- Claude Code: `.claude-plugin/plugin.json` plus `marketplace.json` and `.claude-plugin/marketplace.json`. -- Codex: `.codex-plugin/plugin.json` plus `.agents/plugins/marketplace.json`. -- Grok Bot: `.grok-plugin/plugin.json`. -- Grok Build: `.grok-build-plugin/plugin.json` plus the shared Grok index at `.grok-plugin/marketplace.json`. -- Antigravity (where present): `.antigravity-plugin/plugin.json`. -- Logos: each plugin's `assets/logo.svg`, referenced from every harness manifest and marketplace so listings render the same mark. -- Claude slash commands and agents stay in their original folders; Codex-facing wrapper skills live under `skills/*-workflow/SKILL.md` where a plugin needs a Codex entry point. +## Plugins + + +| Plugin | Category | Description | +| --- | --- | --- | +| [team-agents](./team-agents/) | Agents | Leader, senior, and junior engineer agents plus React, TypeScript, backend, and quality skills for parallel work. | +| [commit](./commit/) | Git | Semantic commits, with optional push or a PR from templates. | +| [frontend-design](./frontend-design/) | Design | Distinctive, production-grade frontend design that avoids generic AI aesthetics. | +| [interview](./interview/) | Productivity | Interview the user to clarify requirements, then write a spec. | +| [statusline](./statusline/) | UI | Configurable status bar showing context usage, API rate limits, git branch, and active tools | +| [orchestration](./orchestration/) | Agents | Orchestrator skill for managing parallel agent workstreams | +| [github](./github/) | Git | Drive PRs to merge-ready with gh: fix CI and review-bot feedback, plus bulk merge, close, and label. | +| [fix](./fix/) | Productivity | Fix failing tests, lint, and CI, then commit and push or open or update a PR. | +| [clickhouse](./clickhouse/) | Database | ClickHouse review rules for schemas, queries, and inserts, with references for debugging and monitoring queries. | +| [prompt-engineering](./prompt-engineering/) | Productivity | Prompting guidance and per-model deltas for Claude, Gemini, and Grok. | +| [clickhouse-monitoring](./clickhouse-monitoring/) | Monitoring | Work on the ClickHouse Monitor dashboard: charts, pages, query configs, its API, and version-aware system queries. | +| [unsloth-training](./unsloth-training/) | ML | Fine-tune LLMs with Unsloth using GRPO or SFT: rewards, datasets, FP8, vision, MLX, export, mobile. | +| [good-html](./good-html/) | Design | Dense, interactive, self-contained HTML artifacts and reviews. | +| [anyrouter](./anyrouter/) | AI | Wire AnyRouter, an OpenAI-compatible LLM gateway, into projects and agents, with migration help and an MCP server. | +| [sag-notify](./sag-notify/) | UI | Spoken voice notifications via sag (ElevenLabs TTS): skill-driven, Claude calls sag directly to speak a short alert just before it asks you something and a one-line summary when work finishes, naming the project. Configurable voice and language. | +| [build-macos-apps](./build-macos-apps/) | Development | Build, debug, instrument, and implement macOS apps with SwiftUI and AppKit guidance, codesigning, packaging, and telemetry workflows. | +| [build-ios-apps](./build-ios-apps/) | Development | Build, debug, and profile iOS apps with SwiftUI, Simulator, App Intents, and on-device AI. | +| [agent-loop](./agent-loop/) | Automation | Unattended repo maintenance that triages issues and PRs, dispatches fixes to parallel subagents, and reports results each scheduled cycle. | +| [kb](./kb/) | Productivity | Knowledge base maintenance skills. Initialize a shared-brain kb, then consolidate, dedupe, prune, refresh, and forget notes in a markdown KB. | +| [okf](./okf/) | Productivity | Open Knowledge Format (OKF) tooling. Author, initialize, validate, render, and refactor knowledge into vendor-neutral OKF v0.1 bundles: markdown files with YAML frontmatter. | +| [command-code](./command-code/) | Development | Dispatch the Command Code CLI (`cmd`) as headless sub-agents across isolated git worktrees. | + + +Each plugin folder has its own README with commands and skills. -## Usage Examples - -### Parallel Team Execution - -```bash -# Delegate to team agents for parallel work -/duyetbot:spawn Implement the frontend dashboard -# Leader coordinates senior + junior engineers working in parallel -``` - -### Smart GitHub Workflow - -```bash -# Automatically creates feature branch from main -/gh-pr create "Add user settings page" -# Detects main/master, creates feature/X branch, implements, creates PR -``` - -### PR Babysitting with /goal - -```bash -# Set a persistent goal to babysit a PR — auto-fix CI, address reviews, wait for green -/goal /github:babysit-pr https://github.com/duyet/clickhouse-monitoring/pull/1355 - -# With auto-merge and CI fixing -/goal /github:babysit-pr --pr 1355 --auto-merge --fix-ci -``` - ---- - -## Plugins at a Glance - -| Plugin | Type | What it does | -| ---------------------------------------------------- | ------- | ---------------------------------------------- | -| [👥 team-agents](./team-agents/) | Skill | Leader, Senior Engineer, and Junior Engi... | -| [📝 commit](./commit/) | Command | Create a Git commit with semantic commit... | -| [🎨 frontend-design](./frontend-design/) | Skill | Create distinctive, production-grade fro... | -| [💬 interview](./interview/) | Command | Conduct in-depth requirements interviews... | -| [📊 statusline](./statusline/) | Hook | Configurable status bar showing context ... | -| [🎼 orchestration](./orchestration/) | Skill | Orchestrator skill for managing parallel... | -| [🤖 duyetbot](./duyetbot/) | Skill | Pragmatic software development companion... | -| [🎯 docs-generator](./docs-generator/) | Hook | Automatically generate and maintain plug... | -| [🐙 github](./github/) | Skill | GitHub operations using gh CLI - PRs, is... | -| [🔧 fix](./fix/) | Command | Fix issues, tests, and CI failures with ... | -| [📈 clickhouse-monitoring](./clickhouse-monitoring/) | Skill | Specialized knowledge for the ClickHouse Mo... | - ---- - -## Plugin Details - -### 👥 team-agents - -**Leader, Senior Engineer, and Junior Engineer agents for coordinated parallel task execution** - -**Components:** - -Agents: - -- **junior-engineer** -- **leader** -- **senior-engineer** - -Skills: - -- **backend-api-patterns** -- **quality-gates** -- **react-nextjs-patterns** -- **task-decomposition** -- **typescript-patterns** - ---- - -### 📝 commit - -**Create a Git commit with semantic commit message format** - -```bash -- `/commit:commit`: Create a git commit with semantic commit message format -- `/commit:and-push`: Commit and push to remote -- `/commit:and-create-pr`: Commit, push, and create a pull request -``` - ---- - -### 🎨 frontend-design - -**Create distinctive, production-grade frontend interfaces avoiding AI slop aesthetics. Emphasizes shadcn/ui, Recharts, and bold design choices.** - -**Components:** - -Skills: - -- **frontend-design** - ---- - -### 💬 interview - -**Conduct in-depth requirements interviews using Socratic questioning to clarify implementation details before coding** - -```bash -- `/interview`: Conduct in-depth requirements interview using Socratic questioning to clarify implementation details -``` - ---- - -### 📊 statusline - -**Configurable status bar showing context usage, API rate limits (5h/7d), git branch, and active tools. Supports 1/2/3 line layouts with smart hiding of empty values.** - -```bash -- `/config` -- `/disable` -- `/setup` -``` - ---- - -### 🎼 orchestration - -**Orchestrator skill for managing parallel agent workstreams. Transform complex requests into coordinated multi-agent execution with elegant result synthesis.** - -**Components:** - -Skills: - -- **orchestration** - ---- - -### 🤖 duyetbot - -**Pragmatic software development companion with engineering discipline and transparent execution.** - -```bash -- `/duyetbot`: Summon duyetbot - pragmatic software development companion with transparent execution -- `/learn`: Learn about @duyet and update knowledge base -- `/orchestrate`: Duyetbot orchestrate - coordinate parallel agent workstreams for complex tasks -- `/spawn`: Duyetbot spawn - delegate tasks to team agents for parallel execution -- `/think`: Duyetbot deep thinking - structured problem analysis with visible reasoning -``` - -**Components:** - -Agents: - -- **duyetbot** - -Skills: - -- **duyet-knowledge** -- **engineering-discipline** -- **team-coordination** -- **transparency** - ---- - -### 🎯 docs-generator - -**Automatically generate and maintain plugin documentation (README.md, CLAUDE.md)** - -```bash -- `/generate-docs`: Manually trigger documentation generation for all plugins -``` - ---- - -### 🐙 github - -**GitHub operations using gh CLI - PRs, issues, workflows, repositories, releases, and smart branch detection for implementation workflows** - -Automatically detects when you're on main/master and creates feature branches before implementing. Handles complete GitHub workflow from branch creation to PR merge. - -**Components:** - -Skills: - -- **github** - ---- - -### 🔧 fix - -**Fix issues, tests, and CI failures with intelligent problem detection and resolution** +## Contributing -Auto-detects project type and runs appropriate checks. Spawns parallel agents for complex multi-file fixes. +`marketplace.json` is the only manifest you edit by hand. It holds each plugin's name, display name, description, version, and category. Everything else is generated: ```bash -- `/fix:and-push`: Fix issues, commit, and push to remote -- `/fix:and-update-pr`: Fix issues and update existing PR -- `/fix:and-create-pr`: Fix issues and create new PR -``` - -**Supported Projects:** - -- Python (pytest, ruff, mypy) -- Node/TypeScript (jest, vitest, eslint, tsc) -- Rust (cargo test, clippy) -- Go (go test, golint) - -**Components:** - -Skills: - -- **test-detection** - ---- - -### 📈 clickhouse-monitoring - -**Agent Skill for the ClickHouse Monitor dashboard - a real-time monitoring and observability tool for ClickHouse clusters** - -Covers 45 dashboard pages including query monitoring, table management, merge operations, system metrics, security logs, and API integration with static site patterns. - -**Components:** - -Skills: - -- **clickhouse-monitoring** - ---- - ---- - -## Manual Installation - -Add to `~/.claude/settings.json`: - -```json -{ - "extraKnownMarketplaces": { - "duyet-claude-plugins": { - "source": { "source": "github", "repo": "duyet/codex-claude-plugins" } - } - }, - "enabledPlugins": { - "team-agents@duyet-claude-plugins": true - } -} +python3 scripts/plugins.py sync # write every harness manifest and the table above +bash scripts/validate-plugins.sh # fail on drift, broken skill links, missing frontmatter ``` ---- - -## Contributing - -```text -your-plugin/ -├── .claude-plugin/plugin.json # name, version, description, logo -├── .codex-plugin/plugin.json # Codex manifest, interface, logo -├── .grok-plugin/plugin.json # Grok Bot / Grok Build manifest + logo -├── .grok-build-plugin/plugin.json # Grok Build interface metadata + logo -├── assets/logo.svg # rendered by every listed harness -├── agents/ # .md with YAML frontmatter -├── commands/ # slash commands -├── skills/ # reusable knowledge -└── hooks/hooks.json # lifecycle hooks -``` - -Update `marketplace.json`, `.claude-plugin/marketplace.json`, `.agents/plugins/marketplace.json`, `.grok-plugin/marketplace.json`, and the harness manifests. Run `bash scripts/validate-plugins.sh` before opening a PR. - ---- +See [CONTRIBUTING.md](CONTRIBUTING.md) for commit and versioning rules. ## License -MIT License - See individual plugin directories for details. - -## Links - -- [Report Issues](https://github.com/duyet/codex-claude-plugins/issues) -- [Request Features](https://github.com/duyet/codex-claude-plugins/issues/new?template=feature_request.md) - ---- +MIT diff --git a/agent-loop/.antigravity-plugin/plugin.json b/agent-loop/.antigravity-plugin/plugin.json index fb73e41..1e97901 100644 --- a/agent-loop/.antigravity-plugin/plugin.json +++ b/agent-loop/.antigravity-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "agent-loop", - "version": "0.4.0", - "description": "Continuous agent loop for overnight/day repository maintenance. Orchestrates triage, autoreview, browser automation, and parallel agent work across threads. Wake every 5 min, direct work, land autonomously.", + "version": "0.5.0", + "description": "Unattended repo maintenance that triages issues and PRs, dispatches fixes to parallel subagents, and reports results each scheduled cycle.", "author": { "name": "duyet", "url": "https://github.com/duyet" @@ -11,7 +11,7 @@ "commands": "./commands/", "interface": { "displayName": "Agent Loop", - "shortDescription": "Continuous agent loop for overnight/day repository maintenance. Orchestrates triage, autoreview, browser automation, and parallel agent work across threads. Wake every 5 min, direct work, land autonomously.", + "shortDescription": "Unattended repo maintenance that triages issues and PRs, dispatches fixes to parallel subagents, and reports results each scheduled cycle.", "developerName": "duyet", "category": "Automation", "capabilities": [ diff --git a/agent-loop/.claude-plugin/plugin.json b/agent-loop/.claude-plugin/plugin.json index cc01ede..067201f 100644 --- a/agent-loop/.claude-plugin/plugin.json +++ b/agent-loop/.claude-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "agent-loop", - "version": "0.4.0", - "description": "Continuous agent loop for overnight/day repository maintenance. Orchestrates triage, autoreview, browser automation, and parallel agent work across threads. Wake every 5 min, direct work, land autonomously.", + "version": "0.5.0", + "description": "Unattended repo maintenance that triages issues and PRs, dispatches fixes to parallel subagents, and reports results each scheduled cycle.", "author": { "name": "duyet", "url": "https://github.com/duyet" diff --git a/agent-loop/.codex-plugin/plugin.json b/agent-loop/.codex-plugin/plugin.json index fb73e41..1e97901 100644 --- a/agent-loop/.codex-plugin/plugin.json +++ b/agent-loop/.codex-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "agent-loop", - "version": "0.4.0", - "description": "Continuous agent loop for overnight/day repository maintenance. Orchestrates triage, autoreview, browser automation, and parallel agent work across threads. Wake every 5 min, direct work, land autonomously.", + "version": "0.5.0", + "description": "Unattended repo maintenance that triages issues and PRs, dispatches fixes to parallel subagents, and reports results each scheduled cycle.", "author": { "name": "duyet", "url": "https://github.com/duyet" @@ -11,7 +11,7 @@ "commands": "./commands/", "interface": { "displayName": "Agent Loop", - "shortDescription": "Continuous agent loop for overnight/day repository maintenance. Orchestrates triage, autoreview, browser automation, and parallel agent work across threads. Wake every 5 min, direct work, land autonomously.", + "shortDescription": "Unattended repo maintenance that triages issues and PRs, dispatches fixes to parallel subagents, and reports results each scheduled cycle.", "developerName": "duyet", "category": "Automation", "capabilities": [ diff --git a/agent-loop/.cursor-plugin/plugin.json b/agent-loop/.cursor-plugin/plugin.json index b41303a..a0b49dd 100644 --- a/agent-loop/.cursor-plugin/plugin.json +++ b/agent-loop/.cursor-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "agent-loop", - "version": "0.4.0", - "description": "Continuous agent loop for overnight/day repository maintenance. Orchestrates triage, autoreview, browser automation, and parallel agent work across threads. Wake every 5 min, direct work, land autonomously.", + "version": "0.5.0", + "description": "Unattended repo maintenance that triages issues and PRs, dispatches fixes to parallel subagents, and reports results each scheduled cycle.", "author": { "name": "duyet" }, diff --git a/agent-loop/.grok-build-plugin/plugin.json b/agent-loop/.grok-build-plugin/plugin.json index 5244f30..c151c39 100644 --- a/agent-loop/.grok-build-plugin/plugin.json +++ b/agent-loop/.grok-build-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "agent-loop", - "version": "0.4.0", - "description": "Continuous agent loop for overnight/day repository maintenance. Orchestrates triage, autoreview, browser automation, and parallel agent work across threads. Wake every 5 min, direct work, land autonomously.", + "version": "0.5.0", + "description": "Unattended repo maintenance that triages issues and PRs, dispatches fixes to parallel subagents, and reports results each scheduled cycle.", "author": { "name": "duyet", "url": "https://github.com/duyet" @@ -12,7 +12,7 @@ "commands": "./commands/", "interface": { "displayName": "Agent Loop", - "shortDescription": "Continuous agent loop for overnight/day repository maintenance. Orchestrates triage, autoreview, browser automation, and parallel agent work across threads. Wake every 5 min, direct work, land autonomously.", + "shortDescription": "Unattended repo maintenance that triages issues and PRs, dispatches fixes to parallel subagents, and reports results each scheduled cycle.", "developerName": "duyet", "category": "Automation", "capabilities": [ diff --git a/agent-loop/.grok-plugin/plugin.json b/agent-loop/.grok-plugin/plugin.json index 8f93bb8..632ebf3 100644 --- a/agent-loop/.grok-plugin/plugin.json +++ b/agent-loop/.grok-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "agent-loop", - "version": "0.4.0", - "description": "Continuous agent loop for overnight/day repository maintenance. Orchestrates triage, autoreview, browser automation, and parallel agent work across threads. Wake every 5 min, direct work, land autonomously.", + "version": "0.5.0", + "description": "Unattended repo maintenance that triages issues and PRs, dispatches fixes to parallel subagents, and reports results each scheduled cycle.", "author": { "name": "duyet", "url": "https://github.com/duyet" diff --git a/agent-loop/CHANGELOG.md b/agent-loop/CHANGELOG.md index af367e9..ee35b82 100644 --- a/agent-loop/CHANGELOG.md +++ b/agent-loop/CHANGELOG.md @@ -1,77 +1,22 @@ # Changelog -All notable changes to the agent-loop plugin are documented here. +## Unreleased -## [0.4.0] — 2026-06-14 +- Repetition now uses the harness scheduler (Claude Code `/loop`, or the Codex and Cursor equivalents) instead of a shell `sleep`. +- The state file is defined once, in the `agent-loop-orchestrator` skill. All state commands point to it. +- `/agent-loop:resume` refuses to restart a stopped loop. Use `/agent-loop:start --resume`. +- Removed duplicate flat skill files under `skills/`. -### Added +## 0.4.0 (2026-06-14) -**State Management & Recovery** -- ✨ Auto-detection of existing `.agent-loop/state.json` on startup — `/agent-loop:start` now checks for saved state and prompts to resume or start fresh -- ✨ `/agent-loop:inspect` command — deep inspection of state file, view cycle history, thread details, errors, and state integrity -- ✨ `/agent-loop:reset` command — clear state and start fresh, with automatic backup of old state to `.agent-loop/backups/` -- ✨ `/agent-loop:restore` command — recover state from timestamped backups -- ✨ State validation and corruption detection — automatic checks when loading state.json -- ✨ Backup system with timestamped files — automatic backups on reset or fresh start +- Added `/agent-loop:inspect`, `/agent-loop:reset`, and `/agent-loop:restore`. +- `/agent-loop:start` detects saved state and offers to resume. +- Timestamped state backups in `.agent-loop/backups/`. -**Enhanced Commands** -- 📝 Improved `/agent-loop:start` to auto-detect and prompt for resume vs. fresh (can force with `--fresh` or `--resume`) -- 📝 Enhanced `/agent-loop:resume` documentation with recovery details and state restoration info -- 📝 Updated `/agent-loop:status` to show when resuming from backed-up state +## 0.3.0 (2026-06-11) -**Documentation** -- 📖 Enhanced orchestrator skill with state validation, recovery procedures, and backup system details -- 📖 Added "State Management & Recovery" section to README with recovery scenarios -- 📖 Updated README with organized command reference (Loop Control, State Management, One-Shot Operations) -- 📖 Comprehensive guides for all new commands with examples and recovery workflows +- Added `/agent-loop:resume` and `/agent-loop:status`. -### Changed +## 0.1.0 (2026-06-09) -- 🔄 Plugin version bumped from 0.3.0 to 0.4.0 (across all manifests: `.claude-plugin`, `.codex-plugin`, `.antigravity-plugin`) -- 🔄 State file schema now includes `version` and `state_valid` fields for better corruption detection -- 🔄 Updated descriptions in all manifests to mention "Auto-detects and resumes from saved state" - -### Technical - -- 🔧 State schema v0.4.0 with enhanced validation fields -- 🔧 Backup directory: `.agent-loop/backups/state-YYYY-MM-DD-HHmmss.json` -- 🔧 Enhanced environment variable: `AGENT_LOOP_BACKUP_DIR` (default: `.agent-loop/backups`) -- 🔧 State integrity checks: JSON validity, required fields, type safety, orphaned threads, metric consistency - -### Why These Changes? - -The agent-loop plugin previously required manual state management. Users had to explicitly remember to resume with `/agent-loop:resume` after interruptions, and there was no built-in recovery from state corruption or accidental resets. - -**v0.4.0 improvements:** -1. **Smarter startup** — Auto-detect saved state and offer to resume (no more lost context) -2. **Better debugging** — Inspect command lets users understand their loop state deeply -3. **Safe reset** — Automatic backups mean resets are never destructive -4. **Full recovery** — Restore from backups for corruption or accidents -5. **Validated state** — Automatic corruption detection prevents silent failures - -## [0.3.0] — 2026-06-11 - -### Added - -- Antigravity manifest and commands -- Resume command for loop restoration -- State persistence documentation - -### Changed - -- Version bumped to 0.3.0 - -## [0.2.0] — 2026-06-10 - -### Added - -- Agent loop orchestrator skill -- Triage, autoreview, and browser skills -- Core commands: start, stop, status - -## [0.1.0] — 2026-06-09 - -### Added - -- Initial agent-loop plugin structure -- Basic CLI commands and skills +- First release with orchestrator, triage, autoreview, and browser skills. diff --git a/agent-loop/README.md b/agent-loop/README.md index 5704c4e..4028f3d 100644 --- a/agent-loop/README.md +++ b/agent-loop/README.md @@ -1,220 +1,36 @@ -# Agent Loop Plugin +# agent-loop -Continuous overnight/day repository maintenance with autonomous agent loops. +Unattended repo maintenance. Each cycle triages open issues and PRs, sends fixable items to parallel subagents, and reports what landed. The harness's own scheduler (Claude Code `/loop`, or the Codex and Cursor equivalents) repeats the cycle. -```text -Wake every 5m ──► Triage repos ──► Dispatch threads ──► Track & land -``` - -## Version - -0.3.0 - -## Overview - -The agent-loop plugin runs a persistent automation cycle that keeps repositories -healthy without human supervision. It is designed for overnight and day-long -autonomous upkeep: triaging issues, reviewing PRs, applying fixes, and landing -changes — all through parallel agent threads. - -Inspired by Peter Steinberger's maintainer-orchestrator pattern: tell Codex to -maintain your repos, wake up every 5 minutes, and direct work to threads. -That makes it easy to parallelize + steer work as needed. - -## Components - -### Skills - -| Skill | Purpose | -| --------------------------- | ------------------------------------------------------ | -| **agent-loop-orchestrator** | Core loop: wait → triage → dispatch → monitor → report | -| **agent-loop-triage** | GitHub issue/PR queue scanning and classification | -| **agent-loop-autoreview** | Autonomous PR review, fix application, and merging | -| **agent-loop-browser** | Browser automation for live UI proof and verification | - -### Commands - -#### Loop Control - -| Command | Description | -| -------------------- | ----------------------------------------------- | -| `/agent-loop:start` | Start or resume the continuous maintenance loop | -| `/agent-loop:stop` | Gracefully stop the loop and persist state | -| `/agent-loop:resume` | Resume from persisted state (explicit resume) | - -#### State Management - -| Command | Description | -| --------------------- | -------------------------------------------------------- | -| `/agent-loop:status` | Quick status check (running, cycles, metrics) | -| `/agent-loop:inspect` | Deep inspection of state file (history, errors, details) | -| `/agent-loop:reset` | Clear state and start fresh (backs up old state) | -| `/agent-loop:restore` | Recover state from a backup | - -#### One-Shot Operations - -| Command | Description | -| ------------------------ | ----------------------------------------------- | -| `/agent-loop:triage` | One-shot repo queue triage (doesn't start loop) | -| `/agent-loop:autoreview` | One-shot PR review and fix (doesn't start loop) | - -## Skill Sources - -Sources adapted for the agent-loop plugin: - -- **agent-loop-triage** — adapted from [steipete/agent-scripts github-project-triage](https://github.com/steipete/agent-scripts/tree/main/skills/github-project-triage) -- **agent-loop-browser** — adapted from [steipete/agent-scripts browser-use](https://github.com/steipete/agent-scripts/tree/main/skills/browser-use) -- **agent-loop-autoreview** — adapted from local autofix skill + CodeRabbit workflow patterns -- **agent-loop-orchestrator** — original orchestrator pattern inspired by maintainer-orchestrator concept - -## Quick Start +## Install ```bash -# Start the loop (auto-prompts to resume if state exists) -/agent-loop:start - -# Check status -/agent-loop:status - -# Inspect state details -/agent-loop:inspect - -# One-shot triage (doesn't start loop) -/agent-loop:triage - -# Review a specific PR -/agent-loop:autoreview --pr 123 --merge - -# Stop the loop gracefully -/agent-loop:stop - -# Resume from saved state (explicit) -/agent-loop:resume - -# Reset and start fresh (backs up old state) -/agent-loop:reset - -# Restore from backup -/agent-loop:restore --list +/plugin install agent-loop@duyet-claude-plugins ``` -## State Management & Recovery - -The agent-loop automatically saves state to `.agent-loop/state.json` and supports robust recovery: - -### Startup Behavior - -When you run `/agent-loop:start`: - -1. **Checks for existing state** — detects `.agent-loop/state.json` -2. **Prompts if found** — asks to resume or start fresh -3. **Backs up on reset** — saves old state to `.agent-loop/backups/` if starting fresh - -### State Operations +## Skills -| Operation | Command | Purpose | -| ------------------ | -------------------------------- | ------------------------------------------ | -| **Check status** | `/agent-loop:status` | Quick summary (running, cycles, metrics) | -| **Deep inspect** | `/agent-loop:inspect` | View thread history, errors, state details | -| **Validate state** | `/agent-loop:inspect --validate` | Check state file integrity | -| **Reset state** | `/agent-loop:reset` | Clear state, backs up old state | -| **Restore state** | `/agent-loop:restore --list` | Recover from backup | -| **Resume loop** | `/agent-loop:resume` | Continue from saved state | +- `agent-loop-orchestrator` runs one cycle and defines the state file. +- `agent-loop-triage` classifies issues and PRs as autonomous, needs review, defer, or blocked. +- `agent-loop-autoreview` applies verified AI review bot fixes and merges when safe. +- `agent-loop-browser` captures screenshot proof for UI changes. -### Recovery Scenarios +## Commands -**If state is corrupted:** - -```bash -/agent-loop:inspect --validate # Identify the problem -/agent-loop:restore --list # List available backups -/agent-loop:restore state-XXXX.json # Restore from backup -/agent-loop:start --resume # Continue from restored state -``` - -**If you want to start fresh:** - -```bash -/agent-loop:reset # Backs up old state automatically -/agent-loop:start --fresh # Starts with clean state -``` +- `/agent-loop:start`, `/agent-loop:resume`, `/agent-loop:stop` control the loop. +- `/agent-loop:status`, `/agent-loop:inspect` read the state file. +- `/agent-loop:reset`, `/agent-loop:restore` clear or recover state from backups. +- `/agent-loop:triage`, `/agent-loop:autoreview` run one pass without the loop. -**If you accidentally reset:** +## Example ```bash -/agent-loop:restore --list # List backups -/agent-loop:restore --select # Interactive menu -/agent-loop:start --resume # Resume from backup -``` - -## Configuration - -| Env Variable | Default | Description | -| ---------------------------- | ---------------------- | ------------------------------ | -| `AGENT_LOOP_INTERVAL` | 300 | Sleep between cycles (seconds) | -| `AGENT_LOOP_MAX_CONCURRENCY` | 3 | Max parallel worker threads | -| `AGENT_LOOP_SCOPE` | current | Default triage scope | -| `AGENT_LOOP_LOG_DIR` | .agent-loop/logs | Log output directory | -| `AGENT_LOOP_STATE_FILE` | .agent-loop/state.json | Persisted loop state | -| `AGENT_LOOP_BACKUP_DIR` | .agent-loop/backups | Timestamped state backups | -| `AGENT_LOOP_REPOS` | (from git remote) | Comma-separated repo list | - -## Plugin Structure - -```text -agent-loop/ -├── .antigravity-plugin/ -│ └── plugin.json # Antigravity manifest -├── .claude-plugin/ -│ └── plugin.json # Claude manifest -├── .codex-plugin/ -│ └── plugin.json # Codex manifest -├── .grok-plugin/ -│ └── plugin.json # Grok Bot / Grok Build manifest -├── .grok-build-plugin/ -│ └── plugin.json # Grok Build interface metadata -├── assets/ -│ └── logo.svg -├── commands/ # Slash commands -│ ├── start.md -│ ├── stop.md -│ ├── status.md -│ ├── triage.md -│ └── autoreview.md -├── skills/ # Reusable knowledge -│ ├── agent-loop-orchestrator/ -│ │ └── SKILL.md -│ ├── agent-loop-triage/ -│ │ └── SKILL.md -│ ├── agent-loop-autoreview/ -│ │ └── SKILL.md -│ └── agent-loop-browser/ -│ └── SKILL.md -└── README.md -``` - -## Versioning - -Follow semantic versioning (semver): - -| Change Type | Version Bump | Example | -| ------------------------- | ------------ | ------------- | -| Bug fix, docs | Patch | 0.2.0 → 0.2.1 | -| New feature, minor change | Minor | 0.2.0 → 0.3.0 | -| Breaking change | Major | 0.2.0 → 1.0.0 | - -## Commit Convention - -Use semantic commits with plugin scope: - -```text -feat(agent-loop): add new feature -fix(agent-loop): fix bug -docs(agent-loop): update documentation +/agent-loop:start --scope current --max-concurrency 3 +/loop 5m /agent-loop:resume ``` -Co-author: `Co-Authored-By: duyetbot ` +State lives in `.agent-loop/state.json`. Add `.agent-loop/` to `.gitignore`. ---- +## Credits -**Based on concepts from [steipete/agent-scripts](https://github.com/steipete/agent-scripts)** +Triage and browser skills are adapted from [steipete/agent-scripts](https://github.com/steipete/agent-scripts). diff --git a/agent-loop/commands/autoreview.md b/agent-loop/commands/autoreview.md index 0ee9cf2..5234d65 100644 --- a/agent-loop/commands/autoreview.md +++ b/agent-loop/commands/autoreview.md @@ -1,46 +1,10 @@ --- -allowed-tools: Bash(git *), Bash(gh *), Read, Edit, Write, Task(deep,quick) -description: One-shot autonomous review of a PR. Fetches review comments from AI bots, applies verified fixes, validates, and merges when safe. +allowed-tools: Bash(git *), Bash(gh *), Read, Edit, Write, Task, Agent +description: Review one PR, apply verified fixes from AI review bots, validate, and optionally merge. Use for a single PR without starting the loop. --- -# Agent Loop Autoreview +# Agent loop autoreview -One-shot autonomous PR review. Does NOT start the loop — just reviews, -fixes, validates, and optionally merges a single PR. +Flags: `--pr ` (default: current branch's PR), `--repo `, `--merge`, `--dry-run`, `--skip-labels ` (default `wip,do-not-merge,blocked`). -## Usage - -```bash -/agent-loop:autoreview -/agent-loop:autoreview --pr 123 -/agent-loop:autoreview --repo duyet/clickhouse-monitoring --pr 123 -/agent-loop:autoreview --pr 123 --merge -/agent-loop:autoreview --pr 123 --merge --dry-run -``` - -## Options - -- `--pr `: PR number (default: current branch's PR) -- `--repo `: Repository (default: from git remote) -- `--merge`: Merge PR after successful review -- `--dry-run`: Preview what would happen without applying changes -- `--skip-labels `: Skip PRs with these labels (default: wip,do-not-merge,blocked) - -## Workflow - -1. Fetch PR details and diff -2. Fetch AI review bot comments (CodeRabbit, Sourcery, Gemini) -3. Extract and apply verified fixes -4. Validate: lint → test → build -5. Commit and push fixes -6. If `--merge`: check merge readiness, merge -7. Report results - -## Safety Gates - -- Skips draft PRs -- Skips PRs with skip-labels -- Skips PRs with unresolved human review changes requested -- Skips security-sensitive changes on first-time contributors -- Validates every fix before applying -- Reports all decisions with reasoning +Follow the `agent-loop-autoreview` skill for that PR. Merge only with `--merge`. With `--dry-run`, report planned fixes and change nothing. diff --git a/agent-loop/commands/inspect.md b/agent-loop/commands/inspect.md index 2b38529..4e1e5e4 100644 --- a/agent-loop/commands/inspect.md +++ b/agent-loop/commands/inspect.md @@ -1,137 +1,10 @@ --- allowed-tools: Bash, Read -description: Deeply inspect the agent-loop state file. View cycle history, thread details, errors, and state integrity. Useful for debugging and understanding loop status. +description: Inspect and validate the agent-loop state file or a backup. Use to debug a stuck or broken loop. --- -# Agent Loop Inspect +# Agent loop inspect -Deeply inspect the agent-loop state file and view detailed information about the loop's execution history. +Flags: `--json`, `--threads`, `--errors`, `--limit `, `--validate`, `--backup `. -Unlike `/agent-loop:status` which shows a summary, this command provides comprehensive details: thread-by-thread outcomes, error logs, corrupted state detection, and recovery hints. - -## What You Get - -- **State file path and size** — where state is stored and its integrity check -- **Cycle summary** — total cycles, current cycle number, last cycle time -- **Thread history** — all past threads with outcomes (passed, failed, needs_human) -- **Active threads** — threads still in progress (IDs, items, elapsed time) -- **Error log** — any errors encountered during threads or cycles -- **State validation** — checks for corruption, missing fields, inconsistencies -- **Recovery hints** — suggestions if state is corrupted or problematic - -## Usage - -```bash -# View full state details -/agent-loop:inspect - -# View state as raw JSON -/agent-loop:inspect --json - -# View only thread history -/agent-loop:inspect --threads - -# View only recent errors -/agent-loop:inspect --errors --limit 10 - -# Validate state integrity (quick check) -/agent-loop:inspect --validate - -# Inspect a backup state file -/agent-loop:inspect --backup state-2026-06-14-143022.json - -# Show just the top-level metrics -/agent-loop:inspect --metrics -``` - -## Output Example - -```text -═══════════════════════════════════════════════════════ -Agent Loop State Inspection -═══════════════════════════════════════════════════════ - -State File: .agent-loop/state.json -Size: 4.2 KB -Last Modified: 2026-06-14 14:30:22 UTC -Integrity: ✓ VALID - -─── Cycle Summary ────────────────────────────────────── -Current Cycle: #42 -Started: 2026-06-11 00:00:00 UTC -Total Uptime: 3d 14h 30m -Last Cycle End: 2026-06-14 14:30:22 UTC -Total Cycles Completed: 41 - -─── Metrics ──────────────────────────────────────────── -Items Processed: 87 - Autonomous: 34 (39%) - Needs Review: 28 (32%) - Deferred: 25 (29%) -PRs Merged: 15 -Success Rate: 88% (30/34 autonomous succeeded) - -─── Active Threads ───────────────────────────────────── -Thread-3: GH-234 | test flakiness fix | 2m 14s running -Thread-5: GH-235 | deps update | 45s running - -─── Thread History (Last 5) ──────────────────────────── -#41: Thread-2 GH-233 → ✓ merged (PR #456) -#41: Thread-1 GH-232 → ✗ failed (test timeout) -#40: Thread-4 GH-231 → ⚠ needs_review (manual check needed) -#39: Thread-3 GH-230 → ✓ merged (PR #455) -#38: Thread-2 GH-229 → ✓ merged (PR #454) - -─── Error Log (Last 3) ───────────────────────────────── -[2026-06-14 14:25:00] Thread-1: Test timeout after 120s -[2026-06-14 14:10:00] Triage error: GitHub API rate limit -[2026-06-14 14:00:00] Thread-4: PR review blocked by CI failure - -═══════════════════════════════════════════════════════ -``` - -## Options - -- `--json`: Output raw state as JSON (useful for parsing) -- `--threads`: Show thread history only -- `--metrics`: Show metrics summary only -- `--errors`: Show error log only -- `--errors --limit N`: Show last N errors (default: 10) -- `--active`: Show active threads only -- `--validate`: Check state file integrity (quick validation) -- `--backup `: Inspect a backup file instead of current state -- `--deep`: Perform deep validation (checks for orphaned threads, inconsistencies) - -## State Validation - -When you run `--validate`, the inspector checks: -- ✓ State file exists and is readable -- ✓ Valid JSON structure -- ✓ Required fields present (cycle, started_at, items_processed, etc.) -- ✓ Field types are correct (numbers, strings, arrays, etc.) -- ✓ No orphaned threads (threads in history but marked as active) -- ✓ Timestamps are valid and chronologically ordered -- ✓ Metrics are consistent (e.g., autonomous + needs_review + deferred = total) - -If validation fails, you'll see error details and recovery suggestions: -``` -✗ INVALID state detected: - Error: Missing required field 'started_at' - Severity: CRITICAL - Recovery: Use /agent-loop:restore to recover from backup, or /agent-loop:reset -``` - -## Backup Inspection - -View details about any backup: -```bash -/agent-loop:inspect --backup state-2026-06-14-143022.json -``` - -This shows the same details as the current state, allowing you to compare before restoring. - -## Related Commands - -- `/agent-loop:status` — Quick summary of loop status -- `/agent-loop:restore` — Restore from a backup -- `/agent-loop:reset` — Clear state and start fresh +Read the state file, or the named file under `.agent-loop/backups/`. Validate it against the rules in the State file section of the `agent-loop-orchestrator` skill. Print each problem found (parse error, missing field, orphaned thread), `last_error`, failed threads with reasons, and the next step: `/agent-loop:resume` if valid, `/agent-loop:restore` if not. diff --git a/agent-loop/commands/reset.md b/agent-loop/commands/reset.md index b6faf2b..d2cad3c 100644 --- a/agent-loop/commands/reset.md +++ b/agent-loop/commands/reset.md @@ -1,69 +1,8 @@ --- allowed-tools: Bash, Read, Write -description: Clear the agent-loop state and start fresh. Creates a backup of the current state before clearing. Use this when you want to reset metrics and start a new loop session. +description: Clear agent-loop state after backing it up. Use to start counting from zero. --- -# Agent Loop Reset +# Agent loop reset -Clear the agent-loop state and start a completely fresh loop. - -This command backs up your current `.agent-loop/state.json` before clearing it, so you can always recover if needed. - -## Use Cases - -- **Clean slate** — Start a new loop session with fresh metrics -- **Corrupted state** — If state.json becomes corrupted, reset and start over (backup is preserved) -- **Cycle restart** — Reset cycle counter and reprocess items -- **Metrics cleanup** — Clear accumulated statistics and start counting fresh - -## What Gets Cleared - -- Current cycle count → resets to 0 -- Items processed → resets to 0 -- Thread history → fully cleared -- Active thread list → reset -- All metrics and statistics → fresh start - -## What Gets Preserved - -The current state.json is **backed up** before clearing: -- Backup location: `.agent-loop/backups/state-YYYY-MM-DD-HHmmss.json` -- Use `/agent-loop:restore` to recover the backup if needed - -## Usage - -```bash -# Reset with confirmation prompt -/agent-loop:reset - -# Force reset without confirmation -/agent-loop:reset --force - -# Reset and show backup location -/agent-loop:reset --show-backup -``` - -## Options - -- `--force`: Skip confirmation prompt and reset immediately -- `--show-backup`: Display the backup file path after reset -- `--keep-logs`: Keep .agent-loop/logs/ (default: clears logs too) - -## After Reset - -Once reset completes, you can: -1. Start a fresh loop: `/agent-loop:start` -2. Inspect what was backed up: `/agent-loop:inspect --backup ` -3. Restore if you changed your mind: `/agent-loop:restore ` - -## Backup Management - -All backups are stored in `.agent-loop/backups/`: -``` -.agent-loop/backups/ -├── state-2026-06-14-143022.json # Created by reset -├── state-2026-06-14-120015.json # Created by previous reset -└── state-2026-06-13-235959.json # Older backup -``` - -Use `/agent-loop:restore --list` to see all available backups. +Refuse while workers are active unless `--force`. Ask for confirmation unless `--force`. Back up the state file per the `agent-loop-orchestrator` skill, then delete it. Print the backup path and point to `/agent-loop:restore` for undo. diff --git a/agent-loop/commands/restore.md b/agent-loop/commands/restore.md index 41fc1aa..880da74 100644 --- a/agent-loop/commands/restore.md +++ b/agent-loop/commands/restore.md @@ -1,157 +1,12 @@ --- allowed-tools: Bash, Read, Write -description: Restore agent-loop state from a backup. List available backups, restore from a specific backup, or use the most recent backup to recover from corruption or accidents. +description: Restore agent-loop state from a backup. Use after corruption, a crash, or an accidental reset. --- -# Agent Loop Restore +# Agent loop restore -Restore the agent-loop state from a backup, either the most recent or a specific timestamped backup. +- `--list`: list files in `.agent-loop/backups/`, newest first, with cycle and timestamp. +- No argument: restore the newest valid backup. +- ``: restore that backup. -Use this command to recover after state.json corruption, accidental resets, or loop crashes where state was inconsistent. - -## Why Restore? - -You might need to restore in these scenarios: - -- **State corruption** — state.json became corrupted (bad JSON, missing fields) -- **Accidental reset** — you ran `/agent-loop:reset` by mistake -- **Loop crash** — the loop crashed and left state in an inconsistent state -- **Wrong start** — you started fresh but wanted to resume from before -- **Recovery** — the loop stopped unexpectedly and you want to pick up where it left off - -## What Gets Restored - -When you restore from a backup, you recover everything from that point in time: -- Cycle count, started time, uptime -- All processed items count and classification history -- Thread history and outcomes -- Active thread list and metrics -- All statistics accumulated up to that backup - -## Usage - -```bash -# List all available backups -/agent-loop:restore --list - -# Restore from most recent backup -/agent-loop:restore - -# Restore from specific backup (interactive menu) -/agent-loop:restore --select - -# Restore from specific backup (by name) -/agent-loop:restore state-2026-06-14-143022.json - -# Restore and verify before committing -/agent-loop:restore --preview state-2026-06-14-143022.json - -# Restore and keep current state as backup -/agent-loop:restore --keep-current state-2026-06-14-143022.json -``` - -## Options - -- `--list`: Show all available backups with timestamps and sizes -- `--select`: Interactive menu to choose from available backups -- `--preview`: Show what will be restored without actually restoring -- `--keep-current`: Backup current state.json before restoring (safety) -- `--force`: Restore without confirmation prompt -- `--verify`: Verify backup integrity before restoring - -## Output Example - -``` -Available Backups -═════════════════════════════════════════════════════════════ -1 state-2026-06-14-143022.json (Jun 14, 2:30 PM) 4.2 KB -2 state-2026-06-14-120015.json (Jun 14, 12:00 PM) 4.1 KB -3 state-2026-06-13-235959.json (Jun 13, 11:59 PM) 3.9 KB - -Most recent: #1 (2 hours ago) - -Use: /agent-loop:restore - /agent-loop:restore --select -``` - -## Restore Workflow - -### Scenario 1: Quick Restore (Most Recent) - -```bash -# Restore from most recent backup -/agent-loop:restore - -# Loop continues from restored state -/agent-loop:start --resume -``` - -### Scenario 2: Previewing Before Restore - -```bash -# See what will be restored -/agent-loop:restore state-2026-06-14-143022.json --preview - -# Inspect the backup details -/agent-loop:inspect --backup state-2026-06-14-143022.json - -# Then restore if it looks good -/agent-loop:restore state-2026-06-14-143022.json --keep-current -``` - -### Scenario 3: Selecting from Menu - -```bash -# Interactive menu -/agent-loop:restore --select - -# Choose from menu (1-3) -# 1 state-2026-06-14-143022.json -# 2 state-2026-06-14-120015.json -# 3 state-2026-06-13-235959.json - -# Shows preview, ask for confirmation, then restores -``` - -## Backup Retention - -Backups are kept in `.agent-loop/backups/`: -- **Auto-created** when you run `/agent-loop:reset` or `/agent-loop:start --fresh` -- **Named with timestamp** for easy identification: `state-YYYY-MM-DD-HHmmss.json` -- **Kept indefinitely** (you can manually clean old ones) -- **Max 50** backups automatically (oldest auto-deleted) - -## Listing Backups - -```bash -# Show all backups -/agent-loop:restore --list - -# Show backups from last 7 days -/agent-loop:restore --list --since 7d - -# Show with detailed metrics -/agent-loop:restore --list --details -``` - -## Safety Features - -All restore operations have safeguards: -1. **Confirmation prompt** — asks before overwriting current state -2. **Backup of current** — can save current state before restoring (use `--keep-current`) -3. **Integrity check** — validates backup before using it -4. **Verification** — use `--preview` to see what will be restored -5. **Rollback** — if restore fails, current state is preserved - -## After Restore - -Once restored, you can: -1. Inspect the restored state: `/agent-loop:inspect` -2. Resume the loop: `/agent-loop:start --resume` -3. Or start fresh if restore revealed issues: `/agent-loop:reset` - -## Related Commands - -- `/agent-loop:inspect` — View details about state or backups -- `/agent-loop:reset` — Clear state (creates backup automatically) -- `/agent-loop:status` — Quick status check of current state +Validate the backup against the State file section of the `agent-loop-orchestrator` skill before restoring. Back up the current state file first, then copy the backup into place. Print the restored cycle and suggest `/agent-loop:resume`. diff --git a/agent-loop/commands/resume.md b/agent-loop/commands/resume.md index d170860..06f8362 100644 --- a/agent-loop/commands/resume.md +++ b/agent-loop/commands/resume.md @@ -1,74 +1,10 @@ --- allowed-tools: Bash, Read, Write, Task, Agent -description: Resume the agent-loop from the last persisted state in .agent-loop/state.json. Loads cycle context and thread history, then continues the maintenance cycle. +description: Resume the agent-loop from .agent-loop/state.json and run the next cycle. Use after a stop, crash, or as the command a scheduler invokes each interval. --- -# Agent Loop Resume +# Agent loop resume -Resume the continuous agent-loop from the last saved state in `.agent-loop/state.json`. - -The loop will load the state file to recover everything that was saved: cycle count, items processed, PRs merged, active thread list, and thread history. This allows you to pick up exactly where you left off without losing context. - -## What Gets Recovered - -When you resume, these are restored from state.json: - -| Field | Purpose | -|-------|---------| -| `cycle` | Current cycle number (resumes from N+1) | -| `started_at` | Original start time (maintains uptime) | -| `items_processed` | Total items seen (cumulative) | -| `items_autonomous` / `items_needs_review` / `items_deferred` | Classification counts | -| `prs_merged` | Total PRs successfully merged | -| `active_threads` | Thread IDs still in progress | -| `thread_history` | Full record of past thread outcomes | - -## Resumption Flow - -1. **Load State** — parse `.agent-loop/state.json`, validate integrity -2. **Validate** — check that state is not corrupted and thread IDs are sane -3. **Restore** — reconstruct loop context and metrics -4. **Wait** — sleep for configured interval (default: 5 min) -5. **Triage** — scan repo queues for new actionable items -6. **Dispatch** — route work to parallel agent threads -7. **Monitor** — track progress and outcomes -8. **Report** — append cycle summary to logs - -## Usage - -```bash -# Resume from saved state (error if state.json missing) -/agent-loop:resume - -# Resume with custom interval -/agent-loop:resume --interval 600 - -# Resume with broader scope -/agent-loop:resume --scope all --max-concurrency 4 - -# Preview what would resume without starting loop -/agent-loop:resume --dry-run -``` - -## Options - -- `--interval `: Sleep between cycles (default: 300) -- `--scope `: Triage scope (default: saved scope or current) -- `--max-concurrency `: Max parallel threads (default: saved or 3) -- `--repos `: Comma-separated repos (default: saved repos) -- `--dry-run`: Validate state and preview first cycle without starting loop -- `--validate-only`: Check state.json integrity and exit (no resumption) - -## Error Recovery - -If state.json is corrupted: -1. Use `/agent-loop:inspect` to view the corruption details -2. Use `/agent-loop:restore` to recover from a timestamped backup -3. Or use `/agent-loop:reset` to start fresh (with backup of corrupted state) - -## State File Location - -State is recovered from `.agent-loop/state.json` in the repo root. -Backups are kept in `.agent-loop/backups/state-YYYY-MM-DD-HHmmss.json` for recovery. - -See `/agent-loop:status`, `/agent-loop:inspect`, and `/agent-loop:stop` for state management. +1. Load and validate the state file per the State file section of the `agent-loop-orchestrator` skill. If it is missing, say so and suggest `/agent-loop:start`. If it is invalid, suggest `/agent-loop:restore`. +2. If `shutdown_requested` is true, the loop was stopped. Print that, tell the user to run `/agent-loop:start --resume` to restart, and exit. A leftover scheduled run must not restart a stopped loop. +3. Otherwise increment `cycle` and run one cycle per that skill. diff --git a/agent-loop/commands/start.md b/agent-loop/commands/start.md index 15fdfb1..237af90 100644 --- a/agent-loop/commands/start.md +++ b/agent-loop/commands/start.md @@ -1,62 +1,14 @@ --- allowed-tools: Bash, Read, Write, Task, Agent -description: Start the agent-loop — continuous overnight/day repo maintenance cycle. Auto-detects existing state and prompts to resume or start fresh. Wakes every 5 minutes, triages repos, dispatches work to parallel agent threads, monitors progress, and reports results. +description: Start the agent-loop repo maintenance cycle. Use to begin unattended triage, fix, and merge work on the current repo or a set of repos. --- -# Agent Loop Start +# Agent loop start -Start the continuous agent-loop for automated repository maintenance. +Flags: `--interval `, `--scope `, `--max-concurrency `, `--repos `, `--fresh`, `--resume`, `--dry-run`. -The loop runs indefinitely, cycling through: -1. **Wait** — sleep for configured interval (default: 5 min) -2. **Triage** — scan repo queues for actionable items -3. **Dispatch** — route autonomous work to parallel agent threads -4. **Monitor** — track thread progress and outcomes -5. **Report** — log cycle summary +1. If `.agent-loop/state.json` exists and neither `--fresh` nor `--resume` was passed, ask the user whether to resume, start fresh, or inspect first. `--fresh` backs up the old state and starts at cycle 0. `--resume` clears `shutdown_requested` and then behaves like `/agent-loop:resume`. +2. With `--dry-run`, run triage only and print what would be dispatched. +3. Otherwise run one cycle per the `agent-loop-orchestrator` skill, then set up recurring runs per its Scheduling section. -## Startup Behavior - -When you run `/agent-loop:start`, the command first **checks for existing state**: - -- **If `.agent-loop/state.json` exists** → You are prompted to: - - `resume` — Continue from saved state (preserves cycle count, items processed, thread history) - - `fresh` — Start a new loop (creates a fresh state.json, backup of old state saved) - - `inspect` — View the existing state before deciding - -- **If no state exists** → Starts a fresh loop immediately - -## Usage - -```bash -# Start fresh or resume existing (auto-prompts if state exists) -/agent-loop:start - -# Force start fresh (ignore existing state, create backup) -/agent-loop:start --fresh - -# Force resume (error if state doesn't exist) -/agent-loop:start --resume - -# Override defaults -/agent-loop:start --interval 600 --scope all --max-concurrency 5 -``` - -## Options - -- `--interval `: Sleep between cycles (default: 300) -- `--scope `: Triage scope (default: current) -- `--max-concurrency `: Max parallel threads (default: 3) -- `--repos `: Comma-separated repos for broad scope -- `--fresh`: Ignore existing state, start fresh (backs up old state) -- `--resume`: Resume from existing state (error if state missing) -- `--dry-run`: Preview what the loop would do without executing - -## State Management - -- Persisted to `.agent-loop/state.json` in repo root -- Backups kept in `.agent-loop/backups/` (timestamped) -- Use `/agent-loop:status` to inspect current state -- Use `/agent-loop:inspect` to view state details -- Use `/agent-loop:reset` to clear state and start fresh -- Use `/agent-loop:restore` to recover from a backup -- Use `/agent-loop:stop` to gracefully shut down +The state file format lives in that skill's State file section. diff --git a/agent-loop/commands/status.md b/agent-loop/commands/status.md index 122e73a..f5476d1 100644 --- a/agent-loop/commands/status.md +++ b/agent-loop/commands/status.md @@ -1,41 +1,8 @@ --- allowed-tools: Bash, Read -description: Check agent-loop status — running state, cycle count, items processed, active threads, and recent results. +description: Show agent-loop status. Use to see the current cycle, active workers, and recent results. --- -# Agent Loop Status +# Agent loop status -Check the current state of the agent-loop. - -## Usage - -```bash -/agent-loop:status -/agent-loop:status --json -/agent-loop:status --history 10 -``` - -## Options - -- `--json`: Output raw state as JSON -- `--history `: Show last N cycle reports (default: 5) - -## Output - -```text -Agent Loop: RUNNING (PID: 42391) - Started: 2026-06-11 00:00:00 UTC - Uptime: 2h 14m 32s - Current cycle: #24 - Active threads: 3 - ├─ Thread-1: GH-123 | login timeout fix | 4m 12s running - ├─ Thread-2: GH-124 | deps update | 2m 03s running - └─ Thread-3: GH-125 | docs fix | 30s running - Cycle history (last 5): - #23: 2 autonomous, 0 failed, 1 needs review | 1m 42s - #22: 1 autonomous, 1 merged | 2m 15s - #21: 0 items | 5m 02s (idle) - #20: 3 autonomous, 2 merged, 1 failed | 4m 30s - #19: 0 items | 5m 00s (idle) - Totals: 87 processed, 34 autonomous, 15 merged PRs -``` +Read the state file (format in the `agent-loop-orchestrator` skill). Print the current cycle, uptime since `started_at`, active workers, the last N results from `thread_history` (`--history `, default 5), and the totals. With `--json`, print the raw file. If no state file exists, say the loop has not started. diff --git a/agent-loop/commands/stop.md b/agent-loop/commands/stop.md index 62db61b..a54c317 100644 --- a/agent-loop/commands/stop.md +++ b/agent-loop/commands/stop.md @@ -1,35 +1,11 @@ --- allowed-tools: Bash, Read, Write -description: Stop the agent-loop gracefully. Lets active threads finish within timeout, persists final state, and reports cycle summary. +description: Stop the agent-loop gracefully. Use when the user wants the maintenance cycle to end. --- -# Agent Loop Stop +# Agent loop stop -Gracefully shut down the running agent-loop. - -## Usage - -```bash -/agent-loop:stop -/agent-loop:stop --force -``` - -## Options - -- `--force`: Immediate stop without waiting for active threads - -## What Happens - -1. Sets `shutdown_requested: true` in state file -2. Active threads get up to 120s to finish (or 0 with `--force`) -3. Final state is persisted to `.agent-loop/state.json` -4. Prints cycle summary: - -```text -Agent Loop Stopped - Cycles completed: 24 - Items processed: 87 - PRs merged: 15 - Duration: 2h 14m - State saved to .agent-loop/state.json -``` +1. Set `shutdown_requested: true` in the state file (format in the `agent-loop-orchestrator` skill). +2. Without `--force`, wait up to 120 seconds for active workers to finish. With `--force`, stop them now and record them as `failed` with reason `stopped`. +3. Cancel any recurring run you set up for the loop in this harness. +4. Print cycles completed, items processed, PRs merged, and total duration. diff --git a/agent-loop/commands/triage.md b/agent-loop/commands/triage.md index 2c0669f..1e4e178 100644 --- a/agent-loop/commands/triage.md +++ b/agent-loop/commands/triage.md @@ -1,49 +1,10 @@ --- allowed-tools: Bash(git *), Bash(gh *), Read -description: Run one-shot triage on repo queues. Scans open issues, PRs, CI status. Classifies items by fit, risk, autonomy. No loop, just snapshot. +description: Run one triage pass over repo issues and PRs and print the classified queue. Use for a snapshot without starting the loop. --- -# Agent Loop Triage +# Agent loop triage -One-shot triage scan of repository queues. Does NOT start the loop — just -inspects and reports. +Flags: `--scope `, `--org `, `--repo `, `--detail`, `--json`, `--limit ` (default 50). -## Usage - -```bash -/agent-loop:triage -/agent-loop:triage --scope all -/agent-loop:triage --scope org --org duyet -/agent-loop:triage --repo duyet/clickhouse-monitoring -/agent-loop:triage --detail # Full detail on every item -/agent-loop:triage --json # Machine-readable output -``` - -## Options - -- `--scope `: Triage scope (default: current repo) -- `--org `: Organization for org scope (default: from git remote) -- `--repo `: Specific repo to triage -- `--detail`: Full detail on every item (not just top items) -- `--json`: Machine-readable JSON output -- `--limit `: Max items per queue (default: 50) - -## Output - -```text -Triage Report — duyet/clickhouse-monitoring -Scanned: 12 issues, 5 PRs - -Autonomous (2): - GH-123: bug | login timeout on slow networks - Risk: low | Proof: repro + failing test - → Dispatch: fix and PR - - GH-124: deps | update lodash to 4.17.21 - Risk: low | Proof: green CI - → Dispatch: merge - -Needs Review (1): GH-125: feature | dark mode - -Defer/Close (2): GH-126, GH-127 (stale/duplicate) -``` +Follow the `agent-loop-triage` skill and print its report. Change nothing. diff --git a/agent-loop/skills/agent-loop-autoreview.md b/agent-loop/skills/agent-loop-autoreview.md deleted file mode 100644 index 9f6e9d8..0000000 --- a/agent-loop/skills/agent-loop-autoreview.md +++ /dev/null @@ -1,148 +0,0 @@ ---- -description: >- - Autonomous code review and fix skill for the agent-loop plugin. Reviews PRs, - applies fixes from AI review bots (CodeRabbit, Sourcery, Gemini), validates - changes, and lands them. Designed for unattended overnight operation. ---- - -# Agent Loop Autoreview - -Autonomously review and fix pull requests. This skill: - -1. Identifies PRs needing review (new, updated, or with review comments) -2. Reads review bot suggestions from CodeRabbit/Sourcery/Gemini -3. Applies verified fixes -4. Runs validation (lint, test, build) -5. Commits and pushes fixes, or merges when green - -## PR Discovery - -Find PRs that need attention: - -```bash -# PRs with review comments from bots -gh pr list --state open --json number,title,author,updatedAt --limit 20 - -# Check for unresolved review threads (bot-originated) -gh api repos/{owner}/{repo}/pulls/{pr}/reviews \ - --jq '.[] | select(.state == "CHANGES_REQUESTED") | {user: .user.login, body: .body}' -``` - -## Fetch Review Comments - -### CodeRabbit Comments - -```bash -# All review threads -gh api repos/{owner}/{repo}/pulls/{pr}/reviews \ - --jq '.[] | select(.user.login | test("coderabbit")) | {id, body, state}' -``` - -### Inline Comments - -```bash -gh api repos/{owner}/{repo}/pulls/{pr}/comments \ - --jq '.[] | select(.user.login | test("coderabbit|sourcery|gemini-code-assist")) | {path, line, body, id}' -``` - -## Apply Fixes - -### Extraction - -From each review comment, extract: -- **File path** and **line number** -- **Issue description** and **severity** (critical, high, medium, low) -- **Suggested fix** or **agent prompt** (from `🤖 Prompt for AI Agents` section) -- **Type** (bug, security, performance, style, docs) - -### Fix Application Workflow - -``` -1. Read file at specified path+line -2. Understand the issue context -3. Apply fix (minimal change, no refactoring) -4. Validate: - - Edit tool → file changed - - LSP diagnostics clean - - Run project linter: npm run lint / ruff / etc - - Run relevant tests -5. If validation fails → log error, skip, report -``` - -### Validation Commands - -```bash -# TypeScript/JS -npx tsc --noEmit 2>&1 | head -50 -npm run lint 2>&1 | head -50 -npm run test -- --run 2>&1 | tail -50 - -# Python -ruff check . 2>&1 | head -30 -pytest -x --timeout=60 2>&1 | tail -50 - -# General -git diff --stat -``` - -## Commit and Push - -After applying all fixes for a PR: - -```bash -git add -A -git commit -m "fix(pr): apply review bot suggestions - -- Applied N fixes from CodeRabbit/Sourcery/Gemini - -Co-Authored-By: duyetbot " -git push -``` - -## Merge When Ready - -Check merge readiness: - -```bash -gh pr view --json mergeStateStatus,reviewDecision,statusCheckRollup -``` - -Conditions for auto-merge: -1. All required status checks passing -2. No unresolved review threads requesting changes -3. No merge conflicts - -```bash -# Merge -gh pr merge --squash --delete-branch -``` - -## Safety Gating - -**Never auto-merge when:** -- PR is a draft -- PR has `WIP`, `do-not-merge`, `blocked`, or `hold` label -- PR has unresolved human review requesting changes -- CI has failing required checks (flake retry 1x first) -- PR changes security-sensitive paths (`Dockerfile`, `.env`, secrets, auth) -- PR is from an untrusted first-time contributor (check trust) - -**Log every decision:** -``` -Autoreview: PR #123 - Bot comments: 3 (CodeRabbit: 2, Sourcery: 1) - Fixes applied: 2 - Skipped: 1 (suggestion only, not actionable) - Validation: lint ✅, test ✅, build ✅ - Result: merged as abc1234 -``` - -## Failure Handling - -| Scenario | Action | -|----------|--------| -| Fix fails validation | Revert, log error, skip | -| CI flake | Retry once after 60s | -| Merge conflict | Report as blocked | -| Unknown file changed by fix | Skip, flag for review | -| Critical security issue | Skip, escalate in report | diff --git a/agent-loop/skills/agent-loop-autoreview/SKILL.md b/agent-loop/skills/agent-loop-autoreview/SKILL.md index 495a13e..bc1eb9c 100644 --- a/agent-loop/skills/agent-loop-autoreview/SKILL.md +++ b/agent-loop/skills/agent-loop-autoreview/SKILL.md @@ -1,149 +1,54 @@ --- name: agent-loop-autoreview -description: >- - Autonomous code review and fix skill for the agent-loop plugin. Reviews PRs, - applies fixes from AI review bots (CodeRabbit, Sourcery, Gemini), validates - changes, and lands them. Designed for unattended overnight operation. +description: Review a PR unattended, apply verified fixes from AI review bots (CodeRabbit, Sourcery, Gemini), validate, and merge when safe. Use for agent-loop workers or /agent-loop:autoreview. --- -# Agent Loop Autoreview +# Agent loop autoreview -Autonomously review and fix pull requests. This skill: - -1. Identifies PRs needing review (new, updated, or with review comments) -2. Reads review bot suggestions from CodeRabbit/Sourcery/Gemini -3. Applies verified fixes -4. Runs validation (lint, test, build) -5. Commits and pushes fixes, or merges when green - -## PR Discovery - -Find PRs that need attention: - -```bash -# PRs with review comments from bots -gh pr list --state open --json number,title,author,updatedAt --limit 20 - -# Check for unresolved review threads (bot-originated) -gh api repos/{owner}/{repo}/pulls/{pr}/reviews \ - --jq '.[] | select(.state == "CHANGES_REQUESTED") | {user: .user.login, body: .body}' -``` - -## Fetch Review Comments - -### CodeRabbit Comments - -```bash -# All review threads -gh api repos/{owner}/{repo}/pulls/{pr}/reviews \ - --jq '.[] | select(.user.login | test("coderabbit")) | {id, body, state}' -``` - -### Inline Comments +## Gather ```bash -gh api repos/{owner}/{repo}/pulls/{pr}/comments \ +gh pr view --json number,title,author,isDraft,labels,reviewDecision,mergeStateStatus,statusCheckRollup +gh pr diff +gh api repos/{owner}/{repo}/pulls/{n}/comments \ --jq '.[] | select(.user.login | test("coderabbit|sourcery|gemini-code-assist")) | {path, line, body, id}' +gh api repos/{owner}/{repo}/pulls/{n}/reviews --jq '.[] | {user: .user.login, state, body}' ``` -## Apply Fixes - -### Extraction - -From each review comment, extract: -- **File path** and **line number** -- **Issue description** and **severity** (critical, high, medium, low) -- **Suggested fix** or **agent prompt** (from `🤖 Prompt for AI Agents` section) -- **Type** (bug, security, performance, style, docs) - -### Fix Application Workflow - -``` -1. Read file at specified path+line -2. Understand the issue context -3. Apply fix (minimal change, no refactoring) -4. Validate: - - Edit tool → file changed - - LSP diagnostics clean - - Run project linter: npm run lint / ruff / etc - - Run relevant tests -5. If validation fails → log error, skip, report -``` - -### Validation Commands +Stop and report if the PR is a draft or carries a skip label (`wip`, `do-not-merge`, `blocked`, `hold`). -```bash -# TypeScript/JS -npx tsc --noEmit 2>&1 | head -50 -npm run lint 2>&1 | head -50 -npm run test -- --run 2>&1 | tail -50 +## Fix -# Python -ruff check . 2>&1 | head -30 -pytest -x --timeout=60 2>&1 | tail -50 +For each bot comment, extract the path, line, issue, severity, and suggested fix. CodeRabbit's "Prompt for AI Agents" block is the most precise source. Then: -# General -git diff --stat -``` +1. Read the code around the line and decide whether the comment is correct. Bots file non-issues. Skip those with a one-line reason. +2. Apply the smallest change that fixes it. No drive-by refactors. +3. Run the project's own lint, typecheck, and the tests near the change. Find the commands in package.json, pyproject.toml, Makefile, or CI config. +4. If validation fails, revert that fix and record it as skipped. -## Commit and Push +Skip and escalate anything that touches auth, secrets, `.env`, or Dockerfiles, and any fix that changes files the comment did not name. -After applying all fixes for a PR: +## Commit ```bash -git add -A -git commit -m "fix(pr): apply review bot suggestions - -- Applied N fixes from CodeRabbit/Sourcery/Gemini - -Co-Authored-By: duyetbot " +git add +git commit -m "fix(pr): apply review bot suggestions" git push ``` -## Merge When Ready +## Merge -Check merge readiness: +Merge only when asked to (`--merge`, or the loop's dispatch said so) and all hold: -```bash -gh pr view --json mergeStateStatus,reviewDecision,statusCheckRollup -``` - -Conditions for auto-merge: -1. All required status checks passing -2. No unresolved review threads requesting changes -3. No merge conflicts +- Required checks pass. Rerun a failed check once to rule out a flake. +- No human review requests changes. +- No merge conflicts. +- The author is not a first-time contributor touching security-sensitive paths. ```bash -# Merge gh pr merge --squash --delete-branch ``` -## Safety Gating - -**Never auto-merge when:** -- PR is a draft -- PR has `WIP`, `do-not-merge`, `blocked`, or `hold` label -- PR has unresolved human review requesting changes -- CI has failing required checks (flake retry 1x first) -- PR changes security-sensitive paths (`Dockerfile`, `.env`, secrets, auth) -- PR is from an untrusted first-time contributor (check trust) - -**Log every decision:** -``` -Autoreview: PR #123 - Bot comments: 3 (CodeRabbit: 2, Sourcery: 1) - Fixes applied: 2 - Skipped: 1 (suggestion only, not actionable) - Validation: lint ✅, test ✅, build ✅ - Result: merged as abc1234 -``` - -## Failure Handling +## Report -| Scenario | Action | -|----------|--------| -| Fix fails validation | Revert, log error, skip | -| CI flake | Retry once after 60s | -| Merge conflict | Report as blocked | -| Unknown file changed by fix | Skip, flag for review | -| Critical security issue | Skip, escalate in report | +One block per PR: bot comments found, fixes applied, fixes skipped with reasons, validation results, and the outcome (`merged`, `pr_updated`, `blocked`, or `needs_human`). diff --git a/agent-loop/skills/agent-loop-browser.md b/agent-loop/skills/agent-loop-browser.md deleted file mode 100644 index 1cd832d..0000000 --- a/agent-loop/skills/agent-loop-browser.md +++ /dev/null @@ -1,115 +0,0 @@ ---- -description: >- - Browser automation and computer-use skill for the agent-loop plugin. Takes - screenshots, validates UI behavior, fills forms, clicks elements, and - performs live web proof. Uses existing Chrome session via DevTools MCP. ---- - -# Agent Loop Browser - -Browser automation for the agent-loop. Use this for: - -- Taking screenshots of deployed previews for visual validation -- Filling forms, clicking buttons, navigating pages -- Checking live UI behavior as part of PR verification -- Capturing before/after proof for autonomous PRs - -## Prerequisites - -Prefer the existing Chrome session (logged-in state, extensions, cookies). - -### DevTools MCP Check - -```bash -# Check if Chrome DevTools MCP is available -mcporter list chrome-devtools --schema 2>/dev/null || echo "MCP not available" -``` - -If MCP is unavailable, fall back to the `browser` skill's CLI: - -```bash -# Check browser CLI -command -v browse >/dev/null 2>&1 || echo "browse CLI not installed" -``` - -## Page Navigation - -```bash -# Navigate to URL -mcporter call chrome-devtools.navigate_page \ - --args '{"url":"https://github.com/owner/repo/pull/123"}' --output text - -# Or with browse CLI -browse goto "https://github.com/owner/repo/pull/123" -``` - -## Taking Snapshots - -```bash -# Text snapshot of current page (for understanding layout) -mcporter call chrome-devtools.take_snapshot --args '{}' --output text - -# Screenshot for visual proof -mcporter call chrome-devtools.take_screenshot \ - --args '{"filePath":"/tmp/agent-loop-proof.png"}' -``` - -## Form Filling - -```bash -# Fill form elements -mcporter call chrome-devtools.fill \ - --args '{"uid":"1_13","value":"text"}' --output text -``` - -## Click Elements - -```bash -# Click a button/link -mcporter call chrome-devtools.click \ - --args '{"uid":"1_38"}' --output text -``` - -## Evaluate Script - -```bash -# Run JavaScript in page context -mcporter call chrome-devtools.evaluate_script \ - --args '{"function":"() => document.title"}' --output text - -# Check CI status from GitHub page -mcporter call chrome-devtools.evaluate_script \ - --args '{"function":"() => document.querySelectorAll('.check-run').length"}' --output text -``` - -## Visual Validation Workflow - -For PR verification requiring UI proof: - -``` -1. Navigate to preview/deployed URL -2. Wait for page to load (wait_for text or timeout) -3. Take full-page screenshot → save to /tmp/agent-loop-proof-{pr}.png -4. Compare against expected state (if reference exists) -5. Report: "Visual proof captured at {path}" -``` - -```bash -# Capture proof -mcporter call chrome-devtools.navigate_page \ - --args '{"url":"https://preview.example.com/pr/123"}' --output text -mcporter call chrome-devtools.wait_for \ - --args '{"text":["Dashboard","Loaded"]}' --output text -mcporter call chrome-devtools.take_screenshot \ - --args '{"filePath":"/tmp/agent-loop-proof-123.png","fullPage":true}' -``` - -## Failure Handling - -| Scenario | Action | -|----------|--------| -| MCP not available | Log warning, skip browser step | -| Page not found | Log 404, report broken link | -| Element not found | Wait 2s, retry once, then skip | -| Login required | Skip — cannot automate with isolated session | -| Screenshot fails | Report with page source instead | diff --git a/agent-loop/skills/agent-loop-browser/SKILL.md b/agent-loop/skills/agent-loop-browser/SKILL.md index 218b726..aea23e2 100644 --- a/agent-loop/skills/agent-loop-browser/SKILL.md +++ b/agent-loop/skills/agent-loop-browser/SKILL.md @@ -1,116 +1,25 @@ --- name: agent-loop-browser -description: >- - Browser automation and computer-use skill for the agent-loop plugin. Takes - screenshots, validates UI behavior, fills forms, clicks elements, and - performs live web proof. Uses existing Chrome session via DevTools MCP. +description: Capture browser proof for a PR, such as screenshots of a preview deploy or a check that a UI flow works. Use when an agent-loop worker needs visual or live-page verification. --- -# Agent Loop Browser +# Agent loop browser -Browser automation for the agent-loop. Use this for: +Use whatever browser tool the harness provides: a Chrome DevTools MCP server, a browser-control extension, or a headless CLI such as Playwright. Prefer one attached to the user's existing browser session when the page needs login. If no browser tool is available, log that and skip the browser step. Do not fail the item for it. -- Taking screenshots of deployed previews for visual validation -- Filling forms, clicking buttons, navigating pages -- Checking live UI behavior as part of PR verification -- Capturing before/after proof for autonomous PRs +## Proof workflow -## Prerequisites +1. Open the preview or deployed URL for the PR. +2. Wait for text that shows the page loaded, not a fixed delay. +3. Exercise the changed behavior (click, fill, navigate) if the PR changes a flow. +4. Take a full-page screenshot to a temp directory, named `agent-loop-proof-.png`. +5. Report the screenshot path and what it shows. -Prefer the existing Chrome session (logged-in state, extensions, cookies). +## Failure handling -### DevTools MCP Check - -```bash -# Check if Chrome DevTools MCP is available -mcporter list chrome-devtools --schema 2>/dev/null || echo "MCP not available" -``` - -If MCP is unavailable, fall back to the `browser` skill's CLI: - -```bash -# Check browser CLI -command -v browse >/dev/null 2>&1 || echo "browse CLI not installed" -``` - -## Page Navigation - -```bash -# Navigate to URL -mcporter call chrome-devtools.navigate_page \ - --args '{"url":"https://github.com/owner/repo/pull/123"}' --output text - -# Or with browse CLI -browse goto "https://github.com/owner/repo/pull/123" -``` - -## Taking Snapshots - -```bash -# Text snapshot of current page (for understanding layout) -mcporter call chrome-devtools.take_snapshot --args '{}' --output text - -# Screenshot for visual proof -mcporter call chrome-devtools.take_screenshot \ - --args '{"filePath":"/tmp/agent-loop-proof.png"}' -``` - -## Form Filling - -```bash -# Fill form elements -mcporter call chrome-devtools.fill \ - --args '{"uid":"1_13","value":"text"}' --output text -``` - -## Click Elements - -```bash -# Click a button/link -mcporter call chrome-devtools.click \ - --args '{"uid":"1_38"}' --output text -``` - -## Evaluate Script - -```bash -# Run JavaScript in page context -mcporter call chrome-devtools.evaluate_script \ - --args '{"function":"() => document.title"}' --output text - -# Check CI status from GitHub page -mcporter call chrome-devtools.evaluate_script \ - --args '{"function":"() => document.querySelectorAll('.check-run').length"}' --output text -``` - -## Visual Validation Workflow - -For PR verification requiring UI proof: - -``` -1. Navigate to preview/deployed URL -2. Wait for page to load (wait_for text or timeout) -3. Take full-page screenshot → save to /tmp/agent-loop-proof-{pr}.png -4. Compare against expected state (if reference exists) -5. Report: "Visual proof captured at {path}" -``` - -```bash -# Capture proof -mcporter call chrome-devtools.navigate_page \ - --args '{"url":"https://preview.example.com/pr/123"}' --output text -mcporter call chrome-devtools.wait_for \ - --args '{"text":["Dashboard","Loaded"]}' --output text -mcporter call chrome-devtools.take_screenshot \ - --args '{"filePath":"/tmp/agent-loop-proof-123.png","fullPage":true}' -``` - -## Failure Handling - -| Scenario | Action | -|----------|--------| -| MCP not available | Log warning, skip browser step | -| Page not found | Log 404, report broken link | -| Element not found | Wait 2s, retry once, then skip | -| Login required | Skip — cannot automate with isolated session | -| Screenshot fails | Report with page source instead | +| Case | Action | +|------|--------| +| Page 404 | Report the broken URL | +| Element missing | Retry once after the page settles, then skip | +| Login required and no logged-in session | Skip and report | +| Screenshot fails | Report the page text instead | diff --git a/agent-loop/skills/agent-loop-orchestrator.md b/agent-loop/skills/agent-loop-orchestrator.md deleted file mode 100644 index ef85b00..0000000 --- a/agent-loop/skills/agent-loop-orchestrator.md +++ /dev/null @@ -1,188 +0,0 @@ ---- -description: >- - Core orchestrator skill for the agent-loop plugin. Runs a continuous - maintenance loop that wakes every N minutes, scans repo queues, dispatches - work to parallel agent threads, tracks progress, and reports results. - Designed for overnight and day-long autonomous repo upkeep. ---- - -# Agent Loop Orchestrator - -You are the agent-loop orchestrator — a persistent automation runtime that keeps -repositories healthy without human supervision. You run in cycles, each cycle: - -1. **Poll** — wake every 5 minutes (configurable) -2. **Triage** — scan repo queues for actionable work -3. **Dispatch** — route work to parallel agent threads -4. **Track** — monitor thread progress and results -5. **Report** — summarize cycle output - -## Core Loop - -``` -┌─────────────────────────────────────────────┐ -│ AGENT LOOP CYCLE │ -│ │ -│ Wait 5m ──► Triage ──► Dispatch ──► Monitor │ -│ ↑ │ -│ └──────────── Cycle complete ────────────┘ -``` - -### 1. Wait / Sleep - -```bash -# Default interval: 5 minutes -sleep 300 -``` - -Override with `AGENT_LOOP_INTERVAL` env var (in seconds): -```bash -AGENT_LOOP_INTERVAL=600 # 10 minutes -AGENT_LOOP_INTERVAL=120 # 2 minutes (dev/testing) -``` - -### 2. Triage Phase - -Run the triage skill to discover actionable items: - -```bash -# Load triage skill — scans open issues, PRs, CI failures -/agent-loop:triage --scope current - -# Or broad scan across all configured repos -/agent-loop:triage --scope all -``` - -Classify each item: - -| Category | Action | Example | -|----------|--------|---------| -| `autonomous` | Can fix/land without human input | Bugfix with repro, clear test, narrow scope | -| `needs_review` | Needs maintainer before land | New feature, risk change, no VISION.md match | -| `defer` | Stale, duplicate, or low-value | Old issue, superseded PR, no-repro bug | -| `blocked` | Blocked on CI, access, or conflict | Failing required check, missing key | - -### 3. Dispatch Phase - -For each autonomous item, spawn a dedicated agent thread to handle it: - -```bash -# Spawn parallel worker threads for each autonomous item -task( - category="deep", - load_skills=["agent-loop-triage", "agent-loop-autoreview", "agent-loop-browser"], - run_in_background=true, - prompt="=== WORKER AGENT ===\n...\nTASK: Implement fix for GH-{issue_number}: {title}\n..." -) -``` - -**Dispatch rules:** -- One thread per item (never merge multiple items into one thread) -- Max concurrent threads: `AGENT_LOOP_MAX_CONCURRENCY` (default: 3) -- Threads are independent — failures in one don't affect others -- Each thread gets full skill context (triage + autoreview + browser) - -### 4. Monitor Phase - -```bash -# Collect results from completed threads -# Track: passed, failed, needs_human, deferred - -# Log outcomes per thread: -# - Thread {id}: {item} → result -# - If failed: reason -# - If needs_human: what's blocking -``` - -### 5. Report Phase - -After each cycle, append a log entry: - -``` -─── Agent Loop Cycle #{n} ────────────────────────── - Interval: 5m - Scope: duyet/clickhouse-monitoring - Scanned: 12 issues, 5 PRs - Autonomous: 2 → dispatched to threads - ✓ Thread-1: GH-123 fix timeout handling → PR #456 merged - ✓ Thread-2: GH-124 update deps → PR #457 landed - Needs review: 1 → GH-125 feature request - Blocked: 0 - Deferred: 1 → GH-126 stale (4mo no activity) - Duration: 4m 23s - Next cycle in 5m -─── ────────────────────────────────────────────── -``` - -## Configuration - -Set via environment variables: - -| Variable | Default | Description | -|----------|---------|-------------| -| `AGENT_LOOP_INTERVAL` | 300 | Sleep between cycles (seconds) | -| `AGENT_LOOP_MAX_CONCURRENCY` | 3 | Max parallel worker threads | -| `AGENT_LOOP_SCOPE` | current | Default triage scope (`current`, `all`, `org`) | -| `AGENT_LOOP_LOG_DIR` | .agent-loop/logs | Log output directory | -| `AGENT_LOOP_STATE_FILE` | .agent-loop/state.json | Persisted loop state | -| `AGENT_LOOP_REPOS` | (from git remote) | Comma-separated repo list for broad scope | - -## State Persistence - -The loop persists its state to `AGENT_LOOP_STATE_FILE`: - -```json -{ - "cycle": 42, - "started_at": "2026-06-11T00:00:00Z", - "last_cycle_end": "2026-06-11T00:05:23Z", - "items_processed": 87, - "items_autonomous": 34, - "items_needs_review": 28, - "items_deferred": 25, - "prs_merged": 15, - "active_threads": [3, 4, 5], - "thread_history": [ - {"id": 1, "item": "GH-123", "result": "merged", "pr": "#456"}, - {"id": 2, "item": "GH-124", "result": "failed", "reason": "test flake"} - ] -} -``` - -## Thread Management - -### Lifecycle - -``` -Created ──► Running ──► Completed - │ - ├──► Failed (retry up to 2x) - │ - └──► Needs human (flag for next report) -``` - -### Thread Safety - -- Threads operate on independent items — no shared state -- Each thread runs in its own agent context -- Git operations are serialized per repo (use lock) -- State file is read/written atomically - -## Graceful Shutdown - -When stopping the loop: - -1. Set `shutdown_requested: true` in state -2. Let active threads finish (up to `AGENT_LOOP_SHUTDOWN_TIMEOUT` = 120s) -3. Persist final state -4. Exit with cycle summary - -## Usage - -Start with: -```bash -/agent-loop:start -``` - -This activates the orchestrator which loads this skill and begins cycling -through triage → dispatch → monitor → report until stopped. diff --git a/agent-loop/skills/agent-loop-orchestrator/SKILL.md b/agent-loop/skills/agent-loop-orchestrator/SKILL.md index 933b06d..f9a0b05 100644 --- a/agent-loop/skills/agent-loop-orchestrator/SKILL.md +++ b/agent-loop/skills/agent-loop-orchestrator/SKILL.md @@ -1,222 +1,69 @@ --- name: agent-loop-orchestrator -description: >- - Core orchestrator for the agent-loop plugin. Runs a continuous maintenance - loop that wakes every N minutes, scans repo queues, dispatches work to - parallel agent threads, tracks progress, and reports results. Designed for - overnight and day-long autonomous repo upkeep. +description: Run a repeating repo maintenance cycle that triages issues and PRs, dispatches autonomous fixes to parallel subagents, and reports results. Use when started by /agent-loop:start or when asked for unattended overnight repo upkeep. --- -# Agent Loop Orchestrator +# Agent loop orchestrator -You are the agent-loop orchestrator — a persistent automation runtime that keeps -repositories healthy without human supervision. You run in cycles, each cycle: +Each cycle runs four steps: triage, dispatch, monitor, report. This skill runs one cycle. Repetition comes from the harness, not from you. -1. **Poll** — wake every 5 minutes (configurable) -2. **Triage** — scan repo queues for actionable work -3. **Dispatch** — route work to parallel agent threads -4. **Track** — monitor thread progress and results -5. **Report** — summarize cycle output +## Scheduling -## Core Loop +Do not run `sleep` in a shell to wait between cycles. A sleeping shell holds the session and usually hits a tool timeout. Use the harness's own recurring-run facility instead: -``` -┌─────────────────────────────────────────────┐ -│ AGENT LOOP CYCLE │ -│ │ -│ Wait 5m ──► Triage ──► Dispatch ──► Monitor │ -│ ↑ │ -│ └──────────── Cycle complete ────────────┘ -``` - -### 1. Wait / Sleep - -```bash -# Default interval: 5 minutes -sleep 300 -``` - -Override with `AGENT_LOOP_INTERVAL` env var (in seconds): -```bash -AGENT_LOOP_INTERVAL=600 # 10 minutes -AGENT_LOOP_INTERVAL=120 # 2 minutes (dev/testing) -``` - -### 2. Triage Phase - -Run the triage skill to discover actionable items: - -```bash -# Load triage skill — scans open issues, PRs, CI failures -# /agent-loop:triage --scope current - -# Or broad scan across all configured repos -# /agent-loop:triage --scope all -``` +- Claude Code: `/loop /agent-loop:resume` (or the `schedule` skill for runs that outlive the session). +- Codex, Cursor, and other harnesses: use their scheduled or recurring task feature, or an external cron job that invokes the agent CLI in headless mode with `/agent-loop:resume`. -Classify each item: +If the harness has no such facility, run one cycle, report, and tell the user how to rerun it. -| Category | Action | Example | -|----------|--------|---------| -| `autonomous` | Can fix/land without human input | Bugfix with repro, clear test, narrow scope | -| `needs_review` | Needs maintainer before land | New feature, risk change, no VISION.md match | -| `defer` | Stale, duplicate, or low-value | Old issue, superseded PR, no-repro bug | -| `blocked` | Blocked on CI, access, or conflict | Failing required check, missing key | +## Cycle -### 3. Dispatch Phase +1. **Triage.** Follow `../agent-loop-triage/SKILL.md` for the configured scope. It returns items classified as `autonomous`, `needs_review`, `defer`, or `blocked`. +2. **Dispatch.** Spawn one background subagent per `autonomous` item, at most `max_concurrency` at a time. Give each one the item, the repo, and pointers to `../agent-loop-autoreview/SKILL.md` and `../agent-loop-browser/SKILL.md`. Never batch two items into one worker. Workers touching the same repo must use separate branches or worktrees. +3. **Monitor.** Collect each worker's result: `merged`, `pr_opened`, `failed` (retry at most twice), or `needs_human` (with what blocks it). +4. **Report.** Update the state file, append a cycle summary to `.agent-loop/logs/`, and print it: repo, counts per class, one line per worker result, duration. -For each autonomous item, spawn a dedicated agent thread to handle it. - -**Dispatch rules:** -- One thread per item (never merge multiple items into one thread) -- Max concurrent threads: `AGENT_LOOP_MAX_CONCURRENCY` (default: 3) -- Threads are independent — failures in one don't affect others -- Each thread gets full skill context (triage + autoreview + browser) - -### 4. Monitor Phase - -```bash -# Collect results from completed threads -# Track: passed, failed, needs_human, deferred - -# Log outcomes per thread: -# - Thread {id}: {item} → result -# - If failed: reason -# - If needs_human: what's blocking -``` - -### 5. Report Phase - -After each cycle, append a log entry: - -``` -─── Agent Loop Cycle #{n} ────────────────────────── - Interval: 5m - Scope: duyet/clickhouse-monitoring - Scanned: 12 issues, 5 PRs - Autonomous: 2 → dispatched to threads - ✓ Thread-1: GH-123 fix timeout handling → PR #456 merged - ✓ Thread-2: GH-124 update deps → PR #457 landed - Needs review: 1 → GH-125 feature request - Blocked: 0 - Deferred: 1 → GH-126 stale (4mo no activity) - Duration: 4m 23s - Next cycle in 5m -─── ────────────────────────────────────────────── -``` +Stop early if the state file has `shutdown_requested: true`. Let running workers finish, write final state, and print the summary. ## Configuration -Set via environment variables: +Read from command flags first, then environment variables, then defaults. -| Variable | Default | Description | -|----------|---------|-------------| -| `AGENT_LOOP_INTERVAL` | 300 | Sleep between cycles (seconds) | -| `AGENT_LOOP_MAX_CONCURRENCY` | 3 | Max parallel worker threads | -| `AGENT_LOOP_SCOPE` | current | Default triage scope (`current`, `all`, `org`) | -| `AGENT_LOOP_LOG_DIR` | .agent-loop/logs | Log output directory | -| `AGENT_LOOP_STATE_FILE` | .agent-loop/state.json | Persisted loop state | -| `AGENT_LOOP_REPOS` | (from git remote) | Comma-separated repo list for broad scope | +| Variable | Default | Meaning | +|----------|---------|---------| +| `AGENT_LOOP_INTERVAL` | 300 | Seconds between cycles, passed to the scheduler | +| `AGENT_LOOP_MAX_CONCURRENCY` | 3 | Max parallel workers | +| `AGENT_LOOP_SCOPE` | current | Triage scope: `current`, `all`, or `org` | +| `AGENT_LOOP_REPOS` | git remote | Comma-separated repos for `all` scope | +| `AGENT_LOOP_STATE_FILE` | .agent-loop/state.json | State file path | -## State Persistence & Recovery +## State file -The loop persists its state to `AGENT_LOOP_STATE_FILE` (default: `.agent-loop/state.json`): +This is the single definition of the state file. All agent-loop commands read and write this shape. ```json { "cycle": 42, - "started_at": "2026-06-11T00:00:00Z", - "last_cycle_end": "2026-06-14T14:30:23Z", + "started_at": "2026-10-19T00:00:00Z", + "last_cycle_end": "2026-10-19T03:30:23Z", + "shutdown_requested": false, "items_processed": 87, "items_autonomous": 34, "items_needs_review": 28, "items_deferred": 25, "prs_merged": 15, - "active_threads": [3, 4, 5], + "active_threads": [3, 4], "thread_history": [ {"id": 1, "item": "GH-123", "result": "merged", "pr": "#456"}, {"id": 2, "item": "GH-124", "result": "failed", "reason": "test flake"} ], - "version": "0.4.0", - "last_error": null, - "state_valid": true + "last_error": null } ``` -### State Validation - -When loading state on startup: -1. **File exists?** → Check if `.agent-loop/state.json` is readable -2. **Valid JSON?** → Parse and catch JSON syntax errors -3. **Required fields?** → Ensure cycle, started_at, items_processed, etc. are present -4. **Type safety?** → Verify fields are correct types (numbers, strings, arrays) -5. **Orphaned threads?** → Check for threads in history but marked as active -6. **Metric consistency?** → Verify autonomous + needs_review + deferred = total - -### State Recovery - -If state.json is corrupted or missing: - -**Option 1: Resume from backup** -```bash -/agent-loop:restore --list # List available backups -/agent-loop:restore state-2026-06-14-143022.json # Restore specific backup -``` - -**Option 2: Fresh start with backup of current** -```bash -/agent-loop:reset # Clear state, backup old state -/agent-loop:start # Begin fresh loop -``` - -**Option 3: Inspect before deciding** -```bash -/agent-loop:inspect # View state details and errors -/agent-loop:inspect --validate # Check state integrity -``` - -### Backup System - -Backups are automatically created in `.agent-loop/backups/`: -- Named with timestamp: `state-YYYY-MM-DD-HHmmss.json` -- Auto-created when you run `/agent-loop:reset` or `/agent-loop:start --fresh` -- Kept for full recovery (automatic cleanup keeps latest 50) -- Can be inspected before restore: `/agent-loop:inspect --backup ` - -## Thread Management - -### Lifecycle - -``` -Created ──► Running ──► Completed - │ - ├──► Failed (retry up to 2x) - │ - └──► Needs human (flag for next report) -``` - -### Thread Safety - -- Threads operate on independent items — no shared state -- Each thread runs in its own agent context -- Git operations are serialized per repo (use lock) -- State file is read/written atomically - -## Graceful Shutdown - -When stopping the loop: - -1. Set `shutdown_requested: true` in state -2. Let active threads finish (up to `AGENT_LOOP_SHUTDOWN_TIMEOUT` = 120s) -3. Persist final state -4. Exit with cycle summary - -## Usage - -Start with: -```bash -/agent-loop:start -``` +Rules: -This activates the orchestrator which loads this skill and begins cycling -through triage → dispatch → monitor → report until stopped. +- Write atomically. Write to a temp file in the same directory, then rename. +- A valid state file parses as JSON and has `cycle`, `started_at`, and `thread_history`. Missing counters default to 0. +- Before overwriting or clearing state, copy it to `.agent-loop/backups/state-YYYY-MM-DD-HHmmss.json`. Keep the newest 50 backups. +- On load, any `active_threads` id with no running worker is orphaned. Record it in `thread_history` as `failed` with reason `orphaned` and remove it from `active_threads`. diff --git a/agent-loop/skills/agent-loop-triage.md b/agent-loop/skills/agent-loop-triage.md deleted file mode 100644 index e3e5dbe..0000000 --- a/agent-loop/skills/agent-loop-triage.md +++ /dev/null @@ -1,179 +0,0 @@ ---- -description: >- - GitHub project triage for the agent-loop plugin. Scans open issues, PRs, CI - queues, and blockers. Classifies items by fit, risk, proof, and autonomy. - Adapted from github-project-triage for autonomous loop integration. ---- - -# Agent Loop Triage - -Scan open issues and PRs for the current repo (or a configured set of repos). -Classify each item and return a structured queue summary suitable for the -orchestrator loop's dispatch phase. - -## Setup - -### GitHub CLI Check - -```bash -gh auth status 2>/dev/null || { echo "gh not authenticated"; exit 1; } -``` - -### Current Repo Detection - -```bash -repo=$(gh repo view --json nameWithOwner --jq .nameWithOwner 2>/dev/null || true) -if [ -z "$repo" ]; then - url=$(git remote get-url origin 2>/dev/null || true) - repo=$(printf '%s\n' "$url" | - sed -E 's#^git@github.com:##; s#^https://github.com/##; s#\.git$##') -fi -printf '%s\n' "$repo" -``` - -### Repo Readiness - -```bash -git status --short --branch -git branch --show-current -git pull --ff-only -git status --short --branch -``` - -Proceed only on `main` with clean worktree. If dirty or non-main, report and -skip — do not branch/stash/commit without instruction. - -## Triage Pass (Issue Queue) - -```bash -gh issue list --repo "$repo" --state open --limit 50 \ - --json number,title,author,labels,createdAt,updatedAt,url -``` - -## Triage Pass (PR Queue) - -```bash -gh pr list --repo "$repo" --state open --limit 50 \ - --json number,title,author,isDraft,reviewDecision,mergeStateStatus,createdAt,updatedAt,url -``` - -## Detail Pass - -For items that look actionable: - -```bash -# Issue detail -gh issue view --repo "$repo" \ - --json number,title,author,body,comments,labels,createdAt,updatedAt,url - -# PR detail -gh pr view --repo "$repo" \ - --json number,title,author,body,comments,files,commits,isDraft,reviewDecision,mergeStateStatus,statusCheckRollup,createdAt,updatedAt,url - -# PR diff for small changes -gh pr diff --repo "$repo" --patch -``` - -## Classification - -Classify each item into one of: - -### Autonomous — can fix/land without maintainer - -Qualifies when: -- Bugfix with clear repro, known root cause, and verification path -- Performance improvement that doesn't increase complexity -- Documentation fix -- Dependency update with passing CI -- Small UI tweak that follows existing patterns -- Narrow test/internal fix - -Does NOT qualify when: -- New feature or product/vision choice -- Broad behavior change -- Security-sensitive change without strong proof -- Anything needing live API keys you don't have -- Anything that can't be end-to-end tested - -### Needs Review — requires maintainer judgment - -- New features -- Risk changes (broad blast radius) -- Items not matching VISION.md -- Items with blocking maintainer comments - -### Defer/Close - -- Stale (>6mo no activity, no maintainer signal) -- Duplicate -- Superseded by another PR/issue -- No repro for bug, no response from author - -### Blocked - -- CI failing with no clear fix -- Merge conflict -- Missing required credentials/access -- Awaiting maintainer decision - -## Trust Signals - -Include author trust for every non-maintainer item: - -```bash -# Quick trust check -gh api users/ --jq '{login, created_at, public_repos}' -``` - -Output format: -``` -Trust: @login; acct 2023-04-03; repo 2 PRs/1 issue; activity: low/medium/high -``` - -## Output Format - -Return structured triage output suitable for the orchestrator: - -```text -Cycle #42 — Triage Report -Repo: owner/name -Scanned: 12 issues, 5 PRs - -Autonomous (3): -- GH-123: Bug — login timeout on slow networks - Type: bug | Fit: good | Risk: low - Proof: repro in description, failing test in CI - Trust: @contributor; acct 2024-01; previous merged PRs: 2 - → Dispatch to thread - -- GH-124: Deps — update lodash to 4.17.21 - Type: dependency | Fit: good | Risk: low - Proof: green CI - → Dispatch to thread - -Needs Review (1): -- GH-125: Feature — dark mode toggle - Type: feature | Fit: mixed | Risk: medium - → Flag for maintainer - -Defer/Close (2): -- GH-126: Stale (8mo no activity) -- GH-127: Duplicate of GH-120 -``` - -## Scope Rule - -- `current` (default): triage only the current repo -- `all`: triage all repos in AGENT_LOOP_REPOS or detected from gh -- `org`: triage all repos under the current org - -## Broad Scan (all/org scope) - -```bash -# Find repos with open issues/PRs -gh search repos --owner --sort updated \ - --json nameWithOwner,openIssuesCount,openPullRequestsCount -``` - -For each repo with open items, run the standard triage pass. -Limit to top 10 repos by activity unless `AGENT_LOOP_DEEP_SCAN` is set. diff --git a/agent-loop/skills/agent-loop-triage/SKILL.md b/agent-loop/skills/agent-loop-triage/SKILL.md index 2d0a442..60461f7 100644 --- a/agent-loop/skills/agent-loop-triage/SKILL.md +++ b/agent-loop/skills/agent-loop-triage/SKILL.md @@ -1,12 +1,9 @@ --- name: agent-loop-triage -description: >- - GitHub project triage for the agent-loop plugin. Scans open issues, PRs, CI - queues, and blockers. Classifies items by fit, risk, proof, and autonomy. - Adapted from github-project-triage for autonomous loop integration. +description: Scan a repo's open issues and PRs and classify each as autonomous, needs review, defer, or blocked. Use for the agent-loop triage phase or /agent-loop:triage. --- -# Agent Loop Triage +# Agent loop triage Scan open issues and PRs for the current repo (or a configured set of repos). Classify each item and return a structured queue summary suitable for the @@ -14,13 +11,13 @@ orchestrator loop's dispatch phase. ## Setup -### GitHub CLI Check +### GitHub CLI check ```bash gh auth status 2>/dev/null || { echo "gh not authenticated"; exit 1; } ``` -### Current Repo Detection +### Current repo ```bash repo=$(gh repo view --json nameWithOwner --jq .nameWithOwner 2>/dev/null || true) @@ -32,7 +29,7 @@ fi printf '%s\n' "$repo" ``` -### Repo Readiness +### Repo readiness ```bash git status --short --branch @@ -41,24 +38,24 @@ git pull --ff-only git status --short --branch ``` -Proceed only on `main` with clean worktree. If dirty or non-main, report and -skip — do not branch/stash/commit without instruction. +Proceed only on the default branch with a clean worktree. Otherwise report and +skip. Do not branch, stash, or commit without instruction. -## Triage Pass (Issue Queue) +## Issue queue ```bash gh issue list --repo "$repo" --state open --limit 50 \ --json number,title,author,labels,createdAt,updatedAt,url ``` -## Triage Pass (PR Queue) +## PR queue ```bash gh pr list --repo "$repo" --state open --limit 50 \ --json number,title,author,isDraft,reviewDecision,mergeStateStatus,createdAt,updatedAt,url ``` -## Detail Pass +## Detail pass For items that look actionable: @@ -79,7 +76,9 @@ gh pr diff --repo "$repo" --patch Classify each item into one of: -### Autonomous — can fix/land without maintainer +### Autonomous + +The agent can fix and land it without a maintainer. Qualifies when: - Bugfix with clear repro, known root cause, and verification path @@ -96,14 +95,16 @@ Does NOT qualify when: - Anything needing live API keys you don't have - Anything that can't be end-to-end tested -### Needs Review — requires maintainer judgment +### Needs review + +A maintainer must decide. - New features - Risk changes (broad blast radius) - Items not matching VISION.md - Items with blocking maintainer comments -### Defer/Close +### Defer or close - Stale (>6mo no activity, no maintainer signal) - Duplicate @@ -117,7 +118,7 @@ Does NOT qualify when: - Missing required credentials/access - Awaiting maintainer decision -## Trust Signals +## Trust signals Include author trust for every non-maintainer item: @@ -131,29 +132,29 @@ Output format: Trust: @login; acct 2023-04-03; repo 2 PRs/1 issue; activity: low/medium/high ``` -## Output Format +## Output format Return structured triage output suitable for the orchestrator: ```text -Cycle #42 — Triage Report +Cycle #42: Triage Report Repo: owner/name Scanned: 12 issues, 5 PRs Autonomous (3): -- GH-123: Bug — login timeout on slow networks +- GH-123: Bug: login timeout on slow networks Type: bug | Fit: good | Risk: low Proof: repro in description, failing test in CI Trust: @contributor; acct 2024-01; previous merged PRs: 2 → Dispatch to thread -- GH-124: Deps — update lodash to 4.17.21 +- GH-124: Deps: update lodash to 4.17.21 Type: dependency | Fit: good | Risk: low Proof: green CI → Dispatch to thread Needs Review (1): -- GH-125: Feature — dark mode toggle +- GH-125: Feature: dark mode toggle Type: feature | Fit: mixed | Risk: medium → Flag for maintainer @@ -162,13 +163,13 @@ Defer/Close (2): - GH-127: Duplicate of GH-120 ``` -## Scope Rule +## Scope - `current` (default): triage only the current repo - `all`: triage all repos in AGENT_LOOP_REPOS or detected from gh - `org`: triage all repos under the current org -## Broad Scan (all/org scope) +## Broad scan ```bash # Find repos with open issues/PRs diff --git a/anyrouter/.claude-plugin/plugin.json b/anyrouter/.claude-plugin/plugin.json index 9b98893..db5ad80 100644 --- a/anyrouter/.claude-plugin/plugin.json +++ b/anyrouter/.claude-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "anyrouter", - "version": "1.0.1", - "description": "Wire AnyRouter into coding agents. Universal OpenAI-compatible LLM gateway for 150+ models, migration recipes from Anthropic/OpenAI/OpenRouter, and a remote MCP server for keys and credits.", + "version": "1.1.0", + "description": "Wire AnyRouter, an OpenAI-compatible LLM gateway, into projects and agents, with migration help and an MCP server.", "author": { "name": "duyet", "url": "https://github.com/duyet" diff --git a/anyrouter/.codex-plugin/plugin.json b/anyrouter/.codex-plugin/plugin.json index 16f9033..7f5e4ef 100644 --- a/anyrouter/.codex-plugin/plugin.json +++ b/anyrouter/.codex-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "anyrouter", - "version": "1.0.1", - "description": "Wire AnyRouter into coding agents. Universal OpenAI-compatible LLM gateway for 150+ models, migration recipes from Anthropic/OpenAI/OpenRouter, and a remote MCP server for keys and credits.", + "version": "1.1.0", + "description": "Wire AnyRouter, an OpenAI-compatible LLM gateway, into projects and agents, with migration help and an MCP server.", "author": { "name": "duyet", "url": "https://github.com/duyet" @@ -13,7 +13,7 @@ "mcpServers": "./.mcp.json", "interface": { "displayName": "AnyRouter", - "shortDescription": "Wire AnyRouter into coding agents. Universal OpenAI-compatible LLM gateway for 150+ models, migration recipes from Anthropic/OpenAI/OpenRouter, and a remote MCP server for keys and credits.", + "shortDescription": "Wire AnyRouter, an OpenAI-compatible LLM gateway, into projects and agents, with migration help and an MCP server.", "developerName": "duyet", "category": "AI", "capabilities": [ diff --git a/anyrouter/.cursor-plugin/plugin.json b/anyrouter/.cursor-plugin/plugin.json index f798038..5d6934a 100644 --- a/anyrouter/.cursor-plugin/plugin.json +++ b/anyrouter/.cursor-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "anyrouter", - "version": "1.0.1", - "description": "Wire AnyRouter into coding agents. Universal OpenAI-compatible LLM gateway for 150+ models, migration recipes from Anthropic/OpenAI/OpenRouter, and a remote MCP server for keys and credits.", + "version": "1.1.0", + "description": "Wire AnyRouter, an OpenAI-compatible LLM gateway, into projects and agents, with migration help and an MCP server.", "author": { "name": "duyet" }, diff --git a/anyrouter/.grok-build-plugin/plugin.json b/anyrouter/.grok-build-plugin/plugin.json index 9b41ed5..8a923ef 100644 --- a/anyrouter/.grok-build-plugin/plugin.json +++ b/anyrouter/.grok-build-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "anyrouter", - "version": "1.0.1", - "description": "Wire AnyRouter into coding agents. Universal OpenAI-compatible LLM gateway for 150+ models, migration recipes from Anthropic/OpenAI/OpenRouter, and a remote MCP server for keys and credits.", + "version": "1.1.0", + "description": "Wire AnyRouter, an OpenAI-compatible LLM gateway, into projects and agents, with migration help and an MCP server.", "author": { "name": "duyet", "url": "https://github.com/duyet" @@ -14,7 +14,7 @@ "mcpServers": "./.mcp.json", "interface": { "displayName": "AnyRouter", - "shortDescription": "Wire AnyRouter into coding agents. Universal OpenAI-compatible LLM gateway for 150+ models, migration recipes from Anthropic/OpenAI/OpenRouter, and a remote MCP server for keys and credits.", + "shortDescription": "Wire AnyRouter, an OpenAI-compatible LLM gateway, into projects and agents, with migration help and an MCP server.", "developerName": "duyet", "category": "AI", "capabilities": [ diff --git a/anyrouter/.grok-plugin/plugin.json b/anyrouter/.grok-plugin/plugin.json index b7c1917..a221a2e 100644 --- a/anyrouter/.grok-plugin/plugin.json +++ b/anyrouter/.grok-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "anyrouter", - "version": "1.0.1", - "description": "Wire AnyRouter into coding agents. Universal OpenAI-compatible LLM gateway for 150+ models, migration recipes from Anthropic/OpenAI/OpenRouter, and a remote MCP server for keys and credits.", + "version": "1.1.0", + "description": "Wire AnyRouter, an OpenAI-compatible LLM gateway, into projects and agents, with migration help and an MCP server.", "author": { "name": "duyet", "url": "https://github.com/duyet" diff --git a/anyrouter/.mcp.json b/anyrouter/.mcp.json index 0add8c7..7a44a0b 100644 --- a/anyrouter/.mcp.json +++ b/anyrouter/.mcp.json @@ -2,8 +2,7 @@ "mcpServers": { "anyrouter": { "command": "npx", - "args": ["-y", "mcp-remote", "https://anyrouter.dev/api/v1/mcp"], - "description": "AnyRouter MCP — list models, manage API keys, check credits, browse presets, and search conversations. Authorizes via OAuth on first use." + "args": ["-y", "mcp-remote", "https://anyrouter.dev/api/v1/mcp"] } } } diff --git a/anyrouter/README.md b/anyrouter/README.md index 2f50038..3aaaaa2 100644 --- a/anyrouter/README.md +++ b/anyrouter/README.md @@ -1,87 +1,26 @@ -# AnyRouter Plugin +# anyrouter -Wire [AnyRouter](https://anyrouter.dev) — a universal, OpenAI-compatible LLM gateway for 150+ models across 28+ providers — into Claude Code, Codex, Cursor, and any other coding agent that accepts a custom base URL. - -This plugin ships as a **Claude Code plugin** (`.claude-plugin/`), a **Codex plugin** (`.codex-plugin/`), and **Grok Build / Grok Bot** manifests (`.grok-plugin/` + `.grok-build-plugin/`), and bundles a remote **MCP server** for key and credit management. - -## What you get - -- **`anyrouter` skill** — discoverable knowledge for the agent: the contract (base URL / key env / model id format), integration patterns, migration recipes (from OpenAI / Anthropic / OpenRouter), routing, streaming, app attribution, MCP overview. Tells the agent to **fetch live `.md` docs** instead of trusting any frozen snapshot. -- **`/anyrouter:migrate` command** — interactive migration of an existing LLM integration to AnyRouter. -- **`anyrouter-integrator` agent** — sub-agent that performs surgical migrations on demand. -- **MCP server** — remote MCP at `https://anyrouter.dev/api/v1/mcp` for `list_models`, `get_credits`, `list_keys`, `create_key`, `revoke_key`, `list_presets`, `list_conversations`. - -There is **no `references/` snapshot** — the skill links to live `.md` URLs (`https://anyrouter.dev/docs/.md`) so the agent always works with current content. The auto-generated index is at [anyrouter.dev/docs.md](https://anyrouter.dev/docs.md). - -## Install - -### Claude Code +Wire [AnyRouter](https://anyrouter.dev), an OpenAI-compatible LLM gateway, into Claude Code, Codex, Cursor, and other coding agents. ```bash -/plugin marketplace add duyet/codex-claude-plugins /plugin install anyrouter@duyet-claude-plugins -``` - -Then set your key: - -```bash export ANYROUTER_API_KEY="sk-ar-..." ``` -(Get one at [anyrouter.dev/dashboard/keys](https://anyrouter.dev/dashboard/keys).) - -### Codex - -The plugin's `.codex-plugin/plugin.json` declares Skill, Command, Agent, and MCP capabilities. Install via your Codex plugin loader the same way you install other plugins from `duyet/codex-claude-plugins`. - -### Grok Build / Grok Bot - -```bash -grok plugin marketplace add duyet/codex-claude-plugins -grok plugin install anyrouter --trust -``` - -### MCP only +Get a key at [anyrouter.dev/dashboard/keys](https://anyrouter.dev/dashboard/keys). -If you only want the AnyRouter MCP server in another client (Claude Desktop, Cursor, Claude Code CLI, OpenCode), point it at `https://anyrouter.dev/api/v1/mcp`. Full per-client setup: [anyrouter.dev/docs/mcp.md](https://anyrouter.dev/docs/mcp.md). +## What ships -## Quick usage +- `anyrouter` skill. The contract (base URL, key env, `provider/model` ids), integration and migration recipes, routing, attribution, and MCP notes. It tells the agent to fetch live docs from [anyrouter.dev/docs.md](https://anyrouter.dev/docs.md) instead of trusting a snapshot. +- `/anyrouter:migrate` command. Moves an existing OpenAI, Anthropic, or OpenRouter integration to AnyRouter and adds a smoke test. +- `anyrouter-integrator` agent. Runs that migration on demand. +- A remote MCP server at `https://anyrouter.dev/api/v1/mcp` for models, credits, keys, presets, and conversations. It authorizes through OAuth on first use. Client setup is at [anyrouter.dev/docs/mcp.md](https://anyrouter.dev/docs/mcp.md). -After installing, the agent will load the `anyrouter` skill on its own when you say things like: +## Try it - "Add AnyRouter to this project." - "Migrate this from OpenAI to AnyRouter." -- "Move my OpenRouter calls to AnyRouter." - "Point Claude Code at AnyRouter." -- "List my AnyRouter API keys." (uses MCP) -- "How much credit do I have left?" (uses MCP) - -You can also invoke the slash command directly: - -```text -/anyrouter:migrate -``` - -## The contract - -| Setting | Value | -| --------------------- | --------------------------------------------- | -| Base URL | `https://anyrouter.dev/api/v1` | -| API key env | `ANYROUTER_API_KEY` (prefix `sk-ar-`) | -| Model id format | `provider/model` | -| Default model | `openai/gpt-5.4-mini` | -| Anthropic-native base | `https://anyrouter.dev/api` (for `/messages`) | -| MCP endpoint | `https://anyrouter.dev/api/v1/mcp` | - -## Live docs - -The skill links to live raw-markdown pages. Start with the index — it lists every section and every page: - -- [anyrouter.dev/docs.md](https://anyrouter.dev/docs.md) — auto-generated index -- [anyrouter.dev/llms-full.txt](https://anyrouter.dev/llms-full.txt) — every doc concatenated -- [anyrouter.dev/llms.txt](https://anyrouter.dev/llms.txt) — short LLM index per `llmstxt.org` -- [anyrouter.dev/docs/index.json](https://anyrouter.dev/docs/index.json) — machine-readable manifest - -## License +- "How much credit do I have left?" MIT. See [LICENSE](LICENSE). diff --git a/anyrouter/agents/anyrouter-integrator.md b/anyrouter/agents/anyrouter-integrator.md index c167851..1a16f8e 100644 --- a/anyrouter/agents/anyrouter-integrator.md +++ b/anyrouter/agents/anyrouter-integrator.md @@ -1,58 +1,14 @@ --- name: anyrouter-integrator -description: Specialist for wiring AnyRouter into an existing codebase. Use proactively when the task is "add AnyRouter", "migrate to AnyRouter", "swap LLM provider for AnyRouter", "point our agent at AnyRouter", or any equivalent. Has full context on the AnyRouter contract, model ids, routing, and MCP. +description: Wires AnyRouter into an existing codebase. Use when the task is to add AnyRouter, migrate to it, swap an LLM provider for it, or point an agent at it. tools: Read, Edit, Write, Glob, Grep, Bash --- -# AnyRouter Integrator +# AnyRouter integrator -You wire AnyRouter into projects. Load the `anyrouter` skill, then work as follows. +Load the `anyrouter` skill (`skills/anyrouter/SKILL.md`) for the contract, then follow `commands/anyrouter-migrate.md` step by step. Where the command asks the user, use its stated defaults unless the task says otherwise. -## Contract (memorize) - -- Base URL: `https://anyrouter.dev/api/v1` -- Anthropic-native base: `https://anyrouter.dev/api` (for `/messages`) -- Key env: `ANYROUTER_API_KEY`, prefix `sk-ar-` -- Model id format: `provider/model` -- Default model: `openai/gpt-5.4-mini` -- MCP endpoint: `https://anyrouter.dev/api/v1/mcp` - -## Operating rules - -1. **Read before write.** Always `Grep` for existing LLM clients, base URLs, and env vars first. Reuse what's there; don't add a parallel client. -2. **Surgical edits only.** Change base URL, key, and model id. Leave everything else — including streaming flags, error handling, and feature flags — untouched. -3. **Never inline a literal key.** Always go through env. -4. **Model id mapping.** Convert bare ids: - - `gpt-4o-mini` → `openai/gpt-5.4-mini` - - `gpt-4o` → `openai/gpt-5.4` - - `claude-3-5-sonnet-*` → `anthropic/claude-sonnet-4.6` - - `claude-3-5-haiku-*` → `anthropic/claude-haiku-4.5` - - Unknown bare ids → leave the existing slug and add a `// TODO(anyrouter): pick a current model id from https://anyrouter.dev/models` comment. -5. **Streaming preserved.** If the original code streams, the migrated code streams. -6. **Smoke test before declaring done.** Hit `/chat/completions` once with a 20-token prompt and report the result. -7. **Speak plainly about failures.** If something didn't migrate cleanly, say so. - -## When to consider the Anthropic-native path - -If the project depends on Anthropic SDK features that the OpenAI-compatible endpoint can't replicate (e.g. specific tool-use block shapes, system message handling that breaks under `/chat/completions`), keep the Anthropic SDK and set `ANTHROPIC_BASE_URL=https://anyrouter.dev/api`. Otherwise prefer unifying on `/chat/completions`. - -## Default deliverables - -For every migration, leave behind: - -- Updated client construction (one place, env-driven). -- Updated model ids. -- `.env.example` entry for `ANYROUTER_API_KEY`. -- Smoke test (or run-and-report if a test harness exists). -- Short summary listing files changed, TODOs left, and the smoke-test outcome. - -## When to hand back - -Hand back to the user (don't keep guessing) when: - -- The project uses a private SDK that doesn't accept a custom base URL. -- Provider-specific request shapes (e.g. non-standard tool blocks) need a product decision. -- Env-loading is non-obvious (custom secret manager, infra-defined env, etc.). -- Smoke test fails for a reason that isn't "bad key". - -State clearly what you need from the user. +- Grep for existing clients, base URLs, and env vars first. Reuse them. +- Change only base URL, key, and model ids. +- Keep the Anthropic SDK with `ANTHROPIC_BASE_URL` only when the project needs Anthropic-native features that `/chat/completions` cannot replicate. Otherwise unify on `/chat/completions`. +- Hand back to the user when the SDK takes no custom base URL, provider-specific request shapes need a product decision, env loading is unclear, or the smoke test fails for a reason other than a bad key. Say what you need. diff --git a/anyrouter/commands/anyrouter-migrate.md b/anyrouter/commands/anyrouter-migrate.md index 6e2c0c0..1bbc5d4 100644 --- a/anyrouter/commands/anyrouter-migrate.md +++ b/anyrouter/commands/anyrouter-migrate.md @@ -1,76 +1,14 @@ --- -description: Migrate the current project's LLM integration to AnyRouter. Detect existing OpenAI / Anthropic / OpenRouter usage, swap base URL + key + model ids, preserve behavior, and add a smoke test. +description: Migrate this project's LLM integration to AnyRouter by swapping base URL, key, and model ids, then smoke test it. --- # /anyrouter:migrate -You are migrating this project to **AnyRouter** — a universal OpenAI-compatible LLM gateway at `https://anyrouter.dev/api/v1`. Read the `anyrouter` skill before doing anything; it has the contract, model-id rules, and migration recipes. +Read the `anyrouter` skill (`skills/anyrouter/SKILL.md`) for the contract and recipes. Edit minimally. -## Step 1 — Detect the current integration - -Search the repo for any of these signals and report what you find before changing anything: - -- Imports: `from openai import`, `import OpenAI`, `import Anthropic`, `from anthropic`, `import openrouter`. -- Base URLs: `api.openai.com`, `api.anthropic.com`, `openrouter.ai/api/v1`. -- Env vars: `OPENAI_API_KEY`, `ANTHROPIC_API_KEY`, `OPENROUTER_API_KEY`, `ANTHROPIC_BASE_URL`, `OPENAI_BASE_URL`. -- Model ids: bare `gpt-*`, bare `claude-*`, `provider/model` slugs. -- SDK instances: `new OpenAI({...})`, `OpenAI(base_url=...)`, `Anthropic({...})`. - -Output a short table: file, line, current value, what it becomes. - -## Step 2 — Confirm the plan with the user - -Before editing, ask the user: - -1. Which key env var should the migrated code read — `ANYROUTER_API_KEY` (default) or an existing project name? -2. Should `anthropic/*` calls keep the `/messages` endpoint (Anthropic-native) or move to `/chat/completions` (unified)? -3. Pin a single model, read from env, or keep per-call overrides? -4. Should `X-AnyRouter-Title / -Source / -Version` headers be added for attribution? - -Do not invent answers. If the user says "you decide", default to: `ANYROUTER_API_KEY`, `/chat/completions` for everything, model from `ANYROUTER_MODEL ?? "openai/gpt-5.4-mini"`, attribution headers on. - -## Step 3 — Edit minimally - -Apply the exact rules from the skill: - -- Base URL → `https://anyrouter.dev/api/v1` (or `https://anyrouter.dev/api` for Anthropic-native). -- Key → `process.env.ANYROUTER_API_KEY` (or chosen env var). Never inline a literal. -- Model ids → `provider/model`. Map common bare ids: - - `gpt-4o-mini` → `openai/gpt-5.4-mini` - - `gpt-4o` → `openai/gpt-5.4` - - `claude-3-5-sonnet-*` → `anthropic/claude-sonnet-4.6` - - `claude-3-5-haiku-*` → `anthropic/claude-haiku-4.5` - - When uncertain, leave the existing id and add a TODO so the user can pick a current model from https://anyrouter.dev/models. -- Reuse the existing LLM client module if one exists. Do **not** add a new one in parallel. -- Keep request/response shapes, streaming behavior, and error handling identical. - -Touch only what you must. Don't refactor unrelated code. - -## Step 4 — Update `.env.example` and docs - -- Add `ANYROUTER_API_KEY=` to `.env.example`. -- If a README mentions `OPENAI_API_KEY` / `ANTHROPIC_API_KEY` / `OPENROUTER_API_KEY`, replace those mentions with `ANYROUTER_API_KEY` and link to https://anyrouter.dev/docs/getting-started/quickstart. - -## Step 5 — Smoke test - -Add (or update) a smoke test that exercises one short prompt end-to-end. Prefer the project's existing test framework; otherwise drop a one-shot script: - -```bash -curl https://anyrouter.dev/api/v1/chat/completions \ - -H "Authorization: Bearer $ANYROUTER_API_KEY" \ - -H "Content-Type: application/json" \ - -d '{"model":"openai/gpt-5.4-mini","messages":[{"role":"user","content":"Reply with: anyrouter-ok"}],"max_tokens":20}' -``` - -Run it. If it fails, do not declare the migration done — diagnose and fix. - -## Step 6 — Summary - -Report back: - -- Files changed (count + paths). -- Bare model ids that were left as TODO for the user. -- Whether streaming, tool-use, and error paths were re-verified. -- The smoke test result. - -If anything was skipped, **say so explicitly**. Don't hide uncertainty. +1. **Detect.** Search for OpenAI, Anthropic, and OpenRouter imports, base URLs (`api.openai.com`, `api.anthropic.com`, `openrouter.ai`), key and base-URL env vars, and model ids. Report file, line, current value, and the planned change before editing. +2. **Confirm.** Ask the user which env var to read (default `ANYROUTER_API_KEY`), whether `anthropic/*` calls keep `/messages` or move to `/chat/completions`, how the model is chosen (pinned, from `ANYROUTER_MODEL`, or per call), and whether to add attribution headers. If told to decide, use `ANYROUTER_API_KEY`, `/chat/completions`, model from `ANYROUTER_MODEL`, and headers on. +3. **Edit.** Change the base URL, read the key from env, and convert model ids to `provider/model`. Look up current ids with the MCP `list_models` tool or `https://anyrouter.dev/models`. If you cannot pick one confidently, keep the existing id and leave a TODO. Reuse the existing client module. Keep request shapes, streaming, and error handling identical. +4. **Docs.** Add `ANYROUTER_API_KEY=` to `.env.example` and replace old key names in the README. +5. **Smoke test.** Add or update a test that sends one short prompt through `/chat/completions`, or use a one-shot `curl` with `Authorization: Bearer $ANYROUTER_API_KEY`. Run it. If it fails, diagnose and fix before calling the migration done. +6. **Report.** List files changed, ids left as TODO, whether streaming, tool use, and error paths were re-checked, and the smoke test result. Say plainly what was skipped. diff --git a/anyrouter/skills/anyrouter/SKILL.md b/anyrouter/skills/anyrouter/SKILL.md index 8b6fe03..7b8624f 100644 --- a/anyrouter/skills/anyrouter/SKILL.md +++ b/anyrouter/skills/anyrouter/SKILL.md @@ -1,127 +1,39 @@ --- name: anyrouter -description: Wire AnyRouter into a project, migrate from Anthropic / OpenAI / OpenRouter, and call its MCP server. Use when the user mentions AnyRouter, asks to add a unified LLM gateway, wants to swap providers without code churn, migrates an existing OpenAI/Anthropic/OpenRouter integration, sets up Claude Code / Codex / Cursor against a custom base URL, or needs help with model ids like `provider/model`, app attribution headers (`X-AnyRouter-*`), provider preferences, streaming, BYOK, or the AnyRouter MCP server at `https://anyrouter.dev/api/v1/mcp`. +description: Wire AnyRouter, an OpenAI-compatible LLM gateway, into a project, migrate from OpenAI, Anthropic, or OpenRouter, point coding agents at it, and use its MCP server. Use when the user mentions AnyRouter, wants a unified LLM gateway, or needs provider routing, attribution headers, BYOK, or `provider/model` ids. --- # AnyRouter -AnyRouter is a universal, OpenAI-compatible LLM gateway. One base URL, one API key, 150+ models across 28+ providers, deterministic failover, and a remote MCP server for key + credit management. Use this skill whenever you need to wire AnyRouter into a project or migrate an existing integration. +One base URL, one API key, many models and providers, with failover and a remote MCP server for keys and credits. -## Always fetch the live docs — do not rely on memory +## Fetch live docs first -This skill is intentionally thin. It tells you **where** to look, not what every page says. AnyRouter ships its full documentation as raw markdown, regenerated on every deploy. Before answering any non-trivial AnyRouter question, **fetch the relevant `.md` URL** with your web-fetch tool (WebFetch, curl via Bash, or your platform's equivalent) and read the current content. Do not rely on the model id, scope name, or header values memorised in this skill — they can change. +This skill is a map. Before answering any non-trivial question, fetch the relevant markdown page and cite its URL. Do not rely on remembered model ids, scopes, or header values. -Discovery sources (in priority order): +- `https://anyrouter.dev/docs.md` is the index of every page. Start here when unsure. +- Append `.md` to any docs URL for raw markdown, for example `https://anyrouter.dev/docs/guides/migrate-from-openai.md`. +- `https://anyrouter.dev/llms-full.txt` is every doc in one file, and `https://anyrouter.dev/llms.txt` is the short index. +- If a page 404s, it was renamed. Re-read the index. -1. **`https://anyrouter.dev/docs.md`** — auto-generated index. Every section, every page, every link points at the `.md` mirror. Start here when you don't know which page you need. -2. **Append `.md` to any docs URL** — `https://anyrouter.dev/docs/.md` gives the raw markdown of any rendered page. -3. **`https://anyrouter.dev/llms-full.txt`** — every doc concatenated, useful when you want one bulk read. -4. **`https://anyrouter.dev/llms.txt`** — short LLM index per `llmstxt.org`. -5. **`https://anyrouter.dev/docs/index.json`** — machine-readable manifest if you need to filter programmatically. +Useful pages: `getting-started/quickstart`, `getting-started/authentication`, `guides/ai-agent-integration`, `guides/claude-code`, `guides/migrate-from-openai`, `guides/migrate-from-anthropic`, `guides/migrate-from-openrouter`, `guides/provider-routing`, `features/app-attribution`, `features/byok`, `api-reference/overview`, `api-reference/mcp`, and `mcp`. -**Operating rule:** when the user asks about AnyRouter, do not paraphrase from this skill alone. Fetch the live `.md`, ground your answer in it, and cite the URL you used. - -## The contract +## Contract | Setting | Value | | --- | --- | | Base URL | `https://anyrouter.dev/api/v1` | -| API key env var | `ANYROUTER_API_KEY` (keys are prefixed `sk-ar-`) | -| Model id format | `provider/model` (e.g. `openai/gpt-5.4-mini`, `anthropic/claude-sonnet-4.6`) | -| Chat endpoint | `POST /chat/completions` (OpenAI-compatible) | -| Anthropic-native endpoint | `POST /messages` (for `anthropic/*` models) | -| Modern agent endpoint | `POST /responses` (typed output items + tools) | -| MCP endpoint | `https://anyrouter.dev/api/v1/mcp` (configured by this plugin) | -| Dashboard | https://anyrouter.dev/dashboard | -| Docs index (markdown) | https://anyrouter.dev/docs.md | - -Default model when unspecified: `openai/gpt-5.4-mini`. Cheap+fast: `openai/gpt-5.4-nano`, `anthropic/claude-haiku-4.5`. High-quality: `anthropic/claude-sonnet-4.6`, `openai/gpt-5.4`. - -## When to use this skill - -- The user mentions **AnyRouter** by name. -- They want to **add a unified LLM gateway** so they can swap providers without rewriting client code. -- They have an existing **OpenAI**, **Anthropic**, or **OpenRouter** integration and want to migrate to AnyRouter. -- They want to point **Claude Code**, **Codex**, **Cursor**, **Aider**, **Hermes**, or another agent at AnyRouter. -- They need **app attribution**, **provider preferences**, **price caps**, **failover**, or **routing controls**. -- They want to use the **AnyRouter MCP server** from a client. - -Before integrating, check if the project already has an LLM client. If so, change the **base URL, key, and model id** rather than introducing a new client. - -## How to look things up - -When the user asks something specific (recipes, headers, scopes, model lists, BYOK setup, billing details, rate limits), **fetch the matching `.md` URL** before answering. Do not summarise from this skill alone. - -Recipe: - -1. Pick the most likely URL from the entry points below. If unsure, fetch `https://anyrouter.dev/docs.md` first and read the section headings. -2. Use WebFetch (or `curl -sSL `) to retrieve the raw markdown. -3. Quote / paraphrase from what you fetched. Include the URL in your response so the user can verify. -4. If the URL 404s, the page was renamed or removed — re-fetch the index and pick the current link. - -Top categories with a one-line summary of every important child page. These hints let you pick the right URL without an index round-trip — the **authoritative, current** list with every page is always at https://anyrouter.dev/docs.md. - -**Getting Started** -- [Quickstart](https://anyrouter.dev/docs/getting-started/quickstart.md) — First request in under five minutes. Point any OpenAI-compatible client at the AnyRouter base URL. -- [Authentication](https://anyrouter.dev/docs/getting-started/authentication.md) — Generate, scope, and rotate API keys. Bearer tokens, BYOK, per-environment isolation. - -**Guides** (recipes for agents and migrations) -- [AI Agent Integration](https://anyrouter.dev/docs/guides/ai-agent-integration.md) — Paste-prompt for any coding agent (Claude Code, Cursor, Codex, Aider, Hermes, …) wiring AnyRouter into an existing project. -- [Claude Code](https://anyrouter.dev/docs/guides/claude-code.md) — Two env vars (`ANTHROPIC_BASE_URL`, `ANTHROPIC_AUTH_TOKEN`) route Claude Code through AnyRouter. Includes a `claude-ar` wrapper recipe. -- [Streaming](https://anyrouter.dev/docs/guides/streaming.md) — SSE incremental completions, cancellation, event shape. -- [Migrate from OpenAI](https://anyrouter.dev/docs/guides/migrate-from-openai.md) — Swap base URL, key env, model id (`gpt-*` → `openai/gpt-*`). -- [Migrate from Anthropic](https://anyrouter.dev/docs/guides/migrate-from-anthropic.md) — Keep the Anthropic SDK, swap base URL + key. Preserve `anthropic-version` header. -- [Migrate from OpenRouter](https://anyrouter.dev/docs/guides/migrate-from-openrouter.md) — Same `provider/model` ids, same `provider` object. Just change base URL and key env. -- [Hermes Agent](https://anyrouter.dev/docs/guides/hermes-agent.md) — Nous Research's Hermes Agent as a custom OpenAI-compatible provider. -- [OpenClaw](https://anyrouter.dev/docs/guides/openclaw.md) — One key across every model and messaging channel. -- [Errors](https://anyrouter.dev/docs/guides/errors.md) — HTTP status codes, error envelopes, retry guidance. -- [Provider Routing](https://anyrouter.dev/docs/guides/provider-routing.md) — Per-request ordering, sorting, fallbacks, performance thresholds, price caps. -- [Model Fallbacks](https://anyrouter.dev/docs/guides/model-fallbacks.md) — Automatic failover between models when providers are down or rate-limited. -- [Latency Overhead](https://anyrouter.dev/docs/guides/latency-overhead.md) — Real-world latency added by AnyRouter vs direct upstream calls. -- [Using Responses API](https://anyrouter.dev/docs/guides/migrate-to-responses.md) — Migration to the modern `/responses` endpoint with typed output items + tools. -- [Dashboard Tour](https://anyrouter.dev/docs/guides/dashboard-tour.md) — Walkthrough of every dashboard page in the order a new team uses them. +| Anthropic-native base | `https://anyrouter.dev/api` (for `/messages`) | +| API key env var | `ANYROUTER_API_KEY` (keys start with `sk-ar-`) | +| Model id | `provider/model` | +| Endpoints | `/chat/completions` (OpenAI-compatible), `/messages` (Anthropic-native), `/responses` | +| MCP | `https://anyrouter.dev/api/v1/mcp`, registered by this plugin | -**Features** (product surface — describe what the platform does) -- [Smart Routing](https://anyrouter.dev/docs/features/routing.md) — How AnyRouter picks an upstream. Priority order, failover, model aliases, `X-AnyRouter-Provider` pinning. -- [App Attribution](https://anyrouter.dev/docs/features/app-attribution.md) — `X-AnyRouter-Title / -Source / -Version` headers; public-ranking surface. -- [Prompt Caching](https://anyrouter.dev/docs/features/caching.md) — Cache long system prompts across requests. -- [BYOK (Bring Your Own Key)](https://anyrouter.dev/docs/features/byok.md) — Attach upstream provider keys so requests run at list price through your accounts. -- [Tool Use](https://anyrouter.dev/docs/features/tool-use.md) — Cross-provider function calling + structured outputs. -- [Presets](https://anyrouter.dev/docs/features/presets.md) — Reusable config bundles, callable as `@preset/` from any request. -- [Rate Limits](https://anyrouter.dev/docs/features/rate-limits.md) — Per-IP and per-key tiers; `429` vs `403` semantics; backoff guidance. -- [Privacy & Logging Controls](https://anyrouter.dev/docs/features/privacy-controls.md) — Body capture, PII redaction, training opt-out, blocked providers, residency. -- [Credits & Billing](https://anyrouter.dev/docs/features/credits.md) — How credits work, free monthly grants, top-ups. -- [Models Catalog](https://anyrouter.dev/docs/features/models-catalog.md) — Browse every model with pricing, context limits, capabilities. -- [Request Logs](https://anyrouter.dev/docs/features/request-logs.md) — Per-request inspection: latency, tokens, cost, upstream provider, full body when privacy allows. -- [Usage Explorer](https://anyrouter.dev/docs/features/usage-explorer.md) — Cost / token / request charts grouped by model, key, or time. -- [Managing API Keys](https://anyrouter.dev/docs/features/api-keys.md) — Create, rotate, scope, and rate-limit keys from the dashboard. -- [Organizations & Workspaces](https://anyrouter.dev/docs/features/organizations.md) — Multi-tenant: invite teammates, set roles, isolate billing. +For current model ids, call the MCP `list_models` tool or read the models catalog at `https://anyrouter.dev/models`. Never invent an id. -**MCP** (configured by this plugin) -- [MCP Server](https://anyrouter.dev/docs/mcp.md) — Consumer setup for Claude Desktop, Cursor, Claude Code, OpenCode. OAuth consent on first tool call. -- [MCP API Reference](https://anyrouter.dev/docs/api-reference/mcp.md) — JSON-RPC tool catalog, scopes (Read-only / Standard / Full), error shapes, manual auth. +## Add to a project -**API Reference** (every inference + management endpoint) -- [API Overview](https://anyrouter.dev/docs/api-reference/overview.md) — Pick the right surface: Chat Completions, Messages, Responses, Images, Embeddings, Models. -- [Chat Completions](https://anyrouter.dev/docs/api-reference/chat-completions.md) — `POST /api/v1/chat/completions`, OpenAI-compatible, every model. -- [Messages](https://anyrouter.dev/docs/api-reference/messages.md) — `POST /api/v1/messages`, Anthropic-compatible passthrough for `anthropic/*` models. -- [Responses](https://anyrouter.dev/docs/api-reference/responses.md) — `POST /api/v1/responses`, structured output items + tools. -- [Models](https://anyrouter.dev/docs/api-reference/models.md) — List and inspect catalog entries: pricing, context, capabilities, routing. -- [Providers](https://anyrouter.dev/docs/api-reference/providers.md) — Upstream backends AnyRouter can dispatch to. -- [Embeddings](https://anyrouter.dev/docs/api-reference/embeddings.md) — Text embeddings for semantic search. -- [Images](https://anyrouter.dev/docs/api-reference/images.md) — Text-to-image generation. -- [Keys](https://anyrouter.dev/docs/api-reference/keys.md) — Inspect, create, update, delete LLM API keys. -- [Management Keys](https://anyrouter.dev/docs/api-reference/management-keys.md) — Programmatic admin credentials (`ak_*`) for keys, presets, BYOK, credits. -- [OAuth](https://anyrouter.dev/docs/api-reference/oauth.md) — PKCE authorization codes for AnyRouter API keys. -- [Credits](https://anyrouter.dev/docs/api-reference/credits.md) — Remaining balance per API key. -- [Health](https://anyrouter.dev/docs/api-reference/health.md) — Gateway and per-provider availability snapshot. -- [Errors (guide)](https://anyrouter.dev/docs/guides/errors.md) — Cross-endpoint error envelope and retry behavior. - -If a URL above 404s, the page was renamed or removed — fetch `/docs.md` and pick the current link from the live index. - -## Adding AnyRouter to a project (fresh) - -### TypeScript (`openai` SDK) +If the project already has an LLM client, change its base URL, key, and model id instead of adding a client. Read the key from `ANYROUTER_API_KEY`, never inline it, and read the model from `ANYROUTER_MODEL`. ```typescript import OpenAI from "openai" @@ -130,142 +42,39 @@ export const llm = new OpenAI({ baseURL: "https://anyrouter.dev/api/v1", apiKey: process.env.ANYROUTER_API_KEY, }) - -export const MODEL = process.env.ANYROUTER_MODEL ?? "openai/gpt-5.4-mini" - -export async function generate(prompt: string) { - const r = await llm.chat.completions.create({ - model: MODEL, - messages: [{ role: "user", content: prompt }], - }) - return r.choices[0]?.message.content ?? "" -} ``` -### Python - ```python import os from openai import OpenAI -client = OpenAI( - base_url="https://anyrouter.dev/api/v1", - api_key=os.environ["ANYROUTER_API_KEY"], -) - -resp = client.chat.completions.create( - model=os.getenv("ANYROUTER_MODEL", "openai/gpt-5.4-mini"), - messages=[{"role": "user", "content": "Reply with: anyrouter-ok"}], -) -print(resp.choices[0].message.content) +client = OpenAI(base_url="https://anyrouter.dev/api/v1", api_key=os.environ["ANYROUTER_API_KEY"]) ``` -### Smoke test - -```bash -curl https://anyrouter.dev/api/v1/chat/completions \ - -H "Authorization: Bearer $ANYROUTER_API_KEY" \ - -H "Content-Type: application/json" \ - -d '{"model":"openai/gpt-5.4-mini","messages":[{"role":"user","content":"Reply with: anyrouter-ok"}],"max_tokens":20}' -``` +The integration is done when calls hit the base URL, the key comes from env, model ids use `provider/model`, streaming still streams, and errors flow through the existing error path. Prove it with one short request to `/chat/completions`. -Integration is **done** when: +## Coding agents -- Calls hit `https://anyrouter.dev/api/v1` -- The key is read from `ANYROUTER_API_KEY` (no inline literal in source) -- Model ids use the `provider/model` form -- Streaming still streams if it did before -- Errors flow through the project's existing error path +- Claude Code: set `ANTHROPIC_BASE_URL="https://anyrouter.dev/api"` and `ANTHROPIC_AUTH_TOKEN` to the key. For tier pinning see `guides/claude-code`. +- Codex, Cursor, Aider, Hermes, OpenClaw: any client with a custom OpenAI base URL works. Use the base URL, the key, and a `provider/model` id. -## Integrating with coding agents +## Migrating -### Claude Code - -```bash -export ANTHROPIC_BASE_URL="https://anyrouter.dev/api" -export ANTHROPIC_AUTH_TOKEN="sk-ar-your-key" -``` +Swap the base URL and key and keep the request shape. For the full procedure, run `/anyrouter:migrate` (`commands/anyrouter-migrate.md`). -For tier-name pinning and a `claude-ar` wrapper, see https://anyrouter.dev/docs/guides/claude-code.md. +- From OpenAI, prefix model ids with `openai/`. +- From Anthropic, either keep the SDK and set `ANTHROPIC_BASE_URL`, or move to `/chat/completions` with `anthropic/` ids. +- From OpenRouter, the request and `provider` object are identical. -### Codex / Cursor / Aider / Hermes / OpenClaw +## Routing and attribution -Any client that accepts a custom OpenAI base URL works. Set: - -- Base URL: `https://anyrouter.dev/api/v1` -- API key: `sk-ar-…` from the dashboard -- Model: `provider/model` from the catalog - -Generic paste-prompt for any coding agent: https://anyrouter.dev/docs/guides/ai-agent-integration.md. - -## Migration recipes (one-line summary) - -All three boil down to **swap base URL, swap key, keep request shape**. - -- **From OpenAI** → change `baseURL` to `https://anyrouter.dev/api/v1`, env to `ANYROUTER_API_KEY`, model id `gpt-*` → `openai/gpt-*`. Details: https://anyrouter.dev/docs/guides/migrate-from-openai.md. -- **From Anthropic** → either keep the Anthropic SDK and set `ANTHROPIC_BASE_URL=https://anyrouter.dev/api` (Anthropic-native `/messages`), or unify on `/chat/completions` with `model: "anthropic/claude-sonnet-4.6"`. Details: https://anyrouter.dev/docs/guides/migrate-from-anthropic.md. -- **From OpenRouter** → identical request shape. Change base URL to `https://anyrouter.dev/api/v1`, key env to `ANYROUTER_API_KEY`. `provider.only / .ignore / .order / .sort / .max_price / .allow_fallbacks` all map across. Details: https://anyrouter.dev/docs/guides/migrate-from-openrouter.md. - -## Provider preferences and routing - -Steer routing from the request body: - -```json -{ - "model": "openai/gpt-5.4-mini", - "provider": { - "only": ["OpenAI", "Groq"], - "order": ["Groq", "OpenAI"], - "sort": "latency", - "allow_fallbacks": true, - "max_price": { "prompt": "1.00", "completion": "4.00" }, - "preferred_max_latency": 300, - "preferred_min_throughput": 40 - } -} -``` - -Pin a single upstream with `X-AnyRouter-Provider: ` — useful for reproducibility, BYOK testing, and outage debugging. Full routing model: https://anyrouter.dev/docs/features/routing.md. - -## App attribution - -```typescript -new OpenAI({ - baseURL: "https://anyrouter.dev/api/v1", - apiKey: process.env.ANYROUTER_API_KEY, - defaultHeaders: { - "X-AnyRouter-Title": "My App", - "X-AnyRouter-Source": "web-app", - "X-AnyRouter-Version": process.env.APP_VERSION ?? "dev", - }, -}) -``` - -Full schema: https://anyrouter.dev/docs/features/app-attribution.md. - -## MCP server (bundled) - -This plugin registers a remote MCP server at `https://anyrouter.dev/api/v1/mcp`. Tools exposed: - -| Tool | Purpose | -| --- | --- | -| `list_models` | Search the catalog by provider, capability, or context window | -| `get_credits` | Workspace balance and lifetime usage | -| `list_keys` | List API keys | -| `create_key` | Mint a new API key | -| `revoke_key` | Disable a key by id | -| `list_presets` | List saved request presets | -| `list_conversations` | Search workspace conversations | +Steer routing with a `provider` object in the request body (`only`, `order`, `sort`, `allow_fallbacks`, `max_price`, `preferred_max_latency`, `preferred_min_throughput`). Pin one upstream with the `X-AnyRouter-Provider` header. Send `X-AnyRouter-Title`, `X-AnyRouter-Source`, and `X-AnyRouter-Version` so dashboard analytics work. Keep `allow_fallbacks: true` unless an eval needs a fixed upstream. Schemas are in `guides/provider-routing` and `features/app-attribution`. -OAuth runs on first tool call — the user picks Read-only / Standard / Full on the consent screen. There is no `chat` tool; use the regular chat endpoint for inference. +## MCP server -Full tool catalog, scopes, and manual-auth path: https://anyrouter.dev/docs/api-reference/mcp.md. Client setup for Claude Desktop / Cursor / Claude Code / OpenCode: https://anyrouter.dev/docs/mcp.md. +The plugin registers the MCP server. It exposes tools for listing models, credits, keys, presets, and conversations, and for creating and revoking keys. OAuth runs on the first tool call and the user picks a scope. There is no chat tool, so use the chat endpoint for inference. Details are in `api-reference/mcp`. -## Defaults that almost always belong in production +## Production defaults -- Read the key from env, never inline. -- Use `provider/model` ids; never bare model names except via aliases the docs explicitly list. -- Set the three `X-AnyRouter-*` attribution headers so dashboard analytics work. -- Keep `allow_fallbacks: true` unless you're running an eval that needs a fixed upstream. -- Long agent loops: bump SDK timeout (`API_TIMEOUT_MS=3000000` for Claude Code). -- Respect `X-RateLimit-Remaining` and `X-Upstream-RateLimit-Remaining` headers. +- Respect the `X-RateLimit-Remaining` and `X-Upstream-RateLimit-Remaining` headers. +- Raise the SDK timeout for long agent loops (`API_TIMEOUT_MS=3000000` for Claude Code). diff --git a/build-ios-apps/.claude-plugin/plugin.json b/build-ios-apps/.claude-plugin/plugin.json index 8b0db3c..bb0782f 100644 --- a/build-ios-apps/.claude-plugin/plugin.json +++ b/build-ios-apps/.claude-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "build-ios-apps", - "version": "1.0.1", - "description": "Build, profile, debug, and refine iOS apps with SwiftUI and Xcode workflows — App Intents, Simulator debugging, performance profiling, memory leak detection, and on-device AI with Apple Intelligence, Foundation Models, and Core AI.", + "version": "1.1.0", + "description": "Build, debug, and profile iOS apps with SwiftUI, Simulator, App Intents, and on-device AI.", "author": { "name": "duyet", "url": "https://github.com/duyet" diff --git a/build-ios-apps/.codex-plugin/plugin.json b/build-ios-apps/.codex-plugin/plugin.json index a51a26d..e44f002 100644 --- a/build-ios-apps/.codex-plugin/plugin.json +++ b/build-ios-apps/.codex-plugin/plugin.json @@ -1,22 +1,20 @@ { "name": "build-ios-apps", - "version": "1.0.1", - "description": "Build, profile, debug, and refine iOS apps with SwiftUI and Xcode workflows — App Intents, Simulator debugging, performance profiling, memory leak detection, and on-device AI with Apple Intelligence, Foundation Models, and Core AI.", + "version": "1.1.0", + "description": "Build, debug, and profile iOS apps with SwiftUI, Simulator, App Intents, and on-device AI.", "author": { "name": "duyet", "url": "https://github.com/duyet" }, "license": "MIT", "skills": "./skills/", - "agents": "./agents/", "interface": { "displayName": "Build iOS Apps", - "shortDescription": "Build, profile, debug, and refine iOS apps with SwiftUI and Xcode workflows — App Intents, Simulator debugging, performance profiling, memory leak detection, and on-device AI with Apple Intelligence, Foundation Models, and Core AI.", + "shortDescription": "Build, debug, and profile iOS apps with SwiftUI, Simulator, App Intents, and on-device AI.", "developerName": "duyet", "category": "Development", "capabilities": [ - "Skill", - "Agent" + "Skill" ], "logo": "./assets/logo.svg", "composerIcon": "./assets/logo.svg" diff --git a/build-ios-apps/.cursor-plugin/plugin.json b/build-ios-apps/.cursor-plugin/plugin.json index cd38c1d..618c4b1 100644 --- a/build-ios-apps/.cursor-plugin/plugin.json +++ b/build-ios-apps/.cursor-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "build-ios-apps", - "version": "1.0.1", - "description": "Build, profile, debug, and refine iOS apps with SwiftUI and Xcode workflows — App Intents, Simulator debugging, performance profiling, memory leak detection, and on-device AI with Apple Intelligence, Foundation Models, and Core AI.", + "version": "1.1.0", + "description": "Build, debug, and profile iOS apps with SwiftUI, Simulator, App Intents, and on-device AI.", "author": { "name": "duyet" }, @@ -11,6 +11,5 @@ "repository": "https://github.com/duyet/codex-claude-plugins", "logo": "./assets/logo.svg", "category": "Development", - "skills": "./skills/", - "agents": "./agents/" + "skills": "./skills/" } diff --git a/build-ios-apps/.grok-build-plugin/plugin.json b/build-ios-apps/.grok-build-plugin/plugin.json index 6432e21..90ba59e 100644 --- a/build-ios-apps/.grok-build-plugin/plugin.json +++ b/build-ios-apps/.grok-build-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "build-ios-apps", - "version": "1.0.1", - "description": "Build, profile, debug, and refine iOS apps with SwiftUI and Xcode workflows — App Intents, Simulator debugging, performance profiling, memory leak detection, and on-device AI with Apple Intelligence, Foundation Models, and Core AI.", + "version": "1.1.0", + "description": "Build, debug, and profile iOS apps with SwiftUI, Simulator, App Intents, and on-device AI.", "author": { "name": "duyet", "url": "https://github.com/duyet" @@ -9,15 +9,13 @@ "license": "MIT", "logo": "./assets/logo.svg", "skills": "./skills/", - "agents": "./agents/", "interface": { "displayName": "Build iOS Apps", - "shortDescription": "Build, profile, debug, and refine iOS apps with SwiftUI and Xcode workflows — App Intents, Simulator debugging, performance profiling, memory leak detection, and on-device AI with Apple Intelligence, Foundation Models, and Core AI.", + "shortDescription": "Build, debug, and profile iOS apps with SwiftUI, Simulator, App Intents, and on-device AI.", "developerName": "duyet", "category": "Development", "capabilities": [ - "Skill", - "Agent" + "Skill" ], "logo": "./assets/logo.svg", "composerIcon": "./assets/logo.svg" diff --git a/build-ios-apps/.grok-plugin/plugin.json b/build-ios-apps/.grok-plugin/plugin.json index 84033e2..157b6ed 100644 --- a/build-ios-apps/.grok-plugin/plugin.json +++ b/build-ios-apps/.grok-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "build-ios-apps", - "version": "1.0.1", - "description": "Build, profile, debug, and refine iOS apps with SwiftUI and Xcode workflows — App Intents, Simulator debugging, performance profiling, memory leak detection, and on-device AI with Apple Intelligence, Foundation Models, and Core AI.", + "version": "1.1.0", + "description": "Build, debug, and profile iOS apps with SwiftUI, Simulator, App Intents, and on-device AI.", "author": { "name": "duyet", "url": "https://github.com/duyet" @@ -11,6 +11,5 @@ "keywords": [ "build-ios-apps" ], - "skills": "./skills/", - "agents": "./agents/" + "skills": "./skills/" } diff --git a/build-ios-apps/README.md b/build-ios-apps/README.md index 23c773f..12b4dbb 100644 --- a/build-ios-apps/README.md +++ b/build-ios-apps/README.md @@ -1,8 +1,9 @@ # Build iOS Apps Plugin -This plugin packages iOS and Swift workflows. +Skills for building, debugging, and profiling iOS and SwiftUI apps. + +## What ships -It currently includes these skills: - `ios-debugger-agent` - `ios-simulator-browser` @@ -17,7 +18,7 @@ It currently includes these skills: - `core-ai` - `foundation-models` -## What It Covers +## Coverage - designing App Intents, app entities, and App Shortcuts for system surfaces - building and refactoring SwiftUI UI using current platform patterns @@ -25,31 +26,14 @@ It currently includes these skills: - auditing SwiftUI performance and guiding profiling workflows - capturing symbolicated ETTrace simulator profiles for focused app flows - capturing and comparing iOS memgraphs to root-cause leaks -- debugging iOS apps on simulators with XcodeBuildMCP-backed flows +- debugging iOS apps on simulators with XcodeBuildMCP (with an `xcrun simctl` fallback) - mirroring Simulator in the browser and hot-reloading package-backed SwiftUI previews - restructuring large SwiftUI views toward smaller, more stable compositions -## Plugin Structure - -```text -build-ios-apps/ -├── .claude-plugin/ # Claude manifest -├── .codex-plugin/ # Codex manifest -├── agents/ -│ └── openai.yaml # OpenAI surface metadata -└── skills/ # Skill payloads - ├── ios-debugger-agent/ - ├── ios-simulator-browser/ - ├── ios-ettrace-performance/ - ├── ios-memgraph-leaks/ - ├── ios-app-intents/ - ├── swiftui-liquid-glass/ - ├── swiftui-performance-audit/ - ├── swiftui-ui-patterns/ - ├── swiftui-view-refactor/ - ├── apple-intelligence/ - ├── core-ai/ - └── foundation-models/ +## Install + +```bash +/plugin install build-ios-apps@duyet-claude-plugins ``` ## License diff --git a/build-ios-apps/agents/openai.yaml b/build-ios-apps/agents/openai.yaml deleted file mode 100644 index c02b566..0000000 --- a/build-ios-apps/agents/openai.yaml +++ /dev/null @@ -1,6 +0,0 @@ -interface: - display_name: "Build iOS Apps" - short_description: "Build, profile, debug, and refine iOS apps with SwiftUI and Xcode workflows" - icon_small: "./assets/build-ios-apps-small.svg" - icon_large: "./assets/app-icon.png" - default_prompt: "Build or debug an iOS app with SwiftUI, App Intents, and Simulator." diff --git a/build-ios-apps/skills/apple-intelligence/SKILL.md b/build-ios-apps/skills/apple-intelligence/SKILL.md index d4429af..fd9bbbc 100644 --- a/build-ios-apps/skills/apple-intelligence/SKILL.md +++ b/build-ios-apps/skills/apple-intelligence/SKILL.md @@ -10,19 +10,19 @@ description: Apple Intelligence participation layer. Wire an app's actions and c Apple Intelligence is the personal intelligence system behind built-in capabilities across Apple platforms. It runs on-device on Apple silicon and in Private Cloud Compute. Your app participates by teaching the system about its **actions** and -**content** so system features — Siri, Spotlight, Shortcuts, Writing Tools, Image -Playground, Visual Intelligence, Genmoji, and summaries — can use them. +**content** so system features, Siri, Spotlight, Shortcuts, Writing Tools, Image +Playground, Visual Intelligence, Genmoji, and summaries, can use them. The participation contract is the **App Intents** framework: an `AppIntent` wraps one of your app's actions; an `AppEntity` represents the data those actions operate on. Apple Intelligence uses donated intents/entities, your Spotlight index, and declared -schemas to find and act on your content — even when described vaguely. +schemas to find and act on your content, even when described vaguely. Two sibling skills handle the custom-model side and are out of scope here: -- **`foundation-models`** — the Foundation Models framework for custom generative +- **`foundation-models`**: the Foundation Models framework for custom generative features (prompting, guided generation, tool calling, Private Cloud Compute). -- **`core-ai`** — running your own deep-learning model files (`.aimodel`) on-device. +- **`core-ai`**: running your own deep-learning model files (`.aimodel`) on-device. This skill covers only the built-in intelligence surfaces an app adopts. @@ -57,20 +57,20 @@ case .unavailable(let other): The single biggest lever. Make the system aware of your actions and data via the App Intents framework: -- **App intents** — a custom type encapsulating one action. Ship in your app or an app +- **App intents**: a custom type encapsulating one action. Ship in your app or an app extension so the action runs even when the app isn't open. Each intent performs an action in `perform()`, returns a result/error, declares parameters, and provides a localized title Siri and Shortcuts can display. -- **App entities** — lightweight versions of your data objects. Define them only for +- **App entities**: lightweight versions of your data objects. Define them only for the subset of data people see and might reference with Siri ("this photo", "this album"). Real data objects stay the source of truth. -- **App enums** — enumerate fixed choices (e.g. repeat options) so the system can +- **App enums**: enumerate fixed choices (e.g. repeat options) so the system can resolve parameters. -- **Donations** — when someone performs an action in your UI, donate the matching +- **Donations**: when someone performs an action in your UI, donate the matching intent/entity. Donations give Apple Intelligence behavioral cues to predict and disambiguate. Donate only direct UI interactions, not actions Siri or Shortcuts initiated. -- **Schemas (domains)** — the predefined intent/entity shapes for common actions (mail, +- **Schemas (domains)**: the predefined intent/entity shapes for common actions (mail, messaging, files, etc.). Prefer building from a schema over a custom intent; schemas are the contract Apple Intelligence uses to match everyday phrases. @@ -106,7 +106,7 @@ struct OrderAlbum: AppIntent { An `AppShortcut` bundles an `AppIntent` with a title, image, preconfigured parameters, and spoken phrases so it appears polished in Shortcuts and other system experiences. The compiler generates system metadata, so shortcuts are available the moment someone -installs your app — no registration needed. Define them in a type adopting the +installs your app, no registration needed. Define them in a type adopting the `AppShortcutProvider` protocol, alongside the intents they use. Surface them in-app with tip views. @@ -115,16 +115,16 @@ with tip views. Beyond a basic App Intents adoption, make content discoverable by Apple Intelligence specifically: -- **Index entities into Spotlight** — Apple Intelligence uses Spotlight's semantic +- **Index entities into Spotlight**: Apple Intelligence uses Spotlight's semantic search to find your content even when described vaguely. This is what makes "the email from Mei about the Q3 plan" work. -- **Choose transferable types** — conform entities/values to transferable types so the +- **Choose transferable types**: conform entities/values to transferable types so the system can move content across apps for cross-app Siri tasks. -- **Adopt schemas** — the contract the system uses to identify, query, and understand +- **Adopt schemas**: the contract the system uses to identify, query, and understand actions and content, and to match them to conversational phrases. -- **Associate entities with views / user activities** — gives Apple Intelligence +- **Associate entities with views / user activities**, gives Apple Intelligence onscreen context so someone can refer to what's visible ("this photo"). -- **Donate actions and content** — behavioral cues for prediction and disambiguation. +- **Donate actions and content**: behavioral cues for prediction and disambiguation. ## Spotlight / semantic indexing @@ -155,10 +155,10 @@ description, an optional source image, and a style. Present a system sheet (Swif view controller (UIKit/AppKit); the system manages all interaction and delivers the resulting image. Key API surface: -- `ImagePlaygroundViewController` — the standard system interface (UIKit/AppKit). -- `ImagePlaygroundConcept` — text elements specifying content to include. -- `ImagePlaygroundStyle` / `ImagePlaygroundOptions` — style and generation options. -- `ImageCreator` — generate images programmatically without the UI. +- `ImagePlaygroundViewController`: the standard system interface (UIKit/AppKit). +- `ImagePlaygroundConcept`: text elements specifying content to include. +- `ImagePlaygroundStyle` / `ImagePlaygroundOptions`, style and generation options. +- `ImageCreator`: generate images programmatically without the UI. - SwiftUI sheet modifier: ```swift @@ -174,7 +174,7 @@ imagePlaygroundSheet( ## Visual Intelligence For object/scene scanning via Camera Control, adopt Visual Intelligence. The framework -detects content and exchanges information with your app using App Intents — so your App +detects content and exchanges information with your app using App Intents, so your App Intents participation is also what makes you a destination for Visual Intelligence results. @@ -205,16 +205,16 @@ results. ## Resources -- Apple Intelligence overview — -- Built-in intelligence (on-device vision/speech/NLP) — -- Generative models overview — -- Apple Intelligence and Siri AI — -- Spotlight integration — -- Donations and discovery — -- Getting started with App Intents — -- App entities — -- App Shortcuts — -- AppIntent protocol — -- Image Playground — -- Foundation Models quick start (eligibility code) — +- Apple Intelligence overview: +- Built-in intelligence (on-device vision/speech/NLP), +- Generative models overview: +- Apple Intelligence and Siri AI: +- Spotlight integration: +- Donations and discovery: +- Getting started with App Intents: +- App entities: +- App Shortcuts: +- AppIntent protocol: +- Image Playground: +- Foundation Models quick start (eligibility code), - Sibling skills: `foundation-models`, `core-ai`, `ios-app-intents` diff --git a/build-ios-apps/skills/core-ai/SKILL.md b/build-ios-apps/skills/core-ai/SKILL.md index 6b4b8bf..6e18033 100644 --- a/build-ios-apps/skills/core-ai/SKILL.md +++ b/build-ios-apps/skills/core-ai/SKILL.md @@ -15,34 +15,34 @@ over `NDArray` tensors (image inputs use a pixel-buffer value). Available on **Apple Intelligence** devices: iPhone/iPad with A17 Pro or later, Mac with M1 or later, Apple Vision Pro (M2+). Building requires the **Metal Toolchain** -in Xcode (not installed by default) — without it, builds that include `.aimodel` +in Xcode (not installed by default), without it, builds that include `.aimodel` files fail with a missing Metal compiler error. > Core AI runs your own model files at the tensor level. For Apple's high-level > on-device LLM API (chat sessions, tool calling, guided generation), use the -> Foundation Models framework — a separate framework, not covered here. +> Foundation Models framework, a separate framework, not covered here. ## Workflow 1. **Inspect the model** in Xcode's model viewer: - - _General_ — size (parameter count and on-disk storage), numeric precision split + - _General_: size (parameter count and on-disk storage), numeric precision split into **compute** (used during inference) and **storage** (weights on disk), operation distribution, and editable metadata. - - _Functions_ — each inference function's input/output names, types, and shapes. + - _Functions_: each inference function's input/output names, types, and shapes. A `?` in a dimension means it is dynamic (supplied or determined at runtime). -2. **Bundle the model** — add the `.aimodel` file to the Xcode target (it appears in +2. **Bundle the model**: add the `.aimodel` file to the Xcode target (it appears in the _Compile Sources_ build phase). Install the Metal Toolchain first. -3. **Load the model** — `AIModel(contentsOf:)` is asynchronous because Core AI +3. **Load the model**: `AIModel(contentsOf:)` is asynchronous because Core AI **specializes** the model for the current device and selects the compute units that deliver the best performance. For large models this can take significant time, so consider ahead-of-time compilation (below). -4. **Load a function** — `model.loadFunction(named:)` returns the function or `nil` +4. **Load a function**: `model.loadFunction(named:)` returns the function or `nil` when no function with that name exists (it throws on other load failures). Use `functionNames` when a model has multiple functions. The same inference function is safe to call from concurrent tasks. -5. **Prepare inputs** — match each input's shape and scalar type from +5. **Prepare inputs**: match each input's shape and scalar type from `function.descriptor`, then write data through a mutable view. -6. **Run and read outputs** — `function.run(inputs:)` returns outputs keyed by name; +6. **Run and read outputs**: `function.run(inputs:)` returns outputs keyed by name; pull each result with `outputs.remove(_:)` and read it through a view. ## Core API @@ -86,21 +86,21 @@ processOutput(prediction.view()) ### Tensors and values -- `NDArray` — an n-dimensional tensor. Build it with `NDArray(shape:scalarType:)`. +- `NDArray`: an n-dimensional tensor. Build it with `NDArray(shape:scalarType:)`. It is **read-only by default**: use `mutableView(as:)` → `contiguousElements` to write, and `view()` to read. Swift enforces read vs. write access at compile time. -- `scalarType` — the element type, e.g. `.float32`. Shape is an `[Int]` matching the +- `scalarType`: the element type, e.g. `.float32`. Shape is an `[Int]` matching the model's expectation; a `?` dimension in the viewer is dynamic. -- **Images** — values marked as images at conversion time use a pixel-buffer value +- **Images**: values marked as images at conversion time use a pixel-buffer value rather than `NDArray`. -- `ValueDescriptor` — `.ndArray(ArrayDescriptor)` vs. image cases. Inspect +- `ValueDescriptor`: `.ndArray(ArrayDescriptor)` vs. image cases. Inspect `descriptor.inputDescriptor(of:)` / `outputDescriptor(of:)` at runtime so the app can adapt if a function's signature changes between deployments without code edits. ## Ahead-of-Time (AOT) Compilation -On-device specialization can delay first load. Move the most expensive part — model -compilation — to the build machine with the **`coreai-build`** CLI. It converts +On-device specialization can delay first load. Move the most expensive part, model +compilation, to the build machine with the **`coreai-build`** CLI. It converts `MyModel.aimodel` into one `MyModel..aimodelc` asset per device architecture. At runtime the app picks the asset for the current architecture and loads it with the **same** `AIModel` API, so loading code does not change. @@ -132,7 +132,7 @@ Notes: matches `` at runtime. - Compute units default to best performance. Pass `--preferred-compute` to override, and use matching load options. -- A compiled asset still requires **some** on-device specialization — AOT removes the +- A compiled asset still requires **some** on-device specialization, AOT removes the bulk of compilation, not all of it. AOT only targets Apple Intelligence devices. ## Checklist @@ -149,7 +149,7 @@ Notes: ## Resources -- Apple — _Integrating on-device AI models in your app with Core AI_ -- Apple — _Compiling Core AI models ahead of time_ +- Apple: _Integrating on-device AI models in your app with Core AI_ +- Apple: _Compiling Core AI models ahead of time_ - Prefer Apple docs for up-to-date API details; web-search the current Core AI documentation alongside this skill. diff --git a/build-ios-apps/skills/foundation-models/SKILL.md b/build-ios-apps/skills/foundation-models/SKILL.md index 15a6946..09eb354 100644 --- a/build-ios-apps/skills/foundation-models/SKILL.md +++ b/build-ios-apps/skills/foundation-models/SKILL.md @@ -8,7 +8,7 @@ description: Build on-device generative AI with Apple's Foundation Models framew ## Overview Foundation Models is Apple's generative-AI framework for intelligent app features. You -drive a language model through a `LanguageModelSession` — generating text, structuring +drive a language model through a `LanguageModelSession`, generating text, structuring output into Swift types with guided generation (`@Generable`, `GenerationSchema`), and letting the model call your own `Tool`s during generation. The default backend is the **system language model** (`SystemLanguageModel`), which runs on Apple Intelligence @@ -16,7 +16,7 @@ letting the model call your own `Tool`s during generation. The default backend i **Private Cloud Compute** (`PrivateCloudComputeLanguageModel`, server-side) or a **custom language model provider**, so session code is portable across backends. -Before any feature, gate on availability — the model can be unavailable for several +Before any feature, gate on availability, the model can be unavailable for several reasons: ```swift @@ -147,12 +147,12 @@ let r = try await session.respond(to: "Find three sourdough bread recipes") ## Choosing a Backend -- `SystemLanguageModel.default` — on-device, Apple Intelligence. Private and +- `SystemLanguageModel.default`: on-device, Apple Intelligence. Private and offline-capable; the default for most features. -- `PrivateCloudComputeLanguageModel` — same session API, runs server-side on Apple's +- `PrivateCloudComputeLanguageModel`: same session API, runs server-side on Apple's cloud. Requires the `com.apple.developer.private-cloud-compute` entitlement. Use when you need a larger cloud model; reuse your existing session code. -- Custom language model provider — bring your own model behind the same session API. +- Custom language model provider: bring your own model behind the same session API. Attach images with `Attachment` / `ImageAttachmentContent` for multimodal prompting and image analysis. @@ -171,14 +171,14 @@ image analysis. ## Related skills -- `apple-intelligence` — the participation layer (Siri, Spotlight, Writing Tools, Image +- `apple-intelligence`: the participation layer (Siri, Spotlight, Writing Tools, Image Playground) that surrounds on-device generation. -- `core-ai` — running your own model files (`.aimodel`) at the tensor level, for +- `core-ai`: running your own model files (`.aimodel`) at the tensor level, for features that are not language-model shaped. ## Resources -- Apple — Foundation Models: +- Apple: Foundation Models: - Generating content and performing tasks with Foundation Models - Generating Swift data structures with guided generation - Expanding generation with tool calling diff --git a/build-ios-apps/skills/ios-debugger-agent/SKILL.md b/build-ios-apps/skills/ios-debugger-agent/SKILL.md index c7c2da9..df94ee9 100644 --- a/build-ios-apps/skills/ios-debugger-agent/SKILL.md +++ b/build-ios-apps/skills/ios-debugger-agent/SKILL.md @@ -7,6 +7,9 @@ description: Build, run, and debug iOS apps on Simulator with XcodeBuildMCP. Use ## Overview +Requires the XcodeBuildMCP server (install: https://github.com/getsentry/XcodeBuildMCP, then add it to your MCP config). Without it, use the `xcrun simctl` fallback below. + + Use XcodeBuildMCP to build and run the current project scheme on a booted iOS simulator, interact with the UI, and capture logs. Prefer the MCP tools for simulator control, logs, and view inspection. ## Core Workflow @@ -52,6 +55,15 @@ Use these when asked to inspect or interact with the running app. - Stop logs: `mcp__XcodeBuildMCP__stop_sim_log_cap` and summarize important lines. - For console output, set `captureConsole: true` and relaunch if required. +## Fallback without XcodeBuildMCP + +- List and boot: `xcrun simctl list devices booted`, `xcrun simctl boot `. +- Build: `xcodebuild -scheme -destination 'platform=iOS Simulator,id=' -derivedDataPath build build`. +- Install and launch: `xcrun simctl install build/Build/Products/Debug-iphonesimulator/.app`, then `xcrun simctl launch --console `. +- Screenshot: `xcrun simctl io screenshot out.png`. +- Logs: `xcrun simctl spawn log stream --predicate 'subsystem == ""'`. +- UI tapping and typing need XcodeBuildMCP or a UI test. + ## Troubleshooting - If build fails, ask whether to retry with `preferXcodebuild: true`. diff --git a/build-ios-apps/skills/ios-ettrace-performance/SKILL.md b/build-ios-apps/skills/ios-ettrace-performance/SKILL.md index 098260f..93ed460 100644 --- a/build-ios-apps/skills/ios-ettrace-performance/SKILL.md +++ b/build-ios-apps/skills/ios-ettrace-performance/SKILL.md @@ -25,7 +25,7 @@ Use a writable run folder for each profiling session: ```bash if [ -z "${RUN_DIR:-}" ]; then - RUN_DIR="$(mktemp -d "${TMPDIR:-/tmp}/codex-ios-ettrace.XXXXXX")" + RUN_DIR="$(mktemp -d "${TMPDIR:-/tmp}/ios-ettrace.XXXXXX")" fi mkdir -p "$RUN_DIR" ``` @@ -100,21 +100,14 @@ Do not draw conclusions from an unsymbolicated flamegraph. Before every capture, Collect dSYMs after the final build that produced the installed app: ```bash -SKILL_DIR="" APP="" DSYMS="$RUN_DIR/dsyms" - -"$SKILL_DIR/scripts/collect_ios_dsyms.sh" \ - --app "$APP" \ - --out-dir "$DSYMS" \ - --search-root "$(dirname "$APP")" \ - --search-root "$PWD" \ - --extra-dsym "$RUN_DIR/ETTrace-iphonesimulator.xcarchive/dSYMs/ETTrace.framework.dSYM" +mkdir -p "$DSYMS" +find "$(dirname "$APP")" "$PWD" -name '*.dSYM' -type d -prune -exec cp -R {} "$DSYMS"/ \; 2>/dev/null +cp -R "$RUN_DIR/ETTrace-iphonesimulator.xcarchive/dSYMs/ETTrace.framework.dSYM" "$DSYMS"/ 2>/dev/null || true ``` -Add `--require-framework ` for app-owned dynamic frameworks that must symbolicate; use `--require-all-frameworks` only when every embedded framework is app-owned or expected to have symbols. If the helper reports a missing required app or framework dSYM, rebuild the exact simulator app with dSYM generation before tracing, or add the build output directory that -contains those dSYMs -as another `--search-root`. +For app-owned dynamic frameworks that must symbolicate, confirm each has a dSYM in `$DSYMS`. If one is missing, rebuild the exact simulator app with dSYM generation before tracing, or copy the dSYMs from the build output directory. Verify important UUIDs before tracing when the report looks suspicious: @@ -151,7 +144,7 @@ ettrace --simulator --verbose --dsyms "$DSYMS" Start from a stable screen, start ETTrace, perform exactly one focused flow, wait until visible work is complete, then stop the runner. For wider attribution, add `--multi-thread`; otherwise start with the main thread. -In Codex, run `ettrace` with a TTY and answer prompts with `write_stdin`. Without a TTY, the runner can exit without a useful trace. +Run `ettrace` in an interactive terminal (TTY) and answer its prompts there. Without a TTY, the runner can exit without a useful trace. ## Preserve Outputs @@ -169,7 +162,7 @@ find "$RUN_DIR" -maxdepth 1 -name 'output_*.json' -newer "$CAPTURE_MARKER" -prin cp "$json" "$preserved" { echo "## ${preserved##*/}" - python3 "$SKILL_DIR/scripts/analyze_flamegraph_json.py" "$preserved" + wc -c "$preserved" } >> "$PRESERVED_DIR/summary.txt" done if [ ! -s "$PRESERVED_DIR/summary.txt" ]; then @@ -178,11 +171,11 @@ if [ ! -s "$PRESERVED_DIR/summary.txt" ]; then fi ``` -Analyze only processed `output_*.json` files in `RUN_DIR`. Ignore `output.json` and raw `emerge-output/output.json` files unless debugging ETTrace itself. If the analyzer rejects the JSON shape, capture again with the Homebrew ETTrace runner and matching app-side `ETTrace.xcframework` tag instead of trying to interpret the rejected file. +Analyze only processed `output_*.json` files in `RUN_DIR`. Ignore `output.json` and raw `emerge-output/output.json` files unless debugging ETTrace itself. If the JSON shape is unexpected, capture again with the Homebrew ETTrace runner and matching app-side `ETTrace.xcframework` tag instead of trying to interpret the rejected file. ## Read The Profile -Start from `run-*/summary.txt`, then inspect processed JSON directly if needed. +Read each preserved `output_*.json` directly (for example with `jq` or a short Python script) and rank stacks by sample weight. Report: diff --git a/build-ios-apps/skills/ios-memgraph-leaks/SKILL.md b/build-ios-apps/skills/ios-memgraph-leaks/SKILL.md index bddac59..1b77629 100644 --- a/build-ios-apps/skills/ios-memgraph-leaks/SKILL.md +++ b/build-ios-apps/skills/ios-memgraph-leaks/SKILL.md @@ -26,7 +26,7 @@ Prefer capturing from the simulator already used for the reproduction. Resolve t SKILL_DIR="" SIM="" BUNDLE_ID="" -MEMGRAPH_DIR="$(mktemp -d "${TMPDIR:-/tmp}/codex-ios-memgraph.XXXXXX")" +MEMGRAPH_DIR="$(mktemp -d "${TMPDIR:-/tmp}/ios-memgraph.XXXXXX")" "$SKILL_DIR/scripts/capture_sim_memgraph.sh" \ --udid "$SIM" \ diff --git a/build-ios-apps/skills/ios-memgraph-leaks/scripts/capture_sim_memgraph.sh b/build-ios-apps/skills/ios-memgraph-leaks/scripts/capture_sim_memgraph.sh index f2cc20d..e4071db 100755 --- a/build-ios-apps/skills/ios-memgraph-leaks/scripts/capture_sim_memgraph.sh +++ b/build-ios-apps/skills/ios-memgraph-leaks/scripts/capture_sim_memgraph.sh @@ -13,7 +13,7 @@ Optional: --out-dir DIR Output directory for the memgraph and leaks output Example: - capture_sim_memgraph.sh --udid "$SIM" --bundle-id com.example.app --out-dir /tmp/codex-ios-memgraph + capture_sim_memgraph.sh --udid "$SIM" --bundle-id com.example.app --out-dir /tmp/ios-memgraph USAGE } @@ -73,7 +73,7 @@ if [[ -z "$bundle_id" ]]; then fi if [[ -z "$out_dir" ]]; then - out_dir="$(mktemp -d "${TMPDIR:-/tmp}/codex-ios-memgraph.XXXXXX")" + out_dir="$(mktemp -d "${TMPDIR:-/tmp}/ios-memgraph.XXXXXX")" fi matching_processes="$( diff --git a/build-ios-apps/skills/ios-simulator-browser/SKILL.md b/build-ios-apps/skills/ios-simulator-browser/SKILL.md index 4f966c5..3537aa6 100644 --- a/build-ios-apps/skills/ios-simulator-browser/SKILL.md +++ b/build-ios-apps/skills/ios-simulator-browser/SKILL.md @@ -1,6 +1,6 @@ --- name: ios-simulator-browser -description: Mirror an iOS Simulator into an in-app browser and hot-reload SwiftUI previews from importable Swift packages. Use when previewing SwiftUI in the simulator, mirroring a running simulator in the browser, or live-reloading package-backed previews. +description: Mirror an iOS Simulator into a browser and hot-reload SwiftUI previews from importable Swift packages. Use when previewing SwiftUI in the simulator, mirroring a running simulator in the browser, or live-reloading package-backed previews. --- # iOS Simulator Browser @@ -20,7 +20,7 @@ description: Mirror an iOS Simulator into an in-app browser and hot-reload Swift npx --yes serve-sim@latest "$SIM" ``` -3. Open the exact local preview URL printed by `serve-sim` in the Codex in-app browser. +3. Open the exact local preview URL printed by `serve-sim` in any browser (your harness's browser tool, or `open ` on macOS). 4. Verify that a real frame is rendering before reporting success. A loaded page alone is not proof that the simulator stream is healthy. - Keep the terminal alive while the browser mirror is in use. When finished, stop the terminal and wait for it to exit so the trap runs. @@ -40,7 +40,7 @@ node /scripts/swiftui-preview-browser.mjs \ - Watch mode is enabled by default. On a Swift package source edit, the launcher rebuilds a generated dylib and hot-swaps it into the running host without relaunching the app. - The generated host shows every preview variant discovered in the selected Swift Package target with in-simulator page controls. To show a subset instead, pass `--preview-filter `; it matches display names and code identifiers such as `StatusRowView_Previews`. -- Once the launcher prints the selected Simulator UDID, start `serve-sim` for that same UDID and open its printed URL in the in-app browser. +- Once the launcher prints the selected Simulator UDID, start `serve-sim` for that same UDID and open its printed URL in a browser. ## Support Boundary diff --git a/build-ios-apps/skills/swiftui-liquid-glass/SKILL.md b/build-ios-apps/skills/swiftui-liquid-glass/SKILL.md index e793193..9b43c2a 100644 --- a/build-ios-apps/skills/swiftui-liquid-glass/SKILL.md +++ b/build-ios-apps/skills/swiftui-liquid-glass/SKILL.md @@ -121,5 +121,5 @@ Button("Confirm") { } ## Resources -- Reference guide: `references/liquid-glass.md` +- For macOS specifics, use the `liquid-glass` skill from the build-macos-apps plugin when it is installed. - Prefer Apple docs for up-to-date API details, and use web search to consult current Apple Developer documentation in addition to the references above. diff --git a/build-ios-apps/skills/swiftui-performance-audit/SKILL.md b/build-ios-apps/skills/swiftui-performance-audit/SKILL.md index 3d259b1..6178b4f 100644 --- a/build-ios-apps/skills/swiftui-performance-audit/SKILL.md +++ b/build-ios-apps/skills/swiftui-performance-audit/SKILL.md @@ -110,5 +110,5 @@ Use `references/report-template.md` when formatting the final audit. - Optimizing SwiftUI performance with Instruments (Apple/WWDC resource, user-supplied) - Understanding and improving SwiftUI performance (Apple Developer documentation, user-supplied) - Understanding hangs in your app (Apple Developer documentation, user-supplied) -- Demystify SwiftUI performance — WWDC23 (Apple/WWDC resource, user-supplied) +- Demystify SwiftUI performance: WWDC23 (Apple/WWDC resource, user-supplied) - In addition to the references above, use web search to consult current Apple Developer documentation when Instruments workflows or SwiftUI performance guidance may have changed. diff --git a/build-ios-apps/skills/swiftui-ui-patterns/SKILL.md b/build-ios-apps/skills/swiftui-ui-patterns/SKILL.md index b584aa8..fc0a0a9 100644 --- a/build-ios-apps/skills/swiftui-ui-patterns/SKILL.md +++ b/build-ios-apps/skills/swiftui-ui-patterns/SKILL.md @@ -14,15 +14,12 @@ Choose a track based on your goal: - Identify the feature or screen and the primary interaction model (list, detail, editor, settings, tabbed). - Find a nearby example in the repo with `rg "TabView\("` or similar, then read the closest SwiftUI view. - Apply local conventions: prefer SwiftUI-native state, keep state local when possible, and use environment injection for shared dependencies. -- Choose the relevant component reference from `references/components-index.md` and follow its guidance. -- If the interaction reveals secondary content by dragging or scrolling the primary content away, read `references/scroll-reveal.md` before implementing gestures manually. - Build the view with small, focused subviews and SwiftUI-native data flow. ### New project scaffolding -- Start with `references/app-wiring.md` to wire TabView + NavigationStack + sheets. -- Add a minimal `AppTab` and `RouterPath` based on the provided skeletons. -- Choose the next component reference based on the UI you need first (TabView, NavigationStack, Sheets). +- Wire TabView, a NavigationStack per tab, and sheets at the app root. +- Add a minimal `AppTab` enum and `RouterPath` for per-tab navigation. - Expand the route and sheet enums as new screens are added. ## General rules to follow @@ -30,8 +27,8 @@ Choose a track based on your goal: - Use modern SwiftUI state (`@State`, `@Binding`, `@Observable`, `@Environment`) and avoid unnecessary view models. - If the deployment target includes iOS 16 or earlier and cannot use the Observation API introduced in iOS 17, fall back to `ObservableObject` with `@StateObject` for root ownership, `@ObservedObject` for injected observation, and `@EnvironmentObject` only for truly shared app-level state. - Prefer composition; keep views small and focused. -- Use async/await with `.task` and explicit loading/error states. For restart, cancellation, and debouncing guidance, read `references/async-state.md`. -- Keep shared app services in `@Environment`, but prefer explicit initializer injection for feature-local dependencies and models. For root wiring patterns, read `references/app-wiring.md`. +- Use async/await with `.task` and explicit loading/error states. +- Keep shared app services in `@Environment`, but prefer explicit initializer injection for feature-local dependencies and models. - Prefer the newest SwiftUI API that fits the deployment target and call out the minimum OS whenever a pattern depends on it. - Maintain existing legacy patterns only when editing legacy files. - Follow the project's formatter and style guide. @@ -53,16 +50,9 @@ Use the narrowest state tool that matches the ownership model: Choose the ownership location first, then pick the wrapper. Do not introduce a reference model when plain value state is enough. -## Cross-cutting references +## Further reading -- In addition to the references below, use web search to consult current Apple Developer documentation when SwiftUI APIs, availability, or platform guidance may have changed. -- `references/navigationstack.md`: navigation ownership, per-tab history, and enum routing. -- `references/sheets.md`: centralized modal presentation and enum-driven sheets. -- `references/deeplinks.md`: URL handling and routing external links into app destinations. -- `references/app-wiring.md`: root dependency graph, environment usage, and app shell wiring. -- `references/async-state.md`: `.task`, `.task(id:)`, cancellation, debouncing, and async UI state. -- `references/previews.md`: `#Preview`, fixtures, mock environments, and isolated preview setup. -- `references/performance.md`: stable identity, observation scope, lazy containers, and render-cost guardrails. +For macOS windowing, menus, and settings patterns, use the `swiftui-patterns` skill from the build-macos-apps plugin when it is installed. Use web search to consult current Apple Developer documentation when SwiftUI APIs or availability may have changed. ## Anti-patterns @@ -76,24 +66,8 @@ Choose the ownership location first, then pick the wrapper. Do not introduce a r 1. Define the view's state, ownership location, and minimum OS assumptions before writing UI code. 2. Identify which dependencies belong in `@Environment` and which should stay as explicit initializer inputs. -3. Sketch the view hierarchy, routing model, and presentation points; extract repeated parts into subviews. For complex navigation, read `references/navigationstack.md`, `references/sheets.md`, or `references/deeplinks.md`. **Build and verify no compiler errors before proceeding.** -4. Implement async loading with `.task` or `.task(id:)`, plus explicit loading and error states when needed. Read `references/async-state.md` when the work depends on changing inputs or cancellation. -5. Add previews for the primary and secondary states, then add accessibility labels or identifiers when the UI is interactive. Read `references/previews.md` when the view needs fixtures or injected mock dependencies. -6. Validate with a build: confirm no compiler errors, check that previews render without crashing, ensure state changes propagate correctly, and sanity-check that list identity and observation scope will not cause avoidable re-renders. Read `references/performance.md` if the screen is large, scroll-heavy, or frequently updated. For common SwiftUI compilation errors — missing - `@State` annotations, - ambiguous `ViewBuilder` closures, or mismatched generic types — resolve them before updating callsites. **If the build fails:** read the error message carefully, fix the identified issue, then rebuild before proceeding to the next step. If a preview crashes, isolate the offending subview, confirm its state initialisation is valid, and re-run the preview before continuing. +3. Sketch the view hierarchy, routing model, and presentation points; extract repeated parts into subviews. **Build and verify no compiler errors before proceeding.** +4. Implement async loading with `.task` or `.task(id:)`, plus explicit loading and error states when needed. +5. Add previews for the primary and secondary states, then add accessibility labels or identifiers when the UI is interactive. +6. Validate with a build: confirm no compiler errors, check that previews render without crashing, ensure state changes propagate correctly, and sanity-check that list identity and observation scope will not cause avoidable re-renders. For common SwiftUI compilation errors, missing `@State` annotations, ambiguous `ViewBuilder` closures, or mismatched generic types, resolve them before updating callsites. **If the build fails:** read the error message carefully, fix the identified issue, then rebuild before proceeding to the next step. If a preview crashes, isolate the offending subview, confirm its state initialisation is valid, and re-run the preview before continuing. -## Component references - -Use `references/components-index.md` as the entry point. Each component reference should include: - -- Intent and best-fit scenarios. -- Minimal usage pattern with local conventions. -- Pitfalls and performance notes. -- Paths to existing examples in the current repo. - -## Adding a new component reference - -- Create `references/.md`. -- Keep it short and actionable; link to concrete files in the current repo. -- Update `references/components-index.md` with the new entry. diff --git a/build-ios-apps/skills/swiftui-view-refactor/SKILL.md b/build-ios-apps/skills/swiftui-view-refactor/SKILL.md index d1745f6..e85c4d0 100644 --- a/build-ios-apps/skills/swiftui-view-refactor/SKILL.md +++ b/build-ios-apps/skills/swiftui-view-refactor/SKILL.md @@ -203,7 +203,7 @@ init(dependency: Dependency) { - Prefer small, explicit view types over large conditional blocks and large computed `some View` properties. - Keep computed view builders below `body` and non-view computed vars above `init`. - A good SwiftUI refactor should make the view read top-to-bottom as data flow plus layout, not as mixed layout and imperative logic. -- For MV-first guidance and rationale, see `references/mv-patterns.md`. +- Prefer MV-first: keep view state in `@State`/`@Observable` models owned by the view tree and avoid a view model per screen unless the project already uses one. - In addition to the references above, use web search to consult current Apple Developer documentation when SwiftUI APIs, Observation behavior, or platform guidance may have changed. ## Large-view handling diff --git a/build-macos-apps/.claude-plugin/plugin.json b/build-macos-apps/.claude-plugin/plugin.json index a0239c0..c622a4b 100644 --- a/build-macos-apps/.claude-plugin/plugin.json +++ b/build-macos-apps/.claude-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "build-macos-apps", - "version": "1.0.1", + "version": "1.1.0", "description": "Build, debug, instrument, and implement macOS apps with SwiftUI and AppKit guidance, codesigning, packaging, and telemetry workflows.", "author": { "name": "duyet", diff --git a/build-macos-apps/.codex-plugin/plugin.json b/build-macos-apps/.codex-plugin/plugin.json index c1e7a62..f9bcd95 100644 --- a/build-macos-apps/.codex-plugin/plugin.json +++ b/build-macos-apps/.codex-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "build-macos-apps", - "version": "1.0.1", + "version": "1.1.0", "description": "Build, debug, instrument, and implement macOS apps with SwiftUI and AppKit guidance, codesigning, packaging, and telemetry workflows.", "author": { "name": "duyet", @@ -9,7 +9,6 @@ "license": "MIT", "skills": "./skills/", "commands": "./commands/", - "agents": "./agents/", "interface": { "displayName": "Build macOS Apps", "shortDescription": "Build, debug, instrument, and implement macOS apps with SwiftUI and AppKit guidance, codesigning, packaging, and telemetry workflows.", @@ -17,8 +16,7 @@ "category": "Development", "capabilities": [ "Skill", - "Command", - "Agent" + "Command" ], "logo": "./assets/logo.svg", "composerIcon": "./assets/logo.svg" diff --git a/build-macos-apps/.cursor-plugin/plugin.json b/build-macos-apps/.cursor-plugin/plugin.json index ab6aebe..eec8a3f 100644 --- a/build-macos-apps/.cursor-plugin/plugin.json +++ b/build-macos-apps/.cursor-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "build-macos-apps", - "version": "1.0.1", + "version": "1.1.0", "description": "Build, debug, instrument, and implement macOS apps with SwiftUI and AppKit guidance, codesigning, packaging, and telemetry workflows.", "author": { "name": "duyet" @@ -12,6 +12,5 @@ "logo": "./assets/logo.svg", "category": "Development", "skills": "./skills/", - "commands": "./commands/", - "agents": "./agents/" + "commands": "./commands/" } diff --git a/build-macos-apps/.grok-build-plugin/plugin.json b/build-macos-apps/.grok-build-plugin/plugin.json index bc83207..f084943 100644 --- a/build-macos-apps/.grok-build-plugin/plugin.json +++ b/build-macos-apps/.grok-build-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "build-macos-apps", - "version": "1.0.1", + "version": "1.1.0", "description": "Build, debug, instrument, and implement macOS apps with SwiftUI and AppKit guidance, codesigning, packaging, and telemetry workflows.", "author": { "name": "duyet", @@ -10,7 +10,6 @@ "logo": "./assets/logo.svg", "skills": "./skills/", "commands": "./commands/", - "agents": "./agents/", "interface": { "displayName": "Build macOS Apps", "shortDescription": "Build, debug, instrument, and implement macOS apps with SwiftUI and AppKit guidance, codesigning, packaging, and telemetry workflows.", @@ -18,8 +17,7 @@ "category": "Development", "capabilities": [ "Skill", - "Command", - "Agent" + "Command" ], "logo": "./assets/logo.svg", "composerIcon": "./assets/logo.svg" diff --git a/build-macos-apps/.grok-plugin/plugin.json b/build-macos-apps/.grok-plugin/plugin.json index 4366691..200abcd 100644 --- a/build-macos-apps/.grok-plugin/plugin.json +++ b/build-macos-apps/.grok-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "build-macos-apps", - "version": "1.0.1", + "version": "1.1.0", "description": "Build, debug, instrument, and implement macOS apps with SwiftUI and AppKit guidance, codesigning, packaging, and telemetry workflows.", "author": { "name": "duyet", @@ -12,6 +12,5 @@ "build-macos-apps" ], "skills": "./skills/", - "commands": "./commands/", - "agents": "./agents/" + "commands": "./commands/" } diff --git a/build-macos-apps/README.md b/build-macos-apps/README.md index 2f57b6a..f4ad6c1 100644 --- a/build-macos-apps/README.md +++ b/build-macos-apps/README.md @@ -1,8 +1,9 @@ # Build macOS Apps Plugin -This plugin packages macOS-first development workflows. +Skills and commands for building, running, testing, signing, and shipping macOS apps. + +## What ships -It currently includes these skills: - `build-run-debug` - `test-triage` @@ -17,49 +18,12 @@ It currently includes these skills: - `view-refactor` - `telemetry` -## What It Covers - -- discovering local Xcode workspaces, projects, and Swift packages -- building and running macOS apps with shell-first desktop workflows -- creating one project-local `script/build_and_run.sh` entrypoint and wiring `.codex/environments/environment.toml` so the Codex app Run button works -- implementing native macOS SwiftUI scenes, menus, settings, toolbars, and multiwindow flows -- adopting modern macOS Liquid Glass and design-system guidance with standard SwiftUI structures, toolbars, search, controls, and custom glass surfaces -- tailoring SwiftUI windows with title/toolbar styling, material-backed container backgrounds, minimize/restoration behavior, default and ideal placement, borderless window style, and launch behavior -- bridging into AppKit for representables, responder-chain behavior, panels, and other desktop-only needs -- refactoring large macOS view files toward stable scene, selection, and command structure -- adding lightweight `Logger` / `os.Logger` instrumentation for windows, sidebars, menu commands, and menu bar actions -- reading and verifying runtime events with Console, `log stream`, and process logs -- triaging failing unit, integration, and UI-hosted macOS tests -- debugging launch failures, crashes, linker problems, and runtime regressions -- inspecting signing identities, entitlements, hardened runtime, and Gatekeeper issues -- preparing packaging and notarization workflows for distribution +Commands: `/build-and-run-macos-app`, `/fix-codesign-error`, `/test-macos-app`. -## Plugin Structure +## Install -```text -build-macos-apps/ -├── .claude-plugin/ # Claude manifest -├── .codex-plugin/ # Codex manifest -├── agents/ -│ └── openai.yaml # OpenAI surface metadata -├── assets/ # Icons and SVGs -├── commands/ # Slash commands -│ ├── build-and-run-macos-app.md -│ ├── fix-codesign-error.md -│ └── test-macos-app.md -└── skills/ # Skill payloads - ├── build-run-debug/ - ├── test-triage/ - ├── signing-entitlements/ - ├── swiftpm-macos/ - ├── packaging-notarization/ - ├── swiftui-patterns/ - ├── macos-app-best-practices/ - ├── liquid-glass/ - ├── window-management/ - ├── appkit-interop/ - ├── view-refactor/ - └── telemetry/ +```bash +/plugin install build-macos-apps@duyet-claude-plugins ``` ## License diff --git a/build-macos-apps/agents/openai.yaml b/build-macos-apps/agents/openai.yaml deleted file mode 100644 index 358d8af..0000000 --- a/build-macos-apps/agents/openai.yaml +++ /dev/null @@ -1,6 +0,0 @@ -interface: - display_name: "Build macOS Apps" - short_description: "Build, debug, instrument, and implement macOS apps with SwiftUI and AppKit guidance" - icon_small: "./assets/build-macos-apps-small.svg" - icon_large: "./assets/app-icon.png" - default_prompt: "Build/refactor native macOS UI, inspect AppKit interop, add telemetry, or debug a macOS app." diff --git a/build-macos-apps/commands/build-and-run-macos-app.md b/build-macos-apps/commands/build-and-run-macos-app.md index dc493ff..fbf0246 100644 --- a/build-macos-apps/commands/build-and-run-macos-app.md +++ b/build-macos-apps/commands/build-and-run-macos-app.md @@ -1,7 +1,10 @@ +--- +description: Create or update the project-local macOS build_and_run.sh script, then use it to build and launch the app. +--- + # /build-and-run-macos-app -Create or update the project-local macOS `build_and_run.sh` script, wire the -Codex app Run button, then use that script as the default build/run entrypoint. +Follow `../skills/build-run-debug/SKILL.md`. Create or update `script/build_and_run.sh`, then use it as the default build/run entrypoint. ## Arguments @@ -15,16 +18,15 @@ Codex app Run button, then use that script as the default build/run entrypoint. ## Workflow 1. Detect whether the repo uses an Xcode workspace, Xcode project, or SwiftPM package. -2. If the workspace is not inside git yet, run `git init` at the project root so Codex app git-backed features unlock. +2. If the workspace is not inside git yet, run `git init` at the project root. 3. Create or update `script/build_and_run.sh` so it always stops the current app, builds the macOS target, and launches the fresh result. 4. For SwiftPM, keep raw executable launch only for true CLI tools; for AppKit/SwiftUI GUI apps, create a project-local `.app` bundle and launch it with `/usr/bin/open -n`. 5. Support optional script flags for `--debug`, `--logs`, `--telemetry`, and `--verify`. -6. Follow the canonical bootstrap contract in `../skills/build-run-debug/references/run-button-bootstrap.md` for the exact script shape and `.codex/environments/environment.toml` format. +6. Follow the script shape in `../skills/build-run-debug/references/run-button-bootstrap.md`. 7. Run the script in the requested mode and summarize any build, script, or launch failure. ## Guardrails - Do not initialize a nested git repo inside an existing parent checkout. -- Do not leave stale `Run` actions pointing at old script paths. - Keep the no-flag script path simple: kill, build, run. - Use `--debug`, `--logs`, `--telemetry`, or `--verify` only when the user asks for those modes. diff --git a/build-macos-apps/commands/fix-codesign-error.md b/build-macos-apps/commands/fix-codesign-error.md index 5414e48..1d9823d 100644 --- a/build-macos-apps/commands/fix-codesign-error.md +++ b/build-macos-apps/commands/fix-codesign-error.md @@ -1,3 +1,7 @@ +--- +description: Inspect a macOS signing or entitlement failure and explain the minimum fix. +--- + # /fix-codesign-error Inspect a macOS signing or entitlement failure and explain the minimum fix path. diff --git a/build-macos-apps/commands/test-macos-app.md b/build-macos-apps/commands/test-macos-app.md index 595b34b..a3a2e64 100644 --- a/build-macos-apps/commands/test-macos-app.md +++ b/build-macos-apps/commands/test-macos-app.md @@ -1,3 +1,7 @@ +--- +description: Run the smallest meaningful macOS test scope first and explain failures by category. +--- + # /test-macos-app Run the smallest meaningful macOS test scope first and explain failures by category. diff --git a/build-macos-apps/skills/appkit-interop/references/appkit-overview.md b/build-macos-apps/skills/appkit-interop/references/appkit-overview.md index 84f4154..cb962b8 100644 --- a/build-macos-apps/skills/appkit-interop/references/appkit-overview.md +++ b/build-macos-apps/skills/appkit-interop/references/appkit-overview.md @@ -4,7 +4,7 @@ AppKit provides the objects to build a macOS app's user interface and to manage interaction between the app, the person, and macOS: windows, panels, buttons, text fields, event handling, drawing, printing, animation, documents, drag and drop, menus, accessibility, and localization. It interops with SwiftUI in both directions -— AppKit views and view controllers embed into SwiftUI via representables, and +, AppKit views and view controllers embed into SwiftUI via representables, and SwiftUI views can be hosted inside AppKit. ## When to reach for AppKit @@ -16,32 +16,32 @@ approach. ## Topic map -- **App and Environment** — app lifecycle, run loop, environment, appearance. -- **Windows, Panels, and Screens** — `NSWindow`, panels, full-screen, restoration. -- **Views and Controls** — buttons, fields, sliders, segmented controls, toolbars. -- **Text System** — text storage, selection, layout, attachments, view providers. -- **Documents, Data, and Pasteboard** — document architecture, pasteboard, undo. -- **Drawing** — `NSBezierPath`, graphics contexts, images and PDF. -- **Color and Fonts** — color management, font descriptors, typography. -- **Menus, Cursors, and the Dock** — menu bars, menu items, dock tiles. -- **Mouse, Keyboard, and Trackpad** — event handling, gestures, responders. -- **Drag and Drop** — pasteboard-based dragging sessions. -- **Animation** — `NSAnimationContext`, animator proxies, layer-backed views. -- **Accessibility** — accessibility elements, traits, and actions. -- **Cocoa Bindings** — KVO/bindings to connect UI to models. -- **Appearance Customization** — light/dark, accent, vibrancy. -- **Mac Catalyst** — bring iPad apps to the Mac. +- **App and Environment**: app lifecycle, run loop, environment, appearance. +- **Windows, Panels, and Screens**: `NSWindow`, panels, full-screen, restoration. +- **Views and Controls**: buttons, fields, sliders, segmented controls, toolbars. +- **Text System**: text storage, selection, layout, attachments, view providers. +- **Documents, Data, and Pasteboard**: document architecture, pasteboard, undo. +- **Drawing**: `NSBezierPath`, graphics contexts, images and PDF. +- **Color and Fonts**: color management, font descriptors, typography. +- **Menus, Cursors, and the Dock**: menu bars, menu items, dock tiles. +- **Mouse, Keyboard, and Trackpad**: event handling, gestures, responders. +- **Drag and Drop**: pasteboard-based dragging sessions. +- **Animation**: `NSAnimationContext`, animator proxies, layer-backed views. +- **Accessibility**: accessibility elements, traits, and actions. +- **Cocoa Bindings**: KVO/bindings to connect UI to models. +- **Appearance Customization**: light/dark, accent, vibrancy. +- **Mac Catalyst**: bring iPad apps to the Mac. ## Notable symbols from the AppKit reference These appear in the current AppKit reference; confirm availability and semantics in the Apple Developer docs before relying on them. -- `NSRefreshController` — a refresh control for AppKit scroll views. -- `NSTextSelectionManager` (plus `.Delegate`, `.Mode`) — unified text selection. -- `NSMenuItem.ImageVisibility` — control menu-item icon visibility. -- `NSSegmentedControl.Role` — per-segment roles. -- `NSStatusItemExpandedInterfaceDelegate` / `NSStatusItemExpandedInterfaceSession` — +- `NSRefreshController`: a refresh control for AppKit scroll views. +- `NSTextSelectionManager` (plus `.Delegate`, `.Mode`), unified text selection. +- `NSMenuItem.ImageVisibility`: control menu-item icon visibility. +- `NSSegmentedControl.Role`: per-segment roles. +- `NSStatusItemExpandedInterfaceDelegate` / `NSStatusItemExpandedInterfaceSession` , expanded status items. -- `NSTextViewportRenderingSurface` / `NSTextViewportRenderingSurfaceKey` — text +- `NSTextViewportRenderingSurface` / `NSTextViewportRenderingSurfaceKey`, text viewport rendering hooks. diff --git a/build-macos-apps/skills/build-run-debug/SKILL.md b/build-macos-apps/skills/build-run-debug/SKILL.md index ec488e6..08386e7 100644 --- a/build-macos-apps/skills/build-run-debug/SKILL.md +++ b/build-macos-apps/skills/build-run-debug/SKILL.md @@ -7,9 +7,7 @@ description: Build, run, and debug macOS apps with shell-first Xcode and Swift w ## Quick Start -Use this skill to set up one project-local `script/build_and_run.sh` entrypoint, -wire `.codex/environments/environment.toml` so the Codex app shows a Run button, -then use that script as the default build/run path. +Set up one project-local `script/build_and_run.sh` entrypoint, then use it as the default build/run path. Prefer shell-first workflows: @@ -30,7 +28,7 @@ simulator-specific workflows onto pure macOS tasks. 1. Discover the project shape. - Check whether the workspace is already inside a git repo with `git rev-parse --is-inside-work-tree`. - - If no git repo is present, run `git init` at the project/workspace root before building so Codex app git-backed features are available. Never run `git init` inside a nested subdirectory when the current workspace already belongs to a parent repo. + - If no git repo is present, run `git init` at the project/workspace root before building so changes are tracked. Never run `git init` inside a nested subdirectory when the current workspace already belongs to a parent repo. - Look for `.xcworkspace`, `.xcodeproj`, and `Package.swift`. - If more than one candidate exists, explain the default choice and the ambiguity. @@ -58,34 +56,25 @@ simulator-specific workflows onto pure macOS tasks. - For SwiftPM GUI apps, make the script build the product, create `dist/.app`, copy the binary to `Contents/MacOS/`, generate a minimal `Contents/Info.plist` with `CFBundlePackageType=APPL`, `CFBundleExecutable`, `CFBundleIdentifier`, `CFBundleName`, `LSMinimumSystemVersion`, and `NSPrincipalClass=NSApplication`, then launch with `/usr/bin/open -n `. - For SwiftPM GUI `--logs` and `--telemetry`, launch the bundle with `/usr/bin/open -n` first, then stream unified logs with `/usr/bin/log stream --info ...`. - Do not recommend direct SwiftPM executable launch for AppKit/SwiftUI GUI apps. - - Use `references/run-button-bootstrap.md` as the canonical source for the - script shape and exact environment file format. Do not fork a second - authoritative snippet in another skill or command. + - Use `references/run-button-bootstrap.md` as the canonical source for the script shape. Do not fork a second snippet elsewhere. - Keep the run script outside app source. It belongs in `script/build_and_run.sh`, not in `App/`, `Views/`, `Models/`, `Stores/`, `Services/`, or `Support/`. -4. Write `.codex/environments/environment.toml` at the project root once the script exists. - - Use this exact placement: `.codex/environments/environment.toml`. - - Use the exact action shape in `references/run-button-bootstrap.md`. - - This file is what gives the user a Codex app Run button wired to the script. - - If the project already has this file, update the `Run` action command to point at `./script/build_and_run.sh` instead of creating a duplicate action. - - Keep this Codex environment config separate from Swift app source files. - -5. Build and run through the script. +4. Build and run through the script. - Default to `./script/build_and_run.sh`. - Use `./script/build_and_run.sh --debug`, `--logs`, `--telemetry`, or `--verify` when the user asks for debugger/log/telemetry/process verification support. -6. Summarize failures correctly. +5. Summarize failures correctly. - Classify the blocker as compiler, linker, signing, build settings, missing SDK/toolchain, script bug, or runtime launch. - Quote the smallest useful error snippet and explain what it means. -7. Debug the right way. +6. Debug the right way. - Use the script's `--logs` or `--telemetry` mode for config, entitlement, sandbox, and action-event verification. - For SwiftPM GUI apps, if the app bundle launches but its window still does not come forward, check whether the entrypoint needs `NSApp.setActivationPolicy(.regular)` and `NSApp.activate(ignoringOtherApps: true)`. - Use the script's `--debug` mode or direct `lldb` if symbolized crash debugging is needed. - If the user needs to instrument and verify specific window, sidebar, menu, or menu bar actions, switch to `telemetry`. - Keep evidence tight and user-facing. -8. Use Xcode-aware MCP tooling only when it helps. +7. Use Xcode-aware MCP tooling only when it helps. - If the user explicitly asks for XcodeBuildMCP and it is already available, prefer it over ad hoc setup. - Use the MCP for Xcode-aware discovery or debug/logging workflows when the available tool surface clearly matches the task. - Fall back to shell commands immediately when the MCP does not provide a clean macOS path. @@ -106,13 +95,12 @@ simulator-specific workflows onto pure macOS tasks. ## References -- `references/run-button-bootstrap.md`: canonical `build_and_run.sh` and `.codex/environments/environment.toml` contract. +- `references/run-button-bootstrap.md`: canonical `build_and_run.sh` script shapes. ## Guardrails - Prefer the narrowest command that proves or disproves the current theory. - Do not leave the user with a one-off manual command chain once a stable `build_and_run.sh` script can own the workflow. -- Do not write `.codex/environments/environment.toml` before the run script exists, and do not point the Run action at a stale script path. - Do not launch a SwiftUI/AppKit SwiftPM GUI app as a raw executable unless the user explicitly wants to diagnose that failure mode: it can produce no Dock icon, no foreground activation, and missing bundle identifier warnings. Keep raw executable launch only for true command-line tools. - Do not claim UI state you cannot inspect directly. - Do not describe mobile or simulator workflows as if they apply to macOS. @@ -123,7 +111,7 @@ simulator-specific workflows onto pure macOS tasks. Provide: - the detected project type -- the script path and Codex environment action you configured, if applicable +- the script path you configured, if applicable - the command you ran - whether build and launch succeeded - the top blocker if they failed diff --git a/build-macos-apps/skills/build-run-debug/references/run-button-bootstrap.md b/build-macos-apps/skills/build-run-debug/references/run-button-bootstrap.md index 8796ca6..424b57a 100644 --- a/build-macos-apps/skills/build-run-debug/references/run-button-bootstrap.md +++ b/build-macos-apps/skills/build-run-debug/references/run-button-bootstrap.md @@ -1,7 +1,6 @@ -# Run Button Bootstrap +# Run script bootstrap -This is the canonical bootstrap contract for the macOS Build plugin's local run -loop. +Canonical contract for the macOS build plugin's local run loop. When a project does not already have an established macOS run entrypoint: @@ -9,8 +8,6 @@ When a project does not already have an established macOS run entrypoint: 2. Make it executable. 3. Use it as the single kill + build + run entrypoint. 4. Support optional `--debug`, `--logs`, `--telemetry`, and `--verify` flags. -5. Write `.codex/environments/environment.toml` so the Codex app exposes a - `Run` action wired to that script. ## `script/build_and_run.sh` @@ -145,28 +142,3 @@ case "$MODE" in ;; esac ``` - -## `.codex/environments/environment.toml` - -Write the environment file at this exact path: - -`.codex/environments/environment.toml` - -with this action shape: - -```toml -# THIS IS AUTOGENERATED. DO NOT EDIT MANUALLY -version = 1 -name = "" - -[setup] -script = "" - -[[actions]] -name = "Run" -icon = "run" -command = "./script/build_and_run.sh" -``` - -If the project already has an environment file, update the existing `Run` -action to point at `./script/build_and_run.sh` instead of adding a duplicate. diff --git a/build-macos-apps/skills/macos-app-best-practices/SKILL.md b/build-macos-apps/skills/macos-app-best-practices/SKILL.md index 761fac8..eb8e07d 100644 --- a/build-macos-apps/skills/macos-app-best-practices/SKILL.md +++ b/build-macos-apps/skills/macos-app-best-practices/SKILL.md @@ -174,9 +174,9 @@ adds the Mac entitlement to the Mac build only and adds a "My Mac" destination. Choose the UI idiom in Xcode after enabling Mac Catalyst: -- **Scale Interface to Match iPad** — iPad idiom. Fastest; UI scaled to the Mac with +- **Scale Interface to Match iPad**: iPad idiom. Fastest; UI scaled to the Mac with iPad-like metrics. The default. -- **Optimize Interface for Mac** — Mac idiom. Controls look and behave like AppKit; +- **Optimize Interface for Mac**: Mac idiom. Controls look and behave like AppKit; points equal AppKit points. May require re-laying out hard-coded sizes and constraints. Detect via `traitCollection.userInterfaceIdiom == .mac`. @@ -235,10 +235,10 @@ let style = UIAlertController.Style.actionSheet ## When To Use Other Skills -- `swiftui-patterns` — concrete scene/window/toolbar/settings/split-view implementations. -- `window-management` — window chrome, placement, restoration, borderless windows. -- `appkit-interop` — reaching AppKit (NSWindow, panels, responder chain) from SwiftUI. -- `signing-entitlements` / `packaging-notarization` — ship the app once it builds. +- `swiftui-patterns`: concrete scene/window/toolbar/settings/split-view implementations. +- `window-management`: window chrome, placement, restoration, borderless windows. +- `appkit-interop`: reaching AppKit (NSWindow, panels, responder chain) from SwiftUI. +- `signing-entitlements` / `packaging-notarization`, ship the app once it builds. ## Resources diff --git a/build-macos-apps/skills/swiftui-patterns/SKILL.md b/build-macos-apps/skills/swiftui-patterns/SKILL.md index 7dd66b5..6f63b09 100644 --- a/build-macos-apps/skills/swiftui-patterns/SKILL.md +++ b/build-macos-apps/skills/swiftui-patterns/SKILL.md @@ -20,8 +20,8 @@ Choose a track based on your goal: - Choose the scene model first: `WindowGroup`, `Window`, `Settings`, `MenuBarExtra`, or `DocumentGroup`. - If the app combines a normal main window and a `MenuBarExtra`, use `WindowGroup(..., id:)` for the primary window when it should appear at launch. Treat `Window(...)` as a better fit for auxiliary/on-demand singleton windows; in menu-bar-heavy apps, a `Window(...)` scene may not present the main window automatically at launch. -- Before creating the scaffold, check whether the workspace is already inside a git repo with `git rev-parse --is-inside-work-tree`. If not, run `git init` at the project root so Codex app git-backed features are available from the start. Do not initialize a nested repo inside an existing parent checkout. -- For a new app scaffold, also create one project-local `script/build_and_run.sh` and `.codex/environments/environment.toml` so the Codex app Run button works immediately. Use the exact bootstrap contract from `build-run-debug` and its `references/run-button-bootstrap.md` file rather than inventing a second variant here. +- Before creating the scaffold, check whether the workspace is already inside a git repo with `git rev-parse --is-inside-work-tree`. If not, run `git init` at the project root. Do not initialize a nested repo inside an existing parent checkout. +- For a new app scaffold, also create one project-local `script/build_and_run.sh`. Use the bootstrap contract in `../build-run-debug/references/run-button-bootstrap.md` rather than inventing a second variant. - Decide which state is app-wide, scene-scoped, or window-scoped before writing views. - Sketch file and module boundaries before writing the full UI. For any non-trivial app, create the folder structure first and split files by responsibility from the start. - Use a single Swift file only for tiny throwaway examples or snippets: roughly under 50 lines, one screen, no persistence, no networking/process client, and no reusable models. Anything beyond that should be multi-file immediately. @@ -53,7 +53,7 @@ Before writing the full UI: 2. Choose state ownership: app-wide, scene-scoped, window-scoped, or view-local. 3. Sketch file and module boundaries. 4. Create the folder structure before filling in the UI. -5. Keep `script/build_and_run.sh` and `.codex/environments/environment.toml` separate from app source. +5. Keep `script/build_and_run.sh` separate from app source. ## General Rules To Follow diff --git a/build-macos-apps/skills/swiftui-patterns/references/components-index.md b/build-macos-apps/skills/swiftui-patterns/references/components-index.md index 0fe2432..dedc536 100644 --- a/build-macos-apps/skills/swiftui-patterns/references/components-index.md +++ b/build-macos-apps/skills/swiftui-patterns/references/components-index.md @@ -4,11 +4,11 @@ Use this file to find scene and component guidance. Each entry lists when to use ## Available references -- Windowing: `references/windowing.md` — Use when choosing between `WindowGroup`, `Window`, `DocumentGroup`, or window-opening APIs. -- Settings: `references/settings.md` — Use for dedicated settings scenes, preference storage, and settings entry points. -- Commands and menus: `references/commands-menus.md` — Use for menu items, keyboard shortcuts, focused actions, and command routing. -- Split views and inspectors: `references/split-inspectors.md` — Use for sidebar-detail apps, inspectors, and selection-driven desktop layouts. -- Menu bar extras: `references/menu-bar-extra.md` — Use when the app belongs primarily in the menu bar. +- Windowing: `references/windowing.md`: Use when choosing between `WindowGroup`, `Window`, `DocumentGroup`, or window-opening APIs. +- Settings: `references/settings.md`: Use for dedicated settings scenes, preference storage, and settings entry points. +- Commands and menus: `references/commands-menus.md`, Use for menu items, keyboard shortcuts, focused actions, and command routing. +- Split views and inspectors: `references/split-inspectors.md`, Use for sidebar-detail apps, inspectors, and selection-driven desktop layouts. +- Menu bar extras: `references/menu-bar-extra.md`, Use when the app belongs primarily in the menu bar. ## Adding entries diff --git a/clickhouse-monitoring/.claude-plugin/plugin.json b/clickhouse-monitoring/.claude-plugin/plugin.json index be0b9d2..5a61cc5 100644 --- a/clickhouse-monitoring/.claude-plugin/plugin.json +++ b/clickhouse-monitoring/.claude-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "clickhouse-monitoring", - "version": "1.1.1", - "description": "Agent Skill for the ClickHouse Monitor dashboard - a real-time monitoring and observability tool for ClickHouse clusters", + "version": "1.2.0", + "description": "Work on the ClickHouse Monitor dashboard: charts, pages, query configs, its API, and version-aware system queries.", "author": { "name": "duyet", "url": "https://github.com/duyet" diff --git a/clickhouse-monitoring/.codex-plugin/plugin.json b/clickhouse-monitoring/.codex-plugin/plugin.json index cb4e766..b9e5851 100644 --- a/clickhouse-monitoring/.codex-plugin/plugin.json +++ b/clickhouse-monitoring/.codex-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "clickhouse-monitoring", - "version": "1.1.1", - "description": "Agent Skill for the ClickHouse Monitor dashboard - a real-time monitoring and observability tool for ClickHouse clusters", + "version": "1.2.0", + "description": "Work on the ClickHouse Monitor dashboard: charts, pages, query configs, its API, and version-aware system queries.", "author": { "name": "duyet", "url": "https://github.com/duyet" @@ -10,7 +10,7 @@ "skills": "./skills/", "interface": { "displayName": "Clickhouse Monitoring", - "shortDescription": "Agent Skill for the ClickHouse Monitor dashboard - a real-time monitoring and observability tool for ClickHouse clusters", + "shortDescription": "Work on the ClickHouse Monitor dashboard: charts, pages, query configs, its API, and version-aware system queries.", "developerName": "duyet", "category": "Monitoring", "capabilities": [ diff --git a/clickhouse-monitoring/.cursor-plugin/plugin.json b/clickhouse-monitoring/.cursor-plugin/plugin.json index 78346de..5b86474 100644 --- a/clickhouse-monitoring/.cursor-plugin/plugin.json +++ b/clickhouse-monitoring/.cursor-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "clickhouse-monitoring", - "version": "1.1.1", - "description": "Agent Skill for the ClickHouse Monitor dashboard - a real-time monitoring and observability tool for ClickHouse clusters", + "version": "1.2.0", + "description": "Work on the ClickHouse Monitor dashboard: charts, pages, query configs, its API, and version-aware system queries.", "author": { "name": "duyet" }, diff --git a/clickhouse-monitoring/.grok-build-plugin/plugin.json b/clickhouse-monitoring/.grok-build-plugin/plugin.json index c6f0dc1..e78c96c 100644 --- a/clickhouse-monitoring/.grok-build-plugin/plugin.json +++ b/clickhouse-monitoring/.grok-build-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "clickhouse-monitoring", - "version": "1.1.1", - "description": "Agent Skill for the ClickHouse Monitor dashboard - a real-time monitoring and observability tool for ClickHouse clusters", + "version": "1.2.0", + "description": "Work on the ClickHouse Monitor dashboard: charts, pages, query configs, its API, and version-aware system queries.", "author": { "name": "duyet", "url": "https://github.com/duyet" @@ -11,7 +11,7 @@ "skills": "./skills/", "interface": { "displayName": "Clickhouse Monitoring", - "shortDescription": "Agent Skill for the ClickHouse Monitor dashboard - a real-time monitoring and observability tool for ClickHouse clusters", + "shortDescription": "Work on the ClickHouse Monitor dashboard: charts, pages, query configs, its API, and version-aware system queries.", "developerName": "duyet", "category": "Monitoring", "capabilities": [ diff --git a/clickhouse-monitoring/.grok-plugin/plugin.json b/clickhouse-monitoring/.grok-plugin/plugin.json index 0d60921..7c69720 100644 --- a/clickhouse-monitoring/.grok-plugin/plugin.json +++ b/clickhouse-monitoring/.grok-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "clickhouse-monitoring", - "version": "1.1.1", - "description": "Agent Skill for the ClickHouse Monitor dashboard - a real-time monitoring and observability tool for ClickHouse clusters", + "version": "1.2.0", + "description": "Work on the ClickHouse Monitor dashboard: charts, pages, query configs, its API, and version-aware system queries.", "author": { "name": "duyet", "url": "https://github.com/duyet" diff --git a/clickhouse-monitoring/README.md b/clickhouse-monitoring/README.md index 07d735f..b88efda 100644 --- a/clickhouse-monitoring/README.md +++ b/clickhouse-monitoring/README.md @@ -1,152 +1,23 @@ -# ClickHouse Monitor Agent Skill +# clickhouse-monitoring -An [Agent Skill](https://agentskills.io) for the ClickHouse Monitor dashboard - a real-time monitoring and observability tool for ClickHouse clusters. +Skill for working on the ClickHouse Monitor dashboard: adding charts, pages, and query configs, calling its API, and writing version-aware system table queries. -## About +## Install -Agent Skills are folders of instructions, scripts, and resources that AI agents can discover and use to do things more accurately and efficiently. This skill provides specialized knowledge for: - -- **Dashboard navigation** - Overview, queries, tables, merges, metrics, security -- **Query monitoring** - Running queries, history, failures, expensive queries -- **Table management** - Data explorer, replicas, replication queue, projections -- **Merge operations** - Active merges, performance, mutations -- **System metrics** - CPU, memory, disk, connections, settings -- **API integration** - Chart data, table data, database explorer endpoints -- **Development** - Static site patterns, SWR fetching, query configs - -## Installation - -### Via Skills CLI - -Install using the skills CLI: - -```bash -npx skills add duyet/clickhouse-monitoring ``` - -### Manual Installation - -Clone this repository and copy the skill directory: - -```bash -git clone https://github.com/duyet/clickhouse-monitoring.git -cp -r clickhouse-monitoring ~/.agents/skills/ -``` - -### Local Development - -For local development or testing: - -```bash -# Mount the repository as a plugin -cc --plugin-dir /path/to/clickhouse-monitoring - -# Or copy to your skills directory -cp -r . ~/.agents/skills/clickhouse-monitoring +/plugin install clickhouse-monitoring@duyet-claude-plugins ``` -Restart your AI agent to load the skill after installation. - -## Usage - -Once installed, AI agents can use this skill when working with: - -- ClickHouse monitoring dashboards -- Query performance analysis -- Database schema exploration -- ClickHouse system table queries -- Dashboard feature development -- API integration with ClickHouse Monitor - -### Example Agent Prompts - -- "How do I monitor running ClickHouse queries?" -- "What API endpoints are available for chart data?" -- "Help me add a new chart to the dashboard" -- "Write a version-aware query for ClickHouse 24.3" -- "Explain the static site architecture" - -## Features - -### Dashboard Coverage +## What ships -| Category | Pages | -|----------|-------| -| **Queries** | Running, History, Failed, Expensive, Cache, Thread Analysis, Parallelization | -| **Tables** | Explorer, Overview, Replicas, Replication Queue, Projections, Dictionaries | -| **Merges** | Active Merges, Performance, Mutations, New Parts | -| **Monitoring** | Metrics, Async Metrics, Custom Dashboard, Profiler | -| **Security** | Sessions, Login Attempts, Audit Log | -| **Logs** | Text Log, Stack Traces, Crashes | -| **Cluster** | Clusters, ZooKeeper, Connections | -| **System** | Settings, MergeTree Settings, Disks | +- `skills/clickhouse-monitoring/SKILL.md`: architecture, SWR patterns, chart and query-config recipes, compatibility rules. +- `references/api-list.md` and `references/api-endpoints.md`: chart and table endpoints. +- `references/dashboard-pages.md`: every dashboard page. +- `references/development.md`: routing, data fetching, multi-host setup, troubleshooting. +- `references/clickhouse-compat.md`: version-aware queries and optional tables. -### API Documentation - -Complete reference for all `/api/v1/*` endpoints: - -- `/api/v1/charts/[name]` - Chart data with SWR caching -- `/api/v1/tables/[name]` - Table data with pagination -- `/api/v1/explorer/*` - Database explorer endpoints -- `/api/v1/hosts` - Multi-host configuration - -### Development Guide - -Patterns and conventions for contributing: - -- Static site architecture (client-side only) -- SWR data fetching patterns -- Adding routes, charts, and query configs -- Multi-host configuration -- Git commit conventions - -## Documentation - -| Document | Description | -|----------|-------------| -| [SKILL.md](SKILL.md) | Main skill file - quick reference and core patterns | -| [Complete API List](references/api-list.md) | All 58 charts and 63 table endpoints (auto-generated) | -| [Dashboard Pages](references/dashboard-pages.md) | All 45 dashboard pages (auto-generated) | -| [API Reference](references/api-endpoints.md) | Complete API documentation with examples | -| [Development Guide](references/development.md) | Architecture, patterns, contribution workflow | -| [ClickHouse Compatibility](references/clickhouse-compat.md) | Version-aware queries and schema handling | - -### Keeping Documentation Updated - -The API list and dashboard pages are automatically generated from the main codebase: - -```bash -bun run scripts/sync-docs.ts -``` - -This scans the main `clickhouse-monitor` repository's `lib/api/charts/` and `lib/query-config/` to extract all available endpoints. - -## Agent Skills Format - -This skill follows the [Agent Skills](https://agentskills.io) open standard originally developed by Anthropic. Skills in this format can be used across multiple agent products that support the standard. - -**Skill Structure:** -``` -clickhouse-monitoring/ -├── SKILL.md # Main skill file (YAML frontmatter + content) at root -├── README.md # This file - installation and overview -├── LICENSE # MIT License -├── scripts/ # Utility scripts -│ └── sync-docs.ts # Sync docs from main repository -└── references/ # Progressive disclosure docs - ├── api-list.md # Auto-generated API endpoints list - ├── dashboard-pages.md # Auto-generated dashboard pages - ├── api-endpoints.md # Complete API documentation with examples - ├── development.md # Architecture, patterns, contribution workflow - └── clickhouse-compat.md # Version-aware queries and schema handling -``` +Source project: https://github.com/duyet/clickhouse-monitor ## License MIT - -## Links - -- [ClickHouse Monitor (Main Repository)](https://github.com/duyet/clickhouse-monitor) - The actual monitoring dashboard application -- [Agent Skills Documentation](https://agentskills.io) -- [ClickHouse Documentation](https://clickhouse.com/docs) diff --git a/clickhouse-monitoring/references/api-endpoints.md b/clickhouse-monitoring/references/api-endpoints.md deleted file mode 100644 index 243c546..0000000 --- a/clickhouse-monitoring/references/api-endpoints.md +++ /dev/null @@ -1,445 +0,0 @@ -# API Endpoints Reference - -Complete reference for the ClickHouse Monitor API layer. All endpoints are prefixed with `/api/v1/`. - -## Overview - -The API provides: -- **Chart data** - Time-series metrics for visualizations -- **Table data** - Paginated query results with filtering -- **Explorer** - Database schema and metadata -- **Host management** - Multi-host configuration - -**Security Note**: API responses include raw SQL queries and database structure for debugging. Do not expose to public internet without authentication. - -## Authentication - -Currently uses hostId-based access control. Configure hosts via environment variables: - -```bash -CLICKHOUSE_HOST=host1.example.com,host2.example.com -CLICKHOUSE_USER=user1,user2 -CLICKHOUSE_PASSWORD=pass1,pass2 -``` - -The `hostId` parameter maps to these arrays (0 = first host, 1 = second, etc.). - -## Response Format - -All endpoints return a consistent `ApiResponse` structure: - -```typescript -interface ApiResponse { - success: boolean - data?: T - metadata: { - queryId: string // Unique execution identifier - duration: number // Duration in milliseconds - rows: number // Rows returned - host: string // Host that executed - clickhouseVersion?: string - cachedAt?: number // Timestamp if cached - status?: DataStatus // 'ok' | 'empty' | 'table_not_found' | etc. - statusMessage?: string - api?: string // Full endpoint URL - sql?: string // Executed SQL - params?: Record - } - error?: ApiError -} -``` - -## Chart Data API - -### GET /api/v1/charts/{name} - -Fetch time-series data for a specific chart. - -**Parameters:** -- `name` (path) - Chart name from registry -- `hostId` (query) - Host index (required) -- `interval` (query) - Time aggregation: `1m`, `1h`, `1d`, etc. -- `lastHours` (query) - Hours of historical data -- `params` (query) - Chart-specific parameters (JSON-encoded) - -**Example:** -```bash -curl "http://localhost:3000/api/v1/charts/query-count?hostId=0&interval=1h&lastHours=24" -``` - -**Response:** -```json -{ - "success": true, - "data": [ - { "ts": "2026-03-05T00:00:00Z", "value": 1234 }, - { "ts": "2026-03-05T01:00:00Z", "value": 1456 } - ], - "metadata": { - "queryId": "q_123456", - "duration": 45, - "rows": 24, - "host": "clickhouse.example.com", - "sql": "SELECT toStartOfTime(event_time) AS ts, COUNT() AS value FROM system.query_log WHERE event_time > now() - INTERVAL 24 HOUR GROUP BY ts ORDER BY ts" - } -} -``` - -### Available Chart Names - -**Query Monitoring:** -- `query-count` - Total query count over time -- `query-count-by-type` - Queries grouped by type (Select, Insert, etc.) -- `query-duration-p95` - 95th percentile query duration -- `query-duration-p99` - 99th percentile query duration -- `query-memory-usage` - Memory consumption by queries -- `query-read-rows` - Rows read by queries -- `query-written-rows` - Rows written by queries -- `query-cache-hit-rate` - Query cache effectiveness -- `expensive-query-count` - Count of expensive queries - -**Merge Operations:** -- `merge-count` - Merge operations over time -- `merge-by-reason` - Merges by reason (Regular, TTL, etc.) -- `merge-count-by-part-type` - Merges by part type -- `parts-merged-per-merge` - Average parts per merge -- `merge-rows-read-per-second` - Merge read throughput -- `merge-rows-write-per-second` - Merge write throughput -- `merge-by-table` - Merge count by table - -**System Metrics:** -- `cpu-usage` - CPU utilization percentage -- `memory-usage` - Memory consumption -- `disk-usage` - Disk space by database -- `network-bytes` - Network bytes transferred -- `connections-http` - HTTP connection count -- `connections-interserver` - Inter-server connection count - -**Replication:** -- `replication-lag-max` - Maximum replication lag -- `replication-queue-length` - Pending replication tasks -- `replica-has-delay` - Replicas with delays - -**ZooKeeper/Keeper:** -- `zookeeper-watch-count` - Active watches -- `zookeeper-outstanding-requests` - Outstanding requests - -## Table Data API - -### GET /api/v1/tables/{name} - -Fetch paginated table data for a query config. - -**Parameters:** -- `name` (path) - Query config name -- `hostId` (query) - Host index (required) -- `pageSize` (query) - Rows per page (default: 50) -- `page` (query) - Page number (default: 1) -- Additional parameters are passed as query params and substituted into SQL - -**Example:** -```bash -curl "http://localhost:3000/api/v1/tables/running-queries?hostId=0&pageSize=20&page=1" -``` - -**Response:** -```json -{ - "success": true, - "data": [ - { - "query_id": "abc-123", - "user": "admin", - "query": "SELECT * FROM system.tables", - "elapsed": 1.5, - "readable_elapsed": "1.5 seconds", - "pct_elapsed": 25.5 - } - ], - "metadata": { - "queryId": "t_789012", - "duration": 12, - "rows": 15, - "host": "clickhouse.example.com", - "table": "running-queries" - } -} -``` - -### Available Table Names - -**Query Monitoring:** -- `running-queries` - Currently executing queries -- `history-queries` - Query execution history -- `failed-queries` - Failed query log -- `common-errors` - Frequent error patterns -- `expensive-queries` - Resource-intensive queries -- `expensive-queries-by-memory` - High memory queries -- `query-cache` - Cache statistics -- `thread-analysis` - Thread-level query breakdown -- `parallelization` - Parallel execution effectiveness - -**Table Management:** -- `tables-overview` - Table storage statistics -- `replicas` - Replicated table status -- `replication-queue` - Pending replication tasks -- `readonly-tables` - Read-only table status -- `distributed-ddl-queue` - DDL task queue -- `top-usage-tables` - Most accessed tables -- `projections` - Projection definitions -- `view-refreshes` - Materialized view refreshes -- `part-info` - Active part details -- `dictionaries` - External dictionary status - -**Merges:** -- `merges` - Active merge operations -- `merge-performance` - Historical merge stats -- `mutations` - Mutation status - -**System:** -- `settings` - Server configuration -- `mergetree-settings` - MergeTree engine settings -- `disks` - Storage disk configuration -- `metrics` - Server metrics -- `asynchronous-metrics` - Background metrics -- `clusters` - Cluster information - -**Security:** -- `sessions` - User session history -- `login-attempts` - Authentication events - -**Operations:** -- `backups` - Backup history -- `errors` - Detailed error log -- `page-views` - Dashboard analytics - -**Explorer:** -- `explorer-databases` - Database list -- `explorer-tables` - Table list by database -- `explorer-columns` - Column metadata -- `explorer-ddl` - Table DDL -- `explorer-dependencies-downstream` - Downstream dependencies -- `explorer-dependencies-upstream` - Upstream dependencies -- `explorer-indexes` - Skip indexes -- `explorer-projections` - Projection metadata - -## Explorer API - -### GET /api/v1/explorer/databases - -List all databases. - -**Response:** -```json -{ - "success": true, - "data": ["default", "system", "information_schema"], - "metadata": { ... } -} -``` - -### GET /api/v1/explorer/tables - -List tables in a database. - -**Parameters:** -- `database` (query) - Database name - -### GET /api/v1/explorer/columns - -Get column metadata for a table. - -**Parameters:** -- `database` (query) - Database name -- `table` (query) - Table name - -### GET /api/v1/explorer/ddl - -Get CREATE TABLE statement. - -**Parameters:** -- `database` (query) - Database name -- `table` (query) - Table name - -### GET /api/v1/explorer/dependencies - -Get table dependencies (views, dictionaries, etc.). - -**Parameters:** -- `database` (query) - Database name -- `table` (query) - Table name -- `type` (query) - Dependency type: `all`, `upstream`, `downstream`, `table` - -**Example:** -```bash -curl "http://localhost:3000/api/v1/explorer/dependencies?database=default&table=my_table&type=all&hostId=0" -``` - -### GET /api/v1/explorer/projections - -Get projection definitions for a table. - -**Parameters:** -- `database` (query) - Database name -- `table` (query) - Table name - -### GET /api/v1/explorer/indexes - -Get skip index definitions for a table. - -**Parameters:** -- `database` (query) - Database name -- `table` (query) - Table name - -### GET /api/v1/explorer/preview - -Preview table data. - -**Parameters:** -- `database` (query) - Database name -- `table` (query) - Table name -- `limit` (query) - Max rows (default: 100) - -## Host Management - -### GET /api/v1/hosts - -List configured hosts. - -**Response:** -```json -{ - "success": true, - "data": [ - { - "id": 0, - "name": "Production", - "host": "clickhouse-prod.example.com" - }, - { - "id": 1, - "name": "Staging", - "host": "clickhouse-staging.example.com" - } - ], - "metadata": { ... } -} -``` - -### GET /api/v1/host-status - -Get connection status for a host. - -**Parameters:** -- `hostId` (query) - Host index - -**Response:** -```json -{ - "success": true, - "data": { - "connected": true, - "version": "24.3.1.1", - "timezone": "UTC" - }, - "metadata": { ... } -} -``` - -## Special Endpoints - -### POST /api/v1/actions - -Execute bulk actions on selected rows. - -**Request:** -```json -{ - "action": "kill-query", - "hostId": 0, - "keys": ["query-id-1", "query-id-2"] -} -``` - -**Available Actions:** -- `kill-query` - Terminate running queries -- `explain-query` - Get query execution plan -- `open-in-explorer` - Navigate to table in explorer - -### POST /api/v1/explain - -Get query execution plan. - -**Request:** -```json -{ - "query": "SELECT * FROM system.tables LIMIT 10", - "hostId": 0, - "type": "AST" // or "PLAN", "PIPELINE" -} -``` - -### GET /api/v1/menu-counts/{key} - -Get count badge for menu items. - -**Available Keys:** -- `running-queries` - Active query count -- `tables-overview` - Table count -- `merges` - Active merge count -- `replicas` - Replica count -- `dictionaries` - Dictionary count - -## Error Handling - -### Error Types - -```typescript -enum ApiErrorType { - TableNotFound = 'table_not_found', - ValidationError = 'validation_error', - QueryError = 'query_error', - NetworkError = 'network_error', - PermissionError = 'permission_error' -} -``` - -### Error Response - -```json -{ - "success": false, - "error": { - "type": "table_not_found", - "message": "Table system.backup_log does not exist", - "details": { - "table": "system.backup_log", - "suggestion": "Enable backup logging to see backup history" - } - }, - "metadata": { - "status": "table_not_found", - "statusMessage": "The backup_log table is not configured" - } -} -``` - -### Data Status Values - -- `ok` - Data returned successfully -- `empty` - Query succeeded but no data -- `table_not_configured` - Required log table not enabled -- `table_not_found` - Table does not exist -- `table_empty` - Table exists but contains no data - -## Caching - -The API uses SWR (stale-while-revalidate) caching on the client: -- Charts refresh every 5 minutes by default -- Manual refresh available via UI -- Stale data displayed with indicator during revalidation - -## See Also - -- [Development Guide](development.md) - API integration patterns -- [ClickHouse Compatibility](clickhouse-compat.md) - Query version handling diff --git a/clickhouse-monitoring/references/api-list.md b/clickhouse-monitoring/references/api-list.md deleted file mode 100644 index a2147db..0000000 --- a/clickhouse-monitoring/references/api-list.md +++ /dev/null @@ -1,168 +0,0 @@ -# API Reference - -This section lists all available API endpoints. Auto-generated from codebase. - -## Chart Data Endpoints - -All chart endpoints follow this pattern: - -```http -GET /api/v1/charts/{chartName}?hostId={hostId}&interval={interval}&lastHours={hours} -``` - -### Available Charts (58 total) - -- `active-sessions-count` -- `backup-size` -- `connections-http` -- `connections-interserver` -- `cpu-time-per-thread` -- `cpu-usage` -- `crash-frequency` -- `dashboard-charts` -- `dashboard-settings` -- `database-count` -- `dictionary-count` -- `disk-size` -- `disk-size-single` -- `disks-usage` -- `error-rate-over-time` -- `failed-login-by-user` -- `failed-query-count` -- `failed-query-count-by-user` -- `human-vs-bot-pageviews` -- `log-count-today` -- `log-level-distribution` -- `login-success-rate` -- `memory-usage` -- `merge-avg-duration` -- `merge-count` -- `merge-sum-read-rows` -- `new-parts-created` -- `page-view` -- `pageviews-by-country` -- `pageviews-by-device` -- `parallelization-efficiency` -- `query-cache` -- `query-cache-usage` -- `query-count` -- `query-count-by-user` -- `query-count-today` -- `query-duration` -- `query-memory` -- `query-type` -- `readonly-replica` -- `replication-lag` -- `replication-queue-count` -- `replication-summary-table` -- `running-queries-count` -- `sessions-by-auth-type` -- `sessions-by-interface` -- `summary-used-by-merges` -- `summary-used-by-mutations` -- `summary-used-by-running-queries` -- `table-count` -- `thread-utilization` -- `top-pages` -- `top-table-size` -- `zookeeper-exception` -- `zookeeper-requests` -- `zookeeper-summary-table` -- `zookeeper-uptime` -- `zookeeper-wait` - -## Table Data Endpoints - -All table endpoints follow this pattern: - -```http -GET /api/v1/tables/{queryConfigName}?hostId={hostId}&pageSize={n}&page={p} -``` - -### Available Table Queries (63 total) - -- `asynchronous-metrics` -- `backups` -- `clusters` -- `clusters-replicas-status` -- `common-errors` -- `count-across-replicas` -- `crash-log` -- `database-disk-space` -- `database-disk-space-by-database` -- `database-table-columns` -- `detached-parts` -- `dictionaries` -- `disk-space` -- `distributed-ddl-queue` -- `errors` -- `expensive-queries` -- `expensive-queries-by-memory` -- `explorer-all-dependencies` -- `explorer-columns` -- `explorer-database-dependencies` -- `explorer-databases` -- `explorer-ddl` -- `explorer-dependencies-downstream` -- `explorer-dependencies-upstream` -- `explorer-dictionary-source` -- `explorer-indexes` -- `explorer-projections` -- `explorer-table-dependencies` -- `explorer-tables` -- `failed-queries` -- `history-queries` -- `login-attempts` -- `merge-performance` -- `merge-tree-settings` -- `merges` -- `metrics` -- `mutations` -- `page-view` -- `page-views` -- `parallelization` -- `part-info` -- `profiler` -- `projections` -- `query-cache` -- `query-detail` -- `read-only-tables` -- `replica-tables` -- `replicas` -- `replication-queue` -- `roles` -- `running-queries` -- `sessions` -- `settings` -- `stack-traces` -- `tables-list` -- `tables-overview` -- `text-log` -- `thread-analysis` -- `top-usage-columns` -- `top-usage-tables` -- `users` -- `view-refreshes` -- `zookeeper` - -## Explorer Endpoints - -```http -GET /api/v1/explorer/databases?hostId={hostId} -GET /api/v1/explorer/tables?hostId={hostId}&database={db} -GET /api/v1/explorer/columns?hostId={hostId}&database={db}&table={t} -GET /api/v1/explorer/dependencies?hostId={hostId}&database={db}&table={t} -GET /api/v1/explorer/ddl?hostId={hostId}&database={db}&table={t} -GET /api/v1/explorer/projections?hostId={hostId}&database={db}&table={t} -GET /api/v1/explorer/indexes?hostId={hostId}&database={db}&table={t} -GET /api/v1/explorer/dictionary-source?hostId={hostId} -``` - -## System Endpoints - -```http -GET /api/v1/hosts # List configured ClickHouse hosts -``` - ---- -*Generated by `scripts/sync-docs.ts` from 2026-03-04T18:39:36.924Z* diff --git a/clickhouse-monitoring/references/clickhouse-compat.md b/clickhouse-monitoring/references/clickhouse-compat.md deleted file mode 100644 index 8808dfa..0000000 --- a/clickhouse-monitoring/references/clickhouse-compat.md +++ /dev/null @@ -1,433 +0,0 @@ -# ClickHouse Compatibility Guide - -Patterns for writing version-aware queries that work across different ClickHouse versions. - -## Overview - -ClickHouse system tables change between versions. Columns are added, removed, or renamed. The dashboard uses **version-aware queries** to handle these changes gracefully. - -## VersionedSql Pattern - -### Basic Syntax - -```typescript -sql: [ - { since: '23.8', sql: 'SELECT col1 FROM system.table' }, - { since: '24.1', sql: 'SELECT col1, col2 FROM system.table' }, - { since: '24.3', sql: 'SELECT col1, col2, col3 FROM system.table' }, -] -``` - -**Rules:** -- Queries are ordered **chronologically** (oldest → newest) -- System selects the **highest `since` version ≤ current version** -- For CH v24.5 → selects `24.3` query (highest ≤ 24.5) -- For CH v23.5 → selects `23.8` query (fallback to oldest) - -### Example: Adding a New Column - -In ClickHouse 24.3, `system.query_log` added a new column `disk_usage`. - -```typescript -export const queryConfig: QueryConfig = { - name: 'query-with-disk', - sql: [ - { - since: '23.8', - sql: ` - SELECT - query_id, - user, - query - FROM system.query_log - `, - columns: ['query_id', 'user', 'query'], - }, - { - since: '24.3', - sql: ` - SELECT - query_id, - user, - query, - disk_usage - FROM system.query_log - `, - columns: ['query_id', 'user', 'query', 'disk_usage'], - }, - ], - columns: ['query_id', 'user', 'query', 'disk_usage'], -} -``` - -### Example: Type Changes - -Some columns changed from `Int8` to `Enum` between versions. - -```typescript -// system.part_log.event_type changed from Int8 to Enum in v24.3 -export const mergesConfig: QueryConfig = { - name: 'merges', - sql: ` - SELECT * - FROM merge('system', '^part_log') - WHERE toInt8(event_type) = 2 -- MergeParts (works for both Int8 and Enum) - AND toInt8(merge_reason) = 1 -- RegularMerge - `, - columns: ['event_time', 'event_type', 'merge_reason', 'database', 'table'], -} -``` - -**Known event_type values:** -- 1 = NewPart -- 2 = MergeParts -- 3 = DownloadPart -- 4 = RemovePart -- 5 = MutatePart -- 6 = MovePart - -**Known merge_reason values:** -- 1 = RegularMerge -- 2 = TTLDeleteMerge -- 3 = TTLRecompressMerge - -## Schema Documentation - -### Available Schemas - -The project includes ClickHouse schema documentation per version: - -``` -docs/clickhouse-schemas/ -├── v23.8.md -├── v24.1.md -├── v24.3.md -├── v24.5.md -├── v24.6.md -├── v24.7.md -├── v24.8.md -├── v24.9.md -├── v24.10.md -├── v24.11.md -├── v24.12.md -└── tables/ - ├── query_log.md - ├── part_log.md - ├── processes.md - └── ... -``` - -### Table Documentation - -Each table has a markdown file documenting: -- Table purpose and requirements -- Column availability by version -- Query examples - -**Example: `tables/query_log.md`** -```markdown -# system.query_log - -## Purpose -Logs all queries executed on the server. - -## Requirements -Must be enabled in ClickHouse config: - -```xml - - system - query_log
- 1 -
-``` - -## Columns - -| Column | Since | Type | Description | -|--------|-------|------|-------------| -| event_date | all | Date | Event date | -| event_time | all | DateTime | Event time | -| query_id | all | String | Query ID | -| query | all | String | Query text | -| disk_usage | 24.3 | UInt64 | Disk usage | -``` - -### Regenerating Schema Docs - -To regenerate schema documentation after adding a new version: - -```bash -bun run scripts/build-ch-schema-docs.ts -``` - -## Optional Tables - -Some tables may not exist depending on ClickHouse configuration: - -### Optional Tables List - -| Table | When Available | -|-------|----------------| -| `system.backup_log` | Only when backup is configured | -| `system.error_log` | Requires error logging configuration | -| `system.zookeeper` | Only with ZooKeeper/Keeper enabled | -| `system.monitoring_events` | Custom table created by monitoring app | - -### Marking Queries as Optional - -```typescript -export const backupsConfig: QueryConfig = { - name: 'backups', - optional: true, // Don't error if table doesn't exist - tableCheck: 'system.backup_log', // Explicit table to check - sql: 'SELECT * FROM system.backup_log', - columns: ['name', 'status', 'start_time'], - suggestion: ` - Enable backup logging to see backup history. - - See: https://clickhouse.com/docs/en/operations/backup - `, -} -``` - -### Automatic Table Detection - -If `tableCheck` is not provided, the system automatically extracts table names from the SQL query. - -**Handles:** -- Direct table access: `SELECT * FROM system.tables` -- JOINs: `FROM system.tables AS t JOIN system.columns AS c` -- Subqueries: `WHERE database IN (SELECT database FROM system.databases)` -- CTEs: `WITH tables AS (SELECT * FROM system.tables)` -- EXISTS clauses: `WHERE EXISTS (SELECT 1 FROM system.parts)` - -### Graceful Error Handling - -When an optional table doesn't exist: - -```json -{ - "success": false, - "error": { - "type": "table_not_found", - "message": "Table system.backup_log does not exist" - }, - "metadata": { - "status": "table_not_found", - "statusMessage": "Backup logging is not configured", - "missingTables": ["system.backup_log"] - } -} -``` - -## BackgroundBar Column Format - -For charts and tables with background progress bars, provide **three SQL columns**: - -### Pattern - -```typescript -sql: ` - SELECT - rows, -- Base value - formatReadableQuantity(rows) AS readable_rows, -- Display text - round(rows * 100.0 / max(rows) OVER (), 2) AS pct_rows -- Percentage - FROM system.parts -`, -columns: [ - 'rows', -- Base column (number) - 'readable_rows', -- Readable format (string) - 'pct_rows', -- Percentage (0-100) -] -``` - -### Naming Convention - -``` -{column} → Base value (number) -readable_{column} → Human-readable format -pct_{column} → Percentage for progress bar -``` - -### Examples - -**Disk usage:** -```sql -disk_size, -formatReadableSize(disk_size) AS readable_disk_size, -round(disk_size * 100.0 / max(disk_size) OVER (), 2) AS pct_disk_size -``` - -**Memory usage:** -```sql -memory_usage, -formatReadableSize(memory_usage) AS readable_memory_usage, -round(memory_usage * 100.0 / max(memory_usage) OVER (), 2) AS pct_memory_usage -``` - -**Elapsed time:** -```sql -elapsed, -formatReadableTimeDelta(elapsed) AS readable_elapsed, -round(elapsed * 100.0 / max(elapsed) OVER (), 2) AS pct_elapsed -``` - -### Using in Column Formats - -```typescript -columnFormats: { - readable_rows: ColumnFormat.BackgroundBar, // Uses pct_rows for bar -} -``` - -## Cross-Version Cluster Queries - -### merge() Function - -For cluster-wide queries, use `merge('system', '^table_name')`: - -```typescript -sql: ` - SELECT * - FROM merge('system', '^part_log') - WHERE toInt8(event_type) = 2 -` -``` - -**This aggregates data from:** -- `system.part_log` (local) -- `system.part_log_1`, `system.part_log_2`, etc. (replicated) - -### Schema Compatibility Issues - -When using `merge()` across shards with different ClickHouse versions: - -```typescript -// Bad: Fails when shards have different schemas -sql: ` - SELECT event_type - FROM merge('system', '^part_log') - WHERE event_type = 2 -- Fails if event_type is Enum on some shards -` - -// Good: Use toInt8() for compatibility -sql: ` - SELECT event_type - FROM merge('system', '^part_log') - WHERE toInt8(event_type) = 2 -- Works for both Int8 and Enum -` -``` - -## Version Detection - -The dashboard automatically detects ClickHouse version on first connection: - -```typescript -// From lib/clickhouse.ts -const version = await client.query({ - query: 'SELECT version() AS v', - format: 'JSONEachRow', -}) -// Returns: "24.3.1.1" -``` - -This version is cached and used to select appropriate queries from `VersionedSql[]`. - -## Best Practices - -### 1. Always Check Schema Docs - -Before writing queries, check `docs/clickhouse-schemas/tables/{table}.md` for: -- Column availability by version -- Type changes -- Query requirements - -### 2. Use toInt8() for Enums - -When filtering on columns that might be Enum or Int8: -```sql -WHERE toInt8(event_type) = 2 -``` - -### 3. Provide Helpful Suggestions - -For optional tables, include setup instructions: -```typescript -suggestion: ` - Enable query logging: - - SET log_queries = 1; - SET log_queries_min_type = 'QueryFinish'; - - See: https://clickhouse.com/docs/en/operations/query-log -` -``` - -### 4. Test Against Multiple Versions - -Test queries against: -- Oldest supported version (23.8) -- Latest stable version -- Development version - -### 5. Document Breaking Changes - -When adding a new `VersionedSql`, document what changed: -```typescript -{ - since: '24.3', - description: 'Added disk_usage column', - sql: 'SELECT query_id, disk_usage FROM system.query_log', -} -``` - -## Common Patterns - -### New Column Added - -```typescript -sql: [ - { since: '23.8', sql: 'SELECT col1 FROM t' }, - { since: '24.3', sql: 'SELECT col1, col2 FROM t' }, // col2 added -] -``` - -### Column Type Changed - -```typescript -sql: ` - SELECT toInt8(event_type) AS type -- Works for Int8 and Enum - FROM system.part_log -` -``` - -### Table Renamed/Moved - -```typescript -sql: [ - { since: '23.8', sql: 'SELECT * FROM system.old_table' }, - { since: '24.1', sql: 'SELECT * FROM system.new_table' }, -] -``` - -### Query Pattern Changed - -```typescript -sql: [ - { - since: '23.8', - sql: 'SELECT count() FROM system.metrics WHERE name = "Query"', - }, - { - since: '24.3', - sql: 'SELECT sum(value) FROM system.metrics WHERE name LIKE "%Query%"', - }, -] -``` - -## See Also - -- [API Endpoints Reference](api-endpoints.md) - Using queries in API -- [Development Guide](development.md) - Adding query configs -- [Schema Documentation](../docs/clickhouse-schemas/) - Complete column reference diff --git a/clickhouse-monitoring/references/dashboard-pages.md b/clickhouse-monitoring/references/dashboard-pages.md deleted file mode 100644 index c5e25f0..0000000 --- a/clickhouse-monitoring/references/dashboard-pages.md +++ /dev/null @@ -1,54 +0,0 @@ -# Dashboard Pages - -Complete list of all dashboard pages (45 total). - -| Page | Path | Description | -|------|------|-------------| -| **Overview** | `/overview` | Real-time view of currently executing queries with progress tracking | -| **History Queries** | `/history-queries` | Historical query log with execution metrics, memory usage, and performance data | -| **Failed Queries** | `/failed-queries` | Query execution failures with error details and stack traces | -| **Recent Errors** | `/common-errors` | Most frequently occurring errors with timestamps and error messages | -| **Most Expensive Queries** | `/expensive-queries` | Resource-intensive queries ranked by CPU, memory, and duration | -| **Expensive by Memory** | `/expensive-queries-by-memory` | Queries with highest memory consumption for optimization | -| **Explain** | `/explain` | Query execution plan analysis for performance tuning | -| **Query Cache** | `/query-cache` | Cache hit/miss statistics and performance impact | -| **Thread Analysis** | `/queries/thread-analysis` | Thread-level query performance breakdown and parallelization | -| **Parallelization** | `/queries/parallelization` | Parallel query execution effectiveness and thread utilization | -| **Tables** | `/tables` | Interactive database schema browser with metadata | -| **Tables Overview** | `/tables-overview` | Table storage statistics with part counts and sizes | -| **DDL Queue** | `/distributed-ddl-queue` | Cluster-wide DDL task queue status and execution history | -| **Table Replicas** | `/replicas` | Replicated table health status and lag metrics | -| **Replication Queue** | `/replication-queue` | Pending and in-progress replication tasks from Keeper/ZooKeeper | -| **Readonly Tables** | `/readonly-tables` | Tables in read-only mode with replica status | -| **Top Usage Tables** | `/top-usage-tables` | Table access frequency for identifying hot data | -| **Projections** | `/projections` | Projection definitions and usage statistics | -| **View Refreshes** | `/view-refreshes` | Materialized view refresh schedules and execution history | -| **Part Info** | `/part-info` | Active part details with levels and sizes | -| **Dictionaries** | `/dictionaries` | External dictionary status and memory usage | -| **Merges** | `/merges` | Active merge and mutation operations with progress | -| **Merge Performance** | `/merge-performance` | Historical merge operation statistics and trends | -| **Mutations** | `/mutations` | Table mutation status with progress and failures | -| **Monitoring** | `/metrics` | Real-time server metrics and counters | -| **Async Metrics** | `/asynchronous-metrics` | Background-calculated metrics for resource monitoring | -| **Custom Dashboard** | `/dashboard` | Build custom monitoring dashboards with charts | -| **Profiler** | `/profiler` | CPU profiling data for query performance analysis | -| **Security** | `/security/sessions` | User session history with authentication details | -| **Login Attempts** | `/security/login-attempts` | Authentication events with failure reasons | -| **Audit Log** | `/security/audit-log` | Security-related events and access control | -| **Logs** | `/logs/text-log` | Server logs with query context and stack traces | -| **Stack Traces** | `/logs/stack-traces` | Live thread stack traces for debugging | -| **Crashes** | `/logs/crashes` | Historical crash reports with diagnostics | -| **System** | `/settings` | Server configuration settings and current values | -| **MergeTree Settings** | `/mergetree-settings` | MergeTree engine-specific settings | -| **Disks** | `/disks` | Storage disk configuration and usage | -| **Cluster** | `/clusters` | Cluster configuration and member information | -| **Zookeeper** | `/zookeeper?path=/` | ZooKeeper/Keeper data browser for distributed coordination | -| **Operations** | `/backups` | Backup operation history with status and sizes | -| **Errors** | `/errors` | Detailed error events with stack traces | -| **Page Views** | `/page-views` | Dashboard usage analytics | -| **About** | `/about` | Dashboard and server version information | -| **Queries** | `/running-queries` | | -| **Data Explorer** | `/explorer` | | - ---- -*Generated by `scripts/sync-docs.ts` from 2026-03-04T18:39:36.926Z* diff --git a/clickhouse-monitoring/references/development.md b/clickhouse-monitoring/references/development.md deleted file mode 100644 index 963bae6..0000000 --- a/clickhouse-monitoring/references/development.md +++ /dev/null @@ -1,513 +0,0 @@ -# Development Guide - -Patterns and conventions for contributing to the ClickHouse Monitor dashboard. - -## Architecture Overview - -### Static Site Design - -**Critical**: This is a **fully static site** with no server-side rendering. All pages use client-side data fetching via SWR. - -**Implications:** -- No `use server()` directives -- No `redirect()` from next/navigation - use `useRouter` + `useEffect` -- All data fetching happens client-side -- Better CDN caching and edge deployment - -### Routing Pattern - -**Old (Don't Use):** -``` -app/[host]/overview/page.tsx → Dynamic route -URL: /0/overview -``` - -**New (Use This):** -``` -app/overview/page.tsx → Static route -URL: /overview?host=0 -``` - -**Benefits:** -- Faster initial page load (static shell pre-rendered) -- Better CDN caching -- Simpler deployment -- Progressive data loading - -### Project Structure - -``` -app/ -├── api/v1/ # API routes for data fetching -│ ├── data/ # Generic query endpoint -│ ├── charts/[name]/ # Chart-specific data -│ ├── tables/[name]/ # Table data with pagination -│ ├── explorer/ # Data explorer API -│ └── hosts/ # Host configuration -├── overview/ # Static pages with ?host= query param -├── dashboard/ -├── explorer/ -└── running-queries/ - -components/ -├── data-table/ # Advanced table system -├── charts/ # Chart components (32+) -├── overview-charts/ # Overview page charts -└── ui/ # shadcn/ui components (DO NOT MODIFY) - -lib/ -├── api/ -│ ├── types.ts # API request/response types -│ ├── chart-registry.ts # Chart query registry -│ └── table-registry.ts # Table query registry -├── swr/ -│ ├── provider.tsx # SWR configuration -│ ├── use-host.ts # Extract hostId from query params -│ ├── use-chart-data.ts # Chart data fetching -│ └── use-table-data.ts # Table data fetching -├── query-config/ # Centralized query configurations -├── clickhouse.ts # ClickHouse client -└── charts/ # Chart query definitions -``` - -## SWR Data Fetching Pattern - -### The Standard Pattern - -**All client components that fetch data follow this pattern:** - -```typescript -'use client' -import { Suspense } from 'react' -import { useHostId } from '@/lib/swr' -import { ChartSkeleton } from '@/components/skeletons' -import { YourChart } from '@/components/charts/your-chart' - -export default function YourPage() { - const hostId = useHostId() // Extracts ?host= from URL - - return ( - }> - - - ) -} -``` - -### Chart Component Template - -```typescript -'use client' -import useSWR from 'swr' -import { useChartData } from '@/lib/swr/use-chart-data' -import { ChartSkeleton } from '@/components/skeletons' -import { ChartError } from '@/components/error-alert' - -interface YourChartProps { - hostId: number - interval?: number -} - -export function YourChart({ hostId, interval = 300000 }: YourChartProps) { - const { data, error, isLoading } = useChartData({ - name: 'your-chart-name', - hostId, - interval, - }) - - if (isLoading) return - if (error) return - if (!data || data.length === 0) return
No data available
- - // Render chart using recharts, tremor, or custom - return
{/* Chart rendering */}
-} -``` - -### useChartData Hook - -```typescript -const { data, error, isLoading } = useChartData({ - name: 'chart-name', // From chart registry - hostId: 0, // Required - interval: 300000, // Refresh interval (ms) - lastHours: 24, // For historical charts - params: { // Optional chart params - database: 'default', - }, -}) -``` - -### useTableData Hook - -```typescript -const { data, error, isLoading } = useTableData({ - queryConfigName: 'running-queries', - hostId: 0, - searchParams: { - pageSize: '50', - page: '1', - }, -}) -``` - -## Adding a New Route - -### Step 1: Create Page Component - -Create `app/your-route/page.tsx`: - -```typescript -'use client' - -import { Suspense } from 'react' -import { useHostId } from '@/lib/swr' -import { ChartSkeleton, TableSkeleton } from '@/components/skeletons' -import { RelatedCharts, Table } from '@/components' - -export default function YourRoutePage() { - const hostId = useHostId() - - return ( -
- }> - - - }> - - - - ) -} -``` - -### Step 2: Add Menu Item - -Edit `menu.ts`: - -```typescript -{ - title: 'Your Route', - href: '/your-route', - description: 'Your route description', - icon: YourIcon, - countKey: 'your-count', - countLabel: 'items', -} -``` - -### Step 3: Create Query Config (if needed) - -Add to `lib/query-config/`: - -```typescript -export const yourConfig: QueryConfig = { - name: 'your-query', - description: 'Query description', - sql: 'SELECT database, table FROM system.parts', - columns: ['database', 'table'], - columnFormats: { - database: ColumnFormat.Badge, - table: ColumnFormat.Text, - }, -} -``` - -## Adding a New Chart - -### Step 1: Define Chart Query - -Add to `lib/api/charts/your-domain-charts.ts`: - -```typescript -export const yourChart: ChartQueryBuilder = (params) => { - const lastHours = params.lastHours || 24 - - return { - sql: ` - SELECT - toStartOfInterval(event_time, INTERVAL 1 hour) AS ts, - COUNT() AS value - FROM system.query_log - WHERE event_time > now() - INTERVAL ${lastHours} HOUR - GROUP BY ts - ORDER BY ts - `, - columns: ['ts', 'value'], - } -} - -export const yourCharts = { - 'your-chart-name': yourChart, -} -``` - -### Step 2: Register Chart - -Add to `lib/api/chart-registry.ts`: - -```typescript -import { yourCharts } from './charts/your-domain-charts' - -export const chartRegistry = { - // ... - ...yourCharts, -} -``` - -### Step 3: Create Chart Component - -Create `components/charts/your-chart.tsx`: - -```typescript -'use client' -import { useChartData } from '@/lib/swr/use-chart-data' -import { ChartSkeleton } from '@/components/skeletons' -import { ChartError } from '@/components/error-alert' -import { AreaChart } from '@/components/charts/area-chart' - -export function YourChart({ hostId, interval, lastHours }: YourChartProps) { - const { data, error, isLoading } = useChartData({ - name: 'your-chart-name', - hostId, - interval, - lastHours, - }) - - if (isLoading) return - if (error) return - if (!data || data.length === 0) return
No data
- - return -} -``` - -## Multi-Host Configuration - -### Environment Variables - -Configure in `.env.local`: - -```bash -# Comma-separated lists (same length) -CLICKHOUSE_HOST=prod.example.com,staging.example.com -CLICKHOUSE_USER=admin,readonly -CLICKHOUSE_PASSWORD=secret123,readonly456 -CLICKHOUSE_NAME="Production,Staging" -``` - -### Accessing Host ID - -```typescript -import { useHostId } from '@/lib/swr' - -function YourComponent() { - const hostId = useHostId() // Extracts from ?host= query param - - // URL: /overview?host=1 → hostId = 1 (Staging) - // URL: /overview?host=0 → hostId = 0 (Production) -} -``` - -### ClickHouse Client with Host ID - -```typescript -import { createClient } from '@clickhouse/client-web' -import { getClickHouseConfig } from '@/lib/clickhouse' - -const hostId = 0 -const client = createClient(getClickHouseConfig(hostId)) -``` - -## Code Conventions - -### Git Commit Format - -Follow semantic commit format with consistent scope: - -``` -feat(scope): description -fix(scope): description -chore(deps): description -refactor(ui): description -docs(api): description -test(unit): description -``` - -**Always include co-authorship:** -``` -Co-Authored-By: duyetbot -``` - -**Examples:** -``` -feat(queries): add thread analysis chart -fix(ui): correct chart loading state -chore(deps): upgrade React to 19 -docs(api): document streaming endpoint -``` - -### Component Patterns - -**Hooks at deepest consumer:** -```typescript -// Bad: Prop drilling hostId -function Nav({ hostId }: { hostId: number }) { - return -} - -// Good: Hook at deepest consumer -function Nav() { - return -} - -function MenuItem() { - const hostId = useHostId() // Call where needed - return Overview -} -``` - -**Client Components:** -- Always add `'use client'` directive -- Use Suspense for loading states -- Handle errors gracefully - -**Server Components:** -- Don't use `'use client'` (default in Next.js) -- Keep mostly static (no data fetching) -- For this project: Most pages are client components - -### shadcn/ui Components - -**DO NOT modify** `components/ui/` files directly. These are installed via CLI and should remain in original state. - -**If you need custom styling:** -```typescript -// Good: Custom classes at usage site - - ... - - -// Bad: Modifying components/ui/card.tsx -``` - -**For reusable custom variants:** -```typescript -// Create wrapper in components/ (not components/ui/) -// components/info-badge.tsx -import { Badge } from '@/components/ui/badge' -import { cn } from '@/lib/utils' - -export function InfoBadge({ className, ...props }) { - return ( - -} - -interface QueryConfig { - name: string - description?: string -} - -/** - * Recursively find all files matching a pattern - */ -function findFiles(dir: string, pattern: RegExp): string[] { - const { readdirSync, statSync } = require('fs') - const files: string[] = [] - - function traverse(currentPath: string) { - const entries = readdirSync(currentPath) - - for (const entry of entries) { - const fullPath = join(currentPath, entry) - const stat = statSync(fullPath) - - if (stat.isDirectory()) { - // Skip node_modules and hidden directories - if (!entry.startsWith('.') && entry !== 'node_modules') { - traverse(fullPath) - } - } else if (stat.isFile() && pattern.test(entry)) { - files.push(fullPath) - } - } - } - - traverse(dir) - return files -} - -/** - * Extract chart names from domain chart modules - */ -function extractChartNames(): string[] { - const chartFiles = findFiles( - join(MAIN_REPO, 'lib/api/charts'), - /-charts\.ts$/ - ) - - const allCharts: Set = new Set() - - for (const filePath of chartFiles) { - try { - const content = readFileSync(filePath, 'utf-8') - - // Extract chart names from export const xxxCharts = { ... } - // Pattern: 'chart-name': ({ ... }) => ({ - const chartRegex = /'([^']+)':\s*\(/g - let match - while ((match = chartRegex.exec(content)) !== null) { - allCharts.add(match[1]) - } - } catch (e) { - console.warn(`Could not read ${filePath}:`, (e as Error).message) - } - } - - return Array.from(allCharts).sort() -} - -/** - * Extract query config names from query-config files - */ -function extractQueryConfigNames(): string[] { - const queryFiles = findFiles(join(MAIN_REPO, 'lib/query-config'), /\.ts$/) - - const configs: Set = new Set() - - for (const filePath of queryFiles) { - try { - const content = readFileSync(filePath, 'utf-8') - - // Extract config name: export const xxxConfig: QueryConfig = { - const configRegex = /export\s+const\s+(\w+)Config:\s*QueryConfig/g - let match - while ((match = configRegex.exec(content)) !== null) { - const name = match[1] - .replace(/([A-Z])/g, '-$1') - .toLowerCase() - .replace(/^-/, '') - configs.add(name) - } - } catch (e) { - console.warn(`Could not read ${filePath}:`, (e as Error).message) - } - } - - return Array.from(configs).sort() -} - -/** - * Generate API reference section - */ -function generateAPIReference( - chartNames: string[], - queryNames: string[] -): string { - return `# API Reference - -This section lists all available API endpoints. Auto-generated from codebase. - -## Chart Data Endpoints - -All chart endpoints follow this pattern: - -\`\`\`http -GET /api/v1/charts/{chartName}?hostId={hostId}&interval={interval}&lastHours={hours} -\`\`\` - -### Available Charts (${chartNames.length} total) - -${chartNames.map((name) => `- \`${name}\``).join('\n')} - -## Table Data Endpoints - -All table endpoints follow this pattern: - -\`\`\`http -GET /api/v1/tables/{queryConfigName}?hostId={hostId}&pageSize={n}&page={p} -\`\`\` - -### Available Table Queries (${queryNames.length} total) - -${queryNames.map((name) => `- \`${name}\``).join('\n')} - -## Explorer Endpoints - -\`\`\`http -GET /api/v1/explorer/databases?hostId={hostId} -GET /api/v1/explorer/tables?hostId={hostId}&database={db} -GET /api/v1/explorer/columns?hostId={hostId}&database={db}&table={t} -GET /api/v1/explorer/dependencies?hostId={hostId}&database={db}&table={t} -GET /api/v1/explorer/ddl?hostId={hostId}&database={db}&table={t} -GET /api/v1/explorer/projections?hostId={hostId}&database={db}&table={t} -GET /api/v1/explorer/indexes?hostId={hostId}&database={db}&table={t} -GET /api/v1/explorer/dictionary-source?hostId={hostId} -\`\`\` - -## System Endpoints - -\`\`\`http -GET /api/v1/hosts # List configured ClickHouse hosts -\`\`\` - ---- -*Generated by \`scripts/sync-docs.ts\` from ${new Date().toISOString()}* -` -} - -/** - * Generate dashboard pages reference - */ -function generateDashboardPages(): string { - // Read menu.ts to extract page structure - const menuPath = join(MAIN_REPO, 'menu.ts') - const menuContent = readFileSync(menuPath, 'utf-8') - - // Parse menu items using a more robust approach - // Look for objects with title, href, description properties - const itemRegex = - /{\s*title:\s*['"]([^'"]+)['"][\s\S]*?href:\s*['"]([^'"]+)['"][\s\S]*?description:\s*['"]([^'"]+)['"]/g - - const pages: Array<{ title: string; href: string; description: string }> = [] - - let match - while ((match = itemRegex.exec(menuContent)) !== null) { - pages.push({ - title: match[1], - href: match[2], - description: match[3], - }) - } - - // Also look for simpler items without description - const simpleRegex = - /{\s*title:\s*['"]([^'"]+)['"][\s\S]*?href:\s*['"]([^'"]+)['"]/g - while ((match = simpleRegex.exec(menuContent)) !== null) { - // Skip if already added - if (!pages.some((p) => p.title === match[1] && p.href === match[2])) { - pages.push({ - title: match[1], - href: match[2], - description: '', - }) - } - } - - // Filter out parent items (empty href or query-only href) - const leafPages = pages.filter( - (p) => p.href && p.href !== '' && !p.href.includes('?name=') - ) - - return `# Dashboard Pages - -Complete list of all dashboard pages (${leafPages.length} total). - -| Page | Path | Description | -|------|------|-------------| -${leafPages - .map( - (page) => - `| **${page.title}** | \`${page.href || '/'}\` | ${page.description} |` - ) - .join('\n')} - ---- -*Generated by \`scripts/sync-docs.ts\` from ${new Date().toISOString()}* -` -} - -/** - * Main execution - */ -function main() { - console.log('🔍 Scanning main codebase for API endpoints...') - console.log(` Main repo: ${MAIN_REPO}`) - console.log(` Skill repo: ${SKILL_ROOT}`) - - const chartNames = extractChartNames() - console.log(` Found ${chartNames.length} chart endpoints`) - - const queryNames = extractQueryConfigNames() - console.log(` Found ${queryNames.length} table query endpoints`) - - // Generate API reference - const apiReference = generateAPIReference(chartNames, queryNames) - writeFileSync(join(SKILL_ROOT, 'references/api-list.md'), apiReference) - console.log('✅ Generated references/api-list.md') - - // Generate dashboard pages reference - const dashboardPages = generateDashboardPages() - writeFileSync( - join(SKILL_ROOT, 'references/dashboard-pages.md'), - dashboardPages - ) - console.log('✅ Generated references/dashboard-pages.md') - - console.log('\n📚 Skill documentation synced successfully!') - console.log('\nNext steps:') - console.log(' 1. Review the generated files') - console.log(' 2. Commit the changes to this repository') - console.log(' 3. Push to GitHub to update the skill') -} - -main() diff --git a/clickhouse-monitoring/skills/clickhouse-monitoring/SKILL.md b/clickhouse-monitoring/skills/clickhouse-monitoring/SKILL.md index 730090e..fc36e34 100644 --- a/clickhouse-monitoring/skills/clickhouse-monitoring/SKILL.md +++ b/clickhouse-monitoring/skills/clickhouse-monitoring/SKILL.md @@ -1,6 +1,6 @@ --- name: clickhouse-monitoring -description: "Specialized knowledge for the ClickHouse Monitor dashboard. Use this skill when: working with ClickHouse monitoring dashboards, analyzing query performance, writing ClickHouse system table queries, developing dashboard features, or integrating with the ClickHouse Monitor API. Covers query monitoring, table management, merge operations, system metrics, and ClickHouse version compatibility." +description: "Use when working on the ClickHouse Monitor dashboard: adding charts, pages, or query configs, calling its API, or handling ClickHouse version differences in system table queries." --- # ClickHouse Monitor @@ -31,57 +31,9 @@ CLICKHOUSE_NAME="Production,Staging" Access hosts via `?host=0`, `?host=1`, etc. in URLs. -## Core Features - -### Query Monitoring - -Track query performance and resource usage: -- **Running Queries** - Active queries with progress %, memory, row counts, estimated completion -- **History Queries** - Query log with execution metrics (duration, CPU, memory) -- **Failed Queries** - Error details, stack traces, failure patterns -- **Expensive Queries** - Ranked by CPU, memory, duration, rows read -- **Query Cache** - Hit/miss rates, size, eviction statistics -- **Thread Analysis** - Per-thread performance breakdown for parallel queries -- **Parallelization** - Thread utilization and parallel effectiveness - -### Table Management - -Browse database objects and metadata: -- **Data Explorer** - Interactive schema tree (databases → tables → columns → dependencies) -- **Tables Overview** - Storage stats, part counts, sizes, replication status -- **Replicas** - Health status, lag, queue size, absolute delay -- **Replication Queue** - Pending/in-progress tasks from Keeper/ZooKeeper -- **Projections** - Definition, status, usage statistics -- **View Refreshes** - Materialized view refresh schedules and history -- **Part Info** - Active part details with levels, rows, bytes -- **Dictionaries** - External dictionary status, source type, memory usage - -### Merge Operations - -Monitor background MergeTree activity: -- **Merges** - Active merges with progress, rows read/written, memory -- **Merge Performance** - Historical merge trends, part size distribution -- **Mutations** - Table mutation status, progress, failed mutations -- **New Parts Created** - Part creation frequency for optimization - -### System Metrics - -Real-time server monitoring: -- **Metrics** - CPU, memory, disk, network, query counters -- **Async Metrics** - Background-calculated metrics (cache sizes, queue depths) -- **Disks** - Storage volume configuration and usage -- **Settings** - Server configuration values and current settings -- **MergeTree Settings** - Engine-specific settings per table - -### Security & Logs - -Track security events and system logs: -- **Sessions** - User session history with authentication details -- **Login Attempts** - Authentication events, failures, reason codes -- **Audit Log** - Security-related events (DDL, user changes, access) -- **Text Log** - Server logs with query context and stack traces -- **Stack Traces** - Live thread stack traces for debugging -- **Crashes** - Historical crash reports with diagnostics +## Core features + +The dashboard covers query monitoring (running, history, failed, expensive, cache), table management (explorer, replicas, projections, dictionaries), merges and mutations, system metrics and settings, and security logs (sessions, login attempts, crashes). See `references/dashboard-pages.md` for every page. ## API Usage @@ -138,14 +90,14 @@ GET /api/v1/explorer/columns?hostId={hostId}&database={db}&table={t} ### Static Site Architecture -**CRITICAL**: Fully static site with client-side data fetching. No SSR, no middleware. +Fully static site with client-side data fetching. No SSR, no middleware. **Routing Pattern:** ```typescript // Static route with query parameter -app/overview/page.tsx → /overview?host=0 +app/overview/page.tsx to /overview?host=0 -// NOT dynamic routes (deprecated) +// NOT dynamic routes (not supported) // app/[host]/overview/page.tsx ``` @@ -300,11 +252,10 @@ export const backupsConfig: QueryConfig = { **Empty charts?** - Verify required log tables enabled: `query_log`, `metric_log`, `part_log` - Check ClickHouse configuration for log settings -- See `docs/clickhouse-schemas/` for table requirements **API returns `table_not_found`?** - Optional table missing - verify ClickHouse configuration -- Version mismatch - check `docs/clickhouse-schemas/tables/{table}.md` +- Version mismatch: check the query's `since` versions in `references/clickhouse-compat.md` **Multi-host not working?** - Verify all three env arrays have same length @@ -319,7 +270,3 @@ export const backupsConfig: QueryConfig = { - [Development Guide](references/development.md) - Architecture patterns, conventions, contribution workflow - [ClickHouse Compatibility](references/clickhouse-compat.md) - Version-aware queries, schema docs, optional tables - [Project Repository](https://github.com/duyet/clickhouse-monitor) - ---- - -*This skill documentation is synced from the main clickhouse-monitor repository. Run `bun run scripts/sync-docs.ts` to update.* diff --git a/clickhouse-monitoring/skills/clickhouse-monitoring/references/api-list.md b/clickhouse-monitoring/skills/clickhouse-monitoring/references/api-list.md index a2147db..2238381 100644 --- a/clickhouse-monitoring/skills/clickhouse-monitoring/references/api-list.md +++ b/clickhouse-monitoring/skills/clickhouse-monitoring/references/api-list.md @@ -165,4 +165,3 @@ GET /api/v1/hosts # List configured ClickHouse hosts ``` --- -*Generated by `scripts/sync-docs.ts` from 2026-03-04T18:39:36.924Z* diff --git a/clickhouse-monitoring/skills/clickhouse-monitoring/references/clickhouse-compat.md b/clickhouse-monitoring/skills/clickhouse-monitoring/references/clickhouse-compat.md index 8808dfa..34299df 100644 --- a/clickhouse-monitoring/skills/clickhouse-monitoring/references/clickhouse-compat.md +++ b/clickhouse-monitoring/skills/clickhouse-monitoring/references/clickhouse-compat.md @@ -91,43 +91,6 @@ export const mergesConfig: QueryConfig = { - 2 = TTLDeleteMerge - 3 = TTLRecompressMerge -## Schema Documentation - -### Available Schemas - -The project includes ClickHouse schema documentation per version: - -``` -docs/clickhouse-schemas/ -├── v23.8.md -├── v24.1.md -├── v24.3.md -├── v24.5.md -├── v24.6.md -├── v24.7.md -├── v24.8.md -├── v24.9.md -├── v24.10.md -├── v24.11.md -├── v24.12.md -└── tables/ - ├── query_log.md - ├── part_log.md - ├── processes.md - └── ... -``` - -### Table Documentation - -Each table has a markdown file documenting: -- Table purpose and requirements -- Column availability by version -- Query examples - -**Example: `tables/query_log.md`** -```markdown -# system.query_log - ## Purpose Logs all queries executed on the server. @@ -336,9 +299,9 @@ This version is cached and used to select appropriate queries from `VersionedSql ## Best Practices -### 1. Always Check Schema Docs +### 1. Check the schema first -Before writing queries, check `docs/clickhouse-schemas/tables/{table}.md` for: +Before writing queries, check the ClickHouse docs for the target system table: - Column availability by version - Type changes - Query requirements @@ -430,4 +393,3 @@ sql: [ - [API Endpoints Reference](api-endpoints.md) - Using queries in API - [Development Guide](development.md) - Adding query configs -- [Schema Documentation](../docs/clickhouse-schemas/) - Complete column reference diff --git a/clickhouse-monitoring/skills/clickhouse-monitoring/references/dashboard-pages.md b/clickhouse-monitoring/skills/clickhouse-monitoring/references/dashboard-pages.md index c5e25f0..4cddaad 100644 --- a/clickhouse-monitoring/skills/clickhouse-monitoring/references/dashboard-pages.md +++ b/clickhouse-monitoring/skills/clickhouse-monitoring/references/dashboard-pages.md @@ -51,4 +51,3 @@ Complete list of all dashboard pages (45 total). | **Data Explorer** | `/explorer` | | --- -*Generated by `scripts/sync-docs.ts` from 2026-03-04T18:39:36.926Z* diff --git a/clickhouse-monitoring/skills/clickhouse-monitoring/references/development.md b/clickhouse-monitoring/skills/clickhouse-monitoring/references/development.md index 963bae6..35c7970 100644 --- a/clickhouse-monitoring/skills/clickhouse-monitoring/references/development.md +++ b/clickhouse-monitoring/skills/clickhouse-monitoring/references/development.md @@ -153,7 +153,7 @@ const { data, error, isLoading } = useTableData({ ## Adding a New Route -### Step 1: Create Page Component +### Step 1. Create Page Component Create `app/your-route/page.tsx`: @@ -188,7 +188,7 @@ export default function YourRoutePage() { } ``` -### Step 2: Add Menu Item +### Step 2. Add Menu Item Edit `menu.ts`: @@ -203,7 +203,7 @@ Edit `menu.ts`: } ``` -### Step 3: Create Query Config (if needed) +### Step 3. Create Query Config (if needed) Add to `lib/query-config/`: @@ -220,268 +220,6 @@ export const yourConfig: QueryConfig = { } ``` -## Adding a New Chart - -### Step 1: Define Chart Query - -Add to `lib/api/charts/your-domain-charts.ts`: - -```typescript -export const yourChart: ChartQueryBuilder = (params) => { - const lastHours = params.lastHours || 24 - - return { - sql: ` - SELECT - toStartOfInterval(event_time, INTERVAL 1 hour) AS ts, - COUNT() AS value - FROM system.query_log - WHERE event_time > now() - INTERVAL ${lastHours} HOUR - GROUP BY ts - ORDER BY ts - `, - columns: ['ts', 'value'], - } -} - -export const yourCharts = { - 'your-chart-name': yourChart, -} -``` - -### Step 2: Register Chart - -Add to `lib/api/chart-registry.ts`: - -```typescript -import { yourCharts } from './charts/your-domain-charts' - -export const chartRegistry = { - // ... - ...yourCharts, -} -``` - -### Step 3: Create Chart Component - -Create `components/charts/your-chart.tsx`: - -```typescript -'use client' -import { useChartData } from '@/lib/swr/use-chart-data' -import { ChartSkeleton } from '@/components/skeletons' -import { ChartError } from '@/components/error-alert' -import { AreaChart } from '@/components/charts/area-chart' - -export function YourChart({ hostId, interval, lastHours }: YourChartProps) { - const { data, error, isLoading } = useChartData({ - name: 'your-chart-name', - hostId, - interval, - lastHours, - }) - - if (isLoading) return - if (error) return - if (!data || data.length === 0) return
No data
- - return -} -``` - -## Multi-Host Configuration - -### Environment Variables - -Configure in `.env.local`: - -```bash -# Comma-separated lists (same length) -CLICKHOUSE_HOST=prod.example.com,staging.example.com -CLICKHOUSE_USER=admin,readonly -CLICKHOUSE_PASSWORD=secret123,readonly456 -CLICKHOUSE_NAME="Production,Staging" -``` - -### Accessing Host ID - -```typescript -import { useHostId } from '@/lib/swr' - -function YourComponent() { - const hostId = useHostId() // Extracts from ?host= query param - - // URL: /overview?host=1 → hostId = 1 (Staging) - // URL: /overview?host=0 → hostId = 0 (Production) -} -``` - -### ClickHouse Client with Host ID - -```typescript -import { createClient } from '@clickhouse/client-web' -import { getClickHouseConfig } from '@/lib/clickhouse' - -const hostId = 0 -const client = createClient(getClickHouseConfig(hostId)) -``` - -## Code Conventions - -### Git Commit Format - -Follow semantic commit format with consistent scope: - -``` -feat(scope): description -fix(scope): description -chore(deps): description -refactor(ui): description -docs(api): description -test(unit): description -``` - -**Always include co-authorship:** -``` -Co-Authored-By: duyetbot -``` - -**Examples:** -``` -feat(queries): add thread analysis chart -fix(ui): correct chart loading state -chore(deps): upgrade React to 19 -docs(api): document streaming endpoint -``` - -### Component Patterns - -**Hooks at deepest consumer:** -```typescript -// Bad: Prop drilling hostId -function Nav({ hostId }: { hostId: number }) { - return -} - -// Good: Hook at deepest consumer -function Nav() { - return -} - -function MenuItem() { - const hostId = useHostId() // Call where needed - return Overview -} -``` - -**Client Components:** -- Always add `'use client'` directive -- Use Suspense for loading states -- Handle errors gracefully - -**Server Components:** -- Don't use `'use client'` (default in Next.js) -- Keep mostly static (no data fetching) -- For this project: Most pages are client components - -### shadcn/ui Components - -**DO NOT modify** `components/ui/` files directly. These are installed via CLI and should remain in original state. - -**If you need custom styling:** -```typescript -// Good: Custom classes at usage site - - ... - - -// Bad: Modifying components/ui/card.tsx -``` - -**For reusable custom variants:** -```typescript -// Create wrapper in components/ (not components/ui/) -// components/info-badge.tsx -import { Badge } from '@/components/ui/badge' -import { cn } from '@/lib/utils' - -export function InfoBadge({ className, ...props }) { - return ( - > "$GITHUB_OUTPUT" - else - echo "has_changes=true" >> "$GITHUB_OUTPUT" - fi - - - name: Create Pull Request - if: steps.check-changes.outputs.has_changes == 'true' - # peter-evans/create-pull-request v8.1.1 - uses: peter-evans/create-pull-request@5f6978faf089d4d20b00c7766989d076bb2fc7f1 - with: - token: ${{ secrets.GITHUB_TOKEN }} - commit-message: "feat(clickhouse): sync rules from ClickHouse/agent-skills" - committer: GitHub - author: github-actions[bot] - title: "feat(clickhouse): sync rules from ClickHouse/agent-skills" - body: | - ## Sync from ClickHouse/agent-skills - - This PR automatically syncs the rule files from the official [ClickHouse/agent-skills](https://github.com/ClickHouse/agent-skills) repository. - - ### Changes - - Updated rule files from upstream - - Version automatically incremented - - Maintains compatibility with our extended `references/` directory - - ### Review Notes - - Review the rule file changes to ensure they align with our skill structure - - Our custom `references/` content is preserved - branch: sync/clickhouse-rules - delete-branch: true diff --git a/clickhouse/.grok-build-plugin/plugin.json b/clickhouse/.grok-build-plugin/plugin.json index 8001610..a927c3b 100644 --- a/clickhouse/.grok-build-plugin/plugin.json +++ b/clickhouse/.grok-build-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "clickhouse", - "version": "1.4.1", - "description": "Comprehensive ClickHouse knowledge base from Altinity KB + official docs", + "version": "2.0.0", + "description": "ClickHouse review rules for schemas, queries, and inserts, with references for debugging and monitoring queries.", "author": { "name": "duyet", "url": "https://github.com/duyet" @@ -11,7 +11,7 @@ "skills": "./skills/", "interface": { "displayName": "Clickhouse", - "shortDescription": "Comprehensive ClickHouse knowledge base from Altinity KB + official docs", + "shortDescription": "ClickHouse review rules for schemas, queries, and inserts, with references for debugging and monitoring queries.", "developerName": "duyet", "category": "Database", "capabilities": [ diff --git a/clickhouse/.grok-plugin/plugin.json b/clickhouse/.grok-plugin/plugin.json index c292b74..425ff96 100644 --- a/clickhouse/.grok-plugin/plugin.json +++ b/clickhouse/.grok-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "clickhouse", - "version": "1.4.1", - "description": "Comprehensive ClickHouse knowledge base from Altinity KB + official docs", + "version": "2.0.0", + "description": "ClickHouse review rules for schemas, queries, and inserts, with references for debugging and monitoring queries.", "author": { "name": "duyet", "url": "https://github.com/duyet" diff --git a/clickhouse/README.md b/clickhouse/README.md index d313f36..86c3ca0 100644 --- a/clickhouse/README.md +++ b/clickhouse/README.md @@ -1,167 +1,17 @@ -# ClickHouse Plugin for Claude Code +# clickhouse -ClickHouse knowledge base with 28 atomic review rules and 15+ deep reference files. Compiled from [ClickHouse/agent-skills](https://github.com/ClickHouse/agent-skills) (Apache-2.0), Altinity Knowledge Base (200+ articles), and official ClickHouse documentation. +ClickHouse review guidance for schemas, queries, and inserts, built around 28 atomic rules. -## Overview +## Install -This plugin provides deep expertise in ClickHouse, a high-performance columnar OLAP database. It combines actionable, citable rules for schema/query/insert review with reference files covering cluster management, Kubernetes, backups, monitoring, and integrations. - -## What's Included - -### 28 Atomic Rules (`skills/clickhouse/rules/`) - -Structured review rules with YAML frontmatter, incorrect/correct examples, and official doc references: - -| Prefix | Count | Focus | Impact | -|--------|-------|-------|--------| -| `schema-pk-*` | 4 | Primary key selection and cardinality | CRITICAL | -| `schema-types-*` | 5 | Data types, LowCardinality, Nullable | CRITICAL | -| `schema-partition-*` | 4 | Partitioning and lifecycle management | HIGH | -| `schema-json-*` | 1 | JSON type usage | MEDIUM | -| `query-join-*` | 5 | JOIN algorithms and filtering | CRITICAL | -| `query-index-*` | 1 | Data skipping indices | HIGH | -| `query-mv-*` | 2 | Materialized views (incremental + refreshable) | HIGH | -| `insert-batch-*` | 1 | Batch sizing (10K-100K rows) | CRITICAL | -| `insert-async-*` | 2 | Async inserts and data formats | HIGH | -| `insert-mutation-*` | 2 | Mutation avoidance (UPDATE/DELETE) | CRITICAL | -| `insert-optimize-*` | 1 | OPTIMIZE FINAL avoidance | HIGH | - -### 15+ Reference Files (`skills/clickhouse/references/`) - -Deep-dive files covering topics beyond the rules: - -- **Core Concepts** — Architecture, data model, MergeTree internals -- **Schema & Table Design** — Database engines, migrations, ORDER BY, partitioning -- **Table Engines** — Complete MergeTree family reference -- **SQL Reference** — Full SQL dialect with data types and functions -- **Query Optimization** — EXPLAIN, JOINs, projections, skip indexes -- **Advanced Features** — Materialized views, mutations, TTL, dictionaries -- **Debugging** — Query debugging, merge issues, replication problems -- **Cluster Management** — Distributed tables, replication, sharding -- **Kubernetes Operator** — K8s deployment with Altinity operator -- **Backup & Restore** — Backup strategies and disaster recovery -- **Monitoring** — Query monitoring, health checks, system queries -- **Integrations** — Kafka, S3, PostgreSQL, MySQL, BI tools -- **Best Practices** — Complete checklist and anti-patterns -- **System Queries** — Ready-to-use operations queries - -## File Structure - -``` -clickhouse/ -├── .claude-plugin/ -│ └── plugin.json -├── .github/ -│ └── workflows/ -│ ├── sync-rules.yml # Auto-sync from ClickHouse/agent-skills -│ └── README.md # Workflow documentation -├── skills/ -│ └── clickhouse/ -│ ├── SKILL.md # Review framework + rule index -│ ├── rules/ # 28 atomic rules + meta files -│ │ ├── _sections.md # Section definitions (schema/query/insert) -│ │ ├── _template.md # Template for new rules -│ │ ├── schema-pk-*.md # Primary key rules (4) -│ │ ├── schema-types-*.md # Data type rules (5) -│ │ ├── schema-partition-*.md # Partitioning rules (4) -│ │ ├── schema-json-*.md # JSON rules (1) -│ │ ├── query-join-*.md # JOIN rules (5) -│ │ ├── query-index-*.md # Index rules (1) -│ │ ├── query-mv-*.md # Materialized view rules (2) -│ │ ├── insert-batch-*.md # Batch sizing rules (1) -│ │ ├── insert-async-*.md # Async insert rules (2) -│ │ ├── insert-mutation-*.md # Mutation rules (2) -│ │ └── insert-optimize-*.md # Optimize rules (1) -│ └── references/ # 15+ deep reference files -│ ├── core-concepts.md -│ ├── schema-design.md -│ ├── table-design.md -│ ├── table-engines.md -│ ├── sql-reference.md -│ ├── query-optimization.md -│ ├── advanced-features.md -│ ├── debugging.md -│ ├── cluster-management.md -│ ├── backup-restore.md -│ ├── monitoring.md -│ ├── integrations.md -│ ├── best-practices.md -│ ├── external.md -│ └── system-queries.md -└── README.md ``` - -## Auto-Activation Triggers - -The skill automatically activates when questions contain: - -- `clickhouse` -- `merge.*tree` (e.g., "MergeTree engine") -- `olap` (online analytical processing) -- `columnar.*database` -- `ch\.` (ClickHouse abbreviation) -- `replicated.*merge` - -## Usage - -When reviewing ClickHouse code, the skill: - -1. Checks applicable rules from `rules/` and cites them (e.g., "Per `schema-pk-cardinality-order`...") -2. Falls back to `references/` for deeper topic coverage -3. Provides structured review output with violations, compliance, and recommendations - -## Attribution - -- **Rules**: Synced from [ClickHouse/agent-skills](https://github.com/ClickHouse/agent-skills) by ClickHouse Inc (Apache-2.0 license) -- **References**: Compiled from Altinity Knowledge Base (200+ articles) and ClickHouse Official Documentation - -## Automation - -### GitHub Actions Sync - -This plugin uses GitHub Actions to automatically sync rule files from the official ClickHouse/agent-skills repository: - -- **Workflow**: `.github/workflows/sync-rules.yml` -- **Specification**: `spec/spec-process-cicd-sync-rules.md` -- **Schedule**: Weekly (Sunday at midnight UTC) -- **Trigger**: Manual trigger available from Actions tab - -The sync workflow: -1. Fetches latest rules from ClickHouse/agent-skills -2. Updates `skills/clickhouse/rules/` directory -3. Auto-increments version number -4. Creates a pull request for review - -**Custom content preserved**: Our extended `references/` directory is never modified by the sync. - -See [Workflow Specification](spec/spec-process-cicd-sync-rules.md) for detailed requirements, error handling, and validation criteria. - -### Manual Sync - -To manually trigger a sync: -```bash -# Via GitHub UI: -# 1. Go to Actions tab -# 2. Select "Sync Rules from ClickHouse/agent-skills" -# 3. Click "Run workflow" - -# Via CLI (gh CLI): -gh workflow run sync-rules.yml +/plugin install clickhouse@duyet-claude-plugins ``` -## Version - -**Current Version**: 1.3.0 - -**Version History**: -- 1.3.0 — Synced rules from ClickHouse/agent-skills -- 1.2.0 — Added security considerations -- 1.1.0 — Initial release with extended references - -## License - -MIT (plugin code) + Apache-2.0 (rules adapted from ClickHouse/agent-skills) +## What ships -## Author +- `skills/clickhouse/SKILL.md`: decision tree that routes a review to the right rules. +- `skills/clickhouse/rules/`: 28 rules with incorrect and correct examples, grouped by schema, query, and insert. +- `skills/clickhouse/references/`: schema design, query optimization, debugging, and monitoring queries. -duyetbot +Rules are synced from [ClickHouse/agent-skills](https://github.com/ClickHouse/agent-skills) (Apache-2.0). diff --git a/clickhouse/skills/clickhouse/SKILL.md b/clickhouse/skills/clickhouse/SKILL.md index 1722e7e..4fef162 100644 --- a/clickhouse/skills/clickhouse/SKILL.md +++ b/clickhouse/skills/clickhouse/SKILL.md @@ -1,284 +1,70 @@ --- name: clickhouse -description: MUST USE when reviewing ClickHouse schemas, queries, or configurations. Contains 28 rules that MUST be checked before providing recommendations. Always read relevant rule files and cite specific rules in responses. +description: Use when reviewing or writing ClickHouse schemas, queries, inserts, or operations. Check the matching rule files in rules/ first and cite them by name in your answer. --- -# ClickHouse Best Practices +# ClickHouse -Guidance for ClickHouse covering schema design, query optimization, and data ingestion. Contains 28 atomic rules across 3 categories (schema, query, insert), prioritized by impact. Extended with 15 reference files covering cluster management, backups, monitoring, and integrations. +ClickHouse behaves differently from row-store databases (sparse primary index, immutable parts, background merges), so general database habits mislead. The 28 files in `rules/` encode the validated guidance. Read the relevant ones before recommending anything, and cite each as "Per `rule-name`". -> **Official docs:** [ClickHouse Best Practices](https://clickhouse.com/docs/best-practices) +Order of sources: `rules/`, then `references/`, then the official docs. Say which one you used. ---- - -## ⚠️ Security Considerations - -### Credential Placeholders -Example credentials in documentation (`password123`, `AKIAIOSFODNN7EXAMPLE`) are placeholders only. Never use these in production. Use proper secret management: -- Environment variables -- Secret managers (AWS Secrets Manager, HashiCorp Vault, etc.) -- Kubernetes secrets (for K8s deployments) -- ClickHouse named collections with external configuration - -### Installation & Operations -For installation and operational procedures: -- Follow official documentation links provided in reference files -- Prefer package managers (`apt`, `yum`, `helm`) over direct downloads -- Use versioned artifacts instead of `latest` in production -- Test procedures in non-production environments first - ---- - -## IMPORTANT: How to Apply This Skill - -**Before answering ClickHouse questions, follow this priority order:** - -1. **Check for applicable rules** in the `rules/` directory -2. **If rules exist:** Apply them and cite them in your response using "Per `rule-name`..." -3. **If no rule exists:** Check `references/` for deeper topic coverage -4. **If neither covers it:** Use general ClickHouse knowledge or search documentation -5. **Always cite your source:** rule name, reference file, or URL - -**Why rules take priority:** ClickHouse has specific behaviors (columnar storage, sparse indexes, merge tree mechanics) where general database intuition can be misleading. The rules encode validated, ClickHouse-specific guidance. - ---- - -## Review Procedures - -### For Schema Reviews (CREATE TABLE, ALTER TABLE) - -**Read these rule files in order:** - -1. `rules/schema-pk-plan-before-creation.md` — ORDER BY is immutable -2. `rules/schema-pk-cardinality-order.md` — Column ordering in keys -3. `rules/schema-pk-prioritize-filters.md` — Filter column inclusion -4. `rules/schema-pk-filter-on-orderby.md` — Query filter alignment -5. `rules/schema-types-native-types.md` — Proper type selection -6. `rules/schema-types-minimize-bitwidth.md` — Numeric type sizing -7. `rules/schema-types-lowcardinality.md` — LowCardinality usage -8. `rules/schema-types-avoid-nullable.md` — Nullable vs DEFAULT -9. `rules/schema-types-enum.md` — Enum for finite value sets -10. `rules/schema-partition-low-cardinality.md` — Partition count limits -11. `rules/schema-partition-lifecycle.md` — Partitioning purpose -12. `rules/schema-partition-query-tradeoffs.md` — Partition pruning trade-offs -13. `rules/schema-partition-start-without.md` — Start without partitioning -14. `rules/schema-json-when-to-use.md` — JSON type usage - -**Check for:** -- [ ] PRIMARY KEY / ORDER BY column order (low-to-high cardinality) -- [ ] Data types match actual data ranges -- [ ] LowCardinality applied to appropriate string columns -- [ ] Partition key cardinality bounded (100-1,000 values) -- [ ] ReplacingMergeTree has version column if used - -### For Query Reviews (SELECT, JOIN, aggregations) - -**Read these rule files:** - -1. `rules/query-join-choose-algorithm.md` — Algorithm selection -2. `rules/query-join-use-any.md` — ANY vs regular JOIN -3. `rules/query-join-filter-before.md` — Pre-join filtering -4. `rules/query-join-consider-alternatives.md` — Dictionaries/denormalization -5. `rules/query-join-null-handling.md` — join_use_nulls setting -6. `rules/query-index-skipping-indices.md` — Secondary index usage -7. `rules/query-mv-incremental.md` — Incremental materialized views -8. `rules/query-mv-refreshable.md` — Refreshable materialized views - -**Check for:** -- [ ] Filters use ORDER BY prefix columns -- [ ] JOINs filter tables before joining (not after) -- [ ] Correct JOIN algorithm for table sizes -- [ ] Skipping indices for non-ORDER BY filter columns - -### For Insert Strategy Reviews (data ingestion, updates, deletes) - -**Read these rule files:** - -1. `rules/insert-batch-size.md` — Batch sizing requirements -2. `rules/insert-async-small-batches.md` — Async insert usage -3. `rules/insert-format-native.md` — Native format for performance -4. `rules/insert-mutation-avoid-update.md` — UPDATE alternatives -5. `rules/insert-mutation-avoid-delete.md` — DELETE alternatives -6. `rules/insert-optimize-avoid-final.md` — OPTIMIZE TABLE risks - -**Check for:** -- [ ] Batch size 10K-100K rows per INSERT -- [ ] No ALTER TABLE UPDATE for frequent changes -- [ ] ReplacingMergeTree or CollapsingMergeTree for update patterns -- [ ] Async inserts enabled for high-frequency small batches - ---- - -## Output Format - -Structure review responses as follows: - -``` -## Rules Checked -- `rule-name-1` — Compliant / Violation found -- `rule-name-2` — Compliant / Violation found -... - -## Findings - -### Violations -- **`rule-name`**: Description of the issue - - Current: [what the code does] - - Required: [what it should do] - - Fix: [specific correction] - -### Compliant -- `rule-name`: Brief note on why it's correct +Never put real credentials in examples. Use environment variables, a secret manager, or named collections. -## Recommendations -[Prioritized list of changes, citing rules] -``` - ---- - -## Rule Categories by Priority - -| Priority | Category | Impact | Prefix | Count | -|----------|----------|--------|--------|-------| -| 1 | Primary Key Selection | CRITICAL | `schema-pk-` | 4 | -| 2 | Data Type Selection | CRITICAL | `schema-types-` | 5 | -| 3 | JOIN Optimization | CRITICAL | `query-join-` | 5 | -| 4 | Insert Batching | CRITICAL | `insert-batch-` | 1 | -| 5 | Mutation Avoidance | CRITICAL | `insert-mutation-` | 2 | -| 6 | Partitioning Strategy | HIGH | `schema-partition-` | 4 | -| 7 | Skipping Indices | HIGH | `query-index-` | 1 | -| 8 | Materialized Views | HIGH | `query-mv-` | 2 | -| 9 | Async Inserts | HIGH | `insert-async-` | 2 | -| 10 | OPTIMIZE Avoidance | HIGH | `insert-optimize-` | 1 | -| 11 | JSON Usage | MEDIUM | `schema-json-` | 1 | - ---- - -## Quick Reference - -### Schema Design — Primary Key (CRITICAL) - -- `schema-pk-plan-before-creation` — Plan ORDER BY before table creation (immutable) -- `schema-pk-cardinality-order` — Order columns low-to-high cardinality -- `schema-pk-prioritize-filters` — Include frequently filtered columns -- `schema-pk-filter-on-orderby` — Query filters must use ORDER BY prefix - -### Schema Design — Data Types (CRITICAL) - -- `schema-types-native-types` — Use native types, not String for everything -- `schema-types-minimize-bitwidth` — Use smallest numeric type that fits -- `schema-types-lowcardinality` — LowCardinality for <10K unique strings -- `schema-types-enum` — Enum for finite value sets with validation -- `schema-types-avoid-nullable` — Avoid Nullable; use DEFAULT instead - -### Schema Design — Partitioning (HIGH) - -- `schema-partition-low-cardinality` — Keep partition count 100-1,000 -- `schema-partition-lifecycle` — Use partitioning for data lifecycle, not queries -- `schema-partition-query-tradeoffs` — Understand partition pruning trade-offs -- `schema-partition-start-without` — Consider starting without partitioning - -### Schema Design — JSON (MEDIUM) - -- `schema-json-when-to-use` — JSON for dynamic schemas; typed columns for known - -### Query Optimization — JOINs (CRITICAL) +## Which rules to read -- `query-join-choose-algorithm` — Select algorithm based on table sizes -- `query-join-use-any` — ANY JOIN when only one match needed -- `query-join-filter-before` — Filter tables before joining -- `query-join-consider-alternatives` — Dictionaries/denormalization vs JOIN -- `query-join-null-handling` — join_use_nulls=0 for default values +### Schema review (CREATE TABLE, ALTER TABLE) -### Query Optimization — Indices (HIGH) +- ORDER BY and primary key: `schema-pk-plan-before-creation`, `schema-pk-cardinality-order`, `schema-pk-prioritize-filters`, `schema-pk-filter-on-orderby`. ORDER BY cannot be changed after creation. +- Types: `schema-types-native-types`, `schema-types-minimize-bitwidth`, `schema-types-lowcardinality`, `schema-types-avoid-nullable`, `schema-types-enum`. +- Partitioning: `schema-partition-start-without`, `schema-partition-low-cardinality`, `schema-partition-lifecycle`, `schema-partition-query-tradeoffs`. +- JSON columns: `schema-json-when-to-use`. -- `query-index-skipping-indices` — Skipping indices for non-ORDER BY filters +### Query review (SELECT, JOIN, aggregation) -### Query Optimization — Materialized Views (HIGH) +- Joins: `query-join-choose-algorithm`, `query-join-use-any`, `query-join-filter-before`, `query-join-consider-alternatives`, `query-join-null-handling`. +- Filters on non-key columns: `query-index-skipping-indices`. +- Precomputation: `query-mv-incremental`, `query-mv-refreshable`. -- `query-mv-incremental` — Incremental MVs for real-time aggregations -- `query-mv-refreshable` — Refreshable MVs for complex joins +### Insert and update review -### Insert Strategy — Batching (CRITICAL) +- Batching: `insert-batch-size` (10K to 100K rows), `insert-async-small-batches`, `insert-format-native`. +- Changes to existing rows: `insert-mutation-avoid-update`, `insert-mutation-avoid-delete`. +- Merges: `insert-optimize-avoid-final`. -- `insert-batch-size` — Batch 10K-100K rows per INSERT +`rules/_sections.md` lists the categories by impact. CRITICAL rules (primary key, types, joins, batching, mutations) come first. -### Insert Strategy — Async (HIGH) - -- `insert-async-small-batches` — Async inserts for high-frequency small batches -- `insert-format-native` — Native format for best performance - -### Insert Strategy — Mutations (CRITICAL) - -- `insert-mutation-avoid-update` — ReplacingMergeTree instead of ALTER UPDATE -- `insert-mutation-avoid-delete` — Lightweight DELETE or DROP PARTITION - -### Insert Strategy — Optimization (HIGH) - -- `insert-optimize-avoid-final` — Let background merges work - ---- - -## Quick Decision Guides - -### Which Table Engine? +## Table engine choice ``` -Need to store data? -├── < 1M rows, dimension → Memory -└── ≥ 1M rows → MergeTree family - ├── Deduplication? → ReplacingMergeTree(version) - ├── Changelog? → CollapsingMergeTree(sign) - ├── Pre-aggregation? → AggregatingMergeTree() - ├── Replication? → ReplicatedMergeTree(...) - └── Default → MergeTree() +Small dimension table (under 1M rows)? Memory or MergeTree +Otherwise MergeTree family +├── Deduplicate by key ReplacingMergeTree(version) +├── Cancel rows with a sign CollapsingMergeTree(sign) +├── Pre-aggregate AggregatingMergeTree +├── Replicated cluster Replicated* variant of the above +└── Default MergeTree ``` -See `references/table-engines.md` for complete reference. +## Common symptoms -### Common Issues & Quick Fixes +| Symptom | First step | +|---------|-----------| +| Too many parts | Fix insert batching (`insert-batch-size`). Do not run `OPTIMIZE ... FINAL` as a routine fix (`insert-optimize-avoid-final`). | +| Slow query | `EXPLAIN indexes = 1` to check whether the key prefix is used | +| Stuck mutation | Check `system.mutations`, then see `insert-mutation-avoid-update` | +| Replication lag | Check `system.replication_queue` and Keeper health | +| Out of memory | Reduce data read first, then tune `max_memory_usage` | -| Issue | Quick Fix | -|-------|-----------| -| Too many parts | `OPTIMIZE TABLE table FINAL` (see `insert-optimize-avoid-final`) | -| Slow query | `EXPLAIN SELECT ...` to check index usage | -| Mutation stuck | Check `system.mutations`, consider alternatives per `insert-mutation-avoid-update` | -| Replication lag | Check `system.replication_queue`, ZooKeeper | -| OOM on query | Increase `max_memory_usage`, optimize query | +## References -See `references/debugging.md` for detailed troubleshooting. +- `references/schema-design.md` for ORDER BY patterns, partition operations, codecs, skip indexes, and migrations. +- `references/query-optimization.md` for EXPLAIN, join tuning, projections. +- `references/debugging.md` for query, merge, mutation, and replication troubleshooting. +- `references/monitoring.md` for ready-to-use `system.*` queries, alerting, and Prometheus. ---- - -## Deep Reference Files - -For topics beyond the 28 rules, see the `references/` directory: - -### Schema & Table Design -- `references/core-concepts.md` — Architecture, data model, internals -- `references/schema-design.md` — Database engines, migrations, version control -- `references/table-design.md` — ORDER BY, partitioning, column selection -- `references/table-engines.md` — Complete MergeTree family reference +## Review output -### Query & Performance -- `references/sql-reference.md` — Complete SQL dialect, data types -- `references/query-optimization.md` — EXPLAIN, JOINs, projections, skip indexes -- `references/advanced-features.md` — Materialized views, mutations, TTL, dictionaries - -### Operations & Cluster -- `references/debugging.md` — Query debugging, merges, mutations, replication -- `references/cluster-management.md` — Distributed tables, replication, sharding -- `references/backup-restore.md` — Backup strategies, disaster recovery -- `references/monitoring.md` — Query monitoring, health checks, system queries - -### Integration & Best Practices -- `references/integrations.md` — Kafka, S3, PostgreSQL, MySQL, BI tools -- `references/best-practices.md` — Complete checklist and anti-patterns -- `references/external.md` — Altinity KB links, official docs -- `references/system-queries.md` — Ready-to-use queries for operations - ---- +List each rule checked as compliant or violated. For each violation give the current state, the required state, and the fix. End with prioritized recommendations that cite rules. -**Version**: 1.4.0 -**Rules**: Synced with [ClickHouse/agent-skills](https://github.com/ClickHouse/agent-skills) (Apache-2.0) -**References**: Altinity Knowledge Base (200+ articles) + ClickHouse Official Docs +Rules are synced from [ClickHouse/agent-skills](https://github.com/ClickHouse/agent-skills) (Apache-2.0). diff --git a/clickhouse/skills/clickhouse/references/advanced-features.md b/clickhouse/skills/clickhouse/references/advanced-features.md deleted file mode 100644 index 85638c2..0000000 --- a/clickhouse/skills/clickhouse/references/advanced-features.md +++ /dev/null @@ -1,354 +0,0 @@ -# ClickHouse Advanced Features - -Materialized views, mutations, TTL, dictionaries, and other advanced capabilities. - -## Materialized Views - -Materialized views automatically process data on INSERT: - -### Basic Materialized View - -```sql --- Pre-aggregate on write -CREATE MATERIALIZED VIEW mv_daily_stats -ENGINE = AggregatingMergeTree() -ORDER BY (date, user_id) -AS SELECT - toDate(timestamp) as date, - user_id, - countState() as hits, - sumState(revenue) as total_revenue -FROM events -GROUP BY date, user_id; - --- Query MV (fast - already aggregated!) -SELECT - user_id, - countMerge(hits) as total_hits, - sumMerge(total_revenue) as revenue -FROM mv_daily_stats -WHERE date = today() -GROUP BY user_id; -``` - -### Materialized View to Target Table - -```sql --- Create target table -CREATE TABLE daily_stats ( - date Date, - user_id UInt32, - hits UInt64, - revenue Decimal(18, 2) -) -ENGINE = AggregatingMergeTree() -ORDER BY (date, user_id); - --- Create MV that populates target table -CREATE MATERIALIZED VIEW mv_populate_daily_stats -TO daily_stats -AS SELECT - toDate(timestamp) as date, - user_id, - count() as hits, - sum(revenue) as revenue -FROM events -GROUP BY date, user_id; -``` - -### POPULATE Option - -```sql --- Create MV and backfill existing data -CREATE MATERIALIZED VIEW mv_daily_stats -ENGINE = AggregatingMergeTree() -ORDER BY (date, user_id) -POPULATE -- Backfill existing data -AS SELECT - toDate(timestamp) as date, - user_id, - count() as hits -FROM events -GROUP BY date, user_id; -``` - -### Drop Materialized View - -```sql --- Drop MV (target table data remains) -DROP TABLE mv_daily_stats; -``` - -**Materialized view use cases:** -- Pre-aggregation (sum, count, avg) -- Rollup data (hourly → daily) -- Data routing (INSERT → multiple tables) -- Real-time analytics - -## Mutations - -Mutations are async UPDATE/DELETE operations: - -### UPDATE - -```sql --- UPDATE (async, expensive - rewrites all data) -ALTER TABLE events UPDATE status = 'done' -WHERE event_id = 123; - --- Multiple columns -ALTER TABLE events UPDATE - status = 'done', - processed_at = now() -WHERE event_id = 123; -``` - -### DELETE - -```sql --- DELETE (async, expensive - rewrites all data) -ALTER TABLE events DELETE -WHERE timestamp < now() - INTERVAL 90 DAY; -``` - -### Monitor Mutations - -```sql --- Show all mutations -SELECT * FROM system.mutations; - --- Active mutations -SELECT - database, - table, - command, - is_done, - parts_to_do, - parts_to_do_names, - elapsed -FROM system.mutations -WHERE is_done = 0; - --- Mutation progress -SELECT - table, - command, - is_done, - parts_to_do - parts_to_do_names as parts_remaining -FROM system.mutations -ORDER BY parts_to_do DESC; -``` - -### Force Mutation Completion - -```sql --- Wait for mutation to complete -SYSTEM STOP MERGES; -ALTER TABLE ... UPDATE ...; -OPTIMIZE TABLE ... FINAL; -SYSTEM START MERGES; -``` - -**Mutation characteristics:** -- Async: Doesn't block table -- Expensive: Rewrites all data -- Can be slow on large tables -- Better: Use TTL or new tables - -## TTL (Time To Live) - -TTL automatically manages data lifecycle: - -### Delete Old Data - -```sql --- Delete old data -CREATE TABLE events ( - timestamp DateTime, - data String -) -ENGINE = MergeTree() -ORDER BY timestamp -TTL timestamp + INTERVAL 90 DAY; -``` - -### Recompress Old Data - -```sql --- Change compression over time -CREATE TABLE events ( - timestamp DateTime, - data String -) -ENGINE = MergeTree() -ORDER BY timestamp -TTL - timestamp + INTERVAL 7 DAY TO VOLUME 'cold', - timestamp + INTERVAL 30 DAY TO DISK 's3'; -``` - -### Column TTL - -```sql --- Column-level TTL -CREATE TABLE events ( - timestamp DateTime, - data String, - metadata String TTL timestamp + INTERVAL 30 DAY DELETE -) -ENGINE = MergeTree() -ORDER BY timestamp; -``` - -### Modify TTL - -```sql --- Modify table TTL -ALTER TABLE events -MODIFY TTL timestamp + INTERVAL 180 DAY; - --- Modify column TTL -ALTER TABLE events -MODIFY COLUMN metadata TTL timestamp + INTERVAL 60 DAY DELETE; -``` - -### Drop Partition (Instant) - -```sql --- Drop entire partition (instant, no mutation) -ALTER TABLE events DROP PARTITION '202401'; -``` - -**TTL operations:** -- Delete old data -- Move to cold storage -- Change compression codec -- Drop partition (instant) - -## Dictionaries - -Dictionaries provide fast in-memory lookups: - -### PostgreSQL Dictionary - -```sql --- Create dictionary -CREATE DICTIONARY users_dict ( - user_id UInt32, - email String, - name String, - created_at DateTime -) -PRIMARY KEY user_id -SOURCE(POSTGRESQL( - port 5432 - host 'localhost' - db 'mydb' - table 'users' - user 'user' - password 'pass' -)) -LIFETIME(60) -- Refresh every 60 seconds -LAYOUT(HASHED()); - --- Use in query -SELECT - e.user_id, - dictGet('users_dict', 'email', e.user_id) as email, - dictGet('users_dict', 'name', e.user_id) as name -FROM events e; -``` - -### Cache Dictionary - -```sql -CREATE DICTIONARY users_cache ( - user_id UInt32, - email String -) -PRIMARY KEY user_id -SOURCE(POSTGRESQL(...)) -LIFETIME(300) -LAYOUT(CACHE(SIZE_IN_CELLS 10000)); -- LRU cache -``` - -### Dictionary Functions - -```sql --- Get value -dictGet('dict_name', 'attribute_type', key) -dictGetOrDefault('dict_name', 'attribute_type', key, default_value) -dictHas('dict_name', key) - --- Check dictionary status -SELECT * FROM system.dictionaries WHERE name = 'users_dict'; -``` - -### Dictionary Layouts - -| Layout | Use Case | Description | -|--------|----------|-------------| -| FLAT | Small dictionaries (< 1M keys) | Fastest, array-based | -| HASHED | Medium dictionaries (1M-10M keys) | Hash table | -| CACHE | Large dictionaries, rare lookups | LRU cache | -| RANGE | Numeric range lookups | Range queries | -| COMPLEX_KEY | Composite keys | Tuple keys | -| IP_TRIE | IP address lookups | CIDR matching | - -## Projections - -Projections are materialized views at part level: - -```sql --- Create projection -ALTER TABLE events ADD PROJECTION pr_user_daily ( - SELECT - user_id, - toDate(timestamp) as date, - count() as events, - sum(revenue) as total_revenue - GROUP BY user_id, date -); - --- Query automatically uses projection (fast!) -SELECT - user_id, - date, - count() as events, - sum(revenue) as total_revenue -FROM events -GROUP BY user_id, date; - --- Drop projection -ALTER TABLE events DROP PROJECTION pr_user_daily; -``` - -**Projection benefits:** -- Automatic usage (no query changes) -- Faster than materialized views -- Maintained per-part (smaller overhead) - -## FINAL Clause - -FINAL forces application of mutations: - -```sql --- Force deduplication (expensive!) -SELECT * FROM ReplacingMergeTree_table FINAL WHERE user_id = 123; - --- Check what FINAL does -EXPLAIN SELECT * FROM table FINAL; - --- Better: Design queries to handle duplicates -SELECT - user_id, - argMax(profile, updated_at) as latest_profile -FROM user_profiles -GROUP BY user_id; -``` - -## See Also - -- `../SKILL.md` - Main skill entry point -- `table-engines.md` - Complete table engine reference -- `debugging.md` - Mutation monitoring and troubleshooting diff --git a/clickhouse/skills/clickhouse/references/backup-restore.md b/clickhouse/skills/clickhouse/references/backup-restore.md deleted file mode 100644 index 6e7d40d..0000000 --- a/clickhouse/skills/clickhouse/references/backup-restore.md +++ /dev/null @@ -1,362 +0,0 @@ -# ClickHouse Backup & Restore - -Backup strategies, disaster recovery, and data protection. - -## Backup Strategies Comparison - -| Strategy | Pros | Cons | Use Case | -|----------|------|------|----------| -| **clickhouse-backup** | Full-featured, S3 support, incremental | External tool | Production (recommended) | -| **BACKUP statement** | Native, SQL-based, async | Newer feature (v23.6+) | Simple setups | -| **Snapshot** | Instant, consistent | Cloud-only, requires coordination | Cloud deployments | -| **rsync** | Simple, no dependencies | Downtime required | Small setups, emergencies | - -## clickhouse-backup (Recommended) - -### Installation - -See the [official clickhouse-backup documentation](https://github.com/AlexAkulov/clickhouse-backup#installation) for installation instructions using: -- Docker images -- DEB/RPM packages -- Helm charts (for Kubernetes) -- Building from source - -### Configuration - -```yaml -# /etc/clickhouse-backup/config.yml -general: - remote_storage: s3 - max_file_size: 1073741824 - disable_progress_bar: false - backups_to_keep_local: 5 - backups_to_keep_remote: 10 - -clickhouse: - username: default - password: "" # ⚠️ Use proper secret management in production - host: localhost - port: 9000 - debug: false - sync_replicated_tables: true - skip_table_engines: [Dictionary, View, Set, Join] - skip_tables: [system.*, temporary_*.*, information_schema*] - -s3: - access_key: AKIAIOSFODNN7EXAMPLE # ⚠️ Placeholder - use AWS IAM roles or proper secrets - secret_key: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY # ⚠️ Placeholder - bucket: clickhouse-backups - endpoint: https://s3.amazonaws.com - region: us-west-2 - acl: private - force_path_style: false - path: /backups/ - -# GCS configuration -gcs: - credentials_file: /path/to/service-account.json - bucket: clickhouse-backups - path: /backups/ - -# Azure configuration -azblob: - account_name: myaccount - account_key: mykey - container: clickhouse-backups - path: /backups/ -``` - -### Commands - -```bash -# Create local backup -clickhouse-backup create my_backup - -# Upload to remote storage -clickhouse-backup upload my_backup - -# List backups -clickhouse-backup list - -# Download from remote -clickhouse-backup download my_backup - -# Restore from backup -clickhouse-backup restore my_backup - -# Restore specific tables -clickhouse-backup restore my_backup -t my_db.my_table - -# Create and upload in one command -clickhouse-backup create my_backup --upload - -# Delete backup -clickhouse-backup delete local my_backup -clickhouse-backup delete remote my_backup -``` - -### Incremental Backups - -```bash -# Differential backup (only changes since last) -clickhouse-backup create --diff-from=previous_backup my_backup - -# Upload -clickhouse-backup upload my_backup -``` - -### Backup Automation - -```bash -# Cron job for daily backups -0 2 * * * clickhouse-backup create "daily-$(date +\%Y\%m\%d)" --upload >/dev/null 2>&1 - -# Cron job for weekly full backup -0 3 * * 0 clickhouse-backup create "weekly-$(date +\%Y\%m\%d)" --upload >/dev/null 2>&1 - -# Cron job to clean old backups -0 4 * * * clickhouse-backup delete local --clickhouse-backup /etc/clickhouse-backup/config.yml >/dev/null 2>&1 -``` - -## BACKUP Statement (v23.6+) - -### Backup to Disk - -```sql --- Backup entire database -BACKUP DATABASE my_db TO DISK('backups/my_db'); - --- Backup specific tables -BACKUP TABLE my_db.table1, my_db.table2 TO DISK('backups/partial'); - --- Backup with pattern -BACKUP DATABASE my_db.* TO DISK('backups/my_db'); - --- Async backup -BACKUP DATABASE my_db TO DISK('backups/my_db') SETTINGS async=true; -``` - -### Backup to S3 - -```sql --- Backup to S3 -BACKUP DATABASE my_db TO S3('https://bucket.s3.amazonaws.com/backups/my_db'); - --- With credentials -BACKUP DATABASE my_db TO S3( - 'https://bucket.s3.amazonaws.com/backups/my_db', - 'access_key', - 'secret_key' -); -``` - -### Restore - -```sql --- Restore database -RESTORE DATABASE my_db FROM DISK('backups/my_db'); - --- Restore with new name -RESTORE DATABASE my_db AS my_db_new FROM DISK('backups/my_db'); - --- Restore specific tables -RESTORE TABLE my_db.table1 FROM DISK('backups/partial'); - --- Async restore -RESTORE DATABASE my_db FROM DISK('backups/my_db') SETTINGS async=true; -``` - -### Backup Status - -```sql --- Check backup status -SELECT * FROM system.backups; - --- List backups -SELECT name, status, size -FROM system.backups -ORDER BY creation_time DESC; -``` - -## Snapshot-Based Backup - -### EBS Snapshots (AWS) - -```bash -# 1. Freeze filesystem -clickhouse-client --query="SYSTEM FREEZE TABLES;" - -# 2. Take snapshot -aws ec2 create-snapshot \ - --volume-id vol-xxxxxxxx \ - --description "ClickHouse backup $(date +%Y-%m-%d)" - -# 3. Unfreeze -clickhouse-client --query="SYSTEM UNFREEZE TABLES;" - -# 4. Cleanup old snapshots (keep last 7 days) -aws ec2 describe-snapshots \ - --filters Name=description,Values="ClickHouse backup*" \ - --query 'Snapshots[?StartTime<`$(date -d '7 days ago' +%Y-%m-%d)`].SnapshotId' \ - --output text | xargs -I {} aws ec2 delete-snapshot --snapshot-id {} -``` - -### GCE Persistent Disks - -```bash -# 1. Freeze tables -clickhouse-client --query="SYSTEM FREEZE TABLES;" - -# 2. Create snapshot -gcloud compute disks snapshot clickhouse-disk \ - --snapshot-names clickhouse-snapshot-$(date +%Y%m%d) - -# 3. Unfreeze -clickhouse-client --query="SYSTEM UNFREEZE TABLES;" -``` - -## Filesystem-Based Backup - -### Using rsync - -```bash -# Stop ClickHouse -systemctl stop clickhouse-server - -# Backup data directory -rsync -av --delete /var/lib/clickhouse/ /backup/clickhouse/ - -# Start ClickHouse -systemctl start clickhouse-server -``` - -### Using cp - -```bash -# Stop ClickHouse -systemctl stop clickhouse-server - -# Copy data directory -cp -r /var/lib/clickhouse/ /backup/clickhouse/ - -# Start ClickHouse -systemctl start clickhouse-server -``` - -## Disaster Recovery - -### Complete Restore Procedure - -For disaster recovery procedures, see the [clickhouse-backup documentation](https://github.com/AlexAkulov/clickhouse-backup#restore-commands). - -Key considerations: -- Always verify backup integrity before restore -- Test restore procedures in non-production environments -- Use clickhouse-backup's built-in restore commands rather than manual filesystem operations -- Consider restoring to a new database/cluster first to verify data integrity - -### Point-in-Time Recovery - -```sql --- 1. Find backup -SELECT * FROM system.backups -WHERE creation_time >= '2024-01-01 00:00:00' - AND creation_time <= '2024-01-01 12:00:00' -ORDER BY creation_time DESC -LIMIT 1; - --- 2. Restore to new database -RESTORE DATABASE my_db AS my_db_pit -FROM DISK('backups/my_db_20240101'); - --- 3. Export needed data --- 4. Import to production -``` - -### Data Migration - -```bash -# Using clickhouse-backup -clickhouse-backup create migration_backup -clickhouse-backup upload migration_backup - -# On new cluster -clickhouse-backup download migration_backup -clickhouse-backup restore migration_backup - -# Using clickhouse-copier for large clusters -# Configure and run: -clickhouse-copier --config=config.xml --base-dir=/tmp/ -``` - -## Backup Verification - -### Check Backup Integrity - -```sql --- Verify row counts after restore -SELECT - database, - table, - sum(rows) as row_count -FROM system.parts -WHERE active = 1 -GROUP BY database, table -ORDER BY database, table; - --- Compare checksums -SELECT - table, - sum(bytes_on_disk) as size, - checksum(*) as checksum -FROM system.parts -WHERE active = 1 -GROUP BY table; -``` - -### Test Restore Procedure - -```bash -# 1. Create test database -clickhouse-client --query="CREATE DATABASE test_restore;" - -# 2. Restore to test database -clickhouse-backup restore my_backup -d my_db --db-target test_restore - -# 3. Verify data -clickhouse-client --query="SELECT count() FROM test_restore.events" - -# 4. Drop test database -clickhouse-client --query="DROP DATABASE test_restore;" -``` - -## Best Practices - -1. **Automate backups** - Use cron or Kubernetes cronjobs -2. **Test restores** - Regularly test restore procedure -3. **Offsite storage** - Store backups in S3/GCS/Azure -4. **Retention policy** - Keep 7-30 daily, 4-12 weekly backups -5. **Monitor backups** - Alert on backup failures -6. **Document RTO/RPO** - Define recovery objectives -7. **Encrypt backups** - Use encryption for sensitive data -8. **Version control** - Track backup configuration - -## Backup Checklist - -- [ ] Automated daily backups configured -- [ ] Backups stored offsite (S3, GCS, Azure) -- [ ] Retention policy defined -- [ ] Test restore procedure documented -- [ ] Backup monitoring configured -- [ ] Disaster recovery plan documented -- [ ] RTO/RPO defined -- [ ] Encryption enabled for sensitive data -- [ ] Backup size monitored and optimized -- [ ] Incremental backups configured - -## See Also - -- `../SKILL.md` - Main skill entry point -- `debugging.md` - Troubleshooting backup issues -- `cluster-management.md` - Replication for high availability -- `monitoring.md` - Backup monitoring and health checks diff --git a/clickhouse/skills/clickhouse/references/best-practices.md b/clickhouse/skills/clickhouse/references/best-practices.md deleted file mode 100644 index 4b6b1e5..0000000 --- a/clickhouse/skills/clickhouse/references/best-practices.md +++ /dev/null @@ -1,290 +0,0 @@ -# ClickHouse Best Practices - -Comprehensive checklist and anti-patterns for ClickHouse. - -## Schema Design Checklist - -- [ ] **ORDER BY matches query WHERE patterns** - - Most selective filter first - - Time-series: timestamp as second column - - Limit to 3-4 columns - -- [ ] **Partitioning aligned with TTL/DROP needs** - - Time-based: Monthly or daily partitions - - Aim for 100-1000 parts total - - Use `toYYYYMM()` for monthly - -- [ ] **Primary key is subset of ORDER BY** - - Reduces primary key size - - Must be prefix of ORDER BY - -- [ ] **Used smallest sufficient types** - - UInt8 vs UInt32 vs UInt64 - - Date vs DateTime (2 bytes vs 4 bytes) - - Decimal for currency - -- [ ] **Used LowCardinality for enum-like strings** - - < 10k distinct values - - Significant compression - -- [ ] **Avoided Nullable when possible** - - Use default values instead - - Nullable has overhead - -- [ ] **Avoided MODIFY/DROP COLUMN** - - Use ADD COLUMN only - - Create new tables for schema changes - -## Query Writing Checklist - -- [ ] **Smaller table on RIGHT side of JOIN** - - ClickHouse sends RIGHT table to all shards - - Minimize network transfer - -- [ ] **Used GLOBAL JOIN for distributed queries** - - Prevents sending right table multiple times - -- [ ] **Added skip indexes for frequent filters** - - Bloom filter for exact match - - Minmax for range queries - - Set for IN queries - -- [ ] **Leveraged projections for common aggregations** - - Pre-computed aggregations - - Automatic usage - -- [ ] **Avoided SELECT *** - - Reads all columns (columnar penalty) - - Select only needed columns - -- [ ] **Used EXPLAIN to verify index usage** - - Look for "Index" in output - - Avoid "Filter" (full scan) - -- [ ] **Set reasonable max_memory_usage** - - Prevent OOM errors - - Tune based on available memory - -- [ ] **Used SAMPLE for exploratory queries** - - Fast approximate results - - `SELECT ... SAMPLE 0.1` - -## Performance Checklist - -- [ ] **Monitored merges (system.merges)** - - Active merges impact performance - - Check merge queue size - -- [ ] **Checked mutation progress** - - Mutations are expensive - - Monitor `system.mutations` - -- [ ] **Used TTL instead of DELETE** - - Automatic data lifecycle - - No mutation overhead - -- [ ] **Preferred INSERT over UPDATE/DELETE** - - Append-first design - - Mutations rewrite all data - -- [ ] **Set appropriate max_block_size** - - Default: 65536 - - Larger for bulk inserts - -- [ ] **Enabled async_insert for frequent small inserts** - - Reduces merge overhead - - `async_insert = 1` - -- [ ] **Configured appropriate index_granularity** - - Default: 8192 - - Smaller = larger index - -- [ ] **Used AggregatingMergeTree for pre-aggregation** - - Materialize aggregations on write - - Fast query performance - -## Operations Checklist - -- [ ] **Automated backups (clickhouse-backup)** - - Daily backups - - Offsite storage (S3) - -- [ ] **Monitoring dashboards (Grafana)** - - Query performance - - Merge queue - - Replication lag - -- [ ] **Alert on replication lag > 5s** - - Check `system.replication_queue` - - ZooKeeper health - -- [ ] **Alert on merge queue > 1000** - - Too many parts - - Consider `OPTIMIZE FINAL` - -- [ ] **Tested disaster recovery** - - Backup restore procedure - - Documented RTO/RPO - -- [ ] **Documented partition retention policy** - - TTL configuration - - DROP PARTITION schedule - -- [ ] **Configured ZooKeeper session timeout** - - Prevent expiration - - Default: 30 seconds - -- [ ] **Set up query logging** - - `system.query_log` - - TTL for log retention - -## Cluster Management Checklist - -- [ ] **Used ReplicatedMergeTree for production** - - Data replication - - Automatic failover - -- [ ] **Configured proper sharding keys** - - Even data distribution - - Consider query patterns - -- [ ] **Set up distributed tables** - - Query across cluster - - Transparent to application - -- [ ] **Monitored cluster health** - - All replicas online - - Replication lag minimal - -- [ ] **Configured load balancing** - - Round-robin or random - - `load_balancing` setting - -- [ ] **Set up cross-DC replication** - - Disaster recovery - - Geographic distribution - -- [ ] **Documented cluster topology** - - Shard/replica mapping - - Network configuration - -- [ ] **Automated failover testing** - - Replica failure - - ZooKeeper failure - -## Anti-Patterns - -### Schema Anti-Patterns - -| Anti-Pattern | Why It's Bad | Better Approach | -|--------------|--------------|-----------------| -| Updating/deleting single rows | Mutations rewrite all data | Use TTL or new tables | -| Too many partitions | Slow queries, high overhead | Aim for 100-1000 parts | -| SELECT * | Reads all columns | Select only needed columns | -| ORDER BY not matching queries | Can't leverage index | Match query WHERE patterns | -| Ignoring merge performance | Background merges impact queries | Monitor system.merges | -| Using mutations for bulk changes | Expensive rewrites | Use INSERT + new tables | -| String comparison for dates | Full scan | Use date functions on column | -| Suboptimal JOIN order | Larger network transfer | Smaller table on RIGHT | - -### Query Anti-Patterns - -| Anti-Pattern | Why It's Bad | Better Approach | -|--------------|--------------|-----------------| -| Function on column in WHERE | Can't use index | Apply function to literal | -| Large table on RIGHT of JOIN | More network transfer | Smaller table on RIGHT | -| No GLOBAL JOIN on distributed | Repeated data transfer | Add GLOBAL keyword | -| SELECT * for wide tables | Reads all columns | Select specific columns | -| Suboptimal date filtering | Full scan | Use date range: `>= today() AND < tomorrow()` | - -### Operations Anti-Patterns - -| Anti-Pattern | Why It's Bad | Better Approach | -|--------------|--------------|-----------------| -| No backups | Data loss risk | Automate with clickhouse-backup | -| Ignoring merge queue | Performance degradation | Monitor and optimize | -| No replication | Single point of failure | Use ReplicatedMergeTree | -| Skipping ZooKeeper monitoring | Cluster can go read-only | Monitor ZK health | -| No query logging | Can't debug issues | Enable query_log | - -## Code Examples - -### Good Schema - -```sql --- ✅ Good: Matches query patterns -CREATE TABLE events ( - timestamp DateTime, - user_id UInt32, - event_type LowCardinality(String), - revenue Decimal(18, 2) DEFAULT 0 -) -ENGINE = MergeTree() -PARTITION BY toYYYYMM(timestamp) -- Monthly partitions -ORDER BY (user_id, timestamp) -- Matches queries -SAMPLE BY user_id -- Enable sampling -TTL timestamp + INTERVAL 90 DAY; -- Auto cleanup -``` - -### Bad Schema - -```sql --- ❌ Bad: ORDER BY doesn't match queries -CREATE TABLE events ( - timestamp DateTime, - user_id UInt32, - event_type String, - revenue Nullable(Decimal(18, 2)) -) -ENGINE = MergeTree() -PARTITION BY toYYYYMM(timestamp) -ORDER BY (timestamp); -- Queries filter by user_id first! -``` - -### Good Query - -```sql --- ✅ Good: Uses index, selective columns -SELECT - user_id, - count() as events, - sum(revenue) as total_revenue -FROM events -WHERE timestamp >= today() AND timestamp < tomorrow() - AND user_id = 123 -GROUP BY user_id; -``` - -### Bad Query - -```sql --- ❌ Bad: Function on column, SELECT * -SELECT * FROM events -WHERE toDate(timestamp) = today(); -``` - -## Monitoring Queries - -```sql --- Health check -SELECT 'uptime' as metric, toString(uptime()) as value -UNION ALL SELECT 'version', version() -UNION ALL SELECT 'replicas_lagging', toString(count()) -FROM system.replication_queue WHERE delay > 5 -UNION ALL SELECT 'mutations_running', toString(count()) -FROM system.mutations WHERE is_done = 0; - --- Merge queue -SELECT database, table, count() as parts -FROM system.parts -WHERE active = 1 -GROUP BY database, table -HAVING parts > 1000; -``` - -## See Also - -- `../SKILL.md` - Main skill entry point -- `schema-design.md` - Database engines and schema organization -- `query-optimization.md` - Query performance tuning -- `monitoring.md` - Health checks and monitoring queries diff --git a/clickhouse/skills/clickhouse/references/cluster-management.md b/clickhouse/skills/clickhouse/references/cluster-management.md deleted file mode 100644 index 242e4ac..0000000 --- a/clickhouse/skills/clickhouse/references/cluster-management.md +++ /dev/null @@ -1,374 +0,0 @@ -# ClickHouse Cluster Management - -Distributed tables, replication, sharding, and cluster operations. - -## Cluster Configuration - -### Define Cluster - -```xml - - - - - - - node1.example.com - 9000 - - - - - node2.example.com - 9000 - - - - - -``` - -### Cluster Macros - -```xml - - - - 01 - replica_1 - - -``` - -## Distributed Tables - -### Create Distributed Table - -```sql --- Create local table on each shard -CREATE TABLE local_events ON CLUSTER my_cluster ( - timestamp DateTime, - user_id UInt32, - event String -) -ENGINE = MergeTree() -PARTITION BY toYYYYMM(timestamp) -ORDER BY (user_id, timestamp); - --- Create distributed table (sharding) -CREATE TABLE distributed_events ON CLUSTER my_cluster AS local_events -ENGINE = Distributed( - 'my_cluster', -- Cluster name - currentDatabase(), -- Database - 'local_events', -- Local table name - rand() -- Sharding key -); - --- Query distributed table -SELECT * FROM distributed_events; -``` - -### Sharding Strategies - -```sql --- Random sharding -ENGINE = Distributed(cluster, db, table, rand()) - --- By user ID (consistent) -ENGINE = Distributed(cluster, db, table, intHash32(user_id)) - --- By date -ENGINE = Distributed(cluster, db, table, toYYYYMM(date)) - --- Composite sharding -ENGINE = Distributed(cluster, db, table, (tenant_id, user_id)) - --- No sharding (all data on all shards) -ENGINE = Distributed(cluster, db, table, const) -``` - -### Distributed DDL - -```sql --- Create table on all shards -CREATE TABLE table_name ON CLUSTER my_cluster ( - id UInt32, - value String -) -ENGINE = MergeTree() -ORDER BY id; - --- Drop table on all shards -DROP TABLE table_name ON CLUSTER my_cluster; - --- Alter table on all shards -ALTER TABLE table_name ON CLUSTER my_cluster ADD COLUMN new_col String; -``` - -## Replication - -### ReplicatedMergeTree Setup - -```sql --- On replica 1 -CREATE TABLE events ON CLUSTER my_cluster ( - timestamp DateTime, - user_id UInt32 -) -ENGINE = ReplicatedMergeTree( - '/clickhouse/tables/{shard}/events', -- ZooKeeper path - '{replica}' -- Replica name -) -PARTITION BY toYYYYMM(timestamp) -ORDER BY (user_id, timestamp); - --- On replica 2 (same DDL, macros handle replica name) --- {replica} macro resolves to 'replica_2' -``` - -### Add Replica to Existing Table - -```sql --- Stop replication sends -SYSTEM STOP REPLICATED SENDS database.table; - --- Copy data to new replica --- (rsync or clickhouse-backup) - --- Start replication -SYSTEM START REPLICATED SENDS database.table; -``` - -### Replica Management - -```sql --- Check replica status -SELECT - database, - table, - is_leader, - is_readonly, - queue_size, - absolute_delay -FROM system.replicas; - --- Check replication queue -SELECT * FROM system.replication_queue -WHERE delay > 5 -ORDER BY delay DESC; -``` - -## Cluster Operations - -### Cluster Information - -```sql --- Show all clusters -SELECT * FROM system.clusters; - --- Cluster nodes -SELECT - cluster, - shard_num, - replica_num, - host_name, - port, - user -FROM system.clusters -WHERE cluster = 'my_cluster'; - --- Cluster health -SELECT - cluster, - sum(error_count) as errors, - sum(num_requests) as requests -FROM system.clusters -GROUP BY cluster; -``` - -### Query Across Cluster - -```sql --- Query all shards -SELECT * FROM clusterAllReplicas( - 'my_cluster', - system.functions -) LIMIT 1; - --- Execute on all nodes -SELECT * FROM remote( - 'node1, node2, node3', - system.dictionaries -); - --- Query specific shard -SELECT * FROM cluster( - 'my_cluster', - 1, -- shard - 0, -- replica - system.query_log -) LIMIT 1; -``` - -### Distributed INSERT - -```sql --- Insert into distributed table (shards data) -INSERT INTO distributed_events VALUES (now(), 123, 'login'); - --- Insert into distributed table with specific shard -INSERT INTO distributed_events SHARD 1 VALUES (now(), 456, 'logout'); -``` - -## Cross-Replication - -### Multi-Datacenter Setup - -```sql --- Multiple datacenters -CREATE TABLE events ( - ... -) -ENGINE = ReplicatedMergeTree( - '/clickhouse/tables/{shard}/events', - '{replica}' -) --- On DC1: shards 1-2, replicas a-b --- On DC2: shards 1-2, replicas c-d -``` - -**Configuration:** -```xml - - - - true - - dc1-node1 - - - dc2-node1 - - - - -``` - -## Load Balancing - -### Load Balancing Settings - -```sql --- Load balancing modes -SET load_balancing = 'random'; -- Random replica -SET load_balancing = 'nearest_hostname'; -- Hostname-based -SET load_balancing = 'in_order'; -- Sequential - --- Failover settings -set failover = 1; -- Enable failover -set failover_by_hostname = 1; -- Hostname-based failover - --- Defaults for distributed table -SETTINGS - load_balancing = 'random', - weights_by_node = 'dc1=1,dc2=1'; -- Weight distribution -``` - -## Cluster Monitoring - -### Cluster Health - -```sql --- Comprehensive cluster health -SELECT - host_address() as host, - 'uptime' as metric, - toString(uptime()) as value -UNION ALL -SELECT host_address(), 'version', version() -UNION ALL -SELECT host_address(), 'replicas_lagging', toString(count()) -FROM system.replication_queue WHERE delay > 5 -UNION ALL -SELECT host_address(), 'mutations_running', toString(count()) -FROM system.mutations WHERE is_done = 0; - --- All cluster nodes status -SELECT * FROM cluster('my_cluster', all, 1, system.replicas); -``` - -### Replication Lag Monitoring - -```sql --- Replication lag across cluster -SELECT - host_address() as host, - database, - table, - max(delay) as max_lag -FROM system.replication_queue -WHERE delay > 0 -GROUP BY host, database, table; -``` - -## Cluster Maintenance - -### Add Shard - -```sql --- 1. Install ClickHouse on new node --- 2. Add to remote_servers config --- 3. Create local tables on new shard --- 4. Restart cluster --- 5. Redistribute data (manual or using clickhouse-copier) -``` - -### Remove Shard - -```sql --- 1. Drop data from shard --- 2. Remove from remote_servers config --- 3. Restart cluster --- 4. Update distributed tables -``` - -### Data Migration - -```sql --- Using clickhouse-copier for data migration --- Config file: - - old-cluster - 9000 - - - new-cluster - 9000 - - - -
- db - table - db - table -
- -``` - -## Best Practices - -1. **Always use ReplicatedMergeTree** for production -2. **Configure proper sharding keys** for even distribution -3. **Monitor replication lag** (alert if > 5s) -4. **Use `GLOBAL JOIN`** for distributed queries with dimension tables -5. **Set up ZooKeeper monitoring** (ZK outage = read-only) -6. **Test failover** regularly -7. **Document cluster topology** (shard/replica mapping) - -## See Also - -- `../SKILL.md` - Main skill entry point -- `core-concepts.md` - Architecture and data model -- `debugging.md` - Replication troubleshooting -- `monitoring.md` - Cluster health checks diff --git a/clickhouse/skills/clickhouse/references/core-concepts.md b/clickhouse/skills/clickhouse/references/core-concepts.md deleted file mode 100644 index 3b2e8c5..0000000 --- a/clickhouse/skills/clickhouse/references/core-concepts.md +++ /dev/null @@ -1,240 +0,0 @@ -# ClickHouse Core Concepts - -## Architecture Overview - -### Columnar Storage - -ClickHouse stores data by columns, not rows: - -**Benefits:** -- Read only needed columns (10-100x faster for analytical queries) -- Excellent compression (similar data types stored together) -- Efficient for wide tables (100+ columns) with selective reads - -**Trade-offs:** -- Slower single-row reads (must read all columns) -- Not optimal for point queries or OLTP - -### Two-Level Index Structure - -``` -┌─────────────────────────────────────┐ -│ Sparse Index (one mark per 8192 rows) │ -├─────────────────────────────────────┤ -│ Mark Files (point to data blocks) │ -├─────────────────────────────────────┤ -│ Compressed Column Data │ -└─────────────────────────────────────┘ -``` - -- **Sparse index**: One mark per 8192 rows (configurable via `index_granularity`) -- **Mark files**: Point to compressed data blocks -- **Query execution**: Uses marks to skip irrelevant data - -```sql --- Check index granularity setting -SELECT index_granularity FROM system.tables -WHERE database = currentDatabase() AND table = 'my_table'; - --- Adjust index granularity (affects mark count) -CREATE TABLE ... SETTINGS index_granularity = 4096; -``` - -### Merge Process - -Background merges continuously organize data: - -**Merge Lifecycle:** -1. New data inserted as small parts -2. Background merges combine parts (exponential backoff) -3. Parts grow from MB → GB → TB -4. Merges can be CPU/disk intensive - -**Monitoring Merges:** -```sql --- Active merges -SELECT table, elapsed, bytes_read_uncompressed, rows_read -FROM system.merges -ORDER BY elapsed DESC; - --- Merge queue size -SELECT database, table, count() as parts -FROM system.parts -WHERE active = 1 AND rows > 0 -GROUP BY database, table -HAVING parts > 1000; -``` - -### Distributed Query Execution - -``` -┌─────────────┐ -│ Coordinator │ -└──────┬──────┘ - │ - ├── Shard 1 ── Query Local Data - ├── Shard 2 ── Query Local Data - └── Shard 3 ── Query Local Data - │ - └── Merge Results -``` - -- Coordinator node shards query across replicas -- Each shard processes local data in parallel -- Coordinator merges and returns results - -## Data Model - -### Append-First Design - -ClickHouse is optimized for appends, not in-place updates: - -**Characteristics:** -- No in-place updates (mutations are expensive rewrite operations) -- Data organized as immutable parts -- Parts merge over time (background process) - -**Parts vs Partitions:** -- **Partition**: Logical division (e.g., monthly `202401`, `202402`) -- **Part**: Physical data file on disk -- Typical: 100-1000 parts per partition -- Too many parts = slow queries, high merge overhead - -### MVCC and Versioning - -ClickHouse offers several patterns for versioned data: - -**ReplacingMergeTree**: Keeps latest version per ORDER BY key -```sql -CREATE TABLE user_profiles ( - user_id UInt32, - updated_at DateTime, - profile String -) -ENGINE = ReplacingMergeTree(updated_at) -ORDER BY user_id; -``` - -**CollapsingMergeTree**: Uses sign column for insert/delete -```sql -CREATE TABLE changes ( - id UInt32, - sign Int8, -- 1 = insert, -1 = delete - data String -) -ENGINE = CollapsingMergeTree(sign) -ORDER BY id; -``` - -### ZooKeeper Coordination - -ReplicatedMergeTree uses ZooKeeper for coordination: - -**ZooKeeper stores:** -- Schema metadata -- Part metadata -- Replication status -- Merge queue - -**ZooKeeper considerations:** -- ZK outage = read-only cluster (can't insert) -- High ZK load can impact performance -- Monitor ZK connection health - -```sql --- Check ZK connection -SELECT * FROM system.zookeeper WHERE path = '/'; - --- Check replication queue -SELECT * FROM system.replication_queue; -``` - -## When ClickHouse Shines - -### Ideal Use Cases - -✅ **Wide tables** (100+ columns), read few columns -✅ **Time-series** with time-based filters -✅ **Aggregations** over billions of rows -✅ **Append-only workloads** (events, logs, metrics) -✅ **Real-time analytics** (sub-second responses) -✅ **Histograms** and quantiles over large datasets - -### Example Workloads - -```sql --- Events/analytics (ideal) -SELECT user_id, count() as events -FROM events -WHERE timestamp >= today() - INTERVAL 7 DAY -GROUP BY user_id; - --- Time-series (ideal) -SELECT toDate(timestamp) as date, sum(revenue) -FROM events -WHERE timestamp >= now() - INTERVAL 30 DAY -GROUP BY date -ORDER BY date; - --- Aggregations (ideal) -SELECT percentile(duration, [50, 90, 99]) as p50_p90_p99 -FROM requests -WHERE timestamp >= today(); -``` - -## When to Avoid ClickHouse - -### Poor Use Cases - -❌ **Point updates/deletes**: Use row store (PostgreSQL, MySQL) -❌ **Heavy JOINs** on non-sorted keys: Consider data warehouse -❌ **Complex transactions**: No ACID support -❌ **Low-latency OLTP**: Use row store -❌ **Unstructured data**: Use document store (MongoDB) -❌ **Single-row lookups**: Use key-value store (Redis) - -### Anti-Patterns - -```sql --- ❌ Point updates (expensive mutation) -UPDATE events SET status = 'done' WHERE event_id = 123; - --- ✅ Use TTL or new table instead -ALTER TABLE events MODIFY TTL timestamp + INTERVAL 90 DAY; --- OR -INSERT INTO events_done SELECT * FROM events WHERE status = 'done'; - --- ❌ Single-row lookup -SELECT * FROM events WHERE event_id = 123; - --- ✅ Use row store or Redis for point queries -``` - -## Performance Characteristics - -### Query Performance - -| Query Type | ClickHouse | Row Store | -|------------|------------|-----------| -| Full table scan | ⚡ Fast | 🐌 Slow | -| Column-selective | ⚡ Very Fast | 🐌 Slow | -| Row-selective | 🐌 Slow | ⚡ Fast | -| Point lookup | 🐌 Slow | ⚡ Fast | -| Aggregation | ⚡ Very Fast | 🐌 Slow | - -### Data Types Performance - -| Type | Size | Compression | Use Case | -|------|------|-------------|----------| -| UInt8 | 1 byte | High | Enums, flags | -| UInt32 | 4 bytes | Medium | IDs, counters | -| UInt64 | 8 bytes | Low | Large IDs | -| String | Variable | Medium | Text data | -| LowCardinality(String) | Integer | Very High | < 10k distinct values | - -## See Also - -- `../SKILL.md` - Main skill entry point -- `schema-design.md` - Database engines and schema organization -- `table-design.md` - ORDER BY and partitioning strategies -- `query-optimization.md` - Query performance tuning diff --git a/clickhouse/skills/clickhouse/references/debugging.md b/clickhouse/skills/clickhouse/references/debugging.md index 8f7ba5b..7f7a6cd 100644 --- a/clickhouse/skills/clickhouse/references/debugging.md +++ b/clickhouse/skills/clickhouse/references/debugging.md @@ -389,4 +389,3 @@ SELECT * FROM system.zookeeper WHERE path = '/clickhouse/tables'; - `../SKILL.md` - Main skill entry point - `monitoring.md` - Health checks and monitoring queries -- `cluster-management.md` - Replication setup and configuration diff --git a/clickhouse/skills/clickhouse/references/external.md b/clickhouse/skills/clickhouse/references/external.md deleted file mode 100644 index e8720fd..0000000 --- a/clickhouse/skills/clickhouse/references/external.md +++ /dev/null @@ -1,202 +0,0 @@ -# External References - -Altinity Knowledge Base (200+ articles) and official ClickHouse documentation. - -## Altinity Knowledge Base - -### Schema Design - -| Topic | Link | -|-------|------| -| MergeTree Engine Guide | https://kb.altinity.com/altinity-kb-engines/mergetree/ | -| Primary Key vs Sorting Key | https://kb.altinity.com/altinity-kb-engines/mergetree/ | -| Partitioning Best Practices | https://kb.altinity.com/altinity-kb-queries-syntax/adjustable-table-partitioning/ | -| Codec Selection | https://kb.altinity.com/altinity-kb-schema-design/codecs/ | -| LowCardinality Performance | https://kb.altinity.com/altinity-kb-schema-design/lowcardinality/ | -| Projections | https://kb.altinity.com/altinity-kb-queries-syntax/clickhouse-projections/ | -| TTL Data Lifecycle | https://kb.altinity.com/altinity-kb-queries-syntax/ttl/ | - -### Query Optimization - -| Topic | Link | -|-------|------| -| JOIN Optimization | https://kb.altinity.com/altinity-kb-queries-syntax/join-optimization-tricks/ | -| GROUP BY Tricks | https://kb.altinity.com/altinity-kb-queries-syntax/group-by-tricks/ | -| Window Functions | https://kb.altinity.com/altinity-kb-queries-syntax/window-functions/ | -| Skip Indexes | https://kb.altinity.com/altinity-kb-engines/mergetree/skip-index/ | -| Query Profiling | https://kb.altinity.com/altinity-kb-queries-syntax/annotate-query/ | -| PREWHERE Optimization | https://kb.altinity.com/altinity-kb-queries-syntax/prewhere-clause/ | - -### Table Engines - -| Topic | Link | -|-------|------| -| ReplacingMergeTree | https://kb.altinity.com/altinity-kb-engines/mergetree/engines-mergetree-replacingmergetree/ | -| CollapsingMergeTree | https://kb.altinity.com/altinity-kb-engines/mergetree/collapsingmergetree/ | -| AggregatingMergeTree | https://kb.altinity.com/altinity-kb-engines/mergetree/aggregatingmergetree/ | -| SummingMergeTree | https://kb.altinity.com/altinity-kb-engines/mergetree/summingmergetree/ | -| ReplicatedMergeTree | https://kb.altinity.com/altinity-kb-engines/mergetree/replicatedmergetree/ | -| MergeTree Family Guide | https://kb.altinity.com/altinity-kb-engines/mergetree/ | - -### Operations - -| Topic | Link | -|-------|------| -| Monitoring Queries | https://kb.altinity.com/altinity-kb-setup-and-maintenance/clickhouse-monitoring/ | -| Backup with clickhouse-backup | https://kb.altinity.com/altinity-kb-setup-and-maintenance/differential-backups-using-clickhouse-backup/ | -| Replication Setup | https://kb.altinity.com/altinity-kb-setup-and-maintenance/converting-mergetree-to-replicated/ | -| Data Migration | https://kb.altinity.com/altinity-kb-setup-and-maintenance/data-migration/ | -| Schema Migrations | https://kb.altinity.com/altinity-kb-schema-design/alter-table-part-2/ | - -### Advanced Features - -| Topic | Link | -|-------|------| -| Materialized Views | https://kb.altinity.com/altinity-kb-schema-design/materialized-views/ | -| Mutations Guide | https://kb.altinity.com/altinity-kb-queries-syntax/mutations/ | -| Dictionaries | https://kb.altinity.com/altinity-kb-dictionaries/ | -| ZooKeeper Coordination | https://kb.altinity.com/altinity-kb-setup-and-maintenance/clickhouse-keeper-入门-altinity-kb/ | -| Distributed Tables | https://kb.altinity.com/altinity-kb-queries-syntax/distributed/ | - -### Integrations - -| Topic | Link | -|-------|------| -| Kafka Integration | https://kb.altinity.com/altinity-kb-integrations/kafka/ | -| S3 Storage | https://kb.altinity.com/altinity-kb-integrations/s3-and-object-storage/ | -| PostgreSQL Dictionary | https://kb.altinity.com/altinity-kb-dictionaries/example-of-postgresql-dictionary/ | -| MySQL Integration | https://kb.altinity.com/altinity-kb-integrations/mysql-integration/ | -| Prometheus Monitoring | https://kb.altinity.com/altinity-kb-setup-and-maintenance/clickhouse-monitoring/prometheus/ | - -### Troubleshooting - -| Topic | Link | -|-------|------| -| Common Issues | https://kb.altinity.com/altinity-kb-troubleshooting/ | -| Debugging Queries | https://kb.altinity.com/altinity-kb-troubleshooting/slow-queries/ | -| Merge Issues | https://kb.altinity.com/altinity-kb-troubleshooting/too-many-parts/ | -| Replication Issues | https://kb.altinity.com/altinity-kb-troubleshooting/replication-issues/ | - -## Official ClickHouse Documentation - -### Getting Started - -| Topic | Link | -|-------|------| -| Quick Start | https://clickhouse.com/docs/en/getting-started/ | -| Installation | https://clickhouse.com/docs/en/install/ | -| Tutorial | https://clickhouse.com/docs/en/tutorial/ | -| First Project | https://clickhouse.com/docs/en/getting-started/example-project/ | - -### SQL Reference - -| Topic | Link | -|-------|------| -| SELECT Syntax | https://clickhouse.com/docs/en/sql-reference/statements/select/ | -| INSERT Syntax | https://clickhouse.com/docs/en/sql-reference/statements/insert-into/ | -| ALTER TABLE | https://clickhouse.com/docs/en/sql-reference/statements/alter/ | -| CREATE TABLE | https://clickhouse.com/docs/en/sql-reference/statements/create/table/ | -| Functions | https://clickhouse.com/docs/en/sql-reference/functions/ | -| Aggregate Functions | https://clickhouse.com/docs/en/sql-reference/aggregate-functions/ | - -### Table Engines - -| Topic | Link | -|-------|------| -| Table Engines Overview | https://clickhouse.com/docs/en/engines/table-engines/ | -| MergeTree Family | https://clickhouse.com/docs/en/engines/table-engines/mergetree-family/ | -| Log Engines | https://clickhouse.com/docs/en/engines/table-engines/log-family/ | -| Integration Engines | https://clickhouse.com/docs/en/engines/table-engines/integrations/ | -| Special Engines | https://clickhouse.com/docs/en/engines/table-engines/special/ | - -### System Tables - -| Topic | Link | -|-------|------| -| System Tables Overview | https://clickhouse.com/docs/en/operations/system-tables/ | -| system.parts | https://clickhouse.com/docs/en/operations/system-tables/parts/ | -| system.processes | https://clickhouse.com/docs/en/operations/system-tables/processes/ | -| system.query_log | https://clickhouse.com/docs/en/operations/system-tables/query_log/ | -| system.merges | https://clickhouse.com/docs/en/operations/system-tables/merges/ | -| system.mutations | https://clickhouse.com/docs/en/operations/system-tables/mutations/ | -| system.replicas | https://clickhouse.com/docs/en/operations/system-tables/replicas/ | -| system.clusters | https://clickhouse.com/docs/en/operations/system-tables/clusters/ | - -### Operations - -| Topic | Link | -|-------|------| -| Configuration Files | https://clickhouse.com/docs/en/operations/configuration-files/ | -| Server Settings | https://clickhouse.com/docs/en/operations/server-configuration-parameters/ | -| User Management | https://clickhouse.com/docs/en/operations/access-rights/ | -| Queries Settings | https://clickhouse.com/docs/en/operations/settings/ | -| Performance Tuning | https://clickhouse.com/docs/en/operations/optimization/ | - -### Cluster Management - -| Topic | Link | -|-------|------| -| Distributed Tables | https://clickhouse.com/docs/en/engines/table-engines/special/distributed/ | -| Replication | https://clickhouse.com/docs/en/engines/table-engines/mergetree-family/replicatedmergetree/ | -| ClickHouse Keeper | https://clickhouse.com/docs/en/operations/clickhouse-keeper/ | -| Cluster Configuration | https://clickhouse.com/docs/en/operations/configuration-files/ | -| Data Skipping | https://clickhouse.com/docs/en/engines/table-engines/mergetree-family/mergetree/#data-skipping-indexes | - -### Backup & Restore - -| Topic | Link | -|-------|------| -| BACKUP Statement | https://clickhouse.com/docs/en/sql-reference/statements/backup/ | -| ClickHouse Backup | https://clickhouse.com/docs/en/operations/backup/ | -| Data Recovery | https://clickhouse.com/docs/en/operations/alter/#mutation | - -### Monitoring - -| Topic | Link | -|-------|------| -| Query Profiling | https://clickhouse.com/docs/en/sql-reference/statements/explain/ | -| Metrics | https://clickhouse.com/docs/en/operations/server-configuration-parameters/settings/ | -| Query Log | https://clickhouse.com/docs/en/operations/system-tables/query_log/ | -| Part Log | https://clickhouse.com/docs/en/operations/system-tables/part_log/ | - -### Integration - -| Topic | Link | -|-------|------| -| Kafka Engine | https://clickhouse.com/docs/en/engines/table-engines/integrations/kafka/ | -| S3 Table Function | https://clickhouse.com/docs/en/sql-reference/table-functions/s3/ | -| PostgreSQL Engine | https://clickhouse.com/docs/en/engines/table-engines/integrations/postgresql/ | -| MySQL Engine | https://clickhouse.com/docs/en/engines/table-engines/integrations/mysql/ | -| RabbitMQ Engine | https://clickhouse.com/docs/en/engines/table-engines/integrations/rabbitmq/ | - -### Kubernetes - -| Topic | Link | -|-------|------| -| Altinity Operator | https://github.com/Altinity/clickhouse-operator | -| Operator Docs | https://docs.altinity.com/clickhouse-operator/ | -| K8s Deployment | https://clickhouse.com/docs/en/guides/sre/ | - -### Community Resources - -| Resource | Link | -|----------|------| -| Slack Community | https://clickhouse.com/slack | -| GitHub | https://github.com/ClickHouse/ClickHouse | -| Stack Overflow | https://stackoverflow.com/questions/tagged/clickhouse | -| Reddit | https://reddit.com/r/ClickHouse | -| Forum | https://clickhouse.com/blog/en/ | - -## Training & Certification - -| Resource | Link | -|----------|------| -| ClickHouse Training | https://clickhouse.com/docs/en/training/ | -| Altinity Training | https://www.altinity.com/services/training/ | -| Certified Professional | https://clickhouse.com/certification/ | - -## See Also - -- `../SKILL.md` - Main skill entry point -- `best-practices.md` - Production-ready checklist -- All reference files - Topic-specific deep dives diff --git a/clickhouse/skills/clickhouse/references/integrations.md b/clickhouse/skills/clickhouse/references/integrations.md deleted file mode 100644 index 5f7737d..0000000 --- a/clickhouse/skills/clickhouse/references/integrations.md +++ /dev/null @@ -1,483 +0,0 @@ -# ClickHouse Integrations - -Kafka, S3, PostgreSQL, MySQL, RabbitMQ, and BI tools. - -> ⚠️ **Credential Security**: All credentials in examples below (`password123`, `AKIAIOSFODNN7EXAMPLE`, etc.) are **placeholders only**. Never use these in production. Use proper secret management: -> - Environment variables -> - Secret managers (AWS Secrets Manager, HashiCorp Vault, etc.) -> - Kubernetes secrets (for K8s deployments) -> - ClickHouse named collections with external configuration - -## Kafka Integration - -### Kafka Table Engine - -```sql -CREATE TABLE kafka_queue ( - timestamp UInt64, - level String, - message String -) -ENGINE = Kafka() -SETTINGS - kafka_broker_list = 'broker1:9092,broker2:9092', - kafka_topic_list = 'logs', - kafka_group_name = 'clickhouse_consumer', - kafka_format = 'JSONEachRow', - kafka_num_consumers = 2, - kafka_max_block_size = 65536, - kafka_skip_broken_messages = 100; -``` - -### Virtual Columns - -Kafka tables provide virtual columns: - -```sql --- Virtual columns available -SELECT - _topic, -- Kafka topic - _key, -- Message key - _offset, -- Message offset - _partition, -- Partition number - _timestamp -- Message timestamp -FROM kafka_queue; -``` - -### Materialized View for Streaming - -```sql --- Create target table -CREATE TABLE logs ( - timestamp DateTime, - level String, - message String -) -ENGINE = MergeTree() -ORDER BY (timestamp, level); - --- Create materialized view to consume continuously -CREATE MATERIALIZED VIEW consumer TO logs -AS SELECT - toDateTime(timestamp) as timestamp, - level, - message -FROM kafka_queue; - --- Data automatically flows from Kafka → MV → target table -``` - -### Kafka Settings - -| Setting | Description | Default | -|---------|-------------|---------| -| `kafka_broker_list` | Comma-separated brokers | Required | -| `kafka_topic_list` | Comma-separated topics | Required | -| `kafka_group_name` | Consumer group | Required | -| `kafka_format` | Input format | Required | -| `kafka_num_consumers` | Number of consumers | 1 | -| `kafka_max_block_size` | Block size for poll | 65536 | -| `kafka_skip_broken_messages` | Skip N broken messages | 0 | - -### Consumer Lag Monitoring - -```sql -SELECT - topic, - partition, - max_offset, - lag -FROM system.kafka_consumers; -``` - -## S3 Integration - -### S3 Table Engine - -```sql -CREATE TABLE s3_table ( - id UInt32, - data String, - timestamp DateTime -) -ENGINE = S3( - 'https://my-bucket.s3.amazonaws.com/data/*.parquet', - 'AWS_ACCESS_KEY', - 'AWS_SECRET_KEY', - 'Parquet' -); -``` - -### S3 Table Function - -```sql --- Query S3 directly -SELECT * FROM s3( - 'https://bucket.s3.amazonaws.com/data/*.csv', - 'access_key', - 'secret_key', - 'CSV' -); - --- With wildcards -SELECT * FROM s3( - 'https://bucket.s3.amazonaws.com/data/file-{000..999}.csv', - 'CSV' -); - --- With compression -SELECT * FROM s3( - 'https://bucket.s3.amazonaws.com/data/*.csv.gz', - 'CSV', - 'access_key', - 'secret_key' -); -``` - -### S3 Disk (Tiered Storage) - -```sql --- Configuration in config.xml - - - - /mnt/ssd/clickhouse/ - - - s3 - https://bucket.s3.amazonaws.com/clickhouse/ - - AKIAIOSFODNN7EXAMPLE - wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY - - - - - - - - hot_ssd - - - s3_cold - - - - - - --- Usage with TTL -CREATE TABLE events ( - timestamp DateTime, - data String -) -ENGINE = MergeTree() -ORDER BY timestamp -SETTINGS storage_policy = 'hot_cold' -TTL timestamp + INTERVAL 7 DAY TO DISK 's3_cold'; -``` - -**Production S3 Configuration:** Use IAM roles or externalized secrets: -```xml - - s3 - https://bucket.s3.amazonaws.com/clickhouse/ - - ${S3_ACCESS_KEY} - ${S3_SECRET_KEY} - -``` - -### S3 Caching - -```sql --- Enable filesystem cache -SELECT * FROM s3(...) -SETTINGS - filesystem_cache_name = 's3_cache', - enable_filesystem_cache = 1; -``` - -## PostgreSQL Integration - -### PostgreSQL Table Engine - -```sql -CREATE TABLE pg_table ( - id Int32, - name String, - created_at DateTime -) -ENGINE = PostgreSQL( - 'localhost:5432', - 'mydb', - 'users', - 'postgres', - 'password' -); -``` - -### PostgreSQL Table Function - -```sql --- Query PostgreSQL directly -SELECT * FROM postgresql( - 'localhost:5432', - 'mydb', - 'users', - 'postgres', - 'password' -) -WHERE active = true; -``` - -### PostgreSQL Dictionary - -```sql -CREATE DICTIONARY pg_users ( - user_id UInt32, - email String, - name String, - created_at DateTime -) -PRIMARY KEY user_id -SOURCE(POSTGRESQL( - port 5432 - host 'localhost' - db 'mydb' - table 'users' - user 'postgres' - password 'password' -)) -LIFETIME(60) -LAYOUT(HASHED()); -``` - -### Named Collections - -```xml - - - localhost - 5432 - postgres - secret - - -``` - -```sql --- Use named collection -SELECT * FROM postgresql( - 'pg_connection', - 'mydb', - 'users' -); -``` - -## MySQL Integration - -### MySQL Table Engine - -```sql -CREATE TABLE mysql_table ( - id Int32, - name String -) -ENGINE = MySQL( - 'localhost:3306', - 'mydb', - 'users', - 'mysql_user', - 'mysql_pass' -); -``` - -### MySQL Table Function - -```sql -SELECT * FROM mysql( - 'localhost:3306', - 'mydb', - 'users', - 'mysql_user', - 'mysql_pass' -); -``` - -### MySQL Dictionary - -```sql -CREATE DICTIONARY mysql_users ( - user_id UInt32, - email String -) -PRIMARY KEY user_id -SOURCE(MYSQL( - port 3306 - host 'localhost' - db 'mydb' - table 'users' - user 'mysql_user' - password 'mysql_pass' -)) -LIFETIME(60) -LAYOUT(HASHED()); -``` - -## RabbitMQ Integration - -```sql -CREATE TABLE rabbitmq_queue ( - timestamp DateTime, - data String -) -ENGINE = RabbitMQ() -SETTINGS - amqp_exchange = 'events', - amqp_exchange_type = 'fanout', - amqp_routing_key_list = 'events', - amqp_queue_base = 'clickhouse_consumer', - amqp_format = 'JSONEachRow', - amqp_host = 'localhost', - amqp_port = 5672, - amqp_user = 'guest', - amqp_password = 'guest'; -``` - -## MongoDB Integration - -```sql -SELECT * FROM mongodb( - 'localhost:27017', - 'mydb', - 'mycollection', - 'user', - 'password' -); -``` - -## Redis Integration - -### Redis Dictionary - -```sql -CREATE DICTIONARY redis_dict ( - key String, - value String -) -PRIMARY KEY key -SOURCE(REDIS( - host 'localhost' - port 6379 - db 0 - password 'password' -)) -LIFETIME(60) -LAYOUT(HASHED()); -``` - -### Redis Table Function - -```sql -SELECT * FROM redis( - 'localhost', - 6379, - 'mykey' -); -``` - -## BI Tools Integration - -### Tableau - -```bash -# Install ODBC driver -# Download from: https://github.com/ClickHouse/clickhouse-odbc - -# Configure DSN in /etc/odbcinst.ini -[ClickHouse] -Description = ClickHouse ODBC Driver -Driver = /usr/lib/libclickhouseodbc.so -Setup = /usr/lib/libclickhouseodbc_s.so -``` - -### Grafana - -```bash -# Install ClickHouse data source plugin -grafana-cli plugins install clickhouse-datasource - -# Configure in Grafana UI: -# - Host: http://clickhouse-server:8123 -# - Database: default -# - User: default -# - Password: (empty) -``` - -### Metabase - -```sql --- Native ClickHouse support --- Add connection in Metabase UI: --- - Database type: ClickHouse -# - Host: clickhouse-server -# - Port: 8123 -# - Database: mydb -# - Username: default -``` - -### Superset - -```python -# Install ClickHouse SQLAlchemy dialect -pip install clickhouse-sqlalchemy - -# Configure in Superset: -# Connection string: -# clickhouse+native://default:@clickhouse-server:9000/mydb -``` - -### Looker - -```yaml -# Looker connection configuration -connection: - dialect: clickhouse - host: clickhouse-server - port: 8123 - database: analytics - username: default - password: "" - ssl: false -``` - -## Data Import Tools - -### clickhouse-import - -```bash -# Import from CSV -clickhouse-import --query="INSERT INTO table FORMAT CSV" < data.csv - -# Import from JSON -clickhouse-import --query="INSERT INTO table FORMAT JSONEachRow" < data.json -``` - -### clickhouse-copier - -```bash -# Copy data between clusters -clickhouse-copier \ - --config=config.xml \ - --base-dir=/tmp/ \ - --src-cluster=production \ - --dst-cluster=staging \ - --tables=events -``` - -## See Also - -- `../SKILL.md` - Main skill entry point -- `cluster-management.md` - Distributed queries and sharding -- `monitoring.md` - Data pipeline monitoring diff --git a/clickhouse/skills/clickhouse/references/monitoring.md b/clickhouse/skills/clickhouse/references/monitoring.md index 759ca2d..65241ea 100644 --- a/clickhouse/skills/clickhouse/references/monitoring.md +++ b/clickhouse/skills/clickhouse/references/monitoring.md @@ -1,6 +1,6 @@ # ClickHouse Monitoring -Query monitoring, health checks, system queries, and metrics. +Query monitoring, health checks, system queries, and metrics. Ready-to-use queries against `system.*` tables. ## Current Query Monitoring @@ -497,14 +497,212 @@ clickhouse_table_size_bytes{table="events"} 4. **Table Sizes** - Top 10 tables by size - Growth rate +## See also -5. **System Resources** - - CPU usage - - Memory usage - - Disk usage +- `debugging.md` for troubleshooting + +## Table, column and partition details + +### Column Information + +```sql +-- Column sizes and compression +SELECT + database, + table, + column, + type, + formatReadableSize(sum(data_uncompressed_bytes)) as uncompressed, + formatReadableSize(sum(data_compressed_bytes)) as compressed, + sum(data_compressed_bytes) / sum(data_uncompressed_bytes) as ratio +FROM system.columns +WHERE database != 'system' +GROUP BY database, table, column, type +ORDER BY sum(data_uncompressed_bytes) DESC +LIMIT 50; + +-- All columns in a table +SELECT + name, + type, + default_kind, + default_expression, + comment +FROM system.columns +WHERE database = 'my_database' + AND table = 'my_table' +ORDER BY position; +``` + +### Partition Information + +```sql +-- Partition details +SELECT + partition, + sum(rows) as total_rows, + count() as parts, + formatReadableSize(sum(bytes)) as size, + min(min_timestamp) as min_time, + max(max_timestamp) as max_time +FROM system.parts +WHERE active = 1 + AND table = 'my_table' + AND database = currentDatabase() +GROUP BY partition +ORDER BY partition DESC; + +-- Large partitions (many parts) +SELECT + partition, + count() as parts, + sum(rows) as total_rows +FROM system.parts +WHERE active = 1 + AND table = 'my_table' +GROUP BY partition +HAVING parts > 100 +ORDER BY parts DESC; +``` + +--- + +## Databases, users and dictionaries + +## Database Information + +### All Databases + +```sql +-- All databases +SELECT + name, + engine, + data_path, + metadata_path +FROM system.databases +ORDER BY name; + +-- Database engine types +SELECT + engine, + count() as count +FROM system.databases +GROUP BY engine +ORDER BY count DESC; +``` + +--- + +## User and Security + +### User Information + +```sql +-- All users +SELECT * FROM system.users; + +-- User quotas +SELECT * FROM system.quotas; + +-- Current roles +SELECT * FROM system.current_roles; +``` + +### Access Control + +```sql +-- Row policies +SELECT * FROM system.row_policies; + +-- Grants +SELECT * FROM system.grants; +``` + +--- + +## System Health + +### General Health + +```sql +-- Server info +SELECT version(), uptime(), now() as current_time; + +-- Memory usage +SELECT + formatReadableSize(sum(bytes_allocated)) as allocated, + formatReadableSize(sum(bytes_used)) as used +FROM system.dictionaries; + +-- Load average +SELECT * FROM system.asynchronous_metrics +WHERE metric LIKE '%load%'; +``` + +### Settings + +```sql +-- All settings +SELECT * FROM system.settings +ORDER BY name; + +-- Current settings +SELECT * FROM system.settings +WHERE changed == 1; +``` + +--- + +## Dictionary Information + +### All Dictionaries + +```sql +-- Dictionary status +SELECT + name, + status, + origin, + type, + element_count, + bytes_allocated +FROM system.dictionaries +ORDER BY name; + +-- Loading dictionaries +SELECT + name, + status, + loading_start_time, + loading_duration_seconds +FROM system.dictionaries +WHERE status != 'LOADED'; +``` + +--- + +## Table growth over time + +```sql +-- Daily table growth +SELECT + toStartOfDay(event_time) as day, + database, + table, + formatReadableSize(sum(bytes)) as size +FROM system.part_log +WHERE event_type = 'NewPart' + AND event_time > now() - INTERVAL 7 DAY +GROUP BY day, database, table +ORDER BY day DESC, sum(bytes) DESC; +``` -## See Also +--- -- `../SKILL.md` - Main skill entry point -- `debugging.md` - Troubleshooting issues -- `system-queries.md` - Ready-to-use monitoring queries +**Tips**: +- Use `formatReadableSize()` for human-readable byte sizes +- Use `formatReadableQuantity()` for human-readable row counts +- Filter `WHERE active = 1` to see only active parts +- Use `currentDatabase()` to refer to current database +- Most `system.*` tables have `event_date` for partitioning diff --git a/clickhouse/skills/clickhouse/references/query-optimization.md b/clickhouse/skills/clickhouse/references/query-optimization.md index 16c5799..03f5a54 100644 --- a/clickhouse/skills/clickhouse/references/query-optimization.md +++ b/clickhouse/skills/clickhouse/references/query-optimization.md @@ -31,12 +31,12 @@ EXPLAIN ESTIMATE SELECT * FROM events WHERE user_id = 123; ### Rule: Smaller Table on RIGHT ```sql --- ✅ Good: Smaller table on RIGHT +-- GOOD: Good: Smaller table on RIGHT SELECT * FROM large_table lt RIGHT JOIN small_table st ON lt.id = st.id; --- ❌ Bad: Large table on RIGHT +-- BAD: Bad: Large table on RIGHT SELECT * FROM small_table st LEFT JOIN large_table lt ON lt.id = st.id; @@ -167,23 +167,23 @@ EXPLAIN SELECT * FROM events WHERE email = 'user@example.com'; ## Common Query Pitfalls ```sql --- ❌ SELECT * reads all columns (expensive in columnar store) +-- BAD: SELECT * reads all columns (expensive in columnar store) SELECT * FROM events; --- ✅ Select only needed columns +-- GOOD: Select only needed columns SELECT user_id, timestamp, event_type FROM events; --- ❌ Suboptimal WHERE (function on column) +-- BAD: Suboptimal WHERE (function on column) SELECT * FROM events WHERE toDate(timestamp) = today(); --- ✅ Use date functions on literal +-- GOOD: Use date functions on literal SELECT * FROM events WHERE timestamp >= today() AND timestamp < tomorrow(); --- ❌ String comparison for dates +-- BAD: String comparison for dates SELECT * FROM events WHERE toString(timestamp) LIKE '2024-01-01%'; --- ✅ Use date range +-- GOOD: Use date range SELECT * FROM events WHERE timestamp >= toDateTime('2024-01-01 00:00:00') AND timestamp < toDateTime('2024-01-02 00:00:00'); @@ -245,5 +245,4 @@ SET use_uncompressed_cache = 0; ## See Also - `../SKILL.md` - Main skill entry point -- `sql-reference.md` - Complete SQL dialect -- `table-design.md` - ORDER BY and indexing strategies +- `schema-design.md` - ORDER BY and indexing strategies diff --git a/clickhouse/skills/clickhouse/references/schema-design.md b/clickhouse/skills/clickhouse/references/schema-design.md index 8d6dbb3..1f47716 100644 --- a/clickhouse/skills/clickhouse/references/schema-design.md +++ b/clickhouse/skills/clickhouse/references/schema-design.md @@ -1,84 +1,310 @@ -# ClickHouse Schema Design +# ClickHouse schema design -Database engines, schema organization, and migration strategies. +ORDER BY, partitioning, column types, codecs, skip indexes, and schema migration. -## Database Engines +## ORDER BY Design (CRITICAL) -ClickHouse supports multiple database engines for different use cases: +The ORDER BY clause defines **data layout on disk** - the most important schema decision! -### Ordinary (Default) +### ORDER BY Design Principles + +1. **Match query WHERE patterns**: Most selective filter first +2. **Time-series**: Timestamp as second column (after dimension) +3. **High-cardinality first**: user_id before event_type +4. **Limit to 3-4 columns**: More columns = larger index + +### Examples ```sql -CREATE DATABASE my_db ENGINE = Ordinary; +-- GOOD: GOOD: ORDER BY matches query pattern +CREATE TABLE events ( + user_id UInt32, + event_timestamp DateTime, + event_type String +) +ENGINE = MergeTree() +ORDER BY (user_id, event_timestamp); + +-- Query leverages index (reads contiguous data) +SELECT * FROM events +WHERE user_id = 123 + AND event_timestamp >= now() - INTERVAL 1 DAY; + +-- BAD: BAD: ORDER BY doesn't match queries +CREATE TABLE events ( + user_id UInt32, + event_timestamp DateTime, + event_type String +) +ENGINE = MergeTree() +ORDER BY (event_timestamp); + +-- Query scans all data (timestamp-ordered, but filtering by user_id) +SELECT * FROM events WHERE user_id = 123; ``` -Simple database with no special features. Default engine for basic use. +### Primary Key vs Sorting Key + +```sql +-- Sorting key: defines data layout on disk +ORDER BY (user_id, event_timestamp, event_type) -### Atomic (Recommended for Production) +-- Primary key: subset of ORDER BY for row-level index +PRIMARY KEY (user_id, event_timestamp) + +-- Effect: +-- - Data on disk: sorted by (user_id, timestamp, event_type) +-- - Primary index: only (user_id, timestamp) +-- - Queries filtering by user_id + timestamp use index +-- - Queries scanning event_type read more data +``` + +**When to use different PRIMARY KEY:** +- Want to optimize for queries that filter on subset of ORDER BY +- Reduce primary key size (faster index scans) +- Note: PRIMARY KEY must be prefix of ORDER BY + +### Common ORDER BY Patterns ```sql -CREATE DATABASE my_db ENGINE = Atomic; +-- Time-series by user +ORDER BY (user_id, timestamp) + +-- Time-series by sensor +ORDER BY (sensor_id, timestamp) + +-- Multi-tenant time-series +ORDER BY (tenant_id, user_id, timestamp) + +-- Event log +ORDER BY (timestamp, event_type) + +-- Metrics +ORDER BY (metric_name, timestamp, labels_hash) ``` -**Features:** -- Supports non-blocking DDL operations -- Atomic table exchange (zero-downtime schema changes) -- Transactional DDL +## Partition Strategy + +Partitions enable fast data drop and TTL operations: + +### Time-Based Partitioning (Most Common) -**Table Exchange:** ```sql --- Zero-downtime schema change -EXCHANGE TABLES events AND events_v2; +-- Monthly partitions (recommended for 10GB+ per day) +PARTITION BY toYYYYMM(timestamp); +-- Results: partitions like '202401', '202402', ... --- Atomic swap - instant, no downtime +-- Daily partitions (for high-volume, 1GB+ per day) +PARTITION BY toDate(timestamp); +-- Results: one partition per day ``` -### Lazy +### Custom Partitioning ```sql -CREATE DATABASE my_db ENGINE = Lazy -SETTINGS lazy_database_ttl = 60; +-- By tenant (multi-tenant cleanup) +PARTITION BY tenant_id; +-- Drop all data for tenant: ALTER TABLE DROP PARTITION 'tenant_123'; + +-- Composite (use carefully - too many partitions!) +PARTITION BY (tenant_id, toYYYYMM(timestamp)); +-- Results: 'tenant_123_202401', 'tenant_123_202402', ... ``` -**Features:** -- Loaded on first access -- Unloaded after timeout -- Useful for rarely-used databases +### Partitioning Guidelines + +| Data Volume | Recommended Partitioning | +|-------------|---------------------------| +| < 1GB/day | No partitioning or monthly | +| 1-10GB/day | Monthly partitions | +| 10-100GB/day | Daily partitions | +| > 100GB/day | Daily + sharding | + +**Key principles:** +- Aim for 100-1000 parts total across all partitions +- Monthly partitions: Good for 10GB+ per day +- Daily partitions: Good for 1GB+ per day +- Too many partitions = slow queries, high merge overhead -### Replicated +### Partition Operations ```sql -CREATE DATABASE my_db ENGINE = Replicated( - 'zk_path', - 'replica_name' -); +-- Drop partition (instant, no mutation) +ALTER TABLE events DROP PARTITION '202401'; + +-- Detach/Attach partition +ALTER TABLE events DETACH PARTITION '202401'; +ALTER TABLE events ATTACH PARTITION '202401'; + +-- Freeze partition (for backup) +ALTER TABLE events FREEZE PARTITION '202401'; + +-- Check partition sizes +SELECT + partition, + sum(rows) as total_rows, + formatReadableSize(sum(bytes)) as size +FROM system.parts +WHERE active = 1 AND table = 'events' +GROUP BY partition +ORDER BY partition DESC; ``` -**Features:** -- Multi-datacenter setups -- Automatic replication -- ZooKeeper-based coordination +## Column Selection + +Choose smallest sufficient type: -### Dictionary +### Numeric Types ```sql -CREATE DATABASE my_db ENGINE = Dictionary(dictionaries_db_name); +-- Use smallest integer type +UInt8 -- 0-255 +UInt16 -- 0-65,535 +UInt32 -- 0-4,294,967,295 +UInt64 -- 0-18,446,744,073,709,551,615 + +-- Decimal for currency +Decimal(18, 2) -- Up to 999 trillion +Decimal(10, 2) -- Smaller range, faster ``` -For in-memory dictionary tables. +### Temporal Types -### PostgreSQL/MySQL (Proxy) +```sql +timestamp Date -- 2 bytes (days since epoch) +timestamp DateTime -- 4 bytes (seconds since epoch) +timestamp DateTime64(3) -- 8 bytes (milliseconds) +``` + +### String Types ```sql -CREATE DATABASE my_db ENGINE = PostgreSQL( - 'postgres-host:5432', - 'postgres_db', - 'postgres_user', - 'postgres_password' -); +-- LowCardinality for enum-like strings (< 10k distinct values) +event_type LowCardinality(String) + +-- Nullable vs default values +status Nullable(String) -- Has overhead (special NULL marker) +status String DEFAULT '' -- Better: Use default value +``` + +## Sampling Key + +Enable SAMPLE queries for approximate analytics: + +```sql +-- Enable sampling +CREATE TABLE events ( + user_id UInt32, + event_timestamp DateTime, + data String +) +ENGINE = MergeTree() +ORDER BY (user_id, event_timestamp) +SAMPLE BY user_id; -- Must be column in ORDER BY + +-- Query with sampling (10% of data) +SELECT * FROM events SAMPLE 0.1; + +-- Sampling with interpolation +SELECT + user_id, + count() * 10 as estimated_count -- Multiply by 1/sampling_rate +FROM events +SAMPLE 0.1 +GROUP BY user_id; +``` + +**Use cases for sampling:** +- Exploratory analytics (fast approximate results) +- Testing queries on large datasets +- Dashboard previews (refresh faster) + +## Codecs + +Apply compression to individual columns: + +```sql +-- ZSTD compression (good default) +CREATE TABLE events ( + data String CODEC(ZSTD) +) +ENGINE = MergeTree() +ORDER BY user_id; + +-- Compression levels +CODEC(ZSTD(3)) -- Fast, less compression +CODEC(ZSTD(15)) -- Slower, more compression + +-- No compression (for already compressed data) +CODEC(NONE) + +-- Multiple codecs +CODEC(Delta, ZSTD) + +-- LZ4 (faster than ZSTD, less compression) +CODEC(LZ4) +``` + +**Codec guidelines:** +- Use ZSTD for most data (good balance) +- Use NONE for already-compressed data (images, encrypted data) +- Use Delta for monotonically increasing values (timestamps, IDs) +- Higher compression levels = slower queries + +## Skip Indexes + +Data skipping indexes allow ClickHouse to skip data during reads: + +```sql +-- Bloom filter for exact match +CREATE TABLE events ( + user_id UInt32, + email String, + timestamp DateTime +) +ENGINE = MergeTree() +ORDER BY (user_id, timestamp) +INDEX idx_email email TYPE bloom_filter GRANULARITY 1; + +-- Minmax for range queries +INDEX idx_time timestamp TYPE minmax GRANULARITY 4; + +-- Set for IN queries +INDEX idx_user user_id TYPE set(1000) GRANULARITY 1; + +-- Tokenbf for string search +INDEX idx_msg message TYPE tokenbf_v1(512, 3, 0) GRANULARITY 1; +``` + +**Index types:** +- `minmax`: Min/max values per granule +- `set`: Set of values (good for IN queries) +- `bloom_filter`: Probabilistic exact match +- `tokenbf_v1`: Token-based bloom filter for text search + +**Granularity:** +- Lower = more precise index, larger index size +- Higher = less precise index, smaller index size +- Default: 1 (most precise) + +## Table Settings + +```sql +CREATE TABLE events ( + timestamp DateTime, + user_id UInt32 +) +ENGINE = MergeTree() +ORDER BY (user_id, timestamp) +SETTINGS + index_granularity = 8192, -- Rows per mark (default) + index_granularity_bytes = 10485760, -- Bytes per mark + enable_mixed_granularity_parts = 1, -- Adaptive marks + min_rows_for_wide_part = 0, -- Always use wide parts + merge_max_block_size = 1048544, -- Block size for merges + storage_policy = 'default'; -- Storage policy ``` -Proxy to external databases for queries. ## Schema Organization @@ -213,8 +439,3 @@ MAX execution_time = 60 TO user_name; ``` -## See Also - -- `../SKILL.md` - Main skill entry point -- `core-concepts.md` - Architecture and data model -- `table-design.md` - ORDER BY and partitioning strategies diff --git a/clickhouse/skills/clickhouse/references/sql-reference.md b/clickhouse/skills/clickhouse/references/sql-reference.md deleted file mode 100644 index 11a961c..0000000 --- a/clickhouse/skills/clickhouse/references/sql-reference.md +++ /dev/null @@ -1,390 +0,0 @@ -# ClickHouse SQL Reference - -Complete SQL dialect reference for ClickHouse. - -## Data Types - -### Numeric Types - -```sql --- Unsigned integers -UInt8 -- 0 to 255 -UInt16 -- 0 to 65,535 -UInt32 -- 0 to 4,294,967,295 -UInt64 -- 0 to 18,446,744,073,709,551,615 -UInt128 -- Very large unsigned -UInt256 -- Extremely large unsigned - --- Signed integers -Int8 -- -128 to 127 -Int16 -- -32,768 to 32,767 -Int32 -- -2,147,483,648 to 2,147,483,647 -Int64 -- -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807 - --- Floating point -Float32 -- Single precision (7 decimal digits) -Float64 -- Double precision (16 decimal digits) - --- Decimal (precise decimal arithmetic) -Decimal32(S) -- 1-9 significant digits -Decimal64(S) -- 10-18 significant digits -Decimal128(S) -- 19-38 significant digits -Decimal256(S) -- 39-76 significant digits -Decimal(P, S) -- P total digits, S after decimal point - --- Examples -CREATE TABLE examples ( - price Decimal(18, 2), -- Currency (up to 999 trillion) - percentage Decimal(5, 2), -- Percentages (0.00 to 999.99) - metric Float64 -- Approximate metrics -) -``` - -### Temporal Types - -```sql --- Date (2 bytes, days since Unix epoch) -Date -- Range: 1970-01-01 to 2149-06-06 - --- DateTime (4 bytes, seconds since Unix epoch) -DateTime -- Range: 1970-01-01 00:00:00 to 2106-02-07 06:28:15 -DateTime('UTC') -- With timezone - --- DateTime64 (8 bytes, sub-second precision) -DateTime64(3) -- Millisecond precision -DateTime64(6, 'UTC') -- Microsecond precision with timezone -DateTime64(9, 'America/New_York') -- Nanosecond precision - --- Functions -toDate('2024-01-01') -- String → Date -toDateTime('2024-01-01 12:00:00') -- String → DateTime -toDateTime64('2024-01-01 12:00:00.123', 3) -- String → DateTime64 - -now() -- Current DateTime -today() -- Current Date -yesterday() -- Yesterday's Date -tomorrow() -- Tomorrow's Date - --- Date arithmetic -now() + INTERVAL 1 DAY -now() - INTERVAL 1 HOUR -date_diff('day', timestamp, now()) -- Days between dates -``` - -### String Types - -```sql --- Variable-length string -String -- No length limit, stores any string - --- Fixed-length string -FixedString(N) -- Fixed N bytes, pads with zeros --- Example: UUID as FixedString(16) - --- Common operations -length(string) -- String length -concat(s1, s2, ...) -- Concatenate -substring(s, offset, length) -- Substring -splitByChar(separator, s) -- Split into array -arrayJoin(splitByChar(' ', s)) -- Split and explode -``` - -### Advanced Types - -```sql --- Arrays -Array(UInt32) -- Array of unsigned integers -Array(String) -- Array of strings -['a', 'b', 'c'] -- Array literal -arrayJoin([1, 2, 3]) -- Explode array into rows - --- Tuples -Tuple(UInt32, String, Float64) -- Mixed-type tuple -tuple(123, 'abc', 45.6) -- Tuple literal -t.1, t.2 -- Access tuple fields - --- Maps (key-value pairs) -Map(String, UInt64) -- String → UInt64 map -map('key1', 1, 'key2', 2) -- Map literal - --- Enums (efficient string storage) -Enum8('action1'=1, 'action2'=2) -- 1 byte per value -Enum16('status1'=1, 'status2'=2) -- 2 bytes per value - --- Nullable (allows NULL values) -Nullable(UInt32) -- Can be NULL or UInt32 --- Nullable has overhead (special NULL marker) - --- LowCardinality (compression for low-cardinality strings) -LowCardinality(String) -- Efficient for < 10k distinct values - --- UUID -UUID -- 16-byte UUID -generateUUIDv4() -- Generate random UUID - --- IPv4/IPv6 -IPv4 -- 4-byte IPv4 address -IPv6 -- 16-byte IPv6 address -toIPv4('192.168.1.1') -- String → IPv4 -``` - -## CREATE TABLE - -```sql --- Basic syntax -CREATE TABLE [IF NOT EXISTS] [db.]table_name -( - column1 Type [DEFAULT|ALIAS expr] [COMMENT 'description'], - column2 Type [DEFAULT|ALIAS expr] [COMMENT 'description'], - ... -) -ENGINE = MergeTree() -PARTITION BY expr -ORDER BY expr -PRIMARY KEY expr -SAMPLE BY expr -TTL expr -SETTINGS name=value, ...; - --- Example with all features -CREATE TABLE events ( - timestamp DateTime, - user_id UInt32, - event_type LowCardinality(String) DEFAULT 'unknown', - session_id UUID DEFAULT generateUUIDv4(), - metadata String DEFAULT '', - revenue Decimal(18, 2) DEFAULT 0.00 COMMENT 'Revenue in USD' -) -ENGINE = MergeTree() -PARTITION BY toYYYYMM(timestamp) -ORDER BY (user_id, timestamp) -PRIMARY KEY (user_id) -SAMPLE BY user_id -TTL timestamp + INTERVAL 90 DAY -SETTINGS index_granularity = 8192; -``` - -## INSERT - -```sql --- Insert values -INSERT INTO events VALUES - (now(), 123, 'login', generateUUIDv4(), '{}', 0.00), - (now(), 456, 'logout', generateUUIDv4(), '{}', 0.00); - --- Insert with columns -INSERT INTO events (timestamp, user_id, event_type) VALUES - (now(), 789, 'purchase'); - --- Insert from SELECT -INSERT INTO events_archive -SELECT * FROM events -WHERE timestamp < today() - INTERVAL 90 DAY; - --- Insert with format -INSERT INTO events FORMAT JSONEachRow -{"timestamp":"2024-01-01 00:00:00","user_id":123,"event_type":"login"} -{"timestamp":"2024-01-01 00:01:00","user_id":456,"event_type":"logout"} -``` - -## SELECT - -```sql --- Basic SELECT -SELECT [DISTINCT] [TOP n] expr -FROM table -[FINAL] -- Apply mutations (deduplication) -[WHERE expr] -[GROUP BY expr] [WITH ROLLUP|WITH CUBE] -[HAVING expr] -[ORDER BY expr] -[LIMIT [offset, ]n] -[UNION ALL] -[SETTINGS name=value, ...]; - --- Examples -SELECT * FROM events WHERE user_id = 123; -SELECT DISTINCT user_id FROM events; -SELECT TOP 10 user_id, count() as cnt FROM events GROUP BY user_id ORDER BY cnt DESC; - --- With FINAL (apply mutations) -SELECT * FROM ReplacingMergeTree_table FINAL WHERE user_id = 123; - --- WITH ROLLUP (hierarchical aggregation) -SELECT - user_id, - event_type, - count() as cnt -FROM events -GROUP BY user_id, event_type WITH ROLLUP; -``` - -## JOIN - -```sql --- All JOINs are RIGHT JOINs internally -SELECT * -FROM t1 -[GLOBAL] [ANY|ALL|ASOF] [INNER|LEFT|RIGHT|FULL|CROSS] JOIN t2 -ON t1.key = t2.key - --- USING for same column names -SELECT * -FROM t1 -[INNER|LEFT|RIGHT|FULL] JOIN t2 USING (common_key); - --- GLOBAL: Sends right table to each shard (for distributed queries) -SELECT * -FROM distributed_table lt -GLOBAL RIGHT JOIN small_table st ON lt.id = st.id; - --- ANY: First match only -SELECT * FROM t1 ANY LEFT JOIN t2 ON t1.id = t2.id; - --- ASOF: As-of join with inequality (time-series) -SELECT * -FROM ticks t1 -ASOF LEFT JOIN trades t2 -ON t1.symbol = t2.symbol -AND t1.time <= t2.time; -``` - -## ALTER TABLE - -```sql --- Add column (safe, metadata-only) -ALTER TABLE table ADD COLUMN col Type DEFAULT expr; - --- Drop column (mutation, expensive) -ALTER TABLE table DROP COLUMN col; - --- Modify column (mutation, expensive) -ALTER TABLE table MODIFY COLUMN col Type; - --- Rename column (metadata-only) -ALTER TABLE table RENAME COLUMN old_name TO new_name; - --- Comment column -ALTER TABLE table COMMENT COLUMN col 'description'; - --- Delete data (mutation, expensive) -ALTER TABLE table DELETE WHERE expr; - --- Update data (mutation, expensive) -ALTER TABLE table UPDATE col = expr WHERE expr; - --- Add index -ALTER TABLE table ADD INDEX idx_name col TYPE bloom_filter GRANULARITY 1; - --- TTL -ALTER TABLE table MODIFY TTL timestamp + INTERVAL 90 DAY; -``` - -## DROP/TRUNCATE - -```sql --- Drop table -DROP TABLE [IF EXISTS] table; - --- Truncate table -TRUNCATE TABLE [IF EXISTS] table; - --- Drop partition (instant, no mutation) -ALTER TABLE table DROP PARTITION '202401'; - --- Detach/Attach -DETACH TABLE table; -- Keeps data on disk -ATTACH TABLE table; -``` - -## OPTIMIZE - -```sql --- Force merge of parts -OPTIMIZE TABLE table [PARTITION partition] [FINAL]; - --- FINAL: Apply mutations, deduplicate --- Without FINAL: Just merges parts -``` - -## SYSTEM Commands - -```sql --- Stop/start merges -SYSTEM STOP MERGES [ON CLUSTER cluster]; -SYSTEM START MERGES [ON CLUSTER cluster]; - --- Stop/start replication -SYSTEM STOP REPLICATION QUEUES; -SYSTEM START REPLICATION QUEUES; - --- Flush logs -SYSTEM FLUSH LOGS; -``` - -## Common Functions - -### Date Functions - -```sql -now() -- Current DateTime -today() -- Current Date -yesterday() -- Yesterday -tomorrow() -- Tomorrow -toDate(expr) -- Convert to Date -toDateTime(expr) -- Convert to DateTime -toStartOfMonth(date) -- First day of month -toStartOfWeek(date) -- First day of week -toStartOfDay(date) -- Start of day -date_diff(unit, start, end) -- Difference between dates -``` - -### Array Functions - -```sql -array(x1, x2, ...) -- Create array -arrayJoin(arr) -- Explode array into rows -length(arr) -- Array length -has(arr, elem) -- Check if element exists -arrayConcat(arr1, arr2) -- Concatenate arrays -arrayMap(func, arr) -- Apply function to each element -arrayFilter(func, arr) -- Filter array -arraySort(func, arr) -- Sort array -``` - -### String Functions - -```sql -length(str) -- String length -substring(str, offset, length) -- Substring -concat(s1, s2, ...) -- Concatenate -splitByChar(sep, str) -- Split into array -join(arr, sep) -- Join array into string -lower(str) -- Lowercase -upper(str) -- Uppercase -trim(str) -- Trim whitespace -replaceOne(str, pattern, replacement) -- Replace first -replaceAll(str, pattern, replacement) -- Replace all -``` - -### Aggregation Functions - -```sql -count() -- Count rows -sum(expr) -- Sum -avg(expr) -- Average -min(expr) -- Minimum -max(expr) -- Maximum -quantile(level)(expr) -- Quantile -median(expr) -- Median -uniq(expr) -- Approximate unique count -uniqCombined(expr) -- Better approximate unique -topK(K)(expr) -- Top K values -histogram(K)(expr) -- Histogram -``` - -## See Also - -- `../SKILL.md` - Main skill entry point -- `query-optimization.md` - Query performance and EXPLAIN -- `table-design.md` - Schema design and ORDER BY diff --git a/clickhouse/skills/clickhouse/references/system-queries.md b/clickhouse/skills/clickhouse/references/system-queries.md deleted file mode 100644 index 9402cb1..0000000 --- a/clickhouse/skills/clickhouse/references/system-queries.md +++ /dev/null @@ -1,694 +0,0 @@ -# ClickHouse System Queries - -Useful queries for monitoring, debugging, and managing ClickHouse databases. - ---- - -## Table Information - -### Table Sizes - -```sql --- All tables with sizes -SELECT - database, - table, - formatReadableSize(sum(bytes)) as size, - sum(rows) as total_rows, - count() as parts -FROM system.parts -WHERE active = 1 -GROUP BY database, table -ORDER BY sum(bytes) DESC; - --- Top 20 largest tables -SELECT - database, - table, - formatReadableSize(sum(bytes)) as size, - sum(rows) as total_rows -FROM system.parts -WHERE active = 1 -GROUP BY database, table -ORDER BY sum(bytes) DESC -LIMIT 20; - --- Tables by row count -SELECT - database, - table, - sum(rows) as total_rows, - formatReadableQuantity(sum(rows)) as readable_rows -FROM system.parts -WHERE active = 1 -GROUP BY database, table -ORDER BY sum(rows) DESC -LIMIT 20; -``` - -### Column Information - -```sql --- Column sizes and compression -SELECT - database, - table, - column, - type, - formatReadableSize(sum(data_uncompressed_bytes)) as uncompressed, - formatReadableSize(sum(data_compressed_bytes)) as compressed, - sum(data_compressed_bytes) / sum(data_uncompressed_bytes) as ratio -FROM system.columns -WHERE database != 'system' -GROUP BY database, table, column, type -ORDER BY sum(data_uncompressed_bytes) DESC -LIMIT 50; - --- All columns in a table -SELECT - name, - type, - default_kind, - default_expression, - comment -FROM system.columns -WHERE database = 'my_database' - AND table = 'my_table' -ORDER BY position; -``` - -### Partition Information - -```sql --- Partition details -SELECT - partition, - sum(rows) as total_rows, - count() as parts, - formatReadableSize(sum(bytes)) as size, - min(min_timestamp) as min_time, - max(max_timestamp) as max_time -FROM system.parts -WHERE active = 1 - AND table = 'my_table' - AND database = currentDatabase() -GROUP BY partition -ORDER BY partition DESC; - --- Large partitions (many parts) -SELECT - partition, - count() as parts, - sum(rows) as total_rows -FROM system.parts -WHERE active = 1 - AND table = 'my_table' -GROUP BY partition -HAVING parts > 100 -ORDER BY parts DESC; -``` - ---- - -## Query Monitoring - -### Running Queries - -```sql --- All running queries -SELECT - query_id, - user, - query, - elapsed, - formatReadableSize(memory_usage) as memory, - formatReadableQuantity(read_rows) as rows_read, - formatReadableSize(read_bytes) as bytes_read -FROM system.processes -ORDER BY elapsed DESC; - --- Long-running queries (> 1 minute) -SELECT - query_id, - user, - query, - elapsed / 60 as minutes_elapsed, - formatReadableSize(memory_usage) as memory -FROM system.processes -WHERE elapsed > 60 -ORDER BY elapsed DESC; - --- Queries by user -SELECT - user, - count() as query_count, - sum(memory_usage) as total_memory -FROM system.processes -GROUP BY user -ORDER BY total_memory DESC; -``` - -### Query History - -```sql --- Recent queries (last hour) -SELECT - type, - substring(query, 1, 100) as query_preview, - query_duration_ms / 1000 as seconds, - formatReadableSize(memory_usage) as memory, - event_time -FROM system.query_log -WHERE event_time > now() - INTERVAL 1 HOUR -ORDER BY event_time DESC -LIMIT 100; - --- Slow queries (> 5 seconds) -SELECT - query, - query_duration_ms / 1000 as seconds, - formatReadableSize(memory_usage) as memory, - formatReadableQuantity(read_rows) as rows_read, - event_time -FROM system.query_log -WHERE type = 'QueryFinish' - AND query_duration_ms > 5000 -ORDER BY query_duration_ms DESC -LIMIT 20; - --- Most expensive by memory -SELECT - query, - formatReadableSize(memory_usage) as memory, - query_duration_ms / 1000 as seconds -FROM system.query_log -WHERE type = 'QueryFinish' -ORDER BY memory_usage DESC -LIMIT 10; - --- Failed queries -SELECT - query, - exception_code, - exception_text, - event_time -FROM system.query_log -WHERE type = 'Exception' - AND event_time > now() - INTERVAL 1 DAY -ORDER BY event_time DESC -LIMIT 50; -``` - -### Query Statistics by Table - -```sql --- Most accessed tables -SELECT - database, - table, - count() as query_count, - sum(read_rows) as total_rows_read, - avg(query_duration_ms) as avg_duration_ms -FROM system.query_log -WHERE type = 'QueryFinish' - AND event_date = today() -GROUP BY database, table -ORDER BY query_count DESC -LIMIT 20; - --- Queries by type -SELECT - type, - count() as count, - avg(query_duration_ms) as avg_duration_ms -FROM system.query_log -WHERE event_date = today() -GROUP BY type -ORDER BY count DESC; -``` - ---- - -## Merge Monitoring - -### Active Merges - -```sql --- Current merges -SELECT - database, - table, - elapsed, - progress, - formatReadableSize(bytes_read_uncompressed) as bytes_read, - rows_read, - is_mutation, - merge_type -FROM system.merges -ORDER BY elapsed DESC; - --- Merge performance by day -SELECT - table, - count() as merge_count, - avg(bytes_read_uncompressed) as avg_size, - sum(rows_read) as total_rows -FROM system.merges -WHERE event_date = today() -GROUP BY table -ORDER BY merge_count DESC; - --- Merge queue size -SELECT - database, - table, - count() as parts_to_merge, - sum(bytes) as total_bytes -FROM system.parts -WHERE active = 1 - AND rows > 0 -GROUP BY database, table -HAVING parts_to_merge > 100 -ORDER BY parts_to_merge DESC; -``` - -### Merge Statistics - -```sql --- Merge performance over time -SELECT - toStartOfHour(event_time) as hour, - count() as merge_count, - avg(bytes_read_uncompressed) as avg_size, - sum(rows_read) as total_rows -FROM system.part_log -WHERE event_time > now() - INTERVAL 1 DAY - AND event_type = 'MergeParts' -GROUP BY hour -ORDER BY hour; -``` - ---- - -## Mutation Monitoring - -### Active Mutations - -```sql --- Current mutations -SELECT - database, - table, - command, - is_done, - parts_to_do, - parts_to_do_names, - formatReadableSize(bytes_read_uncompressed) as bytes_processed -FROM system.mutations -WHERE is_done = 0; - --- Mutation progress -SELECT - table, - command, - is_done, - parts_to_do - parts_to_do_names as parts_remaining, - elapsed -FROM system.mutations -ORDER BY parts_to_do DESC; - --- All mutations history -SELECT - database, - table, - command, - is_done, - created_at, - finished_at -FROM system.mutations -ORDER BY created_at DESC -LIMIT 50; -``` - ---- - -## Replication Monitoring - -### Replica Status - -```sql --- All replicas -SELECT - database, - table, - is_leader, - is_readonly, - queue_size, - absolute_delay, - delay * 1000 as lag_ms -FROM system.replicas -ORDER BY absolute_delay DESC; - --- Replication queue -SELECT * FROM system.replication_queue -WHERE delay > 5 -ORDER BY delay DESC; - --- Replication lag by table -SELECT - database, - table, - replica_name, - is_leader, - is_readonly, - queue_size, - absolute_delay -FROM system.replicas -WHERE absolute_delay > 10 -ORDER BY absolute_delay DESC; -``` - -### ZooKeeper Status - -```sql --- ZooKeeper connection -SELECT * FROM system.zookeeper WHERE path = '/'; - --- Check ZooKeeper path -SELECT - name, - value, - data -FROM system.zookeeper -WHERE path = '/clickhouse/tables'; -``` - ---- - -## Disk and Storage - -### Disk Usage - -```sql --- All disks -SELECT - name, - path, - formatReadableSize(free_space) as free, - formatReadableSize(total_space) as total, - formatReadableSize(keep_free_space) as keep_free, - (free_space / total_space) * 100 as percent_free -FROM system.disks; - --- Disk usage by table -SELECT - disk_name, - database, - table, - formatReadableSize(sum(bytes_on_disk)) as size -FROM system.parts -WHERE active = 1 -GROUP BY disk_name, database, table -ORDER BY sum(bytes_on_disk) DESC -LIMIT 20; -``` - -### Storage Policies - -```sql --- All storage policies -SELECT * FROM system.storage_policies; - --- Volumes in storage policies -SELECT * FROM system.disks; -``` - ---- - -## Cluster Information - -### Cluster Status - -```sql --- All clusters -SELECT * FROM system.clusters; - --- Cluster nodes -SELECT - cluster, - shard_num, - replica_num, - host_name, - port, - user -FROM system.clusters -WHERE cluster = 'my_cluster'; - --- Cluster health -SELECT - cluster, - sum(error_count) as errors, - sum(num_requests) as requests -FROM system.clusters -GROUP BY cluster; -``` - ---- - -## Database Information - -### All Databases - -```sql --- All databases -SELECT - name, - engine, - data_path, - metadata_path -FROM system.databases -ORDER BY name; - --- Database engine types -SELECT - engine, - count() as count -FROM system.databases -GROUP BY engine -ORDER BY count DESC; -``` - ---- - -## User and Security - -### User Information - -```sql --- All users -SELECT * FROM system.users; - --- User quotas -SELECT * FROM system.quotas; - --- Current roles -SELECT * FROM system.current_roles; -``` - -### Access Control - -```sql --- Row policies -SELECT * FROM system.row_policies; - --- Grants -SELECT * FROM system.grants; -``` - ---- - -## System Health - -### General Health - -```sql --- Server info -SELECT version(), uptime(), now() as current_time; - --- Memory usage -SELECT - formatReadableSize(sum(bytes_allocated)) as allocated, - formatReadableSize(sum(bytes_used)) as used -FROM system.dictionaries; - --- Load average -SELECT * FROM system.asynchronous_metrics -WHERE metric LIKE '%load%'; -``` - -### Settings - -```sql --- All settings -SELECT * FROM system.settings -ORDER BY name; - --- Current settings -SELECT * FROM system.settings -WHERE changed == 1; -``` - ---- - -## Dictionary Information - -### All Dictionaries - -```sql --- Dictionary status -SELECT - name, - status, - origin, - type, - element_count, - bytes_allocated -FROM system.dictionaries -ORDER BY name; - --- Loading dictionaries -SELECT - name, - status, - loading_start_time, - loading_duration_seconds -FROM system.dictionaries -WHERE status != 'LOADED'; -``` - ---- - -## Formatted Queries - -### Human-Readable Output - -```sql --- Size formatted -SELECT - database, - table, - formatReadableSize(sum(bytes)) as size, - formatReadableQuantity(sum(rows)) as rows, - formatReadableSize(sum(bytes_on_disk)) as on_disk -FROM system.parts -WHERE active = 1 -GROUP BY database, table -ORDER BY sum(bytes) DESC -LIMIT 20; - --- Time formatted -SELECT - query, - formatDateTime(query_start_time, '%Y-%m-%d %H:%M:%S') as started, - formatDuration(query_duration_ms / 1000) as duration -FROM system.query_log -WHERE type = 'QueryFinish' -ORDER BY query_start_time DESC -LIMIT 10; -``` - ---- - -## Quick Diagnostic Queries - -### One-Liner Health Checks - -```sql --- Quick health check -SELECT 'uptime' as metric, toString(uptime()) as value -UNION ALL SELECT 'version', version() -UNION ALL SELECT 'running_queries', toString(count()) -FROM system.processes -UNION ALL SELECT 'active_merges', toString(count()) -FROM system.merges -UNION ALL SELECT 'replication_lag', toString(count()) -FROM system.replication_queue WHERE delay > 5; - --- Table count by database -SELECT database, count() as tables -FROM system.tables -WHERE database != 'system' -GROUP BY database -ORDER BY tables DESC; - --- Parts count (health check) -SELECT - database, - table, - count() as parts, - sum(rows) as total_rows -FROM system.parts -WHERE active = 1 -GROUP BY database, table -HAVING parts > 1000 -ORDER BY parts DESC; -``` - ---- - -## Useful Subqueries - -### Find Problematic Queries - -```sql --- Queries with exceptions -SELECT - query, - exception_text, - count() as error_count -FROM system.query_log -WHERE type = 'Exception' - AND event_date = today() -GROUP BY query, exception_text -ORDER BY error_count DESC -LIMIT 20; - --- Queries reading too much data -SELECT - query, - read_rows, - formatReadableQuantity(read_rows) as readable_rows, - read_bytes, - formatReadableSize(read_bytes) as readable_bytes -FROM system.query_log -WHERE type = 'QueryFinish' - AND event_date = today() - AND read_rows > 1000000000 -ORDER BY read_rows DESC -LIMIT 20; -``` - -### Table Growth Over Time - -```sql --- Daily table growth -SELECT - toStartOfDay(event_time) as day, - database, - table, - formatReadableSize(sum(bytes)) as size -FROM system.part_log -WHERE event_type = 'NewPart' - AND event_time > now() - INTERVAL 7 DAY -GROUP BY day, database, table -ORDER BY day DESC, sum(bytes) DESC; -``` - ---- - -**Tips**: -- Use `formatReadableSize()` for human-readable byte sizes -- Use `formatReadableQuantity()` for human-readable row counts -- Filter `WHERE active = 1` to see only active parts -- Use `currentDatabase()` to refer to current database -- Most `system.*` tables have `event_date` for partitioning diff --git a/clickhouse/skills/clickhouse/references/table-design.md b/clickhouse/skills/clickhouse/references/table-design.md deleted file mode 100644 index 9479034..0000000 --- a/clickhouse/skills/clickhouse/references/table-design.md +++ /dev/null @@ -1,313 +0,0 @@ -# ClickHouse Table Design - -ORDER BY design, partitioning strategies, column selection, and sampling. - -## ORDER BY Design (CRITICAL) - -The ORDER BY clause defines **data layout on disk** - the most important schema decision! - -### ORDER BY Design Principles - -1. **Match query WHERE patterns**: Most selective filter first -2. **Time-series**: Timestamp as second column (after dimension) -3. **High-cardinality first**: user_id before event_type -4. **Limit to 3-4 columns**: More columns = larger index - -### Examples - -```sql --- ✅ GOOD: ORDER BY matches query pattern -CREATE TABLE events ( - user_id UInt32, - event_timestamp DateTime, - event_type String -) -ENGINE = MergeTree() -ORDER BY (user_id, event_timestamp); - --- Query leverages index (reads contiguous data) -SELECT * FROM events -WHERE user_id = 123 - AND event_timestamp >= now() - INTERVAL 1 DAY; - --- ❌ BAD: ORDER BY doesn't match queries -CREATE TABLE events ( - user_id UInt32, - event_timestamp DateTime, - event_type String -) -ENGINE = MergeTree() -ORDER BY (event_timestamp); - --- Query scans all data (timestamp-ordered, but filtering by user_id) -SELECT * FROM events WHERE user_id = 123; -``` - -### Primary Key vs Sorting Key - -```sql --- Sorting key: defines data layout on disk -ORDER BY (user_id, event_timestamp, event_type) - --- Primary key: subset of ORDER BY for row-level index -PRIMARY KEY (user_id, event_timestamp) - --- Effect: --- - Data on disk: sorted by (user_id, timestamp, event_type) --- - Primary index: only (user_id, timestamp) --- - Queries filtering by user_id + timestamp use index --- - Queries scanning event_type read more data -``` - -**When to use different PRIMARY KEY:** -- Want to optimize for queries that filter on subset of ORDER BY -- Reduce primary key size (faster index scans) -- Note: PRIMARY KEY must be prefix of ORDER BY - -### Common ORDER BY Patterns - -```sql --- Time-series by user -ORDER BY (user_id, timestamp) - --- Time-series by sensor -ORDER BY (sensor_id, timestamp) - --- Multi-tenant time-series -ORDER BY (tenant_id, user_id, timestamp) - --- Event log -ORDER BY (timestamp, event_type) - --- Metrics -ORDER BY (metric_name, timestamp, labels_hash) -``` - -## Partition Strategy - -Partitions enable fast data drop and TTL operations: - -### Time-Based Partitioning (Most Common) - -```sql --- Monthly partitions (recommended for 10GB+ per day) -PARTITION BY toYYYYMM(timestamp); --- Results: partitions like '202401', '202402', ... - --- Daily partitions (for high-volume, 1GB+ per day) -PARTITION BY toDate(timestamp); --- Results: one partition per day -``` - -### Custom Partitioning - -```sql --- By tenant (multi-tenant cleanup) -PARTITION BY tenant_id; --- Drop all data for tenant: ALTER TABLE DROP PARTITION 'tenant_123'; - --- Composite (use carefully - too many partitions!) -PARTITION BY (tenant_id, toYYYYMM(timestamp)); --- Results: 'tenant_123_202401', 'tenant_123_202402', ... -``` - -### Partitioning Guidelines - -| Data Volume | Recommended Partitioning | -|-------------|---------------------------| -| < 1GB/day | No partitioning or monthly | -| 1-10GB/day | Monthly partitions | -| 10-100GB/day | Daily partitions | -| > 100GB/day | Daily + sharding | - -**Key principles:** -- Aim for 100-1000 parts total across all partitions -- Monthly partitions: Good for 10GB+ per day -- Daily partitions: Good for 1GB+ per day -- Too many partitions = slow queries, high merge overhead - -### Partition Operations - -```sql --- Drop partition (instant, no mutation) -ALTER TABLE events DROP PARTITION '202401'; - --- Detach/Attach partition -ALTER TABLE events DETACH PARTITION '202401'; -ALTER TABLE events ATTACH PARTITION '202401'; - --- Freeze partition (for backup) -ALTER TABLE events FREEZE PARTITION '202401'; - --- Check partition sizes -SELECT - partition, - sum(rows) as total_rows, - formatReadableSize(sum(bytes)) as size -FROM system.parts -WHERE active = 1 AND table = 'events' -GROUP BY partition -ORDER BY partition DESC; -``` - -## Column Selection - -Choose smallest sufficient type: - -### Numeric Types - -```sql --- Use smallest integer type -UInt8 -- 0-255 -UInt16 -- 0-65,535 -UInt32 -- 0-4,294,967,295 -UInt64 -- 0-18,446,744,073,709,551,615 - --- Decimal for currency -Decimal(18, 2) -- Up to 999 trillion -Decimal(10, 2) -- Smaller range, faster -``` - -### Temporal Types - -```sql -timestamp Date -- 2 bytes (days since epoch) -timestamp DateTime -- 4 bytes (seconds since epoch) -timestamp DateTime64(3) -- 8 bytes (milliseconds) -``` - -### String Types - -```sql --- LowCardinality for enum-like strings (< 10k distinct values) -event_type LowCardinality(String) - --- Nullable vs default values -status Nullable(String) -- Has overhead (special NULL marker) -status String DEFAULT '' -- Better: Use default value -``` - -## Sampling Key - -Enable SAMPLE queries for approximate analytics: - -```sql --- Enable sampling -CREATE TABLE events ( - user_id UInt32, - event_timestamp DateTime, - data String -) -ENGINE = MergeTree() -ORDER BY (user_id, event_timestamp) -SAMPLE BY user_id; -- Must be column in ORDER BY - --- Query with sampling (10% of data) -SELECT * FROM events SAMPLE 0.1; - --- Sampling with interpolation -SELECT - user_id, - count() * 10 as estimated_count -- Multiply by 1/sampling_rate -FROM events -SAMPLE 0.1 -GROUP BY user_id; -``` - -**Use cases for sampling:** -- Exploratory analytics (fast approximate results) -- Testing queries on large datasets -- Dashboard previews (refresh faster) - -## Codecs - -Apply compression to individual columns: - -```sql --- ZSTD compression (good default) -CREATE TABLE events ( - data String CODEC(ZSTD) -) -ENGINE = MergeTree() -ORDER BY user_id; - --- Compression levels -CODEC(ZSTD(3)) -- Fast, less compression -CODEC(ZSTD(15)) -- Slower, more compression - --- No compression (for already compressed data) -CODEC(NONE) - --- Multiple codecs -CODEC(Delta, ZSTD) - --- LZ4 (faster than ZSTD, less compression) -CODEC(LZ4) -``` - -**Codec guidelines:** -- Use ZSTD for most data (good balance) -- Use NONE for already-compressed data (images, encrypted data) -- Use Delta for monotonically increasing values (timestamps, IDs) -- Higher compression levels = slower queries - -## Skip Indexes - -Data skipping indexes allow ClickHouse to skip data during reads: - -```sql --- Bloom filter for exact match -CREATE TABLE events ( - user_id UInt32, - email String, - timestamp DateTime -) -ENGINE = MergeTree() -ORDER BY (user_id, timestamp) -INDEX idx_email email TYPE bloom_filter GRANULARITY 1; - --- Minmax for range queries -INDEX idx_time timestamp TYPE minmax GRANULARITY 4; - --- Set for IN queries -INDEX idx_user user_id TYPE set(1000) GRANULARITY 1; - --- Tokenbf for string search -INDEX idx_msg message TYPE tokenbf_v1(512, 3, 0) GRANULARITY 1; -``` - -**Index types:** -- `minmax`: Min/max values per granule -- `set`: Set of values (good for IN queries) -- `bloom_filter`: Probabilistic exact match -- `tokenbf_v1`: Token-based bloom filter for text search - -**Granularity:** -- Lower = more precise index, larger index size -- Higher = less precise index, smaller index size -- Default: 1 (most precise) - -## Table Settings - -```sql -CREATE TABLE events ( - timestamp DateTime, - user_id UInt32 -) -ENGINE = MergeTree() -ORDER BY (user_id, timestamp) -SETTINGS - index_granularity = 8192, -- Rows per mark (default) - index_granularity_bytes = 10485760, -- Bytes per mark - enable_mixed_granularity_parts = 1, -- Adaptive marks - min_rows_for_wide_part = 0, -- Always use wide parts - merge_max_block_size = 1048544, -- Block size for merges - storage_policy = 'default'; -- Storage policy -``` - -## See Also - -- `../SKILL.md` - Main skill entry point -- `core-concepts.md` - MergeTree internals -- `table-engines.md` - Complete table engine reference -- `schema-design.md` - Database engines and migrations diff --git a/clickhouse/skills/clickhouse/references/table-engines.md b/clickhouse/skills/clickhouse/references/table-engines.md deleted file mode 100644 index 6f786a0..0000000 --- a/clickhouse/skills/clickhouse/references/table-engines.md +++ /dev/null @@ -1,333 +0,0 @@ -# ClickHouse Table Engines - Complete Reference - -## MergeTree Family Decision Tree - -``` -Need to store data? -├── < 1M rows, dimension table → Memory engine -└── ≥ 1M rows → MergeTree family - ├── Need deduplication? → ReplacingMergeTree(version) - │ └── Keeps latest row per ORDER BY key - ├── Need changelog (insert/delete)? → CollapsingMergeTree(sign) - │ └── Uses sign column: 1=insert, -1=delete - ├── Need changelog with versions? → VersionedCollapsingMergeTree(sign, version) - │ └── Multiple versions per key - ├── Need pre-aggregation? → AggregatingMergeTree() - │ └── Custom aggregation functions - ├── Need numeric summation? → SummingMergeTree() - │ └── Sums numeric columns on merge - ├── Graphite metrics? → GraphiteMergeTree() - │ └── Optimized for Graphite rollups - ├── Need replication? → ReplicatedMergeTree(...) - │ └── All MergeTree features + replication - └── Default → MergeTree() - └── Append-only, general-purpose -``` - -## 1. MergeTree (Default) - -**Use cases**: Append-only time series, general analytics, default choice - -**Key features:** -- Append-only (no in-place updates) -- Automatic background merges -- Sparse index (8192 rows per mark) -- Supports TTL, partitions, projections - -```sql -CREATE TABLE events ( - timestamp DateTime, - user_id UInt32, - event_type String, - metadata String -) -ENGINE = MergeTree() -PARTITION BY toYYYYMM(timestamp) -ORDER BY (user_id, timestamp) -SETTINGS index_granularity = 8192; - --- Insert data -INSERT INTO events VALUES - (now(), 123, 'login', '{"ip":"1.2.3.4"}'), - (now(), 456, 'logout', '{"ip":"5.6.7.8"}'); -``` - -**When to use:** -- Time-series data (events, logs, metrics) -- Append-only workloads -- General analytics - -## 2. ReplacingMergeTree - -**Use cases**: Upsert-like behavior, latest version wins - -**Key features:** -- Deduplicates by ORDER BY on merge -- Async: doesn't guarantee immediate deduplication -- Use version column to control which row to keep -- Requires FINAL for guaranteed deduplication - -```sql -CREATE TABLE user_profiles ( - user_id UInt32, - updated_at DateTime, - profile_json String -) -ENGINE = ReplacingMergeTree(updated_at) -ORDER BY user_id; - --- Insert initial profile -INSERT INTO user_profiles VALUES (123, now(), '{"name":"Alice"}'); - --- Update profile (insert new version) -INSERT INTO user_profiles VALUES (123, now(), '{"name":"Alice Smith"}'); - --- Force final deduplication (expensive!) -SELECT * FROM user_profiles FINAL WHERE user_id = 123; - --- Without FINAL: might return both rows (not merged yet) -``` - -**Important notes:** -- Deduplication happens during merge (async, not immediate) -- Use FINAL only when necessary (expensive!) -- Better: Design queries to handle duplicates (GROUP BY, argMax) - -## 3. CollapsingMergeTree - -**Use cases**: Changelog, append-only data with deletes - -**Key features:** -- Sign column: 1 = insert, -1 = delete -- Collapses rows on merge -- Must use FINAL for correct results - -```sql -CREATE TABLE changes ( - id UInt32, - sign Int8, -- MUST be Int8 - data String -) -ENGINE = CollapsingMergeTree(sign) -ORDER BY id; - --- Insert row -INSERT INTO changes VALUES (1, 1, 'data_v1'); - --- Update row (insert + delete) -INSERT INTO changes VALUES (1, 1, 'data_v2'); -- New version -INSERT INTO changes VALUES (1, -1, 'data_v1'); -- Delete old - --- Delete row -INSERT INTO changes VALUES (1, -1, ''); - --- Query with FINAL (correct results) -SELECT * FROM changes FINAL; -``` - -## 4. VersionedCollapsingMergeTree - -**Use cases**: Multiple versions of same row before collapse - -**Key features:** -- Sign column + version column -- Collapses to latest version per sign -- Handles out-of-order inserts - -```sql -CREATE TABLE versioned_changes ( - id UInt32, - version UInt32, - sign Int8, - data String -) -ENGINE = VersionedCollapsingMergeTree(sign, version) -ORDER BY (id, version); - --- Insert version 1 -INSERT INTO versioned_changes VALUES (1, 1, 1, 'v1'); - --- Insert version 2 -INSERT INTO versioned_changes VALUES (1, 2, 1, 'v2'); - --- Collapse version 1 -INSERT INTO versioned_changes VALUES (1, 1, -1, ''); -``` - -## 5. SummingMergeTree - -**Use cases**: Pre-aggregation, numeric summation - -**Key features:** -- Sums numeric columns on merge -- Leaves first non-numeric value -- Good for incremental counters - -```sql -CREATE TABLE daily_counters ( - date Date, - user_id UInt32, - page_views UInt64, - sessions UInt64 -) -ENGINE = SummingMergeTree() -PARTITION BY date -ORDER BY (date, user_id); - --- Insert counter data -INSERT INTO daily_counters VALUES (today(), 123, 10, 2); -INSERT INTO daily_counters VALUES (today(), 123, 5, 1); - --- After merge: page_views = 15, sessions = 3 -``` - -## 6. AggregatingMergeTree - -**Use cases**: Custom aggregation functions, pre-computed states - -**Key features:** -- Stores aggregate function states -- Requires -State/-Merge combinators - -```sql -CREATE TABLE daily_stats ( - date Date, - user_id UInt32, - hits AggregateFunction(count, UInt32), - unique_users AggregateFunction(uniqCombined, UInt32) -) -ENGINE = AggregatingMergeTree() -ORDER BY (date, user_id); - --- Insert with state functions -INSERT INTO daily_stats VALUES - (today(), 123, countState(toUInt32(1)), uniqCombinedState(toUInt32(456))); - --- Query with merge functions -SELECT - user_id, - countMerge(hits) as total_hits, - uniqCombinedMerge(unique_users) as unique_users -FROM daily_stats -WHERE date = today() -GROUP BY user_id; -``` - -## 7. GraphiteMergeTree - -**Use cases**: Graphite monitoring data - -```sql -CREATE TABLE graphite ( - path String, - value Float64, - timestamp UInt32, - date Date -) -ENGINE = GraphiteMergeTree('graphite_rollup') -PARTITION BY toYYYYMM(date) -ORDER BY (path, timestamp); -``` - -## 8. ReplicatedMergeTree - -**Use cases**: Production clusters, data replication - -**Key features:** -- ZooKeeper-based replication -- Automatic failover -- All MergeTree features + replication - -```sql -CREATE TABLE events ( - timestamp DateTime, - user_id UInt32 -) -ENGINE = ReplicatedMergeTree( - '/clickhouse/tables/{shard}/events', -- ZooKeeper path - '{replica}' -- Replica name -) -PARTITION BY toYYYYMM(timestamp) -ORDER BY (user_id, timestamp); -``` - -**Configuration:** -```xml - - - - 01 - replica_1 - - -``` - -## Special Engines - -### Memory - -**Use cases**: Small dimension tables, caching - -```sql -CREATE TABLE dim_users ( - user_id UInt32, - name String -) -ENGINE = Memory; -``` - -### Dictionary - -```sql -CREATE TABLE users_dict ( - user_id UInt32, - email String -) -ENGINE = Dictionary(user_dictionary); -``` - -### File/URL/S3/HDFS - -```sql --- S3 table -CREATE TABLE s3_data (...) -ENGINE = S3('https://bucket.s3.amazonaws.com/data/*.csv', 'CSV'); - --- URL table -CREATE TABLE url_data (...) -ENGINE = URL('https://example.com/data.csv', 'CSV'); -``` - -### Join - -```sql -CREATE TABLE users_right ( - user_id UInt32, - name String -) -ENGINE = Join(ANY, LEFT, user_id); - --- Usage -SELECT * FROM events LEFT JOIN users_right USING (user_id); -``` - -### Kafka - -```sql -CREATE TABLE kafka_events ( - timestamp DateTime, - data String -) -ENGINE = Kafka -SETTINGS - kafka_broker_list = 'localhost:9092', - kafka_topic_list = 'events', - kafka_group_name = 'clickhouse', - kafka_format = 'JSONEachRow'; -``` - -## See Also - -- `../SKILL.md` - Main skill entry point -- `core-concepts.md` - MergeTree internals and architecture -- `table-design.md` - ORDER BY and partitioning strategies diff --git a/clickhouse/spec/spec-process-cicd-sync-rules.md b/clickhouse/spec/spec-process-cicd-sync-rules.md deleted file mode 100644 index ef141a3..0000000 --- a/clickhouse/spec/spec-process-cicd-sync-rules.md +++ /dev/null @@ -1,241 +0,0 @@ ---- -title: CI/CD Workflow Specification - ClickHouse Rules Sync -version: 1.0 -date_created: 2025-03-13 -last_updated: 2025-03-13 -owner: duyetbot -tags: [process, cicd, github-actions, automation, sync, clickhouse] ---- - -## Workflow Overview - -**Purpose**: Automatically synchronize ClickHouse best practice rule files from the official ClickHouse/agent-skills repository to maintain rule currency. -**Trigger Events**: Manual workflow dispatch, Weekly schedule (Sunday 00:00 UTC) -**Target Environments**: Source code repository (rules directory only) - -## Execution Flow Diagram - -```mermaid -graph TD - A[Trigger Event] --> B[Checkout This Repo] - B --> C[Checkout ClickHouse/agent-skills] - C --> D[Copy Rule Files] - D --> E[Update Version] - E --> F{Changes Detected?} - F -->|Yes| G[Create Pull Request] - F -->|No| H[End - No Changes] - G --> I[End - PR Created] - - style A fill:#e1f5fe - style H fill:#fff9c4 - style I fill:#e8f5e8 -``` - -## Jobs & Dependencies - -| Job Name | Purpose | Dependencies | Execution Context | -|----------|---------|--------------|-------------------| -| sync-rules | Sync upstream rules to local | None | ubuntu-latest | - -## Requirements Matrix - -### Functional Requirements - -| ID | Requirement | Priority | Acceptance Criteria | -|----|-------------|----------|-------------------| -| REQ-001 | Fetch latest ClickHouse/agent-skills | High | Successful git clone from upstream | -| REQ-002 | Copy rule files to skills/clickhouse/rules/ | High | All 28 rule files copied without errors | -| REQ-003 | Auto-increment version number | Medium | SKILL.md and plugin.json versions incremented | -| REQ-004 | Create PR on changes | High | PR created only when actual changes detected | -| REQ-005 | Preserve custom content | Critical | references/ directory never modified | - -### Security Requirements - -| ID | Requirement | Implementation Constraint | -|----|-------------|---------------------------| -| SEC-001 | Token permissions | Minimal: contents:write, pull-requests:write | -| SEC-002 | Upstream verification | Clone only from official ClickHouse/agent-skills repo | -| SEC-003 | Branch isolation | Use dedicated branch, auto-delete after merge | - -### Performance Requirements - -| ID | Metric | Target | Measurement Method | -|----|-------|--------|-------------------| -| PERF-001 | Execution time | < 5 minutes | GitHub Actions timing | -| PERF-002 | PR creation latency | < 30 seconds after sync | PR creation timestamp | - -## Input/Output Contracts - -### Inputs - -```yaml -# Workflow Dispatch Inputs -# (None currently - could add branch, upstream ref options) - -# Schedule Trigger -cron: '0 0 * * 0' # Weekly Sunday midnight UTC - -# Repository Context -default_branch: main -upstream_repo: ClickHouse/agent-skills -upstream_ref: main -``` - -### Outputs - -```yaml -# Job Outputs -has_changes: boolean # Whether changes were detected -new_version: string # Updated version number if changed -pr_number: integer # Created PR number (if applicable) -``` - -### Secrets & Variables - -| Type | Name | Purpose | Scope | -|------|------|---------|-------| -| Token | GITHUB_TOKEN | PR creation, commits | Workflow | -| Variable | RULES_DIR | Target directory path | Repository | -| Variable | UPSTREAM_REPO | Source repository | Repository | - -## Execution Constraints - -### Runtime Constraints - -- **Timeout**: 10 minutes maximum -- **Concurrency**: Single workflow instance at a time -- **Resource Limits**: Standard ubuntu-latest (2-core, 7GB RAM) - -### Environmental Constraints - -- **Runner Requirements**: ubuntu-latest with git, coreutils -- **Network Access**: github.com (read/write), api.github.com -- **Permissions**: contents:write, pull-requests:write - -## Error Handling Strategy - -| Error Type | Response | Recovery Action | -|------------|----------|-----------------| -| Upstream clone failure | Fail workflow | Check network, repo availability | -| Version parse failure | Fail workflow | Manual version update required | -| No changes detected | Exit success | No PR created, workflow ends cleanly | -| PR creation failure | Fail workflow | Check token permissions, branch conflicts | - -## Quality Gates - -### Gate Definitions - -| Gate | Criteria | Bypass Conditions | -|------|----------|-------------------| -| Upstream availability | Repo reachable, ref exists | None - critical path | -| Rule file validity | Files contain expected frontmatter | Review required if malformed | -| Version format | Semantic version (X.Y.Z) | None - automated increment | - -## Monitoring & Observability - -### Key Metrics - -- **Success Rate**: Target 95%+ (upstream deps) -- **Execution Time**: Target < 5 minutes -- **PR Merge Rate**: Track how often sync PRs are merged - -### Alerting - -| Condition | Severity | Notification Target | -|-----------|----------|-------------------| -| 3+ consecutive failures | High | Repository maintainers | -| Upstream repo unavailable | Critical | Immediate notification | -| Version increment failure | Medium | Review required | - -## Integration Points - -### External Systems - -| System | Integration Type | Data Exchange | SLA Requirements | -|--------|------------------|---------------|------------------| -| ClickHouse/agent-skills | Git clone (read-only) | Rule files (Markdown) | Best-effort, retry on failure | -| GitHub API | REST API (write) | Pull requests | GitHub platform SLA | - -### Dependent Workflows - -| Workflow | Relationship | Trigger Mechanism | -|----------|--------------|-------------------| -| None | Independent | Manual/schedule only | - -## Compliance & Governance - -### Audit Requirements - -- **Execution Logs**: Retained 90 days per GitHub default -- **Approval Gates**: Manual review required for sync PRs -- **Change Control**: PR workflow enforces review before merge - -### Security Controls - -- **Access Control**: Repository maintainers approve workflow changes -- **Secret Management**: GitHub Actions token (auto-provisioned) -- **Vulnerability Scanning**: Third-party actions pinned to version - -## Edge Cases & Exceptions - -### Scenario Matrix - -| Scenario | Expected Behavior | Validation Method | -|----------|-------------------|-------------------| -| Upstream rule deleted | Local file preserved | Manual review required | -| Version format changes | Parse failure → workflow fails | Check version string format | -| Conflicting branch exists | PR creation may fail | Force-push or branch rename | -| No upstream changes | Exit cleanly, no PR | Check git diff output | - -## Validation Criteria - -### Workflow Validation - -- **VLD-001**: All 28 rule files copied -- **VLD-002**: Version incremented in both SKILL.md and plugin.json -- **VLD-003**: references/ directory unchanged -- **VLD-004**: PR created only with actual changes - -### Performance Benchmarks - -- **PERF-001**: Complete execution < 5 minutes -- **PERF-002**: PR creation < 30 seconds from workflow start - -## Change Management - -### Update Process - -1. **Specification Update**: Modify this document first -2. **Review & Approval**: Create PR for spec changes -3. **Implementation**: Apply changes to sync-rules.yml -4. **Testing**: Manually trigger workflow to validate -5. **Deployment**: Merge to main branch - -### Version History - -| Version | Date | Changes | Author | -|---------|------|---------|--------| -| 1.0 | 2025-03-13 | Initial specification | duyetbot | - -## Related Specifications - -- [ClickHouse/agent-skills Repository](https://github.com/ClickHouse/agent-skills) -- [GitHub Actions Documentation](https://docs.github.com/en/actions) -- [Claude Plugins Documentation](../README.md) - -## Appendix: Rule File Mapping - -| Rule Category | Count | File Pattern | -|---------------|-------|--------------| -| Primary Key | 4 | schema-pk-*.md | -| Data Types | 5 | schema-types-*.md | -| Partitioning | 4 | schema-partition-*.md | -| JSON | 1 | schema-json-*.md | -| JOIN | 5 | query-join-*.md | -| Materialized Views | 2 | query-mv-*.md | -| Indexing | 1 | query-index-*.md | -| Batching | 1 | insert-batch-*.md | -| Async | 2 | insert-async-*.md | -| Mutation | 2 | insert-mutation-*.md | -| Optimization | 1 | insert-optimize-*.md | -| **Total** | **28** | - | diff --git a/command-code/.claude-plugin/plugin.json b/command-code/.claude-plugin/plugin.json index 87facc5..0eaa5c5 100644 --- a/command-code/.claude-plugin/plugin.json +++ b/command-code/.claude-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "command-code", - "version": "1.0.0", - "description": "Drive the Command Code CLI (`cmd`) and orchestrate it as a headless sub-agent — fan out `cmd -p --yolo --max-turns 100000` workers across isolated git worktrees to implement issues and tasks in parallel.", + "version": "1.1.0", + "description": "Dispatch the Command Code CLI (`cmd`) as headless sub-agents across isolated git worktrees.", "author": { "name": "duyet", "url": "https://github.com/duyet" diff --git a/command-code/.codex-plugin/plugin.json b/command-code/.codex-plugin/plugin.json index 5609ed1..9acc112 100644 --- a/command-code/.codex-plugin/plugin.json +++ b/command-code/.codex-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "command-code", - "version": "1.0.0", - "description": "Drive the Command Code CLI (`cmd`) and orchestrate it as a headless sub-agent — fan out `cmd -p --yolo --max-turns 100000` workers across isolated git worktrees to implement issues and tasks in parallel.", + "version": "1.1.0", + "description": "Dispatch the Command Code CLI (`cmd`) as headless sub-agents across isolated git worktrees.", "author": { "name": "duyet", "url": "https://github.com/duyet" @@ -12,7 +12,7 @@ "agents": "./agents/", "interface": { "displayName": "Command Code", - "shortDescription": "Drive the Command Code CLI (`cmd`) and orchestrate it as a headless sub-agent — fan out `cmd -p --yolo --max-turns 100000` workers across isolated git worktrees to implement issues and tasks in parallel.", + "shortDescription": "Dispatch the Command Code CLI (`cmd`) as headless sub-agents across isolated git worktrees.", "developerName": "duyet", "category": "Development", "capabilities": [ diff --git a/command-code/.cursor-plugin/plugin.json b/command-code/.cursor-plugin/plugin.json index 0fdfdfc..4800b65 100644 --- a/command-code/.cursor-plugin/plugin.json +++ b/command-code/.cursor-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "command-code", - "version": "1.0.0", - "description": "Drive the Command Code CLI (`cmd`) and orchestrate it as a headless sub-agent — fan out `cmd -p --yolo --max-turns 100000` workers across isolated git worktrees to implement issues and tasks in parallel.", + "version": "1.1.0", + "description": "Dispatch the Command Code CLI (`cmd`) as headless sub-agents across isolated git worktrees.", "author": { "name": "duyet" }, diff --git a/command-code/.grok-build-plugin/plugin.json b/command-code/.grok-build-plugin/plugin.json index c944665..c139f69 100644 --- a/command-code/.grok-build-plugin/plugin.json +++ b/command-code/.grok-build-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "command-code", - "version": "1.0.0", - "description": "Drive the Command Code CLI (`cmd`) and orchestrate it as a headless sub-agent — fan out `cmd -p --yolo --max-turns 100000` workers across isolated git worktrees to implement issues and tasks in parallel.", + "version": "1.1.0", + "description": "Dispatch the Command Code CLI (`cmd`) as headless sub-agents across isolated git worktrees.", "author": { "name": "duyet", "url": "https://github.com/duyet" @@ -13,7 +13,7 @@ "agents": "./agents/", "interface": { "displayName": "Command Code", - "shortDescription": "Drive the Command Code CLI (`cmd`) and orchestrate it as a headless sub-agent — fan out `cmd -p --yolo --max-turns 100000` workers across isolated git worktrees to implement issues and tasks in parallel.", + "shortDescription": "Dispatch the Command Code CLI (`cmd`) as headless sub-agents across isolated git worktrees.", "developerName": "duyet", "category": "Development", "capabilities": [ diff --git a/command-code/.grok-plugin/plugin.json b/command-code/.grok-plugin/plugin.json index 000e00a..fe6eb23 100644 --- a/command-code/.grok-plugin/plugin.json +++ b/command-code/.grok-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "command-code", - "version": "1.0.0", - "description": "Drive the Command Code CLI (`cmd`) and orchestrate it as a headless sub-agent — fan out `cmd -p --yolo --max-turns 100000` workers across isolated git worktrees to implement issues and tasks in parallel.", + "version": "1.1.0", + "description": "Dispatch the Command Code CLI (`cmd`) as headless sub-agents across isolated git worktrees.", "author": { "name": "duyet", "url": "https://github.com/duyet" diff --git a/command-code/README.md b/command-code/README.md index 19f2dbc..1179907 100644 --- a/command-code/README.md +++ b/command-code/README.md @@ -1,45 +1,21 @@ # command-code -Drive the **Command Code CLI (`cmd`)** from Claude Code — and orchestrate it as a **headless sub-agent** to implement work in parallel. - -`cmd` (Command Code) is a standalone terminal coding agent that continuously learns your taste of writing code. This plugin teaches Claude how to run it correctly, and how to fan it out across isolated git worktrees so several `cmd` workers implement independent tasks (or GitHub issues) at once. - -## What's inside - -| Component | What it does | -|---|---| -| **Skill** `command-code` | The full contract for running `cmd`: the mandatory headless invocation, the worktree dispatch workflow, taste/MCP/skills, and safety rules. Auto-triggers on "cmd", "Command Code", "dispatch cmd", etc. | -| **Reference** `references/cli-reference.md` | Complete flag list, sub-commands, slash commands, and exit codes. | -| **Command** `/command-code:dispatch` | Guided fan-out: turn issues/tasks into isolated `cmd` workers, launch, track, review. | -| **Agent** `cmd-dispatcher` | Sub-agent that orchestrates the whole dispatch loop end to end. | - -## The one rule to remember - -For any unattended / background run, always: +Drive the Command Code CLI (`cmd`) from your coding agent, and dispatch it as a headless sub-agent that implements tasks or GitHub issues in parallel, each in its own git worktree. ```bash -cmd -p "" --yolo --max-turns 100000 --skip-onboarding +/plugin install command-code@duyet-claude-plugins ``` -Miss any of these and the headless task **breaks**: -- no `-p` → opens a REPL and waits for a human -- no `--yolo` → hangs on the first permission prompt -- default `--max-turns` (10) → exits code 8 mid-implementation -- no `--skip-onboarding` → blocks on the taste-onboarding demo - -## Dispatch pattern +## What ships -1. One git worktree + branch per worker (never two `cmd` runs in one dir). -2. A self-contained spec as the prompt — `cmd` shares none of your context; give it exact file seams, scope, style, and the commit message. -3. Launch in the background, capture a per-worker log. -4. Tell workers **not** to build; verify once after collecting branches (parallel builds OOM). -5. Review each diff; nothing is pushed or merged without your approval. +- `command-code` skill. The headless invocation (`cmd -p ... --yolo --max-turns 100000 --skip-onboarding`), the worktree dispatch workflow, review and resume rules, and safety notes. +- `/command-code:dispatch` command. Turns issues or tasks into isolated workers, launches them, and reviews the branches. +- `cmd-dispatcher` agent. Runs the whole dispatch loop. ## Safety -`--yolo` runs an autonomous agent loop with no approval gate. Only launch with the user's explicit consent, always in a dedicated worktree on a branch (never straight onto `main`), with "do not push" in the prompt. You are the approval gate — moved to diff-review time. +`--yolo` removes the approval gate, so you review each diff before merging. Dispatch only with the user's consent, in a dedicated worktree on a branch, with "do not push" in the prompt. ## Requirements -- `cmd` installed and authenticated (`cmd login`; verify with `cmd status`). -- `git` (for worktree isolation), and `gh` if dispatching over GitHub issues. +`cmd` installed and authenticated (`cmd login`, check with `cmd status`), `git`, and `gh` for issue-based work. diff --git a/command-code/agents/cmd-dispatcher.md b/command-code/agents/cmd-dispatcher.md index ad838b2..e3d65b8 100644 --- a/command-code/agents/cmd-dispatcher.md +++ b/command-code/agents/cmd-dispatcher.md @@ -1,32 +1,11 @@ --- name: cmd-dispatcher -description: Orchestrates the Command Code CLI (`cmd`) as headless sub-agents. Use proactively when the task is "spawn cmd", "dispatch cmd", "use cmd to implement these issues", "fan out cmd workers", or any request to run `cmd` unattended/in parallel. Sets up isolated worktrees, launches `cmd -p --yolo --max-turns 100000`, tracks the runs, and reviews the resulting branches. +description: Orchestrates the Command Code CLI (`cmd`) as headless sub-agents. Use when asked to spawn or dispatch cmd, fan out cmd workers, or run cmd unattended or in parallel. tools: Bash, Read, Edit, Write, Glob, Grep --- -# cmd Dispatcher +# cmd dispatcher -You orchestrate **Command Code (`cmd`)** running headlessly to implement work in parallel. Load the `command-code` skill for the full contract; the essentials are below. +Run the dispatch workflow in `skills/command-code/SKILL.md`, using the steps in `commands/dispatch.md`. Do not deviate from the skill's invocation flags, consent, or isolation rules. -## The invocation (never deviate) - -```bash -cmd -p "" --yolo --max-turns 100000 --skip-onboarding -``` - -Every flag is required for unattended runs: -- `-p` headless (no REPL), `--yolo` no permission gate (else it hangs on the first action), `--max-turns 100000` (default 10 exits code 8 mid-task), `--skip-onboarding` (else the taste demo blocks a fresh run). - -## Operating rules - -1. **Consent + auth first.** `--yolo` is unsupervised. Confirm the user authorized autonomous dispatch, and `cmd status` shows authenticated, before launching anything. -2. **One worktree + branch per worker.** Never two `cmd` sessions in one directory — they corrupt each other's edits and index. `git worktree add -b feat/ `. -3. **The prompt is the whole brief.** `cmd` shares none of your context. Include: what & why, exact file seams (path:line + pattern to copy), scope in/out, style rules, `do not run pnpm install or any build`, the exact commit message, `do not push`, and `print a summary at the end`. -4. **Background + log.** Launch each worker as a background process, redirecting to a per-worker log file. -5. **No parallel builds.** Tell every worker not to install/build; verify once yourself after collecting branches (concurrent builds OOM). -6. **Review the diff, not the log.** On completion: `git -C diff --stat ..HEAD` and read it. Exit code 8 = unfinished; resume with `cmd -c -p "continue…" --yolo --max-turns 100000`. -7. **Never push or merge** without the user's explicit approval. `--yolo` moved the approval gate to you, at review time. - -## Output - -Report a table of workers (slug → branch → worktree → log), then, as each finishes, a concise per-branch review: what changed, whether it's complete, and any deviations from spec. End with a recommendation on what's ready to merge. +Report a table of workers (slug, branch, worktree, log). As each finishes, give a short review of what changed, whether it is complete, and any deviations from the spec. End with what is ready to merge. diff --git a/command-code/commands/dispatch.md b/command-code/commands/dispatch.md index 83a4115..57e82fe 100644 --- a/command-code/commands/dispatch.md +++ b/command-code/commands/dispatch.md @@ -1,48 +1,14 @@ --- -description: Dispatch one or more headless Command Code (`cmd`) workers to implement well-scoped tasks or GitHub issues in parallel — each in its own git worktree, running `cmd -p --yolo --max-turns 100000`, committed to its own branch for review. +description: Dispatch headless Command Code (`cmd`) workers to implement scoped tasks or GitHub issues in parallel, each in its own git worktree and branch. --- # /command-code:dispatch -Fan out implementation work to the **Command Code CLI (`cmd`)** running headlessly as sub-agents. Read the `command-code` skill first — it has the invocation contract, the worktree workflow, and the safety rules. +Work: **$ARGUMENTS** -The user's request (issues, tasks, or a description) is: **$ARGUMENTS** +Follow the dispatch workflow in `skills/command-code/SKILL.md`. -## Step 0 — Preconditions - -- Confirm `cmd` is installed and authenticated: `which cmd && cmd status`. If not authenticated, tell the user to run `cmd login` and stop. -- Confirm you're in a git repo with a clean base branch. Note the base branch (usually `main`). -- **Get explicit consent for `--yolo`.** These workers run unsupervised with no permission gate. State that plainly and confirm the user wants autonomous background dispatch. If the host blocks the launch, surface it and let the user decide — do not try to bypass. - -## Step 1 — Resolve the work-list - -Turn `$ARGUMENTS` into a concrete list of independent units of work: -- GitHub issue numbers → one worker per issue (each will `gh issue view `). -- A larger task → decompose into independent, separately-committable pieces. If pieces have dependencies, dispatch only the independent ones now and note the rest as follow-ups. -- If the work isn't cleanly separable or is too small to be worth a handoff, say so and offer to just do it inline instead. - -## Step 2 — Write a self-contained spec per worker - -`cmd` shares none of this conversation's context. For each unit, write a prompt that stands alone (see the skill's "Write a self-contained spec"): what & why, exact file seams with paths/line numbers and the pattern to copy, scope in/out, style rules, `do not run pnpm install or any build`, the exact conventional-commit message, `do not push`, and a closing `print a summary of files changed + deviations`. - -## Step 3 — Isolate + launch - -One worktree + branch per worker; launch each in the background with the mandatory flags: - -```bash -BASE= -git worktree add -b feat/ "$BASE/" -( cd "$BASE/" && \ - cmd -p "" --yolo --max-turns 100000 --skip-onboarding > "$BASE/.log" 2>&1 ) & -``` - -`--yolo --max-turns 100000 --skip-onboarding` is non-negotiable — without them the headless task hangs or exits code 8 mid-run. Never run two workers in the same directory. - -## Step 4 — Track, then review - -- Report the launched workers (slug → branch → worktree → log path). Let them run in the background; you'll be notified as each finishes. -- On completion, review each branch (`git -C log/diff --stat ..HEAD`) and read the diff — don't trust the log alone. Note anyone that exited code 8 (unfinished) and offer to resume it with `cmd -c`. - -## Step 5 — Verify once, after collecting branches - -Do NOT build inside the parallel workers. After the branches are ready, bring them into one tree and run a single consolidated typecheck/test pass, then report per-branch status (clean / needs-fix) so the user can decide what to merge. Nothing is pushed or merged without the user's say-so. +1. Turn `$ARGUMENTS` into independent units: one worker per issue number, or a larger task split into separately committable pieces. Dispatch only independent pieces now and list the rest as follow-ups. If the work is too small or not separable, offer to do it inline. +2. Check preconditions and get consent, then write a spec, create a worktree, and launch each worker as the skill describes. +3. Report each worker as slug, branch, worktree, and log path. +4. As workers finish, review each diff, note any that exited with code 8, run one consolidated verification, and report each branch as clean or needs-fix. Push and merge nothing without the user's say-so. diff --git a/command-code/skills/command-code/SKILL.md b/command-code/skills/command-code/SKILL.md index f51a645..77a84ab 100644 --- a/command-code/skills/command-code/SKILL.md +++ b/command-code/skills/command-code/SKILL.md @@ -1,141 +1,57 @@ --- name: command-code -description: Drive the Command Code CLI (`cmd`) — a terminal coding agent that learns your taste — and orchestrate it as a headless sub-agent. Use this skill whenever the user mentions "cmd", "Command Code", "commandcode", asks to "spawn cmd", "dispatch cmd", "use cmd as a subagent", run coding work headlessly/unattended, fan out implementation across GitHub issues or tasks with cmd, learn/manage taste, or set up `cmd` MCP/skills/auth. Also use it whenever you are about to launch `cmd` in print/headless mode and need the correct flags (always `--yolo --max-turns 100000 --skip-onboarding`). +description: Run the Command Code CLI (`cmd`) and dispatch it as a headless sub-agent on well-scoped tasks or GitHub issues. Use when the user mentions cmd or Command Code, asks to spawn or dispatch cmd, or when you are about to launch `cmd -p` and need the correct flags. --- # Command Code (`cmd`) -`cmd` (Command Code) is a standalone terminal coding agent — a sibling to Claude Code / Codex — that **continuously learns the user's taste of writing code**. It has its own model access, permission system, session store, MCP support, and a "taste" personalization layer. This skill teaches you to (a) run it interactively, and (b) drive it **headlessly as a sub-agent** to implement work in parallel. +`cmd` is a standalone terminal coding agent with its own model access, permissions, sessions, MCP support, and a "taste" layer that learns how the user writes code. Its best use here is as a headless sub-agent: you write a precise spec, give it an isolated worktree, and it implements, tests, and commits while you do other work. Run `cmd --help` for flags and subcommands. -The high-value use is the second one: `cmd` is excellent at being *dispatched* — you write a precise spec, hand it an isolated worktree, and let it implement, test, and commit autonomously while you do other work. +This skill is the single home for the dispatch rules. `/command-code:dispatch` and the `cmd-dispatcher` agent follow it. -## The one invocation to memorize - -For any unattended / headless / background dispatch, ALWAYS use: +## Headless invocation ```bash -cmd -p "" --yolo --max-turns 100000 --skip-onboarding +cmd -p "" --yolo --max-turns 100000 --skip-onboarding ``` -- **`-p/--print`** runs non-interactive: `cmd` executes the prompt and exits (no REPL). Required for scripting/background. -- **`--yolo`** bypasses every permission prompt (alias for `--dangerously-skip-permissions`). A headless `cmd` **cannot answer prompts** — without this it will hang forever the first time it wants to run a command or edit a file. This is mandatory for background runs. -- **`--max-turns 100000`** effectively removes the turn cap. The default is only **10**, and `cmd` **exits with code 8** the moment it hits the cap — mid-implementation, leaving a half-done branch. Real implementation tasks need many turns; set it absurdly high so the task finishes on its own merits, not on an arbitrary limit. -- **`--skip-onboarding`** skips the interactive taste-onboarding demo, which would otherwise block a fresh headless run. - -`--yolo` is powerful and unsupervised. See [Safety & consent](#safety--consent) — you must have the user's go-ahead and you must isolate the work. - -## When to reach for `cmd` vs. doing it yourself - -Use `cmd` as a sub-agent when: -- The user explicitly asks to "spawn/dispatch/use cmd". -- There is **independent, parallelizable** implementation work (e.g. several GitHub issues, several packages) that can each be handed off with a clear spec and acceptance criteria. -- You want a second, taste-personalized implementer to take a well-scoped task off your plate while you keep orchestrating. - -Do it yourself (don't dispatch) when the task is small, exploratory, needs tight back-and-forth, or isn't cleanly specifiable yet — the cost of writing a full handoff spec exceeds just doing it. +Every flag is required for unattended runs. -## Dispatching `cmd` as a headless sub-agent +- `-p` runs once and exits. Without it `cmd` opens a REPL and waits for a human. +- `--yolo` skips every permission prompt. A headless run cannot answer them and hangs on the first action without it. +- `--max-turns 100000` removes the cap. The default is 10, and `cmd` exits with code 8 at the cap, leaving a half-done branch. +- `--skip-onboarding` stops the taste demo from blocking a fresh run. -This is the core workflow. Follow it exactly; each step exists to prevent a real failure mode. +## When to dispatch -### 1. Isolate the work in a git worktree - -Never run two headless `cmd` sessions in the same working directory — they will clobber each other's edits and git index. Give each its own worktree on its own branch: - -```bash -git worktree add -b feat/ /path/to/wt/ -``` +Dispatch when the user asks for it, or when there is independent work (several issues or packages) that can each be handed off with a clear spec. Do it yourself when the task is small, exploratory, needs back-and-forth, or cannot yet be specified, because the handoff costs more than the work. -One worktree per parallel task. Serial tasks in the same repo can reuse the main tree, but isolation is cheap insurance. +## Dispatch workflow -### 2. Write a self-contained spec as the prompt +1. **Preconditions.** Run `cmd status` and stop if unauthenticated, since every worker would fail the same way. Get the user's explicit consent for `--yolo`, as workers run with no approval gate. If the host blocks the launch, surface it and ask. Do not work around it. +2. **Isolate.** One git worktree and branch per worker: `git worktree add -b feat/ `. Never run two workers in one directory, because they corrupt each other's edits and index. +3. **Write the spec.** `cmd` shares none of your context, so the prompt is the whole brief. Include: + - What and why, in a sentence or two. + - Exact file seams (`path:line`) and the pattern to copy. This is the biggest quality lever. + - Scope in and out, and style rules (match the repo, do not reformat unrelated code). + - "Do not run install or any full build." + - The exact conventional-commit message and "do not push". + - "Print a summary of files changed and deviations at the end." -`cmd` starts fresh — it does **not** share your conversation context. The prompt is the entire brief. A good dispatch prompt contains: -- **What & why** in one or two sentences. -- **Exact file seams** — paths and line numbers to read first (`packages/x/src/y.ts:120`), and the pattern to copy from. This is the single biggest quality lever; `cmd` implements far better against concrete anchors than against prose. -- **Scope boundaries** — what's in and explicitly what's out ("stub the gateway; adapter + tests only"). -- **Style rules** — match the repo (indent, quotes, imports); tell it *not* to reformat unrelated code. -- **Build/test policy** — see [Don't let parallel workers build](#dont-let-parallel-workers-build). -- **Commit instructions** — exact conventional-commit message; "do not push". -- **A closing "print a summary of files changed + deviations"** so the log ends with something reviewable. + For a GitHub issue, tell it to run `gh issue view `, and still restate seams and constraints. +4. **Launch in the background**, one log per worker. -If the work is a GitHub issue, tell `cmd` to `gh issue view ` itself and follow it — but still restate the seams and constraints in the prompt; don't assume the issue body is enough. + ```bash + ( cd && cmd -p "" --yolo --max-turns 100000 --skip-onboarding > .log 2>&1 ) & + ``` -### 3. Launch in the background, capture the log +5. **Review.** When a worker finishes, read `git -C log --oneline ..HEAD` and `git diff --stat ..HEAD`, then the diff. Do not trust the log alone. +6. **Verify once.** Concurrent builds across worktrees cause out-of-memory failures, so run one typecheck and test pass after merging the branches into a single tree. +7. **Resume if needed.** Exit code 8 means unfinished. Prefer a fresh narrowly scoped `cmd -p` naming only the remaining work. `cmd -c -p "..."` reloads the whole prior conversation and can overflow context on a large session, so use it only for short ones. -```bash -cd /path/to/wt/ -cmd -p "" --yolo --max-turns 100000 --skip-onboarding > /path/to/wt/.log 2>&1 -``` - -Run it as a background process so several `cmd` workers proceed concurrently. Redirect to a per-task log file you can tail for progress and read on completion. - -### 4. Review the branch, then verify — after merge, not during - -When a worker finishes, inspect its branch, don't trust the log alone: - -```bash -git -C /path/to/wt/ log --oneline ..HEAD -git -C /path/to/wt/ diff --stat ..HEAD -``` +Nothing is pushed or merged without the user's approval. Treat `--yolo` as moving the approval gate to review time, and never put secrets in a prompt. -Read the diff. Then run the consolidated typecheck/test **once**, after collecting the branches — see below. - -### Don't let parallel workers build - -Concurrent `pnpm build` / `bun build` across several worktrees causes OOM and thrashing. In every dispatch prompt, tell `cmd`: **do not run `pnpm install` or any full build; writing correct code + tests is sufficient.** Verify once, yourself, after merging the branches into a single tree. This is the same discipline you'd apply to any parallel sub-agent fleet. - -## Interactive & other modes - -`cmd` is also a normal interactive agent. Common forms: - -| Goal | Command | -|---|---| -| Start a REPL session | `cmd` | -| Start with a first message | `cmd "refactor the auth module"` | -| One-shot answer, then exit | `cmd -p "explain apps/main/src/auth.ts"` | -| Resume last conversation | `cmd -c` / `cmd --continue` (⚠️ can overflow context on a *large* prior session — for a small leftover task prefer a fresh scoped `cmd -p`; see `references/cli-reference.md`) | -| Resume a named conversation | `cmd -r ""` | -| Fork a session (leave original untouched) | `cmd --resume --fork-session` | -| Plan first, don't edit | `cmd --plan` or `--permission-mode plan` | -| Auto-accept edits but keep some gates | `cmd --auto-accept` / `--permission-mode auto-accept` | -| Pick the model | `cmd -m ` (`cmd --list-models` to see options) | -| Add extra context dirs | `cmd --add-dir ` | - -For the complete flag list, sub-commands (`taste`, `mcp`, `skills`, `login`), slash commands, and exit codes, read **`references/cli-reference.md`**. - -## Taste, goals, MCP, skills — the personalization layer - -`cmd`'s differentiator is **taste**: it learns how the user likes code written and applies it automatically. -- `cmd taste` — manage taste packages; `cmd taste learn ` — learn taste from a codebase. -- `cmd learn-taste` / `cmd --learn-taste` — build taste from existing Claude Code / Codex sessions. -- `/goal ""` (slash command inside a session) — set a standing objective the agent works toward; `/goal status`, `/goal clear`. -- `cmd mcp` — manage MCP servers; `cmd skills` — manage skills from GitHub repos. -- `cmd login` / `cmd status` / `cmd whoami` — auth. Before any headless fleet, confirm `cmd status` shows authenticated, or every worker fails identically. - -When dispatching for a taste-sensitive codebase, consider running `cmd taste learn ` once up front so the workers inherit the house style. - -## Safety & consent - -`--yolo` runs an autonomous agent loop with **no approval gate** — it can run any shell command or file edit in its working directory unsupervised. Treat it like handing someone commit access to that worktree. - -- **Get explicit user consent** before launching `--yolo` runs. The host harness may also block launching an unsupervised third-party agent until the user has clearly authorized "approvals off"; if a launch is denied, surface it and ask — don't try to work around it. -- **Contain the blast radius**: dedicated worktree, a branch (never straight onto `main`), and "do not push" in the prompt so nothing leaves the machine without your review. -- **Never** put secrets in the prompt; `cmd` inherits the environment and its own auth. -- Review every diff before merging. `--yolo` means *you* are the approval gate, moved to the end. - -## Quick reference: dispatch a fleet over GitHub issues - -```bash -BASE=/path/to/worktrees; mkdir -p $BASE -for spec in "72:publications" "76:webhooks" "78:k8s-sandbox"; do - n=${spec%%:*}; slug=${spec##*:} - git worktree add -b "feat/issue-$n-$slug" "$BASE/issue-$n" main - ( cd "$BASE/issue-$n" && \ - cmd -p "Implement GitHub issue #$n. Run 'gh issue view $n' and follow it exactly. ." \ - --yolo --max-turns 100000 --skip-onboarding > "$BASE/issue-$n.log" 2>&1 ) & -done -wait -# then: review each branch's diff, merge, and run ONE consolidated typecheck/test pass. -``` +## Taste and auth -Use the `/command-code:dispatch` command for a guided version of this fan-out. +- `cmd taste learn ` learns house style from a repo. Run it once before dispatching into a taste-sensitive codebase. +- `cmd login` and `cmd status` handle auth. `/goal ""` inside a session sets a standing objective. diff --git a/command-code/skills/command-code/references/cli-reference.md b/command-code/skills/command-code/references/cli-reference.md deleted file mode 100644 index dae6fba..0000000 --- a/command-code/skills/command-code/references/cli-reference.md +++ /dev/null @@ -1,100 +0,0 @@ -# Command Code (`cmd`) — Full CLI Reference - -Reference for `cmd` v0.44.x. Read this when you need a flag, sub-command, slash command, or exit code that isn't in `SKILL.md`. Verify against `cmd --help` if behavior looks different — the CLI evolves. - -## Invocation forms - -| Form | Meaning | -|---|---| -| `cmd` | Start an interactive session (REPL). | -| `cmd "message"` | Start interactive, seeded with an initial message. | -| `cmd -p "query"` / `cmd --print "query"` | **Non-interactive / headless**: run the query, print the response, exit. The basis of all scripting and background dispatch. | - -## Options - -| Flag | Description | -|---|---| -| `-r, --resume [name]` | Resume a conversation by id or name (quote multi-word names), or pick from history if omitted. | -| `-c, --continue` | Continue the last conversation. | -| `--fork-session` | With `--resume`/`--continue`, fork into a new session; the original is left untouched. | -| `-t, --trust` | Auto-trust the project (skip the one-time "trust the files in this folder?" prompt). Per project directory. | -| `-p, --print [query]` | Non-interactive mode: output response and exit. | -| `--max-turns ` | Cap conversation turns in `-p` mode. **Default 10. Exits with code 8 when the cap is hit.** For real implementation work set this very high (e.g. `100000`) so the task finishes on completion, not on the cap. | -| `-m, --model ` | Run this session on a specific model. | -| `--list-models` | List available models and exit. | -| `--plan` | Start in plan mode (agent plans, doesn't edit, until you approve). | -| `--permission-mode ` | `standard` \| `plan` \| `auto-accept`. | -| `--auto-accept` | Start in auto-accept mode (auto-accepts edits; softer than `--yolo`). | -| `--yolo` | Bypass ALL permission prompts. Alias for `--dangerously-skip-permissions`. **Required for unattended/background runs** — otherwise the first action prompt blocks forever. | -| `--add-dir ` | Add a directory to the workspace context. | -| `--skip-onboarding` | Skip taste onboarding (required for clean automated/headless runs). | -| `--ide-setup` | Connect an IDE to share the open file and selected lines. | -| `-v, --version` | Print the version. | -| `-h, --help` | Show help. | - -## The mandatory headless combination - -```bash -cmd -p "" --yolo --max-turns 100000 --skip-onboarding -``` - -If ANY of these is missing, an unattended run breaks: -- no `-p` → it opens a REPL and waits for a human. -- no `--yolo` → it hangs on the first permission prompt (can't run bash / edit files). -- low/default `--max-turns` → it exits code 8 partway through, leaving a half-finished branch. -- no `--skip-onboarding` → a fresh install blocks on the taste-onboarding demo. - -## Sub-commands - -| Command | Purpose | -|---|---| -| `cmd info` | Display system information. | -| `cmd status` | Show authentication status. Run before a headless fleet to confirm auth. | -| `cmd whoami` | Show the current user. | -| `cmd update` | Update `cmd` to the latest version. | -| `cmd feedback [title]` | Share feedback / report a bug. | -| `cmd taste` | Manage taste-learning packages. | -| `cmd taste learn ` | Learn taste from a local repo path or a GitHub repo. | -| `cmd learn-taste` | Learn command structure / taste from existing Claude Code / Codex sessions. | -| `cmd mcp` | Manage MCP (Model Context Protocol) servers. | -| `cmd skills` | Manage skills from GitHub repositories. | -| `cmd login` | Log in with a Command Code account. | -| `cmd logout` | Log out. | - -## Slash commands (inside an interactive session) - -| Slash | Purpose | -|---|---| -| `/init` | Initialize an `AGENTS.md` for this project. | -| `/goal [\|clear\|status]` | Set/clear/inspect a standing objective the agent works toward. | -| `/memory` | Manage Command Code memory. | -| `/resume` | Resume a past conversation. | -| `/fork [name]` | Fork the conversation into a new session. | -| `/rename [name]` | Rename the current session. | - -## Exit codes - -| Code | Meaning | -|---|---| -| `0` | Success. | -| `8` | `--max-turns` cap hit in `-p` mode (task likely unfinished). Treat as "increase the cap and/or resume", not "done". | -| non-zero (other) | Error — read the captured log. | - -## Auth & personalization notes - -- Auth is via `cmd login`; `cmd status` verifies. A whole headless fleet fails identically if auth is missing — check first. -- **Taste** is `cmd`'s differentiator: it learns how the user writes code and applies it automatically. For a taste-sensitive repo, `cmd taste learn ` once up front makes dispatched workers match house style. -- `--add-dir` widens context when the task needs files outside the current tree (e.g. a shared package in a monorepo you didn't cd into). - -## Resuming a capped or interrupted run - -If a run exits 8 (or you interrupted it), resume in the same worktree instead of restarting from scratch: - -```bash -cd -cmd -c -p "continue; finish the remaining acceptance criteria, then commit" --yolo --max-turns 100000 --skip-onboarding -``` - -`-c` continues the last conversation in that directory, preserving its context. - -> **Caveat — `-c` can overflow context on a long session.** Resuming reloads the *entire* prior conversation. If the original run was large (a big multi-file implementation), `cmd -c` can exceed the model's context window (e.g. a 262k-token limit) and fail immediately without doing any work. When the remaining work is small and well-defined (add one file, fix one gap), prefer a **fresh, narrowly-scoped `cmd -p`** — no `-c` — that names only the remaining task and the file(s) to mirror. A fresh small-context run is more reliable than resuming a bloated one. Reserve `-c` for short sessions or when you genuinely need the prior context. diff --git a/commit/.claude-plugin/plugin.json b/commit/.claude-plugin/plugin.json index e675a06..7f25f6f 100644 --- a/commit/.claude-plugin/plugin.json +++ b/commit/.claude-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "commit", - "version": "1.3.2", - "description": "Create a Git commit with semantic commit message format and PR workflow with templates", + "version": "1.4.0", + "description": "Semantic commits, with optional push or a PR from templates.", "author": { "name": "duyet", "url": "https://github.com/duyet" diff --git a/commit/.codex-plugin/plugin.json b/commit/.codex-plugin/plugin.json index 1f2f1d2..d9416bf 100644 --- a/commit/.codex-plugin/plugin.json +++ b/commit/.codex-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "commit", - "version": "1.3.2", - "description": "Create a Git commit with semantic commit message format and PR workflow with templates", + "version": "1.4.0", + "description": "Semantic commits, with optional push or a PR from templates.", "author": { "name": "duyet", "url": "https://github.com/duyet" @@ -11,7 +11,7 @@ "commands": "./commands/", "interface": { "displayName": "Commit", - "shortDescription": "Create a Git commit with semantic commit message format and PR workflow with templates", + "shortDescription": "Semantic commits, with optional push or a PR from templates.", "developerName": "duyet", "category": "Git", "capabilities": [ diff --git a/commit/.cursor-plugin/plugin.json b/commit/.cursor-plugin/plugin.json index 9ef54c8..926501e 100644 --- a/commit/.cursor-plugin/plugin.json +++ b/commit/.cursor-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "commit", - "version": "1.3.2", - "description": "Create a Git commit with semantic commit message format and PR workflow with templates", + "version": "1.4.0", + "description": "Semantic commits, with optional push or a PR from templates.", "author": { "name": "duyet" }, diff --git a/commit/.grok-build-plugin/plugin.json b/commit/.grok-build-plugin/plugin.json index 97e56e3..a3e7874 100644 --- a/commit/.grok-build-plugin/plugin.json +++ b/commit/.grok-build-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "commit", - "version": "1.3.2", - "description": "Create a Git commit with semantic commit message format and PR workflow with templates", + "version": "1.4.0", + "description": "Semantic commits, with optional push or a PR from templates.", "author": { "name": "duyet", "url": "https://github.com/duyet" @@ -12,7 +12,7 @@ "commands": "./commands/", "interface": { "displayName": "Commit", - "shortDescription": "Create a Git commit with semantic commit message format and PR workflow with templates", + "shortDescription": "Semantic commits, with optional push or a PR from templates.", "developerName": "duyet", "category": "Git", "capabilities": [ diff --git a/commit/.grok-plugin/plugin.json b/commit/.grok-plugin/plugin.json index 207b623..2534686 100644 --- a/commit/.grok-plugin/plugin.json +++ b/commit/.grok-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "commit", - "version": "1.3.2", - "description": "Create a Git commit with semantic commit message format and PR workflow with templates", + "version": "1.4.0", + "description": "Semantic commits, with optional push or a PR from templates.", "author": { "name": "duyet", "url": "https://github.com/duyet" diff --git a/commit/README.md b/commit/README.md index 97a6281..ae09ae1 100644 --- a/commit/README.md +++ b/commit/README.md @@ -1,120 +1,16 @@ -# Commit Commands Plugin +# Commit plugin -Create Git commits with semantic commit message format using intelligent change analysis. +Semantic commits, optionally pushed or opened as a PR. -## Installation +## Install -```bash -/plugin install commit@duyet-claude-plugins -``` - -## What It Does - -The `commit` plugin provides commands for creating Git commits with semantic commit message format. - -## Commands - -### `/commit:commit` - -Create a semantic commit without pushing. - -```bash -/commit:commit -``` - -Claude will: -1. Check `git status` to see all changes -2. Review `git diff HEAD` to understand what changed -3. Look at recent commits for context and style -4. Create an appropriate semantic commit message -5. Stage changes and commit - -### `/commit:and-push` - -Create a semantic commit and push to remote. - -```bash -/commit:and-push ``` - -Same as `/commit:commit`, but also pushes the commit to the remote repository. - -### `/commit:and-create-pr` - -Create a semantic commit, push to remote, and create a pull request. - -```bash -/commit:and-create-pr -``` - -Same as `/commit:and-push`, but also creates a pull request after pushing. - -## Commit Format - -Follows the [Conventional Commits](https://www.conventionalcommits.org/) specification: - -``` -type(scope): description -``` - -### Types - -| Type | Description | -|------|-------------| -| `feat` | New feature | -| `fix` | Bug fix | -| `docs` | Documentation changes | -| `style` | Code style (formatting, semicolons, etc.) | -| `refactor` | Code refactoring | -| `test` | Adding or updating tests | -| `chore` | Build process, dependencies, etc. | - -### Examples - -``` -feat(auth): add OAuth2 login support -fix(api): handle null response from external service -docs(readme): update installation instructions -refactor(utils): simplify date formatting logic -test(user): add unit tests for profile validation -``` - -## Architecture - -``` -commit/ -├── .claude-plugin/ -│ └── plugin.json # Plugin manifest -├── commands/ -│ ├── commit.md # Commit command -│ ├── and-push.md # Commit and push command -│ └── and-create-pr.md # Commit, push, and create PR command -└── README.md # This file +/plugin install commit@duyet-claude-plugins ``` -## Tips - -- Make focused, atomic commits (one logical change per commit) -- The scope should match the main area of change -- Keep the description under 72 characters -- Use imperative mood ("add" not "added") - -## Changelog - -### [1.2.1] - 2025-01-10 - -- **Changed**: Renamed `/commit:commit-and-push` to `/commit:and-push` for consistency -- **Added**: Documentation for `/commit:and-create-pr` command - -### [1.2.0] - 2025-01-09 - -- **Added**: `/commit:and-create-pr` command for committing, pushing, and creating PR in one operation - -### [1.1.0] - 2025-01-03 - -- **Added**: `/commit:and-push` command for committing and pushing in one operation -- **Changed**: Plugin renamed from `commit-commands` to `commit` for shorter invocation - -### [1.0.0] - Initial Release +## What ships -Semantic commit command using Conventional Commits specification with intelligent change analysis. +- `/commit:commit` - commit changes with a `type(scope): description` message +- `/commit:and-push` - commit and push +- `/commit:and-create-pr` - commit, push, and open a PR using `.pr-templates/` (feat, fix, default) +- `commit-workflow` skill - the shared rules for all three diff --git a/commit/commands/and-create-pr.md b/commit/commands/and-create-pr.md index 3ed69b4..a508378 100644 --- a/commit/commands/and-create-pr.md +++ b/commit/commands/and-create-pr.md @@ -1,161 +1,10 @@ --- allowed-tools: Bash(git *), Bash(gh *) -description: Create a git commit with semantic commit message format and create a pull request +description: Create a semantic commit, push a branch, and open a pull request --- -# Commit and Create PR +# Commit and create PR -Create a semantic commit and open a pull request for the changes. +Follow `skills/commit-workflow/SKILL.md` in this plugin, including its pull request section. -## Options - -- `--template `: Use a PR template (default, bugfix, feature) -- `--draft`: Create PR as draft -- `--title `: Custom PR title (overrides commit message) -- `--body <body>`: Custom PR body (overrides template) - -## Context - -- Current Git status: `git status` -- Current Git diff (staged and unstaged changes): `git diff HEAD --` -- Current branch: `git branch --show-current` -- Default branch: `git remote show origin | grep 'HEAD branch' | cut -d' ' -f5` -- Recent commits: `git log --oneline -5` - -## Your task - -Create a semantic commit and open a pull request for the changes. - -## Execution Flow - -### Step 1: Analyze Changes - -Look at the diff and determine: -- **Commit type**: feat, fix, docs, style, refactor, test, chore -- **Scope**: The area of code affected (e.g., auth, api, ui) -- **Description**: Brief summary of changes - -### Step 2: Handle Branch - -**Check current branch against default branch (main/master):** - -If current branch IS main/master: -1. Create a new branch based on the commit type and scope: - ```bash - git checkout -b [type]/[short-description] - ``` - Examples: - - `feat/add-user-auth` - - `fix/login-validation` - - `refactor/api-endpoints` - -If current branch is NOT main/master: -- Stay on current branch - -### Step 3: Stage and Commit - -```bash -git add . -git commit -m "type(scope): description - -Co-Authored-By: duyetbot <bot@duyet.net>" -``` - -### Step 4: Push Branch - -```bash -git push -u origin [branch-name] -``` - -### Step 5: Create Pull Request - -**Select template based on commit type:** - -| Commit Type | Template | Use When | -|-------------|----------|----------| -| fix | bugfix.md | Bug fixes | -| feat | feature.md | New features | -| Other | default.md | General changes | - -**Load template and populate:** - -```bash -# Template constants -TEMPLATE_DIR=".pr-templates" -TPL_DEFAULT="default" -TPL_BUGFIX="bugfix" -TPL_FEATURE="feature" - -# Determine template from commit type -COMMIT_TYPE="${COMMIT_MSG%%:*}" # Extract first word before colon -case "$COMMIT_TYPE" in - fix) TEMPLATE="${TEMPLATE_DIR}/${TPL_BUGFIX}.md" ;; - feat) TEMPLATE="${TEMPLATE_DIR}/${TPL_FEATURE}.md" ;; - *) TEMPLATE="${TEMPLATE_DIR}/${TPL_DEFAULT}.md" ;; -esac - -# Load template directly (handle missing file gracefully) -if PR_BODY=$(cat "$TEMPLATE" 2>/dev/null); then - # Replace placeholders with actual values - PR_BODY="${PR_BODY//\{\{ brief description of what this PR does \}\}/Brief description based on commit}" -else - # Fallback to simple body with proper newlines - PR_BODY=$'## Summary\n'"${COMMIT_MSG#*:}"$'\n\n## Changes\n- Key changes here' -fi - -# Create PR (draft if --draft flag) -if [ "$DRAFT" = "true" ]; then - gh pr create --title "$COMMIT_MSG" --body "$PR_BODY" --draft -else - gh pr create --title "$COMMIT_MSG" --body "$PR_BODY" -fi -``` - -**With explicit template selection:** -```bash -# Use specific template -gh pr create --title "Fix: authentication bug" --body "$(cat .pr-templates/bugfix.md)" - -# Create as draft -gh pr create --title "WIP: new feature" --body "..." --draft -``` - -## Branch Naming Convention - -| Type | Branch Prefix | Example | -|------|---------------|---------| -| feat | `feat/` | `feat/add-dark-mode` | -| fix | `fix/` | `fix/null-pointer` | -| refactor | `refactor/` | `refactor/auth-module` | -| docs | `docs/` | `docs/api-readme` | -| chore | `chore/` | `chore/update-deps` | - -## Important Rules - -1. **Never commit directly to main/master** - always create a feature branch first -2. **Branch names**: Use kebab-case, keep short but descriptive -3. **Commit format**: `type(scope): description` (imperative mood) -4. **PR title**: Should match or closely follow the commit message - -## Example Session - -If on `main` with changes to add user authentication: - -```bash -# Create feature branch -git checkout -b feat/user-authentication - -# Stage and commit -git add . -git commit -m "feat(auth): add user authentication flow - -Co-Authored-By: duyetbot <bot@duyet.net>" - -# Push new branch -git push -u origin feat/user-authentication - -# Create PR -gh pr create --title "feat(auth): add user authentication flow" --body "..." -``` - -Output the PR URL when complete. +Options: `--template <default|bugfix|feature>` overrides the template choice, `--draft` opens a draft PR, `--title` and `--body` override the generated ones. diff --git a/commit/commands/and-push.md b/commit/commands/and-push.md index 6b446c3..3efd316 100644 --- a/commit/commands/and-push.md +++ b/commit/commands/and-push.md @@ -1,23 +1,8 @@ --- -allowed-tools: Bash(git add:*), Bash(git status:*), Bash(git commit:*), Bash(git push:*) -description: Create a git commit with semantic commit message format and push to remote +allowed-tools: Bash(git add:*), Bash(git status:*), Bash(git commit:*), Bash(git push:*), Bash(git diff:*), Bash(git branch:*), Bash(git log:*) +description: Create a semantic commit and push it to the remote --- -# Commit and Push Commands +# Commit and push -## Context - -- Current Git status: `git status` -- Current Git diff (staged and unstaged changes): `git diff HEAD --` -- Current branch: `git branch --show-current` -- Recent commits: `git log --oneline -10` - -## Your task - -Based on the above changes, create a single Git commit and push it to the remote repository. - -You have the capability to call multiple tools in a single response. Stage, create the commit, and push using a single message. Do not use any other tools or do not send any other text or messages besides these tool calls. - -Commit should follow semantic commit format: `type(scope): description` - -Types: feat, fix, docs, style, refactor, test, chore +Follow `skills/commit-workflow/SKILL.md` in this plugin. Commit, then push the current branch. diff --git a/commit/commands/commit.md b/commit/commands/commit.md index 950330e..5ebbb7b 100644 --- a/commit/commands/commit.md +++ b/commit/commands/commit.md @@ -1,23 +1,8 @@ --- -allowed-tools: Bash(git add:*), Bash(git status:*), Bash(git commit:*) -description: Create a git commit with semantic commit message format +allowed-tools: Bash(git add:*), Bash(git status:*), Bash(git commit:*), Bash(git diff:*), Bash(git branch:*), Bash(git log:*) +description: Create a semantic commit from local changes --- -# Commit Commands +# Commit -## Context - -- Current Git status: `git status` -- Current Git diff (staged and unstaged changes): `git diff HEAD --` -- Current branch: `git branch --show-current` -- Recent commits: `git log --oneline -10` - -## Your task - -Based on the above changes, create one single or separated git commits. - -You have the capability to call multiple tools in a single response. Stage and create the commit using a single message. Do not use any other tools or do anything else. Do not send any other text or messages besides these tool calls. - -Commit should follow semantic commit format: `type(scope): description` - -Types: feat, fix, docs, style, refactor, test, chore +Follow `skills/commit-workflow/SKILL.md` in this plugin. Stage and commit only. Do not push. diff --git a/commit/skills/commit-workflow/SKILL.md b/commit/skills/commit-workflow/SKILL.md index af905b5..f1d0903 100644 --- a/commit/skills/commit-workflow/SKILL.md +++ b/commit/skills/commit-workflow/SKILL.md @@ -1,23 +1,18 @@ --- name: commit-workflow -description: Use when the user asks to create a semantic commit, commit and push, or create a pull request from local changes. +description: Use when creating a semantic commit, committing and pushing, or opening a pull request from local changes. The commit commands delegate here. --- -# Commit Workflow +# Commit workflow -Use this skill to turn local repository changes into a clean semantic commit, and optionally push or open a pull request. +1. Read git status, the diff against HEAD, the current branch, and recent commits to match the repo's style. +2. Split unrelated changes into separate commits. Stage only files that belong to the change, never unrelated dirty work. +3. Message format is `type(scope): description` in the imperative. Types: feat, fix, docs, style, refactor, test, chore. +4. Push only when asked. Prefer `--force-with-lease` and only when a forced update is requested. Do not rewrite history otherwise. -## Workflow +## Pull requests -1. Inspect the current branch, git status, unstaged/staged diff, and recent commits. -2. Decide whether the change should be one commit or split into multiple focused commits. -3. Stage only the files that belong to the requested change. -4. Use semantic commit format: `type(scope): description`. -5. When creating a pull request, create a feature branch first if the current branch is the default branch. -6. Use the repo's existing pull request templates when present. - -## Safety - -- Do not include unrelated dirty work in the commit. -- Do not rewrite history unless the user explicitly asks. -- Prefer `--force-with-lease` over force push when a forced update is explicitly required. +- On the default branch, first create a branch named `<type>/<short-kebab-description>`. +- Push with `git push -u origin <branch>`, then `gh pr create`. Title matches the commit message. Add `--draft` when asked. +- Body: use the repo's own PR template if it has one. Otherwise pick from `.pr-templates/` in this plugin by commit type: `fix` uses `bugfix.md`, `feat` uses `feature.md`, anything else uses `default.md`. Fill in the placeholders. If no template is found, write a short summary and change list. +- Print the PR URL when done. diff --git a/fix/.claude-plugin/plugin.json b/fix/.claude-plugin/plugin.json index 1543662..054959a 100644 --- a/fix/.claude-plugin/plugin.json +++ b/fix/.claude-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "fix", - "version": "1.0.1", - "description": "Fix issues, tests, and CI failures with intelligent problem detection", + "version": "1.1.0", + "description": "Fix failing tests, lint, and CI, then commit and push or open or update a PR.", "author": { "name": "duyet", "url": "https://github.com/duyet" diff --git a/fix/.codex-plugin/plugin.json b/fix/.codex-plugin/plugin.json index da6a00a..696c830 100644 --- a/fix/.codex-plugin/plugin.json +++ b/fix/.codex-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "fix", - "version": "1.0.1", - "description": "Fix issues, tests, and CI failures with intelligent problem detection", + "version": "1.1.0", + "description": "Fix failing tests, lint, and CI, then commit and push or open or update a PR.", "author": { "name": "duyet", "url": "https://github.com/duyet" @@ -11,7 +11,7 @@ "commands": "./commands/", "interface": { "displayName": "Fix", - "shortDescription": "Fix issues, tests, and CI failures with intelligent problem detection", + "shortDescription": "Fix failing tests, lint, and CI, then commit and push or open or update a PR.", "developerName": "duyet", "category": "Productivity", "capabilities": [ diff --git a/fix/.cursor-plugin/plugin.json b/fix/.cursor-plugin/plugin.json index a032d31..1479f3d 100644 --- a/fix/.cursor-plugin/plugin.json +++ b/fix/.cursor-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "fix", - "version": "1.0.1", - "description": "Fix issues, tests, and CI failures with intelligent problem detection", + "version": "1.1.0", + "description": "Fix failing tests, lint, and CI, then commit and push or open or update a PR.", "author": { "name": "duyet" }, diff --git a/fix/.grok-build-plugin/plugin.json b/fix/.grok-build-plugin/plugin.json index 3791535..a1f5ced 100644 --- a/fix/.grok-build-plugin/plugin.json +++ b/fix/.grok-build-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "fix", - "version": "1.0.1", - "description": "Fix issues, tests, and CI failures with intelligent problem detection", + "version": "1.1.0", + "description": "Fix failing tests, lint, and CI, then commit and push or open or update a PR.", "author": { "name": "duyet", "url": "https://github.com/duyet" @@ -12,7 +12,7 @@ "commands": "./commands/", "interface": { "displayName": "Fix", - "shortDescription": "Fix issues, tests, and CI failures with intelligent problem detection", + "shortDescription": "Fix failing tests, lint, and CI, then commit and push or open or update a PR.", "developerName": "duyet", "category": "Productivity", "capabilities": [ diff --git a/fix/.grok-plugin/plugin.json b/fix/.grok-plugin/plugin.json index 99c9601..5c94170 100644 --- a/fix/.grok-plugin/plugin.json +++ b/fix/.grok-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "fix", - "version": "1.0.1", - "description": "Fix issues, tests, and CI failures with intelligent problem detection", + "version": "1.1.0", + "description": "Fix failing tests, lint, and CI, then commit and push or open or update a PR.", "author": { "name": "duyet", "url": "https://github.com/duyet" diff --git a/fix/README.md b/fix/README.md index 3b727d6..efbcc02 100644 --- a/fix/README.md +++ b/fix/README.md @@ -1,82 +1,16 @@ -# Fix Plugin +# Fix plugin -Intelligent issue detection and resolution with Git workflow integration. +Find and fix failing tests, lint, type errors, and CI, then commit and push or open a PR. -## Commands +## Install -| Command | Description | -|---------|-------------| -| `/fix:and-push` | Fix issues, commit, and push to remote | -| `/fix:and-update-pr` | Fix issues and update an existing PR | -| `/fix:and-create-pr` | Fix issues and create a new PR | - -## Features - -- **Auto-detection**: Automatically detects project type (Python, Node, Rust, Go) -- **Smart fixing**: Analyzes errors and applies appropriate fixes -- **Parallel execution**: Spawns agents for complex multi-file issues -- **Git integration**: Handles commits and pushes with semantic messages -- **PR management**: Creates and updates pull requests via GitHub CLI - -## Usage - -### Fix and Push - -```bash -# Fix all failing tests and push -/fix:and-push - -# Fix specific issues -/fix:and-push - -pytest test_auth.py is failing with assertion error ``` - -### Update Existing PR - -```bash -# Fix CI failures on current branch's PR -/fix:and-update-pr - -# Fix specific PR by number -/fix:and-update-pr 123 +/plugin install fix@duyet-claude-plugins ``` -### Create New PR - -```bash -# Fix issues and create PR to default branch -/fix:and-create-pr - -# With custom title -/fix:and-create-pr - -feat: add user authentication -``` - -## Supported Project Types - -| Type | Detection | Test Commands | -|------|-----------|---------------| -| Python | `pyproject.toml`, `setup.py` | pytest, unittest, ruff, mypy | -| Node/TS | `package.json` | jest, vitest, eslint, tsc | -| Rust | `Cargo.toml` | cargo test, clippy | -| Go | `go.mod` | go test, golint | - -## Prerequisites - -- GitHub CLI (`gh`) installed and authenticated -- Git configured with push access -- Project-specific test tools installed - -## Safety Features - -- Maximum 3 fix attempts per issue -- Local testing before pushing -- Never force pushes -- Stops on repeated failures -- Preserves existing PR metadata - -## Version +## What ships -1.0.0 +- `/fix:and-push` - fix, commit, push +- `/fix:and-update-pr` - fix an existing PR and push +- `/fix:and-create-pr` - fix and open a new PR +- `fix-workflow` skill - the fixing loop all three share diff --git a/fix/commands/and-create-pr.md b/fix/commands/and-create-pr.md index 38cdf99..171f251 100644 --- a/fix/commands/and-create-pr.md +++ b/fix/commands/and-create-pr.md @@ -1,167 +1,13 @@ --- allowed-tools: [Read, Bash, Glob, Grep, TodoWrite, Edit, Write, Task] -description: "Fix issues/tests and create a new pull request" +description: Fix failing tests or checks and open a new pull request --- -# /fix:and-create-pr - Fix and Create PR +# Fix and create PR -## Purpose +Input: optional PR title and base branch. -Fix any failing tests or issues on the current branch, commit the fixes, and create a new pull request. - -## Usage - -``` -/fix:and-create-pr -``` - -``` -/fix:and-create-pr - -<optional: PR title or description> -<optional: target base branch> -``` - -## Context Gathering - -```bash -# Current branch -git branch --show-current - -# Default branch (usually main or master) -git remote show origin | grep 'HEAD branch' | cut -d' ' -f5 - -# Uncommitted changes -git status --short - -# Commits ahead of base -git log origin/$(git remote show origin | grep 'HEAD branch' | cut -d' ' -f5)..HEAD --oneline 2>/dev/null || echo "Branch not pushed yet" -``` - -## Execution Flow - -### Phase 1: Pre-flight Checks -1. Verify current branch is not main/master -2. Check for uncommitted changes -3. Identify base branch for PR -4. Ensure branch is pushed to remote - -### Phase 2: Issue Detection & Fix -1. Run project tests and checks: - - Python: `pytest`, `ruff`, `mypy` - - Node: `npm test`, `npm run lint`, `npm run type-check` - - Rust: `cargo test`, `cargo clippy` - - Go: `go test ./...`, `golint` - -2. For each failure: - - Analyze error message - - Implement fix - - Verify fix locally - -3. **Parallel execution for complex issues:** - ``` - Main Agent (Coordinator) - ├── Senior Agent 1: Test fixes - ├── Senior Agent 2: Lint/type fixes - └── Main Agent: Commit & PR creation - ``` - -### Phase 3: Commit Fixes -If fixes were applied: -```bash -git add . -git commit -m "fix: resolve test failures and linting issues - -Co-Authored-By: duyetbot <duyetbot@users.noreply.github.com>" -``` - -### Phase 4: Push & Create PR -1. Push branch to remote: - ```bash - git push -u origin [BRANCH_NAME] - ``` - -2. Create PR with generated summary: - ```bash - gh pr create --title "[TITLE]" --body "$(cat <<'EOF' - ## Summary - [Auto-generated bullet points based on commits] - - ## Changes - [List of files modified with brief descriptions] - - ## Test Plan - - [ ] All tests passing locally - - [ ] CI checks expected to pass - - [ ] Ready for review - - --- - Generated with Claude Code - EOF - )" - ``` - -## PR Title Generation - -Based on commits and changes: -- `feat(scope):` for new features -- `fix(scope):` for bug fixes -- `refactor(scope):` for code improvements -- `docs(scope):` for documentation - -## Output Format - -``` -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ -Pre-flight Checks -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ -✅ Branch: feature/add-auth -✅ Base: main -✅ Commits ahead: 3 -⚠️ Uncommitted changes: 2 files - -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ -Running Tests & Checks -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ -❌ pytest: 2 failures -✅ ruff: passed -✅ mypy: passed - -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ -Fixing Issues -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ -✅ Fixed test_auth_login assertion -✅ Fixed test_auth_logout mock - -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ -Creating Pull Request -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ -✅ Changes committed -✅ Pushed to origin/feature/add-auth -✅ PR created: #456 - -PR #456: feat(auth): add user authentication -URL: https://github.com/user/repo/pull/456 -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ -``` - -## Options - -- **Base branch**: Defaults to main/master, can be overridden -- **Draft PR**: Add `--draft` in arguments for draft PR -- **Reviewers**: Add `--reviewer @user` to request review - -## Safety Checks - -- ❌ Will NOT create PR from main/master branch -- ❌ Will NOT create PR if tests still failing after fixes -- ❌ Will NOT force push -- ✅ Will commit fixes before PR creation -- ✅ Will push branch if not already pushed - -## Notes - -- Requires GitHub CLI (`gh`) authenticated -- PR body includes auto-generated summary from commits -- Will prompt for confirmation before creating PR -- Respects repository PR templates if present +1. Follow `skills/fix-workflow/SKILL.md` to fix the failures. +2. If on the default branch, create a `fix/<short-description>` branch first. +3. Push with `git push -u origin <branch>` and run `gh pr create` against the base branch. Summarize the commits as bullets in the body. +4. Print the PR URL. diff --git a/fix/commands/and-push.md b/fix/commands/and-push.md index ab94810..b27f477 100644 --- a/fix/commands/and-push.md +++ b/fix/commands/and-push.md @@ -1,99 +1,10 @@ --- allowed-tools: [Read, Bash, Glob, Grep, TodoWrite, Edit, Write, Task] -description: "Fix issues/tests, commit changes, and push to remote" +description: Fix failing tests or checks, commit, and push to the current branch --- -# /fix:and-push - Fix, Commit, and Push +# Fix and push -## Purpose +Optional input: error output or test names to start from. -Intelligently detect and fix issues (tests, linting, type errors), commit the changes, and push to the remote branch. - -## Usage - -``` -/fix:and-push -``` - -``` -/fix:and-push - -<error message or test names> -<user note or context> -``` - -## Issue Detection - -The command automatically detects the project type and runs appropriate checks: - -| Project Type | Detection | Test Command | -|--------------|-----------|--------------| -| Python | `pyproject.toml`, `setup.py`, `requirements.txt` | `pytest`, `python -m pytest` | -| Node/TypeScript | `package.json` | `npm test`, `npm run lint`, `npm run type-check` | -| Rust | `Cargo.toml` | `cargo test`, `cargo clippy` | -| Go | `go.mod` | `go test ./...` | - -## Execution Flow - -### Phase 1: Discovery -1. Detect project type from config files -2. Identify test framework and commands -3. Parse provided error messages (if any) -4. Create todo list for tracking - -### Phase 2: Analysis -1. Run tests/checks to identify failures -2. Categorize issues by type: - - Unit test failures - - Integration test failures - - Linting errors - - Type errors - - Build errors -3. Prioritize fixes (dependencies first) - -### Phase 3: Fix -1. For simple issues (1-2 files): Fix directly -2. For complex issues (3+ files or multiple domains): - - Spawn senior-engineer agents in parallel - - Each agent handles a specific issue domain -3. After each fix: - - Re-run affected tests locally - - Verify fix doesn't break other tests - -### Phase 4: Commit & Push -1. Stage all changed files -2. Create semantic commit message: - ``` - fix(scope): clear description of what was fixed - - Co-Authored-By: duyetbot <duyetbot@users.noreply.github.com> - ``` -3. Push to current branch - -## Parallel Execution Strategy - -For complex multi-file fixes: - -``` -Main Agent (Coordinator) -├── Senior Agent 1: Python test fixes -├── Senior Agent 2: TypeScript type errors -├── Senior Agent 3: Linting issues -└── Main Agent: Monitors, integrates, commits -``` - -## Notes - -- **Mock external dependencies**: Use mocks for databases, external APIs unless explicitly testing integration -- **Logic over green tests**: Think about whether the test logic makes sense, not just making tests pass -- **Document recurring issues**: If a pattern emerges, consider adding notes to local CLAUDE.md -- **Incremental commits**: For large fixes, commit working states incrementally -- **Never auto-merge**: This command only pushes; merging requires separate action - -## Error Recovery - -If fixes fail after 3 attempts: -1. Document what was tried -2. Provide detailed error analysis -3. Suggest manual intervention steps -4. Do NOT continue pushing broken code +Follow `skills/fix-workflow/SKILL.md` in this plugin, then push the current branch. diff --git a/fix/commands/and-update-pr.md b/fix/commands/and-update-pr.md index fe8a5ef..b671800 100644 --- a/fix/commands/and-update-pr.md +++ b/fix/commands/and-update-pr.md @@ -1,140 +1,12 @@ --- allowed-tools: [Read, Bash, Glob, Grep, TodoWrite, Edit, Write, Task] -description: "Fix issues/tests and update an existing pull request" +description: Fix failing CI or requested changes on an existing PR and push --- -# /fix:and-update-pr - Fix and Update PR +# Fix and update PR -## Purpose +Input: optional PR number (default: the current branch's PR) and a specific issue to address. -Fix failing CI checks, tests, or requested changes on an existing pull request, commit the fixes, and push to update the PR. - -## Usage - -``` -/fix:and-update-pr -``` - -``` -/fix:and-update-pr 123 - -<optional: specific issue to address> -``` - -## Context Gathering - -```bash -# Current branch -`git branch --show-current` - -# PR information (if PR number provided as $ARGUMENTS) -`gh pr view $ARGUMENTS --json number,title,url,state,statusCheckRollup,headRefName,baseRefName 2>/dev/null || echo "No PR number provided"` - -# Or find PR for current branch -`gh pr view --json number,title,url,state,statusCheckRollup 2>/dev/null || echo "No PR found for current branch"` -``` - -## Execution Flow - -### Phase 1: PR Analysis -1. Identify the target PR (from argument or current branch) -2. Fetch PR status and CI check results: - ```bash - gh pr checks [PR_NUMBER] - ``` -3. Fetch review comments and requested changes: - ```bash - gh pr view [PR_NUMBER] --comments - ``` -4. Categorize issues: - - CI failures (tests, lint, build) - - Review feedback - - Merge conflicts - -### Phase 2: Issue Resolution - -#### For CI Failures: -1. Fetch failure logs: - ```bash - gh run list --branch [BRANCH] --limit 5 --json databaseId,name,conclusion - gh run view [RUN_ID] --log-failed - ``` -2. Analyze and fix each failure -3. Test fixes locally before pushing - -#### For Review Feedback: -1. Parse review comments -2. Address each requested change -3. Reply to comments if clarification needed - -#### For Merge Conflicts: -1. Fetch latest base branch -2. Resolve conflicts -3. Verify resolution doesn't break tests - -### Phase 3: Fix Implementation - -**Simple issues (1-2 files):** -- Fix directly in main agent - -**Complex issues (3+ files):** -- Spawn parallel agents by domain: - ``` - Main Agent (Coordinator) - ├── Senior Agent 1: Backend fixes - ├── Senior Agent 2: Frontend fixes - ├── Senior Agent 3: Test fixes - └── Main Agent: Integration & commit - ``` - -### Phase 4: Push Update -1. Stage and commit with descriptive message: - ``` - fix(pr): address CI failures and review feedback - - - Fix failing test in auth.spec.ts - - Address review comment on error handling - - Resolve ESLint warnings - - Co-Authored-By: duyetbot <duyetbot@users.noreply.github.com> - ``` -2. Push to PR branch -3. Report updated status - -## Output Format - -``` -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ -PR #[NUMBER]: [TITLE] -Branch: [HEAD] → [BASE] -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - -Issues Found: -❌ CI: ESLint - 3 errors -❌ CI: Unit Tests - 2 failures -📝 Review: 1 requested change - -Fixes Applied: -✅ Fixed ESLint errors in src/utils.ts -✅ Fixed test assertions in auth.spec.ts -✅ Addressed review feedback on error handling - -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ -✅ Changes pushed to PR #[NUMBER] -Waiting for CI to complete... -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ -``` - -## Safety Limits - -- **Max 3 fix attempts** per failing check -- **Never force push** unless explicitly requested -- **Always test locally** before pushing -- **Report and stop** if fix causes new failures - -## Notes - -- Requires GitHub CLI (`gh`) authenticated -- Will NOT merge the PR (use `/github:bulk-merge-prs` for merge) -- Preserves existing PR description and metadata -- Respects branch protection rules +1. Read the PR with `gh pr view <n> --comments` and `gh pr checks <n>`. Read failed logs with `gh run view <id> --log-failed`. +2. Follow `skills/fix-workflow/SKILL.md` for each failing check and requested change. +3. Push to the PR branch and report the PR URL. diff --git a/fix/skills/fix-workflow/SKILL.md b/fix/skills/fix-workflow/SKILL.md index e2f1e52..c73d69a 100644 --- a/fix/skills/fix-workflow/SKILL.md +++ b/fix/skills/fix-workflow/SKILL.md @@ -1,23 +1,14 @@ --- name: fix-workflow -description: Use when the user asks to fix issues, tests, CI failures, or create/update/push a fix branch. +description: Use when fixing failing tests, lint, type errors, build, or CI, and then committing, pushing, or opening or updating a PR. The fix commands delegate here. --- -# Fix Workflow +# Fix workflow -Use this skill to diagnose and repair repository failures with focused changes. - -## Workflow - -1. Identify the project type and the most relevant checks from repository files. -2. Reproduce the failure when possible before editing. -3. Make the smallest change that addresses the root cause. -4. Run targeted verification first, then broader checks when the change is shared or risky. -5. For PR/update flows, commit with semantic format and preserve unrelated local work. - -## Supported Checks - -- Python: pytest, ruff, mypy -- Node/TypeScript: package scripts, tsc, eslint, jest, vitest -- Rust: cargo test, clippy -- Go: go test and lint tools when configured +1. Detect the project's checks from its config files (package scripts, `pyproject.toml`, `Cargo.toml`, `go.mod`, Makefile, CI workflow). Prefer the commands CI runs. +2. Reproduce the failure first. If the user pasted errors or test names, start from those. +3. Fix the root cause with the smallest change. Do not weaken or delete a test to make it pass. Mock external services unless the test is about the integration. +4. Re-run the failing check, then the wider suite when the change touches shared code. +5. For three or more independent failures in different areas, spawn one subagent per area and integrate the results yourself. +6. Stop after three failed attempts at one issue. Report what was tried and do not push broken code. +7. Commit with a semantic message per the `commit` plugin's `commit-workflow` skill, include only files you changed, then push. Never merge. diff --git a/fix/skills/test-detection.md b/fix/skills/test-detection.md deleted file mode 100644 index 360233b..0000000 --- a/fix/skills/test-detection.md +++ /dev/null @@ -1,137 +0,0 @@ -# Test Detection & Fix Strategies - -Reusable knowledge for detecting project types and fixing common test issues. - -## Project Type Detection - -### Python Projects - -**Detection Files:** -- `pyproject.toml` (modern) -- `setup.py` (legacy) -- `requirements.txt` -- `Pipfile` - -**Test Frameworks:** -| Framework | Config | Run Command | -|-----------|--------|-------------| -| pytest | `pytest.ini`, `pyproject.toml [tool.pytest]` | `pytest` or `python -m pytest` | -| unittest | built-in | `python -m unittest discover` | -| nose2 | `setup.cfg` | `nose2` | - -**Linting/Type Checking:** -| Tool | Config | Run Command | -|------|--------|-------------| -| ruff | `pyproject.toml [tool.ruff]` | `ruff check .` | -| flake8 | `.flake8`, `setup.cfg` | `flake8` | -| mypy | `mypy.ini`, `pyproject.toml [tool.mypy]` | `mypy .` | -| black | `pyproject.toml [tool.black]` | `black --check .` | - -**Common Fix Patterns:** -```python -# Assertion error: Check expected vs actual values -# ImportError: Check virtual environment, dependencies -# TypeError: Check function signatures, type hints -# AttributeError: Check object initialization -``` - -### Node/TypeScript Projects - -**Detection Files:** -- `package.json` -- `tsconfig.json` (TypeScript) - -**Test Frameworks:** -| Framework | Config | Run Command | -|-----------|--------|-------------| -| Jest | `jest.config.js` | `npm test` or `npx jest` | -| Vitest | `vite.config.ts` | `npm test` or `npx vitest` | -| Mocha | `.mocharc.js` | `npm test` or `npx mocha` | -| Playwright | `playwright.config.ts` | `npx playwright test` | - -**Linting/Type Checking:** -| Tool | Config | Run Command | -|------|--------|-------------| -| ESLint | `.eslintrc.*`, `eslint.config.js` | `npm run lint` or `npx eslint .` | -| TypeScript | `tsconfig.json` | `npm run type-check` or `npx tsc --noEmit` | -| Prettier | `.prettierrc` | `npm run format` or `npx prettier --check .` | - -**Common Fix Patterns:** -```typescript -// Type error: Add proper type annotations -// undefined is not a function: Check imports, async/await -// Test timeout: Increase timeout, check async handling -// Mock not working: Verify mock setup in beforeEach -``` - -### Rust Projects - -**Detection Files:** -- `Cargo.toml` - -**Commands:** -| Purpose | Command | -|---------|---------| -| Tests | `cargo test` | -| Linting | `cargo clippy` | -| Format | `cargo fmt --check` | -| Build | `cargo build` | - -**Common Fix Patterns:** -```rust -// Borrow checker: Review ownership, use references -// Type mismatch: Check trait implementations -// Unused variable: Prefix with underscore or remove -``` - -### Go Projects - -**Detection Files:** -- `go.mod` - -**Commands:** -| Purpose | Command | -|---------|---------| -| Tests | `go test ./...` | -| Linting | `golint ./...` or `golangci-lint run` | -| Format | `go fmt ./...` | -| Vet | `go vet ./...` | - -## Fix Strategy Matrix - -| Issue Type | Complexity | Strategy | -|------------|------------|----------| -| Single test failure | Low | Direct fix in main agent | -| Multiple test failures (same file) | Low | Direct fix in main agent | -| Multiple test failures (different files) | Medium | Consider parallel agents | -| Linting errors | Low | Auto-fix when possible | -| Type errors | Medium | Analyze root cause first | -| Build errors | High | Fix dependencies first | -| Integration test failures | High | Check external deps, use mocks | - -## Parallel Agent Assignment - -When spawning agents for complex fixes: - -``` -Domain Detection: -- Python tests → Senior Agent (Python expertise) -- TypeScript types → Senior Agent (TS expertise) -- React components → Senior Agent (Frontend expertise) -- API/Backend → Senior Agent (Backend expertise) -- Infrastructure → Senior Agent (DevOps expertise) -``` - -## Mock Strategy - -Default to mocking for: -- Database connections -- External API calls -- File system operations (when appropriate) -- Network requests -- Time-dependent operations - -Do NOT mock: -- Core business logic -- Unit under test -- Simple utility functions diff --git a/frontend-design/.claude-plugin/plugin.json b/frontend-design/.claude-plugin/plugin.json index 68baec6..7bbdbc9 100644 --- a/frontend-design/.claude-plugin/plugin.json +++ b/frontend-design/.claude-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "frontend-design", - "version": "1.4.0", - "description": "Create distinctive, production-grade frontend interfaces avoiding AI slop aesthetics", + "version": "1.5.0", + "description": "Distinctive, production-grade frontend design that avoids generic AI aesthetics.", "author": { "name": "duyet", "url": "https://github.com/duyet" diff --git a/frontend-design/.codex-plugin/plugin.json b/frontend-design/.codex-plugin/plugin.json index c134c5f..abef7de 100644 --- a/frontend-design/.codex-plugin/plugin.json +++ b/frontend-design/.codex-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "frontend-design", - "version": "1.4.0", - "description": "Create distinctive, production-grade frontend interfaces avoiding AI slop aesthetics", + "version": "1.5.0", + "description": "Distinctive, production-grade frontend design that avoids generic AI aesthetics.", "author": { "name": "duyet", "url": "https://github.com/duyet" @@ -10,7 +10,7 @@ "skills": "./skills/", "interface": { "displayName": "Frontend Design", - "shortDescription": "Create distinctive, production-grade frontend interfaces avoiding AI slop aesthetics", + "shortDescription": "Distinctive, production-grade frontend design that avoids generic AI aesthetics.", "developerName": "duyet", "category": "Design", "capabilities": [ diff --git a/frontend-design/.cursor-plugin/plugin.json b/frontend-design/.cursor-plugin/plugin.json index 5e0871d..fafceff 100644 --- a/frontend-design/.cursor-plugin/plugin.json +++ b/frontend-design/.cursor-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "frontend-design", - "version": "1.4.0", - "description": "Create distinctive, production-grade frontend interfaces avoiding AI slop aesthetics", + "version": "1.5.0", + "description": "Distinctive, production-grade frontend design that avoids generic AI aesthetics.", "author": { "name": "duyet" }, diff --git a/frontend-design/.grok-build-plugin/plugin.json b/frontend-design/.grok-build-plugin/plugin.json index a928937..da794d6 100644 --- a/frontend-design/.grok-build-plugin/plugin.json +++ b/frontend-design/.grok-build-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "frontend-design", - "version": "1.4.0", - "description": "Create distinctive, production-grade frontend interfaces avoiding AI slop aesthetics", + "version": "1.5.0", + "description": "Distinctive, production-grade frontend design that avoids generic AI aesthetics.", "author": { "name": "duyet", "url": "https://github.com/duyet" @@ -11,7 +11,7 @@ "skills": "./skills/", "interface": { "displayName": "Frontend Design", - "shortDescription": "Create distinctive, production-grade frontend interfaces avoiding AI slop aesthetics", + "shortDescription": "Distinctive, production-grade frontend design that avoids generic AI aesthetics.", "developerName": "duyet", "category": "Design", "capabilities": [ diff --git a/frontend-design/.grok-plugin/plugin.json b/frontend-design/.grok-plugin/plugin.json index f647ade..001e779 100644 --- a/frontend-design/.grok-plugin/plugin.json +++ b/frontend-design/.grok-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "frontend-design", - "version": "1.4.0", - "description": "Create distinctive, production-grade frontend interfaces avoiding AI slop aesthetics", + "version": "1.5.0", + "description": "Distinctive, production-grade frontend design that avoids generic AI aesthetics.", "author": { "name": "duyet", "url": "https://github.com/duyet" diff --git a/frontend-design/README.md b/frontend-design/README.md index 9db5ba4..b8977a4 100644 --- a/frontend-design/README.md +++ b/frontend-design/README.md @@ -1,105 +1,11 @@ -# Frontend Design Plugin +# Frontend design -Create distinctive, production-grade frontend interfaces that avoid generic AI aesthetics. - -## Installation +Build distinctive, production-grade frontends that avoid generic AI aesthetics. ```bash /plugin install frontend-design@duyet-claude-plugins ``` -## What It Does - -Claude automatically uses this skill for frontend work. Creates production-ready code with: - -- Bold aesthetic choices that avoid "AI slop" -- shadcn/ui components with custom theming -- Recharts for beautiful data visualizations -- Distinctive typography and color palettes -- High-impact animations using Framer Motion -- Context-aware implementation - -## Anti-Slop Guidelines - -This plugin specifically teaches Claude to avoid: - -- Generic fonts (Inter, Roboto, Arial) -- Purple gradients on white backgrounds -- Symmetric layouts with no hierarchy -- Glassmorphism everywhere -- Cookie-cutter card grids - -Instead, it guides toward: - -- Distinctive font pairings (Clash Display, Satoshi, Fraunces) -- Intentional color with one dominant accent -- Asymmetric compositions with clear hierarchy -- Components with character and micro-interactions -- Layouts that break the grid - -## Tech Stack Preferences - -| Category | First Choice | Alternatives | -|----------|--------------|--------------| -| Components | shadcn/ui | Radix UI, Headless UI | -| Charts | Recharts | Tremor, Victory | -| Styling | Tailwind CSS | CSS Variables | -| Animation | Framer Motion | CSS animations, GSAP | - -## Usage - -``` -"Create a dashboard for a music streaming app" -"Build a landing page for an AI security startup" -"Design a settings panel with dark mode" -"Create a data visualization for sales metrics" -``` - -Claude will choose a clear aesthetic direction and implement production code with meticulous attention to detail. - -## Learn More - -See the [Frontend Aesthetics Cookbook](https://github.com/anthropics/claude-cookbooks/blob/main/coding/prompting_for_frontend_aesthetics.ipynb) for detailed guidance. - -## Architecture - -``` -frontend-design/ -├── .claude-plugin/ -│ └── plugin.json # Plugin manifest -├── skills/ -│ └── frontend-design/ -│ └── SKILL.md # Skill definition with guidelines -└── README.md # This file -``` - -## Changelog - -### [1.2.0] - Progressive Disclosure & MCP Documentation - -**Added** -- Progressive disclosure structure for skill content -- shadcn/ui MCP server documentation and patterns -- Enhanced component library integration guidance - -**Changed** -- Restructured skill with clear information hierarchy -- Improved MCP integration examples - -### [1.1.0] - Skill Refinement - -**Added** -- Tech stack preferences table (shadcn/ui, Recharts, Tailwind, Framer Motion) -- Anti-slop guidelines section -- Link to Frontend Aesthetics Cookbook - -**Changed** -- Enhanced from original Anthropic plugin by Prithvi Rajasekaran and Alexander Bricken - -### [1.0.0] - Initial Release - -Frontend design skill with anti-slop guidelines and distinctive aesthetic choices. - -## Credits +## Ships -Enhanced from Anthropic's original frontend-design plugin by Prithvi Rajasekaran and Alexander Bricken. +- `frontend-design` skill: pick a bold aesthetic direction, stack defaults (shadcn/ui, Tailwind, Recharts), a list of AI-design tells to avoid, and short implementation rules. diff --git a/frontend-design/skills/frontend-design/SKILL.md b/frontend-design/skills/frontend-design/SKILL.md index 13a64d4..5094e41 100644 --- a/frontend-design/skills/frontend-design/SKILL.md +++ b/frontend-design/skills/frontend-design/SKILL.md @@ -1,766 +1,46 @@ --- name: frontend-design -description: Create distinctive, production-grade frontend interfaces with React and Next.js. Design quality, component architecture, performance patterns, and state management. Use when building web components, pages, or applications. +description: Build distinctive, production-grade frontend interfaces and avoid generic AI-looking design. Use when building web components, pages, dashboards, or apps where visual quality matters. --- -This skill guides creation of distinctive, production-grade frontend interfaces that avoid generic "AI slop" aesthetics. Implement real working code with exceptional attention to aesthetic details and creative choices. +# Frontend design -## When to Invoke This Skill +Write real working code with a deliberate visual identity. Match the project's existing framework and conventions first. -Automatically activate for: -- Building UI components, pages, dashboards, or applications -- Creating landing pages, forms, or interactive interfaces -- Designing data visualizations or charts -- Implementing design systems or component libraries -- Any frontend work where visual quality matters +## Commit to a direction before coding -## Design Thinking +State the purpose, the audience, and one aesthetic (for example editorial, brutalist, retro-futuristic, soft and organic, industrial, Swiss grid, luxury). Pick the one thing the user will remember. Execute that direction consistently and drop everything that does not serve it. -Before coding, understand the context and commit to a BOLD aesthetic direction: +## Stack defaults -1. **Purpose**: What problem does this interface solve? Who uses it? -2. **Tone**: Pick a distinctive aesthetic: - - Brutally minimal | Maximalist chaos | Retro-futuristic - - Organic/natural | Luxury/refined | Playful/toy-like - - Editorial/magazine | Brutalist/raw | Art deco/geometric - - Soft/pastel | Industrial/utilitarian | Neo-brutalist - - Swiss/grid-based | Cyberpunk/neon | Scandinavian/calm -3. **Constraints**: Technical requirements (framework, performance, accessibility) -4. **Differentiation**: What makes this UNFORGETTABLE? +Use what the project already has. Otherwise prefer: +- Components: shadcn/ui, then Radix UI primitives, then Headless UI. Read the current shadcn docs or its MCP server instead of recalling the API. +- Styling: Tailwind with CSS variables for design tokens. +- Charts: Recharts for standard charts, D3 only for custom ones. +- Motion: CSS first, Framer Motion for orchestrated React animation. -**CRITICAL**: Choose a clear conceptual direction and execute it with precision. +## Avoid these tells -## Technology Stack Preferences +- Type: Inter, Roboto, Arial, or system-ui as the display face. All text at 14 to 16px. One family everywhere. +- Color: purple or blue-violet gradients, default `#3B82F6` primary, low-contrast pastels, gradient progress bars. +- Layout: everything centered, a row of three identical cards, the centered hero over a gradient with floating shapes, the same radius on every element. +- Decoration: glassmorphism everywhere, soft uniform shadows, fade-in-on-scroll for every block, bounce on buttons, cute empty-state art. -### Component Libraries (Priority Order) -1. **shadcn/ui** - First choice for React projects. Copy components, full customization. -2. **Radix UI** - Accessible primitives when shadcn isn't available -3. **Headless UI** - For Tailwind-based projects -4. **Custom CSS** - When libraries aren't appropriate +## Do this instead -### Data Visualization -1. **Recharts** - First choice for charts in React. Clean, composable, customizable. -2. **Tremor** - Dashboard-ready charts with great defaults -3. **Victory** - When Recharts doesn't fit -4. **D3.js** - For complex, custom visualizations only +- Pair a distinctive display face with a plain body face, and push the contrast: headlines at 48px or more, weights far apart (300 against 700). Use fonts with character such as Instrument Serif, Fraunces, Cabinet Grotesk, Satoshi, Geist, DM Sans, JetBrains Mono. +- One dominant color used sparingly, near-black instead of `#000`, color that carries meaning. Design dark mode as a first-class theme. +- Asymmetric composition with a clear hierarchy, overlap for depth, and either generous space or deliberate density. Vary content widths on one page. +- Tactile micro-interactions, loading states that skeleton the real layout, error and empty states that tell the user what to do next. -### Styling -1. **Tailwind CSS** - Utility-first, consistent spacing/colors -2. **CSS Variables** - For theming and design tokens -3. **CSS Modules** - When Tailwind isn't available +## Implementation rules -### Animation -1. **Framer Motion** - First choice for React animations -2. **CSS animations** - For simple, performant effects -3. **GSAP** - For complex timeline animations +- Server Components by default in Next.js. Add `"use client"` only for state, effects, or browser APIs, and keep those leaves small. +- Fetch in parallel, stream slow parts behind Suspense. +- Keep components small and composed. Split a file over about 100 lines. +- Accessible by default: semantic elements, visible focus, labeled controls, contrast that passes WCAG AA, `prefers-reduced-motion` respected. +- Responsive from the first draft. -## Anti-Slop Design Rules +## Before finishing -### NEVER Use These (AI Slop Indicators) - -**Typography Slop**: -- Inter, Roboto, Arial, system-ui as primary fonts -- Font sizes that are too uniform (everything 14-16px) -- Generic font pairings (Inter + Inter) - -**Color Slop**: -- Purple/violet gradients on white backgrounds -- Blue-to-purple CTA buttons -- Washed-out, low-contrast color schemes -- Rainbow gradients for no reason -- Generic blue (#3B82F6) as primary color - -**Layout Slop**: -- Perfectly centered everything -- Cards with equal rounded corners (rounded-lg everywhere) -- Symmetric layouts with no visual hierarchy -- Grid of 3-4 identical cards pattern -- Hero with centered text + gradient background + floating shapes - -**Component Slop**: -- Glassmorphism on everything -- Shadows that are too soft and uniform -- Generic avatar circles with gradient backgrounds -- Empty state illustrations that are too cute -- Progress bars with gradient fills - -**Animation Slop**: -- Fade-in on scroll for everything -- Bounce effects on buttons -- Spinning loaders when skeleton screens work better -- Hover effects that all feel the same - -### INSTEAD, Create Distinctive Design - -**Typography That Stands Out**: -``` -Display fonts: Clash Display, Cabinet Grotesk, Satoshi, Space Grotesk (sparingly), - Instrument Serif, Fraunces, Playfair Display, Editorial New -Body fonts: Geist, Plus Jakarta Sans, DM Sans, Source Serif Pro, Literata -Monospace: JetBrains Mono, Fira Code, IBM Plex Mono -``` -- Create contrast between display and body fonts -- Use larger type than feels comfortable (48px+ for headlines) -- Vary font weights dramatically (300 vs 700) - -**Color With Intent**: -- Pick ONE dominant color and use it sparingly -- Use near-black (#0A0A0A, #111111) instead of pure black -- Create depth with subtle gradients in backgrounds -- Use color for meaning, not decoration -- Consider dark mode as primary (not afterthought) - -**Layouts That Break the Grid**: -- Asymmetric compositions with clear hierarchy -- Overlapping elements that create depth -- Generous negative space OR intentional density -- Grid-breaking hero elements -- Varying content widths within the same page - -**Components With Character**: -- Micro-interactions that feel tactile -- Loading states that match the brand -- Error states that are helpful and on-brand -- Empty states that guide rather than decorate -- Form inputs that feel substantial - -## React Component Architecture - -Design components like you are the creator of React. Think in composition, reusability, and elegance. - -### Component Philosophy - -**Small, Focused Components**: -- Each component does ONE thing well -- Prefer 20-50 lines per component -- If a component exceeds 100 lines, split it -- Name components by what they ARE, not what they DO - -**Composition Over Configuration**: -```tsx -// BAD: Monolithic component with many props -<Card - title="User Profile" - subtitle="Settings" - avatar={user.avatar} - showBadge={true} - badgeColor="green" - actions={[...]} -/> - -// GOOD: Composable components -<Card> - <Card.Header> - <Avatar src={user.avatar} /> - <Card.Title>User Profile</Card.Title> - <Badge variant="success" /> - </Card.Header> - <Card.Content>...</Card.Content> - <Card.Actions>...</Card.Actions> -</Card> -``` - -### Props Design Principles - -**Meaningful, Typed Props**: -```tsx -// Generic, reusable props -interface ButtonProps { - variant?: 'primary' | 'secondary' | 'ghost' | 'destructive'; - size?: 'sm' | 'md' | 'lg'; - loading?: boolean; - disabled?: boolean; - children: React.ReactNode; -} - -// State props that tell a story -interface DataTableProps<T> { - data: T[]; - columns: Column<T>[]; - isLoading?: boolean; - isEmpty?: boolean; - onRowClick?: (row: T) => void; - selectedRows?: Set<string>; -} -``` - -**Prop Patterns**: -- Use `children` for content (not `content` prop) -- Use render props for customization: `renderItem`, `renderEmpty` -- Use compound patterns for complex UIs -- Avoid boolean props when variants work better - -### State Management - -**Local State First**: -```tsx -// Keep state as close to where it's used as possible -function SearchInput({ onSearch }: { onSearch: (query: string) => void }) { - const [query, setQuery] = useState(''); - const debouncedSearch = useDebouncedCallback(onSearch, 300); - - return ( - <Input - value={query} - onChange={(e) => { - setQuery(e.target.value); - debouncedSearch(e.target.value); - }} - /> - ); -} -``` - -**Lift State Only When Needed**: -- Lift when siblings need to share state -- Lift when parent needs to control behavior -- Don't lift "just in case" - -### Component Patterns - -**1. Container/Presenter Pattern**: -```tsx -// Container: handles data fetching, state -function UserProfileContainer({ userId }: { userId: string }) { - const { data: user, isLoading } = useUser(userId); - if (isLoading) return <UserProfileSkeleton />; - return <UserProfile user={user} />; -} - -// Presenter: pure UI, receives props -function UserProfile({ user }: { user: User }) { - return ( - <Card> - <Avatar src={user.avatar} /> - <h2>{user.name}</h2> - </Card> - ); -} -``` - -**2. Compound Components**: -```tsx -// Parent provides context -const TabsContext = createContext<TabsContextValue>(null); - -function Tabs({ children, defaultValue }: TabsProps) { - const [active, setActive] = useState(defaultValue); - return ( - <TabsContext.Provider value={{ active, setActive }}> - <div className="tabs">{children}</div> - </TabsContext.Provider> - ); -} - -Tabs.List = TabsList; -Tabs.Tab = Tab; -Tabs.Panel = TabPanel; - -// Usage -<Tabs defaultValue="overview"> - <Tabs.List> - <Tabs.Tab value="overview">Overview</Tabs.Tab> - <Tabs.Tab value="settings">Settings</Tabs.Tab> - </Tabs.List> - <Tabs.Panel value="overview">...</Tabs.Panel> -</Tabs> -``` - -**3. Render Props for Flexibility**: -```tsx -interface ListProps<T> { - items: T[]; - renderItem: (item: T, index: number) => React.ReactNode; - renderEmpty?: () => React.ReactNode; - keyExtractor: (item: T) => string; -} - -function List<T>({ items, renderItem, renderEmpty, keyExtractor }: ListProps<T>) { - if (items.length === 0 && renderEmpty) return renderEmpty(); - return ( - <ul> - {items.map((item, i) => ( - <li key={keyExtractor(item)}>{renderItem(item, i)}</li> - ))} - </ul> - ); -} -``` - -### File Organization - -``` -components/ -├── ui/ # Primitive components (Button, Input, Card) -│ ├── button.tsx -│ ├── input.tsx -│ └── card.tsx -├── patterns/ # Composed patterns (DataTable, Form, Modal) -│ ├── data-table/ -│ │ ├── data-table.tsx -│ │ ├── data-table-header.tsx -│ │ ├── data-table-row.tsx -│ │ └── index.ts -│ └── form/ -├── features/ # Feature-specific components -│ ├── dashboard/ -│ └── settings/ -└── layouts/ # Page layouts - ├── sidebar-layout.tsx - └── centered-layout.tsx -``` - -### Anti-Patterns to Avoid - -**Component Slop**: -- Giant 500+ line components -- Props drilling through 5+ levels -- `useEffect` for everything -- Inline styles mixed with Tailwind -- `any` types on props - -**Instead**: -- Split into smaller, focused components -- Use Context or composition for deep data -- Prefer derived state over effects -- Consistent styling approach -- Strict TypeScript types - -## Next.js App Router Patterns - -### Server vs Client Components - -```tsx -// Server Component (default) - data fetching, no interactivity -// app/users/page.tsx -export default async function UsersPage() { - const users = await getUsers(); // Runs on server - - return ( - <div> - <h1>Users</h1> - <UserList users={users} /> - </div> - ); -} - -// Client Component - interactivity required -// components/user-search.tsx -'use client'; - -import { useState } from 'react'; - -export function UserSearch({ onSearch }: { onSearch: (q: string) => void }) { - const [query, setQuery] = useState(''); - - return ( - <input - value={query} - onChange={(e) => setQuery(e.target.value)} - onKeyDown={(e) => e.key === 'Enter' && onSearch(query)} - /> - ); -} -``` - -### Streaming with Suspense - -```tsx -// app/dashboard/page.tsx -import { Suspense } from 'react'; - -export default function DashboardPage() { - return ( - <div> - <h1>Dashboard</h1> - - {/* Fast data loads first */} - <Suspense fallback={<StatsSkeleton />}> - <StatsSection /> - </Suspense> - - {/* Slow data streams in */} - <Suspense fallback={<ChartSkeleton />}> - <AnalyticsChart /> - </Suspense> - </div> - ); -} - -// Async component that streams -async function StatsSection() { - const stats = await getStats(); // Can be slow - return <Stats data={stats} />; -} -``` - -### Data Fetching Patterns - -```tsx -// Parallel data fetching -async function DashboardPage() { - const [users, orders, stats] = await Promise.all([ - getUsers(), - getOrders(), - getStats(), - ]); - - return <Dashboard users={users} orders={orders} stats={stats} />; -} - -// With error boundary -import { notFound } from 'next/navigation'; - -async function UserPage({ params }: { params: { id: string } }) { - const user = await getUser(params.id); - - if (!user) { - notFound(); // Renders not-found.tsx - } - - return <UserProfile user={user} />; -} -``` - -## React Performance Patterns - -### Component Decomposition for Performance - -```tsx -// BAD: Large component with all state — all users re-render on any state change -function BadUserList() { - const [filter, setFilter] = useState(''); - const [users, setUsers] = useState<User[]>([]); - const [selectedId, setSelectedId] = useState<string | null>(null); - - return ( - <div> - <input value={filter} onChange={e => setFilter(e.target.value)} /> - {users.map(user => ( - <div - key={user.id} - onClick={() => setSelectedId(user.id)} - className={selectedId === user.id ? 'selected' : ''} - > - {user.name} - </div> - ))} - </div> - ); -} - -// GOOD: Push state down to where it's needed -function FilterableUserList({ users }: { users: User[] }) { - const [filter, setFilter] = useState(''); - const filtered = useMemo( - () => users.filter(u => u.name.includes(filter)), - [users, filter] - ); - - return ( - <div> - <input value={filter} onChange={e => setFilter(e.target.value)} /> - <SelectableList users={filtered} /> - </div> - ); -} - -function SelectableList({ users }: { users: User[] }) { - const [selectedId, setSelectedId] = useState<string | null>(null); - - return users.map(user => ( - <UserItem - key={user.id} - user={user} - selected={selectedId === user.id} - onSelect={() => setSelectedId(user.id)} - /> - )); -} -``` - -### Memoization Strategies - -```tsx -// Only memo when there's a measurable benefit -const UserItem = memo(function UserItem({ - user, - selected, - onSelect -}: { - user: User; - selected: boolean; - onSelect: () => void; -}) { - return ( - <div - onClick={onSelect} - className={selected ? 'selected' : ''} - > - {user.name} - </div> - ); -}); - -// useMemo for expensive computations -function ExpensiveList({ items }: { items: Item[] }) { - const processed = useMemo(() => { - return items - .filter(complexFilter) - .sort(complexSort) - .map(complexTransform); - }, [items]); - - return <List items={processed} />; -} - -// useCallback for stable references passed to children -function Parent() { - const [items, setItems] = useState<Item[]>([]); - - const handleDelete = useCallback((id: string) => { - setItems(prev => prev.filter(item => item.id !== id)); - }, []); - - return <ItemList items={items} onDelete={handleDelete} />; -} -``` - -## State Management Patterns - -### Context with Reducer - -```tsx -// types -interface State { - user: User | null; - isLoading: boolean; - error: Error | null; -} - -type Action = - | { type: 'FETCH_START' } - | { type: 'FETCH_SUCCESS'; user: User } - | { type: 'FETCH_ERROR'; error: Error } - | { type: 'LOGOUT' }; - -// reducer -function reducer(state: State, action: Action): State { - switch (action.type) { - case 'FETCH_START': - return { ...state, isLoading: true, error: null }; - case 'FETCH_SUCCESS': - return { ...state, isLoading: false, user: action.user }; - case 'FETCH_ERROR': - return { ...state, isLoading: false, error: action.error }; - case 'LOGOUT': - return { ...state, user: null }; - } -} - -// context + provider -const AuthContext = createContext<{ - state: State; - dispatch: Dispatch<Action>; -} | null>(null); - -function AuthProvider({ children }: { children: ReactNode }) { - const [state, dispatch] = useReducer(reducer, { - user: null, - isLoading: true, - error: null, - }); - - return ( - <AuthContext.Provider value={{ state, dispatch }}> - {children} - </AuthContext.Provider> - ); -} - -// hook -function useAuth() { - const context = useContext(AuthContext); - if (!context) { - throw new Error('useAuth must be used within AuthProvider'); - } - return context; -} -``` - -### Custom Hooks - -```tsx -// Debounced value hook -function useDebouncedValue<T>(value: T, delay: number): T { - const [debounced, setDebounced] = useState(value); - - useEffect(() => { - const timer = setTimeout(() => setDebounced(value), delay); - return () => clearTimeout(timer); - }, [value, delay]); - - return debounced; -} - -// Local storage hook -function useLocalStorage<T>( - key: string, - initialValue: T -): [T, (value: T | ((prev: T) => T)) => void] { - const [storedValue, setStoredValue] = useState<T>(() => { - if (typeof window === 'undefined') return initialValue; - try { - const item = localStorage.getItem(key); - return item ? JSON.parse(item) : initialValue; - } catch { - return initialValue; - } - }); - - const setValue = useCallback((value: T | ((prev: T) => T)) => { - setStoredValue(prev => { - const newValue = value instanceof Function ? value(prev) : value; - localStorage.setItem(key, JSON.stringify(newValue)); - return newValue; - }); - }, [key]); - - return [storedValue, setValue]; -} -``` - -## shadcn/ui Quick Reference - -**Core Philosophy**: shadcn/ui is NOT a component library—it's how you build your component library. You get actual component code that you own and can modify. - -### Quick Start - -```bash -# Initialize shadcn/ui -npx shadcn@latest init - -# Add components -npx shadcn@latest add button card dialog - -# Search registry -npx shadcn@latest search @shadcn -q "button" -``` - -### Key Principles - -1. **Open Code**: Full transparency, easy customization, AI-readable -2. **Composition**: Common, composable interface across all components -3. **Distribution**: Flat-file schema + CLI for easy installation -4. **Beautiful Defaults**: Great design out-of-the-box, easily customizable -5. **AI-Ready**: Open code structure for LLMs to understand and improve - -### Component Categories - -| Category | Components | -|----------|------------| -| **Form & Input** | Form, Field, Button, Input, Textarea, Checkbox, Radio, Select, Switch, Slider, Calendar, Date Picker, Combobox | -| **Layout & Navigation** | Accordion, Breadcrumb, Navigation Menu, Sidebar, Tabs, Separator, Scroll Area, Resizable | -| **Overlays & Dialogs** | Dialog, Alert Dialog, Sheet, Drawer, Popover, Tooltip, Hover Card, Context Menu, Dropdown Menu, Command | -| **Feedback & Status** | Alert, Toast, Progress, Spinner, Skeleton, Badge, Empty | -| **Display & Media** | Avatar, Card, Table, Data Table, Chart, Carousel, Aspect Ratio, Typography | - -### Theming Basics - -```tsx -// Color convention: background + foreground -<div className="bg-background text-foreground">Hello</div> -<div className="bg-primary text-primary-foreground">Primary</div> -<div className="bg-muted text-muted-foreground">Muted</div> -``` - -### Customization Tips - -1. **Customize the theme** - Don't use defaults - ```css - :root { - --radius: 0.5rem; /* or 0 for sharp corners */ - --primary: 220 13% 10%; /* custom primary */ - } - ``` - -2. **Extend components** - Add custom variants, modify animations, adjust spacing - -3. **Combine primitives** - Layer components for unique effects - -### For Complete Documentation - -See [references/shadcn.md](references/shadcn.md) for: -- Complete components.json configuration -- Full theming system with CSS variables -- Dark mode setup guide -- CLI commands reference -- MCP server integration -- Registry schema for publishing components - -## Recharts Quick Reference - -When creating charts: - -1. **Style the chart to match the UI** - ```jsx - <ResponsiveContainer> - <LineChart data={data}> - <Line - type="monotone" - strokeWidth={2} - dot={false} - stroke="hsl(var(--primary))" - /> - <XAxis - tickLine={false} - axisLine={false} - tick={{ fill: 'hsl(var(--muted-foreground))' }} - /> - </LineChart> - </ResponsiveContainer> - ``` - -2. **Remove visual clutter** - - Hide axis lines when not needed - - Use subtle grid lines or none - - Custom tooltips that match your design - -3. **Add meaningful interactions** - - Hover states that reveal detail - - Click handlers for drill-down - - Animate data changes smoothly - -## Implementation Checklist - -Before considering frontend work complete: - -- [ ] Typography creates clear hierarchy (display vs body) -- [ ] Colors are intentional and consistent (CSS variables) -- [ ] Spacing follows a rhythm (8px/4px grid) -- [ ] Interactive elements have hover/focus/active states -- [ ] Loading and empty states exist -- [ ] Dark mode works (if applicable) -- [ ] Animations are smooth (60fps, no jank) -- [ ] Accessibility: keyboard navigation, ARIA labels, color contrast -- [ ] Mobile responsive (or explicitly desktop-only) -- [ ] Code is production-ready (no console logs, proper error handling) -- [ ] Server Components by default, Client Components only when needed -- [ ] State pushed down to the lowest component that needs it -- [ ] Suspense boundaries for async operations -- [ ] Memoize only when profiling shows benefit -- [ ] Proper error boundaries implemented - -## Output Format - -When implementing frontend: - -1. **Explain the aesthetic direction** (2-3 sentences) -2. **List key design decisions** (typography, colors, key components) -3. **Provide complete, working code** with: - - All imports and dependencies noted - - CSS/Tailwind classes included - - TypeScript types when applicable - - Comments for non-obvious choices - -Remember: Claude is capable of extraordinary creative work. Commit fully to a distinctive vision that could only have been designed for this specific context. +Confirm no item in "Avoid these tells" remains, the direction is recognizable in the first screen, and the build, lint, and types pass. diff --git a/frontend-design/skills/frontend-design/references/shadcn.md b/frontend-design/skills/frontend-design/references/shadcn.md deleted file mode 100644 index db9c010..0000000 --- a/frontend-design/skills/frontend-design/references/shadcn.md +++ /dev/null @@ -1,736 +0,0 @@ -# shadcn/ui Reference - -> shadcn/ui is NOT a component library—it's how you build your component library. You get actual component code that you own and can modify. - -## Core Principles - -1. **Open Code**: Full transparency, easy customization, AI-readable -2. **Composition**: Common, composable interface across all components -3. **Distribution**: Flat-file schema + CLI for easy installation -4. **Beautiful Defaults**: Great design out-of-the-box, easily customizable -5. **AI-Ready**: Open code structure for LLMs to understand and improve - -## Installation & Setup - -```bash -# Using npx (npm) -npx shadcn@latest init - -# Using bunx (bun) -bunx shadcn@latest init - -# Using pnpm -pnpm dlx shadcn@latest init - -# Using yarn -yarn dlx shadcn@latest init -``` - -Or with your package manager's equivalent: - -```bash -# Add components -<npx/bunx/pnpm dlx/yarn dlx> shadcn@latest add button card dialog - -# View component before installing -<npx/bunx/pnpm dlx/yarn dlx> shadcn@latest view button card - -# Search registry -<npx/bunx/pnpm dlx/yarn dlx> shadcn@latest search @shadcn -q "button" -``` - -## components.json Configuration - -The `components.json` file controls how shadcn/ui integrates with your project: - -```json -{ - "$schema": "https://ui.shadcn.com/schema.json", - "style": "new-york", // Design style (cannot change after init) - "tailwind": { - "config": "tailwind.config.js", - "css": "app/globals.css", - "baseColor": "neutral", // neutral, gray, zinc, stone, slate - "cssVariables": true, // Use CSS variables for theming - "prefix": "" // Tailwind prefix if needed - }, - "rsc": true, // React Server Components support - "tsx": true, // TypeScript vs JavaScript - "aliases": { - "utils": "@/lib/utils", - "components": "@/components", - "ui": "@/components/ui", // Where UI components are installed - "lib": "@/lib", - "hooks": "@/hooks" - }, - "registries": { // Multiple registry support - "@shadcn": "https://ui.shadcn.com/r/{name}.json", - "@v0": "https://v0.dev/chat/b/{name}" - } -} -``` - -### Configuration Fields - -| Field | Description | Cannot Change After Init | -|-------|-------------|-------------------------| -| `style` | Design style variant | Yes | -| `tailwind.baseColor` | Base color palette | Yes | -| `tailwind.cssVariables` | Use CSS variables vs utilities | Yes | -| `tailwind.prefix` | Tailwind class prefix | No | -| `rsc` | React Server Components | No | -| `tsx` | TypeScript vs JavaScript | No | - -## Theming System - -### Color Convention - -Simple `background` and `foreground` pattern: - -```tsx -// Background and foreground colors -<div className="bg-background text-foreground">Hello</div> -<div className="bg-primary text-primary-foreground">Primary</div> -<div className="bg-muted text-muted-foreground">Muted</div> -``` - -The `background` suffix is omitted when the variable is used for the background color of the component. - -### CSS Variables (Recommended) - -```css -:root { - --radius: 0.625rem; - --background: oklch(1 0 0); - --foreground: oklch(0.145 0 0); - --card: oklch(1 0 0); - --card-foreground: oklch(0.145 0 0); - --popover: oklch(1 0 0); - --popover-foreground: oklch(0.145 0 0); - --primary: oklch(0.205 0 0); - --primary-foreground: oklch(0.985 0 0); - --secondary: oklch(0.97 0 0); - --secondary-foreground: oklch(0.205 0 0); - --muted: oklch(0.97 0 0); - --muted-foreground: oklch(0.556 0 0); - --accent: oklch(0.97 0 0); - --accent-foreground: oklch(0.205 0 0); - --destructive: oklch(0.577 0.245 27.325); - --border: oklch(0.922 0 0); - --input: oklch(0.922 0 0); - --ring: oklch(0.708 0 0); - --chart-1: oklch(0.646 0.222 41.116); - --chart-2: oklch(0.6 0.118 184.704); - --chart-3: oklch(0.398 0.07 227.392); - --chart-4: oklch(0.828 0.189 84.429); - --chart-5: oklch(0.769 0.188 70.08); - --sidebar: oklch(0.985 0 0); - --sidebar-foreground: oklch(0.145 0 0); - --sidebar-primary: oklch(0.205 0 0); - --sidebar-primary-foreground: oklch(0.985 0 0); - --sidebar-accent: oklch(0.97 0 0); - --sidebar-accent-foreground: oklch(0.205 0 0); - --sidebar-border: oklch(0.922 0 0); - --sidebar-ring: oklch(0.708 0 0); -} - -.dark { - --background: oklch(0.145 0 0); - --foreground: oklch(0.985 0 0); - --card: oklch(0.205 0 0); - --card-foreground: oklch(0.985 0 0); - --popover: oklch(0.269 0 0); - --popover-foreground: oklch(0.985 0 0); - --primary: oklch(0.922 0 0); - --primary-foreground: oklch(0.205 0 0); - --secondary: oklch(0.269 0 0); - --secondary-foreground: oklch(0.985 0 0); - --muted: oklch(0.269 0 0); - --muted-foreground: oklch(0.708 0 0); - --accent: oklch(0.371 0 0); - --accent-foreground: oklch(0.985 0 0); - --destructive: oklch(0.704 0.191 22.216); - --border: oklch(1 0 0 / 10%); - --input: oklch(1 0 0 / 15%); - --ring: oklch(0.556 0 0); - --chart-1: oklch(0.488 0.243 264.376); - --chart-2: oklch(0.696 0.17 162.48); - --chart-3: oklch(0.769 0.188 70.08); - --chart-4: oklch(0.627 0.265 303.9); - --chart-5: oklch(0.645 0.246 16.439); - --sidebar: oklch(0.205 0 0); - --sidebar-foreground: oklch(0.985 0 0); - --sidebar-primary: oklch(0.488 0.243 264.376); - --sidebar-primary-foreground: oklch(0.985 0 0); - --sidebar-accent: oklch(0.269 0 0); - --sidebar-accent-foreground: oklch(0.985 0 0); - --sidebar-border: oklch(1 0 0 / 10%); - --sidebar-ring: oklch(0.439 0 0); -} -``` - -### Adding Custom Colors - -```css -:root { - --warning: oklch(0.84 0.16 84); - --warning-foreground: oklch(0.28 0.07 46); -} - -.dark { - --warning: oklch(0.41 0.11 46); - --warning-foreground: oklch(0.99 0.02 95); -} - -@theme inline { - --color-warning: var(--warning); - --color-warning-foreground: var(--warning-foreground); -} - -/* Usage */ -<div className="bg-warning text-warning-foreground" /> -``` - -### Base Color Options - -Available base colors for `tailwind.baseColor`: - -| Color | Description | -|-------|-------------| -| `neutral` | Pure grayscale, no hue bias | -| `gray` | Slightly cool gray with blue tint | -| `zinc` | Cool gray with slight purple/blue tint | -| `stone` | Warm gray with yellow/beige tint | -| `slate` | Cool gray with strong blue tint | - -### Utility Classes vs CSS Variables - -**CSS Variables (Recommended)**: -```tsx -<div className="bg-background text-foreground" /> -``` - -**Utility Classes**: -```tsx -<div className="bg-zinc-950 dark:bg-white dark:text-zinc-950" /> -``` - -Set `tailwind.cssVariables: false` in `components.json` to use utility classes. - -## Dark Mode Setup (Next.js) - -### 1. Install next-themes - -```bash -# npm -npm install next-themes - -# bun -bun add next-themes - -# pnpm -pnpm add next-themes - -# yarn -yarn add next-themes -``` - -### 2. Create Theme Provider - -```tsx -// components/theme-provider.tsx -"use client" - -import * as React from "react" -import { ThemeProvider as NextThemesProvider } from "next-themes" - -export function ThemeProvider({ - children, - ...props -}: React.ComponentProps<typeof NextThemesProvider>) { - return <NextThemesProvider {...props}>{children}</NextThemesProvider> -} -``` - -### 3. Wrap Root Layout - -```tsx -// app/layout.tsx -import { ThemeProvider } from "@/components/theme-provider" - -export default function RootLayout({ children }: RootLayoutProps) { - return ( - <html lang="en" suppressHydrationWarning> - <body> - <ThemeProvider - attribute="class" - defaultTheme="system" - enableSystem - disableTransitionOnChange - > - {children} - </ThemeProvider> - </body> - </html> - ) -} -``` - -The `suppressHydrationWarning` prop is required on the `html` tag to prevent hydration mismatch warnings when rendering theme classes. - -## Component Categories - -### Form & Input - -| Component | Description | Dependencies | -|-----------|-------------|--------------| -| **Form** | Building forms with React Hook Form + Zod validation | react-hook-form, zod | -| **Field** | Field component with labels and error messages | - | -| **Button** | Button with multiple variants | - | -| **Button Group** | Group multiple buttons together | - | -| **Input** | Text input component | - | -| **Input Group** | Input with prefix/suffix addons | - | -| **Input OTP** | One-time password input | input-otp | -| **Textarea** | Multi-line text input | - | -| **Checkbox** | Checkbox input | @radix-ui/react-checkbox | -| **Radio Group** | Radio button group | @radix-ui/react-radio-group | -| **Select** | Select dropdown | @radix-ui/react-select | -| **Switch** | Toggle switch | @radix-ui/react-switch | -| **Slider** | Slider input | @radix-ui/react-slider | -| **Calendar** | Calendar for date selection | react-day-picker | -| **Date Picker** | Date picker combining input + calendar | calendar | -| **Combobox** | Searchable select with autocomplete | cmdk | -| **Label** | Form label | - | - -### Layout & Navigation - -| Component | Description | Dependencies | -|-----------|-------------|--------------| -| **Accordion** | Collapsible accordion | @radix-ui/react-accordion | -| **Breadcrumb** | Breadcrumb navigation | - | -| **Navigation Menu** | Accessible nav with dropdowns | @radix-ui/react-navigation-menu | -| **Sidebar** | Collapsible sidebar for layouts | - | -| **Tabs** | Tabbed interface | @radix-ui/react-tabs | -| **Separator** | Visual divider | - | -| **Scroll Area** | Custom scrollable area | @radix-ui/react-scroll-area | -| **Resizable** | Resizable panel layout | react-resizable-panels | - -### Overlays & Dialogs - -| Component | Description | Dependencies | -|-----------|-------------|--------------| -| **Dialog** | Modal dialog | @radix-ui/react-dialog | -| **Alert Dialog** | Confirmation dialog | @radix-ui/react-alert-dialog | -| **Sheet** | Slide-out panel (drawer) | @radix-ui/react-dialog | -| **Drawer** | Mobile-friendly drawer | vaul | -| **Popover** | Floating popover | @radix-ui/react-popover | -| **Tooltip** | Tooltip for additional context | @radix-ui/react-tooltip | -| **Hover Card** | Card that appears on hover | @radix-ui/react-hover-card | -| **Context Menu** | Right-click context menu | @radix-ui/react-context-menu | -| **Dropdown Menu** | Dropdown menu | @radix-ui/react-dropdown-menu | -| **Menubar** | Horizontal menubar | @radix-ui/react-menubar | -| **Command** | Command palette | cmdk | - -### Feedback & Status - -| Component | Description | Dependencies | -|-----------|-------------|--------------| -| **Alert** | Alert for messages/notifications | - | -| **Toast** | Toast notifications | sonner | -| **Progress** | Progress bar | @radix-ui/react-progress | -| **Spinner** | Loading spinner | - | -| **Skeleton** | Skeleton loading placeholder | - | -| **Badge** | Badge for labels/status | - | -| **Empty** | Empty state component | - | - -### Display & Media - -| Component | Description | Dependencies | -|-----------|-------------|--------------| -| **Avatar** | Avatar for user profiles | @radix-ui/react-avatar | -| **Card** | Card container | - | -| **Table** | Table for displaying data | - | -| **Data Table** | Advanced table (sorting, filtering, pagination) | tanstack-table | -| **Chart** | Charts using Recharts | recharts | -| **Carousel** | Carousel using Embla | embla-carousel-react | -| **Aspect Ratio** | Container with aspect ratio | @radix-ui/react-aspect-ratio | -| **Typography** | Typography styles | - | -| **Item** | Generic item for lists/menus | - | -| **Kbd** | Keyboard shortcut display | - | - -## MCP Server Integration - -The shadcn MCP Server allows AI assistants to browse, search, and install components from registries using natural language. - -### What is MCP? - -Model Context Protocol (MCP) is an open protocol that enables AI assistants to securely connect to external data sources and tools. With the shadcn MCP server, your AI assistant gains direct access to: - -- **Browse Components** - List all available components, blocks, and templates from any configured registry -- **Search Across Registries** - Find specific components by name or functionality across multiple sources -- **Install with Natural Language** - Add components using simple conversational prompts like "add a login form" -- **Support for Multiple Registries** - Access public registries, private company libraries, and third-party sources - -### Quick Start - -**Run the MCP init command** in your project: - -```bash -<npx/bunx/pnpm dlx/yarn dlx> shadcn@latest mcp init --client claude -``` - -**Restart your MCP client** and try prompts like: -- "Show me all available components in the shadcn registry" -- "Add the button, dialog and card components to my project" -- "Create a contact form using components from the shadcn registry" - -**Supported clients**: `--client claude|cursor|vscode|codex` - -### Configuration - -#### Claude Code - -Add to `.mcp.json` in your project: - -```json -{ - "mcpServers": { - "shadcn": { - "command": "npx", - "args": ["shadcn@latest", "mcp"] - } - } -} -``` - -Restart Claude Code and run `/mcp` to verify connection. - -#### Cursor - -Add to `.cursor/mcp.json`: - -```json -{ - "mcpServers": { - "shadcn": { - "command": "npx", - "args": ["shadcn@latest", "mcp"] - } - } -} -``` - -Enable the shadcn MCP server in Cursor Settings. - -#### VS Code (GitHub Copilot) - -Add to `.vscode/mcp.json`: - -```json -{ - "servers": { - "shadcn": { - "command": "npx", - "args": ["shadcn@latest", "mcp"] - } - } -} -``` - -Open `.vscode/mcp.json` and click **Start** next to the shadcn server. - -#### Codex - -Add to `~/.codex/config.toml`: - -```toml -[mcp_servers.shadcn] -command = "npx" -args = ["shadcn@latest", "mcp"] -``` - -Restart Codex to load the MCP server. - -### Registry Configuration - -Configure multiple registries in your `components.json`: - -```json -{ - "registries": { - "@shadcn": "https://ui.shadcn.com/r/{name}.json", - "@v0": "https://v0.dev/chat/b/{name}", - "@acme": "https://registry.acme.com/{name}.json", - "@private": { - "url": "https://api.company.com/registry/{name}.json", - "headers": { - "Authorization": "Bearer ${REGISTRY_TOKEN}", - "X-API-Key": "${API_KEY}" - }, - "params": { - "version": "latest" - } - } - } -} -``` - -Environment variables in `${VAR_NAME}` format are automatically expanded. - -### Authentication - -For private registries, set environment variables in `.env.local`: - -```bash -REGISTRY_TOKEN=your_token_here -API_KEY=your_api_key_here -``` - -### Example Prompts - -Once configured, use natural language to interact with registries: - -**Browse & Search**: -- "Show me all available components in the shadcn registry" -- "Find me a login form from the shadcn registry" - -**Install Items**: -- "Add the button component to my project" -- "Create a login form using shadcn components" -- "Install the Cursor rules from the acme registry" - -**Work with Namespaces**: -- "Show me components from acme registry" -- "Install @internal/auth-form" -- "Build a landing page using hero, features and testimonials from the acme registry" - -### Installing from Registries (CLI) - -```bash -# Install from public registry -<npx/bunx/pnpm dlx/yarn dlx> shadcn@latest add @shadcn/button - -# Install from v0 -<npx/bunx/pnpm dlx/yarn dlx> shadcn@latest add @v0/dashboard - -# Install from private registry with auth -<npx/bunx/pnpm dlx/yarn dlx> shadcn@latest add @private/button - -# Install multiple resources -<npx/bunx/pnpm dlx/yarn dlx> shadcn@latest add @acme/header @internal/auth-utils -``` - -### Troubleshooting - -**MCP Not Responding**: -1. Check configuration is properly enabled in your MCP client -2. Restart MCP client after configuration changes -3. Ensure `shadcn` is installed in your project -4. Confirm network access to configured registries - -**Registry Access Issues**: -1. Verify registry URLs are correct in `components.json` -2. Ensure environment variables are set for private registries -3. Confirm registry is online and accessible -4. Check namespace syntax is correct (`@namespace/component`) - -**Installation Failures**: -1. Ensure valid `components.json` file -2. Confirm target directories exist -3. Check write permissions for component directories -4. Verify required dependencies are installed - -## Registry Schema - -For publishing your own components: - -### Basic Registry Item - -```json -{ - "name": "my-component", - "type": "registry:component", - "registryDependencies": ["button", "card"], - "dependencies": ["zod", "date-fns"], - "files": [ - { - "path": "components/my-component.tsx", - "type": "registry:component", - "target": "components/my-component.tsx" - } - ] -} -``` - -### Full Registry Item with Styling - -```json -{ - "name": "my-component", - "type": "registry:component", - "registryDependencies": ["button", "card"], - "dependencies": ["zod", "date-fns"], - "devDependencies": ["@types/node"], - "tailwind": { - "config": { - "theme": { - "extend": { - "colors": { - "brand": "hsl(var(--brand))" - } - } - } - } - }, - "cssVars": { - "light": { - "brand": "220 13% 10%" - }, - "dark": { - "brand": "220 13% 90%" - } - }, - "files": [ - { - "path": "components/my-component.tsx", - "type": "registry:component" - } - ], - "categories": ["ui"] -} -``` - -### Registry Types - -| Type | Description | -|------|-------------| -| `registry:component` | React component | -| `registry:hook` | React hook | -| `registry:lib` | Utility/library function | -| `registry:page` | Page component (has `target` property for file-based routing) | -| `registry:block` | Pre-built page/feature with multiple files | -| `registry:theme` | Theme configuration | - -### Building Registry Files - -```bash -# Generate registry JSON from registry.json -<npx/bunx/pnpm dlx/yarn dlx> shadcn@latest build - -# Custom output directory -<npx/bunx/pnpm dlx/yarn dlx> shadcn@latest build --output ./public/registry -``` - -## CLI Commands Reference - -**Package Manager**: Use your preferred package manager's executor: -- `npx` (npm), `bunx` (bun), `pnpm dlx` (pnpm), `yarn dlx` (yarn) - -### init - -Initialize configuration and dependencies: - -```bash -<npx/bunx/pnpm dlx/yarn dlx> shadcn@latest init [options] - -# Options: - -t, --template <template> # Template: next, next-monorepo - -b, --base-color <base-color> # Base color: neutral, gray, zinc, stone, slate - -y, --yes # Skip confirmation - -f, --force # Force overwrite - -c, --cwd <cwd> # Working directory - -s, --silent # Mute output - --src-dir # Use src directory - --css-variables # Use CSS variables (default: true) - --no-base-style # Don't install base style -``` - -### add - -Add components to project: - -```bash -<npx/bunx/pnpm dlx/yarn dlx> shadcn@latest add [options] [components...] - -# Options: - -y, --yes # Skip confirmation - -o, --overwrite # Overwrite existing files - -c, --cwd <cwd> # Working directory - -a, --all # Add all components - -p, --path <path> # Custom install path - -s, --silent # Mute output -``` - -### view - -View components before installing: - -```bash -<npx/bunx/pnpm dlx/yarn dlx> shadcn@latest view [item] - -# View multiple -<npx/bunx/pnpm dlx/yarn dlx> shadcn@latest view button card dialog - -# View from namespaced registries -<npx/bunx/pnpm dlx/yarn dlx> shadcn@latest view @acme/auth @v0/dashboard -``` - -### search - -Search registries: - -```bash -<npx/bunx/pnpm dlx/yarn dlx> shadcn@latest search [options] <registries...> - -# Examples -<npx/bunx/pnpm dlx/yarn dlx> shadcn@latest search @shadcn -q "button" -<npx/bunx/pnpm dlx/yarn dlx> shadcn@latest search @shadcn @v0 @acme - -# Options: - -c, --cwd <cwd> # Working directory - -q, --query <query> # Search query - -l, --limit <number> # Max items per registry (default: 100) - -o, --offset <number> # Items to skip (default: 0) -``` - -### list - -List items from registry (alias for `search`): - -```bash -<npx/bunx/pnpm dlx/yarn dlx> shadcn@latest list <registries...> -``` - -## Customization Best Practices - -1. **Customize the theme** - Don't use defaults - ```css - /* Customize in globals.css */ - :root { - --radius: 0.5rem; /* or 0 for sharp corners */ - --primary: 220 13% 10%; /* custom primary */ - } - ``` - -2. **Extend components** - Don't just copy-paste - - Add custom variants - - Modify animations - - Adjust spacing to match your aesthetic - -3. **Combine primitives creatively** - - Layer components for unique effects - - Use Command for more than command palettes - - Use Sheet for custom navigation patterns - -4. **Follow the composition pattern** - ```tsx - // Compose, don't configure - <Card> - <Card.Header> - <Card.Title>Header</Card.Title> - <Card.Description>Description</Card.Description> - </Card.Header> - <Card.Content>Content</Card.Content> - <Card.Footer>Footer</Card.Footer> - </Card> - ``` diff --git a/github/.claude-plugin/plugin.json b/github/.claude-plugin/plugin.json index e2fd94a..946765a 100644 --- a/github/.claude-plugin/plugin.json +++ b/github/.claude-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "github", - "version": "1.4.2", - "description": "GitHub operations using gh CLI - PRs, issues, workflows, batch operations, PR babysitting with AI review bot integration, and smart branch detection", + "version": "1.5.0", + "description": "Drive PRs to merge-ready with gh: fix CI and review-bot feedback, plus bulk merge, close, and label.", "author": { "name": "duyet", "url": "https://github.com/duyet" diff --git a/github/.codex-plugin/plugin.json b/github/.codex-plugin/plugin.json index ca10931..a8fae24 100644 --- a/github/.codex-plugin/plugin.json +++ b/github/.codex-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "github", - "version": "1.4.2", - "description": "GitHub operations using gh CLI - PRs, issues, workflows, batch operations, PR babysitting with AI review bot integration, and smart branch detection", + "version": "1.5.0", + "description": "Drive PRs to merge-ready with gh: fix CI and review-bot feedback, plus bulk merge, close, and label.", "author": { "name": "duyet", "url": "https://github.com/duyet" @@ -11,7 +11,7 @@ "commands": "./commands/", "interface": { "displayName": "GitHub", - "shortDescription": "GitHub operations using gh CLI - PRs, issues, workflows, batch operations, PR babysitting with AI review bot integration, and smart branch detection", + "shortDescription": "Drive PRs to merge-ready with gh: fix CI and review-bot feedback, plus bulk merge, close, and label.", "developerName": "duyet", "category": "Git", "capabilities": [ diff --git a/github/.cursor-plugin/plugin.json b/github/.cursor-plugin/plugin.json index 66514db..963ada0 100644 --- a/github/.cursor-plugin/plugin.json +++ b/github/.cursor-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "github", - "version": "1.4.2", - "description": "GitHub operations using gh CLI - PRs, issues, workflows, batch operations, PR babysitting with AI review bot integration, and smart branch detection", + "version": "1.5.0", + "description": "Drive PRs to merge-ready with gh: fix CI and review-bot feedback, plus bulk merge, close, and label.", "author": { "name": "duyet" }, diff --git a/github/.grok-build-plugin/plugin.json b/github/.grok-build-plugin/plugin.json index 89acb0d..2b9b5b2 100644 --- a/github/.grok-build-plugin/plugin.json +++ b/github/.grok-build-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "github", - "version": "1.4.2", - "description": "GitHub operations using gh CLI - PRs, issues, workflows, batch operations, PR babysitting with AI review bot integration, and smart branch detection", + "version": "1.5.0", + "description": "Drive PRs to merge-ready with gh: fix CI and review-bot feedback, plus bulk merge, close, and label.", "author": { "name": "duyet", "url": "https://github.com/duyet" @@ -12,7 +12,7 @@ "commands": "./commands/", "interface": { "displayName": "GitHub", - "shortDescription": "GitHub operations using gh CLI - PRs, issues, workflows, batch operations, PR babysitting with AI review bot integration, and smart branch detection", + "shortDescription": "Drive PRs to merge-ready with gh: fix CI and review-bot feedback, plus bulk merge, close, and label.", "developerName": "duyet", "category": "Git", "capabilities": [ diff --git a/github/.grok-plugin/plugin.json b/github/.grok-plugin/plugin.json index 3940e7d..a2ec228 100644 --- a/github/.grok-plugin/plugin.json +++ b/github/.grok-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "github", - "version": "1.4.2", - "description": "GitHub operations using gh CLI - PRs, issues, workflows, batch operations, PR babysitting with AI review bot integration, and smart branch detection", + "version": "1.5.0", + "description": "Drive PRs to merge-ready with gh: fix CI and review-bot feedback, plus bulk merge, close, and label.", "author": { "name": "duyet", "url": "https://github.com/duyet" diff --git a/github/README.md b/github/README.md index b010177..05d3e29 100644 --- a/github/README.md +++ b/github/README.md @@ -1,241 +1,25 @@ -# GitHub Plugin +# GitHub plugin -GitHub operations using gh CLI - PRs, issues, workflows, repositories, batch operations, and smart branch detection for implementation workflows. +GitHub operations with the `gh` CLI: PR babysitting, review-bot feedback, and bulk issue and PR changes. -## Version +## Install -1.4.0 - -## Components - -### Skills -- **github** - GitHub operations knowledge -- **review-bots** - AI code review bot parsing (CodeRabbit, Sourcery, Gemini) - -### Commands -- `/github:bulk-close-issues` - Close multiple issues by label or search query -- `/github:bulk-merge-prs` - Merge multiple approved PRs -- `/github:bulk-label` - Apply labels to multiple issues/PRs -- `/github:watch-and-fix` - Watch PR, fix issues from AI reviews, and auto-merge when ready -- `/github:babysit-pr` - Babysit a PR: monitor, fix review bot suggestions (CodeRabbit, Sourcery, Gemini), resolve conflicts, and merge - -## Features - -### Smart Branch Detection -Automatically detects when you're on main/master and creates feature branches before implementing. - -### Batch Operations -Efficiently manage multiple issues and PRs with bulk commands: -- Close issues in bulk by label or query -- Merge approved PRs with passing CI -- Apply/remove labels across multiple items - -### Complete GitHub Workflow -Handles full workflow from branch creation to PR merge. - -## Usage Examples - -### Create PR from Feature Branch -```bash -# Make changes -git add . -git commit -m "feat: add new feature" - -# Push and create PR -git push -u origin feat/new-feature -gh pr create --title "feat: add new feature" --body "Implements #123" -``` - -### Bulk Close Stale Issues -```bash -# Preview what will be closed -/github:bulk-close-issues --dry-run --label "stale" - -# Close with comment -/github:bulk-close-issues --label "stale" --comment "Closing due to inactivity" -``` - -### Merge Approved PRs -```bash -# Preview before merging -/github:bulk-merge-prs --dry-run --label "ready-to-merge" - -# Merge with squash and delete branches -/github:bulk-merge-prs --label "ready-to-merge" --method squash --delete-branch -``` - -### Apply Labels in Bulk -```bash -# Add priority label to bugs -/github:bulk-label --add "priority:high" --label "bug" - -# Remove triage label from reviewed items -/github:bulk-label --remove "status:triage" --search "reviewed-by:@me" -``` - -### Watch and Fix PR -```bash -# Watch PR, fix issues from AI reviews, and auto-merge when ready -/github:watch-and-fix --auto-merge --max-iterations 5 - -# Preview what would happen -/github:watch-and-fix --dry-run -``` - -### Babysit PR -```bash -# Babysit current branch's PR — reads all review comments and fixes them -/github:babysit-pr --auto-merge - -# Babysit specific PR with limited iterations -/github:babysit-pr --pr 123 --max-iterations 5 - -# Use with /loop for continuous monitoring every 10 minutes -/loop 10m /github:babysit-pr --auto-merge - -# Preview mode -/github:babysit-pr --dry-run -``` - -## Real-World Workflows - -### Automated PR Triage -```bash -# Label first-time contributor PRs -for pr in $(gh pr list --author . --json number --jq '.[].number'); do - count=$(gh api users/$(gh pr view $pr --json author --jq '.author.login')/repos --jq 'length' 2>/dev/null || echo 0) - if [ "$count" -lt 5 ]; then - gh pr edit $pr --add-label "first-time-contributor" - fi -done -``` - -### Watch and Fix Loop -```bash -# Continuous fix loop for a PR -./examples/watch-and-fix.sh --auto-merge --max-iterations 10 - -# Or use the slash command -/github:watch-and-fix --auto-merge ``` - -### CI Failure Analysis -```bash -# Find all PRs with failed CI -gh pr list --search "status:failure" --limit 50 --json number,title - -# Watch specific run in real-time -gh run watch $(gh run list --workflow=ci.yml --limit 1 --json databaseId --jq '.[0].databaseId') -``` - -### Repository Cleanup -```bash -# Close stale draft PRs -gh pr list --search "draft:yes updated:<30 days ago" --json number --jq '.[].number' | \ - while read pr; do gh pr close $pr --comment "Closing stale draft PR"; done -``` - -## Troubleshooting - -### "Not logged in" Error -```bash -gh auth login -``` - -### Token Expired -```bash -gh auth refresh +/plugin install github@duyet-claude-plugins ``` -### Branch Detection Not Working -```bash -# Set remote head explicitly -git remote set-head origin -a - -# Explicitly specify base branch -gh pr create --base main --title "Fix" -``` - -### CI Status Not Showing -```bash -# Check workflow name -gh workflow list - -# View specific workflow status -gh run list --workflow=ci.yml -``` - -### Rate Limiting -```bash -# Check rate limit status -gh api /rate_limit - -# Use pagination for large result sets -gh pr list --limit 100 --json number,title --jq '.[]' -``` - -## Examples - -See the `examples/` directory for complete automation scripts: -- `babysit-pr.sh` - Babysit PR with review bot integration and effort reporting -- `bulk-close-issues.sh` - Close issues by label with confirmation -- `bulk-merge-prs.sh` - Merge approved PRs with passing CI -- `pr-automation.sh` - Auto-label, auto-assign, and welcome contributors -- `watch-and-fix.sh` - Watch PR, fix issues from AI reviews, auto-merge when ready - -## Plugin Structure - -``` -github/ -├── .claude-plugin/ -│ └── plugin.json # Manifest (version 1.4.0) -├── commands/ # Slash commands -│ ├── babysit-pr.md -│ ├── bulk-close-issues.md -│ ├── bulk-merge-prs.md -│ ├── bulk-label.md -│ └── watch-and-fix.md -├── skills/ # Reusable knowledge -│ ├── github.md -│ └── review-bots.md -└── examples/ # Example scripts - ├── babysit-pr.sh - ├── bulk-close-issues.sh - ├── bulk-merge-prs.sh - ├── pr-automation.sh - └── watch-and-fix.sh -``` - -## Versioning - -Follow semantic versioning (semver): - -| Change Type | Version Bump | Example | -|-------------|--------------|---------| -| Bug fix, docs | Patch | 1.2.0 → 1.2.1 | -| New feature, minor change | Minor | 1.2.0 → 1.4.0 | -| Breaking change | Major | 1.2.0 → 2.0.0 | - -**When to bump:** -- Adding new commands → **Minor** -- Modifying existing behavior → **Minor** (or Major if breaking) -- Updating documentation only → **Patch** -- Bug fixes → **Patch** - -Always update `plugin.json` version when making changes. - -## Commit Convention - -Use semantic commits with plugin scope: - -``` -feat(github): add new batch command -fix(github): fix issue listing pagination -docs(github): update examples -``` +## What ships -Co-author: `Co-Authored-By: duyetbot <duyetbot@users.noreply.github.com>` +Skills: +- `github-workflow` - rules for safe `gh` use +- `review-bots` - how to read CodeRabbit, Sourcery, and Gemini comments ---- +Commands: +- `/github:babysit-pr` - fix CI, review comments, and conflicts until the PR is merge-ready +- `/github:watch-and-fix` - alias for babysit-pr +- `/github:review-and-merge` - triage open PRs, fix review feedback, and merge +- `/github:bulk-merge-prs` - merge approved PRs with passing CI +- `/github:bulk-close-issues` - close issues by label or query +- `/github:bulk-label` - label many issues or PRs -**Generated by docs-generator v1.0.0** +Requires an authenticated `gh` CLI. diff --git a/github/commands/babysit-pr.md b/github/commands/babysit-pr.md index 07ff3cc..197fd89 100644 --- a/github/commands/babysit-pr.md +++ b/github/commands/babysit-pr.md @@ -1,321 +1,35 @@ --- -allowed-tools: Bash(git *), Bash(gh *), Read, Edit, Write, Glob, Grep, Agent, Task(general-purpose,code-review) -description: Babysit a PR - monitor, auto-fix review comments, ensure CI is green, handle auto-merge, and merge when ready +allowed-tools: Bash(git *), Bash(gh *), Read, Edit, Write, Glob, Grep, Agent +description: Drive a PR to merge-ready by fixing CI failures, review comments, and conflicts in a loop --- # Babysit PR -Continuously monitor a pull request with intelligent automation: -- **Auto-address code review comments** from AI bots (CodeRabbit, Sourcery, Gemini) and human reviewers -- **Auto-fix CI failures** by analyzing logs, fixing issues, and retrying -- **Keep PR in green state** by monitoring CI checks and resolving blockers -- **Smart merge handling** for repos with auto-merge enabled -- **Effort tracking** — reports total fixes, conflicts, and duration at completion - -This command **always** ensures the PR CI is green before considering the job done. It will auto-fix CI failures, auto-address all review comments (from bots and humans), and **wait** until everything is green — CI checks passing, no unresolved review comments, no merge conflicts. Do not stop the loop until all conditions are met or max iterations is reached. +Drive a pull request until CI is green, no review comments are unresolved, and there are no merge conflicts. ## Usage -```bash -/github:babysit-pr -/github:babysit-pr --pr 123 -/github:babysit-pr --auto-merge -/github:babysit-pr --fix-ci # Auto-fix CI failures -/github:babysit-pr --force-merge # Force merge even if auto-merge is stuck -/github:babysit-pr --max-iterations 10 -/github:babysit-pr --ci-timeout 30 # CI wait timeout in minutes -/github:babysit-pr --dry-run -``` - -## Options - -- `--pr <number>`: Specific PR number (default: current branch's PR) -- `--auto-merge`: Merge PR when CI passes and all review comments are resolved -- `--fix-ci`: Attempt to auto-fix CI failures by analyzing error logs -- `--force-merge`: Force merge via API even if auto-merge is stuck (use with caution) -- `--max-iterations <n>`: Maximum fix iterations (default: 10) -- `--ci-timeout <n>`: Maximum minutes to wait for CI (default: 15) -- `--dry-run`: Preview what would happen without making changes - -## How It Works - -### 1. Initial Setup -- Verify we're on a feature branch (not main/master) -- Find the PR for current branch (or use `--pr`) -- Check if repo has auto-merge enabled (for later handling) -- Record start time for effort tracking -- Validate git state (no uncommitted changes) - -### 2. Babysit Loop - -For each iteration: - -#### Step A: Wait for CI and Reviews -- Poll CI status until all checks complete (timeout per `--ci-timeout`, default 15 min) -- Track which checks are failing vs passing -- Wait for review bots to post their comments (30s grace period after CI completes) - -**Auto-fix CI Failures (if `--fix-ci`):** -```bash -# Get CI workflow run details -gh api repos/{owner}/{repo}/actions/runs/{run_id} - -# Download and analyze CI logs -gh run view $RUN_ID --log - -# Parse error messages and attempt smart fixes: -# - Linting errors → run linter auto-fix (eslint --fix, prettier, etc.) -# - Type errors → analyze TS/flow errors and fix types -# - Test failures → analyze stack trace and fix tests/code -# - Build errors → fix build config or dependency issues -``` - -If CI check fails after analysis: -1. Attempt automatic fix using code understanding (not trial-and-error) -2. Run specific failing check locally to verify fix -3. Commit fix and push (this triggers new CI run) -4. Re-poll CI status - -#### Step B: Fetch ALL Review Comments -Read all review comments — both from AI bots and human reviewers: - -**Known AI Review Bots:** - -| Bot | Username Pattern | Comment Style | -|-----|-----------------|---------------| -| CodeRabbit | `coderabbitai[bot]` | Structured markdown with file paths, actionable suggestions, and code blocks | -| Sourcery | `sourcery-ai[bot]` | Inline suggestions with refactoring advice and quality scores | -| Gemini | `gemini-code-assist[bot]` | Code review with inline suggestions and summary | - -**Fetch all comments (bots + humans):** -```bash -# Top-level PR comments (summaries, discussion) -gh api repos/{owner}/{repo}/issues/{pr}/comments - -# Inline review comments (line-specific suggestions from all reviewers) -gh api repos/{owner}/{repo}/pulls/{pr}/comments - -# Review threads with verdicts -gh api repos/{owner}/{repo}/pulls/{pr}/reviews - -# Human review requests with changes requested -gh pr view $PR_NUMBER --json reviews --jq '.reviews[] | select(.state == "CHANGES_REQUESTED")' -``` - -Both AI bot suggestions and human reviewer feedback are processed. AI bot comments are parsed for structured suggestions; human comments are read as instructions and addressed with code understanding. - -#### Step C: Check for Merge Conflicts -```bash -# Fetch latest base branch -git fetch origin $(gh pr view --json baseRefName --jq '.baseRefName') - -# Check if merge is possible -git merge-tree $(git merge-base HEAD origin/main) HEAD origin/main -``` - -If conflicts exist: -1. Attempt automatic resolution -2. If auto-resolution fails, analyze conflict markers and resolve using code understanding -3. Commit resolution - -#### Step D: Apply Fixes from ALL Review Suggestions -For each unresolved review comment (bot or human): -1. Parse the file path and line number from the comment -2. Read the suggested change or instruction -3. For bot comments: extract structured suggestions (code blocks, diffs) -4. For human comments: read the instruction and apply using code understanding -5. Apply the fix intelligently (understand intent, don't blindly replace) -6. Validate fix (run tests, lint checks if applicable) -7. Track the fix in effort report - -**Auto-integrate suggestions from other agents:** -- Monitor for comments from other AI agents (autofix agents, ML agents) -- Parse structured fix suggestions from agent comments -- Apply verified, safe suggestions automatically -- Flag suspicious or conflicting suggestions for manual review - -#### Step E: Commit and Push -```bash -git add -A -git commit -m "fix(pr): address review bot suggestions - -- Applied N fixes from CodeRabbit/Sourcery/Gemini -- Resolved merge conflicts (if any) - -Co-Authored-By: duyetbot <duyetbot@users.noreply.github.com>" - -git push -``` - -#### Step F: Check Completion -Exit loop if: -- CI passes (all green) AND no unresolved review comments → ready to merge -- Max iterations reached → report and stop -- Critical error → report and stop - -### 3. Smart Merge Logic - -#### Detect Auto-Merge Status -```bash -# Check if auto-merge is enabled and what merge strategy -gh api repos/{owner}/{repo}/pulls/{pr_number} --jq '.autoMerge' - -# Possible states: -# - enabled: auto-merge queued (will merge when ready) -# - disabled: auto-merge off -# - conflicted: enabled but blocked by conflicts or checks -``` - -#### Merge Strategy (Priority Order) -1. **Auto-merge enabled & CI green** → Wait for auto-merge to complete (poll every 30s) -2. **Auto-merge enabled but stuck** → Use `--force-merge` to manually trigger API merge -3. **Auto-merge disabled** → Use direct `gh pr merge` command -4. **Merge conflicts** → Resolve conflicts, push, then retry merge - -#### Force Merge (for stuck auto-merge) -```bash -# If auto-merge is enabled but not progressing, trigger via API -gh api repos/{owner}/{repo}/pulls/{pr_number}/merge \ - --input - <<EOF -{ - "commit_title": "Merge PR #{pr_number}", - "commit_message": "Merged via babysit-pr auto-merge handler", - "merge_method": "squash", - "sha": "$(git rev-parse HEAD)" -} -EOF -``` - -#### Fallback: Simple Direct Merge -```bash -gh pr merge $PR_NUMBER --squash --delete-branch -``` - -### 4. Effort Report - -Print summary at completion: - -``` -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ -PR #123: Feature title -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - -Automation Summary: - Iterations: 3 - Review fixes applied: 7 - CodeRabbit: 4 - Sourcery: 2 - Gemini: 1 - Other agents: 0 - CI fixes applied: 2 - Linting fixes: 1 - Type fixes: 1 - Conflicts resolved: 1 - Total duration: 12m 34s - -Result: ✅ Merged successfully - Auto-merge status: Handled via API (auto-merge was stuck) -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ -``` - -## Exit Conditions - -The loop exits when: -- ✅ CI passes (all green) AND all review suggestions (bot + human) addressed → merge (if `--auto-merge`) -- ✅ Auto-merge successfully triggered or manually merged -- ⚠️ Max iterations reached → report status and stop -- ⚠️ Unresolvable conflict or critical error → report and stop -- ⚠️ Manual interrupt (Ctrl+C) - -## Supported Review Bots - -### CodeRabbit (`coderabbitai[bot]`) -- Posts a summary comment with overall review -- Leaves inline comments on specific lines with code suggestions -- Uses collapsible sections for detailed analysis -- Suggestions often include replacement code blocks - -### Sourcery (`sourcery-ai[bot]`) -- Posts inline suggestions with refactoring advice -- Provides quality metrics (complexity, readability) -- Suggestions include "before" and "after" code -- Labels suggestions by type: bug, refactoring, style - -### Gemini (`gemini-code-assist[bot]`) -- Posts review summary with severity levels -- Leaves inline comments with suggested fixes -- Groups findings by category (security, performance, style) - -## Examples - -### Basic babysit (watch and address reviews) -```bash -# On a feature branch with an open PR -git checkout feat/new-feature -/github:babysit-pr -``` - -### Babysit with auto-fix CI and merge -```bash -/github:babysit-pr --auto-merge --fix-ci -``` - -### Force merge stuck auto-merge -```bash -# Repo has auto-merge enabled but it's stuck/not progressing -/github:babysit-pr --auto-merge --force-merge ``` - -### Babysit specific PR with aggressive CI fixing -```bash -/github:babysit-pr --pr 456 --max-iterations 5 --fix-ci --auto-merge -``` - -### Preview mode (dry-run) -```bash -/github:babysit-pr --dry-run -``` - -### Long CI timeout (for slow repos) -```bash -/github:babysit-pr --auto-merge --fix-ci --ci-timeout 45 +/github:babysit-pr [--pr <number>] [--auto-merge] [--max-iterations <n>] [--ci-timeout <minutes>] [--dry-run] ``` -## Continuous Monitoring with /loop +Defaults: the current branch's PR, 10 iterations, 15 minute CI timeout. Without `--auto-merge`, stop at merge-ready and report. -For long-running PRs, combine with `/loop` for periodic checks: - -```bash -# Check every 10 minutes, auto-fix CI and auto-merge when ready -/loop 10m /github:babysit-pr --auto-merge --fix-ci - -# Check every 5 minutes for a specific PR, with force-merge for stuck auto-merge -/loop 5m /github:babysit-pr --pr 123 --auto-merge --force-merge - -# Check every 3 minutes with aggressive CI fixing and extended timeout -/loop 3m /github:babysit-pr --auto-merge --fix-ci --ci-timeout 30 -``` +## Loop -## Troubleshooting +Refuse to run on the default branch or with uncommitted changes. Then repeat up to the iteration limit. -### Auto-merge is enabled but PR won't merge -- Use `--force-merge` flag to manually trigger merge via API -- Check if all required status checks are passing -- Verify branch protection rules aren't blocking merge -- Check if there are dismissed reviews blocking merge +1. Wait for CI to finish, plus a short grace period for review bots to post. +2. For each failing check, read the failed logs (`gh run view <id> --log-failed`), fix the root cause, and run the failing check locally before pushing. +3. Fetch every review comment: `gh api repos/{owner}/{repo}/pulls/{pr}/comments`, `.../issues/{pr}/comments`, and `gh pr view --json reviews`. See the `review-bots` skill for bot formats. Apply actionable ones. Skip a suggestion that is wrong or out of scope and say why in a reply. +4. Merge the base branch if the PR conflicts and resolve conflicts by intent, not by taking one side. +5. Commit with a semantic message and push. Never force-push to a shared branch. +6. Stop when CI is green with nothing unresolved, or when the limit is reached. On the limit, report what is still failing. -### CI keeps failing on same issue -- Use `--fix-ci` to enable automatic CI failure analysis and fixing -- Check CI logs: `gh run view {run_id} --log` -- Some CI failures may require manual investigation +## Merge -### Conflicts keep appearing -- Ensure base branch is fully fetched: `git fetch origin main` -- Rebase before pushing fixes: `git rebase origin/main` -- Check for competing changes from other contributors +Only with `--auto-merge`. If repo auto-merge is already queued, wait for it. Otherwise `gh pr merge --squash --delete-branch`. Never use `--admin` unless the user asks. -## Related Commands +## Report -- `/github:watch-and-fix` - Simpler CI-focused watch loop (no bot parsing) -- `/fix:and-update-pr` - Single-iteration fix and push -- `/github:bulk-merge-prs` - Merge multiple approved PRs +End with iterations used, fixes applied, conflicts resolved, elapsed time, and the final PR state. diff --git a/github/commands/review-and-merge.md b/github/commands/review-and-merge.md index 311dfdd..3fb9898 100644 --- a/github/commands/review-and-merge.md +++ b/github/commands/review-and-merge.md @@ -68,7 +68,7 @@ Spawn an agent per PR: - Read the affected files - Fix ALL issues raised - Run build verification (`bun run build` or project-specific) -- Commit with semantic format + co-authorship +- Commit with semantic format - Push changes #### Category B: Investigate Build Failures @@ -112,10 +112,10 @@ gh pr merge <number> --squash --admin \ ``` Known failures to ignore: -- `Workers Builds` — always fails on non-main branches -- `e2e-test` — cancelled/flaky -- `unit-tests` — known Jest hanging issue -- `claude-review` — config issues +- `Workers Builds` - always fails on non-main branches +- `e2e-test` - cancelled/flaky +- `unit-tests` - known Jest hanging issue +- `claude-review` - config issues ### Phase 3: Post-Fix Verification @@ -168,12 +168,9 @@ When multiple PRs modify the same files: - Limit to 3-4 concurrent agents to avoid OOM on builds - Each agent: checkout → fix → build → commit → push -### Commit Convention +### Commit convention -All fix commits must include: -``` -Co-Authored-By: duyetbot <duyetbot@users.noreply.github.com> -``` +Use semantic commit messages for fix commits. ### Safety diff --git a/github/commands/watch-and-fix.md b/github/commands/watch-and-fix.md index 6783044..7802144 100644 --- a/github/commands/watch-and-fix.md +++ b/github/commands/watch-and-fix.md @@ -1,138 +1,8 @@ --- -allowed-tools: Bash(git *), Bash(gh *) -description: Watch a PR, fix issues from AI reviews, and auto-merge when ready +allowed-tools: Bash(git *), Bash(gh *), Read, Edit, Write, Glob, Grep, Agent +description: Alias for babysit-pr, kept for existing users --- -# Watch and Fix PR +# Watch and fix PR -Watch a pull request, automatically fix issues identified in AI reviews, and merge when all checks pass. - -## Usage - -```bash -/github:watch-and-fix -/github:watch-and-fix --auto-merge -/github:watch-and-fix --max-iterations 5 -/github:watch-and-fix --dry-run -``` - -## Options - -- `--auto-merge`: Automatically merge PR when CI passes and reviews are approved -- `--max-iterations <n>`: Maximum fix iterations (default: 10) -- `--dry-run`: Preview what would happen without making changes -- `--pr <number>`: Specific PR number (default: current branch's PR) - -## How It Works - -### 1. Initial Check -- Verifies we're on a feature branch (not main/master) -- Finds the PR for current branch -- Checks initial CI status and review state - -### 2. Watch Loop -For each iteration (max `--max-iterations`): - -1. **Wait for CI**: Polls workflow run status until completion -2. **Check reviews**: Gets latest review comments from AI agents -3. **Parse issues**: Extracts fixable issues from review comments -4. **Fix issues**: Applies fixes based on review feedback -5. **Commit and push**: Commits fixes with semantic message -6. **Repeat**: Goes back to step 1 - -### 3. Completion -- **If CI passes AND approved**: Optionally merges (with `--auto-merge`) -- **If max iterations reached**: Reports status and stops -- **If no fixable issues found**: Reports and waits - -## Review Comment Format - -AI agents should format comments in a way that can be parsed: - -```markdown -## Issues Found - -### path/to/file.ts:45 -- **Type**: type-error -- **Message**: Variable 'foo' is implicitly any -- **Fix**: Add type annotation: `const foo: string = ...` - -### src/api/index.ts:123 -- **Type**: lint-error -- **Message**: Missing error handling -- **Fix**: Wrap in try-catch block -``` - -## Exit Conditions - -The loop exits when: -- ✅ CI passes AND PR is approved (merges if `--auto-merge`) -- ⚠️ Max iterations reached -- ⚠️ No fixable issues found but CI still failing -- ⚠️ Manual interrupt (Ctrl+C) - -## Examples - -### Basic watch and fix -```bash -# On a feature branch with an open PR -git checkout feat/new-feature -/github:watch-and-fix -``` - -### Watch and auto-merge when ready -```bash -# Will merge automatically when CI passes and approved -/github:watch-and-fix --auto-merge -``` - -### Limited iterations -```bash -# Try at most 3 times to fix issues -/github:watch-and-fix --max-iterations 3 -``` - -### Preview mode -```bash -# See what would be fixed without making changes -/github:watch-and-fix --dry-run -``` - -## Implementation Notes - -### CI Status Polling -```bash -# Get latest workflow run -RUN_ID=$(gh run list --workflow=ci.yml --branch $BRANCH --limit 1 --json databaseId --jq '.[0].databaseId') - -# Watch the run -gh run watch "$RUN_ID" - -# Check final status -STATUS=$(gh run view "$RUN_ID" --json conclusion --jq '.conclusion') -``` - -### Getting Review Comments -```bash -# Get all review comments -gh pr view $PR_NUMBER --json comments --jq '.comments[] | select(.author.type == "Bot")' -``` - -### Fix Application -```bash -# Parse comment and apply fix -# This is handled by the fix:and-push skill -``` - -## Permissions - -Requires: -- `repo` scope for gh CLI -- Write access to push commits -- Write access to merge PRs (if using `--auto-merge`) - -## Related Commands - -- `/fix:and-update-pr` - Fix issues and update existing PR (single iteration) -- `/fix:and-create-pr` - Fix issues and create new PR -- `/github:bulk-merge-prs` - Merge multiple approved PRs +This command is an alias. Follow `commands/babysit-pr.md` in this plugin with the same arguments: `--pr`, `--auto-merge`, `--max-iterations`, `--dry-run`. diff --git a/github/examples/babysit-pr.sh b/github/examples/babysit-pr.sh deleted file mode 100755 index 5911f94..0000000 --- a/github/examples/babysit-pr.sh +++ /dev/null @@ -1,256 +0,0 @@ -#!/bin/bash -# Babysit PR - Monitor, fix review bot suggestions, resolve conflicts, merge -# Usage: ./babysit-pr.sh [--auto-merge] [--max-iterations N] [--dry-run] [--pr NUMBER] -# shellcheck disable=SC2034 - -set -euo pipefail - -# Default values -AUTO_MERGE=false -MAX_ITERATIONS=10 -DRY_RUN=false -PR_NUMBER="" -FIXES_APPLIED=0 -CONFLICTS_RESOLVED=0 -CODERABBIT_FIXES=0 -SOURCERY_FIXES=0 -GEMINI_FIXES=0 -START_TIME=$(date +%s) - -# Bot username patterns -BOT_PATTERN="coderabbitai\[bot\]|sourcery-ai\[bot\]|gemini-code-assist\[bot\]" - -# Parse arguments -while [[ $# -gt 0 ]]; do - case $1 in - --auto-merge) AUTO_MERGE=true ;; - --max-iterations) MAX_ITERATIONS="$2"; shift ;; - --dry-run) DRY_RUN=true ;; - --pr) PR_NUMBER="$2"; shift ;; - *) echo "Unknown option: $1"; exit 1 ;; - esac - shift -done - -# Get repository info -OWNER=$(gh repo view --json owner --jq '.owner.login') -REPO=$(gh repo view --json name --jq '.name') - -# Get current branch -BRANCH=$(git branch --show-current) -DEFAULT_BRANCH=$(git remote show origin 2>/dev/null | grep 'HEAD branch' | cut -d' ' -f5 || echo "main") - -# Check we're not on main/master -if [ "$BRANCH" = "$DEFAULT_BRANCH" ] || [ "$BRANCH" = "master" ] || [ "$BRANCH" = "main" ]; then - echo "Error: On default branch ($BRANCH). Switch to a feature branch first." - exit 1 -fi - -# Find PR if not specified -if [ -z "$PR_NUMBER" ]; then - PR_NUMBER=$(gh pr list --head "$BRANCH" --json number --jq '.[0].number' 2>/dev/null || echo "") - if [ -z "$PR_NUMBER" ]; then - echo "Error: No PR found for branch $BRANCH" - exit 1 - fi -fi - -PR_TITLE=$(gh pr view "$PR_NUMBER" --json title --jq '.title' 2>/dev/null || echo "Unknown") - -echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" -echo "Babysitting PR #$PR_NUMBER: $PR_TITLE" -echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" -echo "Branch: $BRANCH" -echo "Max iterations: $MAX_ITERATIONS" -echo "Auto-merge: $AUTO_MERGE" -echo "Dry run: $DRY_RUN" -echo - -# Function: fetch all review comments (bots + humans) -fetch_review_comments() { - # Inline review comments from all reviewers (line-specific suggestions) - local inline_comments - inline_comments=$(gh api "repos/$OWNER/$REPO/pulls/$PR_NUMBER/comments" \ - --jq "[.[] | { - author: .user.login, - is_bot: (.user.type == \"Bot\"), - path: .path, - line: (.line // .original_line // 0), - body: .body, - id: .id - }]" 2>/dev/null || echo "[]") - - echo "$inline_comments" -} - -# Function: check for merge conflicts -check_conflicts() { - local mergeable - mergeable=$(gh pr view "$PR_NUMBER" --json mergeable --jq '.mergeable' 2>/dev/null || echo "UNKNOWN") - echo "$mergeable" -} - -# Function: count bot-specific fixes -track_fix() { - local bot="$1" - FIXES_APPLIED=$((FIXES_APPLIED + 1)) - case "$bot" in - *coderabbit*) CODERABBIT_FIXES=$((CODERABBIT_FIXES + 1)) ;; - *sourcery*) SOURCERY_FIXES=$((SOURCERY_FIXES + 1)) ;; - *gemini*) GEMINI_FIXES=$((GEMINI_FIXES + 1)) ;; - esac -} - -# Function: print effort report -print_report() { - local end_time result - end_time=$(date +%s) - local duration=$((end_time - START_TIME)) - local minutes=$((duration / 60)) - local seconds=$((duration % 60)) - result="${1:-Stopped}" - - echo - echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" - echo "PR #$PR_NUMBER: $PR_TITLE" - echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" - echo - echo "Effort Summary:" - echo " Iterations: $iteration" - echo " Fixes applied: $FIXES_APPLIED" - if [ "$CODERABBIT_FIXES" -gt 0 ]; then - echo " CodeRabbit: $CODERABBIT_FIXES" - fi - if [ "$SOURCERY_FIXES" -gt 0 ]; then - echo " Sourcery: $SOURCERY_FIXES" - fi - if [ "$GEMINI_FIXES" -gt 0 ]; then - echo " Gemini: $GEMINI_FIXES" - fi - echo " Conflicts resolved: $CONFLICTS_RESOLVED" - echo " Total duration: ${minutes}m ${seconds}s" - echo - echo "Result: $result" - echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" -} - -# Main babysit loop -for iteration in $(seq 1 "$MAX_ITERATIONS"); do - echo "--- Iteration $iteration/$MAX_ITERATIONS ---" - - # Step A: Wait for CI to complete - echo "Checking CI status..." - RUN_ID=$(gh run list --branch "$BRANCH" --limit 1 --json databaseId,status --jq '.[0].databaseId' 2>/dev/null || echo "") - - if [ -n "$RUN_ID" ]; then - RUN_STATUS=$(gh run view "$RUN_ID" --json status --jq '.status' 2>/dev/null || echo "unknown") - - if [ "$RUN_STATUS" = "in_progress" ] || [ "$RUN_STATUS" = "queued" ]; then - echo "CI running (run #$RUN_ID), waiting..." - gh run watch "$RUN_ID" --interval 10 2>/dev/null || true - fi - - CONCLUSION=$(gh run view "$RUN_ID" --json conclusion --jq '.conclusion' 2>/dev/null || echo "unknown") - echo "CI conclusion: $CONCLUSION" - else - CONCLUSION="unknown" - echo "No CI run found." - fi - - # Give review bots time to post after CI - echo "Waiting for review bots..." - sleep 15 - - # Step B: Fetch all review comments (bots + humans) - echo "Fetching review comments..." - REVIEW_COMMENTS=$(fetch_review_comments) - COMMENT_COUNT=$(echo "$REVIEW_COMMENTS" | jq 'length' 2>/dev/null || echo "0") - BOT_COUNT=$(echo "$REVIEW_COMMENTS" | jq '[.[] | select(.is_bot)] | length' 2>/dev/null || echo "0") - HUMAN_COUNT=$(echo "$REVIEW_COMMENTS" | jq '[.[] | select(.is_bot | not)] | length' 2>/dev/null || echo "0") - echo "Found $COMMENT_COUNT review comments ($BOT_COUNT from bots, $HUMAN_COUNT from humans)." - - # Step C: Check for merge conflicts - echo "Checking for merge conflicts..." - MERGEABLE=$(check_conflicts) - echo "Mergeable status: $MERGEABLE" - - if [ "$MERGEABLE" = "CONFLICTING" ]; then - echo "⚠️ Merge conflicts detected." - if [ "$DRY_RUN" = true ]; then - echo "[DRY RUN] Would resolve merge conflicts" - else - echo "Fetching base branch and resolving..." - BASE_BRANCH=$(gh pr view "$PR_NUMBER" --json baseRefName --jq '.baseRefName') - git fetch origin "$BASE_BRANCH" - - if git merge --no-commit --no-ff "origin/$BASE_BRANCH" 2>/dev/null; then - git commit -m "fix(pr): resolve merge conflicts with $BASE_BRANCH - -Co-Authored-By: duyetbot <duyetbot@users.noreply.github.com>" - git push - CONFLICTS_RESOLVED=$((CONFLICTS_RESOLVED + 1)) - echo "✅ Conflicts resolved." - else - echo "⚠️ Auto-resolution failed. Manual intervention needed." - git merge --abort 2>/dev/null || true - print_report "❌ Failed - unresolvable merge conflict" - exit 1 - fi - fi - fi - - # Step D: Check if PR is ready to merge - REVIEW_STATE=$(gh pr view "$PR_NUMBER" --json reviewDecision --jq '.reviewDecision // "PENDING"' 2>/dev/null || echo "PENDING") - echo "Review state: $REVIEW_STATE" - - if [ "$CONCLUSION" = "success" ] && [ "$COMMENT_COUNT" = "0" ]; then - echo "✅ CI passed and no pending review bot comments!" - - if [ "$AUTO_MERGE" = true ]; then - if [ "$DRY_RUN" = true ]; then - echo "[DRY RUN] Would merge PR #$PR_NUMBER" - print_report "✅ Ready to merge (dry run)" - else - echo "Merging PR #$PR_NUMBER..." - gh pr merge "$PR_NUMBER" --squash --delete-branch - print_report "✅ Merged successfully" - fi - else - print_report "✅ Ready to merge (use --auto-merge to merge automatically)" - fi - exit 0 - fi - - # Step E: Process all review suggestions (bots + humans) - if [ "$COMMENT_COUNT" != "0" ]; then - echo "Processing review suggestions..." - - if [ "$DRY_RUN" = true ]; then - echo "[DRY RUN] Would process $COMMENT_COUNT suggestions:" - echo "$REVIEW_COMMENTS" | jq -r '.[] | " \(.author): \(.path):\(.line)"' 2>/dev/null || true - print_report "✅ Preview complete (dry run)" - exit 0 - fi - - # Display all suggestions for the fix skill to process - echo "Review suggestions to address:" - echo "$REVIEW_COMMENTS" | jq -r '.[] | "[\(.author)] \(.path):\(.line)\n\(.body)\n---"' 2>/dev/null || true - echo - echo "Applying fixes using /fix:and-update-pr..." - # The Claude agent will process these suggestions and apply fixes - # This script serves as reference — actual fix application happens via the skill - echo "Use /github:babysit-pr command for full automation with Claude agent." - fi - - # If CI failed with no bot comments, wait and retry - if [ "$CONCLUSION" = "failure" ] && [ "$COMMENT_COUNT" = "0" ]; then - echo "⚠️ CI failed but no review bot suggestions found." - echo "Waiting 30 seconds before retry..." - sleep 30 - fi - - echo -done - -print_report "⚠️ Reached max iterations ($MAX_ITERATIONS)" -exit 1 diff --git a/github/examples/bulk-close-issues.sh b/github/examples/bulk-close-issues.sh deleted file mode 100644 index 6208539..0000000 --- a/github/examples/bulk-close-issues.sh +++ /dev/null @@ -1,41 +0,0 @@ -#!/bin/bash -# Example: Bulk close issues by label -# Usage: ./bulk-close-issues.sh <label> [dry-run] - -LABEL="${1:-stale}" -DRY_RUN="${2:-}" - -echo "Finding issues with label: $LABEL" - -# List issues to be affected -ISSUES=$(gh issue list --label "$LABEL" --limit 100 --json number --jq '.[].number') - -if [ -z "$ISSUES" ]; then - echo "No issues found with label: $LABEL" - exit 0 -fi - -ISSUE_COUNT=$(echo "$ISSUES" | wc -l) -echo "Found $ISSUE_COUNT issues" - -if [ "$DRY_RUN" = "--dry-run" ]; then - echo "DRY RUN - Would close the following issues:" - gh issue list --label "$LABEL" --limit 100 - exit 0 -fi - -# Confirm -read -p "Close $ISSUE_COUNT issues? (y/N) " -n 1 -r -echo -if [[ ! $REPLY =~ ^[Yy]$ ]]; then - echo "Aborted" - exit 1 -fi - -# Close each issue -for issue in $ISSUES; do - echo "Closing issue #$issue" - gh issue close "$issue" --comment "Closing as $LABEL" -done - -echo "Closed $ISSUE_COUNT issues" diff --git a/github/examples/bulk-merge-prs.sh b/github/examples/bulk-merge-prs.sh deleted file mode 100644 index f27ecd0..0000000 --- a/github/examples/bulk-merge-prs.sh +++ /dev/null @@ -1,38 +0,0 @@ -#!/bin/bash -# Example: Bulk merge approved PRs -# Usage: ./bulk-merge-prs.sh [dry-run] - -echo "Finding approved and passing PRs..." - -# List PRs that are approved and have passing CI -PRS=$(gh pr list --search "review:approved status:success" --limit 50 --json number,title --jq '.[] | "\(.number)|\(.title)"') - -if [ -z "$PRS" ]; then - echo "No approved PRs with passing CI found" - exit 0 -fi - -PR_COUNT=$(echo "$PRS" | wc -l) -echo "Found $PR_COUNT PRs:" -echo "$PRS" - -if [ "$1" = "--dry-run" ]; then - echo "DRY RUN - Would merge the PRs listed above" - exit 0 -fi - -# Confirm -read -p "Merge $PR_COUNT PRs with squash? (y/N) " -n 1 -r -echo -if [[ ! $REPLY =~ ^[Yy]$ ]]; then - echo "Aborted" - exit 1 -fi - -# Merge each PR -echo "$PRS" | while IFS='|' read -r number title; do - echo "Merging PR #$number: $title" - gh pr merge "$number" --squash --delete-branch -done - -echo "Merged $PR_COUNT PRs" diff --git a/github/examples/pr-automation.sh b/github/examples/pr-automation.sh deleted file mode 100644 index 21e4e05..0000000 --- a/github/examples/pr-automation.sh +++ /dev/null @@ -1,76 +0,0 @@ -#!/bin/bash -# Example: PR automation - auto-label and auto-assign -# This script demonstrates PR triage automation - -# Auto-label based on changed files -label_pr() { - local pr_number=$1 - - # Get changed files - FILES=$(gh pr diff "$pr_number" --name-only) - - # Label based on file patterns - if echo "$FILES" | grep -q "^src/api/"; then - gh pr edit "$pr_number" --add-label "area:api" - fi - - if echo "$FILES" | grep -q "^tests/"; then - gh pr edit "$pr_number" --add-label "area:tests" - fi - - if echo "$FILES" | grep -q "\.md$"; then - gh pr edit "$pr_number" --add-label "documentation" - fi - - # Check for breaking changes - if echo "$FILES" | grep -q "BREAKING CHANGE"; then - gh pr edit "$pr_number" --add-label "breaking" - fi -} - -# Auto-assign based on code ownership -assign_reviewers() { - local pr_number=$1 - - # Get changed files - FILES=$(gh pr diff "$pr_number" --name-only) - - # Assign based on file ownership (simplified) - # In practice, use CODEOWNERS file parsing - if echo "$FILES" | grep -q "^src/frontend/"; then - gh pr edit "$pr_number" --add-reviewer "frontend-team" - fi - - if echo "$FILES" | grep -q "^src/backend/"; then - gh pr edit "$pr_number" --add-reviewer "backend-team" - fi -} - -# Welcome first-time contributors -welcome_contributor() { - local pr_number=$1 - - AUTHOR=$(gh pr view "$pr_number" --json author --jq '.author.login') - - # Check if this is their first PR - PR_COUNT=$(gh pr list --author "$AUTHOR" --limit 1 --json number --jq 'length') - - if [ "$PR_COUNT" -eq 1 ]; then - gh pr comment "$pr_number" --body "Welcome! Thanks for your first contribution! 🎉" - gh pr edit "$pr_number" --add-label "first-time-contributor" - fi -} - -# Main script -PR_NUMBER="${1:-}" - -if [ -z "$PR_NUMBER" ]; then - echo "Usage: $0 <pr-number>" - exit 1 -fi - -echo "Processing PR #$PR_NUMBER..." -label_pr "$PR_NUMBER" -assign_reviewers "$PR_NUMBER" -welcome_contributor "$PR_NUMBER" -echo "Done!" diff --git a/github/examples/watch-and-fix.sh b/github/examples/watch-and-fix.sh deleted file mode 100755 index 1fd9ac5..0000000 --- a/github/examples/watch-and-fix.sh +++ /dev/null @@ -1,138 +0,0 @@ -#!/bin/bash -# Watch and Fix PR - Automated fix loop for GitHub PRs -# Usage: ./watch-and-fix.sh [--auto-merge] [--max-iterations N] [--dry-run] [--pr NUMBER] - -set -euo pipefail - -# Default values -AUTO_MERGE=false -MAX_ITERATIONS=10 -DRY_RUN=false -PR_NUMBER="" - -# Parse arguments -while [[ $# -gt 0 ]]; do - case $1 in - --auto-merge) AUTO_MERGE=true ;; - --max-iterations) MAX_ITERATIONS="$2"; shift ;; - --dry-run) DRY_RUN=true ;; - --pr) PR_NUMBER="$2"; shift ;; - *) echo "Unknown option: $1"; exit 1 ;; - esac - shift -done - -# Get current branch -BRANCH=$(git branch --show-current) -DEFAULT_BRANCH=$(git remote show origin | grep 'HEAD branch' | cut -d' ' -f5) - -# Check we're not on main/master -if [ "$BRANCH" = "$DEFAULT_BRANCH" ] || [ "$BRANCH" = "master" ] || [ "$BRANCH" = "main" ]; then - echo "Error: On default branch ($BRANCH). Switch to a feature branch first." - exit 1 -fi - -# Find PR if not specified -if [ -z "$PR_NUMBER" ]; then - PR_NUMBER=$(gh pr list --head "$BRANCH" --json number --jq '.[0].number') - if [ -z "$PR_NUMBER" ]; then - echo "Error: No PR found for branch $BRANCH" - exit 1 - fi -fi - -echo "=== Watch and Fix PR #$PR_NUMBER ===" -echo "Branch: $BRANCH" -echo "Max iterations: $MAX_ITERATIONS" -echo "Auto-merge: $AUTO_MERGE" -echo "Dry run: $DRY_RUN" -echo - -# Main fix loop -for iteration in $(seq 1 "$MAX_ITERATIONS"); do - echo "--- Iteration $iteration/$MAX_ITERATIONS ---" - - # Get latest CI run - echo "Waiting for CI to complete..." - RUN_ID=$(gh run list --workflow=ci.yml --branch "$BRANCH" --limit 1 --json databaseId --jq '.[0].databaseId' 2>/dev/null || echo "") - - if [ -n "$RUN_ID" ]; then - echo "Watching CI run #$RUN_ID..." - gh run watch "$RUN_ID" --interval 10 || true - - # Check CI status - CONCLUSION=$(gh run view "$RUN_ID" --json conclusion --jq '.conclusion' 2>/dev/null || echo "unknown") - STATUS=$(gh run view "$RUN_ID" --json status --jq '.status' 2>/dev/null || echo "unknown") - - echo "CI Status: $STATUS" - echo "CI Conclusion: $CONCLUSION" - else - echo "No CI run found, checking PR status..." - fi - - # Get PR review status - REVIEW_STATE=$(gh pr view "$PR_NUMBER" --json reviewDecision --jq '.reviewDecision // "PENDING"') - echo "Review State: $REVIEW_STATE" - - # Check if we can merge - if [ "$CONCLUSION" = "success" ] && { [ "$REVIEW_STATE" = "APPROVED" ] || [ "$REVIEW_STATE" = "NULL" ]; }; then - echo "✅ CI passed and reviews approved!" - if [ "$AUTO_MERGE" = true ]; then - if [ "$DRY_RUN" = true ]; then - echo "[DRY RUN] Would merge PR #$PR_NUMBER" - else - echo "Merging PR #$PR_NUMBER..." - gh pr merge "$PR_NUMBER" --squash --delete-branch - echo "✅ PR merged successfully!" - fi - else - echo "PR is ready to merge. Use '--auto-merge' to merge automatically." - fi - exit 0 - fi - - # Get review comments - echo "Fetching review comments..." - COMMENTS=$(gh pr view "$PR_NUMBER" --json comments -q '.comments[] | select(.author.type == "Bot" or .authorAssociation == "OWNER") | [.path, .line, .body] | @tsv' 2>/dev/null || echo "") - - if [ -z "$COMMENTS" ]; then - echo "No review comments found." - - # If CI is still failing but no comments, we can't fix - if [ "$CONCLUSION" = "failure" ]; then - echo "⚠️ CI failed but no fixable issues found in comments." - echo "Waiting 30 seconds before retry..." - sleep 30 - continue - fi - - # If just waiting for review, wait longer - echo "Waiting for reviews..." - sleep 60 - continue - fi - - echo "Found review comments:" - echo "$COMMENTS" - echo - - # In dry-run mode, just show what we would do - if [ "$DRY_RUN" = true ]; then - echo "[DRY RUN] Would fix issues based on comments above" - exit 0 - fi - - # Apply fixes using the fix skill - echo "Applying fixes..." - # Invoke fix:and-update-pr to address review comments - # For full review-bot-aware automation, use /github:babysit-pr instead - echo "Use '/fix:and-update-pr' to apply fixes, or '/github:babysit-pr' for full automation." - - # After fixes, the loop continues - echo "Waiting for CI to restart..." - sleep 10 -done - -echo "⚠️ Reached max iterations ($MAX_ITERATIONS) without completion." -echo "Current status:" -gh pr view "$PR_NUMBER" --json statusCheckRollup,reviewDecision --jq '.' diff --git a/github/skills/github.md b/github/skills/github.md deleted file mode 100644 index 9d43e17..0000000 --- a/github/skills/github.md +++ /dev/null @@ -1,596 +0,0 @@ ---- -description: >- - Comprehensive GitHub operations using the gh CLI tool. Supports pull requests, - issues, workflows/actions, releases, repositories, gists, and advanced - Git operations with full access to GitHub API through gh. ---- - -# GitHub Operations with gh CLI - -You are an expert in GitHub operations using the `gh` CLI tool. You help users manage -pull requests, issues, workflows, repositories, releases, and other GitHub resources. - -## Core Capabilities - -### Pull Request Management - -```bash -# List pull requests -gh pr list # List PRs in current repo -gh pr list --state closed # List closed PRs -gh pr list --author @me # List my PRs -gh pr list --assignee @me # List PRs assigned to me -gh pr list --label bug # List PRs with specific label -gh pr list --limit 100 # List more PRs -gh pr list --search "is:open is:pr" # Search PRs - -# View pull request details -gh pr view 123 # View PR #123 -gh pr view # View current branch's PR -gh pr view --json title,body,author # View specific fields as JSON -gh pr view --web # Open PR in browser - -# Create pull request -gh pr create --title "Fix bug" --body "Description" --base main -gh pr create --draft # Create draft PR -gh pr create --assignee @me --label "enhancement" -gh pr create --reviewer user1,user2 - -# Checkout pull request -gh pr checkout 123 # Checkout PR #123 - -# Edit pull request -gh pr edit 123 --title "New title" -gh pr edit 123 --add-label "bug" --remove-label "help wanted" - -# Comment on pull request -gh pr comment 123 --body "LGTM!" -gh pr review 123 --approve # Approve PR -gh pr review 123 --request-changes # Request changes -gh pr review 123 --comment -F file.md # Review with comments from file - -# Merge pull request -gh pr merge 123 --merge # Merge with merge commit -gh pr merge 123 --squash # Squash merge -gh pr merge 123 --rebase # Rebase merge -gh pr merge 123 --delete-branch # Merge and delete branch - -# Close/reopen pull request -gh pr close 123 # Close PR -gh pr reopen 123 # Reopen PR - -# Diff and patches -gh pr diff 123 # View PR diff -gh pr diff 123 --color=never # Diff without color -``` - -### Issue Management - -```bash -# List issues -gh issue list # List open issues -gh issue list --state all # List all issues -gh issue list --author @me # List my issues -gh issue list --assignee @me # List issues assigned to me -gh issue list --label "bug,urgent" # List with labels -gh issue list --limit 50 - -# View issue details -gh issue view 456 # View issue #456 -gh issue view --json title,body,comments,labels -gh issue view --web - -# Create issue -gh issue create --title "Bug found" --body "Steps to reproduce" -gh issue create --label "bug,high-priority" -gh issue create --assignee @me - -# Edit issue -gh issue edit 456 --title "Updated title" -gh issue edit 456 --add-label "confirmed" --remove-label "needs-triage" - -# Comment on issue -gh issue comment 456 --body "Working on this" - -# Close/reopen issue -gh issue close 456 -gh issue reopen 456 - -# Transfer issue to another repo -gh issue transfer 456 owner/repo -``` - -### GitHub Actions & Workflows - -```bash -# List workflow runs -gh run list # List recent workflow runs -gh run list --limit 50 # List more runs -gh run list --workflow=ci.yml # List runs for specific workflow -gh run list --branch main # List runs for specific branch - -# View run details -gh run view 456 # View specific run -gh run view --log # View run with logs -gh run view --log-failed # View only failed logs -gh run view --web # Open in browser - -# Watch workflow run (follow logs in real-time) -gh run watch 456 # Watch run execution -gh run watch 456 --interval 2 # Watch with 2s interval - -# Rerun workflows -gh run rerun 456 # Rerun failed run -gh run rerun 456 --failed # Rerun only failed jobs - -# List workflows -gh workflow list # List all workflows - -# View workflow definition -gh workflow view ci.yml -gh workflow view ci.yml --web -gh workflow view ci.yml --yaml - -# Run workflow manually -gh workflow run ci.yml --raw-field delay=10 -gh workflow run deploy.yml --ref main - -# View artifact list -gh run view 456 --log-failed --json artifacts -``` - -### Repository Management - -```bash -# View repository info -gh repo view # View current repo -gh repo view owner/repo # View specific repo -gh repo view --json name,description,stars,forks - -# Create repository -gh repo create my-new-repo # Create new repo -gh repo create my-repo --public # Create public repo -gh repo create my-repo --source . # Create from current dir -gh repo create my-repo --clone # Create and clone - -# Clone repository -gh repo clone owner/repo # Clone repo -gh repo clone owner/repo my-dir # Clone to specific dir - -# Fork repository -gh repo fork owner/repo # Fork repo -gh repo fork owner/repo --clone # Fork and clone - -# View repository settings -gh repo view --web # Open repo in browser -gh repo settings # View repository settings - -# Archive/delete repository -gh repo delete owner/repo # Delete repo (requires confirmation) -``` - -### Release Management - -```bash -# List releases -gh release list # List releases - -# View release -gh release view v1.0.0 # View specific release -gh release view latest # View latest release -gh release view --web # Open in browser - -# Create release -gh release create v1.0.0 --notes "Release notes" -gh release create v1.0.0 --title "Version 1.0.0" -gh release create v1.0.0 --notes-from-tag -gh release create v1.0.0 --draft - -# Delete release -gh release delete v1.0.0 # Delete release (requires confirmation) - -# Upload assets -gh release upload v1.0.0 ./file.tar.gz -``` - -### Gist Management - -```bash -# List gists -gh gist list # List your gists -gh gist list --public # List public gists - -# View gist -gh gist view abc123 # View specific gist -gh gist view --web # Open in browser - -# Create gist -gh gist create file.py # Create gist from file -gh gist create file.py --desc "My gist" -gh gist create file.py --public # Create public gist - -# Edit gist -gh gist edit abc123 --desc "Updated description" - -# Delete gist -gh gist delete abc123 -``` - -### Git Operations via GitHub - -```bash -# Status and info -gh status # Show repo status - -# View and create commits -gh api /repos/owner/repo/commits # GitHub API call -gh commit list # List recent commits (needs extension) - -# Branch operations -gh repo sync # Sync fork with upstream -gh api /repos/owner/repo/branches # List branches via API -``` - -### Authentication & Configuration - -```bash -# Auth status -gh auth status # Check authentication - -# Login -gh auth login # Login to GitHub -gh auth login --with-token < token.txt - -# Logout -gh auth logout # Logout - -# Token management -gh auth token # Print auth token -gh auth refresh # Refresh auth token - -# Configuration -gh config set editor vim # Set editor -gh config set git_protocol ssh # Use SSH for git operations -gh config set prompt disabled # Disable interactive prompts -``` - -### Search & Discovery - -```bash -# Search repositories -gh search repos # Search repositories -gh search repos --language python # Search Python repos -gh search repos --stars >1000 # Search popular repos -gh search repos "topic:ai" # Search by topic - -# Search issues/PRs -gh search prs --state open # Search open PRs -gh search issues --label "bug" # Search issues by label - -# Search code -gh search code lambda # Search code in repos -``` - -### Advanced Operations - -```bash -# GitHub API calls -gh api /user # Get user info -gh api /repos/owner/repo/issues # Get issues via API -gh api /repos/owner/repo/issues -f title='New issue' -f body='Description' - -# JSON processing -gh pr view --json title,number,author | jq '.title' - -# Set default repository -gh repo set-default owner/repo # Set default for current dir - -# Template operations -gh repo create my-repo --template owner/template-repo -``` - -## Batch Operations - -The GitHub plugin includes commands for bulk operations: - -### Watch and Fix PR - -Automated fix loop for pull requests: - -```bash -# Watch PR, fix issues from AI reviews, auto-merge when ready -/github:watch-and-fix --auto-merge --max-iterations 5 - -# Preview what would happen -/github:watch-and-fix --dry-run - -# Watch specific PR -/github:watch-and-fix --pr 123 -``` - -The watch-and-fix command: -1. Waits for CI to complete -2. Gets review comments from AI agents -3. Parses and applies fixes -4. Commits and pushes changes -5. Repeats until CI passes and PR is approved -6. Optionally auto-merges when ready - -### Babysit PR - -Full PR lifecycle management with AI review bot integration: - -```bash -# Babysit current branch's PR -/github:babysit-pr - -# Babysit and auto-merge when ready -/github:babysit-pr --auto-merge - -# Babysit specific PR with limited iterations -/github:babysit-pr --pr 123 --max-iterations 5 - -# Preview mode -/github:babysit-pr --dry-run - -# Use with /loop for continuous monitoring -/loop 10m /github:babysit-pr --auto-merge -``` - -The babysit-pr command: -1. Waits for CI and review bots to post comments -2. Reads ALL review comments (CodeRabbit, Sourcery, Gemini, and human reviewers) -3. Parses bot-specific suggestion formats (code blocks, diffs, inline suggestions) -4. Checks for and resolves merge conflicts -5. Applies fixes using code understanding -6. Commits, pushes, and waits for next CI cycle -7. Repeats until CI passes and all suggestions addressed -8. Optionally auto-merges with effort report (iterations, fixes per bot, duration) - -### Bulk Close Issues - -```bash -# Close all issues with a specific label -/github:bulk-close-issues --label "wontfix" - -# Close with a comment -/github:bulk-close-issues --label "duplicate" --comment "Closing as duplicate" - -# Preview before closing -/github:bulk-close-issues --dry-run --label "stale" - -# Close by search query -/github:bulk-close-issues --search "updated:<2025-12-01" -``` - -### Bulk Merge PRs - -```bash -# Merge all PRs with ready-to-merge label -/github:bulk-merge-prs --label "ready-to-merge" - -# Merge approved PRs and delete branches -/github:bulk-merge-prs --reviewer-approved --method squash --delete-branch - -# Preview before merging -/github:bulk-merge-prs --dry-run --label "ready-to-merge" - -# Merge PRs with passing CI -/github:bulk-merge-prs --search "status:success review:approved" -``` - -### Bulk Label - -```bash -# Add label to all issues -/github:bulk-label --add "priority:high" --label "bug" - -# Remove label from items -/github:bulk-label --remove "status:triage" --search "reviewed-by:@me" - -# Add multiple labels -/github:bulk-label --add "area:backend" --add "needs-review" --type pr - -# Preview label changes -/github:bulk-label --dry-run --add "quarter-1" --search "created:>=2025-01-01" -``` - -## Best Practices - -1. **Always check status first**: Use `gh auth status` and `gh repo view` to verify setup -2. **Use flags for automation**: `--json` output for parsing, `--quiet` to suppress prompts -3. **Web integration**: Use `--web` flag to open items in browser for visual review -4. **Workflows**: Use `gh run watch` to monitor CI/CD execution in real-time -5. **Bulk operations**: Use dedicated bulk commands or shell loops with gh for batch operations -6. **Error handling**: Check exit codes `echo $?` after gh commands -7. **Preview first**: Always use `--dry-run` with bulk operations before actual execution - -## Common Workflows - -### Implement and Create PR (From Main Branch) - -When user asks to implement something and create a PR, you MUST detect if on main/master branch and follow proper workflow: - -```bash -# 1. Check current branch -CURRENT_BRANCH=$(git branch --show-current) - -# 2. If on main/master, create feature branch first -if [ "$CURRENT_BRANCH" = "main" ] || [ "$CURRENT_BRANCH" = "master" ]; then - # Generate branch name from feature description - BRANCH_NAME="feature/$(echo 'feature description' | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9]/-/g' | sed 's/-\+/-/g' | sed 's/^-\|-$//g')" - git checkout -b "$BRANCH_NAME" -fi - -# 3. Implement the feature (make code changes) - -# 4. Commit changes -git add . -git commit -m "feat: descriptive commit message" - -# 5. Push branch -git push -u origin "$BRANCH_NAME" - -# 6. Create PR -gh pr create --title "Feature title" --body "Feature description" -``` - -**Important**: Always check current branch before implementing. Never commit directly to main/master when creating a PR. - -### PR Management Workflow -```bash -# Already on feature branch - proceed with PR -# ... make changes ... -git commit -am "Add new feature" -git push origin feature/new-feature -gh pr create --title "Add new feature" --body "Implements #123" -``` - -### CI/CD Monitoring -```bash -# Watch workflow run -gh run watch --interval 1 - -# If failed, view logs and rerun -gh run view --log-failed -gh run rerun --failed -``` - -### Issue Triage -```bash -# List issues needing attention -gh issue list --label "needs-triage" --assignee @me - -# Create and link issue to PR -gh issue create --title "Bug: X fails" --body "..." -gh pr create --body "Closes #123" -``` - -## Common Gotchas - -### Rate Limiting -```bash -# Check rate limit status -gh api /rate_limit - -# Use pagination for large result sets -gh pr list --limit 100 --json number,title | jq '.[]' -gh pr list --limit 100 --json number,title --jq '.[]' --page 2 -``` - -### Authentication Issues -```bash -# "Not logged in" error - reauthenticate -gh auth login - -# Token expired - refresh -gh auth refresh - -# Check auth status -gh auth status -``` - -### Branch Detection -```bash -# If gh doesn't detect the correct default branch -git remote set-head origin -a - -# Explicitly specify base branch -gh pr create --base main --title "Fix" -``` - -### CI Status Not Showing -```bash -# CI runs but gh doesn't show status - check workflow name -gh workflow list - -# View specific workflow status -gh run list --workflow=ci.yml -``` - -### JSON Processing with jq -```bash -# When JSON output is empty, check the field names -gh pr view --json title,body,headRefName - -# Use correct field names from gh schema -gh api /repos/owner/repo/pulls | jq '.[] | {number: .number, title: .title}' -``` - -## Real-World Examples - -### Automated PR Triage -```bash -# Label all PRs from first-time contributors (efficient batch approach) -gh pr list --author . --json number,author --jq '.[] | - select(.author.login | test("^[a-z0-9_-]{4,}$")) | - "\(.number) \(.author.login)"' | \ - while IFS=' ' read -r number author; do - # Quick check for first-timers (avoid API call for known contributors) - gh pr edit "$number" --add-label "first-time-contributor" 2>/dev/null || true - done - -# Add welcome comment for labeled PRs -for pr in $(gh pr list --label "first-time-contributor" --json number --jq '.[].number'); do - gh pr comment "$pr" --body "Welcome! Thanks for your first contribution!" -done -``` - -### Bulk Update Issue Labels -```bash -# Migrate old label names to new convention -gh issue list --label "bug" --limit 100 --json number --jq '.[].number' | \ - while read issue; do - gh issue edit $issue --remove-label "bug" --add-label "type:bug,priority:medium" - done -``` - -### CI Failure Analysis -```bash -# Find all PRs with failed CI -gh pr list --search "status:failure" --limit 50 --json number,title,headRefName - -# Watch specific run in real-time -gh run watch $(gh run list --workflow=ci.yml --limit 1 --json databaseId --jq '.[0].databaseId') -``` - -### Repository Cleanup -```bash -# Close all stale draft PRs older than 30 days -gh pr list --search "draft:yes updated:<$(date -v-30d +%Y-%m-%d)" --json number --jq '.[].number' | \ - while read pr; do - gh pr close $pr --comment "Closing stale draft PR" - done - -# Remove old branches already merged -git branch --merged | grep -v "main\|master" | xargs git branch -d -``` - -### Release Automation -```bash -# Create release with auto-generated notes -gh release create v$(npm version patch) --notes-from-tag - -# Upload all build artifacts -gh release upload v1.0.0 ./dist/*.tar.gz ./dist/*.zip - -# Create release with custom notes template -gh release create v1.0.0 --title "Version 1.0.0" --notes "$(cat <<EOF -## What's Changed - -* Full Changelog: https://github.com/owner/repo/commits/v1.0.0 - -**Contributors**: $(gh api /repos/owner/repo/commits?per_page=100\&sha=v1.0.0 --jq '[.[]?.author.login] | unique | join(", ")') -EOF -)" -``` - -## Notes - -- `gh` respects your current Git repository context -- Use `--help` with any command for detailed options -- GitHub token can be set via `GH_TOKEN` environment variable -- For enterprise GitHub, use `gh auth login --hostname enterprise.com` -- Use `--json` output for programmatic processing with `jq` -- Always test bulk commands with `--dry-run` first -- Large operations may require pagination with `--limit` and `--page` diff --git a/github/skills/review-bots.md b/github/skills/review-bots/SKILL.md similarity index 92% rename from github/skills/review-bots.md rename to github/skills/review-bots/SKILL.md index 03ef1bd..ff962eb 100644 --- a/github/skills/review-bots.md +++ b/github/skills/review-bots/SKILL.md @@ -1,4 +1,5 @@ --- +name: review-bots description: >- Knowledge base for parsing AI code review bot comments on GitHub PRs. Covers CodeRabbit, Sourcery, and Gemini - bot identification, comment formats, @@ -80,15 +81,15 @@ gh api repos/{owner}/{repo}/pulls/{pr_number}/comments \ ``` **Parsing suggestions from body:** -- Look for ` ```suggestion ` blocks — these are direct replacements -- Look for ` ```diff ` blocks — these show before/after +- Look for ` ```suggestion ` blocks - these are direct replacements +- Look for ` ```diff ` blocks - these show before/after - Text-only comments describe the issue; use code understanding to fix ### Resolving Comments ```bash # After fixing, minimize/resolve the review thread -# (GitHub API doesn't support resolving — push a fix commit and the bot updates) +# (GitHub API doesn't support resolving - push a fix commit and the bot updates) ``` CodeRabbit automatically re-reviews after new commits and updates its summary. @@ -137,11 +138,11 @@ gh api repos/{owner}/{repo}/pulls/{pr_number}/comments \ - Severity is in the label: `(bug)`, `(refactoring)`, `(style)`, `(performance)` ### Priority Order -1. `bug` — fix immediately -2. `security` — fix immediately -3. `performance` — fix if straightforward -4. `refactoring` — apply if it improves readability -5. `style` — apply if consistent with project conventions +1. `bug` - fix immediately +2. `security` - fix immediately +3. `performance` - fix if straightforward +4. `refactoring` - apply if it improves readability +5. `style` - apply if consistent with project conventions ## Gemini Code Assist (`gemini-code-assist[bot]`) @@ -187,10 +188,10 @@ gh api repos/{owner}/{repo}/pulls/{pr_number}/comments \ - Categories: security, performance, correctness, style, documentation ### Priority Order -1. `critical` — fix immediately -2. `high` — fix immediately -3. `medium` — fix if clear -4. `low` — apply if simple +1. `critical` - fix immediately +2. `high` - fix immediately +3. `medium` - fix if clear +4. `low` - apply if simple ## Unified Parsing Strategy @@ -212,7 +213,7 @@ REVIEW_COMMENTS=$(gh api "repos/$OWNER/$REPO/pulls/$PR_NUMBER/comments" \ created: .created_at }]") -# Top-level comments (summaries — less actionable) +# Top-level comments (summaries - less actionable) SUMMARY_COMMENTS=$(gh api "repos/$OWNER/$REPO/issues/$PR_NUMBER/comments" \ --jq "[.[] | select(.user.login | test(\"coderabbit|sourcery|gemini\")) | { bot: .user.login, diff --git a/good-html/.claude-plugin/plugin.json b/good-html/.claude-plugin/plugin.json index 02cf29c..2e3054a 100644 --- a/good-html/.claude-plugin/plugin.json +++ b/good-html/.claude-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "good-html", - "version": "1.0.0", - "description": "Generate or review high-density, interactive, self-contained HTML artifacts based on Thariq Shihipar's patterns.", + "version": "1.1.0", + "description": "Dense, interactive, self-contained HTML artifacts and reviews.", "author": { "name": "duyet", "url": "https://github.com/duyet" diff --git a/good-html/.codex-plugin/plugin.json b/good-html/.codex-plugin/plugin.json index ed14af1..b8fc8f8 100644 --- a/good-html/.codex-plugin/plugin.json +++ b/good-html/.codex-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "good-html", - "version": "1.0.0", - "description": "Generate or review high-density, interactive, self-contained HTML artifacts based on Thariq Shihipar's patterns.", + "version": "1.1.0", + "description": "Dense, interactive, self-contained HTML artifacts and reviews.", "author": { "name": "duyet", "url": "https://github.com/duyet" @@ -10,7 +10,7 @@ "skills": "./skills/", "interface": { "displayName": "Good HTML", - "shortDescription": "Generate or review high-density, interactive, self-contained HTML artifacts based on Thariq Shihipar's patterns.", + "shortDescription": "Dense, interactive, self-contained HTML artifacts and reviews.", "developerName": "duyet", "category": "Design", "capabilities": [ diff --git a/good-html/.cursor-plugin/plugin.json b/good-html/.cursor-plugin/plugin.json index 7c9e683..a71d3ee 100644 --- a/good-html/.cursor-plugin/plugin.json +++ b/good-html/.cursor-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "good-html", - "version": "1.0.0", - "description": "Generate or review high-density, interactive, self-contained HTML artifacts based on Thariq Shihipar's patterns.", + "version": "1.1.0", + "description": "Dense, interactive, self-contained HTML artifacts and reviews.", "author": { "name": "duyet" }, diff --git a/good-html/.grok-build-plugin/plugin.json b/good-html/.grok-build-plugin/plugin.json index af2bbea..154cba5 100644 --- a/good-html/.grok-build-plugin/plugin.json +++ b/good-html/.grok-build-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "good-html", - "version": "1.0.0", - "description": "Generate or review high-density, interactive, self-contained HTML artifacts based on Thariq Shihipar's patterns.", + "version": "1.1.0", + "description": "Dense, interactive, self-contained HTML artifacts and reviews.", "author": { "name": "duyet", "url": "https://github.com/duyet" @@ -11,7 +11,7 @@ "skills": "./skills/", "interface": { "displayName": "Good HTML", - "shortDescription": "Generate or review high-density, interactive, self-contained HTML artifacts based on Thariq Shihipar's patterns.", + "shortDescription": "Dense, interactive, self-contained HTML artifacts and reviews.", "developerName": "duyet", "category": "Design", "capabilities": [ diff --git a/good-html/.grok-plugin/plugin.json b/good-html/.grok-plugin/plugin.json index 896a768..8d84fd0 100644 --- a/good-html/.grok-plugin/plugin.json +++ b/good-html/.grok-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "good-html", - "version": "1.0.0", - "description": "Generate or review high-density, interactive, self-contained HTML artifacts based on Thariq Shihipar's patterns.", + "version": "1.1.0", + "description": "Dense, interactive, self-contained HTML artifacts and reviews.", "author": { "name": "duyet", "url": "https://github.com/duyet" diff --git a/good-html/README.md b/good-html/README.md new file mode 100644 index 0000000..ae5bc15 --- /dev/null +++ b/good-html/README.md @@ -0,0 +1,11 @@ +# Good HTML + +Build or review dense, interactive, self-contained HTML artifacts: dashboards, PR reviews, plans, explainers. + +```bash +/plugin install good-html@duyet-claude-plugins +``` + +## Ships + +- `good-html` skill with a palette and font stacks, CSS-only tabs and diff components, a boilerplate, and three example pages. diff --git a/good-html/skills/good-html/SKILL.md b/good-html/skills/good-html/SKILL.md index c6a45fe..13bbf55 100644 --- a/good-html/skills/good-html/SKILL.md +++ b/good-html/skills/good-html/SKILL.md @@ -1,46 +1,30 @@ --- name: good-html -description: Generate or review high-density, interactive, self-contained HTML artifacts based on Thariq Shihipar's "Unreasonable Effectiveness of HTML" patterns. Use this skill when asked to "create HTML," "build a dashboard," "format a PR review," "make an interactive explainer," or when you need to "review and update" existing HTML using the "good-html" style. +description: Build or review a dense, interactive, self-contained HTML artifact such as a dashboard, PR review, implementation plan, or explainer. Use when asked to create HTML, or to review and update existing HTML in this style. --- -# Good HTML Artifact Generator +# Good HTML -This skill enables Claude to generate or refactor highly effective, visually distinct, and functional HTML artifacts rather than relying on standard Markdown or low-resolution HTML. It is based on the design patterns from Thariq Shihipar's "The Unreasonable Effectiveness of HTML". +Produce one `.html` file that works as a small app or document, not Markdown and not a generic page. -The core philosophy is that a single HTML file can act as a high-density "mini-app" or interactive document that is completely self-contained and highly portable. +## Rules -## Core Rules for HTML Generation & Review - -1. **Single-File Output Only:** The entire artifact must fit within one `.html` file. -2. **Zero Dependencies:** Do NOT use external CSS frameworks (no Tailwind, Bootstrap, etc.) or external font files. -3. **Inline Everything:** All styles must be in a `<style>` block. Use inline `<svg>` for graphics. -4. **Avoid "AI Defaults":** Do not use generic bright blue/purple gradients or basic Bootstrap aesthetics. Use the provided earthy, muted color palette and robust system fonts. - -## Resources - -When generating or reviewing an artifact, consult the following resources: - -* **[references/patterns.md](references/patterns.md):** Read this for specific architectural patterns, CSS-only interactivity, and the **Review Checklist**. -* **[references/styles.md](references/styles.md):** The design system for colors, typography, and spacing. -* **[references/components.md](references/components.md):** Use this for pre-built interactive components (tabs, diffs, timelines). -* **[assets/boilerplate.html](assets/boilerplate.html):** Use this file as the structural starting point. +1. One file. Styles in a `<style>` block, graphics as inline `<svg>`, no external CSS frameworks, fonts, or images. +2. Prefer CSS-only state: hidden radio inputs plus sibling selectors for tabs, native `<details>` for collapsible sections. Use `<script>` only when CSS cannot do it. +3. Use the palette and system font stacks in [references/styles.md](references/styles.md). Avoid purple or blue gradients and web fonts. +4. Pack information: CSS Grid for side-by-side comparisons, sticky headers or sidebars on long content, semantic severity colors (`.safe`, `.attention`, `.critical`). +5. Write the complete file. Do not truncate. ## Workflow -### For New Artifacts -1. **Analyze Request:** Determine the optimal page type (see [references/page_types.md](references/page_types.md)). -2. **Plan Layout:** Decide on the grid structure and interaction model. -3. **Implement:** Use the boilerplate and component library to build the file. - -### For Review & Refactoring -1. **Audit:** Compare the current HTML against the **Review Checklist** in `patterns.md`. -2. **Identify Bottlenecks:** Find external dependencies, generic styles, or low-density layouts. -3. **Apply Surgical Updates:** - * Inline external CSS/JS. - * Swap web fonts for the system font stack. - * Update colors to the Ivory/Slate/Clay palette. - * Refactor lists or simple tables into high-density Grids or Tabs. -4. **Verify Interactivity:** Ensure state handling (e.g. tabs) is refactored to use the CSS-only radio engine where appropriate. - -## Output Code -Output the complete HTML code within a standard code block for the user to copy, or write it directly to an HTML file if instructed. Do not truncate the code. \ No newline at end of file +New artifact: +1. Pick the page type: comparison of options, PR review, code explainer, implementation plan, status or incident report, triage board, concept explainer, slide deck, or SVG diagram. +2. Start from [assets/boilerplate.html](assets/boilerplate.html). Page-type examples: [assets/pr-review.html](assets/pr-review.html), [assets/implementation-plan.html](assets/implementation-plan.html), [assets/research-explainer.html](assets/research-explainer.html). +3. Copy tabs, diffs, and timelines from [references/components.md](references/components.md). + +Reviewing existing HTML, fix in this order: +1. Remove every external `<link>` and `<script src>`; inline what is needed. +2. Swap web fonts for system stacks and recolor to the palette. +3. Replace a single long column with a grid, and add sticky context for long scrolls. +4. Replace JS-driven simple state with the radio or `<details>` patterns. +5. Replace bitmap icons with inline SVG. diff --git a/good-html/assets/boilerplate.html b/good-html/skills/good-html/assets/boilerplate.html similarity index 100% rename from good-html/assets/boilerplate.html rename to good-html/skills/good-html/assets/boilerplate.html diff --git a/good-html/assets/implementation-plan.html b/good-html/skills/good-html/assets/implementation-plan.html similarity index 100% rename from good-html/assets/implementation-plan.html rename to good-html/skills/good-html/assets/implementation-plan.html diff --git a/good-html/assets/pr-review.html b/good-html/skills/good-html/assets/pr-review.html similarity index 100% rename from good-html/assets/pr-review.html rename to good-html/skills/good-html/assets/pr-review.html diff --git a/good-html/assets/research-explainer.html b/good-html/skills/good-html/assets/research-explainer.html similarity index 100% rename from good-html/assets/research-explainer.html rename to good-html/skills/good-html/assets/research-explainer.html diff --git a/good-html/skills/good-html/references/components.md b/good-html/skills/good-html/references/components.md index 0b0e1ba..9fa7cd8 100644 --- a/good-html/skills/good-html/references/components.md +++ b/good-html/skills/good-html/references/components.md @@ -1,4 +1,4 @@ -# Anthropic HTML Component Library +# Component library Use these components to build high-density, interactive artifacts. All components are self-contained and require only the base CSS variables defined in `boilerplate.html`. diff --git a/good-html/skills/good-html/references/page_types.md b/good-html/skills/good-html/references/page_types.md deleted file mode 100644 index d8a17b6..0000000 --- a/good-html/skills/good-html/references/page_types.md +++ /dev/null @@ -1,29 +0,0 @@ -# HTML Artifact Page Types - -The `good-html` skill supports several specialized page types, each optimized for different engineering and research tasks. - -## 1. Exploration & Comparison -* **Code Approaches:** Side-by-side view of multiple implementation options. Uses 2 or 3-column grids. -* **Visual Designs:** Renders live UI mockups or layout options for fast feedback. -* **Component Variants:** Shows the same component with different "vibes" or states. - -## 2. Engineering Workflows -* **PR Review:** A dashboard showing diffs, finding severity, and architectural context. -* **Code Understanding:** Explains complex logic using inline annotations and split views. -* **Implementation Plan:** Visual timeline of milestones, risk matrices, and data flow. -* **PR Writeup:** Professional summary of changes with "before/after" screenshots (rendered in HTML). - -## 3. Reporting & Triage -* **Status Report:** High-level overview of project health, blocking issues, and next steps. -* **Incident Report:** Timeline of events, root cause analysis, and impact assessment. -* **Triage Board:** Kanban-style view for managing bugs or feature requests. -* **Feature Flags / Prompt Tuner:** Interactive dashboards for adjusting configuration or tuning LLM prompts. - -## 4. Research & Knowledge -* **Concept Explainer:** Deep dive into a technical topic using interactive "explodables" or tabs. -* **Feature Explainer:** Walkthrough of a specific feature's logic and data flow. -* **Slide Deck:** A presentation format using full-screen sections and navigation. - -## 5. Visualizations -* **SVG Flowcharts:** Data flow or logic diagrams that are searchable and interactive. -* **SVG Illustrations:** Technical diagrams (e.g., cloud architecture, memory layout). diff --git a/good-html/skills/good-html/references/patterns.md b/good-html/skills/good-html/references/patterns.md deleted file mode 100644 index ec02f26..0000000 --- a/good-html/skills/good-html/references/patterns.md +++ /dev/null @@ -1,43 +0,0 @@ -# HTML Effectiveness Patterns - -This document outlines the core patterns identified by Thariq Shihipar in "The Unreasonable Effectiveness of HTML". When generating HTML artifacts, strictly adhere to these patterns to produce high-density, interactive, and professional outputs. - -## 1. The "Self-Contained" Architecture -* **Single-File Artifact:** The output MUST be a single `.html` file. -* **Zero External Dependencies:** Do NOT use external CSS frameworks (like Tailwind CDN) or external font files. -* **Inline Everything:** All CSS must be inside a `<style>` block in the `<head>`. All JS (if absolutely necessary, but prefer CSS-only state) must be in `<script>` blocks. -* **Inline SVG:** Use `<svg>` directly in the HTML for icons and diagrams instead of linking external images. - -## 2. Professional Aesthetics (Avoid "AI Defaults") -* **Typography:** Use robust system font stacks. Avoid web fonts that require network requests. - * Serif: `ui-serif, Georgia, 'Times New Roman', serif;` - * Sans: `system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;` - * Mono: `ui-monospace, 'SF Mono', Menlo, Monaco, monospace;` -* **Color Palette:** Use subtle, earthy, or muted tones instead of harsh primary colors or typical "AI" gradients. - * Examples: `--ivory: #FAF9F5;`, `--slate: #141413;`, `--clay: #D97757;`, `--olive: #788C5D;` -* **Spacing:** Be generous with whitespace (e.g., `line-height: 1.55;`, `padding: 48px`). - -## 3. High-Density Layouts -* **Side-by-Side Comparisons:** Use CSS Grid (`display: grid; grid-template-columns: 1fr 1fr; gap: 20px;`) to present alternatives next to each other rather than in a long vertical list. -* **Sticky Headers/Context:** Use `position: sticky; top: 0;` for elements like table headers or summary sidebars so the user retains context while scrolling through long content (e.g., code diffs). -* **Severity Color-Coding:** Use semantic CSS classes (e.g., `.safe { color: var(--olive); }`, `.attention { color: var(--clay); }`) to make data scannable. - -## 4. Interactive Elements (CSS-Only Preferred) -* **The "Radio State" Engine:** Use hidden `<input type="radio">` elements paired with labels and CSS sibling selectors (`+` or `~` or `:has()`) to create interactive tabs or expanding sections without JavaScript. -* **Collapsible Sections:** Use native `<details>` and `<summary>` elements to hide secondary information (like large code blocks) until needed. -* **Hover Effects:** Add subtle `transition: transform 150ms ease, box-shadow 150ms ease;` to cards and interactive elements. - -## 5. Review Checklist (Audit Guide) -When reviewing existing HTML to update it to this style, check for the following: - -- [ ] **Portability:** Are there any external `<link>` or `<script src="...">` tags? (Should be 0). -- [ ] **Aesthetics:** Does it use "AI Defaults" (Inter font, purple gradients)? (Swap for system fonts and Ivory/Slate/Clay palette). -- [ ] **Density:** Is information presented in a single long column? (Use CSS Grid for side-by-side comparisons). -- [ ] **Context:** Does the user lose context when scrolling? (Add sticky headers/sidebars). -- [ ] **Interactivity:** Does it use heavy JS for simple state? (Refactor to Radio State Engine or `<details>`). -- [ ] **Visuals:** Are there bitmapped icons/images? (Swap for Inline SVGs). - -## Example Use Cases -* **PR Reviews:** Render diffs with inline margin annotations. -* **Implementation Plans:** Use grid layouts for milestones and color-coded risk matrices. -* **Architecture Diagrams:** Draw interactive SVGs that show data flow. \ No newline at end of file diff --git a/interview/.claude-plugin/plugin.json b/interview/.claude-plugin/plugin.json index 2168e7a..138e748 100644 --- a/interview/.claude-plugin/plugin.json +++ b/interview/.claude-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "interview", - "version": "1.0.1", - "description": "Conduct in-depth requirements interviews using Socratic questioning", + "version": "1.1.0", + "description": "Interview the user to clarify requirements, then write a spec.", "author": { "name": "duyet", "url": "https://github.com/duyet" diff --git a/interview/.codex-plugin/plugin.json b/interview/.codex-plugin/plugin.json index a0cbdd5..d24aa58 100644 --- a/interview/.codex-plugin/plugin.json +++ b/interview/.codex-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "interview", - "version": "1.0.1", - "description": "Conduct in-depth requirements interviews using Socratic questioning", + "version": "1.1.0", + "description": "Interview the user to clarify requirements, then write a spec.", "author": { "name": "duyet", "url": "https://github.com/duyet" @@ -11,7 +11,7 @@ "commands": "./commands/", "interface": { "displayName": "Interview", - "shortDescription": "Conduct in-depth requirements interviews using Socratic questioning", + "shortDescription": "Interview the user to clarify requirements, then write a spec.", "developerName": "duyet", "category": "Productivity", "capabilities": [ diff --git a/interview/.cursor-plugin/plugin.json b/interview/.cursor-plugin/plugin.json index 713e8ac..121b0d8 100644 --- a/interview/.cursor-plugin/plugin.json +++ b/interview/.cursor-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "interview", - "version": "1.0.1", - "description": "Conduct in-depth requirements interviews using Socratic questioning", + "version": "1.1.0", + "description": "Interview the user to clarify requirements, then write a spec.", "author": { "name": "duyet" }, diff --git a/interview/.grok-build-plugin/plugin.json b/interview/.grok-build-plugin/plugin.json index e44dee1..c796ab4 100644 --- a/interview/.grok-build-plugin/plugin.json +++ b/interview/.grok-build-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "interview", - "version": "1.0.1", - "description": "Conduct in-depth requirements interviews using Socratic questioning", + "version": "1.1.0", + "description": "Interview the user to clarify requirements, then write a spec.", "author": { "name": "duyet", "url": "https://github.com/duyet" @@ -12,7 +12,7 @@ "commands": "./commands/", "interface": { "displayName": "Interview", - "shortDescription": "Conduct in-depth requirements interviews using Socratic questioning", + "shortDescription": "Interview the user to clarify requirements, then write a spec.", "developerName": "duyet", "category": "Productivity", "capabilities": [ diff --git a/interview/.grok-plugin/plugin.json b/interview/.grok-plugin/plugin.json index f49afdd..3f32da7 100644 --- a/interview/.grok-plugin/plugin.json +++ b/interview/.grok-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "interview", - "version": "1.0.1", - "description": "Conduct in-depth requirements interviews using Socratic questioning", + "version": "1.1.0", + "description": "Interview the user to clarify requirements, then write a spec.", "author": { "name": "duyet", "url": "https://github.com/duyet" diff --git a/interview/README.md b/interview/README.md index 52872ce..f5a2a5e 100644 --- a/interview/README.md +++ b/interview/README.md @@ -1,112 +1,19 @@ -# Interview Plugin +# Interview -Conduct in-depth requirements interviews using Socratic questioning before implementation. - -## Installation +Clarify ambiguous requirements before coding. Claude asks batched, option-based questions, then writes a decision-complete spec. ```bash /plugin install interview@duyet-claude-plugins ``` -## What It Does - -The `/interview` command puts Claude into an interview mode where it systematically asks clarifying questions about a feature or plan. It uses the `AskUserQuestion` tool to gather decisions on: +## Ships -- Technical implementation details -- UI/UX decisions -- Edge cases and failure modes -- Tradeoffs and constraints -- Integration requirements +- `interview-workflow` skill: question categories, how to ask, stop condition, spec format. +- `/interview <prompt or spec path>`: runs the skill. ## Usage -### Interview about a prompt - -``` -/interview "build a user authentication system with OAuth" -``` - -### Interview about an existing plan file - ``` +/interview "add a commenting system to the blog" /interview ./docs/feature-spec.md ``` - -## What Gets Asked - -The interview covers: - -1. **Core Functionality** - Primary use cases, failure scenarios, feature boundaries -2. **Technical Implementation** - Performance, persistence, security, error handling -3. **User Experience** - User types, mental models, accessibility -4. **Edge Cases** - Invalid input, high load, dependency failures -5. **Constraints** - Timeline, complexity budget, hard vs soft requirements -6. **Integration** - Existing systems, patterns to follow or avoid - -## Output - -After the interview completes, Claude writes a comprehensive specification document including: - -- Decisions made (with rationale) -- Functional and non-functional requirements -- User stories -- Technical design (architecture, data model, APIs) -- Edge cases and error handling -- Out of scope items -- Open questions - -## Philosophy - -This plugin takes the approach that **asking the right questions is more valuable than assuming answers**. It's designed to: - -- Uncover hidden complexity before coding begins -- Make unstated assumptions explicit -- Identify edge cases the user hasn't considered -- Force explicit decisions on tradeoffs -- Produce specs that make implementation obvious - -## Example Session - -``` -> /interview "add a commenting system to our blog" - -Claude: [Uses AskUserQuestion tool] -Header: "Comment Scope" -Question: "Should comments be available on all content types or just blog posts?" -Options: -- Blog posts only (Recommended) - Simpler scope, can extend later -- All content types - More complex, needs polymorphic design -- Configurable per content type - Maximum flexibility, most work - -[User selects option] - -Claude: [Continues with more questions...] -... - -Claude: Here's the complete specification based on our interview: -[Writes spec document] -``` - -## Tips - -- Don't give vague answers - Claude will push back -- Be honest about constraints (timeline, complexity budget) -- It's okay to say "I don't know" - that gets captured as an open question -- The more specific you are, the better the spec - -## Architecture - -``` -interview/ -├── .claude-plugin/ -│ └── plugin.json # Plugin manifest -├── commands/ -│ └── interview.md # Interview command definition -└── README.md # This file -``` - -## Changelog - -### [1.0.0] - Initial Release - -Requirements interview plugin using Socratic questioning and AskUserQuestion tool for systematic requirements discovery before implementation. diff --git a/interview/commands/interview.md b/interview/commands/interview.md index b6ba8c3..71129f8 100644 --- a/interview/commands/interview.md +++ b/interview/commands/interview.md @@ -1,189 +1,6 @@ --- -description: Conduct in-depth requirements interview using Socratic questioning to clarify implementation details -arguments: - - name: input - description: A prompt describing what to interview about, OR a path to a plan/spec file to interview about - required: true +description: Interview the user to clarify requirements, then write a spec +argument-hint: <topic or path to a plan/spec file> --- -# Requirements Interview Mode - -You are now in **Interview Mode**. Your job is to conduct a thorough, Socratic-style requirements interview to clarify every ambiguity before implementation begins. - -## Input Analysis - -First, analyze the input: `$ARGUMENTS.input` - -**If the input is a file path** (ends with `.md`, `.txt`, or starts with `./`, `/`, or `~/`): -1. Read the file using the Read tool -2. Analyze the plan/spec for gaps, ambiguities, and missing details -3. Interview about those specific gaps - -**If the input is a prompt/description**: -1. Parse the requirements from the description -2. Identify areas that need clarification -3. Interview to fill in missing details - -## Interview Philosophy - -**Your role is like a senior architect or product manager** who needs to understand EVERYTHING before a team can build it. You're not here to validate obvious choices - you're here to uncover: - -- Hidden complexity -- Unstated assumptions -- Edge cases the user hasn't considered -- Tradeoffs that need explicit decisions -- Technical constraints that affect the design - -## Interview Categories - -Cover these areas systematically using the AskUserQuestion tool: - -### 1. Core Functionality -- What is the PRIMARY use case? (not the obvious answer, dig deeper) -- What happens when the happy path fails? -- What are the boundaries of this feature? - -### 2. Technical Implementation -- What are the performance requirements? (latency, throughput, scale) -- What are the data persistence needs? -- What integrations are required? -- What are the security considerations? -- What's the error handling strategy? - -### 3. User Experience -- Who are ALL the user types? (not just the primary one) -- What's the user's mental model? -- What are the critical user flows? -- What feedback does the user need? -- What are the accessibility requirements? - -### 4. Edge Cases & Failure Modes -- What happens with invalid input? -- What happens under high load? -- What happens when dependencies fail? -- What are the race conditions? -- What are the concurrency concerns? - -### 5. Constraints & Tradeoffs -- What's the timeline pressure? -- What can be deferred to v2? -- What's the acceptable complexity budget? -- What are the hard constraints vs preferences? - -### 6. Integration & Context -- How does this fit with existing systems? -- What patterns should be followed? -- What patterns should be avoided? -- Who else needs to know about this? - -## Interview Rules - -1. **Use AskUserQuestion tool** - ALWAYS use the AskUserQuestion tool for each question batch -2. **Batch related questions** - Group 2-4 related questions per AskUserQuestion call -3. **No obvious questions** - Don't ask things that are self-evident from the input -4. **Progressive depth** - Start with architecture, then drill into details -5. **Challenge assumptions** - If user says "just do X", ask WHY and explore alternatives -6. **Capture decisions** - Track every decision made during the interview -7. **Be persistent** - Continue until you have enough clarity to write a complete spec - -## Question Design - -Each question should: -- Be specific enough to get a useful answer -- Offer meaningful choices (not just yes/no) -- Include a recommended option with rationale -- Reveal something the user might not have considered - -**Good question example:** -``` -header: "Data Persistence" -question: "How should we handle data when the user closes the browser mid-operation?" -options: - - label: "Auto-save every 30 seconds" - description: "Prevents data loss but adds complexity and server load" - - label: "Save on explicit action only" - description: "Simpler but user loses work if they forget to save" - - label: "Warn before leaving with unsaved changes" - description: "Browser-native UX, no auto-save infrastructure needed" -``` - -**Bad question example:** -``` -question: "Should we use a database?" -# Too obvious - of course we need persistence -``` - -## Interview Flow - -1. **Opening** (1-2 questions): Confirm you understand the core goal -2. **Architecture** (3-5 questions): High-level design decisions -3. **Implementation** (5-10 questions): Technical specifics -4. **Edge cases** (3-5 questions): Failure modes and unusual scenarios -5. **Polish** (2-3 questions): UX refinements and nice-to-haves -6. **Confirmation**: Summarize decisions and confirm completeness - -## Output: The Spec Document - -After the interview is complete, write a comprehensive specification document that includes: - -```markdown -# [Feature Name] Specification - -## Overview -Brief description of what we're building and why. - -## Decisions Made -| Category | Decision | Rationale | -|----------|----------|-----------| -| ... | ... | ... | - -## Requirements - -### Functional Requirements -- FR-1: ... -- FR-2: ... - -### Non-Functional Requirements -- NFR-1: Performance: ... -- NFR-2: Security: ... - -### User Stories -- As a [user], I want to [action] so that [benefit] - -## Technical Design - -### Architecture -- Components and their responsibilities -- Data flow -- Integration points - -### Data Model -- Entities and relationships -- Storage requirements - -### API Design (if applicable) -- Endpoints -- Request/Response formats - -## Edge Cases & Error Handling -| Scenario | Expected Behavior | -|----------|-------------------| -| ... | ... | - -## Out of Scope (v2+) -- Features explicitly deferred -- Known limitations - -## Open Questions -- Any remaining uncertainties -``` - -## Begin Interview - -Start by reading the input and conducting your first round of questions. Remember: -- Be thorough but not tedious -- Ask the hard questions early -- Don't let the user off easy with vague answers -- Your job is to make implementation OBVIOUS after this interview - -Let's begin! +Use the `interview-workflow` skill on: $ARGUMENTS diff --git a/interview/skills/interview-workflow/SKILL.md b/interview/skills/interview-workflow/SKILL.md index 2f6ad92..3603cc2 100644 --- a/interview/skills/interview-workflow/SKILL.md +++ b/interview/skills/interview-workflow/SKILL.md @@ -1,20 +1,36 @@ --- -name: interview -description: "Use before implementing when requirements are ambiguous: run a Socratic interview to clarify a vague feature request or to find gaps in a plan/spec file, and turn it into a decision-complete plan with scope, edge cases, and tests." +name: interview-workflow +description: Use before implementing when requirements are ambiguous. Interview the user to clarify a vague request or to find gaps in a plan or spec file, then write a decision-complete spec. --- # Interview -Use this skill to clarify requirements before coding when the task has meaningful product or technical ambiguity. +## Start -## Workflow +If the input is a file path, read it and interview about its gaps. Otherwise treat the input as the request. Read relevant repo files, schemas, and docs first so you never ask what the code already answers. -1. Ground the discussion in any existing repository files, designs, schemas, or docs. -2. Ask concise questions that change the implementation plan. -3. Separate product intent from implementation preferences. -4. Turn answers into a decision-complete plan with success criteria, scope, edge cases, and tests. -5. Stop interviewing once the plan is specific enough to implement. +## What to cover + +Probe only where the answer changes the build. + +- Core: the real primary use case, boundaries, what happens when the happy path fails. +- Technical: scale and latency, persistence, integrations, security, error handling. +- Users: every user type, their mental model, critical flows, accessibility. +- Edge cases: invalid input, load, dependency failure, races and concurrency. +- Constraints: deadline, what can wait for v2, hard constraints versus preferences. +- Context: existing patterns to follow or avoid, who else is affected. + +## How to ask + +- Use the ask-user tool, batching 2 to 4 related questions per call. Go from architecture to details. +- Each question offers real options with a recommended one and its tradeoff. No yes/no questions, no questions the input already answers. +- Separate product intent from implementation preference. If the user says "just do X", ask why and name an alternative. +- Record each decision as you go. + +## Stop + +Stop when you could hand the spec to an engineer with no further questions. Summarize the decisions and ask for confirmation once. ## Output -Prefer a compact plan with summary, key changes, test plan, and assumptions. +Write a spec with these sections: overview, decisions and rationale, functional and non-functional requirements, technical design (components, data model, APIs if any), edge cases with expected behavior, out of scope, open questions. diff --git a/kb/.claude-plugin/plugin.json b/kb/.claude-plugin/plugin.json index 879bddc..4574df0 100644 --- a/kb/.claude-plugin/plugin.json +++ b/kb/.claude-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "kb", - "version": "1.1.0", + "version": "1.2.0", "description": "Knowledge base maintenance skills. Initialize a shared-brain kb, then consolidate, dedupe, prune, refresh, and forget notes in a markdown KB.", "author": { "name": "duyet", diff --git a/kb/.codex-plugin/plugin.json b/kb/.codex-plugin/plugin.json index dfd552c..558b718 100644 --- a/kb/.codex-plugin/plugin.json +++ b/kb/.codex-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "kb", - "version": "1.1.0", + "version": "1.2.0", "description": "Knowledge base maintenance skills. Initialize a shared-brain kb, then consolidate, dedupe, prune, refresh, and forget notes in a markdown KB.", "author": { "name": "duyet", diff --git a/kb/.cursor-plugin/plugin.json b/kb/.cursor-plugin/plugin.json index ec9e4af..31f2d51 100644 --- a/kb/.cursor-plugin/plugin.json +++ b/kb/.cursor-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "kb", - "version": "1.1.0", + "version": "1.2.0", "description": "Knowledge base maintenance skills. Initialize a shared-brain kb, then consolidate, dedupe, prune, refresh, and forget notes in a markdown KB.", "author": { "name": "duyet" diff --git a/kb/.grok-build-plugin/plugin.json b/kb/.grok-build-plugin/plugin.json index 763df65..d4fefb6 100644 --- a/kb/.grok-build-plugin/plugin.json +++ b/kb/.grok-build-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "kb", - "version": "1.1.0", + "version": "1.2.0", "description": "Knowledge base maintenance skills. Initialize a shared-brain kb, then consolidate, dedupe, prune, refresh, and forget notes in a markdown KB.", "author": { "name": "duyet", diff --git a/kb/.grok-plugin/plugin.json b/kb/.grok-plugin/plugin.json index dabde7e..f3de36b 100644 --- a/kb/.grok-plugin/plugin.json +++ b/kb/.grok-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "kb", - "version": "1.1.0", + "version": "1.2.0", "description": "Knowledge base maintenance skills. Initialize a shared-brain kb, then consolidate, dedupe, prune, refresh, and forget notes in a markdown KB.", "author": { "name": "duyet", diff --git a/kb/README.md b/kb/README.md index 9c9eb94..d5c468d 100644 --- a/kb/README.md +++ b/kb/README.md @@ -1,42 +1,21 @@ # kb -Knowledge base maintenance skills for markdown KBs. KB-agnostic: point each skill at any -markdown knowledge base via a path argument or the `$KB_DIR` environment variable. - -## Skills - -- **init** — scaffold a brand-new shared-brain kb folder (default `~/kb`): the - memory protocol (`AGENTS.md`/`CLAUDE.md`/`DREAM.md`/`MEMORY.md`), an OKF v0.1 - `memory/` bundle, a capture inbox, and a self-contained CLI (`bin/kb`, - `scripts/render_okf_viewer.py` for the graph viewer, `lint.sh`, `sync.sh`, - `wire.sh`). Idempotent; never overwrites existing files; never edits anything - outside the target folder without asking first. -- **dream** — the consolidation pass. Merges near-duplicate notes, flags contradictions, - prunes stale/low-value notes, ingests inbox captures, refreshes notes from their - source URLs, splits multi-fact notes, relinks/retags, and rebuilds the index. Shows a - diff for approval before changing anything. Supports `--auto` (non-interactive, lock - guarded) and `forget` (delete specific notes). - -## Install +Skills for scaffolding and maintaining a markdown knowledge base shared by every coding agent. Point each skill at a path or set `$KB_DIR`. ```bash /plugin install kb@duyet-claude-plugins ``` -## Usage +## What ships -```bash -init # scaffold a new shared-brain kb at ~/kb (or $KB_DIR) -init ~/kb # scaffold at an explicit path +- `init` scaffolds a shared-brain folder (default `~/kb`): protocol files, an OKF v0.1 `memory/` bundle, a capture inbox, and a self-contained CLI with a graph viewer. It never overwrites existing files and asks before editing anything outside the folder. +- `dream` consolidates a KB: merges duplicates, flags contradictions, prunes stale notes, ingests the inbox, refreshes notes from their sources, and rebuilds the index. It shows a diff first. `--auto` runs unattended and `forget` deletes chosen notes. -dream ./docs/kb # consolidate a KB (interactive, diff-for-approval) -dream $KB_DIR --auto # non-interactive; merges/prunes, skips contradictions -dream forget "old server" # propose deleting notes matching a query +```bash +/init ~/kb +/dream ./docs/kb +/dream $KB_DIR --auto +/dream forget "old server" ``` -The KB is any directory of `*.md` notes with YAML frontmatter (`name`, `type`, `tags`, -`created`, `updated`, optional `pinned`/`confidence`/`sources`), optionally with a -`MEMORY.md` index, a `raw/inbox/` of captures, and `raw/` source docs — exactly what -`init` scaffolds. It is also a conformant [OKF v0.1](https://github.com/GoogleCloudPlatform/knowledge-catalog/blob/main/okf/SPEC.md) -bundle; see the companion **okf** plugin for deeper bundle authoring, validation, and -graph-viewer rendering. +The scaffolded folder vendors its own copy of `render_okf_viewer.py`, identical to the one in the `okf` plugin, so it keeps working without this plugin installed. See `okf` for bundle authoring and validation. diff --git a/kb/commands/dream.md b/kb/commands/dream.md index 31a56b8..f487841 100644 --- a/kb/commands/dream.md +++ b/kb/commands/dream.md @@ -1,38 +1,13 @@ --- -description: Consolidate a markdown knowledge base — merge near-duplicates, flag contradictions, prune stale notes, ingest inbox, refresh from sources, and rebuild the index; supports a forget subcommand and --auto. +description: Consolidate a markdown knowledge base. Supports a forget subcommand and --auto. --- # /dream -Consolidate a markdown knowledge base: merge near-duplicates, flag contradictions, prune -stale notes, ingest inbox captures, refresh notes from sources, split, and rebuild the -index. Delegate to the `dream` skill for the full pass. Nothing changes until the user -approves the diff (unless `--auto`). +Run the `dream` skill (`skills/dream/SKILL.md`) on `$ARGUMENTS`. -## Arguments +- `path`: KB directory, defaulting to `$KB_DIR`. Ask if neither is set. +- `--auto`: non-interactive run. +- `forget "<query>"`: propose deleting matching notes. -- `path`: KB directory (optional; defaults to `$KB_DIR`; ask if unset) -- `--auto`: non-interactive run (apply merges/prunes, skip contradictions, lock-guarded) -- `forget "<query>"`: delete notes matching a query (diff-for-approval) - -Pass the rest of the line as `$ARGUMENTS`. Examples: `/dream ./docs/kb`, -`/dream $KB_DIR --auto`, `/dream forget "old server"`. - -## Workflow - -1. Parse `$ARGUMENTS`: detect `--auto`, a `forget "<query>"` subcommand, and a path. - Resolve the KB path from the argument or `$KB_DIR`; ask if neither is set. -2. Invoke the `dream` skill and follow its pass exactly. The skill owns the consolidation - logic, the diff format, the apply order, and the safety rules. -3. In interactive mode, print the diff, collect A/B/skip for each conflict, confirm, then - apply in the skill's prescribed order. -4. In `--auto`, honor the lock file, apply merges and prunes silently, skip conflicts, and - leave a reminder if conflicts still need review. -5. For `forget`, list matches and apply only approved deletions (and their index lines). - -## Guardrails - -- Never assume a fixed KB location; use the argument or `$KB_DIR`. -- Never auto-push or auto-sync; the user confirms before any write outside the KB. -- Never delete or merge `pinned` notes without explicit per-note confirmation. -- Keep this command thin — all consolidation logic lives in the `dream` skill. +Examples: `/dream ./docs/kb`, `/dream $KB_DIR --auto`, `/dream forget "old server"`. diff --git a/kb/commands/init.md b/kb/commands/init.md index 70f03ae..be38714 100644 --- a/kb/commands/init.md +++ b/kb/commands/init.md @@ -1,34 +1,11 @@ --- -description: Scaffold a new shared-brain knowledge base folder (default ~/kb) — OKF v0.1-conformant, with a graph viewer and its own CLI, vendored and self-contained. +description: Scaffold a new shared-brain knowledge base folder (default ~/kb) with an OKF v0.1 memory bundle, a graph viewer, and its own CLI. --- # /init -Scaffold a new shared-brain kb folder: memory protocol (`AGENTS.md`/`CLAUDE.md`/ -`DREAM.md`/`MEMORY.md`), an OKF v0.1 `memory/` bundle, a capture inbox -(`raw/inbox/`), and a self-contained CLI (`bin/kb`, `scripts/`). Delegate to the -`init` skill for the full scaffold. Idempotent — never overwrites existing files. +Run the `init` skill (`skills/init/SKILL.md`) on `$ARGUMENTS`. -## Arguments +- `path`: target directory, defaulting to `$KB_DIR`, then `~/kb`. -- `path`: target directory (optional; defaults to `$KB_DIR` or `~/kb`) - -Pass the rest of the line as `$ARGUMENTS`. Examples: `/init`, `/init ~/kb`, -`/init ./team-kb`. - -## Workflow - -1. Resolve the target path from `$ARGUMENTS`, `$KB_DIR`, or the default `~/kb`; - confirm with the user if ambiguous. -2. Invoke the `init` skill and follow its steps exactly. -3. Report files created vs. skipped (pre-existing). -4. Offer PATH export, `git init`, and `scripts/wire.sh on` as separate, - confirm-first follow-ups — never run them without asking, since wiring - edits global agent config outside the scaffolded folder. - -## Guardrails - -- Never overwrite a file that already exists in the target. -- Never touch anything outside the target folder without explicit confirmation. -- Never invent personal facts to seed `memory/` with — leave it for the user. -- Keep this command thin — all scaffolding logic lives in the `init` skill. +Examples: `/init`, `/init ./team-kb`. diff --git a/kb/skills/dream/SKILL.md b/kb/skills/dream/SKILL.md index dc0e24a..c56fb3b 100644 --- a/kb/skills/dream/SKILL.md +++ b/kb/skills/dream/SKILL.md @@ -1,196 +1,81 @@ --- name: dream -description: Consolidate a markdown knowledge base — merge near-duplicates, flag contradictions, prune stale notes, ingest inbox, refresh from sources, split, and rebuild the index. Use when a KB is noisy or stale, on a schedule, or to forget notes. Diff-for-approval; supports --auto. +description: Consolidate a markdown knowledge base by merging near-duplicates, flagging contradictions, pruning stale notes, ingesting the inbox, refreshing from sources, and rebuilding the index. Use when a KB is noisy or stale, on a schedule, or to forget notes. --- -# dream — KB memory consolidation +# dream -## Overview +Maintenance pass for a markdown KB. Propose every change as a diff and apply nothing until the user approves, unless run with `--auto`. -Dream is the maintenance pass that keeps a markdown knowledge base compact and -retrievable — the agent equivalent of sleep consolidating the day's memories. Run it when -the KB feels noisy (duplicates, contradictions, sprawl, stale facts), on a schedule, or -to forget specific notes. Everything is proposed as a diff first; nothing changes until -you approve (or you run `--auto`). - -Dream is KB-agnostic and generic. It never assumes a fixed location. +If the KB ships its own `DREAM.md` or `AGENTS.md`, read it first and follow its note format, tag vocabulary, and sync steps. ## Invocation -- `dream [<path>]` — consolidate the KB at `<path>`. If omitted, use `$KB_DIR`; if that - is unset, ask for the path. Examples: `dream ./docs/kb`, `dream $KB_DIR`. -- `dream --auto [<path>]` — non-interactive: apply merges and prunes silently, skip - contradictions (they need human judgment), guarded by a lock file. -- `dream forget "<query>" [<path>]` — find notes matching a query and propose deletion - (same diff-for-approval flow as consolidation). +- `dream [<path>]` consolidates the KB at `<path>`, else `$KB_DIR`, else ask. +- `dream --auto [<path>]` runs without prompts. It applies merges and prunes, skips contradictions, and takes a lock. +- `dream forget "<query>" [<path>]` lists notes matching the query and proposes deleting them through the same diff flow. Pinned notes are deleted only with per-note confirmation. -A note is any `*.md` file with YAML frontmatter. Map missing fields gracefully: +A note is a `*.md` file with YAML frontmatter: `name` (equals the filename stem), `description`, `type`, `tags`, `created`, `updated`, and optional `sources`, `pinned`, `confidence` (0 to 1). Treat a missing `type` as `unknown`, missing dates as file mtime, missing `pinned` as false. -```yaml ---- -name: type-short-slug # equals the filename stem -description: one line, keyword-front-loaded -type: tech # user | feedback | project | reference | tech | ... -tags: [topic, topic] -sources: ["https://example.com/llms.txt"] -created: 2026-06-01 -updated: 2026-06-13 -pinned: false # optional — pinned notes are never pruned or merged -confidence: 0.8 # optional — 0..1; low + generic => prune candidate ---- -``` +## The pass + +Hold everything in memory until the apply step. + +1. Resolve the KB. Expect `memory/` notes, a `MEMORY.md` index, `raw/inbox/` captures, `raw/` source docs, and a state file. Adapt if the layout differs. +2. Ingest the inbox. Promote durable, general facts from `raw/inbox/*` into notes, then delete the inbox files. Keep `raw/` source docs and record them as processed in state. +3. Merge near-duplicates. Two notes qualify when they share a `type`, overlap on more than about 60% of significant nouns, and neither is pinned. Write one note that keeps the clearest, most recent wording. Lose words, not facts. +4. Flag contradictions. When two notes assert opposing facts, propose the more recent, higher-confidence one as the winner and show both. +5. Split notes that hold several facts into one note per fact, named `<type>-<slug>.md`. +6. Validate frontmatter. Fix the `<type>-` filename prefix if the type changed. No nested `metadata:` blocks. +7. Refresh notes whose `sources:` URL is older than about 30 days or whose facts look outdated. Prefer `llms.txt`, bump `updated:`, and skip silently when offline. +8. Compact each note to its essential facts, about 25 lines at most. +9. Propose prunes for notes that are wrong, obsolete, out of scope, past their type's retention, or below 0.3 confidence with nothing project-specific. Never prune `pinned: true`. Refresh before deleting for age alone. +10. Fix `[[slug]]` links, remove links to deleted notes, give every note at least one link, and fold tag sprawl into the existing vocabulary. +11. Rebuild `MEMORY.md` from the surviving notes, grouped by `type`, one line each: `[Title](<file>) - hook`. +12. Remove any secrets, hosts, or confidential facts that slipped in. Set `last_dream` in state to today. -- No `type` => `unknown`. No `created`/`updated` => use file mtime. No `confidence` => - neutral. No `pinned` => false. - -## The pass (run strictly in order) - -Work in memory until the apply step; modify nothing early. - -1. **Resolve the KB.** Confirm `<path>` holds `memory/` (notes) and ideally `MEMORY.md` - (index), `raw/inbox/` (captures), `raw/` (source docs), and a state file. If the - layout differs, operate on whatever `*.md` files exist and adapt. -2. **Load.** Read the index, every note, `raw/inbox/*`, source docs, and state. -3. **Ingest inbox.** Promote durable, general facts from `raw/inbox/*` into `memory/` - (create or merge notes). Delete inbox files once distilled (they are ephemeral). Keep - `raw/` source docs (immutable ground truth); record processed ones in state. -4. **Dedupe and merge (near-duplicates).** Group notes by `type`. Two notes are - near-duplicates when: same `type`; significant-noun overlap above ~60% (a proxy for - cosine similarity > 0.9); neither is `pinned`. Draft a merged note that is more - complete and specific than either, keeping the clearest, most recent phrasing. - Lossless of meaning, not of words. -5. **Contradictions.** Two notes assert opposing facts on the same topic (for example - "deploy to ECS" vs "deploy to Vercel"). Proposed winner: more recent with higher - confidence. Present both for A/B/skip (interactive); skip in `--auto`. -6. **Split.** If a note holds multiple distinct facts, split into atomic notes (one fact - per file), renamed to `<type>-<slug>.md`. -7. **Validate frontmatter.** Every note has `name` (equals filename stem), `description`, - `type`, `tags`, `created`, `updated`. Fix the `<type>-` filename prefix if the type - changed. No nested `metadata:` blocks. -8. **Refresh from sources.** For notes with a `sources:` URL whose `updated:` is stale - (older than ~30 days) or whose facts look outdated, fetch the source (prefer - `llms.txt`), update the note, bump `updated:`. Skip silently when offline. -9. **Compact.** Trim each note to essential facts; drop filler. Aim for ~25 lines or - fewer. -10. **Prune candidates.** A note is a prune candidate when any holds: - - its `type` has a retention policy and it is older than the policy's days (compare - `created`/`updated` to today); - - `confidence` is below 0.3 AND it has no project-unique info (no paths, - identifiers, or domain nouns); - - it is wrong, obsolete, or out of scope. - Never prune `pinned: true`. Prefer refreshing (step 8) over deleting merely because - a note is old. -11. **Relink and retag.** Fix `[[slug]]` references; ensure no orphans (each note links - at least one other); merge tag sprawl into the controlled vocabulary; drop links to - deleted notes. -12. **Rebuild index.** Regenerate `MEMORY.md` from surviving notes, grouped by `type`, - one line each: `[Title](file) — hook`. -13. **Verify scope.** Confirm no secrets, hosts, or confidential facts slipped in; - remove any that did. -14. **Stamp.** Set `state.last_dream` to today. - -## Retention policies (load in step 1) - -Default per-type retention, in days (`null` means keep forever). Override via a -`retention:` map in the KB's state or config file. - -- `feedback`: 180 -- `project`: null -- `reference`: null -- `tech`: 365 -- `user`: null -- `unknown`: 90 - -## Diff report (interactive) - -Print exactly this before any change. Omit any section that has zero items. +Retention in days by type, overridable by a `retention:` map in state: `feedback` 180, `tech` 365, `unknown` 90, `user`, `project`, and `reference` kept forever. + +## Diff report + +Print this before any change and omit empty sections. ```text -## dream — consolidation report +## dream report Merges (<N>): - [note:<file1>] + [note:<file2>] -> "<merged summary, ~80 chars>" + <file1> + <file2> -> "<merged summary>" Conflicts (<N>): - [note:<fileA>] vs [note:<fileB>] — "<topic>" [A/B/skip] + <fileA> vs <fileB> on "<topic>" [A/B/skip] Prune (<N>): - [note:<file>] — <type>, <age>d old - -Inbox ingested (<N>), refreshed (<N>), split (<N>), relinked (<N>). + <file> (<type>, <age>d old) -Proposed: <N> merges, <N> prunes, <N> conflicts. Apply? [Y/n] -``` - -If there are zero proposals, print `Dream complete. No duplicate, contradictory, or stale -notes found.` and stop. - -## Resolve and apply (interactive) - -- For each conflict, collect `A`, `B`, or `skip` (empty input = skip). -- Final confirm: `Apply? [Y/n]`. `n` or `no` prints `Cancelled. No changes made.` and - stops. -- On confirm, apply in this order: - 1. **Merges** — write the merged note (`<type>-<slug>.md`; `type` and `updated` = today; - `confidence` = the higher of the two originals; a `source: dream` marker), delete - both originals, and rewrite inbound links to point at the merged slug. - 2. **Contradictions** — delete the loser of each resolved A/B pair; skipped pairs stay - untouched. - 3. **Prunes** — delete the note and its index line. - 4. **Split, refresh, compact, relink, index rebuild** — apply the file writes. - 5. **Stamp** state, and run the KB's sync step only if one exists and only after the - user confirms — never auto-push. - -## Auto mode (`--auto`) - -- **Concurrency guard.** Before working, check `${TMPDIR:-/tmp}/dream_auto.lock`. If it - exists and is less than 10 minutes old, print - `[dream --auto] another run in progress — skipping.` and stop. Otherwise write the lock - (current timestamp); delete it on every exit path. -- Run load and analyze (steps 1–3). Apply merges and prunes silently (no diff, no - prompt). Skip contradictions (human judgment). Apply split, refresh, compact, relink, - index rebuild, and stamp. -- Print: `[dream --auto] kb=<path> merged=<N> pruned=<N> conflicts_skipped=<N>`. -- If contradictions were skipped, leave a single reminder note so the human runs - interactive `dream` to resolve them. First search for an existing `dream-auto` reminder - (by `source: dream-auto`); skip storing if one already exists. - -## forget - -`dream forget "<query>" [<path>]` searches notes by keyword and semantic match, lists -them, and proposes deletion as a diff: +Inbox ingested <N>, refreshed <N>, split <N>, relinked <N>. -```text -[note:<file>] — "<title>" [Y/n] +Apply? [Y/n] ``` -Apply only approved deletions (and their index lines). Pinned notes are listed but not -deleted unless explicitly confirmed per note. +With no proposals, print `Dream complete. Nothing to change.` and stop. On `n`, print `Cancelled. No changes made.` -## Principles +## Apply order -- **Lossless of meaning** — compaction removes words and redundancy, never facts. -- **Atomic** — one fact per file after the pass. -- **Retrieval-first** — every `description` lets an agent judge relevance from the index - alone; every note is reachable via tags and `[[links]]`. -- **Conservative deletes** — prune only what is wrong, redundant, or out of scope; refresh - rather than delete just because old. -- **Idempotent** — running twice in a row changes nothing the second time. -- **No surprises** — diff before write; never auto-push or auto-sync without approval. +1. Merges. Write the merged note with `updated` set to today, the higher `confidence`, and `source: dream`. Delete both originals and rewrite inbound links. +2. Contradictions. Delete the loser of each resolved pair and leave skipped pairs alone. +3. Prunes. Delete the note and its index line. +4. Splits, refreshes, compaction, relinking, and the index rebuild. +5. Stamp state. Run the KB's sync step only if one exists and the user confirms. Never push automatically. -## Checklist +## Auto mode -- [ ] Resolved KB path from the argument or `$KB_DIR`; never assumed a fixed location. -- [ ] Held everything in memory; no writes before the diff. -- [ ] Inbox ingested and deleted; source docs kept. -- [ ] Near-duplicates merged (same type, >60% noun overlap, not pinned). -- [ ] Contradictions resolved (A/B) or skipped (`--auto`). -- [ ] Stale notes refreshed from sources before pruning; pinned notes untouched. -- [ ] Index rebuilt; no orphans; no broken `[[links]]`. -- [ ] Scope verified (no secrets, hosts, or confidential facts). -- [ ] State stamped; lock removed (`--auto`). +- Check `${TMPDIR:-/tmp}/dream_auto.lock`. If it is under 10 minutes old, print `[dream --auto] another run in progress, skipping.` and stop. Otherwise write the lock and delete it on every exit path. +- Skip the diff and prompts. Skip contradictions. +- Print `[dream --auto] kb=<path> merged=<N> pruned=<N> conflicts_skipped=<N>`. +- If conflicts were skipped, leave one reminder note marked `source: dream-auto` so a human runs interactive `dream`. Do not add a second if one exists. -## Resources +## Rules -- If the KB ships its own `DREAM.md` or `AGENTS.md`, read it first and align with its note - format, controlled vocabulary, and sync steps. +- The pass must be idempotent. A second run changes nothing. +- Every `description` must let an agent judge relevance from the index alone. +- Never assume a fixed KB location. diff --git a/kb/skills/init/SKILL.md b/kb/skills/init/SKILL.md index 1ef7aad..1821a6c 100644 --- a/kb/skills/init/SKILL.md +++ b/kb/skills/init/SKILL.md @@ -1,105 +1,34 @@ --- name: init -description: Scaffold a new shared-brain knowledge base folder (default ~/kb) — a plain-markdown, OKF v0.1-conformant memory store that any coding agent can read/write across sessions. Use when the user asks to set up, init, or bootstrap a kb / shared brain / persistent agent memory folder, or wants an OKF bundle with a graph viewer ready out of the box. +description: Scaffold a new shared-brain knowledge base folder (default ~/kb), a plain-markdown OKF v0.1 memory store any coding agent can read and write. Use when the user asks to set up or bootstrap a kb, shared brain, or persistent agent memory folder. --- -# init — scaffold a shared-brain kb folder +# init -## What this creates +Creates a self-contained folder with no database and no server. -A self-contained directory — plain markdown, no database, no server — that is: +- Protocol files: `AGENTS.md` (read and write rules), `CLAUDE.md` (pointer), `DREAM.md` (consolidation pass), `MEMORY.md` (index). +- `memory/`, an OKF v0.1 bundle with starter groups. +- `raw/inbox/` for quick captures and `raw/` for immutable sources. +- A vendored CLI in `bin/kb` and `scripts/`, so the folder works without this plugin. It includes the graph viewer renderer, `lint.sh`, `sync.sh`, and `wire.sh`. -- **A memory protocol.** `AGENTS.md` (the full read/write/dream rules), `CLAUDE.md` - (thin pointer for Claude Code), `DREAM.md` (the consolidation pass), `MEMORY.md` - (the index every agent reads first). -- **An OKF v0.1 bundle.** `memory/` is the bundle root; every note is one `.md` - file with a `type` in frontmatter. Conforms to - [OKF v0.1](https://github.com/GoogleCloudPlatform/knowledge-catalog/blob/main/okf/SPEC.md) - — see the companion **okf** skill/plugin for deeper bundle authoring and - validation. -- **A capture inbox.** `raw/inbox/` for low-ceremony daily notes; `raw/` for - immutable source docs. -- **Its own CLI and tooling**, vendored into `scripts/`/`bin/` so the folder - keeps working even if this Claude plugin is later removed: `bin/kb` - (capture/lint/sync/gen/viz/wire), `scripts/render_okf_viewer.py` (regenerates - `memory/**/index.md` + a self-contained `viz.html` graph viewer), `scripts/ -lint.sh`, `scripts/sync.sh`, `scripts/wire.sh`. +The scaffold ships no memory content, git remote, or branding. -This is the generic, brand-neutral form of a personal "shared brain" pattern — -it ships with no memory content, no assumed git remote, and no personal -branding. Everything it writes is a template for the user to fill in. - -## When to use - -- "set up a kb / shared brain / persistent memory folder for me" -- "init ~/kb" or "bootstrap my knowledge base" -- The user wants cross-session, cross-agent memory but has none yet. - -If a kb already exists at the target (has `AGENTS.md` or `memory/`), this skill -is still safe to run — see Idempotency below — but check first whether the user -actually wants `dream` (consolidate existing notes) instead of `init`. +If a kb already exists at the target, check whether the user wants the `dream` skill instead. ## Steps -1. **Resolve the target path.** Default `$HOME/kb`. Use `$KB_DIR` if set, or a - path the user gave explicitly. Confirm the path with the user if ambiguous. -2. **Scaffold.** Run the bundled script with an absolute path (it does not - expand `~`): - - ```bash - bash "${CLAUDE_PLUGIN_ROOT}/skills/init/scripts/scaffold.sh" "$HOME/kb" - ``` - - It is idempotent — creates missing files, chmods scripts executable, seeds - starter `memory/{user,feedback,reference,projects,topics}/` groups, and - **never overwrites a file that already exists** in the target. It ends by - running `render_okf_viewer.py` once so `memory/index.md` and `viz.html` - exist immediately. - -3. **Report what happened**: how many files were created vs. skipped - (pre-existing), and the target path. -4. **Offer, but do not run automatically, three follow-ups** — each changes - something outside the new folder or is otherwise consequential, so ask - first: - - **PATH.** Suggest adding `export PATH="<target>/bin:$PATH"` to the user's - shell rc. Don't edit their `.zshrc`/`.bashrc` yourself unless they ask. - - **Version control.** Offer `git init` (and `git remote add origin <url>` - if they have one). Skip silently if they don't want git. - - **Wiring.** `<target>/scripts/wire.sh on` adds a small marked block to - `~/.claude/CLAUDE.md` (and `~/.codex/AGENTS.md` / `~/.config/opencode/ -AGENTS.md` if those tools are present) so every future session - auto-reads the kb. This edits files **outside** the scaffolded folder and - affects every future session — explain what it does and get explicit - confirmation before running it. `wire.sh off` cleanly reverses it. -5. **If the user wants example notes**, don't invent personal facts — either - leave `memory/` empty for them to fill in via `kb capture`, or ask what to - record. - -## After scaffolding - -- Point to `memory/_TEMPLATE.md` for the note format and `AGENTS.md` for the - full protocol — both are self-documenting inside the new folder. -- For ongoing maintenance (merge duplicates, prune stale notes, rebuild the - index), use this plugin's **dream** skill against the new kb. -- For richer OKF authoring/validation beyond what `bin/kb gen` covers (custom - concept types, `validate_okf.py` conformance checks), use the **okf** plugin. -- `kb viz` (or `bin/kb viz` before `PATH` is set) opens the graph viewer any - time after notes are added. - -## Idempotency & safety - -- `scaffold.sh` only ever creates files that don't already exist — re-running - it against a partially-set-up or already-populated kb is safe and adds - nothing to files it finds present. -- It never touches anything outside `<target>` — no global config, no shell - rc, no git remote. Those are the explicit, confirm-first follow-ups above. -- It writes no personal data — the scaffolded files are generic templates. +1. Resolve the target: a path the user gave, else `$KB_DIR`, else `$HOME/kb`. Confirm if ambiguous. +2. Run `scripts/scaffold.sh <absolute-target>` from this skill's directory. It does not expand `~`. It creates only files that do not exist, makes scripts executable, and ends by rendering `memory/index.md` and `viz.html`. +3. Report how many files were created and how many were skipped. +4. Offer these follow-ups separately and run none without a yes. + - Add `export PATH="<target>/bin:$PATH"` to the shell rc. + - `git init`, plus `git remote add origin <url>` if the user has one. + - `<target>/scripts/wire.sh on`. It edits global agent config files outside the folder (`~/.claude/CLAUDE.md`, plus `~/.codex/AGENTS.md` and `~/.config/opencode/AGENTS.md` when present) so every future session reads the kb. `wire.sh off` reverses it. Explain this before asking. +5. Do not invent personal facts to seed `memory/`. Leave it empty or ask what to record. -## Checklist +## Afterwards -- [ ] Resolved target path (arg, `$KB_DIR`, or confirmed default `~/kb`). -- [ ] Ran `scaffold.sh` with an absolute path; reported created vs. skipped files. -- [ ] `memory/index.md` and `viz.html` exist (scaffold.sh generates them). -- [ ] Offered PATH / git init / wire as separate, confirm-first steps — did not - edit anything outside the target folder without asking. -- [ ] Did not invent personal facts to seed `memory/` with. +- The note format is `memory/_TEMPLATE.md` and the full protocol is `AGENTS.md`. +- Use the `dream` skill to consolidate notes and the `okf` plugin for custom concept types and conformance checks. +- `kb viz` opens the graph viewer. diff --git a/kb/skills/init/scripts/scaffold.sh b/kb/skills/init/scripts/scaffold.sh index 134171e..7125e64 100755 --- a/kb/skills/init/scripts/scaffold.sh +++ b/kb/skills/init/scripts/scaffold.sh @@ -3,7 +3,7 @@ # Idempotent: never overwrites a file that already exists in <target>, so it's # safe to re-run against a kb that's already partially set up. Does NOT run # git init, does NOT touch any file outside <target> (wiring is a separate, -# explicit step — see scripts/wire.sh in the scaffolded folder). +# explicit step - see scripts/wire.sh in the scaffolded folder). set -euo pipefail TEMPLATES="$(cd -P "$(dirname "${BASH_SOURCE[0]}")/../templates" && pwd)" @@ -38,7 +38,7 @@ put "scripts/render_okf_viewer.py" "scripts/render_okf_viewer.py" put "bin/kb" "bin/kb" chmod +x "$TARGET"/scripts/*.sh "$TARGET/bin/kb" 2>/dev/null || true -# Starter memory groups + inbox — empty dirs need a placeholder to survive git. +# Starter memory groups + inbox - empty dirs need a placeholder to survive git. for d in memory/user memory/feedback memory/reference memory/projects memory/topics raw/inbox; do mkdir -p "$TARGET/$d" [[ -e "$TARGET/$d/.gitkeep" ]] || { @@ -57,10 +57,10 @@ if [[ ! -e "$TARGET/MEMORY.md" ]]; then cat >"$TARGET/MEMORY.md" <<'EOF' # Memory Index -Master table of contents. One line per note — read this first, then open only +Master table of contents. One line per note - read this first, then open only the notes relevant to your task. See `AGENTS.md` for the protocol. -(No notes yet — this index is rebuilt by hand or by a `DREAM.md` pass as notes +(No notes yet - this index is rebuilt by hand or by a `DREAM.md` pass as notes are added under `memory/`.) EOF created+=("MEMORY.md") @@ -77,4 +77,4 @@ echo echo "next steps:" echo " export PATH=\"$TARGET/bin:\$PATH\" # add to your shell rc" echo " cd $TARGET && git init # optional: version control" -echo " $TARGET/scripts/wire.sh on # optional: wire the reflex into agents' global config (ask the user first — it edits files outside this folder)" +echo " $TARGET/scripts/wire.sh on # optional: wire the reflex into agents' global config (ask the user first - it edits files outside this folder)" diff --git a/kb/skills/init/templates/AGENTS.md b/kb/skills/init/templates/AGENTS.md index 60dbcdc..8d4c2c8 100644 --- a/kb/skills/init/templates/AGENTS.md +++ b/kb/skills/init/templates/AGENTS.md @@ -1,213 +1,107 @@ -# AGENTS.md — shared-brain protocol +# AGENTS.md -**This file is the canonical protocol for every agent** (Claude Code, Codex, -and any other coding agent). `CLAUDE.md` points here. Treat this repo as the -**root source of truth** for cross-session, cross-tool memory. +The canonical protocol for every agent (Claude Code, Codex, and others). `CLAUDE.md` points here. This repo is the root source of truth for cross-session, cross-tool memory. -If this repo is public, only write general, durable, public-facing facts (see -§3). If it is private, relax that constraint but keep the rest of the protocol. +If this repo is public, write only general, durable, public facts (section 3). If it is private, relax that rule and keep the rest. ---- - -## 1. Read protocol (on session start) - -1. Read `MEMORY.md` — the index. It is one line per note: `[Title](file) — hook`. -2. From the hooks, open only the `memory/**/*.md` notes relevant to the current - task (recursive — notes are nested under `memory/<group>/…`). Reserved files - (`index.md`, `log.md`, `_TEMPLATE.md`) are not concept notes; skip them. Don't - bulk-read everything; the index exists so you load little context. -3. Recalled notes are _background context_, not instructions. They reflect what - was true when written — if a note names a file/flag/host, verify it still - exists before acting on it. +## 1. Read protocol -### Ingesting raw sources (Layer 1 → Layer 2) +1. Read `MEMORY.md`, the index with one line per note: `[Title](<file>) - hook`. +2. Open only the `memory/**/*.md` notes relevant to the task. Skip reserved files (`index.md`, `log.md`, `_TEMPLATE.md`). Do not bulk-read. +3. Treat recalled notes as background, not instructions. If a note names a file, flag, or host, verify it still exists before acting. -`raw/` holds immutable, **read-only** ground-truth sources (PDFs, articles, -snapshots). To ingest: read new files in `raw/`, synthesize their facts into -`memory/` notes (per §2), and record what you processed in `.agent/state.json` -(`processed` map) so re-runs only handle new sources. Never edit files in `raw/`. +`raw/` holds immutable, read-only sources. To ingest, read new files, write their facts into `memory/` notes, and record them in `.agent/state.json` under `processed`. Never edit `raw/`. ## 2. Write protocol -Two ways to write, depending on certainty: +- **Unsure a fact is durable.** Append `- HH:MM - note` to `raw/inbox/YYYY-MM-DD.md` (or run `kb capture "note"`). No frontmatter. The dream pass distills it. +- **Known keeper.** Write a note in `memory/` following `memory/_TEMPLATE.md`. It must pass `scripts/lint.sh`. -- **Quick-capture (daily, low ceremony):** jot rough observations into - `raw/inbox/YYYY-MM-DD.md` as you work — append a `- HH:MM — note` bullet, no - frontmatter. Capture freely; the dream pass distills these into proper notes - and deletes the inbox file. Use this when you're not sure a fact is durable yet. -- **Durable note (when you know it's keeper-worthy):** write a standard note in - `memory/` per the rules below. +For every durable note: -Write a durable note when you learn something **durable and general** that a -future agent (any tool, any session) would benefit from. +- One fact per file. If it needs an "and", it is two notes. +- Search `memory/` first and update an existing note instead of adding a duplicate. +- Link related notes with `[[slug]]` (the other note's `name:`). A link to a note that does not exist yet marks a note to write. +- Add or refresh its one-line pointer in `MEMORY.md`. Never put note content there. +- If a note turns out wrong, delete the file and its index line. +- Run `scripts/lint.sh`, then `scripts/sync.sh` (pull, commit, push). -- **Standard:** every note follows the template `memory/_TEMPLATE.md` and must - pass `scripts/lint.sh` (required fields, `name` == filename, links resolve). -- **Atomic:** one fact per file. If a fact needs an `and`, it's probably two notes. -- **Check first:** search `memory/` for an existing note that covers it. **Update - that note** instead of creating a duplicate. -- **Link:** reference related notes in the body with `[[slug]]` (the other note's - `name:`). A `[[slug]]` that doesn't exist yet is fine — it marks a note to write. -- **Index:** add/refresh a one-line pointer in `MEMORY.md`. Never put note content - in `MEMORY.md`. -- **Prune:** if a note turns out wrong, delete the file and its index line. -- **Lint, then sync:** run `scripts/lint.sh`, then `scripts/sync.sh` (pull, commit, - push) so other devices/agents pick it up. +### Naming -### File naming +`memory/<group>/[<sub>/]<type>-<short-kebab-slug>.md`, where `<group>` is `user/`, `feedback/`, `reference/`, `projects/`, or `topics/<domain>/`. Nest freely. The `<type>-` prefix keeps the type visible from the path. -`memory/<group>/[<sub>/]<type>-<short-kebab-slug>.md`. `<group>` is one of -`user/`, `feedback/`, `reference/`, `projects/`, or a topic dir `topics/<domain>/`; -nest freely. The `<type>-` filename prefix is kept so `type` is visible from the -path, e.g. `memory/user/user-stack.md`, `memory/feedback/feedback-working-style.md`, -`memory/topics/infra/tech-example-pattern.md`. +### Frontmatter -### Frontmatter (required on every note) - -All fields are **top-level** (not nested) so Obsidian surfaces them as Properties -and uses `tags`/`related` for the graph view. +All fields are top level and nothing is nested, so Obsidian shows them as Properties. ```markdown --- -name: <type>-<short-kebab-case-slug> # MUST equal the filename stem; this is the [[link]] target -title: <human-readable title> # optional, shown in Obsidian -description: <one line — used to judge relevance during recall> +name: <type>-<slug> # equals the filename stem, the [[link]] target +title: <human-readable title> # optional +description: <one line, keywords first> type: user | feedback | project | reference | tech -category: <finer grouping> # e.g. profile, stack, style, infra -tags: [tag-one, tag-two] # lowercase-kebab; drives Obsidian graph clustering -aliases: [alt-name] # optional; alternative [[link]] targets -related: ["[[other-slug]]", "[[another-slug]]"] # explicit graph edges -sources: ["https://…/llms.txt"] # optional; live URLs to fetch for fresh/deeper detail +category: <finer grouping> # optional +tags: [tag-one, tag-two] # lowercase-kebab +aliases: [alt-name] # optional +related: ["[[other-slug]]"] # optional explicit edges +sources: ["https://.../llms.txt"] # optional created: YYYY-MM-DD updated: YYYY-MM-DD -timestamp: 2026-01-01T00:00:00Z # ISO 8601 — lint-required (stricter than OKF spec, which mandates only `type`) +timestamp: 2026-01-01T00:00:00Z # ISO 8601 --- -<the fact. For feedback/project, follow with **Why:** and **How to apply:** lines. -Link related notes inline with [[their-slug]] too.> +The fact. For feedback and project notes add **Why:** and **How to apply:** lines. ``` -Required: `name`, `description`, `type`, `tags`, `created`, `updated`, `timestamp` -(ISO 8601). The rest are optional but encouraged. `title`, `category`, `aliases`, -`related` improve Obsidian. - -### Live sources for deep retrieval - -A note is a **compact snapshot**; the web is the live truth. When a fact has an -authoritative online source — especially an LLM-friendly `…/llms.txt` — list it -in `sources:` (and/or link it inline). Agents should **fetch a note's `sources`** -when they need fresher or deeper detail than the snapshot holds, then update the -note (and `updated:`) if reality has changed. Prefer `llms.txt` endpoints; they -are built for exactly this. - -### Memory types - -| type | holds | -| ----------- | ----------------------------------------------------------- | -| `user` | who the user is — profile, stack, preferences | -| `feedback` | how agents should work — style, corrections, confirmed wins | -| `project` | durable context about ongoing work | -| `reference` | pointers to external resources (URLs, dashboards, docs) | -| `tech` | reusable technical knowledge / patterns | - -### Linking & tagging rules (for Obsidian graph) - -Two things drive the graph; use both. - -1. **Wikilinks `[[slug]]`** create edges between notes. Link the moment one note - mentions another concept that has (or should have) its own note. Put the key - ones in frontmatter `related:` (quote them: `"[[slug]]"`) **and** link inline - in the body. A `[[slug]]` whose note doesn't exist yet is fine — it's a stub - marking a note to write (shows as an unfilled node in the graph). -2. **Tags** create tag-nodes that cluster related notes. Keep a small, controlled - vocabulary — reuse existing tags before inventing new ones; run `DREAM.md` to - merge tag sprawl. - - Always include the `type` as a tag (e.g. `user`, `tech`). - - Add 1–4 topic tags, lowercase-kebab: an entity, a domain, and/or a facet. - - Don't tag with one-off words; a tag is only useful if ≥2 notes will share it. - -`name` must equal the filename stem so `[[name]]` resolves. Use `aliases` for -other names a note might be linked by. - -### Note quality (compact · correct · retrievable · Obsidian-friendly) - -Every note must satisfy all four: - -- **Compact.** Shortest form that stays correct. One fact per note. Prefer - tables/lists over prose; cut filler. If a note passes ~25 lines, it probably - holds >1 fact — split it. -- **Correct.** Evidence over assumption. Cite the source (a `[[link]]`, URL, or - `llms.txt`) for non-obvious facts. Stamp `updated:` when you change a note. - Never record a guess as fact — mark uncertainty inline ("(unverified)"). If a - note conflicts with newer truth, fix or delete it, don't append. -- **Retrievable.** `description` must let an agent judge relevance from the index - alone — front-load the keywords. Reuse the controlled tag/`[[link]]` vocabulary - so related notes co-locate. Title and filename should be searchable terms. -- **Obsidian-friendly.** Top-level frontmatter only (no nesting). Filename == - `name`. Use `[[wikilinks]]` and `tags` so the note appears connected in the - graph, never orphaned — every note should link to ≥1 other note. - -### OKF v0.1 conformance - -This repo **is a conformant [OKF v0.1](https://github.com/GoogleCloudPlatform/knowledge-catalog/blob/main/okf/SPEC.md) bundle** — `memory/` is the bundle root, each concept is one `.md` carrying `type` (an OKF custom field, orthogonal to the topic path). Notes on alignment: - -- **Reserved filenames are not concepts:** `index.md` (one per dir, OKF - progressive-disclosure listing) and `log.md` (root change history) are - **generated** by `kb gen` (via `scripts/render_okf_viewer.py`) — never hand-edit - them; re-run `kb gen`. `memory/index.md` carries `okf_version: "0.1"` - frontmatter; other `index.md`/`log.md` carry none. `_TEMPLATE.md` is also skipped. -- **Cross-links stay Obsidian wikilinks** (`[[slug]]`, resolved by `name:`). The - OKF spec's plain `/path.md` links also work (the renderer reads both) — pick - whichever convention you prefer and stay consistent. -- **`kb gen`** regenerates all `memory/**/index.md` files + the self-contained - `viz.html` graph viewer; **`kb viz`** regenerates and opens it. Both are - generated artifacts — re-run `kb gen` after writing notes. - -## 3. Do NOT store (only if this repo is public — treat it as read by anyone) - -If you cloned or scaffolded this as a **public** repo, never write these -anywhere in it (notes, inbox, commit messages, frontmatter, tags, filenames, -comments): - -- **Credentials:** API keys, tokens, passwords, certificates, connection strings, - auth headers, `.env` values. -- **Infrastructure:** hostnames, IP addresses, SSH endpoints, private URLs, - cluster names, subnet/VPC IDs, cloud resource IDs, internal service endpoints. -- **Machine identity:** machine names, device hostnames, server aliases, - `user@host` patterns, SSH config entries. -- **Network topology:** port numbers on internal services, VPN details, proxy - configs, firewall rules, internal DNS names. -- **Location data:** physical addresses, GPS coordinates, city of residence, - office locations, timezone-precise schedules that reveal geography. -- **Employer-internal:** project codenames, internal tool names, team structures, - org charts, internal abbreviations, customer/client names, proprietary - processes — anything not already public. -- **Personal identifiers:** phone numbers, email addresses (unless already - public), government IDs, financial data, medical information. - -**Rule of thumb:** if you would not put it on a public GitHub README, do not put -it in a public kb. When in doubt, leave it out — or keep this repo private. - -## 4. Auto-dream - -Memory degrades as it grows: duplicates, verbose notes, stale facts, broken -links, tag sprawl. The "dream" pass — full steps in `DREAM.md` — consolidates it -back into compact, correct, well-linked notes. - -Run it: - -- **Manually:** "run kb dream" → execute `DREAM.md` end to end. -- **Recurring (autopilot):** `/loop 1d "run <this kb>/DREAM.md consolidation"`. -- **Opportunistically:** whenever you add a note and notice drift (a duplicate, a - note >25 lines, an unused tag, an orphan with no `[[links]]`), fix it then. - -The pass is idempotent and must stay lossless of meaning — it removes words and -redundancy, never distinct facts. It always ends by rebuilding `MEMORY.md` and -committing. +Required: `name`, `description`, `type`, `tags`, `created`, `updated`, `timestamp`. The lint requires `timestamp`, which OKF itself does not. ---- +| type | holds | +| --- | --- | +| `user` | who the user is: profile, stack, preferences | +| `feedback` | how agents should work: style, corrections, confirmed wins | +| `project` | durable context about ongoing work | +| `reference` | pointers to external resources | +| `tech` | reusable technical knowledge and patterns | + +### Live sources + +A note is a snapshot and the web is the live truth. List an authoritative URL, preferably an `llms.txt`, in `sources:`. Fetch it when you need fresher or deeper detail, then update the note and `updated:`. + +### Links and tags + +- Link with `[[slug]]` the moment a note mentions a concept that has, or should have, its own note. Put key ones in `related:` and inline. +- Keep a small tag vocabulary and reuse tags before inventing new ones. Include the `type` as a tag, add 1 to 4 topic tags, and skip one-off words. +- Every note links to at least one other note. + +### Quality + +- **Compact.** One fact, about 25 lines at most. Prefer tables and lists. +- **Correct.** Cite non-obvious facts. Stamp `updated:` on every change. Mark guesses "(unverified)". If a note conflicts with newer truth, fix or delete it. +- **Retrievable.** The `description` lets an agent judge relevance from the index alone, so front-load keywords. + +### OKF v0.1 + +`memory/` is a conformant [OKF v0.1](https://github.com/GoogleCloudPlatform/knowledge-catalog/blob/main/okf/SPEC.md) bundle. Each concept is one `.md` with a `type`. + +- `index.md` (one per directory) and `log.md` (root change history) are generated by `kb gen`. Never hand-edit them. `memory/index.md` carries `okf_version: "0.1"`. +- `kb gen` regenerates every `memory/**/index.md` and the self-contained `viz.html`. `kb viz` does the same and opens the viewer. Re-run after writing notes. +- Cross-links are `[[slug]]` wikilinks. Plain `/path.md` links also work. Pick one and stay consistent. + +## 3. Do not store (if this repo is public) + +Never write these anywhere in the repo, including notes, inbox, commit messages, tags, and filenames. + +- Credentials: keys, tokens, passwords, certificates, connection strings, `.env` values. +- Infrastructure and network: hostnames, IPs, SSH endpoints, private URLs, cluster and cloud resource IDs, internal ports, VPN and DNS details. +- Machine identity: machine names, `user@host` patterns, SSH config. +- Location: addresses, coordinates, city of residence. +- Employer-internal: codenames, internal tools, team structure, customer names, anything not already public. +- Personal identifiers: phone numbers, non-public emails, government IDs, financial or medical data. + +If you would not put it on a public README, leave it out, or keep this repo private. + +## 4. Dream + +Run `DREAM.md` to consolidate duplicates, stale facts, broken links, and tag sprawl. Run it by hand ("run kb dream"), on a loop (`/loop 1d "run DREAM.md"`), or whenever you notice drift while adding a note. It is idempotent and never drops a distinct fact. -_Relationship to per-tool memory:_ your tool's private memory (e.g. Claude -Code's per-project `memory/`) is a scratchpad. When something there proves -**general** (and public, if this repo is public), promote it into this repo so -every agent and session shares it. +Your tool's private memory (for example Claude Code's per-project `memory/`) is a scratchpad. Promote anything general into this repo. diff --git a/kb/skills/init/templates/CLAUDE.md b/kb/skills/init/templates/CLAUDE.md index dd2ba17..67562f7 100644 --- a/kb/skills/init/templates/CLAUDE.md +++ b/kb/skills/init/templates/CLAUDE.md @@ -1,28 +1,11 @@ # CLAUDE.md -This repo is the **shared brain** — the root source of truth for agent memory -across every tool and session. +This repo is the shared brain, the root source of truth for agent memory across tools and sessions. Read [`AGENTS.md`](./AGENTS.md) for the protocol. -**The protocol lives in [`AGENTS.md`](./AGENTS.md). Read it.** It defines how to -read the index, write atomic notes, the frontmatter format, what must never be -stored, and the dream/consolidation pass. +- `MEMORY.md` is the index. Read it first. +- [`memory/`](./memory/) holds atomic notes as an OKF v0.1 bundle. +- [`DREAM.md`](./DREAM.md) is the consolidation pass. -Quick map: +Per-project memory under `~/.claude/projects/<project>/memory/` is a scratchpad. Promote general facts from it into this repo's `memory/`, then commit. -- [`MEMORY.md`](./MEMORY.md) — master index, read first. -- [`memory/`](./memory/) — atomic notes, one fact per file; OKF v0.1 bundle (nested `<group>/…` topics). -- [`DREAM.md`](./DREAM.md) — memory-consolidation protocol. -- [`README.md`](./README.md) — human onboarding & new-device setup. - -Claude-specific note: your per-project memory under -`~/.claude/projects/<project>/memory/` is a private scratchpad. When a fact -there is **general** (and public, if this repo is public), promote it into this -repo's `memory/` so every other session and tool shares it too. Then commit -(and push, if this repo has a remote). - -## ⚠️ If this repo is public - -Never commit: credentials, hostnames, IPs, machine names, SSH endpoints, -internal project names, locations, or anything not already public. Full list -in [`AGENTS.md` §3](./AGENTS.md). If you wouldn't put it on a public README, -don't put it here — or keep this repo private instead. +If this repo is public, never store credentials, hostnames, IPs, machine names, locations, or anything not already public. See `AGENTS.md` section 3. diff --git a/kb/skills/init/templates/DREAM.md b/kb/skills/init/templates/DREAM.md index 46fa5e4..007a689 100644 --- a/kb/skills/init/templates/DREAM.md +++ b/kb/skills/init/templates/DREAM.md @@ -1,64 +1,20 @@ -# DREAM.md — memory consolidation +# DREAM.md -"Dreaming" is the maintenance pass that keeps the KB compact and retrievable — -the agent equivalent of sleep consolidating the day's memories. Run it manually, -on a `/loop`, or whenever the KB feels noisy (duplicates, sprawl, stale facts). - -## When to dream - -- The index `MEMORY.md` has grown large or has near-duplicate lines. -- Several notes restate the same fact, or one note has grown into many facts. -- A note contradicts newer knowledge, or its `updated:`/`timestamp` is old and - may be stale. -- A note is orphaned (no `[[links]]`), or links/tags have sprawled. -- Links `[[slug]]` point at notes that don't exist (or should). -- New unprocessed files sit in `raw/`. -- On a schedule, e.g. `/loop 1d "run <this kb>/DREAM.md consolidation"`. +The maintenance pass that keeps this KB compact and retrievable. Run it by hand, on a schedule (`/loop 1d "run DREAM.md"`), or when notes duplicate, contradict newer facts, go stale, or sprawl. ## The pass -1. **Load.** Read `MEMORY.md`, every `memory/**/*.md` (recursive — **excluding** - reserved `index.md`, `log.md`, and `_TEMPLATE.md`), `raw/inbox/*.md`, the - `raw/` source docs, and `.agent/state.json`. -2. **Ingest & rewrite.** Read `raw/inbox/*` (daily captures) and any `raw/` source - doc not in `state.json.processed`. Promote durable, general facts into - `memory/` — **create new notes or rewrite/merge existing ones** to absorb them - (per `AGENTS.md` §2 + the standard). Then clean up: - - **inbox files:** once distilled, **delete** them (they're ephemeral). - - **source docs:** **keep** them (immutable ground truth); record in `processed`. -3. **Dedupe & merge.** Fold duplicate/overlapping notes into one. Keep the - clearest, most recent phrasing. Lossless of meaning, not of words. -4. **Split.** If a note holds multiple facts, split into atomic notes. -5. **Validate frontmatter.** Every note has top-level `name` (== filename stem), - `description`, `type`, `tags`, `created`, `updated`, `timestamp` (ISO 8601). - Fix the `<type>-` filename prefix if `type` changed. No nested `metadata:` - blocks. -6. **Refresh from sources.** For notes with a `sources:` URL whose `timestamp`/ - `updated:` is stale (>~30 days) or whose facts look outdated, fetch the source - (prefer `llms.txt`), update the note, and bump `updated:` and `timestamp`. -7. **Compact.** Trim notes to the essential facts. Drop filler. Aim ≤~25 lines. -8. **Relink & retag.** Fix `[[slug]]` references; ensure no orphans (every note - links ≥1 other); merge tag sprawl into the controlled vocabulary; drop links - to deleted notes. -9. **Prune.** Delete notes that are wrong, obsolete, or now-private — and their - index lines. -10. **Rebuild index.** Regenerate `MEMORY.md` from surviving notes — grouped by - `type`, one line each: `[Title](file) — hook`. Then run **`kb gen`** to - regenerate every `memory/**/index.md` (OKF listings) + `viz.html` (graph - viewer) so they stay in sync with the nested layout. Append a new dated entry - to `memory/log.md` summarizing the pass (what merged/split/pruned). -11. **Verify scope.** If this repo is public, confirm no secrets/hosts/confidential - facts slipped in (`AGENTS.md` §3). Remove any that did. -12. **Stamp & sync.** Set `state.json.last_dream` to today, then `scripts/sync.sh` - (only if this repo has a git remote). - -## Principles +1. Load `MEMORY.md`, every `memory/**/*.md` except `index.md`, `log.md`, and `_TEMPLATE.md`, `raw/inbox/*.md`, the `raw/` source docs, and `.agent/state.json`. +2. Ingest. Promote durable, general facts from the inbox and from any `raw/` doc not in `state.json.processed` into new or rewritten notes (see `AGENTS.md` section 2). Delete processed inbox files. Keep source docs and record them in `processed`. +3. Merge duplicates into one note. Keep the clearest, most recent wording. Lose words, not facts. +4. Split notes that hold several facts. +5. Validate frontmatter: top-level `name` (equals the filename stem), `description`, `type`, `tags`, `created`, `updated`, `timestamp`. Fix the `<type>-` filename prefix if `type` changed. +6. Refresh notes whose `sources:` are older than about 30 days, preferring `llms.txt`. Bump `updated` and `timestamp`. +7. Compact each note to about 25 lines. +8. Fix `[[slug]]` links, give every note at least one link, and fold tag sprawl into the existing vocabulary. +9. Prune notes that are wrong, obsolete, or now private. Refresh instead of deleting for age alone. +10. Rebuild `MEMORY.md`, grouped by `type`, one line each: `[Title](<file>) - hook`. Run `kb gen` to regenerate `memory/**/index.md` and `viz.html`, then append a dated entry to `memory/log.md`. +11. If this repo is public, remove anything that breaks `AGENTS.md` section 3. +12. Set `state.json.last_dream` to today and run `scripts/sync.sh` if there is a git remote. -- **Lossless of meaning.** Compaction removes words and redundancy, never facts. -- **Atomic.** One fact per file after the pass. -- **Retrieval-first.** Every `description` must let an agent judge relevance from - the index alone; every note is reachable via tags and `[[links]]`. -- **Conservative deletes.** Only prune what is wrong, redundant, or out-of-scope — - never delete a fact just because it's old (refresh it instead, step 6). -- **Idempotent.** Running the pass twice in a row should change nothing the - second time. +The pass is idempotent. A second run changes nothing. diff --git a/kb/skills/init/templates/README.md b/kb/skills/init/templates/README.md index 3c8c281..49e134e 100644 --- a/kb/skills/init/templates/README.md +++ b/kb/skills/init/templates/README.md @@ -1,91 +1,34 @@ -# kb — your shared brain +# kb -A single, plain-text knowledge base that every coding agent (Claude Code, Codex, -opencode, …) reads from and writes to — the root source of truth for agent -memory on this machine. Write a fact once; every agent and session uses it. +A plain-text knowledge base that every coding agent reads from and writes to. Write a fact once and every agent and session uses it. -## Design +It is plain markdown with no database, atomic notes, an index-first read (`MEMORY.md`), `[[wikilinks]]` and tags for a graph view (Obsidian or `kb viz`), and a `DREAM.md` pass that keeps it tidy. `memory/` is a conformant [OKF v0.1](https://github.com/GoogleCloudPlatform/knowledge-catalog/blob/main/okf/SPEC.md) bundle. -Simple and hackable (Zettelkasten-style): plain markdown, no database (agents -`grep` it); **atomic notes** (one fact per file); **index-first** (`MEMORY.md` -loaded before anything else); **linked** via `[[wikilinks]]` + `tags` (browsable -as a graph in Obsidian, or `kb viz` for a standalone viewer); **self-healing** -via the `DREAM.md` consolidation pass. +## Layout -## Structure +- `AGENTS.md` is the protocol for all agents. `CLAUDE.md` points to it. +- `DREAM.md` is the consolidation pass. `MEMORY.md` is the index. +- `memory/` holds the notes, nested under `<group>/`. `index.md`, `log.md`, and `viz.html` are generated by `kb gen`. `_TEMPLATE.md` is the note standard. +- `raw/` holds the capture inbox (`raw/inbox/`) and source docs. +- `bin/kb` and `scripts/` are the CLI. `.agent/state.json` holds ingest state. -```text -. -├── AGENTS.md ← canonical protocol for ALL agents (read/write/dream rules) -├── CLAUDE.md ← thin pointer to AGENTS.md -├── DREAM.md ← memory-consolidation ("dream") protocol -├── MEMORY.md ← master index, one line per note — load first -├── raw/ ← capture inbox (raw/inbox/<date>.md) + ground-truth sources -├── memory/ ← the OKF v0.1 bundle: notes nested under <group>/… -│ ├── index.md ← generated OKF listing (okf_version: "0.1") — run `kb gen` -│ ├── log.md ← generated change history (newest-first) -│ ├── _TEMPLATE.md ← the note standard -│ └── user/ feedback/ reference/ projects/ topics/ ← starter groups; nest freely -├── scripts/ ← kb CLI internals: lint / sync / wire / render_okf_viewer.py -├── bin/kb ← the `kb` CLI -├── viz.html ← generated self-contained graph viewer — run `kb viz` -└── .agent/ ← state.json (ingested files + tasks) -``` - -This repo **is a conformant [OKF v0.1](https://github.com/GoogleCloudPlatform/knowledge-catalog/blob/main/okf/SPEC.md) bundle** — `memory/` is the bundle root; each concept is one `.md` carrying `type` (an OKF custom field). `index.md`/`log.md`/`viz.html` are generated; re-run `kb gen` (or `kb viz` to also open the viewer) after writing notes. - -Every note follows `memory/_TEMPLATE.md` and must pass `kb lint`. Format spec in -`AGENTS.md`. - -## How it works - -- **Read in:** `kb index` (= `MEMORY.md`), open the relevant notes; fetch a note's - `sources:` (`llms.txt`) for deeper detail. -- **Write out:** unsure it's durable → `kb capture "note"` (lands in `raw/inbox/`); - known keeper → a standard note in `memory/<group>/…`. Then - `kb lint && kb gen` (regenerate the OKF `index.md`/`viz.html`), and - `kb sync` if this repo has a git remote. -- **Dream:** periodically (or `/loop`) run `DREAM.md` — it ingests the inbox + raw - sources into clean notes, dedupes, refreshes stale notes from `sources:`, rebuilds - the index, and syncs. - -## Put this KB on PATH - -```bash -export PATH="<this-directory>/bin:$PATH" # add to ~/.zshrc or ~/.bashrc -``` - -## Wire the reflex into your agents (optional) - -`scripts/wire.sh on` adds a small, removable, marked block to each installed -agent's global instruction file (`~/.claude/CLAUDE.md`, `~/.codex/AGENTS.md`, -`~/.config/opencode/AGENTS.md` — only the ones that already exist) so every new -session reads `MEMORY.md` on start and knows how to capture/write notes. Remove -it any time with `scripts/wire.sh off`; it touches nothing else in those files. - -## Version control (optional but recommended) - -```bash -git init -git remote add origin <your-git-remote> # e.g. a private repo for personal notes -``` +## Use -If you make this repo **public**, keep only general, durable, public-facing -knowledge in it — see `AGENTS.md` §3 for what must never be committed. +- Read: `kb index`, open the relevant notes, and fetch a note's `sources:` for depth. +- Write: `kb capture "note"` when unsure, or a standard note in `memory/<group>/` for a keeper. Then `kb lint && kb gen`, and `kb sync` if there is a git remote. +- Dream: run `DREAM.md` periodically or with `/loop`. -## CLI +Put the CLI on PATH with `export PATH="<this-directory>/bin:$PATH"`. ```bash -kb capture "rough note" # → raw/inbox/<today>.md +kb capture "rough note" # raw/inbox/<today>.md kb ingest <file> # add a source doc to raw/ kb index | kb lint | kb sync | kb dream | kb root -kb gen | kb viz # regenerate (and open) the OKF index.md files + viz.html -kb wire on|off # add/remove the reflex block in agents' global config -kb autosync on|off|status # opt-in */15min sync cron (requires a git remote) +kb gen | kb viz # regenerate (and open) index.md files and viz.html +kb wire on|off # add or remove the reflex block in agents' global config +kb autosync on|off|status # opt-in 15 minute sync cron, needs a git remote ``` -## Scope +`scripts/wire.sh on` adds a small marked block to each existing agent global instruction file (`~/.claude/CLAUDE.md`, `~/.codex/AGENTS.md`, `~/.config/opencode/AGENTS.md`) so new sessions read `MEMORY.md`. `scripts/wire.sh off` removes it. -If this repo is public: general, durable, public-facing knowledge only. -**Never** here: secrets, SSH hosts, internal/employer-confidential details, -anything private — keep those in a private repo or the agent's local memory. +For version control, run `git init` and add a remote. If the repo is public, keep only general, public knowledge in it (`AGENTS.md` section 3). diff --git a/kb/skills/init/templates/bin/kb b/kb/skills/init/templates/bin/kb index 9c7b646..71d618f 100755 --- a/kb/skills/init/templates/bin/kb +++ b/kb/skills/init/templates/bin/kb @@ -1,5 +1,5 @@ #!/usr/bin/env bash -# kb — capture/ingest/consolidate this shared-brain knowledge base. +# kb - capture/ingest/consolidate this shared-brain knowledge base. # KB location is configurable: $KB_DIR if set, else auto-detected from this # script's own location (resolves symlinks), so it works wherever kb lives. set -euo pipefail @@ -30,8 +30,8 @@ capture | c) } f="$(inbox)" mkdir -p "$(dirname "$f")" - [[ -f "$f" ]] || printf '# Inbox — %s\n\n' "$(date +%F)" >"$f" - printf -- '- %s — %s\n' "$(date +%H:%M)" "$text" >>"$f" + [[ -f "$f" ]] || printf '# Inbox - %s\n\n' "$(date +%F)" >"$f" + printf -- '- %s - %s\n' "$(date +%H:%M)" "$text" >>"$f" echo "captured → ${f#"$KB_DIR"/} (run 'kb sync' to push)" ;; ingest | i) @@ -87,7 +87,7 @@ autosync) ;; help | -h | --help) cat <<EOF -kb — shared-brain CLI (KB_DIR=$KB_DIR) +kb - shared-brain CLI (KB_DIR=$KB_DIR) kb capture "<note>" append a timestamped line to today's raw/inbox kb ingest <file> copy a source doc into raw/ for later ingestion diff --git a/kb/skills/init/templates/memory/_TEMPLATE.md b/kb/skills/init/templates/memory/_TEMPLATE.md index 2f0d37f..2ca6616 100644 --- a/kb/skills/init/templates/memory/_TEMPLATE.md +++ b/kb/skills/init/templates/memory/_TEMPLATE.md @@ -1,7 +1,7 @@ --- name: type-short-kebab-slug title: Human-readable title -description: One line — front-load keywords; this is what agents see in the index +description: One line with the keywords first. Agents judge relevance from this in the index. type: user category: profile tags: [type, topic-one, topic-two] @@ -13,12 +13,9 @@ updated: 2026-01-01 timestamp: 2026-01-01T00:00:00Z --- -The fact(s), compact. One entity/topic per file, ≤~25 lines. Prefer lists/tables -over prose. Cite non-obvious claims with a [[link]] or URL. +One fact, about 25 lines at most. Prefer lists and tables. Cite non-obvious claims with a [[link]] or URL. -For `feedback`/`project` notes, add: +For `feedback` and `project` notes, add: -**Why:** the reason this matters. -**How to apply:** the concrete action an agent should take. - -Link related notes inline with [[their-slug]] so nothing is orphaned. +**Why:** the reason it matters. +**How to apply:** the action an agent should take. diff --git a/kb/skills/init/templates/raw/README.md b/kb/skills/init/templates/raw/README.md index cdb335a..f067bab 100644 --- a/kb/skills/init/templates/raw/README.md +++ b/kb/skills/init/templates/raw/README.md @@ -1,25 +1,8 @@ -# raw/ — capture inbox + ground-truth sources (Layer 1) +# raw -Raw material that the **dream** pass (`../DREAM.md`) consumes into clean, -linked notes under `../memory/`. Two kinds of content live here: +Input for the dream pass (`../DREAM.md`). -## `inbox/` — daily quick-capture (writable, ephemeral) - -Agents append rough observations here as they work — no frontmatter, no -ceremony. One file per day: `inbox/YYYY-MM-DD.md`, timestamped bullets. This is -a scratch journal, not the final memory. - -The dream pass **consumes** these: it promotes durable, general facts into -`memory/` notes, then **deletes the processed inbox file** (it's been distilled). -So `inbox/` stays small and self-cleaning — capture freely, dream tidies up. - -## source docs — immutable ground truth (read-only) - -Drop PDFs, articles, transcripts, `llms.txt` snapshots directly in `raw/` (not in -`inbox/`). Agents read these to synthesize notes but **never edit them**. Dream -records each in `.agent/state.json` (`processed`) so it's ingested once, and -**keeps** the file (it's permanent ground truth, unlike the inbox). - ---- +- `inbox/YYYY-MM-DD.md` holds rough captures as timestamped bullets with no frontmatter. The dream pass promotes durable facts into `../memory/` and deletes the processed file. +- Source docs placed directly in `raw/` (PDFs, articles, `llms.txt` snapshots) are read-only ground truth. Never edit them. Dream records each one in `.agent/state.json` under `processed` and keeps the file. If this repo is public, keep only public material here. diff --git a/kb/skills/init/templates/scripts/lint.sh b/kb/skills/init/templates/scripts/lint.sh index cc12304..f8c7037 100755 --- a/kb/skills/init/templates/scripts/lint.sh +++ b/kb/skills/init/templates/scripts/lint.sh @@ -7,7 +7,7 @@ set -euo pipefail REPO="${KB_DIR:-$HOME/kb}" cd "$REPO" -# `timestamp` (ISO 8601) is required by our lint — stricter than the OKF spec +# `timestamp` (ISO 8601) is required by our lint - stricter than the OKF spec # (which only mandates `type`), matching Google's reference validator, which # rejects a concept missing type/title/description/timestamp. REQUIRED=(name description type tags created updated timestamp) @@ -24,7 +24,7 @@ while IFS= read -r f; do done < <(find memory -type f -name '*.md' | sort) if [[ ${#notes[@]} -eq 0 ]]; then - echo "✓ 0 notes yet — nothing to lint" + echo "✓ 0 notes yet - nothing to lint" exit 0 fi @@ -50,7 +50,7 @@ for f in "${notes[@]}"; do } grep -qE '^metadata:' <<<"$fm" && { - echo "✗ $f: nested 'metadata:' block — use top-level fields" + echo "✗ $f: nested 'metadata:' block - use top-level fields" fail=1 } @@ -65,10 +65,10 @@ done # Broken-link check across all notes. while read -r target; do [[ -z "$target" ]] && continue - [[ "$slugs" == *" $target "* ]] || echo "✗ broken link: [[$target]] has no note (stub — create it or fix)" + [[ "$slugs" == *" $target "* ]] || echo "✗ broken link: [[$target]] has no note (stub - create it or fix)" done < <(grep -rho '\[\[[^]]*\]\]' "${notes[@]}" 2>/dev/null | sed 's/\[\[//;s/\]\]//' | sort -u) -# Security leak check — only meaningful if this repo is public (AGENTS.md §3). +# Security leak check - only meaningful if this repo is public (AGENTS.md §3). while IFS= read -r line; do [[ -z "$line" ]] && continue echo "✗ possible secret/host leak: $line" diff --git a/kb/skills/init/templates/scripts/render_okf_viewer.py b/kb/skills/init/templates/scripts/render_okf_viewer.py index c79b0bf..6402bb1 100755 --- a/kb/skills/init/templates/scripts/render_okf_viewer.py +++ b/kb/skills/init/templates/scripts/render_okf_viewer.py @@ -1,17 +1,15 @@ #!/usr/bin/env python3 -# Vendored from the `okf` plugin's skills/okf/scripts/render_okf_viewer.py so -# this kb stays self-contained (works even if that plugin is uninstalled). """Render OKF v0.1 derived artifacts for any bundle. Stdlib only. Walks a bundle directory once and emits: - - `<dir>/index.md` at every level — OKF progressive-disclosure listings + - `<dir>/index.md` at every level - OKF progressive-disclosure listings (root carries `okf_version: "0.1"`; others carry none) - - `<bundle>/viz.html` (or --out) — self-contained graph viewer + - `<bundle>/viz.html` (or --out) - self-contained graph viewer (cytoscape + marked via CDN) Frontmatter is read with a flat line-scan (`key: value`), the same convention -used by validate_okf.py — no nested YAML, no PyYAML dependency. Concepts link +used by validate_okf.py - no nested YAML, no PyYAML dependency. Concepts link to each other three ways, all three are read as graph edges: - `related: ["[[slug]]", "other-slug"]` frontmatter - `[[slug]]` wikilinks in the body @@ -25,7 +23,7 @@ Trust boundary: viz.html renders each concept's title/description/tags/type HTML-escaped, but a concept's markdown *body* is passed through `marked.parse` -unsanitized, same as any local Markdown-to-HTML viewer (e.g. Obsidian) — a +unsanitized, same as any local Markdown-to-HTML viewer (e.g. Obsidian) - a bundle is trusted the way a vault you open locally is trusted. Don't point this at a bundle containing untrusted, unreviewed markdown. """ @@ -35,7 +33,7 @@ import re import sys -# Deterministic, cycling palette — assigned to types in first-seen order so +# Deterministic, cycling palette - assigned to types in first-seen order so # any bundle's custom `type` values get stable, distinct colors without # hardcoding a fixed vocabulary. PALETTE = [ @@ -100,7 +98,7 @@ def collect(root): slug = name[:-3] if slug in seen_slugs: print(f"warning: duplicate slug '{slug}' ({rel} and {seen_slugs[slug]}) " - "— ids will collide in the viewer; rename one", file=sys.stderr) + "- ids will collide in the viewer; rename one", file=sys.stderr) seen_slugs[slug] = rel md_links = [ href.split("#")[0] for href in re.findall(r"\]\(([^)\s]+)\)", body) @@ -138,7 +136,7 @@ def write_indexes(root, concepts, bundle_label): by_dir.setdefault(c["dirpath"], []).append(c) # Bottom-up: a directory earns an index.md only if it holds concepts - # itself or a child directory does — so a parent's "Groups" links never + # itself or a child directory does - so a parent's "Groups" links never # point at an empty, unindexed child, and hidden dirs (holding no # collected concepts) never qualify. has_content = set() @@ -169,7 +167,7 @@ def write_indexes(root, concepts, bundle_label): if here: out += ["## Concepts", ""] for c in here: - tail = f" — {c['description']}" if c["description"] else "" + tail = f" - {c['description']}" if c["description"] else "" out.append(f"- [{c['title']}]({os.path.basename(c['path'])}){tail}") out += [""] p = os.path.join(dirpath, "index.md") @@ -221,7 +219,7 @@ def build_bundle(root, concepts): <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> -<title>__NAME__ — OKF Bundle Viewer +__NAME__ - OKF Bundle Viewer
- - + +
@@ -38,32 +63,83 @@ Uses the "Radio State Engine" for zero-JS interactivity. ``` ## 2. Code Diff Viewer + Optimized for PR reviews. ```html ``` ## 3. Status Board (Kanban/Triage) + ```html ``` ## 4. JS Utility: Copy to Clipboard + Simple snippet for code blocks or prompt tuners. ```javascript @@ -72,50 +148,140 @@ function copyText(id) { navigator.clipboard.writeText(text).then(() => { const btn = event.target; const original = btn.innerText; - btn.innerText = 'Copied!'; - setTimeout(() => btn.innerText = original, 2000); + btn.innerText = "Copied!"; + setTimeout(() => (btn.innerText = original), 2000); }); } ``` ## 5. Visual Timeline (Milestones) + ```html ``` ## 6. Risk / Impact Matrix + ```html ``` ## 7. Interactive SVG Flowchart + Use inline SVGs for diagrams. Add simple hover effects for interactivity. ```html - + @@ -128,38 +294,83 @@ Use inline SVGs for diagrams. Add simple hover effects for interactivity. ``` ## 9. Slide Deck (Full-screen Sections) + ```html ``` ## 11. Sidebar Navigation (Multi-Page Artifacts) + Uses radio buttons for switching between "pages" within a single HTML file. ```html -
``` - diff --git a/good-html/skills/good-html/references/styles.md b/good-html/skills/good-html/references/styles.md index 0293b84..eb070f7 100644 --- a/good-html/skills/good-html/references/styles.md +++ b/good-html/skills/good-html/references/styles.md @@ -3,40 +3,46 @@ This guide defines the aesthetic standards for `good-html` artifacts. Strictly follow these to avoid the "generic AI" look and produce professional, high-fidelity engineering documents. ## 1. Color Palettes + Avoid standard bright blue/purple gradients. Use these muted, sophisticated palettes. ### Core Palette (The "Engineering" Look) -* `--ivory`: `#FAF9F5` (Main background) -* `--paper`: `#FFFFFF` (Card background) -* `--slate`: `#141413` (Main text) -* `--clay`: `#D97757` (Primary accent / Warnings) -* `--olive`: `#788C5D` (Success / Safe / Secondary accent) -* `--oat`: `#E3DACC` (Borders / Background accents) -* `--rust`: `#B04A3F` (Critical / Errors) + +- `--ivory`: `#FAF9F5` (Main background) +- `--paper`: `#FFFFFF` (Card background) +- `--slate`: `#141413` (Main text) +- `--clay`: `#D97757` (Primary accent / Warnings) +- `--olive`: `#788C5D` (Success / Safe / Secondary accent) +- `--oat`: `#E3DACC` (Borders / Background accents) +- `--rust`: `#B04A3F` (Critical / Errors) ### Neutrals (Grays) -* `--g100`: `#F0EEE6` (Code background / Section headers) -* `--g200`: `#E6E3DA` (Subtle borders) -* `--g300`: `#D1CFC5` (Prominent borders) -* `--g500`: `#87867F` (Muted text / Captions) -* `--g700`: `#3D3D3A` (Stronger accents) + +- `--g100`: `#F0EEE6` (Code background / Section headers) +- `--g200`: `#E6E3DA` (Subtle borders) +- `--g300`: `#D1CFC5` (Prominent borders) +- `--g500`: `#87867F` (Muted text / Captions) +- `--g700`: `#3D3D3A` (Stronger accents) ## 2. Typography + Use robust system font stacks. -* **Serif (Headers):** `ui-serif, Georgia, "Times New Roman", Times, serif;` - * *Usage:* Use for `h1`, `h2`, and quotes. It gives the document a "published" or "official report" feel. -* **Sans (Body):** `system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;` - * *Usage:* Main body text, UI labels. -* **Mono (Code):** `ui-monospace, "SF Mono", Menlo, Monaco, Consolas, monospace;` - * *Usage:* Code blocks, badges, technical IDs, and data labels. +- **Serif (Headers):** `ui-serif, Georgia, "Times New Roman", Times, serif;` + - _Usage:_ Use for `h1`, `h2`, and quotes. It gives the document a "published" or "official report" feel. +- **Sans (Body):** `system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;` + - _Usage:_ Main body text, UI labels. +- **Mono (Code):** `ui-monospace, "SF Mono", Menlo, Monaco, Consolas, monospace;` + - _Usage:_ Code blocks, badges, technical IDs, and data labels. ## 3. UI Components Style -* **Cards:** 1.5px solid borders (`--g300`), 12px border radius, subtle box-shadow (`0 4px 12px rgba(20,20,19,0.03)`). -* **Badges:** 1.5px solid borders, monospaced font, small caps or all caps for labels. -* **Spacing:** Use generous padding (48px top/bottom for pages, 24px for cards) and a tall `line-height: 1.55`. + +- **Cards:** 1.5px solid borders (`--g300`), 12px border radius, subtle box-shadow (`0 4px 12px rgba(20,20,19,0.03)`). +- **Badges:** 1.5px solid borders, monospaced font, small caps or all caps for labels. +- **Spacing:** Use generous padding (48px top/bottom for pages, 24px for cards) and a tall `line-height: 1.55`. ## 4. Layout Rules -* **Page Width:** Maximum `920px` for optimal readability. -* **Grid Gap:** Standardize on `20px` or `24px`. -* **Sticky Elements:** Always stick headers for long data tables or sidebars for multi-section reports to maintain context. + +- **Page Width:** Maximum `920px` for optimal readability. +- **Grid Gap:** Standardize on `20px` or `24px`. +- **Sticky Elements:** Always stick headers for long data tables or sidebars for multi-section reports to maintain context. diff --git a/interview/.codex-plugin/plugin.json b/interview/.codex-plugin/plugin.json index d24aa58..84219d3 100644 --- a/interview/.codex-plugin/plugin.json +++ b/interview/.codex-plugin/plugin.json @@ -14,10 +14,7 @@ "shortDescription": "Interview the user to clarify requirements, then write a spec.", "developerName": "duyet", "category": "Productivity", - "capabilities": [ - "Skill", - "Command" - ], + "capabilities": ["Skill", "Command"], "logo": "./assets/logo.svg", "composerIcon": "./assets/logo.svg" } diff --git a/interview/.grok-build-plugin/plugin.json b/interview/.grok-build-plugin/plugin.json index c796ab4..cd579cf 100644 --- a/interview/.grok-build-plugin/plugin.json +++ b/interview/.grok-build-plugin/plugin.json @@ -15,10 +15,7 @@ "shortDescription": "Interview the user to clarify requirements, then write a spec.", "developerName": "duyet", "category": "Productivity", - "capabilities": [ - "Skill", - "Command" - ], + "capabilities": ["Skill", "Command"], "logo": "./assets/logo.svg", "composerIcon": "./assets/logo.svg" } diff --git a/interview/.grok-plugin/plugin.json b/interview/.grok-plugin/plugin.json index 3f32da7..136191b 100644 --- a/interview/.grok-plugin/plugin.json +++ b/interview/.grok-plugin/plugin.json @@ -8,9 +8,7 @@ }, "license": "MIT", "logo": "./assets/logo.svg", - "keywords": [ - "interview" - ], + "keywords": ["interview"], "skills": "./skills/", "commands": "./commands/" } diff --git a/interview/README.md b/interview/README.md index be9c380..6c550a3 100644 --- a/interview/README.md +++ b/interview/README.md @@ -13,7 +13,7 @@ Clarify ambiguous requirements before coding. Claude asks batched, option-based ## Usage -``` +```text /interview "add a commenting system to the blog" /interview ./docs/feature-spec.md ``` diff --git a/kb/.codex-plugin/plugin.json b/kb/.codex-plugin/plugin.json index 558b718..22dfb5a 100644 --- a/kb/.codex-plugin/plugin.json +++ b/kb/.codex-plugin/plugin.json @@ -14,10 +14,7 @@ "shortDescription": "Knowledge base maintenance skills. Initialize a shared-brain kb, then consolidate, dedupe, prune, refresh, and forget notes in a markdown KB.", "developerName": "duyet", "category": "Productivity", - "capabilities": [ - "Skill", - "Command" - ], + "capabilities": ["Skill", "Command"], "logo": "./assets/logo.svg", "composerIcon": "./assets/logo.svg" } diff --git a/kb/.grok-build-plugin/plugin.json b/kb/.grok-build-plugin/plugin.json index d4fefb6..ee059c3 100644 --- a/kb/.grok-build-plugin/plugin.json +++ b/kb/.grok-build-plugin/plugin.json @@ -15,10 +15,7 @@ "shortDescription": "Knowledge base maintenance skills. Initialize a shared-brain kb, then consolidate, dedupe, prune, refresh, and forget notes in a markdown KB.", "developerName": "duyet", "category": "Productivity", - "capabilities": [ - "Skill", - "Command" - ], + "capabilities": ["Skill", "Command"], "logo": "./assets/logo.svg", "composerIcon": "./assets/logo.svg" } diff --git a/kb/.grok-plugin/plugin.json b/kb/.grok-plugin/plugin.json index f3de36b..8805781 100644 --- a/kb/.grok-plugin/plugin.json +++ b/kb/.grok-plugin/plugin.json @@ -8,9 +8,7 @@ }, "license": "MIT", "logo": "./assets/logo.svg", - "keywords": [ - "kb" - ], + "keywords": ["kb"], "skills": "./skills/", "commands": "./commands/" } diff --git a/kb/skills/init/templates/AGENTS.md b/kb/skills/init/templates/AGENTS.md index 8d4c2c8..658338d 100644 --- a/kb/skills/init/templates/AGENTS.md +++ b/kb/skills/init/templates/AGENTS.md @@ -36,18 +36,18 @@ All fields are top level and nothing is nested, so Obsidian shows them as Proper ```markdown --- -name: - # equals the filename stem, the [[link]] target -title: # optional +name: - # equals the filename stem, the [[link]] target +title: # optional description: type: user | feedback | project | reference | tech -category: # optional -tags: [tag-one, tag-two] # lowercase-kebab -aliases: [alt-name] # optional -related: ["[[other-slug]]"] # optional explicit edges -sources: ["https://.../llms.txt"] # optional +category: # optional +tags: [tag-one, tag-two] # lowercase-kebab +aliases: [alt-name] # optional +related: ["[[other-slug]]"] # optional explicit edges +sources: ["https://.../llms.txt"] # optional created: YYYY-MM-DD updated: YYYY-MM-DD -timestamp: 2026-01-01T00:00:00Z # ISO 8601 +timestamp: 2026-01-01T00:00:00Z # ISO 8601 --- The fact. For feedback and project notes add **Why:** and **How to apply:** lines. @@ -55,13 +55,13 @@ The fact. For feedback and project notes add **Why:** and **How to apply:** line Required: `name`, `description`, `type`, `tags`, `created`, `updated`, `timestamp`. The lint requires `timestamp`, which OKF itself does not. -| type | holds | -| --- | --- | -| `user` | who the user is: profile, stack, preferences | -| `feedback` | how agents should work: style, corrections, confirmed wins | -| `project` | durable context about ongoing work | -| `reference` | pointers to external resources | -| `tech` | reusable technical knowledge and patterns | +| type | holds | +| ----------- | ---------------------------------------------------------- | +| `user` | who the user is: profile, stack, preferences | +| `feedback` | how agents should work: style, corrections, confirmed wins | +| `project` | durable context about ongoing work | +| `reference` | pointers to external resources | +| `tech` | reusable technical knowledge and patterns | ### Live sources diff --git a/marketplace.json b/marketplace.json index eeef08c..48acfa3 100644 --- a/marketplace.json +++ b/marketplace.json @@ -79,10 +79,10 @@ "category": "Productivity" }, { - "name": "clickhouse-monitoring", - "displayName": "Clickhouse Monitoring", + "name": "chmonitor", + "displayName": "chmonitor", "description": "Work on the ClickHouse Monitor dashboard: charts, pages, query configs, its API, and version-aware system queries.", - "version": "1.2.0", + "version": "2.0.0", "category": "Monitoring" }, { diff --git a/okf/.codex-plugin/plugin.json b/okf/.codex-plugin/plugin.json index 4fd8933..6779b51 100644 --- a/okf/.codex-plugin/plugin.json +++ b/okf/.codex-plugin/plugin.json @@ -13,9 +13,7 @@ "shortDescription": "Open Knowledge Format (OKF) tooling. Author, initialize, validate, render, and refactor knowledge into vendor-neutral OKF v0.1 bundles: markdown files with YAML frontmatter.", "developerName": "duyet", "category": "Productivity", - "capabilities": [ - "Skill" - ], + "capabilities": ["Skill"], "logo": "./assets/logo.svg", "composerIcon": "./assets/logo.svg" } diff --git a/okf/.grok-build-plugin/plugin.json b/okf/.grok-build-plugin/plugin.json index ba37bfb..86858b9 100644 --- a/okf/.grok-build-plugin/plugin.json +++ b/okf/.grok-build-plugin/plugin.json @@ -14,9 +14,7 @@ "shortDescription": "Open Knowledge Format (OKF) tooling. Author, initialize, validate, render, and refactor knowledge into vendor-neutral OKF v0.1 bundles: markdown files with YAML frontmatter.", "developerName": "duyet", "category": "Productivity", - "capabilities": [ - "Skill" - ], + "capabilities": ["Skill"], "logo": "./assets/logo.svg", "composerIcon": "./assets/logo.svg" } diff --git a/okf/.grok-plugin/plugin.json b/okf/.grok-plugin/plugin.json index a9037bf..5946f7e 100644 --- a/okf/.grok-plugin/plugin.json +++ b/okf/.grok-plugin/plugin.json @@ -8,8 +8,6 @@ }, "license": "MIT", "logo": "./assets/logo.svg", - "keywords": [ - "okf" - ], + "keywords": ["okf"], "skills": "./skills/" } diff --git a/okf/skills/okf/SKILL.md b/okf/skills/okf/SKILL.md index a26b52a..8a12703 100644 --- a/okf/skills/okf/SKILL.md +++ b/okf/skills/okf/SKILL.md @@ -37,8 +37,8 @@ timestamp: 2026-01-01T00:00:00Z # Schema -| Column | Type | Description | -| --- | --- | --- | +| Column | Type | Description | +| ----------- | ------ | --------------------------------------- | | customer_id | STRING | FK to [customers](/tables/customers.md) | ``` diff --git a/okf/skills/okf/reference/SPEC.md b/okf/skills/okf/reference/SPEC.md index 7af03f8..3c6748a 100644 --- a/okf/skills/okf/reference/SPEC.md +++ b/okf/skills/okf/reference/SPEC.md @@ -103,12 +103,12 @@ Optional, support progressive disclosure. Sections group concepts. No frontmatte ```markdown # Section Heading -- [Title]() - description from the linked concept -- [Subdirectory]() - group description +- [Title](relative-url) - description from the linked concept +- [Subdirectory](subdir/) - group description # Another Section -- [Title]() - description +- [Title](url) - description ``` Producers may generate them automatically; consumers may synthesize dynamically. diff --git a/orchestration/.codex-plugin/plugin.json b/orchestration/.codex-plugin/plugin.json index 0f85a3e..a7c7fc6 100644 --- a/orchestration/.codex-plugin/plugin.json +++ b/orchestration/.codex-plugin/plugin.json @@ -13,9 +13,7 @@ "shortDescription": "Orchestrator skill for managing parallel agent workstreams", "developerName": "duyet", "category": "Agents", - "capabilities": [ - "Skill" - ], + "capabilities": ["Skill"], "logo": "./assets/logo.svg", "composerIcon": "./assets/logo.svg" } diff --git a/orchestration/.grok-build-plugin/plugin.json b/orchestration/.grok-build-plugin/plugin.json index 2c95f2a..c45d91b 100644 --- a/orchestration/.grok-build-plugin/plugin.json +++ b/orchestration/.grok-build-plugin/plugin.json @@ -14,9 +14,7 @@ "shortDescription": "Orchestrator skill for managing parallel agent workstreams", "developerName": "duyet", "category": "Agents", - "capabilities": [ - "Skill" - ], + "capabilities": ["Skill"], "logo": "./assets/logo.svg", "composerIcon": "./assets/logo.svg" } diff --git a/orchestration/.grok-plugin/plugin.json b/orchestration/.grok-plugin/plugin.json index 9134d6e..d32cd4e 100644 --- a/orchestration/.grok-plugin/plugin.json +++ b/orchestration/.grok-plugin/plugin.json @@ -8,8 +8,6 @@ }, "license": "MIT", "logo": "./assets/logo.svg", - "keywords": [ - "orchestration" - ], + "keywords": ["orchestration"], "skills": "./skills/" } diff --git a/orchestration/skills/orchestration/SKILL.md b/orchestration/skills/orchestration/SKILL.md index b4fb052..df3c3cd 100644 --- a/orchestration/skills/orchestration/SKILL.md +++ b/orchestration/skills/orchestration/SKILL.md @@ -21,7 +21,8 @@ Ask the user before spawning only when scope is ambiguous in a way the code cann ## Fan out -Spawn every lane in the current wave in one message, as background subagents, so they run concurrently. Pick the cheapest model and agent type that can do the lane well: a fast model for search and mechanical edits, a stronger one for design and subtle bugs. If the team-agents plugin is installed, its `leader`, `senior-engineer`, and `junior-engineer` agents fit these roles. Any general-purpose subagent works without it. +Spawn every lane in the current wave in one message, as background subagents, so they run concurrently. Pick the cheapest model and agent type that can do the lane well: a fast model for search and mechanical edits, a stronger one for design and subtle bugs. +If the team-agents plugin is installed, its `leader`, `senior-engineer`, and `junior-engineer` agents fit these roles. Any general-purpose subagent works without it. Start every worker prompt with this preamble: diff --git a/prompt-engineering/.codex-plugin/plugin.json b/prompt-engineering/.codex-plugin/plugin.json index f1266b1..8c5ddfa 100644 --- a/prompt-engineering/.codex-plugin/plugin.json +++ b/prompt-engineering/.codex-plugin/plugin.json @@ -13,9 +13,7 @@ "shortDescription": "Prompting guidance and per-model deltas for Claude, Gemini, and Grok.", "developerName": "duyet", "category": "Productivity", - "capabilities": [ - "Skill" - ], + "capabilities": ["Skill"], "logo": "./assets/logo.svg", "composerIcon": "./assets/logo.svg" } diff --git a/prompt-engineering/.grok-build-plugin/plugin.json b/prompt-engineering/.grok-build-plugin/plugin.json index 49ccec6..3bd3443 100644 --- a/prompt-engineering/.grok-build-plugin/plugin.json +++ b/prompt-engineering/.grok-build-plugin/plugin.json @@ -14,9 +14,7 @@ "shortDescription": "Prompting guidance and per-model deltas for Claude, Gemini, and Grok.", "developerName": "duyet", "category": "Productivity", - "capabilities": [ - "Skill" - ], + "capabilities": ["Skill"], "logo": "./assets/logo.svg", "composerIcon": "./assets/logo.svg" } diff --git a/prompt-engineering/.grok-plugin/plugin.json b/prompt-engineering/.grok-plugin/plugin.json index 5b20c0d..54b1623 100644 --- a/prompt-engineering/.grok-plugin/plugin.json +++ b/prompt-engineering/.grok-plugin/plugin.json @@ -8,8 +8,6 @@ }, "license": "MIT", "logo": "./assets/logo.svg", - "keywords": [ - "prompt-engineering" - ], + "keywords": ["prompt-engineering"], "skills": "./skills/" } diff --git a/sag-notify/.codex-plugin/plugin.json b/sag-notify/.codex-plugin/plugin.json index 8342283..c5a13e3 100644 --- a/sag-notify/.codex-plugin/plugin.json +++ b/sag-notify/.codex-plugin/plugin.json @@ -14,10 +14,7 @@ "shortDescription": "Spoken voice notifications via sag (ElevenLabs TTS): skill-driven, Claude calls sag directly to speak a short alert just before it asks you something and a one-line summary when work finishes, naming the project. Configurable voice and language.", "developerName": "duyet", "category": "UI", - "capabilities": [ - "Skill", - "Command" - ], + "capabilities": ["Skill", "Command"], "logo": "./assets/logo.svg", "composerIcon": "./assets/logo.svg" } diff --git a/sag-notify/.grok-build-plugin/plugin.json b/sag-notify/.grok-build-plugin/plugin.json index 88cab93..bd862e8 100644 --- a/sag-notify/.grok-build-plugin/plugin.json +++ b/sag-notify/.grok-build-plugin/plugin.json @@ -15,10 +15,7 @@ "shortDescription": "Spoken voice notifications via sag (ElevenLabs TTS): skill-driven, Claude calls sag directly to speak a short alert just before it asks you something and a one-line summary when work finishes, naming the project. Configurable voice and language.", "developerName": "duyet", "category": "UI", - "capabilities": [ - "Skill", - "Command" - ], + "capabilities": ["Skill", "Command"], "logo": "./assets/logo.svg", "composerIcon": "./assets/logo.svg" } diff --git a/sag-notify/.grok-plugin/plugin.json b/sag-notify/.grok-plugin/plugin.json index c1be79c..c5c71e4 100644 --- a/sag-notify/.grok-plugin/plugin.json +++ b/sag-notify/.grok-plugin/plugin.json @@ -8,9 +8,7 @@ }, "license": "MIT", "logo": "./assets/logo.svg", - "keywords": [ - "sag-notify" - ], + "keywords": ["sag-notify"], "skills": "./skills/", "commands": "./commands/" } diff --git a/sag-notify/skills/sag-voice/SKILL.md b/sag-notify/skills/sag-voice/SKILL.md index ab96a1f..13cb5ef 100644 --- a/sag-notify/skills/sag-voice/SKILL.md +++ b/sag-notify/skills/sag-voice/SKILL.md @@ -35,16 +35,16 @@ Stay silent on trivial or chatty turns. The trailing sentence is one clear claus `~/.config/sag-notify/config.json` overrides `config.default.json`. Change it with `jq` through a temp file, then validate with `jq .`. -| Key | Meaning | -| --- | --- | -| `enabled` | Master switch | -| `events.notification`, `events.summary` | Toggle the needs-you and done lines | -| `voice_id`, `model_id` | ElevenLabs voice and model | -| `self_name` | Name in the greeting | -| `language` | Language of the spoken line | -| `key_file` | File to read `ELEVENLABS_API_KEY` from when the variable is unset | -| `error_log` | Where sag stderr goes | -| `max_chars` | Length cap for the trailing sentence | +| Key | Meaning | +| --------------------------------------- | ----------------------------------------------------------------- | +| `enabled` | Master switch | +| `events.notification`, `events.summary` | Toggle the needs-you and done lines | +| `voice_id`, `model_id` | ElevenLabs voice and model | +| `self_name` | Name in the greeting | +| `language` | Language of the spoken line | +| `key_file` | File to read `ELEVENLABS_API_KEY` from when the variable is unset | +| `error_log` | Where sag stderr goes | +| `max_chars` | Length cap for the trailing sentence | ## Voice tiers and 402 diff --git a/scripts/plugins.py b/scripts/plugins.py index f14810a..c2cb168 100644 --- a/scripts/plugins.py +++ b/scripts/plugins.py @@ -24,6 +24,8 @@ "agents": ("agents", "Agent"), } FRONTMATTER = re.compile(r"\A---\n(.*?)\n---\n", re.S) +FENCE = re.compile(r"^```.*?^```", re.S | re.M) +SCALAR_ARRAY = re.compile(r"\[\n\s*((?:\"[^\"\n]*\",?\n\s*)+)\]") LINK = re.compile(r"\]\(([^)#\s]+)(?:#[^)]*)?\)") @@ -155,18 +157,35 @@ def marketplaces(registry): def readme(registry): text = (ROOT / "README.md").read_text() start, end = "", "" - rows = ["| Plugin | Category | Description |", "| --- | --- | --- |"] - rows += [f"| [{p['name']}](./{p['name']}/) | {p['category']} | {p['description']} |" for p in registry["plugins"]] + cells = [("Plugin", "Category", "Description")] + cells += [(f"[{p['name']}](./{p['name']}/)", p["category"], p["description"]) for p in registry["plugins"]] + widths = [max(len(row[i]) for row in cells) for i in range(3)] + pad = lambda row: "| " + " | ".join(c.ljust(w) for c, w in zip(row, widths)) + " |" + rows = [pad(cells[0]), "| " + " | ".join("-" * w for w in widths) + " |"] + [pad(r) for r in cells[1:]] head, _, rest = text.partition(start) _, _, tail = rest.partition(end) - return f"{head}{start}\n" + "\n".join(rows) + f"\n{end}{tail}" + return f"{head}{start}\n\n" + "\n".join(rows) + f"\n\n{end}{tail}" + + +def to_json(data): + """json.dumps matching Prettier, which inlines string arrays that fit in 80 columns.""" + + def inline(match): + line_start = text.rfind("\n", 0, match.start()) + 1 + items = ", ".join(item.strip().rstrip(",") for item in match.group(1).strip().splitlines()) + flat = f"[{items}]" + tail = text[match.end():].split("\n", 1)[0] + return flat if match.start() - line_start + len(flat) + len(tail) <= 80 else match.group(0) + + text = json.dumps(data, indent=2, ensure_ascii=False) + return SCALAR_ARRAY.sub(inline, text) + "\n" def generated(registry): out = marketplaces(registry) for entry in registry["plugins"]: out.update(plugin_manifests(entry, registry["author"])) - files = {path: json.dumps(data, indent=2, ensure_ascii=False) + "\n" for path, data in out.items()} + files = {path: to_json(data) for path, data in out.items()} files["README.md"] = readme(registry) return files @@ -210,7 +229,7 @@ def lint_plugin(plugin_dir): errors.append(f"{skill_md.relative_to(ROOT)}: missing description") for doc in plugin_dir.rglob("*.md"): text = doc.read_text() - for ref in LINK.findall(text): + for ref in LINK.findall(FENCE.sub("", text)): if re.match(r"[a-z]+:", ref) or ref.startswith(("/", "<", "$", "~")): continue target = (doc.parent / ref).resolve() diff --git a/statusline/.codex-plugin/plugin.json b/statusline/.codex-plugin/plugin.json index 4145c5d..88909ff 100644 --- a/statusline/.codex-plugin/plugin.json +++ b/statusline/.codex-plugin/plugin.json @@ -14,11 +14,7 @@ "shortDescription": "Configurable status bar showing context usage, API rate limits, git branch, and active tools", "developerName": "duyet", "category": "UI", - "capabilities": [ - "Skill", - "Command", - "Hook" - ], + "capabilities": ["Skill", "Command", "Hook"], "logo": "./assets/logo.svg", "composerIcon": "./assets/logo.svg" } diff --git a/statusline/.grok-build-plugin/plugin.json b/statusline/.grok-build-plugin/plugin.json index 752451c..8a5c90c 100644 --- a/statusline/.grok-build-plugin/plugin.json +++ b/statusline/.grok-build-plugin/plugin.json @@ -15,11 +15,7 @@ "shortDescription": "Configurable status bar showing context usage, API rate limits, git branch, and active tools", "developerName": "duyet", "category": "UI", - "capabilities": [ - "Skill", - "Command", - "Hook" - ], + "capabilities": ["Skill", "Command", "Hook"], "logo": "./assets/logo.svg", "composerIcon": "./assets/logo.svg" } diff --git a/statusline/.grok-plugin/plugin.json b/statusline/.grok-plugin/plugin.json index 61c7b16..5a2a101 100644 --- a/statusline/.grok-plugin/plugin.json +++ b/statusline/.grok-plugin/plugin.json @@ -8,9 +8,7 @@ }, "license": "MIT", "logo": "./assets/logo.svg", - "keywords": [ - "statusline" - ], + "keywords": ["statusline"], "skills": "./skills/", "commands": "./commands/" } diff --git a/statusline/scripts/test-statusline.sh b/statusline/scripts/test-statusline.sh index 9f8483e..2a0aa55 100755 --- a/statusline/scripts/test-statusline.sh +++ b/statusline/scripts/test-statusline.sh @@ -1,4 +1,5 @@ #!/bin/bash +# shellcheck disable=SC2015 # pass and fail always return 0 # Statusline compatibility and regression tests # Run: bash statusline/scripts/test-statusline.sh @@ -21,11 +22,17 @@ FAILED=0 [ -f "$CONFIG_FILE" ] && cp "$CONFIG_FILE" "$BACKUP_CONFIG" trap '[ -f "$BACKUP_CONFIG" ] && mv "$BACKUP_CONFIG" "$CONFIG_FILE" || rm -f "$CONFIG_FILE"' EXIT -pass() { echo -e "${GREEN}✓${NC} $1"; PASSED=$((PASSED + 1)); } -fail() { echo -e "${RED}✗${NC} $1"; FAILED=$((FAILED + 1)); } +pass() { + echo -e "${GREEN}✓${NC} $1" + PASSED=$((PASSED + 1)) +} +fail() { + echo -e "${RED}✗${NC} $1" + FAILED=$((FAILED + 1)) +} run() { - echo "$2" | python3 "$STATUSLINE_SCRIPT" 2>&1 + echo "$2" | python3 "$STATUSLINE_SCRIPT" 2>&1 } # ============================================ @@ -37,12 +44,15 @@ echo "" # Dependencies echo "=== Dependencies ===" command -v jq &>/dev/null && pass "jq installed" || fail "jq missing" -[ -f "$STATUSLINE_SCRIPT" ] && pass "Script exists" || { fail "Script missing"; exit 1; } +[ -f "$STATUSLINE_SCRIPT" ] && pass "Script exists" || { + fail "Script missing" + exit 1 +} echo "" # Context tests echo "=== Context ===" -echo '{"line_format":"3"}' > "$CONFIG_FILE" +echo '{"line_format":"3"}' >"$CONFIG_FILE" out=$(run "ctx from current_usage" '{"context_window":{"context_window_size":200000,"current_usage":{"input_tokens":42000}}}') echo "$out" | grep -q "21%" && pass "Context from current_usage" || fail "Context from current_usage" @@ -57,22 +67,22 @@ echo "" # Line format tests echo "=== Line Formats ===" -echo '{"line_format":"1"}' > "$CONFIG_FILE" +echo '{"line_format":"1"}' >"$CONFIG_FILE" lines=$(run "1-line" '{"context_window":{"total_input_tokens":43000,"context_window_size":200000}}' | wc -l | tr -d ' ') [ "$lines" -eq 1 ] && pass "1-line format (1 line)" || fail "1-line format ($lines lines)" -echo '{"line_format":"2"}' > "$CONFIG_FILE" +echo '{"line_format":"2"}' >"$CONFIG_FILE" lines=$(run "2-line" '{"context_window":{"total_input_tokens":43000,"context_window_size":200000}}' | wc -l | tr -d ' ') [ "$lines" -eq 2 ] && pass "2-line format (2 lines)" || fail "2-line format ($lines lines)" -echo '{"line_format":"3"}' > "$CONFIG_FILE" +echo '{"line_format":"3"}' >"$CONFIG_FILE" lines=$(run "3-line" '{"context_window":{"total_input_tokens":43000,"context_window_size":200000}}' | wc -l | tr -d ' ') [ "$lines" -ge 2 ] && pass "3-line format ($lines lines)" || fail "3-line format ($lines lines)" echo "" # Empty value hiding echo "=== Empty Value Hiding ===" -echo '{"line_format":"3"}' > "$CONFIG_FILE" +echo '{"line_format":"3"}' >"$CONFIG_FILE" out=$(run "empty" '{"context_window":{"total_input_tokens":43000,"context_window_size":200000}}') echo "$out" | grep -q "Tools: None" && fail "Should hide 'Tools: None'" || pass "Hides 'Tools: None'" echo "$out" | grep -q "Agents: None" && fail "Should hide 'Agents: None'" || pass "Hides 'Agents: None'" @@ -90,7 +100,7 @@ echo "" # Model formatting echo "=== Model Formatting ===" -echo '{"line_format":"1"}' > "$CONFIG_FILE" +echo '{"line_format":"1"}' >"$CONFIG_FILE" out=$(run "model" '{"model":{"id":"claude-opus-4-5-20251101"},"context_window":{"total_input_tokens":0,"context_window_size":200000}}') echo "$out" | grep -q "opus-4.5" && pass "Formats opus model (opus-4.5)" || fail "Model formatting: $out" diff --git a/statusline/skills/statusline-workflow/SKILL.md b/statusline/skills/statusline-workflow/SKILL.md index 3cd51d9..4ddeb8e 100644 --- a/statusline/skills/statusline-workflow/SKILL.md +++ b/statusline/skills/statusline-workflow/SKILL.md @@ -16,7 +16,12 @@ Resolve the plugin directory from this skill's location (`${CLAUDE_PLUGIN_ROOT}` 3. Point `statusLine` at `~/.claude/statusline/statusline.py`. The plugin's SessionStart hook copies the renderer there on every session, so the path survives plugin updates. On first setup, copy it there yourself. ```json - {"statusLine": {"type": "command", "command": "python3 ~/.claude/statusline/statusline.py"}} + { + "statusLine": { + "type": "command", + "command": "python3 ~/.claude/statusline/statusline.py" + } + } ``` 4. Preview by piping sample JSON to the renderer. @@ -31,24 +36,24 @@ To disable, remove the `statusLine` key from `~/.claude/settings.json`. ## Config fields -| Field | Values | Default | -| --- | --- | --- | -| `line_format` | `"1"`, `"2"`, `"3"` | `"3"` | -| `separator` | `arrow`, `pipe`, `dot`, `slash` | `arrow` | -| `context_style` | `progress_bar`, `tokens`, `compact` | `progress_bar` | -| `icon_style` | `emoji`, `unicode`, `minimal` | `emoji` | -| `cache_ttl` | `"5m"`, `"1h"` | `"5m"` | -| `show_context`, `show_rate_limits`, `show_git_branch`, `show_tools`, `show_agents`, `show_cache`, `show_session`, `show_reasoning`, `show_cost` | boolean | `true` | +| Field | Values | Default | +| ----------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------- | -------------- | +| `line_format` | `"1"`, `"2"`, `"3"` | `"3"` | +| `separator` | `arrow`, `pipe`, `dot`, `slash` | `arrow` | +| `context_style` | `progress_bar`, `tokens`, `compact` | `progress_bar` | +| `icon_style` | `emoji`, `unicode`, `minimal` | `emoji` | +| `cache_ttl` | `"5m"`, `"1h"` | `"5m"` | +| `show_context`, `show_rate_limits`, `show_git_branch`, `show_tools`, `show_agents`, `show_cache`, `show_session`, `show_reasoning`, `show_cost` | boolean | `true` | Cache stats show for Claude models only, because other providers report proxy values that are not real cache metrics. Empty sections are hidden. Rate limits read `n/a` when the provider sends none. ## Presets -| Preset | Lines | Icons | Focus | -| --- | --- | --- | --- | -| detailed | 3 | emoji | Everything (default) | -| balanced | 2 | unicode | Key metrics | -| minimal | 1 | none | Essentials | -| monitor | 2 | emoji | Rate limits and cache, no tools | -| developer | 2 | unicode | Tools, agents, git | -| performance | 3 | emoji | Cache and context | +| Preset | Lines | Icons | Focus | +| ----------- | ----- | ------- | ------------------------------- | +| detailed | 3 | emoji | Everything (default) | +| balanced | 2 | unicode | Key metrics | +| minimal | 1 | none | Essentials | +| monitor | 2 | emoji | Rate limits and cache, no tools | +| developer | 2 | unicode | Tools, agents, git | +| performance | 3 | emoji | Cache and context | diff --git a/team-agents/.codex-plugin/plugin.json b/team-agents/.codex-plugin/plugin.json index bcc0863..04c9cc6 100644 --- a/team-agents/.codex-plugin/plugin.json +++ b/team-agents/.codex-plugin/plugin.json @@ -15,11 +15,7 @@ "shortDescription": "Leader, senior, and junior engineer agents plus React, TypeScript, backend, and quality skills for parallel work.", "developerName": "duyet", "category": "Agents", - "capabilities": [ - "Skill", - "Command", - "Agent" - ], + "capabilities": ["Skill", "Command", "Agent"], "logo": "./assets/logo.svg", "composerIcon": "./assets/logo.svg" } diff --git a/team-agents/.grok-build-plugin/plugin.json b/team-agents/.grok-build-plugin/plugin.json index 144ae59..b6c89cd 100644 --- a/team-agents/.grok-build-plugin/plugin.json +++ b/team-agents/.grok-build-plugin/plugin.json @@ -16,11 +16,7 @@ "shortDescription": "Leader, senior, and junior engineer agents plus React, TypeScript, backend, and quality skills for parallel work.", "developerName": "duyet", "category": "Agents", - "capabilities": [ - "Skill", - "Command", - "Agent" - ], + "capabilities": ["Skill", "Command", "Agent"], "logo": "./assets/logo.svg", "composerIcon": "./assets/logo.svg" } diff --git a/team-agents/.grok-plugin/plugin.json b/team-agents/.grok-plugin/plugin.json index bdd7081..2b49b8c 100644 --- a/team-agents/.grok-plugin/plugin.json +++ b/team-agents/.grok-plugin/plugin.json @@ -8,9 +8,7 @@ }, "license": "MIT", "logo": "./assets/logo.svg", - "keywords": [ - "team-agents" - ], + "keywords": ["team-agents"], "skills": "./skills/", "commands": "./commands/", "agents": "./agents/" diff --git a/team-agents/skills/quality-gates/SKILL.md b/team-agents/skills/quality-gates/SKILL.md index 94ff949..fed1158 100644 --- a/team-agents/skills/quality-gates/SKILL.md +++ b/team-agents/skills/quality-gates/SKILL.md @@ -19,13 +19,13 @@ Run in this order and stop at the first failure. Add these when the change warrants them. -| Change touches | Extra gate | -|----------------|-----------| -| Public API, schema, config format | Check callers and docs, note breaking changes | -| Migrations | Apply on a scratch database and roll forward | -| Hot path or query | Measure before and after, report the numbers | -| UI | Run the app and exercise the changed flow, including empty and error states | -| Deploy config, auth, payments | Second reviewer, and a rollback plan in the PR | +| Change touches | Extra gate | +| --------------------------------- | --------------------------------------------------------------------------- | +| Public API, schema, config format | Check callers and docs, note breaking changes | +| Migrations | Apply on a scratch database and roll forward | +| Hot path or query | Measure before and after, report the numbers | +| UI | Run the app and exercise the changed flow, including empty and error states | +| Deploy config, auth, payments | Second reviewer, and a rollback plan in the PR | ## Reporting rules diff --git a/unsloth-training/.codex-plugin/plugin.json b/unsloth-training/.codex-plugin/plugin.json index 49e3797..cb78808 100644 --- a/unsloth-training/.codex-plugin/plugin.json +++ b/unsloth-training/.codex-plugin/plugin.json @@ -13,9 +13,7 @@ "shortDescription": "Fine-tune LLMs with Unsloth using GRPO or SFT: rewards, datasets, FP8, vision, MLX, export, mobile.", "developerName": "duyet", "category": "ML", - "capabilities": [ - "Skill" - ], + "capabilities": ["Skill"], "logo": "./assets/logo.svg", "composerIcon": "./assets/logo.svg" } diff --git a/unsloth-training/.grok-build-plugin/plugin.json b/unsloth-training/.grok-build-plugin/plugin.json index f17d541..8dd0300 100644 --- a/unsloth-training/.grok-build-plugin/plugin.json +++ b/unsloth-training/.grok-build-plugin/plugin.json @@ -14,9 +14,7 @@ "shortDescription": "Fine-tune LLMs with Unsloth using GRPO or SFT: rewards, datasets, FP8, vision, MLX, export, mobile.", "developerName": "duyet", "category": "ML", - "capabilities": [ - "Skill" - ], + "capabilities": ["Skill"], "logo": "./assets/logo.svg", "composerIcon": "./assets/logo.svg" } diff --git a/unsloth-training/.grok-plugin/plugin.json b/unsloth-training/.grok-plugin/plugin.json index 786506a..cc3fb53 100644 --- a/unsloth-training/.grok-plugin/plugin.json +++ b/unsloth-training/.grok-plugin/plugin.json @@ -8,8 +8,6 @@ }, "license": "MIT", "logo": "./assets/logo.svg", - "keywords": [ - "unsloth-training" - ], + "keywords": ["unsloth-training"], "skills": "./skills/" } diff --git a/unsloth-training/README.md b/unsloth-training/README.md index 49ecb31..a5a669e 100644 --- a/unsloth-training/README.md +++ b/unsloth-training/README.md @@ -4,7 +4,7 @@ Fine-tune LLMs with [Unsloth](https://unsloth.ai/) using GRPO (reinforcement lea ## Install -``` +```text /plugin install unsloth-training@duyet-claude-plugins ``` diff --git a/unsloth-training/skills/unsloth-training/SKILL.md b/unsloth-training/skills/unsloth-training/SKILL.md index d07033f..f77e288 100644 --- a/unsloth-training/skills/unsloth-training/SKILL.md +++ b/unsloth-training/skills/unsloth-training/SKILL.md @@ -9,51 +9,51 @@ Pick the method, then read the matching reference. Model names below are example ## GRPO or SFT -| Situation | Method | Data needed | -|-----------|--------|-------------| -| You can verify correctness or score outputs | GRPO | Prompts plus a reward function or ground-truth answers | -| Improving reasoning quality | GRPO | Prompts plus verifiable answers | -| Teaching an output format, new instructions, or domain knowledge | SFT | Input/output or conversation examples | -| Image inputs | Vision SFT or GRPO | See `reference/vision-training.md` | +| Situation | Method | Data needed | +| ---------------------------------------------------------------- | ------------------ | ------------------------------------------------------ | +| You can verify correctness or score outputs | GRPO | Prompts plus a reward function or ground-truth answers | +| Improving reasoning quality | GRPO | Prompts plus verifiable answers | +| Teaching an output format, new instructions, or domain knowledge | SFT | Input/output or conversation examples | +| Image inputs | Vision SFT or GRPO | See `reference/vision-training.md` | ## Where to look -| Need | Read | -|------|------| -| GRPO script to start from | `reference/grpo/basic_grpo.py` | -| Reward patterns (correctness, format, quality, constraints) | `reference/reward-design.md`, `reference/grpo/reward_functions.py` | -| GRPO and SFT hyperparameters | `reference/hyperparameters.md`, `reference/grpo/hyperparameters.py` | -| Dataset formats, chat templates, synthetic data | `reference/datasets-guide.md` | -| Install, CUDA versions, Colab | `reference/installation.md` | -| Environment flags | `reference/environment-flags.md` | -| FP8 training | `reference/fp8-training.md` | -| Long context, packing, checkpoints | `reference/advanced-training.md` | -| Vision-language models | `reference/vision-training.md` | -| Apple Silicon | `reference/mlx-training.md` | -| Export to GGUF, Ollama, vLLM, LM Studio | `reference/export-formats.md` | -| Docker, vLLM serving, LoRA hot-swap, SGLang | `reference/deployment.md` | -| Phones (QAT, ExecuTorch) | `reference/mobile-deployment.md` | -| Failures and odd behavior | `reference/troubleshooting.md` | +| Need | Read | +| ----------------------------------------------------------- | ------------------------------------------------------------------- | +| GRPO script to start from | `reference/grpo/basic_grpo.py` | +| Reward patterns (correctness, format, quality, constraints) | `reference/reward-design.md`, `reference/grpo/reward_functions.py` | +| GRPO and SFT hyperparameters | `reference/hyperparameters.md`, `reference/grpo/hyperparameters.py` | +| Dataset formats, chat templates, synthetic data | `reference/datasets-guide.md` | +| Install, CUDA versions, Colab | `reference/installation.md` | +| Environment flags | `reference/environment-flags.md` | +| FP8 training | `reference/fp8-training.md` | +| Long context, packing, checkpoints | `reference/advanced-training.md` | +| Vision-language models | `reference/vision-training.md` | +| Apple Silicon | `reference/mlx-training.md` | +| Export to GGUF, Ollama, vLLM, LM Studio | `reference/export-formats.md` | +| Docker, vLLM serving, LoRA hot-swap, SGLang | `reference/deployment.md` | +| Phones (QAT, ExecuTorch) | `reference/mobile-deployment.md` | +| Failures and odd behavior | `reference/troubleshooting.md` | ## Defaults to start from -| Setting | GRPO | SFT | -|---------|------|-----| -| Learning rate | 5e-6 (about 10x lower than SFT) | 2e-4 | -| Length of run | 300+ steps before judging | 2 to 4 epochs | -| `num_generations` | 4 (range 2 to 8) | n/a | -| `beta` (KL penalty) | 0.04 (range 0.01 to 0.1) | n/a | -| Gradient checkpointing | `"unsloth"` | `"unsloth"` | -| Packing | n/a | `packing=True` for mixed-length data | +| Setting | GRPO | SFT | +| ---------------------- | ------------------------------- | ------------------------------------ | +| Learning rate | 5e-6 (about 10x lower than SFT) | 2e-4 | +| Length of run | 300+ steps before judging | 2 to 4 epochs | +| `num_generations` | 4 (range 2 to 8) | n/a | +| `beta` (KL penalty) | 0.04 (range 0.01 to 0.1) | n/a | +| Gradient checkpointing | `"unsloth"` | `"unsloth"` | +| Packing | n/a | `packing=True` for mixed-length data | ## Choosing a model size -| Goal | Start with | -|------|-----------| -| Prototype or learn the workflow | Around 1B to 3B, 4-bit | -| Production quality | 7B or larger, if VRAM allows | -| Phone deployment | Sub-1B, quantization-aware training | -| Less VRAM on supported GPUs | FP8 (`load_in_fp8=True`), see `reference/fp8-training.md` | +| Goal | Start with | +| ------------------------------- | --------------------------------------------------------- | +| Prototype or learn the workflow | Around 1B to 3B, 4-bit | +| Production quality | 7B or larger, if VRAM allows | +| Phone deployment | Sub-1B, quantization-aware training | +| Less VRAM on supported GPUs | FP8 (`load_in_fp8=True`), see `reference/fp8-training.md` | ## Reward design rules @@ -63,13 +63,13 @@ Pick the method, then read the matching reference. Model names below are example ## GRPO symptoms -| Symptom | Fix | -|---------|-----| -| Reward flat | Wait 300+ steps, then raise the learning rate 2x | -| Reward spiky | Halve the learning rate, raise `beta` | -| Garbage output | Raise `beta` 2 to 4x, check the prompt format | -| Out of memory | Lower `max_completion_length`, set `num_generations=2` | -| No reasoning appears | Train 500+ steps, use a model of 1.5B or more | +| Symptom | Fix | +| -------------------- | ------------------------------------------------------ | +| Reward flat | Wait 300+ steps, then raise the learning rate 2x | +| Reward spiky | Halve the learning rate, raise `beta` | +| Garbage output | Raise `beta` 2 to 4x, check the prompt format | +| Out of memory | Lower `max_completion_length`, set `num_generations=2` | +| No reasoning appears | Train 500+ steps, use a model of 1.5B or more | ## Before training diff --git a/unsloth-training/skills/unsloth-training/reference/datasets-guide.md b/unsloth-training/skills/unsloth-training/reference/datasets-guide.md index 5be4a99..ac100c1 100644 --- a/unsloth-training/skills/unsloth-training/reference/datasets-guide.md +++ b/unsloth-training/skills/unsloth-training/reference/datasets-guide.md @@ -2,14 +2,15 @@ ## Dataset Formats -| Format | Use Case | Structure | -|--------|----------|-----------| -| **Raw Corpus** | Continued pretraining | Plain text | -| **Instruct (Alpaca)** | Single-turn tasks | instruction/input/output | -| **Conversation (ShareGPT)** | Multi-turn chat | conversations array | -| **ChatML** | OpenAI-style chat | messages array | +| Format | Use Case | Structure | +| --------------------------- | --------------------- | ------------------------ | +| **Raw Corpus** | Continued pretraining | Plain text | +| **Instruct (Alpaca)** | Single-turn tasks | instruction/input/output | +| **Conversation (ShareGPT)** | Multi-turn chat | conversations array | +| **ChatML** | OpenAI-style chat | messages array | ### Alpaca Format + ```json { "instruction": "Task description", @@ -19,22 +20,24 @@ ``` ### ShareGPT Format + ```json { "conversations": [ - {"from": "human", "value": "Can you help me?"}, - {"from": "gpt", "value": "Of course!"} + { "from": "human", "value": "Can you help me?" }, + { "from": "gpt", "value": "Of course!" } ] } ``` ### ChatML Format (recommended for Qwen/most models) + ```json { "messages": [ - {"role": "system", "content": "You are helpful."}, - {"role": "user", "content": "What is 1+1?"}, - {"role": "assistant", "content": "It's 2!"} + { "role": "system", "content": "You are helpful." }, + { "role": "user", "content": "What is 1+1?" }, + { "role": "assistant", "content": "It's 2!" } ] } ``` @@ -124,6 +127,7 @@ dataset = to_sharegpt( ### Using LLM APIs Prompt strategies: + - **Extend existing**: "Using this dataset example, follow the structure and generate similar conversations." - **From scratch**: "Create 10 examples of [domain] classified as [categories]." - **Reformat**: "Structure my dataset in QA ChatML format. Then generate 5 synthetic examples." @@ -159,8 +163,10 @@ messages = [ ## Reasoning Datasets For models with reasoning (DeepSeek-R1): + - Include chain-of-thought in answers For models without reasoning: + - Use standard SFT datasets - Apply GRPO with reward functions for reasoning development diff --git a/unsloth-training/skills/unsloth-training/reference/deployment.md b/unsloth-training/skills/unsloth-training/reference/deployment.md index 1c72bcf..7883eaf 100644 --- a/unsloth-training/skills/unsloth-training/reference/deployment.md +++ b/unsloth-training/skills/unsloth-training/reference/deployment.md @@ -26,12 +26,12 @@ Access Jupyter Lab at `http://localhost:8888` ### Environment Variables -| Variable | Purpose | Default | -|----------|---------|---------| -| `JUPYTER_PASSWORD` | Lab access | `unsloth` | -| `JUPYTER_PORT` | Internal port | `8888` | -| `SSH_KEY` | Public key auth | None | -| `USER_PASSWORD` | Sudo password | `unsloth` | +| Variable | Purpose | Default | +| ------------------ | --------------- | --------- | +| `JUPYTER_PASSWORD` | Lab access | `unsloth` | +| `JUPYTER_PORT` | Internal port | `8888` | +| `SSH_KEY` | Public key auth | None | +| `USER_PASSWORD` | Sudo password | `unsloth` | ### Advanced Configuration @@ -105,15 +105,15 @@ vllm serve unsloth/Llama-3.1-8B-Instruct \ ### All Important Arguments -| Argument | Description | Default | -|----------|-------------|---------| -| `--port` | API port | 8000 | -| `--api-key` | Auth password | None | -| `--seed` | Random seed | 0 | -| `--enforce-eager` | Disable compilation | False | -| `--disable-log-stats` | Suppress logs | False | -| `--tokenizer` | Custom tokenizer | Model default | -| `--hf-token` | HF authentication | None | +| Argument | Description | Default | +| --------------------- | ------------------- | ------------- | +| `--port` | API port | 8000 | +| `--api-key` | Auth password | None | +| `--seed` | Random seed | 0 | +| `--enforce-eager` | Disable compilation | False | +| `--disable-log-stats` | Suppress logs | False | +| `--tokenizer` | Custom tokenizer | Model default | +| `--hf-token` | HF authentication | None | --- @@ -250,9 +250,9 @@ response = client.chat.completions.create( ### Performance Comparison | Server | gpt-oss-20b Output Tokens/s | First Token Latency | -|--------|----------------------------|---------------------| -| SGLang | ~2,562 | 0.40-0.42s | -| vLLM | ~2,400 | 0.45-0.50s | +| ------ | --------------------------- | ------------------- | +| SGLang | ~2,562 | 0.40-0.42s | +| vLLM | ~2,400 | 0.45-0.50s | ### Troubleshooting diff --git a/unsloth-training/skills/unsloth-training/reference/environment-flags.md b/unsloth-training/skills/unsloth-training/reference/environment-flags.md index 4cb7826..5f0e7ca 100644 --- a/unsloth-training/skills/unsloth-training/reference/environment-flags.md +++ b/unsloth-training/skills/unsloth-training/reference/environment-flags.md @@ -11,20 +11,20 @@ from unsloth import FastLanguageModel # Must come after ## Flags -| Flag | Purpose | Default | -|------|---------|---------| -| `UNSLOTH_RETURN_LOGITS` | Force return logits - needed for evaluation | Off | -| `UNSLOTH_COMPILE_DISABLE` | Disable auto compiler - debug incorrect results | Off | -| `UNSLOTH_DISABLE_FAST_GENERATION` | Disable fast generation for generic models | Off | -| `UNSLOTH_ENABLE_LOGGING` | Show which functions are compiled | Off | -| `UNSLOTH_FORCE_FLOAT32` | Use float32 on float16 machines (useful for Gemma 3) | Off | -| `UNSLOTH_STUDIO_DISABLED` | Disable extra features | Off | -| `UNSLOTH_COMPILE_DEBUG` | Verbose torch.compile logs | Off | -| `UNSLOTH_COMPILE_MAXIMUM` | Maximum torch.compile optimizations (not recommended) | `"0"` | -| `UNSLOTH_COMPILE_IGNORE_ERRORS` | Turn off to enable fullgraph parsing | `"1"` | -| `UNSLOTH_FULLGRAPH` | Enable torch.compile fullgraph mode | `"0"` | -| `UNSLOTH_DISABLE_AUTO_UPDATES` | Prevent auto-updates to unsloth-zoo | Off | -| `UNSLOTH_VLLM_STANDBY` | Shared memory for GRPO vLLM inference | Off | +| Flag | Purpose | Default | +| --------------------------------- | ----------------------------------------------------- | ------- | +| `UNSLOTH_RETURN_LOGITS` | Force return logits - needed for evaluation | Off | +| `UNSLOTH_COMPILE_DISABLE` | Disable auto compiler - debug incorrect results | Off | +| `UNSLOTH_DISABLE_FAST_GENERATION` | Disable fast generation for generic models | Off | +| `UNSLOTH_ENABLE_LOGGING` | Show which functions are compiled | Off | +| `UNSLOTH_FORCE_FLOAT32` | Use float32 on float16 machines (useful for Gemma 3) | Off | +| `UNSLOTH_STUDIO_DISABLED` | Disable extra features | Off | +| `UNSLOTH_COMPILE_DEBUG` | Verbose torch.compile logs | Off | +| `UNSLOTH_COMPILE_MAXIMUM` | Maximum torch.compile optimizations (not recommended) | `"0"` | +| `UNSLOTH_COMPILE_IGNORE_ERRORS` | Turn off to enable fullgraph parsing | `"1"` | +| `UNSLOTH_FULLGRAPH` | Enable torch.compile fullgraph mode | `"0"` | +| `UNSLOTH_DISABLE_AUTO_UPDATES` | Prevent auto-updates to unsloth-zoo | Off | +| `UNSLOTH_VLLM_STANDBY` | Shared memory for GRPO vLLM inference | Off | ## Common Usage diff --git a/unsloth-training/skills/unsloth-training/reference/mlx-training.md b/unsloth-training/skills/unsloth-training/reference/mlx-training.md index e9f1cbc..1c07f11 100644 --- a/unsloth-training/skills/unsloth-training/reference/mlx-training.md +++ b/unsloth-training/skills/unsloth-training/reference/mlx-training.md @@ -60,15 +60,15 @@ trainer.train() ## Supported Training Methods -| Method | Class | Use Case | -|--------|-------|----------| -| **SFT** | `SFTTrainer` | Instruction fine-tuning | -| **DPO** | `DPOTrainer` | Preference learning | -| **ORPO** | `ORPOTrainer` | Combined SFT + preference | -| **GRPO** | `GRPOTrainer` | Multi-generation reasoning (DeepSeek R1 style) | -| **KTO** | `KTOTrainer` | Kahneman-Tversky optimization | -| **SimPO** | `SimPOTrainer` | Simple preference optimization | -| **VLM** | `VLMSFTTrainer` | Vision-language (beta) | +| Method | Class | Use Case | +| --------- | --------------- | ---------------------------------------------- | +| **SFT** | `SFTTrainer` | Instruction fine-tuning | +| **DPO** | `DPOTrainer` | Preference learning | +| **ORPO** | `ORPOTrainer` | Combined SFT + preference | +| **GRPO** | `GRPOTrainer` | Multi-generation reasoning (DeepSeek R1 style) | +| **KTO** | `KTOTrainer` | Kahneman-Tversky optimization | +| **SimPO** | `SimPOTrainer` | Simple preference optimization | +| **VLM** | `VLMSFTTrainer` | Vision-language (beta) | ## Chat Templates @@ -101,21 +101,23 @@ model.save_pretrained_gguf("model", tokenizer) ``` ### GGUF Limitation + Direct GGUF export from 4-bit quantized base models is not supported. Workarounds: + 1. Train quantized, export from non-quantized base 2. Dequantize during export, re-quantize with llama.cpp 3. Use `save_pretrained_merged()` for MLX-native inference ## Unsloth vs MLX-Tune -| Aspect | Unsloth | MLX-Tune | -|--------|---------|----------| -| Platform | NVIDIA GPUs (Linux/Windows) | Apple Silicon (macOS) | -| Backend | Triton kernels | MLX framework | -| Memory | VRAM (8-80GB) | Unified memory (16-512GB) | -| API | Original | 100% compatible | -| Use case | Production training | Local dev & prototyping | +| Aspect | Unsloth | MLX-Tune | +| -------- | --------------------------- | ------------------------- | +| Platform | NVIDIA GPUs (Linux/Windows) | Apple Silicon (macOS) | +| Backend | Triton kernels | MLX framework | +| Memory | VRAM (8-80GB) | Unified memory (16-512GB) | +| API | Original | 100% compatible | +| Use case | Production training | Local dev & prototyping | ## Code Portability @@ -134,13 +136,13 @@ from unsloth import FastLanguageModel ## Memory Guidelines | Model Size | Min Unified RAM | Quantization | -|-----------|----------------|--------------| -| 1B | 16GB | 4-bit | -| 3B | 16GB | 4-bit | -| 7B | 32GB | 4-bit | -| 14B | 64GB | 4-bit | -| 32B | 96GB | 4-bit | -| 70B | 192GB+ | 4-bit | +| ---------- | --------------- | ------------ | +| 1B | 16GB | 4-bit | +| 3B | 16GB | 4-bit | +| 7B | 32GB | 4-bit | +| 14B | 64GB | 4-bit | +| 32B | 96GB | 4-bit | +| 70B | 192GB+ | 4-bit | Apple Silicon unified memory allows training much larger models than equivalent NVIDIA VRAM since system RAM and GPU memory are shared. From 459cb4b09b6c9313e84fcce0cde4b61ccf82b234 Mon Sep 17 00:00:00 2001 From: duyet Date: Mon, 19 Oct 2026 14:18:03 +0700 Subject: [PATCH 5/5] refactor(plugins): trim skills to what, when, and where; add chmonitor MCP server Skills now say when to act, what matters, and where to look (docs, --help, MCP tools, the project's AGENTS.md). Procedures, cookbooks, and copied upstream references are gone. Kept output contracts, safety rules, and taste choices. Markdown across plugins drops to about 2.6k lines. chmonitor ships the hosted MCP server (CHMONITOR_URL, CHMONITOR_API_KEY) and points at docs.chmonitor.dev and the repo AGENTS.md instead of copied docs. The lint caps SKILL.md at 60 lines. Co-Authored-By: Claude Opus 5.5 --- .claude-plugin/marketplace.json | 2 +- .cursor-plugin/marketplace.json | 2 +- .grok-plugin/marketplace.json | 2 +- README.md | 2 +- agent-loop/README.md | 34 +- .../skills/agent-loop-autoreview/SKILL.md | 52 +- agent-loop/skills/agent-loop-browser/SKILL.md | 19 +- .../skills/agent-loop-orchestrator/SKILL.md | 17 +- agent-loop/skills/agent-loop-triage/SKILL.md | 174 +---- anyrouter/README.md | 26 +- anyrouter/agents/anyrouter-integrator.md | 10 +- anyrouter/commands/anyrouter-migrate.md | 14 +- anyrouter/skills/anyrouter/SKILL.md | 95 +-- build-ios-apps/README.md | 40 +- .../skills/apple-intelligence/SKILL.md | 219 +----- build-ios-apps/skills/core-ai/SKILL.md | 155 +--- .../skills/foundation-models/SKILL.md | 184 +---- .../skills/ios-app-intents/SKILL.md | 80 +- .../references/code-templates.md | 303 -------- .../references/example-patterns.md | 161 ---- .../references/first-pass-checklist.md | 57 -- .../references/system-surfaces.md | 31 - .../skills/ios-debugger-agent/SKILL.md | 69 +- .../skills/ios-ettrace-performance/SKILL.md | 191 +---- .../skills/ios-memgraph-leaks/SKILL.md | 77 +- .../skills/ios-simulator-browser/SKILL.md | 50 +- .../skills/swiftui-liquid-glass/SKILL.md | 119 +-- .../skills/swiftui-performance-audit/SKILL.md | 113 +-- .../references/code-smells.md | 153 ---- .../references/profiling-intake.md | 45 -- .../references/report-template.md | 47 -- .../skills/swiftui-ui-patterns/SKILL.md | 75 +- .../skills/swiftui-view-refactor/SKILL.md | 213 +----- build-macos-apps/README.md | 28 +- .../commands/build-and-run-macos-app.md | 27 +- .../commands/fix-codesign-error.md | 21 +- build-macos-apps/commands/test-macos-app.md | 22 +- .../skills/appkit-interop/SKILL.md | 69 +- .../references/appkit-overview.md | 47 -- .../references/drag-drop-pasteboard.md | 23 - .../references/representables.md | 56 -- .../references/responder-menus.md | 22 - .../references/window-panels.md | 37 - .../skills/build-run-debug/SKILL.md | 119 +-- .../references/run-button-bootstrap.md | 144 ---- build-macos-apps/skills/liquid-glass/SKILL.md | 180 +---- .../skills/macos-app-best-practices/SKILL.md | 255 +------ .../skills/packaging-notarization/SKILL.md | 45 +- .../skills/signing-entitlements/SKILL.md | 55 +- .../skills/swiftpm-macos/SKILL.md | 49 +- .../skills/swiftui-patterns/SKILL.md | 139 +--- .../references/commands-menus.md | 41 - .../references/components-index.md | 16 - .../references/menu-bar-extra.md | 62 -- .../swiftui-patterns/references/settings.md | 51 -- .../references/split-inspectors.md | 111 --- .../swiftui-patterns/references/windowing.md | 46 -- build-macos-apps/skills/telemetry/SKILL.md | 82 +- build-macos-apps/skills/test-triage/SKILL.md | 53 +- .../skills/view-refactor/SKILL.md | 108 +-- .../skills/window-management/SKILL.md | 169 +---- .../references/api-snippets.md | 60 -- chmonitor/.claude-plugin/plugin.json | 2 +- chmonitor/.codex-plugin/plugin.json | 7 +- chmonitor/.cursor-plugin/plugin.json | 5 +- chmonitor/.grok-build-plugin/plugin.json | 7 +- chmonitor/.grok-plugin/plugin.json | 5 +- chmonitor/.mcp.json | 11 + chmonitor/README.md | 20 +- chmonitor/skills/chmonitor/SKILL.md | 287 +------ .../chmonitor/references/api-endpoints.md | 481 ------------ .../skills/chmonitor/references/api-list.md | 167 ---- .../chmonitor/references/clickhouse-compat.md | 411 ---------- .../chmonitor/references/dashboard-pages.md | 53 -- .../chmonitor/references/development.md | 253 ------- clickhouse/README.md | 8 +- clickhouse/skills/clickhouse/SKILL.md | 109 ++- .../skills/clickhouse/references/debugging.md | 400 ---------- .../clickhouse/references/monitoring.md | 710 ------------------ .../references/query-optimization.md | 252 ------- .../clickhouse/references/schema-design.md | 446 ----------- .../skills/clickhouse/rules/_sections.md | 24 - .../skills/clickhouse/rules/_template.md | 28 - .../rules/insert-async-small-batches.md | 55 -- .../clickhouse/rules/insert-batch-size.md | 54 -- .../clickhouse/rules/insert-format-native.md | 29 - .../rules/insert-mutation-avoid-delete.md | 74 -- .../rules/insert-mutation-avoid-update.md | 58 -- .../rules/insert-optimize-avoid-final.md | 57 -- .../rules/query-index-skipping-indices.md | 77 -- .../rules/query-join-choose-algorithm.md | 43 -- .../rules/query-join-consider-alternatives.md | 72 -- .../rules/query-join-filter-before.md | 54 -- .../rules/query-join-null-handling.md | 33 - .../clickhouse/rules/query-join-use-any.md | 40 - .../clickhouse/rules/query-mv-incremental.md | 68 -- .../clickhouse/rules/query-mv-refreshable.md | 64 -- .../rules/schema-json-when-to-use.md | 76 -- .../rules/schema-partition-lifecycle.md | 50 -- .../rules/schema-partition-low-cardinality.md | 61 -- .../rules/schema-partition-query-tradeoffs.md | 35 - .../rules/schema-partition-start-without.md | 42 -- .../rules/schema-pk-cardinality-order.md | 45 -- .../rules/schema-pk-filter-on-orderby.md | 52 -- .../rules/schema-pk-plan-before-creation.md | 64 -- .../rules/schema-pk-prioritize-filters.md | 44 -- .../rules/schema-types-avoid-nullable.md | 55 -- .../clickhouse/rules/schema-types-enum.md | 58 -- .../rules/schema-types-lowcardinality.md | 58 -- .../rules/schema-types-minimize-bitwidth.md | 49 -- .../rules/schema-types-native-types.md | 51 -- command-code/README.md | 22 +- command-code/agents/cmd-dispatcher.md | 6 +- command-code/commands/dispatch.md | 7 +- command-code/skills/command-code/SKILL.md | 58 +- commit/README.md | 18 +- commit/skills/commit-workflow/SKILL.md | 14 +- fix/README.md | 18 +- fix/skills/fix-workflow/SKILL.md | 12 +- frontend-design/README.md | 12 +- .../skills/frontend-design/SKILL.md | 13 +- github/README.md | 33 +- github/commands/babysit-pr.md | 4 +- github/commands/bulk-close-issues.md | 44 +- github/commands/bulk-label.md | 48 +- github/commands/bulk-merge-prs.md | 47 +- github/commands/watch-and-fix.md | 4 +- github/skills/github-workflow/SKILL.md | 21 +- github/skills/review-bots/SKILL.md | 310 +------- good-html/README.md | 12 +- interview/README.md | 20 +- interview/skills/interview/SKILL.md | 32 +- kb/README.md | 21 +- kb/commands/dream.md | 10 +- kb/commands/init.md | 8 +- kb/skills/dream/SKILL.md | 85 +-- kb/skills/init/SKILL.md | 32 +- marketplace.json | 2 +- okf/README.md | 27 +- okf/skills/okf-refactor/SKILL.md | 31 +- okf/skills/okf/SKILL.md | 55 +- orchestration/README.md | 14 +- orchestration/skills/orchestration/SKILL.md | 51 +- prompt-engineering/README.md | 12 +- .../skills/prompt-engineering/SKILL.md | 28 +- .../prompt-engineering/references/claude.md | 10 - .../prompt-engineering/references/gemini.md | 11 - .../prompt-engineering/references/grok.md | 8 - sag-notify/README.md | 21 +- sag-notify/skills/sag-voice/SKILL.md | 56 +- scripts/plugins.py | 4 + statusline/README.md | 34 +- statusline/scripts/test-statusline.sh | 6 +- .../skills/statusline-workflow/SKILL.md | 23 +- team-agents/README.md | 32 +- team-agents/agents/deep-research-agent.md | 19 +- team-agents/agents/junior-engineer.md | 14 +- team-agents/agents/performance-engineer.md | 14 +- team-agents/agents/python-expert.md | 13 +- .../skills/backend-api-patterns/SKILL.md | 67 +- team-agents/skills/quality-gates/SKILL.md | 61 +- .../skills/react-nextjs-patterns/SKILL.md | 59 +- .../skills/team-agents-workflow/SKILL.md | 15 +- .../skills/typescript-patterns/SKILL.md | 56 +- unsloth-training/README.md | 6 +- .../skills/unsloth-training/SKILL.md | 81 +- .../reference/advanced-training.md | 259 ------- .../reference/datasets-guide.md | 172 ----- .../unsloth-training/reference/deployment.md | 262 ------- .../reference/environment-flags.md | 44 -- .../reference/export-formats.md | 253 ------- .../reference/fp8-training.md | 156 ---- .../reference/grpo/basic_grpo.py | 370 --------- .../reference/grpo/hyperparameters.py | 243 ------ .../reference/grpo/reward_functions.py | 598 --------------- .../reference/hyperparameters.md | 210 ------ .../reference/installation.md | 64 -- .../reference/mlx-training.md | 154 ---- .../reference/mobile-deployment.md | 233 ------ .../reference/reward-design.md | 247 ------ .../reference/troubleshooting.md | 171 ----- .../reference/vision-training.md | 213 ------ 182 files changed, 549 insertions(+), 15013 deletions(-) delete mode 100644 build-ios-apps/skills/ios-app-intents/references/code-templates.md delete mode 100644 build-ios-apps/skills/ios-app-intents/references/example-patterns.md delete mode 100644 build-ios-apps/skills/ios-app-intents/references/first-pass-checklist.md delete mode 100644 build-ios-apps/skills/ios-app-intents/references/system-surfaces.md delete mode 100644 build-ios-apps/skills/swiftui-performance-audit/references/code-smells.md delete mode 100644 build-ios-apps/skills/swiftui-performance-audit/references/profiling-intake.md delete mode 100644 build-ios-apps/skills/swiftui-performance-audit/references/report-template.md delete mode 100644 build-macos-apps/skills/appkit-interop/references/appkit-overview.md delete mode 100644 build-macos-apps/skills/appkit-interop/references/drag-drop-pasteboard.md delete mode 100644 build-macos-apps/skills/appkit-interop/references/representables.md delete mode 100644 build-macos-apps/skills/appkit-interop/references/responder-menus.md delete mode 100644 build-macos-apps/skills/appkit-interop/references/window-panels.md delete mode 100644 build-macos-apps/skills/build-run-debug/references/run-button-bootstrap.md delete mode 100644 build-macos-apps/skills/swiftui-patterns/references/commands-menus.md delete mode 100644 build-macos-apps/skills/swiftui-patterns/references/components-index.md delete mode 100644 build-macos-apps/skills/swiftui-patterns/references/menu-bar-extra.md delete mode 100644 build-macos-apps/skills/swiftui-patterns/references/settings.md delete mode 100644 build-macos-apps/skills/swiftui-patterns/references/split-inspectors.md delete mode 100644 build-macos-apps/skills/swiftui-patterns/references/windowing.md delete mode 100644 build-macos-apps/skills/window-management/references/api-snippets.md create mode 100644 chmonitor/.mcp.json delete mode 100644 chmonitor/skills/chmonitor/references/api-endpoints.md delete mode 100644 chmonitor/skills/chmonitor/references/api-list.md delete mode 100644 chmonitor/skills/chmonitor/references/clickhouse-compat.md delete mode 100644 chmonitor/skills/chmonitor/references/dashboard-pages.md delete mode 100644 chmonitor/skills/chmonitor/references/development.md delete mode 100644 clickhouse/skills/clickhouse/references/debugging.md delete mode 100644 clickhouse/skills/clickhouse/references/monitoring.md delete mode 100644 clickhouse/skills/clickhouse/references/query-optimization.md delete mode 100644 clickhouse/skills/clickhouse/references/schema-design.md delete mode 100644 clickhouse/skills/clickhouse/rules/_sections.md delete mode 100644 clickhouse/skills/clickhouse/rules/_template.md delete mode 100644 clickhouse/skills/clickhouse/rules/insert-async-small-batches.md delete mode 100644 clickhouse/skills/clickhouse/rules/insert-batch-size.md delete mode 100644 clickhouse/skills/clickhouse/rules/insert-format-native.md delete mode 100644 clickhouse/skills/clickhouse/rules/insert-mutation-avoid-delete.md delete mode 100644 clickhouse/skills/clickhouse/rules/insert-mutation-avoid-update.md delete mode 100644 clickhouse/skills/clickhouse/rules/insert-optimize-avoid-final.md delete mode 100644 clickhouse/skills/clickhouse/rules/query-index-skipping-indices.md delete mode 100644 clickhouse/skills/clickhouse/rules/query-join-choose-algorithm.md delete mode 100644 clickhouse/skills/clickhouse/rules/query-join-consider-alternatives.md delete mode 100644 clickhouse/skills/clickhouse/rules/query-join-filter-before.md delete mode 100644 clickhouse/skills/clickhouse/rules/query-join-null-handling.md delete mode 100644 clickhouse/skills/clickhouse/rules/query-join-use-any.md delete mode 100644 clickhouse/skills/clickhouse/rules/query-mv-incremental.md delete mode 100644 clickhouse/skills/clickhouse/rules/query-mv-refreshable.md delete mode 100644 clickhouse/skills/clickhouse/rules/schema-json-when-to-use.md delete mode 100644 clickhouse/skills/clickhouse/rules/schema-partition-lifecycle.md delete mode 100644 clickhouse/skills/clickhouse/rules/schema-partition-low-cardinality.md delete mode 100644 clickhouse/skills/clickhouse/rules/schema-partition-query-tradeoffs.md delete mode 100644 clickhouse/skills/clickhouse/rules/schema-partition-start-without.md delete mode 100644 clickhouse/skills/clickhouse/rules/schema-pk-cardinality-order.md delete mode 100644 clickhouse/skills/clickhouse/rules/schema-pk-filter-on-orderby.md delete mode 100644 clickhouse/skills/clickhouse/rules/schema-pk-plan-before-creation.md delete mode 100644 clickhouse/skills/clickhouse/rules/schema-pk-prioritize-filters.md delete mode 100644 clickhouse/skills/clickhouse/rules/schema-types-avoid-nullable.md delete mode 100644 clickhouse/skills/clickhouse/rules/schema-types-enum.md delete mode 100644 clickhouse/skills/clickhouse/rules/schema-types-lowcardinality.md delete mode 100644 clickhouse/skills/clickhouse/rules/schema-types-minimize-bitwidth.md delete mode 100644 clickhouse/skills/clickhouse/rules/schema-types-native-types.md delete mode 100644 prompt-engineering/skills/prompt-engineering/references/claude.md delete mode 100644 prompt-engineering/skills/prompt-engineering/references/gemini.md delete mode 100644 prompt-engineering/skills/prompt-engineering/references/grok.md delete mode 100644 unsloth-training/skills/unsloth-training/reference/advanced-training.md delete mode 100644 unsloth-training/skills/unsloth-training/reference/datasets-guide.md delete mode 100644 unsloth-training/skills/unsloth-training/reference/deployment.md delete mode 100644 unsloth-training/skills/unsloth-training/reference/environment-flags.md delete mode 100644 unsloth-training/skills/unsloth-training/reference/export-formats.md delete mode 100644 unsloth-training/skills/unsloth-training/reference/fp8-training.md delete mode 100644 unsloth-training/skills/unsloth-training/reference/grpo/basic_grpo.py delete mode 100644 unsloth-training/skills/unsloth-training/reference/grpo/hyperparameters.py delete mode 100644 unsloth-training/skills/unsloth-training/reference/grpo/reward_functions.py delete mode 100644 unsloth-training/skills/unsloth-training/reference/hyperparameters.md delete mode 100644 unsloth-training/skills/unsloth-training/reference/installation.md delete mode 100644 unsloth-training/skills/unsloth-training/reference/mlx-training.md delete mode 100644 unsloth-training/skills/unsloth-training/reference/mobile-deployment.md delete mode 100644 unsloth-training/skills/unsloth-training/reference/reward-design.md delete mode 100644 unsloth-training/skills/unsloth-training/reference/troubleshooting.md delete mode 100644 unsloth-training/skills/unsloth-training/reference/vision-training.md diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index a3617a6..f55e59b 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -92,7 +92,7 @@ { "name": "chmonitor", "source": "./chmonitor", - "description": "Work on the ClickHouse Monitor dashboard: charts, pages, query configs, its API, and version-aware system queries.", + "description": "Read-only ClickHouse monitoring and advice through the chmonitor MCP server, with pointers to its docs and codebase.", "version": "2.0.0", "category": "Monitoring", "logo": "./chmonitor/assets/logo.svg" diff --git a/.cursor-plugin/marketplace.json b/.cursor-plugin/marketplace.json index 2934378..02ecfd8 100644 --- a/.cursor-plugin/marketplace.json +++ b/.cursor-plugin/marketplace.json @@ -60,7 +60,7 @@ { "name": "chmonitor", "source": "chmonitor", - "description": "Work on the ClickHouse Monitor dashboard: charts, pages, query configs, its API, and version-aware system queries." + "description": "Read-only ClickHouse monitoring and advice through the chmonitor MCP server, with pointers to its docs and codebase." }, { "name": "unsloth-training", diff --git a/.grok-plugin/marketplace.json b/.grok-plugin/marketplace.json index e48bebf..f898aa8 100644 --- a/.grok-plugin/marketplace.json +++ b/.grok-plugin/marketplace.json @@ -178,7 +178,7 @@ }, { "name": "chmonitor", - "description": "Work on the ClickHouse Monitor dashboard: charts, pages, query configs, its API, and version-aware system queries.", + "description": "Read-only ClickHouse monitoring and advice through the chmonitor MCP server, with pointers to its docs and codebase.", "category": "Monitoring", "source": { "type": "local", diff --git a/README.md b/README.md index 4bb4ff5..2b9dbdc 100644 --- a/README.md +++ b/README.md @@ -46,7 +46,7 @@ npx skills add duyet/codex-claude-plugins | [fix](./fix/) | Productivity | Fix failing tests, lint, and CI, then commit and push or open or update a PR. | | [clickhouse](./clickhouse/) | Database | ClickHouse review rules for schemas, queries, and inserts, with references for debugging and monitoring queries. | | [prompt-engineering](./prompt-engineering/) | Productivity | Prompting guidance and per-model deltas for Claude, Gemini, and Grok. | -| [chmonitor](./chmonitor/) | Monitoring | Work on the ClickHouse Monitor dashboard: charts, pages, query configs, its API, and version-aware system queries. | +| [chmonitor](./chmonitor/) | Monitoring | Read-only ClickHouse monitoring and advice through the chmonitor MCP server, with pointers to its docs and codebase. | | [unsloth-training](./unsloth-training/) | ML | Fine-tune LLMs with Unsloth using GRPO or SFT: rewards, datasets, FP8, vision, MLX, export, mobile. | | [good-html](./good-html/) | Design | Dense, interactive, self-contained HTML artifacts and reviews. | | [anyrouter](./anyrouter/) | AI | Wire AnyRouter, an OpenAI-compatible LLM gateway, into projects and agents, with migration help and an MCP server. | diff --git a/agent-loop/README.md b/agent-loop/README.md index 4028f3d..2e87c5f 100644 --- a/agent-loop/README.md +++ b/agent-loop/README.md @@ -1,36 +1,10 @@ # agent-loop -Unattended repo maintenance. Each cycle triages open issues and PRs, sends fixable items to parallel subagents, and reports what landed. The harness's own scheduler (Claude Code `/loop`, or the Codex and Cursor equivalents) repeats the cycle. +Unattended repo maintenance: triage issues and PRs, fix the safe ones in parallel subagents, report. Repetition comes from the harness (`/loop`). State lives in `.agent-loop/state.json`; add `.agent-loop/` to `.gitignore`. -## Install +Install: `/plugin install agent-loop@duyet-claude-plugins` -```bash -/plugin install agent-loop@duyet-claude-plugins -``` - -## Skills - -- `agent-loop-orchestrator` runs one cycle and defines the state file. -- `agent-loop-triage` classifies issues and PRs as autonomous, needs review, defer, or blocked. -- `agent-loop-autoreview` applies verified AI review bot fixes and merges when safe. -- `agent-loop-browser` captures screenshot proof for UI changes. - -## Commands - -- `/agent-loop:start`, `/agent-loop:resume`, `/agent-loop:stop` control the loop. -- `/agent-loop:status`, `/agent-loop:inspect` read the state file. -- `/agent-loop:reset`, `/agent-loop:restore` clear or recover state from backups. -- `/agent-loop:triage`, `/agent-loop:autoreview` run one pass without the loop. - -## Example - -```bash -/agent-loop:start --scope current --max-concurrency 3 -/loop 5m /agent-loop:resume -``` - -State lives in `.agent-loop/state.json`. Add `.agent-loop/` to `.gitignore`. - -## Credits +- Skills: `agent-loop-orchestrator` (one cycle, state file), `agent-loop-triage`, `agent-loop-autoreview`, `agent-loop-browser`. +- Commands: `/agent-loop:start`, `resume`, `stop`, `status`, `inspect`, `reset`, `restore`, `triage`, `autoreview`. Triage and browser skills are adapted from [steipete/agent-scripts](https://github.com/steipete/agent-scripts). diff --git a/agent-loop/skills/agent-loop-autoreview/SKILL.md b/agent-loop/skills/agent-loop-autoreview/SKILL.md index bc1eb9c..4a17caf 100644 --- a/agent-loop/skills/agent-loop-autoreview/SKILL.md +++ b/agent-loop/skills/agent-loop-autoreview/SKILL.md @@ -5,50 +5,16 @@ description: Review a PR unattended, apply verified fixes from AI review bots (C # Agent loop autoreview -## Gather +Stop and report if the PR is a draft or has a skip label (`wip`, `do-not-merge`, `blocked`, `hold`). -```bash -gh pr view --json number,title,author,isDraft,labels,reviewDecision,mergeStateStatus,statusCheckRollup -gh pr diff -gh api repos/{owner}/{repo}/pulls/{n}/comments \ - --jq '.[] | select(.user.login | test("coderabbit|sourcery|gemini-code-assist")) | {path, line, body, id}' -gh api repos/{owner}/{repo}/pulls/{n}/reviews --jq '.[] | {user: .user.login, state, body}' -``` +Use the `review-bots` skill of the github plugin to read bot comments, or fetch them with `gh api`. CodeRabbit's "Prompt for AI Agents" block is the most precise source. -Stop and report if the PR is a draft or carries a skip label (`wip`, `do-not-merge`, `blocked`, `hold`). +- Verify each comment against the code. Bots file non-issues. Skip those with a one-line reason. +- Apply the smallest fix. No drive-by refactors. +- Run the project's own lint, typecheck, and nearby tests. Revert a fix that fails validation and record it as skipped. +- Skip and escalate anything touching auth, secrets, `.env`, or Dockerfiles, and any fix outside the files the comment named. +- Commit as `fix(pr): apply review bot suggestions` and push. -## Fix +Merge only when asked (`--merge` or loop dispatch) and all hold: required checks pass (rerun a failure once to rule out a flake), no human requested changes, no conflicts, and the author is not a first-time contributor touching security-sensitive paths. Never use `--admin`. Never merge release-please PRs. -For each bot comment, extract the path, line, issue, severity, and suggested fix. CodeRabbit's "Prompt for AI Agents" block is the most precise source. Then: - -1. Read the code around the line and decide whether the comment is correct. Bots file non-issues. Skip those with a one-line reason. -2. Apply the smallest change that fixes it. No drive-by refactors. -3. Run the project's own lint, typecheck, and the tests near the change. Find the commands in package.json, pyproject.toml, Makefile, or CI config. -4. If validation fails, revert that fix and record it as skipped. - -Skip and escalate anything that touches auth, secrets, `.env`, or Dockerfiles, and any fix that changes files the comment did not name. - -## Commit - -```bash -git add -git commit -m "fix(pr): apply review bot suggestions" -git push -``` - -## Merge - -Merge only when asked to (`--merge`, or the loop's dispatch said so) and all hold: - -- Required checks pass. Rerun a failed check once to rule out a flake. -- No human review requests changes. -- No merge conflicts. -- The author is not a first-time contributor touching security-sensitive paths. - -```bash -gh pr merge --squash --delete-branch -``` - -## Report - -One block per PR: bot comments found, fixes applied, fixes skipped with reasons, validation results, and the outcome (`merged`, `pr_updated`, `blocked`, or `needs_human`). +Report per PR: comments found, fixes applied, fixes skipped with reasons, validation results, and an outcome of `merged`, `pr_updated`, `blocked`, or `needs_human`. diff --git a/agent-loop/skills/agent-loop-browser/SKILL.md b/agent-loop/skills/agent-loop-browser/SKILL.md index 773a284..6e04c52 100644 --- a/agent-loop/skills/agent-loop-browser/SKILL.md +++ b/agent-loop/skills/agent-loop-browser/SKILL.md @@ -5,21 +5,6 @@ description: Capture browser proof for a PR, such as screenshots of a preview de # Agent loop browser -Use whatever browser tool the harness provides: a Chrome DevTools MCP server, a browser-control extension, or a headless CLI such as Playwright. Prefer one attached to the user's existing browser session when the page needs login. If no browser tool is available, log that and skip the browser step. Do not fail the item for it. +Use whatever browser tool the harness provides. Prefer one attached to the user's session when the page needs login. If none is available, log it and skip. Do not fail the item for it. -## Proof workflow - -1. Open the preview or deployed URL for the PR. -2. Wait for text that shows the page loaded, not a fixed delay. -3. Exercise the changed behavior (click, fill, navigate) if the PR changes a flow. -4. Take a full-page screenshot to a temp directory, named `agent-loop-proof-.png`. -5. Report the screenshot path and what it shows. - -## Failure handling - -| Case | Action | -| --------------------------------------- | -------------------------------------------- | -| Page 404 | Report the broken URL | -| Element missing | Retry once after the page settles, then skip | -| Login required and no logged-in session | Skip and report | -| Screenshot fails | Report the page text instead | +Open the PR's preview URL, wait for content rather than a fixed delay, exercise the changed flow, and save a full-page screenshot to a temp directory as `agent-loop-proof-.png`. Report the path and what it shows. On a 404, report the URL. On a missing login or a failed screenshot, skip and report the page text instead. diff --git a/agent-loop/skills/agent-loop-orchestrator/SKILL.md b/agent-loop/skills/agent-loop-orchestrator/SKILL.md index b58a015..d7c2072 100644 --- a/agent-loop/skills/agent-loop-orchestrator/SKILL.md +++ b/agent-loop/skills/agent-loop-orchestrator/SKILL.md @@ -9,12 +9,7 @@ Each cycle runs four steps: triage, dispatch, monitor, report. This skill runs o ## Scheduling -Do not run `sleep` in a shell to wait between cycles. A sleeping shell holds the session and usually hits a tool timeout. Use the harness's own recurring-run facility instead: - -- Claude Code: `/loop /agent-loop:resume` (or the `schedule` skill for runs that outlive the session). -- Codex, Cursor, and other harnesses: use their scheduled or recurring task feature, or an external cron job that invokes the agent CLI in headless mode with `/agent-loop:resume`. - -If the harness has no such facility, run one cycle, report, and tell the user how to rerun it. +Never `sleep` in a shell between cycles. Use the harness's recurring-run facility (Claude Code: `/loop /agent-loop:resume`, or the `schedule` skill). Without one, run one cycle, report, and tell the user how to rerun. ## Cycle @@ -27,15 +22,7 @@ Stop early if the state file has `shutdown_requested: true`. Let running workers ## Configuration -Read from command flags first, then environment variables, then defaults. - -| Variable | Default | Meaning | -| ---------------------------- | ---------------------- | ----------------------------------------------- | -| `AGENT_LOOP_INTERVAL` | 300 | Seconds between cycles, passed to the scheduler | -| `AGENT_LOOP_MAX_CONCURRENCY` | 3 | Max parallel workers | -| `AGENT_LOOP_SCOPE` | current | Triage scope: `current`, `all`, or `org` | -| `AGENT_LOOP_REPOS` | git remote | Comma-separated repos for `all` scope | -| `AGENT_LOOP_STATE_FILE` | .agent-loop/state.json | State file path | +Flags, then env, then defaults: `AGENT_LOOP_INTERVAL` (300 s), `AGENT_LOOP_MAX_CONCURRENCY` (3), `AGENT_LOOP_SCOPE` (`current`, `all`, `org`), `AGENT_LOOP_REPOS` (git remote), `AGENT_LOOP_STATE_FILE` (`.agent-loop/state.json`). ## State file diff --git a/agent-loop/skills/agent-loop-triage/SKILL.md b/agent-loop/skills/agent-loop-triage/SKILL.md index f27ca2a..d35bb5e 100644 --- a/agent-loop/skills/agent-loop-triage/SKILL.md +++ b/agent-loop/skills/agent-loop-triage/SKILL.md @@ -5,180 +5,24 @@ description: Scan a repo's open issues and PRs and classify each as autonomous, # Agent loop triage -Scan open issues and PRs for the current repo (or a configured set of repos). -Classify each item and return a structured queue summary suitable for the -orchestrator loop's dispatch phase. +Scan open issues and PRs with `gh` (scope: `current`, `all` via `AGENT_LOOP_REPOS`, or `org`). Scan only from the default branch with a clean worktree, otherwise report and skip. Do not branch, stash, or commit. -## Setup +Classes: -### GitHub CLI check +- **autonomous**: fixable and landable without a maintainer. Clear-repro bugfix, simple perf win, docs fix, dependency update with green CI, narrow test fix. Never new features, broad behavior changes, security-sensitive changes without strong proof, work needing keys you lack, or anything that cannot be tested end to end. +- **needs_review**: new features, wide blast radius, items against VISION.md, items with blocking maintainer comments. +- **defer**: stale (over 6 months, no maintainer signal), duplicate, superseded, no repro and no author reply. +- **blocked**: CI failing with no clear fix, merge conflict, missing access, awaiting a maintainer decision. -```bash -gh auth status 2>/dev/null || { echo "gh not authenticated"; exit 1; } -``` - -### Current repo - -```bash -repo=$(gh repo view --json nameWithOwner --jq .nameWithOwner 2>/dev/null || true) -if [ -z "$repo" ]; then - url=$(git remote get-url origin 2>/dev/null || true) - repo=$(printf '%s\n' "$url" | - sed -E 's#^git@github.com:##; s#^https://github.com/##; s#\.git$##') -fi -printf '%s\n' "$repo" -``` - -### Repo readiness - -```bash -git status --short --branch -git branch --show-current -git pull --ff-only -git status --short --branch -``` - -Proceed only on the default branch with a clean worktree. Otherwise report and -skip. Do not branch, stash, or commit without instruction. - -## Issue queue - -```bash -gh issue list --repo "$repo" --state open --limit 50 \ - --json number,title,author,labels,createdAt,updatedAt,url -``` - -## PR queue - -```bash -gh pr list --repo "$repo" --state open --limit 50 \ - --json number,title,author,isDraft,reviewDecision,mergeStateStatus,createdAt,updatedAt,url -``` - -## Detail pass - -For items that look actionable: - -```bash -# Issue detail -gh issue view --repo "$repo" \ - --json number,title,author,body,comments,labels,createdAt,updatedAt,url - -# PR detail -gh pr view --repo "$repo" \ - --json number,title,author,body,comments,files,commits,isDraft,reviewDecision,mergeStateStatus,statusCheckRollup,createdAt,updatedAt,url - -# PR diff for small changes -gh pr diff --repo "$repo" --patch -``` - -## Classification - -Classify each item into one of: - -### Autonomous - -The agent can fix and land it without a maintainer. - -Qualifies when: - -- Bugfix with clear repro, known root cause, and verification path -- Performance improvement that doesn't increase complexity -- Documentation fix -- Dependency update with passing CI -- Small UI tweak that follows existing patterns -- Narrow test/internal fix - -Does NOT qualify when: +For every non-maintainer item, add a trust line from `gh api users/`: `Trust: @login; acct ; repo PRs/ issues; activity: low|medium|high`. -- New feature or product/vision choice -- Broad behavior change -- Security-sensitive change without strong proof -- Anything needing live API keys you don't have -- Anything that can't be end-to-end tested - -### Needs review - -A maintainer must decide. - -- New features -- Risk changes (broad blast radius) -- Items not matching VISION.md -- Items with blocking maintainer comments - -### Defer or close - -- Stale (>6mo no activity, no maintainer signal) -- Duplicate -- Superseded by another PR/issue -- No repro for bug, no response from author - -### Blocked - -- CI failing with no clear fix -- Merge conflict -- Missing required credentials/access -- Awaiting maintainer decision - -## Trust signals - -Include author trust for every non-maintainer item: - -```bash -# Quick trust check -gh api users/ --jq '{login, created_at, public_repos}' -``` - -Output format: - -```text -Trust: @login; acct 2023-04-03; repo 2 PRs/1 issue; activity: low/medium/high -``` - -## Output format - -Return structured triage output suitable for the orchestrator: +Output, one per item under its class heading, with the cycle number, repo, and scan counts first: ```text -Cycle #42: Triage Report -Repo: owner/name -Scanned: 12 issues, 5 PRs - -Autonomous (3): - GH-123: Bug: login timeout on slow networks Type: bug | Fit: good | Risk: low Proof: repro in description, failing test in CI Trust: @contributor; acct 2024-01; previous merged PRs: 2 - → Dispatch to thread - -- GH-124: Deps: update lodash to 4.17.21 - Type: dependency | Fit: good | Risk: low - Proof: green CI - → Dispatch to thread - -Needs Review (1): -- GH-125: Feature: dark mode toggle - Type: feature | Fit: mixed | Risk: medium - → Flag for maintainer - -Defer/Close (2): -- GH-126: Stale (8mo no activity) -- GH-127: Duplicate of GH-120 -``` - -## Scope - -- `current` (default): triage only the current repo -- `all`: triage all repos in AGENT_LOOP_REPOS or detected from gh -- `org`: triage all repos under the current org - -## Broad scan - -```bash -# Find repos with open issues/PRs -gh search repos --owner --sort updated \ - --json nameWithOwner,openIssuesCount,openPullRequestsCount ``` -For each repo with open items, run the standard triage pass. -Limit to top 10 repos by activity unless `AGENT_LOOP_DEEP_SCAN` is set. +With `AGENT_LOOP_DEEP_SCAN` unset, limit a multi-repo scan to the 10 most active repos. diff --git a/anyrouter/README.md b/anyrouter/README.md index 3aaaaa2..ffb9e62 100644 --- a/anyrouter/README.md +++ b/anyrouter/README.md @@ -1,26 +1,12 @@ # anyrouter -Wire [AnyRouter](https://anyrouter.dev), an OpenAI-compatible LLM gateway, into Claude Code, Codex, Cursor, and other coding agents. +[AnyRouter](https://anyrouter.dev) is an OpenAI-compatible LLM gateway. -```bash -/plugin install anyrouter@duyet-claude-plugins -export ANYROUTER_API_KEY="sk-ar-..." -``` +Install: `/plugin install anyrouter@duyet-claude-plugins`, then `export ANYROUTER_API_KEY="sk-ar-..."` (keys at anyrouter.dev/dashboard/keys). -Get a key at [anyrouter.dev/dashboard/keys](https://anyrouter.dev/dashboard/keys). - -## What ships - -- `anyrouter` skill. The contract (base URL, key env, `provider/model` ids), integration and migration recipes, routing, attribution, and MCP notes. It tells the agent to fetch live docs from [anyrouter.dev/docs.md](https://anyrouter.dev/docs.md) instead of trusting a snapshot. -- `/anyrouter:migrate` command. Moves an existing OpenAI, Anthropic, or OpenRouter integration to AnyRouter and adds a smoke test. -- `anyrouter-integrator` agent. Runs that migration on demand. -- A remote MCP server at `https://anyrouter.dev/api/v1/mcp` for models, credits, keys, presets, and conversations. It authorizes through OAuth on first use. Client setup is at [anyrouter.dev/docs/mcp.md](https://anyrouter.dev/docs/mcp.md). - -## Try it - -- "Add AnyRouter to this project." -- "Migrate this from OpenAI to AnyRouter." -- "Point Claude Code at AnyRouter." -- "How much credit do I have left?" +- `anyrouter` skill: contract and pointers to live docs. +- `/anyrouter:migrate`: move an OpenAI, Anthropic, or OpenRouter integration to AnyRouter. +- `anyrouter-integrator` agent: runs that migration. +- Remote MCP server at `https://anyrouter.dev/api/v1/mcp` (OAuth on first use). MIT. See [LICENSE](LICENSE). diff --git a/anyrouter/agents/anyrouter-integrator.md b/anyrouter/agents/anyrouter-integrator.md index 1a16f8e..305de68 100644 --- a/anyrouter/agents/anyrouter-integrator.md +++ b/anyrouter/agents/anyrouter-integrator.md @@ -4,11 +4,5 @@ description: Wires AnyRouter into an existing codebase. Use when the task is to tools: Read, Edit, Write, Glob, Grep, Bash --- -# AnyRouter integrator - -Load the `anyrouter` skill (`skills/anyrouter/SKILL.md`) for the contract, then follow `commands/anyrouter-migrate.md` step by step. Where the command asks the user, use its stated defaults unless the task says otherwise. - -- Grep for existing clients, base URLs, and env vars first. Reuse them. -- Change only base URL, key, and model ids. -- Keep the Anthropic SDK with `ANTHROPIC_BASE_URL` only when the project needs Anthropic-native features that `/chat/completions` cannot replicate. Otherwise unify on `/chat/completions`. -- Hand back to the user when the SDK takes no custom base URL, provider-specific request shapes need a product decision, env loading is unclear, or the smoke test fails for a reason other than a bad key. Say what you need. +Load the `anyrouter` skill, then follow `commands/anyrouter-migrate.md`, using its defaults where it asks the user. Change only base URL, key, and model ids, and reuse existing clients. +Keep the Anthropic SDK only when the project needs Anthropic-native features. Done means the smoke test passes. Hand back to the user when the SDK takes no custom base URL, request shapes need a product decision, env loading is unclear, or the smoke test fails for a reason other than a bad key. diff --git a/anyrouter/commands/anyrouter-migrate.md b/anyrouter/commands/anyrouter-migrate.md index 1bbc5d4..858f692 100644 --- a/anyrouter/commands/anyrouter-migrate.md +++ b/anyrouter/commands/anyrouter-migrate.md @@ -4,11 +4,11 @@ description: Migrate this project's LLM integration to AnyRouter by swapping bas # /anyrouter:migrate -Read the `anyrouter` skill (`skills/anyrouter/SKILL.md`) for the contract and recipes. Edit minimally. +Read the `anyrouter` skill. Edit minimally. -1. **Detect.** Search for OpenAI, Anthropic, and OpenRouter imports, base URLs (`api.openai.com`, `api.anthropic.com`, `openrouter.ai`), key and base-URL env vars, and model ids. Report file, line, current value, and the planned change before editing. -2. **Confirm.** Ask the user which env var to read (default `ANYROUTER_API_KEY`), whether `anthropic/*` calls keep `/messages` or move to `/chat/completions`, how the model is chosen (pinned, from `ANYROUTER_MODEL`, or per call), and whether to add attribution headers. If told to decide, use `ANYROUTER_API_KEY`, `/chat/completions`, model from `ANYROUTER_MODEL`, and headers on. -3. **Edit.** Change the base URL, read the key from env, and convert model ids to `provider/model`. Look up current ids with the MCP `list_models` tool or `https://anyrouter.dev/models`. If you cannot pick one confidently, keep the existing id and leave a TODO. Reuse the existing client module. Keep request shapes, streaming, and error handling identical. -4. **Docs.** Add `ANYROUTER_API_KEY=` to `.env.example` and replace old key names in the README. -5. **Smoke test.** Add or update a test that sends one short prompt through `/chat/completions`, or use a one-shot `curl` with `Authorization: Bearer $ANYROUTER_API_KEY`. Run it. If it fails, diagnose and fix before calling the migration done. -6. **Report.** List files changed, ids left as TODO, whether streaming, tool use, and error paths were re-checked, and the smoke test result. Say plainly what was skipped. +1. Find existing OpenAI, Anthropic, and OpenRouter clients, base URLs, key env vars, and model ids. Report planned changes before editing. +2. Ask which env var to read (default `ANYROUTER_API_KEY`), whether `anthropic/*` calls use `/messages` or `/chat/completions`, and how the model is chosen. If told to decide, use `ANYROUTER_API_KEY`, `/chat/completions`, and `ANYROUTER_MODEL`. +3. Change base URL, key source, and model ids (`provider/model`, looked up via MCP `list_models`). Keep an id you cannot place and leave a TODO. Keep request shapes, streaming, and error handling identical. +4. Update `.env.example` and README key names. +5. Add or run a smoke test sending one short prompt. Fix failures before calling it done. +6. Report files changed, TODO ids, what was re-checked, and what was skipped. diff --git a/anyrouter/skills/anyrouter/SKILL.md b/anyrouter/skills/anyrouter/SKILL.md index 3a24e03..666dc19 100644 --- a/anyrouter/skills/anyrouter/SKILL.md +++ b/anyrouter/skills/anyrouter/SKILL.md @@ -5,77 +5,24 @@ description: Wire AnyRouter, an OpenAI-compatible LLM gateway, into a project, m # AnyRouter -One base URL, one API key, many models and providers, with failover and a remote MCP server for keys and credits. - -## Fetch live docs first - -This skill is a map. Before answering any non-trivial question, fetch the relevant markdown page and cite its URL. Do not rely on remembered model ids, scopes, or header values. - -- `https://anyrouter.dev/docs.md` is the index of every page. Start here when unsure. -- Append `.md` to any docs URL for raw markdown, for example `https://anyrouter.dev/docs/guides/migrate-from-openai.md`. -- `https://anyrouter.dev/llms-full.txt` is every doc in one file, and `https://anyrouter.dev/llms.txt` is the short index. -- If a page 404s, it was renamed. Re-read the index. - -Useful pages: `getting-started/quickstart`, `getting-started/authentication`, `guides/ai-agent-integration`, `guides/claude-code`, `guides/migrate-from-openai`, `guides/migrate-from-anthropic`, `guides/migrate-from-openrouter`, `guides/provider-routing`, `features/app-attribution`, `features/byok`, `api-reference/overview`, `api-reference/mcp`, and `mcp`. - -## Contract - -| Setting | Value | -| --------------------- | ------------------------------------------------------------------------------------- | -| Base URL | `https://anyrouter.dev/api/v1` | -| Anthropic-native base | `https://anyrouter.dev/api` (for `/messages`) | -| API key env var | `ANYROUTER_API_KEY` (keys start with `sk-ar-`) | -| Model id | `provider/model` | -| Endpoints | `/chat/completions` (OpenAI-compatible), `/messages` (Anthropic-native), `/responses` | -| MCP | `https://anyrouter.dev/api/v1/mcp`, registered by this plugin | - -For current model ids, call the MCP `list_models` tool or read the models catalog at `https://anyrouter.dev/models`. Never invent an id. - -## Add to a project - -If the project already has an LLM client, change its base URL, key, and model id instead of adding a client. Read the key from `ANYROUTER_API_KEY`, never inline it, and read the model from `ANYROUTER_MODEL`. - -```typescript -import OpenAI from "openai"; - -export const llm = new OpenAI({ - baseURL: "https://anyrouter.dev/api/v1", - apiKey: process.env.ANYROUTER_API_KEY, -}); -``` - -```python -import os -from openai import OpenAI - -client = OpenAI(base_url="https://anyrouter.dev/api/v1", api_key=os.environ["ANYROUTER_API_KEY"]) -``` - -The integration is done when calls hit the base URL, the key comes from env, model ids use `provider/model`, streaming still streams, and errors flow through the existing error path. Prove it with one short request to `/chat/completions`. - -## Coding agents - -- Claude Code: set `ANTHROPIC_BASE_URL="https://anyrouter.dev/api"` and `ANTHROPIC_AUTH_TOKEN` to the key. For tier pinning see `guides/claude-code`. -- Codex, Cursor, Aider, Hermes, OpenClaw: any client with a custom OpenAI base URL works. Use the base URL, the key, and a `provider/model` id. - -## Migrating - -Swap the base URL and key and keep the request shape. For the full procedure, run `/anyrouter:migrate` (`commands/anyrouter-migrate.md`). - -- From OpenAI, prefix model ids with `openai/`. -- From Anthropic, either keep the SDK and set `ANTHROPIC_BASE_URL`, or move to `/chat/completions` with `anthropic/` ids. -- From OpenRouter, the request and `provider` object are identical. - -## Routing and attribution - -Steer routing with a `provider` object in the request body (`only`, `order`, `sort`, `allow_fallbacks`, `max_price`, `preferred_max_latency`, `preferred_min_throughput`). Pin one upstream with the `X-AnyRouter-Provider` header. -Send `X-AnyRouter-Title`, `X-AnyRouter-Source`, and `X-AnyRouter-Version` so dashboard analytics work. Keep `allow_fallbacks: true` unless an eval needs a fixed upstream. Schemas are in `guides/provider-routing` and `features/app-attribution`. - -## MCP server - -The plugin registers the MCP server. It exposes tools for listing models, credits, keys, presets, and conversations, and for creating and revoking keys. OAuth runs on the first tool call and the user picks a scope. There is no chat tool, so use the chat endpoint for inference. Details are in `api-reference/mcp`. - -## Production defaults - -- Respect the `X-RateLimit-Remaining` and `X-Upstream-RateLimit-Remaining` headers. -- Raise the SDK timeout for long agent loops (`API_TIMEOUT_MS=3000000` for Claude Code). +This skill is a map. Fetch the relevant page and cite its URL before answering non-trivial questions. Never rely on remembered model ids, scopes, or headers. + +- Docs index: `https://anyrouter.dev/docs.md`. Append `.md` to any docs URL for markdown. `https://anyrouter.dev/llms-full.txt` is everything in one file. +- Guides live under `guides/` (quickstart, claude-code, migrate-from-openai, migrate-from-anthropic, migrate-from-openrouter, provider-routing) and `features/` (app-attribution, byok). +- Model ids: MCP `list_models` tool or `https://anyrouter.dev/models`. Never invent one. + +Contract: + +| Setting | Value | +| --------------------- | ------------------------------------------------------------- | +| Base URL | `https://anyrouter.dev/api/v1` | +| Anthropic-native base | `https://anyrouter.dev/api` (for `/messages`) | +| API key env var | `ANYROUTER_API_KEY` (keys start with `sk-ar-`) | +| Model id | `provider/model` | +| MCP | `https://anyrouter.dev/api/v1/mcp`, registered by this plugin | + +- In an existing project, change the client's base URL, key, and model id rather than adding a client. Read the key and `ANYROUTER_MODEL` from env, never inline. +- Claude Code: set `ANTHROPIC_BASE_URL="https://anyrouter.dev/api"` and `ANTHROPIC_AUTH_TOKEN` to the key. +- Send `X-AnyRouter-Title`, `X-AnyRouter-Source`, and `X-AnyRouter-Version` so analytics work. Keep `allow_fallbacks: true` unless an eval needs a fixed upstream. +- Done means calls hit the base URL, streaming still streams, and one short `/chat/completions` request succeeds. For migrations run `/anyrouter:migrate`. +- The MCP server has no chat tool. Use the chat endpoint for inference. diff --git a/build-ios-apps/README.md b/build-ios-apps/README.md index f5ce4fa..430699e 100644 --- a/build-ios-apps/README.md +++ b/build-ios-apps/README.md @@ -1,40 +1,18 @@ -# Build iOS Apps Plugin +# build-ios-apps Skills for building, debugging, and profiling iOS and SwiftUI apps. -## What ships - -- `ios-debugger-agent` -- `ios-simulator-browser` -- `ios-ettrace-performance` -- `ios-memgraph-leaks` -- `ios-app-intents` -- `swiftui-liquid-glass` -- `swiftui-performance-audit` -- `swiftui-ui-patterns` -- `swiftui-view-refactor` -- `apple-intelligence` -- `core-ai` -- `foundation-models` - -## Coverage - -- designing App Intents, app entities, and App Shortcuts for system surfaces -- building and refactoring SwiftUI UI using current platform patterns -- reviewing or adopting iOS 26+ Liquid Glass APIs -- auditing SwiftUI performance and guiding profiling workflows -- capturing symbolicated ETTrace simulator profiles for focused app flows -- capturing and comparing iOS memgraphs to root-cause leaks -- debugging iOS apps on simulators with XcodeBuildMCP (with an `xcrun simctl` fallback) -- mirroring Simulator in the browser and hot-reloading package-backed SwiftUI previews -- restructuring large SwiftUI views toward smaller, more stable compositions - ## Install -```bash +```text /plugin install build-ios-apps@duyet-claude-plugins ``` -## License +## What ships -MIT +- `ios-debugger-agent`: build, run, and drive the simulator with XcodeBuildMCP. +- `ios-simulator-browser`: mirror the simulator and hot-reload package previews in a browser. +- `ios-ettrace-performance`: symbolicated ETTrace profiles. +- `ios-memgraph-leaks`: capture and summarize memgraph leaks. +- `ios-app-intents`, `apple-intelligence`, `foundation-models`, `core-ai`: system and on-device AI integration. +- `swiftui-liquid-glass`, `swiftui-performance-audit`, `swiftui-ui-patterns`, `swiftui-view-refactor`: SwiftUI guidance. diff --git a/build-ios-apps/skills/apple-intelligence/SKILL.md b/build-ios-apps/skills/apple-intelligence/SKILL.md index fd9bbbc..42dd26c 100644 --- a/build-ios-apps/skills/apple-intelligence/SKILL.md +++ b/build-ios-apps/skills/apple-intelligence/SKILL.md @@ -1,220 +1,13 @@ --- name: apple-intelligence -description: Apple Intelligence participation layer. Wire an app's actions and content into Siri, Spotlight, Writing Tools, Image Playground, and summaries via App Intents, entities, and schemas. Use before adding App Intents/schemas, Spotlight indexing, Writing Tools, or Image Playground; defer custom generative features and on-device model files to the sibling skills. +description: Wire app actions and content into Siri, Spotlight, Writing Tools, and Image Playground via App Intents and schemas. Use before adding intents, schemas, Spotlight indexing, Writing Tools, or Image Playground. --- # Apple Intelligence -## Overview +Docs: and . Custom generative features use `foundation-models`. On-device model files use `core-ai`. -Apple Intelligence is the personal intelligence system behind built-in capabilities -across Apple platforms. It runs on-device on Apple silicon and in Private Cloud -Compute. Your app participates by teaching the system about its **actions** and -**content** so system features, Siri, Spotlight, Shortcuts, Writing Tools, Image -Playground, Visual Intelligence, Genmoji, and summaries, can use them. - -The participation contract is the **App Intents** framework: an `AppIntent` wraps one -of your app's actions; an `AppEntity` represents the data those actions operate on. -Apple Intelligence uses donated intents/entities, your Spotlight index, and declared -schemas to find and act on your content, even when described vaguely. - -Two sibling skills handle the custom-model side and are out of scope here: - -- **`foundation-models`**: the Foundation Models framework for custom generative - features (prompting, guided generation, tool calling, Private Cloud Compute). -- **`core-ai`**: running your own deep-learning model files (`.aimodel`) on-device. - -This skill covers only the built-in intelligence surfaces an app adopts. - -## Device eligibility and availability - -Apple Intelligence requires Apple silicon (iPhone 15 Pro and later, iPad with A17 Pro -or M-series, Mac with M-series). It is opt-in via the Apple Intelligence toggle in -Settings. Before exposing intelligence features, branch on the system model's -`availability` rather than assuming it is on: - -```swift -import FoundationModels - -private var model = SystemLanguageModel.default - -switch model.availability { -case .available: - // Show your intelligence UI. -case .unavailable(.deviceNotEligible): - // Show an alternative UI. -case .unavailable(.appleIntelligenceNotEnabled): - // Ask the person to turn on Apple Intelligence. -case .unavailable(.modelNotReady): - // Model is downloading or not ready. -case .unavailable(let other): - // Unknown reason. -} -``` - -## How an app participates: App Intents, entities, schemas - -The single biggest lever. Make the system aware of your actions and data via the App -Intents framework: - -- **App intents**: a custom type encapsulating one action. Ship in your app or an app - extension so the action runs even when the app isn't open. Each intent performs an - action in `perform()`, returns a result/error, declares parameters, and provides a - localized title Siri and Shortcuts can display. -- **App entities**: lightweight versions of your data objects. Define them only for - the subset of data people see and might reference with Siri ("this photo", "this - album"). Real data objects stay the source of truth. -- **App enums**: enumerate fixed choices (e.g. repeat options) so the system can - resolve parameters. -- **Donations**: when someone performs an action in your UI, donate the matching - intent/entity. Donations give Apple Intelligence behavioral cues to predict and - disambiguate. Donate only direct UI interactions, not actions Siri or Shortcuts - initiated. -- **Schemas (domains)**: the predefined intent/entity shapes for common actions (mail, - messaging, files, etc.). Prefer building from a schema over a custom intent; schemas - are the contract Apple Intelligence uses to match everyday phrases. - -Grounded minimal `AppIntent` shape: - -```swift -struct OrderAlbum: AppIntent { - static var title: LocalizedStringResource { "Order Album" } - static var description = IntentDescription("Order a vinyl record album.") - - @Parameter(title: "Album", description: "The name of the album to order.") - var albumName: String - - @Dependency - private var albumManager: AlbumDataManager - - func perform() async throws -> some IntentResult { - // Perform the action... - return .result() - } - - static var parameterSummary: some ParameterSummary { - Summary("Order \(\.$albumName)") - } -} -``` - -> For full intent/entity/schema implementation patterns, see the sibling -> `ios-app-intents` skill. - -## App Shortcuts - -An `AppShortcut` bundles an `AppIntent` with a title, image, preconfigured parameters, -and spoken phrases so it appears polished in Shortcuts and other system experiences. -The compiler generates system metadata, so shortcuts are available the moment someone -installs your app, no registration needed. Define them in a type adopting the -`AppShortcutProvider` protocol, alongside the intents they use. Surface them in-app -with tip views. - -## Apple Intelligence + Siri AI: the extra steps - -Beyond a basic App Intents adoption, make content discoverable by Apple Intelligence -specifically: - -- **Index entities into Spotlight**: Apple Intelligence uses Spotlight's semantic - search to find your content even when described vaguely. This is what makes "the - email from Mei about the Q3 plan" work. -- **Choose transferable types**: conform entities/values to transferable types so the - system can move content across apps for cross-app Siri tasks. -- **Adopt schemas**: the contract the system uses to identify, query, and understand - actions and content, and to match them to conversational phrases. -- **Associate entities with views / user activities**, gives Apple Intelligence - onscreen context so someone can refer to what's visible ("this photo"). -- **Donate actions and content**: behavioral cues for prediction and disambiguation. - -## Spotlight / semantic indexing - -Indexing your app's content makes it findable in search and lets Siri and other system -features locate app-specific data. If you define app entities for your data, index -those entities with the rest of your content. When a search finds your content, the -system uses the associated entity to open your app and navigate to it. Apple -Intelligence retrieves entities it finds in your Spotlight index to interact with your -content. - -## Writing Tools and Genmoji - -Writing Tools (proofreading, rewrite, summaries) integrate into standard system text -views automatically: - -- Adopt `NSAttributedString` / attributed strings as the backing store for text content. -- Use standard text views whenever possible and customize via their configuration - options. -- Use the Writing Tools API directly only if you have a custom text-editing engine or - can't use system views. -- Genmoji is built into system text views. In custom views, add Genmoji text - attachments and read/write them correctly when persisting to a custom file format. - -## Image Playground - -The ImagePlayground framework gives a system interface to generate images from a text -description, an optional source image, and a style. Present a system sheet (SwiftUI) or -view controller (UIKit/AppKit); the system manages all interaction and delivers the -resulting image. Key API surface: - -- `ImagePlaygroundViewController`: the standard system interface (UIKit/AppKit). -- `ImagePlaygroundConcept`: text elements specifying content to include. -- `ImagePlaygroundStyle` / `ImagePlaygroundOptions`, style and generation options. -- `ImageCreator`: generate images programmatically without the UI. -- SwiftUI sheet modifier: - -```swift -imagePlaygroundSheet( - isPresented: Binding, - concept: String, // or concepts: [ImagePlaygroundConcept] - sourceImage: Image?, // or sourceImageURL: URL - onCompletion: (URL) -> Void, - onCancellation: (() -> Void)? -) -``` - -## Visual Intelligence - -For object/scene scanning via Camera Control, adopt Visual Intelligence. The framework -detects content and exchanges information with your app using App Intents, so your App -Intents participation is also what makes you a destination for Visual Intelligence -results. - -## Checklist - -- [ ] Check `SystemLanguageModel.default.availability` before showing intelligence UI; - handle `.deviceNotEligible` and `.appleIntelligenceNotEnabled`. -- [ ] Identified the user-visible actions and data; modeled them as `AppIntent` and - `AppEntity`. -- [ ] Built common actions from built-in schema domains (not bespoke intents) where one - exists. -- [ ] Each intent has `perform()`, a result/error, declared `@Parameter`s, and a - localized `title`. -- [ ] Entities are lightweight and cover only what people see/reference. -- [ ] Donating intents/entities on direct UI interactions (not Siri/Shortcuts ones). -- [ ] App entities indexed into Spotlight (enables semantic search by Apple - Intelligence). -- [ ] Entities associated with views/user activities for onscreen context. -- [ ] Conformed entities to transferable types for cross-app Siri tasks. -- [ ] App Shortcuts defined via `AppShortcutProvider` for headline actions. -- [ ] Text content backed by attributed strings; Writing Tools and Genmoji handled in - custom text views. -- [ ] Image Playground adopted via `imagePlaygroundSheet` / `ImagePlaygroundViewController` - (or `ImageCreator` for programmatic generation). -- [ ] Custom generative features delegated to `foundation-models`; on-device model files - to `core-ai`. -- [ ] Tested intents end-to-end (Siri, Spotlight, Shortcuts) on a real eligible device. - -## Resources - -- Apple Intelligence overview: -- Built-in intelligence (on-device vision/speech/NLP), -- Generative models overview: -- Apple Intelligence and Siri AI: -- Spotlight integration: -- Donations and discovery: -- Getting started with App Intents: -- App entities: -- App Shortcuts: -- AppIntent protocol: -- Image Playground: -- Foundation Models quick start (eligibility code), -- Sibling skills: `foundation-models`, `core-ai`, `ios-app-intents` +- Apple Intelligence needs supported Apple silicon devices. Gate features on availability and keep a non-AI path. +- Prefer building from an Apple schema over a custom intent. +- Keep app entities lightweight and limited to what people see or reference. Donate only direct UI interactions. +- Use standard text views so Writing Tools works for free. Use the Writing Tools API directly only for a custom text engine. diff --git a/build-ios-apps/skills/core-ai/SKILL.md b/build-ios-apps/skills/core-ai/SKILL.md index 6e18033..5a1e2d8 100644 --- a/build-ios-apps/skills/core-ai/SKILL.md +++ b/build-ios-apps/skills/core-ai/SKILL.md @@ -1,155 +1,12 @@ --- name: core-ai -description: Run on-device AI models in iOS, iPadOS, macOS, and visionOS apps with Core AI. Use when bundling .aimodel files, loading an AIModel, running inference over NDArray tensors, or compiling models ahead of time with coreai-build. +description: Run on-device AI models with Core AI. Use when bundling .aimodel files, loading an AIModel, running inference over NDArray tensors, or compiling models ahead of time with coreai-build. --- -# Core AI: On-Device AI Models +# Core AI -## Overview +Docs: search the current Core AI documentation at . APIs are new, so do not answer from memory. -Core AI runs AI models **on device** inside your app. Inference stays private, works -offline, and has no per-inference cost. You start from a `.aimodel` file (converted -from a model or already in the correct format) that contains one or more named -inference functions, bundle it, load it as an `AIModel`, and run those functions -over `NDArray` tensors (image inputs use a pixel-buffer value). - -Available on **Apple Intelligence** devices: iPhone/iPad with A17 Pro or later, Mac -with M1 or later, Apple Vision Pro (M2+). Building requires the **Metal Toolchain** -in Xcode (not installed by default), without it, builds that include `.aimodel` -files fail with a missing Metal compiler error. - -> Core AI runs your own model files at the tensor level. For Apple's high-level -> on-device LLM API (chat sessions, tool calling, guided generation), use the -> Foundation Models framework, a separate framework, not covered here. - -## Workflow - -1. **Inspect the model** in Xcode's model viewer: - - _General_: size (parameter count and on-disk storage), numeric precision split - into **compute** (used during inference) and **storage** (weights on disk), - operation distribution, and editable metadata. - - _Functions_: each inference function's input/output names, types, and shapes. - A `?` in a dimension means it is dynamic (supplied or determined at runtime). -2. **Bundle the model**: add the `.aimodel` file to the Xcode target (it appears in - the _Compile Sources_ build phase). Install the Metal Toolchain first. -3. **Load the model**: `AIModel(contentsOf:)` is asynchronous because Core AI - **specializes** the model for the current device and selects the compute units - that deliver the best performance. For large models this can take significant - time, so consider ahead-of-time compilation (below). -4. **Load a function**: `model.loadFunction(named:)` returns the function or `nil` - when no function with that name exists (it throws on other load failures). Use - `functionNames` when a model has multiple functions. The same inference function - is safe to call from concurrent tasks. -5. **Prepare inputs**: match each input's shape and scalar type from - `function.descriptor`, then write data through a mutable view. -6. **Run and read outputs**: `function.run(inputs:)` returns outputs keyed by name; - pull each result with `outputs.remove(_:)` and read it through a view. - -## Core API - -```swift -import CoreAI - -// 1. Specialize for this device and load the model. -let model = try await AIModel(contentsOf: urlOfModel) - -// 2. Load the inference function. Returns nil if the name is absent. -guard let function = try model.loadFunction(named: "main") else { - // Handle a missing function. -} - -// 3. Verify the input's shape and scalar type from the descriptor. -let descriptor = function.descriptor -guard let valueDescriptor = descriptor.inputDescriptor(of: "input"), - case .ndArray(let arrayDescriptor) = valueDescriptor, - arrayDescriptor.shape == [3, 4], - arrayDescriptor.scalarType == .float32 else { - // Handle an unexpected type or shape. -} - -// 4. Create the input tensor and write data through a mutable view. -var input = NDArray(shape: [3, 4], scalarType: .float32) -var mutableView = input.mutableView(as: Float.self) -guard let elements = mutableView.contiguousElements else { - // Handle a non-contiguous memory layout. -} -writeInputData(into: elements) - -// 5. Run inference and extract the named output. -var outputs = try await function.run(inputs: ["input": input]) -guard let value = outputs.remove("prediction"), - let prediction = value.ndArray else { - // Handle a missing or unexpected output. -} -processOutput(prediction.view()) -``` - -### Tensors and values - -- `NDArray`: an n-dimensional tensor. Build it with `NDArray(shape:scalarType:)`. - It is **read-only by default**: use `mutableView(as:)` → `contiguousElements` to - write, and `view()` to read. Swift enforces read vs. write access at compile time. -- `scalarType`: the element type, e.g. `.float32`. Shape is an `[Int]` matching the - model's expectation; a `?` dimension in the viewer is dynamic. -- **Images**: values marked as images at conversion time use a pixel-buffer value - rather than `NDArray`. -- `ValueDescriptor`: `.ndArray(ArrayDescriptor)` vs. image cases. Inspect - `descriptor.inputDescriptor(of:)` / `outputDescriptor(of:)` at runtime so the app - can adapt if a function's signature changes between deployments without code edits. - -## Ahead-of-Time (AOT) Compilation - -On-device specialization can delay first load. Move the most expensive part, model -compilation, to the build machine with the **`coreai-build`** CLI. It converts -`MyModel.aimodel` into one `MyModel..aimodelc` asset per device architecture. -At runtime the app picks the asset for the current architecture and loads it with the -**same** `AIModel` API, so loading code does not change. - -```bash -# 1. Install the Metal Toolchain (also: Xcode > Settings > Components > Get). -xcodebuild -downloadComponent MetalToolchain - -# 2. Compile one .aimodelc per architecture. -xcrun coreai-build compile MyModel.aimodel --platform iOS --output compiled/ - -# Override compute units, deployment version, target arch, and more: -xcrun coreai-build compile MyModel.aimodel --platform macOS \ - --preferred-compute gpuAndNeuralEngine --output compiled/ -xcrun coreai-build compile --help -``` - -```swift -// Select the compiled asset for this device, then load normally. -let arch = AIModel.deviceArchitectureName -let assetName = "MyModel.\(arch).aimodelc" -let model = try await AIModel(contentsOf: bundledURL(for: assetName)) -``` - -Notes: - -- `coreai-build` emits one `..aimodelc` per architecture; the filename prefix - comes from the input model. `AIModel.deviceArchitectureName` is the identifier that - matches `` at runtime. -- Compute units default to best performance. Pass `--preferred-compute` to override, - and use matching load options. -- A compiled asset still requires **some** on-device specialization, AOT removes the - bulk of compilation, not all of it. AOT only targets Apple Intelligence devices. - -## Checklist - -- [ ] Metal Toolchain installed (Xcode, or `xcodebuild -downloadComponent MetalToolchain`). -- [ ] `.aimodel` added to the target and visible in _Compile Sources_. -- [ ] `AIModel(contentsOf:)` awaited; slow first load handled (or AOT-compiled). -- [ ] `loadFunction(named:)` nil-checked; `functionNames` inspected for multi-function models. -- [ ] Input `shape` / `scalarType` verified against `function.descriptor`. -- [ ] Mutable views for writes, read-only views for reads. -- [ ] Outputs extracted by name with `outputs.remove(_:)`. -- [ ] For large models: per-architecture `.aimodelc` built via `coreai-build`, and the - correct asset selected at runtime using `AIModel.deviceArchitectureName`. - -## Resources - -- Apple: _Integrating on-device AI models in your app with Core AI_ -- Apple: _Compiling Core AI models ahead of time_ -- Prefer Apple docs for up-to-date API details; web-search the current Core AI - documentation alongside this skill. +- Building needs the Metal Toolchain. +- NDArray views are read-only by default. Use `mutableView(as:)` for writes. +- Ahead-of-time compilation removes most but not all on-device specialization, and only targets Apple Intelligence devices. `--preferred-compute` overrides the default compute units. diff --git a/build-ios-apps/skills/foundation-models/SKILL.md b/build-ios-apps/skills/foundation-models/SKILL.md index 09eb354..0e51f29 100644 --- a/build-ios-apps/skills/foundation-models/SKILL.md +++ b/build-ios-apps/skills/foundation-models/SKILL.md @@ -1,186 +1,12 @@ --- name: foundation-models -description: Build on-device generative AI with Apple's Foundation Models framework. Use the system language model (Apple Intelligence) for text generation, structured output via @Generable and GenerationSchema, tool calling, and multimodal prompts through a LanguageModelSession. +description: Build on-device generative AI with Apple's Foundation Models framework. Use for text generation, @Generable structured output, tool calling, or multimodal prompts through a LanguageModelSession. --- # Foundation Models -## Overview +Docs: . APIs are new, so check current docs instead of answering from memory. -Foundation Models is Apple's generative-AI framework for intelligent app features. You -drive a language model through a `LanguageModelSession`, generating text, structuring -output into Swift types with guided generation (`@Generable`, `GenerationSchema`), and -letting the model call your own `Tool`s during generation. The default backend is the -**system language model** (`SystemLanguageModel`), which runs on Apple Intelligence -(iPhone, iPad, and Mac with Apple silicon). The same session API also targets -**Private Cloud Compute** (`PrivateCloudComputeLanguageModel`, server-side) or a -**custom language model provider**, so session code is portable across backends. - -Before any feature, gate on availability, the model can be unavailable for several -reasons: - -```swift -private var model = SystemLanguageModel.default - -switch model.availability { -case .available: - // Show your intelligence UI. -case .unavailable(.deviceNotEligible): - // Device can't run the model; offer an alternative. -case .unavailable(.appleIntelligenceNotEnabled): - // Ask the person to turn on Apple Intelligence. -case .unavailable(.modelNotReady): - // Still downloading or otherwise not ready. -case .unavailable(let other): - // Other system reason. -} -``` - -## Essentials - -Create a session and respond to a prompt. `respond(to:)` is async and throws. - -```swift -let session = LanguageModelSession() -let response = try await session.respond(to: "Write a profile for a dog breed.") -print(response.content) -``` - -Instructions give the session persistent behavior; `GenerationOptions` (e.g. -`temperature`) tunes sampling; `ContextOptions` manages the context window: - -```swift -let session = LanguageModelSession(instructions: """ - Suggest five related topics. Keep them concise (three to seven words). - """) - -let response = try await session.respond(to: "Making homemade bread") - -// More creative sampling. -let session2 = LanguageModelSession() -let r = try await session2.respond( - to: "Write me a story about coffee.", - options: GenerationOptions(temperature: 1.0) -) -``` - -Use `LanguageModelSession(model:)` to target a backend, and the session's streaming API -to receive output incrementally for long generations. - -## Structured Output (Guided Generation) - -Generate typed data instead of free text. For primitives, pass the type directly: - -```swift -let r = try await session.respond(to: "How many tablespoons are in a cup?", - generating: Float.self) -``` - -For custom types, conform to `Generable` and guide fields with `@Guide` (supports -constraints such as `.range(...)`): - -```swift -@Generable(description: "Basic profile information about a cat") -struct CatProfile { - var name: String - - @Guide(description: "The age of the cat", .range(0...20)) - var age: Int - - @Guide(description: "A one sentence profile about the cat's personality") - var profile: String -} - -let r = try await session.respond(to: "Generate a cute rescue cat", - generating: CatProfile.self) -``` - -For schemas built at runtime, assemble `DynamicGenerationSchema` nodes into a -`GenerationSchema`, then pass `schema:`: - -```swift -let menuSchema = DynamicGenerationSchema( - name: "Menu", - properties: [ - DynamicGenerationSchema.Property( - name: "dailySoup", - schema: DynamicGenerationSchema( - name: "dailySoup", - anyOf: ["Tomato", "Chicken Noodle", "Clam Chowder"] - ) - ) - // Add additional properties. - ] -) - -let schema = try GenerationSchema(root: menuSchema, dependencies: []) -let r = try await session.respond(to: "What is today's menu?", schema: schema) -``` - -## Tool Calling - -Let the model invoke your code during generation. Conform to `Tool`; describe arguments -with `@Generable` and return simple, model-friendly content from `call(arguments:)`: - -```swift -struct BreadDatabaseTool: Tool { - let name = "searchBreadDatabase" - let description = "Searches a local database for bread recipes." - - @Generable struct Arguments { - @Guide(description: "The type of bread to search for") - var searchTerm: String - - @Guide(description: "The number of recipes to get", .range(1...6)) - var limit: Int - } - - func call(arguments: Arguments) async throws -> [String] { - // Retrieve recipes from your database, then return formatted strings. - return [] - } -} - -let session = LanguageModelSession(tools: [BreadDatabaseTool()]) -let r = try await session.respond(to: "Find three sourdough bread recipes") -``` - -## Choosing a Backend - -- `SystemLanguageModel.default`: on-device, Apple Intelligence. Private and - offline-capable; the default for most features. -- `PrivateCloudComputeLanguageModel`: same session API, runs server-side on Apple's - cloud. Requires the `com.apple.developer.private-cloud-compute` entitlement. Use when - you need a larger cloud model; reuse your existing session code. -- Custom language model provider: bring your own model behind the same session API. - -Attach images with `Attachment` / `ImageAttachmentContent` for multimodal prompting and -image analysis. - -## Checklist - -- [ ] Check `SystemLanguageModel.default.availability`; provide a fallback for each case. -- [ ] Use `LanguageModelSession`, with `instructions:` for persistent guidance. -- [ ] Prefer guided generation (`@Generable` / `@Guide` or `GenerationSchema`) over - parsing free text. -- [ ] Constrain numeric fields with `@Guide` ranges; validate generated values. -- [ ] Expose app capabilities as `Tool`s that return simple, model-friendly content. -- [ ] Pick the backend deliberately: system vs Private Cloud Compute vs custom provider. -- [ ] Stream long responses and manage the context window with `ContextOptions`. -- [ ] Evaluate prompts and responses, and apply safety guidance for generative output. - -## Related skills - -- `apple-intelligence`: the participation layer (Siri, Spotlight, Writing Tools, Image - Playground) that surrounds on-device generation. -- `core-ai`: running your own model files (`.aimodel`) at the tensor level, for - features that are not language-model shaped. - -## Resources - -- Apple: Foundation Models: -- Generating content and performing tasks with Foundation Models -- Generating Swift data structures with guided generation -- Expanding generation with tool calling -- Prefer Apple docs for up-to-date API details; web-search the current Foundation Models - documentation alongside this skill. +- Check model availability before use and provide a fallback UI. +- Prefer guided generation (`@Generable`, `@Guide`, or `GenerationSchema`) over parsing free text. +- Private Cloud Compute needs the `com.apple.developer.private-cloud-compute` entitlement. diff --git a/build-ios-apps/skills/ios-app-intents/SKILL.md b/build-ios-apps/skills/ios-app-intents/SKILL.md index c75bbb0..9a48168 100644 --- a/build-ios-apps/skills/ios-app-intents/SKILL.md +++ b/build-ios-apps/skills/ios-app-intents/SKILL.md @@ -5,79 +5,9 @@ description: Design App Intents, app entities, and App Shortcuts for iOS system # iOS App Intents -## Overview +Docs: . -Expose the smallest useful action and entity surface to the system. Start with the verbs and objects people would actually want outside the app, then implement a narrow App Intents layer that can deep-link or hand off cleanly into the main app when needed. - -Read these references as needed: - -- `references/first-pass-checklist.md` for choosing the first intent and entity surface -- `references/example-patterns.md` for concrete example shapes to copy and adapt -- `references/code-templates.md` for generalized App Intents code templates -- `references/system-surfaces.md` for how to think about Shortcuts, Siri, Spotlight, widgets, and other system entry points - -## Core workflow - -### 1) Start with actions, not screens - -- Identify the 1-3 highest-value actions that should work outside the app UI. -- Prefer verbs like compose, open, find, filter, continue, inspect, or start. -- Do not mirror the entire app navigation tree as intents. - -### 2) Define a small entity surface - -- Add `AppEntity` types only for the objects the system needs to understand or route. -- Keep the entity shape narrower than the app's persistence model. -- Add `EntityQuery` or other query types only where disambiguation or suggestions are genuinely useful. - -### 3) Decide whether the action completes in place or opens the app - -- Use non-opening intents for actions that can complete directly from the system surface. -- Use `openAppWhenRun` or open-style intents when the user should land in a specific in-app workflow. -- When the app must react inside the main scene, add one clear runtime handoff path instead of scattering ad hoc routing logic. -- If the action can work in both modes, consider shipping both an inline version and an open-app version rather than forcing one compromise. - -### 4) Make the actions discoverable - -- Add `AppShortcutsProvider` entries for the first set of high-value intents. -- Choose titles, phrases, and symbols that make sense in Shortcuts, Siri, and Spotlight. -- Keep shortcut phrases direct and task-oriented. -- Reuse the same action model for widgets and controls when a widget configuration or intent-driven control already needs the same parameters. - -### 5) Validate the runtime handoff - -- Build the app and confirm the intents target compiles cleanly. -- Verify the app opens or routes to the expected place when an intent runs. -- Summarize which actions are now exposed, which entities back them, and how the app handles invocation. - -## Strong defaults - -- Prefer a dedicated intents target or module for the system-facing layer. -- Keep intent types thin; business logic should stay in app services or domain models. -- Keep app entities small and display-friendly. -- Use `AppEnum` for fixed app choices such as tabs, modes, or visibility levels before reaching for a full entity type. -- Prefer one predictable app-intent routing surface in the main app scene or root router. -- Treat App Intents as system integration infrastructure, not only as a Shortcuts feature. - -## Anti-patterns - -- Exposing every screen or tab as its own intent without a real user value. -- Mirroring the entire model graph as `AppEntity` types. -- Hiding runtime handoff in global side effects with no clear app entry path. -- Adding App Shortcuts with vague phrases or generic titles. -- Treating the first App Intents pass as a broad taxonomy project instead of a small useful release. - -## Notes - -- Apple documentation to use as primary references: - - `https://developer.apple.com/documentation/appintents/making-actions-and-content-discoverable-and-widely-available` - - `https://developer.apple.com/documentation/appintents/creating-your-first-app-intent` - - `https://developer.apple.com/documentation/appintents/adopting-app-intents-to-support-system-experiences` -- In addition to the links above, use web search to consult current Apple Developer documentation when App Intents APIs or platform behavior may have changed. -- A good first pass often includes one open-app intent, one action intent, one or two entity types, and a small `AppShortcutsProvider`. -- Good example families to cover are: - - open a destination or editor in the app - - perform a lightweight action inline without opening the app - - choose from a fixed enum such as a tab or mode - - resolve one or more entities through `EntityQuery` - - power widget configuration or controls from the same entity surface +- Name intents with verbs (open, find, compose, continue). Do not mirror the whole navigation tree as intents. +- Add `AppEntity` and `EntityQuery` types only where the system needs to route or disambiguate. +- Put the system-facing layer in a dedicated intents target or module, with one predictable handoff into the main scene. +- Treat App Intents as system integration infrastructure, not only a Shortcuts feature. diff --git a/build-ios-apps/skills/ios-app-intents/references/code-templates.md b/build-ios-apps/skills/ios-app-intents/references/code-templates.md deleted file mode 100644 index 08a76aa..0000000 --- a/build-ios-apps/skills/ios-app-intents/references/code-templates.md +++ /dev/null @@ -1,303 +0,0 @@ -# Code templates - -These templates are intentionally generic. Rename types and services to fit the app. - -## Open-app handoff intent - -```swift -import AppIntents - -struct OpenComposerIntent: AppIntent { - static let title: LocalizedStringResource = "Open composer" - static let description = IntentDescription("Open the app to compose content") - static let openAppWhenRun = true - - @Parameter( - title: "Prefilled text", - inputConnectionBehavior: .connectToPreviousIntentResult - ) - var text: String? - - func perform() async throws -> some IntentResult { - await MainActor.run { - AppIntentRouter.shared.handledIntent = .init(intent: self) - } - return .result() - } -} -``` - -Scene-side handoff: - -```swift -import AppIntents -import Observation - -@Observable -final class AppIntentRouter { - struct HandledIntent: Equatable { - let id = UUID() - let intent: any AppIntent - - static func == (lhs: Self, rhs: Self) -> Bool { - lhs.id == rhs.id - } - } - - static let shared = AppIntentRouter() - var handledIntent: HandledIntent? - - private init() {} -} - -private func handleIntent() { - guard let intent = appIntentRouter.handledIntent?.intent else { return } - - if let composerIntent = intent as? OpenComposerIntent { - appRouter.presentComposer(prefilledText: composerIntent.text ?? "") - } else if let sectionIntent = intent as? OpenSectionIntent { - selectedTab = sectionIntent.section.toTab - } -} -``` - -## Inline action intent - -```swift -import AppIntents - -struct CreateItemIntent: AppIntent { - static let title: LocalizedStringResource = "Create item" - static let description = IntentDescription("Create a new item without opening the app") - static let openAppWhenRun = false - - @Parameter(title: "Title") - var title: String - - @Parameter(title: "Workspace") - var workspace: WorkspaceEntity - - func perform() async throws -> some IntentResult & ProvidesDialog { - do { - try await ItemService.shared.createItem(title: title, workspaceID: workspace.id) - return .result(dialog: "Created \(title).") - } catch { - return .result(dialog: "Could not create the item. Please try again.") - } - } -} -``` - -## Fixed selection with `AppEnum` - -```swift -import AppIntents - -enum SectionIntentValue: String, AppEnum { - case inbox - case projects - case settings - - static var typeDisplayName: LocalizedStringResource { "Section" } - static let typeDisplayRepresentation: TypeDisplayRepresentation = "Section" - - static var caseDisplayRepresentations: [Self: DisplayRepresentation] { - [ - .inbox: "Inbox", - .projects: "Projects", - .settings: "Settings", - ] - } - - var toTab: AppTab { - switch self { - case .inbox: .inbox - case .projects: .projects - case .settings: .settings - } - } -} - -struct OpenSectionIntent: AppIntent { - static let title: LocalizedStringResource = "Open section" - static let openAppWhenRun = true - - @Parameter(title: "Section") - var section: SectionIntentValue - - func perform() async throws -> some IntentResult { - await MainActor.run { - AppIntentRouter.shared.handledIntent = .init(intent: self) - } - return .result() - } -} -``` - -## Entity and query - -```swift -import AppIntents - -struct WorkspaceEntity: AppEntity, Identifiable { - let workspace: Workspace - - var id: String { workspace.id } - - static let typeDisplayRepresentation: TypeDisplayRepresentation = "Workspace" - static let defaultQuery = WorkspaceQuery() - - var displayRepresentation: DisplayRepresentation { - DisplayRepresentation(title: "\(workspace.name)") - } -} - -struct WorkspaceQuery: EntityQuery { - func entities(for identifiers: [WorkspaceEntity.ID]) async throws -> [WorkspaceEntity] { - let workspaces = try await WorkspaceStore.shared.workspaces(matching: identifiers) - return workspaces.map(WorkspaceEntity.init) - } - - func suggestedEntities() async throws -> [WorkspaceEntity] { - try await WorkspaceStore.shared.recentWorkspaces().map(WorkspaceEntity.init) - } - - func defaultResult() async -> WorkspaceEntity? { - guard let workspace = try? await WorkspaceStore.shared.currentWorkspace() else { return nil } - return WorkspaceEntity(workspace: workspace) - } -} -``` - -## Dependent query - -```swift -import AppIntents - -struct ProjectEntity: AppEntity, Identifiable { - let project: Project - - var id: String { project.id } - - static let typeDisplayRepresentation: TypeDisplayRepresentation = "Project" - static let defaultQuery = ProjectQuery() - - var displayRepresentation: DisplayRepresentation { - DisplayRepresentation(title: "\(project.name)") - } -} - -struct ProjectSelectionIntent: WidgetConfigurationIntent { - static let title: LocalizedStringResource = "Project widget configuration" - - @Parameter(title: "Workspace") - var workspace: WorkspaceEntity? - - @Parameter(title: "Project") - var project: ProjectEntity? -} - -struct ProjectQuery: EntityQuery { - @IntentParameterDependency(\.$workspace) - var workspace - - func entities(for identifiers: [ProjectEntity.ID]) async throws -> [ProjectEntity] { - try await fetchProjects().filter { identifiers.contains($0.id) }.map(ProjectEntity.init) - } - - func suggestedEntities() async throws -> [ProjectEntity] { - try await fetchProjects().map(ProjectEntity.init) - } - - func defaultResult() async -> ProjectEntity? { - try? await fetchProjects().first.map(ProjectEntity.init) - } - - private func fetchProjects() async throws -> [Project] { - guard let workspaceID = workspace?.id else { return [] } - return try await ProjectStore.shared.projects(in: workspaceID) - } -} -``` - -## Widget configuration intent - -```swift -import AppIntents -import WidgetKit - -struct ActivityWidgetConfiguration: WidgetConfigurationIntent { - static let title: LocalizedStringResource = "Activity widget configuration" - static let description = IntentDescription("Choose which workspace and filter the widget should show") - - @Parameter(title: "Workspace") - var workspace: WorkspaceEntity? - - @Parameter(title: "Filter") - var filter: ActivityFilterEntity? -} -``` - -## App shortcuts provider - -```swift -import AppIntents - -struct AppShortcuts: AppShortcutsProvider { - static var appShortcuts: [AppShortcut] { - AppShortcut( - intent: OpenComposerIntent(), - phrases: [ - "Open composer in \(.applicationName)", - "Draft with \(.applicationName)", - ], - shortTitle: "Open composer", - systemImageName: "square.and.pencil" - ) - - AppShortcut( - intent: CreateItemIntent(), - phrases: [ - "Create item with \(.applicationName)", - "Add a task in \(.applicationName)", - ], - shortTitle: "Create item", - systemImageName: "plus.circle" - ) - } -} -``` - -## Inline file input - -```swift -import AppIntents -import UniformTypeIdentifiers - -struct ImportAttachmentIntent: AppIntent { - static let title: LocalizedStringResource = "Import attachment" - static let openAppWhenRun = false - - @Parameter( - title: "Files", - supportedContentTypes: [.image, .pdf, .plainText], - inputConnectionBehavior: .connectToPreviousIntentResult - ) - var files: [IntentFile] - - func perform() async throws -> some IntentResult & ProvidesDialog { - guard !files.isEmpty else { - return .result(dialog: "No files were provided.") - } - - for file in files { - guard let url = file.fileURL else { continue } - _ = url.startAccessingSecurityScopedResource() - defer { url.stopAccessingSecurityScopedResource() } - try await AttachmentImporter.shared.importFile(at: url) - } - - return .result(dialog: "Imported \(files.count) file(s).") - } -} -``` diff --git a/build-ios-apps/skills/ios-app-intents/references/example-patterns.md b/build-ios-apps/skills/ios-app-intents/references/example-patterns.md deleted file mode 100644 index 3fd0b15..0000000 --- a/build-ios-apps/skills/ios-app-intents/references/example-patterns.md +++ /dev/null @@ -1,161 +0,0 @@ -# Example patterns - -Use these as starting points when deciding what to expose first. - -## 1) Open-app handoff intent - -Best for: - -- compose flows -- editors -- navigation to a destination -- actions that need the full app scene, auth state, or richer UI - -Pattern: - -- `openAppWhenRun = true` -- collect lightweight input in the intent -- store one handled-intent payload in a central router or handoff service -- let the app scene translate that payload into tabs, sheets, routes, or windows - -Example: - -- "Open the app to compose a draft" -- "Open the app on a selected section" -- "Open an editor prefilled with content from the previous shortcut step" - -## 2) Inline background action intent - -Best for: - -- quick create/update actions -- send, archive, mark, favorite, or toggle operations -- actions that can finish without the main app UI - -Pattern: - -- `openAppWhenRun = false` -- perform the operation directly in `perform()` -- return dialog or snippet feedback so the result feels complete in Shortcuts or Siri - -Example: - -- "Create a task" -- "Send a message" -- "Archive a document" - -## 3) Paired open-app and inline variants - -Best for: - -- actions that need both automation and richer manual review -- flows where some users want a background shortcut but others want to land in the app - -Pattern: - -- keep parameter names aligned between the two intents -- let the open-app version hand off to UI -- let the inline version call the same domain service directly -- expose both in `AppShortcutsProvider` with clear titles - -Example: - -- "Draft in app" and "Send now" -- "Open image post editor" and "Post images in background" - -## 4) Fixed choice via `AppEnum` - -Best for: - -- tabs -- modes -- visibility levels -- small sets of filters or categories - -Pattern: - -- define an `AppEnum` -- give every case a user-facing `DisplayRepresentation` -- map enum cases into app-specific types in one place - -Example: - -- open a selected tab -- run an action in "public", "private", or "team" mode - -## 5) Entity-backed selection via `AppEntity` - -Best for: - -- accounts -- projects -- lists -- destinations -- saved searches - -Pattern: - -- expose only the fields needed for display and lookup -- add `suggestedEntities()` for picker UX -- add `defaultResult()` only when there is a genuinely helpful default -- keep network or database fetch logic inside the query type, not the view layer - -Example: - -- choose an account to post from -- pick a project to open -- select a saved list for a widget - -## 6) Query dependency between parameters - -Best for: - -- when one parameter changes the valid choices for another -- widget or control configuration where "account" determines "project" - -Pattern: - -- use `@IntentParameterDependency` inside the query -- read the upstream parameter -- scope entity fetching to the chosen parent value - -Example: - -- selected workspace filters available documents -- selected account filters available lists - -## 7) Widget configuration intent - -Best for: - -- widgets that need a selected account, project, filter, or destination -- intent-driven controls that should reuse the same parameter model - -Pattern: - -- define a `WidgetConfigurationIntent` -- use the same `AppEntity` types that your shortcuts already use -- provide preview-friendly sample values when the widget needs them - -Example: - -- choose account plus list -- choose project plus status filter - -## 8) Shortcut phrase design - -Best for: - -- making actions discoverable in Siri and Shortcuts - -Pattern: - -- keep phrases short and verb-led -- expose one or two canonical phrases, then add only a few natural variants -- use precise `shortTitle` and `systemImageName` - -Example: - -- "Create a note with \(.applicationName)" -- "Open inbox in \(.applicationName)" -- "Send image with \(.applicationName)" diff --git a/build-ios-apps/skills/ios-app-intents/references/first-pass-checklist.md b/build-ios-apps/skills/ios-app-intents/references/first-pass-checklist.md deleted file mode 100644 index 274003f..0000000 --- a/build-ios-apps/skills/ios-app-intents/references/first-pass-checklist.md +++ /dev/null @@ -1,57 +0,0 @@ -# First-pass checklist - -Use this checklist when deciding what to expose in the first App Intents release. - -## Pick the first actions - -Choose actions that are: - -- useful without browsing the full app first -- easy to describe in one sentence -- valuable in Shortcuts, Siri, Spotlight, or widgets -- backed by existing app logic instead of requiring a major rewrite - -Good first candidates: - -- compose something -- open a destination or object -- find or filter a known object -- continue an existing workflow -- start a focused action - -Avoid as a first pass: - -- giant setup flows -- actions that only make sense after many in-app taps -- low-value screens exposed only because they exist - -## Pick the first entities - -Use app entities when the system needs to identify or display app objects. - -Good first entities: - -- account -- list -- filter -- destination -- draft -- media item - -Keep each entity focused on: - -- identifier -- display representation -- the few fields the system needs for routing or disambiguation - -Do not mirror the entire persistence model if a much smaller system-facing type will do. - -## Decide the handoff model - -For each intent, ask: - -- Can this finish directly from the system surface? -- Should this open the app to a specific place? -- If it opens the app, what is the single clean route back into the main scene? - -Prefer one explicit routing or handoff service over many feature-specific side channels. diff --git a/build-ios-apps/skills/ios-app-intents/references/system-surfaces.md b/build-ios-apps/skills/ios-app-intents/references/system-surfaces.md deleted file mode 100644 index becd986..0000000 --- a/build-ios-apps/skills/ios-app-intents/references/system-surfaces.md +++ /dev/null @@ -1,31 +0,0 @@ -# System surfaces - -Think in system entry points, not just in shortcuts. - -## Shortcuts - -- Good for direct actions and automation chains. -- Expose the actions that users would actually want to reuse. -- Add `AppShortcutsProvider` entries for the first high-value intents. - -## Siri - -- Good for clear verbs and deep-linkable actions. -- Phrase titles and parameters so the system can present and disambiguate them clearly. - -## Spotlight - -- Good for discoverability of both actions and entities. -- Use strong display representations and clear type names. - -## Widgets, Live Activities, and controls - -- Good when the same actions already make sense as intent-driven entry points. -- Reuse the same intent surface where practical instead of inventing separate action models. - -## General guidance - -- Design one small action layer that can serve several surfaces. -- Keep action names concrete and user-facing. -- Prefer structured entities and parameters over trying to encode everything in free-form text. -- Start narrow, ship a useful set, then expand based on real use. diff --git a/build-ios-apps/skills/ios-debugger-agent/SKILL.md b/build-ios-apps/skills/ios-debugger-agent/SKILL.md index 0c3cfe4..d174e52 100644 --- a/build-ios-apps/skills/ios-debugger-agent/SKILL.md +++ b/build-ios-apps/skills/ios-debugger-agent/SKILL.md @@ -3,68 +3,11 @@ name: ios-debugger-agent description: Build, run, and debug iOS apps on Simulator with XcodeBuildMCP. Use when launching an app, inspecting simulator UI or logs, or diagnosing runtime behavior. --- -# iOS Debugger Agent +# iOS debugger agent -## Overview +Use the XcodeBuildMCP tools (). Without it, fall back to `xcrun simctl` and `xcodebuild`, noting that tapping and typing then need a UI test. -Requires the XcodeBuildMCP server (install: , then add it to your MCP config). Without it, use the `xcrun simctl` fallback below. - -Use XcodeBuildMCP to build and run the current project scheme on a booted iOS simulator, interact with the UI, and capture logs. Prefer the MCP tools for simulator control, logs, and view inspection. - -## Core Workflow - -Follow this sequence unless the user asks for a narrower action. - -### 1) Discover the booted simulator - -- Call `mcp__XcodeBuildMCP__list_sims` and select the simulator with state `Booted`. -- If none are booted, ask the user to boot one (do not boot automatically unless asked). - -### 2) Set session defaults - -- Call `mcp__XcodeBuildMCP__session-set-defaults` with: - - `projectPath` or `workspacePath` (whichever the repo uses) - - `scheme` for the current app - - `simulatorId` from the booted device - - Optional: `configuration: "Debug"`, `useLatestOS: true` - -### 3) Build + run (when requested) - -- Call `mcp__XcodeBuildMCP__build_run_sim`. -- **If the build fails**, check the error output and retry (optionally with `preferXcodebuild: true`) or escalate to the user before attempting any UI interaction. -- **After a successful build**, verify the app launched by calling `mcp__XcodeBuildMCP__describe_ui` or `mcp__XcodeBuildMCP__screenshot` before proceeding to UI interaction. -- If the app is already built and only launch is requested, use `mcp__XcodeBuildMCP__launch_app_sim`. -- If bundle id is unknown: - 1. `mcp__XcodeBuildMCP__get_sim_app_path` - 2. `mcp__XcodeBuildMCP__get_app_bundle_id` - -## UI Interaction & Debugging - -Use these when asked to inspect or interact with the running app. - -- **Describe UI**: `mcp__XcodeBuildMCP__describe_ui` before tapping or swiping. -- **Tap**: `mcp__XcodeBuildMCP__tap` (prefer `id` or `label`; use coordinates only if needed). -- **Type**: `mcp__XcodeBuildMCP__type_text` after focusing a field. -- **Gestures**: `mcp__XcodeBuildMCP__gesture` for common scrolls and edge swipes. -- **Screenshot**: `mcp__XcodeBuildMCP__screenshot` for visual confirmation. - -## Logs & Console Output - -- Start logs: `mcp__XcodeBuildMCP__start_sim_log_cap` with the app bundle id. -- Stop logs: `mcp__XcodeBuildMCP__stop_sim_log_cap` and summarize important lines. -- For console output, set `captureConsole: true` and relaunch if required. - -## Fallback without XcodeBuildMCP - -- List and boot: `xcrun simctl list devices booted`, `xcrun simctl boot `. -- Build: `xcodebuild -scheme -destination 'platform=iOS Simulator,id=' -derivedDataPath build build`. -- Install and launch: `xcrun simctl install build/Build/Products/Debug-iphonesimulator/.app`, then `xcrun simctl launch --console `. -- Screenshot: `xcrun simctl io screenshot out.png`. -- Logs: `xcrun simctl spawn log stream --predicate 'subsystem == ""'`. -- UI tapping and typing need XcodeBuildMCP or a UI test. - -## Troubleshooting - -- If build fails, ask whether to retry with `preferXcodebuild: true`. -- If the wrong app launches, confirm the scheme and bundle id. -- If UI elements are not hittable, re-run `describe_ui` after layout changes. +- Use a booted simulator. Ask before booting one. +- Set session defaults (project or workspace, scheme, simulator id) before building. +- After a build, confirm the app launched with a UI description or screenshot before interacting. +- Describe the UI before tapping. Prefer `id` or `label` over coordinates. diff --git a/build-ios-apps/skills/ios-ettrace-performance/SKILL.md b/build-ios-apps/skills/ios-ettrace-performance/SKILL.md index 93ed460..47badbf 100644 --- a/build-ios-apps/skills/ios-ettrace-performance/SKILL.md +++ b/build-ios-apps/skills/ios-ettrace-performance/SKILL.md @@ -3,189 +3,12 @@ name: ios-ettrace-performance description: Capture and interpret iOS Simulator ETTrace profiles. Use when profiling launch or runtime latency, comparing traces, or finding CPU-heavy stacks. --- -# iOS ETTrace Performance +# iOS ETTrace performance -Use this skill to capture a focused, symbolicated ETTrace profile from an iOS simulator app. Pair it with `../ios-debugger-agent/SKILL.md` when the task also needs simulator build, install, launch, UI driving, logs, or screenshots. +Tool: (`brew install emergetools/homebrew-tap/ettrace`, then `ettrace --help`). Pair with `ios-debugger-agent` for build, launch, and UI driving. -## Core Workflow - -1. Pick one focused flow and write down the expected start and stop points. -2. Build the exact simulator app that will be installed and profiled. -3. Temporarily link ETTrace into that app target for simulator/debug profiling. -4. Collect UUID-matched dSYMs for the app executable and embedded dynamic frameworks. -5. Capture one launch or runtime trace. -6. Preserve the processed flamegraph JSON immediately after the run. -7. Analyze only the processed JSON and report the flow, artifacts, hotspots, and caveats. - -Avoid broad "use the app for a while" captures. One trace should correspond to one user-visible flow. - -## Setup - -Use a writable run folder for each profiling session: - -```bash -if [ -z "${RUN_DIR:-}" ]; then - RUN_DIR="$(mktemp -d "${TMPDIR:-/tmp}/ios-ettrace.XXXXXX")" -fi -mkdir -p "$RUN_DIR" -``` - -Install the ETTrace runner CLI if it is not already available: - -```bash -brew install emergetools/homebrew-tap/ettrace -``` - -`ettrace` is the host-side macOS runner. The app must also link an `ETTrace.xcframework` for the iOS Simulator architecture. -This workflow is validated for ETTrace v1.1.0 processed `output_.json` files with top-level `nodes`. - -## Link ETTrace Into The App - -Wire ETTrace into the exact app target being profiled. Keep the integration in a clearly temporary patch and remove it when the profiling task is done unless the user explicitly asks to keep it. - -Preferred options: - -- Reuse an existing simulator-compatible `ETTrace.xcframework` if the repo already vendors one. -- If none exists, build a simulator-only copy into `RUN_DIR` from the upstream ETTrace package. -- Link the framework directly into the app target, not only into tests, resources, data files, or a nested launcher target. -- Confirm launch logs print `Starting ETTrace`. -- Profile only one ETTrace-instrumented simulator app at a time because simulator mode listens on a fixed localhost port. - -Build a simulator framework when needed: - -```bash -ETTRACE_TAG="${ETTRACE_TAG:-v1.1.0}" # Override to match the installed runner when Homebrew updates. -ETTRACE_SRC="$RUN_DIR/ETTrace-src" -if [ ! -d "$ETTRACE_SRC" ]; then - git clone --depth 1 --branch "$ETTRACE_TAG" https://github.com/EmergeTools/ETTrace "$ETTRACE_SRC" -fi - -rm -rf "$RUN_DIR/ETTrace-iphonesimulator.xcarchive" "$RUN_DIR/ETTrace.xcframework" -pushd "$ETTRACE_SRC" >/dev/null -xcodebuild archive \ - -scheme ETTrace \ - -archivePath "$RUN_DIR/ETTrace-iphonesimulator.xcarchive" \ - -sdk iphonesimulator \ - -destination 'generic/platform=iOS Simulator' \ - BUILD_LIBRARY_FOR_DISTRIBUTION=YES \ - INSTALL_PATH='Library/Frameworks' \ - SKIP_INSTALL=NO \ - CLANG_CXX_LANGUAGE_STANDARD=c++17 - -xcodebuild -create-xcframework \ - -framework "$RUN_DIR/ETTrace-iphonesimulator.xcarchive/Products/Library/Frameworks/ETTrace.framework" \ - -output "$RUN_DIR/ETTrace.xcframework" -popd >/dev/null -``` - -For Bazel apps, a temporary import usually looks like: - -```python -load("@rules_apple//apple:apple.bzl", "apple_dynamic_xcframework_import") - -package(default_visibility = ["//visibility:public"]) - -apple_dynamic_xcframework_import( - name = "ETTrace", - xcframework_imports = glob(["ETTrace.xcframework/**"]), -) -``` - -For Xcode projects, temporarily add the simulator `ETTrace.xcframework` to the app target's Link Binary With Libraries / Embed Frameworks phases for the debug simulator build you are profiling, then remove that wiring after profiling. - -## Symbolication Gate - -Do not draw conclusions from an unsymbolicated flamegraph. Before every capture, prepare a dSYM folder that includes the app dSYM and any embedded first-party dynamic framework dSYMs. - -Collect dSYMs after the final build that produced the installed app: - -```bash -APP="" -DSYMS="$RUN_DIR/dsyms" -mkdir -p "$DSYMS" -find "$(dirname "$APP")" "$PWD" -name '*.dSYM' -type d -prune -exec cp -R {} "$DSYMS"/ \; 2>/dev/null -cp -R "$RUN_DIR/ETTrace-iphonesimulator.xcarchive/dSYMs/ETTrace.framework.dSYM" "$DSYMS"/ 2>/dev/null || true -``` - -For app-owned dynamic frameworks that must symbolicate, confirm each has a dSYM in `$DSYMS`. If one is missing, rebuild the exact simulator app with dSYM generation before tracing, or copy the dSYMs from the build output directory. - -Verify important UUIDs before tracing when the report looks suspicious: - -```bash -dwarfdump --uuid "$APP/$(/usr/libexec/PlistBuddy -c 'Print :CFBundleExecutable' "$APP/Info.plist")" -find "$DSYMS" -maxdepth 1 -type d -name '*.dSYM' -print -exec dwarfdump --uuid {} \; -``` - -After ETTrace exits, read its symbolication summary. Treat meaningful first-party "have library but no symbol" lines as a failed trace unless they are tiny noise. Unsymbolicated system-framework or ETTrace internal buckets are usually acceptable. - -## Capture - -For launch traces: - -```bash -cd "$RUN_DIR" -CAPTURE_MARKER="$RUN_DIR/.ettrace-capture-start" -: > "$CAPTURE_MARKER" -find "$RUN_DIR" -maxdepth 1 \( -name 'output.json' -o -name 'output_*.json' \) -delete -ettrace --simulator --launch --verbose --dsyms "$DSYMS" -``` - -Use `--launch` only when measuring startup or first render. The first launch connection can force quit the app; relaunch from the simulator home screen rather than Xcode if prompted. For first-launch-after-install traces, temporarily set `ETTraceRunAtStartup=YES` in the app Info.plist, then run `ettrace --simulator` and launch from the home screen. - -For runtime flow traces: - -```bash -cd "$RUN_DIR" -CAPTURE_MARKER="$RUN_DIR/.ettrace-capture-start" -: > "$CAPTURE_MARKER" -find "$RUN_DIR" -maxdepth 1 \( -name 'output.json' -o -name 'output_*.json' \) -delete -ettrace --simulator --verbose --dsyms "$DSYMS" -``` - -Start from a stable screen, start ETTrace, perform exactly one focused flow, wait until visible work is complete, then stop the runner. For wider attribution, add `--multi-thread`; otherwise start with the main thread. - -Run `ettrace` in an interactive terminal (TTY) and answer its prompts there. Without a TTY, the runner can exit without a useful trace. - -## Preserve Outputs - -The next ETTrace run can overwrite processed flamegraph files, so preserve fresh `output_.json` files immediately. Do not analyze a saved `output.json`; ETTrace also serves a viewer route with that name, and raw `emerge-output/output.json` files are not the processed flamegraph artifacts this workflow expects. - -```bash -PRESERVED_DIR="$(mktemp -d "$RUN_DIR/run-$(date +%Y%m%d-%H%M%S).XXXXXX")" -: > "$PRESERVED_DIR/summary.txt" -if [ ! -e "$CAPTURE_MARKER" ]; then - echo "error: capture marker missing; start a fresh ETTrace capture before preserving outputs" >&2 - exit 1 -fi -find "$RUN_DIR" -maxdepth 1 -name 'output_*.json' -newer "$CAPTURE_MARKER" -print | while IFS= read -r json; do - preserved="$PRESERVED_DIR/${json##*/}" - cp "$json" "$preserved" - { - echo "## ${preserved##*/}" - wc -c "$preserved" - } >> "$PRESERVED_DIR/summary.txt" -done -if [ ! -s "$PRESERVED_DIR/summary.txt" ]; then - echo "error: no fresh processed ETTrace output JSON found in $RUN_DIR" >&2 - exit 1 -fi -``` - -Analyze only processed `output_*.json` files in `RUN_DIR`. Ignore `output.json` and raw `emerge-output/output.json` files unless debugging ETTrace itself. If the JSON shape is unexpected, capture again with the Homebrew ETTrace runner and matching app-side `ETTrace.xcframework` tag instead of trying to interpret the rejected file. - -## Read The Profile - -Read each preserved `output_*.json` directly (for example with `jq` or a short Python script) and rank stacks by sample weight. - -Report: - -- exact flow, app build, simulator model/runtime, and run count -- processed flamegraph JSON paths -- top active leaves and inclusive first-party stacks with sample weights or percentages -- whether symbols were complete for app-owned binaries -- caveats such as first-run setup, simulator-only cost, network variance, or low sample count -- before/after deltas only when the same flow was captured with comparable setup - -## Cleanup - -Remove temporary ETTrace app wiring when profiling is complete unless the user asked to keep it. Keep or discard run artifacts based on the active task. +- One trace per user-visible flow. Link `ETTrace.xcframework` into the exact app target temporarily and remove it afterward. +- Do not draw conclusions from an unsymbolicated trace. Provide UUID-matched dSYMs for the app and embedded first-party frameworks via `--dsyms`. +- Run `ettrace` in a TTY. Only one instrumented simulator app at a time (fixed localhost port). +- Analyze only the processed `output_.json` files, and copy them right away because the next run overwrites them. Ignore `output.json`. +- Report flow, build, simulator runtime, top stacks with weights, symbolication completeness, and caveats. Compare before and after only for the same flow and setup. diff --git a/build-ios-apps/skills/ios-memgraph-leaks/SKILL.md b/build-ios-apps/skills/ios-memgraph-leaks/SKILL.md index 1b77629..f922214 100644 --- a/build-ios-apps/skills/ios-memgraph-leaks/SKILL.md +++ b/build-ios-apps/skills/ios-memgraph-leaks/SKILL.md @@ -3,74 +3,13 @@ name: ios-memgraph-leaks description: Capture and inspect iOS leaks and memgraphs. Use when debugging leaked objects, retain cycles, memory growth, or before/after leak evidence. --- -# iOS Memgraph Leaks +# iOS memgraph leaks -Use this skill to prove iOS leaks from a live simulator process or an existing `.memgraph`. Pair it with `../ios-debugger-agent/SKILL.md` when the task also needs simulator build, install, launch, UI driving, logs, or screenshots. +Pair with `ios-debugger-agent` to build and drive the flow. Scripts live in this skill's `scripts/` (resolve the skill folder, not the app repo's cwd). Store captures in a temp folder. -## Core Workflow - -1. Build, launch, and drive the exact flow that should release objects. -2. Capture a memgraph from the running simulator process with `scripts/capture_sim_memgraph.sh`. -3. Summarize leaks with `scripts/summarize_memgraph_leaks.py`. -4. For each app-owned leaked type, inspect ownership with `leaks --traceTree=
` and grouped leak evidence. -5. Make the smallest root-cause patch, then recapture the same flow on the same simulator when possible. -6. Report proof: before/after leak counts, disappeared root types, remaining leaks, memgraph paths, and test/build results. - -Do not claim a leak fix from a smaller memgraph alone. A credible fix explains the ownership path that kept the object alive and shows that the same path or type disappears after the patch. - -## Capture - -Prefer capturing from the simulator already used for the reproduction. Resolve the simulator UDID and app bundle identifier, then capture the running app: - -```bash -SKILL_DIR="" -SIM="" -BUNDLE_ID="" -MEMGRAPH_DIR="$(mktemp -d "${TMPDIR:-/tmp}/ios-memgraph.XXXXXX")" - -"$SKILL_DIR/scripts/capture_sim_memgraph.sh" \ - --udid "$SIM" \ - --bundle-id "$BUNDLE_ID" \ - --out-dir "$MEMGRAPH_DIR" -``` - -Do not derive `SKILL_DIR` from the target app repo's `pwd`; installed plugins usually live outside the app being debugged. Store captures in a run-specific temp or user-chosen folder, not under `SKILL_DIR`. - -If the process cannot be found, confirm the bundle identifier and use `xcrun simctl spawn "$SIM" launchctl list` to inspect running labels. - -## Summarize - -Summarize an existing memgraph: - -```bash -"$SKILL_DIR/scripts/summarize_memgraph_leaks.py" \ - /path/to/app.memgraph \ - --trace-limit 5 \ - --out /path/to/leak-summary.md -``` - -Use `--trace-limit` sparingly. Trace trees are useful root-cause evidence, but large memgraphs can produce noisy output. If a trace tree says `Found 0 roots referencing`, treat it as an unreachable/self-retained leak candidate and use the summary's grouped leak tree or `leaks --groupByType ` to identify the retained fields and payload chain. - -## Root Cause Rules - -- Identify the first app-owned leaked type in the leak output or trace. -- Determine the intended lifetime: process, session, account, view, request, or task. -- Treat lazy or deferred allocation as a scope reduction, not a leak fix, unless the original eager allocation itself violated the intended lifetime. -- Prove retain-cycle claims with either a `traceTree` ownership path or an isolated reproduction. -- For unreachable/self-cycle leaks, `traceTree` may have no root path; use `leaks --groupByType` plus source verification to find the self-retaining edge. -- Do not claim success just because total leak count went down; prove the specific type or path disappeared. -- Separate real root-cause branches from candidate/noise branches. -- Prefer deleting the retaining edge over adding broad cleanup code. - -## Report - -A useful leak report includes: - -- the exact flow and simulator/app build -- the memgraph and summary paths -- app-owned leaked types and counts -- at least one ownership path, or grouped leak tree evidence when the object is unreachable from roots -- the smallest proposed or applied retaining-edge fix -- before/after evidence when a fix was made - -If the memgraph shows only framework/runtime noise, say that and recommend the next narrower capture rather than inventing an app leak. +- Capture: `scripts/capture_sim_memgraph.sh --udid --bundle-id --out-dir `. +- Summarize: `scripts/summarize_memgraph_leaks.py --trace-limit 5 --out `. +- Inspect ownership with `leaks --traceTree=
`. "Found 0 roots" means an unreachable self-retained leak, so use `leaks --groupByType`. +- Do not claim a fix because the total count dropped. Show the specific type or ownership path disappeared after recapturing the same flow. +- Lazy allocation is a scope reduction, not a fix. Prefer deleting the retaining edge over cleanup code. +- If only framework noise appears, say so and recommend a narrower capture. diff --git a/build-ios-apps/skills/ios-simulator-browser/SKILL.md b/build-ios-apps/skills/ios-simulator-browser/SKILL.md index 3537aa6..77890af 100644 --- a/build-ios-apps/skills/ios-simulator-browser/SKILL.md +++ b/build-ios-apps/skills/ios-simulator-browser/SKILL.md @@ -1,52 +1,12 @@ --- name: ios-simulator-browser -description: Mirror an iOS Simulator into a browser and hot-reload SwiftUI previews from importable Swift packages. Use when previewing SwiftUI in the simulator, mirroring a running simulator in the browser, or live-reloading package-backed previews. +description: Mirror an iOS Simulator into a browser and hot-reload SwiftUI previews from importable Swift packages. Use when previewing SwiftUI in the simulator or live-reloading package-backed previews. --- -# iOS Simulator Browser +# iOS simulator browser -## Browser Workflow +Mirror with `npx --yes serve-sim@latest ` (see `--help`) and open the URL it prints. Run it in a long-lived terminal with a trap that runs `serve-sim --kill `. Never run an unscoped `--kill`. Verify a real frame renders before reporting success. -1. Obtain an explicit Simulator UDID from the existing iOS build/run workflow or from `xcrun simctl list devices available`. -2. Start `serve-sim` in a long-running terminal pinned to that simulator. Clean up any tracked stale helper for this simulator before starting, and install a trap so the helper is cleaned up when this terminal exits: +Previews from a Swift package: `node /scripts/swiftui-preview-browser.mjs /abs/Package.swift --package-target --device ` (see `--help`, including `--preview-filter`). It builds a disposable host outside the source tree and hot-swaps on edits. Never edit the user's `.xcodeproj`, `.xcworkspace`, `Package.swift`, or schemes for preview support. - ```bash - SIM="" - cleanup_serve_sim() { - npx --yes serve-sim@latest --kill "$SIM" >/dev/null 2>&1 || true - } - trap cleanup_serve_sim EXIT INT TERM HUP - cleanup_serve_sim - npx --yes serve-sim@latest "$SIM" - ``` - -3. Open the exact local preview URL printed by `serve-sim` in any browser (your harness's browser tool, or `open ` on macOS). -4. Verify that a real frame is rendering before reporting success. A loaded page alone is not proof that the simulator stream is healthy. - -- Keep the terminal alive while the browser mirror is in use. When finished, stop the terminal and wait for it to exit so the trap runs. -- If the terminal disappeared or did not exit cleanly, run `npx --yes serve-sim@latest --kill "$SIM"` before starting another mirror for that simulator. -- Never run an unscoped `serve-sim --kill`; another thread may own a different simulator mirror. - -## SwiftUI Preview Workflow - -Use the bundled launcher when the requested previews live in an importable Swift package. Point it at the package manifest and select the target whose previews should be displayed. It generates a disposable host project outside the user's source tree, installs and launches that host in Simulator, and watches the package for edits. - -```bash -node /scripts/swiftui-preview-browser.mjs \ - /absolute/path/to/Package.swift \ - --package-target "" \ - --device "" -``` - -- Watch mode is enabled by default. On a Swift package source edit, the launcher rebuilds a generated dylib and hot-swaps it into the running host without relaunching the app. -- The generated host shows every preview variant discovered in the selected Swift Package target with in-simulator page controls. To show a subset instead, pass `--preview-filter `; it matches display names and code identifiers such as `StatusRowView_Previews`. -- Once the launcher prints the selected Simulator UDID, start `serve-sim` for that same UDID and open its printed URL in a browser. - -## Support Boundary - -- Support Swift Package-backed `PreviewProvider` and `#Preview` declarations through the generated host. -- Do not edit the user's `.xcodeproj`, `.xcworkspace`, `Package.swift`, schemes, or build settings to force preview support. - -## Proof - -For browser or preview QA, capture a browser screenshot showing the simulator frame. For hot reload QA, also report the launcher's `hot reloaded package preview ... in pid ...` output and show the changed frame after editing. +Proof: a browser screenshot of the simulator frame. For hot reload, also the launcher's `hot reloaded package preview` output and the changed frame. diff --git a/build-ios-apps/skills/swiftui-liquid-glass/SKILL.md b/build-ios-apps/skills/swiftui-liquid-glass/SKILL.md index 9b43c2a..a76b6ad 100644 --- a/build-ios-apps/skills/swiftui-liquid-glass/SKILL.md +++ b/build-ios-apps/skills/swiftui-liquid-glass/SKILL.md @@ -5,121 +5,8 @@ description: Implement and review iOS 26+ SwiftUI Liquid Glass UI. Use when adop # SwiftUI Liquid Glass -## Overview +Docs: . Check current docs, the API is new. -Use this skill to build or review SwiftUI features that fully align with the iOS 26+ Liquid Glass API. Prioritize native APIs (`glassEffect`, `GlassEffectContainer`, glass button styles) and Apple design guidance. Keep usage consistent, interactive where needed, and performance aware. - -## Adoption Guidance - -Liquid Glass is a dynamic material that forms a distinct functional layer for -controls and navigation. Adopting it well is mostly about getting out of the way: - -- **Prefer standard components.** Bars, sheets, popovers, and controls from SwiftUI - (and UIKit) adopt Liquid Glass automatically when you build with the latest SDK. - Reach for the explicit `glassEffect` API only when a standard component does not - already give you the treatment you need. -- **Remove custom backgrounds on controls and navigation.** Custom backgrounds in - split views, tab bars, and toolbars can overlay or interfere with Liquid Glass and - the scroll-edge effect. Let the system determine background appearance; remove - custom effects unless they are essential. -- **Test accessibility and display settings.** Reduce Transparency, Reduce Motion, - and the user's preferred Liquid Glass look can remove or modify effects. Standard - components adapt automatically; verify your custom elements, colors, and - animations under these configurations. -- **Use glass on custom controls sparingly.** Overusing it distracts from content. - Limit glass to the most important functional elements. -- **App icons are now layered and dynamic.** They respond to lighting and visual - effects, and use a standardized, concentric icon grid. Provide default (light), - dark, clear, and tinted appearances. -- **New navigation affordances.** `TabView` gains `.tabBarMinimizeBehavior(.onScrollDown)` - and a search role via `Tab(role: .search)` (UIKit: `UISearchTab`). - -## Workflow Decision Tree - -Choose the path that matches the request: - -### 1) Review an existing feature - -- Inspect where Liquid Glass should be used and where it should not. -- Verify correct modifier order, shape usage, and container placement. -- Check for iOS 26+ availability handling and sensible fallbacks. - -### 2) Improve a feature using Liquid Glass - -- Identify target components for glass treatment (surfaces, chips, buttons, cards). -- Refactor to use `GlassEffectContainer` where multiple glass elements appear. -- Introduce interactive glass only for tappable or focusable elements. - -### 3) Implement a new feature using Liquid Glass - -- Design the glass surfaces and interactions first (shape, prominence, grouping). -- Add glass modifiers after layout/appearance modifiers. -- Add morphing transitions only when the view hierarchy changes with animation. - -## Core Guidelines - -- Prefer native Liquid Glass APIs over custom blurs. -- Use `GlassEffectContainer` when multiple glass elements coexist. -- Apply `.glassEffect(...)` after layout and visual modifiers. -- Use `.interactive()` for elements that respond to touch/pointer. -- Keep shapes consistent across related elements for a cohesive look. +- Standard bars, sheets, and controls get glass automatically. Use `glassEffect` only when no standard component fits, and never stack custom blurs. +- Group nearby glass in `GlassEffectContainer`. Use `interactive()` only on tappable elements. - Gate with `#available(iOS 26, *)` and provide a non-glass fallback. - -## Review Checklist - -- **Availability**: `#available(iOS 26, *)` present with fallback UI. -- **Composition**: Multiple glass views wrapped in `GlassEffectContainer`. -- **Modifier order**: `glassEffect` applied after layout/appearance modifiers. -- **Interactivity**: `interactive()` only where user interaction exists. -- **Transitions**: `glassEffectID` used with `@Namespace` for morphing. -- **Consistency**: Shapes, tinting, and spacing align across the feature. - -## Implementation Checklist - -- Define target elements and desired glass prominence. -- Wrap grouped glass elements in `GlassEffectContainer` and tune spacing. -- Use `.glassEffect(.regular.tint(...).interactive(), in: .rect(cornerRadius: ...))` as needed. -- Use `.buttonStyle(.glass)` / `.buttonStyle(.glassProminent)` for actions. -- Add morphing transitions with `glassEffectID` when hierarchy changes. -- Provide fallback materials and visuals for earlier iOS versions. - -## Quick Snippets - -Use these patterns directly and tailor shapes/tints/spacing. - -```swift -if #available(iOS 26, *) { - Text("Hello") - .padding() - .glassEffect(.regular.interactive(), in: .rect(cornerRadius: 16)) -} else { - Text("Hello") - .padding() - .background(.ultraThinMaterial, in: RoundedRectangle(cornerRadius: 16)) -} -``` - -```swift -GlassEffectContainer(spacing: 24) { - HStack(spacing: 24) { - Image(systemName: "scribble.variable") - .frame(width: 72, height: 72) - .font(.system(size: 32)) - .glassEffect() - Image(systemName: "eraser.fill") - .frame(width: 72, height: 72) - .font(.system(size: 32)) - .glassEffect() - } -} -``` - -```swift -Button("Confirm") { } - .buttonStyle(.glassProminent) -``` - -## Resources - -- For macOS specifics, use the `liquid-glass` skill from the build-macos-apps plugin when it is installed. -- Prefer Apple docs for up-to-date API details, and use web search to consult current Apple Developer documentation in addition to the references above. diff --git a/build-ios-apps/skills/swiftui-performance-audit/SKILL.md b/build-ios-apps/skills/swiftui-performance-audit/SKILL.md index 6178b4f..feb8272 100644 --- a/build-ios-apps/skills/swiftui-performance-audit/SKILL.md +++ b/build-ios-apps/skills/swiftui-performance-audit/SKILL.md @@ -3,112 +3,11 @@ name: swiftui-performance-audit description: Audit SwiftUI runtime performance from code first. Use when diagnosing slow rendering, janky scrolling, expensive updates, or profiling needs. --- -# SwiftUI Performance Audit +# SwiftUI performance audit -## Quick start +Docs: . -Use this skill to diagnose SwiftUI performance issues from code first, then request profiling evidence when code review alone cannot explain the symptoms. - -## Workflow - -1. Classify the symptom: slow rendering, janky scrolling, high CPU, memory growth, hangs, or excessive view updates. -2. If code is available, start with a code-first review using `references/code-smells.md`. -3. If code is not available, ask for the smallest useful slice: target view, data flow, reproduction steps, and deployment target. -4. If code review is inconclusive or runtime evidence is required, guide the user through profiling with `references/profiling-intake.md`. -5. Summarize likely causes, evidence, remediation, and validation steps using `references/report-template.md`. - -## 1. Intake - -Collect: - -- Target view or feature code. -- Symptoms and exact reproduction steps. -- Data flow: `@State`, `@Binding`, environment dependencies, and observable models. -- Whether the issue shows up on device or simulator, and whether it was observed in Debug or Release. - -Ask the user to classify the issue if possible: - -- CPU spike or battery drain -- Janky scrolling or dropped frames -- High memory or image pressure -- Hangs or unresponsive interactions -- Excessive or unexpectedly broad view updates - -For the full profiling intake checklist, read `references/profiling-intake.md`. - -## 2. Code-First Review - -Focus on: - -- Invalidation storms from broad observation or environment reads. -- Unstable identity in lists and `ForEach`. -- Heavy derived work in `body` or view builders. -- Layout thrash from complex hierarchies, `GeometryReader`, or preference chains. -- Large image decode or resize work on the main thread. -- Animation or transition work applied too broadly. - -Use `references/code-smells.md` for the detailed smell catalog and fix guidance. - -Provide: - -- Likely root causes with code references. -- Suggested fixes and refactors. -- If needed, a minimal repro or instrumentation suggestion. - -## 3. Guide the User to Profile - -If code review does not explain the issue, ask for runtime evidence: - -- A trace export or screenshots of the SwiftUI timeline and Time Profiler call tree. -- Device/OS/build configuration. -- The exact interaction being profiled. -- Before/after metrics if the user is comparing a change. - -Use `references/profiling-intake.md` for the exact checklist and collection steps. - -## 4. Analyze and Diagnose - -- Map the evidence to the most likely category: invalidation, identity churn, layout thrash, main-thread work, image cost, or animation cost. -- Prioritize problems by impact, not by how easy they are to explain. -- Distinguish code-level suspicion from trace-backed evidence. -- Call out when profiling is still insufficient and what additional evidence would reduce uncertainty. - -## 5. Remediate - -Apply targeted fixes: - -- Narrow state scope and reduce broad observation fan-out. -- Stabilize identities for `ForEach` and lists. -- Move heavy work out of `body` into derived state updated from inputs, model-layer precomputation, memoized helpers, or background preprocessing. Use `@State` only for view-owned state, not as an ad hoc cache for arbitrary computation. -- Use `equatable()` only when equality is cheaper than recomputing the subtree and the inputs are truly value-semantic. -- Downsample images before rendering. -- Reduce layout complexity or use fixed sizing where possible. - -Use `references/code-smells.md` for examples, Observation-specific fan-out guidance, and remediation patterns. - -## 6. Verify - -Ask the user to re-run the same capture and compare with baseline metrics. -Summarize the delta (CPU, frame drops, memory peak) if provided. - -## Outputs - -Provide: - -- A short metrics table (before/after if available). -- Top issues (ordered by impact). -- Proposed fixes with estimated effort. - -Use `references/report-template.md` when formatting the final audit. - -## References - -- Profiling intake and collection checklist: `references/profiling-intake.md` -- Common code smells and remediation patterns: `references/code-smells.md` -- Audit output template: `references/report-template.md` -- Add Apple documentation and WWDC resources under `references/` as they are supplied by the user. -- Optimizing SwiftUI performance with Instruments (Apple/WWDC resource, user-supplied) -- Understanding and improving SwiftUI performance (Apple Developer documentation, user-supplied) -- Understanding hangs in your app (Apple Developer documentation, user-supplied) -- Demystify SwiftUI performance: WWDC23 (Apple/WWDC resource, user-supplied) -- In addition to the references above, use web search to consult current Apple Developer documentation when Instruments workflows or SwiftUI performance guidance may have changed. +- Review code first. Ask for an Instruments SwiftUI trace only when the code review is inconclusive. +- Look for heavy work in `body`, broad Observation fan-out, unstable identity in lists, `GeometryReader` and preference chains, and image decoding on the main thread. +- Move heavy work into derived state or the model layer. Use `@State` for view-owned state, not as a cache. Use `equatable()` only when equality is cheaper than the subtree. +- Report likely causes, evidence, fix, and how to validate. diff --git a/build-ios-apps/skills/swiftui-performance-audit/references/code-smells.md b/build-ios-apps/skills/swiftui-performance-audit/references/code-smells.md deleted file mode 100644 index 88f1af0..0000000 --- a/build-ios-apps/skills/swiftui-performance-audit/references/code-smells.md +++ /dev/null @@ -1,153 +0,0 @@ -# Common code smells and remediation patterns - -## Intent - -Use this reference during code-first review to map visible SwiftUI patterns to likely runtime costs and safer remediation guidance. - -## High-priority smells - -### Expensive formatters in `body` - -```swift -var body: some View { - let number = NumberFormatter() - let measure = MeasurementFormatter() - Text(measure.string(from: .init(value: meters, unit: .meters))) -} -``` - -Prefer cached formatters in a model or dedicated helper: - -```swift -final class DistanceFormatter { - static let shared = DistanceFormatter() - let number = NumberFormatter() - let measure = MeasurementFormatter() -} -``` - -### Heavy computed properties - -```swift -var filtered: [Item] { - items.filter { $0.isEnabled } -} -``` - -Prefer deriving this once per meaningful input change in a model/helper, or store derived view-owned state only when the view truly owns the transformation lifecycle. - -### Sorting or filtering inside `body` - -```swift -List { - ForEach(items.sorted(by: sortRule)) { item in - Row(item) - } -} -``` - -Prefer sorting before render work begins: - -```swift -let sortedItems = items.sorted(by: sortRule) -``` - -### Inline filtering inside `ForEach` - -```swift -ForEach(items.filter { $0.isEnabled }) { item in - Row(item) -} -``` - -Prefer a prefiltered collection with stable identity. - -### Unstable identity - -```swift -ForEach(items, id: \.self) { item in - Row(item) -} -``` - -Avoid `id: \.self` for non-stable values or collections that reorder. Use a stable domain identifier. - -### Top-level conditional view swapping - -```swift -var content: some View { - if isEditing { - editingView - } else { - readOnlyView - } -} -``` - -Prefer one stable base view and localize conditions to sections or modifiers. This reduces root identity churn and makes diffing cheaper. - -### Image decoding on the main thread - -```swift -Image(uiImage: UIImage(data: data)!) -``` - -Prefer decode and downsample work off the main thread, then store the processed image. - -## Observation fan-out - -### Broad `@Observable` reads on iOS 17+ - -```swift -@Observable final class Model { - var items: [Item] = [] -} - -var body: some View { - Row(isFavorite: model.items.contains(item)) -} -``` - -If many views read the same broad collection or root model, small changes can fan out into wide invalidation. Prefer narrower derived inputs, smaller observable surfaces, or per-item state closer to the leaf views. - -### Broad `ObservableObject` reads on iOS 16 and earlier - -```swift -final class Model: ObservableObject { - @Published var items: [Item] = [] -} -``` - -The same warning applies to legacy observation. Avoid having many descendants observe a large shared object when they only need one derived field. - -## Remediation notes - -### `@State` is not a generic cache - -Use `@State` for view-owned state and derived values that intentionally belong to the view lifecycle. Do not move arbitrary expensive computation into `@State` unless you also define when and why it updates. - -Better alternatives: - -- precompute in the model or store -- update derived state in response to a specific input change -- memoize in a dedicated helper -- preprocess on a background task before rendering - -### `equatable()` is conditional guidance - -Use `equatable()` only when: - -- equality is cheaper than recomputing the subtree, and -- the view inputs are value-semantic and stable enough for meaningful equality checks - -Do not apply `equatable()` as a blanket fix for all redraws. - -## Triage order - -When multiple smells appear together, prioritize in this order: - -1. Broad invalidation and observation fan-out -2. Unstable identity and list churn -3. Main-thread work during render -4. Image decode or resize cost -5. Layout and animation complexity diff --git a/build-ios-apps/skills/swiftui-performance-audit/references/profiling-intake.md b/build-ios-apps/skills/swiftui-performance-audit/references/profiling-intake.md deleted file mode 100644 index ad2a530..0000000 --- a/build-ios-apps/skills/swiftui-performance-audit/references/profiling-intake.md +++ /dev/null @@ -1,45 +0,0 @@ -# Profiling intake and collection checklist - -## Intent - -Use this checklist when code review alone cannot explain the SwiftUI performance issue and you need runtime evidence from the user. - -## Ask for first - -- Exact symptom: CPU spike, dropped frames, memory growth, hangs, or excessive view updates. -- Exact interaction: scrolling, typing, initial load, navigation push/pop, animation, sheet presentation, or background refresh. -- Target device and OS version. -- Whether the issue was reproduced on a real device or only in Simulator. -- Build configuration: Debug or Release. -- Whether the user already has a baseline or before/after comparison. - -## Default profiling request - -Ask the user to: - -- Run the app in a Release build when possible. -- Use the SwiftUI Instruments template. -- Reproduce the exact problematic interaction only long enough to capture the issue. -- Capture the SwiftUI timeline and Time Profiler together. -- Export the trace or provide screenshots of the key SwiftUI lanes and the Time Profiler call tree. - -## Ask for these artifacts - -- Trace export or screenshots of the relevant SwiftUI lanes -- Time Profiler call tree screenshot or export -- Device/OS/build configuration -- A short note describing what action was happening at the time of the capture -- If memory is involved, the memory graph or Allocations data if available - -## When to ask for more - -- Ask for a second capture if the first run mixes multiple interactions. -- Ask for a before/after pair if the user has already tried a fix. -- Ask for a device capture if the issue only appears in Simulator or if scrolling smoothness matters. - -## Common traps - -- Debug builds can distort SwiftUI timing and allocation behavior. -- Simulator traces can miss device-only rendering or memory issues. -- Mixed interactions in one capture make attribution harder. -- Screenshots without the reproduction note are much harder to interpret. diff --git a/build-ios-apps/skills/swiftui-performance-audit/references/report-template.md b/build-ios-apps/skills/swiftui-performance-audit/references/report-template.md deleted file mode 100644 index 5652de2..0000000 --- a/build-ios-apps/skills/swiftui-performance-audit/references/report-template.md +++ /dev/null @@ -1,47 +0,0 @@ -# Audit output template - -## Intent - -Use this structure when reporting SwiftUI performance findings so the user can quickly see the symptom, evidence, likely cause, and next validation step. - -## Template - -```markdown -## Summary - -[One short paragraph on the most likely bottleneck and whether the conclusion is code-backed or trace-backed.] - -## Findings - -1. [Issue title] - - Symptom: [what the user sees] - - Likely cause: [root cause] - - Evidence: [code reference or profiling evidence] - - Fix: [specific change] - - Validation: [what to measure after the fix] - -2. [Issue title] - - Symptom: ... - - Likely cause: ... - - Evidence: ... - - Fix: ... - - Validation: ... - -## Metrics - -| Metric | Before | After | Notes | -| ---------------------- | ------- | ------- | ------ | -| CPU | [value] | [value] | [note] | -| Frame drops / hitching | [value] | [value] | [note] | -| Memory peak | [value] | [value] | [note] | - -## Next step - -[One concrete next action: apply a fix, capture a better trace, or validate on device.] -``` - -## Notes - -- Order findings by impact, not by file order. -- Say explicitly when a conclusion is still a hypothesis. -- If no metrics are available, omit the table and say what should be measured next. diff --git a/build-ios-apps/skills/swiftui-ui-patterns/SKILL.md b/build-ios-apps/skills/swiftui-ui-patterns/SKILL.md index 027dada..3ebfbd2 100644 --- a/build-ios-apps/skills/swiftui-ui-patterns/SKILL.md +++ b/build-ios-apps/skills/swiftui-ui-patterns/SKILL.md @@ -1,73 +1,14 @@ --- name: swiftui-ui-patterns -description: Build and refactor SwiftUI UI with component patterns and examples. Use when shaping navigation, state, layouts, controls, or screen composition. +description: Build and refactor SwiftUI UI with component patterns. Use when shaping navigation, state, layouts, controls, or screen composition. --- -# SwiftUI UI Patterns +# SwiftUI UI patterns -## Quick start +Docs: . Match the repo's existing conventions first. -Choose a track based on your goal: - -### Existing project - -- Identify the feature or screen and the primary interaction model (list, detail, editor, settings, tabbed). -- Find a nearby example in the repo with `rg "TabView\("` or similar, then read the closest SwiftUI view. -- Apply local conventions: prefer SwiftUI-native state, keep state local when possible, and use environment injection for shared dependencies. -- Build the view with small, focused subviews and SwiftUI-native data flow. - -### New project scaffolding - -- Wire TabView, a NavigationStack per tab, and sheets at the app root. -- Add a minimal `AppTab` enum and `RouterPath` for per-tab navigation. -- Expand the route and sheet enums as new screens are added. - -## General rules to follow - -- Use modern SwiftUI state (`@State`, `@Binding`, `@Observable`, `@Environment`) and avoid unnecessary view models. -- If the deployment target includes iOS 16 or earlier and cannot use the Observation API introduced in iOS 17, fall back to `ObservableObject` with `@StateObject` for root ownership, `@ObservedObject` for injected observation, and `@EnvironmentObject` only for truly shared app-level state. -- Prefer composition; keep views small and focused. -- Use async/await with `.task` and explicit loading/error states. -- Keep shared app services in `@Environment`, but prefer explicit initializer injection for feature-local dependencies and models. -- Prefer the newest SwiftUI API that fits the deployment target and call out the minimum OS whenever a pattern depends on it. -- Maintain existing legacy patterns only when editing legacy files. -- Follow the project's formatter and style guide. -- **Sheets**: Prefer `.sheet(item:)` over `.sheet(isPresented:)` when state represents a selected model. Avoid `if let` inside a sheet body. Sheets should own their actions and call `dismiss()` internally instead of forwarding `onCancel`/`onConfirm` closures. -- **Scroll-driven reveals**: Prefer deriving a normalized progress value from scroll offset and driving the visual state from that single source of truth. Avoid parallel gesture state machines unless scroll alone cannot express the interaction. - -## State ownership summary - -Use the narrowest state tool that matches the ownership model: - -| Scenario | Preferred pattern | -| ----------------------------------------------------------------- | ----------------------------------------------------------- | -| Local UI state owned by one view | `@State` | -| Child mutates parent-owned value state | `@Binding` | -| Root-owned reference model on iOS 17+ | `@State` with an `@Observable` type | -| Child reads or mutates an injected `@Observable` model on iOS 17+ | Pass it explicitly as a stored property | -| Shared app service or configuration | `@Environment(Type.self)` | -| Legacy reference model on iOS 16 and earlier | `@StateObject` at the root, `@ObservedObject` when injected | - -Choose the ownership location first, then pick the wrapper. Do not introduce a reference model when plain value state is enough. - -## Further reading - -For macOS windowing, menus, and settings patterns, use the `swiftui-patterns` skill from the build-macos-apps plugin when it is installed. Use web search to consult current Apple Developer documentation when SwiftUI APIs or availability may have changed. - -## Anti-patterns - -- Giant views that mix layout, business logic, networking, routing, and formatting in one file. -- Multiple boolean flags for mutually exclusive sheets, alerts, or navigation destinations. -- Live service calls directly inside `body`-driven code paths instead of view lifecycle hooks or injected models/services. -- Reaching for `AnyView` to work around type mismatches that should be solved with better composition. -- Defaulting every shared dependency to `@EnvironmentObject` or a global router without a clear ownership reason. - -## Workflow for a new SwiftUI view - -1. Define the view's state, ownership location, and minimum OS assumptions before writing UI code. -2. Identify which dependencies belong in `@Environment` and which should stay as explicit initializer inputs. -3. Sketch the view hierarchy, routing model, and presentation points; extract repeated parts into subviews. **Build and verify no compiler errors before proceeding.** -4. Implement async loading with `.task` or `.task(id:)`, plus explicit loading and error states when needed. -5. Add previews for the primary and secondary states, then add accessibility labels or identifiers when the UI is interactive. -6. Build to validate. Fix compiler errors (missing `@State`, ambiguous `ViewBuilder` closures, mismatched generics) before updating call sites. Confirm previews render, state changes propagate, and list identity will not cause extra re-renders. - If the build fails, fix the reported error and rebuild before the next step. If a preview crashes, isolate the subview and check its state initialization. +- Use `@State`, `@Binding`, `@Observable`, `@Environment`. Fall back to `ObservableObject` only below iOS 17. Avoid view models that only mirror view state. +- Shared services in `@Environment`, feature-local dependencies by initializer. +- Prefer `.sheet(item:)` over `.sheet(isPresented:)` for selected models. Sheets own their actions and call `dismiss()`. +- Drive scroll-based reveals from one normalized progress value. +- State the minimum OS for any pattern that needs it. diff --git a/build-ios-apps/skills/swiftui-view-refactor/SKILL.md b/build-ios-apps/skills/swiftui-view-refactor/SKILL.md index e85c4d0..068ccf7 100644 --- a/build-ios-apps/skills/swiftui-view-refactor/SKILL.md +++ b/build-ios-apps/skills/swiftui-view-refactor/SKILL.md @@ -3,211 +3,10 @@ name: swiftui-view-refactor description: Refactor SwiftUI view files into stable, testable structure. Use when splitting large views, tightening data flow, or cleaning Observation ownership. --- -# SwiftUI View Refactor +# SwiftUI view refactor -## Overview - -Refactor SwiftUI views toward small, explicit, stable view types. Default to vanilla SwiftUI: local state in the view, shared dependencies in the environment, business logic in services/models, and view models only when the request or existing code clearly requires one. - -## Core Guidelines - -### 1) View ordering (top → bottom) - -- Enforce this ordering unless the existing file has a stronger local convention you must preserve. -- Environment -- `private`/`public` `let` -- `@State` / other stored properties -- computed `var` (non-view) -- `init` -- `body` -- computed view builders / other view helpers -- helper / async functions - -### 2) Default to MV, not MVVM - -- Views should be lightweight state expressions and orchestration points, not containers for business logic. -- Favor `@State`, `@Environment`, `@Query`, `.task`, `.task(id:)`, and `onChange` before reaching for a view model. -- Inject services and shared models via `@Environment`; keep domain logic in services/models, not in the view body. -- Do not introduce a view model just to mirror local view state or wrap environment dependencies. -- If a screen is getting large, split the UI into subviews before inventing a new view model layer. - -### 3) Strongly prefer dedicated subview types over computed `some View` helpers - -- Flag `body` properties that are longer than roughly one screen or contain multiple logical sections. -- Prefer extracting dedicated `View` types for non-trivial sections, especially when they have state, async work, branching, or deserve their own preview. -- Keep computed `some View` helpers rare and small. Do not build an entire screen out of `private var header: some View`-style fragments. -- Pass small, explicit inputs (data, bindings, callbacks) into extracted subviews instead of handing down the entire parent state. -- If an extracted subview becomes reusable or independently meaningful, move it to its own file. - -Prefer: - -```swift -var body: some View { - List { - HeaderSection(title: title, subtitle: subtitle) - FilterSection( - filterOptions: filterOptions, - selectedFilter: $selectedFilter - ) - ResultsSection(items: filteredItems) - FooterSection() - } -} - -private struct HeaderSection: View { - let title: String - let subtitle: String - - var body: some View { - VStack(alignment: .leading, spacing: 6) { - Text(title).font(.title2) - Text(subtitle).font(.subheadline) - } - } -} - -private struct FilterSection: View { - let filterOptions: [FilterOption] - @Binding var selectedFilter: FilterOption - - var body: some View { - ScrollView(.horizontal, showsIndicators: false) { - HStack { - ForEach(filterOptions, id: \.self) { option in - FilterChip(option: option, isSelected: option == selectedFilter) - .onTapGesture { selectedFilter = option } - } - } - } - } -} -``` - -Avoid: - -```swift -var body: some View { - List { - header - filters - results - footer - } -} - -private var header: some View { - VStack(alignment: .leading, spacing: 6) { - Text(title).font(.title2) - Text(subtitle).font(.subheadline) - } -} -``` - -### 3b) Extract actions and side effects out of `body` - -- Do not keep non-trivial button actions inline in the view body. -- Do not bury business logic inside `.task`, `.onAppear`, `.onChange`, or `.refreshable`. -- Prefer calling small private methods from the view, and move real business logic into services/models. -- The body should read like UI, not like a view controller. - -```swift -Button("Save", action: save) - .disabled(isSaving) - -.task(id: searchText) { - await reload(for: searchText) -} - -private func save() { - Task { await saveAsync() } -} - -private func reload(for searchText: String) async { - guard !searchText.isEmpty else { - results = [] - return - } - await searchService.search(searchText) -} -``` - -### 4) Keep a stable view tree (avoid top-level conditional view swapping) - -- Avoid `body` or computed views that return completely different root branches via `if/else`. -- Prefer a single stable base view with conditions inside sections/modifiers (`overlay`, `opacity`, `disabled`, `toolbar`, etc.). -- Root-level branch swapping causes identity churn, broader invalidation, and extra recomputation. - -Prefer: - -```swift -var body: some View { - List { - documentsListContent - } - .toolbar { - if canEdit { - editToolbar - } - } -} -``` - -Avoid: - -```swift -var documentsListView: some View { - if canEdit { - editableDocumentsList - } else { - readOnlyDocumentsList - } -} -``` - -### 5) View model handling (only if already present or explicitly requested) - -- Treat view models as a legacy or explicit-need pattern, not the default. -- Do not introduce a view model unless the request or existing code clearly calls for one. -- If a view model exists, make it non-optional when possible. -- Pass dependencies to the view via `init`, then create the view model in the view's `init`. -- Avoid `bootstrapIfNeeded` patterns and other delayed setup workarounds. - -Example (Observation-based): - -```swift -@State private var viewModel: SomeViewModel - -init(dependency: Dependency) { - _viewModel = State(initialValue: SomeViewModel(dependency: dependency)) -} -``` - -### 6) Observation usage - -- For `@Observable` reference types on iOS 17+, store them as `@State` in the owning view. -- Pass observables down explicitly; avoid optional state unless the UI genuinely needs it. -- If the deployment target includes iOS 16 or earlier, use `@StateObject` at the owner and `@ObservedObject` when injecting legacy observable models. - -## Workflow - -1. Reorder the view to match the ordering rules. -2. Remove inline actions and side effects from `body`; move business logic into services/models and keep only thin orchestration in the view. -3. Shorten long bodies by extracting dedicated subview types; avoid rebuilding the screen out of many computed `some View` helpers. -4. Ensure stable view structure: avoid top-level `if`-based branch swapping; move conditions to localized sections/modifiers. -5. If a view model exists or is explicitly required, replace optional view models with a non-optional `@State` view model initialized in `init`. -6. Confirm Observation usage: `@State` for root `@Observable` models on iOS 17+, legacy wrappers only when the deployment target requires them. -7. Keep behavior intact: do not change layout or business logic unless requested. - -## Notes - -- Prefer small, explicit view types over large conditional blocks and large computed `some View` properties. -- Keep computed view builders below `body` and non-view computed vars above `init`. -- A good SwiftUI refactor should make the view read top-to-bottom as data flow plus layout, not as mixed layout and imperative logic. -- Prefer MV-first: keep view state in `@State`/`@Observable` models owned by the view tree and avoid a view model per screen unless the project already uses one. -- In addition to the references above, use web search to consult current Apple Developer documentation when SwiftUI APIs, Observation behavior, or platform guidance may have changed. - -## Large-view handling - -When a SwiftUI view file exceeds ~300 lines, split it aggressively. Extract meaningful sections into dedicated `View` types instead of hiding complexity in many computed properties. Use `private` extensions with `// MARK: -` comments for actions and helpers, but do not treat extensions as a substitute for breaking a giant screen into smaller view types. If an extracted subview -is reused or -independently meaningful, move it into its own file. +- Default to vanilla SwiftUI: local state in the view, shared dependencies in the environment, business logic in services or models. Add a view model only if one exists or is requested. +- Extract dedicated `View` types for non-trivial sections. Keep computed `some View` helpers rare and small. +- Keep a stable view tree. Put conditions inside sections and modifiers, not as `if/else` root swaps. +- Keep business logic out of `body`, `.task`, `.onAppear`, `.onChange`, and `.refreshable`. Call small private methods. +- Pass observables explicitly. Avoid `bootstrapIfNeeded`-style delayed setup. diff --git a/build-macos-apps/README.md b/build-macos-apps/README.md index 3ee7052..b646bf9 100644 --- a/build-macos-apps/README.md +++ b/build-macos-apps/README.md @@ -1,30 +1,16 @@ -# Build macOS Apps Plugin +# build-macos-apps Skills and commands for building, running, testing, signing, and shipping macOS apps. -## What ships - -- `build-run-debug` -- `test-triage` -- `signing-entitlements` -- `swiftpm-macos` -- `packaging-notarization` -- `swiftui-patterns` -- `macos-app-best-practices` -- `liquid-glass` -- `window-management` -- `appkit-interop` -- `view-refactor` -- `telemetry` - -Commands: `/build-and-run-macos-app`, `/fix-codesign-error`, `/test-macos-app`. - ## Install -```bash +```text /plugin install build-macos-apps@duyet-claude-plugins ``` -## License +## What ships -MIT +- `build-run-debug`, `swiftpm-macos`, `test-triage`, `telemetry`: build, run, test, and log. +- `signing-entitlements`, `packaging-notarization`: signing and distribution. +- `swiftui-patterns`, `macos-app-best-practices`, `liquid-glass`, `window-management`, `view-refactor`, `appkit-interop`: UI guidance. +- Commands: `/build-and-run-macos-app`, `/fix-codesign-error`, `/test-macos-app`. diff --git a/build-macos-apps/commands/build-and-run-macos-app.md b/build-macos-apps/commands/build-and-run-macos-app.md index fbf0246..0e8fca7 100644 --- a/build-macos-apps/commands/build-and-run-macos-app.md +++ b/build-macos-apps/commands/build-and-run-macos-app.md @@ -4,29 +4,4 @@ description: Create or update the project-local macOS build_and_run.sh script, t # /build-and-run-macos-app -Follow `../skills/build-run-debug/SKILL.md`. Create or update `script/build_and_run.sh`, then use it as the default build/run entrypoint. - -## Arguments - -- `scheme`: Xcode scheme name (optional) -- `workspace`: path to `.xcworkspace` (optional) -- `project`: path to `.xcodeproj` (optional) -- `product`: SwiftPM executable product name (optional) -- `mode`: `run`, `debug`, `logs`, `telemetry`, or `verify` (optional, default: `run`) -- `app_name`: process/app name to stop before relaunching (optional) - -## Workflow - -1. Detect whether the repo uses an Xcode workspace, Xcode project, or SwiftPM package. -2. If the workspace is not inside git yet, run `git init` at the project root. -3. Create or update `script/build_and_run.sh` so it always stops the current app, builds the macOS target, and launches the fresh result. -4. For SwiftPM, keep raw executable launch only for true CLI tools; for AppKit/SwiftUI GUI apps, create a project-local `.app` bundle and launch it with `/usr/bin/open -n`. -5. Support optional script flags for `--debug`, `--logs`, `--telemetry`, and `--verify`. -6. Follow the script shape in `../skills/build-run-debug/references/run-button-bootstrap.md`. -7. Run the script in the requested mode and summarize any build, script, or launch failure. - -## Guardrails - -- Do not initialize a nested git repo inside an existing parent checkout. -- Keep the no-flag script path simple: kill, build, run. -- Use `--debug`, `--logs`, `--telemetry`, or `--verify` only when the user asks for those modes. +Follow the `build-run-debug` skill. Optional arguments: `scheme`, `workspace`, `project`, `product`, `mode` (`run`, `debug`, `logs`, `telemetry`, `verify`), `app_name`. diff --git a/build-macos-apps/commands/fix-codesign-error.md b/build-macos-apps/commands/fix-codesign-error.md index 1d9823d..78b9e3d 100644 --- a/build-macos-apps/commands/fix-codesign-error.md +++ b/build-macos-apps/commands/fix-codesign-error.md @@ -4,23 +4,4 @@ description: Inspect a macOS signing or entitlement failure and explain the mini # /fix-codesign-error -Inspect a macOS signing or entitlement failure and explain the minimum fix path. - -## Arguments - -- `app`: path to `.app` bundle or binary (optional) -- `identity`: signing identity hint (optional) -- `mode`: `inspect` or `repair-plan` (optional, default: `inspect`) - -## Workflow - -1. Inspect the app bundle, executable, signing info, and entitlements. -2. Determine whether the problem is identity, provisioning, hardened runtime, sandboxing, or trust policy. -3. Summarize the exact failure class in plain language. -4. Provide the minimal repair sequence or validation command. - -## Guardrails - -- Never invent entitlements; read them from the binary or source files. -- Distinguish local development signing problems from distribution or notarization failures. -- Prefer verifiable commands like `codesign -d`, `spctl`, and `plutil` over guesswork. +Follow the `signing-entitlements` skill. Optional arguments: `app`, `identity`, `mode` (`inspect` or `repair-plan`). diff --git a/build-macos-apps/commands/test-macos-app.md b/build-macos-apps/commands/test-macos-app.md index a3a2e64..95ace80 100644 --- a/build-macos-apps/commands/test-macos-app.md +++ b/build-macos-apps/commands/test-macos-app.md @@ -4,24 +4,4 @@ description: Run the smallest meaningful macOS test scope first and explain fail # /test-macos-app -Run the smallest meaningful macOS test scope first and explain failures by category. - -## Arguments - -- `scheme`: Xcode scheme name (optional) -- `target`: test target or product name (optional) -- `filter`: test filter expression (optional) -- `configuration`: `Debug` or `Release` (optional, default: `Debug`) - -## Workflow - -1. Detect whether the repo uses `xcodebuild test` or `swift test`. -2. Prefer focused test execution when a target or filter is provided. -3. Classify failures as compile, assertion, crash, env/setup, or flake. -4. Summarize the top blocker and the narrowest sensible next step. - -## Guardrails - -- Avoid rerunning the full suite if a focused rerun is possible. -- Distinguish build failures from actual failing tests. -- Note when host app setup or simulator-only test assumptions leak into a macOS run. +Follow the `test-triage` skill. Optional arguments: `scheme`, `target`, `filter`, `configuration`. diff --git a/build-macos-apps/skills/appkit-interop/SKILL.md b/build-macos-apps/skills/appkit-interop/SKILL.md index b6c14fb..5262a5d 100644 --- a/build-macos-apps/skills/appkit-interop/SKILL.md +++ b/build-macos-apps/skills/appkit-interop/SKILL.md @@ -3,68 +3,11 @@ name: appkit-interop description: Bridge macOS SwiftUI into AppKit narrowly. Use when implementing representables, reaching NSWindow or panels, handling menus, or using the responder chain. --- -# AppKit Interop +# AppKit interop -## Quick Start +Docs: . -Use this skill when SwiftUI is close but not quite enough for native macOS behavior. -Keep the bridge as small and explicit as possible. SwiftUI should usually remain -the source of truth, while AppKit handles the imperative edge. - -## Choose The Smallest Bridge - -- Use pure SwiftUI when the required behavior already exists in scenes, toolbars, commands, inspectors, or standard controls. -- Use `NSViewRepresentable` when you need a specific AppKit view with lightweight lifecycle needs. -- Use `NSViewControllerRepresentable` when you need controller lifecycle, delegation, or presentation coordination. -- Use direct AppKit window or app hooks when you need `NSWindow`, responder-chain, menu validation, panels, or app-level behavior. - -## Workflow - -1. Name the capability gap precisely. - - Window behavior - - Text system behavior - - Menu validation - - Drag and drop - - File open/save panels - - First responder control - -2. Pick the smallest boundary that solves it. - - Avoid porting a whole screen to AppKit when one wrapped control or coordinator would do. - -3. Keep ownership explicit. - - SwiftUI owns value state, selection, and observable models. - - AppKit objects stay inside the representable, coordinator, or bridge object. - -4. Expose a narrow interface back to SwiftUI. - - Bindings for editable state - - Small callbacks for events - - Focused bridge services only when necessary - -5. Validate lifecycle assumptions. - - SwiftUI may recreate representables. - - Coordinators exist to hold delegate and target-action glue, not as a second app architecture. - -## References - -- `references/representables.md`: choosing between view and view-controller wrappers, plus coordinator patterns. -- `references/window-panels.md`: window access, utility windows, and open/save panels. -- `references/responder-menus.md`: first responder, command routing, and menu validation. -- `references/drag-drop-pasteboard.md`: pasteboard, file URLs, and desktop drag/drop edges. -- `references/appkit-overview.md`: AppKit topic map and notable symbols for orienting before bridging. - -## Guardrails - -- Do not duplicate the source of truth between SwiftUI and AppKit. -- Do not let `Coordinator` become an unstructured dumping ground. -- Do not store long-lived `NSView` or `NSWindow` instances globally without a strong ownership reason. -- Prefer a tiny tested bridge over rewriting the feature in raw AppKit. -- If a pattern can remain entirely in `swiftui-patterns`, keep it there. - -## Output Expectations - -Provide: - -- the exact SwiftUI limitation being crossed -- the smallest recommended bridge type -- the data-flow boundary between SwiftUI and AppKit -- the lifecycle or validation risks to watch +- Wrap one control or coordinator, not a whole screen. +- One source of truth. Do not duplicate state between SwiftUI and AppKit. +- Keep `Coordinator` focused. Do not store long-lived `NSView` or `NSWindow` instances globally. +- Do not let AppKit references spread through unrelated SwiftUI views. diff --git a/build-macos-apps/skills/appkit-interop/references/appkit-overview.md b/build-macos-apps/skills/appkit-interop/references/appkit-overview.md deleted file mode 100644 index 4a4317c..0000000 --- a/build-macos-apps/skills/appkit-interop/references/appkit-overview.md +++ /dev/null @@ -1,47 +0,0 @@ -# AppKit Overview - -AppKit provides the objects to build a macOS app's user interface and to manage -interaction between the app, the person, and macOS: windows, panels, buttons, text -fields, event handling, drawing, printing, animation, documents, drag and drop, -menus, accessibility, and localization. It interops with SwiftUI in both directions -, AppKit views and view controllers embed into SwiftUI via representables, and -SwiftUI views can be hosted inside AppKit. - -## When to reach for AppKit - -Prefer SwiftUI for new macOS UI. Reach for AppKit directly only when SwiftUI lacks a -capability (window behavior, responder-chain control, a specific control, text-system -behavior, menus). See the parent `appkit-interop` skill for the smallest-bridge -approach. - -## Topic map - -- **App and Environment**: app lifecycle, run loop, environment, appearance. -- **Windows, Panels, and Screens**: `NSWindow`, panels, full-screen, restoration. -- **Views and Controls**: buttons, fields, sliders, segmented controls, toolbars. -- **Text System**: text storage, selection, layout, attachments, view providers. -- **Documents, Data, and Pasteboard**: document architecture, pasteboard, undo. -- **Drawing**: `NSBezierPath`, graphics contexts, images and PDF. -- **Color and Fonts**: color management, font descriptors, typography. -- **Menus, Cursors, and the Dock**: menu bars, menu items, dock tiles. -- **Mouse, Keyboard, and Trackpad**: event handling, gestures, responders. -- **Drag and Drop**: pasteboard-based dragging sessions. -- **Animation**: `NSAnimationContext`, animator proxies, layer-backed views. -- **Accessibility**: accessibility elements, traits, and actions. -- **Cocoa Bindings**: KVO/bindings to connect UI to models. -- **Appearance Customization**: light/dark, accent, vibrancy. -- **Mac Catalyst**: bring iPad apps to the Mac. - -## Notable symbols from the AppKit reference - -These appear in the current AppKit reference; confirm availability and semantics in -the Apple Developer docs before relying on them. - -- `NSRefreshController`: a refresh control for AppKit scroll views. -- `NSTextSelectionManager` (plus `.Delegate`, `.Mode`), unified text selection. -- `NSMenuItem.ImageVisibility`: control menu-item icon visibility. -- `NSSegmentedControl.Role`: per-segment roles. -- `NSStatusItemExpandedInterfaceDelegate` / `NSStatusItemExpandedInterfaceSession` , - expanded status items. -- `NSTextViewportRenderingSurface` / `NSTextViewportRenderingSurfaceKey`, text - viewport rendering hooks. diff --git a/build-macos-apps/skills/appkit-interop/references/drag-drop-pasteboard.md b/build-macos-apps/skills/appkit-interop/references/drag-drop-pasteboard.md deleted file mode 100644 index d1f5e73..0000000 --- a/build-macos-apps/skills/appkit-interop/references/drag-drop-pasteboard.md +++ /dev/null @@ -1,23 +0,0 @@ -# Drag, Drop, and Pasteboard - -## Intent - -Use this when desktop drag/drop or pasteboard behavior exceeds what plain SwiftUI modifiers cover comfortably. - -## Good fits - -- File URL dragging -- Pasteboard interoperability with other macOS apps -- Rich drag previews or AppKit-specific drop validation -- Legacy AppKit views with custom drag types - -## Core patterns - -- Start with SwiftUI drag/drop APIs when they already cover the use case. -- Drop to AppKit when you need `NSPasteboard`, custom pasteboard types, or older AppKit delegate flows. -- Keep data conversion at the boundary instead of leaking AppKit types through the whole feature. - -## Pitfalls - -- Do not move your whole list or canvas into AppKit just for one drop target. -- Keep file and pasteboard types explicit and validated. diff --git a/build-macos-apps/skills/appkit-interop/references/representables.md b/build-macos-apps/skills/appkit-interop/references/representables.md deleted file mode 100644 index 104eea3..0000000 --- a/build-macos-apps/skills/appkit-interop/references/representables.md +++ /dev/null @@ -1,56 +0,0 @@ -# Representables - -## Intent - -Use this when wrapping an AppKit control or controller for a SwiftUI macOS app. - -## Choose the wrapper type - -- Use `NSViewRepresentable` for a view-level bridge such as `NSTextView`, `NSScrollView`, or a custom AppKit control. -- Use `NSViewControllerRepresentable` when you need controller lifecycle, delegate coordination, or AppKit presentation logic. - -## Skeleton - -```swift -struct LegacyTextView: NSViewRepresentable { - @Binding var text: String - - func makeCoordinator() -> Coordinator { - Coordinator(text: $text) - } - - func makeNSView(context: Context) -> NSScrollView { - let scrollView = NSScrollView() - let textView = NSTextView() - textView.delegate = context.coordinator - scrollView.documentView = textView - return scrollView - } - - func updateNSView(_ nsView: NSScrollView, context: Context) { - guard let textView = nsView.documentView as? NSTextView else { return } - if textView.string != text { - textView.string = text - } - } - - final class Coordinator: NSObject, NSTextViewDelegate { - @Binding var text: String - - init(text: Binding) { - _text = text - } - - func textDidChange(_ notification: Notification) { - guard let textView = notification.object as? NSTextView else { return } - text = textView.string - } - } -} -``` - -## Pitfalls - -- Avoid infinite update loops by only pushing state into AppKit when values actually changed. -- Keep delegates and target-action wiring in the coordinator. -- If the wrapper grows into a full screen, re-evaluate the boundary. diff --git a/build-macos-apps/skills/appkit-interop/references/responder-menus.md b/build-macos-apps/skills/appkit-interop/references/responder-menus.md deleted file mode 100644 index 9c312d7..0000000 --- a/build-macos-apps/skills/appkit-interop/references/responder-menus.md +++ /dev/null @@ -1,22 +0,0 @@ -# Responder Chain and Menus - -## Intent - -Use this when command handling depends on the active window, first responder, or AppKit menu validation. - -## Core patterns - -- Start with SwiftUI `commands`, `FocusedValue`, and focused scene state. -- Use AppKit responder-chain hooks only when command routing or validation truly depends on the underlying responder system. -- Keep menu enablement rules close to the state they depend on. - -## Good fits for AppKit - -- Validating whether a menu item should be enabled -- Routing actions through the current first responder -- Integrating with existing AppKit document or text behaviors - -## Pitfalls - -- Do not recreate AppKit-style global command handling when SwiftUI focused values would work. -- Avoid scattering command logic between SwiftUI closures and AppKit selectors without a clear boundary. diff --git a/build-macos-apps/skills/appkit-interop/references/window-panels.md b/build-macos-apps/skills/appkit-interop/references/window-panels.md deleted file mode 100644 index f89e0f3..0000000 --- a/build-macos-apps/skills/appkit-interop/references/window-panels.md +++ /dev/null @@ -1,37 +0,0 @@ -# Windows and Panels - -## Intent - -Use this when SwiftUI scenes are not enough for the required macOS window or panel behavior. - -## Common cases - -- Accessing the backing `NSWindow` -- Configuring titlebar or toolbar behavior -- Presenting `NSOpenPanel` or `NSSavePanel` -- Managing utility panels or floating windows - -## Core patterns - -- Prefer SwiftUI `Window`, `WindowGroup`, and `openWindow` first. -- Use AppKit only for window features SwiftUI does not expose cleanly. -- Keep file open/save panels behind a small service or helper instead of scattering panel setup throughout the view tree. - -## Example: open panel - -```swift -@MainActor -func chooseFile() -> URL? { - let panel = NSOpenPanel() - panel.canChooseFiles = true - panel.canChooseDirectories = false - panel.allowsMultipleSelection = false - return panel.runModal() == .OK ? panel.url : nil -} -``` - -## Pitfalls - -- Do not let random views own long-lived `NSWindow` references. -- Keep floating panels and utility windows consistent with the scene model. -- If the behavior is really just settings or a secondary scene, go back to `swiftui-patterns`. diff --git a/build-macos-apps/skills/build-run-debug/SKILL.md b/build-macos-apps/skills/build-run-debug/SKILL.md index 08386e7..9859995 100644 --- a/build-macos-apps/skills/build-run-debug/SKILL.md +++ b/build-macos-apps/skills/build-run-debug/SKILL.md @@ -3,116 +3,13 @@ name: build-run-debug description: Build, run, and debug macOS apps with shell-first Xcode and Swift workflows. Use when launching apps or diagnosing build, startup, or runtime failures. --- -# Build / Run / Debug +# Build, run, debug -## Quick Start +Own the workflow with one project-local `script/build_and_run.sh` (never inside app source dirs). Other tools may depend on its contract. -Set up one project-local `script/build_and_run.sh` entrypoint, then use it as the default build/run path. - -Prefer shell-first workflows: - -- `./script/build_and_run.sh` as the single kill + build + run entrypoint once it exists -- `xcodebuild` for Xcode workspaces or projects -- `swift build` plus raw executable launch inside that script for true SwiftPM command-line tools -- `swift build` plus project-local `.app` bundle staging and `/usr/bin/open -n` launch for SwiftPM AppKit/SwiftUI GUI apps -- optional script flags for `lldb`, `log stream`, telemetry verification, or post-launch process checks - -Do not assume simulators, touch interaction, or mobile-specific tooling. - -If an Xcode-aware MCP surface is already available and the user explicitly wants -it, use it only where it fits. Keep that usage narrow and honest: prefer it for -Xcode-oriented discovery, logging, or debugging support, and do not force -simulator-specific workflows onto pure macOS tasks. - -## Workflow - -1. Discover the project shape. - - Check whether the workspace is already inside a git repo with `git rev-parse --is-inside-work-tree`. - - If no git repo is present, run `git init` at the project/workspace root before building so changes are tracked. Never run `git init` inside a nested subdirectory when the current workspace already belongs to a parent repo. - - Look for `.xcworkspace`, `.xcodeproj`, and `Package.swift`. - - If more than one candidate exists, explain the default choice and the ambiguity. - -2. Resolve the runnable target and process name. - - For Xcode, list schemes and prefer the app-producing scheme unless the user names another one. - - For SwiftPM, identify executable products when possible. - - Split SwiftPM launch handling by product type: - - use raw executable launch only for true command-line tools, - - use a generated project-local `.app` bundle for AppKit/SwiftUI GUI apps. - - Determine the app/process name to kill before relaunching. - -3. Create or update `script/build_and_run.sh`. - - Make the script project-specific and executable. - - It should always: - 1. stop the existing running app/process if present, - 2. build the macOS target, - 3. launch the freshly built app or executable. - - Add optional flags for debugging/log inspection: - - `--debug` to launch under `lldb` or attach the debugger - - `--logs` to stream process logs after launch - - `--telemetry` to stream unified logs filtered to the app subsystem/category - - `--verify` to launch the app and confirm the process exists with `pgrep -x ` - - Keep the default no-flag path simple: kill, build, run. - - Prefer writing one script that owns this workflow instead of repeatedly asking the agent to manually run `swift build`, locate the artifact, then invoke an ad hoc run command. - - For SwiftPM GUI apps, make the script build the product, create `dist/.app`, copy the binary to `Contents/MacOS/`, generate a minimal `Contents/Info.plist` with `CFBundlePackageType=APPL`, `CFBundleExecutable`, `CFBundleIdentifier`, `CFBundleName`, `LSMinimumSystemVersion`, and `NSPrincipalClass=NSApplication`, then launch with `/usr/bin/open -n `. - - For SwiftPM GUI `--logs` and `--telemetry`, launch the bundle with `/usr/bin/open -n` first, then stream unified logs with `/usr/bin/log stream --info ...`. - - Do not recommend direct SwiftPM executable launch for AppKit/SwiftUI GUI apps. - - Use `references/run-button-bootstrap.md` as the canonical source for the script shape. Do not fork a second snippet elsewhere. - - Keep the run script outside app source. It belongs in `script/build_and_run.sh`, not in `App/`, `Views/`, `Models/`, `Stores/`, `Services/`, or `Support/`. - -4. Build and run through the script. - - Default to `./script/build_and_run.sh`. - - Use `./script/build_and_run.sh --debug`, `--logs`, `--telemetry`, or `--verify` when the user asks for debugger/log/telemetry/process verification support. - -5. Summarize failures correctly. - - Classify the blocker as compiler, linker, signing, build settings, missing SDK/toolchain, script bug, or runtime launch. - - Quote the smallest useful error snippet and explain what it means. - -6. Debug the right way. - - Use the script's `--logs` or `--telemetry` mode for config, entitlement, sandbox, and action-event verification. - - For SwiftPM GUI apps, if the app bundle launches but its window still does not come forward, check whether the entrypoint needs `NSApp.setActivationPolicy(.regular)` and `NSApp.activate(ignoringOtherApps: true)`. - - Use the script's `--debug` mode or direct `lldb` if symbolized crash debugging is needed. - - If the user needs to instrument and verify specific window, sidebar, menu, or menu bar actions, switch to `telemetry`. - - Keep evidence tight and user-facing. - -7. Use Xcode-aware MCP tooling only when it helps. - - If the user explicitly asks for XcodeBuildMCP and it is already available, prefer it over ad hoc setup. - - Use the MCP for Xcode-aware discovery or debug/logging workflows when the available tool surface clearly matches the task. - - Fall back to shell commands immediately when the MCP does not provide a clean macOS path. - -## Preferred Commands - -- Project discovery: - - `find . -name '*.xcworkspace' -o -name '*.xcodeproj' -o -name 'Package.swift'` -- Scheme discovery: - - `xcodebuild -list -workspace ` - - `xcodebuild -list -project ` -- Build/run: - - `./script/build_and_run.sh` - - `./script/build_and_run.sh --debug` - - `./script/build_and_run.sh --logs` - - `./script/build_and_run.sh --telemetry` - - `./script/build_and_run.sh --verify` - -## References - -- `references/run-button-bootstrap.md`: canonical `build_and_run.sh` script shapes. - -## Guardrails - -- Prefer the narrowest command that proves or disproves the current theory. -- Do not leave the user with a one-off manual command chain once a stable `build_and_run.sh` script can own the workflow. -- Do not launch a SwiftUI/AppKit SwiftPM GUI app as a raw executable unless the user explicitly wants to diagnose that failure mode: it can produce no Dock icon, no foreground activation, and missing bundle identifier warnings. Keep raw executable launch only for true command-line tools. -- Do not claim UI state you cannot inspect directly. -- Do not describe mobile or simulator workflows as if they apply to macOS. -- If build output is huge, summarize the first real blocker and point to follow-up commands. - -## Output Expectations - -Provide: - -- the detected project type -- the script path you configured, if applicable -- the command you ran -- whether build and launch succeeded -- the top blocker if they failed -- the smallest sensible next action +- Default path is kill the running app, build, launch. Optional flags: `--debug` (lldb), `--logs` (stream process logs), `--telemetry` (unified log filtered to app subsystem), `--verify` (launch, then `pgrep -x `). +- Xcode projects use `xcodebuild`. SwiftPM command-line tools launch raw. +- SwiftPM GUI apps must be staged as `dist/.app` (binary in `Contents/MacOS`, minimal `Info.plist` with `CFBundlePackageType=APPL`, `CFBundleExecutable`, `CFBundleIdentifier`, `CFBundleName`, `LSMinimumSystemVersion`, `NSPrincipalClass=NSApplication`) and launched with `/usr/bin/open -n`. + A raw executable gives no Dock icon, no activation, and bundle id warnings. If the window stays behind, check `NSApp.setActivationPolicy(.regular)` and `NSApp.activate(ignoringOtherApps: true)`. +- Run `git init` only if the workspace is not already inside a git repo. Never nest one. +- Classify failures (compiler, linker, signing, build settings, SDK, script, runtime launch) and quote the smallest useful error. No simulator or mobile workflows on macOS. Do not claim UI state you cannot inspect. diff --git a/build-macos-apps/skills/build-run-debug/references/run-button-bootstrap.md b/build-macos-apps/skills/build-run-debug/references/run-button-bootstrap.md deleted file mode 100644 index 424b57a..0000000 --- a/build-macos-apps/skills/build-run-debug/references/run-button-bootstrap.md +++ /dev/null @@ -1,144 +0,0 @@ -# Run script bootstrap - -Canonical contract for the macOS build plugin's local run loop. - -When a project does not already have an established macOS run entrypoint: - -1. Create one project-local `script/build_and_run.sh`. -2. Make it executable. -3. Use it as the single kill + build + run entrypoint. -4. Support optional `--debug`, `--logs`, `--telemetry`, and `--verify` flags. - -## `script/build_and_run.sh` - -Use one project-specific script with a tiny mode switch and a default no-flag -path that just kills, builds, and launches. Keep raw executable launch only for -true command-line tools. For SwiftPM AppKit/SwiftUI GUI apps, stage a -project-local `.app` bundle and launch that bundle with `/usr/bin/open -n`. - -### SwiftPM CLI executable - -Use this shape for true command-line tools: - -```bash -#!/usr/bin/env bash -set -euo pipefail - -MODE="${1:-run}" -APP_NAME="MyTool" - -pkill -x "$APP_NAME" >/dev/null 2>&1 || true - -swift build -APP_BINARY="$(swift build --show-bin-path)/$APP_NAME" - -case "$MODE" in - run) - "$APP_BINARY" - ;; - --debug|debug) - lldb -- "$APP_BINARY" - ;; - --logs|logs) - "$APP_BINARY" & - /usr/bin/log stream --info --style compact --predicate "process == \"$APP_NAME\"" - ;; - --telemetry|telemetry) - "$APP_BINARY" & - /usr/bin/log stream --info --style compact --predicate "subsystem == \"com.example.MyTool\"" - ;; - --verify|verify) - "$APP_BINARY" & - sleep 1 - pgrep -x "$APP_NAME" >/dev/null - ;; - *) - echo "usage: $0 [run|--debug|--logs|--telemetry|--verify]" >&2 - exit 2 - ;; -esac -``` - -### SwiftPM AppKit/SwiftUI GUI app - -Use this shape for SwiftPM GUI apps so they launch as a real foreground app -bundle with Dock activation and bundle metadata: - -```bash -#!/usr/bin/env bash -set -euo pipefail - -MODE="${1:-run}" -APP_NAME="MyApp" -BUNDLE_ID="com.example.MyApp" -MIN_SYSTEM_VERSION="14.0" - -ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" -DIST_DIR="$ROOT_DIR/dist" -APP_BUNDLE="$DIST_DIR/$APP_NAME.app" -APP_CONTENTS="$APP_BUNDLE/Contents" -APP_MACOS="$APP_CONTENTS/MacOS" -APP_BINARY="$APP_MACOS/$APP_NAME" -INFO_PLIST="$APP_CONTENTS/Info.plist" - -pkill -x "$APP_NAME" >/dev/null 2>&1 || true - -swift build -BUILD_BINARY="$(swift build --show-bin-path)/$APP_NAME" - -rm -rf "$APP_BUNDLE" -mkdir -p "$APP_MACOS" -cp "$BUILD_BINARY" "$APP_BINARY" -chmod +x "$APP_BINARY" - -cat >"$INFO_PLIST" < - - - - CFBundleExecutable - $APP_NAME - CFBundleIdentifier - $BUNDLE_ID - CFBundleName - $APP_NAME - CFBundlePackageType - APPL - LSMinimumSystemVersion - $MIN_SYSTEM_VERSION - NSPrincipalClass - NSApplication - - -PLIST - -open_app() { - /usr/bin/open -n "$APP_BUNDLE" -} - -case "$MODE" in - run) - open_app - ;; - --debug|debug) - lldb -- "$APP_BINARY" - ;; - --logs|logs) - open_app - /usr/bin/log stream --info --style compact --predicate "process == \"$APP_NAME\"" - ;; - --telemetry|telemetry) - open_app - /usr/bin/log stream --info --style compact --predicate "subsystem == \"$BUNDLE_ID\"" - ;; - --verify|verify) - open_app - sleep 1 - pgrep -x "$APP_NAME" >/dev/null - ;; - *) - echo "usage: $0 [run|--debug|--logs|--telemetry|--verify]" >&2 - exit 2 - ;; -esac -``` diff --git a/build-macos-apps/skills/liquid-glass/SKILL.md b/build-macos-apps/skills/liquid-glass/SKILL.md index ed55be0..edd1aa9 100644 --- a/build-macos-apps/skills/liquid-glass/SKILL.md +++ b/build-macos-apps/skills/liquid-glass/SKILL.md @@ -3,178 +3,12 @@ name: liquid-glass description: Implement and review macOS SwiftUI Liquid Glass UI. Use when adopting system glass, removing conflicting custom chrome, or building glass surfaces. --- -# Liquid Glass +# Liquid Glass (macOS) -## Overview +Docs: . The API is new, so check current docs. -Use this skill to bring a macOS SwiftUI app into the modern macOS design system -with the least custom chrome possible. Start with standard app structure, -toolbars, search placement, sheets, and controls, then add custom Liquid Glass -only where the app needs a distinctive surface. - -Prefer system-provided glass and adaptive materials over bespoke blur, opaque -backgrounds, or custom toolbar/sidebar skins. Audit existing UI for extra fills, -scrims, and clipping before adding more effects. - -## Workflow - -1. Read the relevant scene or root view and identify the structural pattern: - `NavigationSplitView`, `TabView`, sheet presentation, detail/inspector - layout, toolbar, or custom floating controls. -2. Remove custom backgrounds or darkening layers behind system sheets, - sidebars, and toolbars unless the product explicitly needs them. These can - obscure Liquid Glass and interfere with the automatic scroll-edge effect. -3. Update standard SwiftUI structure and controls first. -4. Add custom `glassEffect` surfaces only for app-specific UI that standard - controls do not cover. -5. Validate that glass grouping, transitions, icon treatment, and foreground - activation are visually coherent and still usable with pointer and keyboard. -6. If the UI change also affects launch behavior for a SwiftPM GUI app, use - `build-run-debug` so the app runs as a foreground `.app` bundle rather - than as a raw executable. - -## App Structure - -- Prefer `NavigationSplitView` for hierarchy-driven macOS layouts. Let the - sidebar use the system Liquid Glass material instead of painting over it. -- For hero artwork or large media adjacent to a floating sidebar, use - `backgroundExtensionEffect` so the visual can extend beyond the safe area - without clipping the subject. -- Keep inspectors visually associated with the current selection and avoid - giving them a heavier custom background than the content they inspect. -- If the app uses tabs, keep `TabView` for persistent top-level sections and - preserve each tab's local navigation state. -- Do not force iPhone-only tab bar minimize/accessory behavior onto a Mac app. - On macOS, prefer a conventional top toolbar and native tab/search placement. -- If a sheet already uses `presentationBackground` purely to imitate frosted - material, consider removing it and letting the system's new material render. -- For sheet transitions that should visually originate from a toolbar button, - make the presenting item the source of a navigation zoom transition and mark - the sheet content as the destination. - -## Toolbars - -- Assume toolbar items are rendered on a floating Liquid Glass surface and are - grouped automatically. -- Use `ToolbarSpacer` to communicate grouping: - - fixed spacing to split related actions into a distinct group, - - flexible spacing to push a leading action away from a trailing group. -- Use `sharedBackgroundVisibility` when an item should stand alone without the - shared glass background, for example a profile/avatar item. -- Add `badge` to toolbar item content for notification or status indicators. -- Expect monochrome icon rendering in more toolbar contexts. Use `tint` only to - convey semantic meaning such as a primary action or alert state, not as pure - decoration. -- If content underneath a toolbar has extra darkening, blur, or custom - background layers, remove them before judging the new automatic scroll-edge - effect. -- For dense windows with many floating elements, tune the content's scroll-edge - treatment with `scrollEdgeEffectStyle` instead of building a custom bar - background. - -## Search - -- For a search field that applies across a whole split-view hierarchy, attach - `searchable` to the `NavigationSplitView`, not to just one column. -- When search is secondary and a compact affordance is better, use - `searchToolbarBehavior` instead of hand-rolling a toolbar button and a - separate field. -- For a dedicated search page in a multi-tab app, assign the search role to one - tab and place `searchable` on the `TabView`. -- Make most of the app's content discoverable from search when the field lives - in the top-trailing toolbar location. -- On iPad and Mac, expect the dedicated search tab to show a centered field - above browsing suggestions rather than a bottom search bar. - -## Controls - -- Prefer standard SwiftUI controls before creating custom glass components. -- Expect bordered buttons to default to a capsule shape at larger sizes. On - macOS, mini/small/medium controls preserve a rounded-rectangle shape for - denser layouts. -- Use `buttonBorderShape` when a button shape needs to be explicit. -- Use `controlSize` to preserve density in inspectors and popovers, and reserve - extra-large sizing for truly prominent actions. -- Use the system glass and glass-prominent button styles for primary actions - instead of recreating a translucent button background by hand. -- For sliders with discrete values, pass `step` to get automatic tick marks or - provide specific ticks in a `ticks` closure. -- For sliders that should expand left and right around a baseline, set - `neutralValue`. -- Use `Label` or standard control initializers for menu items so icons are - consistently placed on the leading edge across platforms. -- For custom shapes that must align concentrically with a sheet, card, or - window corner, use a concentric rectangle shape with the - `containerConcentric` corner configuration instead of guessing a radius. - -## Custom Liquid Glass - -- Use `glassEffect` for custom glass surfaces. The default shape is capsule-like - and text foregrounds are automatically made vibrant and legible against - changing content underneath. -- Pass an explicit shape to `glassEffect` when a capsule is not the right fit. -- Add `tint` only when color carries meaning, such as a status or call to - action. -- Use `glassEffect(... .interactive())` for custom controls or containers with - interactive elements so they scale, bounce, and shimmer like system glass. -- Wrap nearby custom glass elements in one `GlassEffectContainer`. This is a - visual correctness rule, not just organization: separate containers cannot - sample each other's glass and can produce inconsistent refraction. -- Use `glassEffectID` with a local `@Namespace` when matching glass elements - should morph between collapsed and expanded states. - -## Review Checklist - -- Standard structures and controls were updated first before adding custom - glass. -- Opaque backgrounds, dark scrims, and custom toolbar/sheet fills that fight the - system material were removed unless intentionally required. -- `searchable` is attached at the correct container level for the intended - search scope. -- Toolbar grouping uses `ToolbarSpacer`, `sharedBackgroundVisibility`, and - `badge` instead of one-off hand-built chrome. -- Icon tint is semantic, not decorative. -- Custom glass elements that sit near each other share a - `GlassEffectContainer`. -- Morphing glass transitions use `glassEffectID` with a namespace and stable - identity. -- Any SwiftPM GUI app used to test the result is launched as a `.app` bundle, - not as a raw executable. - -## Guardrails - -- Do not rebuild system sidebars, toolbars, sheets, or controls from scratch if - standard SwiftUI APIs already provide the modern macOS behavior. -- Do not apply custom opaque backgrounds behind a `NavigationSplitView` - sidebar, system toolbar, or sheet just because an older version needed - one. -- Do not scatter related glass elements across multiple - `GlassEffectContainer`s. -- Do not tint every icon or glass surface for visual variety alone. -- Do not assume an iPhone tab/search behavior is the right answer on macOS. - Prefer desktop-native toolbar, split-view, and inspector placement. -- Do not leave a GUI SwiftPM app launching as a bare executable when reviewing - Liquid Glass behavior; missing foreground activation can make a design bug - look like a rendering bug. - -## App Icons and Accessibility - -- App icons are now layered and dynamic on macOS too. They respond to lighting and - system effects and follow a standardized, concentric icon grid. Ship the default, - dark, clear, and tinted appearances rather than a single flat icon. -- Verify custom glass, colors, and animations under Reduce Transparency, Reduce - Motion, and the user's preferred Liquid Glass look. Standard components adapt - automatically; custom surfaces and animations may need explicit handling so they - stay legible and calm under these settings. - -## When To Use Other Skills - -- Use `swiftui-patterns` when the main question is scene architecture, - sidebar/detail layout, commands, or settings rather than Liquid Glass-specific - treatment. -- Use `view-refactor` when the main issue is file structure, state - ownership, and extracting large views before design changes. -- Use `appkit-interop` when the design requires window, panel, responder-chain, - or AppKit-only control behavior. -- Use `build-run-debug` when you need to launch, verify, or inspect logs - for the app after the visual update. +- Let system sidebars, toolbars, sheets, and controls provide glass. Do not rebuild them. Add custom `glassEffect` only for app-specific surfaces. +- No opaque custom backgrounds behind `NavigationSplitView`. Keep related glass in one container. +- Tint only when color carries meaning. +- Do not port iPhone tab bar or search behavior to the Mac. +- A GUI SwiftPM app must be launched as an `.app` bundle (see `build-run-debug`). diff --git a/build-macos-apps/skills/macos-app-best-practices/SKILL.md b/build-macos-apps/skills/macos-app-best-practices/SKILL.md index eb8e07d..bcd299c 100644 --- a/build-macos-apps/skills/macos-app-best-practices/SKILL.md +++ b/build-macos-apps/skills/macos-app-best-practices/SKILL.md @@ -1,255 +1,12 @@ --- name: macos-app-best-practices -description: Best practices for building macOS apps with SwiftUI, AppKit, and Mac Catalyst. Use when architecting a Mac app, choosing scene and window types, wiring menus and commands, or deciding between native SwiftUI, AppKit, and Mac Catalyst. +description: Best practices for macOS apps with SwiftUI, AppKit, and Mac Catalyst. Use when architecting a Mac app, choosing scene and window types, wiring menus and commands, or choosing between SwiftUI, AppKit, and Catalyst. --- -# macOS App Best Practices +# macOS app best practices -## Overview +Docs: and . -macOS apps are organized around scenes the system manages: windows, document groups, -settings, and menu-bar extras. Pick the right scene types for SwiftUI, gate Mac-only -behavior behind `#if os(macOS)`, and reserve Mac Catalyst for bringing an existing iPad -app to the Mac rather than starting new Mac apps on it. The guidance below is grounded -in Apple's SwiftUI, AppKit, and Mac Catalyst docs. - -## App Architecture: Scenes - -A `Scene` is a root of a view hierarchy with a system-managed life cycle; an `App` -presents its scenes. The system shows scenes differently per type and platform, and may -display several instances of one `WindowGroup` at once (for example, multiple windows). - -- Default to `WindowGroup` for the main window. -- Use `DocumentGroup` for document-based apps (it adds Save/Duplicate to the menu bar - automatically). -- Use `Settings` (macOS only) for the app-menu Settings window. -- Use `MenuBarExtra` for utility apps or a persistent status item. - -```swift -@main -struct Mail: App { - var body: some Scene { - WindowGroup { - MailViewer() - } - // A typed window group keyed by a model id. - WindowGroup(for: Message.ID.self) { $messageID in - MessageDetail(messageID: messageID) - } - } -} -``` - -## Opening and Identifying Windows - -Give a `WindowGroup` an `id` and open instances via the `openWindow` environment action, -matching the group id. This is how a Mac app supports multiple windows from one -declaration. - -```swift -WindowGroup(id: "mail-viewer") { - MailViewer() -} - -struct NewViewerButton: View { - @Environment(\.openWindow) private var openWindow - var body: some View { - Button("Open new mail viewer") { openWindow(id: "mail-viewer") } - } -} -``` - -## Settings Window (macOS only) - -`Settings` presents the App-menu > Settings window. Gate it with `#if os(macOS)`. -`@AppStorage` persists the bound values. - -```swift -@main -struct MyApp: App { - var body: some Scene { - WindowGroup { ContentView() } - #if os(macOS) - Settings { GeneralSettingsView() } - #endif - } -} - -struct GeneralSettingsView: View { - @AppStorage("showPreview") private var showPreview = true - @AppStorage("fontSize") private var fontSize = 12.0 - var body: some View { - Form { - Toggle("Show Previews", isOn: $showPreview) - Slider(value: $fontSize, in: 9...96) { Text("Font Size") } - } - } -} -``` - -## Menu Bar Extra - -`MenuBarExtra` renders a persistent control in the system menu bar. A utility app can -use it as the sole scene. `.menuBarExtraStyle(.window)` shows a panel with arbitrary -SwiftUI content. - -```swift -@main -struct UtilityApp: App { - var body: some Scene { - MenuBarExtra("Utility App", systemImage: "hammer") { - AppMenu() - } - } -} - -// Toggle a status item on/off. -MenuBarExtra("App Menu Bar Extra", systemImage: "star", isInserted: $show) { - StatusMenu() -} - -// Window-styled panel. -MenuBarExtra("Utility App", systemImage: "hammer") { - ScrollView { /* LazyVGrid content */ } -} -.menuBarExtraStyle(.window) -``` - -## Menus and Commands - -The menu bar is populated from your scenes plus `.commands { }` modifiers. Scene -defaults differ: `WindowGroup` adds quit/hide, Copy/Paste, and window management; on -macOS the `Settings` scene adds the App-menu > Settings item; `DocumentGroup` adds -Save/Duplicate. The order of system menus is fixed; custom menus insert after the View -menu. - -- Add system command groups contextually: `SidebarCommands()` only if your scene has a - sidebar; text-editing scenes get a Format menu via `TextFormattingCommands`. -- Build custom menus with `CommandMenu("Actions")` using standard `Button`/`Toggle` - views, and bind `.keyboardShortcut(...)`. - -```swift -@main -struct MyApp: App { - var body: some Scene { - DocumentGroup(newDocument: MyAppDocument()) { file in - ContentView(document: file.$document) - } - .commands { SidebarCommands() } - - WindowGroup { - ContentView() - } - .commands { - CommandMenu("Actions") { - Button("Run") { /* ... */ }.keyboardShortcut("R") - Button("Stop") { /* ... */ }.keyboardShortcut(".") - } - } - } -} -``` - -## SwiftUI vs AppKit - -- SwiftUI is the default for new Mac UI; AppKit remains the layer for advanced or legacy - controls and when a SwiftUI equivalent is missing. -- SwiftUI symbols and scenes provide the cross-platform contract; gate Mac-specific - scenes (`Settings`, `MenuBarExtra`) and platform-only modifiers with `#if os(macOS)`. -- For AppKit bridging details, use `appkit-interop`; this skill stays at the - architecture/decision level. - -## Mac Catalyst (iPad app to Mac) - -Mac Catalyst produces a Mac version of an iPad app from the same project and source. In -Xcode: iOS target > General > Supported Destinations > add **Mac > Mac Catalyst**. Xcode -adds the Mac entitlement to the Mac build only and adds a "My Mac" destination. - -- Mac Catalyst apps can use only APIs available in Mac Catalyst; AppKit APIs are not - accessible from Catalyst. -- Exclude incompatible frameworks by setting the platform filter to iOS only in - Frameworks, Libraries, and Embedded Content. -- Gate code with `#if !targetEnvironment(macCatalyst)` (unavailable API) and - `#if targetEnvironment(macCatalyst)` (macOS-only). - -Choose the UI idiom in Xcode after enabling Mac Catalyst: - -- **Scale Interface to Match iPad**: iPad idiom. Fastest; UI scaled to the Mac with - iPad-like metrics. The default. -- **Optimize Interface for Mac**: Mac idiom. Controls look and behave like AppKit; - points equal AppKit points. May require re-laying out hard-coded sizes and constraints. - Detect via `traitCollection.userInterfaceIdiom == .mac`. - -```swift -// Tailor behavior for the Mac idiom. -if traitCollection.userInterfaceIdiom == .mac { - showFavoritesAtTop.preferredStyle = .checkbox - showFavoritesAtTop.title = "Always show favorite recipes at the top" -} - -// Keep a control's iPad appearance in the Mac idiom. -slider.preferredBehavioralStyle = .pad -``` - -macOS features you get for free with Catalyst: default menu bar, pointer/mouse/keyboard -input, window resizing and full screen, Mac-style scroll bars, copy/paste, drag and -drop, Touch Bar. Extend with custom menu bar items (`UIMenuBuilder`), a Settings window -(auto-provided with a Settings bundle), pointer hover (`UIHoverGestureRecognizer`), and a -Liquid Glass sidebar background -(`splitViewController.primaryBackgroundStyle = .sidebar`). - -```swift -// Pointer hover (Catalyst + macOS). -let hover = UIHoverGestureRecognizer(target: self, action: #selector(hovering(_:))) -button.addGestureRecognizer(hover) - -@objc func hovering(_ r: UIHoverGestureRecognizer) { - switch r.state { - case .began, .changed: button.titleLabel?.textColor = .red - case .ended: button.titleLabel?.textColor = .link - default: break - } -} - -// Use .alert (not .actionSheet) under Mac Catalyst. -#if targetEnvironment(macCatalyst) -let style = UIAlertController.Style.alert -#else -let style = UIAlertController.Style.actionSheet -#endif -``` - -## Checklist - -- [ ] Main UI in a `WindowGroup`; document apps in `DocumentGroup`. -- [ ] App-menu settings via `Settings { }` gated with `#if os(macOS)`. -- [ ] Utility/status UI via `MenuBarExtra` (`.menuBarExtraStyle(.window)` for panels). -- [ ] Multi-window: id the group and open with `@Environment(\.openWindow)`. -- [ ] Menus via `.commands { }`; add `SidebarCommands` / `TextFormattingCommands` only - when relevant; custom items in `CommandMenu` with `keyboardShortcut`. -- [ ] Mac-only scenes and modifiers wrapped in `#if os(macOS)`. -- [ ] Mac Catalyst: no AppKit calls; gate with `#if targetEnvironment(macCatalyst)`; - pick Scale-to-iPad vs Optimize-for-Mac deliberately; detect via - `userInterfaceIdiom == .mac`. -- [ ] Build verified for "My Mac" (native) and "My Mac (Catalyst)" destinations. - -## When To Use Other Skills - -- `swiftui-patterns`: concrete scene/window/toolbar/settings/split-view implementations. -- `window-management`: window chrome, placement, restoration, borderless windows. -- `appkit-interop`: reaching AppKit (NSWindow, panels, responder chain) from SwiftUI. -- `signing-entitlements` / `packaging-notarization`, ship the app once it builds. - -## Resources - -- -- -- -- -- -- -- -- -- -- -- +- Choose scenes deliberately (`WindowGroup`, `Window`, `DocumentGroup`, `Settings`, `MenuBarExtra`). Wrap Mac-only scenes and modifiers in `#if os(macOS)` in shared code. +- Wire real menu commands and keyboard shortcuts. Add system command groups only when the scene has the matching content. +- Mac Catalyst can use only Catalyst-available APIs, so AppKit is unavailable there. Exclude incompatible frameworks with platform filters. diff --git a/build-macos-apps/skills/packaging-notarization/SKILL.md b/build-macos-apps/skills/packaging-notarization/SKILL.md index f6c044f..468b1e6 100644 --- a/build-macos-apps/skills/packaging-notarization/SKILL.md +++ b/build-macos-apps/skills/packaging-notarization/SKILL.md @@ -3,46 +3,9 @@ name: packaging-notarization description: Prepare macOS packaging and notarization workflows. Use when archiving apps, validating bundles, or explaining distribution-only failures. --- -# Packaging & Notarization +# Packaging and notarization -## Quick Start +Docs: (`xcrun notarytool --help`). -Use this skill when the work is about shipping the app rather than merely -running it locally: archives, exported app bundles, notarization readiness, -hardened runtime, or distribution validation. - -## Workflow - -1. Confirm the distribution goal. - - Local archive validation - - Signed distributable app - - Notarization troubleshooting - -2. Inspect the artifact. - - Validate app bundle structure. - - Check nested frameworks, helper tools, and entitlements. - -3. Inspect signing and runtime prerequisites. - - Hardened runtime - - Signing identity - - Nested code signatures - - Required entitlements - -4. Explain notarization readiness or failure. - - Separate packaging issues from trust-policy symptoms. - - Point to the minimum follow-up validation commands. - -## Guardrails - -- Do not present notarization as required for ordinary local debug runs. -- Call out when you lack the actual exported artifact and are inferring from project settings. -- Keep advice concrete and verifiable. - -## Output Expectations - -Provide: - -- what artifact or settings were inspected -- whether the app looks distribution-ready -- the top missing prerequisite or failure mode -- the next validation or repair step +- Notarization is a distribution step. Do not present it as required for local debug runs. +- Validate the bundle (`codesign`, `spctl`) before submitting. Keep distribution failures separate from local signing failures. diff --git a/build-macos-apps/skills/signing-entitlements/SKILL.md b/build-macos-apps/skills/signing-entitlements/SKILL.md index 72eff3f..d54e0d5 100644 --- a/build-macos-apps/skills/signing-entitlements/SKILL.md +++ b/build-macos-apps/skills/signing-entitlements/SKILL.md @@ -3,57 +3,10 @@ name: signing-entitlements description: Inspect macOS signing, entitlements, and Gatekeeper issues. Use when diagnosing code signing, sandbox, hardened runtime, or trust failures. --- -# Signing & Entitlements +# Signing and entitlements -## Quick Start +Use `codesign -dvvv --entitlements :-`, `spctl --assess -vv`, and `plutil` to read facts. -Use this skill when the failure smells like codesigning rather than compilation: -launch refusal, missing entitlement, invalid signature, sandbox mismatch, -hardened runtime confusion, or trust-policy rejection. - -## Workflow - -1. Inspect the bundle or binary. - - Locate the `.app` or executable. - - Identify the main binary inside `Contents/MacOS/`. - -2. Read signing details. - - Use `codesign -dvvv --entitlements :- `. - - Use `spctl -a -vv ` when Gatekeeper behavior matters. - - Use `plutil -p` for entitlements or Info.plist inspection. - -3. Classify the failure. - - Unsigned or ad hoc signed - - Wrong identity - - Entitlement mismatch - - Hardened runtime issue - - App Sandbox issue - - Nested code signing issue - - Distribution/notarization prerequisite issue - -4. Explain the minimum fix path. - - Say exactly what is wrong. - - Show the shortest set of validation or repair commands. - - Distinguish local development problems from distribution problems. - -## Useful Commands - -- `codesign -dvvv --entitlements :- ` -- `spctl -a -vv ` -- `security find-identity -p codesigning -v` -- `plutil -p ` - -## Guardrails - -- Never invent missing entitlements. +- Never invent entitlements. Read them from the binary or source files. +- Name the failure class: identity, provisioning, hardened runtime, sandbox, or trust policy. - Do not conflate notarization with local debug signing. -- If the real issue is a build setting or provisioning profile, say so directly. - -## Output Expectations - -Provide: - -- what artifact was inspected -- what signing state it is in -- the exact failure class -- the minimum fix or validation sequence diff --git a/build-macos-apps/skills/swiftpm-macos/SKILL.md b/build-macos-apps/skills/swiftpm-macos/SKILL.md index c047e7c..6cef866 100644 --- a/build-macos-apps/skills/swiftpm-macos/SKILL.md +++ b/build-macos-apps/skills/swiftpm-macos/SKILL.md @@ -3,49 +3,10 @@ name: swiftpm-macos description: Build, run, and test SwiftPM macOS packages and executables. Use when the repo is package-first or has no Xcode project. --- -# SwiftPM for macOS +# SwiftPM on macOS -## Quick Start +Docs: `swift build --help`, . -Use this skill when `Package.swift` is the primary entrypoint or when SwiftPM is -the fastest path to a reproducible result. - -## Workflow - -1. Inspect the package. - - Read `Package.swift`. - - Identify executable, library, and test products. - -2. Build with SwiftPM. - - Use `swift build` by default. - - Use release mode only when the user explicitly needs it. - -3. Run the right product. - - Use `swift run ` when an executable exists. - - If multiple executables exist, explain the default choice. - -4. Test narrowly. - - Use `swift test`. - - Apply filters when a specific test target or case is known. - -5. Summarize failures. - - Module/import resolution - - Package graph or dependency issue - - Linker failure - - Runtime failure - - Test regression - -## Guardrails - -- Prefer SwiftPM over Xcode when both exist and the package path is clearly simpler. -- Do not assume an app bundle exists in a pure package workflow. -- Explain when the package is library-only and therefore not directly runnable. - -## Output Expectations - -Provide: - -- the package products you found -- the command you ran -- whether build, run, or test succeeded -- the top blocker if not +- Use release mode only when asked. +- A pure package has no app bundle. Library-only packages are not runnable, so say so. +- GUI executables need `.app` staging, see `build-run-debug`. diff --git a/build-macos-apps/skills/swiftui-patterns/SKILL.md b/build-macos-apps/skills/swiftui-patterns/SKILL.md index 6f63b09..4884f3d 100644 --- a/build-macos-apps/skills/swiftui-patterns/SKILL.md +++ b/build-macos-apps/skills/swiftui-patterns/SKILL.md @@ -3,137 +3,12 @@ name: swiftui-patterns description: Build macOS SwiftUI scenes and components with desktop patterns. Use when shaping windows, commands, toolbars, settings, split views, or inspectors. --- -# SwiftUI Patterns +# SwiftUI patterns (macOS) -## Quick Start +Docs: and the macOS HIG. -Choose a track based on your goal: - -### Existing project - -- Identify the feature or scene and the primary interaction model: document, editor, sidebar-detail, utility window, settings, or menu bar extra. -- Read the nearest existing scene or root view before inventing a new desktop structure. -- Choose the relevant reference from `references/components-index.md`. -- If SwiftUI cannot express the required platform behavior cleanly, use the `appkit-interop` skill rather than forcing a shaky workaround. - -### New app scaffolding - -- Choose the scene model first: `WindowGroup`, `Window`, `Settings`, `MenuBarExtra`, or `DocumentGroup`. -- If the app combines a normal main window and a `MenuBarExtra`, use `WindowGroup(..., id:)` for the primary window when it should appear at launch. Treat `Window(...)` as a better fit for auxiliary/on-demand singleton windows; in menu-bar-heavy apps, a `Window(...)` scene may not present the main window automatically at launch. -- Before creating the scaffold, check whether the workspace is already inside a git repo with `git rev-parse --is-inside-work-tree`. If not, run `git init` at the project root. Do not initialize a nested repo inside an existing parent checkout. -- For a new app scaffold, also create one project-local `script/build_and_run.sh`. Use the bootstrap contract in `../build-run-debug/references/run-button-bootstrap.md` rather than inventing a second variant. -- Decide which state is app-wide, scene-scoped, or window-scoped before writing views. -- Sketch file and module boundaries before writing the full UI. For any non-trivial app, create the folder structure first and split files by responsibility from the start. -- Use a single Swift file only for tiny throwaway examples or snippets: roughly under 50 lines, one screen, no persistence, no networking/process client, and no reusable models. Anything beyond that should be multi-file immediately. -- Use system-adaptive colors and materials by default (`Color.primary`, `Color.secondary`, semantic foreground styles, `.regularMaterial`, etc.) so the app follows Light/Dark mode automatically. Do not hardcode white or light backgrounds unless the user explicitly asks for a fixed theme, and do not reach for opaque `windowBackgroundColor` fills for root panes by default. -- Pick the references for the first feature surface you need: windowing, commands, split layouts, or settings. - -## New App File Structure - -For any non-trivial macOS app, start with this shape instead of putting the app, -all views, models, stores, services, and helpers in one Swift file: - -- `App/App.swift`: the `@main` app type and `AppDelegate` only. -- `Views/ContentView.swift`: root layout and high-level composition only. -- `Views/SidebarView.swift`, `Views/DetailView.swift`, `Views/ComposerView.swift`, etc.: feature views named after their primary type. -- `Models/*.swift`: value models, identifiers, and selection enums. -- `Stores/*.swift`: persistence and state stores. -- `Services/*.swift`: app-server, network, process, or platform clients. -- `Support/*.swift`: small formatters, resolvers, extensions, and glue helpers. - -Keep files small and named after the primary type they contain. If a file starts -collecting unrelated views, models, stores, networking clients, and helper -extensions, split it before adding more behavior. - -## Pre-Edit Checklist For New App Scaffolds - -Before writing the full UI: - -1. Choose the scene model. -2. Choose state ownership: app-wide, scene-scoped, window-scoped, or view-local. -3. Sketch file and module boundaries. -4. Create the folder structure before filling in the UI. -5. Keep `script/build_and_run.sh` separate from app source. - -## General Rules To Follow - -- Design for pointer, keyboard, menus, and multiple windows. -- Keep scenes explicit. A separate settings window, utility window, or menu bar extra should be modeled as its own scene, not hidden inside one monolithic `ContentView`. -- Prefer system desktop affordances: `commands`, toolbars, sidebars, inspectors, contextual menus, and `searchable`. -- For menu bar apps, keep `MenuBarExtra` item titles and action labels short and scannable. Cap visible menu item text at 30 characters; if source content is longer, truncate or summarize it before rendering and open the full content in a dedicated window or detail surface. -- If a `MenuBarExtra` app should still behave like a regular Dock app with a visible main window/process, install an `NSApplicationDelegate` via `@NSApplicationDelegateAdaptor`, call `NSApp.setActivationPolicy(.regular)` during launch, and activate the app with `NSApp.activate(ignoringOtherApps: true)`. - If the app is intentionally menu-bar-only, document that `.accessory` / no-Dock behavior is a deliberate product choice. -- Prefer system-adaptive colors, materials, and semantic foreground styles. Avoid fixed white/light backgrounds in scaffolding and examples unless the requested design explicitly calls for a custom non-adaptive theme. -- Do not paint `NavigationSplitView` sidebars or root window panes with opaque custom `Color(...)` or `Color(nsColor: .windowBackgroundColor)` fills by default. Prefer native macOS sidebar/window materials and system-provided backgrounds unless the user explicitly asks for a custom opaque surface. - In sidebar-detail-inspector layouts, let the sidebar keep the standard source-list/material appearance and reserve custom backgrounds for detail or inspector content cards where needed. -- Use `@SceneStorage` for per-window ephemeral state and `@AppStorage` for durable user preferences. -- Keep selection state explicit and stable. macOS layouts often pivot around sidebar selection rather than push navigation. -- Prefer `NavigationSplitView` or a deliberate manual split layout over iOS-style stacked flows when the app benefits from always-visible structure. -- For `List(...).listStyle(.sidebar)` and `NavigationSplitView` sidebars, prefer flat native rows with standard system selection/highlight behavior. Keep rows visually lightweight and Mail-like: at most one leading icon, one strong title line, and one optional secondary detail line in `.secondary`. - Avoid stacked metadata rows, repeated inline utility icons, or dense multi-column status text in the sidebar. Reserve card-style and metadata-heavy surfaces for detail or inspector panes unless the user explicitly asks for a highly custom sidebar treatment. -- Keep primary actions discoverable from both UI chrome and keyboard shortcuts when appropriate. -- Use SwiftUI-native scenes and views first. If you need low-level window, responder-chain, text system, or panel control, switch to `appkit-interop`. - -For concrete sidebar row and split-view background examples, read -`references/split-inspectors.md`. - -## State Ownership Summary - -Use the narrowest state tool that matches the ownership model: - -| Scenario | Preferred pattern | -| ------------------------------------------------------ | --------------------------------------------------------------- | -| Local view or control state | `@State` | -| Child mutates parent-owned value state | `@Binding` | -| Root-owned reference model on macOS 14+ | `@State` with an `@Observable` type | -| Child reads or mutates an injected `@Observable` model | Pass it explicitly as a stored property | -| Window-scoped ephemeral selection or expansion state | `@SceneStorage` when practical, otherwise scene-owned `@State` | -| Shared user preference | `@AppStorage` | -| Shared app service or configuration | `@Environment(Type.self)` | -| Legacy reference model on older targets | `@StateObject` at the owner and `@ObservedObject` when injected | - -Choose the ownership location first, then the wrapper. Do not turn simple desktop state into a view model by reflex. - -## Cross-Cutting References - -- `references/components-index.md`: entry point for scene and component guidance. -- `references/windowing.md`: choosing between `WindowGroup`, `Window`, `DocumentGroup`, and window-opening patterns. -- `references/settings.md`: dedicated settings scenes, `SettingsLink`, and preference layouts. -- `references/commands-menus.md`: command menus, keyboard shortcuts, focused values, and desktop action routing. -- `references/split-inspectors.md`: sidebars, split views, selection-driven layout, and inspectors. -- `references/menu-bar-extra.md`: menu bar extra structure and when it fits. - -## Anti-Patterns - -- One huge `ContentView` pretending the whole app is a single screen. -- A single Swift file containing the `@main` app, all views, models, stores, networking/process clients, formatters, and extensions. This is acceptable only for tiny throwaway snippets under the new-app threshold above. -- Touch-first interaction models ported directly from iOS without desktop affordances. -- Hiding core actions behind gestures with no menu, toolbar, or keyboard path. -- Building a menu-bar-plus-window app around only a `Window(...)` scene and then expecting the main window to appear at launch. Use `WindowGroup(..., id:)` for the primary launch window and reserve `Window(...)` for auxiliary/on-demand windows. -- Rendering full unbounded document titles, prompts, or message text directly inside a menu bar extra. Menu item labels should stay at or below 30 characters, with longer content moved into a dedicated window or detail view. -- Treating settings as another navigation destination in the main content window. -- Hardcoding `.background(.white)`, `Color.white`, or a fixed light palette in a brand-new scaffold without an explicit design requirement. -- Wrapping each sidebar item in large rounded custom cards inside a `.sidebar` list, which fights native source-list density, alignment, and selection behavior unless the user explicitly asked for a bespoke visual sidebar. -- Building sidebar rows with multiple repeated icons, three or more text lines, or a dense strip of inline metadata counters/timestamps/models. Keep the sidebar row to one icon and one or two text lines, then move richer metadata into the detail pane. -- Painting `NavigationSplitView` sidebars or root window panes with opaque custom color fills by default, instead of letting the sidebar use native source-list/material appearance and reserving custom backgrounds for actual content cards. -- Using push navigation for layouts that want stable sidebar selection and detail panes. -- Reaching for AppKit before the SwiftUI scene and command APIs have been used properly. - -## Workflow For A New macOS Scene Or View - -1. Define the scene type and ownership model before writing child views. -2. Decide which actions live in content, toolbars, commands, inspectors, or settings. -3. Sketch the selection model and layout: sidebar-detail, editor-inspector, document window, or utility window. -4. Create the file/folder structure for app entrypoint, root layout, feature views, models, stores, services, and support helpers. -5. Build with small, focused subviews and explicit inputs rather than giant computed fragments. -6. Add keyboard shortcuts and menu or toolbar exposure for actions that matter on desktop. -7. Validate the flow with a build and a quick usability pass: multiwindow assumptions, settings entry points, and selection stability. - -## Component References - -Use `references/components-index.md` as the entry point. Each component reference should include: - -- intent and best-fit scenarios -- minimal usage pattern with desktop conventions -- pitfalls and discoverability notes -- when to fall back to `appkit-interop` +- Use system-adaptive colors and materials. Do not fill `NavigationSplitView` sidebars or root panes with opaque custom colors. +- Use `WindowGroup(..., id:)` for the primary launch window. A `Window` scene alone will not appear at launch in a menu-bar-plus-window app. +- Keep sidebars simple. Put metadata-heavy content in detail or inspector panes. +- Do not add a view model by reflex. Pick the state owner first. +- For a new app scaffold, split into files and add one `script/build_and_run.sh` (see `build-run-debug`). A single file is only for snippets under about 50 lines. diff --git a/build-macos-apps/skills/swiftui-patterns/references/commands-menus.md b/build-macos-apps/skills/swiftui-patterns/references/commands-menus.md deleted file mode 100644 index 47fb3b7..0000000 --- a/build-macos-apps/skills/swiftui-patterns/references/commands-menus.md +++ /dev/null @@ -1,41 +0,0 @@ -# Commands and Menus - -## Intent - -Use this when mapping desktop actions into menu items, keyboard shortcuts, and focused scene behavior. - -## Core patterns - -- Add `commands` at the scene level. -- Use `CommandMenu` for app-specific actions. -- Use `CommandGroup` to insert, replace, or remove menu sections. -- Use `FocusedValue` or scene state to make commands context-sensitive. -- Pair important commands with keyboard shortcuts and visible toolbar or content affordances when appropriate. - -## Example - -```swift -@main -struct SampleApp: App { - var body: some Scene { - WindowGroup { - EditorRootView() - } - .commands { - CommandMenu("Document") { - Button("New Note") { /* create */ } - .keyboardShortcut("n") - - Button("Toggle Inspector") { /* toggle */ } - .keyboardShortcut("i", modifiers: [.command, .option]) - } - } - } -} -``` - -## Pitfalls - -- Do not register the same shortcut in multiple places. -- Do not make commands the only discoverable path for a critical action. -- If you need responder-chain validation, custom menu item state, or AppKit-specific command behavior, use `appkit-interop`. diff --git a/build-macos-apps/skills/swiftui-patterns/references/components-index.md b/build-macos-apps/skills/swiftui-patterns/references/components-index.md deleted file mode 100644 index dedc536..0000000 --- a/build-macos-apps/skills/swiftui-patterns/references/components-index.md +++ /dev/null @@ -1,16 +0,0 @@ -# Components Index - -Use this file to find scene and component guidance. Each entry lists when to use it. - -## Available references - -- Windowing: `references/windowing.md`: Use when choosing between `WindowGroup`, `Window`, `DocumentGroup`, or window-opening APIs. -- Settings: `references/settings.md`: Use for dedicated settings scenes, preference storage, and settings entry points. -- Commands and menus: `references/commands-menus.md`, Use for menu items, keyboard shortcuts, focused actions, and command routing. -- Split views and inspectors: `references/split-inspectors.md`, Use for sidebar-detail apps, inspectors, and selection-driven desktop layouts. -- Menu bar extras: `references/menu-bar-extra.md`, Use when the app belongs primarily in the menu bar. - -## Adding entries - -- Add a new reference file when a macOS-specific pattern comes up repeatedly. -- Keep each reference short, actionable, and explicit about when SwiftUI is enough versus when AppKit interop is warranted. diff --git a/build-macos-apps/skills/swiftui-patterns/references/menu-bar-extra.md b/build-macos-apps/skills/swiftui-patterns/references/menu-bar-extra.md deleted file mode 100644 index 864c68a..0000000 --- a/build-macos-apps/skills/swiftui-patterns/references/menu-bar-extra.md +++ /dev/null @@ -1,62 +0,0 @@ -# Menu Bar Extra - -## Intent - -Use this when the app primarily lives in the macOS menu bar instead of a traditional always-open window. - -## Core patterns - -- Use `MenuBarExtra` for lightweight utilities, status indicators, and quick actions. -- If the app also has a primary main window that should appear at launch, define that scene with `WindowGroup(..., id:)` and use `Window(...)` only for auxiliary/on-demand windows. -- If the menu bar app should still show in the Dock and activate like a normal app, install an app delegate with `@NSApplicationDelegateAdaptor`, call `NSApp.setActivationPolicy(.regular)` during launch, and then `NSApp.activate(ignoringOtherApps: true)`. -- If the app is intentionally menu-bar-only, explicitly document that `.accessory` / no-Dock behavior is expected product behavior rather than a launch bug. -- Keep the menu content concise and action-oriented. -- Keep each visible menu item label to 30 characters or fewer. If the backing content can be longer than that, derive a short display title and open the full text in a separate window or detail pane. -- If the app has deeper workflows, open a dedicated window from the menu bar extra rather than cramming everything into the menu. - -## Example - -```swift -import AppKit - -private func shortMenuTitle(_ title: String) -> String { - if title.count <= 30 { - return title - } - return String(title.prefix(27)) + "..." -} - -final class AppDelegate: NSObject, NSApplicationDelegate { - func applicationDidFinishLaunching(_ notification: Notification) { - NSApp.setActivationPolicy(.regular) - NSApp.activate(ignoringOtherApps: true) - } -} - -@main -struct SampleApp: App { - @NSApplicationDelegateAdaptor(AppDelegate.self) private var appDelegate - - var body: some Scene { - WindowGroup("Sample", id: "main") { - ContentView() - } - - MenuBarExtra("Sample", systemImage: "bolt.circle") { - Button(shortMenuTitle("Open Dashboard")) { /* open window */ } - Divider() - Button("Quit") { - NSApplication.shared.terminate(nil) - } - } - } -} -``` - -## Pitfalls - -- Do not rely on a `Window(...)` scene alone for the main launch window in a menu-bar-plus-window app when the product expects a regular window at startup. -- Do not silently ship a no-Dock menu-bar-only app if the user expects a normal app process. Either install the app delegate and switch to `.regular`, or clearly document that `.accessory` behavior is intentional. -- Do not turn the menu bar extra into a tiny, overloaded substitute for a full app window. -- Do not render raw unbounded titles or message bodies as menu items. Long labels quickly blow out the menu width and should be capped to 30 characters with a short display title. -- If the extra needs advanced status item customization or AppKit menu control, use `appkit-interop`. diff --git a/build-macos-apps/skills/swiftui-patterns/references/settings.md b/build-macos-apps/skills/swiftui-patterns/references/settings.md deleted file mode 100644 index 89813bd..0000000 --- a/build-macos-apps/skills/swiftui-patterns/references/settings.md +++ /dev/null @@ -1,51 +0,0 @@ -# Settings - -## Intent - -Use this when building a native macOS settings window with SwiftUI. - -## Core patterns - -- Declare a dedicated `Settings` scene in the app. -- Keep settings content in a separate root view. -- Use `@AppStorage` for user preferences that should persist. -- Prefer tabs, sections, or a split settings layout over deep push navigation. -- Use `SettingsLink` or `OpenSettingsAction` for in-app entry points. - -## Example - -```swift -@main -struct SampleApp: App { - var body: some Scene { - WindowGroup { - ContentView() - } - - Settings { - SettingsView() - } - } -} - -struct SettingsView: View { - @AppStorage("showSidebarIcons") private var showSidebarIcons = true - - var body: some View { - TabView { - Form { - Toggle("Show Sidebar Icons", isOn: $showSidebarIcons) - } - .tabItem { Label("General", systemImage: "gearshape") } - } - .frame(width: 460, height: 260) - .scenePadding() - } -} -``` - -## Pitfalls - -- Do not reuse an iOS full-screen settings screen unless the app really is a direct Catalyst-style port. -- Keep settings rows simple and accessible. -- If settings require custom panels, responders, or first-responder integration, use `appkit-interop`. diff --git a/build-macos-apps/skills/swiftui-patterns/references/split-inspectors.md b/build-macos-apps/skills/swiftui-patterns/references/split-inspectors.md deleted file mode 100644 index 98563ed..0000000 --- a/build-macos-apps/skills/swiftui-patterns/references/split-inspectors.md +++ /dev/null @@ -1,111 +0,0 @@ -# Split Views and Inspectors - -## Intent - -Use this when the app benefits from a stable sidebar-detail layout, optional supplementary content, or an inspector panel. - -## Core patterns - -- Prefer explicit selection state over push-only navigation. -- Start with `NavigationSplitView` when the layout matches the system mental model. -- Use a manual split only when you need unusual sizing or an always-visible custom column. -- Use `inspector(isPresented:)` for lightweight detail controls that complement the main content. - -## Example: sidebar + detail - -```swift -struct LibraryRootView: View { - @State private var selection: Item.ID? - @State private var showInspector = false - - var body: some View { - NavigationSplitView { - SidebarList(selection: $selection) - } detail: { - DetailView(selection: selection) - .inspector(isPresented: $showInspector) { - InspectorView(selection: selection) - } - } - } -} -``` - -## Example: native sidebar row - -Prefer a native source-list row shape: - -```swift -List(selection: $selection) { - ForEach(items) { item in - HStack(spacing: 10) { - Image(systemName: item.systemImage) - .foregroundStyle(.secondary) - .frame(width: 16) - - VStack(alignment: .leading, spacing: 2) { - Text(item.title) - .lineLimit(1) - - if let detail = item.detail { - Text(detail) - .font(.caption) - .foregroundStyle(.secondary) - .lineLimit(1) - } - } - } - .tag(item.id) - } -} -.listStyle(.sidebar) -``` - -Keep each row to one icon and one or two text lines. Put richer metadata in the -detail or inspector content instead of every sidebar row. - -## Example: split-view backgrounds - -Let the sidebar and split container keep system backgrounds while detail content -owns custom surfaces: - -```swift -NavigationSplitView { - List(selection: $selection) { - ForEach(items) { item in - Label(item.title, systemImage: item.systemImage) - .tag(item.id) - } - } - .listStyle(.sidebar) -} detail: { - ScrollView { - VStack(alignment: .leading, spacing: 16) { - DetailSummaryCard(item: selectedItem) - DetailMetricsCard(item: selectedItem) - } - .padding() - } -} -``` - -Avoid opaque sidebar and root split-pane fills by default: - -```swift -NavigationSplitView { - List(items) { item in - SidebarCardRow(item: item) - } - .listStyle(.sidebar) - .background(Color(nsColor: .windowBackgroundColor)) -} detail: { - DetailView(item: selectedItem) - .background(Color(.white)) -} -``` - -## Pitfalls - -- Avoid swapping the whole root layout with top-level conditionals when selection changes. -- Avoid hiding too much detail behind modal sheets when an inspector or secondary column would fit better. -- If the layout requires AppKit split view delegation or advanced window coordination, use `appkit-interop`. diff --git a/build-macos-apps/skills/swiftui-patterns/references/windowing.md b/build-macos-apps/skills/swiftui-patterns/references/windowing.md deleted file mode 100644 index 1b34da1..0000000 --- a/build-macos-apps/skills/swiftui-patterns/references/windowing.md +++ /dev/null @@ -1,46 +0,0 @@ -# Windowing - -## Intent - -Use this when choosing the top-level scene model for a native macOS app. - -## Choose the scene type deliberately - -- Use `WindowGroup(..., id:)` for the primary app window when it should appear at launch, especially in apps that also have a `MenuBarExtra`. -- Use `WindowGroup` for any scene that can have multiple independent instances. -- Use `Window` for singleton utility windows or focused secondary surfaces. In menu-bar-heavy apps, `Window(...)` is better for auxiliary/on-demand windows and may not present the main window automatically at launch. -- Use `Settings` for preferences. Do not bury settings inside the main content flow. -- Use `DocumentGroup` when the app is fundamentally document-driven. - -## Example: main app plus utility window - -```swift -@main -struct SampleApp: App { - var body: some Scene { - WindowGroup("Library", id: "library") { - LibraryRootView() - } - - Window("Inspector", id: "inspector") { - InspectorRootView() - } - - Settings { - SettingsView() - } - } -} -``` - -## Opening windows - -- Use `openWindow(id:)` when a command, toolbar item, or button should open another scene. -- Keep per-window state in the scene or `@SceneStorage`, not in a single global pile. - -## Pitfalls - -- Avoid modeling every feature as a pushed destination inside one window. -- Do not use only `Window(...)` for the main launch window in a menu-bar-plus-window app unless you have verified the launch behavior and intentionally want an on-demand auxiliary window. -- Avoid singleton state for window-specific selections or drafts. -- If you need lower-level titlebar, tabbing, or window lifecycle control, switch to `appkit-interop`. diff --git a/build-macos-apps/skills/telemetry/SKILL.md b/build-macos-apps/skills/telemetry/SKILL.md index c1ba13a..98c7cb3 100644 --- a/build-macos-apps/skills/telemetry/SKILL.md +++ b/build-macos-apps/skills/telemetry/SKILL.md @@ -5,82 +5,8 @@ description: Add and verify lightweight macOS runtime telemetry. Use when wiring # Telemetry -## Quick Start +Use `Logger` (os) with a subsystem and category, read via Console or `log stream --predicate`. Docs: . -Use this skill to add lightweight app instrumentation that helps debug behavior -without turning the codebase into a logging landfill. Prefer Apple's unified -logging APIs and verify the events after a build/run loop. - -## Core Guidelines - -- Prefer `Logger` from the `OSLog` framework for structured app logs. -- Give each feature a clear subsystem/category pair so runtime filtering stays easy. -- Log meaningful user and app lifecycle events: window opening, sidebar selection changes, menu commands, menu bar extra actions, sync/load milestones, and unexpected fallback paths. -- Keep info logs concise and stable. Use debug logs for noisy state details. -- Do not log secrets, auth tokens, personal data, or raw document contents. -- Add signposts only when measuring timing or performance spans; do not overinstrument by default. - -## Minimal Logger Pattern - -```swift -import OSLog - -private let logger = Logger( - subsystem: Bundle.main.bundleIdentifier ?? "SampleApp", - category: "Sidebar" -) - -@MainActor -func selectItem(_ item: SidebarItem) { - logger.info("Selected sidebar item: \(item.id, privacy: .public)") - selection = item.id -} -``` - -Use feature-specific categories like `Windowing`, `Commands`, `MenuBar`, `Sidebar`, -`Sync`, or `Import` so logs can be filtered quickly. - -## Workflow - -1. Identify the behavior that needs observability. - - Window open/close - - Sidebar or inspector selection changes - - Menu or keyboard command actions - - Menu bar extra actions - - Background load/sync/import events - - Error and recovery paths - -2. Add the smallest useful instrumentation. - - Create one `Logger` per feature area or type. - - Log action boundaries and key state transitions. - - Prefer one high-signal line per user action over noisy value dumps. - -3. Build and run the app. - - Use `build-run-debug` for the build/run loop. - - If `script/build_and_run.sh` exists, prefer `./script/build_and_run.sh --telemetry` for live telemetry checks or `./script/build_and_run.sh --logs` for broader process logs. - - Exercise the UI or command path that should emit telemetry. - -4. Read runtime logs and verify the event fired. - - Use Console.app with a process/subsystem filter when that is the fastest manual check. - - Use `log stream --style compact --predicate 'process == "AppName"'` for live terminal verification. - - Prefer tighter predicates when you know the subsystem/category: - `log stream --style compact --predicate 'subsystem == "com.example.app" && category == "Sidebar"'` - -5. Tighten or remove instrumentation. - - If the event fires, keep only the logs that remain useful for future debugging. - - If it does not fire, move the log closer to the suspected control path and rerun. - -## Verification Checklist - -- The app builds after telemetry changes. -- The relevant action emits exactly one clear log line or a small bounded sequence. -- The log can be filtered by process, subsystem, or category. -- No sensitive payloads are written to unified logs. -- Noisy temporary debug logs are removed or demoted before finishing. - -## Guardrails - -- Do not use `print` as the primary app telemetry mechanism for macOS app code. -- Do not leave a dense trail of permanent debug logs around every state mutation. -- Do not claim an event is wired correctly until you have a concrete verification path through Console, `log stream`, or captured process output. -- If the debugging task is mostly about crash/backtrace analysis rather than action telemetry, switch to `build-run-debug`. +- No `print` as telemetry. Never log secrets, tokens, personal data, or document contents. +- Signposts only for timing spans. +- Do not claim an event is wired until you saw it in `log stream` or captured output. Remove logs that are not useful afterward. diff --git a/build-macos-apps/skills/test-triage/SKILL.md b/build-macos-apps/skills/test-triage/SKILL.md index 7deab0c..6b1142f 100644 --- a/build-macos-apps/skills/test-triage/SKILL.md +++ b/build-macos-apps/skills/test-triage/SKILL.md @@ -3,53 +3,10 @@ name: test-triage description: Triage macOS tests across Xcode and SwiftPM. Use when narrowing failures, explaining assertions or crashes, or separating setup from regressions. --- -# Test Triage +# Test triage -## Quick Start +Use `xcodebuild test` or `swift test` with a filter. -Use this skill to run the smallest meaningful test scope first, classify -failures precisely, and avoid treating every test failure like a product bug. - -## Workflow - -1. Detect the test harness. - - Use `xcodebuild test` for Xcode-based projects. - - Use `swift test` for SwiftPM packages. - -2. Narrow the scope. - - If the user gave a target, product, or test filter, use it. - - If not, prefer the smallest likely failing target before a full suite. - -3. Classify the result. - - Build failure - - Assertion failure - - Crash or signal - - Async timing or flake - - Environment or fixture setup issue - - Missing entitlement or host app issue - -4. Rerun intelligently. - - Use focused reruns when a specific case fails. - - Avoid burning time on full-suite reruns without new information. - -5. Summarize clearly. - - What command ran - - Which tests failed - - What kind of failure it was - - The best next proof step or fix path - -## Guardrails - -- Distinguish compilation failures from test execution failures. -- Call out when a test appears to assume iOS-only or simulator-only behavior. -- Mark likely flakes as such instead of overstating confidence. - -## Output Expectations - -Provide: - -- the command used -- the smallest failing scope -- the top failure category -- a concise explanation of the likely cause -- the next rerun or fix step +- Run the smallest scope first. No full-suite reruns without new information. +- Classify each failure: compile, assertion, crash, environment, or flake. Separate build failures from failing tests. +- Flag tests that assume iOS-only or simulator-only behavior. diff --git a/build-macos-apps/skills/view-refactor/SKILL.md b/build-macos-apps/skills/view-refactor/SKILL.md index 89ccaf7..1f73ed2 100644 --- a/build-macos-apps/skills/view-refactor/SKILL.md +++ b/build-macos-apps/skills/view-refactor/SKILL.md @@ -3,107 +3,9 @@ name: view-refactor description: Refactor macOS SwiftUI views and scenes into stable structure. Use when splitting large views, tightening scene state, or narrowing AppKit escapes. --- -# View Refactor +# View refactor (macOS) -## Overview - -Refactor macOS views toward small, explicit, stable scene and view types. Default -to native SwiftUI for layout, selection, commands, and settings. Reach for AppKit -only at the narrow edges where desktop behavior truly requires it. - -## Core Guidelines - -### 1) Model scenes explicitly - -- Break the app into meaningful scene roots: main window, settings, utility windows, inspectors, or menu bar extras. -- Do not let one giant root view silently own every desktop surface. - -### 2) Keep a predictable file shape - -- Follow this ordering unless the file already has a stronger local convention: -- Environment -- `private`/`public` `let` -- `@State` / other stored properties -- computed `var` (non-view) -- `init` -- `body` -- computed view builders / other view helpers -- helper / async functions - -### 2b) Split files by responsibility - -- For non-trivial apps, do not keep the full app, all views, models, stores, networking clients, process clients, and helpers in one Swift file. -- Accept a single Swift file only for tiny throwaway examples or snippets: roughly under 50 lines, one screen, no persistence, no networking/process client, and no reusable models. -- Use `App/App.swift` for the `@main` app and `AppDelegate` only. -- Keep `Views/ContentView.swift` focused on root layout and composition; move feature UI into files such as `Views/SidebarView.swift`, `Views/DetailView.swift`, and `Views/ComposerView.swift`. -- Move value types and selection enums into `Models/*.swift`, stores into `Stores/*.swift`, app-server/network/process clients into `Services/*.swift`, and small formatters/resolvers/extensions into `Support/*.swift`. -- Keep files small and named after the primary type they contain. - -### 3) Prefer dedicated subview types over many computed `some View` fragments - -- Extract meaningful desktop sections like sidebar rows, detail panels, inspectors, or toolbar content into focused subviews. -- Keep computed `some View` helpers small and rare. -- Pass explicit data, bindings, and actions into subviews instead of handing down the whole scene model. - -### 4) Keep selection and layout stable - -- Prefer one stable split or window layout with local conditionals inside it. -- Avoid top-level branch swapping between radically different roots when selection changes. -- Let the layout be constant; let state drive the content inside it. - -### 5) Extract commands, toolbars, and actions out of `body` - -- Do not bury non-trivial button logic inline. -- Do not mix command routing, menu state, and layout in the same block if they can be named clearly. -- Keep `body` readable as UI, not as a desktop view controller. - -### 6) Use scene and app storage intentionally - -- Use `@SceneStorage` for per-window ephemeral state when it truly helps restore the scene. -- Use `@AppStorage` for durable preferences, not transient UI toggles that only matter in one window. -- Keep scene-owned state close to the scene root. - -### 7) Keep AppKit escape hatches narrow - -- If a representable or `NSWindow` bridge exists, isolate it behind a small wrapper or helper. -- Do not let AppKit references spread through unrelated SwiftUI views. -- If the bridge starts owning the feature, re-evaluate the architecture. - -### 8) Observation usage - -- For `@Observable` reference types on modern macOS targets, store them as `@State` in the owning view. -- Pass observables explicitly to children. -- On older deployment targets, fall back to `@StateObject` and `@ObservedObject` where needed. - -## Workflow - -1. Identify the current scene boundary and whether the file is trying to do too much. -2. Reorder the file into a predictable top-to-bottom structure. -3. Extract desktop-specific sections into dedicated subview types. -4. Stabilize the root layout around selection, scenes, and commands rather than top-level branching. -5. Move action logic, command routing, and toolbar behavior into named helpers or separate types. -6. Tighten any AppKit bridge so the imperative edge is small and explicit. -7. Keep behavior intact unless the request explicitly asks for structural and behavioral changes together. - -## Refactor Checklist - -- Split oversized view files before adding more UI. -- Move pure models, identifiers, and selection enums out of view files. -- Move `Process`, `URLSession`, app-server, and platform client code out of SwiftUI views into `Services/`. -- Keep `AppDelegate` and the `@main` app entrypoint minimal. -- Build after each major split so compile errors stay local. - -## Common Smells - -- A root view that mixes window scaffolding, settings, toolbar code, command handling, and detail layout. -- A single app file that mixes app entrypoint, root layout, feature views, models, stores, service clients, and support extensions. -- iOS-style push navigation forced into a Mac sidebar-detail problem. -- Several booleans for mutually exclusive inspectors, sheets, or utility windows. -- AppKit objects passed through many SwiftUI layers without a clear ownership reason. -- Large computed view fragments standing in for real subviews. - -## Notes - -- A good macOS refactor should make scene structure, selection flow, and command ownership obvious. -- When the problem is fundamentally a missing desktop pattern, use `swiftui-patterns`. -- When the problem is fundamentally a boundary with AppKit, use `appkit-interop`. +- Split a giant root view by desktop surface. Non-trivial apps do not live in one Swift file. +- Keep a stable root. No top-level branch swapping when selection changes. +- Move button logic out of `body`. Keep command routing, menu state, and layout separate. +- `@AppStorage` for durable preferences only. Contain AppKit references at the edges (see `appkit-interop`). diff --git a/build-macos-apps/skills/window-management/SKILL.md b/build-macos-apps/skills/window-management/SKILL.md index a5a66a4..cc13ac2 100644 --- a/build-macos-apps/skills/window-management/SKILL.md +++ b/build-macos-apps/skills/window-management/SKILL.md @@ -3,168 +3,11 @@ name: window-management description: Customize macOS SwiftUI windows and scene behavior. Use when tuning window chrome, drag regions, placement, restoration, launch behavior, or borderless windows. --- -# Window Management +# Window management -## Overview +Docs: . -Use this skill to tailor each SwiftUI window to its job. Start by identifying -which scene owns the window (`Window`, `WindowGroup`, or a dedicated utility -scene), then customize the toolbar/title area, background material, resize and -restoration behavior, and initial or zoomed placement. - -Prefer scene and window modifiers over ad hoc AppKit bridges when SwiftUI offers -the behavior directly. Keep each window purpose-built: a main browser window, an -About window, and a media player window usually want different chrome, -resizability, restoration, and placement rules. - -These APIs are macOS 15+ SwiftUI window/scene customizations. For older -deployment targets, expect to use more AppKit bridging or availability guards. - -## Workflow - -1. Inspect the relevant scene declaration and classify the window role: - main app navigation, inspector/detail utility, About/support window, media - playback window, welcome window, or a borderless custom surface. -2. Adjust toolbar and title presentation to match the content. -3. If the toolbar background or entire toolbar is hidden, make sure the window - still has a usable drag region. -4. Refine window behavior for that role: minimize availability, restoration, - resize expectations, and whether the window should appear at launch. -5. Set default placement for newly opened windows and ideal placement for zoom - behavior when content and display size matter. -6. Build and launch the app with `build-run-debug` to verify the result in - a real foreground `.app` bundle. -7. If SwiftUI scene/window modifiers are not enough, switch to `appkit-interop` - for a narrow `NSWindow` bridge rather than spreading AppKit through the view - tree. - -## Toolbar And Title - -- Use `.toolbar(removing: .title)` when the window title should stay associated - with the window for accessibility and menus, but not be visibly drawn in the - title bar. -- Use `.toolbarBackgroundVisibility(.hidden, for: .windowToolbar)` when large - media or hero content should visually extend to the top edge of the window. -- If the window still needs close/minimize/full-screen controls, remove only the - title and toolbar background. If the toolbar should disappear entirely, use - `.toolbarVisibility(.hidden, for: .windowToolbar)` instead. -- Remove custom toolbar backgrounds and manually painted titlebar fills before - layering new SwiftUI toolbar APIs on top. -- Keep the window's logical title meaningful even if hidden; the system can - still use it for accessibility and menu items. These are visual changes only. - -## Drag Regions - -- If a toolbar background is hidden or the toolbar is removed entirely, use - `WindowDragGesture()` to extend the draggable area into your content. -- Attach the gesture to a transparent overlay or non-interactive header region - that does not steal gestures from real controls. -- For a media player with custom playback controls, insert the drag overlay - between the video content and the controls so AVKit or transport controls keep - receiving input. -- Pair the drag gesture with `.allowsWindowActivationEvents(true)` so clicking - and immediately dragging a background window still activates and moves it. - -## Background And Materials - -- Use `.containerBackground(.thickMaterial, for: .window)` when a utility window - or About window should replace the default window background with a subtle - frosted material. -- Prefer system materials for stylized windows instead of hardcoded translucent - colors. -- Use this especially for fixed-content utility windows where a softer backdrop - is part of the design. - -## Window Behavior - -- Use `.windowMinimizeBehavior(.disabled)` for always-reachable utility windows - such as a custom About window where minimizing adds little value. -- Disable the green zoom control through fixed sizing or window constraints when - the window's content has one intended size. -- Use `.restorationBehavior(.disabled)` for windows that should not reopen on - next launch, such as About panels, transient support/info windows, or - first-run welcome surfaces. -- Keep state restoration enabled for primary document or navigation windows when - reopening prior size and position is desirable. -- By default, SwiftUI respects the user's system-wide macOS state restoration - setting. Use `restorationBehavior(...)` only when a specific window should - intentionally opt into or out of that system behavior. -- Use `.defaultLaunchBehavior(.presented)` for windows that should appear first - on launch, such as a welcome window, and choose that behavior intentionally - rather than relying on side effects from scene creation order. - -## Window Placement - -- Use `.defaultWindowPlacement { content, context in ... }` to control the - initial size and optional position of newly opened windows. -- Inside the placement closure, call `content.sizeThatFits(.unspecified)` to get - the content's ideal size. -- Read `context.defaultDisplay.visibleRect` to get the display's usable region - after accounting for the menu bar and Dock. -- Return `WindowPlacement(size: size)` with a size clamped to the visible rect - when media or document content may be larger than the display. If no position - is provided, the window is centered by default. -- Use `.windowIdealPlacement { content, context in ... }` to control what - happens when the user chooses Zoom from the Window menu or Option-clicks the - green toolbar button. For media windows, preserve aspect ratio and grow to the - largest size that fits the display. -- Treat default placement and ideal placement as separate policies: - - default placement controls where a new window first appears, - - ideal placement controls how large a zoomed window should become. -- Always consider external displays and rotated/narrow screens when sizing - player windows or document windows from content dimensions. - -## Borderless And Specialized Windows - -- Use `.windowStyle(.plain)` for borderless or highly custom chrome windows, but - make sure the content still provides a clear drag/move affordance and visible - context. -- For a borderless player, HUD, or welcome window, decide upfront whether losing - standard titlebar affordances is worth the custom presentation. -- Keep one clear path back to regular window management if the plain style makes - the window feel invisible or hard to move. - -For concrete window modifier examples, read `references/api-snippets.md`. - -## Review Checklist - -- The scene type matches the window's role and lifecycle. -- Hidden titles still leave a meaningful logical title for accessibility and - menus. -- Toolbar background removal is intentional and does not hurt titlebar legibility - or window control placement. -- Windows with hidden or removed toolbars still have a reliable drag region and - support click-then-drag activation from the background. -- Utility windows have restoration/minimize behavior that matches their purpose. -- Restoration overrides are used only when a scene should intentionally differ - from the user's system-wide setting. -- Default and ideal placement use `content.sizeThatFits(.unspecified)` and - `context.defaultDisplay.visibleRect` when content/display size matters. -- Media windows preserve aspect ratio and fit on small or rotated displays. -- Borderless windows still have a usable move/drag affordance. - -## Guardrails - -- Do not use `.toolbar(removing: .title)` just to hide a title you forgot to set. - Keep the underlying window title meaningful. -- Do not hide the toolbar background or the whole toolbar without replacing the - lost drag affordance. -- Do not disable restoration on the main document/navigation window unless the - user explicitly wants a fresh-start app every launch. -- Do not hardcode one monitor size or assume a single-display setup when sizing - player windows. -- Do not reach for `NSWindow` mutation before checking whether - `.windowMinimizeBehavior`, `.restorationBehavior`, `.defaultWindowPlacement`, - `.windowIdealPlacement`, `.windowStyle`, or `.defaultLaunchBehavior` already - solve the problem. -- Do not leave a plain borderless window without any obvious drag or close path. - -## When To Use Other Skills - -- Use `swiftui-patterns` for broader scene, commands, settings, sidebar, - and inspector architecture. -- Use `liquid-glass` when the main question is modern macOS visual treatment, - Liquid Glass, or system material adoption. -- Use `appkit-interop` if a custom window behavior truly requires `NSWindow`, - `NSPanel`, or responder-chain control. -- Use `build-run-debug` to launch and verify the resulting windows. +- Try SwiftUI scene and window modifiers before mutating `NSWindow` (then see `appkit-interop`). +- Do not hide the toolbar or its background without a replacement. Do not use `.toolbar(removing: .title)` to hide an unset title. +- Do not disable restoration on the main document or navigation window. +- A borderless window needs an obvious drag and close path. Do not assume one display size. diff --git a/build-macos-apps/skills/window-management/references/api-snippets.md b/build-macos-apps/skills/window-management/references/api-snippets.md deleted file mode 100644 index 5b2d060..0000000 --- a/build-macos-apps/skills/window-management/references/api-snippets.md +++ /dev/null @@ -1,60 +0,0 @@ -# Window API Snippets - -Use these examples after the window role and modifier choices are clear. - -```swift -WindowGroup("Destination Video") { - CatalogView() - .toolbar(removing: .title) - .toolbarBackgroundVisibility(.hidden, for: .windowToolbar) -} -``` - -```swift -Window("About", id: "about") { - AboutView() - .toolbar(removing: .title) - .toolbarBackgroundVisibility(.hidden, for: .windowToolbar) - .containerBackground(.thickMaterial, for: .window) -} -.windowMinimizeBehavior(.disabled) -.restorationBehavior(.disabled) -``` - -```swift -WindowGroup("Player", for: Video.self) { $video in - PlayerView(video: video) -} -.defaultWindowPlacement { content, context in - let idealSize = content.sizeThatFits(.unspecified) - let displayBounds = context.defaultDisplay.visibleRect - let fittedSize = clampToDisplay(idealSize, displayBounds: displayBounds) - return WindowPlacement(size: fittedSize) -} -.windowIdealPlacement { content, context in - let idealSize = content.sizeThatFits(.unspecified) - let displayBounds = context.defaultDisplay.visibleRect - let zoomedSize = zoomToFit(idealSize, displayBounds: displayBounds) - let position = centeredPosition(for: zoomedSize, in: displayBounds) - return WindowPlacement(position, size: zoomedSize) -} -``` - -```swift -PlayerView(video: video) - .overlay(alignment: .top) { - Color.clear - .frame(height: 48) - .contentShape(Rectangle()) - .gesture(WindowDragGesture()) - .allowsWindowActivationEvents(true) - } -``` - -```swift -Window("Welcome", id: "welcome") { - WelcomeView() -} -.windowStyle(.plain) -.defaultLaunchBehavior(.presented) -``` diff --git a/chmonitor/.claude-plugin/plugin.json b/chmonitor/.claude-plugin/plugin.json index ab17e4c..ec2ea23 100644 --- a/chmonitor/.claude-plugin/plugin.json +++ b/chmonitor/.claude-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "chmonitor", "version": "2.0.0", - "description": "Work on the ClickHouse Monitor dashboard: charts, pages, query configs, its API, and version-aware system queries.", + "description": "Read-only ClickHouse monitoring and advice through the chmonitor MCP server, with pointers to its docs and codebase.", "author": { "name": "duyet", "url": "https://github.com/duyet" diff --git a/chmonitor/.codex-plugin/plugin.json b/chmonitor/.codex-plugin/plugin.json index 4df79f2..01228e6 100644 --- a/chmonitor/.codex-plugin/plugin.json +++ b/chmonitor/.codex-plugin/plugin.json @@ -1,19 +1,20 @@ { "name": "chmonitor", "version": "2.0.0", - "description": "Work on the ClickHouse Monitor dashboard: charts, pages, query configs, its API, and version-aware system queries.", + "description": "Read-only ClickHouse monitoring and advice through the chmonitor MCP server, with pointers to its docs and codebase.", "author": { "name": "duyet", "url": "https://github.com/duyet" }, "license": "MIT", "skills": "./skills/", + "mcpServers": "./.mcp.json", "interface": { "displayName": "chmonitor", - "shortDescription": "Work on the ClickHouse Monitor dashboard: charts, pages, query configs, its API, and version-aware system queries.", + "shortDescription": "Read-only ClickHouse monitoring and advice through the chmonitor MCP server, with pointers to its docs and codebase.", "developerName": "duyet", "category": "Monitoring", - "capabilities": ["Skill"], + "capabilities": ["Skill", "MCP"], "logo": "./assets/logo.svg", "composerIcon": "./assets/logo.svg" } diff --git a/chmonitor/.cursor-plugin/plugin.json b/chmonitor/.cursor-plugin/plugin.json index 9b4eed6..0a240b0 100644 --- a/chmonitor/.cursor-plugin/plugin.json +++ b/chmonitor/.cursor-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "chmonitor", "version": "2.0.0", - "description": "Work on the ClickHouse Monitor dashboard: charts, pages, query configs, its API, and version-aware system queries.", + "description": "Read-only ClickHouse monitoring and advice through the chmonitor MCP server, with pointers to its docs and codebase.", "author": { "name": "duyet" }, @@ -11,5 +11,6 @@ "repository": "https://github.com/duyet/codex-claude-plugins", "logo": "./assets/logo.svg", "category": "Monitoring", - "skills": "./skills/" + "skills": "./skills/", + "mcpServers": "./.mcp.json" } diff --git a/chmonitor/.grok-build-plugin/plugin.json b/chmonitor/.grok-build-plugin/plugin.json index 80b607c..09fe2c7 100644 --- a/chmonitor/.grok-build-plugin/plugin.json +++ b/chmonitor/.grok-build-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "chmonitor", "version": "2.0.0", - "description": "Work on the ClickHouse Monitor dashboard: charts, pages, query configs, its API, and version-aware system queries.", + "description": "Read-only ClickHouse monitoring and advice through the chmonitor MCP server, with pointers to its docs and codebase.", "author": { "name": "duyet", "url": "https://github.com/duyet" @@ -9,12 +9,13 @@ "license": "MIT", "logo": "./assets/logo.svg", "skills": "./skills/", + "mcpServers": "./.mcp.json", "interface": { "displayName": "chmonitor", - "shortDescription": "Work on the ClickHouse Monitor dashboard: charts, pages, query configs, its API, and version-aware system queries.", + "shortDescription": "Read-only ClickHouse monitoring and advice through the chmonitor MCP server, with pointers to its docs and codebase.", "developerName": "duyet", "category": "Monitoring", - "capabilities": ["Skill"], + "capabilities": ["Skill", "MCP"], "logo": "./assets/logo.svg", "composerIcon": "./assets/logo.svg" } diff --git a/chmonitor/.grok-plugin/plugin.json b/chmonitor/.grok-plugin/plugin.json index a5e65be..6945034 100644 --- a/chmonitor/.grok-plugin/plugin.json +++ b/chmonitor/.grok-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "chmonitor", "version": "2.0.0", - "description": "Work on the ClickHouse Monitor dashboard: charts, pages, query configs, its API, and version-aware system queries.", + "description": "Read-only ClickHouse monitoring and advice through the chmonitor MCP server, with pointers to its docs and codebase.", "author": { "name": "duyet", "url": "https://github.com/duyet" @@ -9,5 +9,6 @@ "license": "MIT", "logo": "./assets/logo.svg", "keywords": ["chmonitor"], - "skills": "./skills/" + "skills": "./skills/", + "mcpServers": "./.mcp.json" } diff --git a/chmonitor/.mcp.json b/chmonitor/.mcp.json new file mode 100644 index 0000000..acd76e3 --- /dev/null +++ b/chmonitor/.mcp.json @@ -0,0 +1,11 @@ +{ + "mcpServers": { + "chmonitor": { + "type": "http", + "url": "${CHMONITOR_URL:-https://dash.chmonitor.dev}/api/mcp", + "headers": { + "Authorization": "Bearer ${CHMONITOR_API_KEY}" + } + } + } +} diff --git a/chmonitor/README.md b/chmonitor/README.md index 1cabb77..eb6de2f 100644 --- a/chmonitor/README.md +++ b/chmonitor/README.md @@ -1,23 +1,9 @@ # chmonitor -Skill for working on the ClickHouse Monitor dashboard: adding charts, pages, and query configs, calling its API, and writing version-aware system table queries. +Agent skill and MCP server for [chmonitor](https://chmonitor.dev), the read-only ClickHouse dashboard and advisor. -## Install - -```text +```bash /plugin install chmonitor@duyet-claude-plugins ``` -## What ships - -- `skills/chmonitor/SKILL.md`: architecture, SWR patterns, chart and query-config recipes, compatibility rules. -- `references/api-list.md` and `references/api-endpoints.md`: chart and table endpoints. -- `references/dashboard-pages.md`: every dashboard page. -- `references/development.md`: routing, data fetching, multi-host setup, troubleshooting. -- `references/clickhouse-compat.md`: version-aware queries and optional tables. - -Source project: - -## License - -MIT +Set `CHMONITOR_API_KEY` to a `chm_` key. Set `CHMONITOR_URL` to point at a self-hosted instance instead of `https://dash.chmonitor.dev`. diff --git a/chmonitor/skills/chmonitor/SKILL.md b/chmonitor/skills/chmonitor/SKILL.md index 34fd34a..c64c8b3 100644 --- a/chmonitor/skills/chmonitor/SKILL.md +++ b/chmonitor/skills/chmonitor/SKILL.md @@ -1,287 +1,12 @@ --- name: chmonitor -description: "Use when working on the ClickHouse Monitor dashboard: adding charts, pages, or query configs, calling its API, or handling ClickHouse version differences in system table queries." +description: Use when monitoring or diagnosing a ClickHouse cluster with chmonitor (queries, merges, replication, storage, health), or when working in the chmonitor codebase. --- -# ClickHouse Monitor +# chmonitor -Real-time monitoring and observability dashboard for ClickHouse clusters. Static site architecture with client-side SWR data fetching, multi-host support, and version-aware queries. +chmonitor is a read-only dashboard and advisor for ClickHouse. It reads `system.*` tables and recommends changes. It never applies DDL. -## Quick Start - -### Dashboard Access - -Navigate using query parameter routing (`?host=N` for multi-host setups): - -- `/overview?host=0` - System overview (Connections, Queries, Merges, Replication, System) -- `/running-queries?host=0` - Active queries with progress tracking -- `/explorer?host=0` - Interactive database schema browser -- `/merges?host=0` - Active merge operations with progress -- `/clusters?host=0` - Cluster configuration and ZooKeeper status - -### Multi-Host Configuration - -Configure multiple ClickHouse instances via comma-separated environment variables: - -```bash -CLICKHOUSE_HOST=prod.example.com,staging.example.com -CLICKHOUSE_USER=admin,readonly -CLICKHOUSE_PASSWORD=secret,readonly_secret -CLICKHOUSE_NAME="Production,Staging" -``` - -Access hosts via `?host=0`, `?host=1`, etc. in URLs. - -## Core features - -The dashboard covers query monitoring (running, history, failed, expensive, cache), table management (explorer, replicas, projections, dictionaries), merges and mutations, system metrics and settings, and security logs (sessions, login attempts, crashes). See `references/dashboard-pages.md` for every page. - -## API Usage - -### Chart Data - -Fetch time-series data for visualization: - -```http -GET /api/v1/charts/{chartName}?hostId={hostId}&interval={interval}&lastHours={hours} -``` - -**Parameters:** - -- `chartName` - Name from chart registry (see references for full list) -- `hostId` - Host index (0-based) -- `interval` - Time bucket: `1m`, `5m`, `1h`, `1d` -- `lastHours` - Historical range (default: 24) - -**Response:** - -```json -{ - "success": true, - "data": [{ "ts": "2026-03-05T00:00:00Z", "value": 1234 }], - "metadata": { - "queryId": "abc123", - "duration": 45, - "rows": 24, - "host": "clickhouse.example.com", - "clickhouseVersion": "24.3.1.1" - } -} -``` - -### Table Data - -Fetch paginated table data: - -```http -GET /api/v1/tables/{queryConfigName}?hostId={hostId}&pageSize={n}&page={p} -``` - -Supports sorting (`sortCol`, `sortOrder`) and filtering per query config. - -### Database Explorer - -Browse schema structure: - -```http -GET /api/v1/explorer/databases?hostId={hostId} -GET /api/v1/explorer/tables?hostId={hostId}&database={db} -GET /api/v1/explorer/columns?hostId={hostId}&database={db}&table={t} -``` - -## Development Patterns - -### Static Site Architecture - -Fully static site with client-side data fetching. No SSR, no middleware. - -**Routing Pattern:** - -```typescript -// Static route with query parameter -app/overview/page.tsx to /overview?host=0 - -// NOT dynamic routes (not supported) -// app/[host]/overview/page.tsx -``` - -**Page Component Template:** - -```typescript -'use client' - -import { Suspense } from 'react' -import { useHostId } from '@/lib/swr' -import { ChartSkeleton } from '@/components/skeletons' -import { YourChart } from '@/components/charts/your-chart' - -export default function YourPage() { - const hostId = useHostId() // Extracts from ?host= query param - - return ( - }> - - - ) -} -``` - -### SWR Data Fetching - -All data uses SWR with the `hostId` pattern: - -```typescript -import useSWR from 'swr' -import { useChartData } from '@/lib/swr/use-chart-data' - -export function YourChart({ hostId }: { hostId: number }) { - const { data, error, isLoading } = useChartData({ - name: 'your-chart-name', - hostId, - interval: 300000, // 5 minutes SWR cache - }) - - if (isLoading) return - if (error) return - // ... render chart with data -} -``` - -### Adding Charts - -1. **Define query** in `lib/api/charts/{domain}-charts.ts`: - -```typescript -export const yourChart: ChartQueryBuilder = (params) => ({ - sql: ` - SELECT toStartOfInterval(event_time, INTERVAL {interval:UInt64} SECOND) AS ts, - COUNT() AS value - FROM system.query_log - WHERE event_time > now() - INTERVAL {lastHours:UInt64} HOUR - GROUP BY ts ORDER BY ts - `, - columns: ["ts", "value"], -}); -``` - -2. **Register** in `lib/api/chart-registry.ts`: - -```typescript -export const chartRegistry = { - // ... - "your-chart-name": yourChart, -}; -``` - -3. **Create component** in `components/charts/`: - -```typescript -"use client"; -import { useChartData } from "@/lib/swr/use-chart-data"; - -export function YourChart({ hostId }: { hostId: number }) { - const { data } = useChartData({ name: "your-chart-name", hostId }); - // Render using Recharts or Tremor -} -``` - -### Query Configuration - -Add table views via `QueryConfig` in `lib/query-config/queries/`: - -```typescript -export const yourConfig: QueryConfig = { - name: "your-query", - description: "Query description", - sql: ` - SELECT database, table, - formatReadableQuantity(sum(rows)) AS total_rows - FROM system.parts - WHERE active - GROUP BY database, table - ORDER BY total_rows DESC - `, - columns: ["database", "table", "total_rows"], - columnFormats: { - database: ColumnFormat.Badge, - total_rows: [ - ColumnFormat.BackgroundBar, - { - base: "rows", - readable: "total_rows", - pct: "pct_rows", - }, - ], - }, -}; -``` - -**BackgroundBar format** requires 3 SQL columns: - -```sql -rows, -- base value -formatReadableQuantity(rows) AS total_rows, -- display -round(rows * 100 / max(rows) OVER (), 2) AS pct_rows -- percentage -``` - -## ClickHouse Compatibility - -### Version-Aware Queries - -ClickHouse system tables change between versions. Use `VersionedSql[]`: - -```typescript -export const yourConfig: QueryConfig = { - name: "your-query", - sql: [ - { since: "23.8", sql: "SELECT col1 FROM system.table" }, - { since: "24.3", sql: "SELECT col1, col2 FROM system.table" }, - ], - columns: ["col1", "col2"], -}; -``` - -The system selects the appropriate query based on detected ClickHouse version. - -### Optional Tables - -Some tables don't exist depending on configuration. Mark as `optional`: - -```typescript -export const backupsConfig: QueryConfig = { - name: "backups", - optional: true, // Graceful handling if table missing - tableCheck: "system.backup_log", - sql: "SELECT * FROM system.backup_log", - // ... -}; -``` - -**Optional tables**: `backup_log`, `error_log`, `zookeeper`, `monitoring_events`. - -## Common Issues - -**Empty charts?** - -- Verify required log tables enabled: `query_log`, `metric_log`, `part_log` -- Check ClickHouse configuration for log settings - -**API returns `table_not_found`?** - -- Optional table missing - verify ClickHouse configuration -- Version mismatch: check the query's `since` versions in `references/clickhouse-compat.md` - -**Multi-host not working?** - -- Verify all three env arrays have same length -- Use comma-separated values: `host1,host2` (not spaces) -- Check each host's credentials individually - -## References - -- [Complete API List](references/api-list.md) - All 58 charts and 63 table endpoints -- [Dashboard Pages](references/dashboard-pages.md) - All 45 dashboard pages with descriptions -- [API Endpoints](references/api-endpoints.md) - Detailed API documentation with examples -- [Development Guide](references/development.md) - Architecture patterns, conventions, contribution workflow -- [ClickHouse Compatibility](references/clickhouse-compat.md) - Version-aware queries, schema docs, optional tables -- [Project Repository](https://github.com/chmonitor/chmonitor) +- Cluster questions. Use the `chmonitor` MCP tools this plugin installs. They read schema, queries, merges, replication, and health. +- Running or deploying it. Read . +- Changing its code. Clone and follow its `AGENTS.md`. diff --git a/chmonitor/skills/chmonitor/references/api-endpoints.md b/chmonitor/skills/chmonitor/references/api-endpoints.md deleted file mode 100644 index 5c70e43..0000000 --- a/chmonitor/skills/chmonitor/references/api-endpoints.md +++ /dev/null @@ -1,481 +0,0 @@ -# API Endpoints Reference - -Complete reference for the ClickHouse Monitor API layer. All endpoints are prefixed with `/api/v1/`. - -## Overview - -The API provides: - -- **Chart data** - Time-series metrics for visualizations -- **Table data** - Paginated query results with filtering -- **Explorer** - Database schema and metadata -- **Host management** - Multi-host configuration - -**Security Note**: API responses include raw SQL queries and database structure for debugging. Do not expose to public internet without authentication. - -## Authentication - -Currently uses hostId-based access control. Configure hosts via environment variables: - -```bash -CLICKHOUSE_HOST=host1.example.com,host2.example.com -CLICKHOUSE_USER=user1,user2 -CLICKHOUSE_PASSWORD=pass1,pass2 -``` - -The `hostId` parameter maps to these arrays (0 = first host, 1 = second, etc.). - -## Response Format - -All endpoints return a consistent `ApiResponse` structure: - -```typescript -interface ApiResponse { - success: boolean; - data?: T; - metadata: { - queryId: string; // Unique execution identifier - duration: number; // Duration in milliseconds - rows: number; // Rows returned - host: string; // Host that executed - clickhouseVersion?: string; - cachedAt?: number; // Timestamp if cached - status?: DataStatus; // 'ok' | 'empty' | 'table_not_found' | etc. - statusMessage?: string; - api?: string; // Full endpoint URL - sql?: string; // Executed SQL - params?: Record; - }; - error?: ApiError; -} -``` - -## Chart Data API - -### GET /api/v1/charts/{name} - -Fetch time-series data for a specific chart. - -**Parameters:** - -- `name` (path) - Chart name from registry -- `hostId` (query) - Host index (required) -- `interval` (query) - Time aggregation: `1m`, `1h`, `1d`, etc. -- `lastHours` (query) - Hours of historical data -- `params` (query) - Chart-specific parameters (JSON-encoded) - -**Example:** - -```bash -curl "http://localhost:3000/api/v1/charts/query-count?hostId=0&interval=1h&lastHours=24" -``` - -**Response:** - -```json -{ - "success": true, - "data": [ - { "ts": "2026-03-05T00:00:00Z", "value": 1234 }, - { "ts": "2026-03-05T01:00:00Z", "value": 1456 } - ], - "metadata": { - "queryId": "q_123456", - "duration": 45, - "rows": 24, - "host": "clickhouse.example.com", - "sql": "SELECT toStartOfTime(event_time) AS ts, COUNT() AS value FROM system.query_log WHERE event_time > now() - INTERVAL 24 HOUR GROUP BY ts ORDER BY ts" - } -} -``` - -### Available Chart Names - -**Query Monitoring:** - -- `query-count` - Total query count over time -- `query-count-by-type` - Queries grouped by type (Select, Insert, etc.) -- `query-duration-p95` - 95th percentile query duration -- `query-duration-p99` - 99th percentile query duration -- `query-memory-usage` - Memory consumption by queries -- `query-read-rows` - Rows read by queries -- `query-written-rows` - Rows written by queries -- `query-cache-hit-rate` - Query cache effectiveness -- `expensive-query-count` - Count of expensive queries - -**Merge Operations:** - -- `merge-count` - Merge operations over time -- `merge-by-reason` - Merges by reason (Regular, TTL, etc.) -- `merge-count-by-part-type` - Merges by part type -- `parts-merged-per-merge` - Average parts per merge -- `merge-rows-read-per-second` - Merge read throughput -- `merge-rows-write-per-second` - Merge write throughput -- `merge-by-table` - Merge count by table - -**System Metrics:** - -- `cpu-usage` - CPU utilization percentage -- `memory-usage` - Memory consumption -- `disk-usage` - Disk space by database -- `network-bytes` - Network bytes transferred -- `connections-http` - HTTP connection count -- `connections-interserver` - Inter-server connection count - -**Replication:** - -- `replication-lag-max` - Maximum replication lag -- `replication-queue-length` - Pending replication tasks -- `replica-has-delay` - Replicas with delays - -**ZooKeeper/Keeper:** - -- `zookeeper-watch-count` - Active watches -- `zookeeper-outstanding-requests` - Outstanding requests - -## Table Data API - -### GET /api/v1/tables/{name} - -Fetch paginated table data for a query config. - -**Parameters:** - -- `name` (path) - Query config name -- `hostId` (query) - Host index (required) -- `pageSize` (query) - Rows per page (default: 50) -- `page` (query) - Page number (default: 1) -- Additional parameters are passed as query params and substituted into SQL - -**Example:** - -```bash -curl "http://localhost:3000/api/v1/tables/running-queries?hostId=0&pageSize=20&page=1" -``` - -**Response:** - -```json -{ - "success": true, - "data": [ - { - "query_id": "abc-123", - "user": "admin", - "query": "SELECT * FROM system.tables", - "elapsed": 1.5, - "readable_elapsed": "1.5 seconds", - "pct_elapsed": 25.5 - } - ], - "metadata": { - "queryId": "t_789012", - "duration": 12, - "rows": 15, - "host": "clickhouse.example.com", - "table": "running-queries" - } -} -``` - -### Available Table Names - -**Query Monitoring:** - -- `running-queries` - Currently executing queries -- `history-queries` - Query execution history -- `failed-queries` - Failed query log -- `common-errors` - Frequent error patterns -- `expensive-queries` - Resource-intensive queries -- `expensive-queries-by-memory` - High memory queries -- `query-cache` - Cache statistics -- `thread-analysis` - Thread-level query breakdown -- `parallelization` - Parallel execution effectiveness - -**Table Management:** - -- `tables-overview` - Table storage statistics -- `replicas` - Replicated table status -- `replication-queue` - Pending replication tasks -- `readonly-tables` - Read-only table status -- `distributed-ddl-queue` - DDL task queue -- `top-usage-tables` - Most accessed tables -- `projections` - Projection definitions -- `view-refreshes` - Materialized view refreshes -- `part-info` - Active part details -- `dictionaries` - External dictionary status - -**Merges:** - -- `merges` - Active merge operations -- `merge-performance` - Historical merge stats -- `mutations` - Mutation status - -**System:** - -- `settings` - Server configuration -- `mergetree-settings` - MergeTree engine settings -- `disks` - Storage disk configuration -- `metrics` - Server metrics -- `asynchronous-metrics` - Background metrics -- `clusters` - Cluster information - -**Security:** - -- `sessions` - User session history -- `login-attempts` - Authentication events - -**Operations:** - -- `backups` - Backup history -- `errors` - Detailed error log -- `page-views` - Dashboard analytics - -**Explorer:** - -- `explorer-databases` - Database list -- `explorer-tables` - Table list by database -- `explorer-columns` - Column metadata -- `explorer-ddl` - Table DDL -- `explorer-dependencies-downstream` - Downstream dependencies -- `explorer-dependencies-upstream` - Upstream dependencies -- `explorer-indexes` - Skip indexes -- `explorer-projections` - Projection metadata - -## Explorer API - -### GET /api/v1/explorer/databases - -List all databases. - -**Response:** - -```json -{ - "success": true, - "data": ["default", "system", "information_schema"], - "metadata": { ... } -} -``` - -### GET /api/v1/explorer/tables - -List tables in a database. - -**Parameters:** - -- `database` (query) - Database name - -### GET /api/v1/explorer/columns - -Get column metadata for a table. - -**Parameters:** - -- `database` (query) - Database name -- `table` (query) - Table name - -### GET /api/v1/explorer/ddl - -Get CREATE TABLE statement. - -**Parameters:** - -- `database` (query) - Database name -- `table` (query) - Table name - -### GET /api/v1/explorer/dependencies - -Get table dependencies (views, dictionaries, etc.). - -**Parameters:** - -- `database` (query) - Database name -- `table` (query) - Table name -- `type` (query) - Dependency type: `all`, `upstream`, `downstream`, `table` - -**Example:** - -```bash -curl "http://localhost:3000/api/v1/explorer/dependencies?database=default&table=my_table&type=all&hostId=0" -``` - -### GET /api/v1/explorer/projections - -Get projection definitions for a table. - -**Parameters:** - -- `database` (query) - Database name -- `table` (query) - Table name - -### GET /api/v1/explorer/indexes - -Get skip index definitions for a table. - -**Parameters:** - -- `database` (query) - Database name -- `table` (query) - Table name - -### GET /api/v1/explorer/preview - -Preview table data. - -**Parameters:** - -- `database` (query) - Database name -- `table` (query) - Table name -- `limit` (query) - Max rows (default: 100) - -## Host Management - -### GET /api/v1/hosts - -List configured hosts. - -**Response:** - -```json -{ - "success": true, - "data": [ - { - "id": 0, - "name": "Production", - "host": "clickhouse-prod.example.com" - }, - { - "id": 1, - "name": "Staging", - "host": "clickhouse-staging.example.com" - } - ], - "metadata": { ... } -} -``` - -### GET /api/v1/host-status - -Get connection status for a host. - -**Parameters:** - -- `hostId` (query) - Host index - -**Response:** - -```json -{ - "success": true, - "data": { - "connected": true, - "version": "24.3.1.1", - "timezone": "UTC" - }, - "metadata": { ... } -} -``` - -## Special Endpoints - -### POST /api/v1/actions - -Execute bulk actions on selected rows. - -**Request:** - -```json -{ - "action": "kill-query", - "hostId": 0, - "keys": ["query-id-1", "query-id-2"] -} -``` - -**Available Actions:** - -- `kill-query` - Terminate running queries -- `explain-query` - Get query execution plan -- `open-in-explorer` - Navigate to table in explorer - -### POST /api/v1/explain - -Get query execution plan. - -**Request:** - -```json -{ - "query": "SELECT * FROM system.tables LIMIT 10", - "hostId": 0, - "type": "AST" // or "PLAN", "PIPELINE" -} -``` - -### GET /api/v1/menu-counts/{key} - -Get count badge for menu items. - -**Available Keys:** - -- `running-queries` - Active query count -- `tables-overview` - Table count -- `merges` - Active merge count -- `replicas` - Replica count -- `dictionaries` - Dictionary count - -## Error Handling - -### Error Types - -```typescript -enum ApiErrorType { - TableNotFound = "table_not_found", - ValidationError = "validation_error", - QueryError = "query_error", - NetworkError = "network_error", - PermissionError = "permission_error", -} -``` - -### Error Response - -```json -{ - "success": false, - "error": { - "type": "table_not_found", - "message": "Table system.backup_log does not exist", - "details": { - "table": "system.backup_log", - "suggestion": "Enable backup logging to see backup history" - } - }, - "metadata": { - "status": "table_not_found", - "statusMessage": "The backup_log table is not configured" - } -} -``` - -### Data Status Values - -- `ok` - Data returned successfully -- `empty` - Query succeeded but no data -- `table_not_configured` - Required log table not enabled -- `table_not_found` - Table does not exist -- `table_empty` - Table exists but contains no data - -## Caching - -The API uses SWR (stale-while-revalidate) caching on the client: - -- Charts refresh every 5 minutes by default -- Manual refresh available via UI -- Stale data displayed with indicator during revalidation - -## See Also - -- [Development Guide](development.md) - API integration patterns -- [ClickHouse Compatibility](clickhouse-compat.md) - Query version handling diff --git a/chmonitor/skills/chmonitor/references/api-list.md b/chmonitor/skills/chmonitor/references/api-list.md deleted file mode 100644 index 2238381..0000000 --- a/chmonitor/skills/chmonitor/references/api-list.md +++ /dev/null @@ -1,167 +0,0 @@ -# API Reference - -This section lists all available API endpoints. Auto-generated from codebase. - -## Chart Data Endpoints - -All chart endpoints follow this pattern: - -```http -GET /api/v1/charts/{chartName}?hostId={hostId}&interval={interval}&lastHours={hours} -``` - -### Available Charts (58 total) - -- `active-sessions-count` -- `backup-size` -- `connections-http` -- `connections-interserver` -- `cpu-time-per-thread` -- `cpu-usage` -- `crash-frequency` -- `dashboard-charts` -- `dashboard-settings` -- `database-count` -- `dictionary-count` -- `disk-size` -- `disk-size-single` -- `disks-usage` -- `error-rate-over-time` -- `failed-login-by-user` -- `failed-query-count` -- `failed-query-count-by-user` -- `human-vs-bot-pageviews` -- `log-count-today` -- `log-level-distribution` -- `login-success-rate` -- `memory-usage` -- `merge-avg-duration` -- `merge-count` -- `merge-sum-read-rows` -- `new-parts-created` -- `page-view` -- `pageviews-by-country` -- `pageviews-by-device` -- `parallelization-efficiency` -- `query-cache` -- `query-cache-usage` -- `query-count` -- `query-count-by-user` -- `query-count-today` -- `query-duration` -- `query-memory` -- `query-type` -- `readonly-replica` -- `replication-lag` -- `replication-queue-count` -- `replication-summary-table` -- `running-queries-count` -- `sessions-by-auth-type` -- `sessions-by-interface` -- `summary-used-by-merges` -- `summary-used-by-mutations` -- `summary-used-by-running-queries` -- `table-count` -- `thread-utilization` -- `top-pages` -- `top-table-size` -- `zookeeper-exception` -- `zookeeper-requests` -- `zookeeper-summary-table` -- `zookeeper-uptime` -- `zookeeper-wait` - -## Table Data Endpoints - -All table endpoints follow this pattern: - -```http -GET /api/v1/tables/{queryConfigName}?hostId={hostId}&pageSize={n}&page={p} -``` - -### Available Table Queries (63 total) - -- `asynchronous-metrics` -- `backups` -- `clusters` -- `clusters-replicas-status` -- `common-errors` -- `count-across-replicas` -- `crash-log` -- `database-disk-space` -- `database-disk-space-by-database` -- `database-table-columns` -- `detached-parts` -- `dictionaries` -- `disk-space` -- `distributed-ddl-queue` -- `errors` -- `expensive-queries` -- `expensive-queries-by-memory` -- `explorer-all-dependencies` -- `explorer-columns` -- `explorer-database-dependencies` -- `explorer-databases` -- `explorer-ddl` -- `explorer-dependencies-downstream` -- `explorer-dependencies-upstream` -- `explorer-dictionary-source` -- `explorer-indexes` -- `explorer-projections` -- `explorer-table-dependencies` -- `explorer-tables` -- `failed-queries` -- `history-queries` -- `login-attempts` -- `merge-performance` -- `merge-tree-settings` -- `merges` -- `metrics` -- `mutations` -- `page-view` -- `page-views` -- `parallelization` -- `part-info` -- `profiler` -- `projections` -- `query-cache` -- `query-detail` -- `read-only-tables` -- `replica-tables` -- `replicas` -- `replication-queue` -- `roles` -- `running-queries` -- `sessions` -- `settings` -- `stack-traces` -- `tables-list` -- `tables-overview` -- `text-log` -- `thread-analysis` -- `top-usage-columns` -- `top-usage-tables` -- `users` -- `view-refreshes` -- `zookeeper` - -## Explorer Endpoints - -```http -GET /api/v1/explorer/databases?hostId={hostId} -GET /api/v1/explorer/tables?hostId={hostId}&database={db} -GET /api/v1/explorer/columns?hostId={hostId}&database={db}&table={t} -GET /api/v1/explorer/dependencies?hostId={hostId}&database={db}&table={t} -GET /api/v1/explorer/ddl?hostId={hostId}&database={db}&table={t} -GET /api/v1/explorer/projections?hostId={hostId}&database={db}&table={t} -GET /api/v1/explorer/indexes?hostId={hostId}&database={db}&table={t} -GET /api/v1/explorer/dictionary-source?hostId={hostId} -``` - -## System Endpoints - -```http -GET /api/v1/hosts # List configured ClickHouse hosts -``` - ---- diff --git a/chmonitor/skills/chmonitor/references/clickhouse-compat.md b/chmonitor/skills/chmonitor/references/clickhouse-compat.md deleted file mode 100644 index febe06f..0000000 --- a/chmonitor/skills/chmonitor/references/clickhouse-compat.md +++ /dev/null @@ -1,411 +0,0 @@ -# ClickHouse Compatibility Guide - -Patterns for writing version-aware queries that work across different ClickHouse versions. - -## Overview - -ClickHouse system tables change between versions. Columns are added, removed, or renamed. The dashboard uses **version-aware queries** to handle these changes gracefully. - -## VersionedSql Pattern - -### Basic Syntax - -```typescript -sql: [ - { since: "23.8", sql: "SELECT col1 FROM system.table" }, - { since: "24.1", sql: "SELECT col1, col2 FROM system.table" }, - { since: "24.3", sql: "SELECT col1, col2, col3 FROM system.table" }, -]; -``` - -**Rules:** - -- Queries are ordered **chronologically** (oldest → newest) -- System selects the **highest `since` version ≤ current version** -- For CH v24.5 → selects `24.3` query (highest ≤ 24.5) -- For CH v23.5 → selects `23.8` query (fallback to oldest) - -### Example: Adding a New Column - -In ClickHouse 24.3, `system.query_log` added a new column `disk_usage`. - -```typescript -export const queryConfig: QueryConfig = { - name: "query-with-disk", - sql: [ - { - since: "23.8", - sql: ` - SELECT - query_id, - user, - query - FROM system.query_log - `, - columns: ["query_id", "user", "query"], - }, - { - since: "24.3", - sql: ` - SELECT - query_id, - user, - query, - disk_usage - FROM system.query_log - `, - columns: ["query_id", "user", "query", "disk_usage"], - }, - ], - columns: ["query_id", "user", "query", "disk_usage"], -}; -``` - -### Example: Type Changes - -Some columns changed from `Int8` to `Enum` between versions. - -```typescript -// system.part_log.event_type changed from Int8 to Enum in v24.3 -export const mergesConfig: QueryConfig = { - name: "merges", - sql: ` - SELECT * - FROM merge('system', '^part_log') - WHERE toInt8(event_type) = 2 -- MergeParts (works for both Int8 and Enum) - AND toInt8(merge_reason) = 1 -- RegularMerge - `, - columns: ["event_time", "event_type", "merge_reason", "database", "table"], -}; -``` - -**Known event_type values:** - -- 1 = NewPart -- 2 = MergeParts -- 3 = DownloadPart -- 4 = RemovePart -- 5 = MutatePart -- 6 = MovePart - -**Known merge_reason values:** - -- 1 = RegularMerge -- 2 = TTLDeleteMerge -- 3 = TTLRecompressMerge - -## Purpose - -Logs all queries executed on the server. - -## Requirements - -Must be enabled in ClickHouse config: - -```xml - - system - query_log
- 1 -
-``` - -## Columns - -| Column | Since | Type | Description | -| ---------- | ----- | -------- | ----------- | -| event_date | all | Date | Event date | -| event_time | all | DateTime | Event time | -| query_id | all | String | Query ID | -| query | all | String | Query text | -| disk_usage | 24.3 | UInt64 | Disk usage | - -````text - -### Regenerating Schema Docs - -To regenerate schema documentation after adding a new version: - -```bash -bun run scripts/build-ch-schema-docs.ts -```` - -## Optional Tables - -Some tables may not exist depending on ClickHouse configuration: - -### Optional Tables List - -| Table | When Available | -| -------------------------- | -------------------------------------- | -| `system.backup_log` | Only when backup is configured | -| `system.error_log` | Requires error logging configuration | -| `system.zookeeper` | Only with ZooKeeper/Keeper enabled | -| `system.monitoring_events` | Custom table created by monitoring app | - -### Marking Queries as Optional - -```typescript -export const backupsConfig: QueryConfig = { - name: "backups", - optional: true, // Don't error if table doesn't exist - tableCheck: "system.backup_log", // Explicit table to check - sql: "SELECT * FROM system.backup_log", - columns: ["name", "status", "start_time"], - suggestion: ` - Enable backup logging to see backup history. - - See: https://clickhouse.com/docs/en/operations/backup - `, -}; -``` - -### Automatic Table Detection - -If `tableCheck` is not provided, the system automatically extracts table names from the SQL query. - -**Handles:** - -- Direct table access: `SELECT * FROM system.tables` -- JOINs: `FROM system.tables AS t JOIN system.columns AS c` -- Subqueries: `WHERE database IN (SELECT database FROM system.databases)` -- CTEs: `WITH tables AS (SELECT * FROM system.tables)` -- EXISTS clauses: `WHERE EXISTS (SELECT 1 FROM system.parts)` - -### Graceful Error Handling - -When an optional table doesn't exist: - -```json -{ - "success": false, - "error": { - "type": "table_not_found", - "message": "Table system.backup_log does not exist" - }, - "metadata": { - "status": "table_not_found", - "statusMessage": "Backup logging is not configured", - "missingTables": ["system.backup_log"] - } -} -``` - -## BackgroundBar Column Format - -For charts and tables with background progress bars, provide **three SQL columns**: - -### Pattern - -```typescript -sql: ` - SELECT - rows, -- Base value - formatReadableQuantity(rows) AS readable_rows, -- Display text - round(rows * 100.0 / max(rows) OVER (), 2) AS pct_rows -- Percentage - FROM system.parts -`, -columns: [ - 'rows', -- Base column (number) - 'readable_rows', -- Readable format (string) - 'pct_rows', -- Percentage (0-100) -] -``` - -### Naming Convention - -```text -{column} → Base value (number) -readable_{column} → Human-readable format -pct_{column} → Percentage for progress bar -``` - -### Examples - -**Disk usage:** - -```sql -disk_size, -formatReadableSize(disk_size) AS readable_disk_size, -round(disk_size * 100.0 / max(disk_size) OVER (), 2) AS pct_disk_size -``` - -**Memory usage:** - -```sql -memory_usage, -formatReadableSize(memory_usage) AS readable_memory_usage, -round(memory_usage * 100.0 / max(memory_usage) OVER (), 2) AS pct_memory_usage -``` - -**Elapsed time:** - -```sql -elapsed, -formatReadableTimeDelta(elapsed) AS readable_elapsed, -round(elapsed * 100.0 / max(elapsed) OVER (), 2) AS pct_elapsed -``` - -### Using in Column Formats - -```typescript -columnFormats: { - readable_rows: ColumnFormat.BackgroundBar, // Uses pct_rows for bar -} -``` - -## Cross-Version Cluster Queries - -### merge() Function - -For cluster-wide queries, use `merge('system', '^table_name')`: - -```typescript -sql: ` - SELECT * - FROM merge('system', '^part_log') - WHERE toInt8(event_type) = 2 -`; -``` - -**This aggregates data from:** - -- `system.part_log` (local) -- `system.part_log_1`, `system.part_log_2`, etc. (replicated) - -### Schema Compatibility Issues - -When using `merge()` across shards with different ClickHouse versions: - -```typescript -// Bad: Fails when shards have different schemas -sql: ` - SELECT event_type - FROM merge('system', '^part_log') - WHERE event_type = 2 -- Fails if event_type is Enum on some shards -`; - -// Good: Use toInt8() for compatibility -sql: ` - SELECT event_type - FROM merge('system', '^part_log') - WHERE toInt8(event_type) = 2 -- Works for both Int8 and Enum -`; -``` - -## Version Detection - -The dashboard automatically detects ClickHouse version on first connection: - -```typescript -// From lib/clickhouse.ts -const version = await client.query({ - query: "SELECT version() AS v", - format: "JSONEachRow", -}); -// Returns: "24.3.1.1" -``` - -This version is cached and used to select appropriate queries from `VersionedSql[]`. - -## Best Practices - -### 1. Check the schema first - -Before writing queries, check the ClickHouse docs for the target system table: - -- Column availability by version -- Type changes -- Query requirements - -### 2. Use toInt8() for Enums - -When filtering on columns that might be Enum or Int8: - -```sql -WHERE toInt8(event_type) = 2 -``` - -### 3. Provide Helpful Suggestions - -For optional tables, include setup instructions: - -```typescript -suggestion: ` - Enable query logging: - - SET log_queries = 1; - SET log_queries_min_type = 'QueryFinish'; - - See: https://clickhouse.com/docs/en/operations/query-log -`; -``` - -### 4. Test Against Multiple Versions - -Test queries against: - -- Oldest supported version (23.8) -- Latest stable version -- Development version - -### 5. Document Breaking Changes - -When adding a new `VersionedSql`, document what changed: - -```typescript -{ - since: '24.3', - description: 'Added disk_usage column', - sql: 'SELECT query_id, disk_usage FROM system.query_log', -} -``` - -## Common Patterns - -### New Column Added - -```typescript -sql: [ - { since: "23.8", sql: "SELECT col1 FROM t" }, - { since: "24.3", sql: "SELECT col1, col2 FROM t" }, // col2 added -]; -``` - -### Column Type Changed - -```typescript -sql: ` - SELECT toInt8(event_type) AS type -- Works for Int8 and Enum - FROM system.part_log -`; -``` - -### Table Renamed/Moved - -```typescript -sql: [ - { since: "23.8", sql: "SELECT * FROM system.old_table" }, - { since: "24.1", sql: "SELECT * FROM system.new_table" }, -]; -``` - -### Query Pattern Changed - -```typescript -sql: [ - { - since: "23.8", - sql: 'SELECT count() FROM system.metrics WHERE name = "Query"', - }, - { - since: "24.3", - sql: 'SELECT sum(value) FROM system.metrics WHERE name LIKE "%Query%"', - }, -]; -``` - -## See Also - -- [API Endpoints Reference](api-endpoints.md) - Using queries in API -- [Development Guide](development.md) - Adding query configs diff --git a/chmonitor/skills/chmonitor/references/dashboard-pages.md b/chmonitor/skills/chmonitor/references/dashboard-pages.md deleted file mode 100644 index 365c5cc..0000000 --- a/chmonitor/skills/chmonitor/references/dashboard-pages.md +++ /dev/null @@ -1,53 +0,0 @@ -# Dashboard Pages - -Complete list of all dashboard pages (45 total). - -| Page | Path | Description | -| -------------------------- | ------------------------------ | ------------------------------------------------------------------------------- | -| **Overview** | `/overview` | Real-time view of currently executing queries with progress tracking | -| **History Queries** | `/history-queries` | Historical query log with execution metrics, memory usage, and performance data | -| **Failed Queries** | `/failed-queries` | Query execution failures with error details and stack traces | -| **Recent Errors** | `/common-errors` | Most frequently occurring errors with timestamps and error messages | -| **Most Expensive Queries** | `/expensive-queries` | Resource-intensive queries ranked by CPU, memory, and duration | -| **Expensive by Memory** | `/expensive-queries-by-memory` | Queries with highest memory consumption for optimization | -| **Explain** | `/explain` | Query execution plan analysis for performance tuning | -| **Query Cache** | `/query-cache` | Cache hit/miss statistics and performance impact | -| **Thread Analysis** | `/queries/thread-analysis` | Thread-level query performance breakdown and parallelization | -| **Parallelization** | `/queries/parallelization` | Parallel query execution effectiveness and thread utilization | -| **Tables** | `/tables` | Interactive database schema browser with metadata | -| **Tables Overview** | `/tables-overview` | Table storage statistics with part counts and sizes | -| **DDL Queue** | `/distributed-ddl-queue` | Cluster-wide DDL task queue status and execution history | -| **Table Replicas** | `/replicas` | Replicated table health status and lag metrics | -| **Replication Queue** | `/replication-queue` | Pending and in-progress replication tasks from Keeper/ZooKeeper | -| **Readonly Tables** | `/readonly-tables` | Tables in read-only mode with replica status | -| **Top Usage Tables** | `/top-usage-tables` | Table access frequency for identifying hot data | -| **Projections** | `/projections` | Projection definitions and usage statistics | -| **View Refreshes** | `/view-refreshes` | Materialized view refresh schedules and execution history | -| **Part Info** | `/part-info` | Active part details with levels and sizes | -| **Dictionaries** | `/dictionaries` | External dictionary status and memory usage | -| **Merges** | `/merges` | Active merge and mutation operations with progress | -| **Merge Performance** | `/merge-performance` | Historical merge operation statistics and trends | -| **Mutations** | `/mutations` | Table mutation status with progress and failures | -| **Monitoring** | `/metrics` | Real-time server metrics and counters | -| **Async Metrics** | `/asynchronous-metrics` | Background-calculated metrics for resource monitoring | -| **Custom Dashboard** | `/dashboard` | Build custom monitoring dashboards with charts | -| **Profiler** | `/profiler` | CPU profiling data for query performance analysis | -| **Security** | `/security/sessions` | User session history with authentication details | -| **Login Attempts** | `/security/login-attempts` | Authentication events with failure reasons | -| **Audit Log** | `/security/audit-log` | Security-related events and access control | -| **Logs** | `/logs/text-log` | Server logs with query context and stack traces | -| **Stack Traces** | `/logs/stack-traces` | Live thread stack traces for debugging | -| **Crashes** | `/logs/crashes` | Historical crash reports with diagnostics | -| **System** | `/settings` | Server configuration settings and current values | -| **MergeTree Settings** | `/mergetree-settings` | MergeTree engine-specific settings | -| **Disks** | `/disks` | Storage disk configuration and usage | -| **Cluster** | `/clusters` | Cluster configuration and member information | -| **Zookeeper** | `/zookeeper?path=/` | ZooKeeper/Keeper data browser for distributed coordination | -| **Operations** | `/backups` | Backup operation history with status and sizes | -| **Errors** | `/errors` | Detailed error events with stack traces | -| **Page Views** | `/page-views` | Dashboard usage analytics | -| **About** | `/about` | Dashboard and server version information | -| **Queries** | `/running-queries` | | -| **Data Explorer** | `/explorer` | | - ---- diff --git a/chmonitor/skills/chmonitor/references/development.md b/chmonitor/skills/chmonitor/references/development.md deleted file mode 100644 index e3ee156..0000000 --- a/chmonitor/skills/chmonitor/references/development.md +++ /dev/null @@ -1,253 +0,0 @@ -# Development Guide - -Patterns and conventions for contributing to the ClickHouse Monitor dashboard. - -## Architecture Overview - -### Static Site Design - -**Critical**: This is a **fully static site** with no server-side rendering. All pages use client-side data fetching via SWR. - -**Implications:** - -- No `use server()` directives -- No `redirect()` from next/navigation - use `useRouter` + `useEffect` -- All data fetching happens client-side -- Better CDN caching and edge deployment - -### Routing Pattern - -**Old (Don't Use):** - -```text -app/[host]/overview/page.tsx → Dynamic route -URL: /0/overview -``` - -**New (Use This):** - -```text -app/overview/page.tsx → Static route -URL: /overview?host=0 -``` - -**Benefits:** - -- Faster initial page load (static shell pre-rendered) -- Better CDN caching -- Simpler deployment -- Progressive data loading - -### Project Structure - -```text -app/ -├── api/v1/ # API routes for data fetching -│ ├── data/ # Generic query endpoint -│ ├── charts/[name]/ # Chart-specific data -│ ├── tables/[name]/ # Table data with pagination -│ ├── explorer/ # Data explorer API -│ └── hosts/ # Host configuration -├── overview/ # Static pages with ?host= query param -├── dashboard/ -├── explorer/ -└── running-queries/ - -components/ -├── data-table/ # Advanced table system -├── charts/ # Chart components (32+) -├── overview-charts/ # Overview page charts -└── ui/ # shadcn/ui components (DO NOT MODIFY) - -lib/ -├── api/ -│ ├── types.ts # API request/response types -│ ├── chart-registry.ts # Chart query registry -│ └── table-registry.ts # Table query registry -├── swr/ -│ ├── provider.tsx # SWR configuration -│ ├── use-host.ts # Extract hostId from query params -│ ├── use-chart-data.ts # Chart data fetching -│ └── use-table-data.ts # Table data fetching -├── query-config/ # Centralized query configurations -├── clickhouse.ts # ClickHouse client -└── charts/ # Chart query definitions -``` - -## SWR Data Fetching Pattern - -### The Standard Pattern - -**All client components that fetch data follow this pattern:** - -```typescript -'use client' -import { Suspense } from 'react' -import { useHostId } from '@/lib/swr' -import { ChartSkeleton } from '@/components/skeletons' -import { YourChart } from '@/components/charts/your-chart' - -export default function YourPage() { - const hostId = useHostId() // Extracts ?host= from URL - - return ( - }> - - - ) -} -``` - -### Chart Component Template - -```typescript -'use client' -import useSWR from 'swr' -import { useChartData } from '@/lib/swr/use-chart-data' -import { ChartSkeleton } from '@/components/skeletons' -import { ChartError } from '@/components/error-alert' - -interface YourChartProps { - hostId: number - interval?: number -} - -export function YourChart({ hostId, interval = 300000 }: YourChartProps) { - const { data, error, isLoading } = useChartData({ - name: 'your-chart-name', - hostId, - interval, - }) - - if (isLoading) return - if (error) return - if (!data || data.length === 0) return
No data available
- - // Render chart using recharts, tremor, or custom - return
{/* Chart rendering */}
-} -``` - -### useChartData Hook - -```typescript -const { data, error, isLoading } = useChartData({ - name: "chart-name", // From chart registry - hostId: 0, // Required - interval: 300000, // Refresh interval (ms) - lastHours: 24, // For historical charts - params: { - // Optional chart params - database: "default", - }, -}); -``` - -### useTableData Hook - -```typescript -const { data, error, isLoading } = useTableData({ - queryConfigName: "running-queries", - hostId: 0, - searchParams: { - pageSize: "50", - page: "1", - }, -}); -``` - -## Adding a New Route - -### Step 1. Create Page Component - -Create `app/your-route/page.tsx`: - -```typescript -'use client' - -import { Suspense } from 'react' -import { useHostId } from '@/lib/swr' -import { ChartSkeleton, TableSkeleton } from '@/components/skeletons' -import { RelatedCharts, Table } from '@/components' - -export default function YourRoutePage() { - const hostId = useHostId() - - return ( -
- }> - - - }> - - - - ) -} -``` - -### Step 2. Add Menu Item - -Edit `menu.ts`: - -```typescript -{ - title: 'Your Route', - href: '/your-route', - description: 'Your route description', - icon: YourIcon, - countKey: 'your-count', - countLabel: 'items', -} -``` - -### Step 3. Create Query Config (if needed) - -Add to `lib/query-config/`: - -```typescript -export const yourConfig: QueryConfig = { - name: "your-query", - description: "Query description", - sql: "SELECT database, table FROM system.parts", - columns: ["database", "table"], - columnFormats: { - database: ColumnFormat.Badge, - table: ColumnFormat.Text, - }, -}; -``` - -## Troubleshooting Development - -### Common Issues - -**Build fails with TypeScript errors:** - -- Check `bun run build` output -- Fix type errors in indicated files -- Ensure imports are correct - -**SWR not refetching:** - -- Check `interval` is set correctly -- Verify API endpoint returns data -- Check network tab for failed requests - -**Charts show "No data available":** - -- Verify ClickHouse table exists and has data -- Check query is valid for ClickHouse version - -**Multi-host not working:** - -- Verify all environment arrays have same length -- Check `CLICKHOUSE_HOST`, `CLICKHOUSE_USER`, `CLICKHOUSE_PASSWORD` -- Use comma-separated values diff --git a/clickhouse/README.md b/clickhouse/README.md index 921c8d0..e57b04a 100644 --- a/clickhouse/README.md +++ b/clickhouse/README.md @@ -1,6 +1,6 @@ # clickhouse -ClickHouse review guidance for schemas, queries, and inserts, built around 28 atomic rules. +ClickHouse review checklist for schemas, queries, and inserts. ## Install @@ -10,8 +10,4 @@ ClickHouse review guidance for schemas, queries, and inserts, built around 28 at ## What ships -- `skills/clickhouse/SKILL.md`: decision tree that routes a review to the right rules. -- `skills/clickhouse/rules/`: 28 rules with incorrect and correct examples, grouped by schema, query, and insert. -- `skills/clickhouse/references/`: schema design, query optimization, debugging, and monitoring queries. - -Rules are synced from [ClickHouse/agent-skills](https://github.com/ClickHouse/agent-skills) (Apache-2.0). +- `skills/clickhouse/SKILL.md`: 28-rule review checklist, cited by rule name. diff --git a/clickhouse/skills/clickhouse/SKILL.md b/clickhouse/skills/clickhouse/SKILL.md index 2e0ed60..16c7fb5 100644 --- a/clickhouse/skills/clickhouse/SKILL.md +++ b/clickhouse/skills/clickhouse/SKILL.md @@ -1,70 +1,51 @@ --- name: clickhouse -description: Use when reviewing or writing ClickHouse schemas, queries, inserts, or operations. Check the matching rule files in rules/ first and cite them by name in your answer. +description: Use when reviewing or writing ClickHouse schemas, queries, inserts, or operations. Check the checklist below and cite rules by name. --- # ClickHouse -ClickHouse behaves differently from row-store databases (sparse primary index, immutable parts, background merges), so general database habits mislead. The 28 files in `rules/` encode the validated guidance. Read the relevant ones before recommending anything, and cite each as "Per `rule-name`". - -Order of sources: `rules/`, then `references/`, then the official docs. Say which one you used. - -Never put real credentials in examples. Use environment variables, a secret manager, or named collections. - -## Which rules to read - -### Schema review (CREATE TABLE, ALTER TABLE) - -- ORDER BY and primary key: `schema-pk-plan-before-creation`, `schema-pk-cardinality-order`, `schema-pk-prioritize-filters`, `schema-pk-filter-on-orderby`. ORDER BY cannot be changed after creation. -- Types: `schema-types-native-types`, `schema-types-minimize-bitwidth`, `schema-types-lowcardinality`, `schema-types-avoid-nullable`, `schema-types-enum`. -- Partitioning: `schema-partition-start-without`, `schema-partition-low-cardinality`, `schema-partition-lifecycle`, `schema-partition-query-tradeoffs`. -- JSON columns: `schema-json-when-to-use`. - -### Query review (SELECT, JOIN, aggregation) - -- Joins: `query-join-choose-algorithm`, `query-join-use-any`, `query-join-filter-before`, `query-join-consider-alternatives`, `query-join-null-handling`. -- Filters on non-key columns: `query-index-skipping-indices`. -- Precomputation: `query-mv-incremental`, `query-mv-refreshable`. - -### Insert and update review - -- Batching: `insert-batch-size` (10K to 100K rows), `insert-async-small-batches`, `insert-format-native`. -- Changes to existing rows: `insert-mutation-avoid-update`, `insert-mutation-avoid-delete`. -- Merges: `insert-optimize-avoid-final`. - -`rules/_sections.md` lists the categories by impact. CRITICAL rules (primary key, types, joins, batching, mutations) come first. - -## Table engine choice - -```text -Small dimension table (under 1M rows)? Memory or MergeTree -Otherwise MergeTree family -├── Deduplicate by key ReplacingMergeTree(version) -├── Cancel rows with a sign CollapsingMergeTree(sign) -├── Pre-aggregate AggregatingMergeTree -├── Replicated cluster Replicated* variant of the above -└── Default MergeTree -``` - -## Common symptoms - -| Symptom | First step | -| --------------- | ---------------------------------------------------------------------------------------------------------------------------- | -| Too many parts | Fix insert batching (`insert-batch-size`). Do not run `OPTIMIZE ... FINAL` as a routine fix (`insert-optimize-avoid-final`). | -| Slow query | `EXPLAIN indexes = 1` to check whether the key prefix is used | -| Stuck mutation | Check `system.mutations`, then see `insert-mutation-avoid-update` | -| Replication lag | Check `system.replication_queue` and Keeper health | -| Out of memory | Reduce data read first, then tune `max_memory_usage` | - -## References - -- `references/schema-design.md` for ORDER BY patterns, partition operations, codecs, skip indexes, and migrations. -- `references/query-optimization.md` for EXPLAIN, join tuning, projections. -- `references/debugging.md` for query, merge, mutation, and replication troubleshooting. -- `references/monitoring.md` for ready-to-use `system.*` queries, alerting, and Prometheus. - -## Review output - -List each rule checked as compliant or violated. For each violation give the current state, the required state, and the fix. End with prioritized recommendations that cite rules. - -Rules are synced from [ClickHouse/agent-skills](https://github.com/ClickHouse/agent-skills) (Apache-2.0). +ClickHouse has a sparse primary index, immutable parts, and background merges, so row-store habits mislead. Details: . Never put real credentials in examples. + +Review output: list each rule checked as compliant or violated, cite as "Per `rule-name`", give current state, required state, and fix. End with prioritized recommendations. + +## Review checklist + +Schema, ORDER BY cannot change after creation: + +- `schema-pk-plan-before-creation`: decide ORDER BY before creating the table. +- `schema-pk-cardinality-order`: order key columns low to high cardinality. +- `schema-pk-prioritize-filters`: put frequently filtered columns in ORDER BY. +- `schema-pk-filter-on-orderby`: queries filter on the ORDER BY prefix. +- `schema-types-native-types`: use native types, not String. +- `schema-types-minimize-bitwidth`: smallest numeric width that fits. +- `schema-types-lowcardinality`: LowCardinality for repeated strings under about 10K values. +- `schema-types-avoid-nullable`: avoid Nullable, use defaults. +- `schema-types-enum`: Enum for finite value sets. +- `schema-partition-start-without`: start without partitioning. +- `schema-partition-low-cardinality`: 100 to 1,000 partitions at most. +- `schema-partition-lifecycle`: partition for data lifecycle, drop partitions instead of DELETE. +- `schema-partition-query-tradeoffs`: queries spanning many partitions get slower. +- `schema-json-when-to-use`: JSON type only for dynamic schemas, typed columns otherwise. + +Queries: + +- `query-join-choose-algorithm`: pick the join algorithm for table size to avoid OOM. +- `query-join-use-any`: ANY JOIN when one match is enough. +- `query-join-filter-before`: filter both sides before joining. +- `query-join-consider-alternatives`: dictionaries or denormalization instead of joins. +- `query-join-null-handling`: default values instead of NULL in outer joins. +- `query-index-skipping-indices`: skipping indices for non-ORDER BY filters. +- `query-mv-incremental`: incremental materialized views for real-time aggregation. +- `query-mv-refreshable`: refreshable materialized views for complex joins and batch. + +Inserts and changes: + +- `insert-batch-size`: batch 10K to 100K rows per insert. +- `insert-async-small-batches`: async inserts when client batching is impractical. +- `insert-format-native`: Native format over JSONEachRow. +- `insert-mutation-avoid-update`: no ALTER UPDATE, use ReplacingMergeTree. +- `insert-mutation-avoid-delete`: no ALTER DELETE, use lightweight DELETE, CollapsingMergeTree, or DROP PARTITION. +- `insert-optimize-avoid-final`: no routine `OPTIMIZE ... FINAL` or `FINAL` reads. + +Rules derive from [ClickHouse/agent-skills](https://github.com/ClickHouse/agent-skills) (Apache-2.0). diff --git a/clickhouse/skills/clickhouse/references/debugging.md b/clickhouse/skills/clickhouse/references/debugging.md deleted file mode 100644 index 995e6b4..0000000 --- a/clickhouse/skills/clickhouse/references/debugging.md +++ /dev/null @@ -1,400 +0,0 @@ -# ClickHouse Debugging - -Query debugging, merge issues, mutations, replication problems, and troubleshooting. - -## Query Debugging - -### Enable Query Log - -```sql --- Check if enabled -SELECT * FROM system.settings -WHERE name = 'log_queries'; - --- Enable query logging -SYSTEM STOP DISTRIBUTED SENDS query_log; -ALTER TABLE system.query_log MODIFY TTL query_start_time + INTERVAL 30 DAY; -SYSTEM START DISTRIBUTED SENDS query_log; -``` - -### Analyze Slow Queries - -```sql --- Find slow queries -SELECT - query, - query_duration_ms / 1000 as seconds, - memory_usage, - read_rows, - read_bytes -FROM system.query_log -WHERE type = 'QueryFinish' - AND query_duration_ms > 1000 -ORDER BY query_duration_ms DESC -LIMIT 10; - --- Find expensive queries by memory -SELECT - query, - formatReadableSize(memory_usage) as memory, - query_duration_ms -FROM system.query_log -WHERE type = 'QueryFinish' -ORDER BY memory_usage DESC -LIMIT 10; -``` - -### Check Query Plan - -```sql -EXPLAIN SELECT * FROM events WHERE user_id = 123; - --- Readable query plan -EXPLAIN PLAN SELECT * FROM events WHERE user_id = 123; - --- Pipeline details -EXPLAIN PIPELINE SELECT * FROM events WHERE user_id = 123; - --- With estimates -EXPLAIN ESTIMATE SELECT * FROM events WHERE user_id = 123; -``` - -**Key indicators:** - -- `"Filter"` → Not using index (full scan) -- `"Index"` → Using index marks -- `"Projection"` → Pre-computed data -- `"Filter with index"` → Using skip index - -### Debug Hanging Queries - -```sql --- Show running queries -SELECT - query_id, - user, - query, - elapsed, - memory_usage, - read_rows -FROM system.processes -WHERE elapsed > 10 -ORDER BY elapsed DESC; - --- Kill query -KILL QUERY WHERE query_id = 'query-id'; - --- Cancel mutation -KILL MUTATION WHERE mutation_id = 'mutation-id'; -``` - -## Merge Debugging - -### Active Merges - -```sql --- Active merges -SELECT - database, - table, - elapsed, - progress, - bytes_read_uncompressed, - rows_read, - is_mutation -FROM system.merges -ORDER BY elapsed DESC; - --- Merge performance by day -SELECT - table, - count() as merge_count, - avg(bytes_read_uncompressed) as avg_size, - sum(rows_read) as total_rows -FROM system.merges -WHERE event_date = today() -GROUP BY table -ORDER BY merge_count DESC; -``` - -### Merge Queue Size - -```sql --- Tables with too many parts (need optimization) -SELECT - database, - table, - count() as parts, - sum(rows) as total_rows -FROM system.parts -WHERE active = 1 -GROUP BY database, table -HAVING parts > 1000 -ORDER BY parts DESC; -``` - -### Common Merge Issues - -| Issue | Symptom | Solution | -| ----------------- | ------------------------- | ------------------------------------------------------------------------- | -| Too many parts | Slow queries, high memory | `OPTIMIZE TABLE table FINAL` | -| Slow merges | High CPU, disk usage | Reduce insert frequency, increase `max_bytes_to_merge_at_max_space_usage` | -| Merge bottleneck | Queries slow | Check `background_pool` settings | -| Parts not merging | Parts count increasing | Check `max_bytes_to_merge_at_once` | - -## Mutation Debugging - -### Show Mutations - -```sql --- All mutations -SELECT * FROM system.mutations; - --- Active mutations -SELECT - database, - table, - command, - is_done, - parts_to_do, - parts_to_do_names -FROM system.mutations -WHERE is_done = 0; -``` - -### Mutation Progress - -```sql --- Mutation progress details -SELECT - table, - command, - is_done, - parts_to_do - parts_to_do_names as parts_remaining, - elapsed, - formatReadableSize(bytes_read_uncompressed) as bytes_processed -FROM system.mutations -WHERE is_done = 0 -ORDER BY parts_to_do DESC; -``` - -### Common Mutation Issues - -| Issue | Symptom | Solution | -| --------------- | -------------------------------- | ------------------------------------------------------- | -| Mutation stuck | `is_done = 0` for long time | Check `system.merges`, use `OPTIMIZE FINAL` | -| Slow mutation | Low `parts_to_do_names` progress | Reduce concurrent mutations, increase `background_pool` | -| Mutation failed | `is_fail = 1` | Check `exception_text`, fix issue, retry | - -## Replication Debugging - -### Replication Status - -```sql --- All replicas -SELECT - database, - table, - is_leader, - is_readonly, - queue_size, - absolute_delay -FROM system.replicas -ORDER BY absolute_delay DESC; - --- Replication queue -SELECT * FROM system.replication_queue -WHERE delay > 5 -ORDER BY delay DESC; -``` - -### ZooKeeper Health - -```sql --- ZooKeeper connection -SELECT * FROM system.zookeeper WHERE path = '/'; - --- Check ZK queue -SELECT count() FROM system.zookeeper -WHERE path = '/clickhouse/queues'; - --- ZK exceptions -SELECT * FROM system.zookeeper_log -WHERE type = 'ERROR' -ORDER BY event_time DESC -LIMIT 10; -``` - -### Common Replication Issues - -| Issue | Symptom | Solution | -| ------------------ | ----------------------- | ------------------------------------------- | -| Replication lag | `absolute_delay > 5` | Check network, ZooKeeper, disk I/O | -| ZK connection lost | `is_readonly = 1` | Check ZooKeeper, increase `session_timeout` | -| Queue growing | `queue_size` increasing | Check merge performance, reduce insert rate | -| ZK expired | Cluster down | Check ZK connection, restart ClickHouse | - -## Data Issues - -### Check Parts Count - -```sql --- Parts per partition -SELECT - partition, - count() as parts, - sum(rows) as total_rows -FROM system.parts -WHERE active = 1 - AND table = 'my_table' -GROUP BY partition -HAVING parts > 1000 -ORDER BY parts DESC; -``` - -### Check for Duplicates - -```sql --- Check for duplicates in ReplacingMergeTree -SELECT - user_id, - count() as cnt -FROM ReplacingMergeTree_table -GROUP BY user_id -HAVING cnt > 1; -``` - -### Data Distribution - -```sql --- Data skew -SELECT - user_id, - count() as cnt -FROM events -GROUP BY user_id -ORDER BY cnt DESC -LIMIT 10; -``` - -## Common Issues & Solutions - -### Issue: Too Many Parts - -**Symptoms:** - -- Slow queries -- High memory usage -- Large merge queue - -**Solutions:** - -```sql --- Force merge -OPTIMIZE TABLE table FINAL; - --- Check partitioning -SELECT partition, count() as parts -FROM system.parts -WHERE active = 1 AND table = 'my_table' -GROUP BY partition; - --- Consider larger partitions --- Monthly instead of daily -``` - -### Issue: Mutation Stuck - -**Symptoms:** - -- `ALTER UPDATE/DELETE` not completing -- `is_done = 0` in `system.mutations` - -**Solutions:** - -```sql --- Check mutation progress -SELECT * FROM system.mutations WHERE is_done = 0; - --- Cancel and retry -KILL MUTATION WHERE mutation_id = '...'; - --- Force with OPTIMIZE -OPTIMIZE TABLE table FINAL; -``` - -### Issue: OOM on Queries - -**Symptoms:** - -- Query killed with memory limit -- `"Memory limit exceeded"` error - -**Solutions:** - -```sql --- Increase memory limit -SET max_memory_usage = 10000000000; - --- Optimize query --- - Select fewer columns --- - Add filters --- - Use SAMPLE - --- Check query memory usage -SELECT - query, - formatReadableSize(memory_usage) as memory -FROM system.query_log -WHERE type = 'QueryFinish' -ORDER BY memory_usage DESC -LIMIT 10; -``` - -### Issue: Replication Lag - -**Symptoms:** - -- Data not replicating -- High `absolute_delay` in `system.replicas` - -**Solutions:** - -```sql --- Check replication queue -SELECT * FROM system.replication_queue; - --- Check ZooKeeper -SELECT * FROM system.zookeeper WHERE path = '/clickhouse/tables'; - --- Check network/disk --- Verify connectivity between replicas --- Check disk I/O performance -``` - -## Debugging Workflow - -1. **Identify the problem** - - Query slow? Check `system.processes` - - Data missing? Check replication status - - High memory? Check `system.query_log` - -2. **Gather information** - - Use `EXPLAIN` for query plans - - Check `system.merges` for merge issues - - Check `system.mutations` for mutation progress - -3. **Apply fixes** - - `OPTIMIZE TABLE` for merge issues - - Adjust settings for performance - - Fix network/ZooKeeper for replication - -4. **Verify** - - Re-run query - - Check metrics again - - Monitor for recurrence - -## See Also - -- `../SKILL.md` - Main skill entry point -- `monitoring.md` - Health checks and monitoring queries diff --git a/clickhouse/skills/clickhouse/references/monitoring.md b/clickhouse/skills/clickhouse/references/monitoring.md deleted file mode 100644 index 916041b..0000000 --- a/clickhouse/skills/clickhouse/references/monitoring.md +++ /dev/null @@ -1,710 +0,0 @@ -# ClickHouse Monitoring - -Query monitoring, health checks, system queries, and metrics. Ready-to-use queries against `system.*` tables. - -## Current Query Monitoring - -### Running Queries - -```sql --- All running queries -SELECT - query_id, - user, - query, - elapsed, - formatReadableSize(memory_usage) as memory, - formatReadableQuantity(read_rows) as rows_read, - formatReadableSize(read_bytes) as bytes_read -FROM system.processes -ORDER BY elapsed DESC; - --- Long-running queries (> 1 minute) -SELECT - query_id, - user, - query, - elapsed / 60 as minutes_elapsed, - formatReadableSize(memory_usage) as memory -FROM system.processes -WHERE elapsed > 60 -ORDER BY elapsed DESC; - --- Queries by user -SELECT - user, - count() as query_count, - sum(memory_usage) as total_memory -FROM system.processes -GROUP BY user -ORDER BY total_memory DESC; -``` - -### Kill Query - -```sql --- Kill specific query -KILL QUERY WHERE query_id = 'query-id'; - --- Kill all queries from user -KILL QUERY WHERE user = 'username'; - --- Kill long-running queries -KILL QUERY WHERE elapsed > 3600; -``` - -## Query History - -### Recent Queries - -```sql --- Recent queries (last hour) -SELECT - type, - substring(query, 1, 100) as query_preview, - query_duration_ms / 1000 as seconds, - formatReadableSize(memory_usage) as memory, - event_time -FROM system.query_log -WHERE event_time > now() - INTERVAL 1 HOUR -ORDER BY event_time DESC -LIMIT 100; -``` - -### Slow Queries - -```sql --- Slow queries (> 5 seconds) -SELECT - query, - query_duration_ms / 1000 as seconds, - formatReadableSize(memory_usage) as memory, - formatReadableQuantity(read_rows) as rows_read, - event_time -FROM system.query_log -WHERE type = 'QueryFinish' - AND query_duration_ms > 5000 -ORDER BY query_duration_ms DESC -LIMIT 20; -``` - -### Failed Queries - -```sql --- Failed queries with errors -SELECT - query, - exception_code, - exception_text, - event_time -FROM system.query_log -WHERE type = 'Exception' - AND event_time > now() - INTERVAL 1 DAY -ORDER BY event_time DESC -LIMIT 50; -``` - -## Table Usage - -### Most Accessed Tables - -```sql --- Most queried tables -SELECT - database, - table, - count() as query_count, - sum(read_rows) as total_rows, - avg(query_duration_ms) as avg_duration_ms -FROM system.query_log -WHERE type = 'QueryFinish' - AND event_date = today() -GROUP BY database, table -ORDER BY query_count DESC -LIMIT 20; -``` - -### Table Sizes - -```sql --- Tables by size -SELECT - database, - table, - formatReadableSize(sum(bytes)) as size, - sum(rows) as total_rows, - count() as parts -FROM system.parts -WHERE active = 1 -GROUP BY database, table -ORDER BY sum(bytes) DESC -LIMIT 20; -``` - -### Column Compression - -```sql --- Column compression ratios -SELECT - database, - table, - column, - type, - formatReadableSize(sum(data_uncompressed_bytes)) as uncompressed, - formatReadableSize(sum(data_compressed_bytes)) as compressed, - sum(data_compressed_bytes) / sum(data_uncompressed_bytes) as ratio -FROM system.columns -WHERE database != 'system' -GROUP BY database, table, column, type -ORDER BY sum(data_uncompressed_bytes) DESC -LIMIT 50; -``` - -## Merge Monitoring - -### Active Merges - -```sql --- Current merges -SELECT - database, - table, - elapsed, - progress, - formatReadableSize(bytes_read_uncompressed) as bytes_read, - rows_read, - is_mutation, - merge_type -FROM system.merges -ORDER BY elapsed DESC; -``` - -### Merge Performance - -```sql --- Merge performance by day -SELECT - table, - count() as merge_count, - avg(bytes_read_uncompressed) as avg_size, - sum(rows_read) as total_rows -FROM system.merges -WHERE event_date = today() -GROUP BY table -ORDER BY merge_count DESC; -``` - -### Merge Queue - -```sql --- Tables needing optimization -SELECT - database, - table, - count() as parts, - sum(rows) as total_rows -FROM system.parts -WHERE active = 1 -GROUP BY database, table -HAVING parts > 1000 -ORDER BY parts DESC; -``` - -## Mutation Monitoring - -```sql --- Active mutations -SELECT - database, - table, - command, - is_done, - parts_to_do, - parts_to_do_names, - formatReadableSize(bytes_read_uncompressed) as bytes_processed -FROM system.mutations -WHERE is_done = 0; - --- Mutation history -SELECT - table, - command, - is_done, - created_at, - finished_at -FROM system.mutations -ORDER BY created_at DESC -LIMIT 50; -``` - -## Cluster Health - -### Basic Health - -```sql --- Quick health check -SELECT - 'uptime' as metric, - toString(uptime()) as value -UNION ALL -SELECT 'version', version() -UNION ALL -SELECT 'running_queries', toString(count()) -FROM system.processes -UNION ALL -SELECT 'active_merges', toString(count()) -FROM system.merges -UNION ALL -SELECT 'mutations_running', toString(count()) -FROM system.mutations WHERE is_done = 0; -``` - -### Cluster Status - -```sql --- Cluster nodes -SELECT - cluster, - shard_num, - replica_num, - host_name, - port, - user -FROM system.clusters -WHERE cluster = 'my_cluster'; -``` - -### Replica Status - -```sql --- All replicas -SELECT - database, - table, - is_leader, - is_readonly, - queue_size, - absolute_delay -FROM system.replicas -ORDER BY absolute_delay DESC; -``` - -### Replication Lag - -```sql --- Lagging replicas -SELECT - database, - table, - replica_name, - is_leader, - is_readonly, - queue_size, - delay * 1000 as lag_ms -FROM system.replication_queue -WHERE delay > 5 -ORDER BY delay DESC; -``` - -## Disk and Memory Health - -### Disk Usage - -```sql --- All disks -SELECT - name, - path, - formatReadableSize(free_space) as free, - formatReadableSize(total_space) as total, - formatReadableSize(keep_free_space) as keep_free, - (free_space / total_space) * 100 as percent_free -FROM system.disks; -``` - -### Memory Usage - -```sql --- Memory by dictionaries -SELECT - formatReadableSize(sum(bytes_allocated)) as allocated, - formatReadableSize(sum(bytes_used)) as used -FROM system.dictionaries; - --- Current memory metrics -SELECT - formatReadableSize(os_userspace_memory) as userspace, - formatReadableSize(os_committed_memory) as committed -FROM system.asynchronous_metrics -WHERE metric LIKE '%memory%'; -``` - -## Performance Metrics - -### Query Statistics - -```sql --- Query statistics by type -SELECT - type, - count() as count, - avg(query_duration_ms) as avg_duration_ms -FROM system.query_log -WHERE event_date = today() -GROUP BY type -ORDER BY count DESC; -``` - -### Top Consumers - -```sql --- Most memory-intensive queries -SELECT - query, - formatReadableSize(memory_usage) as memory, - query_duration_ms / 1000 as seconds -FROM system.query_log -WHERE type = 'QueryFinish' - AND event_date = today() -ORDER BY memory_usage DESC -LIMIT 10; - --- Most row-intensive queries -SELECT - query, - formatReadableQuantity(read_rows) as rows_read, - query_duration_ms / 1000 as seconds -FROM system.query_log -WHERE type = 'QueryFinish' - AND event_date = today() -ORDER BY read_rows DESC -LIMIT 10; -``` - -## Alerting Queries - -### Critical Alerts - -```sql --- Replicas lagging > 30s -SELECT - 'CRITICAL: Replication lag' as alert, - database, - table, - delay as lag_seconds -FROM system.replication_queue -WHERE delay > 30; - --- Too many parts -SELECT - 'WARNING: Too many parts' as alert, - database, - table, - count() as parts -FROM system.parts -WHERE active = 1 -GROUP BY database, table -HAVING parts > 5000; - --- Long-running queries -SELECT - 'WARNING: Long-running query' as alert, - query_id, - elapsed / 60 as minutes, - substring(query, 1, 100) as query_preview -FROM system.processes -WHERE elapsed > 1800; -- 30 minutes -``` - -## Asynchronous Metrics - -```sql --- System metrics -SELECT - metric, - formatReadableSize(value) as value -FROM system.asynchronous_metrics -WHERE metric LIKE '%bytes%' -ORDER BY metric; - --- Load average -SELECT - metric, - value -FROM system.asynchronous_metrics -WHERE metric LIKE '%load%'; -``` - -## Prometheus Integration - -### Export Metrics - -```sql --- ClickHouse exposes metrics on port 9363 -# Enable in config.xml - - /metrics - 9363 - - -# Scrape config -scrape_configs: - - job_name: 'clickhouse' - static_configs: - - targets: ['localhost:9363'] -``` - -### Key Metrics - -```text -# Query metrics -clickhouse_queries_total -clickhouse_query_duration_seconds -clickhouse_query_memory_usage_bytes - -# Merge metrics -clickhouse_merges_total -clickhouse_merge_duration_seconds - -# Replication metrics -clickhouse_replication_queue_size -clickhouse_replication_lag_seconds - -# Table metrics -clickhouse_table_rows{table="events"} -clickhouse_table_size_bytes{table="events"} -``` - -## Grafana Dashboard - -### Recommended Panels - -1. **Query Performance** - - Queries per second - - Average query duration - - Memory usage - -2. **Merge Health** - - Active merges - - Merge queue size - - Parts count - -3. **Replication** - - Replication lag - - Queue size - - Replica status - -4. **Table Sizes** - - Top 10 tables by size - - Growth rate - -## See also - -- `debugging.md` for troubleshooting - -## Table, column and partition details - -### Column Information - -```sql --- Column sizes and compression -SELECT - database, - table, - column, - type, - formatReadableSize(sum(data_uncompressed_bytes)) as uncompressed, - formatReadableSize(sum(data_compressed_bytes)) as compressed, - sum(data_compressed_bytes) / sum(data_uncompressed_bytes) as ratio -FROM system.columns -WHERE database != 'system' -GROUP BY database, table, column, type -ORDER BY sum(data_uncompressed_bytes) DESC -LIMIT 50; - --- All columns in a table -SELECT - name, - type, - default_kind, - default_expression, - comment -FROM system.columns -WHERE database = 'my_database' - AND table = 'my_table' -ORDER BY position; -``` - -### Partition Information - -```sql --- Partition details -SELECT - partition, - sum(rows) as total_rows, - count() as parts, - formatReadableSize(sum(bytes)) as size, - min(min_timestamp) as min_time, - max(max_timestamp) as max_time -FROM system.parts -WHERE active = 1 - AND table = 'my_table' - AND database = currentDatabase() -GROUP BY partition -ORDER BY partition DESC; - --- Large partitions (many parts) -SELECT - partition, - count() as parts, - sum(rows) as total_rows -FROM system.parts -WHERE active = 1 - AND table = 'my_table' -GROUP BY partition -HAVING parts > 100 -ORDER BY parts DESC; -``` - ---- - -## Databases, users and dictionaries - -## Database Information - -### All Databases - -```sql --- All databases -SELECT - name, - engine, - data_path, - metadata_path -FROM system.databases -ORDER BY name; - --- Database engine types -SELECT - engine, - count() as count -FROM system.databases -GROUP BY engine -ORDER BY count DESC; -``` - ---- - -## User and Security - -### User Information - -```sql --- All users -SELECT * FROM system.users; - --- User quotas -SELECT * FROM system.quotas; - --- Current roles -SELECT * FROM system.current_roles; -``` - -### Access Control - -```sql --- Row policies -SELECT * FROM system.row_policies; - --- Grants -SELECT * FROM system.grants; -``` - ---- - -## System Health - -### General Health - -```sql --- Server info -SELECT version(), uptime(), now() as current_time; - --- Memory usage -SELECT - formatReadableSize(sum(bytes_allocated)) as allocated, - formatReadableSize(sum(bytes_used)) as used -FROM system.dictionaries; - --- Load average -SELECT * FROM system.asynchronous_metrics -WHERE metric LIKE '%load%'; -``` - -### Settings - -```sql --- All settings -SELECT * FROM system.settings -ORDER BY name; - --- Current settings -SELECT * FROM system.settings -WHERE changed == 1; -``` - ---- - -## Dictionary Information - -### All Dictionaries - -```sql --- Dictionary status -SELECT - name, - status, - origin, - type, - element_count, - bytes_allocated -FROM system.dictionaries -ORDER BY name; - --- Loading dictionaries -SELECT - name, - status, - loading_start_time, - loading_duration_seconds -FROM system.dictionaries -WHERE status != 'LOADED'; -``` - ---- - -## Table growth over time - -```sql --- Daily table growth -SELECT - toStartOfDay(event_time) as day, - database, - table, - formatReadableSize(sum(bytes)) as size -FROM system.part_log -WHERE event_type = 'NewPart' - AND event_time > now() - INTERVAL 7 DAY -GROUP BY day, database, table -ORDER BY day DESC, sum(bytes) DESC; -``` - ---- - -**Tips**: - -- Use `formatReadableSize()` for human-readable byte sizes -- Use `formatReadableQuantity()` for human-readable row counts -- Filter `WHERE active = 1` to see only active parts -- Use `currentDatabase()` to refer to current database -- Most `system.*` tables have `event_date` for partitioning diff --git a/clickhouse/skills/clickhouse/references/query-optimization.md b/clickhouse/skills/clickhouse/references/query-optimization.md deleted file mode 100644 index 0d1133d..0000000 --- a/clickhouse/skills/clickhouse/references/query-optimization.md +++ /dev/null @@ -1,252 +0,0 @@ -# ClickHouse Query Optimization - -Techniques for optimizing ClickHouse query performance. - -## EXPLAIN - -Use EXPLAIN to understand query execution: - -```sql --- Basic explain -EXPLAIN SELECT * FROM events WHERE user_id = 123; - --- Readable query plan -EXPLAIN PLAN SELECT * FROM events WHERE user_id = 123; - --- Pipeline details -EXPLAIN PIPELINE SELECT * FROM events WHERE user_id = 123; - --- With estimates -EXPLAIN ESTIMATE SELECT * FROM events WHERE user_id = 123; -``` - -**Key indicators:** - -- `"Filter"` → Not using index (full scan) -- `"Index"` → Using index marks -- `"Projection"` → Pre-computed data -- `"Filter with index"` → Using skip index - -## JOIN Optimization - -### Rule: Smaller Table on RIGHT - -```sql --- GOOD: Good: Smaller table on RIGHT -SELECT * -FROM large_table lt -RIGHT JOIN small_table st ON lt.id = st.id; - --- BAD: Bad: Large table on RIGHT -SELECT * -FROM small_table st -LEFT JOIN large_table lt ON lt.id = st.id; -``` - -**Why?** ClickHouse sends RIGHT table to all shards. Smaller RIGHT = less network transfer. - -### GLOBAL JOIN for Distributed Queries - -```sql --- For distributed queries, use GLOBAL -SELECT * -FROM large_table lt -GLOBAL RIGHT JOIN small_table st ON lt.id = st.id; - --- GLOBAL ensures right table is sent once to each shard -``` - -### ASOF JOIN for Time-Series - -```sql --- As-of join for time-series (latest value before timestamp) -SELECT * -FROM ticks t -ASOF LEFT JOIN quotes q -ON t.symbol = q.symbol -AND t.time <= q.time; -``` - -## GROUP BY Optimization - -### WITH ROLLUP - -```sql --- Hierarchical aggregation -SELECT - user_id, - event_type, - count() as cnt -FROM events -GROUP BY user_id, event_type WITH ROLLUP; --- Results: (user, type), (user, NULL), (NULL, NULL) -``` - -### WITH CUBE - -```sql --- All combinations -SELECT - user_id, - event_type, - count() as cnt -FROM events -GROUP BY user_id, event_type WITH CUBE; --- Results: All 4 combinations -``` - -## Projections (Pre-computed Aggregations) - -Projections automatically speed up common aggregations: - -```sql --- Create projection -ALTER TABLE events ADD PROJECTION pr_user_daily ( - SELECT - user_id, - toDate(timestamp) as date, - count() as events, - sum(revenue) as total_revenue - GROUP BY user_id, date -); - --- Query automatically uses projection (fast!) -SELECT - user_id, - date, - count() as events, - sum(revenue) as total_revenue -FROM events -GROUP BY user_id, date; - --- Drop projection -ALTER TABLE events DROP PROJECTION pr_user_daily; -``` - -**When projections are used:** - -- Query GROUP BY matches projection GROUP BY -- Query SELECT matches projection SELECT -- Automatic (no query changes needed) - -## Skip Indexes - -Skip indexes allow data skipping during reads: - -```sql --- Bloom filter for exact match -CREATE TABLE events ( - user_id UInt32, - email String, - timestamp DateTime -) -ENGINE = MergeTree() -ORDER BY (user_id, timestamp) -INDEX idx_email email TYPE bloom_filter GRANULARITY 1; - --- Minmax for range queries -INDEX idx_time timestamp TYPE minmax GRANULARITY 4; - --- Set for IN queries -INDEX idx_user user_id TYPE set(1000) GRANULARITY 1; - --- Tokenbf for string search -INDEX idx_msg message TYPE tokenbf_v1(512, 3, 0) GRANULARITY 1; -``` - -**Skip index types:** - -- `minmax`: Min/max values per granule -- `set`: Set of values (good for IN queries) -- `bloom_filter`: Probabilistic exact match -- `tokenbf_v1`: Token-based bloom filter for text search - -**Check if index used:** - -```sql -EXPLAIN SELECT * FROM events WHERE email = 'user@example.com'; --- Look for "Index" or "Filter with index" in output -``` - -## Common Query Pitfalls - -```sql --- BAD: SELECT * reads all columns (expensive in columnar store) -SELECT * FROM events; - --- GOOD: Select only needed columns -SELECT user_id, timestamp, event_type FROM events; - --- BAD: Suboptimal WHERE (function on column) -SELECT * FROM events WHERE toDate(timestamp) = today(); - --- GOOD: Use date functions on literal -SELECT * FROM events -WHERE timestamp >= today() AND timestamp < tomorrow(); - --- BAD: String comparison for dates -SELECT * FROM events WHERE toString(timestamp) LIKE '2024-01-01%'; - --- GOOD: Use date range -SELECT * FROM events -WHERE timestamp >= toDateTime('2024-01-01 00:00:00') - AND timestamp < toDateTime('2024-01-02 00:00:00'); -``` - -## Window Functions - -```sql --- Ranking -SELECT - user_id, - event_timestamp, - row_number() OVER (PARTITION BY user_id ORDER BY event_timestamp) as rn -FROM events; - --- Running totals -SELECT - date, - revenue, - sum(revenue) OVER (ORDER BY date) as running_total -FROM daily_revenue; - --- Lag/Lead -SELECT - date, - revenue, - lag(revenue, 1) OVER (ORDER BY date) as prev_revenue, - lead(revenue, 1) OVER (ORDER BY date) as next_revenue -FROM daily_revenue; -``` - -## Performance Tuning Settings - -```sql --- Increase memory limit -SET max_memory_usage = 10000000000; - --- Parallel processing -SET max_threads = 8; - --- Block size -SET max_block_size = 65536; - --- Disable query cache -SET use_uncompressed_cache = 0; -``` - -## Query Profiling Checklist - -- [ ] Used EXPLAIN to verify index usage -- [ ] Selected only needed columns (no SELECT *) -- [ ] Used date range filters instead of functions on columns -- [ ] Smaller table on RIGHT side of JOIN -- [ ] Used GLOBAL JOIN for distributed queries -- [ ] Added skip indexes for frequent filters -- [ ] Considered projections for common aggregations -- [ ] Set appropriate max_memory_usage - -## See Also - -- `../SKILL.md` - Main skill entry point -- `schema-design.md` - ORDER BY and indexing strategies diff --git a/clickhouse/skills/clickhouse/references/schema-design.md b/clickhouse/skills/clickhouse/references/schema-design.md deleted file mode 100644 index 1a5da12..0000000 --- a/clickhouse/skills/clickhouse/references/schema-design.md +++ /dev/null @@ -1,446 +0,0 @@ -# ClickHouse schema design - -ORDER BY, partitioning, column types, codecs, skip indexes, and schema migration. - -## ORDER BY Design (CRITICAL) - -The ORDER BY clause defines **data layout on disk** - the most important schema decision! - -### ORDER BY Design Principles - -1. **Match query WHERE patterns**: Most selective filter first -2. **Time-series**: Timestamp as second column (after dimension) -3. **High-cardinality first**: user_id before event_type -4. **Limit to 3-4 columns**: More columns = larger index - -### Examples - -```sql --- GOOD: GOOD: ORDER BY matches query pattern -CREATE TABLE events ( - user_id UInt32, - event_timestamp DateTime, - event_type String -) -ENGINE = MergeTree() -ORDER BY (user_id, event_timestamp); - --- Query leverages index (reads contiguous data) -SELECT * FROM events -WHERE user_id = 123 - AND event_timestamp >= now() - INTERVAL 1 DAY; - --- BAD: BAD: ORDER BY doesn't match queries -CREATE TABLE events ( - user_id UInt32, - event_timestamp DateTime, - event_type String -) -ENGINE = MergeTree() -ORDER BY (event_timestamp); - --- Query scans all data (timestamp-ordered, but filtering by user_id) -SELECT * FROM events WHERE user_id = 123; -``` - -### Primary Key vs Sorting Key - -```sql --- Sorting key: defines data layout on disk -ORDER BY (user_id, event_timestamp, event_type) - --- Primary key: subset of ORDER BY for row-level index -PRIMARY KEY (user_id, event_timestamp) - --- Effect: --- - Data on disk: sorted by (user_id, timestamp, event_type) --- - Primary index: only (user_id, timestamp) --- - Queries filtering by user_id + timestamp use index --- - Queries scanning event_type read more data -``` - -**When to use different PRIMARY KEY:** - -- Want to optimize for queries that filter on subset of ORDER BY -- Reduce primary key size (faster index scans) -- Note: PRIMARY KEY must be prefix of ORDER BY - -### Common ORDER BY Patterns - -```sql --- Time-series by user -ORDER BY (user_id, timestamp) - --- Time-series by sensor -ORDER BY (sensor_id, timestamp) - --- Multi-tenant time-series -ORDER BY (tenant_id, user_id, timestamp) - --- Event log -ORDER BY (timestamp, event_type) - --- Metrics -ORDER BY (metric_name, timestamp, labels_hash) -``` - -## Partition Strategy - -Partitions enable fast data drop and TTL operations: - -### Time-Based Partitioning (Most Common) - -```sql --- Monthly partitions (recommended for 10GB+ per day) -PARTITION BY toYYYYMM(timestamp); --- Results: partitions like '202401', '202402', ... - --- Daily partitions (for high-volume, 1GB+ per day) -PARTITION BY toDate(timestamp); --- Results: one partition per day -``` - -### Custom Partitioning - -```sql --- By tenant (multi-tenant cleanup) -PARTITION BY tenant_id; --- Drop all data for tenant: ALTER TABLE DROP PARTITION 'tenant_123'; - --- Composite (use carefully - too many partitions!) -PARTITION BY (tenant_id, toYYYYMM(timestamp)); --- Results: 'tenant_123_202401', 'tenant_123_202402', ... -``` - -### Partitioning Guidelines - -| Data Volume | Recommended Partitioning | -| ------------ | -------------------------- | -| < 1GB/day | No partitioning or monthly | -| 1-10GB/day | Monthly partitions | -| 10-100GB/day | Daily partitions | -| > 100GB/day | Daily + sharding | - -**Key principles:** - -- Aim for 100-1000 parts total across all partitions -- Monthly partitions: Good for 10GB+ per day -- Daily partitions: Good for 1GB+ per day -- Too many partitions = slow queries, high merge overhead - -### Partition Operations - -```sql --- Drop partition (instant, no mutation) -ALTER TABLE events DROP PARTITION '202401'; - --- Detach/Attach partition -ALTER TABLE events DETACH PARTITION '202401'; -ALTER TABLE events ATTACH PARTITION '202401'; - --- Freeze partition (for backup) -ALTER TABLE events FREEZE PARTITION '202401'; - --- Check partition sizes -SELECT - partition, - sum(rows) as total_rows, - formatReadableSize(sum(bytes)) as size -FROM system.parts -WHERE active = 1 AND table = 'events' -GROUP BY partition -ORDER BY partition DESC; -``` - -## Column Selection - -Choose smallest sufficient type: - -### Numeric Types - -```sql --- Use smallest integer type -UInt8 -- 0-255 -UInt16 -- 0-65,535 -UInt32 -- 0-4,294,967,295 -UInt64 -- 0-18,446,744,073,709,551,615 - --- Decimal for currency -Decimal(18, 2) -- Up to 999 trillion -Decimal(10, 2) -- Smaller range, faster -``` - -### Temporal Types - -```sql -timestamp Date -- 2 bytes (days since epoch) -timestamp DateTime -- 4 bytes (seconds since epoch) -timestamp DateTime64(3) -- 8 bytes (milliseconds) -``` - -### String Types - -```sql --- LowCardinality for enum-like strings (< 10k distinct values) -event_type LowCardinality(String) - --- Nullable vs default values -status Nullable(String) -- Has overhead (special NULL marker) -status String DEFAULT '' -- Better: Use default value -``` - -## Sampling Key - -Enable SAMPLE queries for approximate analytics: - -```sql --- Enable sampling -CREATE TABLE events ( - user_id UInt32, - event_timestamp DateTime, - data String -) -ENGINE = MergeTree() -ORDER BY (user_id, event_timestamp) -SAMPLE BY user_id; -- Must be column in ORDER BY - --- Query with sampling (10% of data) -SELECT * FROM events SAMPLE 0.1; - --- Sampling with interpolation -SELECT - user_id, - count() * 10 as estimated_count -- Multiply by 1/sampling_rate -FROM events -SAMPLE 0.1 -GROUP BY user_id; -``` - -**Use cases for sampling:** - -- Exploratory analytics (fast approximate results) -- Testing queries on large datasets -- Dashboard previews (refresh faster) - -## Codecs - -Apply compression to individual columns: - -```sql --- ZSTD compression (good default) -CREATE TABLE events ( - data String CODEC(ZSTD) -) -ENGINE = MergeTree() -ORDER BY user_id; - --- Compression levels -CODEC(ZSTD(3)) -- Fast, less compression -CODEC(ZSTD(15)) -- Slower, more compression - --- No compression (for already compressed data) -CODEC(NONE) - --- Multiple codecs -CODEC(Delta, ZSTD) - --- LZ4 (faster than ZSTD, less compression) -CODEC(LZ4) -``` - -**Codec guidelines:** - -- Use ZSTD for most data (good balance) -- Use NONE for already-compressed data (images, encrypted data) -- Use Delta for monotonically increasing values (timestamps, IDs) -- Higher compression levels = slower queries - -## Skip Indexes - -Data skipping indexes allow ClickHouse to skip data during reads: - -```sql --- Bloom filter for exact match -CREATE TABLE events ( - user_id UInt32, - email String, - timestamp DateTime -) -ENGINE = MergeTree() -ORDER BY (user_id, timestamp) -INDEX idx_email email TYPE bloom_filter GRANULARITY 1; - --- Minmax for range queries -INDEX idx_time timestamp TYPE minmax GRANULARITY 4; - --- Set for IN queries -INDEX idx_user user_id TYPE set(1000) GRANULARITY 1; - --- Tokenbf for string search -INDEX idx_msg message TYPE tokenbf_v1(512, 3, 0) GRANULARITY 1; -``` - -**Index types:** - -- `minmax`: Min/max values per granule -- `set`: Set of values (good for IN queries) -- `bloom_filter`: Probabilistic exact match -- `tokenbf_v1`: Token-based bloom filter for text search - -**Granularity:** - -- Lower = more precise index, larger index size -- Higher = less precise index, smaller index size -- Default: 1 (most precise) - -## Table Settings - -```sql -CREATE TABLE events ( - timestamp DateTime, - user_id UInt32 -) -ENGINE = MergeTree() -ORDER BY (user_id, timestamp) -SETTINGS - index_granularity = 8192, -- Rows per mark (default) - index_granularity_bytes = 10485760, -- Bytes per mark - enable_mixed_granularity_parts = 1, -- Adaptive marks - min_rows_for_wide_part = 0, -- Always use wide parts - merge_max_block_size = 1048544, -- Block size for merges - storage_policy = 'default'; -- Storage policy -``` - -## Schema Organization - -Organize databases by environment and purpose: - -```sql --- Environment structure -CREATE DATABASE analytics_raw; -- Staging tables -CREATE DATABASE analytics_staging; -- Cleaned data -CREATE DATABASE analytics_prod; -- Production tables -CREATE DATABASE analytics_mvs; -- Materialized views -CREATE DATABASE analytics_dicts; -- Dictionary definitions -``` - -### Naming Conventions - -```sql --- Tables: snake_case, plural -events, user_sessions, daily_metrics - --- Columns: snake_case -event_timestamp, user_id, session_id - --- Partitions: YYYYMM format -PARTITION BY toYYYYMM(timestamp) - --- Engines: Explicit ENGINE = clause -ENGINE = MergeTree() -``` - -## Schema Migration Strategy - -### Safe Operations (No Data Rewrite) - -```sql --- Add column (safe, metadata-only) -ALTER TABLE events ADD COLUMN new_column UInt32 DEFAULT 0; - --- Add index (safe, background) -ALTER TABLE events ADD INDEX idx_new_column new_column TYPE bloom_filter GRANULARITY 1; - --- Add projection (safe, background) -ALTER TABLE events ADD PROJECTION pr_summary ( - SELECT user_id, count() as cnt - GROUP BY user_id -); -``` - -### Unsafe Operations (Require Data Rewrite) - -```sql --- These trigger mutations (expensive!) -ALTER TABLE events DROP COLUMN old_column; -ALTER TABLE events MODIFY COLUMN col Type; -ALTER TABLE events RENAME COLUMN old_name TO new_name; -ALTER TABLE events DELETE WHERE expr; -ALTER TABLE events UPDATE col = expr WHERE expr; -``` - -### Zero-Downtime Schema Change - -```sql --- 1. Create new table with new schema -CREATE TABLE events_v2 ( - timestamp DateTime, - user_id UInt32, - new_column String -) -ENGINE = MergeTree() -ORDER BY (user_id, timestamp); - --- 2. Backfill data -INSERT INTO events_v2 SELECT * FROM events; - --- 3. Verify data -SELECT count() FROM events; -SELECT count() FROM events_v2; - --- 4. Swap tables (atomic, instantaneous) -EXCHANGE TABLES events AND events_v2; - --- 5. Drop old table after validation -DROP TABLE events_v2; -``` - -### Schema Version Control - -**Best practices:** - -- Store all DDL in version control (Git) -- Use migration tools: `clickhouse-migrate`, `golang-migrate` -- Document table relationships and dependencies -- Track migration order to support rollbacks -- Test migrations on staging first - -```sql --- Example migration tracking table -CREATE TABLE schema_migrations ( - version UInt32, - description String, - applied_at DateTime, - checksum String -) -ENGINE = MergeTree() -ORDER BY version; -``` - -## Database Configuration - -### Settings - -```sql --- Database-level settings -ALTER DATABASE my_db MODIFY SETTING max_bytes = 10000000000; - --- Check database settings -SELECT * FROM system.databases WHERE name = 'my_db'; -``` - -### Quotas - -```sql -CREATE QUOTA my_quota -KEYED BY user_name -FOR INTERVAL 1 hour -MAX queries = 1000 -MAX errors = 100 -MAX result_rows = 1000000000 -MAX result_bytes = 10000000000 -MAX read_rows = 10000000000 -MAX read_bytes = 100000000000 -MAX execution_time = 60 -TO user_name; -``` diff --git a/clickhouse/skills/clickhouse/rules/_sections.md b/clickhouse/skills/clickhouse/rules/_sections.md deleted file mode 100644 index 06fc1a6..0000000 --- a/clickhouse/skills/clickhouse/rules/_sections.md +++ /dev/null @@ -1,24 +0,0 @@ -# Sections - -This file defines all sections, their ordering, impact levels, and descriptions. -The section ID (in parentheses) is the filename prefix used to group rules. - ---- - -## 1. Schema Design (schema) - -**Impact:** CRITICAL - -**Description:** Proper schema design is foundational to ClickHouse performance. ORDER BY is immutable after table creation; wrong choices require full data migration. Includes primary key selection, data types, partitioning strategy, and JSON usage. Column types and ordering can impact query speed by orders of magnitude. - -## 2. Query Optimization (query) - -**Impact:** CRITICAL - -**Description:** Query patterns dramatically affect performance. JOIN algorithms, filtering strategies, skipping indices, and materialized views can reduce query time from minutes to milliseconds. Pre-computed aggregations read thousands of rows instead of billions. - -## 3. Insert Strategy (insert) - -**Impact:** CRITICAL - -**Description:** Each INSERT creates a data part. Single-row inserts overwhelm the merge process. Proper batching (10K-100K rows), async inserts for high-frequency writes, mutation avoidance, and letting background merges work are essential for stable cluster performance. diff --git a/clickhouse/skills/clickhouse/rules/_template.md b/clickhouse/skills/clickhouse/rules/_template.md deleted file mode 100644 index a010695..0000000 --- a/clickhouse/skills/clickhouse/rules/_template.md +++ /dev/null @@ -1,28 +0,0 @@ ---- -title: Rule Title Here -impact: CRITICAL | HIGH | MEDIUM | LOW -impactDescription: "Quantified improvement (e.g., 10x faster queries)" -tags: [tag1, tag2] ---- - -## Rule Title Here - -**Impact: CRITICAL** (optional description) - -Brief explanation of the rule and why it matters. This should be clear and concise, explaining the performance implications. - -**Incorrect (description of what's wrong):** - -```sql --- Bad: description -SELECT * FROM table; -``` - -**Correct (description of what's right):** - -```sql --- Good: description -SELECT * FROM table; -``` - -Reference: [Official Docs](https://clickhouse.com/docs/best-practices/...) diff --git a/clickhouse/skills/clickhouse/rules/insert-async-small-batches.md b/clickhouse/skills/clickhouse/rules/insert-async-small-batches.md deleted file mode 100644 index a94ad3e..0000000 --- a/clickhouse/skills/clickhouse/rules/insert-async-small-batches.md +++ /dev/null @@ -1,55 +0,0 @@ ---- -title: Use Async Inserts for High-Frequency Small Batches -impact: HIGH -impactDescription: "Server-side buffering when client batching isn't practical" -tags: [insert, async, buffering, small-batches] ---- - -## Use Async Inserts for High-Frequency Small Batches - -**Impact: HIGH** - -When client-side batching isn't practical, async inserts buffer server-side and create larger parts automatically. - -**Incorrect (small batches without async):** - -```python -# Small batches without async_insert - creates too many parts -for batch in chunks(events, 100): - client.execute("INSERT INTO events VALUES", batch) -``` - -**Correct (enable async inserts):** - -```python -# Enable async_insert with safe defaults -client.execute("SET async_insert = 1") -client.execute("SET wait_for_async_insert = 1") # Confirms durability - -for batch in chunks(events, 100): - client.execute("INSERT INTO events VALUES", batch) -# Server buffers and creates larger parts automatically -``` - -```sql --- Configure server-side for specific users -ALTER USER my_app_user SETTINGS - async_insert = 1, - wait_for_async_insert = 1, - async_insert_max_data_size = 10000000, -- Flush at 10MB - async_insert_busy_timeout_ms = 1000; -- Flush after 1s -``` - -**Flush conditions (whichever occurs first):** -- Buffer reaches `async_insert_max_data_size` -- Time threshold `async_insert_busy_timeout_ms` elapses -- Maximum insert queries accumulate - -**Return modes:** - -| Setting | Behavior | Use Case | -|---------|----------|----------| -| `wait_for_async_insert=1` | Waits for flush, confirms durability | **Recommended** | -| `wait_for_async_insert=0` | Fire-and-forget, unaware of errors | **Risky** - only if you accept data loss | - -Reference: [Selecting an Insert Strategy](https://clickhouse.com/docs/best-practices/selecting-an-insert-strategy) diff --git a/clickhouse/skills/clickhouse/rules/insert-batch-size.md b/clickhouse/skills/clickhouse/rules/insert-batch-size.md deleted file mode 100644 index 48c7bb7..0000000 --- a/clickhouse/skills/clickhouse/rules/insert-batch-size.md +++ /dev/null @@ -1,54 +0,0 @@ ---- -title: Batch Inserts Appropriately (10K-100K rows) -impact: CRITICAL -impactDescription: "Each INSERT creates a part; single-row inserts overwhelm merge process" -tags: [insert, batching, parts, performance] ---- - -## Batch Inserts Appropriately (10K-100K rows) - -**Impact: CRITICAL** - -Each INSERT creates a new data part. Single-row or small-batch inserts create thousands of tiny parts, overwhelming the merge process and causing cluster instability. - -**Incorrect (single-row or tiny batches):** - -```python -# Single-row inserts - creates 10,000 parts! -for event in events: - client.execute("INSERT INTO events VALUES", [event]) - -# Tiny batches - still too many parts -for batch in chunks(events, 100): # 100 rows per INSERT - client.execute("INSERT INTO events VALUES", batch) -``` - -**Correct (proper batch size):** - -```python -# Ideal batch size: 10,000-100,000 rows -BATCH_SIZE = 10_000 -for batch in chunks(events, BATCH_SIZE): - client.execute("INSERT INTO events VALUES", batch) -``` - -**Recommended batch sizes:** - -| Threshold | Value | -|-----------|-------| -| Minimum | 1,000 rows | -| Ideal range | 10,000-100,000 rows | -| Insert rate (sync) | ~1 insert per second | - -**Validation:** - -```sql --- Monitor part count (>3000 per partition blocks inserts) -SELECT table, count() as parts, sum(rows) as total_rows -FROM system.parts -WHERE active AND database = 'default' -GROUP BY table -ORDER BY parts DESC; -``` - -Reference: [Selecting an Insert Strategy](https://clickhouse.com/docs/best-practices/selecting-an-insert-strategy) diff --git a/clickhouse/skills/clickhouse/rules/insert-format-native.md b/clickhouse/skills/clickhouse/rules/insert-format-native.md deleted file mode 100644 index 4097af8..0000000 --- a/clickhouse/skills/clickhouse/rules/insert-format-native.md +++ /dev/null @@ -1,29 +0,0 @@ ---- -title: Use Native Format for Best Insert Performance -impact: MEDIUM -impactDescription: "Native format is most efficient; JSONEachRow is expensive to parse" -tags: [insert, format, Native, performance] ---- - -## Use Native Format for Best Insert Performance - -**Impact: MEDIUM** - -Data format affects insert performance. Native format is column-oriented with minimal parsing overhead. - -**Performance Ranking (fastest to slowest):** - -| Format | Notes | -|--------|-------| -| **Native** | Most efficient. Column-oriented, minimal parsing. Recommended. | -| **RowBinary** | Efficient row-based alternative | -| **JSONEachRow** | Easier to use but expensive to parse | - -**Example:** - -```python -# Use Native format for best performance -client.execute("INSERT INTO events VALUES", data, settings={'input_format': 'Native'}) -``` - -Reference: [Selecting an Insert Strategy](https://clickhouse.com/docs/best-practices/selecting-an-insert-strategy) diff --git a/clickhouse/skills/clickhouse/rules/insert-mutation-avoid-delete.md b/clickhouse/skills/clickhouse/rules/insert-mutation-avoid-delete.md deleted file mode 100644 index 72dd20a..0000000 --- a/clickhouse/skills/clickhouse/rules/insert-mutation-avoid-delete.md +++ /dev/null @@ -1,74 +0,0 @@ ---- -title: Avoid ALTER TABLE DELETE -impact: CRITICAL -impactDescription: "Use lightweight DELETE, CollapsingMergeTree, or DROP PARTITION instead" -tags: [insert, mutation, DELETE, CollapsingMergeTree] ---- - -## Avoid ALTER TABLE DELETE - -**Impact: CRITICAL** - -`ALTER TABLE DELETE` is a mutation that rewrites entire data parts. Use alternatives like lightweight DELETE, CollapsingMergeTree, or DROP PARTITION. - -**Incorrect (mutation delete):** - -```sql --- Mutation delete for cleanup -ALTER TABLE orders DELETE WHERE status = 'cancelled'; - --- Time-based cleanup via mutation (very expensive) -ALTER TABLE sessions DELETE WHERE created_at < now() - INTERVAL 7 DAY; -``` - -**Correct - CollapsingMergeTree:** - -```sql -CREATE TABLE orders ( - order_id UInt64, - customer_id UInt64, - total Decimal(10,2), - sign Int8 -- 1 = active, -1 = deleted -) -ENGINE = CollapsingMergeTree(sign) -ORDER BY order_id; - --- Insert order -INSERT INTO orders VALUES (123, 456, 99.99, 1); - --- "Delete" by inserting with sign = -1 -INSERT INTO orders VALUES (123, 456, 99.99, -1); - --- Query collapses +1 and -1 pairs -SELECT order_id, sum(total * sign) as total -FROM orders GROUP BY order_id HAVING sum(sign) > 0; -``` - -**Correct - Lightweight Deletes (23.3+):** - -```sql --- Marks rows, doesn't rewrite immediately -DELETE FROM orders WHERE status = 'cancelled'; --- Physical deletion happens during normal merges -``` - -**Correct - DROP PARTITION for Bulk Deletion:** - -```sql --- Instant deletion of old data -ALTER TABLE events DROP PARTITION '202301'; - --- Much faster than: -ALTER TABLE events DELETE WHERE toYYYYMM(timestamp) = 202301; -``` - -**Delete strategy comparison:** - -| Method | Speed | When to Use | -|--------|-------|-------------| -| ALTER DELETE | Slow | Rare corrections only | -| CollapsingMergeTree | Fast | Frequent soft deletes | -| Lightweight DELETE | Medium | Occasional deletes | -| DROP PARTITION | Instant | Bulk deletion by partition | - -Reference: [Avoid Mutations](https://clickhouse.com/docs/best-practices/avoid-mutations) diff --git a/clickhouse/skills/clickhouse/rules/insert-mutation-avoid-update.md b/clickhouse/skills/clickhouse/rules/insert-mutation-avoid-update.md deleted file mode 100644 index 4d25b15..0000000 --- a/clickhouse/skills/clickhouse/rules/insert-mutation-avoid-update.md +++ /dev/null @@ -1,58 +0,0 @@ ---- -title: Avoid ALTER TABLE UPDATE -impact: CRITICAL -impactDescription: "Mutations rewrite entire parts; use ReplacingMergeTree instead" -tags: [insert, mutation, UPDATE, ReplacingMergeTree] ---- - -## Avoid ALTER TABLE UPDATE - -**Impact: CRITICAL** - -`ALTER TABLE UPDATE` is a mutation - an asynchronous background process that rewrites entire data parts affected by the change. This is extremely expensive for frequent or large-scale operations. - -**Why mutations are problematic:** -- **Write amplification:** Rewrite complete parts even for minor changes -- **Disk I/O spike:** Degrades overall cluster performance -- **No rollback:** Cannot be rolled back after submission -- **Inconsistent reads:** SELECT may read mix of mutated and unmutated parts - -**Incorrect (mutation for updates):** - -```sql --- Rewrites potentially huge amounts of data -ALTER TABLE users UPDATE status = 'inactive' -WHERE last_login < now() - INTERVAL 90 DAY; - --- Frequent row updates via mutation -ALTER TABLE inventory UPDATE quantity = quantity - 1 -WHERE product_id = 123; --- If product exists across 100 parts, rewrites ALL 100 parts -``` - -**Correct (ReplacingMergeTree):** - -```sql --- Table design for updates -CREATE TABLE users ( - user_id UInt64, - name String, - status LowCardinality(String), - updated_at DateTime DEFAULT now() -) -ENGINE = ReplacingMergeTree(updated_at) -ORDER BY user_id; - --- "Update" by inserting new version -INSERT INTO users (user_id, name, status) -VALUES (123, 'John', 'inactive'); - --- Query with FINAL to get latest version -SELECT * FROM users FINAL WHERE user_id = 123; - --- Or use aggregation -SELECT user_id, argMax(status, updated_at) as status -FROM users GROUP BY user_id; -``` - -Reference: [Avoid Mutations](https://clickhouse.com/docs/best-practices/avoid-mutations) diff --git a/clickhouse/skills/clickhouse/rules/insert-optimize-avoid-final.md b/clickhouse/skills/clickhouse/rules/insert-optimize-avoid-final.md deleted file mode 100644 index 0dacb26..0000000 --- a/clickhouse/skills/clickhouse/rules/insert-optimize-avoid-final.md +++ /dev/null @@ -1,57 +0,0 @@ ---- -title: Avoid OPTIMIZE TABLE FINAL -impact: HIGH -impactDescription: "Forces expensive merge of all parts; let background merges work" -tags: [insert, OPTIMIZE, merge, performance] ---- - -## Avoid OPTIMIZE TABLE FINAL - -**Impact: HIGH** - -`OPTIMIZE TABLE ... FINAL` forces immediate merge of all parts into one part per partition. This is resource-intensive and rarely necessary. ClickHouse already performs smart background merges. - -**Note:** `OPTIMIZE FINAL` is not the same as `FINAL`. The `FINAL` modifier in SELECT queries may be necessary for deduplicated results in ReplacingMergeTree and is generally fine to use. - -**Incorrect (OPTIMIZE FINAL after inserts):** - -```sql --- Running OPTIMIZE FINAL after every batch insert -INSERT INTO events SELECT * FROM staging_events; -OPTIMIZE TABLE events FINAL; -- Expensive and unnecessary! - --- Scheduled OPTIMIZE FINAL jobs --- Cron: 0 * * * * clickhouse-client -q "OPTIMIZE TABLE events FINAL" -``` - -**Correct (let background merges work):** - -```sql --- Let background merges handle optimization -INSERT INTO events SELECT * FROM staging_events; --- Done! ClickHouse merges automatically - --- For ReplacingMergeTree deduplication, use FINAL in queries -SELECT * FROM events FINAL WHERE user_id = 123; --- Instead of running OPTIMIZE FINAL to deduplicate -``` - -**Problems with OPTIMIZE FINAL:** -- Rewrites entire partition regardless of need -- Ignores the ~150 GB part size safeguard -- Can cause memory pressure or OOM errors -- Lengthy execution time for large datasets - -**When OPTIMIZE FINAL may be acceptable:** -- Finalizing data before table freezing -- Preparing data for export operations -- One-time operations, not regular workflows - -**Better alternatives:** - -| Need | Alternative | -|------|-------------| -| Deduplicate ReplacingMergeTree | Use `FINAL` modifier in SELECT | -| Reduce part count | Rely on background merges | - -Reference: [Avoid OPTIMIZE FINAL](https://clickhouse.com/docs/best-practices/avoid-optimize-final) diff --git a/clickhouse/skills/clickhouse/rules/query-index-skipping-indices.md b/clickhouse/skills/clickhouse/rules/query-index-skipping-indices.md deleted file mode 100644 index 50691d5..0000000 --- a/clickhouse/skills/clickhouse/rules/query-index-skipping-indices.md +++ /dev/null @@ -1,77 +0,0 @@ ---- -title: Use Data Skipping Indices for Non-ORDER BY Filters -impact: HIGH -impactDescription: "Up to 60x faster queries by skipping irrelevant granules" -tags: [query, index, skipping, bloom_filter] ---- - -## Use Data Skipping Indices for Non-ORDER BY Filters - -**Impact: HIGH** - -Queries filtering on columns not in ORDER BY cannot use the primary index and result in full scans. Data skipping indices store metadata about blocks and skip granules that definitely don't match. - -**Important:** Skip indices should be considered **after** optimizing data types, primary key selection, and materialized views. - -**When to use:** -- High overall cardinality but low cardinality within blocks -- Rare values critical for search (error codes, specific IDs) -- Column correlates with primary key - -**When NOT to use:** -- As a first optimization step -- Matching values scattered across many blocks -- Without testing on real data - -**Incorrect (filtering on non-ORDER BY column):** - -```sql -CREATE TABLE events ( - event_type LowCardinality(String), - timestamp DateTime, - user_id UInt64 -- Not in ORDER BY -) -ENGINE = MergeTree() -ORDER BY (event_type, toDate(timestamp)); - --- Query filters on user_id - scans all matching event_type -SELECT * FROM events -WHERE event_type = 'click' AND user_id = 12345; -``` - -**Correct (add skipping index):** - -```sql -CREATE TABLE events ( - event_type LowCardinality(String), - timestamp DateTime, - user_id UInt64, - INDEX idx_user_id user_id TYPE bloom_filter GRANULARITY 4 -) -ENGINE = MergeTree() -ORDER BY (event_type, toDate(timestamp)); - --- Or add to existing table -ALTER TABLE events ADD INDEX idx_user_id user_id TYPE bloom_filter GRANULARITY 4; -ALTER TABLE events MATERIALIZE INDEX idx_user_id; -``` - -**Index types:** - -| Type | Best For | Example Filter | -|------|----------|----------------| -| `bloom_filter` | Equality on high-cardinality | `WHERE user_id = 123` | -| `set(N)` | Low cardinality (N unique values) | `WHERE status IN ('a','b')` | -| `minmax` | Range queries | `WHERE amount > 1000` | -| `ngrambf_v1` | Text search | `WHERE text LIKE '%term%'` | -| `tokenbf_v1` | Token search | `WHERE hasToken(text, 'word')` | - -**Validation:** - -```sql -EXPLAIN indexes = 1 -SELECT * FROM events WHERE user_id = 12345; --- Look for "Skip" in output showing granules skipped -``` - -Reference: [Use Data Skipping Indices Where Appropriate](https://clickhouse.com/docs/best-practices/use-data-skipping-indices-where-appropriate) diff --git a/clickhouse/skills/clickhouse/rules/query-join-choose-algorithm.md b/clickhouse/skills/clickhouse/rules/query-join-choose-algorithm.md deleted file mode 100644 index b1a5e17..0000000 --- a/clickhouse/skills/clickhouse/rules/query-join-choose-algorithm.md +++ /dev/null @@ -1,43 +0,0 @@ ---- -title: Choose the Right JOIN Algorithm -impact: CRITICAL -impactDescription: "Wrong algorithm causes OOM; right algorithm handles large tables efficiently" -tags: [query, JOIN, algorithm, memory] ---- - -## Choose the Right JOIN Algorithm - -**Impact: CRITICAL** - -ClickHouse's default hash join loads the RIGHT table entirely into memory. Choose the right algorithm based on table sizes and constraints. - -**Algorithm selection:** - -| Algorithm | Best For | Trade-off | -|-----------|----------|-----------| -| `parallel_hash` | Small-to-medium in-memory tables | Default since 24.11; fast, concurrent | -| `hash` | General purpose, all join types | Single-threaded hash table build | -| `direct` | Dictionary lookups (INNER/LEFT only) | Fastest; no hash table construction | -| `full_sorting_merge` | Tables already sorted on join key | Skips sort if pre-ordered; low memory | -| `partial_merge` | Large tables, memory-constrained | Minimized memory; slower execution | -| `grace_hash` | Large datasets, tunable memory | Flexible; disk-spilling capability | -| `auto` | Adaptive algorithm selection | Tries hash first, falls back on memory pressure | - -**Example usage:** - -```sql --- Let ClickHouse choose automatically -SET join_algorithm = 'auto'; - --- For large-to-large joins where memory is constrained -SET join_algorithm = 'partial_merge'; -SELECT * FROM large_a JOIN large_b ON large_b.id = large_a.id; - --- When joining by primary key columns, sort-merge skips sorting step -SET join_algorithm = 'full_sorting_merge'; -SELECT * FROM table_a a JOIN table_b b ON b.pk_col = a.pk_col; -``` - -**Note:** ClickHouse 24.12+ automatically positions smaller tables on the right side. For earlier versions, manually ensure the smaller table is on the RIGHT. - -Reference: [Minimize and Optimize JOINs](https://clickhouse.com/docs/best-practices/minimize-optimize-joins) diff --git a/clickhouse/skills/clickhouse/rules/query-join-consider-alternatives.md b/clickhouse/skills/clickhouse/rules/query-join-consider-alternatives.md deleted file mode 100644 index 2666359..0000000 --- a/clickhouse/skills/clickhouse/rules/query-join-consider-alternatives.md +++ /dev/null @@ -1,72 +0,0 @@ ---- -title: Consider Alternatives to JOINs -impact: CRITICAL -impactDescription: "Dictionaries and denormalization shift work from query time to insert time" -tags: [query, JOIN, dictionary, denormalization] ---- - -## Consider Alternatives to JOINs - -**Impact: CRITICAL** - -Repeated JOINs to dimension tables add overhead. Dictionaries or denormalization shift computational work from query time to insert/pre-processing time. - -**Incorrect (JOIN on every query):** - -```sql --- JOIN on every query -SELECT o.order_id, c.name, c.email -FROM orders o -JOIN customers c ON c.id = o.customer_id -WHERE o.created_at > '2024-01-01'; -``` - -**Correct - Dictionary Lookup:** - -```sql --- Create dictionary -CREATE DICTIONARY customer_dict ( - id UInt64, - name String, - email String -) -PRIMARY KEY id -SOURCE(CLICKHOUSE(TABLE 'customers')) -LAYOUT(HASHED()) -LIFETIME(MIN 300 MAX 360); - --- Use dictGet instead of JOIN (uses direct join algorithm - fastest) -SELECT - order_id, - dictGet('customer_dict', 'name', customer_id) as customer_name, - dictGet('customer_dict', 'email', customer_id) as customer_email -FROM orders -WHERE created_at > '2024-01-01'; -``` - -**Correct - Denormalization:** - -```sql --- Denormalized table with materialized view -CREATE MATERIALIZED VIEW orders_enriched_mv TO orders_enriched AS -SELECT - o.order_id, o.customer_id, - c.name as customer_name, - c.email as customer_email, - o.total, o.created_at -FROM orders o -JOIN customers c ON c.id = o.customer_id; -``` - -**Approach comparison:** - -| Approach | Use Case | Performance | -|----------|----------|-------------| -| Dictionary | Frequent lookups to small dimension | Fastest (in-memory) | -| Denormalization | Analytics always need enriched data | Fast (no join at query) | -| IN subquery | Existence filtering | Often faster than JOIN | -| JOIN | Infrequent or complex joins | Acceptable | - -**Critical dictionary caveat:** Dictionaries silently deduplicate duplicate keys, retaining only the final value. Only use when source has unique keys. - -Reference: [Minimize and Optimize JOINs](https://clickhouse.com/docs/best-practices/minimize-optimize-joins) diff --git a/clickhouse/skills/clickhouse/rules/query-join-filter-before.md b/clickhouse/skills/clickhouse/rules/query-join-filter-before.md deleted file mode 100644 index e2eb729..0000000 --- a/clickhouse/skills/clickhouse/rules/query-join-filter-before.md +++ /dev/null @@ -1,54 +0,0 @@ ---- -title: Filter Tables Before Joining -impact: CRITICAL -impactDescription: "Joining full tables then filtering wastes resources" -tags: [query, JOIN, filtering, subquery] ---- - -## Filter Tables Before Joining - -**Impact: CRITICAL** - -Joining full tables then filtering wastes resources. Add filtering in `WHERE` or `JOIN ON` clauses. If automatic pushdown fails, restructure as a subquery. - -**Incorrect (join then filter):** - -```sql --- Joins entire tables, then filters -SELECT o.order_id, c.name, o.total -FROM orders o -JOIN customers c ON c.id = o.customer_id -WHERE o.created_at > '2024-01-01' AND c.country = 'US'; -``` - -**Correct (filter in subqueries before joining):** - -```sql --- Filter in subqueries before joining -SELECT o.order_id, c.name, o.total -FROM ( - SELECT order_id, customer_id, total - FROM orders - WHERE created_at > '2024-01-01' -) o -JOIN ( - SELECT id, name - FROM customers - WHERE country = 'US' -) c ON c.id = o.customer_id; -``` - -**Even better - aggregate before joining:** - -```sql -SELECT c.country, o.total_revenue -FROM ( - SELECT customer_id, sum(total) as total_revenue - FROM orders - WHERE created_at > '2024-01-01' - GROUP BY customer_id -) o -JOIN customers c ON c.id = o.customer_id; -``` - -Reference: [Minimize and Optimize JOINs](https://clickhouse.com/docs/best-practices/minimize-optimize-joins) diff --git a/clickhouse/skills/clickhouse/rules/query-join-null-handling.md b/clickhouse/skills/clickhouse/rules/query-join-null-handling.md deleted file mode 100644 index 4fe5ee9..0000000 --- a/clickhouse/skills/clickhouse/rules/query-join-null-handling.md +++ /dev/null @@ -1,33 +0,0 @@ ---- -title: Optimize NULL Handling in Outer JOINs -impact: MEDIUM -impactDescription: "Default values instead of NULL reduces memory overhead" -tags: [query, JOIN, NULL, memory] ---- - -## Optimize NULL Handling in Outer JOINs - -**Impact: MEDIUM** - -Set `join_use_nulls = 0` to use default column values instead of NULL markers, reducing memory overhead compared to Nullable wrappers. - -**Example:** - -```sql --- Use default values instead of NULLs for non-matching rows -SET join_use_nulls = 0; - -SELECT o.order_id, c.name -FROM orders o -LEFT JOIN customers c ON c.id = o.customer_id; --- Non-matching rows get '' for name instead of NULL -``` - -**When to use:** - -| Setting | Behavior | Use Case | -|---------|----------|----------| -| `join_use_nulls = 0` | Default values (empty string, 0) for non-matches | When you can handle default values | -| `join_use_nulls = 1` (default) | NULL for non-matches | When you need to distinguish "no match" from "matched with default" | - -Reference: [Minimize and Optimize JOINs](https://clickhouse.com/docs/best-practices/minimize-optimize-joins) diff --git a/clickhouse/skills/clickhouse/rules/query-join-use-any.md b/clickhouse/skills/clickhouse/rules/query-join-use-any.md deleted file mode 100644 index 4483a33..0000000 --- a/clickhouse/skills/clickhouse/rules/query-join-use-any.md +++ /dev/null @@ -1,40 +0,0 @@ ---- -title: Use ANY JOIN When Only One Match Needed -impact: HIGH -impactDescription: "Returns first match only; less memory and faster execution" -tags: [query, JOIN, ANY, performance] ---- - -## Use ANY JOIN When Only One Match Needed - -**Impact: HIGH** - -Use `ANY` JOINs when you only need a single match rather than all matches. They consume less memory and execute faster. - -**Incorrect (returns all matches):** - -```sql --- Returns all matching rows, uses more memory -SELECT o.order_id, c.name -FROM orders o -LEFT JOIN customers c ON c.id = o.customer_id; -``` - -**Correct (returns first match only):** - -```sql --- Returns only first match per row, faster and less memory -SELECT o.order_id, c.name -FROM orders o -LEFT ANY JOIN customers c ON c.id = o.customer_id; -``` - -**ANY JOIN types:** - -| Type | Behavior | -|------|----------| -| `LEFT ANY JOIN` | At most one match from right table | -| `INNER ANY JOIN` | At most one match, only matching rows | -| `RIGHT ANY JOIN` | At most one match from left table | - -Reference: [Minimize and Optimize JOINs](https://clickhouse.com/docs/best-practices/minimize-optimize-joins) diff --git a/clickhouse/skills/clickhouse/rules/query-mv-incremental.md b/clickhouse/skills/clickhouse/rules/query-mv-incremental.md deleted file mode 100644 index 0d00e13..0000000 --- a/clickhouse/skills/clickhouse/rules/query-mv-incremental.md +++ /dev/null @@ -1,68 +0,0 @@ ---- -title: Use Incremental MVs for Real-Time Aggregations -impact: HIGH -impactDescription: "Read thousands of rows instead of billions; minimal cluster overhead" -tags: [query, materialized-view, aggregation, real-time] ---- - -## Use Incremental MVs for Real-Time Aggregations - -**Impact: HIGH** - -Incremental MVs automatically apply the view's query to new data blocks at insert time. Results are written to a target table and partial results merge over time. - -**Incorrect (full aggregation on every query):** - -```sql --- Full aggregation on every dashboard load -SELECT - event_type, - toStartOfHour(timestamp) as hour, - count() as events, - uniq(user_id) as unique_users -FROM events -WHERE timestamp >= now() - INTERVAL 7 DAY -GROUP BY event_type, hour; --- Scans 7 days of data every time (billions of rows) -``` - -**Correct (incremental MV with pre-aggregation):** - -```sql --- Create target table for aggregated data -CREATE TABLE events_hourly ( - event_type LowCardinality(String), - hour DateTime, - events AggregateFunction(count), - unique_users AggregateFunction(uniq, UInt64) -) -ENGINE = AggregatingMergeTree() -ORDER BY (event_type, hour); - --- Create materialized view to populate incrementally -CREATE MATERIALIZED VIEW events_hourly_mv TO events_hourly AS -SELECT - event_type, - toStartOfHour(timestamp) as hour, - countState() as events, - uniqState(user_id) as unique_users -FROM events -GROUP BY event_type, hour; - --- Query the pre-aggregated data -SELECT - event_type, hour, - countMerge(events) as events, - uniqMerge(unique_users) as unique_users -FROM events_hourly -WHERE hour >= now() - INTERVAL 7 DAY -GROUP BY event_type, hour; --- Reads thousands of rows instead of billions -``` - -**Key points:** -- Use `-State` functions in MV, `-Merge` functions in query -- Incremental - existing data not automatically included (backfill separately) -- Minimal cluster overhead at insert time - -Reference: [Use Materialized Views](https://clickhouse.com/docs/best-practices/use-materialized-views) diff --git a/clickhouse/skills/clickhouse/rules/query-mv-refreshable.md b/clickhouse/skills/clickhouse/rules/query-mv-refreshable.md deleted file mode 100644 index 858fc0f..0000000 --- a/clickhouse/skills/clickhouse/rules/query-mv-refreshable.md +++ /dev/null @@ -1,64 +0,0 @@ ---- -title: Use Refreshable MVs for Complex Joins and Batch Workflows -impact: HIGH -impactDescription: "Sub-millisecond queries with periodic refresh; ideal for complex joins" -tags: [query, materialized-view, refresh, batch] ---- - -## Use Refreshable MVs for Complex Joins and Batch Workflows - -**Impact: HIGH** - -Refreshable MVs execute queries periodically on a schedule. The full query re-executes and overwrites (or appends to) the target table. - -**Best for:** -- Sub-millisecond latency where minor staleness is acceptable -- Caching "top N" results or lookup tables -- Complex multi-table joins requiring denormalization -- Batch workflows and DAG dependencies - -**Incorrect (expensive join on every request):** - -```sql --- Complex join executed on every request -SELECT - o.order_id, o.total, - c.name as customer_name, - p.name as product_name -FROM orders o -JOIN customers c ON o.customer_id = c.id -JOIN products p ON o.product_id = p.id -WHERE o.created_at >= now() - INTERVAL 1 DAY; -``` - -**Correct (refreshable MV):** - -```sql --- Create refreshable MV that runs every 5 minutes -CREATE MATERIALIZED VIEW orders_denormalized -REFRESH EVERY 5 MINUTE -ENGINE = MergeTree() -ORDER BY (created_at, order_id) -AS SELECT - o.order_id, o.created_at, o.total, - c.name as customer_name, c.segment, - p.name as product_name -FROM orders o -JOIN customers c ON o.customer_id = c.id -JOIN products p ON o.product_id = p.id -WHERE o.created_at >= now() - INTERVAL 1 DAY; - --- Query the pre-joined data (sub-millisecond) -SELECT * FROM orders_denormalized WHERE segment = 'enterprise'; -``` - -**APPEND vs REPLACE modes:** - -| Mode | Behavior | Use Case | -|------|----------|----------| -| `REPLACE` (default) | Overwrites previous contents | Current state, lookup tables | -| `APPEND` | Adds new rows to existing data | Periodic snapshots, historical accumulation | - -**Critical warning:** Query should run quickly compared to refresh interval. Don't schedule every 10 seconds if the query takes 10+ seconds. - -Reference: [Use Materialized Views](https://clickhouse.com/docs/best-practices/use-materialized-views) diff --git a/clickhouse/skills/clickhouse/rules/schema-json-when-to-use.md b/clickhouse/skills/clickhouse/rules/schema-json-when-to-use.md deleted file mode 100644 index 39eba52..0000000 --- a/clickhouse/skills/clickhouse/rules/schema-json-when-to-use.md +++ /dev/null @@ -1,76 +0,0 @@ ---- -title: Use JSON Type for Dynamic Schemas -impact: MEDIUM -impactDescription: "Field-level querying for semi-structured data; use typed columns for known schemas" -tags: [schema, JSON, semi-structured, flexibility] ---- - -## Use JSON Type for Dynamic Schemas - -**Impact: MEDIUM** - -ClickHouse's JSON type splits JSON objects into separate sub-columns, enabling field-level query optimization. Use it for truly dynamic data, not everything. - -**Incorrect (schema bloat or opaque String):** - -```sql --- BAD: Hundreds of nullable columns for event properties -CREATE TABLE events ( - event_id UUID, - prop_page_url Nullable(String), - prop_button_id Nullable(String), - -- ... 100 more nullable columns -) - --- BAD: JSON as String when you need field queries -CREATE TABLE events ( - event_id UUID, - properties String -- No field-level optimization -) -``` - -**Correct (JSON for dynamic, typed for known):** - -```sql --- Use JSON type for dynamic properties -CREATE TABLE events ( - event_id UUID DEFAULT generateUUIDv4(), - event_type LowCardinality(String), - timestamp DateTime DEFAULT now(), - properties JSON -- Flexible schema with type inference -) -ENGINE = MergeTree() -ORDER BY (event_type, timestamp); - --- Query JSON paths directly -SELECT - event_type, - properties.url as page_url, - properties.amount as purchase_amount -FROM events -WHERE event_type = 'page_view' AND properties.url = '/home'; -``` - -**When to use JSON:** - -| Scenario | Use JSON? | -|----------|-----------| -| Data structure varies unpredictably | Yes | -| Field types/schemas change over time | Yes | -| Need field-level querying | Yes | -| Fixed, known schema | No (use typed columns) | -| JSON as opaque blob (no field queries) | No (use String) | - -**Optimization: specify types for known paths:** - -```sql -CREATE TABLE events ( - properties JSON( - url String, - amount Float64, - product_id UInt64 - ) -) -``` - -Reference: [Use JSON Where Appropriate](https://clickhouse.com/docs/best-practices/use-json-where-appropriate) diff --git a/clickhouse/skills/clickhouse/rules/schema-partition-lifecycle.md b/clickhouse/skills/clickhouse/rules/schema-partition-lifecycle.md deleted file mode 100644 index a2c0518..0000000 --- a/clickhouse/skills/clickhouse/rules/schema-partition-lifecycle.md +++ /dev/null @@ -1,50 +0,0 @@ ---- -title: Use Partitioning for Data Lifecycle Management -impact: HIGH -impactDescription: "DROP PARTITION is instant; DELETE is expensive row-by-row scan" -tags: [schema, partitioning, TTL, data-management] ---- - -## Use Partitioning for Data Lifecycle Management - -**Impact: HIGH** - -Partitioning is **primarily a data management technique, not a query optimization tool**. It excels at: -- **Dropping data**: Remove entire partitions as single metadata operations -- **TTL retention**: Implement time-based retention policies efficiently -- **Tiered storage**: Move old partitions to cold storage -- **Archiving**: Move partitions between tables - -**Incorrect (no time alignment for lifecycle):** - -```sql --- Cannot efficiently drop old data by time -CREATE TABLE events (...) -ENGINE = MergeTree() -PARTITION BY event_type -- No time alignment -ORDER BY (timestamp); - --- Slow: must scan and delete row by row -DELETE FROM events WHERE timestamp < '2023-01-01'; -``` - -**Correct (time-based for lifecycle):** - -```sql -CREATE TABLE events ( - timestamp DateTime, - event_type LowCardinality(String) -) -ENGINE = MergeTree() -PARTITION BY toStartOfMonth(timestamp) -ORDER BY (event_type, timestamp) -TTL timestamp + INTERVAL 1 YEAR DELETE; -- Drops whole partitions - --- Fast: metadata-only operation -ALTER TABLE events DROP PARTITION '202301'; - --- Archive to cold storage -ALTER TABLE events_archive ATTACH PARTITION '202301' FROM events; -``` - -Reference: [Choosing a Partitioning Key](https://clickhouse.com/docs/best-practices/choosing-a-partitioning-key) diff --git a/clickhouse/skills/clickhouse/rules/schema-partition-low-cardinality.md b/clickhouse/skills/clickhouse/rules/schema-partition-low-cardinality.md deleted file mode 100644 index 533bde9..0000000 --- a/clickhouse/skills/clickhouse/rules/schema-partition-low-cardinality.md +++ /dev/null @@ -1,61 +0,0 @@ ---- -title: Keep Partition Cardinality Low (100-1,000 Values) -impact: HIGH -impactDescription: "Too many partitions cause part explosion and 'too many parts' errors" -tags: [schema, partitioning, parts] ---- - -## Keep Partition Cardinality Low (100-1,000 Values) - -**Impact: HIGH** - -Too many distinct partition values create excessive data parts, eventually triggering "too many parts" errors. ClickHouse enforces limits via `max_parts_in_total` and `parts_to_throw_insert` settings. - -**Incorrect (high cardinality partitioning):** - -```sql --- High cardinality = too many partitions -CREATE TABLE events (...) -ENGINE = MergeTree() -PARTITION BY user_id -- Millions of partitions! -ORDER BY (timestamp); - --- Daily partitions can grow unbounded over years -CREATE TABLE logs (...) -ENGINE = MergeTree() -PARTITION BY toDate(timestamp) -- 3650 partitions over 10 years -ORDER BY (service, timestamp); -``` - -**Correct (bounded cardinality):** - -```sql --- Monthly partitions = 12 per year, bounded cardinality -CREATE TABLE events ( - timestamp DateTime, - event_type LowCardinality(String), - user_id UInt64 -) -ENGINE = MergeTree() -PARTITION BY toStartOfMonth(timestamp) -ORDER BY (event_type, timestamp); -``` - -**Validation:** - -```sql --- Check partition count and health -SELECT - partition, - count() as parts, - sum(rows) as rows, - formatReadableSize(sum(bytes_on_disk)) as size -FROM system.parts -WHERE table = 'events' AND active -GROUP BY partition -ORDER BY partition; - --- Warning signs: hundreds or thousands of partitions -``` - -Reference: [Choosing a Partitioning Key](https://clickhouse.com/docs/best-practices/choosing-a-partitioning-key) diff --git a/clickhouse/skills/clickhouse/rules/schema-partition-query-tradeoffs.md b/clickhouse/skills/clickhouse/rules/schema-partition-query-tradeoffs.md deleted file mode 100644 index 1f9d954..0000000 --- a/clickhouse/skills/clickhouse/rules/schema-partition-query-tradeoffs.md +++ /dev/null @@ -1,35 +0,0 @@ ---- -title: Understand Partition Query Performance Trade-offs -impact: MEDIUM -impactDescription: "Partition pruning helps some queries; spanning many partitions hurts others" -tags: [schema, partitioning, query, performance] ---- - -## Understand Partition Query Performance Trade-offs - -**Impact: MEDIUM** - -Partitioning can help or hurt query performance: -- **Potential improvement**: Queries filtering by partition key may benefit from partition pruning -- **Potential degradation**: Queries spanning many partitions increase total parts scanned - -ClickHouse automatically builds **MinMax indexes** on partition columns. Data merges occur **within partitions only**, not across them. - -**Incorrect (query scans all partitions):** - -```sql --- Query must scan all partitions -SELECT count(*) FROM events -WHERE event_type = 'click'; -- No partition pruning -``` - -**Correct (query prunes to single partition):** - -```sql --- Query prunes to single partition -SELECT count(*) FROM events -WHERE timestamp >= '2024-01-01' AND timestamp < '2024-02-01' - AND event_type = 'click'; -``` - -Reference: [Choosing a Partitioning Key](https://clickhouse.com/docs/best-practices/choosing-a-partitioning-key) diff --git a/clickhouse/skills/clickhouse/rules/schema-partition-start-without.md b/clickhouse/skills/clickhouse/rules/schema-partition-start-without.md deleted file mode 100644 index 661c1f2..0000000 --- a/clickhouse/skills/clickhouse/rules/schema-partition-start-without.md +++ /dev/null @@ -1,42 +0,0 @@ ---- -title: Consider Starting Without Partitioning -impact: MEDIUM -impactDescription: "Add partitioning later when you have clear lifecycle requirements" -tags: [schema, partitioning, simplicity] ---- - -## Consider Starting Without Partitioning - -**Impact: MEDIUM** - -Start without partitioning and add it later only if: -- You have clear data lifecycle requirements (retention, archiving) -- Your access patterns clearly benefit from partition pruning -- You understand the cardinality implications - -**Example (start simple):** - -```sql --- Start simple, no partitioning -CREATE TABLE events ( - timestamp DateTime, - event_type LowCardinality(String), - user_id UInt64 -) -ENGINE = MergeTree() -ORDER BY (event_type, timestamp); - --- Add partitioning later if needed for lifecycle management --- (requires table recreation or materialized view migration) -``` - -**When to add partitioning:** - -| Need | Add Partitioning? | -|------|-------------------| -| Time-based data retention | Yes | -| Archive old data to cold storage | Yes | -| Query performance on time ranges | Maybe (test first) | -| No specific lifecycle needs | No | - -Reference: [Choosing a Partitioning Key](https://clickhouse.com/docs/best-practices/choosing-a-partitioning-key) diff --git a/clickhouse/skills/clickhouse/rules/schema-pk-cardinality-order.md b/clickhouse/skills/clickhouse/rules/schema-pk-cardinality-order.md deleted file mode 100644 index 654377d..0000000 --- a/clickhouse/skills/clickhouse/rules/schema-pk-cardinality-order.md +++ /dev/null @@ -1,45 +0,0 @@ ---- -title: Order Columns by Cardinality (Low to High) -impact: CRITICAL -impactDescription: "Enables granule skipping; high-cardinality first prevents index pruning" -tags: [schema, primary-key, cardinality, ORDER BY] ---- - -## Order Columns by Cardinality (Low to High) - -**Impact: CRITICAL** - -Since the sparse primary index operates on data blocks (granules) rather than individual rows, low-cardinality leading columns create more useful index entries that can skip entire blocks. Place lower-cardinality columns before higher-cardinality ones in the ordering key. - -**Incorrect (high cardinality first):** - -```sql --- UUID first means no pruning benefit -CREATE TABLE events (...) -ENGINE = MergeTree() -ORDER BY (event_id, event_type, timestamp); --- Every granule has different event_id values, index can't skip anything -``` - -**Correct (low cardinality first):** - -```sql --- Low cardinality first enables pruning -CREATE TABLE events (...) -ENGINE = MergeTree() -ORDER BY (event_type, event_date, event_id); --- Index can skip entire event_type groups -``` - -**Column Order Guidelines:** - -| Position | Cardinality | Examples | -|----------|-------------|----------| -| 1st | Low (few distinct values) | event_type, status, country | -| 2nd | Date (coarse granularity) | toDate(timestamp) | -| 3rd+ | Medium-High | user_id, session_id | -| Last | High (if needed) | event_id, uuid | - -**Tip:** Use `toDate(timestamp)` instead of raw `DateTime` columns when day-level filtering suffices - this reduces index size from 32-bit to 16-bit representations. - -Reference: [Choosing a Primary Key](https://clickhouse.com/docs/best-practices/choosing-a-primary-key) diff --git a/clickhouse/skills/clickhouse/rules/schema-pk-filter-on-orderby.md b/clickhouse/skills/clickhouse/rules/schema-pk-filter-on-orderby.md deleted file mode 100644 index feb6bba..0000000 --- a/clickhouse/skills/clickhouse/rules/schema-pk-filter-on-orderby.md +++ /dev/null @@ -1,52 +0,0 @@ ---- -title: Filter on ORDER BY Columns in Queries -impact: CRITICAL -impactDescription: "Skipping prefix columns prevents index usage" -tags: [schema, primary-key, WHERE, query] ---- - -## Filter on ORDER BY Columns in Queries - -**Impact: CRITICAL** - -Even with good schema design, queries must use ORDER BY columns to benefit. Skipping prefix columns or filtering on non-ORDER BY columns prevents index usage. - -**Incorrect (skips prefix or uses non-ORDER BY columns):** - -```sql --- Given: ORDER BY (tenant_id, event_type, timestamp) - --- Skips prefix columns - can't use index effectively -SELECT * FROM events WHERE event_type = 'click'; - --- Filter on column not in ORDER BY - full table scan -SELECT * FROM events WHERE user_agent LIKE '%Chrome%'; -``` - -**Correct (uses ORDER BY prefix):** - -```sql --- Given: ORDER BY (tenant_id, event_type, timestamp) - --- Full prefix match - best performance -SELECT * FROM events -WHERE tenant_id = 123 AND event_type = 'click'; - --- Partial prefix - still uses index -SELECT * FROM events WHERE tenant_id = 123; - --- Range on later column after equality on earlier -SELECT * FROM events -WHERE tenant_id = 123 AND event_type = 'click' AND timestamp >= '2024-01-01'; -``` - -**Index usage reference:** - -| Filter | Index Used? | -|--------|-------------| -| `WHERE tenant_id = 123` | Full | -| `WHERE tenant_id = 123 AND event_type = 'click'` | Full | -| `WHERE event_type = 'click'` | None (skipped prefix) | -| `WHERE timestamp > '2024-01-01'` | None (skipped both) | - -Reference: [Choosing a Primary Key](https://clickhouse.com/docs/best-practices/choosing-a-primary-key) diff --git a/clickhouse/skills/clickhouse/rules/schema-pk-plan-before-creation.md b/clickhouse/skills/clickhouse/rules/schema-pk-plan-before-creation.md deleted file mode 100644 index dede8d1..0000000 --- a/clickhouse/skills/clickhouse/rules/schema-pk-plan-before-creation.md +++ /dev/null @@ -1,64 +0,0 @@ ---- -title: Plan PRIMARY KEY Before Table Creation -impact: CRITICAL -impactDescription: "ORDER BY is immutable; wrong choice requires full data migration" -tags: [schema, primary-key, ORDER BY] ---- - -## Plan PRIMARY KEY Before Table Creation - -**Impact: CRITICAL** (immutable after creation) - -ClickHouse's ORDER BY clause defines physical data ordering and the sparse index. Unlike other databases, **ORDER BY cannot be modified after table creation**. A wrong choice requires creating a new table and migrating all data. - -**Incorrect (arbitrary ORDER BY without query analysis):** - -```sql --- Creating table without analyzing query patterns -CREATE TABLE events ( - event_id UUID, - user_id UInt64, - timestamp DateTime -) -ENGINE = MergeTree() -ORDER BY (event_id); -- Chosen arbitrarily - --- Later: "Most queries filter by user_id!" --- Cannot fix with: ALTER TABLE events MODIFY ORDER BY (user_id, timestamp) --- ERROR: Cannot modify ORDER BY -``` - -**Correct (query-driven ORDER BY selection):** - -```sql --- Step 1: Document query patterns BEFORE creating table -/* -Query Analysis: -- 60% of queries: WHERE user_id = ? AND timestamp BETWEEN ? AND ? -- 25% of queries: WHERE event_type = ? AND timestamp > ? -- 15% of queries: WHERE event_id = ? - -Conclusion: user_id and event_type are primary filters -*/ - --- Step 2: Create table with correct ORDER BY -CREATE TABLE events ( - event_id UUID DEFAULT generateUUIDv4(), - user_id UInt64, - event_type LowCardinality(String), - timestamp DateTime, - event_date Date DEFAULT toDate(timestamp) -) -ENGINE = MergeTree() -PARTITION BY toYYYYMM(event_date) -ORDER BY (user_id, event_date, event_id); -``` - -**Pre-creation checklist:** -- [ ] Listed top 5-10 query patterns -- [ ] Identified columns in WHERE clauses with frequency -- [ ] Prioritized columns that exclude large numbers of rows -- [ ] Ordered columns by cardinality (low first, high last) -- [ ] Limited to 4-5 key columns (typically sufficient) - -Reference: [Choosing a Primary Key](https://clickhouse.com/docs/best-practices/choosing-a-primary-key) diff --git a/clickhouse/skills/clickhouse/rules/schema-pk-prioritize-filters.md b/clickhouse/skills/clickhouse/rules/schema-pk-prioritize-filters.md deleted file mode 100644 index 2dee741..0000000 --- a/clickhouse/skills/clickhouse/rules/schema-pk-prioritize-filters.md +++ /dev/null @@ -1,44 +0,0 @@ ---- -title: Prioritize Filter Columns in ORDER BY -impact: CRITICAL -impactDescription: "Columns not in ORDER BY cause full table scans" -tags: [schema, primary-key, WHERE, filtering] ---- - -## Prioritize Filter Columns in ORDER BY - -**Impact: CRITICAL** - -Prioritize columns frequently used in query filters (WHERE clause), especially those that exclude large numbers of rows. Queries filtering on columns not in ORDER BY result in full table scans. - -**Incorrect (ORDER BY doesn't match query patterns):** - -```sql --- If most queries filter by tenant_id: -CREATE TABLE events (...) -ENGINE = MergeTree() -ORDER BY (event_id); -- Queries by tenant_id will full-scan! -``` - -**Correct (ORDER BY matches filter patterns):** - -```sql --- ORDER BY matches query filter patterns -CREATE TABLE events (...) -ENGINE = MergeTree() -ORDER BY (tenant_id, event_date, event_id); - --- Query now uses primary index: -SELECT * FROM events WHERE tenant_id = 123 AND event_date >= '2024-01-01'; -``` - -**Validation:** - -```sql --- Verify index usage -EXPLAIN indexes = 1 -SELECT * FROM events WHERE tenant_id = 123; --- Look for "PrimaryKey" with Key Condition -``` - -Reference: [Choosing a Primary Key](https://clickhouse.com/docs/best-practices/choosing-a-primary-key) diff --git a/clickhouse/skills/clickhouse/rules/schema-types-avoid-nullable.md b/clickhouse/skills/clickhouse/rules/schema-types-avoid-nullable.md deleted file mode 100644 index 0960c6a..0000000 --- a/clickhouse/skills/clickhouse/rules/schema-types-avoid-nullable.md +++ /dev/null @@ -1,55 +0,0 @@ ---- -title: Avoid Nullable Unless Semantically Required -impact: HIGH -impactDescription: "Nullable adds storage overhead; use DEFAULT values instead" -tags: [schema, data-types, Nullable, DEFAULT] ---- - -## Avoid Nullable Unless Semantically Required - -**Impact: HIGH** - -Nullable columns maintain a separate UInt8 column for tracking null values, increasing storage and degrading performance. Use DEFAULT values instead when feasible. - -**Incorrect (Nullable everywhere):** - -```sql -CREATE TABLE users ( - id Nullable(UInt64), -- IDs should never be null - name Nullable(String), -- Empty string is fine - age Nullable(UInt8), -- 0 is a valid default - login_count Nullable(UInt32) -- 0 is a valid default -) -``` - -**Correct (DEFAULT values, Nullable only when semantic):** - -```sql -CREATE TABLE users ( - id UInt64, -- Never null - name String DEFAULT '', -- Empty = unknown - age UInt8 DEFAULT 0, -- 0 = unknown - login_count UInt32 DEFAULT 0, -- 0 = never logged in - deleted_at Nullable(DateTime), -- NULL = not deleted (semantic!) - parent_id Nullable(UInt64) -- NULL = no parent (semantic!) -) -``` - -**When Nullable IS appropriate:** - -| Use Case | Why | -|----------|-----| -| `deleted_at` | NULL = "not deleted", timestamp = "deleted at X" | -| `parent_id` | NULL = "no parent", value = "has parent" | -| `discount_percent` | NULL = "no discount", 0 = "0% discount" | - -**Defaults instead of Nullable:** - -| Type | Default | -|------|---------| -| String | `''` (empty string) | -| UInt*/Int* | `0` | -| DateTime | `now()` or `toDateTime(0)` | -| UUID | `generateUUIDv4()` | - -Reference: [Select Data Types](https://clickhouse.com/docs/best-practices/select-data-types) diff --git a/clickhouse/skills/clickhouse/rules/schema-types-enum.md b/clickhouse/skills/clickhouse/rules/schema-types-enum.md deleted file mode 100644 index e9d0e96..0000000 --- a/clickhouse/skills/clickhouse/rules/schema-types-enum.md +++ /dev/null @@ -1,58 +0,0 @@ ---- -title: Use Enum for Finite Value Sets -impact: MEDIUM -impactDescription: "Insert-time validation and natural ordering; 1-2 bytes storage" -tags: [schema, data-types, Enum, validation] ---- - -## Use Enum for Finite Value Sets - -**Impact: MEDIUM** - -Enum types provide validation at insert time and enable queries that exploit natural ordering. Use Enum8 (up to 256 values) or Enum16 (up to 65,536 values). - -**Incorrect (String without validation):** - -```sql -CREATE TABLE orders ( - status String -- No validation, typos like "shiped" allowed -) - --- Ordering requires CASE statements -SELECT * FROM orders ORDER BY - CASE status - WHEN 'pending' THEN 1 - WHEN 'processing' THEN 2 - WHEN 'shipped' THEN 3 - END; -``` - -**Correct (Enum with validation and ordering):** - -```sql -CREATE TABLE orders ( - status Enum8('pending' = 1, 'processing' = 2, 'shipped' = 3, 'delivered' = 4) -) - --- Insert validation: invalid values rejected -INSERT INTO orders VALUES ('shiped'); -- ERROR: Unknown element 'shiped' - --- Natural ordering works automatically -SELECT * FROM orders ORDER BY status; -- Orders by enum value (1, 2, 3, 4) - --- Comparisons use natural order -SELECT * FROM orders WHERE status > 'processing'; -- shipped and delivered -``` - -**Enum Guidelines:** - -| Scenario | Use | -|----------|-----| -| Fixed set of values known at schema time | Enum8/Enum16 | -| Values may change frequently | LowCardinality(String) | -| Need insert-time validation | Enum | -| Need natural ordering in queries | Enum | -| < 256 distinct values | Enum8 (1 byte) | -| 256-65,536 distinct values | Enum16 (2 bytes) | - -Reference: [Select Data Types](https://clickhouse.com/docs/best-practices/select-data-types) diff --git a/clickhouse/skills/clickhouse/rules/schema-types-lowcardinality.md b/clickhouse/skills/clickhouse/rules/schema-types-lowcardinality.md deleted file mode 100644 index bc83b70..0000000 --- a/clickhouse/skills/clickhouse/rules/schema-types-lowcardinality.md +++ /dev/null @@ -1,58 +0,0 @@ ---- -title: Use LowCardinality for Repeated Strings -impact: HIGH -impactDescription: "Dictionary encoding for <10K unique values; significant storage reduction" -tags: [schema, data-types, LowCardinality, storage] ---- - -## Use LowCardinality for Repeated Strings - -**Impact: HIGH** - -String columns with repeated values store each value repeatedly. LowCardinality uses dictionary encoding for significant storage reduction. - -**Incorrect (plain String for repeated values):** - -```sql -CREATE TABLE events ( - country String, -- "United States" stored 500M times - browser String, -- "Chrome" stored 300M times - event_type String -- "page_view" stored 800M times -) -``` - -**Correct (LowCardinality for low unique counts):** - -```sql -CREATE TABLE events ( - country LowCardinality(String), -- ~200 unique values - browser LowCardinality(String), -- ~50 unique values - event_type LowCardinality(String) -- ~100 unique values -) -``` - -**When to use LowCardinality:** - -| Unique Values | Recommendation | -|---------------|----------------| -| < 10,000 | Use LowCardinality | -| > 10,000 | Use regular String | - -```sql --- Check cardinality before deciding -SELECT uniq(column_name) FROM table_name; -``` - -**LowCardinality vs FixedString:** - -Reserve `FixedString` for strictly fixed-length data (e.g., 2-char country codes). For most low-cardinality text, `LowCardinality(String)` outperforms `FixedString`. - -```sql --- FixedString: Only for truly fixed-length data -country_code FixedString(2), -- "US", "DE", "JP" - always 2 chars - --- LowCardinality: For variable-length low-cardinality strings -country_name LowCardinality(String), -- "United States", "Germany" -``` - -Reference: [Select Data Types](https://clickhouse.com/docs/best-practices/select-data-types) diff --git a/clickhouse/skills/clickhouse/rules/schema-types-minimize-bitwidth.md b/clickhouse/skills/clickhouse/rules/schema-types-minimize-bitwidth.md deleted file mode 100644 index 04ac139..0000000 --- a/clickhouse/skills/clickhouse/rules/schema-types-minimize-bitwidth.md +++ /dev/null @@ -1,49 +0,0 @@ ---- -title: Minimize Bit-Width for Numeric Types -impact: HIGH -impactDescription: "Smaller types reduce storage and improve cache efficiency" -tags: [schema, data-types, numeric, storage] ---- - -## Minimize Bit-Width for Numeric Types - -**Impact: HIGH** - -Select the smallest numeric type that accommodates your data range. Prefer unsigned types when negative values aren't needed. - -**Incorrect (oversized types):** - -```sql -CREATE TABLE metrics ( - status_code Int64, -- HTTP codes are 100-599 - age Int64, -- Human age fits in UInt8 - year Int64, -- Years fit in UInt16 - item_count Int64 -- Often small numbers -) -``` - -**Correct (right-sized types):** - -```sql -CREATE TABLE metrics ( - status_code UInt16, -- 0-65,535 (HTTP codes fit easily) - age UInt8, -- 0-255 (sufficient for age) - year UInt16, -- 0-65,535 (sufficient for years) - item_count UInt32 -- 0-4 billion (adjust based on actual max) -) -``` - -**Numeric Type Reference:** - -| Type | Range | Bytes | -|------|-------|-------| -| UInt8 | 0 to 255 | 1 | -| UInt16 | 0 to 65,535 | 2 | -| UInt32 | 0 to 4.3 billion | 4 | -| UInt64 | 0 to 18 quintillion | 8 | -| Int8 | -128 to 127 | 1 | -| Int16 | -32,768 to 32,767 | 2 | -| Int32 | -2.1 billion to 2.1 billion | 4 | -| Int64 | -9 quintillion to 9 quintillion | 8 | - -Reference: [Select Data Types](https://clickhouse.com/docs/best-practices/select-data-types) diff --git a/clickhouse/skills/clickhouse/rules/schema-types-native-types.md b/clickhouse/skills/clickhouse/rules/schema-types-native-types.md deleted file mode 100644 index 77a9067..0000000 --- a/clickhouse/skills/clickhouse/rules/schema-types-native-types.md +++ /dev/null @@ -1,51 +0,0 @@ ---- -title: Use Native Types Instead of String -impact: CRITICAL -impactDescription: "2-10x storage reduction; enables compression and correct semantics" -tags: [schema, data-types, storage] ---- - -## Use Native Types Instead of String - -**Impact: CRITICAL** - -Using String for all data wastes storage, prevents compression optimization, and makes comparisons slower. ClickHouse's column-oriented architecture benefits directly from optimal type selection. - -**Incorrect (String for everything):** - -```sql -CREATE TABLE events ( - event_id String, -- "550e8400-e29b-41d4-a716-446655440000" = 36 bytes - user_id String, -- "12345" = 5 bytes (no numeric operations) - created_at String, -- "2024-01-15 10:30:00" = 19 bytes - count String, -- "42" - can't do math! - is_active String -- "true" = 4 bytes -) -``` - -**Correct (native types):** - -```sql -CREATE TABLE events ( - event_id UUID DEFAULT generateUUIDv4(), -- 16 bytes (vs 36) - user_id UInt64, -- 8 bytes, numeric ops - created_at DateTime DEFAULT now(), -- 4 bytes (vs 19) - count UInt32 DEFAULT 0, -- 4 bytes, math works - is_active Bool DEFAULT true -- 1 byte (vs 4) -) -``` - -**Type Selection Quick Reference:** - -| Data | Use | Avoid | -|------|-----|-------| -| Sequential IDs | UInt32/UInt64 | String | -| UUIDs | UUID | String | -| Status/Category | Enum8 or LowCardinality(String) | String | -| Timestamps | DateTime | DateTime64, String | -| Dates only | Date or Date32 | DateTime, String | -| Counts | UInt8/16/32 (smallest that fits) | Int64, String | -| Money | Decimal(P,S) or Int64 (cents) | Float64, String | -| Booleans | Bool or UInt8 | String | - -Reference: [Select Data Types](https://clickhouse.com/docs/best-practices/select-data-types) diff --git a/command-code/README.md b/command-code/README.md index 1179907..1aebe5b 100644 --- a/command-code/README.md +++ b/command-code/README.md @@ -1,21 +1,9 @@ # command-code -Drive the Command Code CLI (`cmd`) from your coding agent, and dispatch it as a headless sub-agent that implements tasks or GitHub issues in parallel, each in its own git worktree. +Install: `/plugin install command-code@duyet-claude-plugins`. Needs `cmd` authenticated (`cmd login`), `git`, and `gh` for issues. -```bash -/plugin install command-code@duyet-claude-plugins -``` +- `command-code` skill: headless invocation and worktree dispatch rules. +- `/command-code:dispatch`: run tasks or issues as parallel workers. +- `cmd-dispatcher` agent: runs the dispatch loop. -## What ships - -- `command-code` skill. The headless invocation (`cmd -p ... --yolo --max-turns 100000 --skip-onboarding`), the worktree dispatch workflow, review and resume rules, and safety notes. -- `/command-code:dispatch` command. Turns issues or tasks into isolated workers, launches them, and reviews the branches. -- `cmd-dispatcher` agent. Runs the whole dispatch loop. - -## Safety - -`--yolo` removes the approval gate, so you review each diff before merging. Dispatch only with the user's consent, in a dedicated worktree on a branch, with "do not push" in the prompt. - -## Requirements - -`cmd` installed and authenticated (`cmd login`, check with `cmd status`), `git`, and `gh` for issue-based work. +`--yolo` removes the approval gate, so review every diff before merging. diff --git a/command-code/agents/cmd-dispatcher.md b/command-code/agents/cmd-dispatcher.md index e3d65b8..174fff6 100644 --- a/command-code/agents/cmd-dispatcher.md +++ b/command-code/agents/cmd-dispatcher.md @@ -4,8 +4,4 @@ description: Orchestrates the Command Code CLI (`cmd`) as headless sub-agents. U tools: Bash, Read, Edit, Write, Glob, Grep --- -# cmd dispatcher - -Run the dispatch workflow in `skills/command-code/SKILL.md`, using the steps in `commands/dispatch.md`. Do not deviate from the skill's invocation flags, consent, or isolation rules. - -Report a table of workers (slug, branch, worktree, log). As each finishes, give a short review of what changed, whether it is complete, and any deviations from the spec. End with what is ready to merge. +Run the dispatch workflow in `skills/command-code/SKILL.md` and `commands/dispatch.md` without deviating from its flags, consent, or isolation rules. Report workers as slug, branch, worktree, log, then a short review per finished worker. Done means each branch is reviewed and the report says what is ready to merge. diff --git a/command-code/commands/dispatch.md b/command-code/commands/dispatch.md index 57e82fe..22e33ea 100644 --- a/command-code/commands/dispatch.md +++ b/command-code/commands/dispatch.md @@ -6,9 +6,4 @@ description: Dispatch headless Command Code (`cmd`) workers to implement scoped Work: **$ARGUMENTS** -Follow the dispatch workflow in `skills/command-code/SKILL.md`. - -1. Turn `$ARGUMENTS` into independent units: one worker per issue number, or a larger task split into separately committable pieces. Dispatch only independent pieces now and list the rest as follow-ups. If the work is too small or not separable, offer to do it inline. -2. Check preconditions and get consent, then write a spec, create a worktree, and launch each worker as the skill describes. -3. Report each worker as slug, branch, worktree, and log path. -4. As workers finish, review each diff, note any that exited with code 8, run one consolidated verification, and report each branch as clean or needs-fix. Push and merge nothing without the user's say-so. +Follow `skills/command-code/SKILL.md`. Split the work into independent units (one worker per issue), list the rest as follow-ups, and offer to do too-small work inline. Report each worker as slug, branch, worktree, and log. When workers finish, review each diff, note exit code 8, verify once, and report each branch as clean or needs-fix. Push and merge nothing without the user's say-so. diff --git a/command-code/skills/command-code/SKILL.md b/command-code/skills/command-code/SKILL.md index 4099788..2308047 100644 --- a/command-code/skills/command-code/SKILL.md +++ b/command-code/skills/command-code/SKILL.md @@ -5,54 +5,16 @@ description: Run the Command Code CLI (`cmd`) and dispatch it as a headless sub- # Command Code (`cmd`) -`cmd` is a standalone terminal coding agent with its own model access, permissions, sessions, MCP support, and a "taste" layer that learns how the user writes code. Its best use here is as a headless sub-agent: you write a precise spec, give it an isolated worktree, and it implements, tests, and commits while you do other work. Run `cmd --help` for flags and subcommands. +Run `cmd --help` for flags. This skill holds the dispatch rules that `/command-code:dispatch` and `cmd-dispatcher` follow. -This skill is the single home for the dispatch rules. `/command-code:dispatch` and the `cmd-dispatcher` agent follow it. +Unattended invocation needs all of: `cmd -p "" --yolo --max-turns 100000 --skip-onboarding`. Without `-p` it opens a REPL. Without `--yolo` it hangs on the first permission prompt. The default turn cap is 10 and exit code 8 means it hit the cap with a half-done branch. `--skip-onboarding` stops the taste demo blocking. -## Headless invocation +Dispatch only independent, well-specified work. Do small, exploratory, or back-and-forth work yourself. -```bash -cmd -p "" --yolo --max-turns 100000 --skip-onboarding -``` - -Every flag is required for unattended runs. - -- `-p` runs once and exits. Without it `cmd` opens a REPL and waits for a human. -- `--yolo` skips every permission prompt. A headless run cannot answer them and hangs on the first action without it. -- `--max-turns 100000` removes the cap. The default is 10, and `cmd` exits with code 8 at the cap, leaving a half-done branch. -- `--skip-onboarding` stops the taste demo from blocking a fresh run. - -## When to dispatch - -Dispatch when the user asks for it, or when there is independent work (several issues or packages) that can each be handed off with a clear spec. Do it yourself when the task is small, exploratory, needs back-and-forth, or cannot yet be specified, because the handoff costs more than the work. - -## Dispatch workflow - -1. **Preconditions.** Run `cmd status` and stop if unauthenticated, since every worker would fail the same way. Get the user's explicit consent for `--yolo`, as workers run with no approval gate. If the host blocks the launch, surface it and ask. Do not work around it. -2. **Isolate.** One git worktree and branch per worker: `git worktree add -b feat/ `. Never run two workers in one directory, because they corrupt each other's edits and index. -3. **Write the spec.** `cmd` shares none of your context, so the prompt is the whole brief. Include: - - What and why, in a sentence or two. - - Exact file seams (`path:line`) and the pattern to copy. This is the biggest quality lever. - - Scope in and out, and style rules (match the repo, do not reformat unrelated code). - - "Do not run install or any full build." - - The exact conventional-commit message and "do not push". - - "Print a summary of files changed and deviations at the end." - - For a GitHub issue, tell it to run `gh issue view `, and still restate seams and constraints. - -4. **Launch in the background**, one log per worker. - - ```bash - ( cd && cmd -p "" --yolo --max-turns 100000 --skip-onboarding > .log 2>&1 ) & - ``` - -5. **Review.** When a worker finishes, read `git -C log --oneline ..HEAD` and `git diff --stat ..HEAD`, then the diff. Do not trust the log alone. -6. **Verify once.** Concurrent builds across worktrees cause out-of-memory failures, so run one typecheck and test pass after merging the branches into a single tree. -7. **Resume if needed.** Exit code 8 means unfinished. Prefer a fresh narrowly scoped `cmd -p` naming only the remaining work. `cmd -c -p "..."` reloads the whole prior conversation and can overflow context on a large session, so use it only for short ones. - -Nothing is pushed or merged without the user's approval. Treat `--yolo` as moving the approval gate to review time, and never put secrets in a prompt. - -## Taste and auth - -- `cmd taste learn ` learns house style from a repo. Run it once before dispatching into a taste-sensitive codebase. -- `cmd login` and `cmd status` handle auth. `/goal ""` inside a session sets a standing objective. +- Run `cmd status` first and stop if unauthenticated. Get the user's explicit consent for `--yolo`. If the host blocks the launch, surface it and ask. +- One git worktree and branch per worker. Never two workers in one directory. +- `cmd` shares none of your context, so the prompt is the whole brief: what and why, exact `path:line` seams and the pattern to copy, scope in and out, "do not run install or a full build", the exact conventional-commit message, "do not push", and "print files changed and deviations at the end". For an issue also say to run `gh issue view `. +- Launch in the background with one log per worker. +- Review each diff yourself, not just the log. Verify once after merging branches into one tree, since concurrent builds across worktrees run out of memory. +- On exit code 8 prefer a fresh narrowly scoped `cmd -p` over `cmd -c -p`, which reloads the whole conversation. +- Push and merge nothing without the user's approval. Never put secrets in a prompt. diff --git a/commit/README.md b/commit/README.md index 073e309..19f4d71 100644 --- a/commit/README.md +++ b/commit/README.md @@ -1,16 +1,6 @@ -# Commit plugin +# commit -Semantic commits, optionally pushed or opened as a PR. +Install: `/plugin install commit@duyet-claude-plugins` -## Install - -```text -/plugin install commit@duyet-claude-plugins -``` - -## What ships - -- `/commit:commit` - commit changes with a `type(scope): description` message -- `/commit:and-push` - commit and push -- `/commit:and-create-pr` - commit, push, and open a PR using `.pr-templates/` (feat, fix, default) -- `commit-workflow` skill - the shared rules for all three +- `/commit:commit`, `/commit:and-push`, `/commit:and-create-pr`: semantic commit, push, or PR. +- `commit-workflow` skill: shared rules. PR bodies use `.pr-templates/` (feature, bugfix, default). diff --git a/commit/skills/commit-workflow/SKILL.md b/commit/skills/commit-workflow/SKILL.md index f1d0903..faba1f3 100644 --- a/commit/skills/commit-workflow/SKILL.md +++ b/commit/skills/commit-workflow/SKILL.md @@ -5,14 +5,12 @@ description: Use when creating a semantic commit, committing and pushing, or ope # Commit workflow -1. Read git status, the diff against HEAD, the current branch, and recent commits to match the repo's style. -2. Split unrelated changes into separate commits. Stage only files that belong to the change, never unrelated dirty work. -3. Message format is `type(scope): description` in the imperative. Types: feat, fix, docs, style, refactor, test, chore. -4. Push only when asked. Prefer `--force-with-lease` and only when a forced update is requested. Do not rewrite history otherwise. +- Match the repo's recent commit style. Message format is `type(scope): description`, imperative. +- Split unrelated changes into separate commits. Stage only files that belong to the change. +- Push only when asked. Never rewrite history. Use `--force-with-lease` only on a requested forced update to a non-shared branch. -## Pull requests +Pull requests: -- On the default branch, first create a branch named `/`. -- Push with `git push -u origin `, then `gh pr create`. Title matches the commit message. Add `--draft` when asked. -- Body: use the repo's own PR template if it has one. Otherwise pick from `.pr-templates/` in this plugin by commit type: `fix` uses `bugfix.md`, `feat` uses `feature.md`, anything else uses `default.md`. Fill in the placeholders. If no template is found, write a short summary and change list. +- On the default branch, branch first as `/`. +- Title matches the commit message. Use the repo's own PR template if it has one, else `.pr-templates/` in this plugin by commit type: `fix` uses `bugfix.md`, `feat` uses `feature.md`, anything else `default.md`. Fill the placeholders. - Print the PR URL when done. diff --git a/fix/README.md b/fix/README.md index b181c63..0e5c021 100644 --- a/fix/README.md +++ b/fix/README.md @@ -1,16 +1,6 @@ -# Fix plugin +# fix -Find and fix failing tests, lint, type errors, and CI, then commit and push or open a PR. +Install: `/plugin install fix@duyet-claude-plugins` -## Install - -```text -/plugin install fix@duyet-claude-plugins -``` - -## What ships - -- `/fix:and-push` - fix, commit, push -- `/fix:and-update-pr` - fix an existing PR and push -- `/fix:and-create-pr` - fix and open a new PR -- `fix-workflow` skill - the fixing loop all three share +- `/fix:and-push`, `/fix:and-update-pr`, `/fix:and-create-pr`: fix failing checks, then push, update a PR, or open one. +- `fix-workflow` skill: the shared fixing rules. diff --git a/fix/skills/fix-workflow/SKILL.md b/fix/skills/fix-workflow/SKILL.md index c73d69a..e944af2 100644 --- a/fix/skills/fix-workflow/SKILL.md +++ b/fix/skills/fix-workflow/SKILL.md @@ -5,10 +5,8 @@ description: Use when fixing failing tests, lint, type errors, build, or CI, and # Fix workflow -1. Detect the project's checks from its config files (package scripts, `pyproject.toml`, `Cargo.toml`, `go.mod`, Makefile, CI workflow). Prefer the commands CI runs. -2. Reproduce the failure first. If the user pasted errors or test names, start from those. -3. Fix the root cause with the smallest change. Do not weaken or delete a test to make it pass. Mock external services unless the test is about the integration. -4. Re-run the failing check, then the wider suite when the change touches shared code. -5. For three or more independent failures in different areas, spawn one subagent per area and integrate the results yourself. -6. Stop after three failed attempts at one issue. Report what was tried and do not push broken code. -7. Commit with a semantic message per the `commit` plugin's `commit-workflow` skill, include only files you changed, then push. Never merge. +- Find the project's checks from its config and CI, and reproduce the failure first. +- Fix the root cause with the smallest change. Never weaken or delete a test to pass. +- Rerun the failing check, then the wider suite if shared code changed. Use one subagent per area for three or more independent failures. +- After three failed attempts on one issue, stop and report. Never push broken code. +- Commit per the `commit` plugin's `commit-workflow` skill, only files you changed. Never merge. diff --git a/frontend-design/README.md b/frontend-design/README.md index b8977a4..5152d95 100644 --- a/frontend-design/README.md +++ b/frontend-design/README.md @@ -1,11 +1,5 @@ -# Frontend design +# frontend-design -Build distinctive, production-grade frontends that avoid generic AI aesthetics. +Install: `/plugin install frontend-design@duyet-claude-plugins` -```bash -/plugin install frontend-design@duyet-claude-plugins -``` - -## Ships - -- `frontend-design` skill: pick a bold aesthetic direction, stack defaults (shadcn/ui, Tailwind, Recharts), a list of AI-design tells to avoid, and short implementation rules. +- `frontend-design` skill: pick a bold aesthetic direction, avoid generic AI design tells, and apply short implementation rules. diff --git a/frontend-design/skills/frontend-design/SKILL.md b/frontend-design/skills/frontend-design/SKILL.md index 6a1df10..7e3054e 100644 --- a/frontend-design/skills/frontend-design/SKILL.md +++ b/frontend-design/skills/frontend-design/SKILL.md @@ -13,12 +13,7 @@ State the purpose, the audience, and one aesthetic (for example editorial, bruta ## Stack defaults -Use what the project already has. Otherwise prefer: - -- Components: shadcn/ui, then Radix UI primitives, then Headless UI. Read the current shadcn docs or its MCP server instead of recalling the API. -- Styling: Tailwind with CSS variables for design tokens. -- Charts: Recharts for standard charts, D3 only for custom ones. -- Motion: CSS first, Framer Motion for orchestrated React animation. +Use what the project already has. Otherwise prefer shadcn/ui (read its current docs or MCP server), Tailwind with CSS variable tokens, Recharts, and CSS motion first. ## Avoid these tells @@ -36,11 +31,7 @@ Use what the project already has. Otherwise prefer: ## Implementation rules -- Server Components by default in Next.js. Add `"use client"` only for state, effects, or browser APIs, and keep those leaves small. -- Fetch in parallel, stream slow parts behind Suspense. -- Keep components small and composed. Split a file over about 100 lines. -- Accessible by default: semantic elements, visible focus, labeled controls, contrast that passes WCAG AA, `prefers-reduced-motion` respected. -- Responsive from the first draft. +Match the project's framework. Fetch in parallel and stream slow parts. Keep components small. Accessible by default (semantic elements, visible focus, WCAG AA contrast, `prefers-reduced-motion`) and responsive from the first draft. ## Before finishing diff --git a/github/README.md b/github/README.md index 7d9487e..58514f5 100644 --- a/github/README.md +++ b/github/README.md @@ -1,27 +1,10 @@ # GitHub plugin -GitHub operations with the `gh` CLI: PR babysitting, review-bot feedback, and bulk issue and PR changes. - -## Install - -```text -/plugin install github@duyet-claude-plugins -``` - -## What ships - -Skills: - -- `github-workflow` - rules for safe `gh` use -- `review-bots` - how to read CodeRabbit, Sourcery, and Gemini comments - -Commands: - -- `/github:babysit-pr` - fix CI, review comments, and conflicts until the PR is merge-ready -- `/github:watch-and-fix` - alias for babysit-pr -- `/github:review-and-merge` - triage open PRs, fix review feedback, and merge -- `/github:bulk-merge-prs` - merge approved PRs with passing CI -- `/github:bulk-close-issues` - close issues by label or query -- `/github:bulk-label` - label many issues or PRs - -Requires an authenticated `gh` CLI. +Install: `/plugin install github@duyet-claude-plugins`. Requires an authenticated `gh` CLI. + +- `github-workflow` skill: safety rules for `gh` use. +- `review-bots` skill: triage CodeRabbit, Sourcery, and Gemini comments. +- `/github:babysit-pr`: fix CI, comments, and conflicts until merge-ready. +- `/github:watch-and-fix`: alias for babysit-pr. +- `/github:review-and-merge`: triage open PRs, fix, and merge. +- `/github:bulk-merge-prs`, `/github:bulk-close-issues`, `/github:bulk-label`: bulk operations. diff --git a/github/commands/babysit-pr.md b/github/commands/babysit-pr.md index 27f9874..d1f3da4 100644 --- a/github/commands/babysit-pr.md +++ b/github/commands/babysit-pr.md @@ -20,8 +20,8 @@ Defaults: the current branch's PR, 10 iterations, 15 minute CI timeout. Without Refuse to run on the default branch or with uncommitted changes. Then repeat up to the iteration limit. 1. Wait for CI to finish, plus a short grace period for review bots to post. -2. For each failing check, read the failed logs (`gh run view --log-failed`), fix the root cause, and run the failing check locally before pushing. -3. Fetch every review comment: `gh api repos/{owner}/{repo}/pulls/{pr}/comments`, `.../issues/{pr}/comments`, and `gh pr view --json reviews`. See the `review-bots` skill for bot formats. Apply actionable ones. Skip a suggestion that is wrong or out of scope and say why in a reply. +2. For each failing check, read the failed logs (`gh run view --log-failed`), fix the root cause, and run the failing check locally before pushing. +3. Fetch every review comment: inline, issue, and review comments. See the `review-bots` skill for bot formats. Apply actionable ones. Skip a suggestion that is wrong or out of scope and say why in a reply. 4. Merge the base branch if the PR conflicts and resolve conflicts by intent, not by taking one side. 5. Commit with a semantic message and push. Never force-push to a shared branch. 6. Stop when CI is green with nothing unresolved, or when the limit is reached. On the limit, report what is still failing. diff --git a/github/commands/bulk-close-issues.md b/github/commands/bulk-close-issues.md index c75fd77..2b52120 100644 --- a/github/commands/bulk-close-issues.md +++ b/github/commands/bulk-close-issues.md @@ -3,46 +3,8 @@ allowed-tools: Bash(gh *) description: Close multiple GitHub issues by label or search query --- -# Bulk Close Issues +# Bulk close issues -Close multiple GitHub issues based on labels, status, or search criteria. +Usage: `/github:bulk-close-issues [--label ] [--search ] [--comment ] [--dry-run]` -## Usage - -```bash -/github:bulk-close-issues --label "wontfix" -/github:bulk-close-issues --label "duplicate" --comment "Closing as duplicate" -/github:bulk-close-issues --search "status:stale" -/github:bulk-close-issues --dry-run --label "wontfix" -``` - -## Options - -- `--label `: Close all issues with this label -- `--search `: Use GitHub search syntax to find issues -- `--comment `: Add closing comment to each issue -- `--state `: Filter by state (default: open) -- `--dry-run`: Preview what would be closed without executing - -## Examples - -```bash -# Close all stale issues -/github:bulk-close-issues --label "stale" - -# Close duplicates with comment -/github:bulk-close-issues --label "duplicate" --comment "Closing as duplicate of #123" - -# Close issues older than 90 days -/github:bulk-close-issues --search "updated:<2025-12-01" - -# Preview before closing -/github:bulk-close-issues --dry-run --label "wontfix" -``` - -## Implementation - -1. List matching issues with `gh issue list` -2. Show preview of affected issues -3. Confirm with user before closing -4. Close each issue with optional comment +List matches with `gh issue list`, show them, and confirm with the user before closing. `--dry-run` stops after the list. diff --git a/github/commands/bulk-label.md b/github/commands/bulk-label.md index ab0107d..7450656 100644 --- a/github/commands/bulk-label.md +++ b/github/commands/bulk-label.md @@ -3,50 +3,8 @@ allowed-tools: Bash(gh *) description: Add or remove labels across multiple issues or pull requests, selected by label or GitHub search query --- -# Bulk Label +# Bulk label -Add or remove labels from multiple issues or pull requests at once. +Usage: `/github:bulk-label [--add