From 8003fcbb59a6e28e60eb0be8237649f69a85dd26 Mon Sep 17 00:00:00 2001 From: Artur Do Lago Date: Wed, 14 Jan 2026 15:11:36 +0100 Subject: [PATCH] chore: apply local updates after upstream merge --- .agent-core/agent-core.jsonc | 27 +- .claude/skills/1password/SKILL.md | 53 + .../1password/references/cli-examples.md | 29 + .../1password/references/get-started.md | 17 + .claude/skills/agentdb-advanced/SKILL.md | 550 +++++++ .claude/skills/agentdb-learning/SKILL.md | 545 +++++++ .../skills/agentdb-memory-patterns/SKILL.md | 339 +++++ .claude/skills/agentdb-optimization/SKILL.md | 509 +++++++ .claude/skills/agentdb-vector-search/SKILL.md | 339 +++++ .claude/skills/agentic-jujutsu/SKILL.md | 645 +++++++++ .claude/skills/apple-notes/SKILL.md | 50 + .claude/skills/apple-reminders/SKILL.md | 67 + .claude/skills/bear-notes/SKILL.md | 79 + .claude/skills/bird/SKILL.md | 25 + .claude/skills/blogwatcher/SKILL.md | 46 + .claude/skills/blucli/SKILL.md | 27 + .claude/skills/brave-search/SKILL.md | 30 + .../skills/brave-search/scripts/content.mjs | 53 + .../skills/brave-search/scripts/search.mjs | 79 + .claude/skills/camsnap/SKILL.md | 25 + .claude/skills/clawdhub/SKILL.md | 53 + .claude/skills/coding-agent/SKILL.md | 274 ++++ .claude/skills/concept-exploration/SKILL.md | 101 ++ .claude/skills/deliberate-practice/SKILL.md | 92 ++ .claude/skills/discord/SKILL.md | 369 +++++ .claude/skills/earnings-intelligence/SKILL.md | 109 ++ .claude/skills/eightctl/SKILL.md | 29 + .claude/skills/financial-research/SKILL.md | 104 ++ .claude/skills/flow-nexus-neural/SKILL.md | 738 ++++++++++ .claude/skills/flow-nexus-platform/SKILL.md | 1157 +++++++++++++++ .claude/skills/flow-nexus-swarm/SKILL.md | 610 ++++++++ .claude/skills/food-order/SKILL.md | 41 + .claude/skills/gemini/SKILL.md | 23 + .claude/skills/gifgrep/SKILL.md | 47 + .claude/skills/github-code-review/SKILL.md | 1140 +++++++++++++++ .claude/skills/github-multi-repo/SKILL.md | 874 +++++++++++ .../skills/github-project-management/SKILL.md | 1277 +++++++++++++++++ .../skills/github-release-management/SKILL.md | 1081 ++++++++++++++ .../github-workflow-automation/SKILL.md | 1065 ++++++++++++++ .claude/skills/github/SKILL.md | 47 + .claude/skills/gog/SKILL.md | 36 + .claude/skills/goplaces/SKILL.md | 30 + .claude/skills/himalaya/SKILL.md | 217 +++ .../himalaya/references/configuration.md | 174 +++ .../references/message-composition.md | 182 +++ .claude/skills/hive-mind-advanced/SKILL.md | 712 +++++++++ .claude/skills/hooks-automation/SKILL.md | 1201 ++++++++++++++++ .claude/skills/imsg/SKILL.md | 25 + .claude/skills/investment-thesis/SKILL.md | 136 ++ .claude/skills/johny/SKILL.md | 6 +- .claude/skills/johny/scripts/johny-session.ts | 2 +- .claude/skills/local-places/SERVER_README.md | 101 ++ .claude/skills/local-places/SKILL.md | 91 ++ .claude/skills/local-places/pyproject.toml | 27 + .../local-places/src/local_places/__init__.py | 2 + .../__pycache__/__init__.cpython-314.pyc | Bin 0 -> 218 bytes .../__pycache__/google_places.cpython-314.pyc | Bin 0 -> 14487 bytes .../__pycache__/main.cpython-314.pyc | Bin 0 -> 3794 bytes .../__pycache__/schemas.cpython-314.pyc | Bin 0 -> 6290 bytes .../src/local_places/google_places.py | 314 ++++ .../local-places/src/local_places/main.py | 65 + .../local-places/src/local_places/schemas.py | 107 ++ .claude/skills/market-analysis/SKILL.md | 95 ++ .claude/skills/mcporter/SKILL.md | 38 + .claude/skills/model-usage/SKILL.md | 45 + .../model-usage/references/codexbar-cli.md | 28 + .../skills/model-usage/scripts/model_usage.py | 310 ++++ .claude/skills/nano-banana-pro/SKILL.md | 30 + .../nano-banana-pro/scripts/generate_image.py | 169 +++ .claude/skills/nano-pdf/SKILL.md | 20 + .claude/skills/news-digest/SKILL.md | 335 +++++ .../skills/news-digest/scripts/__init__.py | 29 + .../__pycache__/news_digest.cpython-313.pyc | Bin 0 -> 23323 bytes .../skills/news-digest/scripts/news_digest.py | 527 +++++++ .claude/skills/notion/SKILL.md | 156 ++ .claude/skills/obsidian/SKILL.md | 55 + .claude/skills/openai-image-gen/SKILL.md | 31 + .../skills/openai-image-gen/scripts/gen.py | 173 +++ .claude/skills/openai-whisper-api/SKILL.md | 43 + .../openai-whisper-api/scripts/transcribe.sh | 85 ++ .claude/skills/openai-whisper/SKILL.md | 19 + .claude/skills/openhue/SKILL.md | 30 + .claude/skills/oracle/SKILL.md | 105 ++ .claude/skills/ordercli/SKILL.md | 47 + .claude/skills/pair-programming/SKILL.md | 1202 ++++++++++++++++ .claude/skills/peekaboo/SKILL.md | 153 ++ .claude/skills/performance-analysis/SKILL.md | 563 ++++++++ .claude/skills/portfolio-analytics/SKILL.md | 117 ++ .claude/skills/problem-solving/SKILL.md | 107 ++ .claude/skills/progress-tracking/SKILL.md | 137 ++ .claude/skills/qmd/SKILL.md | 26 + .claude/skills/reasoningbank-agentdb/SKILL.md | 446 ++++++ .../reasoningbank-intelligence/SKILL.md | 201 +++ .claude/skills/risk-management/SKILL.md | 173 +++ .claude/skills/sag/SKILL.md | 62 + .claude/skills/session-logs/SKILL.md | 95 ++ .claude/skills/shared/SKILL.md | 2 +- .claude/skills/shared/scripts/zee-runner.ts | 2 +- .claude/skills/skill-builder/SKILL.md | 910 ++++++++++++ .claude/skills/slack/SKILL.md | 143 ++ .claude/skills/songsee/SKILL.md | 29 + .claude/skills/sonoscli/SKILL.md | 26 + .claude/skills/sparc-methodology/SKILL.md | 1115 ++++++++++++++ .claude/skills/spotify-player/SKILL.md | 34 + .claude/skills/stanley/SKILL.md | 2 +- .claude/skills/stanley/scripts/stanley-gui.ts | 4 +- .../skills/stanley/scripts/stanley-market.ts | 2 +- .../stanley/scripts/stanley-nautilus.ts | 2 +- .../stanley/scripts/stanley-portfolio.ts | 2 +- .../stanley/scripts/stanley-research.ts | 2 +- .claude/skills/stream-chain/SKILL.md | 563 ++++++++ .claude/skills/summarize/SKILL.md | 49 + .claude/skills/swarm-advanced/SKILL.md | 973 +++++++++++++ .claude/skills/swarm-orchestration/SKILL.md | 179 +++ .claude/skills/things-mac/SKILL.md | 61 + .claude/skills/tmux/SKILL.md | 121 ++ .claude/skills/tmux/scripts/find-sessions.sh | 112 ++ .claude/skills/tmux/scripts/wait-for-text.sh | 83 ++ .claude/skills/trello/SKILL.md | 84 ++ .claude/skills/verification-quality/SKILL.md | 649 +++++++++ .claude/skills/video-frames/SKILL.md | 29 + .claude/skills/video-frames/scripts/frame.sh | 81 ++ .claude/skills/wacli/SKILL.md | 42 + .claude/skills/weather/SKILL.md | 49 + .github/ISSUE_TEMPLATE/bug-report.yml | 6 +- .gitignore | 15 + AGENTS.md | 15 + CLAUDE.md | 29 +- agent-core | 1 + agent-core.json | 8 +- docs/ALPHA_RELEASE_TODO.md | 52 + docs/ENVIRONMENT_VARIABLES.md | 22 +- docs/PROVIDERS.md | 11 +- docs/ROADMAP.md | 2 +- docs/UPSTREAM-SYNC.md | 8 + docs/USER_GUIDE.md | 9 +- docs/architecture/ALWAYS-ON-PERSONAS.md | 28 +- install | 28 +- packages/agent-core/Dockerfile | 8 +- packages/agent-core/script/postinstall.mjs | 8 +- .../agent-core/script/publish-registries.ts | 72 +- packages/agent-core/script/publish.ts | 10 +- packages/agent-core/src/cli/cmd/daemon.ts | 482 ++++++- .../agent-core/src/cli/cmd/debug/memory.ts | 50 +- .../agent-core/src/cli/cmd/debug/status.ts | 139 ++ packages/agent-core/src/cli/cmd/mcp.ts | 9 +- packages/agent-core/src/cli/cmd/tui/app.tsx | 6 +- .../cli/cmd/tui/component/dialog-status.tsx | 2 +- .../cmd/tui/component/prompt/autocomplete.tsx | 11 +- .../cli/cmd/tui/component/prompt/index.tsx | 12 +- .../src/cli/cmd/tui/context/local.tsx | 44 +- .../src/cli/cmd/tui/util/clipboard.ts | 2 +- packages/agent-core/src/cli/cmd/uninstall.ts | 20 +- packages/agent-core/src/cli/cmd/upgrade.ts | 4 +- packages/agent-core/src/config/config.ts | 63 + .../src/diagnostics/check-engine.ts | 4 +- .../src/diagnostics/checks/config.ts | 1 + .../src/diagnostics/checks/integrity.ts | 225 ++- .../src/diagnostics/checks/providers.ts | 7 + packages/agent-core/src/index.ts | 3 +- packages/agent-core/src/installation/index.ts | 43 +- packages/agent-core/src/paths.ts | 177 +++ packages/agent-core/src/plugin/index.ts | 2 +- packages/opencode-anthropic-auth | 1 + packages/script/src/index.ts | 6 +- scripts/beta-readiness.sh | 54 + scripts/systemd/agent-core.service | 12 +- scripts/systemd/install.sh | 7 +- src/agent-types.ts | 294 ---- src/config/embedding-profiles.ts | 70 + src/config/runtime.ts | 203 +++ src/council/auth/google-antigravity-auth.ts | 529 ------- src/council/auth/index.ts | 8 - src/council/auth/storage.ts | 420 ------ src/council/council-coordinator.ts | 376 ----- src/council/council-providers.ts | 290 ---- src/council/council-stages.ts | 752 ---------- src/council/council-types.ts | 468 ------ src/council/index.ts | 241 ---- src/daemon/index.ts | 153 -- src/lsp/nvim-config.lua | 4 +- src/lsp/server.ts | 45 +- src/lsp/types.ts | 7 + src/mcp/servers/portfolio.ts | 31 +- src/memory/embedding.ts | 154 +- src/memory/qdrant.ts | 34 + src/memory/types.ts | 1 + src/memory/unified.ts | 84 +- src/model-catalog.ts | 120 -- src/paths.ts | 177 +++ src/personas/tiara.ts | 9 +- src/tiara.ts | 329 ----- src/util/grammar.ts | 62 + 193 files changed, 29487 insertions(+), 4287 deletions(-) create mode 100644 .claude/skills/1password/SKILL.md create mode 100644 .claude/skills/1password/references/cli-examples.md create mode 100644 .claude/skills/1password/references/get-started.md create mode 100644 .claude/skills/agentdb-advanced/SKILL.md create mode 100644 .claude/skills/agentdb-learning/SKILL.md create mode 100644 .claude/skills/agentdb-memory-patterns/SKILL.md create mode 100644 .claude/skills/agentdb-optimization/SKILL.md create mode 100644 .claude/skills/agentdb-vector-search/SKILL.md create mode 100644 .claude/skills/agentic-jujutsu/SKILL.md create mode 100644 .claude/skills/apple-notes/SKILL.md create mode 100644 .claude/skills/apple-reminders/SKILL.md create mode 100644 .claude/skills/bear-notes/SKILL.md create mode 100644 .claude/skills/bird/SKILL.md create mode 100644 .claude/skills/blogwatcher/SKILL.md create mode 100644 .claude/skills/blucli/SKILL.md create mode 100644 .claude/skills/brave-search/SKILL.md create mode 100644 .claude/skills/brave-search/scripts/content.mjs create mode 100644 .claude/skills/brave-search/scripts/search.mjs create mode 100644 .claude/skills/camsnap/SKILL.md create mode 100644 .claude/skills/clawdhub/SKILL.md create mode 100644 .claude/skills/coding-agent/SKILL.md create mode 100644 .claude/skills/concept-exploration/SKILL.md create mode 100644 .claude/skills/deliberate-practice/SKILL.md create mode 100644 .claude/skills/discord/SKILL.md create mode 100644 .claude/skills/earnings-intelligence/SKILL.md create mode 100644 .claude/skills/eightctl/SKILL.md create mode 100644 .claude/skills/financial-research/SKILL.md create mode 100644 .claude/skills/flow-nexus-neural/SKILL.md create mode 100644 .claude/skills/flow-nexus-platform/SKILL.md create mode 100644 .claude/skills/flow-nexus-swarm/SKILL.md create mode 100644 .claude/skills/food-order/SKILL.md create mode 100644 .claude/skills/gemini/SKILL.md create mode 100644 .claude/skills/gifgrep/SKILL.md create mode 100644 .claude/skills/github-code-review/SKILL.md create mode 100644 .claude/skills/github-multi-repo/SKILL.md create mode 100644 .claude/skills/github-project-management/SKILL.md create mode 100644 .claude/skills/github-release-management/SKILL.md create mode 100644 .claude/skills/github-workflow-automation/SKILL.md create mode 100644 .claude/skills/github/SKILL.md create mode 100644 .claude/skills/gog/SKILL.md create mode 100644 .claude/skills/goplaces/SKILL.md create mode 100644 .claude/skills/himalaya/SKILL.md create mode 100644 .claude/skills/himalaya/references/configuration.md create mode 100644 .claude/skills/himalaya/references/message-composition.md create mode 100644 .claude/skills/hive-mind-advanced/SKILL.md create mode 100644 .claude/skills/hooks-automation/SKILL.md create mode 100644 .claude/skills/imsg/SKILL.md create mode 100644 .claude/skills/investment-thesis/SKILL.md create mode 100644 .claude/skills/local-places/SERVER_README.md create mode 100644 .claude/skills/local-places/SKILL.md create mode 100644 .claude/skills/local-places/pyproject.toml create mode 100644 .claude/skills/local-places/src/local_places/__init__.py create mode 100644 .claude/skills/local-places/src/local_places/__pycache__/__init__.cpython-314.pyc create mode 100644 .claude/skills/local-places/src/local_places/__pycache__/google_places.cpython-314.pyc create mode 100644 .claude/skills/local-places/src/local_places/__pycache__/main.cpython-314.pyc create mode 100644 .claude/skills/local-places/src/local_places/__pycache__/schemas.cpython-314.pyc create mode 100644 .claude/skills/local-places/src/local_places/google_places.py create mode 100644 .claude/skills/local-places/src/local_places/main.py create mode 100644 .claude/skills/local-places/src/local_places/schemas.py create mode 100644 .claude/skills/market-analysis/SKILL.md create mode 100644 .claude/skills/mcporter/SKILL.md create mode 100644 .claude/skills/model-usage/SKILL.md create mode 100644 .claude/skills/model-usage/references/codexbar-cli.md create mode 100644 .claude/skills/model-usage/scripts/model_usage.py create mode 100644 .claude/skills/nano-banana-pro/SKILL.md create mode 100755 .claude/skills/nano-banana-pro/scripts/generate_image.py create mode 100644 .claude/skills/nano-pdf/SKILL.md create mode 100644 .claude/skills/news-digest/SKILL.md create mode 100644 .claude/skills/news-digest/scripts/__init__.py create mode 100644 .claude/skills/news-digest/scripts/__pycache__/news_digest.cpython-313.pyc create mode 100755 .claude/skills/news-digest/scripts/news_digest.py create mode 100644 .claude/skills/notion/SKILL.md create mode 100644 .claude/skills/obsidian/SKILL.md create mode 100644 .claude/skills/openai-image-gen/SKILL.md create mode 100644 .claude/skills/openai-image-gen/scripts/gen.py create mode 100644 .claude/skills/openai-whisper-api/SKILL.md create mode 100644 .claude/skills/openai-whisper-api/scripts/transcribe.sh create mode 100644 .claude/skills/openai-whisper/SKILL.md create mode 100644 .claude/skills/openhue/SKILL.md create mode 100644 .claude/skills/oracle/SKILL.md create mode 100644 .claude/skills/ordercli/SKILL.md create mode 100644 .claude/skills/pair-programming/SKILL.md create mode 100644 .claude/skills/peekaboo/SKILL.md create mode 100644 .claude/skills/performance-analysis/SKILL.md create mode 100644 .claude/skills/portfolio-analytics/SKILL.md create mode 100644 .claude/skills/problem-solving/SKILL.md create mode 100644 .claude/skills/progress-tracking/SKILL.md create mode 100644 .claude/skills/qmd/SKILL.md create mode 100644 .claude/skills/reasoningbank-agentdb/SKILL.md create mode 100644 .claude/skills/reasoningbank-intelligence/SKILL.md create mode 100644 .claude/skills/risk-management/SKILL.md create mode 100644 .claude/skills/sag/SKILL.md create mode 100644 .claude/skills/session-logs/SKILL.md create mode 100644 .claude/skills/skill-builder/SKILL.md create mode 100644 .claude/skills/slack/SKILL.md create mode 100644 .claude/skills/songsee/SKILL.md create mode 100644 .claude/skills/sonoscli/SKILL.md create mode 100644 .claude/skills/sparc-methodology/SKILL.md create mode 100644 .claude/skills/spotify-player/SKILL.md create mode 100644 .claude/skills/stream-chain/SKILL.md create mode 100644 .claude/skills/summarize/SKILL.md create mode 100644 .claude/skills/swarm-advanced/SKILL.md create mode 100644 .claude/skills/swarm-orchestration/SKILL.md create mode 100644 .claude/skills/things-mac/SKILL.md create mode 100644 .claude/skills/tmux/SKILL.md create mode 100755 .claude/skills/tmux/scripts/find-sessions.sh create mode 100755 .claude/skills/tmux/scripts/wait-for-text.sh create mode 100644 .claude/skills/trello/SKILL.md create mode 100644 .claude/skills/verification-quality/SKILL.md create mode 100644 .claude/skills/video-frames/SKILL.md create mode 100644 .claude/skills/video-frames/scripts/frame.sh create mode 100644 .claude/skills/wacli/SKILL.md create mode 100644 .claude/skills/weather/SKILL.md create mode 120000 agent-core create mode 100644 docs/ALPHA_RELEASE_TODO.md create mode 100644 packages/agent-core/src/paths.ts create mode 160000 packages/opencode-anthropic-auth create mode 100755 scripts/beta-readiness.sh delete mode 100644 src/agent-types.ts create mode 100644 src/config/embedding-profiles.ts create mode 100644 src/config/runtime.ts delete mode 100644 src/council/auth/google-antigravity-auth.ts delete mode 100644 src/council/auth/index.ts delete mode 100644 src/council/auth/storage.ts delete mode 100644 src/council/council-coordinator.ts delete mode 100644 src/council/council-providers.ts delete mode 100644 src/council/council-stages.ts delete mode 100644 src/council/council-types.ts delete mode 100644 src/council/index.ts delete mode 100644 src/model-catalog.ts create mode 100644 src/paths.ts delete mode 100644 src/tiara.ts create mode 100644 src/util/grammar.ts diff --git a/.agent-core/agent-core.jsonc b/.agent-core/agent-core.jsonc index a1fd443e27..62bddf4ee1 100644 --- a/.agent-core/agent-core.jsonc +++ b/.agent-core/agent-core.jsonc @@ -9,20 +9,39 @@ }, "personas-memory": { "type": "local", - "command": ["bun", "run", "~/.local/src/agent-core/src/mcp/servers/memory.ts"], + "command": ["bun", "run", "/home/artur/.local/src/agent-core/src/mcp/servers/memory.ts"], "enabled": true }, "personas-calendar": { "type": "local", - "command": ["bun", "run", "~/.local/src/agent-core/src/mcp/servers/calendar.ts"], + "command": ["bun", "run", "/home/artur/.local/src/agent-core/src/mcp/servers/calendar.ts"], "enabled": true }, "personas-portfolio": { "type": "local", - "command": ["bun", "run", "~/.local/src/agent-core/src/mcp/servers/portfolio.ts"], + "command": ["bun", "run", "/home/artur/.local/src/agent-core/src/mcp/servers/portfolio.ts"], "enabled": true } }, + "memory": { + "qdrant": { + "url": "http://localhost:6333", + "collection": "personas_memory" + }, + "embedding": { + "profile": "nebius/qwen3-embedding-8b", + "dimensions": 4096, + "apiKey": "{env:NEBIUS_API_KEY}" + } + }, + "tiara": { + "qdrant": { + "url": "http://localhost:6333", + "stateCollection": "personas_state", + "memoryCollection": "personas_memory", + "embeddingDimension": 4096 + } + }, "tools": { "github-triage": false, "github-pr-search": false @@ -44,10 +63,12 @@ "color": "#7fd88c" }, "title": { + "model": "google/antigravity-gemini-3-flash", "temperature": 0.5, "hidden": true }, "compaction": { + "model": "google/antigravity-gemini-3-flash", "temperature": 0.3, "hidden": true } diff --git a/.claude/skills/1password/SKILL.md b/.claude/skills/1password/SKILL.md new file mode 100644 index 0000000000..f80b68af9a --- /dev/null +++ b/.claude/skills/1password/SKILL.md @@ -0,0 +1,53 @@ +--- +name: 1password +description: Set up and use 1Password CLI (op). Use when installing the CLI, enabling desktop app integration, signing in (single or multi-account), or reading/injecting/running secrets via op. +homepage: https://developer.1password.com/docs/cli/get-started/ +metadata: {"zee":{"emoji":"๐Ÿ”","requires":{"bins":["op"]},"install":[{"id":"brew","kind":"brew","formula":"1password-cli","bins":["op"],"label":"Install 1Password CLI (brew)"}]}} +--- + +# 1Password CLI + +Follow the official CLI get-started steps. Don't guess install commands. + +## References + +- `references/get-started.md` (install + app integration + sign-in flow) +- `references/cli-examples.md` (real `op` examples) + +## Workflow + +1. Check OS + shell. +2. Verify CLI present: `op --version`. +3. Confirm desktop app integration is enabled (per get-started) and the app is unlocked. +4. REQUIRED: create a fresh tmux session for all `op` commands (no direct `op` calls outside tmux). +5. Sign in / authorize inside tmux: `op signin` (expect app prompt). +6. Verify access inside tmux: `op whoami` (must succeed before any secret read). +7. If multiple accounts: use `--account` or `OP_ACCOUNT`. + +## REQUIRED tmux session (T-Max) + +The shell tool uses a fresh TTY per command. To avoid re-prompts and failures, always run `op` inside a dedicated tmux session with a fresh socket/session name. + +Example (see `tmux` skill for socket conventions, do not reuse old session names): + +```bash +SOCKET_DIR="${ZEE_TMUX_SOCKET_DIR:-${TMPDIR:-/tmp}/zee-tmux-sockets}" +mkdir -p "$SOCKET_DIR" +SOCKET="$SOCKET_DIR/zee-op.sock" +SESSION="op-auth-$(date +%Y%m%d-%H%M%S)" + +tmux -S "$SOCKET" new -d -s "$SESSION" -n shell +tmux -S "$SOCKET" send-keys -t "$SESSION":0.0 -- "op signin --account my.1password.com" Enter +tmux -S "$SOCKET" send-keys -t "$SESSION":0.0 -- "op whoami" Enter +tmux -S "$SOCKET" send-keys -t "$SESSION":0.0 -- "op vault list" Enter +tmux -S "$SOCKET" capture-pane -p -J -t "$SESSION":0.0 -S -200 +tmux -S "$SOCKET" kill-session -t "$SESSION" +``` + +## Guardrails + +- Never paste secrets into logs, chat, or code. +- Prefer `op run` / `op inject` over writing secrets to disk. +- If sign-in without app integration is needed, use `op account add`. +- If a command returns "account is not signed in", re-run `op signin` inside tmux and authorize in the app. +- Do not run `op` outside tmux; stop and ask if tmux is unavailable. diff --git a/.claude/skills/1password/references/cli-examples.md b/.claude/skills/1password/references/cli-examples.md new file mode 100644 index 0000000000..c8da0972bc --- /dev/null +++ b/.claude/skills/1password/references/cli-examples.md @@ -0,0 +1,29 @@ +# op CLI examples (from op help) + +## Sign in + +- `op signin` +- `op signin --account ` + +## Read + +- `op read op://app-prod/db/password` +- `op read "op://app-prod/db/one-time password?attribute=otp"` +- `op read "op://app-prod/ssh key/private key?ssh-format=openssh"` +- `op read --out-file ./key.pem op://app-prod/server/ssh/key.pem` + +## Run + +- `export DB_PASSWORD="op://app-prod/db/password"` +- `op run --no-masking -- printenv DB_PASSWORD` +- `op run --env-file="./.env" -- printenv DB_PASSWORD` + +## Inject + +- `echo "db_password: {{ op://app-prod/db/password }}" | op inject` +- `op inject -i config.yml.tpl -o config.yml` + +## Whoami / accounts + +- `op whoami` +- `op account list` diff --git a/.claude/skills/1password/references/get-started.md b/.claude/skills/1password/references/get-started.md new file mode 100644 index 0000000000..3c60f75cea --- /dev/null +++ b/.claude/skills/1password/references/get-started.md @@ -0,0 +1,17 @@ +# 1Password CLI get-started (summary) + +- Works on macOS, Windows, and Linux. + - macOS/Linux shells: bash, zsh, sh, fish. + - Windows shell: PowerShell. +- Requires a 1Password subscription and the desktop app to use app integration. +- macOS requirement: Big Sur 11.0.0 or later. +- Linux app integration requires PolKit + an auth agent. +- Install the CLI per the official doc for your OS. +- Enable desktop app integration in the 1Password app: + - Open and unlock the app, then select your account/collection. + - macOS: Settings > Developer > Integrate with 1Password CLI (Touch ID optional). + - Windows: turn on Windows Hello, then Settings > Developer > Integrate. + - Linux: Settings > Security > Unlock using system authentication, then Settings > Developer > Integrate. +- After integration, run any command to sign in (example in docs: `op vault list`). +- If multiple accounts: use `op signin` to pick one, or `--account` / `OP_ACCOUNT`. +- For non-integration auth, use `op account add`. diff --git a/.claude/skills/agentdb-advanced/SKILL.md b/.claude/skills/agentdb-advanced/SKILL.md new file mode 100644 index 0000000000..da61dc2ead --- /dev/null +++ b/.claude/skills/agentdb-advanced/SKILL.md @@ -0,0 +1,550 @@ +--- +name: "AgentDB Advanced Features" +description: "Master advanced AgentDB features including QUIC synchronization, multi-database management, custom distance metrics, hybrid search, and distributed systems integration. Use when building distributed AI systems, multi-agent coordination, or advanced vector search applications." +--- + +# AgentDB Advanced Features + +## What This Skill Does + +Covers advanced AgentDB capabilities for distributed systems, multi-database coordination, custom distance metrics, hybrid search (vector + metadata), QUIC synchronization, and production deployment patterns. Enables building sophisticated AI systems with sub-millisecond cross-node communication and advanced search capabilities. + +**Performance**: <1ms QUIC sync, hybrid search with filters, custom distance metrics. + +## Prerequisites + +- Node.js 18+ +- AgentDB v1.0.7+ (via agentic-flow) +- Understanding of distributed systems (for QUIC sync) +- Vector search fundamentals + +--- + +## QUIC Synchronization + +### What is QUIC Sync? + +QUIC (Quick UDP Internet Connections) enables sub-millisecond latency synchronization between AgentDB instances across network boundaries with automatic retry, multiplexing, and encryption. + +**Benefits**: +- <1ms latency between nodes +- Multiplexed streams (multiple operations simultaneously) +- Built-in encryption (TLS 1.3) +- Automatic retry and recovery +- Event-based broadcasting + +### Enable QUIC Sync + +```typescript +import { createAgentDBAdapter } from 'agentic-flow/reasoningbank'; + +// Initialize with QUIC synchronization +const adapter = await createAgentDBAdapter({ + dbPath: '.agentdb/distributed.db', + enableQUICSync: true, + syncPort: 4433, + syncPeers: [ + '192.168.1.10:4433', + '192.168.1.11:4433', + '192.168.1.12:4433', + ], +}); + +// Patterns automatically sync across all peers +await adapter.insertPattern({ + // ... pattern data +}); + +// Available on all peers within ~1ms +``` + +### QUIC Configuration + +```typescript +const adapter = await createAgentDBAdapter({ + enableQUICSync: true, + syncPort: 4433, // QUIC server port + syncPeers: ['host1:4433'], // Peer addresses + syncInterval: 1000, // Sync interval (ms) + syncBatchSize: 100, // Patterns per batch + maxRetries: 3, // Retry failed syncs + compression: true, // Enable compression +}); +``` + +### Multi-Node Deployment + +```bash +# Node 1 (192.168.1.10) +AGENTDB_QUIC_SYNC=true \ +AGENTDB_QUIC_PORT=4433 \ +AGENTDB_QUIC_PEERS=192.168.1.11:4433,192.168.1.12:4433 \ +node server.js + +# Node 2 (192.168.1.11) +AGENTDB_QUIC_SYNC=true \ +AGENTDB_QUIC_PORT=4433 \ +AGENTDB_QUIC_PEERS=192.168.1.10:4433,192.168.1.12:4433 \ +node server.js + +# Node 3 (192.168.1.12) +AGENTDB_QUIC_SYNC=true \ +AGENTDB_QUIC_PORT=4433 \ +AGENTDB_QUIC_PEERS=192.168.1.10:4433,192.168.1.11:4433 \ +node server.js +``` + +--- + +## Distance Metrics + +### Cosine Similarity (Default) + +Best for normalized vectors, semantic similarity: + +```bash +# CLI +npx agentdb@latest query ./vectors.db "[0.1,0.2,...]" -m cosine + +# API +const result = await adapter.retrieveWithReasoning(queryEmbedding, { + metric: 'cosine', + k: 10, +}); +``` + +**Use Cases**: +- Text embeddings (BERT, GPT, etc.) +- Semantic search +- Document similarity +- Most general-purpose applications + +**Formula**: `cos(ฮธ) = (A ยท B) / (||A|| ร— ||B||)` +**Range**: [-1, 1] (1 = identical, -1 = opposite) + +### Euclidean Distance (L2) + +Best for spatial data, geometric similarity: + +```bash +# CLI +npx agentdb@latest query ./vectors.db "[0.1,0.2,...]" -m euclidean + +# API +const result = await adapter.retrieveWithReasoning(queryEmbedding, { + metric: 'euclidean', + k: 10, +}); +``` + +**Use Cases**: +- Image embeddings +- Spatial data +- Computer vision +- When vector magnitude matters + +**Formula**: `d = โˆš(ฮฃ(ai - bi)ยฒ)` +**Range**: [0, โˆž] (0 = identical, โˆž = very different) + +### Dot Product + +Best for pre-normalized vectors, fast computation: + +```bash +# CLI +npx agentdb@latest query ./vectors.db "[0.1,0.2,...]" -m dot + +# API +const result = await adapter.retrieveWithReasoning(queryEmbedding, { + metric: 'dot', + k: 10, +}); +``` + +**Use Cases**: +- Pre-normalized embeddings +- Fast similarity computation +- When vectors are already unit-length + +**Formula**: `dot = ฮฃ(ai ร— bi)` +**Range**: [-โˆž, โˆž] (higher = more similar) + +### Custom Distance Metrics + +```typescript +// Implement custom distance function +function customDistance(vec1: number[], vec2: number[]): number { + // Weighted Euclidean distance + const weights = [1.0, 2.0, 1.5, ...]; + let sum = 0; + for (let i = 0; i < vec1.length; i++) { + sum += weights[i] * Math.pow(vec1[i] - vec2[i], 2); + } + return Math.sqrt(sum); +} + +// Use in search (requires custom implementation) +``` + +--- + +## Hybrid Search (Vector + Metadata) + +### Basic Hybrid Search + +Combine vector similarity with metadata filtering: + +```typescript +// Store documents with metadata +await adapter.insertPattern({ + id: '', + type: 'document', + domain: 'research-papers', + pattern_data: JSON.stringify({ + embedding: documentEmbedding, + text: documentText, + metadata: { + author: 'Jane Smith', + year: 2025, + category: 'machine-learning', + citations: 150, + } + }), + confidence: 1.0, + usage_count: 0, + success_count: 0, + created_at: Date.now(), + last_used: Date.now(), +}); + +// Hybrid search: vector similarity + metadata filters +const result = await adapter.retrieveWithReasoning(queryEmbedding, { + domain: 'research-papers', + k: 20, + filters: { + year: { $gte: 2023 }, // Published 2023 or later + category: 'machine-learning', // ML papers only + citations: { $gte: 50 }, // Highly cited + }, +}); +``` + +### Advanced Filtering + +```typescript +// Complex metadata queries +const result = await adapter.retrieveWithReasoning(queryEmbedding, { + domain: 'products', + k: 50, + filters: { + price: { $gte: 10, $lte: 100 }, // Price range + category: { $in: ['electronics', 'gadgets'] }, // Multiple categories + rating: { $gte: 4.0 }, // High rated + inStock: true, // Available + tags: { $contains: 'wireless' }, // Has tag + }, +}); +``` + +### Weighted Hybrid Search + +Combine vector and metadata scores: + +```typescript +const result = await adapter.retrieveWithReasoning(queryEmbedding, { + domain: 'content', + k: 20, + hybridWeights: { + vectorSimilarity: 0.7, // 70% weight on semantic similarity + metadataScore: 0.3, // 30% weight on metadata match + }, + filters: { + category: 'technology', + recency: { $gte: Date.now() - 30 * 24 * 3600000 }, // Last 30 days + }, +}); +``` + +--- + +## Multi-Database Management + +### Multiple Databases + +```typescript +// Separate databases for different domains +const knowledgeDB = await createAgentDBAdapter({ + dbPath: '.agentdb/knowledge.db', +}); + +const conversationDB = await createAgentDBAdapter({ + dbPath: '.agentdb/conversations.db', +}); + +const codeDB = await createAgentDBAdapter({ + dbPath: '.agentdb/code.db', +}); + +// Use appropriate database for each task +await knowledgeDB.insertPattern({ /* knowledge */ }); +await conversationDB.insertPattern({ /* conversation */ }); +await codeDB.insertPattern({ /* code */ }); +``` + +### Database Sharding + +```typescript +// Shard by domain for horizontal scaling +const shards = { + 'domain-a': await createAgentDBAdapter({ dbPath: '.agentdb/shard-a.db' }), + 'domain-b': await createAgentDBAdapter({ dbPath: '.agentdb/shard-b.db' }), + 'domain-c': await createAgentDBAdapter({ dbPath: '.agentdb/shard-c.db' }), +}; + +// Route queries to appropriate shard +function getDBForDomain(domain: string) { + const shardKey = domain.split('-')[0]; // Extract shard key + return shards[shardKey] || shards['domain-a']; +} + +// Insert to correct shard +const db = getDBForDomain('domain-a-task'); +await db.insertPattern({ /* ... */ }); +``` + +--- + +## MMR (Maximal Marginal Relevance) + +Retrieve diverse results to avoid redundancy: + +```typescript +// Without MMR: Similar results may be redundant +const standardResults = await adapter.retrieveWithReasoning(queryEmbedding, { + k: 10, + useMMR: false, +}); + +// With MMR: Diverse, non-redundant results +const diverseResults = await adapter.retrieveWithReasoning(queryEmbedding, { + k: 10, + useMMR: true, + mmrLambda: 0.5, // Balance relevance (0) vs diversity (1) +}); +``` + +**MMR Parameters**: +- `mmrLambda = 0`: Maximum relevance (may be redundant) +- `mmrLambda = 0.5`: Balanced (default) +- `mmrLambda = 1`: Maximum diversity (may be less relevant) + +**Use Cases**: +- Search result diversification +- Recommendation systems +- Avoiding echo chambers +- Exploratory search + +--- + +## Context Synthesis + +Generate rich context from multiple memories: + +```typescript +const result = await adapter.retrieveWithReasoning(queryEmbedding, { + domain: 'problem-solving', + k: 10, + synthesizeContext: true, // Enable context synthesis +}); + +// ContextSynthesizer creates coherent narrative +console.log('Synthesized Context:', result.context); +// "Based on 10 similar problem-solving attempts, the most effective +// approach involves: 1) analyzing root cause, 2) brainstorming solutions, +// 3) evaluating trade-offs, 4) implementing incrementally. Success rate: 85%" + +console.log('Patterns:', result.patterns); +// Extracted common patterns across memories +``` + +--- + +## Production Patterns + +### Connection Pooling + +```typescript +// Singleton pattern for shared adapter +class AgentDBPool { + private static instance: AgentDBAdapter; + + static async getInstance() { + if (!this.instance) { + this.instance = await createAgentDBAdapter({ + dbPath: '.agentdb/production.db', + quantizationType: 'scalar', + cacheSize: 2000, + }); + } + return this.instance; + } +} + +// Use in application +const db = await AgentDBPool.getInstance(); +const results = await db.retrieveWithReasoning(queryEmbedding, { k: 10 }); +``` + +### Error Handling + +```typescript +async function safeRetrieve(queryEmbedding: number[], options: any) { + try { + const result = await adapter.retrieveWithReasoning(queryEmbedding, options); + return result; + } catch (error) { + if (error.code === 'DIMENSION_MISMATCH') { + console.error('Query embedding dimension mismatch'); + // Handle dimension error + } else if (error.code === 'DATABASE_LOCKED') { + // Retry with exponential backoff + await new Promise(resolve => setTimeout(resolve, 100)); + return safeRetrieve(queryEmbedding, options); + } + throw error; + } +} +``` + +### Monitoring and Logging + +```typescript +// Performance monitoring +const startTime = Date.now(); +const result = await adapter.retrieveWithReasoning(queryEmbedding, { k: 10 }); +const latency = Date.now() - startTime; + +if (latency > 100) { + console.warn('Slow query detected:', latency, 'ms'); +} + +// Log statistics +const stats = await adapter.getStats(); +console.log('Database Stats:', { + totalPatterns: stats.totalPatterns, + dbSize: stats.dbSize, + cacheHitRate: stats.cacheHitRate, + avgSearchLatency: stats.avgSearchLatency, +}); +``` + +--- + +## CLI Advanced Operations + +### Database Import/Export + +```bash +# Export with compression +npx agentdb@latest export ./vectors.db ./backup.json.gz --compress + +# Import from backup +npx agentdb@latest import ./backup.json.gz --decompress + +# Merge databases +npx agentdb@latest merge ./db1.sqlite ./db2.sqlite ./merged.sqlite +``` + +### Database Optimization + +```bash +# Vacuum database (reclaim space) +sqlite3 .agentdb/vectors.db "VACUUM;" + +# Analyze for query optimization +sqlite3 .agentdb/vectors.db "ANALYZE;" + +# Rebuild indices +npx agentdb@latest reindex ./vectors.db +``` + +--- + +## Environment Variables + +```bash +# AgentDB configuration +AGENTDB_PATH=.agentdb/reasoningbank.db +AGENTDB_ENABLED=true + +# Performance tuning +AGENTDB_QUANTIZATION=binary # binary|scalar|product|none +AGENTDB_CACHE_SIZE=2000 +AGENTDB_HNSW_M=16 +AGENTDB_HNSW_EF=100 + +# Learning plugins +AGENTDB_LEARNING=true + +# Reasoning agents +AGENTDB_REASONING=true + +# QUIC synchronization +AGENTDB_QUIC_SYNC=true +AGENTDB_QUIC_PORT=4433 +AGENTDB_QUIC_PEERS=host1:4433,host2:4433 +``` + +--- + +## Troubleshooting + +### Issue: QUIC sync not working + +```bash +# Check firewall allows UDP port 4433 +sudo ufw allow 4433/udp + +# Verify peers are reachable +ping host1 + +# Check QUIC logs +DEBUG=agentdb:quic node server.js +``` + +### Issue: Hybrid search returns no results + +```typescript +// Relax filters +const result = await adapter.retrieveWithReasoning(queryEmbedding, { + k: 100, // Increase k + filters: { + // Remove or relax filters + }, +}); +``` + +### Issue: Memory consolidation too aggressive + +```typescript +// Disable automatic optimization +const result = await adapter.retrieveWithReasoning(queryEmbedding, { + optimizeMemory: false, // Disable auto-consolidation + k: 10, +}); +``` + +--- + +## Learn More + +- **QUIC Protocol**: docs/quic-synchronization.pdf +- **Hybrid Search**: docs/hybrid-search-guide.md +- **GitHub**: https://github.com/ruvnet/agentic-flow/tree/main/packages/agentdb +- **Website**: https://agentdb.ruv.io + +--- + +**Category**: Advanced / Distributed Systems +**Difficulty**: Advanced +**Estimated Time**: 45-60 minutes diff --git a/.claude/skills/agentdb-learning/SKILL.md b/.claude/skills/agentdb-learning/SKILL.md new file mode 100644 index 0000000000..874760cf29 --- /dev/null +++ b/.claude/skills/agentdb-learning/SKILL.md @@ -0,0 +1,545 @@ +--- +name: "AgentDB Learning Plugins" +description: "Create and train AI learning plugins with AgentDB's 9 reinforcement learning algorithms. Includes Decision Transformer, Q-Learning, SARSA, Actor-Critic, and more. Use when building self-learning agents, implementing RL, or optimizing agent behavior through experience." +--- + +# AgentDB Learning Plugins + +## What This Skill Does + +Provides access to 9 reinforcement learning algorithms via AgentDB's plugin system. Create, train, and deploy learning plugins for autonomous agents that improve through experience. Includes offline RL (Decision Transformer), value-based learning (Q-Learning), policy gradients (Actor-Critic), and advanced techniques. + +**Performance**: Train models 10-100x faster with WASM-accelerated neural inference. + +## Prerequisites + +- Node.js 18+ +- AgentDB v1.0.7+ (via agentic-flow) +- Basic understanding of reinforcement learning (recommended) + +--- + +## Quick Start with CLI + +### Create Learning Plugin + +```bash +# Interactive wizard +npx agentdb@latest create-plugin + +# Use specific template +npx agentdb@latest create-plugin -t decision-transformer -n my-agent + +# Preview without creating +npx agentdb@latest create-plugin -t q-learning --dry-run + +# Custom output directory +npx agentdb@latest create-plugin -t actor-critic -o ./plugins +``` + +### List Available Templates + +```bash +# Show all plugin templates +npx agentdb@latest list-templates + +# Available templates: +# - decision-transformer (sequence modeling RL - recommended) +# - q-learning (value-based learning) +# - sarsa (on-policy TD learning) +# - actor-critic (policy gradient with baseline) +# - curiosity-driven (exploration-based) +``` + +### Manage Plugins + +```bash +# List installed plugins +npx agentdb@latest list-plugins + +# Get plugin information +npx agentdb@latest plugin-info my-agent + +# Shows: algorithm, configuration, training status +``` + +--- + +## Quick Start with API + +```typescript +import { createAgentDBAdapter } from 'agentic-flow/reasoningbank'; + +// Initialize with learning enabled +const adapter = await createAgentDBAdapter({ + dbPath: '.agentdb/learning.db', + enableLearning: true, // Enable learning plugins + enableReasoning: true, + cacheSize: 1000, +}); + +// Store training experience +await adapter.insertPattern({ + id: '', + type: 'experience', + domain: 'game-playing', + pattern_data: JSON.stringify({ + embedding: await computeEmbedding('state-action-reward'), + pattern: { + state: [0.1, 0.2, 0.3], + action: 2, + reward: 1.0, + next_state: [0.15, 0.25, 0.35], + done: false + } + }), + confidence: 0.9, + usage_count: 1, + success_count: 1, + created_at: Date.now(), + last_used: Date.now(), +}); + +// Train learning model +const metrics = await adapter.train({ + epochs: 50, + batchSize: 32, +}); + +console.log('Training Loss:', metrics.loss); +console.log('Duration:', metrics.duration, 'ms'); +``` + +--- + +## Available Learning Algorithms (9 Total) + +### 1. Decision Transformer (Recommended) + +**Type**: Offline Reinforcement Learning +**Best For**: Learning from logged experiences, imitation learning +**Strengths**: No online interaction needed, stable training + +```bash +npx agentdb@latest create-plugin -t decision-transformer -n dt-agent +``` + +**Use Cases**: +- Learn from historical data +- Imitation learning from expert demonstrations +- Safe learning without environment interaction +- Sequence modeling tasks + +**Configuration**: +```json +{ + "algorithm": "decision-transformer", + "model_size": "base", + "context_length": 20, + "embed_dim": 128, + "n_heads": 8, + "n_layers": 6 +} +``` + +### 2. Q-Learning + +**Type**: Value-Based RL (Off-Policy) +**Best For**: Discrete action spaces, sample efficiency +**Strengths**: Proven, simple, works well for small/medium problems + +```bash +npx agentdb@latest create-plugin -t q-learning -n q-agent +``` + +**Use Cases**: +- Grid worlds, board games +- Navigation tasks +- Resource allocation +- Discrete decision-making + +**Configuration**: +```json +{ + "algorithm": "q-learning", + "learning_rate": 0.001, + "gamma": 0.99, + "epsilon": 0.1, + "epsilon_decay": 0.995 +} +``` + +### 3. SARSA + +**Type**: Value-Based RL (On-Policy) +**Best For**: Safe exploration, risk-sensitive tasks +**Strengths**: More conservative than Q-Learning, better for safety + +```bash +npx agentdb@latest create-plugin -t sarsa -n sarsa-agent +``` + +**Use Cases**: +- Safety-critical applications +- Risk-sensitive decision-making +- Online learning with exploration + +**Configuration**: +```json +{ + "algorithm": "sarsa", + "learning_rate": 0.001, + "gamma": 0.99, + "epsilon": 0.1 +} +``` + +### 4. Actor-Critic + +**Type**: Policy Gradient with Value Baseline +**Best For**: Continuous actions, variance reduction +**Strengths**: Stable, works for continuous/discrete actions + +```bash +npx agentdb@latest create-plugin -t actor-critic -n ac-agent +``` + +**Use Cases**: +- Continuous control (robotics, simulations) +- Complex action spaces +- Multi-agent coordination + +**Configuration**: +```json +{ + "algorithm": "actor-critic", + "actor_lr": 0.001, + "critic_lr": 0.002, + "gamma": 0.99, + "entropy_coef": 0.01 +} +``` + +### 5. Active Learning + +**Type**: Query-Based Learning +**Best For**: Label-efficient learning, human-in-the-loop +**Strengths**: Minimizes labeling cost, focuses on uncertain samples + +**Use Cases**: +- Human feedback incorporation +- Label-efficient training +- Uncertainty sampling +- Annotation cost reduction + +### 6. Adversarial Training + +**Type**: Robustness Enhancement +**Best For**: Safety, robustness to perturbations +**Strengths**: Improves model robustness, adversarial defense + +**Use Cases**: +- Security applications +- Robust decision-making +- Adversarial defense +- Safety testing + +### 7. Curriculum Learning + +**Type**: Progressive Difficulty Training +**Best For**: Complex tasks, faster convergence +**Strengths**: Stable learning, faster convergence on hard tasks + +**Use Cases**: +- Complex multi-stage tasks +- Hard exploration problems +- Skill composition +- Transfer learning + +### 8. Federated Learning + +**Type**: Distributed Learning +**Best For**: Privacy, distributed data +**Strengths**: Privacy-preserving, scalable + +**Use Cases**: +- Multi-agent systems +- Privacy-sensitive data +- Distributed training +- Collaborative learning + +### 9. Multi-Task Learning + +**Type**: Transfer Learning +**Best For**: Related tasks, knowledge sharing +**Strengths**: Faster learning on new tasks, better generalization + +**Use Cases**: +- Task families +- Transfer learning +- Domain adaptation +- Meta-learning + +--- + +## Training Workflow + +### 1. Collect Experiences + +```typescript +// Store experiences during agent execution +for (let i = 0; i < numEpisodes; i++) { + const episode = runEpisode(); + + for (const step of episode.steps) { + await adapter.insertPattern({ + id: '', + type: 'experience', + domain: 'task-domain', + pattern_data: JSON.stringify({ + embedding: await computeEmbedding(JSON.stringify(step)), + pattern: { + state: step.state, + action: step.action, + reward: step.reward, + next_state: step.next_state, + done: step.done + } + }), + confidence: step.reward > 0 ? 0.9 : 0.5, + usage_count: 1, + success_count: step.reward > 0 ? 1 : 0, + created_at: Date.now(), + last_used: Date.now(), + }); + } +} +``` + +### 2. Train Model + +```typescript +// Train on collected experiences +const trainingMetrics = await adapter.train({ + epochs: 100, + batchSize: 64, + learningRate: 0.001, + validationSplit: 0.2, +}); + +console.log('Training Metrics:', trainingMetrics); +// { +// loss: 0.023, +// valLoss: 0.028, +// duration: 1523, +// epochs: 100 +// } +``` + +### 3. Evaluate Performance + +```typescript +// Retrieve similar successful experiences +const testQuery = await computeEmbedding(JSON.stringify(testState)); +const result = await adapter.retrieveWithReasoning(testQuery, { + domain: 'task-domain', + k: 10, + synthesizeContext: true, +}); + +// Evaluate action quality +const suggestedAction = result.memories[0].pattern.action; +const confidence = result.memories[0].similarity; + +console.log('Suggested Action:', suggestedAction); +console.log('Confidence:', confidence); +``` + +--- + +## Advanced Training Techniques + +### Experience Replay + +```typescript +// Store experiences in buffer +const replayBuffer = []; + +// Sample random batch for training +const batch = sampleRandomBatch(replayBuffer, batchSize: 32); + +// Train on batch +await adapter.train({ + data: batch, + epochs: 1, + batchSize: 32, +}); +``` + +### Prioritized Experience Replay + +```typescript +// Store experiences with priority (TD error) +await adapter.insertPattern({ + // ... standard fields + confidence: tdError, // Use TD error as confidence/priority + // ... +}); + +// Retrieve high-priority experiences +const highPriority = await adapter.retrieveWithReasoning(queryEmbedding, { + domain: 'task-domain', + k: 32, + minConfidence: 0.7, // Only high TD-error experiences +}); +``` + +### Multi-Agent Training + +```typescript +// Collect experiences from multiple agents +for (const agent of agents) { + const experience = await agent.step(); + + await adapter.insertPattern({ + // ... store experience with agent ID + domain: `multi-agent/${agent.id}`, + }); +} + +// Train shared model +await adapter.train({ + epochs: 50, + batchSize: 64, +}); +``` + +--- + +## Performance Optimization + +### Batch Training + +```typescript +// Collect batch of experiences +const experiences = collectBatch(size: 1000); + +// Batch insert (500x faster) +for (const exp of experiences) { + await adapter.insertPattern({ /* ... */ }); +} + +// Train on batch +await adapter.train({ + epochs: 10, + batchSize: 128, // Larger batch for efficiency +}); +``` + +### Incremental Learning + +```typescript +// Train incrementally as new data arrives +setInterval(async () => { + const newExperiences = getNewExperiences(); + + if (newExperiences.length > 100) { + await adapter.train({ + epochs: 5, + batchSize: 32, + }); + } +}, 60000); // Every minute +``` + +--- + +## Integration with Reasoning Agents + +Combine learning with reasoning for better performance: + +```typescript +// Train learning model +await adapter.train({ epochs: 50, batchSize: 32 }); + +// Use reasoning agents for inference +const result = await adapter.retrieveWithReasoning(queryEmbedding, { + domain: 'decision-making', + k: 10, + useMMR: true, // Diverse experiences + synthesizeContext: true, // Rich context + optimizeMemory: true, // Consolidate patterns +}); + +// Make decision based on learned experiences + reasoning +const decision = result.context.suggestedAction; +const confidence = result.memories[0].similarity; +``` + +--- + +## CLI Operations + +```bash +# Create plugin +npx agentdb@latest create-plugin -t decision-transformer -n my-plugin + +# List plugins +npx agentdb@latest list-plugins + +# Get plugin info +npx agentdb@latest plugin-info my-plugin + +# List templates +npx agentdb@latest list-templates +``` + +--- + +## Troubleshooting + +### Issue: Training not converging +```typescript +// Reduce learning rate +await adapter.train({ + epochs: 100, + batchSize: 32, + learningRate: 0.0001, // Lower learning rate +}); +``` + +### Issue: Overfitting +```typescript +// Use validation split +await adapter.train({ + epochs: 50, + batchSize: 64, + validationSplit: 0.2, // 20% validation +}); + +// Enable memory optimization +await adapter.retrieveWithReasoning(queryEmbedding, { + optimizeMemory: true, // Consolidate, reduce overfitting +}); +``` + +### Issue: Slow training +```bash +# Enable quantization for faster inference +# Use binary quantization (32x faster) +``` + +--- + +## Learn More + +- **Algorithm Papers**: See docs/algorithms/ for detailed papers +- **GitHub**: https://github.com/ruvnet/agentic-flow/tree/main/packages/agentdb +- **MCP Integration**: `npx agentdb@latest mcp` +- **Website**: https://agentdb.ruv.io + +--- + +**Category**: Machine Learning / Reinforcement Learning +**Difficulty**: Intermediate to Advanced +**Estimated Time**: 30-60 minutes diff --git a/.claude/skills/agentdb-memory-patterns/SKILL.md b/.claude/skills/agentdb-memory-patterns/SKILL.md new file mode 100644 index 0000000000..84a3f10698 --- /dev/null +++ b/.claude/skills/agentdb-memory-patterns/SKILL.md @@ -0,0 +1,339 @@ +--- +name: "AgentDB Memory Patterns" +description: "Implement persistent memory patterns for AI agents using AgentDB. Includes session memory, long-term storage, pattern learning, and context management. Use when building stateful agents, chat systems, or intelligent assistants." +--- + +# AgentDB Memory Patterns + +## What This Skill Does + +Provides memory management patterns for AI agents using AgentDB's persistent storage and ReasoningBank integration. Enables agents to remember conversations, learn from interactions, and maintain context across sessions. + +**Performance**: 150x-12,500x faster than traditional solutions with 100% backward compatibility. + +## Prerequisites + +- Node.js 18+ +- AgentDB v1.0.7+ (via agentic-flow or standalone) +- Understanding of agent architectures + +## Quick Start with CLI + +### Initialize AgentDB + +```bash +# Initialize vector database +npx agentdb@latest init ./agents.db + +# Or with custom dimensions +npx agentdb@latest init ./agents.db --dimension 768 + +# Use preset configurations +npx agentdb@latest init ./agents.db --preset large + +# In-memory database for testing +npx agentdb@latest init ./memory.db --in-memory +``` + +### Start MCP Server for Claude Code + +```bash +# Start MCP server (integrates with Claude Code) +npx agentdb@latest mcp + +# Add to Claude Code (one-time setup) +claude mcp add agentdb npx agentdb@latest mcp +``` + +### Create Learning Plugin + +```bash +# Interactive plugin wizard +npx agentdb@latest create-plugin + +# Use template directly +npx agentdb@latest create-plugin -t decision-transformer -n my-agent + +# Available templates: +# - decision-transformer (sequence modeling RL) +# - q-learning (value-based learning) +# - sarsa (on-policy TD learning) +# - actor-critic (policy gradient) +# - curiosity-driven (exploration-based) +``` + +## Quick Start with API + +```typescript +import { createAgentDBAdapter } from 'agentic-flow/reasoningbank'; + +// Initialize with default configuration +const adapter = await createAgentDBAdapter({ + dbPath: '.agentdb/reasoningbank.db', + enableLearning: true, // Enable learning plugins + enableReasoning: true, // Enable reasoning agents + quantizationType: 'scalar', // binary | scalar | product | none + cacheSize: 1000, // In-memory cache +}); + +// Store interaction memory +const patternId = await adapter.insertPattern({ + id: '', + type: 'pattern', + domain: 'conversation', + pattern_data: JSON.stringify({ + embedding: await computeEmbedding('What is the capital of France?'), + pattern: { + user: 'What is the capital of France?', + assistant: 'The capital of France is Paris.', + timestamp: Date.now() + } + }), + confidence: 0.95, + usage_count: 1, + success_count: 1, + created_at: Date.now(), + last_used: Date.now(), +}); + +// Retrieve context with reasoning +const context = await adapter.retrieveWithReasoning(queryEmbedding, { + domain: 'conversation', + k: 10, + useMMR: true, // Maximal Marginal Relevance + synthesizeContext: true, // Generate rich context +}); +``` + +## Memory Patterns + +### 1. Session Memory +```typescript +class SessionMemory { + async storeMessage(role: string, content: string) { + return await db.storeMemory({ + sessionId: this.sessionId, + role, + content, + timestamp: Date.now() + }); + } + + async getSessionHistory(limit = 20) { + return await db.query({ + filters: { sessionId: this.sessionId }, + orderBy: 'timestamp', + limit + }); + } +} +``` + +### 2. Long-Term Memory +```typescript +// Store important facts +await db.storeFact({ + category: 'user_preference', + key: 'language', + value: 'English', + confidence: 1.0, + source: 'explicit' +}); + +// Retrieve facts +const prefs = await db.getFacts({ + category: 'user_preference' +}); +``` + +### 3. Pattern Learning +```typescript +// Learn from successful interactions +await db.storePattern({ + trigger: 'user_asks_time', + response: 'provide_formatted_time', + success: true, + context: { timezone: 'UTC' } +}); + +// Apply learned patterns +const pattern = await db.matchPattern(currentContext); +``` + +## Advanced Patterns + +### Hierarchical Memory +```typescript +// Organize memory in hierarchy +await memory.organize({ + immediate: recentMessages, // Last 10 messages + shortTerm: sessionContext, // Current session + longTerm: importantFacts, // Persistent facts + semantic: embeddedKnowledge // Vector search +}); +``` + +### Memory Consolidation +```typescript +// Periodically consolidate memories +await memory.consolidate({ + strategy: 'importance', // Keep important memories + maxSize: 10000, // Size limit + minScore: 0.5 // Relevance threshold +}); +``` + +## CLI Operations + +### Query Database + +```bash +# Query with vector embedding +npx agentdb@latest query ./agents.db "[0.1,0.2,0.3,...]" + +# Top-k results +npx agentdb@latest query ./agents.db "[0.1,0.2,0.3]" -k 10 + +# With similarity threshold +npx agentdb@latest query ./agents.db "0.1 0.2 0.3" -t 0.75 + +# JSON output +npx agentdb@latest query ./agents.db "[...]" -f json +``` + +### Import/Export Data + +```bash +# Export vectors to file +npx agentdb@latest export ./agents.db ./backup.json + +# Import vectors from file +npx agentdb@latest import ./backup.json + +# Get database statistics +npx agentdb@latest stats ./agents.db +``` + +### Performance Benchmarks + +```bash +# Run performance benchmarks +npx agentdb@latest benchmark + +# Results show: +# - Pattern Search: 150x faster (100ยตs vs 15ms) +# - Batch Insert: 500x faster (2ms vs 1s) +# - Large-scale Query: 12,500x faster (8ms vs 100s) +``` + +## Integration with ReasoningBank + +```typescript +import { createAgentDBAdapter, migrateToAgentDB } from 'agentic-flow/reasoningbank'; + +// Migrate from legacy ReasoningBank +const result = await migrateToAgentDB( + '.swarm/memory.db', // Source (legacy) + '.agentdb/reasoningbank.db' // Destination (AgentDB) +); + +console.log(`โœ… Migrated ${result.patternsMigrated} patterns`); + +// Train learning model +const adapter = await createAgentDBAdapter({ + enableLearning: true, +}); + +await adapter.train({ + epochs: 50, + batchSize: 32, +}); + +// Get optimal strategy with reasoning +const result = await adapter.retrieveWithReasoning(queryEmbedding, { + domain: 'task-planning', + synthesizeContext: true, + optimizeMemory: true, +}); +``` + +## Learning Plugins + +### Available Algorithms (9 Total) + +1. **Decision Transformer** - Sequence modeling RL (recommended) +2. **Q-Learning** - Value-based learning +3. **SARSA** - On-policy TD learning +4. **Actor-Critic** - Policy gradient with baseline +5. **Active Learning** - Query selection +6. **Adversarial Training** - Robustness +7. **Curriculum Learning** - Progressive difficulty +8. **Federated Learning** - Distributed learning +9. **Multi-task Learning** - Transfer learning + +### List and Manage Plugins + +```bash +# List available plugins +npx agentdb@latest list-plugins + +# List plugin templates +npx agentdb@latest list-templates + +# Get plugin info +npx agentdb@latest plugin-info +``` + +## Reasoning Agents (4 Modules) + +1. **PatternMatcher** - Find similar patterns with HNSW indexing +2. **ContextSynthesizer** - Generate rich context from multiple sources +3. **MemoryOptimizer** - Consolidate similar patterns, prune low-quality +4. **ExperienceCurator** - Quality-based experience filtering + +## Best Practices + +1. **Enable quantization**: Use scalar/binary for 4-32x memory reduction +2. **Use caching**: 1000 pattern cache for <1ms retrieval +3. **Batch operations**: 500x faster than individual inserts +4. **Train regularly**: Update learning models with new experiences +5. **Enable reasoning**: Automatic context synthesis and optimization +6. **Monitor metrics**: Use `stats` command to track performance + +## Troubleshooting + +### Issue: Memory growing too large +```bash +# Check database size +npx agentdb@latest stats ./agents.db + +# Enable quantization +# Use 'binary' (32x smaller) or 'scalar' (4x smaller) +``` + +### Issue: Slow search performance +```bash +# Enable HNSW indexing and caching +# Results: <100ยตs search time +``` + +### Issue: Migration from legacy ReasoningBank +```bash +# Automatic migration with validation +npx agentdb@latest migrate --source .swarm/memory.db +``` + +## Performance Characteristics + +- **Vector Search**: <100ยตs (HNSW indexing) +- **Pattern Retrieval**: <1ms (with cache) +- **Batch Insert**: 2ms for 100 patterns +- **Memory Efficiency**: 4-32x reduction with quantization +- **Backward Compatibility**: 100% compatible with ReasoningBank API + +## Learn More + +- GitHub: https://github.com/ruvnet/agentic-flow/tree/main/packages/agentdb +- Documentation: node_modules/agentic-flow/docs/AGENTDB_INTEGRATION.md +- MCP Integration: `npx agentdb@latest mcp` for Claude Code +- Website: https://agentdb.ruv.io diff --git a/.claude/skills/agentdb-optimization/SKILL.md b/.claude/skills/agentdb-optimization/SKILL.md new file mode 100644 index 0000000000..f19df8617d --- /dev/null +++ b/.claude/skills/agentdb-optimization/SKILL.md @@ -0,0 +1,509 @@ +--- +name: "AgentDB Performance Optimization" +description: "Optimize AgentDB performance with quantization (4-32x memory reduction), HNSW indexing (150x faster search), caching, and batch operations. Use when optimizing memory usage, improving search speed, or scaling to millions of vectors." +--- + +# AgentDB Performance Optimization + +## What This Skill Does + +Provides comprehensive performance optimization techniques for AgentDB vector databases. Achieve 150x-12,500x performance improvements through quantization, HNSW indexing, caching strategies, and batch operations. Reduce memory usage by 4-32x while maintaining accuracy. + +**Performance**: <100ยตs vector search, <1ms pattern retrieval, 2ms batch insert for 100 vectors. + +## Prerequisites + +- Node.js 18+ +- AgentDB v1.0.7+ (via agentic-flow) +- Existing AgentDB database or application + +--- + +## Quick Start + +### Run Performance Benchmarks + +```bash +# Comprehensive performance benchmarking +npx agentdb@latest benchmark + +# Results show: +# โœ… Pattern Search: 150x faster (100ยตs vs 15ms) +# โœ… Batch Insert: 500x faster (2ms vs 1s for 100 vectors) +# โœ… Large-scale Query: 12,500x faster (8ms vs 100s at 1M vectors) +# โœ… Memory Efficiency: 4-32x reduction with quantization +``` + +### Enable Optimizations + +```typescript +import { createAgentDBAdapter } from 'agentic-flow/reasoningbank'; + +// Optimized configuration +const adapter = await createAgentDBAdapter({ + dbPath: '.agentdb/optimized.db', + quantizationType: 'binary', // 32x memory reduction + cacheSize: 1000, // In-memory cache + enableLearning: true, + enableReasoning: true, +}); +``` + +--- + +## Quantization Strategies + +### 1. Binary Quantization (32x Reduction) + +**Best For**: Large-scale deployments (1M+ vectors), memory-constrained environments +**Trade-off**: ~2-5% accuracy loss, 32x memory reduction, 10x faster + +```typescript +const adapter = await createAgentDBAdapter({ + quantizationType: 'binary', + // 768-dim float32 (3072 bytes) โ†’ 96 bytes binary + // 1M vectors: 3GB โ†’ 96MB +}); +``` + +**Use Cases**: +- Mobile/edge deployment +- Large-scale vector storage (millions of vectors) +- Real-time search with memory constraints + +**Performance**: +- Memory: 32x smaller +- Search Speed: 10x faster (bit operations) +- Accuracy: 95-98% of original + +### 2. Scalar Quantization (4x Reduction) + +**Best For**: Balanced performance/accuracy, moderate datasets +**Trade-off**: ~1-2% accuracy loss, 4x memory reduction, 3x faster + +```typescript +const adapter = await createAgentDBAdapter({ + quantizationType: 'scalar', + // 768-dim float32 (3072 bytes) โ†’ 768 bytes (uint8) + // 1M vectors: 3GB โ†’ 768MB +}); +``` + +**Use Cases**: +- Production applications requiring high accuracy +- Medium-scale deployments (10K-1M vectors) +- General-purpose optimization + +**Performance**: +- Memory: 4x smaller +- Search Speed: 3x faster +- Accuracy: 98-99% of original + +### 3. Product Quantization (8-16x Reduction) + +**Best For**: High-dimensional vectors, balanced compression +**Trade-off**: ~3-7% accuracy loss, 8-16x memory reduction, 5x faster + +```typescript +const adapter = await createAgentDBAdapter({ + quantizationType: 'product', + // 768-dim float32 (3072 bytes) โ†’ 48-96 bytes + // 1M vectors: 3GB โ†’ 192MB +}); +``` + +**Use Cases**: +- High-dimensional embeddings (>512 dims) +- Image/video embeddings +- Large-scale similarity search + +**Performance**: +- Memory: 8-16x smaller +- Search Speed: 5x faster +- Accuracy: 93-97% of original + +### 4. No Quantization (Full Precision) + +**Best For**: Maximum accuracy, small datasets +**Trade-off**: No accuracy loss, full memory usage + +```typescript +const adapter = await createAgentDBAdapter({ + quantizationType: 'none', + // Full float32 precision +}); +``` + +--- + +## HNSW Indexing + +**Hierarchical Navigable Small World** - O(log n) search complexity + +### Automatic HNSW + +AgentDB automatically builds HNSW indices: + +```typescript +const adapter = await createAgentDBAdapter({ + dbPath: '.agentdb/vectors.db', + // HNSW automatically enabled +}); + +// Search with HNSW (100ยตs vs 15ms linear scan) +const results = await adapter.retrieveWithReasoning(queryEmbedding, { + k: 10, +}); +``` + +### HNSW Parameters + +```typescript +// Advanced HNSW configuration +const adapter = await createAgentDBAdapter({ + dbPath: '.agentdb/vectors.db', + hnswM: 16, // Connections per layer (default: 16) + hnswEfConstruction: 200, // Build quality (default: 200) + hnswEfSearch: 100, // Search quality (default: 100) +}); +``` + +**Parameter Tuning**: +- **M** (connections): Higher = better recall, more memory + - Small datasets (<10K): M = 8 + - Medium datasets (10K-100K): M = 16 + - Large datasets (>100K): M = 32 +- **efConstruction**: Higher = better index quality, slower build + - Fast build: 100 + - Balanced: 200 (default) + - High quality: 400 +- **efSearch**: Higher = better recall, slower search + - Fast search: 50 + - Balanced: 100 (default) + - High recall: 200 + +--- + +## Caching Strategies + +### In-Memory Pattern Cache + +```typescript +const adapter = await createAgentDBAdapter({ + cacheSize: 1000, // Cache 1000 most-used patterns +}); + +// First retrieval: ~2ms (database) +// Subsequent: <1ms (cache hit) +const result = await adapter.retrieveWithReasoning(queryEmbedding, { + k: 10, +}); +``` + +**Cache Tuning**: +- Small applications: 100-500 patterns +- Medium applications: 500-2000 patterns +- Large applications: 2000-5000 patterns + +### LRU Cache Behavior + +```typescript +// Cache automatically evicts least-recently-used patterns +// Most frequently accessed patterns stay in cache + +// Monitor cache performance +const stats = await adapter.getStats(); +console.log('Cache Hit Rate:', stats.cacheHitRate); +// Aim for >80% hit rate +``` + +--- + +## Batch Operations + +### Batch Insert (500x Faster) + +```typescript +// โŒ SLOW: Individual inserts +for (const doc of documents) { + await adapter.insertPattern({ /* ... */ }); // 1s for 100 docs +} + +// โœ… FAST: Batch insert +const patterns = documents.map(doc => ({ + id: '', + type: 'document', + domain: 'knowledge', + pattern_data: JSON.stringify({ + embedding: doc.embedding, + text: doc.text, + }), + confidence: 1.0, + usage_count: 0, + success_count: 0, + created_at: Date.now(), + last_used: Date.now(), +})); + +// Insert all at once (2ms for 100 docs) +for (const pattern of patterns) { + await adapter.insertPattern(pattern); +} +``` + +### Batch Retrieval + +```typescript +// Retrieve multiple queries efficiently +const queries = [queryEmbedding1, queryEmbedding2, queryEmbedding3]; + +// Parallel retrieval +const results = await Promise.all( + queries.map(q => adapter.retrieveWithReasoning(q, { k: 5 })) +); +``` + +--- + +## Memory Optimization + +### Automatic Consolidation + +```typescript +// Enable automatic pattern consolidation +const result = await adapter.retrieveWithReasoning(queryEmbedding, { + domain: 'documents', + optimizeMemory: true, // Consolidate similar patterns + k: 10, +}); + +console.log('Optimizations:', result.optimizations); +// { +// consolidated: 15, // Merged 15 similar patterns +// pruned: 3, // Removed 3 low-quality patterns +// improved_quality: 0.12 // 12% quality improvement +// } +``` + +### Manual Optimization + +```typescript +// Manually trigger optimization +await adapter.optimize(); + +// Get statistics +const stats = await adapter.getStats(); +console.log('Before:', stats.totalPatterns); +console.log('After:', stats.totalPatterns); // Reduced by ~10-30% +``` + +### Pruning Strategies + +```typescript +// Prune low-confidence patterns +await adapter.prune({ + minConfidence: 0.5, // Remove confidence < 0.5 + minUsageCount: 2, // Remove usage_count < 2 + maxAge: 30 * 24 * 3600, // Remove >30 days old +}); +``` + +--- + +## Performance Monitoring + +### Database Statistics + +```bash +# Get comprehensive stats +npx agentdb@latest stats .agentdb/vectors.db + +# Output: +# Total Patterns: 125,430 +# Database Size: 47.2 MB (with binary quantization) +# Avg Confidence: 0.87 +# Domains: 15 +# Cache Hit Rate: 84% +# Index Type: HNSW +``` + +### Runtime Metrics + +```typescript +const stats = await adapter.getStats(); + +console.log('Performance Metrics:'); +console.log('Total Patterns:', stats.totalPatterns); +console.log('Database Size:', stats.dbSize); +console.log('Avg Confidence:', stats.avgConfidence); +console.log('Cache Hit Rate:', stats.cacheHitRate); +console.log('Search Latency (avg):', stats.avgSearchLatency); +console.log('Insert Latency (avg):', stats.avgInsertLatency); +``` + +--- + +## Optimization Recipes + +### Recipe 1: Maximum Speed (Sacrifice Accuracy) + +```typescript +const adapter = await createAgentDBAdapter({ + quantizationType: 'binary', // 32x memory reduction + cacheSize: 5000, // Large cache + hnswM: 8, // Fewer connections = faster + hnswEfSearch: 50, // Low search quality = faster +}); + +// Expected: <50ยตs search, 90-95% accuracy +``` + +### Recipe 2: Balanced Performance + +```typescript +const adapter = await createAgentDBAdapter({ + quantizationType: 'scalar', // 4x memory reduction + cacheSize: 1000, // Standard cache + hnswM: 16, // Balanced connections + hnswEfSearch: 100, // Balanced quality +}); + +// Expected: <100ยตs search, 98-99% accuracy +``` + +### Recipe 3: Maximum Accuracy + +```typescript +const adapter = await createAgentDBAdapter({ + quantizationType: 'none', // No quantization + cacheSize: 2000, // Large cache + hnswM: 32, // Many connections + hnswEfSearch: 200, // High search quality +}); + +// Expected: <200ยตs search, 100% accuracy +``` + +### Recipe 4: Memory-Constrained (Mobile/Edge) + +```typescript +const adapter = await createAgentDBAdapter({ + quantizationType: 'binary', // 32x memory reduction + cacheSize: 100, // Small cache + hnswM: 8, // Minimal connections +}); + +// Expected: <100ยตs search, ~10MB for 100K vectors +``` + +--- + +## Scaling Strategies + +### Small Scale (<10K vectors) + +```typescript +const adapter = await createAgentDBAdapter({ + quantizationType: 'none', // Full precision + cacheSize: 500, + hnswM: 8, +}); +``` + +### Medium Scale (10K-100K vectors) + +```typescript +const adapter = await createAgentDBAdapter({ + quantizationType: 'scalar', // 4x reduction + cacheSize: 1000, + hnswM: 16, +}); +``` + +### Large Scale (100K-1M vectors) + +```typescript +const adapter = await createAgentDBAdapter({ + quantizationType: 'binary', // 32x reduction + cacheSize: 2000, + hnswM: 32, +}); +``` + +### Massive Scale (>1M vectors) + +```typescript +const adapter = await createAgentDBAdapter({ + quantizationType: 'product', // 8-16x reduction + cacheSize: 5000, + hnswM: 48, + hnswEfConstruction: 400, +}); +``` + +--- + +## Troubleshooting + +### Issue: High memory usage + +```bash +# Check database size +npx agentdb@latest stats .agentdb/vectors.db + +# Enable quantization +# Use 'binary' for 32x reduction +``` + +### Issue: Slow search performance + +```typescript +// Increase cache size +const adapter = await createAgentDBAdapter({ + cacheSize: 2000, // Increase from 1000 +}); + +// Reduce search quality (faster) +const result = await adapter.retrieveWithReasoning(queryEmbedding, { + k: 5, // Reduce from 10 +}); +``` + +### Issue: Low accuracy + +```typescript +// Disable or use lighter quantization +const adapter = await createAgentDBAdapter({ + quantizationType: 'scalar', // Instead of 'binary' + hnswEfSearch: 200, // Higher search quality +}); +``` + +--- + +## Performance Benchmarks + +**Test System**: AMD Ryzen 9 5950X, 64GB RAM + +| Operation | Vector Count | No Optimization | Optimized | Improvement | +|-----------|-------------|-----------------|-----------|-------------| +| Search | 10K | 15ms | 100ยตs | 150x | +| Search | 100K | 150ms | 120ยตs | 1,250x | +| Search | 1M | 100s | 8ms | 12,500x | +| Batch Insert (100) | - | 1s | 2ms | 500x | +| Memory Usage | 1M | 3GB | 96MB | 32x (binary) | + +--- + +## Learn More + +- **Quantization Paper**: docs/quantization-techniques.pdf +- **HNSW Algorithm**: docs/hnsw-index.pdf +- **GitHub**: https://github.com/ruvnet/agentic-flow/tree/main/packages/agentdb +- **Website**: https://agentdb.ruv.io + +--- + +**Category**: Performance / Optimization +**Difficulty**: Intermediate +**Estimated Time**: 20-30 minutes diff --git a/.claude/skills/agentdb-vector-search/SKILL.md b/.claude/skills/agentdb-vector-search/SKILL.md new file mode 100644 index 0000000000..78cd76f1de --- /dev/null +++ b/.claude/skills/agentdb-vector-search/SKILL.md @@ -0,0 +1,339 @@ +--- +name: "AgentDB Vector Search" +description: "Implement semantic vector search with AgentDB for intelligent document retrieval, similarity matching, and context-aware querying. Use when building RAG systems, semantic search engines, or intelligent knowledge bases." +--- + +# AgentDB Vector Search + +## What This Skill Does + +Implements vector-based semantic search using AgentDB's high-performance vector database with **150x-12,500x faster** operations than traditional solutions. Features HNSW indexing, quantization, and sub-millisecond search (<100ยตs). + +## Prerequisites + +- Node.js 18+ +- AgentDB v1.0.7+ (via agentic-flow or standalone) +- OpenAI API key (for embeddings) or custom embedding model + +## Quick Start with CLI + +### Initialize Vector Database + +```bash +# Initialize with default dimensions (1536 for OpenAI ada-002) +npx agentdb@latest init ./vectors.db + +# Custom dimensions for different embedding models +npx agentdb@latest init ./vectors.db --dimension 768 # sentence-transformers +npx agentdb@latest init ./vectors.db --dimension 384 # all-MiniLM-L6-v2 + +# Use preset configurations +npx agentdb@latest init ./vectors.db --preset small # <10K vectors +npx agentdb@latest init ./vectors.db --preset medium # 10K-100K vectors +npx agentdb@latest init ./vectors.db --preset large # >100K vectors + +# In-memory database for testing +npx agentdb@latest init ./vectors.db --in-memory +``` + +### Query Vector Database + +```bash +# Basic similarity search +npx agentdb@latest query ./vectors.db "[0.1,0.2,0.3,...]" + +# Top-k results +npx agentdb@latest query ./vectors.db "[0.1,0.2,0.3]" -k 10 + +# With similarity threshold (cosine similarity) +npx agentdb@latest query ./vectors.db "0.1 0.2 0.3" -t 0.75 -m cosine + +# Different distance metrics +npx agentdb@latest query ./vectors.db "[...]" -m euclidean # L2 distance +npx agentdb@latest query ./vectors.db "[...]" -m dot # Dot product + +# JSON output for automation +npx agentdb@latest query ./vectors.db "[...]" -f json -k 5 + +# Verbose output with distances +npx agentdb@latest query ./vectors.db "[...]" -v +``` + +### Import/Export Vectors + +```bash +# Export vectors to JSON +npx agentdb@latest export ./vectors.db ./backup.json + +# Import vectors from JSON +npx agentdb@latest import ./backup.json + +# Get database statistics +npx agentdb@latest stats ./vectors.db +``` + +## Quick Start with API + +```typescript +import { createAgentDBAdapter, computeEmbedding } from 'agentic-flow/reasoningbank'; + +// Initialize with vector search optimizations +const adapter = await createAgentDBAdapter({ + dbPath: '.agentdb/vectors.db', + enableLearning: false, // Vector search only + enableReasoning: true, // Enable semantic matching + quantizationType: 'binary', // 32x memory reduction + cacheSize: 1000, // Fast retrieval +}); + +// Store document with embedding +const text = "The quantum computer achieved 100 qubits"; +const embedding = await computeEmbedding(text); + +await adapter.insertPattern({ + id: '', + type: 'document', + domain: 'technology', + pattern_data: JSON.stringify({ + embedding, + text, + metadata: { category: "quantum", date: "2025-01-15" } + }), + confidence: 1.0, + usage_count: 0, + success_count: 0, + created_at: Date.now(), + last_used: Date.now(), +}); + +// Semantic search with MMR (Maximal Marginal Relevance) +const queryEmbedding = await computeEmbedding("quantum computing advances"); +const results = await adapter.retrieveWithReasoning(queryEmbedding, { + domain: 'technology', + k: 10, + useMMR: true, // Diverse results + synthesizeContext: true, // Rich context +}); +``` + +## Core Features + +### 1. Vector Storage +```typescript +// Store with automatic embedding +await db.storeWithEmbedding({ + content: "Your document text", + metadata: { source: "docs", page: 42 } +}); +``` + +### 2. Similarity Search +```typescript +// Find similar documents +const similar = await db.findSimilar("quantum computing", { + limit: 5, + minScore: 0.75 +}); +``` + +### 3. Hybrid Search (Vector + Metadata) +```typescript +// Combine vector similarity with metadata filtering +const results = await db.hybridSearch({ + query: "machine learning models", + filters: { + category: "research", + date: { $gte: "2024-01-01" } + }, + limit: 20 +}); +``` + +## Advanced Usage + +### RAG (Retrieval Augmented Generation) +```typescript +// Build RAG pipeline +async function ragQuery(question: string) { + // 1. Get relevant context + const context = await db.searchSimilar( + await embed(question), + { limit: 5, threshold: 0.7 } + ); + + // 2. Generate answer with context + const prompt = `Context: ${context.map(c => c.text).join('\n')} +Question: ${question}`; + + return await llm.generate(prompt); +} +``` + +### Batch Operations +```typescript +// Efficient batch storage +await db.batchStore(documents.map(doc => ({ + text: doc.content, + embedding: doc.vector, + metadata: doc.meta +}))); +``` + +## MCP Server Integration + +```bash +# Start AgentDB MCP server for Claude Code +npx agentdb@latest mcp + +# Add to Claude Code (one-time setup) +claude mcp add agentdb npx agentdb@latest mcp + +# Now use MCP tools in Claude Code: +# - agentdb_query: Semantic vector search +# - agentdb_store: Store documents with embeddings +# - agentdb_stats: Database statistics +``` + +## Performance Benchmarks + +```bash +# Run comprehensive benchmarks +npx agentdb@latest benchmark + +# Results: +# โœ… Pattern Search: 150x faster (100ยตs vs 15ms) +# โœ… Batch Insert: 500x faster (2ms vs 1s for 100 vectors) +# โœ… Large-scale Query: 12,500x faster (8ms vs 100s at 1M vectors) +# โœ… Memory Efficiency: 4-32x reduction with quantization +``` + +## Quantization Options + +AgentDB provides multiple quantization strategies for memory efficiency: + +### Binary Quantization (32x reduction) +```typescript +const adapter = await createAgentDBAdapter({ + quantizationType: 'binary', // 768-dim โ†’ 96 bytes +}); +``` + +### Scalar Quantization (4x reduction) +```typescript +const adapter = await createAgentDBAdapter({ + quantizationType: 'scalar', // 768-dim โ†’ 768 bytes +}); +``` + +### Product Quantization (8-16x reduction) +```typescript +const adapter = await createAgentDBAdapter({ + quantizationType: 'product', // 768-dim โ†’ 48-96 bytes +}); +``` + +## Distance Metrics + +```bash +# Cosine similarity (default, best for most use cases) +npx agentdb@latest query ./db.sqlite "[...]" -m cosine + +# Euclidean distance (L2 norm) +npx agentdb@latest query ./db.sqlite "[...]" -m euclidean + +# Dot product (for normalized vectors) +npx agentdb@latest query ./db.sqlite "[...]" -m dot +``` + +## Advanced Features + +### HNSW Indexing +- **O(log n) search complexity** +- **Sub-millisecond retrieval** (<100ยตs) +- **Automatic index building** + +### Caching +- **1000 pattern in-memory cache** +- **<1ms pattern retrieval** +- **Automatic cache invalidation** + +### MMR (Maximal Marginal Relevance) +- **Diverse result sets** +- **Avoid redundancy** +- **Balance relevance and diversity** + +## Performance Tips + +1. **Enable HNSW indexing**: Automatic with AgentDB, 10-100x faster +2. **Use quantization**: Binary (32x), Scalar (4x), Product (8-16x) memory reduction +3. **Batch operations**: 500x faster for bulk inserts +4. **Match dimensions**: 1536 (OpenAI), 768 (sentence-transformers), 384 (MiniLM) +5. **Similarity threshold**: Start at 0.7 for quality, adjust based on use case +6. **Enable caching**: 1000 pattern cache for frequent queries + +## Troubleshooting + +### Issue: Slow search performance +```bash +# Check if HNSW indexing is enabled (automatic) +npx agentdb@latest stats ./vectors.db + +# Expected: <100ยตs search time +``` + +### Issue: High memory usage +```bash +# Enable binary quantization (32x reduction) +# Use in adapter: quantizationType: 'binary' +``` + +### Issue: Poor relevance +```bash +# Adjust similarity threshold +npx agentdb@latest query ./db.sqlite "[...]" -t 0.8 # Higher threshold + +# Or use MMR for diverse results +# Use in adapter: useMMR: true +``` + +### Issue: Wrong dimensions +```bash +# Check embedding model dimensions: +# - OpenAI ada-002: 1536 +# - sentence-transformers: 768 +# - all-MiniLM-L6-v2: 384 + +npx agentdb@latest init ./db.sqlite --dimension 768 +``` + +## Database Statistics + +```bash +# Get comprehensive stats +npx agentdb@latest stats ./vectors.db + +# Shows: +# - Total patterns/vectors +# - Database size +# - Average confidence +# - Domains distribution +# - Index status +``` + +## Performance Characteristics + +- **Vector Search**: <100ยตs (HNSW indexing) +- **Pattern Retrieval**: <1ms (with cache) +- **Batch Insert**: 2ms for 100 vectors +- **Memory Efficiency**: 4-32x reduction with quantization +- **Scalability**: Handles 1M+ vectors efficiently +- **Latency**: Sub-millisecond for most operations + +## Learn More + +- GitHub: https://github.com/ruvnet/agentic-flow/tree/main/packages/agentdb +- Documentation: node_modules/agentic-flow/docs/AGENTDB_INTEGRATION.md +- MCP Integration: `npx agentdb@latest mcp` for Claude Code +- Website: https://agentdb.ruv.io +- CLI Help: `npx agentdb@latest --help` +- Command Help: `npx agentdb@latest help ` diff --git a/.claude/skills/agentic-jujutsu/SKILL.md b/.claude/skills/agentic-jujutsu/SKILL.md new file mode 100644 index 0000000000..a5bf762c8a --- /dev/null +++ b/.claude/skills/agentic-jujutsu/SKILL.md @@ -0,0 +1,645 @@ +--- +name: agentic-jujutsu +version: 2.3.2 +description: Quantum-resistant, self-learning version control for AI agents with ReasoningBank intelligence and multi-agent coordination +--- + +# Agentic Jujutsu - AI Agent Version Control + +> Quantum-ready, self-learning version control designed for multiple AI agents working simultaneously without conflicts. + +## When to Use This Skill + +Use **agentic-jujutsu** when you need: +- โœ… Multiple AI agents modifying code simultaneously +- โœ… Lock-free version control (23x faster than Git) +- โœ… Self-learning AI that improves from experience +- โœ… Quantum-resistant security for future-proof protection +- โœ… Automatic conflict resolution (87% success rate) +- โœ… Pattern recognition and intelligent suggestions +- โœ… Multi-agent coordination without blocking + +## Quick Start + +### Installation + +```bash +npx agentic-jujutsu +``` + +### Basic Usage + +```javascript +const { JjWrapper } = require('agentic-jujutsu'); + +const jj = new JjWrapper(); + +// Basic operations +await jj.status(); +await jj.newCommit('Add feature'); +await jj.log(10); + +// Self-learning trajectory +const id = jj.startTrajectory('Implement authentication'); +await jj.branchCreate('feature/auth'); +await jj.newCommit('Add auth'); +jj.addToTrajectory(); +jj.finalizeTrajectory(0.9, 'Clean implementation'); + +// Get AI suggestions +const suggestion = JSON.parse(jj.getSuggestion('Add logout feature')); +console.log(`Confidence: ${suggestion.confidence}`); +``` + +## Core Capabilities + +### 1. Self-Learning with ReasoningBank + +Track operations, learn patterns, and get intelligent suggestions: + +```javascript +// Start learning trajectory +const trajectoryId = jj.startTrajectory('Deploy to production'); + +// Perform operations (automatically tracked) +await jj.execute(['git', 'push', 'origin', 'main']); +await jj.branchCreate('release/v1.0'); +await jj.newCommit('Release v1.0'); + +// Record operations to trajectory +jj.addToTrajectory(); + +// Finalize with success score (0.0-1.0) and critique +jj.finalizeTrajectory(0.95, 'Deployment successful, no issues'); + +// Later: Get AI-powered suggestions for similar tasks +const suggestion = JSON.parse(jj.getSuggestion('Deploy to staging')); +console.log('AI Recommendation:', suggestion.reasoning); +console.log('Confidence:', (suggestion.confidence * 100).toFixed(1) + '%'); +console.log('Expected Success:', (suggestion.expectedSuccessRate * 100).toFixed(1) + '%'); +``` + +**Validation (v2.3.1)**: +- โœ… Tasks must be non-empty (max 10KB) +- โœ… Success scores must be 0.0-1.0 +- โœ… Must have operations before finalizing +- โœ… Contexts cannot be empty + +### 2. Pattern Discovery + +Automatically identify successful operation sequences: + +```javascript +// Get discovered patterns +const patterns = JSON.parse(jj.getPatterns()); + +patterns.forEach(pattern => { + console.log(`Pattern: ${pattern.name}`); + console.log(` Success rate: ${(pattern.successRate * 100).toFixed(1)}%`); + console.log(` Used ${pattern.observationCount} times`); + console.log(` Operations: ${pattern.operationSequence.join(' โ†’ ')}`); + console.log(` Confidence: ${(pattern.confidence * 100).toFixed(1)}%`); +}); +``` + +### 3. Learning Statistics + +Track improvement over time: + +```javascript +const stats = JSON.parse(jj.getLearningStats()); + +console.log('Learning Progress:'); +console.log(` Total trajectories: ${stats.totalTrajectories}`); +console.log(` Patterns discovered: ${stats.totalPatterns}`); +console.log(` Average success: ${(stats.avgSuccessRate * 100).toFixed(1)}%`); +console.log(` Improvement rate: ${(stats.improvementRate * 100).toFixed(1)}%`); +console.log(` Prediction accuracy: ${(stats.predictionAccuracy * 100).toFixed(1)}%`); +``` + +### 4. Multi-Agent Coordination + +Multiple agents work concurrently without conflicts: + +```javascript +// Agent 1: Developer +const dev = new JjWrapper(); +dev.startTrajectory('Implement feature'); +await dev.newCommit('Add feature X'); +dev.addToTrajectory(); +dev.finalizeTrajectory(0.85); + +// Agent 2: Reviewer (learns from Agent 1) +const reviewer = new JjWrapper(); +const suggestion = JSON.parse(reviewer.getSuggestion('Review feature X')); + +if (suggestion.confidence > 0.7) { + console.log('High confidence approach:', suggestion.reasoning); +} + +// Agent 3: Tester (benefits from both) +const tester = new JjWrapper(); +const similar = JSON.parse(tester.queryTrajectories('test feature', 5)); +console.log(`Found ${similar.length} similar test approaches`); +``` + +### 5. Quantum-Resistant Security (v2.3.0+) + +Fast integrity verification with quantum-resistant cryptography: + +```javascript +const { generateQuantumFingerprint, verifyQuantumFingerprint } = require('agentic-jujutsu'); + +// Generate SHA3-512 fingerprint (NIST FIPS 202) +const data = Buffer.from('commit-data'); +const fingerprint = generateQuantumFingerprint(data); +console.log('Fingerprint:', fingerprint.toString('hex')); + +// Verify integrity (<1ms) +const isValid = verifyQuantumFingerprint(data, fingerprint); +console.log('Valid:', isValid); + +// HQC-128 encryption for trajectories +const crypto = require('crypto'); +const key = crypto.randomBytes(32).toString('base64'); +jj.enableEncryption(key); +``` + +### 6. Operation Tracking with AgentDB + +Automatic tracking of all operations: + +```javascript +// Operations are tracked automatically +await jj.status(); +await jj.newCommit('Fix bug'); +await jj.rebase('main'); + +// Get operation statistics +const stats = JSON.parse(jj.getStats()); +console.log(`Total operations: ${stats.total_operations}`); +console.log(`Success rate: ${(stats.success_rate * 100).toFixed(1)}%`); +console.log(`Avg duration: ${stats.avg_duration_ms.toFixed(2)}ms`); + +// Query recent operations +const ops = jj.getOperations(10); +ops.forEach(op => { + console.log(`${op.operationType}: ${op.command}`); + console.log(` Duration: ${op.durationMs}ms, Success: ${op.success}`); +}); + +// Get user operations (excludes snapshots) +const userOps = jj.getUserOperations(20); +``` + +## Advanced Use Cases + +### Use Case 1: Adaptive Workflow Optimization + +Learn and improve deployment workflows: + +```javascript +async function adaptiveDeployment(jj, environment) { + // Get AI suggestion based on past deployments + const suggestion = JSON.parse(jj.getSuggestion(`Deploy to ${environment}`)); + + console.log(`Deploying with ${(suggestion.confidence * 100).toFixed(0)}% confidence`); + console.log(`Expected duration: ${suggestion.estimatedDurationMs}ms`); + + // Start tracking + jj.startTrajectory(`Deploy to ${environment}`); + + // Execute recommended operations + for (const op of suggestion.recommendedOperations) { + console.log(`Executing: ${op}`); + await executeOperation(op); + } + + jj.addToTrajectory(); + + // Record outcome + const success = await verifyDeployment(); + jj.finalizeTrajectory( + success ? 0.95 : 0.5, + success ? 'Deployment successful' : 'Issues detected' + ); +} +``` + +### Use Case 2: Multi-Agent Code Review + +Coordinate review across multiple agents: + +```javascript +async function coordinatedReview(agents) { + const reviews = await Promise.all(agents.map(async (agent) => { + const jj = new JjWrapper(); + + // Start review trajectory + jj.startTrajectory(`Review by ${agent.name}`); + + // Get AI suggestion for review approach + const suggestion = JSON.parse(jj.getSuggestion('Code review')); + + // Perform review + const diff = await jj.diff('@', '@-'); + const issues = await agent.analyze(diff); + + jj.addToTrajectory(); + jj.finalizeTrajectory( + issues.length === 0 ? 0.9 : 0.6, + `Found ${issues.length} issues` + ); + + return { agent: agent.name, issues, suggestion }; + })); + + // Aggregate learning from all agents + return reviews; +} +``` + +### Use Case 3: Error Pattern Detection + +Learn from failures to prevent future issues: + +```javascript +async function smartMerge(jj, branch) { + // Query similar merge attempts + const similar = JSON.parse(jj.queryTrajectories(`merge ${branch}`, 10)); + + // Analyze past failures + const failures = similar.filter(t => t.successScore < 0.5); + + if (failures.length > 0) { + console.log('โš ๏ธ Similar merges failed in the past:'); + failures.forEach(f => { + if (f.critique) { + console.log(` - ${f.critique}`); + } + }); + } + + // Get AI recommendation + const suggestion = JSON.parse(jj.getSuggestion(`merge ${branch}`)); + + if (suggestion.confidence < 0.7) { + console.log('โš ๏ธ Low confidence. Recommended steps:'); + suggestion.recommendedOperations.forEach(op => console.log(` - ${op}`)); + } + + // Execute merge with tracking + jj.startTrajectory(`Merge ${branch}`); + try { + await jj.execute(['merge', branch]); + jj.addToTrajectory(); + jj.finalizeTrajectory(0.9, 'Merge successful'); + } catch (err) { + jj.addToTrajectory(); + jj.finalizeTrajectory(0.3, `Merge failed: ${err.message}`); + throw err; + } +} +``` + +### Use Case 4: Continuous Learning Loop + +Implement a self-improving agent: + +```javascript +class SelfImprovingAgent { + constructor() { + this.jj = new JjWrapper(); + } + + async performTask(taskDescription) { + // Get AI suggestion + const suggestion = JSON.parse(this.jj.getSuggestion(taskDescription)); + + console.log(`Task: ${taskDescription}`); + console.log(`AI Confidence: ${(suggestion.confidence * 100).toFixed(1)}%`); + console.log(`Expected Success: ${(suggestion.expectedSuccessRate * 100).toFixed(1)}%`); + + // Start trajectory + this.jj.startTrajectory(taskDescription); + + // Execute with recommended approach + const startTime = Date.now(); + let success = false; + + try { + for (const op of suggestion.recommendedOperations) { + await this.execute(op); + } + success = true; + } catch (err) { + console.error('Task failed:', err.message); + } + + const duration = Date.now() - startTime; + + // Record learning + this.jj.addToTrajectory(); + this.jj.finalizeTrajectory( + success ? 0.9 : 0.4, + success + ? `Completed in ${duration}ms using ${suggestion.recommendedOperations.length} operations` + : `Failed after ${duration}ms` + ); + + // Check improvement + const stats = JSON.parse(this.jj.getLearningStats()); + console.log(`Improvement rate: ${(stats.improvementRate * 100).toFixed(1)}%`); + + return success; + } + + async execute(operation) { + // Execute operation logic + } +} + +// Usage +const agent = new SelfImprovingAgent(); + +// Agent improves over time +for (let i = 1; i <= 10; i++) { + console.log(`\n--- Attempt ${i} ---`); + await agent.performTask('Deploy application'); +} +``` + +## API Reference + +### Core Methods + +| Method | Description | Returns | +|--------|-------------|---------| +| `new JjWrapper()` | Create wrapper instance | JjWrapper | +| `status()` | Get repository status | Promise | +| `newCommit(msg)` | Create new commit | Promise | +| `log(limit)` | Show commit history | Promise | +| `diff(from, to)` | Show differences | Promise | +| `branchCreate(name, rev?)` | Create branch | Promise | +| `rebase(source, dest)` | Rebase commits | Promise | + +### ReasoningBank Methods + +| Method | Description | Returns | +|--------|-------------|---------| +| `startTrajectory(task)` | Begin learning trajectory | string (trajectory ID) | +| `addToTrajectory()` | Add recent operations | void | +| `finalizeTrajectory(score, critique?)` | Complete trajectory (score: 0.0-1.0) | void | +| `getSuggestion(task)` | Get AI recommendation | JSON: DecisionSuggestion | +| `getLearningStats()` | Get learning metrics | JSON: LearningStats | +| `getPatterns()` | Get discovered patterns | JSON: Pattern[] | +| `queryTrajectories(task, limit)` | Find similar trajectories | JSON: Trajectory[] | +| `resetLearning()` | Clear learned data | void | + +### AgentDB Methods + +| Method | Description | Returns | +|--------|-------------|---------| +| `getStats()` | Get operation statistics | JSON: Stats | +| `getOperations(limit)` | Get recent operations | JjOperation[] | +| `getUserOperations(limit)` | Get user operations only | JjOperation[] | +| `clearLog()` | Clear operation log | void | + +### Quantum Security Methods (v2.3.0+) + +| Method | Description | Returns | +|--------|-------------|---------| +| `generateQuantumFingerprint(data)` | Generate SHA3-512 fingerprint | Buffer (64 bytes) | +| `verifyQuantumFingerprint(data, fp)` | Verify fingerprint | boolean | +| `enableEncryption(key, pubKey?)` | Enable HQC-128 encryption | void | +| `disableEncryption()` | Disable encryption | void | +| `isEncryptionEnabled()` | Check encryption status | boolean | + +## Performance Characteristics + +| Metric | Git | Agentic Jujutsu | +|--------|-----|-----------------| +| Concurrent commits | 15 ops/s | 350 ops/s (23x) | +| Context switching | 500-1000ms | 50-100ms (10x) | +| Conflict resolution | 30-40% auto | 87% auto (2.5x) | +| Lock waiting | 50 min/day | 0 min (โˆž) | +| Quantum fingerprints | N/A | <1ms | + +## Best Practices + +### 1. Trajectory Management + +```javascript +// โœ… Good: Meaningful task descriptions +jj.startTrajectory('Implement user authentication with JWT'); + +// โŒ Bad: Vague descriptions +jj.startTrajectory('fix stuff'); + +// โœ… Good: Honest success scores +jj.finalizeTrajectory(0.7, 'Works but needs refactoring'); + +// โŒ Bad: Always 1.0 +jj.finalizeTrajectory(1.0, 'Perfect!'); // Prevents learning +``` + +### 2. Pattern Recognition + +```javascript +// โœ… Good: Let patterns emerge naturally +for (let i = 0; i < 10; i++) { + jj.startTrajectory('Deploy feature'); + await deploy(); + jj.addToTrajectory(); + jj.finalizeTrajectory(wasSuccessful ? 0.9 : 0.5); +} + +// โŒ Bad: Not recording outcomes +await deploy(); // No learning +``` + +### 3. Multi-Agent Coordination + +```javascript +// โœ… Good: Concurrent operations +const agents = ['agent1', 'agent2', 'agent3']; +await Promise.all(agents.map(async (agent) => { + const jj = new JjWrapper(); + // Each agent works independently + await jj.newCommit(`Changes by ${agent}`); +})); + +// โŒ Bad: Sequential with locks +for (const agent of agents) { + await agent.waitForLock(); // Not needed! + await agent.commit(); +} +``` + +### 4. Error Handling + +```javascript +// โœ… Good: Record failures with details +try { + await jj.execute(['complex-operation']); + jj.finalizeTrajectory(0.9); +} catch (err) { + jj.finalizeTrajectory(0.3, `Failed: ${err.message}. Root cause: ...`); +} + +// โŒ Bad: Silent failures +try { + await jj.execute(['operation']); +} catch (err) { + // No learning from failure +} +``` + +## Validation Rules (v2.3.1+) + +### Task Description +- โœ… Cannot be empty or whitespace-only +- โœ… Maximum length: 10,000 bytes +- โœ… Automatically trimmed + +### Success Score +- โœ… Must be finite (not NaN or Infinity) +- โœ… Must be between 0.0 and 1.0 (inclusive) + +### Operations +- โœ… Must have at least one operation before finalizing + +### Context +- โœ… Cannot be empty +- โœ… Keys cannot be empty or whitespace-only +- โœ… Keys max 1,000 bytes, values max 10,000 bytes + +## Troubleshooting + +### Issue: Low Confidence Suggestions + +```javascript +const suggestion = JSON.parse(jj.getSuggestion('new task')); + +if (suggestion.confidence < 0.5) { + // Not enough data - check learning stats + const stats = JSON.parse(jj.getLearningStats()); + console.log(`Need more data. Current trajectories: ${stats.totalTrajectories}`); + + // Recommend: Record 5-10 trajectories first +} +``` + +### Issue: Validation Errors + +```javascript +try { + jj.startTrajectory(''); // Empty task +} catch (err) { + if (err.message.includes('Validation error')) { + console.log('Invalid input:', err.message); + // Use non-empty, meaningful task description + } +} + +try { + jj.finalizeTrajectory(1.5); // Score > 1.0 +} catch (err) { + // Use score between 0.0 and 1.0 + jj.finalizeTrajectory(Math.max(0, Math.min(1, score))); +} +``` + +### Issue: No Patterns Discovered + +```javascript +const patterns = JSON.parse(jj.getPatterns()); + +if (patterns.length === 0) { + // Need more trajectories with >70% success + // Record at least 3-5 successful trajectories +} +``` + +## Examples + +### Example 1: Simple Learning Workflow + +```javascript +const { JjWrapper } = require('agentic-jujutsu'); + +async function learnFromWork() { + const jj = new JjWrapper(); + + // Start tracking + jj.startTrajectory('Add user profile feature'); + + // Do work + await jj.branchCreate('feature/user-profile'); + await jj.newCommit('Add user profile model'); + await jj.newCommit('Add profile API endpoints'); + await jj.newCommit('Add profile UI'); + + // Record operations + jj.addToTrajectory(); + + // Finalize with result + jj.finalizeTrajectory(0.85, 'Feature complete, minor styling issues remain'); + + // Next time, get suggestions + const suggestion = JSON.parse(jj.getSuggestion('Add settings page')); + console.log('AI suggests:', suggestion.reasoning); +} +``` + +### Example 2: Multi-Agent Swarm + +```javascript +async function agentSwarm(taskList) { + const agents = taskList.map((task, i) => ({ + name: `agent-${i}`, + jj: new JjWrapper(), + task + })); + + // All agents work concurrently (no conflicts!) + const results = await Promise.all(agents.map(async (agent) => { + agent.jj.startTrajectory(agent.task); + + // Get AI suggestion + const suggestion = JSON.parse(agent.jj.getSuggestion(agent.task)); + + // Execute task + const success = await executeTask(agent, suggestion); + + agent.jj.addToTrajectory(); + agent.jj.finalizeTrajectory(success ? 0.9 : 0.5); + + return { agent: agent.name, success }; + })); + + console.log('Results:', results); +} +``` + +## Related Documentation + +- **NPM Package**: https://npmjs.com/package/agentic-jujutsu +- **GitHub**: https://github.com/ruvnet/agentic-flow/tree/main/packages/agentic-jujutsu +- **Full README**: See package README.md +- **Validation Guide**: docs/VALIDATION_FIXES_v2.3.1.md +- **AgentDB Guide**: docs/AGENTDB_GUIDE.md + +## Version History + +- **v2.3.2** - Documentation updates +- **v2.3.1** - Validation fixes for ReasoningBank +- **v2.3.0** - Quantum-resistant security with @qudag/napi-core +- **v2.1.0** - Self-learning AI with ReasoningBank +- **v2.0.0** - Zero-dependency installation with embedded jj binary + +--- + +**Status**: โœ… Production Ready +**License**: MIT +**Maintained**: Active diff --git a/.claude/skills/apple-notes/SKILL.md b/.claude/skills/apple-notes/SKILL.md new file mode 100644 index 0000000000..3a0395ba11 --- /dev/null +++ b/.claude/skills/apple-notes/SKILL.md @@ -0,0 +1,50 @@ +--- +name: apple-notes +description: Manage Apple Notes via the `memo` CLI on macOS (create, view, edit, delete, search, move, and export notes). Use when a user asks Zee to add a note, list notes, search notes, or manage note folders. +homepage: https://github.com/antoniorodr/memo +metadata: {"zee":{"emoji":"๐Ÿ“","os":["darwin"],"requires":{"bins":["memo"]},"install":[{"id":"brew","kind":"brew","formula":"antoniorodr/memo/memo","bins":["memo"],"label":"Install memo via Homebrew"}]}} +--- + +# Apple Notes CLI + +Use `memo notes` to manage Apple Notes directly from the terminal. Create, view, edit, delete, search, move notes between folders, and export to HTML/Markdown. + +Setup +- Install (Homebrew): `brew tap antoniorodr/memo && brew install antoniorodr/memo/memo` +- Manual (pip): `pip install .` (after cloning the repo) +- macOS-only; if prompted, grant Automation access to Notes.app. + +View Notes +- List all notes: `memo notes` +- Filter by folder: `memo notes -f "Folder Name"` +- Search notes (fuzzy): `memo notes -s "query"` + +Create Notes +- Add a new note: `memo notes -a` + - Opens an interactive editor to compose the note. +- Quick add with title: `memo notes -a "Note Title"` + +Edit Notes +- Edit existing note: `memo notes -e` + - Interactive selection of note to edit. + +Delete Notes +- Delete a note: `memo notes -d` + - Interactive selection of note to delete. + +Move Notes +- Move note to folder: `memo notes -m` + - Interactive selection of note and destination folder. + +Export Notes +- Export to HTML/Markdown: `memo notes -ex` + - Exports selected note; uses Mistune for markdown processing. + +Limitations +- Cannot edit notes containing images or attachments. +- Interactive prompts may require terminal access. + +Notes +- macOS-only. +- Requires Apple Notes.app to be accessible. +- For automation, grant permissions in System Settings > Privacy & Security > Automation. diff --git a/.claude/skills/apple-reminders/SKILL.md b/.claude/skills/apple-reminders/SKILL.md new file mode 100644 index 0000000000..34d25c7aa2 --- /dev/null +++ b/.claude/skills/apple-reminders/SKILL.md @@ -0,0 +1,67 @@ +--- +name: apple-reminders +description: Manage Apple Reminders via the `remindctl` CLI on macOS (list, add, edit, complete, delete). Supports lists, date filters, and JSON/plain output. +homepage: https://github.com/steipete/remindctl +metadata: {"zee":{"emoji":"โฐ","os":["darwin"],"requires":{"bins":["remindctl"]},"install":[{"id":"brew","kind":"brew","formula":"steipete/tap/remindctl","bins":["remindctl"],"label":"Install remindctl via Homebrew"}]}} +--- + +# Apple Reminders CLI (remindctl) + +Use `remindctl` to manage Apple Reminders directly from the terminal. It supports list filtering, date-based views, and scripting output. + +Setup +- Install (Homebrew): `brew install steipete/tap/remindctl` +- From source: `pnpm install && pnpm build` (binary at `./bin/remindctl`) +- macOS-only; grant Reminders permission when prompted. + +Permissions +- Check status: `remindctl status` +- Request access: `remindctl authorize` + +View Reminders +- Default (today): `remindctl` +- Today: `remindctl today` +- Tomorrow: `remindctl tomorrow` +- Week: `remindctl week` +- Overdue: `remindctl overdue` +- Upcoming: `remindctl upcoming` +- Completed: `remindctl completed` +- All: `remindctl all` +- Specific date: `remindctl 2026-01-04` + +Manage Lists +- List all lists: `remindctl list` +- Show list: `remindctl list Work` +- Create list: `remindctl list Projects --create` +- Rename list: `remindctl list Work --rename Office` +- Delete list: `remindctl list Work --delete` + +Create Reminders +- Quick add: `remindctl add "Buy milk"` +- With list + due: `remindctl add --title "Call mom" --list Personal --due tomorrow` + +Edit Reminders +- Edit title/due: `remindctl edit 1 --title "New title" --due 2026-01-04` + +Complete Reminders +- Complete by id: `remindctl complete 1 2 3` + +Delete Reminders +- Delete by id: `remindctl delete 4A83 --force` + +Output Formats +- JSON (scripting): `remindctl today --json` +- Plain TSV: `remindctl today --plain` +- Counts only: `remindctl today --quiet` + +Date Formats +Accepted by `--due` and date filters: +- `today`, `tomorrow`, `yesterday` +- `YYYY-MM-DD` +- `YYYY-MM-DD HH:mm` +- ISO 8601 (`2026-01-04T12:34:56Z`) + +Notes +- macOS-only. +- If access is denied, enable Terminal/remindctl in System Settings โ†’ Privacy & Security โ†’ Reminders. +- If running over SSH, grant access on the Mac that runs the command. diff --git a/.claude/skills/bear-notes/SKILL.md b/.claude/skills/bear-notes/SKILL.md new file mode 100644 index 0000000000..489855725b --- /dev/null +++ b/.claude/skills/bear-notes/SKILL.md @@ -0,0 +1,79 @@ +--- +name: bear-notes +description: Create, search, and manage Bear notes via grizzly CLI. +homepage: https://bear.app +metadata: {"zee":{"emoji":"๐Ÿป","os":["darwin"],"requires":{"bins":["grizzly"]},"install":[{"id":"go","kind":"go","module":"github.com/tylerwince/grizzly/cmd/grizzly@latest","bins":["grizzly"],"label":"Install grizzly (go)"}]}} +--- + +# Bear Notes + +Use `grizzly` to create, read, and manage notes in Bear on macOS. + +Requirements +- Bear app installed and running +- For some operations (add-text, tags, open-note --selected), a Bear app token (stored in `~/.config/grizzly/token`) + +## Getting a Bear Token + +For operations that require a token (add-text, tags, open-note --selected), you need an authentication token: +1. Open Bear โ†’ Help โ†’ API Token โ†’ Copy Token +2. Save it: `echo "YOUR_TOKEN" > ~/.config/grizzly/token` + +## Common Commands + +Create a note +```bash +echo "Note content here" | grizzly create --title "My Note" --tag work +grizzly create --title "Quick Note" --tag inbox < /dev/null +``` + +Open/read a note by ID +```bash +grizzly open-note --id "NOTE_ID" --enable-callback --json +``` + +Append text to a note +```bash +echo "Additional content" | grizzly add-text --id "NOTE_ID" --mode append --token-file ~/.config/grizzly/token +``` + +List all tags +```bash +grizzly tags --enable-callback --json --token-file ~/.config/grizzly/token +``` + +Search notes (via open-tag) +```bash +grizzly open-tag --name "work" --enable-callback --json +``` + +## Options + +Common flags: +- `--dry-run` โ€” Preview the URL without executing +- `--print-url` โ€” Show the x-callback-url +- `--enable-callback` โ€” Wait for Bear's response (needed for reading data) +- `--json` โ€” Output as JSON (when using callbacks) +- `--token-file PATH` โ€” Path to Bear API token file + +## Configuration + +Grizzly reads config from (in priority order): +1. CLI flags +2. Environment variables (`GRIZZLY_TOKEN_FILE`, `GRIZZLY_CALLBACK_URL`, `GRIZZLY_TIMEOUT`) +3. `.grizzly.toml` in current directory +4. `~/.config/grizzly/config.toml` + +Example `~/.config/grizzly/config.toml`: +```toml +token_file = "~/.config/grizzly/token" +callback_url = "http://127.0.0.1:42123/success" +timeout = "5s" +``` + +## Notes + +- Bear must be running for commands to work +- Note IDs are Bear's internal identifiers (visible in note info or via callbacks) +- Use `--enable-callback` when you need to read data back from Bear +- Some operations require a valid token (add-text, tags, open-note --selected) diff --git a/.claude/skills/bird/SKILL.md b/.claude/skills/bird/SKILL.md new file mode 100644 index 0000000000..689979438c --- /dev/null +++ b/.claude/skills/bird/SKILL.md @@ -0,0 +1,25 @@ +--- +name: bird +description: X/Twitter CLI for reading, searching, and posting via cookies or Sweetistics. +homepage: https://bird.fast +metadata: {"zee":{"emoji":"๐Ÿฆ","requires":{"bins":["bird"]},"install":[{"id":"brew","kind":"brew","formula":"steipete/tap/bird","bins":["bird"],"label":"Install bird (brew)"}]}} +--- + +# bird + +Use `bird` to read/search X and post tweets/replies. + +Quick start +- `bird whoami` +- `bird read ` +- `bird thread ` +- `bird search "query" -n 5` + +Posting (confirm with user first) +- `bird tweet "text"` +- `bird reply "text"` + +Auth sources +- Browser cookies (default: Firefox/Chrome) +- Sweetistics API: set `SWEETISTICS_API_KEY` or use `--engine sweetistics` +- Check sources: `bird check` diff --git a/.claude/skills/blogwatcher/SKILL.md b/.claude/skills/blogwatcher/SKILL.md new file mode 100644 index 0000000000..99e0a0f0a3 --- /dev/null +++ b/.claude/skills/blogwatcher/SKILL.md @@ -0,0 +1,46 @@ +--- +name: blogwatcher +description: Monitor blogs and RSS/Atom feeds for updates using the blogwatcher CLI. +homepage: https://github.com/Hyaxia/blogwatcher +metadata: {"zee":{"emoji":"๐Ÿ“ฐ","requires":{"bins":["blogwatcher"]},"install":[{"id":"go","kind":"go","module":"github.com/Hyaxia/blogwatcher/cmd/blogwatcher@latest","bins":["blogwatcher"],"label":"Install blogwatcher (go)"}]}} +--- + +# blogwatcher + +Track blog and RSS/Atom feed updates with the `blogwatcher` CLI. + +Install +- Go: `go install github.com/Hyaxia/blogwatcher/cmd/blogwatcher@latest` + +Quick start +- `blogwatcher --help` + +Common commands +- Add a blog: `blogwatcher add "My Blog" https://example.com` +- List blogs: `blogwatcher blogs` +- Scan for updates: `blogwatcher scan` +- List articles: `blogwatcher articles` +- Mark an article read: `blogwatcher read 1` +- Mark all articles read: `blogwatcher read-all` +- Remove a blog: `blogwatcher remove "My Blog"` + +Example output +``` +$ blogwatcher blogs +Tracked blogs (1): + + xkcd + URL: https://xkcd.com +``` +``` +$ blogwatcher scan +Scanning 1 blog(s)... + + xkcd + Source: RSS | Found: 4 | New: 4 + +Found 4 new article(s) total! +``` + +Notes +- Use `blogwatcher --help` to discover flags and options. diff --git a/.claude/skills/blucli/SKILL.md b/.claude/skills/blucli/SKILL.md new file mode 100644 index 0000000000..bebe85483d --- /dev/null +++ b/.claude/skills/blucli/SKILL.md @@ -0,0 +1,27 @@ +--- +name: blucli +description: BluOS CLI (blu) for discovery, playback, grouping, and volume. +homepage: https://blucli.sh +metadata: {"zee":{"emoji":"๐Ÿซ","requires":{"bins":["blu"]},"install":[{"id":"go","kind":"go","module":"github.com/steipete/blucli/cmd/blu@latest","bins":["blu"],"label":"Install blucli (go)"}]}} +--- + +# blucli (blu) + +Use `blu` to control Bluesound/NAD players. + +Quick start +- `blu devices` (pick target) +- `blu --device status` +- `blu play|pause|stop` +- `blu volume set 15` + +Target selection (in priority order) +- `--device ` +- `BLU_DEVICE` +- config default (if set) + +Common tasks +- Grouping: `blu group status|add|remove` +- TuneIn search/play: `blu tunein search "query"`, `blu tunein play "query"` + +Prefer `--json` for scripts. Confirm the target device before changing playback. diff --git a/.claude/skills/brave-search/SKILL.md b/.claude/skills/brave-search/SKILL.md new file mode 100644 index 0000000000..1c687c83cc --- /dev/null +++ b/.claude/skills/brave-search/SKILL.md @@ -0,0 +1,30 @@ +--- +name: brave-search +description: Web search and content extraction via Brave Search API. +homepage: https://brave.com/search/api +metadata: {"zee":{"emoji":"๐Ÿฆ","requires":{"bins":["node"],"env":["BRAVE_API_KEY"]},"primaryEnv":"BRAVE_API_KEY"}} +--- + +# Brave Search + +Headless web search (and lightweight content extraction) using Brave Search API. No browser required. + +## Search + +```bash +node {baseDir}/scripts/search.mjs "query" +node {baseDir}/scripts/search.mjs "query" -n 10 +node {baseDir}/scripts/search.mjs "query" --content +node {baseDir}/scripts/search.mjs "query" -n 3 --content +``` + +## Extract a page + +```bash +node {baseDir}/scripts/content.mjs "https://example.com/article" +``` + +Notes: +- Needs `BRAVE_API_KEY`. +- Content extraction is best-effort (good for articles; not for app-like sites). +- If a site is blocked or too JS-heavy, prefer the `summarize` skill (it can use a Firecrawl fallback). diff --git a/.claude/skills/brave-search/scripts/content.mjs b/.claude/skills/brave-search/scripts/content.mjs new file mode 100644 index 0000000000..cfdff7836d --- /dev/null +++ b/.claude/skills/brave-search/scripts/content.mjs @@ -0,0 +1,53 @@ +#!/usr/bin/env node + +function usage() { + console.error(`Usage: content.mjs `); + process.exit(2); +} + +export async function fetchAsMarkdown(url) { + const resp = await fetch(url, { + headers: { "User-Agent": "clawdbot-brave-search/1.0" }, + }); + const html = await resp.text(); + + // Very lightweight โ€œreadability-ishโ€ extraction without dependencies: + // - drop script/style/nav/footer + // - strip tags + // - keep paragraphs + const cleaned = html + .replace(//gi, " ") + .replace(//gi, " ") + .replace(/<(nav|footer|header)[\s\S]*?<\/\1>/gi, " ") + .replace(//gi, "\n") + .replace(/<\/p>/gi, "\n\n") + .replace(/<\/div>/gi, "\n") + .replace(/<[^>]+>/g, " ") + .replace(/ /g, " ") + .replace(/&/g, "&") + .replace(/</g, "<") + .replace(/>/g, ">") + .replace(/"/g, '"') + .replace(/'/g, "'") + .replace(/\s+\n/g, "\n") + .replace(/\n{3,}/g, "\n\n") + .replace(/[ \t]{2,}/g, " ") + .trim(); + + if (!resp.ok) { + return `> Fetch failed (${resp.status}).\n\n${cleaned.slice(0, 2000)}\n`; + } + + const paras = cleaned + .split("\n\n") + .map((p) => p.trim()) + .filter(Boolean) + .slice(0, 30); + + return paras.map((p) => `- ${p}`).join("\n") + "\n"; +} + +const args = process.argv.slice(2); +if (args.length === 0 || args[0] === "-h" || args[0] === "--help") usage(); +const url = args[0]; +process.stdout.write(await fetchAsMarkdown(url)); diff --git a/.claude/skills/brave-search/scripts/search.mjs b/.claude/skills/brave-search/scripts/search.mjs new file mode 100644 index 0000000000..901ba6c17b --- /dev/null +++ b/.claude/skills/brave-search/scripts/search.mjs @@ -0,0 +1,79 @@ +#!/usr/bin/env node + +function usage() { + console.error(`Usage: search.mjs "query" [-n 5] [--content]`); + process.exit(2); +} + +const args = process.argv.slice(2); +if (args.length === 0 || args[0] === "-h" || args[0] === "--help") usage(); + +const query = args[0]; +let n = 5; +let withContent = false; + +for (let i = 1; i < args.length; i++) { + const a = args[i]; + if (a === "-n") { + n = Number.parseInt(args[i + 1] ?? "5", 10); + i++; + continue; + } + if (a === "--content") { + withContent = true; + continue; + } + console.error(`Unknown arg: ${a}`); + usage(); +} + +const apiKey = (process.env.BRAVE_API_KEY ?? "").trim(); +if (!apiKey) { + console.error("Missing BRAVE_API_KEY"); + process.exit(1); +} + +const endpoint = new URL("https://api.search.brave.com/res/v1/web/search"); +endpoint.searchParams.set("q", query); +endpoint.searchParams.set("count", String(Math.max(1, Math.min(n, 20)))); +endpoint.searchParams.set("text_decorations", "false"); +endpoint.searchParams.set("safesearch", "moderate"); + +const resp = await fetch(endpoint, { + headers: { + Accept: "application/json", + "X-Subscription-Token": apiKey, + }, +}); + +if (!resp.ok) { + const text = await resp.text().catch(() => ""); + throw new Error(`Brave Search failed (${resp.status}): ${text}`); +} + +const data = await resp.json(); +const results = (data?.web?.results ?? []).slice(0, n); + +const lines = []; +for (const r of results) { + const title = String(r?.title ?? "").trim(); + const url = String(r?.url ?? "").trim(); + const desc = String(r?.description ?? "").trim(); + if (!title || !url) continue; + lines.push(`- ${title}\n ${url}${desc ? `\n ${desc}` : ""}`); +} + +process.stdout.write(lines.join("\n\n") + "\n"); + +if (!withContent) process.exit(0); + +process.stdout.write("\n---\n\n"); +for (const r of results) { + const title = String(r?.title ?? "").trim(); + const url = String(r?.url ?? "").trim(); + if (!url) continue; + process.stdout.write(`# ${title || url}\n${url}\n\n`); + const child = await import("./content.mjs"); + const text = await child.fetchAsMarkdown(url); + process.stdout.write(text.trimEnd() + "\n\n"); +} diff --git a/.claude/skills/camsnap/SKILL.md b/.claude/skills/camsnap/SKILL.md new file mode 100644 index 0000000000..25dfc0799e --- /dev/null +++ b/.claude/skills/camsnap/SKILL.md @@ -0,0 +1,25 @@ +--- +name: camsnap +description: Capture frames or clips from RTSP/ONVIF cameras. +homepage: https://camsnap.ai +metadata: {"zee":{"emoji":"๐Ÿ“ธ","requires":{"bins":["camsnap"]},"install":[{"id":"brew","kind":"brew","formula":"steipete/tap/camsnap","bins":["camsnap"],"label":"Install camsnap (brew)"}]}} +--- + +# camsnap + +Use `camsnap` to grab snapshots, clips, or motion events from configured cameras. + +Setup +- Config file: `~/.config/camsnap/config.yaml` +- Add camera: `camsnap add --name kitchen --host 192.168.0.10 --user user --pass pass` + +Common commands +- Discover: `camsnap discover --info` +- Snapshot: `camsnap snap kitchen --out shot.jpg` +- Clip: `camsnap clip kitchen --dur 5s --out clip.mp4` +- Motion watch: `camsnap watch kitchen --threshold 0.2 --action '...'` +- Doctor: `camsnap doctor --probe` + +Notes +- Requires `ffmpeg` on PATH. +- Prefer a short test capture before longer clips. diff --git a/.claude/skills/clawdhub/SKILL.md b/.claude/skills/clawdhub/SKILL.md new file mode 100644 index 0000000000..5462387e43 --- /dev/null +++ b/.claude/skills/clawdhub/SKILL.md @@ -0,0 +1,53 @@ +--- +name: clawdhub +description: Use the ClawdHub CLI to search, install, update, and publish agent skills from clawdhub.com. Use when you need to fetch new skills on the fly, sync installed skills to latest or a specific version, or publish new/updated skill folders with the npm-installed clawdhub CLI. +metadata: {"zee":{"requires":{"bins":["clawdhub"]},"install":[{"id":"node","kind":"node","package":"clawdhub","bins":["clawdhub"],"label":"Install ClawdHub CLI (npm)"}]}} +--- + +# ClawdHub CLI + +Install +```bash +npm i -g clawdhub +``` + +Auth (publish) +```bash +clawdhub login +clawdhub whoami +``` + +Search +```bash +clawdhub search "postgres backups" +``` + +Install +```bash +clawdhub install my-skill +clawdhub install my-skill --version 1.2.3 +``` + +Update (hash-based match + upgrade) +```bash +clawdhub update my-skill +clawdhub update my-skill --version 1.2.3 +clawdhub update --all +clawdhub update my-skill --force +clawdhub update --all --no-input --force +``` + +List +```bash +clawdhub list +``` + +Publish +```bash +clawdhub publish ./my-skill --slug my-skill --name "My Skill" --version 1.2.0 --changelog "Fixes + docs" +``` + +Notes +- Default registry: https://clawdhub.com (override with CLAWDHUB_REGISTRY or --registry) +- Default workdir: cwd; install dir: ./skills (override with --workdir / --dir) +- Update command hashes local files, resolves matching version, and upgrades to latest unless --version is set diff --git a/.claude/skills/coding-agent/SKILL.md b/.claude/skills/coding-agent/SKILL.md new file mode 100644 index 0000000000..5eaf7e5596 --- /dev/null +++ b/.claude/skills/coding-agent/SKILL.md @@ -0,0 +1,274 @@ +--- +name: coding-agent +description: Run Codex CLI, Claude Code, agent-core, or Pi Coding Agent via background process for programmatic control. +metadata: {"zee":{"emoji":"๐Ÿงฉ","requires":{"anyBins":["claude","codex","agent-core","pi"]}}} +--- + +# Coding Agent (background-first) + +Use **bash background mode** for non-interactive coding work. For interactive coding sessions, use the **tmux** skill (always, except very simple one-shot prompts). + +## The Pattern: workdir + background + +```bash +# Create temp space for chats/scratch work +SCRATCH=$(mktemp -d) + +# Start agent in target directory ("little box" - only sees relevant files) +bash workdir:$SCRATCH background:true command:"" +# Or for project work: +bash workdir:~/project/folder background:true command:"" +# Returns sessionId for tracking + +# Monitor progress +process action:log sessionId:XXX + +# Check if done +process action:poll sessionId:XXX + +# Send input (if agent asks a question) +process action:write sessionId:XXX data:"y" + +# Kill if needed +process action:kill sessionId:XXX +``` + +**Why workdir matters:** Agent wakes up in a focused directory, doesn't wander off reading unrelated files (like your soul.md ๐Ÿ˜…). + +--- + +## Codex CLI + +**Model:** `gpt-5.2-codex` is the default (set in ~/.codex/config.toml) + +### Building/Creating (use --full-auto or --yolo) +```bash +# --full-auto: sandboxed but auto-approves in workspace +bash workdir:~/project background:true command:"codex exec --full-auto \"Build a snake game with dark theme\"" + +# --yolo: NO sandbox, NO approvals (fastest, most dangerous) +bash workdir:~/project background:true command:"codex --yolo \"Build a snake game with dark theme\"" + +# Note: --yolo is a shortcut for --dangerously-bypass-approvals-and-sandbox +``` + +### Reviewing PRs (vanilla, no flags) + +**โš ๏ธ CRITICAL: Never review PRs in Zee's own project folder!** +- Either use the project where the PR is submitted (if it's NOT ~/Projects/zee) +- Or clone to a temp folder first + +```bash +# Option 1: Review in the actual project (if NOT zee) +bash workdir:~/Projects/some-other-repo background:true command:"codex review --base main" + +# Option 2: Clone to temp folder for safe review (REQUIRED for zee PRs!) +REVIEW_DIR=$(mktemp -d) +git clone https://github.com/zee/zee.git $REVIEW_DIR +cd $REVIEW_DIR && gh pr checkout 130 +bash workdir:$REVIEW_DIR background:true command:"codex review --base origin/main" +# Clean up after: rm -rf $REVIEW_DIR + +# Option 3: Use git worktree (keeps main intact) +git worktree add /tmp/pr-130-review pr-130-branch +bash workdir:/tmp/pr-130-review background:true command:"codex review --base main" +``` + +**Why?** Checking out branches in the running Zee repo can break the live instance! + +### Batch PR Reviews (parallel army!) +```bash +# Fetch all PR refs first +git fetch origin '+refs/pull/*/head:refs/remotes/origin/pr/*' + +# Deploy the army - one Codex per PR! +bash workdir:~/project background:true command:"codex exec \"Review PR #86. git diff origin/main...origin/pr/86\"" +bash workdir:~/project background:true command:"codex exec \"Review PR #87. git diff origin/main...origin/pr/87\"" +bash workdir:~/project background:true command:"codex exec \"Review PR #95. git diff origin/main...origin/pr/95\"" +# ... repeat for all PRs + +# Monitor all +process action:list + +# Get results and post to GitHub +process action:log sessionId:XXX +gh pr comment --body "" +``` + +### Tips for PR Reviews +- **Fetch refs first:** `git fetch origin '+refs/pull/*/head:refs/remotes/origin/pr/*'` +- **Use git diff:** Tell Codex to use `git diff origin/main...origin/pr/XX` +- **Don't checkout:** Multiple parallel reviews = don't let them change branches +- **Post results:** Use `gh pr comment` to post reviews to GitHub + +--- + +## Claude Code + +```bash +bash workdir:~/project background:true command:"claude \"Your task\"" +``` + +--- + +## Agent-Core + +```bash +bash workdir:~/project background:true command:"agent-core run \"Your task\"" +``` + +--- + +## Pi Coding Agent + +```bash +# Install: npm install -g @mariozechner/pi-coding-agent +bash workdir:~/project background:true command:"pi \"Your task\"" +``` + +--- + +## Pi flags (common) + +- `--print` / `-p`: non-interactive; runs prompt and exits. +- `--provider `: pick provider (default: google). +- `--model `: pick model (default: gemini-2.5-flash). +- `--api-key `: override API key (defaults to env vars). + +Examples: + +```bash +# Set provider + model, non-interactive +bash workdir:~/project background:true command:"pi --provider openai --model gpt-4o-mini -p \"Summarize src/\"" +``` + +--- + +## tmux (interactive sessions) + +Use the tmux skill for interactive coding sessions (always, except very simple one-shot prompts). Prefer bash background mode for non-interactive runs. + +--- + +## Parallel Issue Fixing with git worktrees + tmux + +For fixing multiple issues in parallel, use git worktrees (isolated branches) + tmux sessions: + +```bash +# 1. Clone repo to temp location +cd /tmp && git clone git@github.com:user/repo.git repo-worktrees +cd repo-worktrees + +# 2. Create worktrees for each issue (isolated branches!) +git worktree add -b fix/issue-78 /tmp/issue-78 main +git worktree add -b fix/issue-99 /tmp/issue-99 main + +# 3. Set up tmux sessions +SOCKET="${TMPDIR:-/tmp}/codex-fixes.sock" +tmux -S "$SOCKET" new-session -d -s fix-78 +tmux -S "$SOCKET" new-session -d -s fix-99 + +# 4. Launch Codex in each (after pnpm install!) +tmux -S "$SOCKET" send-keys -t fix-78 "cd /tmp/issue-78 && pnpm install && codex --yolo 'Fix issue #78: . Commit and push.'" Enter +tmux -S "$SOCKET" send-keys -t fix-99 "cd /tmp/issue-99 && pnpm install && codex --yolo 'Fix issue #99: . Commit and push.'" Enter + +# 5. Monitor progress +tmux -S "$SOCKET" capture-pane -p -t fix-78 -S -30 +tmux -S "$SOCKET" capture-pane -p -t fix-99 -S -30 + +# 6. Check if done (prompt returned) +tmux -S "$SOCKET" capture-pane -p -t fix-78 -S -3 | grep -q "โฏ" && echo "Done!" + +# 7. Create PRs after fixes +cd /tmp/issue-78 && git push -u origin fix/issue-78 +gh pr create --repo user/repo --head fix/issue-78 --title "fix: ..." --body "..." + +# 8. Cleanup +tmux -S "$SOCKET" kill-server +git worktree remove /tmp/issue-78 +git worktree remove /tmp/issue-99 +``` + +**Why worktrees?** Each Codex works in isolated branch, no conflicts. Can run 5+ parallel fixes! + +**Why tmux over bash background?** Codex is interactive โ€” needs TTY for proper output. tmux provides persistent sessions with full history capture. + +--- + +## โš ๏ธ Rules + +1. **Respect tool choice** โ€” if user asks for Codex, use Codex. NEVER offer to build it yourself! +2. **Be patient** โ€” don't kill sessions because they're "slow" +3. **Monitor with process:log** โ€” check progress without interfering +4. **--full-auto for building** โ€” auto-approves changes +5. **vanilla for reviewing** โ€” no special flags needed +6. **Parallel is OK** โ€” run many Codex processes at once for batch work +7. **NEVER start Codex in ~/clawd/** โ€” it'll read your soul docs and get weird ideas about the org chart! Use the target project dir or /tmp for blank slate chats +8. **NEVER checkout branches in ~/Projects/zee/** โ€” that's the LIVE Zee instance! Clone to /tmp or use git worktree for PR reviews + +--- + +## PR Template (The Razor Standard) + +When submitting PRs to external repos, use this format for quality & maintainer-friendliness: + +````markdown +## Original Prompt +[Exact request/problem statement] + +## What this does +[High-level description] + +**Features:** +- [Key feature 1] +- [Key feature 2] + +**Example usage:** +```bash +# Example +command example +``` + +## Feature intent (maintainer-friendly) +[Why useful, how it fits, workflows it enables] + +## Prompt history (timestamped) +- YYYY-MM-DD HH:MM UTC: [Step 1] +- YYYY-MM-DD HH:MM UTC: [Step 2] + +## How I tested +**Manual verification:** +1. [Test step] - Output: `[result]` +2. [Test step] - Result: [result] + +**Files tested:** +- [Detail] +- [Edge cases] + +## Session logs (implementation) +- [What was researched] +- [What was discovered] +- [Time spent] + +## Implementation details +**New files:** +- `path/file.ts` - [description] + +**Modified files:** +- `path/file.ts` - [change] + +**Technical notes:** +- [Detail 1] +- [Detail 2] + +--- +*Submitted by Razor ๐Ÿฅท - Mariano's AI agent* +```` + +**Key principles:** +1. Human-written description (no AI slop) +2. Feature intent for maintainers +3. Timestamped prompt history +4. Session logs if using Codex/agent + +**Example:** https://github.com/steipete/bird/pull/22 diff --git a/.claude/skills/concept-exploration/SKILL.md b/.claude/skills/concept-exploration/SKILL.md new file mode 100644 index 0000000000..f363b27366 --- /dev/null +++ b/.claude/skills/concept-exploration/SKILL.md @@ -0,0 +1,101 @@ +--- +name: concept-exploration +description: Deep understanding through Socratic questioning and concept mapping +triggers: + - explain + - understand + - why does + - how does + - concept + - theory +--- + +# Concept Exploration + +Build deep understanding through active inquiry, not passive reading. + +## Learning Approach + +Inspired by Math Academy and Feynman technique: + +1. **Can you explain it simply?** If not, you don't understand it +2. **What are the prerequisites?** Map dependencies +3. **What are the edge cases?** Test understanding limits +4. **How does it connect?** Link to known concepts + +## Exploration Methods + +### Socratic Questioning +Ask probing questions: +- What do you mean by X? +- How did you arrive at that? +- What would be a counterexample? +- What assumptions are you making? +- What would change if...? + +### Concept Mapping +``` + โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” + โ”‚ Limits โ”‚ + โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”˜ + โ”‚ enables + โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” + โ–ผ โ–ผ โ–ผ +โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” +โ”‚Derivat.โ”‚ โ”‚Continu.โ”‚ โ”‚Integralโ”‚ +โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ +``` + +### Prerequisite Check +Before teaching concept X: +1. List prerequisites A, B, C +2. Quick-check student knows A, B, C +3. If gap found, address prerequisite first +4. Only then proceed to X + +## Mastery Criteria + +A concept is "understood" when student can: +- [ ] Explain it in own words +- [ ] Give examples and non-examples +- [ ] Apply it to novel problems +- [ ] Identify when it's applicable +- [ ] Explain why it works (not just how) + +## Memory Integration + +Track concept mastery: +```typescript +await memory.store({ + namespace: "johny/concepts", + key: topic, + value: { + topic, + prerequisites: ["limits", "continuity"], + masteryLevel: 0.85, // 0-1 scale + lastAssessed: new Date(), + canExplain: true, + canApply: true, + canGeneralize: false, // needs more work + commonMisconceptions: ["confuses with..."] + } +}); +``` + +## Knowledge Graph + +Build interconnected understanding: +```typescript +await memory.store({ + namespace: "johny/knowledge-graph", + key: "edges", + value: { + edges: [ + { from: "derivative", to: "limit", relation: "defined-by" }, + { from: "integral", to: "antiderivative", relation: "inverse-of" }, + { from: "ftc", to: "derivative", relation: "connects" }, + { from: "ftc", to: "integral", relation: "connects" } + ] + } +}); +``` diff --git a/.claude/skills/deliberate-practice/SKILL.md b/.claude/skills/deliberate-practice/SKILL.md new file mode 100644 index 0000000000..1e99d3de7c --- /dev/null +++ b/.claude/skills/deliberate-practice/SKILL.md @@ -0,0 +1,92 @@ +--- +name: deliberate-practice +description: Structured practice sessions with immediate feedback for skill acquisition +triggers: + - practice + - drill + - exercise + - train + - learn by doing +--- + +# Deliberate Practice + +Facilitate focused, goal-oriented practice sessions based on Anders Ericsson's deliberate practice principles. + +## Core Principles + +1. **Specific Goals**: Each session targets a specific sub-skill +2. **Full Attention**: Concentrated effort, no distractions +3. **Immediate Feedback**: Know if you're right/wrong instantly +4. **Stretch Zone**: Just beyond current ability (not too easy, not impossible) +5. **Repetition with Refinement**: Repeat until mastery, then move on + +## Practice Session Structure + +### 1. Warm-up (5 min) +- Review prerequisites +- Recall relevant concepts +- Set specific goal for session + +### 2. Focused Practice (20-25 min) +- Work on problems at edge of ability +- Get immediate feedback on each attempt +- Identify specific errors and why they occurred + +### 3. Cool-down (5 min) +- Summarize what was learned +- Note persistent difficulties +- Queue items for spaced repetition + +## Difficulty Calibration + +``` +Too Easy โ”‚ Optimal Zone โ”‚ Too Hard +โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +< 70% right โ”‚ 70-85% right โ”‚ > 85% wrong +Boring โ”‚ Challenging โ”‚ Frustrating +No growth โ”‚ Maximum โ”‚ No growth + โ”‚ learning โ”‚ +``` + +## Feedback Patterns + +### Immediate Correction +When student makes error: +1. Show correct answer +2. Explain why it's correct +3. Have them redo the problem +4. Queue similar problem for later + +### Error Analysis +Track error types: +- Conceptual (misunderstanding) +- Procedural (wrong steps) +- Careless (attention lapse) +- Knowledge gap (missing prerequisite) + +## Memory Integration + +Store practice data: +```typescript +await memory.store({ + namespace: "johny/practice", + key: `session/${date}/${topic}`, + value: { + topic, + problemsAttempted: 15, + accuracy: 0.73, + timeSpent: 25, + errorsBy Type: { conceptual: 2, procedural: 2 }, + itemsForReview: ["integration-by-parts", "trig-substitution"] + } +}); +``` + +## Spaced Repetition Queue + +Items needing review are scheduled based on performance: +- First error: Review in 1 day +- Second error: Review in 4 hours +- Correct after error: Review in 3 days +- Consistently correct: Review in 7 days, then 14, 30... diff --git a/.claude/skills/discord/SKILL.md b/.claude/skills/discord/SKILL.md new file mode 100644 index 0000000000..ac8d7d2ac7 --- /dev/null +++ b/.claude/skills/discord/SKILL.md @@ -0,0 +1,369 @@ +--- +name: discord +description: Use when you need to control Discord from Zee via the discord tool: send messages, react, post or upload stickers, upload emojis, run polls, manage threads/pins/search, fetch permissions or member/role/channel info, or handle moderation actions in Discord DMs or channels. +--- + +# Discord Actions + +## Overview + +Use `discord` to manage messages, reactions, threads, polls, and moderation. You can disable groups via `discord.actions.*` (defaults to enabled, except roles/moderation). The tool uses the bot token configured for Zee. + +## Inputs to collect + +- For reactions: `channelId`, `messageId`, and an `emoji`. +- For stickers/polls/sendMessage: a `to` target (`channel:` or `user:`). Optional `content` text. +- Polls also need a `question` plus 2โ€“10 `answers`. +- For media: `mediaUrl` with `file:///path` for local files or `https://...` for remote. +- For emoji uploads: `guildId`, `name`, `mediaUrl`, optional `roleIds` (limit 256KB, PNG/JPG/GIF). +- For sticker uploads: `guildId`, `name`, `description`, `tags`, `mediaUrl` (limit 512KB, PNG/APNG/Lottie JSON). + +Message context lines include `discord message id` and `channel` fields you can reuse directly. + +**Note:** `sendMessage` uses `to: "channel:"` format, not `channelId`. Other actions like `react`, `readMessages`, `editMessage` use `channelId` directly. + +## Actions + +### React to a message + +```json +{ + "action": "react", + "channelId": "123", + "messageId": "456", + "emoji": "โœ…" +} +``` + +### List reactions + users + +```json +{ + "action": "reactions", + "channelId": "123", + "messageId": "456", + "limit": 100 +} +``` + +### Send a sticker + +```json +{ + "action": "sticker", + "to": "channel:123", + "stickerIds": ["9876543210"], + "content": "Nice work!" +} +``` + +- Up to 3 sticker IDs per message. +- `to` can be `user:` for DMs. + +### Upload a custom emoji + +```json +{ + "action": "emojiUpload", + "guildId": "999", + "name": "party_blob", + "mediaUrl": "file:///tmp/party.png", + "roleIds": ["222"] +} +``` + +- Emoji images must be PNG/JPG/GIF and <= 256KB. +- `roleIds` is optional; omit to make the emoji available to everyone. + +### Upload a sticker + +```json +{ + "action": "stickerUpload", + "guildId": "999", + "name": "zee_wave", + "description": "Zee waving hello", + "tags": "๐Ÿ‘‹", + "mediaUrl": "file:///tmp/wave.png" +} +``` + +- Stickers require `name`, `description`, and `tags`. +- Uploads must be PNG/APNG/Lottie JSON and <= 512KB. + +### Create a poll + +```json +{ + "action": "poll", + "to": "channel:123", + "question": "Lunch?", + "answers": ["Pizza", "Sushi", "Salad"], + "allowMultiselect": false, + "durationHours": 24, + "content": "Vote now" +} +``` + +- `durationHours` defaults to 24; max 32 days (768 hours). + +### Check bot permissions for a channel + +```json +{ + "action": "permissions", + "channelId": "123" +} +``` + +## Ideas to try + +- React with โœ…/โš ๏ธ to mark status updates. +- Post a quick poll for release decisions or meeting times. +- Send celebratory stickers after successful deploys. +- Upload new emojis/stickers for release moments. +- Run weekly โ€œpriority checkโ€ polls in team channels. +- DM stickers as acknowledgements when a userโ€™s request is completed. + +## Action gating + +Use `discord.actions.*` to disable action groups: +- `reactions` (react + reactions list + emojiList) +- `stickers`, `polls`, `permissions`, `messages`, `threads`, `pins`, `search` +- `emojiUploads`, `stickerUploads` +- `memberInfo`, `roleInfo`, `channelInfo`, `voiceStatus`, `events` +- `roles` (role add/remove, default `false`) +- `moderation` (timeout/kick/ban, default `false`) +### Read recent messages + +```json +{ + "action": "readMessages", + "channelId": "123", + "limit": 20 +} +``` + +### Send/edit/delete a message + +```json +{ + "action": "sendMessage", + "to": "channel:123", + "content": "Hello from Zee" +} +``` + +**With media attachment:** + +```json +{ + "action": "sendMessage", + "to": "channel:123", + "content": "Check out this audio!", + "mediaUrl": "file:///tmp/audio.mp3" +} +``` + +- `to` uses format `channel:` or `user:` for DMs (not `channelId`!) +- `mediaUrl` supports local files (`file:///path/to/file`) and remote URLs (`https://...`) +- Optional `replyTo` with a message ID to reply to a specific message + +```json +{ + "action": "editMessage", + "channelId": "123", + "messageId": "456", + "content": "Fixed typo" +} +``` + +```json +{ + "action": "deleteMessage", + "channelId": "123", + "messageId": "456" +} +``` + +### Threads + +```json +{ + "action": "threadCreate", + "channelId": "123", + "name": "Bug triage", + "messageId": "456" +} +``` + +```json +{ + "action": "threadList", + "guildId": "999" +} +``` + +```json +{ + "action": "threadReply", + "channelId": "777", + "content": "Replying in thread" +} +``` + +### Pins + +```json +{ + "action": "pinMessage", + "channelId": "123", + "messageId": "456" +} +``` + +```json +{ + "action": "listPins", + "channelId": "123" +} +``` + +### Search messages + +```json +{ + "action": "searchMessages", + "guildId": "999", + "content": "release notes", + "channelIds": ["123", "456"], + "limit": 10 +} +``` + +### Member + role info + +```json +{ + "action": "memberInfo", + "guildId": "999", + "userId": "111" +} +``` + +```json +{ + "action": "roleInfo", + "guildId": "999" +} +``` + +### List available custom emojis + +```json +{ + "action": "emojiList", + "guildId": "999" +} +``` + +### Role changes (disabled by default) + +```json +{ + "action": "roleAdd", + "guildId": "999", + "userId": "111", + "roleId": "222" +} +``` + +### Channel info + +```json +{ + "action": "channelInfo", + "channelId": "123" +} +``` + +```json +{ + "action": "channelList", + "guildId": "999" +} +``` + +### Voice status + +```json +{ + "action": "voiceStatus", + "guildId": "999", + "userId": "111" +} +``` + +### Scheduled events + +```json +{ + "action": "eventList", + "guildId": "999" +} +``` + +### Moderation (disabled by default) + +```json +{ + "action": "timeout", + "guildId": "999", + "userId": "111", + "durationMinutes": 10 +} +``` + +## Discord Writing Style Guide + +**Keep it conversational!** Discord is a chat platform, not documentation. + +### Do +- Short, punchy messages (1-3 sentences ideal) +- Multiple quick replies > one wall of text +- Use emoji for tone/emphasis ๐Ÿฆž +- Lowercase casual style is fine +- Break up info into digestible chunks +- Match the energy of the conversation + +### Don't +- No markdown tables (Discord renders them as ugly raw `| text |`) +- No `## Headers` for casual chat (use **bold** or CAPS for emphasis) +- Avoid multi-paragraph essays +- Don't over-explain simple things +- Skip the "I'd be happy to help!" fluff + +### Formatting that works +- **bold** for emphasis +- `code` for technical terms +- Lists for multiple items +- > quotes for referencing +- Wrap multiple links in `<>` to suppress embeds + +### Example transformations + +โŒ Bad: +``` +I'd be happy to help with that! Here's a comprehensive overview of the versioning strategies available: + +## Semantic Versioning +Semver uses MAJOR.MINOR.PATCH format where... + +## Calendar Versioning +CalVer uses date-based versions like... +``` + +โœ… Good: +``` +versioning options: semver (1.2.3), calver (2026.01.04), or yolo (`latest` forever). what fits your release cadence? +``` diff --git a/.claude/skills/earnings-intelligence/SKILL.md b/.claude/skills/earnings-intelligence/SKILL.md new file mode 100644 index 0000000000..98e5944e17 --- /dev/null +++ b/.claude/skills/earnings-intelligence/SKILL.md @@ -0,0 +1,109 @@ +--- +name: earnings-intelligence +description: Analyze earnings reports, calls, and estimate revisions +triggers: + - earnings analysis + - earnings call + - earnings surprise + - estimate revisions + - quarterly results +--- + +# Earnings Intelligence + +Comprehensive earnings analysis and call intelligence. + +## Pre-Earnings Research + +### Upcoming Earnings +``` +# Get earnings calendar +obb.equity.calendar.earnings(start_date="2024-01-15", end_date="2024-01-31") + +# Earnings estimates +obb.equity.estimates.consensus(symbol="AAPL", provider="fmp") +``` + +### Historical Performance +``` +# Past earnings surprises +obb.equity.fundamental.historical_eps(symbol="AAPL", provider="fmp") +``` + +## Earnings Call Analysis + +### Transcript Processing +Using meeting intelligence integration: +``` +# When an earnings call transcript is available +from stanley.notes import NoteManager + +notes = NoteManager() +event = notes.create_event( + symbol="AAPL", + company_name="Apple Inc.", + event_type="earnings_call", + event_date="2024-01-25" +) +``` + +### Key Metrics to Track +1. Revenue vs estimates +2. EPS vs estimates +3. Guidance changes +4. Margin trends +5. Key segment performance +6. Management tone/confidence + +## Post-Earnings Analysis + +### Estimate Revisions +``` +from stanley.research import analyze_estimate_revisions + +revisions = analyze_estimate_revisions( + symbol="AAPL", + days_after_earnings=30 +) +``` + +### Price Reaction +``` +# Implied vs actual move +obb.equity.price.historical(symbol="AAPL", start_date=earnings_date) +``` + +## Memory Patterns + +Store earnings insights: +```typescript +await memory.store({ + namespace: "stanley/earnings", + key: `${symbol}/${quarter}`, + value: { + date: earningsDate, + epsActual: 1.52, + epsEstimate: 1.48, + surprise: 0.027, + guidance: "raised", + keyTakeaways: ["..."], + analystReactions: ["..."] + } +}); +``` + +## Automated Workflows + +### Pre-Earnings Alert +Triggered by earnings calendar: +1. Get consensus estimates +2. Review prior quarter +3. Set up event note +4. Identify key metrics to watch + +### Post-Earnings Summary +Day after earnings: +1. Pull actual results +2. Calculate surprise +3. Get analyst revisions +4. Update thesis if needed diff --git a/.claude/skills/eightctl/SKILL.md b/.claude/skills/eightctl/SKILL.md new file mode 100644 index 0000000000..7dea42db5a --- /dev/null +++ b/.claude/skills/eightctl/SKILL.md @@ -0,0 +1,29 @@ +--- +name: eightctl +description: Control Eight Sleep pods (status, temperature, alarms, schedules). +homepage: https://eightctl.sh +metadata: {"zee":{"emoji":"๐ŸŽ›๏ธ","requires":{"bins":["eightctl"]},"install":[{"id":"go","kind":"go","module":"github.com/steipete/eightctl/cmd/eightctl@latest","bins":["eightctl"],"label":"Install eightctl (go)"}]}} +--- + +# eightctl + +Use `eightctl` for Eight Sleep pod control. Requires auth. + +Auth +- Config: `~/.config/eightctl/config.yaml` +- Env: `EIGHTCTL_EMAIL`, `EIGHTCTL_PASSWORD` + +Quick start +- `eightctl status` +- `eightctl on|off` +- `eightctl temp 20` + +Common tasks +- Alarms: `eightctl alarm list|create|dismiss` +- Schedules: `eightctl schedule list|create|update` +- Audio: `eightctl audio state|play|pause` +- Base: `eightctl base info|angle` + +Notes +- API is unofficial and rate-limited; avoid repeated logins. +- Confirm before changing temperature or alarms. diff --git a/.claude/skills/financial-research/SKILL.md b/.claude/skills/financial-research/SKILL.md new file mode 100644 index 0000000000..2b24cda8c6 --- /dev/null +++ b/.claude/skills/financial-research/SKILL.md @@ -0,0 +1,104 @@ +--- +name: financial-research +description: Conduct fundamental investment research using OpenBB and Stanley backend +triggers: + - stock research + - company analysis + - investment thesis + - fundamental analysis + - valuation +--- + +# Financial Research + +Conduct rigorous fundamental investment research on public companies using OpenBB data and Stanley analysis tools. + +## Available Data Sources + +### Via OpenBB MCP +- **Equity Data**: Historical prices, fundamentals, ownership, shorts +- **News & Sentiment**: Company news, market news, analyst coverage +- **SEC Filings**: 10-K, 10-Q, 8-K filings via SEC provider + +### Via Stanley Backend +- **Research**: ResearchAnalyzer, DCF models, peer comparison +- **Analytics**: Money flow, institutional positioning, options flow +- **Accounting**: Financial statements, earnings quality, red flags + +## Research Workflow + +### 1. Company Overview +``` +# Quick overview using OpenBB +obb.equity.fundamental.overview(symbol="AAPL", provider="fmp") +obb.equity.profile(symbol="AAPL") +``` + +### 2. Financial Analysis +``` +# Income statement trend +obb.equity.fundamental.income(symbol="AAPL", period="annual", limit=5) + +# Balance sheet strength +obb.equity.fundamental.balance(symbol="AAPL", period="annual") + +# Cash flow analysis +obb.equity.fundamental.cash(symbol="AAPL", period="annual") + +# Key ratios +obb.equity.fundamental.ratios(symbol="AAPL") +``` + +### 3. Ownership & Positioning +``` +# Institutional holders (13F) +obb.equity.ownership.institutional(symbol="AAPL", provider="fmp") + +# Insider trading +obb.equity.ownership.insider_trading(symbol="AAPL") + +# Short interest +obb.equity.shorts.short_volume(symbol="AAPL") +``` + +### 4. Valuation Analysis +``` +# Use Stanley's valuation module +from stanley.research import calculate_dcf, compare_to_peers + +dcf_result = calculate_dcf( + symbol="AAPL", + growth_rate=0.08, + discount_rate=0.10, + terminal_growth=0.025 +) + +peers = compare_to_peers("AAPL", ["MSFT", "GOOGL", "AMZN"]) +``` + +## Output Format + +Research reports should include: +1. **Executive Summary**: Key thesis and recommendation +2. **Business Overview**: What the company does, moat analysis +3. **Financial Analysis**: Revenue trends, margins, ROE/ROIC +4. **Valuation**: DCF, comparables, historical multiples +5. **Risks**: Key risks and bear case scenarios +6. **Catalysts**: Upcoming events and inflection points + +## Memory Integration + +Store research findings: +```typescript +await memory.store({ + namespace: "stanley/research", + key: `thesis/${symbol}`, + value: { + symbol, + thesis: "...", + conviction: "high", + targetPrice: 185, + lastUpdated: new Date() + } +}); +``` diff --git a/.claude/skills/flow-nexus-neural/SKILL.md b/.claude/skills/flow-nexus-neural/SKILL.md new file mode 100644 index 0000000000..1f1f7d7fa2 --- /dev/null +++ b/.claude/skills/flow-nexus-neural/SKILL.md @@ -0,0 +1,738 @@ +--- +name: flow-nexus-neural +description: Train and deploy neural networks in distributed E2B sandboxes with Flow Nexus +version: 1.0.0 +category: ai-ml +tags: + - neural-networks + - distributed-training + - machine-learning + - deep-learning + - flow-nexus + - e2b-sandboxes +requires_auth: true +mcp_server: flow-nexus +--- + +# Flow Nexus Neural Networks + +Deploy, train, and manage neural networks in distributed E2B sandbox environments. Train custom models with multiple architectures (feedforward, LSTM, GAN, transformer) or use pre-built templates from the marketplace. + +## Prerequisites + +```bash +# Add Flow Nexus MCP server +claude mcp add flow-nexus npx flow-nexus@latest mcp start + +# Register and login +npx flow-nexus@latest register +npx flow-nexus@latest login +``` + +## Core Capabilities + +### 1. Single-Node Neural Training + +Train neural networks with custom architectures and configurations. + +**Available Architectures:** +- `feedforward` - Standard fully-connected networks +- `lstm` - Long Short-Term Memory for sequences +- `gan` - Generative Adversarial Networks +- `autoencoder` - Dimensionality reduction +- `transformer` - Attention-based models + +**Training Tiers:** +- `nano` - Minimal resources (fast, limited) +- `mini` - Small models +- `small` - Standard models +- `medium` - Complex models +- `large` - Large-scale training + +#### Example: Train Custom Classifier + +```javascript +mcp__flow-nexus__neural_train({ + config: { + architecture: { + type: "feedforward", + layers: [ + { type: "dense", units: 256, activation: "relu" }, + { type: "dropout", rate: 0.3 }, + { type: "dense", units: 128, activation: "relu" }, + { type: "dropout", rate: 0.2 }, + { type: "dense", units: 64, activation: "relu" }, + { type: "dense", units: 10, activation: "softmax" } + ] + }, + training: { + epochs: 100, + batch_size: 32, + learning_rate: 0.001, + optimizer: "adam" + }, + divergent: { + enabled: true, + pattern: "lateral", // quantum, chaotic, associative, evolutionary + factor: 0.5 + } + }, + tier: "small", + user_id: "your_user_id" +}) +``` + +#### Example: LSTM for Time Series + +```javascript +mcp__flow-nexus__neural_train({ + config: { + architecture: { + type: "lstm", + layers: [ + { type: "lstm", units: 128, return_sequences: true }, + { type: "dropout", rate: 0.2 }, + { type: "lstm", units: 64 }, + { type: "dense", units: 1, activation: "linear" } + ] + }, + training: { + epochs: 150, + batch_size: 64, + learning_rate: 0.01, + optimizer: "adam" + } + }, + tier: "medium" +}) +``` + +#### Example: Transformer Architecture + +```javascript +mcp__flow-nexus__neural_train({ + config: { + architecture: { + type: "transformer", + layers: [ + { type: "embedding", vocab_size: 10000, embedding_dim: 512 }, + { type: "transformer_encoder", num_heads: 8, ff_dim: 2048 }, + { type: "global_average_pooling" }, + { type: "dense", units: 128, activation: "relu" }, + { type: "dense", units: 2, activation: "softmax" } + ] + }, + training: { + epochs: 50, + batch_size: 16, + learning_rate: 0.0001, + optimizer: "adam" + } + }, + tier: "large" +}) +``` + +### 2. Model Inference + +Run predictions on trained models. + +```javascript +mcp__flow-nexus__neural_predict({ + model_id: "model_abc123", + input: [ + [0.5, 0.3, 0.2, 0.1], + [0.8, 0.1, 0.05, 0.05], + [0.2, 0.6, 0.15, 0.05] + ], + user_id: "your_user_id" +}) +``` + +**Response:** +```json +{ + "predictions": [ + [0.12, 0.85, 0.03], + [0.89, 0.08, 0.03], + [0.05, 0.92, 0.03] + ], + "inference_time_ms": 45, + "model_version": "1.0.0" +} +``` + +### 3. Template Marketplace + +Browse and deploy pre-trained models from the marketplace. + +#### List Available Templates + +```javascript +mcp__flow-nexus__neural_list_templates({ + category: "classification", // timeseries, regression, nlp, vision, anomaly, generative + tier: "free", // or "paid" + search: "sentiment", + limit: 20 +}) +``` + +**Response:** +```json +{ + "templates": [ + { + "id": "sentiment-analysis-v2", + "name": "Sentiment Analysis Classifier", + "description": "Pre-trained BERT model for sentiment analysis", + "category": "nlp", + "accuracy": 0.94, + "downloads": 1523, + "tier": "free" + }, + { + "id": "image-classifier-resnet", + "name": "ResNet Image Classifier", + "description": "ResNet-50 for image classification", + "category": "vision", + "accuracy": 0.96, + "downloads": 2341, + "tier": "paid" + } + ] +} +``` + +#### Deploy Template + +```javascript +mcp__flow-nexus__neural_deploy_template({ + template_id: "sentiment-analysis-v2", + custom_config: { + training: { + epochs: 50, + learning_rate: 0.0001 + } + }, + user_id: "your_user_id" +}) +``` + +### 4. Distributed Training Clusters + +Train large models across multiple E2B sandboxes with distributed computing. + +#### Initialize Cluster + +```javascript +mcp__flow-nexus__neural_cluster_init({ + name: "large-model-cluster", + architecture: "transformer", // transformer, cnn, rnn, gnn, hybrid + topology: "mesh", // mesh, ring, star, hierarchical + consensus: "proof-of-learning", // byzantine, raft, gossip + daaEnabled: true, // Decentralized Autonomous Agents + wasmOptimization: true +}) +``` + +**Response:** +```json +{ + "cluster_id": "cluster_xyz789", + "name": "large-model-cluster", + "status": "initializing", + "topology": "mesh", + "max_nodes": 100, + "created_at": "2025-10-19T10:30:00Z" +} +``` + +#### Deploy Worker Nodes + +```javascript +// Deploy parameter server +mcp__flow-nexus__neural_node_deploy({ + cluster_id: "cluster_xyz789", + node_type: "parameter_server", + model: "large", + template: "nodejs", + capabilities: ["parameter_management", "gradient_aggregation"], + autonomy: 0.8 +}) + +// Deploy worker nodes +mcp__flow-nexus__neural_node_deploy({ + cluster_id: "cluster_xyz789", + node_type: "worker", + model: "xl", + role: "worker", + capabilities: ["training", "inference"], + layers: [ + { type: "transformer_encoder", num_heads: 16 }, + { type: "feed_forward", units: 4096 } + ], + autonomy: 0.9 +}) + +// Deploy aggregator +mcp__flow-nexus__neural_node_deploy({ + cluster_id: "cluster_xyz789", + node_type: "aggregator", + model: "large", + capabilities: ["gradient_aggregation", "model_synchronization"] +}) +``` + +#### Connect Cluster Topology + +```javascript +mcp__flow-nexus__neural_cluster_connect({ + cluster_id: "cluster_xyz789", + topology: "mesh" // Override default if needed +}) +``` + +#### Start Distributed Training + +```javascript +mcp__flow-nexus__neural_train_distributed({ + cluster_id: "cluster_xyz789", + dataset: "imagenet", // or custom dataset identifier + epochs: 100, + batch_size: 128, + learning_rate: 0.001, + optimizer: "adam", // sgd, rmsprop, adagrad + federated: true // Enable federated learning +}) +``` + +**Federated Learning Example:** +```javascript +mcp__flow-nexus__neural_train_distributed({ + cluster_id: "cluster_xyz789", + dataset: "medical_images_distributed", + epochs: 200, + batch_size: 64, + learning_rate: 0.0001, + optimizer: "adam", + federated: true, // Data stays on local nodes + aggregation_rounds: 50, + min_nodes_per_round: 5 +}) +``` + +#### Monitor Cluster Status + +```javascript +mcp__flow-nexus__neural_cluster_status({ + cluster_id: "cluster_xyz789" +}) +``` + +**Response:** +```json +{ + "cluster_id": "cluster_xyz789", + "status": "training", + "nodes": [ + { + "node_id": "node_001", + "type": "parameter_server", + "status": "active", + "cpu_usage": 0.75, + "memory_usage": 0.82 + }, + { + "node_id": "node_002", + "type": "worker", + "status": "active", + "training_progress": 0.45 + } + ], + "training_metrics": { + "current_epoch": 45, + "total_epochs": 100, + "loss": 0.234, + "accuracy": 0.891 + } +} +``` + +#### Run Distributed Inference + +```javascript +mcp__flow-nexus__neural_predict_distributed({ + cluster_id: "cluster_xyz789", + input_data: JSON.stringify([ + [0.1, 0.2, 0.3], + [0.4, 0.5, 0.6] + ]), + aggregation: "ensemble" // mean, majority, weighted, ensemble +}) +``` + +#### Terminate Cluster + +```javascript +mcp__flow-nexus__neural_cluster_terminate({ + cluster_id: "cluster_xyz789" +}) +``` + +### 5. Model Management + +#### List Your Models + +```javascript +mcp__flow-nexus__neural_list_models({ + user_id: "your_user_id", + include_public: true +}) +``` + +**Response:** +```json +{ + "models": [ + { + "model_id": "model_abc123", + "name": "Custom Classifier v1", + "architecture": "feedforward", + "accuracy": 0.92, + "created_at": "2025-10-15T14:20:00Z", + "status": "trained" + }, + { + "model_id": "model_def456", + "name": "LSTM Forecaster", + "architecture": "lstm", + "mse": 0.0045, + "created_at": "2025-10-18T09:15:00Z", + "status": "training" + } + ] +} +``` + +#### Check Training Status + +```javascript +mcp__flow-nexus__neural_training_status({ + job_id: "job_training_xyz" +}) +``` + +**Response:** +```json +{ + "job_id": "job_training_xyz", + "status": "training", + "progress": 0.67, + "current_epoch": 67, + "total_epochs": 100, + "current_loss": 0.234, + "estimated_completion": "2025-10-19T12:45:00Z" +} +``` + +#### Performance Benchmarking + +```javascript +mcp__flow-nexus__neural_performance_benchmark({ + model_id: "model_abc123", + benchmark_type: "comprehensive" // inference, throughput, memory, comprehensive +}) +``` + +**Response:** +```json +{ + "model_id": "model_abc123", + "benchmarks": { + "inference_latency_ms": 12.5, + "throughput_qps": 8000, + "memory_usage_mb": 245, + "gpu_utilization": 0.78, + "accuracy": 0.92, + "f1_score": 0.89 + }, + "timestamp": "2025-10-19T11:00:00Z" +} +``` + +#### Create Validation Workflow + +```javascript +mcp__flow-nexus__neural_validation_workflow({ + model_id: "model_abc123", + user_id: "your_user_id", + validation_type: "comprehensive" // performance, accuracy, robustness, comprehensive +}) +``` + +### 6. Publishing and Marketplace + +#### Publish Model as Template + +```javascript +mcp__flow-nexus__neural_publish_template({ + model_id: "model_abc123", + name: "High-Accuracy Sentiment Classifier", + description: "Fine-tuned BERT model for sentiment analysis with 94% accuracy", + category: "nlp", + price: 0, // 0 for free, or credits amount + user_id: "your_user_id" +}) +``` + +#### Rate a Template + +```javascript +mcp__flow-nexus__neural_rate_template({ + template_id: "sentiment-analysis-v2", + rating: 5, + review: "Excellent model! Achieved 95% accuracy on my dataset.", + user_id: "your_user_id" +}) +``` + +## Common Use Cases + +### Image Classification with CNN + +```javascript +// Initialize cluster for large-scale image training +const cluster = await mcp__flow-nexus__neural_cluster_init({ + name: "image-classification-cluster", + architecture: "cnn", + topology: "hierarchical", + wasmOptimization: true +}) + +// Deploy worker nodes +await mcp__flow-nexus__neural_node_deploy({ + cluster_id: cluster.cluster_id, + node_type: "worker", + model: "large", + capabilities: ["training", "data_augmentation"] +}) + +// Start training +await mcp__flow-nexus__neural_train_distributed({ + cluster_id: cluster.cluster_id, + dataset: "custom_images", + epochs: 100, + batch_size: 64, + learning_rate: 0.001, + optimizer: "adam" +}) +``` + +### NLP Sentiment Analysis + +```javascript +// Use pre-built template +const deployment = await mcp__flow-nexus__neural_deploy_template({ + template_id: "sentiment-analysis-v2", + custom_config: { + training: { + epochs: 30, + batch_size: 16 + } + } +}) + +// Run inference +const result = await mcp__flow-nexus__neural_predict({ + model_id: deployment.model_id, + input: ["This product is amazing!", "Terrible experience."] +}) +``` + +### Time Series Forecasting + +```javascript +// Train LSTM model +const training = await mcp__flow-nexus__neural_train({ + config: { + architecture: { + type: "lstm", + layers: [ + { type: "lstm", units: 128, return_sequences: true }, + { type: "dropout", rate: 0.2 }, + { type: "lstm", units: 64 }, + { type: "dense", units: 1 } + ] + }, + training: { + epochs: 150, + batch_size: 64, + learning_rate: 0.01, + optimizer: "adam" + } + }, + tier: "medium" +}) + +// Monitor progress +const status = await mcp__flow-nexus__neural_training_status({ + job_id: training.job_id +}) +``` + +### Federated Learning for Privacy + +```javascript +// Initialize federated cluster +const cluster = await mcp__flow-nexus__neural_cluster_init({ + name: "federated-medical-cluster", + architecture: "transformer", + topology: "mesh", + consensus: "proof-of-learning", + daaEnabled: true +}) + +// Deploy nodes across different locations +for (let i = 0; i < 5; i++) { + await mcp__flow-nexus__neural_node_deploy({ + cluster_id: cluster.cluster_id, + node_type: "worker", + model: "large", + autonomy: 0.9 + }) +} + +// Train with federated learning (data never leaves nodes) +await mcp__flow-nexus__neural_train_distributed({ + cluster_id: cluster.cluster_id, + dataset: "medical_records_distributed", + epochs: 200, + federated: true, + aggregation_rounds: 100 +}) +``` + +## Architecture Patterns + +### Feedforward Networks +Best for: Classification, regression, simple pattern recognition +```javascript +{ + type: "feedforward", + layers: [ + { type: "dense", units: 256, activation: "relu" }, + { type: "dropout", rate: 0.3 }, + { type: "dense", units: 128, activation: "relu" }, + { type: "dense", units: 10, activation: "softmax" } + ] +} +``` + +### LSTM Networks +Best for: Time series, sequences, forecasting +```javascript +{ + type: "lstm", + layers: [ + { type: "lstm", units: 128, return_sequences: true }, + { type: "lstm", units: 64 }, + { type: "dense", units: 1 } + ] +} +``` + +### Transformers +Best for: NLP, attention mechanisms, large-scale text +```javascript +{ + type: "transformer", + layers: [ + { type: "embedding", vocab_size: 10000, embedding_dim: 512 }, + { type: "transformer_encoder", num_heads: 8, ff_dim: 2048 }, + { type: "global_average_pooling" }, + { type: "dense", units: 2, activation: "softmax" } + ] +} +``` + +### GANs +Best for: Generative tasks, image synthesis +```javascript +{ + type: "gan", + generator_layers: [...], + discriminator_layers: [...] +} +``` + +### Autoencoders +Best for: Dimensionality reduction, anomaly detection +```javascript +{ + type: "autoencoder", + encoder_layers: [ + { type: "dense", units: 128, activation: "relu" }, + { type: "dense", units: 64, activation: "relu" } + ], + decoder_layers: [ + { type: "dense", units: 128, activation: "relu" }, + { type: "dense", units: input_dim, activation: "sigmoid" } + ] +} +``` + +## Best Practices + +1. **Start Small**: Begin with `nano` or `mini` tiers for experimentation +2. **Use Templates**: Leverage marketplace templates for common tasks +3. **Monitor Training**: Check status regularly to catch issues early +4. **Benchmark Models**: Always benchmark before production deployment +5. **Distributed Training**: Use clusters for large models (>1B parameters) +6. **Federated Learning**: Use for privacy-sensitive data +7. **Version Models**: Publish successful models as templates for reuse +8. **Validate Thoroughly**: Use validation workflows before deployment + +## Troubleshooting + +### Training Stalled +```javascript +// Check cluster status +const status = await mcp__flow-nexus__neural_cluster_status({ + cluster_id: "cluster_id" +}) + +// Terminate and restart if needed +await mcp__flow-nexus__neural_cluster_terminate({ + cluster_id: "cluster_id" +}) +``` + +### Low Accuracy +- Increase epochs +- Adjust learning rate +- Add regularization (dropout) +- Try different optimizer +- Use data augmentation + +### Out of Memory +- Reduce batch size +- Use smaller model tier +- Enable gradient accumulation +- Use distributed training + +## Related Skills + +- `flow-nexus-sandbox` - E2B sandbox management +- `flow-nexus-swarm` - AI swarm orchestration +- `flow-nexus-workflow` - Workflow automation + +## Resources + +- Flow Nexus Docs: https://flow-nexus.ruv.io/docs +- Neural Network Guide: https://flow-nexus.ruv.io/docs/neural +- Template Marketplace: https://flow-nexus.ruv.io/templates +- API Reference: https://flow-nexus.ruv.io/api + +--- + +**Note**: Distributed training requires authentication. Register at https://flow-nexus.ruv.io or use `npx flow-nexus@latest register`. diff --git a/.claude/skills/flow-nexus-platform/SKILL.md b/.claude/skills/flow-nexus-platform/SKILL.md new file mode 100644 index 0000000000..37050f001f --- /dev/null +++ b/.claude/skills/flow-nexus-platform/SKILL.md @@ -0,0 +1,1157 @@ +--- +name: flow-nexus-platform +description: Comprehensive Flow Nexus platform management - authentication, sandboxes, app deployment, payments, and challenges +category: platform +version: 1.0.0 +author: Flow Nexus +tags: [authentication, sandboxes, deployment, payments, gamification, cloud] +--- + +# Flow Nexus Platform Management + +Comprehensive platform management for Flow Nexus - covering authentication, sandbox execution, app deployment, credit management, and coding challenges. + +## Table of Contents +1. [Authentication & User Management](#authentication--user-management) +2. [Sandbox Management](#sandbox-management) +3. [App Store & Deployment](#app-store--deployment) +4. [Payments & Credits](#payments--credits) +5. [Challenges & Achievements](#challenges--achievements) +6. [Storage & Real-time](#storage--real-time) +7. [System Utilities](#system-utilities) + +--- + +## Authentication & User Management + +### Registration & Login + +**Register New Account** +```javascript +mcp__flow-nexus__user_register({ + email: "user@example.com", + password: "secure_password", + full_name: "Your Name", + username: "unique_username" // optional +}) +``` + +**Login** +```javascript +mcp__flow-nexus__user_login({ + email: "user@example.com", + password: "your_password" +}) +``` + +**Check Authentication Status** +```javascript +mcp__flow-nexus__auth_status({ detailed: true }) +``` + +**Logout** +```javascript +mcp__flow-nexus__user_logout() +``` + +### Password Management + +**Request Password Reset** +```javascript +mcp__flow-nexus__user_reset_password({ + email: "user@example.com" +}) +``` + +**Update Password with Token** +```javascript +mcp__flow-nexus__user_update_password({ + token: "reset_token_from_email", + new_password: "new_secure_password" +}) +``` + +**Verify Email** +```javascript +mcp__flow-nexus__user_verify_email({ + token: "verification_token_from_email" +}) +``` + +### Profile Management + +**Get User Profile** +```javascript +mcp__flow-nexus__user_profile({ + user_id: "your_user_id" +}) +``` + +**Update Profile** +```javascript +mcp__flow-nexus__user_update_profile({ + user_id: "your_user_id", + updates: { + full_name: "Updated Name", + bio: "AI Developer and researcher", + github_username: "yourusername", + twitter_handle: "@yourhandle" + } +}) +``` + +**Get User Statistics** +```javascript +mcp__flow-nexus__user_stats({ + user_id: "your_user_id" +}) +``` + +**Upgrade User Tier** +```javascript +mcp__flow-nexus__user_upgrade({ + user_id: "your_user_id", + tier: "pro" // pro, enterprise +}) +``` + +--- + +## Sandbox Management + +### Create & Configure Sandboxes + +**Create Sandbox** +```javascript +mcp__flow-nexus__sandbox_create({ + template: "node", // node, python, react, nextjs, vanilla, base, claude-code + name: "my-sandbox", + env_vars: { + API_KEY: "your_api_key", + NODE_ENV: "development", + DATABASE_URL: "postgres://..." + }, + install_packages: ["express", "cors", "dotenv"], + startup_script: "npm run dev", + timeout: 3600, // seconds + metadata: { + project: "my-project", + environment: "staging" + } +}) +``` + +**Configure Existing Sandbox** +```javascript +mcp__flow-nexus__sandbox_configure({ + sandbox_id: "sandbox_id", + env_vars: { + NEW_VAR: "value" + }, + install_packages: ["axios", "lodash"], + run_commands: ["npm run migrate", "npm run seed"], + anthropic_key: "sk-ant-..." // For Claude Code integration +}) +``` + +### Execute Code + +**Run Code in Sandbox** +```javascript +mcp__flow-nexus__sandbox_execute({ + sandbox_id: "sandbox_id", + code: ` + console.log('Hello from sandbox!'); + const result = await fetch('https://api.example.com/data'); + const data = await result.json(); + return data; + `, + language: "javascript", + capture_output: true, + timeout: 60, // seconds + working_dir: "/app", + env_vars: { + TEMP_VAR: "override" + } +}) +``` + +### Manage Sandboxes + +**List Sandboxes** +```javascript +mcp__flow-nexus__sandbox_list({ + status: "running" // running, stopped, all +}) +``` + +**Get Sandbox Status** +```javascript +mcp__flow-nexus__sandbox_status({ + sandbox_id: "sandbox_id" +}) +``` + +**Upload File to Sandbox** +```javascript +mcp__flow-nexus__sandbox_upload({ + sandbox_id: "sandbox_id", + file_path: "/app/config/database.json", + content: JSON.stringify(databaseConfig, null, 2) +}) +``` + +**Get Sandbox Logs** +```javascript +mcp__flow-nexus__sandbox_logs({ + sandbox_id: "sandbox_id", + lines: 100 // max 1000 +}) +``` + +**Stop Sandbox** +```javascript +mcp__flow-nexus__sandbox_stop({ + sandbox_id: "sandbox_id" +}) +``` + +**Delete Sandbox** +```javascript +mcp__flow-nexus__sandbox_delete({ + sandbox_id: "sandbox_id" +}) +``` + +### Sandbox Templates + +- **node**: Node.js environment with npm +- **python**: Python 3.x with pip +- **react**: React development setup +- **nextjs**: Next.js full-stack framework +- **vanilla**: Basic HTML/CSS/JS +- **base**: Minimal Linux environment +- **claude-code**: Claude Code integrated environment + +### Common Sandbox Patterns + +**API Development Sandbox** +```javascript +mcp__flow-nexus__sandbox_create({ + template: "node", + name: "api-development", + install_packages: [ + "express", + "cors", + "helmet", + "dotenv", + "jsonwebtoken", + "bcrypt" + ], + env_vars: { + PORT: "3000", + NODE_ENV: "development" + }, + startup_script: "npm run dev" +}) +``` + +**Machine Learning Sandbox** +```javascript +mcp__flow-nexus__sandbox_create({ + template: "python", + name: "ml-training", + install_packages: [ + "numpy", + "pandas", + "scikit-learn", + "matplotlib", + "tensorflow" + ], + env_vars: { + CUDA_VISIBLE_DEVICES: "0" + } +}) +``` + +**Full-Stack Development** +```javascript +mcp__flow-nexus__sandbox_create({ + template: "nextjs", + name: "fullstack-app", + install_packages: [ + "prisma", + "@prisma/client", + "next-auth", + "zod" + ], + env_vars: { + DATABASE_URL: "postgresql://...", + NEXTAUTH_SECRET: "secret" + } +}) +``` + +--- + +## App Store & Deployment + +### Browse & Search + +**Search Applications** +```javascript +mcp__flow-nexus__app_search({ + search: "authentication api", + category: "backend", + featured: true, + limit: 20 +}) +``` + +**Get App Details** +```javascript +mcp__flow-nexus__app_get({ + app_id: "app_id" +}) +``` + +**List Templates** +```javascript +mcp__flow-nexus__app_store_list_templates({ + category: "web-api", + tags: ["express", "jwt", "typescript"], + limit: 20 +}) +``` + +**Get Template Details** +```javascript +mcp__flow-nexus__template_get({ + template_name: "express-api-starter", + template_id: "template_id" // alternative +}) +``` + +**List All Available Templates** +```javascript +mcp__flow-nexus__template_list({ + category: "backend", + template_type: "starter", + featured: true, + limit: 50 +}) +``` + +### Publish Applications + +**Publish App to Store** +```javascript +mcp__flow-nexus__app_store_publish_app({ + name: "JWT Authentication Service", + description: "Production-ready JWT authentication microservice with refresh tokens", + category: "backend", + version: "1.0.0", + source_code: sourceCodeString, + tags: ["auth", "jwt", "express", "typescript", "security"], + metadata: { + author: "Your Name", + license: "MIT", + repository: "github.com/username/repo", + homepage: "https://yourapp.com", + documentation: "https://docs.yourapp.com" + } +}) +``` + +**Update Application** +```javascript +mcp__flow-nexus__app_update({ + app_id: "app_id", + updates: { + version: "1.1.0", + description: "Added OAuth2 support", + tags: ["auth", "jwt", "oauth2", "express"], + source_code: updatedSourceCode + } +}) +``` + +### Deploy Templates + +**Deploy Template** +```javascript +mcp__flow-nexus__template_deploy({ + template_name: "express-api-starter", + deployment_name: "my-production-api", + variables: { + api_key: "your_api_key", + database_url: "postgres://user:pass@host:5432/db", + redis_url: "redis://localhost:6379" + }, + env_vars: { + NODE_ENV: "production", + PORT: "8080", + LOG_LEVEL: "info" + } +}) +``` + +### Analytics & Management + +**Get App Analytics** +```javascript +mcp__flow-nexus__app_analytics({ + app_id: "your_app_id", + timeframe: "30d" // 24h, 7d, 30d, 90d +}) +``` + +**View Installed Apps** +```javascript +mcp__flow-nexus__app_installed({ + user_id: "your_user_id" +}) +``` + +**Get Market Statistics** +```javascript +mcp__flow-nexus__market_data() +``` + +### App Categories + +- **web-api**: RESTful APIs and microservices +- **frontend**: React, Vue, Angular applications +- **full-stack**: Complete end-to-end applications +- **cli-tools**: Command-line utilities +- **data-processing**: ETL pipelines and analytics +- **ml-models**: Pre-trained machine learning models +- **blockchain**: Web3 and blockchain applications +- **mobile**: React Native and mobile apps + +### Publishing Best Practices + +1. **Documentation**: Include comprehensive README with setup instructions +2. **Examples**: Provide usage examples and sample configurations +3. **Testing**: Include test suite and CI/CD configuration +4. **Versioning**: Use semantic versioning (MAJOR.MINOR.PATCH) +5. **Licensing**: Add clear license information (MIT, Apache, etc.) +6. **Deployment**: Include Docker/docker-compose configurations +7. **Migrations**: Provide upgrade guides for version updates +8. **Security**: Document security considerations and best practices + +### Revenue Sharing + +- Earn rUv credits when others deploy your templates +- Set pricing (0 for free, or credits for premium) +- Track usage and earnings via analytics +- Withdraw credits or use for Flow Nexus services + +--- + +## Payments & Credits + +### Balance & Credits + +**Check Credit Balance** +```javascript +mcp__flow-nexus__check_balance() +``` + +**Check rUv Balance** +```javascript +mcp__flow-nexus__ruv_balance({ + user_id: "your_user_id" +}) +``` + +**View Transaction History** +```javascript +mcp__flow-nexus__ruv_history({ + user_id: "your_user_id", + limit: 100 +}) +``` + +**Get Payment History** +```javascript +mcp__flow-nexus__get_payment_history({ + limit: 50 +}) +``` + +### Purchase Credits + +**Create Payment Link** +```javascript +mcp__flow-nexus__create_payment_link({ + amount: 50 // USD, minimum $10 +}) +// Returns secure Stripe payment URL +``` + +### Auto-Refill Configuration + +**Enable Auto-Refill** +```javascript +mcp__flow-nexus__configure_auto_refill({ + enabled: true, + threshold: 100, // Refill when credits drop below 100 + amount: 50 // Purchase $50 worth of credits +}) +``` + +**Disable Auto-Refill** +```javascript +mcp__flow-nexus__configure_auto_refill({ + enabled: false +}) +``` + +### Credit Pricing + +**Service Costs:** +- **Swarm Operations**: 1-10 credits/hour +- **Sandbox Execution**: 0.5-5 credits/hour +- **Neural Training**: 5-50 credits/job +- **Workflow Runs**: 0.1-1 credit/execution +- **Storage**: 0.01 credits/GB/day +- **API Calls**: 0.001-0.01 credits/request + +### Earning Credits + +**Ways to Earn:** +1. **Complete Challenges**: 10-500 credits per challenge +2. **Publish Templates**: Earn when others deploy (you set pricing) +3. **Referral Program**: Bonus credits for user invites +4. **Daily Login**: Small daily bonus (5-10 credits) +5. **Achievements**: Unlock milestone rewards (50-1000 credits) +6. **App Store Sales**: Revenue share from paid templates + +**Earn Credits Programmatically** +```javascript +mcp__flow-nexus__app_store_earn_ruv({ + user_id: "your_user_id", + amount: 100, + reason: "Completed expert algorithm challenge", + source: "challenge" // challenge, app_usage, referral, etc. +}) +``` + +### Subscription Tiers + +**Free Tier** +- 100 free credits monthly +- Basic sandbox access (2 concurrent) +- Limited swarm agents (3 max) +- Community support +- 1GB storage + +**Pro Tier ($29/month)** +- 1000 credits monthly +- Priority sandbox access (10 concurrent) +- Unlimited swarm agents +- Advanced workflows +- Email support +- 10GB storage +- Early access to features + +**Enterprise Tier (Custom Pricing)** +- Unlimited credits +- Dedicated compute resources +- Custom neural models +- 99.9% SLA guarantee +- Priority 24/7 support +- Unlimited storage +- White-label options +- On-premise deployment + +### Cost Optimization Tips + +1. **Use Smaller Sandboxes**: Choose appropriate templates (base vs full-stack) +2. **Optimize Neural Training**: Tune hyperparameters, reduce epochs +3. **Batch Operations**: Group workflow executions together +4. **Clean Up Resources**: Delete unused sandboxes and storage +5. **Monitor Usage**: Check `user_stats` regularly +6. **Use Free Templates**: Leverage community templates +7. **Schedule Off-Peak**: Run heavy jobs during low-cost periods + +--- + +## Challenges & Achievements + +### Browse Challenges + +**List Available Challenges** +```javascript +mcp__flow-nexus__challenges_list({ + difficulty: "intermediate", // beginner, intermediate, advanced, expert + category: "algorithms", + status: "active", // active, completed, locked + limit: 20 +}) +``` + +**Get Challenge Details** +```javascript +mcp__flow-nexus__challenge_get({ + challenge_id: "two-sum-problem" +}) +``` + +### Submit Solutions + +**Submit Challenge Solution** +```javascript +mcp__flow-nexus__challenge_submit({ + challenge_id: "challenge_id", + user_id: "your_user_id", + solution_code: ` + function twoSum(nums, target) { + const map = new Map(); + for (let i = 0; i < nums.length; i++) { + const complement = target - nums[i]; + if (map.has(complement)) { + return [map.get(complement), i]; + } + map.set(nums[i], i); + } + return []; + } + `, + language: "javascript", + execution_time: 45 // milliseconds (optional) +}) +``` + +**Mark Challenge as Complete** +```javascript +mcp__flow-nexus__app_store_complete_challenge({ + challenge_id: "challenge_id", + user_id: "your_user_id", + submission_data: { + passed_tests: 10, + total_tests: 10, + execution_time: 45, + memory_usage: 2048 // KB + } +}) +``` + +### Leaderboards + +**Global Leaderboard** +```javascript +mcp__flow-nexus__leaderboard_get({ + type: "global", // global, weekly, monthly, challenge + limit: 100 +}) +``` + +**Challenge-Specific Leaderboard** +```javascript +mcp__flow-nexus__leaderboard_get({ + type: "challenge", + challenge_id: "specific_challenge_id", + limit: 50 +}) +``` + +### Achievements & Badges + +**List User Achievements** +```javascript +mcp__flow-nexus__achievements_list({ + user_id: "your_user_id", + category: "speed_demon" // Optional filter +}) +``` + +### Challenge Categories + +- **algorithms**: Classic algorithm problems (sorting, searching, graphs) +- **data-structures**: DS implementation (trees, heaps, tries) +- **system-design**: Architecture and scalability challenges +- **optimization**: Performance and efficiency problems +- **security**: Security-focused vulnerabilities and fixes +- **ml-basics**: Machine learning fundamentals +- **distributed-systems**: Concurrency and distributed computing +- **databases**: Query optimization and schema design + +### Challenge Difficulty Rewards + +- **Beginner**: 10-25 credits +- **Intermediate**: 50-100 credits +- **Advanced**: 150-300 credits +- **Expert**: 400-500 credits +- **Master**: 600-1000 credits + +### Achievement Types + +- **Speed Demon**: Complete challenges in record time +- **Code Golf**: Minimize code length +- **Perfect Score**: 100% test pass rate +- **Streak Master**: Complete challenges N days in a row +- **Polyglot**: Solve in multiple languages +- **Debugger**: Fix broken code challenges +- **Optimizer**: Achieve top performance benchmarks + +### Tips for Success + +1. **Start Simple**: Begin with beginner challenges to build confidence +2. **Review Solutions**: Study top solutions after completing +3. **Optimize**: Aim for both correctness and performance +4. **Daily Practice**: Complete daily challenges for bonus credits +5. **Community**: Engage with discussions and learn from others +6. **Track Progress**: Monitor achievements and leaderboard position +7. **Experiment**: Try multiple approaches to problems + +--- + +## Storage & Real-time + +### File Storage + +**Upload File** +```javascript +mcp__flow-nexus__storage_upload({ + bucket: "my-bucket", // public, private, shared, temp + path: "data/users.json", + content: JSON.stringify(userData, null, 2), + content_type: "application/json" +}) +``` + +**List Files** +```javascript +mcp__flow-nexus__storage_list({ + bucket: "my-bucket", + path: "data/", // prefix filter + limit: 100 +}) +``` + +**Get Public URL** +```javascript +mcp__flow-nexus__storage_get_url({ + bucket: "my-bucket", + path: "data/report.pdf", + expires_in: 3600 // seconds (default: 1 hour) +}) +``` + +**Delete File** +```javascript +mcp__flow-nexus__storage_delete({ + bucket: "my-bucket", + path: "data/old-file.json" +}) +``` + +### Storage Buckets + +- **public**: Publicly accessible files (CDN-backed) +- **private**: User-only access with authentication +- **shared**: Team collaboration with ACL +- **temp**: Auto-deleted after 24 hours + +### Real-time Subscriptions + +**Subscribe to Database Changes** +```javascript +mcp__flow-nexus__realtime_subscribe({ + table: "tasks", + event: "INSERT", // INSERT, UPDATE, DELETE, * + filter: "status=eq.pending AND priority=eq.high" +}) +``` + +**List Active Subscriptions** +```javascript +mcp__flow-nexus__realtime_list() +``` + +**Unsubscribe** +```javascript +mcp__flow-nexus__realtime_unsubscribe({ + subscription_id: "subscription_id" +}) +``` + +### Execution Monitoring + +**Subscribe to Execution Stream** +```javascript +mcp__flow-nexus__execution_stream_subscribe({ + stream_type: "claude-flow-swarm", // claude-code, claude-flow-swarm, claude-flow-hive-mind, github-integration + deployment_id: "deployment_id", + sandbox_id: "sandbox_id" // alternative +}) +``` + +**Get Stream Status** +```javascript +mcp__flow-nexus__execution_stream_status({ + stream_id: "stream_id" +}) +``` + +**List Generated Files** +```javascript +mcp__flow-nexus__execution_files_list({ + stream_id: "stream_id", + created_by: "claude-flow", // claude-code, claude-flow, git-clone, user + file_type: "javascript" // filter by extension +}) +``` + +**Get File Content from Execution** +```javascript +mcp__flow-nexus__execution_file_get({ + file_id: "file_id", + file_path: "/path/to/file.js" // alternative +}) +``` + +--- + +## System Utilities + +### Queen Seraphina AI Assistant + +**Seek Guidance from Seraphina** +```javascript +mcp__flow-nexus__seraphina_chat({ + message: "How should I architect a distributed microservices system?", + enable_tools: true, // Allow her to create swarms, deploy code, etc. + conversation_history: [ + { role: "user", content: "I need help with system architecture" }, + { role: "assistant", content: "I can help you design that. What are your requirements?" } + ] +}) +``` + +Queen Seraphina is an advanced AI assistant with: +- Deep expertise in distributed systems +- Ability to create swarms and orchestrate agents +- Code deployment and architecture design +- Multi-turn conversation with context retention +- Tool usage for hands-on assistance + +### System Health & Monitoring + +**Check System Health** +```javascript +mcp__flow-nexus__system_health() +``` + +**View Audit Logs** +```javascript +mcp__flow-nexus__audit_log({ + user_id: "your_user_id", // optional filter + limit: 100 +}) +``` + +### Authentication Management + +**Initialize Authentication** +```javascript +mcp__flow-nexus__auth_init({ + mode: "user" // user, service +}) +``` + +--- + +## Quick Start Guide + +### Step 1: Register & Login + +```javascript +// Register +mcp__flow-nexus__user_register({ + email: "dev@example.com", + password: "SecurePass123!", + full_name: "Developer Name" +}) + +// Login +mcp__flow-nexus__user_login({ + email: "dev@example.com", + password: "SecurePass123!" +}) + +// Check auth status +mcp__flow-nexus__auth_status({ detailed: true }) +``` + +### Step 2: Configure Billing + +```javascript +// Check current balance +mcp__flow-nexus__check_balance() + +// Add credits +const paymentLink = mcp__flow-nexus__create_payment_link({ + amount: 50 // $50 +}) + +// Setup auto-refill +mcp__flow-nexus__configure_auto_refill({ + enabled: true, + threshold: 100, + amount: 50 +}) +``` + +### Step 3: Create Your First Sandbox + +```javascript +// Create development sandbox +const sandbox = mcp__flow-nexus__sandbox_create({ + template: "node", + name: "dev-environment", + install_packages: ["express", "dotenv"], + env_vars: { + NODE_ENV: "development" + } +}) + +// Execute code +mcp__flow-nexus__sandbox_execute({ + sandbox_id: sandbox.id, + code: 'console.log("Hello Flow Nexus!")', + language: "javascript" +}) +``` + +### Step 4: Deploy an App + +```javascript +// Browse templates +mcp__flow-nexus__template_list({ + category: "backend", + featured: true +}) + +// Deploy template +mcp__flow-nexus__template_deploy({ + template_name: "express-api-starter", + deployment_name: "my-api", + variables: { + database_url: "postgres://..." + } +}) +``` + +### Step 5: Complete a Challenge + +```javascript +// Find challenges +mcp__flow-nexus__challenges_list({ + difficulty: "beginner", + category: "algorithms" +}) + +// Submit solution +mcp__flow-nexus__challenge_submit({ + challenge_id: "fizzbuzz", + user_id: "your_id", + solution_code: "...", + language: "javascript" +}) +``` + +--- + +## Best Practices + +### Security +1. Never hardcode API keys - use environment variables +2. Enable 2FA when available +3. Regularly rotate passwords and tokens +4. Use private buckets for sensitive data +5. Review audit logs periodically +6. Set appropriate file expiration times + +### Performance +1. Clean up unused sandboxes to save credits +2. Use smaller sandbox templates when possible +3. Optimize storage by deleting old files +4. Batch operations to reduce API calls +5. Monitor usage via `user_stats` +6. Use temp buckets for transient data + +### Development +1. Start with sandbox testing before deployment +2. Version your applications semantically +3. Document all templates thoroughly +4. Include tests in published apps +5. Use execution monitoring for debugging +6. Leverage real-time subscriptions for live updates + +### Cost Management +1. Set auto-refill thresholds carefully +2. Monitor credit usage regularly +3. Complete daily challenges for bonus credits +4. Publish templates to earn passive credits +5. Use free-tier resources when appropriate +6. Schedule heavy jobs during off-peak times + +--- + +## Troubleshooting + +### Authentication Issues +- **Login Failed**: Check email/password, verify email first +- **Token Expired**: Re-login to get fresh tokens +- **Permission Denied**: Check tier limits, upgrade if needed + +### Sandbox Issues +- **Sandbox Won't Start**: Check template compatibility, verify credits +- **Execution Timeout**: Increase timeout parameter or optimize code +- **Out of Memory**: Use larger template or optimize memory usage +- **Package Install Failed**: Check package name, verify npm/pip availability + +### Payment Issues +- **Payment Failed**: Check payment method, sufficient funds +- **Credits Not Applied**: Allow 5-10 minutes for processing +- **Auto-refill Not Working**: Verify payment method on file + +### Challenge Issues +- **Submission Rejected**: Check code syntax, ensure all tests pass +- **Wrong Answer**: Review test cases, check edge cases +- **Performance Too Slow**: Optimize algorithm complexity + +--- + +## Support & Resources + +- **Documentation**: https://docs.flow-nexus.ruv.io +- **API Reference**: https://api.flow-nexus.ruv.io/docs +- **Status Page**: https://status.flow-nexus.ruv.io +- **Community Forum**: https://community.flow-nexus.ruv.io +- **GitHub Issues**: https://github.com/ruvnet/flow-nexus/issues +- **Discord**: https://discord.gg/flow-nexus +- **Email Support**: support@flow-nexus.ruv.io (Pro/Enterprise only) + +--- + +## Progressive Disclosure + +
+Advanced Sandbox Configuration + +### Custom Docker Images +```javascript +mcp__flow-nexus__sandbox_create({ + template: "base", + name: "custom-environment", + startup_script: ` + apt-get update + apt-get install -y custom-package + git clone https://github.com/user/repo + cd repo && npm install + ` +}) +``` + +### Multi-Stage Execution +```javascript +// Stage 1: Setup +mcp__flow-nexus__sandbox_execute({ + sandbox_id: "id", + code: "npm install && npm run build" +}) + +// Stage 2: Run +mcp__flow-nexus__sandbox_execute({ + sandbox_id: "id", + code: "npm start", + working_dir: "/app/dist" +}) +``` + +
+ +
+Advanced Storage Patterns + +### Large File Upload (Chunked) +```javascript +const chunkSize = 5 * 1024 * 1024 // 5MB chunks +for (let i = 0; i < chunks.length; i++) { + await mcp__flow-nexus__storage_upload({ + bucket: "private", + path: `large-file.bin.part${i}`, + content: chunks[i] + }) +} +``` + +### Storage Lifecycle +```javascript +// Upload to temp for processing +mcp__flow-nexus__storage_upload({ + bucket: "temp", + path: "processing/data.json", + content: data +}) + +// Move to permanent storage after processing +mcp__flow-nexus__storage_upload({ + bucket: "private", + path: "archive/processed-data.json", + content: processedData +}) +``` + +
+ +
+Advanced Real-time Patterns + +### Multi-Table Sync +```javascript +const tables = ["users", "tasks", "notifications"] +tables.forEach(table => { + mcp__flow-nexus__realtime_subscribe({ + table, + event: "*", + filter: `user_id=eq.${userId}` + }) +}) +``` + +### Event-Driven Workflows +```javascript +// Subscribe to task completion +mcp__flow-nexus__realtime_subscribe({ + table: "tasks", + event: "UPDATE", + filter: "status=eq.completed" +}) + +// Trigger notification workflow on event +// (handled by your application logic) +``` + +
+ +--- + +## Version History + +- **v1.0.0** (2025-10-19): Initial comprehensive platform skill + - Authentication & user management + - Sandbox creation and execution + - App store and deployment + - Payments and credits + - Challenges and achievements + - Storage and real-time features + - System utilities and Queen Seraphina integration + +--- + +*This skill consolidates 6 Flow Nexus command modules into a single comprehensive platform management interface.* diff --git a/.claude/skills/flow-nexus-swarm/SKILL.md b/.claude/skills/flow-nexus-swarm/SKILL.md new file mode 100644 index 0000000000..ae6c5f9cfa --- /dev/null +++ b/.claude/skills/flow-nexus-swarm/SKILL.md @@ -0,0 +1,610 @@ +--- +name: flow-nexus-swarm +description: Cloud-based AI swarm deployment and event-driven workflow automation with Flow Nexus platform +category: orchestration +tags: [swarm, workflow, cloud, agents, automation, message-queue] +version: 1.0.0 +requires: + - flow-nexus MCP server + - Active Flow Nexus account (register at flow-nexus.ruv.io) +--- + +# Flow Nexus Swarm & Workflow Orchestration + +Deploy and manage cloud-based AI agent swarms with event-driven workflow automation, message queue processing, and intelligent agent coordination. + +## ๐Ÿ“‹ Table of Contents + +1. [Overview](#overview) +2. [Swarm Management](#swarm-management) +3. [Workflow Automation](#workflow-automation) +4. [Agent Orchestration](#agent-orchestration) +5. [Templates & Patterns](#templates--patterns) +6. [Advanced Features](#advanced-features) +7. [Best Practices](#best-practices) + +## Overview + +Flow Nexus provides cloud-based orchestration for AI agent swarms with: + +- **Multi-topology Support**: Hierarchical, mesh, ring, and star architectures +- **Event-driven Workflows**: Message queue processing with async execution +- **Template Library**: Pre-built swarm configurations for common use cases +- **Intelligent Agent Assignment**: Vector similarity matching for optimal agent selection +- **Real-time Monitoring**: Comprehensive metrics and audit trails +- **Scalable Infrastructure**: Cloud-based execution with auto-scaling + +## Swarm Management + +### Initialize Swarm + +Create a new swarm with specified topology and configuration: + +```javascript +mcp__flow-nexus__swarm_init({ + topology: "hierarchical", // Options: mesh, ring, star, hierarchical + maxAgents: 8, + strategy: "balanced" // Options: balanced, specialized, adaptive +}) +``` + +**Topology Guide:** +- **Hierarchical**: Tree structure with coordinator nodes (best for complex projects) +- **Mesh**: Peer-to-peer collaboration (best for research and analysis) +- **Ring**: Circular coordination (best for sequential workflows) +- **Star**: Centralized hub (best for simple delegation) + +**Strategy Guide:** +- **Balanced**: Equal distribution of workload across agents +- **Specialized**: Agents focus on specific expertise areas +- **Adaptive**: Dynamic adjustment based on task complexity + +### Spawn Agents + +Add specialized agents to the swarm: + +```javascript +mcp__flow-nexus__agent_spawn({ + type: "researcher", // Options: researcher, coder, analyst, optimizer, coordinator + name: "Lead Researcher", + capabilities: ["web_search", "analysis", "summarization"] +}) +``` + +**Agent Types:** +- **Researcher**: Information gathering, web search, analysis +- **Coder**: Code generation, refactoring, implementation +- **Analyst**: Data analysis, pattern recognition, insights +- **Optimizer**: Performance tuning, resource optimization +- **Coordinator**: Task delegation, progress tracking, integration + +### Orchestrate Tasks + +Distribute tasks across the swarm: + +```javascript +mcp__flow-nexus__task_orchestrate({ + task: "Build a REST API with authentication and database integration", + strategy: "parallel", // Options: parallel, sequential, adaptive + maxAgents: 5, + priority: "high" // Options: low, medium, high, critical +}) +``` + +**Execution Strategies:** +- **Parallel**: Maximum concurrency for independent subtasks +- **Sequential**: Step-by-step execution with dependencies +- **Adaptive**: AI-powered strategy selection based on task analysis + +### Monitor & Scale Swarms + +```javascript +// Get detailed swarm status +mcp__flow-nexus__swarm_status({ + swarm_id: "optional-id" // Uses active swarm if not provided +}) + +// List all active swarms +mcp__flow-nexus__swarm_list({ + status: "active" // Options: active, destroyed, all +}) + +// Scale swarm up or down +mcp__flow-nexus__swarm_scale({ + target_agents: 10, + swarm_id: "optional-id" +}) + +// Gracefully destroy swarm +mcp__flow-nexus__swarm_destroy({ + swarm_id: "optional-id" +}) +``` + +## Workflow Automation + +### Create Workflow + +Define event-driven workflows with message queue processing: + +```javascript +mcp__flow-nexus__workflow_create({ + name: "CI/CD Pipeline", + description: "Automated testing, building, and deployment", + steps: [ + { + id: "test", + action: "run_tests", + agent: "tester", + parallel: true + }, + { + id: "build", + action: "build_app", + agent: "builder", + depends_on: ["test"] + }, + { + id: "deploy", + action: "deploy_prod", + agent: "deployer", + depends_on: ["build"] + } + ], + triggers: ["push_to_main", "manual_trigger"], + metadata: { + priority: 10, + retry_policy: "exponential_backoff" + } +}) +``` + +**Workflow Features:** +- **Dependency Management**: Define step dependencies with `depends_on` +- **Parallel Execution**: Set `parallel: true` for concurrent steps +- **Event Triggers**: GitHub events, schedules, manual triggers +- **Retry Policies**: Automatic retry on transient failures +- **Priority Queuing**: High-priority workflows execute first + +### Execute Workflow + +Run workflows synchronously or asynchronously: + +```javascript +mcp__flow-nexus__workflow_execute({ + workflow_id: "workflow_id", + input_data: { + branch: "main", + commit: "abc123", + environment: "production" + }, + async: true // Queue-based execution for long-running workflows +}) +``` + +**Execution Modes:** +- **Sync (async: false)**: Immediate execution, wait for completion +- **Async (async: true)**: Message queue processing, non-blocking + +### Monitor Workflows + +```javascript +// Get workflow status and metrics +mcp__flow-nexus__workflow_status({ + workflow_id: "id", + execution_id: "specific-run-id", // Optional + include_metrics: true +}) + +// List workflows with filters +mcp__flow-nexus__workflow_list({ + status: "running", // Options: running, completed, failed, pending + limit: 10, + offset: 0 +}) + +// Get complete audit trail +mcp__flow-nexus__workflow_audit_trail({ + workflow_id: "id", + limit: 50, + start_time: "2025-01-01T00:00:00Z" +}) +``` + +### Agent Assignment + +Intelligently assign agents to workflow tasks: + +```javascript +mcp__flow-nexus__workflow_agent_assign({ + task_id: "task_id", + agent_type: "coder", // Preferred agent type + use_vector_similarity: true // AI-powered capability matching +}) +``` + +**Vector Similarity Matching:** +- Analyzes task requirements and agent capabilities +- Finds optimal agent based on past performance +- Considers workload and availability + +### Queue Management + +Monitor and manage message queues: + +```javascript +mcp__flow-nexus__workflow_queue_status({ + queue_name: "optional-specific-queue", + include_messages: true // Show pending messages +}) +``` + +## Agent Orchestration + +### Full-Stack Development Pattern + +```javascript +// 1. Initialize swarm with hierarchical topology +mcp__flow-nexus__swarm_init({ + topology: "hierarchical", + maxAgents: 8, + strategy: "specialized" +}) + +// 2. Spawn specialized agents +mcp__flow-nexus__agent_spawn({ type: "coordinator", name: "Project Manager" }) +mcp__flow-nexus__agent_spawn({ type: "coder", name: "Backend Developer" }) +mcp__flow-nexus__agent_spawn({ type: "coder", name: "Frontend Developer" }) +mcp__flow-nexus__agent_spawn({ type: "coder", name: "Database Architect" }) +mcp__flow-nexus__agent_spawn({ type: "analyst", name: "QA Engineer" }) + +// 3. Create development workflow +mcp__flow-nexus__workflow_create({ + name: "Full-Stack Development", + steps: [ + { id: "requirements", action: "analyze_requirements", agent: "coordinator" }, + { id: "db_design", action: "design_schema", agent: "Database Architect" }, + { id: "backend", action: "build_api", agent: "Backend Developer", depends_on: ["db_design"] }, + { id: "frontend", action: "build_ui", agent: "Frontend Developer", depends_on: ["requirements"] }, + { id: "integration", action: "integrate", agent: "Backend Developer", depends_on: ["backend", "frontend"] }, + { id: "testing", action: "qa_testing", agent: "QA Engineer", depends_on: ["integration"] } + ] +}) + +// 4. Execute workflow +mcp__flow-nexus__workflow_execute({ + workflow_id: "workflow_id", + input_data: { + project: "E-commerce Platform", + tech_stack: ["Node.js", "React", "PostgreSQL"] + } +}) +``` + +### Research & Analysis Pattern + +```javascript +// 1. Initialize mesh topology for collaborative research +mcp__flow-nexus__swarm_init({ + topology: "mesh", + maxAgents: 5, + strategy: "balanced" +}) + +// 2. Spawn research agents +mcp__flow-nexus__agent_spawn({ type: "researcher", name: "Primary Researcher" }) +mcp__flow-nexus__agent_spawn({ type: "researcher", name: "Secondary Researcher" }) +mcp__flow-nexus__agent_spawn({ type: "analyst", name: "Data Analyst" }) +mcp__flow-nexus__agent_spawn({ type: "analyst", name: "Insights Analyst" }) + +// 3. Orchestrate research task +mcp__flow-nexus__task_orchestrate({ + task: "Research machine learning trends for 2025 and analyze market opportunities", + strategy: "parallel", + maxAgents: 4, + priority: "high" +}) +``` + +### CI/CD Pipeline Pattern + +```javascript +mcp__flow-nexus__workflow_create({ + name: "Deployment Pipeline", + description: "Automated testing, building, and multi-environment deployment", + steps: [ + { id: "lint", action: "lint_code", agent: "code_quality", parallel: true }, + { id: "unit_test", action: "unit_tests", agent: "test_runner", parallel: true }, + { id: "integration_test", action: "integration_tests", agent: "test_runner", parallel: true }, + { id: "build", action: "build_artifacts", agent: "builder", depends_on: ["lint", "unit_test", "integration_test"] }, + { id: "security_scan", action: "security_scan", agent: "security", depends_on: ["build"] }, + { id: "deploy_staging", action: "deploy", agent: "deployer", depends_on: ["security_scan"] }, + { id: "smoke_test", action: "smoke_tests", agent: "test_runner", depends_on: ["deploy_staging"] }, + { id: "deploy_prod", action: "deploy", agent: "deployer", depends_on: ["smoke_test"] } + ], + triggers: ["github_push", "github_pr_merged"], + metadata: { + priority: 10, + auto_rollback: true + } +}) +``` + +### Data Processing Pipeline Pattern + +```javascript +mcp__flow-nexus__workflow_create({ + name: "ETL Pipeline", + description: "Extract, Transform, Load data processing", + steps: [ + { id: "extract", action: "extract_data", agent: "data_extractor" }, + { id: "validate_raw", action: "validate_data", agent: "validator", depends_on: ["extract"] }, + { id: "transform", action: "transform_data", agent: "transformer", depends_on: ["validate_raw"] }, + { id: "enrich", action: "enrich_data", agent: "enricher", depends_on: ["transform"] }, + { id: "load", action: "load_data", agent: "loader", depends_on: ["enrich"] }, + { id: "validate_final", action: "validate_data", agent: "validator", depends_on: ["load"] } + ], + triggers: ["schedule:0 2 * * *"], // Daily at 2 AM + metadata: { + retry_policy: "exponential_backoff", + max_retries: 3 + } +}) +``` + +## Templates & Patterns + +### Use Pre-built Templates + +```javascript +// Create swarm from template +mcp__flow-nexus__swarm_create_from_template({ + template_name: "full-stack-dev", + overrides: { + maxAgents: 6, + strategy: "specialized" + } +}) + +// List available templates +mcp__flow-nexus__swarm_templates_list({ + category: "quickstart", // Options: quickstart, specialized, enterprise, custom, all + includeStore: true +}) +``` + +**Available Template Categories:** + +**Quickstart Templates:** +- `full-stack-dev`: Complete web development swarm +- `research-team`: Research and analysis swarm +- `code-review`: Automated code review swarm +- `data-pipeline`: ETL and data processing + +**Specialized Templates:** +- `ml-development`: Machine learning project swarm +- `mobile-dev`: Mobile app development +- `devops-automation`: Infrastructure and deployment +- `security-audit`: Security analysis and testing + +**Enterprise Templates:** +- `enterprise-migration`: Large-scale system migration +- `multi-repo-sync`: Multi-repository coordination +- `compliance-review`: Regulatory compliance workflows +- `incident-response`: Automated incident management + +### Custom Template Creation + +Save successful swarm configurations as reusable templates for future projects. + +## Advanced Features + +### Real-time Monitoring + +```javascript +// Subscribe to execution streams +mcp__flow-nexus__execution_stream_subscribe({ + stream_type: "claude-flow-swarm", + deployment_id: "deployment_id" +}) + +// Get execution status +mcp__flow-nexus__execution_stream_status({ + stream_id: "stream_id" +}) + +// List files created during execution +mcp__flow-nexus__execution_files_list({ + stream_id: "stream_id", + created_by: "claude-flow" +}) +``` + +### Swarm Metrics & Analytics + +```javascript +// Get swarm performance metrics +mcp__flow-nexus__swarm_status({ + swarm_id: "id" +}) + +// Analyze workflow efficiency +mcp__flow-nexus__workflow_status({ + workflow_id: "id", + include_metrics: true +}) +``` + +### Multi-Swarm Coordination + +Coordinate multiple swarms for complex, multi-phase projects: + +```javascript +// Phase 1: Research swarm +const researchSwarm = await mcp__flow-nexus__swarm_init({ + topology: "mesh", + maxAgents: 4 +}) + +// Phase 2: Development swarm +const devSwarm = await mcp__flow-nexus__swarm_init({ + topology: "hierarchical", + maxAgents: 8 +}) + +// Phase 3: Testing swarm +const testSwarm = await mcp__flow-nexus__swarm_init({ + topology: "star", + maxAgents: 5 +}) +``` + +## Best Practices + +### 1. Choose the Right Topology + +```javascript +// Simple projects: Star +mcp__flow-nexus__swarm_init({ topology: "star", maxAgents: 3 }) + +// Collaborative work: Mesh +mcp__flow-nexus__swarm_init({ topology: "mesh", maxAgents: 5 }) + +// Complex projects: Hierarchical +mcp__flow-nexus__swarm_init({ topology: "hierarchical", maxAgents: 10 }) + +// Sequential workflows: Ring +mcp__flow-nexus__swarm_init({ topology: "ring", maxAgents: 4 }) +``` + +### 2. Optimize Agent Assignment + +```javascript +// Use vector similarity for optimal matching +mcp__flow-nexus__workflow_agent_assign({ + task_id: "complex-task", + use_vector_similarity: true +}) +``` + +### 3. Implement Proper Error Handling + +```javascript +mcp__flow-nexus__workflow_create({ + name: "Resilient Workflow", + steps: [...], + metadata: { + retry_policy: "exponential_backoff", + max_retries: 3, + timeout: 300000, // 5 minutes + on_failure: "notify_and_rollback" + } +}) +``` + +### 4. Monitor and Scale + +```javascript +// Regular monitoring +const status = await mcp__flow-nexus__swarm_status() + +// Scale based on workload +if (status.workload > 0.8) { + await mcp__flow-nexus__swarm_scale({ target_agents: status.agents + 2 }) +} +``` + +### 5. Use Async Execution for Long-Running Workflows + +```javascript +// Long-running workflows should use message queues +mcp__flow-nexus__workflow_execute({ + workflow_id: "data-pipeline", + async: true // Non-blocking execution +}) + +// Monitor progress +mcp__flow-nexus__workflow_queue_status({ include_messages: true }) +``` + +### 6. Clean Up Resources + +```javascript +// Destroy swarm when complete +mcp__flow-nexus__swarm_destroy({ swarm_id: "id" }) +``` + +### 7. Leverage Templates + +```javascript +// Use proven templates instead of building from scratch +mcp__flow-nexus__swarm_create_from_template({ + template_name: "code-review", + overrides: { maxAgents: 4 } +}) +``` + +## Integration with Claude Flow + +Flow Nexus swarms integrate seamlessly with Claude Flow hooks: + +```bash +# Pre-task coordination setup +npx claude-flow@alpha hooks pre-task --description "Initialize swarm" + +# Post-task metrics export +npx claude-flow@alpha hooks post-task --task-id "swarm-execution" +``` + +## Common Use Cases + +### 1. Multi-Repo Development +- Coordinate development across multiple repositories +- Synchronized testing and deployment +- Cross-repo dependency management + +### 2. Research Projects +- Distributed information gathering +- Parallel analysis of different data sources +- Collaborative synthesis and reporting + +### 3. DevOps Automation +- Infrastructure as Code deployment +- Multi-environment testing +- Automated rollback and recovery + +### 4. Code Quality Workflows +- Automated code review +- Security scanning +- Performance benchmarking + +### 5. Data Processing +- Large-scale ETL pipelines +- Real-time data transformation +- Data validation and quality checks + +## Authentication & Setup + +```bash +# Install Flow Nexus +npm install -g flow-nexus@latest + +# Register account +npx flow-nexus@latest register + +# Login +npx flow-nexus@latest login + +# Add MCP server to Claude Code +claude mcp add flow-nexus npx flow-nexus@latest mcp start +``` + +## Support & Resources + +- **Platform**: https://flow-nexus.ruv.io +- **Documentation**: https://github.com/ruvnet/flow-nexus +- **Issues**: https://github.com/ruvnet/flow-nexus/issues + +--- + +**Remember**: Flow Nexus provides cloud-based orchestration infrastructure. For local execution and coordination, use the core `claude-flow` MCP server alongside Flow Nexus for maximum flexibility. diff --git a/.claude/skills/food-order/SKILL.md b/.claude/skills/food-order/SKILL.md new file mode 100644 index 0000000000..6d47798fa2 --- /dev/null +++ b/.claude/skills/food-order/SKILL.md @@ -0,0 +1,41 @@ +--- +name: food-order +description: Reorder Foodora orders + track ETA/status with ordercli. Never confirm without explicit user approval. Triggers: order food, reorder, track ETA. +homepage: https://ordercli.sh +metadata: {"zee":{"emoji":"๐Ÿฅก","requires":{"bins":["ordercli"]},"install":[{"id":"go","kind":"go","module":"github.com/steipete/ordercli/cmd/ordercli@latest","bins":["ordercli"],"label":"Install ordercli (go)"}]}} +--- + +# Food order (Foodora via ordercli) + +Goal: reorder a previous Foodora order safely (preview first; confirm only on explicit user โ€œyes/confirm/place the orderโ€). + +Hard safety rules +- Never run `ordercli foodora reorder ... --confirm` unless user explicitly confirms placing the order. +- Prefer preview-only steps first; show what will happen; ask for confirmation. +- If user is unsure: stop at preview and ask questions. + +Setup (once) +- Country: `ordercli foodora countries` โ†’ `ordercli foodora config set --country AT` +- Login (password): `ordercli foodora login --email you@example.com --password-stdin` +- Login (no password, preferred): `ordercli foodora session chrome --url https://www.foodora.at/ --profile "Default"` + +Find what to reorder +- Recent list: `ordercli foodora history --limit 10` +- Details: `ordercli foodora history show ` +- If needed (machine-readable): `ordercli foodora history show --json` + +Preview reorder (no cart changes) +- `ordercli foodora reorder ` + +Place reorder (cart change; explicit confirmation required) +- Confirm first, then run: `ordercli foodora reorder --confirm` +- Multiple addresses? Ask user for the right `--address-id` (take from their Foodora account / prior order data) and run: + - `ordercli foodora reorder --confirm --address-id ` + +Track the order +- ETA/status (active list): `ordercli foodora orders` +- Live updates: `ordercli foodora orders --watch` +- Single order detail: `ordercli foodora order ` + +Debug / safe testing +- Use a throwaway config: `ordercli --config /tmp/ordercli.json ...` diff --git a/.claude/skills/gemini/SKILL.md b/.claude/skills/gemini/SKILL.md new file mode 100644 index 0000000000..6cb0fb4169 --- /dev/null +++ b/.claude/skills/gemini/SKILL.md @@ -0,0 +1,23 @@ +--- +name: gemini +description: Gemini CLI for one-shot Q&A, summaries, and generation. +homepage: https://ai.google.dev/ +metadata: {"zee":{"emoji":"โ™Š๏ธ","requires":{"bins":["gemini"]},"install":[{"id":"brew","kind":"brew","formula":"gemini-cli","bins":["gemini"],"label":"Install Gemini CLI (brew)"}]}} +--- + +# Gemini CLI + +Use Gemini in one-shot mode with a positional prompt (avoid interactive mode). + +Quick start +- `gemini "Answer this question..."` +- `gemini --model "Prompt..."` +- `gemini --output-format json "Return JSON"` + +Extensions +- List: `gemini --list-extensions` +- Manage: `gemini extensions ` + +Notes +- If auth is required, run `gemini` once interactively and follow the login flow. +- Avoid `--yolo` for safety. diff --git a/.claude/skills/gifgrep/SKILL.md b/.claude/skills/gifgrep/SKILL.md new file mode 100644 index 0000000000..a8cc6b935d --- /dev/null +++ b/.claude/skills/gifgrep/SKILL.md @@ -0,0 +1,47 @@ +--- +name: gifgrep +description: Search GIF providers with CLI/TUI, download results, and extract stills/sheets. +homepage: https://gifgrep.com +metadata: {"zee":{"emoji":"๐Ÿงฒ","requires":{"bins":["gifgrep"]},"install":[{"id":"brew","kind":"brew","formula":"steipete/tap/gifgrep","bins":["gifgrep"],"label":"Install gifgrep (brew)"},{"id":"go","kind":"go","module":"github.com/steipete/gifgrep/cmd/gifgrep@latest","bins":["gifgrep"],"label":"Install gifgrep (go)"}]}} +--- + +# gifgrep + +Use `gifgrep` to search GIF providers (Tenor/Giphy), browse in a TUI, download results, and extract stills or sheets. + +GIF-Grab (gifgrep workflow) +- Search โ†’ preview โ†’ download โ†’ extract (still/sheet) for fast review and sharing. + +Quick start +- `gifgrep cats --max 5` +- `gifgrep cats --format url | head -n 5` +- `gifgrep search --json cats | jq '.[0].url'` +- `gifgrep tui "office handshake"` +- `gifgrep cats --download --max 1 --format url` + +TUI + previews +- TUI: `gifgrep tui "query"` +- CLI still previews: `--thumbs` (Kitty/Ghostty only; still frame) + +Download + reveal +- `--download` saves to `~/Downloads` +- `--reveal` shows the last download in Finder + +Stills + sheets +- `gifgrep still ./clip.gif --at 1.5s -o still.png` +- `gifgrep sheet ./clip.gif --frames 9 --cols 3 -o sheet.png` +- Sheets = single PNG grid of sampled frames (great for quick review, docs, PRs, chat). +- Tune: `--frames` (count), `--cols` (grid width), `--padding` (spacing). + +Providers +- `--source auto|tenor|giphy` +- `GIPHY_API_KEY` required for `--source giphy` +- `TENOR_API_KEY` optional (Tenor demo key used if unset) + +Output +- `--json` prints an array of results (`id`, `title`, `url`, `preview_url`, `tags`, `width`, `height`) +- `--format` for pipe-friendly fields (e.g., `url`) + +Environment tweaks +- `GIFGREP_SOFTWARE_ANIM=1` to force software animation +- `GIFGREP_CELL_ASPECT=0.5` to tweak preview geometry diff --git a/.claude/skills/github-code-review/SKILL.md b/.claude/skills/github-code-review/SKILL.md new file mode 100644 index 0000000000..7813c7f823 --- /dev/null +++ b/.claude/skills/github-code-review/SKILL.md @@ -0,0 +1,1140 @@ +--- +name: github-code-review +version: 1.0.0 +description: Comprehensive GitHub code review with AI-powered swarm coordination +category: github +tags: [code-review, github, swarm, pr-management, automation] +author: Claude Code Flow +requires: + - github-cli + - ruv-swarm + - claude-flow +capabilities: + - Multi-agent code review + - Automated PR management + - Security and performance analysis + - Swarm-based review orchestration + - Intelligent comment generation + - Quality gate enforcement +--- + +# GitHub Code Review Skill + +> **AI-Powered Code Review**: Deploy specialized review agents to perform comprehensive, intelligent code reviews that go beyond traditional static analysis. + +## ๐ŸŽฏ Quick Start + +### Simple Review +```bash +# Initialize review swarm for PR +gh pr view 123 --json files,diff | npx ruv-swarm github review-init --pr 123 + +# Post review status +gh pr comment 123 --body "๐Ÿ” Multi-agent code review initiated" +``` + +### Complete Review Workflow +```bash +# Get PR context with gh CLI +PR_DATA=$(gh pr view 123 --json files,additions,deletions,title,body) +PR_DIFF=$(gh pr diff 123) + +# Initialize comprehensive review +npx ruv-swarm github review-init \ + --pr 123 \ + --pr-data "$PR_DATA" \ + --diff "$PR_DIFF" \ + --agents "security,performance,style,architecture,accessibility" \ + --depth comprehensive +``` + +--- + +## ๐Ÿ“š Table of Contents + +
+Core Features + +- [Multi-Agent Review System](#multi-agent-review-system) +- [Specialized Review Agents](#specialized-review-agents) +- [PR-Based Swarm Management](#pr-based-swarm-management) +- [Automated Workflows](#automated-workflows) +- [Quality Gates & Checks](#quality-gates--checks) + +
+ +
+Review Agents + +- [Security Review Agent](#security-review-agent) +- [Performance Review Agent](#performance-review-agent) +- [Architecture Review Agent](#architecture-review-agent) +- [Style & Convention Agent](#style--convention-agent) +- [Accessibility Agent](#accessibility-agent) + +
+ +
+Advanced Features + +- [Context-Aware Reviews](#context-aware-reviews) +- [Learning from History](#learning-from-history) +- [Cross-PR Analysis](#cross-pr-analysis) +- [Custom Review Agents](#custom-review-agents) + +
+ +
+Integration & Automation + +- [CI/CD Integration](#cicd-integration) +- [Webhook Handlers](#webhook-handlers) +- [PR Comment Commands](#pr-comment-commands) +- [Automated Fixes](#automated-fixes) + +
+ +--- + +## ๐Ÿš€ Core Features + +### Multi-Agent Review System + +Deploy specialized AI agents for comprehensive code review: + +```bash +# Initialize review swarm with GitHub CLI integration +PR_DATA=$(gh pr view 123 --json files,additions,deletions,title,body) +PR_DIFF=$(gh pr diff 123) + +# Start multi-agent review +npx ruv-swarm github review-init \ + --pr 123 \ + --pr-data "$PR_DATA" \ + --diff "$PR_DIFF" \ + --agents "security,performance,style,architecture,accessibility" \ + --depth comprehensive + +# Post initial review status +gh pr comment 123 --body "๐Ÿ” Multi-agent code review initiated" +``` + +**Benefits:** +- โœ… Parallel review by specialized agents +- โœ… Comprehensive coverage across multiple domains +- โœ… Faster review cycles with coordinated analysis +- โœ… Consistent quality standards enforcement + +--- + +## ๐Ÿค– Specialized Review Agents + +### Security Review Agent + +**Focus:** Identify security vulnerabilities and suggest fixes + +```bash +# Get changed files from PR +CHANGED_FILES=$(gh pr view 123 --json files --jq '.files[].path') + +# Run security-focused review +SECURITY_RESULTS=$(npx ruv-swarm github review-security \ + --pr 123 \ + --files "$CHANGED_FILES" \ + --check "owasp,cve,secrets,permissions" \ + --suggest-fixes) + +# Post findings based on severity +if echo "$SECURITY_RESULTS" | grep -q "critical"; then + # Request changes for critical issues + gh pr review 123 --request-changes --body "$SECURITY_RESULTS" + gh pr edit 123 --add-label "security-review-required" +else + # Post as comment for non-critical issues + gh pr comment 123 --body "$SECURITY_RESULTS" +fi +``` + +
+Security Checks Performed + +```javascript +{ + "checks": [ + "SQL injection vulnerabilities", + "XSS attack vectors", + "Authentication bypasses", + "Authorization flaws", + "Cryptographic weaknesses", + "Dependency vulnerabilities", + "Secret exposure", + "CORS misconfigurations" + ], + "actions": [ + "Block PR on critical issues", + "Suggest secure alternatives", + "Add security test cases", + "Update security documentation" + ] +} +``` + +
+ +
+Comment Template: Security Issue + +```markdown +๐Ÿ”’ **Security Issue: [Type]** + +**Severity**: ๐Ÿ”ด Critical / ๐ŸŸก High / ๐ŸŸข Low + +**Description**: +[Clear explanation of the security issue] + +**Impact**: +[Potential consequences if not addressed] + +**Suggested Fix**: +```language +[Code example of the fix] +``` + +**References**: +- [OWASP Guide](link) +- [Security Best Practices](link) +``` + +
+ +--- + +### Performance Review Agent + +**Focus:** Analyze performance impact and optimization opportunities + +```bash +# Run performance analysis +npx ruv-swarm github review-performance \ + --pr 123 \ + --profile "cpu,memory,io" \ + --benchmark-against main \ + --suggest-optimizations +``` + +
+Performance Metrics Analyzed + +```javascript +{ + "metrics": [ + "Algorithm complexity (Big O analysis)", + "Database query efficiency", + "Memory allocation patterns", + "Cache utilization", + "Network request optimization", + "Bundle size impact", + "Render performance" + ], + "benchmarks": [ + "Compare with baseline", + "Load test simulations", + "Memory leak detection", + "Bottleneck identification" + ] +} +``` + +
+ +--- + +### Architecture Review Agent + +**Focus:** Evaluate design patterns and architectural decisions + +```bash +# Architecture review +npx ruv-swarm github review-architecture \ + --pr 123 \ + --check "patterns,coupling,cohesion,solid" \ + --visualize-impact \ + --suggest-refactoring +``` + +
+Architecture Analysis + +```javascript +{ + "patterns": [ + "Design pattern adherence", + "SOLID principles", + "DRY violations", + "Separation of concerns", + "Dependency injection", + "Layer violations", + "Circular dependencies" + ], + "metrics": [ + "Coupling metrics", + "Cohesion scores", + "Complexity measures", + "Maintainability index" + ] +} +``` + +
+ +--- + +### Style & Convention Agent + +**Focus:** Enforce coding standards and best practices + +```bash +# Style enforcement with auto-fix +npx ruv-swarm github review-style \ + --pr 123 \ + --check "formatting,naming,docs,tests" \ + --auto-fix "formatting,imports,whitespace" +``` + +
+Style Checks + +```javascript +{ + "checks": [ + "Code formatting", + "Naming conventions", + "Documentation standards", + "Comment quality", + "Test coverage", + "Error handling patterns", + "Logging standards" + ], + "auto-fix": [ + "Formatting issues", + "Import organization", + "Trailing whitespace", + "Simple naming issues" + ] +} +``` + +
+ +--- + +## ๐Ÿ”„ PR-Based Swarm Management + +### Create Swarm from PR + +```bash +# Create swarm from PR description using gh CLI +gh pr view 123 --json body,title,labels,files | npx ruv-swarm swarm create-from-pr + +# Auto-spawn agents based on PR labels +gh pr view 123 --json labels | npx ruv-swarm swarm auto-spawn + +# Create swarm with full PR context +gh pr view 123 --json body,labels,author,assignees | \ + npx ruv-swarm swarm init --from-pr-data +``` + +### Label-Based Agent Assignment + +Map PR labels to specialized agents: + +```json +{ + "label-mapping": { + "bug": ["debugger", "tester"], + "feature": ["architect", "coder", "tester"], + "refactor": ["analyst", "coder"], + "docs": ["researcher", "writer"], + "performance": ["analyst", "optimizer"], + "security": ["security", "authentication", "audit"] + } +} +``` + +### Topology Selection by PR Size + +```bash +# Automatic topology selection based on PR complexity +# Small PR (< 100 lines): ring topology +# Medium PR (100-500 lines): mesh topology +# Large PR (> 500 lines): hierarchical topology +npx ruv-swarm github pr-topology --pr 123 +``` + +--- + +## ๐ŸŽฌ PR Comment Commands + +Execute swarm commands directly from PR comments: + +```markdown + +/swarm init mesh 6 +/swarm spawn coder "Implement authentication" +/swarm spawn tester "Write unit tests" +/swarm status +/swarm review --agents security,performance +``` + +
+Webhook Handler for Comment Commands + +```javascript +// webhook-handler.js +const { createServer } = require('http'); +const { execSync } = require('child_process'); + +createServer((req, res) => { + if (req.url === '/github-webhook') { + const event = JSON.parse(body); + + if (event.action === 'opened' && event.pull_request) { + execSync(`npx ruv-swarm github pr-init ${event.pull_request.number}`); + } + + if (event.comment && event.comment.body.startsWith('/swarm')) { + const command = event.comment.body; + execSync(`npx ruv-swarm github handle-comment --pr ${event.issue.number} --command "${command}"`); + } + + res.writeHead(200); + res.end('OK'); + } +}).listen(3000); +``` + +
+ +--- + +## โš™๏ธ Review Configuration + +### Configuration File + +```yaml +# .github/review-swarm.yml +version: 1 +review: + auto-trigger: true + required-agents: + - security + - performance + - style + optional-agents: + - architecture + - accessibility + - i18n + + thresholds: + security: block # Block merge on security issues + performance: warn # Warn on performance issues + style: suggest # Suggest style improvements + + rules: + security: + - no-eval + - no-hardcoded-secrets + - proper-auth-checks + - validate-input + performance: + - no-n-plus-one + - efficient-queries + - proper-caching + - optimize-loops + architecture: + - max-coupling: 5 + - min-cohesion: 0.7 + - follow-patterns + - avoid-circular-deps +``` + +### Custom Review Triggers + +```javascript +{ + "triggers": { + "high-risk-files": { + "paths": ["**/auth/**", "**/payment/**", "**/admin/**"], + "agents": ["security", "architecture"], + "depth": "comprehensive", + "require-approval": true + }, + "performance-critical": { + "paths": ["**/api/**", "**/database/**", "**/cache/**"], + "agents": ["performance", "database"], + "benchmarks": true, + "regression-threshold": "5%" + }, + "ui-changes": { + "paths": ["**/components/**", "**/styles/**", "**/pages/**"], + "agents": ["accessibility", "style", "i18n"], + "visual-tests": true, + "responsive-check": true + } + } +} +``` + +--- + +## ๐Ÿค– Automated Workflows + +### Auto-Review on PR Creation + +```yaml +# .github/workflows/auto-review.yml +name: Automated Code Review +on: + pull_request: + types: [opened, synchronize] + issue_comment: + types: [created] + +jobs: + swarm-review: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 + + - name: Setup GitHub CLI + run: echo "${{ secrets.GITHUB_TOKEN }}" | gh auth login --with-token + + - name: Run Review Swarm + run: | + # Get PR context with gh CLI + PR_NUM=${{ github.event.pull_request.number }} + PR_DATA=$(gh pr view $PR_NUM --json files,title,body,labels) + PR_DIFF=$(gh pr diff $PR_NUM) + + # Run swarm review + REVIEW_OUTPUT=$(npx ruv-swarm github review-all \ + --pr $PR_NUM \ + --pr-data "$PR_DATA" \ + --diff "$PR_DIFF" \ + --agents "security,performance,style,architecture") + + # Post review results + echo "$REVIEW_OUTPUT" | gh pr review $PR_NUM --comment -F - + + # Update PR status + if echo "$REVIEW_OUTPUT" | grep -q "approved"; then + gh pr review $PR_NUM --approve + elif echo "$REVIEW_OUTPUT" | grep -q "changes-requested"; then + gh pr review $PR_NUM --request-changes -b "See review comments above" + fi + + - name: Update Labels + run: | + # Add labels based on review results + if echo "$REVIEW_OUTPUT" | grep -q "security"; then + gh pr edit $PR_NUM --add-label "security-review" + fi + if echo "$REVIEW_OUTPUT" | grep -q "performance"; then + gh pr edit $PR_NUM --add-label "performance-review" + fi +``` + +--- + +## ๐Ÿ’ฌ Intelligent Comment Generation + +### Generate Contextual Review Comments + +```bash +# Get PR diff with context +PR_DIFF=$(gh pr diff 123 --color never) +PR_FILES=$(gh pr view 123 --json files) + +# Generate review comments +COMMENTS=$(npx ruv-swarm github review-comment \ + --pr 123 \ + --diff "$PR_DIFF" \ + --files "$PR_FILES" \ + --style "constructive" \ + --include-examples \ + --suggest-fixes) + +# Post comments using gh CLI +echo "$COMMENTS" | jq -c '.[]' | while read -r comment; do + FILE=$(echo "$comment" | jq -r '.path') + LINE=$(echo "$comment" | jq -r '.line') + BODY=$(echo "$comment" | jq -r '.body') + COMMIT_ID=$(gh pr view 123 --json headRefOid -q .headRefOid) + + # Create inline review comments + gh api \ + --method POST \ + /repos/:owner/:repo/pulls/123/comments \ + -f path="$FILE" \ + -f line="$LINE" \ + -f body="$BODY" \ + -f commit_id="$COMMIT_ID" +done +``` + +### Batch Comment Management + +```bash +# Manage review comments efficiently +npx ruv-swarm github review-comments \ + --pr 123 \ + --group-by "agent,severity" \ + --summarize \ + --resolve-outdated +``` + +--- + +## ๐Ÿšช Quality Gates & Checks + +### Status Checks + +```yaml +# Required status checks in branch protection +protection_rules: + required_status_checks: + strict: true + contexts: + - "review-swarm/security" + - "review-swarm/performance" + - "review-swarm/architecture" + - "review-swarm/tests" +``` + +### Define Quality Gates + +```bash +# Set quality gate thresholds +npx ruv-swarm github quality-gates \ + --define '{ + "security": {"threshold": "no-critical"}, + "performance": {"regression": "<5%"}, + "coverage": {"minimum": "80%"}, + "architecture": {"complexity": "<10"}, + "duplication": {"maximum": "5%"} + }' +``` + +### Track Review Metrics + +```bash +# Monitor review effectiveness +npx ruv-swarm github review-metrics \ + --period 30d \ + --metrics "issues-found,false-positives,fix-rate,time-to-review" \ + --export-dashboard \ + --format json +``` + +--- + +## ๐ŸŽ“ Advanced Features + +### Context-Aware Reviews + +Analyze PRs with full project context: + +```bash +# Review with comprehensive context +npx ruv-swarm github review-context \ + --pr 123 \ + --load-related-prs \ + --analyze-impact \ + --check-breaking-changes \ + --dependency-analysis +``` + +### Learning from History + +Train review agents on your codebase patterns: + +```bash +# Learn from past reviews +npx ruv-swarm github review-learn \ + --analyze-past-reviews \ + --identify-patterns \ + --improve-suggestions \ + --reduce-false-positives + +# Train on your codebase +npx ruv-swarm github review-train \ + --learn-patterns \ + --adapt-to-style \ + --improve-accuracy +``` + +### Cross-PR Analysis + +Coordinate reviews across related pull requests: + +```bash +# Analyze related PRs together +npx ruv-swarm github review-batch \ + --prs "123,124,125" \ + --check-consistency \ + --verify-integration \ + --combined-impact +``` + +### Multi-PR Swarm Coordination + +```bash +# Coordinate swarms across related PRs +npx ruv-swarm github multi-pr \ + --prs "123,124,125" \ + --strategy "parallel" \ + --share-memory +``` + +--- + +## ๐Ÿ› ๏ธ Custom Review Agents + +### Create Custom Agent + +```javascript +// custom-review-agent.js +class CustomReviewAgent { + constructor(config) { + this.config = config; + this.rules = config.rules || []; + } + + async review(pr) { + const issues = []; + + // Custom logic: Check for TODO comments in production code + if (await this.checkTodoComments(pr)) { + issues.push({ + severity: 'warning', + file: pr.file, + line: pr.line, + message: 'TODO comment found in production code', + suggestion: 'Resolve TODO or create issue to track it' + }); + } + + // Custom logic: Verify API versioning + if (await this.checkApiVersioning(pr)) { + issues.push({ + severity: 'error', + file: pr.file, + line: pr.line, + message: 'API endpoint missing versioning', + suggestion: 'Add /v1/, /v2/ prefix to API routes' + }); + } + + return issues; + } + + async checkTodoComments(pr) { + // Implementation + const todoRegex = /\/\/\s*TODO|\/\*\s*TODO/gi; + return todoRegex.test(pr.diff); + } + + async checkApiVersioning(pr) { + // Implementation + const apiRegex = /app\.(get|post|put|delete)\(['"]\/api\/(?!v\d+)/; + return apiRegex.test(pr.diff); + } +} + +module.exports = CustomReviewAgent; +``` + +### Register Custom Agent + +```bash +# Register custom review agent +npx ruv-swarm github register-agent \ + --name "custom-reviewer" \ + --file "./custom-review-agent.js" \ + --category "standards" +``` + +--- + +## ๐Ÿ”ง CI/CD Integration + +### Integration with Build Pipeline + +```yaml +# .github/workflows/build-and-review.yml +name: Build and Review +on: [pull_request] + +jobs: + build-and-test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - run: npm install + - run: npm test + - run: npm run build + + swarm-review: + needs: build-and-test + runs-on: ubuntu-latest + steps: + - name: Run Swarm Review + run: | + npx ruv-swarm github review-all \ + --pr ${{ github.event.pull_request.number }} \ + --include-build-results +``` + +### Automated PR Fixes + +```bash +# Auto-fix common issues +npx ruv-swarm github pr-fix 123 \ + --issues "lint,test-failures,formatting" \ + --commit-fixes \ + --push-changes +``` + +### Progress Updates to PR + +```bash +# Post swarm progress to PR using gh CLI +PROGRESS=$(npx ruv-swarm github pr-progress 123 --format markdown) + +gh pr comment 123 --body "$PROGRESS" + +# Update PR labels based on progress +if [[ $(echo "$PROGRESS" | grep -o '[0-9]\+%' | sed 's/%//') -gt 90 ]]; then + gh pr edit 123 --add-label "ready-for-review" +fi +``` + +--- + +## ๐Ÿ“‹ Complete Workflow Examples + +### Example 1: Security-Critical PR + +```bash +# Review authentication system changes +npx ruv-swarm github review-init \ + --pr 456 \ + --agents "security,authentication,audit" \ + --depth "maximum" \ + --require-security-approval \ + --penetration-test +``` + +### Example 2: Performance-Sensitive PR + +```bash +# Review database optimization +npx ruv-swarm github review-init \ + --pr 789 \ + --agents "performance,database,caching" \ + --benchmark \ + --profile \ + --load-test +``` + +### Example 3: UI Component PR + +```bash +# Review new component library +npx ruv-swarm github review-init \ + --pr 321 \ + --agents "accessibility,style,i18n,docs" \ + --visual-regression \ + --component-tests \ + --responsive-check +``` + +### Example 4: Feature Development PR + +```bash +# Review new feature implementation +gh pr view 456 --json body,labels,files | \ + npx ruv-swarm github pr-init 456 \ + --topology hierarchical \ + --agents "architect,coder,tester,security" \ + --auto-assign-tasks +``` + +### Example 5: Bug Fix PR + +```bash +# Review bug fix with debugging focus +npx ruv-swarm github pr-init 789 \ + --topology mesh \ + --agents "debugger,analyst,tester" \ + --priority high \ + --regression-test +``` + +--- + +## ๐Ÿ“Š Monitoring & Analytics + +### Review Dashboard + +```bash +# Launch real-time review dashboard +npx ruv-swarm github review-dashboard \ + --real-time \ + --show "agent-activity,issue-trends,fix-rates,coverage" +``` + +### Generate Review Reports + +```bash +# Create comprehensive review report +npx ruv-swarm github review-report \ + --format "markdown" \ + --include "summary,details,trends,recommendations" \ + --email-stakeholders \ + --export-pdf +``` + +### PR Swarm Analytics + +```bash +# Generate PR-specific analytics +npx ruv-swarm github pr-report 123 \ + --metrics "completion-time,agent-efficiency,token-usage,issue-density" \ + --format markdown \ + --compare-baseline +``` + +### Export to GitHub Insights + +```bash +# Export metrics to GitHub Insights +npx ruv-swarm github export-metrics \ + --pr 123 \ + --to-insights \ + --dashboard-url +``` + +--- + +## ๐Ÿ” Security Considerations + +### Best Practices + +1. **Token Permissions**: Ensure GitHub tokens have minimal required scopes +2. **Command Validation**: Validate all PR comments before execution +3. **Rate Limiting**: Implement rate limits for PR operations +4. **Audit Trail**: Log all swarm operations for compliance +5. **Secret Management**: Never expose API keys in PR comments or logs + +### Security Checklist + +- [ ] GitHub token scoped to repository only +- [ ] Webhook signatures verified +- [ ] Command injection protection enabled +- [ ] Rate limiting configured +- [ ] Audit logging enabled +- [ ] Secrets scanning active +- [ ] Branch protection rules enforced + +--- + +## ๐Ÿ“š Best Practices + +### 1. Review Configuration +- โœ… Define clear review criteria upfront +- โœ… Set appropriate severity thresholds +- โœ… Configure agent specializations for your stack +- โœ… Establish override procedures for emergencies + +### 2. Comment Quality +- โœ… Provide actionable, specific feedback +- โœ… Include code examples with suggestions +- โœ… Reference documentation and best practices +- โœ… Maintain respectful, constructive tone + +### 3. Performance Optimization +- โœ… Cache analysis results to avoid redundant work +- โœ… Use incremental reviews for large PRs +- โœ… Enable parallel agent execution +- โœ… Batch comment operations efficiently + +### 4. PR Templates + +```markdown + +## Swarm Configuration +- Topology: [mesh/hierarchical/ring/star] +- Max Agents: [number] +- Auto-spawn: [yes/no] +- Priority: [high/medium/low] + +## Tasks for Swarm +- [ ] Task 1 description +- [ ] Task 2 description +- [ ] Task 3 description + +## Review Focus Areas +- [ ] Security review +- [ ] Performance analysis +- [ ] Architecture validation +- [ ] Accessibility check +``` + +### 5. Auto-Merge When Ready + +```bash +# Auto-merge when swarm completes and passes checks +SWARM_STATUS=$(npx ruv-swarm github pr-status 123) + +if [[ "$SWARM_STATUS" == "complete" ]]; then + # Check review requirements + REVIEWS=$(gh pr view 123 --json reviews --jq '.reviews | length') + + if [[ $REVIEWS -ge 2 ]]; then + # Enable auto-merge + gh pr merge 123 --auto --squash + fi +fi +``` + +--- + +## ๐Ÿ”— Integration with Claude Code + +### Workflow Pattern + +1. **Claude Code** reads PR diff and context +2. **Swarm** coordinates review approach based on PR type +3. **Agents** work in parallel on different review aspects +4. **Progress** updates posted to PR automatically +5. **Final review** performed before marking ready + +### Example: Complete PR Management + +```javascript +[Single Message - Parallel Execution]: + // Initialize coordination + mcp__claude-flow__swarm_init { topology: "hierarchical", maxAgents: 5 } + mcp__claude-flow__agent_spawn { type: "reviewer", name: "Senior Reviewer" } + mcp__claude-flow__agent_spawn { type: "tester", name: "QA Engineer" } + mcp__claude-flow__agent_spawn { type: "coordinator", name: "Merge Coordinator" } + + // Create and manage PR using gh CLI + Bash("gh pr create --title 'Feature: Add authentication' --base main") + Bash("gh pr view 54 --json files,diff") + Bash("gh pr review 54 --approve --body 'LGTM after automated review'") + + // Execute tests and validation + Bash("npm test") + Bash("npm run lint") + Bash("npm run build") + + // Track progress + TodoWrite { todos: [ + { content: "Complete code review", status: "completed", activeForm: "Completing code review" }, + { content: "Run test suite", status: "completed", activeForm: "Running test suite" }, + { content: "Validate security", status: "completed", activeForm: "Validating security" }, + { content: "Merge when ready", status: "pending", activeForm: "Merging when ready" } + ]} +``` + +--- + +## ๐Ÿ†˜ Troubleshooting + +### Common Issues + +
+Issue: Review agents not spawning + +**Solution:** +```bash +# Check swarm status +npx ruv-swarm swarm-status + +# Verify GitHub CLI authentication +gh auth status + +# Re-initialize swarm +npx ruv-swarm github review-init --pr 123 --force +``` + +
+ +
+Issue: Comments not posting to PR + +**Solution:** +```bash +# Verify GitHub token permissions +gh auth status + +# Check API rate limits +gh api rate_limit + +# Use batch comment posting +npx ruv-swarm github review-comments --pr 123 --batch +``` + +
+ +
+Issue: Review taking too long + +**Solution:** +```bash +# Use incremental review for large PRs +npx ruv-swarm github review-init --pr 123 --incremental + +# Reduce agent count +npx ruv-swarm github review-init --pr 123 --agents "security,style" --max-agents 3 + +# Enable parallel processing +npx ruv-swarm github review-init --pr 123 --parallel --cache-results +``` + +
+ +--- + +## ๐Ÿ“– Additional Resources + +### Related Skills +- `github-pr-manager` - Comprehensive PR lifecycle management +- `github-workflow-automation` - Automate GitHub workflows +- `swarm-coordination` - Advanced swarm orchestration + +### Documentation +- [GitHub CLI Documentation](https://cli.github.com/manual/) +- [RUV Swarm Guide](https://github.com/ruvnet/ruv-swarm) +- [Claude Flow Integration](https://github.com/ruvnet/claude-flow) + +### Support +- GitHub Issues: Report bugs and request features +- Community: Join discussions and share experiences +- Examples: Browse example configurations and workflows + +--- + +## ๐Ÿ“„ License + +This skill is part of the Claude Code Flow project and is licensed under the MIT License. + +--- + +**Last Updated:** 2025-10-19 +**Version:** 1.0.0 +**Maintainer:** Claude Code Flow Team diff --git a/.claude/skills/github-multi-repo/SKILL.md b/.claude/skills/github-multi-repo/SKILL.md new file mode 100644 index 0000000000..73ff842fe0 --- /dev/null +++ b/.claude/skills/github-multi-repo/SKILL.md @@ -0,0 +1,874 @@ +--- +name: github-multi-repo +version: 1.0.0 +description: Multi-repository coordination, synchronization, and architecture management with AI swarm orchestration +category: github-integration +tags: [multi-repo, synchronization, architecture, coordination, github] +author: Claude Flow Team +requires: + - ruv-swarm@^1.0.11 + - gh-cli@^2.0.0 +capabilities: + - cross-repository coordination + - package synchronization + - architecture optimization + - template management + - distributed workflows +--- + +# GitHub Multi-Repository Coordination Skill + +## Overview + +Advanced multi-repository coordination system that combines swarm intelligence, package synchronization, and repository architecture optimization. This skill enables organization-wide automation, cross-project collaboration, and scalable repository management. + +## Core Capabilities + +### ๐Ÿ”„ Multi-Repository Swarm Coordination +Cross-repository AI swarm orchestration for distributed development workflows. + +### ๐Ÿ“ฆ Package Synchronization +Intelligent dependency resolution and version alignment across multiple packages. + +### ๐Ÿ—๏ธ Repository Architecture +Structure optimization and template management for scalable projects. + +### ๐Ÿ”— Integration Management +Cross-package integration testing and deployment coordination. + +## Quick Start + +### Initialize Multi-Repo Coordination +```bash +# Basic swarm initialization +npx claude-flow skill run github-multi-repo init \ + --repos "org/frontend,org/backend,org/shared" \ + --topology hierarchical + +# Advanced initialization with synchronization +npx claude-flow skill run github-multi-repo init \ + --repos "org/frontend,org/backend,org/shared" \ + --topology mesh \ + --shared-memory \ + --sync-strategy eventual +``` + +### Synchronize Packages +```bash +# Synchronize package versions and dependencies +npx claude-flow skill run github-multi-repo sync \ + --packages "claude-code-flow,ruv-swarm" \ + --align-versions \ + --update-docs +``` + +### Optimize Architecture +```bash +# Analyze and optimize repository structure +npx claude-flow skill run github-multi-repo optimize \ + --analyze-structure \ + --suggest-improvements \ + --create-templates +``` + +## Features + +### 1. Cross-Repository Swarm Orchestration + +#### Repository Discovery +```javascript +// Auto-discover related repositories with gh CLI +const REPOS = Bash(`gh repo list my-organization --limit 100 \ + --json name,description,languages,topics \ + --jq '.[] | select(.languages | keys | contains(["TypeScript"]))'`) + +// Analyze repository dependencies +const DEPS = Bash(`gh repo list my-organization --json name | \ + jq -r '.[].name' | while read -r repo; do + gh api repos/my-organization/$repo/contents/package.json \ + --jq '.content' 2>/dev/null | base64 -d | jq '{name, dependencies}' + done | jq -s '.'`) + +// Initialize swarm with discovered repositories +mcp__claude-flow__swarm_init({ + topology: "hierarchical", + maxAgents: 8, + metadata: { repos: REPOS, dependencies: DEPS } +}) +``` + +#### Synchronized Operations +```javascript +// Execute synchronized changes across repositories +[Parallel Multi-Repo Operations]: + // Spawn coordination agents + Task("Repository Coordinator", "Coordinate changes across all repositories", "coordinator") + Task("Dependency Analyzer", "Analyze cross-repo dependencies", "analyst") + Task("Integration Tester", "Validate cross-repo changes", "tester") + + // Get matching repositories + Bash(`gh repo list org --limit 100 --json name \ + --jq '.[] | select(.name | test("-service$")) | .name' > /tmp/repos.txt`) + + // Execute task across repositories + Bash(`cat /tmp/repos.txt | while read -r repo; do + gh repo clone org/$repo /tmp/$repo -- --depth=1 + cd /tmp/$repo + + # Apply changes + npm update + npm test + + # Create PR if successful + if [ $? -eq 0 ]; then + git checkout -b update-dependencies-$(date +%Y%m%d) + git add -A + git commit -m "chore: Update dependencies" + git push origin HEAD + gh pr create --title "Update dependencies" --body "Automated update" --label "dependencies" + fi + done`) + + // Track all operations + TodoWrite { todos: [ + { id: "discover", content: "Discover all service repositories", status: "completed" }, + { id: "update", content: "Update dependencies", status: "completed" }, + { id: "test", content: "Run integration tests", status: "in_progress" }, + { id: "pr", content: "Create pull requests", status: "pending" } + ]} +``` + +### 2. Package Synchronization + +#### Version Alignment +```javascript +// Synchronize package dependencies and versions +[Complete Package Sync]: + // Initialize sync swarm + mcp__claude-flow__swarm_init({ topology: "mesh", maxAgents: 5 }) + + // Spawn sync agents + Task("Sync Coordinator", "Coordinate version alignment", "coordinator") + Task("Dependency Analyzer", "Analyze dependencies", "analyst") + Task("Integration Tester", "Validate synchronization", "tester") + + // Read package states + Read("/workspaces/ruv-FANN/claude-code-flow/claude-code-flow/package.json") + Read("/workspaces/ruv-FANN/ruv-swarm/npm/package.json") + + // Align versions using gh CLI + Bash(`gh api repos/:owner/:repo/git/refs \ + -f ref='refs/heads/sync/package-alignment' \ + -f sha=$(gh api repos/:owner/:repo/git/refs/heads/main --jq '.object.sha')`) + + // Update package.json files + Bash(`gh api repos/:owner/:repo/contents/package.json \ + --method PUT \ + -f message="feat: Align Node.js version requirements" \ + -f branch="sync/package-alignment" \ + -f content="$(cat aligned-package.json | base64)"`) + + // Store sync state + mcp__claude-flow__memory_usage({ + action: "store", + key: "sync/packages/status", + value: { + timestamp: Date.now(), + packages_synced: ["claude-code-flow", "ruv-swarm"], + status: "synchronized" + } + }) +``` + +#### Documentation Synchronization +```javascript +// Synchronize CLAUDE.md files across packages +[Documentation Sync]: + // Get source documentation + Bash(`gh api repos/:owner/:repo/contents/ruv-swarm/docs/CLAUDE.md \ + --jq '.content' | base64 -d > /tmp/claude-source.md`) + + // Update target documentation + Bash(`gh api repos/:owner/:repo/contents/claude-code-flow/CLAUDE.md \ + --method PUT \ + -f message="docs: Synchronize CLAUDE.md" \ + -f branch="sync/documentation" \ + -f content="$(cat /tmp/claude-source.md | base64)"`) + + // Track sync status + mcp__claude-flow__memory_usage({ + action: "store", + key: "sync/documentation/status", + value: { status: "synchronized", files: ["CLAUDE.md"] } + }) +``` + +#### Cross-Package Integration +```javascript +// Coordinate feature implementation across packages +[Cross-Package Feature]: + // Push changes to all packages + mcp__github__push_files({ + branch: "feature/github-integration", + files: [ + { + path: "claude-code-flow/.claude/commands/github/github-modes.md", + content: "[GitHub modes documentation]" + }, + { + path: "ruv-swarm/src/github-coordinator/hooks.js", + content: "[GitHub coordination hooks]" + } + ], + message: "feat: Add GitHub workflow integration" + }) + + // Create coordinated PR + Bash(`gh pr create \ + --title "Feature: GitHub Workflow Integration" \ + --body "## ๐Ÿš€ GitHub Integration + +### Features +- โœ… Multi-repo coordination +- โœ… Package synchronization +- โœ… Architecture optimization + +### Testing +- [x] Package dependency verification +- [x] Integration tests +- [x] Cross-package compatibility"`) +``` + +### 3. Repository Architecture + +#### Structure Analysis +```javascript +// Analyze and optimize repository structure +[Architecture Analysis]: + // Initialize architecture swarm + mcp__claude-flow__swarm_init({ topology: "hierarchical", maxAgents: 6 }) + + // Spawn architecture agents + Task("Senior Architect", "Analyze repository structure", "architect") + Task("Structure Analyst", "Identify optimization opportunities", "analyst") + Task("Performance Optimizer", "Optimize structure for scalability", "optimizer") + Task("Best Practices Researcher", "Research architecture patterns", "researcher") + + // Analyze current structures + LS("/workspaces/ruv-FANN/claude-code-flow/claude-code-flow") + LS("/workspaces/ruv-FANN/ruv-swarm/npm") + + // Search for best practices + Bash(`gh search repos "language:javascript template architecture" \ + --limit 10 \ + --json fullName,description,stargazersCount \ + --sort stars \ + --order desc`) + + // Store analysis results + mcp__claude-flow__memory_usage({ + action: "store", + key: "architecture/analysis/results", + value: { + repositories_analyzed: ["claude-code-flow", "ruv-swarm"], + optimization_areas: ["structure", "workflows", "templates"], + recommendations: ["standardize_structure", "improve_workflows"] + } + }) +``` + +#### Template Creation +```javascript +// Create standardized repository template +[Template Creation]: + // Create template repository + mcp__github__create_repository({ + name: "claude-project-template", + description: "Standardized template for Claude Code projects", + private: false, + autoInit: true + }) + + // Push template structure + mcp__github__push_files({ + repo: "claude-project-template", + files: [ + { + path: ".claude/commands/github/github-modes.md", + content: "[GitHub modes template]" + }, + { + path: ".claude/config.json", + content: JSON.stringify({ + version: "1.0", + mcp_servers: { + "ruv-swarm": { + command: "npx", + args: ["ruv-swarm", "mcp", "start"] + } + } + }) + }, + { + path: "CLAUDE.md", + content: "[Standardized CLAUDE.md]" + }, + { + path: "package.json", + content: JSON.stringify({ + name: "claude-project-template", + engines: { node: ">=20.0.0" }, + dependencies: { "ruv-swarm": "^1.0.11" } + }) + } + ], + message: "feat: Create standardized template" + }) +``` + +#### Cross-Repository Standardization +```javascript +// Synchronize structure across repositories +[Structure Standardization]: + const repositories = ["claude-code-flow", "ruv-swarm", "claude-extensions"] + + // Update common files across all repositories + repositories.forEach(repo => { + mcp__github__create_or_update_file({ + repo: "ruv-FANN", + path: `${repo}/.github/workflows/integration.yml`, + content: `name: Integration Tests +on: [push, pull_request] +jobs: + test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 + with: { node-version: '20' } + - run: npm install && npm test`, + message: "ci: Standardize integration workflow", + branch: "structure/standardization" + }) + }) +``` + +### 4. Orchestration Workflows + +#### Dependency Management +```javascript +// Update dependencies across all repositories +[Organization-Wide Dependency Update]: + // Create tracking issue + TRACKING_ISSUE=$(Bash(`gh issue create \ + --title "Dependency Update: typescript@5.0.0" \ + --body "Tracking TypeScript update across all repositories" \ + --label "dependencies,tracking" \ + --json number -q .number`)) + + // Find all TypeScript repositories + TS_REPOS=$(Bash(`gh repo list org --limit 100 --json name | \ + jq -r '.[].name' | while read -r repo; do + if gh api repos/org/$repo/contents/package.json 2>/dev/null | \ + jq -r '.content' | base64 -d | grep -q '"typescript"'; then + echo "$repo" + fi + done`)) + + // Update each repository + Bash(`echo "$TS_REPOS" | while read -r repo; do + gh repo clone org/$repo /tmp/$repo -- --depth=1 + cd /tmp/$repo + + npm install --save-dev typescript@5.0.0 + + if npm test; then + git checkout -b update-typescript-5 + git add package.json package-lock.json + git commit -m "chore: Update TypeScript to 5.0.0 + +Part of #$TRACKING_ISSUE" + + git push origin HEAD + gh pr create \ + --title "Update TypeScript to 5.0.0" \ + --body "Updates TypeScript\n\nTracking: #$TRACKING_ISSUE" \ + --label "dependencies" + else + gh issue comment $TRACKING_ISSUE \ + --body "โŒ Failed to update $repo - tests failing" + fi + done`) +``` + +#### Refactoring Operations +```javascript +// Coordinate large-scale refactoring +[Cross-Repo Refactoring]: + // Initialize refactoring swarm + mcp__claude-flow__swarm_init({ topology: "mesh", maxAgents: 8 }) + + // Spawn specialized agents + Task("Refactoring Coordinator", "Coordinate refactoring across repos", "coordinator") + Task("Impact Analyzer", "Analyze refactoring impact", "analyst") + Task("Code Transformer", "Apply refactoring changes", "coder") + Task("Migration Guide Creator", "Create migration documentation", "documenter") + Task("Integration Tester", "Validate refactored code", "tester") + + // Execute refactoring + mcp__claude-flow__task_orchestrate({ + task: "Rename OldAPI to NewAPI across all repositories", + strategy: "sequential", + priority: "high" + }) +``` + +#### Security Updates +```javascript +// Coordinate security patches +[Security Patch Deployment]: + // Scan all repositories + Bash(`gh repo list org --limit 100 --json name | jq -r '.[].name' | \ + while read -r repo; do + gh repo clone org/$repo /tmp/$repo -- --depth=1 + cd /tmp/$repo + npm audit --json > /tmp/audit-$repo.json + done`) + + // Apply patches + Bash(`for repo in /tmp/audit-*.json; do + if [ $(jq '.vulnerabilities | length' $repo) -gt 0 ]; then + cd /tmp/$(basename $repo .json | sed 's/audit-//') + npm audit fix + + if npm test; then + git checkout -b security/patch-$(date +%Y%m%d) + git add -A + git commit -m "security: Apply security patches" + git push origin HEAD + gh pr create --title "Security patches" --label "security" + fi + fi + done`) +``` + +## Configuration + +### Multi-Repo Config File +```yaml +# .swarm/multi-repo.yml +version: 1 +organization: my-org + +repositories: + - name: frontend + url: github.com/my-org/frontend + role: ui + agents: [coder, designer, tester] + + - name: backend + url: github.com/my-org/backend + role: api + agents: [architect, coder, tester] + + - name: shared + url: github.com/my-org/shared + role: library + agents: [analyst, coder] + +coordination: + topology: hierarchical + communication: webhook + memory: redis://shared-memory + +dependencies: + - from: frontend + to: [backend, shared] + - from: backend + to: [shared] +``` + +### Repository Roles +```javascript +{ + "roles": { + "ui": { + "responsibilities": ["user-interface", "ux", "accessibility"], + "default-agents": ["designer", "coder", "tester"] + }, + "api": { + "responsibilities": ["endpoints", "business-logic", "data"], + "default-agents": ["architect", "coder", "security"] + }, + "library": { + "responsibilities": ["shared-code", "utilities", "types"], + "default-agents": ["analyst", "coder", "documenter"] + } + } +} +``` + +## Communication Strategies + +### 1. Webhook-Based Coordination +```javascript +const { MultiRepoSwarm } = require('ruv-swarm'); + +const swarm = new MultiRepoSwarm({ + webhook: { + url: 'https://swarm-coordinator.example.com', + secret: process.env.WEBHOOK_SECRET + } +}); + +swarm.on('repo:update', async (event) => { + await swarm.propagate(event, { + to: event.dependencies, + strategy: 'eventual-consistency' + }); +}); +``` + +### 2. Event Streaming +```yaml +# Kafka configuration for real-time coordination +kafka: + brokers: ['kafka1:9092', 'kafka2:9092'] + topics: + swarm-events: + partitions: 10 + replication: 3 + swarm-memory: + partitions: 5 + replication: 3 +``` + +## Synchronization Patterns + +### 1. Eventually Consistent +```javascript +{ + "sync": { + "strategy": "eventual", + "max-lag": "5m", + "retry": { + "attempts": 3, + "backoff": "exponential" + } + } +} +``` + +### 2. Strong Consistency +```javascript +{ + "sync": { + "strategy": "strong", + "consensus": "raft", + "quorum": 0.51, + "timeout": "30s" + } +} +``` + +### 3. Hybrid Approach +```javascript +{ + "sync": { + "default": "eventual", + "overrides": { + "security-updates": "strong", + "dependency-updates": "strong", + "documentation": "eventual" + } + } +} +``` + +## Use Cases + +### 1. Microservices Coordination +```bash +npx claude-flow skill run github-multi-repo microservices \ + --services "auth,users,orders,payments" \ + --ensure-compatibility \ + --sync-contracts \ + --integration-tests +``` + +### 2. Library Updates +```bash +npx claude-flow skill run github-multi-repo lib-update \ + --library "org/shared-lib" \ + --version "2.0.0" \ + --find-consumers \ + --update-imports \ + --run-tests +``` + +### 3. Organization-Wide Changes +```bash +npx claude-flow skill run github-multi-repo org-policy \ + --policy "add-security-headers" \ + --repos "org/*" \ + --validate-compliance \ + --create-reports +``` + +## Architecture Patterns + +### Monorepo Structure +``` +ruv-FANN/ +โ”œโ”€โ”€ packages/ +โ”‚ โ”œโ”€โ”€ claude-code-flow/ +โ”‚ โ”‚ โ”œโ”€โ”€ src/ +โ”‚ โ”‚ โ”œโ”€โ”€ .claude/ +โ”‚ โ”‚ โ””โ”€โ”€ package.json +โ”‚ โ”œโ”€โ”€ ruv-swarm/ +โ”‚ โ”‚ โ”œโ”€โ”€ src/ +โ”‚ โ”‚ โ”œโ”€โ”€ wasm/ +โ”‚ โ”‚ โ””โ”€โ”€ package.json +โ”‚ โ””โ”€โ”€ shared/ +โ”‚ โ”œโ”€โ”€ types/ +โ”‚ โ”œโ”€โ”€ utils/ +โ”‚ โ””โ”€โ”€ config/ +โ”œโ”€โ”€ tools/ +โ”‚ โ”œโ”€โ”€ build/ +โ”‚ โ”œโ”€โ”€ test/ +โ”‚ โ””โ”€โ”€ deploy/ +โ”œโ”€โ”€ docs/ +โ”‚ โ”œโ”€โ”€ architecture/ +โ”‚ โ”œโ”€โ”€ integration/ +โ”‚ โ””โ”€โ”€ examples/ +โ””โ”€โ”€ .github/ + โ”œโ”€โ”€ workflows/ + โ”œโ”€โ”€ templates/ + โ””โ”€โ”€ actions/ +``` + +### Command Structure +``` +.claude/ +โ”œโ”€โ”€ commands/ +โ”‚ โ”œโ”€โ”€ github/ +โ”‚ โ”‚ โ”œโ”€โ”€ github-modes.md +โ”‚ โ”‚ โ”œโ”€โ”€ pr-manager.md +โ”‚ โ”‚ โ”œโ”€โ”€ issue-tracker.md +โ”‚ โ”‚ โ””โ”€โ”€ sync-coordinator.md +โ”‚ โ”œโ”€โ”€ sparc/ +โ”‚ โ”‚ โ”œโ”€โ”€ sparc-modes.md +โ”‚ โ”‚ โ”œโ”€โ”€ coder.md +โ”‚ โ”‚ โ””โ”€โ”€ tester.md +โ”‚ โ””โ”€โ”€ swarm/ +โ”‚ โ”œโ”€โ”€ coordination.md +โ”‚ โ””โ”€โ”€ orchestration.md +โ”œโ”€โ”€ templates/ +โ”‚ โ”œโ”€โ”€ issue.md +โ”‚ โ”œโ”€โ”€ pr.md +โ”‚ โ””โ”€โ”€ project.md +โ””โ”€โ”€ config.json +``` + +## Monitoring & Visualization + +### Multi-Repo Dashboard +```bash +npx claude-flow skill run github-multi-repo dashboard \ + --port 3000 \ + --metrics "agent-activity,task-progress,memory-usage" \ + --real-time +``` + +### Dependency Graph +```bash +npx claude-flow skill run github-multi-repo dep-graph \ + --format mermaid \ + --include-agents \ + --show-data-flow +``` + +### Health Monitoring +```bash +npx claude-flow skill run github-multi-repo health-check \ + --repos "org/*" \ + --check "connectivity,memory,agents" \ + --alert-on-issues +``` + +## Best Practices + +### 1. Repository Organization +- Clear repository roles and boundaries +- Consistent naming conventions +- Documented dependencies +- Shared configuration standards + +### 2. Communication +- Use appropriate sync strategies +- Implement circuit breakers +- Monitor latency and failures +- Clear error propagation + +### 3. Security +- Secure cross-repo authentication +- Encrypted communication channels +- Audit trail for all operations +- Principle of least privilege + +### 4. Version Management +- Semantic versioning alignment +- Dependency compatibility validation +- Automated version bump coordination + +### 5. Testing Integration +- Cross-package test validation +- Integration test automation +- Performance regression detection + +## Performance Optimization + +### Caching Strategy +```bash +npx claude-flow skill run github-multi-repo cache-strategy \ + --analyze-patterns \ + --suggest-cache-layers \ + --implement-invalidation +``` + +### Parallel Execution +```bash +npx claude-flow skill run github-multi-repo parallel-optimize \ + --analyze-dependencies \ + --identify-parallelizable \ + --execute-optimal +``` + +### Resource Pooling +```bash +npx claude-flow skill run github-multi-repo resource-pool \ + --share-agents \ + --distribute-load \ + --monitor-usage +``` + +## Troubleshooting + +### Connectivity Issues +```bash +npx claude-flow skill run github-multi-repo diagnose-connectivity \ + --test-all-repos \ + --check-permissions \ + --verify-webhooks +``` + +### Memory Synchronization +```bash +npx claude-flow skill run github-multi-repo debug-memory \ + --check-consistency \ + --identify-conflicts \ + --repair-state +``` + +### Performance Bottlenecks +```bash +npx claude-flow skill run github-multi-repo perf-analysis \ + --profile-operations \ + --identify-bottlenecks \ + --suggest-optimizations +``` + +## Advanced Features + +### 1. Distributed Task Queue +```bash +npx claude-flow skill run github-multi-repo queue \ + --backend redis \ + --workers 10 \ + --priority-routing \ + --dead-letter-queue +``` + +### 2. Cross-Repo Testing +```bash +npx claude-flow skill run github-multi-repo test \ + --setup-test-env \ + --link-services \ + --run-e2e \ + --tear-down +``` + +### 3. Monorepo Migration +```bash +npx claude-flow skill run github-multi-repo to-monorepo \ + --analyze-repos \ + --suggest-structure \ + --preserve-history \ + --create-migration-prs +``` + +## Examples + +### Full-Stack Application Update +```bash +npx claude-flow skill run github-multi-repo fullstack-update \ + --frontend "org/web-app" \ + --backend "org/api-server" \ + --database "org/db-migrations" \ + --coordinate-deployment +``` + +### Cross-Team Collaboration +```bash +npx claude-flow skill run github-multi-repo cross-team \ + --teams "frontend,backend,devops" \ + --task "implement-feature-x" \ + --assign-by-expertise \ + --track-progress +``` + +## Metrics and Reporting + +### Sync Quality Metrics +- Package version alignment percentage +- Documentation consistency score +- Integration test success rate +- Synchronization completion time + +### Architecture Health Metrics +- Repository structure consistency score +- Documentation coverage percentage +- Cross-repository integration success rate +- Template adoption and usage statistics + +### Automated Reporting +- Weekly sync status reports +- Dependency drift detection +- Documentation divergence alerts +- Integration health monitoring + +## Integration Points + +### Related Skills +- `github-workflow` - GitHub workflow automation +- `github-pr` - Pull request management +- `sparc-architect` - Architecture design +- `sparc-optimizer` - Performance optimization + +### Related Commands +- `/github sync-coordinator` - Cross-repo synchronization +- `/github release-manager` - Coordinated releases +- `/github repo-architect` - Repository optimization +- `/sparc architect` - Detailed architecture design + +## Support and Resources + +- Documentation: https://github.com/ruvnet/claude-flow +- Issues: https://github.com/ruvnet/claude-flow/issues +- Examples: `.claude/examples/github-multi-repo/` + +--- + +**Version:** 1.0.0 +**Last Updated:** 2025-10-19 +**Maintainer:** Claude Flow Team diff --git a/.claude/skills/github-project-management/SKILL.md b/.claude/skills/github-project-management/SKILL.md new file mode 100644 index 0000000000..cd2fa54e05 --- /dev/null +++ b/.claude/skills/github-project-management/SKILL.md @@ -0,0 +1,1277 @@ +--- +name: github-project-management +title: GitHub Project Management +version: 2.0.0 +category: github +description: Comprehensive GitHub project management with swarm-coordinated issue tracking, project board automation, and sprint planning +author: Claude Code +tags: + - github + - project-management + - issue-tracking + - project-boards + - sprint-planning + - agile + - swarm-coordination +difficulty: intermediate +prerequisites: + - GitHub CLI (gh) installed and authenticated + - ruv-swarm or claude-flow MCP server configured + - Repository access permissions +tools_required: + - mcp__github__* + - mcp__claude-flow__* + - Bash + - Read + - Write + - TodoWrite +related_skills: + - github-pr-workflow + - github-release-management + - sparc-orchestrator +estimated_time: 30-45 minutes +--- + +# GitHub Project Management + +## Overview + +A comprehensive skill for managing GitHub projects using AI swarm coordination. This skill combines intelligent issue management, automated project board synchronization, and swarm-based coordination for efficient project delivery. + +## Quick Start + +### Basic Issue Creation with Swarm Coordination + +```bash +# Create a coordinated issue +gh issue create \ + --title "Feature: Advanced Authentication" \ + --body "Implement OAuth2 with social login..." \ + --label "enhancement,swarm-ready" + +# Initialize swarm for issue +npx claude-flow@alpha hooks pre-task --description "Feature implementation" +``` + +### Project Board Quick Setup + +```bash +# Get project ID +PROJECT_ID=$(gh project list --owner @me --format json | \ + jq -r '.projects[0].id') + +# Initialize board sync +npx ruv-swarm github board-init \ + --project-id "$PROJECT_ID" \ + --sync-mode "bidirectional" +``` + +--- + +## Core Capabilities + +### 1. Issue Management & Triage + +
+Automated Issue Creation + +#### Single Issue with Swarm Coordination + +```javascript +// Initialize issue management swarm +mcp__claude-flow__swarm_init { topology: "star", maxAgents: 3 } +mcp__claude-flow__agent_spawn { type: "coordinator", name: "Issue Coordinator" } +mcp__claude-flow__agent_spawn { type: "researcher", name: "Requirements Analyst" } +mcp__claude-flow__agent_spawn { type: "coder", name: "Implementation Planner" } + +// Create comprehensive issue +mcp__github__create_issue { + owner: "org", + repo: "repository", + title: "Integration Review: Complete system integration", + body: `## ๐Ÿ”„ Integration Review + + ### Overview + Comprehensive review and integration between components. + + ### Objectives + - [ ] Verify dependencies and imports + - [ ] Ensure API integration + - [ ] Check hook system integration + - [ ] Validate data systems alignment + + ### Swarm Coordination + This issue will be managed by coordinated swarm agents for optimal progress tracking.`, + labels: ["integration", "review", "enhancement"], + assignees: ["username"] +} + +// Set up automated tracking +mcp__claude-flow__task_orchestrate { + task: "Monitor and coordinate issue progress with automated updates", + strategy: "adaptive", + priority: "medium" +} +``` + +#### Batch Issue Creation + +```bash +# Create multiple related issues using gh CLI +gh issue create \ + --title "Feature: Advanced GitHub Integration" \ + --body "Implement comprehensive GitHub workflow automation..." \ + --label "feature,github,high-priority" + +gh issue create \ + --title "Bug: Merge conflicts in integration branch" \ + --body "Resolve merge conflicts..." \ + --label "bug,integration,urgent" + +gh issue create \ + --title "Documentation: Update integration guides" \ + --body "Update all documentation..." \ + --label "documentation,integration" +``` + +
+ +
+Issue-to-Swarm Conversion + +#### Transform Issues into Swarm Tasks + +```bash +# Get issue details +ISSUE_DATA=$(gh issue view 456 --json title,body,labels,assignees,comments) + +# Create swarm from issue +npx ruv-swarm github issue-to-swarm 456 \ + --issue-data "$ISSUE_DATA" \ + --auto-decompose \ + --assign-agents + +# Batch process multiple issues +ISSUES=$(gh issue list --label "swarm-ready" --json number,title,body,labels) +npx ruv-swarm github issues-batch \ + --issues "$ISSUES" \ + --parallel + +# Update issues with swarm status +echo "$ISSUES" | jq -r '.[].number' | while read -r num; do + gh issue edit $num --add-label "swarm-processing" +done +``` + +#### Issue Comment Commands + +Execute swarm operations via issue comments: + +```markdown + +/swarm analyze +/swarm decompose 5 +/swarm assign @agent-coder +/swarm estimate +/swarm start +``` + +
+ +
+Automated Issue Triage + +#### Auto-Label Based on Content + +```javascript +// .github/swarm-labels.json +{ + "rules": [ + { + "keywords": ["bug", "error", "broken"], + "labels": ["bug", "swarm-debugger"], + "agents": ["debugger", "tester"] + }, + { + "keywords": ["feature", "implement", "add"], + "labels": ["enhancement", "swarm-feature"], + "agents": ["architect", "coder", "tester"] + }, + { + "keywords": ["slow", "performance", "optimize"], + "labels": ["performance", "swarm-optimizer"], + "agents": ["analyst", "optimizer"] + } + ] +} +``` + +#### Automated Triage System + +```bash +# Analyze and triage unlabeled issues +npx ruv-swarm github triage \ + --unlabeled \ + --analyze-content \ + --suggest-labels \ + --assign-priority + +# Find and link duplicate issues +npx ruv-swarm github find-duplicates \ + --threshold 0.8 \ + --link-related \ + --close-duplicates +``` + +
+ +
+Task Decomposition & Progress Tracking + +#### Break Down Issues into Subtasks + +```bash +# Get issue body +ISSUE_BODY=$(gh issue view 456 --json body --jq '.body') + +# Decompose into subtasks +SUBTASKS=$(npx ruv-swarm github issue-decompose 456 \ + --body "$ISSUE_BODY" \ + --max-subtasks 10 \ + --assign-priorities) + +# Update issue with checklist +CHECKLIST=$(echo "$SUBTASKS" | jq -r '.tasks[] | "- [ ] " + .description') +UPDATED_BODY="$ISSUE_BODY + +## Subtasks +$CHECKLIST" + +gh issue edit 456 --body "$UPDATED_BODY" + +# Create linked issues for major subtasks +echo "$SUBTASKS" | jq -r '.tasks[] | select(.priority == "high")' | while read -r task; do + TITLE=$(echo "$task" | jq -r '.title') + BODY=$(echo "$task" | jq -r '.description') + + gh issue create \ + --title "$TITLE" \ + --body "$BODY + +Parent issue: #456" \ + --label "subtask" +done +``` + +#### Automated Progress Updates + +```bash +# Get current issue state +CURRENT=$(gh issue view 456 --json body,labels) + +# Get swarm progress +PROGRESS=$(npx ruv-swarm github issue-progress 456) + +# Update checklist in issue body +UPDATED_BODY=$(echo "$CURRENT" | jq -r '.body' | \ + npx ruv-swarm github update-checklist --progress "$PROGRESS") + +# Edit issue with updated body +gh issue edit 456 --body "$UPDATED_BODY" + +# Post progress summary as comment +SUMMARY=$(echo "$PROGRESS" | jq -r ' +"## ๐Ÿ“Š Progress Update + +**Completion**: \(.completion)% +**ETA**: \(.eta) + +### Completed Tasks +\(.completed | map("- โœ… " + .) | join("\n")) + +### In Progress +\(.in_progress | map("- ๐Ÿ”„ " + .) | join("\n")) + +### Remaining +\(.remaining | map("- โณ " + .) | join("\n")) + +--- +๐Ÿค– Automated update by swarm agent"') + +gh issue comment 456 --body "$SUMMARY" + +# Update labels based on progress +if [[ $(echo "$PROGRESS" | jq -r '.completion') -eq 100 ]]; then + gh issue edit 456 --add-label "ready-for-review" --remove-label "in-progress" +fi +``` + +
+ +
+Stale Issue Management + +#### Auto-Close Stale Issues with Swarm Analysis + +```bash +# Find stale issues +STALE_DATE=$(date -d '30 days ago' --iso-8601) +STALE_ISSUES=$(gh issue list --state open --json number,title,updatedAt,labels \ + --jq ".[] | select(.updatedAt < \"$STALE_DATE\")") + +# Analyze each stale issue +echo "$STALE_ISSUES" | jq -r '.number' | while read -r num; do + # Get full issue context + ISSUE=$(gh issue view $num --json title,body,comments,labels) + + # Analyze with swarm + ACTION=$(npx ruv-swarm github analyze-stale \ + --issue "$ISSUE" \ + --suggest-action) + + case "$ACTION" in + "close") + gh issue comment $num --body "This issue has been inactive for 30 days and will be closed in 7 days if there's no further activity." + gh issue edit $num --add-label "stale" + ;; + "keep") + gh issue edit $num --remove-label "stale" 2>/dev/null || true + ;; + "needs-info") + gh issue comment $num --body "This issue needs more information. Please provide additional context or it may be closed as stale." + gh issue edit $num --add-label "needs-info" + ;; + esac +done + +# Close issues that have been stale for 37+ days +gh issue list --label stale --state open --json number,updatedAt \ + --jq ".[] | select(.updatedAt < \"$(date -d '37 days ago' --iso-8601)\") | .number" | \ + while read -r num; do + gh issue close $num --comment "Closing due to inactivity. Feel free to reopen if this is still relevant." + done +``` + +
+ +### 2. Project Board Automation + +
+Board Initialization & Configuration + +#### Connect Swarm to GitHub Project + +```bash +# Get project details +PROJECT_ID=$(gh project list --owner @me --format json | \ + jq -r '.projects[] | select(.title == "Development Board") | .id') + +# Initialize swarm with project +npx ruv-swarm github board-init \ + --project-id "$PROJECT_ID" \ + --sync-mode "bidirectional" \ + --create-views "swarm-status,agent-workload,priority" + +# Create project fields for swarm tracking +gh project field-create $PROJECT_ID --owner @me \ + --name "Swarm Status" \ + --data-type "SINGLE_SELECT" \ + --single-select-options "pending,in_progress,completed" +``` + +#### Board Mapping Configuration + +```yaml +# .github/board-sync.yml +version: 1 +project: + name: "AI Development Board" + number: 1 + +mapping: + # Map swarm task status to board columns + status: + pending: "Backlog" + assigned: "Ready" + in_progress: "In Progress" + review: "Review" + completed: "Done" + blocked: "Blocked" + + # Map agent types to labels + agents: + coder: "๐Ÿ”ง Development" + tester: "๐Ÿงช Testing" + analyst: "๐Ÿ“Š Analysis" + designer: "๐ŸŽจ Design" + architect: "๐Ÿ—๏ธ Architecture" + + # Map priority to project fields + priority: + critical: "๐Ÿ”ด Critical" + high: "๐ŸŸก High" + medium: "๐ŸŸข Medium" + low: "โšช Low" + + # Custom fields + fields: + - name: "Agent Count" + type: number + source: task.agents.length + - name: "Complexity" + type: select + source: task.complexity + - name: "ETA" + type: date + source: task.estimatedCompletion +``` + +
+ +
+Task Synchronization + +#### Real-time Board Sync + +```bash +# Sync swarm tasks with project cards +npx ruv-swarm github board-sync \ + --map-status '{ + "todo": "To Do", + "in_progress": "In Progress", + "review": "Review", + "done": "Done" + }' \ + --auto-move-cards \ + --update-metadata + +# Enable real-time board updates +npx ruv-swarm github board-realtime \ + --webhook-endpoint "https://api.example.com/github-sync" \ + --update-frequency "immediate" \ + --batch-updates false +``` + +#### Convert Issues to Project Cards + +```bash +# List issues with label +ISSUES=$(gh issue list --label "enhancement" --json number,title,body) + +# Add issues to project +echo "$ISSUES" | jq -r '.[].number' | while read -r issue; do + gh project item-add $PROJECT_ID --owner @me --url "https://github.com/$GITHUB_REPOSITORY/issues/$issue" +done + +# Process with swarm +npx ruv-swarm github board-import-issues \ + --issues "$ISSUES" \ + --add-to-column "Backlog" \ + --parse-checklist \ + --assign-agents +``` + +
+ +
+Smart Card Management + +#### Auto-Assignment + +```bash +# Automatically assign cards to agents +npx ruv-swarm github board-auto-assign \ + --strategy "load-balanced" \ + --consider "expertise,workload,availability" \ + --update-cards +``` + +#### Intelligent Card State Transitions + +```bash +# Smart card movement based on rules +npx ruv-swarm github board-smart-move \ + --rules '{ + "auto-progress": "when:all-subtasks-done", + "auto-review": "when:tests-pass", + "auto-done": "when:pr-merged" + }' +``` + +#### Bulk Operations + +```bash +# Bulk card operations +npx ruv-swarm github board-bulk \ + --filter "status:blocked" \ + --action "add-label:needs-attention" \ + --notify-assignees +``` + +
+ +
+Custom Views & Dashboards + +#### View Configuration + +```javascript +// Custom board views +{ + "views": [ + { + "name": "Swarm Overview", + "type": "board", + "groupBy": "status", + "filters": ["is:open"], + "sort": "priority:desc" + }, + { + "name": "Agent Workload", + "type": "table", + "groupBy": "assignedAgent", + "columns": ["title", "status", "priority", "eta"], + "sort": "eta:asc" + }, + { + "name": "Sprint Progress", + "type": "roadmap", + "dateField": "eta", + "groupBy": "milestone" + } + ] +} +``` + +#### Dashboard Configuration + +```javascript +// Dashboard with performance widgets +{ + "dashboard": { + "widgets": [ + { + "type": "chart", + "title": "Task Completion Rate", + "data": "completed-per-day", + "visualization": "line" + }, + { + "type": "gauge", + "title": "Sprint Progress", + "data": "sprint-completion", + "target": 100 + }, + { + "type": "heatmap", + "title": "Agent Activity", + "data": "agent-tasks-per-day" + } + ] + } +} +``` + +
+ +### 3. Sprint Planning & Tracking + +
+Sprint Management + +#### Initialize Sprint with Swarm Coordination + +```bash +# Manage sprints with swarms +npx ruv-swarm github sprint-manage \ + --sprint "Sprint 23" \ + --auto-populate \ + --capacity-planning \ + --track-velocity + +# Track milestone progress +npx ruv-swarm github milestone-track \ + --milestone "v2.0 Release" \ + --update-board \ + --show-dependencies \ + --predict-completion +``` + +#### Agile Development Board Setup + +```bash +# Setup agile board +npx ruv-swarm github agile-board \ + --methodology "scrum" \ + --sprint-length "2w" \ + --ceremonies "planning,review,retro" \ + --metrics "velocity,burndown" +``` + +#### Kanban Flow Board Setup + +```bash +# Setup kanban board +npx ruv-swarm github kanban-board \ + --wip-limits '{ + "In Progress": 5, + "Review": 3 + }' \ + --cycle-time-tracking \ + --continuous-flow +``` + +
+ +
+Progress Tracking & Analytics + +#### Board Analytics + +```bash +# Fetch project data +PROJECT_DATA=$(gh project item-list $PROJECT_ID --owner @me --format json) + +# Get issue metrics +ISSUE_METRICS=$(echo "$PROJECT_DATA" | jq -r '.items[] | select(.content.type == "Issue")' | \ + while read -r item; do + ISSUE_NUM=$(echo "$item" | jq -r '.content.number') + gh issue view $ISSUE_NUM --json createdAt,closedAt,labels,assignees + done) + +# Generate analytics with swarm +npx ruv-swarm github board-analytics \ + --project-data "$PROJECT_DATA" \ + --issue-metrics "$ISSUE_METRICS" \ + --metrics "throughput,cycle-time,wip" \ + --group-by "agent,priority,type" \ + --time-range "30d" \ + --export "dashboard" +``` + +#### Performance Reports + +```bash +# Track and visualize progress +npx ruv-swarm github board-progress \ + --show "burndown,velocity,cycle-time" \ + --time-period "sprint" \ + --export-metrics + +# Generate reports +npx ruv-swarm github board-report \ + --type "sprint-summary" \ + --format "markdown" \ + --include "velocity,burndown,blockers" \ + --distribute "slack,email" +``` + +#### KPI Tracking + +```bash +# Track board performance +npx ruv-swarm github board-kpis \ + --metrics '[ + "average-cycle-time", + "throughput-per-sprint", + "blocked-time-percentage", + "first-time-pass-rate" + ]' \ + --dashboard-url + +# Track team performance +npx ruv-swarm github team-metrics \ + --board "Development" \ + --per-member \ + --include "velocity,quality,collaboration" \ + --anonymous-option +``` + +
+ +
+Release Planning + +#### Release Coordination + +```bash +# Plan releases using board data +npx ruv-swarm github release-plan-board \ + --analyze-velocity \ + --estimate-completion \ + --identify-risks \ + --optimize-scope +``` + +
+ +### 4. Advanced Coordination + +
+Multi-Board Synchronization + +#### Cross-Board Sync + +```bash +# Sync across multiple boards +npx ruv-swarm github multi-board-sync \ + --boards "Development,QA,Release" \ + --sync-rules '{ + "Development->QA": "when:ready-for-test", + "QA->Release": "when:tests-pass" + }' + +# Cross-organization sync +npx ruv-swarm github cross-org-sync \ + --source "org1/Project-A" \ + --target "org2/Project-B" \ + --field-mapping "custom" \ + --conflict-resolution "source-wins" +``` + +
+ +
+Issue Dependencies & Epic Management + +#### Dependency Resolution + +```bash +# Handle issue dependencies +npx ruv-swarm github issue-deps 456 \ + --resolve-order \ + --parallel-safe \ + --update-blocking +``` + +#### Epic Coordination + +```bash +# Coordinate epic-level swarms +npx ruv-swarm github epic-swarm \ + --epic 123 \ + --child-issues "456,457,458" \ + --orchestrate +``` + +
+ +
+Cross-Repository Coordination + +#### Multi-Repo Issue Management + +```bash +# Handle issues across repositories +npx ruv-swarm github cross-repo \ + --issue "org/repo#456" \ + --related "org/other-repo#123" \ + --coordinate +``` + +
+ +
+Team Collaboration + +#### Work Distribution + +```bash +# Distribute work among team +npx ruv-swarm github board-distribute \ + --strategy "skills-based" \ + --balance-workload \ + --respect-preferences \ + --notify-assignments +``` + +#### Standup Automation + +```bash +# Generate standup reports +npx ruv-swarm github standup-report \ + --team "frontend" \ + --include "yesterday,today,blockers" \ + --format "slack" \ + --schedule "daily-9am" +``` + +#### Review Coordination + +```bash +# Coordinate reviews via board +npx ruv-swarm github review-coordinate \ + --board "Code Review" \ + --assign-reviewers \ + --track-feedback \ + --ensure-coverage +``` + +
+ +--- + +## Issue Templates + +### Integration Issue Template + +```markdown +## ๐Ÿ”„ Integration Task + +### Overview +[Brief description of integration requirements] + +### Objectives +- [ ] Component A integration +- [ ] Component B validation +- [ ] Testing and verification +- [ ] Documentation updates + +### Integration Areas +#### Dependencies +- [ ] Package.json updates +- [ ] Version compatibility +- [ ] Import statements + +#### Functionality +- [ ] Core feature integration +- [ ] API compatibility +- [ ] Performance validation + +#### Testing +- [ ] Unit tests +- [ ] Integration tests +- [ ] End-to-end validation + +### Swarm Coordination +- **Coordinator**: Overall progress tracking +- **Analyst**: Technical validation +- **Tester**: Quality assurance +- **Documenter**: Documentation updates + +### Progress Tracking +Updates will be posted automatically by swarm agents during implementation. + +--- +๐Ÿค– Generated with Claude Code +``` + +### Bug Report Template + +```markdown +## ๐Ÿ› Bug Report + +### Problem Description +[Clear description of the issue] + +### Expected Behavior +[What should happen] + +### Actual Behavior +[What actually happens] + +### Reproduction Steps +1. [Step 1] +2. [Step 2] +3. [Step 3] + +### Environment +- Package: [package name and version] +- Node.js: [version] +- OS: [operating system] + +### Investigation Plan +- [ ] Root cause analysis +- [ ] Fix implementation +- [ ] Testing and validation +- [ ] Regression testing + +### Swarm Assignment +- **Debugger**: Issue investigation +- **Coder**: Fix implementation +- **Tester**: Validation and testing + +--- +๐Ÿค– Generated with Claude Code +``` + +### Feature Request Template + +```markdown +## โœจ Feature Request + +### Feature Description +[Clear description of the proposed feature] + +### Use Cases +1. [Use case 1] +2. [Use case 2] +3. [Use case 3] + +### Acceptance Criteria +- [ ] Criterion 1 +- [ ] Criterion 2 +- [ ] Criterion 3 + +### Implementation Approach +#### Design +- [ ] Architecture design +- [ ] API design +- [ ] UI/UX mockups + +#### Development +- [ ] Core implementation +- [ ] Integration with existing features +- [ ] Performance optimization + +#### Testing +- [ ] Unit tests +- [ ] Integration tests +- [ ] User acceptance testing + +### Swarm Coordination +- **Architect**: Design and planning +- **Coder**: Implementation +- **Tester**: Quality assurance +- **Documenter**: Documentation + +--- +๐Ÿค– Generated with Claude Code +``` + +### Swarm Task Template + +```markdown + +name: Swarm Task +description: Create a task for AI swarm processing +body: + - type: dropdown + id: topology + attributes: + label: Swarm Topology + options: + - mesh + - hierarchical + - ring + - star + - type: input + id: agents + attributes: + label: Required Agents + placeholder: "coder, tester, analyst" + - type: textarea + id: tasks + attributes: + label: Task Breakdown + placeholder: | + 1. Task one description + 2. Task two description +``` + +--- + +## Workflow Integration + +### GitHub Actions for Issue Management + +```yaml +# .github/workflows/issue-swarm.yml +name: Issue Swarm Handler +on: + issues: + types: [opened, labeled, commented] + +jobs: + swarm-process: + runs-on: ubuntu-latest + steps: + - name: Process Issue + uses: ruvnet/swarm-action@v1 + with: + command: | + if [[ "${{ github.event.label.name }}" == "swarm-ready" ]]; then + npx ruv-swarm github issue-init ${{ github.event.issue.number }} + fi +``` + +### Board Integration Workflow + +```bash +# Sync with project board +npx ruv-swarm github issue-board-sync \ + --project "Development" \ + --column-mapping '{ + "To Do": "pending", + "In Progress": "active", + "Done": "completed" + }' +``` + +--- + +## Specialized Issue Strategies + +### Bug Investigation Swarm + +```bash +# Specialized bug handling +npx ruv-swarm github bug-swarm 456 \ + --reproduce \ + --isolate \ + --fix \ + --test +``` + +### Feature Implementation Swarm + +```bash +# Feature implementation swarm +npx ruv-swarm github feature-swarm 456 \ + --design \ + --implement \ + --document \ + --demo +``` + +### Technical Debt Refactoring + +```bash +# Refactoring swarm +npx ruv-swarm github debt-swarm 456 \ + --analyze-impact \ + --plan-migration \ + --execute \ + --validate +``` + +--- + +## Best Practices + +### 1. Swarm-Coordinated Issue Management +- Always initialize swarm for complex issues +- Assign specialized agents based on issue type +- Use memory for progress coordination +- Regular automated progress updates + +### 2. Board Organization +- Clear column definitions with consistent naming +- Systematic labeling strategy across repositories +- Regular board grooming and maintenance +- Well-defined automation rules + +### 3. Data Integrity +- Bidirectional sync validation +- Conflict resolution strategies +- Comprehensive audit trails +- Regular backups of project data + +### 4. Team Adoption +- Comprehensive training materials +- Clear, documented workflows +- Regular team reviews and retrospectives +- Active feedback loops for improvement + +### 5. Smart Labeling and Organization +- Consistent labeling strategy across repositories +- Priority-based issue sorting and assignment +- Milestone integration for project coordination +- Agent-type to label mapping + +### 6. Automated Progress Tracking +- Regular automated updates with swarm coordination +- Progress metrics and completion tracking +- Cross-issue dependency management +- Real-time status synchronization + +--- + +## Troubleshooting + +### Sync Issues + +```bash +# Diagnose sync problems +npx ruv-swarm github board-diagnose \ + --check "permissions,webhooks,rate-limits" \ + --test-sync \ + --show-conflicts +``` + +### Performance Optimization + +```bash +# Optimize board performance +npx ruv-swarm github board-optimize \ + --analyze-size \ + --archive-completed \ + --index-fields \ + --cache-views +``` + +### Data Recovery + +```bash +# Recover board data +npx ruv-swarm github board-recover \ + --backup-id "2024-01-15" \ + --restore-cards \ + --preserve-current \ + --merge-conflicts +``` + +--- + +## Metrics & Analytics + +### Performance Metrics + +Automatic tracking of: +- Issue creation and resolution times +- Agent productivity metrics +- Project milestone progress +- Cross-repository coordination efficiency +- Sprint velocity and burndown +- Cycle time and throughput +- Work-in-progress limits + +### Reporting Features + +- Weekly progress summaries +- Agent performance analytics +- Project health metrics +- Integration success rates +- Team collaboration metrics +- Quality and defect tracking + +### Issue Resolution Time + +```bash +# Analyze swarm performance +npx ruv-swarm github issue-metrics \ + --issue 456 \ + --metrics "time-to-close,agent-efficiency,subtask-completion" +``` + +### Swarm Effectiveness + +```bash +# Generate effectiveness report +npx ruv-swarm github effectiveness \ + --issues "closed:>2024-01-01" \ + --compare "with-swarm,without-swarm" +``` + +--- + +## Security & Permissions + +1. **Command Authorization**: Validate user permissions before executing commands +2. **Rate Limiting**: Prevent spam and abuse of issue commands +3. **Audit Logging**: Track all swarm operations on issues and boards +4. **Data Privacy**: Respect private repository settings +5. **Access Control**: Proper GitHub permissions for board operations +6. **Webhook Security**: Secure webhook endpoints for real-time updates + +--- + +## Integration with Other Skills + +### Seamless Integration With: +- `github-pr-workflow` - Link issues to pull requests automatically +- `github-release-management` - Coordinate release issues and milestones +- `sparc-orchestrator` - Complex project coordination workflows +- `sparc-tester` - Automated testing workflows for issues + +--- + +## Complete Workflow Example + +### Full-Stack Feature Development + +```bash +# 1. Create feature issue with swarm coordination +gh issue create \ + --title "Feature: Real-time Collaboration" \ + --body "$(cat < +npx ruv-swarm github issue-decompose +npx ruv-swarm github triage --unlabeled + +# Project Boards +npx ruv-swarm github board-init --project-id +npx ruv-swarm github board-sync +npx ruv-swarm github board-analytics + +# Sprint Management +npx ruv-swarm github sprint-manage --sprint "Sprint X" +npx ruv-swarm github milestone-track --milestone "vX.X" + +# Analytics +npx ruv-swarm github issue-metrics --issue +npx ruv-swarm github board-kpis +``` + +--- + +## Additional Resources + +- [GitHub CLI Documentation](https://cli.github.com/manual/) +- [GitHub Projects Documentation](https://docs.github.com/en/issues/planning-and-tracking-with-projects) +- [Swarm Coordination Guide](https://github.com/ruvnet/ruv-swarm) +- [Claude Flow Documentation](https://github.com/ruvnet/claude-flow) + +--- + +**Last Updated**: 2025-10-19 +**Version**: 2.0.0 +**Maintainer**: Claude Code diff --git a/.claude/skills/github-release-management/SKILL.md b/.claude/skills/github-release-management/SKILL.md new file mode 100644 index 0000000000..5ddeb335a7 --- /dev/null +++ b/.claude/skills/github-release-management/SKILL.md @@ -0,0 +1,1081 @@ +--- +name: github-release-management +version: 2.0.0 +description: Comprehensive GitHub release orchestration with AI swarm coordination for automated versioning, testing, deployment, and rollback management +category: github +tags: [release, deployment, versioning, automation, ci-cd, swarm, orchestration] +author: Claude Flow Team +requires: + - gh (GitHub CLI) + - claude-flow + - ruv-swarm (optional for enhanced coordination) + - mcp-github (optional for MCP integration) +dependencies: + - git + - npm or yarn + - node >= 20.0.0 +related_skills: + - github-pr-management + - github-issue-tracking + - github-workflow-automation + - multi-repo-coordination +--- + +# GitHub Release Management Skill + +Intelligent release automation and orchestration using AI swarms for comprehensive software releases - from changelog generation to multi-platform deployment with rollback capabilities. + +## Quick Start + +### Simple Release Flow +```bash +# Plan and create a release +gh release create v2.0.0 \ + --draft \ + --generate-notes \ + --title "Release v2.0.0" + +# Orchestrate with swarm +npx claude-flow github release-create \ + --version "2.0.0" \ + --build-artifacts \ + --deploy-targets "npm,docker,github" +``` + +### Full Automated Release +```bash +# Initialize release swarm +npx claude-flow swarm init --topology hierarchical + +# Execute complete release pipeline +npx claude-flow sparc pipeline "Release v2.0.0 with full validation" +``` + +--- + +## Core Capabilities + +### 1. Release Planning & Version Management +- Semantic version analysis and suggestion +- Breaking change detection from commits +- Release timeline generation +- Multi-package version coordination + +### 2. Automated Testing & Validation +- Multi-stage test orchestration +- Cross-platform compatibility testing +- Performance regression detection +- Security vulnerability scanning + +### 3. Build & Deployment Orchestration +- Multi-platform build coordination +- Parallel artifact generation +- Progressive deployment strategies +- Automated rollback mechanisms + +### 4. Documentation & Communication +- Automated changelog generation +- Release notes with categorization +- Migration guide creation +- Stakeholder notification + +--- + +## Progressive Disclosure: Level 1 - Basic Usage + +### Essential Release Commands + +#### Create Release Draft +```bash +# Get last release tag +LAST_TAG=$(gh release list --limit 1 --json tagName -q '.[0].tagName') + +# Generate changelog from commits +CHANGELOG=$(gh api repos/:owner/:repo/compare/${LAST_TAG}...HEAD \ + --jq '.commits[].commit.message') + +# Create draft release +gh release create v2.0.0 \ + --draft \ + --title "Release v2.0.0" \ + --notes "$CHANGELOG" \ + --target main +``` + +#### Basic Version Bump +```bash +# Update package.json version +npm version patch # or minor, major + +# Push version tag +git push --follow-tags +``` + +#### Simple Deployment +```bash +# Build and publish npm package +npm run build +npm publish + +# Create GitHub release +gh release create $(npm pkg get version) \ + --generate-notes +``` + +### Quick Integration Example +```javascript +// Simple release preparation in Claude Code +[Single Message]: + // Update version files + Edit("package.json", { old: '"version": "1.0.0"', new: '"version": "2.0.0"' }) + + // Generate changelog + Bash("gh api repos/:owner/:repo/compare/v1.0.0...HEAD --jq '.commits[].commit.message' > CHANGELOG.md") + + // Create release branch + Bash("git checkout -b release/v2.0.0") + Bash("git add -A && git commit -m 'release: Prepare v2.0.0'") + + // Create PR + Bash("gh pr create --title 'Release v2.0.0' --body 'Automated release preparation'") +``` + +--- + +## Progressive Disclosure: Level 2 - Swarm Coordination + +### AI Swarm Release Orchestration + +#### Initialize Release Swarm +```javascript +// Set up coordinated release team +[Single Message - Swarm Initialization]: + mcp__claude-flow__swarm_init { + topology: "hierarchical", + maxAgents: 6, + strategy: "balanced" + } + + // Spawn specialized agents + mcp__claude-flow__agent_spawn { type: "coordinator", name: "Release Director" } + mcp__claude-flow__agent_spawn { type: "coder", name: "Version Manager" } + mcp__claude-flow__agent_spawn { type: "tester", name: "QA Engineer" } + mcp__claude-flow__agent_spawn { type: "reviewer", name: "Release Reviewer" } + mcp__claude-flow__agent_spawn { type: "analyst", name: "Deployment Analyst" } + mcp__claude-flow__agent_spawn { type: "researcher", name: "Compatibility Checker" } +``` + +#### Coordinated Release Workflow +```javascript +[Single Message - Full Release Coordination]: + // Create release branch + Bash("gh api repos/:owner/:repo/git/refs --method POST -f ref='refs/heads/release/v2.0.0' -f sha=$(gh api repos/:owner/:repo/git/refs/heads/main --jq '.object.sha')") + + // Orchestrate release preparation + mcp__claude-flow__task_orchestrate { + task: "Prepare release v2.0.0 with comprehensive testing and validation", + strategy: "sequential", + priority: "critical", + maxAgents: 6 + } + + // Update all release files + Write("package.json", "[updated version]") + Write("CHANGELOG.md", "[release changelog]") + Write("RELEASE_NOTES.md", "[detailed notes]") + + // Run comprehensive validation + Bash("npm install && npm test && npm run lint && npm run build") + + // Create release PR + Bash(`gh pr create \ + --title "Release v2.0.0: Feature Set and Improvements" \ + --head "release/v2.0.0" \ + --base "main" \ + --body "$(cat RELEASE_NOTES.md)"`) + + // Track progress + TodoWrite { todos: [ + { content: "Prepare release branch", status: "completed", priority: "critical" }, + { content: "Run validation suite", status: "completed", priority: "high" }, + { content: "Create release PR", status: "completed", priority: "high" }, + { content: "Code review approval", status: "pending", priority: "high" }, + { content: "Merge and deploy", status: "pending", priority: "critical" } + ]} + + // Store release state + mcp__claude-flow__memory_usage { + action: "store", + key: "release/v2.0.0/status", + value: JSON.stringify({ + version: "2.0.0", + stage: "validation_complete", + timestamp: Date.now(), + ready_for_review: true + }) + } +``` + +### Release Agent Specializations + +#### Changelog Agent +```bash +# Get merged PRs between versions +PRS=$(gh pr list --state merged --base main --json number,title,labels,author,mergedAt \ + --jq ".[] | select(.mergedAt > \"$(gh release view v1.0.0 --json publishedAt -q .publishedAt)\")") + +# Get commit history +COMMITS=$(gh api repos/:owner/:repo/compare/v1.0.0...HEAD \ + --jq '.commits[].commit.message') + +# Generate categorized changelog +npx claude-flow github changelog \ + --prs "$PRS" \ + --commits "$COMMITS" \ + --from v1.0.0 \ + --to HEAD \ + --categorize \ + --add-migration-guide +``` + +**Capabilities:** +- Semantic commit analysis +- Breaking change detection +- Contributor attribution +- Migration guide generation +- Multi-language support + +#### Version Agent +```bash +# Intelligent version suggestion +npx claude-flow github version-suggest \ + --current v1.2.3 \ + --analyze-commits \ + --check-compatibility \ + --suggest-pre-release +``` + +**Logic:** +- Analyzes commit messages and PR labels +- Detects breaking changes via keywords +- Suggests appropriate version bump +- Handles pre-release versioning +- Validates version constraints + +#### Build Agent +```bash +# Multi-platform build coordination +npx claude-flow github release-build \ + --platforms "linux,macos,windows" \ + --architectures "x64,arm64" \ + --parallel \ + --optimize-size +``` + +**Features:** +- Cross-platform compilation +- Parallel build execution +- Artifact optimization and compression +- Dependency bundling +- Build caching and reuse + +#### Test Agent +```bash +# Comprehensive pre-release testing +npx claude-flow github release-test \ + --suites "unit,integration,e2e,performance" \ + --environments "node:16,node:18,node:20" \ + --fail-fast false \ + --generate-report +``` + +#### Deploy Agent +```bash +# Multi-target deployment orchestration +npx claude-flow github release-deploy \ + --targets "npm,docker,github,s3" \ + --staged-rollout \ + --monitor-metrics \ + --auto-rollback +``` + +--- + +## Progressive Disclosure: Level 3 - Advanced Workflows + +### Multi-Package Release Coordination + +#### Monorepo Release Strategy +```javascript +[Single Message - Multi-Package Release]: + // Initialize mesh topology for cross-package coordination + mcp__claude-flow__swarm_init { topology: "mesh", maxAgents: 8 } + + // Spawn package-specific agents + Task("Package A Manager", "Coordinate claude-flow package release v1.0.72", "coder") + Task("Package B Manager", "Coordinate ruv-swarm package release v1.0.12", "coder") + Task("Integration Tester", "Validate cross-package compatibility", "tester") + Task("Version Coordinator", "Align dependencies and versions", "coordinator") + + // Update all packages simultaneously + Write("packages/claude-flow/package.json", "[v1.0.72 content]") + Write("packages/ruv-swarm/package.json", "[v1.0.12 content]") + Write("CHANGELOG.md", "[consolidated changelog]") + + // Run cross-package validation + Bash("cd packages/claude-flow && npm install && npm test") + Bash("cd packages/ruv-swarm && npm install && npm test") + Bash("npm run test:integration") + + // Create unified release PR + Bash(`gh pr create \ + --title "Release: claude-flow v1.0.72, ruv-swarm v1.0.12" \ + --body "Multi-package coordinated release with cross-compatibility validation"`) +``` + +### Progressive Deployment Strategy + +#### Staged Rollout Configuration +```yaml +# .github/release-deployment.yml +deployment: + strategy: progressive + stages: + - name: canary + percentage: 5 + duration: 1h + metrics: + - error-rate < 0.1% + - latency-p99 < 200ms + auto-advance: true + + - name: partial + percentage: 25 + duration: 4h + validation: automated-tests + approval: qa-team + + - name: rollout + percentage: 50 + duration: 8h + monitor: true + + - name: full + percentage: 100 + approval: release-manager + rollback-enabled: true +``` + +#### Execute Staged Deployment +```bash +# Deploy with progressive rollout +npx claude-flow github release-deploy \ + --version v2.0.0 \ + --strategy progressive \ + --config .github/release-deployment.yml \ + --monitor-metrics \ + --auto-rollback-on-error +``` + +### Multi-Repository Coordination + +#### Coordinated Multi-Repo Release +```bash +# Synchronize releases across repositories +npx claude-flow github multi-release \ + --repos "frontend:v2.0.0,backend:v2.1.0,cli:v1.5.0" \ + --ensure-compatibility \ + --atomic-release \ + --synchronized \ + --rollback-all-on-failure +``` + +#### Cross-Repo Dependency Management +```javascript +[Single Message - Cross-Repo Release]: + // Initialize star topology for centralized coordination + mcp__claude-flow__swarm_init { topology: "star", maxAgents: 6 } + + // Spawn repo-specific coordinators + Task("Frontend Release", "Release frontend v2.0.0 with API compatibility", "coordinator") + Task("Backend Release", "Release backend v2.1.0 with breaking changes", "coordinator") + Task("CLI Release", "Release CLI v1.5.0 with new commands", "coordinator") + Task("Compatibility Checker", "Validate cross-repo compatibility", "researcher") + + // Coordinate version updates across repos + Bash("gh api repos/org/frontend/dispatches --method POST -f event_type='release' -F client_payload[version]=v2.0.0") + Bash("gh api repos/org/backend/dispatches --method POST -f event_type='release' -F client_payload[version]=v2.1.0") + Bash("gh api repos/org/cli/dispatches --method POST -f event_type='release' -F client_payload[version]=v1.5.0") + + // Monitor all releases + mcp__claude-flow__swarm_monitor { interval: 5, duration: 300 } +``` + +### Hotfix Emergency Procedures + +#### Emergency Hotfix Workflow +```bash +# Fast-track critical bug fix +npx claude-flow github emergency-release \ + --issue 789 \ + --severity critical \ + --target-version v1.2.4 \ + --cherry-pick-commits \ + --bypass-checks security-only \ + --fast-track \ + --notify-all +``` + +#### Automated Hotfix Process +```javascript +[Single Message - Emergency Hotfix]: + // Create hotfix branch from last stable release + Bash("git checkout -b hotfix/v1.2.4 v1.2.3") + + // Cherry-pick critical fixes + Bash("git cherry-pick abc123def") + + // Fast validation + Bash("npm run test:critical && npm run build") + + // Create emergency release + Bash(`gh release create v1.2.4 \ + --title "HOTFIX v1.2.4: Critical Security Patch" \ + --notes "Emergency release addressing CVE-2024-XXXX" \ + --prerelease=false`) + + // Immediate deployment + Bash("npm publish --tag hotfix") + + // Notify stakeholders + Bash(`gh issue create \ + --title "๐Ÿšจ HOTFIX v1.2.4 Deployed" \ + --body "Critical security patch deployed. Please update immediately." \ + --label "critical,security,hotfix"`) +``` + +--- + +## Progressive Disclosure: Level 4 - Enterprise Features + +### Release Configuration Management + +#### Comprehensive Release Config +```yaml +# .github/release-swarm.yml +version: 2.0.0 + +release: + versioning: + strategy: semantic + breaking-keywords: ["BREAKING", "BREAKING CHANGE", "!"] + feature-keywords: ["feat", "feature"] + fix-keywords: ["fix", "bugfix"] + + changelog: + sections: + - title: "๐Ÿš€ Features" + labels: ["feature", "enhancement"] + emoji: true + - title: "๐Ÿ› Bug Fixes" + labels: ["bug", "fix"] + - title: "๐Ÿ’ฅ Breaking Changes" + labels: ["breaking"] + highlight: true + - title: "๐Ÿ“š Documentation" + labels: ["docs", "documentation"] + - title: "โšก Performance" + labels: ["performance", "optimization"] + - title: "๐Ÿ”’ Security" + labels: ["security"] + priority: critical + + artifacts: + - name: npm-package + build: npm run build + test: npm run test:all + publish: npm publish + registry: https://registry.npmjs.org + + - name: docker-image + build: docker build -t app:$VERSION . + test: docker run app:$VERSION npm test + publish: docker push app:$VERSION + platforms: [linux/amd64, linux/arm64] + + - name: binaries + build: ./scripts/build-binaries.sh + platforms: [linux, macos, windows] + architectures: [x64, arm64] + upload: github-release + sign: true + + validation: + pre-release: + - lint: npm run lint + - typecheck: npm run typecheck + - unit-tests: npm run test:unit + - integration-tests: npm run test:integration + - security-scan: npm audit + - license-check: npm run license-check + + post-release: + - smoke-tests: npm run test:smoke + - deployment-validation: ./scripts/validate-deployment.sh + - performance-baseline: npm run benchmark + + deployment: + environments: + - name: staging + auto-deploy: true + validation: npm run test:e2e + approval: false + + - name: production + auto-deploy: false + approval-required: true + approvers: ["release-manager", "tech-lead"] + rollback-enabled: true + health-checks: + - endpoint: /health + expected: 200 + timeout: 30s + + monitoring: + metrics: + - error-rate: <1% + - latency-p95: <500ms + - availability: >99.9% + - memory-usage: <80% + + alerts: + - type: slack + channel: releases + on: [deploy, rollback, error] + - type: email + recipients: ["team@company.com"] + on: [critical-error, rollback] + - type: pagerduty + service: production-releases + on: [critical-error] + + rollback: + auto-rollback: + triggers: + - error-rate > 5% + - latency-p99 > 2000ms + - availability < 99% + grace-period: 5m + + manual-rollback: + preserve-data: true + notify-users: true + create-incident: true +``` + +### Advanced Testing Strategies + +#### Comprehensive Validation Suite +```bash +# Pre-release validation with all checks +npx claude-flow github release-validate \ + --checks " + version-conflicts, + dependency-compatibility, + api-breaking-changes, + security-vulnerabilities, + performance-regression, + documentation-completeness, + license-compliance, + backwards-compatibility + " \ + --block-on-failure \ + --generate-report \ + --upload-results +``` + +#### Backward Compatibility Testing +```bash +# Test against previous versions +npx claude-flow github compat-test \ + --previous-versions "v1.0,v1.1,v1.2" \ + --api-contracts \ + --data-migrations \ + --integration-tests \ + --generate-report +``` + +#### Performance Regression Detection +```bash +# Benchmark against baseline +npx claude-flow github performance-test \ + --baseline v1.9.0 \ + --candidate v2.0.0 \ + --metrics "throughput,latency,memory,cpu" \ + --threshold 5% \ + --fail-on-regression +``` + +### Release Monitoring & Analytics + +#### Real-Time Release Monitoring +```bash +# Monitor release health post-deployment +npx claude-flow github release-monitor \ + --version v2.0.0 \ + --metrics "error-rate,latency,throughput,adoption" \ + --alert-thresholds \ + --duration 24h \ + --export-dashboard +``` + +#### Release Analytics & Insights +```bash +# Analyze release performance and adoption +npx claude-flow github release-analytics \ + --version v2.0.0 \ + --compare-with v1.9.0 \ + --metrics "adoption,performance,stability,feedback" \ + --generate-insights \ + --export-report +``` + +#### Automated Rollback Configuration +```bash +# Configure intelligent auto-rollback +npx claude-flow github rollback-config \ + --triggers '{ + "error-rate": ">5%", + "latency-p99": ">1000ms", + "availability": "<99.9%", + "failed-health-checks": ">3" + }' \ + --grace-period 5m \ + --notify-on-rollback \ + --preserve-metrics +``` + +### Security & Compliance + +#### Security Scanning +```bash +# Comprehensive security validation +npx claude-flow github release-security \ + --scan-dependencies \ + --check-secrets \ + --audit-permissions \ + --sign-artifacts \ + --sbom-generation \ + --vulnerability-report +``` + +#### Compliance Validation +```bash +# Ensure regulatory compliance +npx claude-flow github release-compliance \ + --standards "SOC2,GDPR,HIPAA" \ + --license-audit \ + --data-governance \ + --audit-trail \ + --generate-attestation +``` + +--- + +## GitHub Actions Integration + +### Complete Release Workflow +```yaml +# .github/workflows/release.yml +name: Intelligent Release Workflow +on: + push: + tags: ['v*'] + +jobs: + release-orchestration: + runs-on: ubuntu-latest + permissions: + contents: write + packages: write + issues: write + + steps: + - name: Checkout Repository + uses: actions/checkout@v3 + with: + fetch-depth: 0 + + - name: Setup Node.js + uses: actions/setup-node@v3 + with: + node-version: '20' + cache: 'npm' + + - name: Authenticate GitHub CLI + run: echo "${{ secrets.GITHUB_TOKEN }}" | gh auth login --with-token + + - name: Initialize Release Swarm + run: | + # Extract version from tag + RELEASE_TAG=${{ github.ref_name }} + PREV_TAG=$(gh release list --limit 2 --json tagName -q '.[1].tagName') + + # Get merged PRs for changelog + PRS=$(gh pr list --state merged --base main --json number,title,labels,author,mergedAt \ + --jq ".[] | select(.mergedAt > \"$(gh release view $PREV_TAG --json publishedAt -q .publishedAt)\")") + + # Get commit history + COMMITS=$(gh api repos/${{ github.repository }}/compare/${PREV_TAG}...HEAD \ + --jq '.commits[].commit.message') + + # Initialize swarm coordination + npx claude-flow@alpha swarm init --topology hierarchical + + # Store release context + echo "$PRS" > /tmp/release-prs.json + echo "$COMMITS" > /tmp/release-commits.txt + + - name: Generate Release Changelog + run: | + # Generate intelligent changelog + CHANGELOG=$(npx claude-flow@alpha github changelog \ + --prs "$(cat /tmp/release-prs.json)" \ + --commits "$(cat /tmp/release-commits.txt)" \ + --from $PREV_TAG \ + --to $RELEASE_TAG \ + --categorize \ + --add-migration-guide \ + --format markdown) + + echo "$CHANGELOG" > RELEASE_CHANGELOG.md + + - name: Build Release Artifacts + run: | + # Install dependencies + npm ci + + # Run comprehensive validation + npm run lint + npm run typecheck + npm run test:all + npm run build + + # Build platform-specific binaries + npx claude-flow@alpha github release-build \ + --platforms "linux,macos,windows" \ + --architectures "x64,arm64" \ + --parallel + + - name: Security Scan + run: | + # Run security validation + npm audit --audit-level=moderate + + npx claude-flow@alpha github release-security \ + --scan-dependencies \ + --check-secrets \ + --sign-artifacts + + - name: Create GitHub Release + run: | + # Update release with generated changelog + gh release edit ${{ github.ref_name }} \ + --notes "$(cat RELEASE_CHANGELOG.md)" \ + --draft=false + + # Upload all artifacts + for file in dist/*; do + gh release upload ${{ github.ref_name }} "$file" + done + + - name: Deploy to Package Registries + run: | + # Publish to npm + echo "//registry.npmjs.org/:_authToken=${{ secrets.NPM_TOKEN }}" > .npmrc + npm publish + + # Build and push Docker images + docker build -t ${{ github.repository }}:${{ github.ref_name }} . + docker push ${{ github.repository }}:${{ github.ref_name }} + + - name: Post-Release Validation + run: | + # Run smoke tests + npm run test:smoke + + # Validate deployment + npx claude-flow@alpha github release-validate \ + --version ${{ github.ref_name }} \ + --smoke-tests \ + --health-checks + + - name: Create Release Announcement + run: | + # Create announcement issue + gh issue create \ + --title "๐ŸŽ‰ Released ${{ github.ref_name }}" \ + --body "$(cat RELEASE_CHANGELOG.md)" \ + --label "announcement,release" + + # Notify via discussion + gh api repos/${{ github.repository }}/discussions \ + --method POST \ + -f title="Release ${{ github.ref_name }} Now Available" \ + -f body="$(cat RELEASE_CHANGELOG.md)" \ + -f category_id="$(gh api repos/${{ github.repository }}/discussions/categories --jq '.[] | select(.slug=="announcements") | .id')" + + - name: Monitor Release + run: | + # Start release monitoring + npx claude-flow@alpha github release-monitor \ + --version ${{ github.ref_name }} \ + --duration 1h \ + --alert-on-errors & +``` + +### Hotfix Workflow +```yaml +# .github/workflows/hotfix.yml +name: Emergency Hotfix Workflow +on: + issues: + types: [labeled] + +jobs: + emergency-hotfix: + if: contains(github.event.issue.labels.*.name, 'critical-hotfix') + runs-on: ubuntu-latest + + steps: + - name: Create Hotfix Branch + run: | + LAST_STABLE=$(gh release list --limit 1 --json tagName -q '.[0].tagName') + HOTFIX_VERSION=$(echo $LAST_STABLE | awk -F. '{print $1"."$2"."$3+1}') + + git checkout -b hotfix/$HOTFIX_VERSION $LAST_STABLE + + - name: Fast-Track Testing + run: | + npm ci + npm run test:critical + npm run build + + - name: Emergency Release + run: | + npx claude-flow@alpha github emergency-release \ + --issue ${{ github.event.issue.number }} \ + --severity critical \ + --fast-track \ + --notify-all +``` + +--- + +## Best Practices & Patterns + +### Release Planning Guidelines + +#### 1. Regular Release Cadence +- **Weekly**: Patch releases with bug fixes +- **Bi-weekly**: Minor releases with features +- **Quarterly**: Major releases with breaking changes +- **On-demand**: Hotfixes for critical issues + +#### 2. Feature Freeze Strategy +- Code freeze 3 days before release +- Only critical bug fixes allowed +- Beta testing period for major releases +- Stakeholder communication plan + +#### 3. Version Management Rules +- Strict semantic versioning compliance +- Breaking changes only in major versions +- Deprecation warnings one minor version ahead +- Cross-package version synchronization + +### Automation Recommendations + +#### 1. Comprehensive CI/CD Pipeline +- Automated testing at every stage +- Security scanning before release +- Performance benchmarking +- Documentation generation + +#### 2. Progressive Deployment +- Canary releases for early detection +- Staged rollouts with monitoring +- Automated health checks +- Quick rollback mechanisms + +#### 3. Monitoring & Observability +- Real-time error tracking +- Performance metrics collection +- User adoption analytics +- Feedback collection automation + +### Documentation Standards + +#### 1. Changelog Requirements +- Categorized changes by type +- Breaking changes highlighted +- Migration guides for major versions +- Contributor attribution + +#### 2. Release Notes Content +- High-level feature summaries +- Detailed technical changes +- Upgrade instructions +- Known issues and limitations + +#### 3. API Documentation +- Automated API doc generation +- Example code updates +- Deprecation notices +- Version compatibility matrix + +--- + +## Troubleshooting & Common Issues + +### Issue: Failed Release Build +```bash +# Debug build failures +npx claude-flow@alpha diagnostic-run \ + --component build \ + --verbose + +# Retry with isolated environment +docker run --rm -v $(pwd):/app node:20 \ + bash -c "cd /app && npm ci && npm run build" +``` + +### Issue: Test Failures in CI +```bash +# Run tests with detailed output +npm run test -- --verbose --coverage + +# Check for environment-specific issues +npm run test:ci + +# Compare local vs CI environment +npx claude-flow@alpha github compat-test \ + --environments "local,ci" \ + --compare +``` + +### Issue: Deployment Rollback Needed +```bash +# Immediate rollback to previous version +npx claude-flow@alpha github rollback \ + --to-version v1.9.9 \ + --reason "Critical bug in v2.0.0" \ + --preserve-data \ + --notify-users + +# Investigate rollback cause +npx claude-flow@alpha github release-analytics \ + --version v2.0.0 \ + --identify-issues +``` + +### Issue: Version Conflicts +```bash +# Check and resolve version conflicts +npx claude-flow@alpha github release-validate \ + --checks version-conflicts \ + --auto-resolve + +# Align multi-package versions +npx claude-flow@alpha github version-sync \ + --packages "package-a,package-b" \ + --strategy semantic +``` + +--- + +## Performance Metrics & Benchmarks + +### Expected Performance +- **Release Planning**: < 2 minutes +- **Build Process**: 3-8 minutes (varies by project) +- **Test Execution**: 5-15 minutes +- **Deployment**: 2-5 minutes per target +- **Complete Pipeline**: 15-30 minutes + +### Optimization Tips +1. **Parallel Execution**: Use swarm coordination for concurrent tasks +2. **Caching**: Enable build and dependency caching +3. **Incremental Builds**: Only rebuild changed components +4. **Test Optimization**: Run critical tests first, full suite in parallel + +### Success Metrics +- **Release Frequency**: Target weekly minor releases +- **Lead Time**: < 2 hours from commit to production +- **Failure Rate**: < 2% of releases require rollback +- **MTTR**: < 30 minutes for critical hotfixes + +--- + +## Related Resources + +### Documentation +- [GitHub CLI Documentation](https://cli.github.com/manual/) +- [Semantic Versioning Spec](https://semver.org/) +- [Claude Flow SPARC Guide](../../docs/sparc-methodology.md) +- [Swarm Coordination Patterns](../../docs/swarm-patterns.md) + +### Related Skills +- **github-pr-management**: PR review and merge automation +- **github-workflow-automation**: CI/CD workflow orchestration +- **multi-repo-coordination**: Cross-repository synchronization +- **deployment-orchestration**: Advanced deployment strategies + +### Support & Community +- Issues: https://github.com/ruvnet/claude-flow/issues +- Discussions: https://github.com/ruvnet/claude-flow/discussions +- Documentation: https://claude-flow.dev/docs + +--- + +## Appendix: Release Checklist Template + +### Pre-Release Checklist +- [ ] Version numbers updated across all packages +- [ ] Changelog generated and reviewed +- [ ] Breaking changes documented with migration guide +- [ ] All tests passing (unit, integration, e2e) +- [ ] Security scan completed with no critical issues +- [ ] Performance benchmarks within acceptable range +- [ ] Documentation updated (API docs, README, examples) +- [ ] Release notes drafted and reviewed +- [ ] Stakeholders notified of upcoming release +- [ ] Deployment plan reviewed and approved + +### Release Checklist +- [ ] Release branch created and validated +- [ ] CI/CD pipeline completed successfully +- [ ] Artifacts built and verified +- [ ] GitHub release created with proper notes +- [ ] Packages published to registries +- [ ] Docker images pushed to container registry +- [ ] Deployment to staging successful +- [ ] Smoke tests passing in staging +- [ ] Production deployment completed +- [ ] Health checks passing + +### Post-Release Checklist +- [ ] Release announcement published +- [ ] Monitoring dashboards reviewed +- [ ] Error rates within normal range +- [ ] Performance metrics stable +- [ ] User feedback collected +- [ ] Documentation links verified +- [ ] Release retrospective scheduled +- [ ] Next release planning initiated + +--- + +**Version**: 2.0.0 +**Last Updated**: 2025-10-19 +**Maintained By**: Claude Flow Team diff --git a/.claude/skills/github-workflow-automation/SKILL.md b/.claude/skills/github-workflow-automation/SKILL.md new file mode 100644 index 0000000000..48334d5835 --- /dev/null +++ b/.claude/skills/github-workflow-automation/SKILL.md @@ -0,0 +1,1065 @@ +--- +name: github-workflow-automation +version: 1.0.0 +category: github +description: Advanced GitHub Actions workflow automation with AI swarm coordination, intelligent CI/CD pipelines, and comprehensive repository management +tags: + - github + - github-actions + - ci-cd + - workflow-automation + - swarm-coordination + - deployment + - security +authors: + - claude-flow +requires: + - gh (GitHub CLI) + - git + - claude-flow@alpha + - node (v16+) +priority: high +progressive_disclosure: true +--- + +# GitHub Workflow Automation Skill + +## Overview + +This skill provides comprehensive GitHub Actions automation with AI swarm coordination. It integrates intelligent CI/CD pipelines, workflow orchestration, and repository management to create self-organizing, adaptive GitHub workflows. + +## Quick Start + +
+๐Ÿ’ก Basic Usage - Click to expand + +### Initialize GitHub Workflow Automation +```bash +# Start with a simple workflow +npx ruv-swarm actions generate-workflow \ + --analyze-codebase \ + --detect-languages \ + --create-optimal-pipeline +``` + +### Common Commands +```bash +# Optimize existing workflow +npx ruv-swarm actions optimize \ + --workflow ".github/workflows/ci.yml" \ + --suggest-parallelization + +# Analyze failed runs +gh run view --json jobs,conclusion | \ + npx ruv-swarm actions analyze-failure \ + --suggest-fixes +``` + +
+ +## Core Capabilities + +### ๐Ÿค– Swarm-Powered GitHub Modes + +
+Available GitHub Integration Modes + +#### 1. gh-coordinator +**GitHub workflow orchestration and coordination** +- **Coordination Mode**: Hierarchical +- **Max Parallel Operations**: 10 +- **Batch Optimized**: Yes +- **Best For**: Complex GitHub workflows, multi-repo coordination + +```bash +# Usage example +npx claude-flow@alpha github gh-coordinator \ + "Coordinate multi-repo release across 5 repositories" +``` + +#### 2. pr-manager +**Pull request management and review coordination** +- **Review Mode**: Automated +- **Multi-reviewer**: Yes +- **Conflict Resolution**: Intelligent + +```bash +# Create PR with automated review +gh pr create --title "Feature: New capability" \ + --body "Automated PR with swarm review" | \ + npx ruv-swarm actions pr-validate \ + --spawn-agents "linter,tester,security,docs" +``` + +#### 3. issue-tracker +**Issue management and project coordination** +- **Issue Workflow**: Automated +- **Label Management**: Smart +- **Progress Tracking**: Real-time + +```bash +# Create coordinated issue workflow +npx claude-flow@alpha github issue-tracker \ + "Manage sprint issues with automated tracking" +``` + +#### 4. release-manager +**Release coordination and deployment** +- **Release Pipeline**: Automated +- **Versioning**: Semantic +- **Deployment**: Multi-stage + +```bash +# Automated release management +npx claude-flow@alpha github release-manager \ + "Create v2.0.0 release with changelog and deployment" +``` + +#### 5. repo-architect +**Repository structure and organization** +- **Structure Optimization**: Yes +- **Multi-repo Support**: Yes +- **Template Management**: Advanced + +```bash +# Optimize repository structure +npx claude-flow@alpha github repo-architect \ + "Restructure monorepo with optimal organization" +``` + +#### 6. code-reviewer +**Automated code review and quality assurance** +- **Review Quality**: Deep +- **Security Analysis**: Yes +- **Performance Check**: Automated + +```bash +# Automated code review +gh pr view 123 --json files | \ + npx ruv-swarm actions pr-validate \ + --deep-review \ + --security-scan +``` + +#### 7. ci-orchestrator +**CI/CD pipeline coordination** +- **Pipeline Management**: Advanced +- **Test Coordination**: Parallel +- **Deployment**: Automated + +```bash +# Orchestrate CI/CD pipeline +npx claude-flow@alpha github ci-orchestrator \ + "Setup parallel test execution with smart caching" +``` + +#### 8. security-guardian +**Security and compliance management** +- **Security Scan**: Automated +- **Compliance Check**: Continuous +- **Vulnerability Management**: Proactive + +```bash +# Security audit +npx ruv-swarm actions security \ + --deep-scan \ + --compliance-check \ + --create-issues +``` + +
+ +### ๐Ÿ”ง Workflow Templates + +
+Production-Ready GitHub Actions Templates + +#### 1. Intelligent CI with Swarms +```yaml +# .github/workflows/swarm-ci.yml +name: Intelligent CI with Swarms +on: [push, pull_request] + +jobs: + swarm-analysis: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: Initialize Swarm + uses: ruvnet/swarm-action@v1 + with: + topology: mesh + max-agents: 6 + + - name: Analyze Changes + run: | + npx ruv-swarm actions analyze \ + --commit ${{ github.sha }} \ + --suggest-tests \ + --optimize-pipeline +``` + +#### 2. Multi-Language Detection +```yaml +# .github/workflows/polyglot-swarm.yml +name: Polyglot Project Handler +on: push + +jobs: + detect-and-build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: Detect Languages + id: detect + run: | + npx ruv-swarm actions detect-stack \ + --output json > stack.json + + - name: Dynamic Build Matrix + run: | + npx ruv-swarm actions create-matrix \ + --from stack.json \ + --parallel-builds +``` + +#### 3. Adaptive Security Scanning +```yaml +# .github/workflows/security-swarm.yml +name: Intelligent Security Scan +on: + schedule: + - cron: '0 0 * * *' + workflow_dispatch: + +jobs: + security-swarm: + runs-on: ubuntu-latest + steps: + - name: Security Analysis Swarm + run: | + SECURITY_ISSUES=$(npx ruv-swarm actions security \ + --deep-scan \ + --format json) + + echo "$SECURITY_ISSUES" | jq -r '.issues[]? | @base64' | while read -r issue; do + _jq() { + echo ${issue} | base64 --decode | jq -r ${1} + } + gh issue create \ + --title "$(_jq '.title')" \ + --body "$(_jq '.body')" \ + --label "security,critical" + done +``` + +#### 4. Self-Healing Pipeline +```yaml +# .github/workflows/self-healing.yml +name: Self-Healing Pipeline +on: workflow_run + +jobs: + heal-pipeline: + if: ${{ github.event.workflow_run.conclusion == 'failure' }} + runs-on: ubuntu-latest + steps: + - name: Diagnose and Fix + run: | + npx ruv-swarm actions self-heal \ + --run-id ${{ github.event.workflow_run.id }} \ + --auto-fix-common \ + --create-pr-complex +``` + +#### 5. Progressive Deployment +```yaml +# .github/workflows/smart-deployment.yml +name: Smart Deployment +on: + push: + branches: [main] + +jobs: + progressive-deploy: + runs-on: ubuntu-latest + steps: + - name: Analyze Risk + id: risk + run: | + npx ruv-swarm actions deploy-risk \ + --changes ${{ github.sha }} \ + --history 30d + + - name: Choose Strategy + run: | + npx ruv-swarm actions deploy-strategy \ + --risk ${{ steps.risk.outputs.level }} \ + --auto-execute +``` + +#### 6. Performance Regression Detection +```yaml +# .github/workflows/performance-guard.yml +name: Performance Guard +on: pull_request + +jobs: + perf-swarm: + runs-on: ubuntu-latest + steps: + - name: Performance Analysis + run: | + npx ruv-swarm actions perf-test \ + --baseline main \ + --threshold 10% \ + --auto-profile-regression +``` + +#### 7. PR Validation Swarm +```yaml +# .github/workflows/pr-validation.yml +name: PR Validation Swarm +on: pull_request + +jobs: + validate: + runs-on: ubuntu-latest + steps: + - name: Multi-Agent Validation + run: | + PR_DATA=$(gh pr view ${{ github.event.pull_request.number }} --json files,labels) + + RESULTS=$(npx ruv-swarm actions pr-validate \ + --spawn-agents "linter,tester,security,docs" \ + --parallel \ + --pr-data "$PR_DATA") + + gh pr comment ${{ github.event.pull_request.number }} \ + --body "$RESULTS" +``` + +#### 8. Intelligent Release +```yaml +# .github/workflows/intelligent-release.yml +name: Intelligent Release +on: + push: + tags: ['v*'] + +jobs: + release: + runs-on: ubuntu-latest + steps: + - name: Release Swarm + run: | + npx ruv-swarm actions release \ + --analyze-changes \ + --generate-notes \ + --create-artifacts \ + --publish-smart +``` + +
+ +### ๐Ÿ“Š Monitoring & Analytics + +
+Workflow Analysis & Optimization + +#### Workflow Analytics +```bash +# Analyze workflow performance +npx ruv-swarm actions analytics \ + --workflow "ci.yml" \ + --period 30d \ + --identify-bottlenecks \ + --suggest-improvements +``` + +#### Cost Optimization +```bash +# Optimize GitHub Actions costs +npx ruv-swarm actions cost-optimize \ + --analyze-usage \ + --suggest-caching \ + --recommend-self-hosted +``` + +#### Failure Pattern Analysis +```bash +# Identify failure patterns +npx ruv-swarm actions failure-patterns \ + --period 90d \ + --classify-failures \ + --suggest-preventions +``` + +#### Resource Management +```bash +# Optimize resource usage +npx ruv-swarm actions resources \ + --analyze-usage \ + --suggest-runners \ + --cost-optimize +``` + +
+ +## Advanced Features + +### ๐Ÿงช Dynamic Test Strategies + +
+Intelligent Test Selection & Execution + +#### Smart Test Selection +```yaml +# Automatically select relevant tests +- name: Swarm Test Selection + run: | + npx ruv-swarm actions smart-test \ + --changed-files ${{ steps.files.outputs.all }} \ + --impact-analysis \ + --parallel-safe +``` + +#### Dynamic Test Matrix +```yaml +# Generate test matrix from code analysis +jobs: + generate-matrix: + outputs: + matrix: ${{ steps.set-matrix.outputs.matrix }} + steps: + - id: set-matrix + run: | + MATRIX=$(npx ruv-swarm actions test-matrix \ + --detect-frameworks \ + --optimize-coverage) + echo "matrix=${MATRIX}" >> $GITHUB_OUTPUT + + test: + needs: generate-matrix + strategy: + matrix: ${{fromJson(needs.generate-matrix.outputs.matrix)}} +``` + +#### Intelligent Parallelization +```bash +# Determine optimal parallelization +npx ruv-swarm actions parallel-strategy \ + --analyze-dependencies \ + --time-estimates \ + --cost-aware +``` + +
+ +### ๐Ÿ”ฎ Predictive Analysis + +
+AI-Powered Workflow Predictions + +#### Predictive Failures +```bash +# Predict potential failures +npx ruv-swarm actions predict \ + --analyze-history \ + --identify-risks \ + --suggest-preventive +``` + +#### Workflow Recommendations +```bash +# Get workflow recommendations +npx ruv-swarm actions recommend \ + --analyze-repo \ + --suggest-workflows \ + --industry-best-practices +``` + +#### Automated Optimization +```bash +# Continuously optimize workflows +npx ruv-swarm actions auto-optimize \ + --monitor-performance \ + --apply-improvements \ + --track-savings +``` + +
+ +### ๐ŸŽฏ Custom Actions Development + +
+Build Your Own Swarm Actions + +#### Custom Swarm Action Template +```javascript +// action.yml +name: 'Swarm Custom Action' +description: 'Custom swarm-powered action' +inputs: + task: + description: 'Task for swarm' + required: true +runs: + using: 'node16' + main: 'dist/index.js' + +// index.js +const { SwarmAction } = require('ruv-swarm'); + +async function run() { + const swarm = new SwarmAction({ + topology: 'mesh', + agents: ['analyzer', 'optimizer'] + }); + + await swarm.execute(core.getInput('task')); +} + +run().catch(error => core.setFailed(error.message)); +``` + +
+ +## Integration with Claude-Flow + +### ๐Ÿ”„ Swarm Coordination Patterns + +
+MCP-Based GitHub Workflow Coordination + +#### Initialize GitHub Swarm +```javascript +// Step 1: Initialize swarm coordination +mcp__claude-flow__swarm_init { + topology: "hierarchical", + maxAgents: 8 +} + +// Step 2: Spawn specialized agents +mcp__claude-flow__agent_spawn { type: "coordinator", name: "GitHub Coordinator" } +mcp__claude-flow__agent_spawn { type: "reviewer", name: "Code Reviewer" } +mcp__claude-flow__agent_spawn { type: "tester", name: "QA Agent" } +mcp__claude-flow__agent_spawn { type: "analyst", name: "Security Analyst" } + +// Step 3: Orchestrate GitHub workflow +mcp__claude-flow__task_orchestrate { + task: "Complete PR review and merge workflow", + strategy: "parallel", + priority: "high" +} +``` + +#### GitHub Hooks Integration +```bash +# Pre-task: Setup GitHub context +npx claude-flow@alpha hooks pre-task \ + --description "PR review workflow" \ + --context "pr-123" + +# During task: Track progress +npx claude-flow@alpha hooks notify \ + --message "Completed security scan" \ + --type "github-action" + +# Post-task: Export results +npx claude-flow@alpha hooks post-task \ + --task-id "pr-review-123" \ + --export-github-summary +``` + +
+ +### ๐Ÿ“ฆ Batch Operations + +
+Concurrent GitHub Operations + +#### Parallel GitHub CLI Commands +```javascript +// Single message with all GitHub operations +[Concurrent Execution]: + Bash("gh issue create --title 'Feature A' --body 'Description A' --label 'enhancement'") + Bash("gh issue create --title 'Feature B' --body 'Description B' --label 'enhancement'") + Bash("gh pr create --title 'PR 1' --head 'feature-a' --base 'main'") + Bash("gh pr create --title 'PR 2' --head 'feature-b' --base 'main'") + Bash("gh pr checks 123 --watch") + TodoWrite { todos: [ + {content: "Review security scan results", status: "pending"}, + {content: "Merge approved PRs", status: "pending"}, + {content: "Update changelog", status: "pending"} + ]} +``` + +
+ +## Best Practices + +### ๐Ÿ—๏ธ Workflow Organization + +
+Structure Your GitHub Workflows + +#### 1. Use Reusable Workflows +```yaml +# .github/workflows/reusable-swarm.yml +name: Reusable Swarm Workflow +on: + workflow_call: + inputs: + topology: + required: true + type: string + +jobs: + swarm-task: + runs-on: ubuntu-latest + steps: + - name: Initialize Swarm + run: | + npx ruv-swarm init --topology ${{ inputs.topology }} +``` + +#### 2. Implement Proper Caching +```yaml +- name: Cache Swarm Dependencies + uses: actions/cache@v3 + with: + path: ~/.npm + key: ${{ runner.os }}-swarm-${{ hashFiles('**/package-lock.json') }} +``` + +#### 3. Set Appropriate Timeouts +```yaml +jobs: + swarm-task: + timeout-minutes: 30 + steps: + - name: Swarm Operation + timeout-minutes: 10 +``` + +#### 4. Use Workflow Dependencies +```yaml +jobs: + setup: + runs-on: ubuntu-latest + + test: + needs: setup + runs-on: ubuntu-latest + + deploy: + needs: [setup, test] + runs-on: ubuntu-latest +``` + +
+ +### ๐Ÿ”’ Security Best Practices + +
+Secure Your GitHub Workflows + +#### 1. Store Configurations Securely +```yaml +- name: Setup Swarm + env: + SWARM_CONFIG: ${{ secrets.SWARM_CONFIG }} + API_KEY: ${{ secrets.API_KEY }} + run: | + npx ruv-swarm init --config "$SWARM_CONFIG" +``` + +#### 2. Use OIDC Authentication +```yaml +permissions: + id-token: write + contents: read + +- name: Configure AWS Credentials + uses: aws-actions/configure-aws-credentials@v2 + with: + role-to-assume: arn:aws:iam::123456789012:role/GitHubAction + aws-region: us-east-1 +``` + +#### 3. Implement Least-Privilege +```yaml +permissions: + contents: read + pull-requests: write + issues: write +``` + +#### 4. Audit Swarm Operations +```yaml +- name: Audit Swarm Actions + run: | + npx ruv-swarm actions audit \ + --export-logs \ + --compliance-report +``` + +
+ +### โšก Performance Optimization + +
+Maximize Workflow Performance + +#### 1. Cache Swarm Dependencies +```yaml +- uses: actions/cache@v3 + with: + path: | + ~/.npm + node_modules + key: ${{ runner.os }}-swarm-${{ hashFiles('**/package-lock.json') }} +``` + +#### 2. Use Appropriate Runner Sizes +```yaml +jobs: + heavy-task: + runs-on: ubuntu-latest-4-cores + steps: + - name: Intensive Swarm Operation +``` + +#### 3. Implement Early Termination +```yaml +- name: Quick Fail Check + run: | + if ! npx ruv-swarm actions pre-check; then + echo "Pre-check failed, terminating early" + exit 1 + fi +``` + +#### 4. Optimize Parallel Execution +```yaml +strategy: + matrix: + include: + - runner: ubuntu-latest + task: test + - runner: ubuntu-latest + task: lint + - runner: ubuntu-latest + task: security + max-parallel: 3 +``` + +
+ +## Debugging & Troubleshooting + +### ๐Ÿ› Debug Tools + +
+Debug GitHub Workflow Issues + +#### Debug Mode +```yaml +- name: Debug Swarm + run: | + npx ruv-swarm actions debug \ + --verbose \ + --trace-agents \ + --export-logs + env: + ACTIONS_STEP_DEBUG: true +``` + +#### Performance Profiling +```bash +# Profile workflow performance +npx ruv-swarm actions profile \ + --workflow "ci.yml" \ + --identify-slow-steps \ + --suggest-optimizations +``` + +#### Failure Analysis +```bash +# Analyze failed runs +gh run view --json jobs,conclusion | \ + npx ruv-swarm actions analyze-failure \ + --suggest-fixes \ + --auto-retry-flaky +``` + +#### Log Analysis +```bash +# Download and analyze logs +gh run download +npx ruv-swarm actions analyze-logs \ + --directory ./logs \ + --identify-errors +``` + +
+ +## Real-World Examples + +### ๐Ÿš€ Complete Workflows + +
+Production-Ready Integration Examples + +#### Example 1: Full-Stack Application CI/CD +```yaml +name: Full-Stack CI/CD with Swarms +on: + push: + branches: [main, develop] + pull_request: + +jobs: + initialize: + runs-on: ubuntu-latest + outputs: + swarm-id: ${{ steps.init.outputs.swarm-id }} + steps: + - id: init + run: | + SWARM_ID=$(npx ruv-swarm init --topology mesh --output json | jq -r '.id') + echo "swarm-id=${SWARM_ID}" >> $GITHUB_OUTPUT + + backend: + needs: initialize + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Backend Tests + run: | + npx ruv-swarm agents spawn --type tester \ + --task "Run backend test suite" \ + --swarm-id ${{ needs.initialize.outputs.swarm-id }} + + frontend: + needs: initialize + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Frontend Tests + run: | + npx ruv-swarm agents spawn --type tester \ + --task "Run frontend test suite" \ + --swarm-id ${{ needs.initialize.outputs.swarm-id }} + + security: + needs: initialize + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Security Scan + run: | + npx ruv-swarm agents spawn --type security \ + --task "Security audit" \ + --swarm-id ${{ needs.initialize.outputs.swarm-id }} + + deploy: + needs: [backend, frontend, security] + if: github.ref == 'refs/heads/main' + runs-on: ubuntu-latest + steps: + - name: Deploy + run: | + npx ruv-swarm actions deploy \ + --strategy progressive \ + --swarm-id ${{ needs.initialize.outputs.swarm-id }} +``` + +#### Example 2: Monorepo Management +```yaml +name: Monorepo Coordination +on: push + +jobs: + detect-changes: + runs-on: ubuntu-latest + outputs: + packages: ${{ steps.detect.outputs.packages }} + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 + + - id: detect + run: | + PACKAGES=$(npx ruv-swarm actions detect-changes \ + --monorepo \ + --output json) + echo "packages=${PACKAGES}" >> $GITHUB_OUTPUT + + build-packages: + needs: detect-changes + runs-on: ubuntu-latest + strategy: + matrix: + package: ${{ fromJson(needs.detect-changes.outputs.packages) }} + steps: + - name: Build Package + run: | + npx ruv-swarm actions build \ + --package ${{ matrix.package }} \ + --parallel-deps +``` + +#### Example 3: Multi-Repo Synchronization +```bash +# Synchronize multiple repositories +npx claude-flow@alpha github sync-coordinator \ + "Synchronize version updates across: + - github.com/org/repo-a + - github.com/org/repo-b + - github.com/org/repo-c + + Update dependencies, align versions, create PRs" +``` + +
+ +## Command Reference + +### ๐Ÿ“š Quick Command Guide + +
+All Available Commands + +#### Workflow Generation +```bash +npx ruv-swarm actions generate-workflow [options] + --analyze-codebase Analyze repository structure + --detect-languages Detect programming languages + --create-optimal-pipeline Generate optimized workflow +``` + +#### Optimization +```bash +npx ruv-swarm actions optimize [options] + --workflow Path to workflow file + --suggest-parallelization Suggest parallel execution + --reduce-redundancy Remove redundant steps + --estimate-savings Estimate time/cost savings +``` + +#### Analysis +```bash +npx ruv-swarm actions analyze [options] + --commit Analyze specific commit + --suggest-tests Suggest test improvements + --optimize-pipeline Optimize pipeline structure +``` + +#### Testing +```bash +npx ruv-swarm actions smart-test [options] + --changed-files Files that changed + --impact-analysis Analyze test impact + --parallel-safe Only parallel-safe tests +``` + +#### Security +```bash +npx ruv-swarm actions security [options] + --deep-scan Deep security analysis + --format Output format (json/text) + --create-issues Auto-create GitHub issues +``` + +#### Deployment +```bash +npx ruv-swarm actions deploy [options] + --strategy Deployment strategy + --risk Risk assessment level + --auto-execute Execute automatically +``` + +#### Monitoring +```bash +npx ruv-swarm actions analytics [options] + --workflow Workflow to analyze + --period Analysis period + --identify-bottlenecks Find bottlenecks + --suggest-improvements Improvement suggestions +``` + +
+ +## Integration Checklist + +### โœ… Setup Verification + +
+Verify Your Setup + +- [ ] GitHub CLI (`gh`) installed and authenticated +- [ ] Git configured with user credentials +- [ ] Node.js v16+ installed +- [ ] `claude-flow@alpha` package available +- [ ] Repository has `.github/workflows` directory +- [ ] GitHub Actions enabled on repository +- [ ] Necessary secrets configured +- [ ] Runner permissions verified + +#### Quick Setup Script +```bash +#!/bin/bash +# setup-github-automation.sh + +# Install dependencies +npm install -g claude-flow@alpha + +# Verify GitHub CLI +gh auth status || gh auth login + +# Create workflow directory +mkdir -p .github/workflows + +# Generate initial workflow +npx ruv-swarm actions generate-workflow \ + --analyze-codebase \ + --create-optimal-pipeline > .github/workflows/ci.yml + +echo "โœ… GitHub workflow automation setup complete" +``` + +
+ +## Related Skills + +- `github-pr-enhancement` - Advanced PR management +- `release-coordination` - Release automation +- `swarm-coordination` - Multi-agent orchestration +- `ci-cd-optimization` - Pipeline optimization + +## Support & Documentation + +- **GitHub CLI Docs**: https://cli.github.com/manual/ +- **GitHub Actions**: https://docs.github.com/en/actions +- **Claude-Flow**: https://github.com/ruvnet/claude-flow +- **Ruv-Swarm**: https://github.com/ruvnet/ruv-swarm + +## Version History + +- **v1.0.0** (2025-01-19): Initial skill consolidation + - Merged workflow-automation.md (441 lines) + - Merged github-modes.md (146 lines) + - Added progressive disclosure + - Enhanced with swarm coordination patterns + - Added comprehensive examples and best practices + +--- + +**Skill Status**: โœ… Production Ready +**Last Updated**: 2025-01-19 +**Maintainer**: claude-flow team diff --git a/.claude/skills/github/SKILL.md b/.claude/skills/github/SKILL.md new file mode 100644 index 0000000000..03b2a00336 --- /dev/null +++ b/.claude/skills/github/SKILL.md @@ -0,0 +1,47 @@ +--- +name: github +description: "Interact with GitHub using the `gh` CLI. Use `gh issue`, `gh pr`, `gh run`, and `gh api` for issues, PRs, CI runs, and advanced queries." +--- + +# GitHub Skill + +Use the `gh` CLI to interact with GitHub. Always specify `--repo owner/repo` when not in a git directory, or use URLs directly. + +## Pull Requests + +Check CI status on a PR: +```bash +gh pr checks 55 --repo owner/repo +``` + +List recent workflow runs: +```bash +gh run list --repo owner/repo --limit 10 +``` + +View a run and see which steps failed: +```bash +gh run view --repo owner/repo +``` + +View logs for failed steps only: +```bash +gh run view --repo owner/repo --log-failed +``` + +## API for Advanced Queries + +The `gh api` command is useful for accessing data not available through other subcommands. + +Get PR with specific fields: +```bash +gh api repos/owner/repo/pulls/55 --jq '.title, .state, .user.login' +``` + +## JSON Output + +Most commands support `--json` for structured output. You can use `--jq` to filter: + +```bash +gh issue list --repo owner/repo --json number,title --jq '.[] | "\(.number): \(.title)"' +``` diff --git a/.claude/skills/gog/SKILL.md b/.claude/skills/gog/SKILL.md new file mode 100644 index 0000000000..d7c448e2cd --- /dev/null +++ b/.claude/skills/gog/SKILL.md @@ -0,0 +1,36 @@ +--- +name: gog +description: Google Workspace CLI for Gmail, Calendar, Drive, Contacts, Sheets, and Docs. +homepage: https://gogcli.sh +metadata: {"zee":{"emoji":"๐ŸŽฎ","requires":{"bins":["gog"]},"install":[{"id":"brew","kind":"brew","formula":"steipete/tap/gogcli","bins":["gog"],"label":"Install gog (brew)"}]}} +--- + +# gog + +Use `gog` for Gmail/Calendar/Drive/Contacts/Sheets/Docs. Requires OAuth setup. + +Setup (once) +- `gog auth credentials /path/to/client_secret.json` +- `gog auth add you@gmail.com --services gmail,calendar,drive,contacts,sheets,docs` +- `gog auth list` + +Common commands +- Gmail search: `gog gmail search 'newer_than:7d' --max 10` +- Gmail send: `gog gmail send --to a@b.com --subject "Hi" --body "Hello"` +- Calendar: `gog calendar events --from --to ` +- Drive search: `gog drive search "query" --max 10` +- Contacts: `gog contacts list --max 20` +- Sheets get: `gog sheets get "Tab!A1:D10" --json` +- Sheets update: `gog sheets update "Tab!A1:B2" --values-json '[["A","B"],["1","2"]]' --input USER_ENTERED` +- Sheets append: `gog sheets append "Tab!A:C" --values-json '[["x","y","z"]]' --insert INSERT_ROWS` +- Sheets clear: `gog sheets clear "Tab!A2:Z"` +- Sheets metadata: `gog sheets metadata --json` +- Docs export: `gog docs export --format txt --out /tmp/doc.txt` +- Docs cat: `gog docs cat ` + +Notes +- Set `GOG_ACCOUNT=you@gmail.com` to avoid repeating `--account`. +- For scripting, prefer `--json` plus `--no-input`. +- Sheets values can be passed via `--values-json` (recommended) or as inline rows. +- Docs supports export/cat/copy. In-place edits require a Docs API client (not in gog). +- Confirm before sending mail or creating events. diff --git a/.claude/skills/goplaces/SKILL.md b/.claude/skills/goplaces/SKILL.md new file mode 100644 index 0000000000..862f0b6cf8 --- /dev/null +++ b/.claude/skills/goplaces/SKILL.md @@ -0,0 +1,30 @@ +--- +name: goplaces +description: Query Google Places API (New) via the goplaces CLI for text search, place details, resolve, and reviews. Use for human-friendly place lookup or JSON output for scripts. +homepage: https://github.com/steipete/goplaces +metadata: {"zee":{"emoji":"๐Ÿ“","requires":{"bins":["goplaces"],"env":["GOOGLE_PLACES_API_KEY"]},"primaryEnv":"GOOGLE_PLACES_API_KEY","install":[{"id":"brew","kind":"brew","formula":"steipete/tap/goplaces","bins":["goplaces"],"label":"Install goplaces (brew)"}]}} +--- + +# goplaces + +Modern Google Places API (New) CLI. Human output by default, `--json` for scripts. + +Install +- Homebrew: `brew install steipete/tap/goplaces` + +Config +- `GOOGLE_PLACES_API_KEY` required. +- Optional: `GOOGLE_PLACES_BASE_URL` for testing/proxying. + +Common commands +- Search: `goplaces search "coffee" --open-now --min-rating 4 --limit 5` +- Bias: `goplaces search "pizza" --lat 40.8 --lng -73.9 --radius-m 3000` +- Pagination: `goplaces search "pizza" --page-token "NEXT_PAGE_TOKEN"` +- Resolve: `goplaces resolve "Soho, London" --limit 5` +- Details: `goplaces details --reviews` +- JSON: `goplaces search "sushi" --json` + +Notes +- `--no-color` or `NO_COLOR` disables ANSI color. +- Price levels: 0..4 (free โ†’ very expensive). +- Type filter sends only the first `--type` value (API accepts one). diff --git a/.claude/skills/himalaya/SKILL.md b/.claude/skills/himalaya/SKILL.md new file mode 100644 index 0000000000..df1392c163 --- /dev/null +++ b/.claude/skills/himalaya/SKILL.md @@ -0,0 +1,217 @@ +--- +name: himalaya +description: "CLI to manage emails via IMAP/SMTP. Use `himalaya` to list, read, write, reply, forward, search, and organize emails from the terminal. Supports multiple accounts and message composition with MML (MIME Meta Language)." +homepage: https://github.com/pimalaya/himalaya +metadata: {"zee":{"emoji":"๐Ÿ“ง","requires":{"bins":["himalaya"]},"install":[{"id":"brew","kind":"brew","formula":"himalaya","bins":["himalaya"],"label":"Install Himalaya (brew)"}]}} +--- + +# Himalaya Email CLI + +Himalaya is a CLI email client that lets you manage emails from the terminal using IMAP, SMTP, Notmuch, or Sendmail backends. + +## References + +- `references/configuration.md` (config file setup + IMAP/SMTP authentication) +- `references/message-composition.md` (MML syntax for composing emails) + +## Prerequisites + +1. Himalaya CLI installed (`himalaya --version` to verify) +2. A configuration file at `~/.config/himalaya/config.toml` +3. IMAP/SMTP credentials configured (password stored securely) + +## Configuration Setup + +Run the interactive wizard to set up an account: +```bash +himalaya account configure +``` + +Or create `~/.config/himalaya/config.toml` manually: +```toml +[accounts.personal] +email = "you@example.com" +display-name = "Your Name" +default = true + +backend.type = "imap" +backend.host = "imap.example.com" +backend.port = 993 +backend.encryption.type = "tls" +backend.login = "you@example.com" +backend.auth.type = "password" +backend.auth.cmd = "pass show email/imap" # or use keyring + +message.send.backend.type = "smtp" +message.send.backend.host = "smtp.example.com" +message.send.backend.port = 587 +message.send.backend.encryption.type = "start-tls" +message.send.backend.login = "you@example.com" +message.send.backend.auth.type = "password" +message.send.backend.auth.cmd = "pass show email/smtp" +``` + +## Common Operations + +### List Folders + +```bash +himalaya folder list +``` + +### List Emails + +List emails in INBOX (default): +```bash +himalaya envelope list +``` + +List emails in a specific folder: +```bash +himalaya envelope list --folder "Sent" +``` + +List with pagination: +```bash +himalaya envelope list --page 1 --page-size 20 +``` + +### Search Emails + +```bash +himalaya envelope list from john@example.com subject meeting +``` + +### Read an Email + +Read email by ID (shows plain text): +```bash +himalaya message read 42 +``` + +Export raw MIME: +```bash +himalaya message export 42 --full +``` + +### Reply to an Email + +Interactive reply (opens $EDITOR): +```bash +himalaya message reply 42 +``` + +Reply-all: +```bash +himalaya message reply 42 --all +``` + +### Forward an Email + +```bash +himalaya message forward 42 +``` + +### Write a New Email + +Interactive compose (opens $EDITOR): +```bash +himalaya message write +``` + +Send directly using template: +```bash +cat << 'EOF' | himalaya template send +From: you@example.com +To: recipient@example.com +Subject: Test Message + +Hello from Himalaya! +EOF +``` + +Or with headers flag: +```bash +himalaya message write -H "To:recipient@example.com" -H "Subject:Test" "Message body here" +``` + +### Move/Copy Emails + +Move to folder: +```bash +himalaya message move 42 "Archive" +``` + +Copy to folder: +```bash +himalaya message copy 42 "Important" +``` + +### Delete an Email + +```bash +himalaya message delete 42 +``` + +### Manage Flags + +Add flag: +```bash +himalaya flag add 42 --flag seen +``` + +Remove flag: +```bash +himalaya flag remove 42 --flag seen +``` + +## Multiple Accounts + +List accounts: +```bash +himalaya account list +``` + +Use a specific account: +```bash +himalaya --account work envelope list +``` + +## Attachments + +Save attachments from a message: +```bash +himalaya attachment download 42 +``` + +Save to specific directory: +```bash +himalaya attachment download 42 --dir ~/Downloads +``` + +## Output Formats + +Most commands support `--output` for structured output: +```bash +himalaya envelope list --output json +himalaya envelope list --output plain +``` + +## Debugging + +Enable debug logging: +```bash +RUST_LOG=debug himalaya envelope list +``` + +Full trace with backtrace: +```bash +RUST_LOG=trace RUST_BACKTRACE=1 himalaya envelope list +``` + +## Tips + +- Use `himalaya --help` or `himalaya --help` for detailed usage. +- Message IDs are relative to the current folder; re-list after folder changes. +- For composing rich emails with attachments, use MML syntax (see `references/message-composition.md`). +- Store passwords securely using `pass`, system keyring, or a command that outputs the password. diff --git a/.claude/skills/himalaya/references/configuration.md b/.claude/skills/himalaya/references/configuration.md new file mode 100644 index 0000000000..0150492033 --- /dev/null +++ b/.claude/skills/himalaya/references/configuration.md @@ -0,0 +1,174 @@ +# Himalaya Configuration Reference + +Configuration file location: `~/.config/himalaya/config.toml` + +## Minimal IMAP + SMTP Setup + +```toml +[accounts.default] +email = "user@example.com" +display-name = "Your Name" +default = true + +# IMAP backend for reading emails +backend.type = "imap" +backend.host = "imap.example.com" +backend.port = 993 +backend.encryption.type = "tls" +backend.login = "user@example.com" +backend.auth.type = "password" +backend.auth.raw = "your-password" + +# SMTP backend for sending emails +message.send.backend.type = "smtp" +message.send.backend.host = "smtp.example.com" +message.send.backend.port = 587 +message.send.backend.encryption.type = "start-tls" +message.send.backend.login = "user@example.com" +message.send.backend.auth.type = "password" +message.send.backend.auth.raw = "your-password" +``` + +## Password Options + +### Raw password (testing only, not recommended) +```toml +backend.auth.raw = "your-password" +``` + +### Password from command (recommended) +```toml +backend.auth.cmd = "pass show email/imap" +# backend.auth.cmd = "security find-generic-password -a user@example.com -s imap -w" +``` + +### System keyring (requires keyring feature) +```toml +backend.auth.keyring = "imap-example" +``` +Then run `himalaya account configure ` to store the password. + +## Gmail Configuration + +```toml +[accounts.gmail] +email = "you@gmail.com" +display-name = "Your Name" +default = true + +backend.type = "imap" +backend.host = "imap.gmail.com" +backend.port = 993 +backend.encryption.type = "tls" +backend.login = "you@gmail.com" +backend.auth.type = "password" +backend.auth.cmd = "pass show google/app-password" + +message.send.backend.type = "smtp" +message.send.backend.host = "smtp.gmail.com" +message.send.backend.port = 587 +message.send.backend.encryption.type = "start-tls" +message.send.backend.login = "you@gmail.com" +message.send.backend.auth.type = "password" +message.send.backend.auth.cmd = "pass show google/app-password" +``` + +**Note:** Gmail requires an App Password if 2FA is enabled. + +## iCloud Configuration + +```toml +[accounts.icloud] +email = "you@icloud.com" +display-name = "Your Name" + +backend.type = "imap" +backend.host = "imap.mail.me.com" +backend.port = 993 +backend.encryption.type = "tls" +backend.login = "you@icloud.com" +backend.auth.type = "password" +backend.auth.cmd = "pass show icloud/app-password" + +message.send.backend.type = "smtp" +message.send.backend.host = "smtp.mail.me.com" +message.send.backend.port = 587 +message.send.backend.encryption.type = "start-tls" +message.send.backend.login = "you@icloud.com" +message.send.backend.auth.type = "password" +message.send.backend.auth.cmd = "pass show icloud/app-password" +``` + +**Note:** Generate an app-specific password at appleid.apple.com + +## Folder Aliases + +Map custom folder names: +```toml +[accounts.default.folder.alias] +inbox = "INBOX" +sent = "Sent" +drafts = "Drafts" +trash = "Trash" +``` + +## Multiple Accounts + +```toml +[accounts.personal] +email = "personal@example.com" +default = true +# ... backend config ... + +[accounts.work] +email = "work@company.com" +# ... backend config ... +``` + +Switch accounts with `--account`: +```bash +himalaya --account work envelope list +``` + +## Notmuch Backend (local mail) + +```toml +[accounts.local] +email = "user@example.com" + +backend.type = "notmuch" +backend.db-path = "~/.mail/.notmuch" +``` + +## OAuth2 Authentication (for providers that support it) + +```toml +backend.auth.type = "oauth2" +backend.auth.client-id = "your-client-id" +backend.auth.client-secret.cmd = "pass show oauth/client-secret" +backend.auth.access-token.cmd = "pass show oauth/access-token" +backend.auth.refresh-token.cmd = "pass show oauth/refresh-token" +backend.auth.auth-url = "https://provider.com/oauth/authorize" +backend.auth.token-url = "https://provider.com/oauth/token" +``` + +## Additional Options + +### Signature +```toml +[accounts.default] +signature = "Best regards,\nYour Name" +signature-delim = "-- \n" +``` + +### Downloads directory +```toml +[accounts.default] +downloads-dir = "~/Downloads/himalaya" +``` + +### Editor for composing +Set via environment variable: +```bash +export EDITOR="vim" +``` diff --git a/.claude/skills/himalaya/references/message-composition.md b/.claude/skills/himalaya/references/message-composition.md new file mode 100644 index 0000000000..17e40ef371 --- /dev/null +++ b/.claude/skills/himalaya/references/message-composition.md @@ -0,0 +1,182 @@ +# Message Composition with MML (MIME Meta Language) + +Himalaya uses MML for composing emails. MML is a simple XML-based syntax that compiles to MIME messages. + +## Basic Message Structure + +An email message is a list of **headers** followed by a **body**, separated by a blank line: + +``` +From: sender@example.com +To: recipient@example.com +Subject: Hello World + +This is the message body. +``` + +## Headers + +Common headers: +- `From`: Sender address +- `To`: Primary recipient(s) +- `Cc`: Carbon copy recipients +- `Bcc`: Blind carbon copy recipients +- `Subject`: Message subject +- `Reply-To`: Address for replies (if different from From) +- `In-Reply-To`: Message ID being replied to + +### Address Formats + +``` +To: user@example.com +To: John Doe +To: "John Doe" +To: user1@example.com, user2@example.com, "Jane" +``` + +## Plain Text Body + +Simple plain text email: +``` +From: alice@localhost +To: bob@localhost +Subject: Plain Text Example + +Hello, this is a plain text email. +No special formatting needed. + +Best, +Alice +``` + +## MML for Rich Emails + +### Multipart Messages + +Alternative text/html parts: +``` +From: alice@localhost +To: bob@localhost +Subject: Multipart Example + +<#multipart type=alternative> +This is the plain text version. +<#part type=text/html> +

This is the HTML version

+<#/multipart> +``` + +### Attachments + +Attach a file: +``` +From: alice@localhost +To: bob@localhost +Subject: With Attachment + +Here is the document you requested. + +<#part filename=/path/to/document.pdf><#/part> +``` + +Attachment with custom name: +``` +<#part filename=/path/to/file.pdf name=report.pdf><#/part> +``` + +Multiple attachments: +``` +<#part filename=/path/to/doc1.pdf><#/part> +<#part filename=/path/to/doc2.pdf><#/part> +``` + +### Inline Images + +Embed an image inline: +``` +From: alice@localhost +To: bob@localhost +Subject: Inline Image + +<#multipart type=related> +<#part type=text/html> + +

Check out this image:

+ + +<#part disposition=inline id=image1 filename=/path/to/image.png><#/part> +<#/multipart> +``` + +### Mixed Content (Text + Attachments) + +``` +From: alice@localhost +To: bob@localhost +Subject: Mixed Content + +<#multipart type=mixed> +<#part type=text/plain> +Please find the attached files. + +Best, +Alice +<#part filename=/path/to/file1.pdf><#/part> +<#part filename=/path/to/file2.zip><#/part> +<#/multipart> +``` + +## MML Tag Reference + +### `<#multipart>` +Groups multiple parts together. +- `type=alternative`: Different representations of same content +- `type=mixed`: Independent parts (text + attachments) +- `type=related`: Parts that reference each other (HTML + images) + +### `<#part>` +Defines a message part. +- `type=`: Content type (e.g., `text/html`, `application/pdf`) +- `filename=`: File to attach +- `name=`: Display name for attachment +- `disposition=inline`: Display inline instead of as attachment +- `id=`: Content ID for referencing in HTML + +## Composing from CLI + +### Interactive compose +Opens your `$EDITOR`: +```bash +himalaya message write +``` + +### Reply (opens editor with quoted message) +```bash +himalaya message reply 42 +himalaya message reply 42 --all # reply-all +``` + +### Forward +```bash +himalaya message forward 42 +``` + +### Send from stdin +```bash +cat message.txt | himalaya template send +``` + +### Prefill headers from CLI +```bash +himalaya message write \ + -H "To:recipient@example.com" \ + -H "Subject:Quick Message" \ + "Message body here" +``` + +## Tips + +- The editor opens with a template; fill in headers and body. +- Save and exit the editor to send; exit without saving to cancel. +- MML parts are compiled to proper MIME when sending. +- Use `himalaya message export --full` to inspect the raw MIME structure of received emails. diff --git a/.claude/skills/hive-mind-advanced/SKILL.md b/.claude/skills/hive-mind-advanced/SKILL.md new file mode 100644 index 0000000000..5e48baba45 --- /dev/null +++ b/.claude/skills/hive-mind-advanced/SKILL.md @@ -0,0 +1,712 @@ +--- +name: hive-mind-advanced +description: Advanced Hive Mind collective intelligence system for queen-led multi-agent coordination with consensus mechanisms and persistent memory +version: 1.0.0 +category: coordination +tags: [hive-mind, swarm, queen-worker, consensus, collective-intelligence, multi-agent, coordination] +author: Claude Flow Team +--- + +# Hive Mind Advanced Skill + +Master the advanced Hive Mind collective intelligence system for sophisticated multi-agent coordination using queen-led architecture, Byzantine consensus, and collective memory. + +## Overview + +The Hive Mind system represents the pinnacle of multi-agent coordination in Claude Flow, implementing a queen-led hierarchical architecture where a strategic queen coordinator directs specialized worker agents through collective decision-making and shared memory. + +## Core Concepts + +### Architecture Patterns + +**Queen-Led Coordination** +- Strategic queen agents orchestrate high-level objectives +- Tactical queens manage mid-level execution +- Adaptive queens dynamically adjust strategies based on performance + +**Worker Specialization** +- Researcher agents: Analysis and investigation +- Coder agents: Implementation and development +- Analyst agents: Data processing and metrics +- Tester agents: Quality assurance and validation +- Architect agents: System design and planning +- Reviewer agents: Code review and improvement +- Optimizer agents: Performance enhancement +- Documenter agents: Documentation generation + +**Collective Memory System** +- Shared knowledge base across all agents +- LRU cache with memory pressure handling +- SQLite persistence with WAL mode +- Memory consolidation and association +- Access pattern tracking and optimization + +### Consensus Mechanisms + +**Majority Consensus** +Simple voting where the option with most votes wins. + +**Weighted Consensus** +Queen vote counts as 3x weight, providing strategic guidance. + +**Byzantine Fault Tolerance** +Requires 2/3 majority for decision approval, ensuring robust consensus even with faulty agents. + +## Getting Started + +### 1. Initialize Hive Mind + +```bash +# Basic initialization +npx claude-flow hive-mind init + +# Force reinitialize +npx claude-flow hive-mind init --force + +# Custom configuration +npx claude-flow hive-mind init --config hive-config.json +``` + +### 2. Spawn a Swarm + +```bash +# Basic spawn with objective +npx claude-flow hive-mind spawn "Build microservices architecture" + +# Strategic queen type +npx claude-flow hive-mind spawn "Research AI patterns" --queen-type strategic + +# Tactical queen with max workers +npx claude-flow hive-mind spawn "Implement API" --queen-type tactical --max-workers 12 + +# Adaptive queen with consensus +npx claude-flow hive-mind spawn "Optimize system" --queen-type adaptive --consensus byzantine + +# Generate Claude Code commands +npx claude-flow hive-mind spawn "Build full-stack app" --claude +``` + +### 3. Monitor Status + +```bash +# Check hive mind status +npx claude-flow hive-mind status + +# Get detailed metrics +npx claude-flow hive-mind metrics + +# Monitor collective memory +npx claude-flow hive-mind memory +``` + +## Advanced Workflows + +### Session Management + +**Create and Manage Sessions** + +```bash +# List active sessions +npx claude-flow hive-mind sessions + +# Pause a session +npx claude-flow hive-mind pause + +# Resume a paused session +npx claude-flow hive-mind resume + +# Stop a running session +npx claude-flow hive-mind stop +``` + +**Session Features** +- Automatic checkpoint creation +- Progress tracking with completion percentages +- Parent-child process management +- Session logs with event tracking +- Export/import capabilities + +### Consensus Building + +The Hive Mind builds consensus through structured voting: + +```javascript +// Programmatic consensus building +const decision = await hiveMind.buildConsensus( + 'Architecture pattern selection', + ['microservices', 'monolith', 'serverless'] +); + +// Result includes: +// - decision: Winning option +// - confidence: Vote percentage +// - votes: Individual agent votes +``` + +**Consensus Algorithms** + +1. **Majority** - Simple democratic voting +2. **Weighted** - Queen has 3x voting power +3. **Byzantine** - 2/3 supermajority required + +### Collective Memory + +**Storing Knowledge** + +```javascript +// Store in collective memory +await memory.store('api-patterns', { + rest: { pros: [...], cons: [...] }, + graphql: { pros: [...], cons: [...] } +}, 'knowledge', { confidence: 0.95 }); +``` + +**Memory Types** +- `knowledge`: Permanent insights (no TTL) +- `context`: Session context (1 hour TTL) +- `task`: Task-specific data (30 min TTL) +- `result`: Execution results (permanent, compressed) +- `error`: Error logs (24 hour TTL) +- `metric`: Performance metrics (1 hour TTL) +- `consensus`: Decision records (permanent) +- `system`: System configuration (permanent) + +**Searching and Retrieval** + +```javascript +// Search memory by pattern +const results = await memory.search('api*', { + type: 'knowledge', + minConfidence: 0.8, + limit: 50 +}); + +// Get related memories +const related = await memory.getRelated('api-patterns', 10); + +// Build associations +await memory.associate('rest-api', 'authentication', 0.9); +``` + +### Task Distribution + +**Automatic Worker Assignment** + +The system intelligently assigns tasks based on: +- Keyword matching with agent specialization +- Historical performance metrics +- Worker availability and load +- Task complexity analysis + +```javascript +// Create task (auto-assigned) +const task = await hiveMind.createTask( + 'Implement user authentication', + priority: 8, + { estimatedDuration: 30000 } +); +``` + +**Auto-Scaling** + +```javascript +// Configure auto-scaling +const config = { + autoScale: true, + maxWorkers: 12, + scaleUpThreshold: 2, // Pending tasks per idle worker + scaleDownThreshold: 2 // Idle workers above pending tasks +}; +``` + +## Integration Patterns + +### With Claude Code + +Generate Claude Code spawn commands directly: + +```bash +npx claude-flow hive-mind spawn "Build REST API" --claude +``` + +Output: +```javascript +Task("Queen Coordinator", "Orchestrate REST API development...", "coordinator") +Task("Backend Developer", "Implement Express routes...", "backend-dev") +Task("Database Architect", "Design PostgreSQL schema...", "code-analyzer") +Task("Test Engineer", "Create Jest test suite...", "tester") +``` + +### With SPARC Methodology + +```bash +# Use hive mind for SPARC workflow +npx claude-flow sparc tdd "User authentication" --hive-mind + +# Spawns: +# - Specification agent +# - Architecture agent +# - Coder agents +# - Tester agents +# - Reviewer agents +``` + +### With GitHub Integration + +```bash +# Repository analysis with hive mind +npx claude-flow hive-mind spawn "Analyze repo quality" --objective "owner/repo" + +# PR review coordination +npx claude-flow hive-mind spawn "Review PR #123" --queen-type tactical +``` + +## Performance Optimization + +### Memory Optimization + +The collective memory system includes advanced optimizations: + +**LRU Cache** +- Configurable cache size (default: 1000 entries) +- Memory pressure handling (default: 50MB) +- Automatic eviction of least-used entries + +**Database Optimization** +- WAL (Write-Ahead Logging) mode +- 64MB cache size +- 256MB memory mapping +- Prepared statements for common queries +- Automatic ANALYZE and OPTIMIZE + +**Object Pooling** +- Query result pooling +- Memory entry pooling +- Reduced garbage collection pressure + +### Performance Metrics + +```javascript +// Get performance insights +const insights = hiveMind.getPerformanceInsights(); + +// Includes: +// - asyncQueue utilization +// - Batch processing stats +// - Success rates +// - Average processing times +// - Memory efficiency +``` + +### Task Execution + +**Parallel Processing** +- Batch agent spawning (5 agents per batch) +- Concurrent task orchestration +- Async operation optimization +- Non-blocking task assignment + +**Benchmarks** +- 10-20x faster batch spawning +- 2.8-4.4x speed improvement overall +- 32.3% token reduction +- 84.8% SWE-Bench solve rate + +## Configuration + +### Hive Mind Config + +```javascript +{ + "objective": "Build microservices", + "name": "my-hive", + "queenType": "strategic", // strategic | tactical | adaptive + "maxWorkers": 8, + "consensusAlgorithm": "byzantine", // majority | weighted | byzantine + "autoScale": true, + "memorySize": 100, // MB + "taskTimeout": 60, // minutes + "encryption": false +} +``` + +### Memory Config + +```javascript +{ + "maxSize": 100, // MB + "compressionThreshold": 1024, // bytes + "gcInterval": 300000, // 5 minutes + "cacheSize": 1000, + "cacheMemoryMB": 50, + "enablePooling": true, + "enableAsyncOperations": true +} +``` + +## Hooks Integration + +Hive Mind integrates with Claude Flow hooks for automation: + +**Pre-Task Hooks** +- Auto-assign agents by file type +- Validate objective complexity +- Optimize topology selection +- Cache search patterns + +**Post-Task Hooks** +- Auto-format deliverables +- Train neural patterns +- Update collective memory +- Analyze performance bottlenecks + +**Session Hooks** +- Generate session summaries +- Persist checkpoint data +- Track comprehensive metrics +- Restore execution context + +## Best Practices + +### 1. Choose the Right Queen Type + +**Strategic Queens** - For research, planning, and analysis +```bash +npx claude-flow hive-mind spawn "Research ML frameworks" --queen-type strategic +``` + +**Tactical Queens** - For implementation and execution +```bash +npx claude-flow hive-mind spawn "Build authentication" --queen-type tactical +``` + +**Adaptive Queens** - For optimization and dynamic tasks +```bash +npx claude-flow hive-mind spawn "Optimize performance" --queen-type adaptive +``` + +### 2. Leverage Consensus + +Use consensus for critical decisions: +- Architecture pattern selection +- Technology stack choices +- Implementation approach +- Code review approval +- Release readiness + +### 3. Utilize Collective Memory + +**Store Learnings** +```javascript +// After successful pattern implementation +await memory.store('auth-pattern', { + approach: 'JWT with refresh tokens', + pros: ['Stateless', 'Scalable'], + cons: ['Token size', 'Revocation complexity'], + implementation: {...} +}, 'knowledge', { confidence: 0.95 }); +``` + +**Build Associations** +```javascript +// Link related concepts +await memory.associate('jwt-auth', 'refresh-tokens', 0.9); +await memory.associate('jwt-auth', 'oauth2', 0.7); +``` + +### 4. Monitor Performance + +```bash +# Regular status checks +npx claude-flow hive-mind status + +# Track metrics +npx claude-flow hive-mind metrics + +# Analyze memory usage +npx claude-flow hive-mind memory +``` + +### 5. Session Management + +**Checkpoint Frequently** +```javascript +// Create checkpoints at key milestones +await sessionManager.saveCheckpoint( + sessionId, + 'api-routes-complete', + { completedRoutes: [...], remaining: [...] } +); +``` + +**Resume Sessions** +```bash +# Resume from any previous state +npx claude-flow hive-mind resume +``` + +## Troubleshooting + +### Memory Issues + +**High Memory Usage** +```bash +# Run garbage collection +npx claude-flow hive-mind memory --gc + +# Optimize database +npx claude-flow hive-mind memory --optimize + +# Export and clear +npx claude-flow hive-mind memory --export --clear +``` + +**Low Cache Hit Rate** +```javascript +// Increase cache size in config +{ + "cacheSize": 2000, + "cacheMemoryMB": 100 +} +``` + +### Performance Issues + +**Slow Task Assignment** +```javascript +// Enable worker type caching +// The system caches best worker matches for 5 minutes +// Automatic - no configuration needed +``` + +**High Queue Utilization** +```javascript +// Increase async queue concurrency +{ + "asyncQueueConcurrency": 20 // Default: min(maxWorkers * 2, 20) +} +``` + +### Consensus Failures + +**No Consensus Reached (Byzantine)** +```bash +# Switch to weighted consensus for more decisive results +npx claude-flow hive-mind spawn "..." --consensus weighted + +# Or use simple majority +npx claude-flow hive-mind spawn "..." --consensus majority +``` + +## Advanced Topics + +### Custom Worker Types + +Define specialized workers in `.claude/agents/`: + +```yaml +name: security-auditor +type: specialist +capabilities: + - vulnerability-scanning + - security-review + - penetration-testing + - compliance-checking +priority: high +``` + +### Neural Pattern Training + +The system trains on successful patterns: + +```javascript +// Automatic pattern learning +// Happens after successful task completion +// Stores in collective memory +// Improves future task matching +``` + +### Multi-Hive Coordination + +Run multiple hive minds simultaneously: + +```bash +# Frontend hive +npx claude-flow hive-mind spawn "Build UI" --name frontend-hive + +# Backend hive +npx claude-flow hive-mind spawn "Build API" --name backend-hive + +# They share collective memory for coordination +``` + +### Export/Import Sessions + +```bash +# Export session for backup +npx claude-flow hive-mind export --output backup.json + +# Import session +npx claude-flow hive-mind import backup.json +``` + +## API Reference + +### HiveMindCore + +```javascript +const hiveMind = new HiveMindCore({ + objective: 'Build system', + queenType: 'strategic', + maxWorkers: 8, + consensusAlgorithm: 'byzantine' +}); + +await hiveMind.initialize(); +await hiveMind.spawnQueen(queenData); +await hiveMind.spawnWorkers(['coder', 'tester']); +await hiveMind.createTask('Implement feature', 7); +const decision = await hiveMind.buildConsensus('topic', options); +const status = hiveMind.getStatus(); +await hiveMind.shutdown(); +``` + +### CollectiveMemory + +```javascript +const memory = new CollectiveMemory({ + swarmId: 'hive-123', + maxSize: 100, + cacheSize: 1000 +}); + +await memory.store(key, value, type, metadata); +const data = await memory.retrieve(key); +const results = await memory.search(pattern, options); +const related = await memory.getRelated(key, limit); +await memory.associate(key1, key2, strength); +const stats = memory.getStatistics(); +const analytics = memory.getAnalytics(); +const health = await memory.healthCheck(); +``` + +### HiveMindSessionManager + +```javascript +const sessionManager = new HiveMindSessionManager(); + +const sessionId = await sessionManager.createSession( + swarmId, swarmName, objective, metadata +); + +await sessionManager.saveCheckpoint(sessionId, name, data); +const sessions = await sessionManager.getActiveSessions(); +const session = await sessionManager.getSession(sessionId); +await sessionManager.pauseSession(sessionId); +await sessionManager.resumeSession(sessionId); +await sessionManager.stopSession(sessionId); +await sessionManager.completeSession(sessionId); +``` + +## Examples + +### Full-Stack Development + +```bash +# Initialize hive mind +npx claude-flow hive-mind init + +# Spawn full-stack hive +npx claude-flow hive-mind spawn "Build e-commerce platform" \ + --queen-type strategic \ + --max-workers 10 \ + --consensus weighted \ + --claude + +# Output generates Claude Code commands: +# - Queen coordinator +# - Frontend developers (React) +# - Backend developers (Node.js) +# - Database architects +# - DevOps engineers +# - Security auditors +# - Test engineers +# - Documentation specialists +``` + +### Research and Analysis + +```bash +# Spawn research hive +npx claude-flow hive-mind spawn "Research GraphQL vs REST" \ + --queen-type adaptive \ + --consensus byzantine + +# Researchers gather data +# Analysts process findings +# Queen builds consensus on recommendation +# Results stored in collective memory +``` + +### Code Review + +```bash +# Review coordination +npx claude-flow hive-mind spawn "Review PR #456" \ + --queen-type tactical \ + --max-workers 6 + +# Spawns: +# - Code analyzers +# - Security reviewers +# - Performance reviewers +# - Test coverage analyzers +# - Documentation reviewers +# - Consensus on approval/changes +``` + +## Skill Progression + +### Beginner +1. Initialize hive mind +2. Spawn basic swarms +3. Monitor status +4. Use majority consensus + +### Intermediate +1. Configure queen types +2. Implement session management +3. Use weighted consensus +4. Access collective memory +5. Enable auto-scaling + +### Advanced +1. Byzantine fault tolerance +2. Memory optimization +3. Custom worker types +4. Multi-hive coordination +5. Neural pattern training +6. Session export/import +7. Performance tuning + +## Related Skills + +- `swarm-orchestration`: Basic swarm coordination +- `consensus-mechanisms`: Distributed decision making +- `memory-systems`: Advanced memory management +- `sparc-methodology`: Structured development workflow +- `github-integration`: Repository coordination + +## References + +- [Hive Mind Documentation](https://github.com/ruvnet/claude-flow/docs/hive-mind) +- [Collective Intelligence Patterns](https://github.com/ruvnet/claude-flow/docs/patterns) +- [Byzantine Consensus](https://github.com/ruvnet/claude-flow/docs/consensus) +- [Memory Optimization](https://github.com/ruvnet/claude-flow/docs/memory) + +--- + +**Skill Version**: 1.0.0 +**Last Updated**: 2025-10-19 +**Maintained By**: Claude Flow Team +**License**: MIT diff --git a/.claude/skills/hooks-automation/SKILL.md b/.claude/skills/hooks-automation/SKILL.md new file mode 100644 index 0000000000..7acce959ef --- /dev/null +++ b/.claude/skills/hooks-automation/SKILL.md @@ -0,0 +1,1201 @@ +--- +name: Hooks Automation +description: Automated coordination, formatting, and learning from Claude Code operations using intelligent hooks with MCP integration. Includes pre/post task hooks, session management, Git integration, memory coordination, and neural pattern training for enhanced development workflows. +--- + +# Hooks Automation + +Intelligent automation system that coordinates, validates, and learns from Claude Code operations through hooks integrated with MCP tools and neural pattern training. + +## What This Skill Does + +This skill provides a comprehensive hook system that automatically manages development operations, coordinates swarm agents, maintains session state, and continuously learns from coding patterns. It enables automated agent assignment, code formatting, performance tracking, and cross-session memory persistence. + +**Key Capabilities:** +- **Pre-Operation Hooks**: Validate, prepare, and auto-assign agents before operations +- **Post-Operation Hooks**: Format, analyze, and train patterns after operations +- **Session Management**: Persist state, restore context, generate summaries +- **Memory Coordination**: Synchronize knowledge across swarm agents +- **Git Integration**: Automated commit hooks with quality verification +- **Neural Training**: Continuous learning from successful patterns +- **MCP Integration**: Seamless coordination with swarm tools + +## Prerequisites + +**Required:** +- Claude Flow CLI installed (`npm install -g claude-flow@alpha`) +- Claude Code with hooks enabled +- `.claude/settings.json` with hook configurations + +**Optional:** +- MCP servers configured (claude-flow, ruv-swarm, flow-nexus) +- Git repository for version control +- Testing framework for quality verification + +## Quick Start + +### Initialize Hooks System + +```bash +# Initialize with default hooks configuration +npx claude-flow init --hooks +``` + +This creates: +- `.claude/settings.json` with pre-configured hooks +- Hook command documentation in `.claude/commands/hooks/` +- Default hook handlers for common operations + +### Basic Hook Usage + +```bash +# Pre-task hook (auto-spawns agents) +npx claude-flow hook pre-task --description "Implement authentication" + +# Post-edit hook (auto-formats and stores in memory) +npx claude-flow hook post-edit --file "src/auth.js" --memory-key "auth/login" + +# Session end hook (saves state and metrics) +npx claude-flow hook session-end --session-id "dev-session" --export-metrics +``` + +--- + +## Complete Guide + +### Available Hooks + +#### Pre-Operation Hooks + +Hooks that execute BEFORE operations to prepare and validate: + +**pre-edit** - Validate and assign agents before file modifications +```bash +npx claude-flow hook pre-edit [options] + +Options: + --file, -f File path to be edited + --auto-assign-agent Automatically assign best agent (default: true) + --validate-syntax Pre-validate syntax before edit + --check-conflicts Check for merge conflicts + --backup-file Create backup before editing + +Examples: + npx claude-flow hook pre-edit --file "src/auth/login.js" + npx claude-flow hook pre-edit -f "config/db.js" --validate-syntax + npx claude-flow hook pre-edit -f "production.env" --backup-file --check-conflicts +``` + +**Features:** +- Auto agent assignment based on file type +- Syntax validation to prevent broken code +- Conflict detection for concurrent edits +- Automatic file backups for safety + +**pre-bash** - Check command safety and resource requirements +```bash +npx claude-flow hook pre-bash --command + +Options: + --command, -c Command to validate + --check-safety Verify command safety (default: true) + --estimate-resources Estimate resource usage + --require-confirmation Request user confirmation for risky commands + +Examples: + npx claude-flow hook pre-bash -c "rm -rf /tmp/cache" + npx claude-flow hook pre-bash --command "docker build ." --estimate-resources +``` + +**Features:** +- Command safety validation +- Resource requirement estimation +- Destructive command confirmation +- Permission checks + +**pre-task** - Auto-spawn agents and prepare for complex tasks +```bash +npx claude-flow hook pre-task [options] + +Options: + --description, -d Task description for context + --auto-spawn-agents Automatically spawn required agents (default: true) + --load-memory Load relevant memory from previous sessions + --optimize-topology Select optimal swarm topology + --estimate-complexity Analyze task complexity + +Examples: + npx claude-flow hook pre-task --description "Implement user authentication" + npx claude-flow hook pre-task -d "Continue API dev" --load-memory + npx claude-flow hook pre-task -d "Refactor codebase" --optimize-topology +``` + +**Features:** +- Automatic agent spawning based on task analysis +- Memory loading for context continuity +- Topology optimization for task structure +- Complexity estimation and time prediction + +**pre-search** - Prepare and optimize search operations +```bash +npx claude-flow hook pre-search --query + +Options: + --query, -q Search query + --check-cache Check cache first (default: true) + --optimize-query Optimize search pattern + +Examples: + npx claude-flow hook pre-search -q "authentication middleware" +``` + +**Features:** +- Cache checking for faster results +- Query optimization +- Search pattern improvement + +#### Post-Operation Hooks + +Hooks that execute AFTER operations to process and learn: + +**post-edit** - Auto-format, validate, and update memory +```bash +npx claude-flow hook post-edit [options] + +Options: + --file, -f File path that was edited + --auto-format Automatically format code (default: true) + --memory-key, -m Store edit context in memory + --train-patterns Train neural patterns from edit + --validate-output Validate edited file + +Examples: + npx claude-flow hook post-edit --file "src/components/Button.jsx" + npx claude-flow hook post-edit -f "api/auth.js" --memory-key "auth/login" + npx claude-flow hook post-edit -f "utils/helpers.ts" --train-patterns +``` + +**Features:** +- Language-specific auto-formatting (Prettier, Black, gofmt) +- Memory storage for edit context and decisions +- Neural pattern training for continuous improvement +- Output validation with linting + +**post-bash** - Log execution and update metrics +```bash +npx claude-flow hook post-bash --command + +Options: + --command, -c Command that was executed + --log-output Log command output (default: true) + --update-metrics Update performance metrics + --store-result Store result in memory + +Examples: + npx claude-flow hook post-bash -c "npm test" --update-metrics +``` + +**Features:** +- Command execution logging +- Performance metric tracking +- Result storage for analysis +- Error pattern detection + +**post-task** - Performance analysis and decision storage +```bash +npx claude-flow hook post-task [options] + +Options: + --task-id, -t Task identifier for tracking + --analyze-performance Generate performance metrics (default: true) + --store-decisions Save task decisions to memory + --export-learnings Export neural pattern learnings + --generate-report Create task completion report + +Examples: + npx claude-flow hook post-task --task-id "auth-implementation" + npx claude-flow hook post-task -t "api-refactor" --analyze-performance + npx claude-flow hook post-task -t "bug-fix-123" --store-decisions +``` + +**Features:** +- Execution time and token usage measurement +- Decision and implementation choice recording +- Neural learning pattern export +- Completion report generation + +**post-search** - Cache results and improve patterns +```bash +npx claude-flow hook post-search --query --results + +Options: + --query, -q Original search query + --results, -r Results file path + --cache-results Cache for future use (default: true) + --train-patterns Improve search patterns + +Examples: + npx claude-flow hook post-search -q "auth" -r "results.json" --train-patterns +``` + +**Features:** +- Result caching for faster subsequent searches +- Search pattern improvement +- Relevance scoring + +#### MCP Integration Hooks + +Hooks that coordinate with MCP swarm tools: + +**mcp-initialized** - Persist swarm configuration +```bash +npx claude-flow hook mcp-initialized --swarm-id + +Features: +- Save swarm topology and configuration +- Store agent roster in memory +- Initialize coordination namespace +``` + +**agent-spawned** - Update agent roster and memory +```bash +npx claude-flow hook agent-spawned --agent-id --type + +Features: +- Register agent in coordination memory +- Update agent roster +- Initialize agent-specific memory namespace +``` + +**task-orchestrated** - Monitor task progress +```bash +npx claude-flow hook task-orchestrated --task-id + +Features: +- Track task progress through memory +- Monitor agent assignments +- Update coordination state +``` + +**neural-trained** - Save pattern improvements +```bash +npx claude-flow hook neural-trained --pattern + +Features: +- Export trained neural patterns +- Update coordination models +- Share learning across agents +``` + +#### Memory Coordination Hooks + +**memory-write** - Triggered when agents write to coordination memory +```bash +Features: +- Validate memory key format +- Update cross-agent indexes +- Trigger dependent hooks +- Notify subscribed agents +``` + +**memory-read** - Triggered when agents read from coordination memory +```bash +Features: +- Log access patterns +- Update popularity metrics +- Preload related data +- Track usage statistics +``` + +**memory-sync** - Synchronize memory across swarm agents +```bash +npx claude-flow hook memory-sync --namespace + +Features: +- Sync memory state across agents +- Resolve conflicts +- Propagate updates +- Maintain consistency +``` + +#### Session Hooks + +**session-start** - Initialize new session +```bash +npx claude-flow hook session-start --session-id + +Options: + --session-id, -s Session identifier + --load-context Load context from previous session + --init-agents Initialize required agents + +Features: +- Create session directory +- Initialize metrics tracking +- Load previous context +- Set up coordination namespace +``` + +**session-restore** - Load previous session state +```bash +npx claude-flow hook session-restore --session-id + +Options: + --session-id, -s Session to restore + --restore-memory Restore memory state (default: true) + --restore-agents Restore agent configurations + +Examples: + npx claude-flow hook session-restore --session-id "swarm-20241019" + npx claude-flow hook session-restore -s "feature-auth" --restore-memory +``` + +**Features:** +- Load previous session context +- Restore memory state and decisions +- Reconfigure agents to previous state +- Resume in-progress tasks + +**session-end** - Cleanup and persist session state +```bash +npx claude-flow hook session-end [options] + +Options: + --session-id, -s Session identifier to end + --save-state Save current session state (default: true) + --export-metrics Export session metrics + --generate-summary Create session summary + --cleanup-temp Remove temporary files + +Examples: + npx claude-flow hook session-end --session-id "dev-session-2024" + npx claude-flow hook session-end -s "feature-auth" --export-metrics --generate-summary + npx claude-flow hook session-end -s "quick-fix" --cleanup-temp +``` + +**Features:** +- Save current context and progress +- Export session metrics (duration, commands, tokens, files) +- Generate work summary with decisions and next steps +- Cleanup temporary files and optimize storage + +**notify** - Custom notifications with swarm status +```bash +npx claude-flow hook notify --message + +Options: + --message, -m Notification message + --level Notification level (info|warning|error) + --swarm-status Include swarm status (default: true) + --broadcast Send to all agents + +Examples: + npx claude-flow hook notify -m "Task completed" --level info + npx claude-flow hook notify -m "Critical error" --level error --broadcast +``` + +**Features:** +- Send notifications to coordination system +- Include swarm status and metrics +- Broadcast to all agents +- Log important events + +### Configuration + +#### Basic Configuration + +Edit `.claude/settings.json` to configure hooks: + +```json +{ + "hooks": { + "PreToolUse": [ + { + "matcher": "^(Write|Edit|MultiEdit)$", + "hooks": [{ + "type": "command", + "command": "npx claude-flow hook pre-edit --file '${tool.params.file_path}' --memory-key 'swarm/editor/current'" + }] + }, + { + "matcher": "^Bash$", + "hooks": [{ + "type": "command", + "command": "npx claude-flow hook pre-bash --command '${tool.params.command}'" + }] + } + ], + "PostToolUse": [ + { + "matcher": "^(Write|Edit|MultiEdit)$", + "hooks": [{ + "type": "command", + "command": "npx claude-flow hook post-edit --file '${tool.params.file_path}' --memory-key 'swarm/editor/complete' --auto-format --train-patterns" + }] + }, + { + "matcher": "^Bash$", + "hooks": [{ + "type": "command", + "command": "npx claude-flow hook post-bash --command '${tool.params.command}' --update-metrics" + }] + } + ] + } +} +``` + +#### Advanced Configuration + +Complete hook configuration with all features: + +```json +{ + "hooks": { + "enabled": true, + "debug": false, + "timeout": 5000, + + "PreToolUse": [ + { + "matcher": "^(Write|Edit|MultiEdit)$", + "hooks": [ + { + "type": "command", + "command": "npx claude-flow hook pre-edit --file '${tool.params.file_path}' --auto-assign-agent --validate-syntax", + "timeout": 3000, + "continueOnError": true + } + ] + }, + { + "matcher": "^Task$", + "hooks": [ + { + "type": "command", + "command": "npx claude-flow hook pre-task --description '${tool.params.task}' --auto-spawn-agents --load-memory", + "async": true + } + ] + }, + { + "matcher": "^Grep$", + "hooks": [ + { + "type": "command", + "command": "npx claude-flow hook pre-search --query '${tool.params.pattern}' --check-cache" + } + ] + } + ], + + "PostToolUse": [ + { + "matcher": "^(Write|Edit|MultiEdit)$", + "hooks": [ + { + "type": "command", + "command": "npx claude-flow hook post-edit --file '${tool.params.file_path}' --memory-key 'edits/${tool.params.file_path}' --auto-format --train-patterns", + "async": true + } + ] + }, + { + "matcher": "^Task$", + "hooks": [ + { + "type": "command", + "command": "npx claude-flow hook post-task --task-id '${result.task_id}' --analyze-performance --store-decisions --export-learnings", + "async": true + } + ] + }, + { + "matcher": "^Grep$", + "hooks": [ + { + "type": "command", + "command": "npx claude-flow hook post-search --query '${tool.params.pattern}' --cache-results --train-patterns" + } + ] + } + ], + + "SessionStart": [ + { + "hooks": [ + { + "type": "command", + "command": "npx claude-flow hook session-start --session-id '${session.id}' --load-context" + } + ] + } + ], + + "SessionEnd": [ + { + "hooks": [ + { + "type": "command", + "command": "npx claude-flow hook session-end --session-id '${session.id}' --export-metrics --generate-summary --cleanup-temp" + } + ] + } + ] + } +} +``` + +#### Protected File Patterns + +Add protection for sensitive files: + +```json +{ + "hooks": { + "PreToolUse": [ + { + "matcher": "^(Write|Edit|MultiEdit)$", + "hooks": [ + { + "type": "command", + "command": "npx claude-flow hook check-protected --file '${tool.params.file_path}'" + } + ] + } + ] + } +} +``` + +#### Automatic Testing + +Run tests after file modifications: + +```json +{ + "hooks": { + "PostToolUse": [ + { + "matcher": "^Write$", + "hooks": [ + { + "type": "command", + "command": "test -f '${tool.params.file_path%.js}.test.js' && npm test '${tool.params.file_path%.js}.test.js'", + "continueOnError": true + } + ] + } + ] + } +} +``` + +### MCP Tool Integration + +Hooks automatically integrate with MCP tools for coordination: + +#### Pre-Task Hook with Agent Spawning + +```javascript +// Hook command +npx claude-flow hook pre-task --description "Build REST API" + +// Internally calls MCP tools: +mcp__claude-flow__agent_spawn { + type: "backend-dev", + capabilities: ["api", "database", "testing"] +} + +mcp__claude-flow__memory_usage { + action: "store", + key: "swarm/task/api-build/context", + namespace: "coordination", + value: JSON.stringify({ + description: "Build REST API", + agents: ["backend-dev"], + started: Date.now() + }) +} +``` + +#### Post-Edit Hook with Memory Storage + +```javascript +// Hook command +npx claude-flow hook post-edit --file "api/auth.js" + +// Internally calls MCP tools: +mcp__claude-flow__memory_usage { + action: "store", + key: "swarm/edits/api/auth.js", + namespace: "coordination", + value: JSON.stringify({ + file: "api/auth.js", + timestamp: Date.now(), + changes: { added: 45, removed: 12 }, + formatted: true, + linted: true + }) +} + +mcp__claude-flow__neural_train { + pattern_type: "coordination", + training_data: { /* edit patterns */ } +} +``` + +#### Session End Hook with State Persistence + +```javascript +// Hook command +npx claude-flow hook session-end --session-id "dev-2024" + +// Internally calls MCP tools: +mcp__claude-flow__memory_persist { + sessionId: "dev-2024" +} + +mcp__claude-flow__swarm_status { + swarmId: "current" +} + +// Generates metrics and summary +``` + +### Memory Coordination Protocol + +All hooks follow a standardized memory coordination pattern: + +#### Three-Phase Memory Protocol + +**Phase 1: STATUS** - Hook starts +```javascript +mcp__claude-flow__memory_usage { + action: "store", + key: "swarm/hooks/pre-edit/status", + namespace: "coordination", + value: JSON.stringify({ + status: "running", + hook: "pre-edit", + file: "src/auth.js", + timestamp: Date.now() + }) +} +``` + +**Phase 2: PROGRESS** - Hook processes +```javascript +mcp__claude-flow__memory_usage { + action: "store", + key: "swarm/hooks/pre-edit/progress", + namespace: "coordination", + value: JSON.stringify({ + progress: 50, + action: "validating syntax", + file: "src/auth.js" + }) +} +``` + +**Phase 3: COMPLETE** - Hook finishes +```javascript +mcp__claude-flow__memory_usage { + action: "store", + key: "swarm/hooks/pre-edit/complete", + namespace: "coordination", + value: JSON.stringify({ + status: "complete", + result: "success", + agent_assigned: "backend-dev", + syntax_valid: true, + backup_created: true + }) +} +``` + +### Hook Response Format + +Hooks return JSON responses to control operation flow: + +#### Continue Response +```json +{ + "continue": true, + "reason": "All validations passed", + "metadata": { + "agent_assigned": "backend-dev", + "syntax_valid": true, + "file": "src/auth.js" + } +} +``` + +#### Block Response +```json +{ + "continue": false, + "reason": "Protected file - manual review required", + "metadata": { + "file": ".env.production", + "protection_level": "high", + "requires": "manual_approval" + } +} +``` + +#### Warning Response +```json +{ + "continue": true, + "reason": "Syntax valid but complexity high", + "warnings": [ + "Cyclomatic complexity: 15 (threshold: 10)", + "Consider refactoring for better maintainability" + ], + "metadata": { + "complexity": 15, + "threshold": 10 + } +} +``` + +### Git Integration + +Hooks can integrate with Git operations for quality control: + +#### Pre-Commit Hook +```bash +# Add to .git/hooks/pre-commit or use husky + +#!/bin/bash +# Run quality checks before commit + +# Get staged files +FILES=$(git diff --cached --name-only --diff-filter=ACM) + +for FILE in $FILES; do + # Run pre-edit hook for validation + npx claude-flow hook pre-edit --file "$FILE" --validate-syntax + + if [ $? -ne 0 ]; then + echo "Validation failed for $FILE" + exit 1 + fi + + # Run post-edit hook for formatting + npx claude-flow hook post-edit --file "$FILE" --auto-format +done + +# Run tests +npm test + +exit $? +``` + +#### Post-Commit Hook +```bash +# Add to .git/hooks/post-commit + +#!/bin/bash +# Track commit metrics + +COMMIT_HASH=$(git rev-parse HEAD) +COMMIT_MSG=$(git log -1 --pretty=%B) + +npx claude-flow hook notify \ + --message "Commit completed: $COMMIT_MSG" \ + --level info \ + --swarm-status +``` + +#### Pre-Push Hook +```bash +# Add to .git/hooks/pre-push + +#!/bin/bash +# Quality gate before push + +# Run full test suite +npm run test:all + +# Run quality checks +npx claude-flow hook session-end \ + --generate-report \ + --export-metrics + +# Verify quality thresholds +TRUTH_SCORE=$(npx claude-flow metrics score --format json | jq -r '.truth_score') + +if (( $(echo "$TRUTH_SCORE < 0.95" | bc -l) )); then + echo "Truth score below threshold: $TRUTH_SCORE < 0.95" + exit 1 +fi + +exit 0 +``` + +### Agent Coordination Workflow + +How agents use hooks for coordination: + +#### Agent Workflow Example + +```bash +# Agent 1: Backend Developer +# STEP 1: Pre-task preparation +npx claude-flow hook pre-task \ + --description "Implement user authentication API" \ + --auto-spawn-agents \ + --load-memory + +# STEP 2: Work begins - pre-edit validation +npx claude-flow hook pre-edit \ + --file "api/auth.js" \ + --auto-assign-agent \ + --validate-syntax + +# STEP 3: Edit file (via Claude Code Edit tool) +# ... code changes ... + +# STEP 4: Post-edit processing +npx claude-flow hook post-edit \ + --file "api/auth.js" \ + --memory-key "swarm/backend/auth-api" \ + --auto-format \ + --train-patterns + +# STEP 5: Notify coordination system +npx claude-flow hook notify \ + --message "Auth API implementation complete" \ + --swarm-status \ + --broadcast + +# STEP 6: Task completion +npx claude-flow hook post-task \ + --task-id "auth-api" \ + --analyze-performance \ + --store-decisions \ + --export-learnings +``` + +```bash +# Agent 2: Test Engineer (receives notification) +# STEP 1: Check memory for API details +npx claude-flow hook session-restore \ + --session-id "swarm-current" \ + --restore-memory + +# Memory contains: swarm/backend/auth-api with implementation details + +# STEP 2: Generate tests +npx claude-flow hook pre-task \ + --description "Write tests for auth API" \ + --load-memory + +# STEP 3: Create test file +npx claude-flow hook post-edit \ + --file "api/auth.test.js" \ + --memory-key "swarm/testing/auth-api-tests" \ + --train-patterns + +# STEP 4: Share test results +npx claude-flow hook notify \ + --message "Auth API tests complete - 100% coverage" \ + --broadcast +``` + +### Custom Hook Creation + +Create custom hooks for specific workflows: + +#### Custom Hook Template + +```javascript +// .claude/hooks/custom-quality-check.js + +module.exports = { + name: 'custom-quality-check', + type: 'pre', + matcher: /\.(ts|js)$/, + + async execute(context) { + const { file, content } = context; + + // Custom validation logic + const complexity = await analyzeComplexity(content); + const securityIssues = await scanSecurity(content); + + // Store in memory + await storeInMemory({ + key: `quality/${file}`, + value: { complexity, securityIssues } + }); + + // Return decision + if (complexity > 15 || securityIssues.length > 0) { + return { + continue: false, + reason: 'Quality checks failed', + warnings: [ + `Complexity: ${complexity} (max: 15)`, + `Security issues: ${securityIssues.length}` + ] + }; + } + + return { + continue: true, + reason: 'Quality checks passed', + metadata: { complexity, securityIssues: 0 } + }; + } +}; +``` + +#### Register Custom Hook + +```json +{ + "hooks": { + "PreToolUse": [ + { + "matcher": "^(Write|Edit)$", + "hooks": [ + { + "type": "script", + "script": ".claude/hooks/custom-quality-check.js" + } + ] + } + ] + } +} +``` + +### Real-World Examples + +#### Example 1: Full-Stack Development Workflow + +```bash +# Session start - initialize coordination +npx claude-flow hook session-start --session-id "fullstack-feature" + +# Pre-task planning +npx claude-flow hook pre-task \ + --description "Build user profile feature - frontend + backend + tests" \ + --auto-spawn-agents \ + --optimize-topology + +# Backend work +npx claude-flow hook pre-edit --file "api/profile.js" +# ... implement backend ... +npx claude-flow hook post-edit \ + --file "api/profile.js" \ + --memory-key "profile/backend" \ + --train-patterns + +# Frontend work (reads backend details from memory) +npx claude-flow hook pre-edit --file "components/Profile.jsx" +# ... implement frontend ... +npx claude-flow hook post-edit \ + --file "components/Profile.jsx" \ + --memory-key "profile/frontend" \ + --train-patterns + +# Testing (reads both backend and frontend from memory) +npx claude-flow hook pre-task \ + --description "Test profile feature" \ + --load-memory + +# Session end - export everything +npx claude-flow hook session-end \ + --session-id "fullstack-feature" \ + --export-metrics \ + --generate-summary +``` + +#### Example 2: Debugging with Hooks + +```bash +# Start debugging session +npx claude-flow hook session-start --session-id "debug-memory-leak" + +# Pre-task: analyze issue +npx claude-flow hook pre-task \ + --description "Debug memory leak in event handlers" \ + --load-memory \ + --estimate-complexity + +# Search for event emitters +npx claude-flow hook pre-search --query "EventEmitter" +# ... search executes ... +npx claude-flow hook post-search \ + --query "EventEmitter" \ + --cache-results + +# Fix the issue +npx claude-flow hook pre-edit \ + --file "services/events.js" \ + --backup-file +# ... fix code ... +npx claude-flow hook post-edit \ + --file "services/events.js" \ + --memory-key "debug/memory-leak-fix" \ + --validate-output + +# Verify fix +npx claude-flow hook post-task \ + --task-id "memory-leak-fix" \ + --analyze-performance \ + --generate-report + +# End session +npx claude-flow hook session-end \ + --session-id "debug-memory-leak" \ + --export-metrics +``` + +#### Example 3: Multi-Agent Refactoring + +```bash +# Initialize swarm for refactoring +npx claude-flow hook pre-task \ + --description "Refactor legacy codebase to modern patterns" \ + --auto-spawn-agents \ + --optimize-topology + +# Agent 1: Code Analyzer +npx claude-flow hook pre-task --description "Analyze code complexity" +# ... analysis ... +npx claude-flow hook post-task \ + --task-id "analysis" \ + --store-decisions + +# Agent 2: Refactoring (reads analysis from memory) +npx claude-flow hook session-restore \ + --session-id "swarm-refactor" \ + --restore-memory + +for file in src/**/*.js; do + npx claude-flow hook pre-edit --file "$file" --backup-file + # ... refactor ... + npx claude-flow hook post-edit \ + --file "$file" \ + --memory-key "refactor/$file" \ + --auto-format \ + --train-patterns +done + +# Agent 3: Testing (reads refactored code from memory) +npx claude-flow hook pre-task \ + --description "Generate tests for refactored code" \ + --load-memory + +# Broadcast completion +npx claude-flow hook notify \ + --message "Refactoring complete - all tests passing" \ + --broadcast +``` + +### Performance Tips + +1. **Keep Hooks Lightweight** - Target < 100ms execution time +2. **Use Async for Heavy Operations** - Don't block the main flow +3. **Cache Aggressively** - Store frequently accessed data +4. **Batch Related Operations** - Combine multiple actions +5. **Use Memory Wisely** - Set appropriate TTLs +6. **Monitor Hook Performance** - Track execution times +7. **Parallelize When Possible** - Run independent hooks concurrently + +### Debugging Hooks + +Enable debug mode for troubleshooting: + +```bash +# Enable debug output +export CLAUDE_FLOW_DEBUG=true + +# Test specific hook with verbose output +npx claude-flow hook pre-edit --file "test.js" --debug + +# Check hook execution logs +cat .claude-flow/logs/hooks-$(date +%Y-%m-%d).log + +# Validate configuration +npx claude-flow hook validate-config +``` + +### Benefits + +- **Automatic Agent Assignment**: Right agent for every file type +- **Consistent Code Formatting**: Language-specific formatters +- **Continuous Learning**: Neural patterns improve over time +- **Cross-Session Memory**: Context persists between sessions +- **Performance Tracking**: Comprehensive metrics and analytics +- **Automatic Coordination**: Agents sync via memory +- **Smart Agent Spawning**: Task-based agent selection +- **Quality Gates**: Pre-commit validation and verification +- **Error Prevention**: Syntax validation before edits +- **Knowledge Sharing**: Decisions stored and shared +- **Reduced Manual Work**: Automation of repetitive tasks +- **Better Collaboration**: Seamless multi-agent coordination + +### Best Practices + +1. **Configure Hooks Early** - Set up during project initialization +2. **Use Memory Keys Strategically** - Organize with clear namespaces +3. **Enable Auto-Formatting** - Maintain code consistency +4. **Train Patterns Continuously** - Learn from successful operations +5. **Monitor Performance** - Track hook execution times +6. **Validate Configuration** - Test hooks before production use +7. **Document Custom Hooks** - Maintain hook documentation +8. **Set Appropriate Timeouts** - Prevent hanging operations +9. **Handle Errors Gracefully** - Use continueOnError when appropriate +10. **Review Metrics Regularly** - Optimize based on usage patterns + +### Troubleshooting + +#### Hooks Not Executing +- Verify `.claude/settings.json` syntax +- Check hook matcher patterns +- Enable debug mode +- Review permission settings +- Ensure claude-flow CLI is in PATH + +#### Hook Timeouts +- Increase timeout values in configuration +- Make hooks asynchronous for heavy operations +- Optimize hook logic +- Check network connectivity for MCP tools + +#### Memory Issues +- Set appropriate TTLs for memory keys +- Clean up old memory entries +- Use memory namespaces effectively +- Monitor memory usage + +#### Performance Problems +- Profile hook execution times +- Use caching for repeated operations +- Batch operations when possible +- Reduce hook complexity + +### Related Commands + +- `npx claude-flow init --hooks` - Initialize hooks system +- `npx claude-flow hook --list` - List available hooks +- `npx claude-flow hook --test ` - Test specific hook +- `npx claude-flow memory usage` - Manage memory +- `npx claude-flow agent spawn` - Spawn agents +- `npx claude-flow swarm init` - Initialize swarm + +### Integration with Other Skills + +This skill works seamlessly with: +- **SPARC Methodology** - Hooks enhance SPARC workflows +- **Pair Programming** - Automated quality in pairing sessions +- **Verification Quality** - Truth-score validation in hooks +- **GitHub Workflows** - Git integration for commits/PRs +- **Performance Analysis** - Metrics collection in hooks +- **Swarm Advanced** - Multi-agent coordination via hooks diff --git a/.claude/skills/imsg/SKILL.md b/.claude/skills/imsg/SKILL.md new file mode 100644 index 0000000000..26d4488569 --- /dev/null +++ b/.claude/skills/imsg/SKILL.md @@ -0,0 +1,25 @@ +--- +name: imsg +description: iMessage/SMS CLI for listing chats, history, watch, and sending. +homepage: https://imsg.to +metadata: {"zee":{"emoji":"๐Ÿ“จ","os":["darwin"],"requires":{"bins":["imsg"]},"install":[{"id":"brew","kind":"brew","formula":"steipete/tap/imsg","bins":["imsg"],"label":"Install imsg (brew)"}]}} +--- + +# imsg + +Use `imsg` to read and send Messages.app iMessage/SMS on macOS. + +Requirements +- Messages.app signed in +- Full Disk Access for your terminal +- Automation permission to control Messages.app (for sending) + +Common commands +- List chats: `imsg chats --limit 10 --json` +- History: `imsg history --chat-id 1 --limit 20 --attachments --json` +- Watch: `imsg watch --chat-id 1 --attachments` +- Send: `imsg send --to "+14155551212" --text "hi" --file /path/pic.jpg` + +Notes +- `--service imessage|sms|auto` controls delivery. +- Confirm recipient + message before sending. diff --git a/.claude/skills/investment-thesis/SKILL.md b/.claude/skills/investment-thesis/SKILL.md new file mode 100644 index 0000000000..360ecd0cc9 --- /dev/null +++ b/.claude/skills/investment-thesis/SKILL.md @@ -0,0 +1,136 @@ +--- +name: investment-thesis +description: Create and track investment theses with conviction levels +triggers: + - investment thesis + - stock thesis + - create thesis + - update thesis + - thesis tracking +--- + +# Investment Thesis Management + +Create, track, and manage investment theses using Stanley's note system. + +## Creating a Thesis + +### Research Phase +1. Gather fundamental data (via OpenBB) +2. Analyze financial statements (via Stanley/edgartools) +3. Assess competitive position +4. Build valuation model +5. Identify risks and catalysts + +### Thesis Template + +Using Stanley's NoteManager: +``` +from stanley.notes import NoteManager, ConvictionLevel + +notes = NoteManager() + +thesis = notes.create_thesis( + symbol="AAPL", + company_name="Apple Inc.", + sector="Technology", + conviction="high" # low, medium, high, very_high +) +``` + +## Thesis Structure + +```markdown +## Investment Thesis: AAPL + +### Bull Case +- Services revenue growing 15%+ annually +- Installed base creates recurring revenue +- Strong cash generation, shareholder returns + +### Bear Case +- iPhone dependence (50%+ revenue) +- China regulatory/geopolitical risk +- Hardware margin pressure + +### Valuation +- DCF Target: $185 +- Comparable Multiple: 28x forward PE +- Current Price: $172 + +### Conviction Level: HIGH +- Time Horizon: 12-18 months +- Position Size: 5% of portfolio + +### Catalysts +- Q1 2024 earnings (Jan 25) +- WWDC 2024 (Jun) +- iPhone 16 launch (Sep) + +### Risk Monitoring +- Services growth < 10% +- China revenue decline > 15% +- Gross margin < 42% +``` + +## Tracking Theses + +``` +# Get active theses +active = notes.get_theses(status="active") + +# Get by symbol +aapl_thesis = notes.get_theses(symbol="AAPL") + +# Search theses +results = notes.search("Services growth Technology") +``` + +## Memory Integration + +```typescript +// Store thesis in memory for cross-session access +await memory.store({ + namespace: "stanley/theses", + key: symbol, + value: { + symbol, + conviction, + targetPrice, + bullCase: [...], + bearCase: [...], + catalysts: [...], + riskTriggers: [...], + lastReviewed: new Date() + } +}); + +// Retrieve for quick access +const thesis = await memory.retrieve("stanley/theses", symbol); +``` + +## Thesis Review Workflow + +Weekly review checklist: +1. Price action vs thesis +2. Any material news/events? +3. Estimate revisions direction +4. Technical levels +5. Thesis still valid? + +## Conviction Changes + +Track conviction history: +```typescript +await memory.store({ + namespace: "stanley/theses", + key: symbol, + value: { + // ... existing fields + history: [ + { date: "2024-01-01", conviction: "medium", note: "Initial thesis" }, + { date: "2024-01-20", conviction: "high", note: "Strong Q4 results" } + ] + } +}); +``` diff --git a/.claude/skills/johny/SKILL.md b/.claude/skills/johny/SKILL.md index 42de3f6bf3..9e84769c6d 100644 --- a/.claude/skills/johny/SKILL.md +++ b/.claude/skills/johny/SKILL.md @@ -76,7 +76,7 @@ johny: Shows mastery levels, at-risk topics, review schedule ## Integration Points -- **persona repo**: `~/Repositories/personas/johny/scripts/johny_cli.py` +- **persona repo**: `~/.local/src/agent-core/vendor/personas/johny/scripts/johny_cli.py` - **Memory**: Qdrant vector store for topic embeddings - **Council**: Multi-model deliberation for explanations - **Browser**: Ingest content from web, PDFs, videos @@ -91,8 +91,8 @@ npx tsx scripts/johny-daemon.ts status ## Environment -- `JOHNY_REPO` (default: `~/Repositories/personas/johny`) -- `JOHNY_CLI` (default: `~/Repositories/personas/johny/scripts/johny_cli.py`) +- `JOHNY_REPO` (default: `~/.local/src/agent-core/vendor/personas/johny`) +- `JOHNY_CLI` (default: `~/.local/src/agent-core/vendor/personas/johny/scripts/johny_cli.py`) ## When to Use johny diff --git a/.claude/skills/johny/scripts/johny-session.ts b/.claude/skills/johny/scripts/johny-session.ts index fe05982be5..261b006503 100644 --- a/.claude/skills/johny/scripts/johny-session.ts +++ b/.claude/skills/johny/scripts/johny-session.ts @@ -33,7 +33,7 @@ function getArg(name: string): string | undefined { function resolveJohnyCli(): { python: string; cliPath: string } { const python = process.env.JOHNY_PYTHON || "python3"; - const repo = process.env.JOHNY_REPO || join(homedir(), "Repositories", "personas", "johny"); + const repo = process.env.JOHNY_REPO || join(homedir(), ".local", "src", "agent-core", "vendor", "personas", "johny"); const cliPath = process.env.JOHNY_CLI || join(repo, "scripts", "johny_cli.py"); return { python, cliPath }; } diff --git a/.claude/skills/local-places/SERVER_README.md b/.claude/skills/local-places/SERVER_README.md new file mode 100644 index 0000000000..1a69931f28 --- /dev/null +++ b/.claude/skills/local-places/SERVER_README.md @@ -0,0 +1,101 @@ +# Local Places + +This repo is a fusion of two pieces: + +- A FastAPI server that exposes endpoints for searching and resolving places via the Google Maps Places API. +- A companion agent skill that explains how to use the API and can call it to find places efficiently. + +Together, the skill and server let an agent turn natural-language place queries into structured results quickly. + +## Run locally + +```bash +# copy skill definition into the relevant folder (where the agent looks for it) +# then run the server + +uv venv +uv pip install -e ".[dev]" +uv run --env-file .env uvicorn local_places.main:app --host 0.0.0.0 --reload +``` + +Open the API docs at http://127.0.0.1:8000/docs. + +## Places API + +Set the Google Places API key before running: + +```bash +export GOOGLE_PLACES_API_KEY="your-key" +``` + +Endpoints: + +- `POST /places/search` (free-text query + filters) +- `GET /places/{place_id}` (place details) +- `POST /locations/resolve` (resolve a user-provided location string) + +Example search request: + +```json +{ + "query": "italian restaurant", + "filters": { + "types": ["restaurant"], + "open_now": true, + "min_rating": 4.0, + "price_levels": [1, 2] + }, + "limit": 10 +} +``` + +Notes: + +- `filters.types` supports a single type (mapped to Google `includedType`). + +Example search request (curl): + +```bash +curl -X POST http://127.0.0.1:8000/places/search \ + -H "Content-Type: application/json" \ + -d '{ + "query": "italian restaurant", + "location_bias": { + "lat": 40.8065, + "lng": -73.9719, + "radius_m": 3000 + }, + "filters": { + "types": ["restaurant"], + "open_now": true, + "min_rating": 4.0, + "price_levels": [1, 2, 3] + }, + "limit": 10 + }' +``` + +Example resolve request (curl): + +```bash +curl -X POST http://127.0.0.1:8000/locations/resolve \ + -H "Content-Type: application/json" \ + -d '{ + "location_text": "Riverside Park, New York", + "limit": 5 + }' +``` + +## Test + +```bash +uv run pytest +``` + +## OpenAPI + +Generate the OpenAPI schema: + +```bash +uv run python scripts/generate_openapi.py +``` diff --git a/.claude/skills/local-places/SKILL.md b/.claude/skills/local-places/SKILL.md new file mode 100644 index 0000000000..20592710e6 --- /dev/null +++ b/.claude/skills/local-places/SKILL.md @@ -0,0 +1,91 @@ +--- +name: local-places +description: Search for places (restaurants, cafes, etc.) via Google Places API proxy on localhost. +homepage: https://github.com/Hyaxia/local_places +metadata: {"zee":{"emoji":"๐Ÿ“","requires":{"bins":["uv"],"env":["GOOGLE_PLACES_API_KEY"]},"primaryEnv":"GOOGLE_PLACES_API_KEY"}} +--- + +# ๐Ÿ“ Local Places + +*Find places, Go fast* + +Search for nearby places using a local Google Places API proxy. Two-step flow: resolve location first, then search. + +## Setup + +```bash +cd {baseDir} +echo "GOOGLE_PLACES_API_KEY=your-key" > .env +uv venv && uv pip install -e ".[dev]" +uv run --env-file .env uvicorn local_places.main:app --host 127.0.0.1 --port 8000 +``` + +Requires `GOOGLE_PLACES_API_KEY` in `.env` or environment. + +## Quick Start + +1. **Check server:** `curl http://127.0.0.1:8000/ping` + +2. **Resolve location:** +```bash +curl -X POST http://127.0.0.1:8000/locations/resolve \ + -H "Content-Type: application/json" \ + -d '{"location_text": "Soho, London", "limit": 5}' +``` + +3. **Search places:** +```bash +curl -X POST http://127.0.0.1:8000/places/search \ + -H "Content-Type: application/json" \ + -d '{ + "query": "coffee shop", + "location_bias": {"lat": 51.5137, "lng": -0.1366, "radius_m": 1000}, + "filters": {"open_now": true, "min_rating": 4.0}, + "limit": 10 + }' +``` + +4. **Get details:** +```bash +curl http://127.0.0.1:8000/places/{place_id} +``` + +## Conversation Flow + +1. If user says "near me" or gives vague location โ†’ resolve it first +2. If multiple results โ†’ show numbered list, ask user to pick +3. Ask for preferences: type, open now, rating, price level +4. Search with `location_bias` from chosen location +5. Present results with name, rating, address, open status +6. Offer to fetch details or refine search + +## Filter Constraints + +- `filters.types`: exactly ONE type (e.g., "restaurant", "cafe", "gym") +- `filters.price_levels`: integers 0-4 (0=free, 4=very expensive) +- `filters.min_rating`: 0-5 in 0.5 increments +- `filters.open_now`: boolean +- `limit`: 1-20 for search, 1-10 for resolve +- `location_bias.radius_m`: must be > 0 + +## Response Format + +```json +{ + "results": [ + { + "place_id": "ChIJ...", + "name": "Coffee Shop", + "address": "123 Main St", + "location": {"lat": 51.5, "lng": -0.1}, + "rating": 4.6, + "price_level": 2, + "types": ["cafe", "food"], + "open_now": true + } + ], + "next_page_token": "..." +} +``` + +Use `next_page_token` as `page_token` in next request for more results. diff --git a/.claude/skills/local-places/pyproject.toml b/.claude/skills/local-places/pyproject.toml new file mode 100644 index 0000000000..c59e336a12 --- /dev/null +++ b/.claude/skills/local-places/pyproject.toml @@ -0,0 +1,27 @@ +[project] +name = "my-api" +version = "0.1.0" +description = "FastAPI server" +readme = "README.md" +requires-python = ">=3.11" +dependencies = [ + "fastapi>=0.110.0", + "httpx>=0.27.0", + "uvicorn[standard]>=0.29.0", +] + +[project.optional-dependencies] +dev = [ + "pytest>=8.0.0", +] + +[build-system] +requires = ["hatchling"] +build-backend = "hatchling.build" + +[tool.hatch.build.targets.wheel] +packages = ["src/local_places"] + +[tool.pytest.ini_options] +addopts = "-q" +testpaths = ["tests"] diff --git a/.claude/skills/local-places/src/local_places/__init__.py b/.claude/skills/local-places/src/local_places/__init__.py new file mode 100644 index 0000000000..07c5de9e2c --- /dev/null +++ b/.claude/skills/local-places/src/local_places/__init__.py @@ -0,0 +1,2 @@ +__all__ = ["__version__"] +__version__ = "0.1.0" diff --git a/.claude/skills/local-places/src/local_places/__pycache__/__init__.cpython-314.pyc b/.claude/skills/local-places/src/local_places/__pycache__/__init__.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0a17848a45a0a0a69ee91bccfa284ee891b61154 GIT binary patch literal 218 zcmdPqD`4)G4d|7Hy zab|vAe0&wFfu5nBfuAPRE%x~M#GIV?_#!5twv`N@L8jbt(hn^Ls?{$pNzE)sElJf6 zD9X=DO)e?c&&f|t%!x0^NlZ=!N*5)g3dF}}=4F<|$LkeT-r}&y%}*)KNwq6t2O0@- eU9ljL_`uA_$asTWqC>xd{RW?C6L%3SP!s^PnmC#O literal 0 HcmV?d00001 diff --git a/.claude/skills/local-places/src/local_places/__pycache__/google_places.cpython-314.pyc b/.claude/skills/local-places/src/local_places/__pycache__/google_places.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..94944facf8666a5131c4bb4a8855f5acfed649c5 GIT binary patch literal 14487 zcmcgTYiwKBdFS%-^8M0V6!oAUwoE@nH?b`{@guTLNwy`KzLJ$>kCcE8cC3{5KFht%~#K3?p1v+#on(QxSx)6J-q5%pF$d3W?EZ433XWw`3 zgS1T9?i}>kJkRf*$9KN-z0T1#kJ~{Y?EdeUlh@k``85{wKwAi5?&cUmX31H?Gsj3j zBQq_SHyty{CYrJ`3n_cd+|S9J)@G3{P-i}7?YGG`TE`u;_d8@qzf*ShyJT0tTXy$* zWKX|W_V)W^Uw?&M(L&C!(GGq1V%kc03vbx)$uCr#|9p>cPGqusM3R4>I(h5Funw(~)*f5zg^;!wJ1Y?TK%f54_6Lv!E zq?t^yStd*5dfp@Zd9U2S`{Y0kfw3#<2w!Q;v5~KWa&;X^`Q#?P2J*Eu-^|xRzMke= zct7MDXg9Myyr~`5)S}HlNkZE`$2Er-#TiehGjd!`X429Sl-Zv2G$ii+k&$TRjd3B1 zEg_p?8HmdR=?SHFATv&(c|ppgE(*Nxl_^1zmAXgjr7UzQD6VKKJ}w*;g7XK^s8Ya)}GND1+5QtBGdOolIhX{I3s^G?McYS&7NFUlV~5{V5&Mk52UUOp00 z>Pl;l4MkpwMuvuujYgE}(uTp4M(Toh7zjXa$djE~2s zL{Uh~C$mBtKI+d*iPHA8@P-_XPY5HK*M;=Vw_sAGvw371#`yZc#Szt^L}6ko6&D{G zqwKhJ8Szx~LMAN?O--H?#O;@ab5c?kPK(KzQ(q*K=*-4T&poRan7cWz&Cuw|% zAP<8VGjPB9l4p5aYl20CItM_9!MyH2~A@gRl2(WQ5L1JABS z-53eGZ&UihrzJs@!jdc`vw|#yqhjXE!niDjOG!U0iQ^AfsAok#8QE#Y6^m(1L5Rha z#&rwoDsAn9k)CE!<6Qfxev5EOe%M-jA`B_VZQtcUL<9C!0(F#w5Ti^Y=ZqzsFx ze{?Zw3tdPJ0MC*_pnW+IUJ8USn{V6d3;xzW_lV8V^8ejQu@2{85e0clOh51>lH>Ag zk}Pfy0;fGA`k^tzhz*da`$(rOB7ula5S_pV9m5Q_=?;PDYMLg+X#o%o8iCpG?tvm; zn3ThCRHJ+C8=B~}+)l(GRD?`o8zhSP%TgwNgAv=IK&Pi-RNRV<)$5Uoz;wPEBE3~} zU%T?PWpCS(w=M7O$k{rIGuHQ2oAJ{e35rOu6NhF2flox;Nt|>Mb?u0=_N(JGDNY1{ zXut^pV(fRjAhRLraJuWldX&k)OT}#fREn^jP<|9)2s(t2l@QI6&q@)Nv$fGlYFi<; z0>}_B7$D{}hzKBNM=Um(Nlc|M4`=o(Q}LA6;*G`5Cq+q4CDTGW6N`x*@UgmSwyc=R z3ZgtM(ka!%VtAU8<1vskV)ERSEJy&4R7poysS)>6#Hbg3QV^nVl6xjN>i29wjjI-7 z@vNBuxp!GTr+$o|JalZ#PytA0?qVN^xI)CgalUB5n>P zftiwn1jO+8gM_DP7=98SvsrSVI2p?wjOK?|Fos?FVGLiAXY=P3?YCT zNOTo6%ZxHesTd|a$lk{|wM0OX=1n}?t@Qv*-^_EoWt8Eqqa@72x@}6$!+K6n^jPdf z7*|uO(3W6dRlmxl!hKW*(Vo6Y~YsPgXla@i`?-&6+V8$2EW>ZO3fe7P~ zo$fgPR}5<}2=N36B(VqJDE5y)W|pjYd~?ZfCv)}Tyl3ZZ->;mNE1p21K2WIIv&OMr z$0}j%j#US-*X8QB7HswNodsLN{P9(**=1QJX3kRFCOoqk&{m<_v>h^!AuE%LYCyl0 zw}m+r*cx}96yyt;1SKzpof1=uH5;E!W#WkkH4iiF;GYGDKv$uQr-Vq)#bbF9QePZ? zk}CG@6AuGy9HN5DyUJo(>sQl`eQMfwoTi^~)ps~(R~KxCF7yEAh`Qi5K*1~tkS9|n z&va|(dXb4SQ>H04Ms%*9HIJI327T&-5ICQs%$QX#kFq*-kD7Q>w>F<3?Sc)! z&_c%CYL1XsIQ@%u5+vJ*aUy{B8%Yujk|u!1e*=LR*(Q=?f~705>HQQ_3rSStw^_@W zQ?FGwRXtDO}HAo88bu0B93xATY-&v?>T(y(> z&36e`@44K6pCz6xYt_URnBSXscI3<*_iLaAy7>K?hqx-{4qZ942BH(X_XHN%+^&(^ zp3}M4&gN`qf4|CN{R2wb-)QOCOx|zlsp38+HpqTl>T9BktFel0SStp;vi%mbBaragE$DVq6;G=E>%7}PN%}dD8kPW1!l&7hd?y{ zRbVcR|7H~}6?qK6(tzYmXZIt>;Oxq&Ryu(vK<8`R0H&Pi7zD$kRAeNA+V_Z)b-@J! zWR!7{=h!IH$GV^&>2@5w%-6v4OhXD244D<{`D9842CZ0ue_zUo355gN0<)Y0ftt($ zho{ILg%KX&?iI0fQ%MlWsJ(#J0bhu(0u03}DhQxLhjxD0@?pzj%jJo=%$3ZtXVWdu zrjHW9?5&GOu2(AgmD94WW| zVH50r+5Ivo%C|8^fa+k{43mH!a2D%=(Zc}tfXWrmm4}R$VYr}}l~t=s zXr*3POa&GHW!vCOhxR21r}e@3vP>I%>D0cgUH=_1#AO1k3E(ECXc-vrS+Y~6F7#N! z472PQTE8@mvZbpVGM#``Q6Hu$%fh%WIxeI61)&bSf^Nl*hx!!d0=6tTgocwdU}IyB zx`q_Xcv2is36O%Q6GX+90^>oRLPI>2Nl&O*ix^KNr@+~#`-u)G<4{Vb$5Q~AKrK|U zf)$b;%3M!=(&PAk+B15MKK|eqSsF=@X z64P3jDm?PlqEN2X_@P8ymoW-`5g;fVi2xS>%g$DHyJqvkrF>1eV5_{^cYW~M;3~&9 zT4s-erfc&qTmA4qXZ05v+m{==mKwV*n=ik%Wb=P!^(?Lx1b7Z@o497INkAweV#tWx#U>E*~hgZ~frF`v-1T{H*=? z%SW#^FS&xyw(JZnIRm$xorUI2%gtR&&0WyuzjBf`H7z-tZaG7RVCQo1xuxK9&=gp5 zHPN<~WoJvy+49-GmzMVp-r6^Kmo>F}e!g$;CU@J{v2c3Xw=L(}wzO~X4%WkmO-rs8 zScA(qd*XNhYlk|?0x13I-r7j5`I)r_g%#tM#9ru7wI$uEb6eN#pQJzhEqo}UX9-P7 zD-*thQLcW+DyBDg(Bh*40`+UEKzx&aIcgm538)3e4E`-(o`%o>AT98WEg0{Re&7J* z=4m(j0~pWPXqE}wArR%7o&yt=3EZ5a#o{ahm!tiLNpY8vy8R z(TTerpZoI8rkuH{IMXi@p}tg7qK@J-Pm9%m#l@g~gKUXqwjvt0=4!VgR=4JMzC_E# z$pRn^UldxEs!M|KdLll3RFKBOexO&1<BBwv3FKnA9_p{o|6`2(w%EP|^RlH%+DmWB$5DcAij#Iq%C zB(Rssb6{T;g&^9`MR#lw!(%A!XxL>|Q)*q5vx-c6!3~h;LqR)cSVB=;-MYZDptqOl z0cy)wGbK(mTn`P@UMt%NtjzKp%UgBV*99hkRzj8jWii#g0$Fy1jUp>s7kFnE(O)lQ zxh`<8jc`8F`xCGztRt2vZrHjohU}Y$5o_5VUA$ZGajfYHupV7~(bEn3^y=+nEl=pt zr$g%L20d2j?PIM^=&@3V)YA=mtkT=Z+Mm#4wGOGLd`-7TDSAx{Iq_4~Y8%^R^k&&$ z4{P5K7HG7&sJd~)ca?jO`2)0(ue^`X0l6pQ*2K`|v03Q?RT zuOk%S`sWc~6l?D@;MP~QY#l|*R?NU6l&UhXA>iJ}Mu&;PAZEPEgWDDL;fMG)@R5jW zwPqx%hAZt$%wo0sp(h-07Y=S{X(}a4iWgfz4CwZAs7gf6Lp{hM+NnxqY&g=xAL)lpnbL<*w7_YP($$L-F_J3vtdpodX4a`fo zt!*nd&z$RutKiyQa8)n6f@tTus^rSOql*U|qx zoU7_9y{)oxuQG+o2J~!xAFSwAAMw=8y>{ib`TB+D^6t&Ey#^=*;|@zI>(?5ItD)elE7Z5V=X}Sxa57)N3)Y6W zZ7gT`?OK?)YS#z{D>QI*SVs{DcXewvKoMRH4Bhse%$*_toetM9D{4<;J;sW$uyb>1iR_uw&#s2`1pNPnpj4Fv@EzA@rs{@4TO?𔴣^if{SeGuq z^mGF_x87c&gp^ln9#t&L!xa^aqN-9J@=?X2Je;9eY_JAHo!Fqgs74f3o$@0+qDGXc zGUdOh(ebCJd~LTzYgAz{+}|Y%!{e#a4hlm#`YS37rS#`0(il}3OzRYex*40MFoYGh zFETPDUIP*nzlRa30OI#C`U{NqWAv98{S`*@7`=?ta^FH?V_Ye2~4@Uo77T+=|R;@?49i~Pu3h7WqQSyTO=4fQ3 z=h(pTdZ{ZeVqZ5f+KCbR4e8q*@t-h9nH-AS^%C|n*1Zi8yqj6Td>IKVVP{mJs?xLq zoP6rbznJ<~L=ry&2+AWbmPpiv{>4`oj~hajo0k@j-rjm3?>+cO5vOZD0@AXg{(9hA zV18s_Z@yytiaWSa_d($Oz~Y&F>x+5!eh^^So!6YX#;&|Cyi(D!VEw@PzH{+-KG>bF z*jw<{&b@i%O}OFqcC1u`C;o#s-+%Mw{(R?4`Rbkm$m-XxyguKV_q1vGTm!yN(fXVp z$ooPoo`(7E_g;MG#a!q9eBeOdb8w|Xn?i2K;e6|ne8thVIu}Y!7fMaF_ya{~ahWvzHv;Y^Srs9hfo_)D;%-~Fhlx0WRa@Ui* zxkSnu+$w5tCVdQ$vRwHdpw?G}(sLzJ)-b*CPZrAe0aDfmQr7;Elx3ra9MyX*k+S9y zb2$^7cb6FL7BJeuR0pGd7L0Zq7^jATUhJ{N5Vw`>(ZhQUqrE71%ELY?3CqJ7lCVTB zm4`HBqAr(4%EKA5k+1GXh6X|Z0u1JFXa;k;+Cs>P6%1>jUkp^f)v9?y4Ee^5J)RyM zAf?Ogd{MrY?!2?OyCWPJ#I7uNh$}IOYsER3fjEZI8H}!C^prAgNVSrvqyYw_<+V!DkjiT?pmls}y-kyyG7Sa8+N z*Dd?Imi%2e9Ut}mc<_gVIp^`&qq=Rl?O@(}=#L`Ap2{X{d^Ve~#OzyhTF}U|=|)~H zakVdY-*!HqGe7^^wa_z4r=Pfe5te+yI(r%R6HixUKl{mk4)UQ8K1)771#jKqS+WRR zAD-5s7Xkj%L_CNk3*5?M0hzmag0`QJ!yDvml4?3iHEyi&hdR>u1pyxZ(u+t{W>IlP zl_2V7pj3v3mpT{3LzqMNhGGZRW`MdcRE0{yN)G<8WKt5pgHU))CjL7{Kf(wZFnzM8 zI!0c_B6>$uAI8@)_clhCG5Rh>KfnmpB}#$da$(^emBN8{3H~AqIm6DKs+MKjufEeh zDE=4JA}5mE5X0j+hWRCF`!(_Wg4lmaYJW{!za*{q&349gpFngMqt#l{(Dfhx{|ZwSm>&Kjg~6OEf`+z$8u_3&x+ zs)y`3&MfafxwQM_?cJwt*YQicPrX00AkA~{Iv{(ijz=hqjjLW|2~)M&;NU7SSH0S7 z=BjA!ex-wf2lWu$Yj84_dyVi+^KwroZIK#jyM<){vGhGi!ZeK?aBi7Clr zcUMBpqJW$haE!EwQ52{j{E&yDu+aj2?Vmwc1}v;&AV7@-LEk#FM~al(s6d;Q zxgWDLyK}#t`R)4q;ZPreGWCyZl?@Lef5$Yc^~)5zI)c6@8f;4@0ktcgFKiI@lZa@!&2s*J&=#^NIuG= z`52Go5AuWge%_xXMQxPmKHXnb3a@wE>b5Y~rw2}ecUW>tR?&l}+9N(#B!#Rq(_4d0 z=!D`(c%nF1INm$!^!0E@Lq8BFdL&M&krQn-J_I(WUbQLuc5I?x6We7o3^u1&(h%BD!dCqfs?W zmQl92S*bD+r53ZRE0$5UOVXB!5VK5LT5=Rw#w`Zt+HbCb2@mJ)|P9j*qJ>G6_ z5xOGR>sW<5Lr1yk`N^#mexn7glgri2k1I8H ztY(&O+V)S6nH4%SJvliENV$21S1sXX7G1F@YsT?os_hTRuI%8_bmtnC`eF&AxE;yF z1${h)Ej*}IGEZ)()4zgq1lcfoPgzoQWdUZKve3>ELb|=<>Kj9ydCa9Tl2Koxp72nM zFVi|W=qguATxg8rsdzrLY0cyeJxGglxvStd%Q0?M8Wy*51!{j}l{m}wengJZ(r!V` ztkkoOTOw!}X1#86lUs&C55t=14a3eV`GzP;aucgxmw$Ksfp%~DH+4DOf@xC1s#DNo zi38HwD$yYtoo^A|n#Gv8XbBg@(c&XQQ=ma1&I!e>Kn$4DQRp6m9}7XXO1=sX+*@e{ zMp~{Bsk#eu;7ez(Gg5bd%yqSkwXQ9=z(kgu21vW;01SkeIvFA~>*Ep~1W`t#s7Y}v z>P3M9_<-R!Nv=N1#H)LW*Y-t1m!e3MuN36<(<6c|ND=)#r9;3c+|ERj zEF9>lKyXKQ`s)7nIc0~awGQ=;ktwaBWL(WRy6ls(kbY8jJ$019zijHJUA}b|`clrI zSNS8Hg77#T1nCiA5WdUIKt>bZl3nLkooD>QQ?(ZtEh^m7Qg~_>U$VMh-Mb(8Pf1B^=|n zkGKPO=5Eie`%bR=4tyTI8^$JZH}KS#cKJ*X$&7K}k%^+xFswr{B=*Y@+>BwqJFJpM z8c9DmyMfK0Z^%(M(LqfXbW^&TfDU8@CZ8V z7;m}8I~d~4gNea%?bpF~havqT>Vc?Z)7|ns+i#v z-{lVBfybp)UlAI7tnkBNPLemx;944t7uLX+@ef?1LYm_qSRhTX9}VZXR@H`J)A zR%#?xNhA3oQvFE!(2|#`4}FN#KIBhuv{r3Ksj8|{E8g6C)vCOt=iHfHk6{T&=}2?t z-gD2~nR|Zc{O*}~Ar=i0IF9`NviYYlA%DY8`%s*Quqg_J)Jcx0!dWsUFkuMW;#qM@ zV$zh%Vp>z+P-O>O_%3C z7j1Fgu*ITbD|5w)&TOg31q_kwgI|C1%{LFGLBJgWO)KjqL(}Y#rj;s%S`ph3O}kms zi|$BV)87F|~iRvN^z&u>|pka-H zxI^wI`>@aHH;Nr75D&*8&tYqzEr1Y+^%97udbBC; zyWc;seDl*A^{IxjCJ#H);Y{27ix|NnY|5NcI(KK7l_;u$KAQDI zUI;moQ&iv4Hn{{;Ka2;s4+ZdH5PBhxwV;MOSrh{LP}C?N4I@zEj+E*5xMca_aHUYLkC0%S|+&18`O@S>COc&d@+RGBE0GRjL{?lfWK@wyiCW@xT zerz#1oBnA!TPZ`j5)nlWE5GPB3=(8Jki_6 zp^{nFD1=mb-kshov(EI9DmC+lRx~~^idIIXdtm~b-%>Qn^K9W^2wtW=mH&pZc&kDS zd32oXJR(CI;1D*`(5RCck`s@8NJs&6gXA4yK~M!%R3%lM6k)OQ10*$D0b;Bf6mPM8 z)L=DQ<}nDt?VGF6lFlrge}rN z1iUjNW^bRlP%bW}0l+lkmo}}mRjXDjlo^GIG%#NJCMs<2~W3hG2`Qon_}*6V`w~P?Ebc+w(F7itQSGl z$%c$9>-cdpZG6 zYX3p@QDv^|(pBprGP1V&^BSsx+`VrBoU8~l3W0`EVLEN%)M*#1dWf*%I9+i>l zF}QFa+6vEF+i#XRz?KXndFGc#mX3U8H2f>6slS9%5Hl;g&o@)ql}L6y-rI=$_g{X}b5^hr zh>uez1g-DHLTW8~xDZB@ZttLpdSWs|GtIQ4qeJd}CC3=K|di*0uy&y{+(#DSNxeTZgs_fGF1FxJPN%p*p=Cb0e-j?4NV$7&^wM z15N{uGD{|-FQ6h+)#qVvs@yQ#%|6mKqlMfJ4~)5Tpmq6HXC33q>sVzXYFdGW2)>t4h3_mEDqG0$lwt<`l0I;2MM; zFJ8eisD_~zac2psQRv0oURaGoFTs0B7EvX@G-XHL#xJFJYo(G-7wKE@Vs?OkJZWYj z>i{6*SDfvKLW3HX^)TvuBDT>Bw85n~Gn8dc%@_h0+a_VpUcrku%JY8&?CB_qIEYNN zE3Evp<02YeLU9?zk5F7i!RO&qbi)>jn4&lVrsw*=0n7-A-;TA@ z%&NkF0^@dySNC3=W^F$}0p+{pLKH6>KVjOViQ<2qvXVD>a z#>ja6!qU|>dE8ky8f{y*4-{|+n+TU@-4~ulR-BL&Af%8gcL>Q#Uw#O4{LT&9{cV0x z4XaZ8z;L;UV)5Zb?-toG@CoM>iqJbefRUEX1iLzhGl-6+Jm@%YbPKEZ&;$iqw0|5t zx98sQ>T?I`=a+yo4j?<+y!+0*msXP#$PR1rgyS^4ZJX01P{1K9Q{<4M~6FG05?<@a=RA1dD$71kvR91UtxGH*||LW(fDw21bjt%M+qEyF}`X$8V~@4pFL_>2AzTlh3w literal 0 HcmV?d00001 diff --git a/.claude/skills/local-places/src/local_places/google_places.py b/.claude/skills/local-places/src/local_places/google_places.py new file mode 100644 index 0000000000..5a9bd60a30 --- /dev/null +++ b/.claude/skills/local-places/src/local_places/google_places.py @@ -0,0 +1,314 @@ +from __future__ import annotations + +import logging +import os +from typing import Any + +import httpx +from fastapi import HTTPException + +from local_places.schemas import ( + LatLng, + LocationResolveRequest, + LocationResolveResponse, + PlaceDetails, + PlaceSummary, + ResolvedLocation, + SearchRequest, + SearchResponse, +) + +GOOGLE_PLACES_BASE_URL = os.getenv( + "GOOGLE_PLACES_BASE_URL", "https://places.googleapis.com/v1" +) +logger = logging.getLogger("local_places.google_places") + +_PRICE_LEVEL_TO_ENUM = { + 0: "PRICE_LEVEL_FREE", + 1: "PRICE_LEVEL_INEXPENSIVE", + 2: "PRICE_LEVEL_MODERATE", + 3: "PRICE_LEVEL_EXPENSIVE", + 4: "PRICE_LEVEL_VERY_EXPENSIVE", +} +_ENUM_TO_PRICE_LEVEL = {value: key for key, value in _PRICE_LEVEL_TO_ENUM.items()} + +_SEARCH_FIELD_MASK = ( + "places.id," + "places.displayName," + "places.formattedAddress," + "places.location," + "places.rating," + "places.priceLevel," + "places.types," + "places.currentOpeningHours," + "nextPageToken" +) + +_DETAILS_FIELD_MASK = ( + "id," + "displayName," + "formattedAddress," + "location," + "rating," + "priceLevel," + "types," + "regularOpeningHours," + "currentOpeningHours," + "nationalPhoneNumber," + "websiteUri" +) + +_RESOLVE_FIELD_MASK = ( + "places.id," + "places.displayName," + "places.formattedAddress," + "places.location," + "places.types" +) + + +class _GoogleResponse: + def __init__(self, response: httpx.Response): + self.status_code = response.status_code + self._response = response + + def json(self) -> dict[str, Any]: + return self._response.json() + + @property + def text(self) -> str: + return self._response.text + + +def _api_headers(field_mask: str) -> dict[str, str]: + api_key = os.getenv("GOOGLE_PLACES_API_KEY") + if not api_key: + raise HTTPException( + status_code=500, + detail="GOOGLE_PLACES_API_KEY is not set.", + ) + return { + "Content-Type": "application/json", + "X-Goog-Api-Key": api_key, + "X-Goog-FieldMask": field_mask, + } + + +def _request( + method: str, url: str, payload: dict[str, Any] | None, field_mask: str +) -> _GoogleResponse: + try: + with httpx.Client(timeout=10.0) as client: + response = client.request( + method=method, + url=url, + headers=_api_headers(field_mask), + json=payload, + ) + except httpx.HTTPError as exc: + raise HTTPException(status_code=502, detail="Google Places API unavailable.") from exc + + return _GoogleResponse(response) + + +def _build_text_query(request: SearchRequest) -> str: + keyword = request.filters.keyword if request.filters else None + if keyword: + return f"{request.query} {keyword}".strip() + return request.query + + +def _build_search_body(request: SearchRequest) -> dict[str, Any]: + body: dict[str, Any] = { + "textQuery": _build_text_query(request), + "pageSize": request.limit, + } + + if request.page_token: + body["pageToken"] = request.page_token + + if request.location_bias: + body["locationBias"] = { + "circle": { + "center": { + "latitude": request.location_bias.lat, + "longitude": request.location_bias.lng, + }, + "radius": request.location_bias.radius_m, + } + } + + if request.filters: + filters = request.filters + if filters.types: + body["includedType"] = filters.types[0] + if filters.open_now is not None: + body["openNow"] = filters.open_now + if filters.min_rating is not None: + body["minRating"] = filters.min_rating + if filters.price_levels: + body["priceLevels"] = [ + _PRICE_LEVEL_TO_ENUM[level] for level in filters.price_levels + ] + + return body + + +def _parse_lat_lng(raw: dict[str, Any] | None) -> LatLng | None: + if not raw: + return None + latitude = raw.get("latitude") + longitude = raw.get("longitude") + if latitude is None or longitude is None: + return None + return LatLng(lat=latitude, lng=longitude) + + +def _parse_display_name(raw: dict[str, Any] | None) -> str | None: + if not raw: + return None + return raw.get("text") + + +def _parse_open_now(raw: dict[str, Any] | None) -> bool | None: + if not raw: + return None + return raw.get("openNow") + + +def _parse_hours(raw: dict[str, Any] | None) -> list[str] | None: + if not raw: + return None + return raw.get("weekdayDescriptions") + + +def _parse_price_level(raw: str | None) -> int | None: + if not raw: + return None + return _ENUM_TO_PRICE_LEVEL.get(raw) + + +def search_places(request: SearchRequest) -> SearchResponse: + url = f"{GOOGLE_PLACES_BASE_URL}/places:searchText" + response = _request("POST", url, _build_search_body(request), _SEARCH_FIELD_MASK) + + if response.status_code >= 400: + logger.error( + "Google Places API error %s. response=%s", + response.status_code, + response.text, + ) + raise HTTPException( + status_code=502, + detail=f"Google Places API error ({response.status_code}).", + ) + + try: + payload = response.json() + except ValueError as exc: + logger.error( + "Google Places API returned invalid JSON. response=%s", + response.text, + ) + raise HTTPException(status_code=502, detail="Invalid Google response.") from exc + + places = payload.get("places", []) + results = [] + for place in places: + results.append( + PlaceSummary( + place_id=place.get("id", ""), + name=_parse_display_name(place.get("displayName")), + address=place.get("formattedAddress"), + location=_parse_lat_lng(place.get("location")), + rating=place.get("rating"), + price_level=_parse_price_level(place.get("priceLevel")), + types=place.get("types"), + open_now=_parse_open_now(place.get("currentOpeningHours")), + ) + ) + + return SearchResponse( + results=results, + next_page_token=payload.get("nextPageToken"), + ) + + +def get_place_details(place_id: str) -> PlaceDetails: + url = f"{GOOGLE_PLACES_BASE_URL}/places/{place_id}" + response = _request("GET", url, None, _DETAILS_FIELD_MASK) + + if response.status_code >= 400: + logger.error( + "Google Places API error %s. response=%s", + response.status_code, + response.text, + ) + raise HTTPException( + status_code=502, + detail=f"Google Places API error ({response.status_code}).", + ) + + try: + payload = response.json() + except ValueError as exc: + logger.error( + "Google Places API returned invalid JSON. response=%s", + response.text, + ) + raise HTTPException(status_code=502, detail="Invalid Google response.") from exc + + return PlaceDetails( + place_id=payload.get("id", place_id), + name=_parse_display_name(payload.get("displayName")), + address=payload.get("formattedAddress"), + location=_parse_lat_lng(payload.get("location")), + rating=payload.get("rating"), + price_level=_parse_price_level(payload.get("priceLevel")), + types=payload.get("types"), + phone=payload.get("nationalPhoneNumber"), + website=payload.get("websiteUri"), + hours=_parse_hours(payload.get("regularOpeningHours")), + open_now=_parse_open_now(payload.get("currentOpeningHours")), + ) + + +def resolve_locations(request: LocationResolveRequest) -> LocationResolveResponse: + url = f"{GOOGLE_PLACES_BASE_URL}/places:searchText" + body = {"textQuery": request.location_text, "pageSize": request.limit} + response = _request("POST", url, body, _RESOLVE_FIELD_MASK) + + if response.status_code >= 400: + logger.error( + "Google Places API error %s. response=%s", + response.status_code, + response.text, + ) + raise HTTPException( + status_code=502, + detail=f"Google Places API error ({response.status_code}).", + ) + + try: + payload = response.json() + except ValueError as exc: + logger.error( + "Google Places API returned invalid JSON. response=%s", + response.text, + ) + raise HTTPException(status_code=502, detail="Invalid Google response.") from exc + + places = payload.get("places", []) + results = [] + for place in places: + results.append( + ResolvedLocation( + place_id=place.get("id", ""), + name=_parse_display_name(place.get("displayName")), + address=place.get("formattedAddress"), + location=_parse_lat_lng(place.get("location")), + types=place.get("types"), + ) + ) + + return LocationResolveResponse(results=results) diff --git a/.claude/skills/local-places/src/local_places/main.py b/.claude/skills/local-places/src/local_places/main.py new file mode 100644 index 0000000000..1197719deb --- /dev/null +++ b/.claude/skills/local-places/src/local_places/main.py @@ -0,0 +1,65 @@ +import logging +import os + +from fastapi import FastAPI, Request +from fastapi.encoders import jsonable_encoder +from fastapi.exceptions import RequestValidationError +from fastapi.responses import JSONResponse + +from local_places.google_places import get_place_details, resolve_locations, search_places +from local_places.schemas import ( + LocationResolveRequest, + LocationResolveResponse, + PlaceDetails, + SearchRequest, + SearchResponse, +) + +app = FastAPI( + title="My API", + servers=[{"url": os.getenv("OPENAPI_SERVER_URL", "http://maxims-macbook-air:8000")}], +) +logger = logging.getLogger("local_places.validation") + + +@app.get("/ping") +def ping() -> dict[str, str]: + return {"message": "pong"} + + +@app.exception_handler(RequestValidationError) +async def validation_exception_handler( + request: Request, exc: RequestValidationError +) -> JSONResponse: + logger.error( + "Validation error on %s %s. body=%s errors=%s", + request.method, + request.url.path, + exc.body, + exc.errors(), + ) + return JSONResponse( + status_code=422, + content=jsonable_encoder({"detail": exc.errors()}), + ) + + +@app.post("/places/search", response_model=SearchResponse) +def places_search(request: SearchRequest) -> SearchResponse: + return search_places(request) + + +@app.get("/places/{place_id}", response_model=PlaceDetails) +def places_details(place_id: str) -> PlaceDetails: + return get_place_details(place_id) + + +@app.post("/locations/resolve", response_model=LocationResolveResponse) +def locations_resolve(request: LocationResolveRequest) -> LocationResolveResponse: + return resolve_locations(request) + + +if __name__ == "__main__": + import uvicorn + + uvicorn.run("local_places.main:app", host="0.0.0.0", port=8000) diff --git a/.claude/skills/local-places/src/local_places/schemas.py b/.claude/skills/local-places/src/local_places/schemas.py new file mode 100644 index 0000000000..e0590e659e --- /dev/null +++ b/.claude/skills/local-places/src/local_places/schemas.py @@ -0,0 +1,107 @@ +from __future__ import annotations + +from pydantic import BaseModel, Field, field_validator + + +class LatLng(BaseModel): + lat: float = Field(ge=-90, le=90) + lng: float = Field(ge=-180, le=180) + + +class LocationBias(BaseModel): + lat: float = Field(ge=-90, le=90) + lng: float = Field(ge=-180, le=180) + radius_m: float = Field(gt=0) + + +class Filters(BaseModel): + types: list[str] | None = None + open_now: bool | None = None + min_rating: float | None = Field(default=None, ge=0, le=5) + price_levels: list[int] | None = None + keyword: str | None = Field(default=None, min_length=1) + + @field_validator("types") + @classmethod + def validate_types(cls, value: list[str] | None) -> list[str] | None: + if value is None: + return value + if len(value) > 1: + raise ValueError( + "Only one type is supported. Use query/keyword for additional filtering." + ) + return value + + @field_validator("price_levels") + @classmethod + def validate_price_levels(cls, value: list[int] | None) -> list[int] | None: + if value is None: + return value + invalid = [level for level in value if level not in range(0, 5)] + if invalid: + raise ValueError("price_levels must be integers between 0 and 4.") + return value + + @field_validator("min_rating") + @classmethod + def validate_min_rating(cls, value: float | None) -> float | None: + if value is None: + return value + if (value * 2) % 1 != 0: + raise ValueError("min_rating must be in 0.5 increments.") + return value + + +class SearchRequest(BaseModel): + query: str = Field(min_length=1) + location_bias: LocationBias | None = None + filters: Filters | None = None + limit: int = Field(default=10, ge=1, le=20) + page_token: str | None = None + + +class PlaceSummary(BaseModel): + place_id: str + name: str | None = None + address: str | None = None + location: LatLng | None = None + rating: float | None = None + price_level: int | None = None + types: list[str] | None = None + open_now: bool | None = None + + +class SearchResponse(BaseModel): + results: list[PlaceSummary] + next_page_token: str | None = None + + +class LocationResolveRequest(BaseModel): + location_text: str = Field(min_length=1) + limit: int = Field(default=5, ge=1, le=10) + + +class ResolvedLocation(BaseModel): + place_id: str + name: str | None = None + address: str | None = None + location: LatLng | None = None + types: list[str] | None = None + + +class LocationResolveResponse(BaseModel): + results: list[ResolvedLocation] + + +class PlaceDetails(BaseModel): + place_id: str + name: str | None = None + address: str | None = None + location: LatLng | None = None + rating: float | None = None + price_level: int | None = None + types: list[str] | None = None + phone: str | None = None + website: str | None = None + hours: list[str] | None = None + open_now: bool | None = None diff --git a/.claude/skills/market-analysis/SKILL.md b/.claude/skills/market-analysis/SKILL.md new file mode 100644 index 0000000000..d4fea1154b --- /dev/null +++ b/.claude/skills/market-analysis/SKILL.md @@ -0,0 +1,95 @@ +--- +name: market-analysis +description: Analyze market conditions, sector rotation, and macro trends +triggers: + - market analysis + - sector rotation + - market overview + - macro outlook + - economic data +--- + +# Market Analysis + +Analyze overall market conditions and identify sector opportunities. + +## Market Overview Queries + +### Major Indices +``` +# Index performance +obb.index.price.historical(symbol="^SPX,^IXIC,^DJI", provider="yfinance") + +# VIX (fear gauge) +obb.index.price.historical(symbol="^VIX", provider="cboe") +``` + +### Sector Performance +``` +# Sector ETF performance comparison +sectors = ["XLK", "XLF", "XLE", "XLV", "XLI", "XLC", "XLY", "XLP", "XLU", "XLRE", "XLB"] +obb.equity.price.performance(symbol=",".join(sectors), provider="fmp") +``` + +### Economic Indicators +``` +# Key FRED series +obb.economy.fred_series(symbol="GDP") # GDP +obb.economy.fred_series(symbol="UNRATE") # Unemployment +obb.economy.fred_series(symbol="CPIAUCSL") # CPI +obb.economy.fred_series(symbol="FEDFUNDS") # Fed Funds Rate +obb.economy.fred_series(symbol="T10Y2Y") # Yield curve spread +``` + +## Sector Rotation Analysis + +Using Stanley's SectorRotationAnalyzer: +``` +from stanley.analytics import SectorRotationAnalyzer + +analyzer = SectorRotationAnalyzer(stanley) +rotation = analyzer.detect_rotation(lookback_days=90) +momentum = analyzer.calculate_sector_momentum() +regime = analyzer.detect_market_regime() +``` + +## Money Flow Analysis + +``` +from stanley.analytics import MoneyFlowAnalyzer + +mf = MoneyFlowAnalyzer(stanley) +sector_flows = mf.get_sector_money_flow(["XLK", "XLF", "XLE"]) +institutional_flow = mf.get_institutional_flow("SPY") +``` + +## Output Templates + +### Daily Market Brief +- Index moves and VIX +- Sector leadership/laggards +- Key economic data releases +- Notable earnings/events + +### Weekly Market Review +- Sector rotation trends +- Money flow analysis +- Risk-on vs risk-off positioning +- Forward calendar + +## Memory Integration + +Store market context: +```typescript +await memory.store({ + namespace: "stanley/market", + key: `daily/${date}`, + value: { + indices: { spx, ndx, vix }, + sectorLeaders: [...], + sectorLaggards: [...], + keyEvents: [...] + }, + ttl: 86400 * 7 +}); +``` diff --git a/.claude/skills/mcporter/SKILL.md b/.claude/skills/mcporter/SKILL.md new file mode 100644 index 0000000000..c1f1d1a81b --- /dev/null +++ b/.claude/skills/mcporter/SKILL.md @@ -0,0 +1,38 @@ +--- +name: mcporter +description: Use the mcporter CLI to list, configure, auth, and call MCP servers/tools directly (HTTP or stdio), including ad-hoc servers, config edits, and CLI/type generation. +homepage: http://mcporter.dev +metadata: {"zee":{"emoji":"๐Ÿ“ฆ","requires":{"bins":["mcporter"]},"install":[{"id":"node","kind":"node","package":"mcporter","bins":["mcporter"],"label":"Install mcporter (node)"}]}} +--- + +# mcporter + +Use `mcporter` to work with MCP servers directly. + +Quick start +- `mcporter list` +- `mcporter list --schema` +- `mcporter call key=value` + +Call tools +- Selector: `mcporter call linear.list_issues team=ENG limit:5` +- Function syntax: `mcporter call "linear.create_issue(title: \"Bug\")"` +- Full URL: `mcporter call https://api.example.com/mcp.fetch url:https://example.com` +- Stdio: `mcporter call --stdio "bun run ./server.ts" scrape url=https://example.com` +- JSON payload: `mcporter call --args '{"limit":5}'` + +Auth + config +- OAuth: `mcporter auth [--reset]` +- Config: `mcporter config list|get|add|remove|import|login|logout` + +Daemon +- `mcporter daemon start|status|stop|restart` + +Codegen +- CLI: `mcporter generate-cli --server ` or `--command ` +- Inspect: `mcporter inspect-cli [--json]` +- TS: `mcporter emit-ts --mode client|types` + +Notes +- Config default: `./config/mcporter.json` (override with `--config`). +- Prefer `--output json` for machine-readable results. diff --git a/.claude/skills/model-usage/SKILL.md b/.claude/skills/model-usage/SKILL.md new file mode 100644 index 0000000000..bd716f3520 --- /dev/null +++ b/.claude/skills/model-usage/SKILL.md @@ -0,0 +1,45 @@ +--- +name: model-usage +description: Use CodexBar CLI local cost usage to summarize per-model usage for Codex or Claude, including the current (most recent) model or a full model breakdown. Trigger when asked for model-level usage/cost data from codexbar, or when you need a scriptable per-model summary from codexbar cost JSON. +metadata: {"zee":{"emoji":"๐Ÿ“Š","os":["darwin"],"requires":{"bins":["codexbar"]},"install":[{"id":"brew-cask","kind":"brew","cask":"steipete/tap/codexbar","bins":["codexbar"],"label":"Install CodexBar (brew cask)"}]}} +--- + +# Model usage + +## Overview +Get per-model usage cost from CodexBar's local cost logs. Supports "current model" (most recent daily entry) or "all models" summaries for Codex or Claude. + +TODO: add Linux CLI support guidance once CodexBar CLI install path is documented for Linux. + +## Quick start +1) Fetch cost JSON via CodexBar CLI or pass a JSON file. +2) Use the bundled script to summarize by model. + +```bash +python {baseDir}/scripts/model_usage.py --provider codex --mode current +python {baseDir}/scripts/model_usage.py --provider codex --mode all +python {baseDir}/scripts/model_usage.py --provider claude --mode all --format json --pretty +``` + +## Current model logic +- Uses the most recent daily row with `modelBreakdowns`. +- Picks the model with the highest cost in that row. +- Falls back to the last entry in `modelsUsed` when breakdowns are missing. +- Override with `--model ` when you need a specific model. + +## Inputs +- Default: runs `codexbar cost --format json --provider `. +- File or stdin: + +```bash +codexbar cost --provider codex --format json > /tmp/cost.json +python {baseDir}/scripts/model_usage.py --input /tmp/cost.json --mode all +cat /tmp/cost.json | python {baseDir}/scripts/model_usage.py --input - --mode current +``` + +## Output +- Text (default) or JSON (`--format json --pretty`). +- Values are cost-only per model; tokens are not split by model in CodexBar output. + +## References +- Read `references/codexbar-cli.md` for CLI flags and cost JSON fields. diff --git a/.claude/skills/model-usage/references/codexbar-cli.md b/.claude/skills/model-usage/references/codexbar-cli.md new file mode 100644 index 0000000000..a41db4d320 --- /dev/null +++ b/.claude/skills/model-usage/references/codexbar-cli.md @@ -0,0 +1,28 @@ +# CodexBar CLI quick ref (usage + cost) + +## Install +- App: Preferences -> Advanced -> Install CLI +- Repo: ./bin/install-codexbar-cli.sh + +## Commands +- Usage snapshot (web/cli sources): + - codexbar usage --format json --pretty + - codexbar --provider all --format json +- Local cost usage (Codex + Claude only): + - codexbar cost --format json --pretty + - codexbar cost --provider codex|claude --format json + +## Cost JSON fields +The payload is an array (one per provider). +- provider, source, updatedAt +- sessionTokens, sessionCostUSD +- last30DaysTokens, last30DaysCostUSD +- daily[]: date, inputTokens, outputTokens, cacheReadTokens, cacheCreationTokens, totalTokens, totalCost, modelsUsed, modelBreakdowns[] +- modelBreakdowns[]: modelName, cost +- totals: totalInputTokens, totalOutputTokens, cacheReadTokens, cacheCreationTokens, totalTokens, totalCost + +## Notes +- Cost usage is local-only. It reads JSONL logs under: + - Codex: ~/.codex/sessions/**/*.jsonl + - Claude: ~/.config/claude/projects/**/*.jsonl or ~/.claude/projects/**/*.jsonl +- If web usage is required (non-local), use codexbar usage (not cost). diff --git a/.claude/skills/model-usage/scripts/model_usage.py b/.claude/skills/model-usage/scripts/model_usage.py new file mode 100644 index 0000000000..0b71f96ea0 --- /dev/null +++ b/.claude/skills/model-usage/scripts/model_usage.py @@ -0,0 +1,310 @@ +#!/usr/bin/env python3 +""" +Summarize CodexBar local cost usage by model. + +Defaults to current model (most recent daily entry), or list all models. +""" + +from __future__ import annotations + +import argparse +import json +import os +import subprocess +import sys +from dataclasses import dataclass +from datetime import date, datetime, timedelta +from typing import Any, Dict, Iterable, List, Optional, Tuple + + +def eprint(msg: str) -> None: + print(msg, file=sys.stderr) + + +def run_codexbar_cost(provider: str) -> List[Dict[str, Any]]: + cmd = ["codexbar", "cost", "--format", "json", "--provider", provider] + try: + output = subprocess.check_output(cmd, text=True) + except FileNotFoundError: + raise RuntimeError("codexbar not found on PATH. Install CodexBar CLI first.") + except subprocess.CalledProcessError as exc: + raise RuntimeError(f"codexbar cost failed (exit {exc.returncode}).") + try: + payload = json.loads(output) + except json.JSONDecodeError as exc: + raise RuntimeError(f"Failed to parse codexbar JSON output: {exc}") + if not isinstance(payload, list): + raise RuntimeError("Expected codexbar cost JSON array.") + return payload + + +def load_payload(input_path: Optional[str], provider: str) -> Dict[str, Any]: + if input_path: + if input_path == "-": + raw = sys.stdin.read() + else: + with open(input_path, "r", encoding="utf-8") as handle: + raw = handle.read() + data = json.loads(raw) + else: + data = run_codexbar_cost(provider) + + if isinstance(data, dict): + return data + + if isinstance(data, list): + for entry in data: + if isinstance(entry, dict) and entry.get("provider") == provider: + return entry + raise RuntimeError(f"Provider '{provider}' not found in codexbar payload.") + + raise RuntimeError("Unsupported JSON input format.") + + +@dataclass +class ModelCost: + model: str + cost: float + + +def parse_daily_entries(payload: Dict[str, Any]) -> List[Dict[str, Any]]: + daily = payload.get("daily") + if not daily: + return [] + if not isinstance(daily, list): + return [] + return [entry for entry in daily if isinstance(entry, dict)] + + +def parse_date(value: str) -> Optional[date]: + try: + return datetime.strptime(value, "%Y-%m-%d").date() + except Exception: + return None + + +def filter_by_days(entries: List[Dict[str, Any]], days: Optional[int]) -> List[Dict[str, Any]]: + if not days: + return entries + cutoff = date.today() - timedelta(days=days - 1) + filtered: List[Dict[str, Any]] = [] + for entry in entries: + day = entry.get("date") + if not isinstance(day, str): + continue + parsed = parse_date(day) + if parsed and parsed >= cutoff: + filtered.append(entry) + return filtered + + +def aggregate_costs(entries: Iterable[Dict[str, Any]]) -> Dict[str, float]: + totals: Dict[str, float] = {} + for entry in entries: + breakdowns = entry.get("modelBreakdowns") + if not breakdowns: + continue + if not isinstance(breakdowns, list): + continue + for item in breakdowns: + if not isinstance(item, dict): + continue + model = item.get("modelName") + cost = item.get("cost") + if not isinstance(model, str): + continue + if not isinstance(cost, (int, float)): + continue + totals[model] = totals.get(model, 0.0) + float(cost) + return totals + + +def pick_current_model(entries: List[Dict[str, Any]]) -> Tuple[Optional[str], Optional[str]]: + if not entries: + return None, None + sorted_entries = sorted( + entries, + key=lambda entry: entry.get("date") or "", + ) + for entry in reversed(sorted_entries): + breakdowns = entry.get("modelBreakdowns") + if isinstance(breakdowns, list) and breakdowns: + scored: List[ModelCost] = [] + for item in breakdowns: + if not isinstance(item, dict): + continue + model = item.get("modelName") + cost = item.get("cost") + if isinstance(model, str) and isinstance(cost, (int, float)): + scored.append(ModelCost(model=model, cost=float(cost))) + if scored: + scored.sort(key=lambda item: item.cost, reverse=True) + return scored[0].model, entry.get("date") if isinstance(entry.get("date"), str) else None + models_used = entry.get("modelsUsed") + if isinstance(models_used, list) and models_used: + last = models_used[-1] + if isinstance(last, str): + return last, entry.get("date") if isinstance(entry.get("date"), str) else None + return None, None + + +def usd(value: Optional[float]) -> str: + if value is None: + return "โ€”" + return f"${value:,.2f}" + + +def latest_day_cost(entries: List[Dict[str, Any]], model: str) -> Tuple[Optional[str], Optional[float]]: + if not entries: + return None, None + sorted_entries = sorted( + entries, + key=lambda entry: entry.get("date") or "", + ) + for entry in reversed(sorted_entries): + breakdowns = entry.get("modelBreakdowns") + if not isinstance(breakdowns, list): + continue + for item in breakdowns: + if not isinstance(item, dict): + continue + if item.get("modelName") == model: + cost = item.get("cost") if isinstance(item.get("cost"), (int, float)) else None + day = entry.get("date") if isinstance(entry.get("date"), str) else None + return day, float(cost) if cost is not None else None + return None, None + + +def render_text_current( + provider: str, + model: str, + latest_date: Optional[str], + total_cost: Optional[float], + latest_cost: Optional[float], + latest_cost_date: Optional[str], + entry_count: int, +) -> str: + lines = [f"Provider: {provider}", f"Current model: {model}"] + if latest_date: + lines.append(f"Latest model date: {latest_date}") + lines.append(f"Total cost (rows): {usd(total_cost)}") + if latest_cost_date: + lines.append(f"Latest day cost: {usd(latest_cost)} ({latest_cost_date})") + lines.append(f"Daily rows: {entry_count}") + return "\n".join(lines) + + +def render_text_all(provider: str, totals: Dict[str, float]) -> str: + lines = [f"Provider: {provider}", "Models:"] + for model, cost in sorted(totals.items(), key=lambda item: item[1], reverse=True): + lines.append(f"- {model}: {usd(cost)}") + return "\n".join(lines) + + +def build_json_current( + provider: str, + model: str, + latest_date: Optional[str], + total_cost: Optional[float], + latest_cost: Optional[float], + latest_cost_date: Optional[str], + entry_count: int, +) -> Dict[str, Any]: + return { + "provider": provider, + "mode": "current", + "model": model, + "latestModelDate": latest_date, + "totalCostUSD": total_cost, + "latestDayCostUSD": latest_cost, + "latestDayCostDate": latest_cost_date, + "dailyRowCount": entry_count, + } + + +def build_json_all(provider: str, totals: Dict[str, float]) -> Dict[str, Any]: + return { + "provider": provider, + "mode": "all", + "models": [ + {"model": model, "totalCostUSD": cost} + for model, cost in sorted(totals.items(), key=lambda item: item[1], reverse=True) + ], + } + + +def main() -> int: + parser = argparse.ArgumentParser(description="Summarize CodexBar model usage from local cost logs.") + parser.add_argument("--provider", choices=["codex", "claude"], default="codex") + parser.add_argument("--mode", choices=["current", "all"], default="current") + parser.add_argument("--model", help="Explicit model name to report instead of auto-current.") + parser.add_argument("--input", help="Path to codexbar cost JSON (or '-' for stdin).") + parser.add_argument("--days", type=int, help="Limit to last N days (based on daily rows).") + parser.add_argument("--format", choices=["text", "json"], default="text") + parser.add_argument("--pretty", action="store_true", help="Pretty-print JSON output.") + + args = parser.parse_args() + + try: + payload = load_payload(args.input, args.provider) + except Exception as exc: + eprint(str(exc)) + return 1 + + entries = parse_daily_entries(payload) + entries = filter_by_days(entries, args.days) + + if args.mode == "current": + model = args.model + latest_date = None + if not model: + model, latest_date = pick_current_model(entries) + if not model: + eprint("No model data found in codexbar cost payload.") + return 2 + totals = aggregate_costs(entries) + total_cost = totals.get(model) + latest_cost_date, latest_cost = latest_day_cost(entries, model) + + if args.format == "json": + payload_out = build_json_current( + provider=args.provider, + model=model, + latest_date=latest_date, + total_cost=total_cost, + latest_cost=latest_cost, + latest_cost_date=latest_cost_date, + entry_count=len(entries), + ) + indent = 2 if args.pretty else None + print(json.dumps(payload_out, indent=indent, sort_keys=args.pretty)) + else: + print( + render_text_current( + provider=args.provider, + model=model, + latest_date=latest_date, + total_cost=total_cost, + latest_cost=latest_cost, + latest_cost_date=latest_cost_date, + entry_count=len(entries), + ) + ) + return 0 + + totals = aggregate_costs(entries) + if not totals: + eprint("No model breakdowns found in codexbar cost payload.") + return 2 + + if args.format == "json": + payload_out = build_json_all(provider=args.provider, totals=totals) + indent = 2 if args.pretty else None + print(json.dumps(payload_out, indent=indent, sort_keys=args.pretty)) + else: + print(render_text_all(provider=args.provider, totals=totals)) + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/.claude/skills/nano-banana-pro/SKILL.md b/.claude/skills/nano-banana-pro/SKILL.md new file mode 100644 index 0000000000..638c8c92f1 --- /dev/null +++ b/.claude/skills/nano-banana-pro/SKILL.md @@ -0,0 +1,30 @@ +--- +name: nano-banana-pro +description: Generate or edit images via Gemini 3 Pro Image (Nano Banana Pro). +homepage: https://ai.google.dev/ +metadata: {"zee":{"emoji":"๐ŸŒ","requires":{"bins":["uv"],"env":["GEMINI_API_KEY"]},"primaryEnv":"GEMINI_API_KEY","install":[{"id":"uv-brew","kind":"brew","formula":"uv","bins":["uv"],"label":"Install uv (brew)"}]}} +--- + +# Nano Banana Pro (Gemini 3 Pro Image) + +Use the bundled script to generate or edit images. + +Generate +```bash +uv run {baseDir}/scripts/generate_image.py --prompt "your image description" --filename "output.png" --resolution 1K +``` + +Edit +```bash +uv run {baseDir}/scripts/generate_image.py --prompt "edit instructions" --filename "output.png" --input-image "/path/in.png" --resolution 2K +``` + +API key +- `GEMINI_API_KEY` env var +- Or set `skills."nano-banana-pro".apiKey` / `skills."nano-banana-pro".env.GEMINI_API_KEY` in `~/.zee/zee.json` + +Notes +- Resolutions: `1K` (default), `2K`, `4K`. +- Use timestamps in filenames: `yyyy-mm-dd-hh-mm-ss-name.png`. +- The script prints a `MEDIA:` line for Zee to auto-attach on supported chat providers. +- Do not read the image back; report the saved path only. diff --git a/.claude/skills/nano-banana-pro/scripts/generate_image.py b/.claude/skills/nano-banana-pro/scripts/generate_image.py new file mode 100755 index 0000000000..48dd9e9e5a --- /dev/null +++ b/.claude/skills/nano-banana-pro/scripts/generate_image.py @@ -0,0 +1,169 @@ +#!/usr/bin/env python3 +# /// script +# requires-python = ">=3.10" +# dependencies = [ +# "google-genai>=1.0.0", +# "pillow>=10.0.0", +# ] +# /// +""" +Generate images using Google's Nano Banana Pro (Gemini 3 Pro Image) API. + +Usage: + uv run generate_image.py --prompt "your image description" --filename "output.png" [--resolution 1K|2K|4K] [--api-key KEY] +""" + +import argparse +import os +import sys +from pathlib import Path + + +def get_api_key(provided_key: str | None) -> str | None: + """Get API key from argument first, then environment.""" + if provided_key: + return provided_key + return os.environ.get("GEMINI_API_KEY") + + +def main(): + parser = argparse.ArgumentParser( + description="Generate images using Nano Banana Pro (Gemini 3 Pro Image)" + ) + parser.add_argument( + "--prompt", "-p", + required=True, + help="Image description/prompt" + ) + parser.add_argument( + "--filename", "-f", + required=True, + help="Output filename (e.g., sunset-mountains.png)" + ) + parser.add_argument( + "--input-image", "-i", + help="Optional input image path for editing/modification" + ) + parser.add_argument( + "--resolution", "-r", + choices=["1K", "2K", "4K"], + default="1K", + help="Output resolution: 1K (default), 2K, or 4K" + ) + parser.add_argument( + "--api-key", "-k", + help="Gemini API key (overrides GEMINI_API_KEY env var)" + ) + + args = parser.parse_args() + + # Get API key + api_key = get_api_key(args.api_key) + if not api_key: + print("Error: No API key provided.", file=sys.stderr) + print("Please either:", file=sys.stderr) + print(" 1. Provide --api-key argument", file=sys.stderr) + print(" 2. Set GEMINI_API_KEY environment variable", file=sys.stderr) + sys.exit(1) + + # Import here after checking API key to avoid slow import on error + from google import genai + from google.genai import types + from PIL import Image as PILImage + + # Initialise client + client = genai.Client(api_key=api_key) + + # Set up output path + output_path = Path(args.filename) + output_path.parent.mkdir(parents=True, exist_ok=True) + + # Load input image if provided + input_image = None + output_resolution = args.resolution + if args.input_image: + try: + input_image = PILImage.open(args.input_image) + print(f"Loaded input image: {args.input_image}") + + # Auto-detect resolution if not explicitly set by user + if args.resolution == "1K": # Default value + # Map input image size to resolution + width, height = input_image.size + max_dim = max(width, height) + if max_dim >= 3000: + output_resolution = "4K" + elif max_dim >= 1500: + output_resolution = "2K" + else: + output_resolution = "1K" + print(f"Auto-detected resolution: {output_resolution} (from input {width}x{height})") + except Exception as e: + print(f"Error loading input image: {e}", file=sys.stderr) + sys.exit(1) + + # Build contents (image first if editing, prompt only if generating) + if input_image: + contents = [input_image, args.prompt] + print(f"Editing image with resolution {output_resolution}...") + else: + contents = args.prompt + print(f"Generating image with resolution {output_resolution}...") + + try: + response = client.models.generate_content( + model="gemini-3-pro-image-preview", + contents=contents, + config=types.GenerateContentConfig( + response_modalities=["TEXT", "IMAGE"], + image_config=types.ImageConfig( + image_size=output_resolution + ) + ) + ) + + # Process response and convert to PNG + image_saved = False + for part in response.parts: + if part.text is not None: + print(f"Model response: {part.text}") + elif part.inline_data is not None: + # Convert inline data to PIL Image and save as PNG + from io import BytesIO + + # inline_data.data is already bytes, not base64 + image_data = part.inline_data.data + if isinstance(image_data, str): + # If it's a string, it might be base64 + import base64 + image_data = base64.b64decode(image_data) + + image = PILImage.open(BytesIO(image_data)) + + # Ensure RGB mode for PNG (convert RGBA to RGB with white background if needed) + if image.mode == 'RGBA': + rgb_image = PILImage.new('RGB', image.size, (255, 255, 255)) + rgb_image.paste(image, mask=image.split()[3]) + rgb_image.save(str(output_path), 'PNG') + elif image.mode == 'RGB': + image.save(str(output_path), 'PNG') + else: + image.convert('RGB').save(str(output_path), 'PNG') + image_saved = True + + if image_saved: + full_path = output_path.resolve() + print(f"\nImage saved: {full_path}") + # Clawdbot parses MEDIA tokens and will attach the file on supported providers. + print(f"MEDIA: {full_path}") + else: + print("Error: No image was generated in the response.", file=sys.stderr) + sys.exit(1) + + except Exception as e: + print(f"Error generating image: {e}", file=sys.stderr) + sys.exit(1) + + +if __name__ == "__main__": + main() diff --git a/.claude/skills/nano-pdf/SKILL.md b/.claude/skills/nano-pdf/SKILL.md new file mode 100644 index 0000000000..a2933b8377 --- /dev/null +++ b/.claude/skills/nano-pdf/SKILL.md @@ -0,0 +1,20 @@ +--- +name: nano-pdf +description: Edit PDFs with natural-language instructions using the nano-pdf CLI. +homepage: https://pypi.org/project/nano-pdf/ +metadata: {"zee":{"emoji":"๐Ÿ“„","requires":{"bins":["nano-pdf"]},"install":[{"id":"uv","kind":"uv","package":"nano-pdf","bins":["nano-pdf"],"label":"Install nano-pdf (uv)"}]}} +--- + +# nano-pdf + +Use `nano-pdf` to apply edits to a specific page in a PDF using a natural-language instruction. + +## Quick start + +```bash +nano-pdf edit deck.pdf 1 "Change the title to 'Q3 Results' and fix the typo in the subtitle" +``` + +Notes: +- Page numbers are 0-based or 1-based depending on the toolโ€™s version/config; if the result looks off by one, retry with the other. +- Always sanity-check the output PDF before sending it out. diff --git a/.claude/skills/news-digest/SKILL.md b/.claude/skills/news-digest/SKILL.md new file mode 100644 index 0000000000..7e2b8246db --- /dev/null +++ b/.claude/skills/news-digest/SKILL.md @@ -0,0 +1,335 @@ +--- +name: "News Digest" +description: "Generate daily news digests for portfolio holdings and watchlist. Aggregates financial news from multiple sources, summarizes key developments, and highlights market-moving events. Use when you need a comprehensive market briefing or want to stay informed on specific tickers." +--- + +# News Digest + +## What This Skill Does + +Generates comprehensive news digests for your portfolio holdings and watchlist by: + +1. **Searching** via agent-core's Exa MCP (no API key needed) +2. **Filtering** for financially relevant content (earnings, filings, analyst ratings, M&A) +3. **Summarizing** using agent-core's LLM providers (already authenticated) +4. **Categorizing** news by sentiment and impact level +5. **Outputting** structured digests in multiple formats (JSON, Markdown, Email) + +**Use Cases**: +- Morning market briefing before market open +- End-of-day summary of portfolio-relevant news +- Earnings season monitoring +- SEC filing alerts +- Macro event tracking + +## Architecture + +``` +Stanley -> Tiara (claude-flow) -> Agent-Core + โ”‚ โ”‚ + โ”‚ โ”œโ”€โ”€ WebSearch (Exa MCP) + โ”‚ โ”œโ”€โ”€ WebFetch (content extraction) + โ”‚ โ””โ”€โ”€ 15+ LLM providers (auth.json) + โ”‚ + โ””โ”€โ”€ MCP Tools (100+ orchestration tools) +``` + +**No separate API keys required** - leverages agent-core infrastructure: +- Web search via `mcp.exa.ai` (same as agent-core's websearch.ts) +- LLM summarization via `~/.opencode/auth.json` providers +- Python 3.10+ with `httpx` + +## Quick Start + +```bash +# Single ticker digest +python {baseDir}/scripts/news_digest.py --tickers AAPL + +# Portfolio digest (multiple tickers) +python {baseDir}/scripts/news_digest.py --tickers AAPL,NVDA,MSFT,GOOGL + +# With summarization +python {baseDir}/scripts/news_digest.py --tickers AAPL --summarize + +# Custom time range (last 24h, 7d, 30d) +python {baseDir}/scripts/news_digest.py --tickers AAPL --range 7d + +# Output formats +python {baseDir}/scripts/news_digest.py --tickers AAPL --format json +python {baseDir}/scripts/news_digest.py --tickers AAPL --format markdown +python {baseDir}/scripts/news_digest.py --tickers AAPL --format email +``` + +--- + +## Search Categories + +The digest searches for news in these categories per ticker: + +| Category | Search Query Pattern | +|----------|---------------------| +| **General** | `{ticker} stock news` | +| **Earnings** | `{ticker} earnings report results` | +| **SEC Filings** | `{ticker} SEC filing 10-K 10-Q 8-K` | +| **Analyst** | `{ticker} analyst rating upgrade downgrade` | +| **Insider** | `{ticker} insider trading buy sell` | +| **M&A** | `{ticker} merger acquisition deal` | +| **Macro** | `{ticker} Fed interest rates inflation` | + +--- + +## Output Formats + +### JSON (for programmatic use) + +```json +{ + "generated_at": "2026-01-09T08:00:00Z", + "tickers": ["AAPL"], + "range": "24h", + "articles": [ + { + "ticker": "AAPL", + "category": "earnings", + "title": "Apple Reports Record Q1 Revenue", + "url": "https://...", + "source": "Reuters", + "published": "2026-01-09T06:30:00Z", + "summary": "Apple reported Q1 revenue of $130B...", + "sentiment": "positive", + "impact": "high" + } + ], + "summary": { + "total_articles": 15, + "by_sentiment": {"positive": 8, "neutral": 5, "negative": 2}, + "key_themes": ["earnings beat", "services growth", "China recovery"] + } +} +``` + +### Markdown (for reading/sharing) + +```markdown +# News Digest - 2026-01-09 + +## AAPL - Apple Inc. + +### High Impact +- **[Apple Reports Record Q1 Revenue](https://...)** (Reuters) + Revenue beat expectations at $130B, driven by services growth... + +### Earnings & Financials +- [Apple CFO Comments on Margin Outlook](https://...) +- [Analysts Raise Price Targets Post-Earnings](https://...) + +### Analyst Activity +- [Morgan Stanley Upgrades to Overweight](https://...) +``` + +### Email (for notifications) + +Generates HTML email-ready content with: +- Executive summary at top +- Color-coded sentiment indicators +- Clickable article links +- Unsubscribe footer + +--- + +## Integration with Stanley + +### Use with Portfolio Analyzer + +```python +from stanley.portfolio import PortfolioAnalyzer +from stanley.skills.news_digest import generate_digest + +# Get holdings from portfolio +portfolio = PortfolioAnalyzer() +holdings = portfolio.get_holdings() +tickers = [h['symbol'] for h in holdings] + +# Generate digest for all holdings +digest = await generate_digest( + tickers=tickers, + range='24h', + summarize=True +) +``` + +### Use with Research Module + +```python +from stanley.research import ResearchAnalyzer +from stanley.skills.news_digest import search_news + +# Enrich research report with recent news +research = ResearchAnalyzer() +report = await research.get_report('AAPL') + +news = await search_news('AAPL', categories=['earnings', 'analyst']) +report['recent_news'] = news +``` + +### API Endpoint + +```python +# Add to stanley/api/routers/news.py +@router.get("/news/digest/{symbols}") +async def get_news_digest( + symbols: str, + range: str = "24h", + summarize: bool = False, + format: str = "json" +): + tickers = symbols.upper().split(",") + return await generate_digest(tickers, range, summarize, format) +``` + +--- + +## Configuration + +### Agent-Core Auth (automatic) + +Authentication is handled by agent-core's centralized auth system: + +```bash +# View current auth status +cat ~/.opencode/auth.json + +# Auth is managed via opencode CLI +opencode auth login anthropic +opencode auth login openai +``` + +### Config File (optional) + +Create `~/.stanley/news_digest.toml`: + +```toml +[search] +max_results_per_category = 5 +excluded_domains = ["seekingalpha.com"] # Paywall sites +preferred_sources = ["reuters.com", "bloomberg.com", "wsj.com"] + +[summarization] +enabled = true +max_tokens = 150 + +[categories] +# Enable/disable specific categories +earnings = true +sec_filings = true +analyst = true +insider = true +ma = true +macro = false # Disable macro news +``` + +--- + +## Scheduling + +### Cron Job (Daily Digest) + +```bash +# Morning digest at 6:30 AM ET (before market open) +30 6 * * 1-5 cd ~/stanley && python -m stanley.skills.news_digest \ + --portfolio --summarize --format email --send + +# Evening digest at 5:00 PM ET (after market close) +0 17 * * 1-5 cd ~/stanley && python -m stanley.skills.news_digest \ + --portfolio --summarize --format markdown > ~/digests/$(date +%Y-%m-%d).md +``` + +### With Zee Integration + +```bash +# Zee can trigger digest and send via messaging +zee agent --message "Generate news digest for my portfolio and send to Slack" +``` + +--- + +## Sentiment Analysis + +Articles are classified by sentiment using keyword analysis and optional LLM scoring: + +| Sentiment | Indicators | +|-----------|------------| +| **Positive** | beat, exceeds, upgrade, growth, record, surge, rally | +| **Negative** | miss, downgrade, decline, layoffs, lawsuit, warning | +| **Neutral** | announces, reports, files, updates, maintains | + +Impact levels (high/medium/low) are determined by: +- Source authority (Bloomberg/Reuters = higher) +- Article recency +- Keyword intensity +- Ticker mention prominence + +--- + +## Troubleshooting + +### No results returned +- Check `BRAVE_API_KEY` is set and valid +- Verify ticker symbol is correct (use standard symbols) +- Try broader time range (`--range 7d`) + +### Rate limiting +- Brave Search API has rate limits +- Use `--cache` flag to cache results +- Reduce `max_results_per_category` in config + +### Summarization failures +- Check LLM API key is set +- Fall back to excerpt mode: `--no-summarize` +- Check model availability + +--- + +## Examples + +### Morning Briefing Workflow + +```bash +# 1. Generate digest +python {baseDir}/scripts/news_digest.py \ + --tickers AAPL,NVDA,MSFT,GOOGL,AMZN \ + --range 24h \ + --summarize \ + --format markdown \ + > /tmp/morning_digest.md + +# 2. View in terminal +cat /tmp/morning_digest.md | less + +# 3. Or open in browser +python -m markdown /tmp/morning_digest.md > /tmp/digest.html && open /tmp/digest.html +``` + +### Earnings Season Monitor + +```bash +# Track earnings-specific news for tech holdings +python {baseDir}/scripts/news_digest.py \ + --tickers AAPL,GOOGL,META,AMZN,MSFT \ + --categories earnings,analyst \ + --range 7d \ + --format json \ + | jq '.articles[] | select(.impact == "high")' +``` + +### SEC Filing Alerts + +```bash +# Monitor for new SEC filings +python {baseDir}/scripts/news_digest.py \ + --tickers AAPL \ + --categories sec_filings \ + --range 24h \ + --format json \ + | jq '.articles[] | {title, url, published}' +``` diff --git a/.claude/skills/news-digest/scripts/__init__.py b/.claude/skills/news-digest/scripts/__init__.py new file mode 100644 index 0000000000..367774ba53 --- /dev/null +++ b/.claude/skills/news-digest/scripts/__init__.py @@ -0,0 +1,29 @@ +""" +News Digest module for Stanley. + +Provides functions to generate news digests for portfolio holdings. +""" + +from .news_digest import ( + Article, + Digest, + generate_digest, + search_ticker_news, + analyze_sentiment, + format_json, + format_markdown, + format_email, + CATEGORIES, +) + +__all__ = [ + "Article", + "Digest", + "generate_digest", + "search_ticker_news", + "analyze_sentiment", + "format_json", + "format_markdown", + "format_email", + "CATEGORIES", +] diff --git a/.claude/skills/news-digest/scripts/__pycache__/news_digest.cpython-313.pyc b/.claude/skills/news-digest/scripts/__pycache__/news_digest.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..980ae6bea911bb2f41a0196d75d9381e91bb82a5 GIT binary patch literal 23323 zcmcJ1dvqJudFKq?Z-NBDH^t$bph!@no}^^iG)cW57DtR_Qx*e(LlPDU&@-SVAx^`_ z?S^vNN^0VYO0!2)x;>`bJ+X35w^8@(wo(%}?%C}r5hx}+R$ArMeRxm*pe$z-r+aqy z_uat&Bn{c_HhW3jxpUu-?|$ERzwf*A(Cv0`aBuiRkr$rixWA(p-MO=YhldRu_bMlH zGAHt);SewL>}ik<>}iyZ>}irs>}i(G>}ioLcp48`587ngLAz`hsJ!Wr)#P ztKb?qv80L=S_0CSb3^68&kz% zD#Yqso*EWYiS(jVZZq20Y7lE#Too&05I3;5YH^ELhf>0+8pPM0+Q9N!#Cl47o|o$$ zk=~F^7qb1*OPa(+R&V_VPTVRsq2^}PT1K^sE!j3oSsOO7HCso+22T4Ew~1}J+yPd$ zNPlNFw4Z7eH?ms%TU}yDwtSP=dCH%ii6Cpec~wjoi)mREvx&vDikquAx$RUy?Cw3u zaUmPWooZ{yt%tx(7$yvX?V(wo;~Yn&bBZt!nUIu(uuqCfawrj(g>n4EL?{-OE;t<7 zXh{*m@u_K9nv`Nn$#`@u5}QzjGZ%!Y^df4Vz^fxP zA;l7%;kYcdD#Fv!8Bq$!;YlGB8xsy6J|axZ@fRawlB@)Uqj5ozrbFnBB=kLXKsYO1 zPy|_eVJ0F=V?l?b59J~WDV&&*rCx`icUI`!BbOM$_;sUBURY6br}4q^=Osg3l}QnB#rgBu4`V)jk$VgwSV2QO)BK zDLRHY8{(uyWJ*$Po>J7In$Ad}glZ-qRmh=e^nz+u zX5M442r()q9?jVY>? z>WfGS%uG+np)vGGOG0kjbXWHJ4QxPQ*2_rm{n3iM!*HpI8 z;Td$+gk<<~L^-RP&Pk!Os`*?cM;yi+1-w_=dUjsAt>v9Kh^RO^@&jz(gV zYK?}@DKn7-1un$L$I)X2lR8OVr%C~Zm{u(_x*n4zu$1V!eJp-1rj5*z3y!JIv4|3y zo{j?`lw{=>FbK5&ML|i#!)G=4PsGPU7n1F{B=n3LAz-ELfQK>@O(?<(Ga)%4$^zj*p34%#`d+}+#73ZO*=ZGWT?EiY!jg~(Vc`yYqm40VJf7Wr$S*lzQ+!b{e@*b z5d=#4h4q~BJPX*uu`^*7vR?>I#^WsLJQI=uo{IJ&OEc(?_ToMhjmM|XU>GdT9f`e& zj$*j%wFo=)tduwxN`xmVB1~INcgAes;UWUBa;G@ZQ;uk^ z7~L(F$esy%z^7XKWB_4QdVeSCPF4*`z{d)Zsv?9mcm$MDdQi1!z^dB9Kq3=y8Q35Z zNkk>pI3q`~)#EdASOS1cN?49COmbAUPtTm8jZZj0LvX1RrY97lOgtKYRSVl4$@ zLEqLpeasu8gcfYLa>e(x2 zGZi)0-Phb1f92I@uRNRam0#U?WoIUvR#|&}!?g{W>bm9Xjj8I5neytZFI{;lla1Cg zJ@7ldjup;ncRWPB-0NJRNVScQ#zIrl=&0%#9i57g%|t2e8XX0SjAm1cMuA3TB|$hn z7DuvmbaX5pM!*OfqaryJi^UU+3@f9f+T;=(teafbL?e}lk)rxXM=@#G6{DdzH-jY)i;<}%r^2JsME7?r@Ot>OrSs!O8}326)y z4ya?ald&eT3F2dl#-#BOXyfQOPzd2CTNZaI@>6JI4KksnWyoX_8{|>Q#K(P(R}5X8 zV(@YMu}$N}LsVv+(~l)j8IFK&a&iI}GsNgH#STNpoBb&6opzVJvIx~zE>75%kY|EnLVH#Dj9-n{evmu&- zM$sHJH(~Y!{9^n#7qA?a2|EXjas?jpVe)7g?^C4#qv}au3r0uvWm8>eE{x`hgdK0% zq6f^fL}kaxn;w z&9$xNR214n0-UzBSsNY=jCGv%9C9eX2XB_k1UlcS{e#-HZ^s|hF7#bJaOJ@79D2QW z&bH*+k!cIu4BbASs@}I`tH>1luhxFOcCIhev3t4WiB!iEw~K#JeW&`ZP`cx(CGkY6 z99LK`oPJR?o%9+Wm>a0D3;*-;lG3TDz}MX^phai09d8` z>)f!R5Yb%)!3GAwC53XWfnXk_(5OLl9+s@wH)qMOM_u#vYOD9Z3mO9C?&iA;M22r6W_~Pn-N1ck$)Mi_fG@WsI=Av!U_kKx#wJ?Ebm2%R4Sk zrA<96CNI&74>>$mnoQ=hg{B2%v47$Gjo{BXylR7?`c+dxI-mGB_N0E({673PywgU8 zKeKoN5jnRl8=5kXP;Taijaz{iK?-amR10&yoG3xZE-`*x2?Hx(`GgXNlO-BX?EN}K z6zI)_>16%781sZBU`@7(;4-5Ui2%;wwAy(lgfk(e16gJi(gQjoMQ|ioJti8#7W^J= zhqs4se$N_w)C;S#GJ~&<~rp&&#(RsosOvi?0>q?W2c84PLfa@|W@ZWe-sPA}ZIQ^;ZyD zGZ^{Hl=d>bBn5tryk94ewzNhM2p=$_5HP7`HXY#3a4IN%>X>-o#DUKZjvg9(=ILWY z1EN}dbZ}qany7$DrixXME54;X|DoBVAB(te^)D8uD%#W5_DoS_#$LX-IaSq> zws+8*vy|;GoMyFy)tWV+EkO|Q@GiXU#zJVlD}-)WZ8k#S%&ppNpR{#&NL>wQ`IzAm z%mM>#lKKtvZP}XH1|t@r5Obkz1?$K1n;zZbFP>cJ9PwYQ7bl}7@qvEmQq5eUUo%{gWzeRam5oMGleK@%#E~sTxTehd8*)us# zbnpB4Ut{<8F4P>IdsL(-$;M-SqbuQlxp%pShyE4y1Z@T2bjblE`K zH!yoxt=+R^s=9CWEL+P{*7Bw5&1viAKaOUK{29A<*cGaR3p(;vmQyP78tt8W4j`g(5LwT#io(!$XII8oLV7C`23( z9xGDPbne`_pvpmR89N(;h%aDPT}X^Z&IDNo`J3pNYKch+U}uOqrRiu0ViEfw1fNVO zg2kjM$>w8aAdu7=)|XA=FI5i_U-WKN>z(}jD0dk@8K{FMO9V1~33^tzjo5 zzR(FtM|e6)Vzd{;Zy0Abfosy}t|?$nHtdZ+AFxWU4)Gz58BuoF7p5Wn4kpXj2u1RF zllGjDJz3NR(Q{Wm?I>^y0V4J_ge$5=IuD*sftcM)bt)=9tZRve^A zmPRR;{D;W#yZ9+|M4aV5v~hO#CHpJ(uR52?x>B~Tdp4K$diiY1R*$zO_lC5sZpCVH zTV@9zIyjGSj?Xw9m zT?T9}Y_A@+DuwuU(aaP>H2VdGYD2)*>z%%SP25OMv{p!*whFo|3|;_XniH)$ynN;w zY*YiFiy!6zUCn?lLNU4XtzL6p*|;9MMvC=3`LpmUc(Vr_$;y3FLeNz+!kI`cBwx_L z40?#kNO)4U>8U3GEuL^_nzT-%q|AV1l(-m%capv!8`d{$u2!%*qvb0DBAPskn6d zmDBT2FFe0gv-x(@TPITPq1n9|t9#j6k+N3I_oc11KxLP{c=3zNMGdKiWxPfchC?s zjpS-9w66*hx*{FwW9DJA4xb^gjweru-d1!75d8`Jjpq(vPfw!HFY>P%kD6Uv%ra~l z%IzwBcsRurL&{?kOGICf=>S;7HD#>B)1;>A^h&*kHEqwJ&knJI$gEh&e4hDL&7G>#tBaRUCR zyv9U<$pVem9GI*Y^xid6r^krZ!!8fE#V{i1F+&Y{DE|~|dRWb(A?E6HQQcZ-95O?# z6~@umCMO(O1^O3y0cgN|VZipIf{eWTF)(-~4@@TAy_5$FL) z0VPDnh0u$kNHlZ?sxAjZzekhC?%*bNJWV>NPNfUS?WpQGC!N75oD2;{rSl=x1eQFm z+QyM~CKNsk{_eXN8bl`-rX|$@e8?rIu`}jH<4mOwL{H1Lmg0Xr(?N_b7>ZDELR+k!CxGis z)VgY&l%Tbjp_L^S9tgzyZ_%iEN777&2fgnTAj|)W;z+4ZEi=lN^y{V(G?~IU=3E-< z6-ZwNJ+BlfQO(qa^Qs|^y0c3plZZ}r_9+));eMD6Kx1gaF+TzQFcdH|3iv7Xg$O6e z6s9Qwk_HWSLOB-!i}gp;6V^Kj6+$pRC}vzYEuN0ouqGc~~nW~0wBXZ_H{`TSSgue4tc zUI{MLrc1i!tbgMy$uzcKK9q6^_k9)1zNVC~Y1!9u*VnSxlBuk_UVW`P<890M8#5Jk z(B`e!xvJ(B&RpgB8D}o_%nht~IB)54QC+I2ZedHhsO5f*aQ(ow1J{pTJGMCRcFpF? z10=Ej(v>eQoLesMN|$$K8e13nMZ?0**Y@1llWyEHZ~NQo#`&H18e3oM{Z{YdWV&(3 z`~cKp*Uw)&zi7MJkgnUdT-TGT>$w$Jt{X_#4P;t3F7ChaD>oylRtU~ht^K$6rdkgz znC`Xiyj7ZR-IEgb{H&2HZN(^3zLp22Ty6Ky{M!3UJLmGu9(b@3uMZ69|IdtCf|fU% z{4XC`IhUVKPrL8g+)Li(h0ubyD2q<-cQ%zRd6K z;(x8LY;ZSsr-~n}wA`sSQg}nzV7>9qR(`PBa%Wqg1uuX8cm@3LRrkXGeq|N;TU^Nc z{m1#iTFaZ93E?+QRNb3q15)3#Iw_`vAFMOI>0_zo21>2uDZZMgJhd!b$NYNBV2}09 zR(`PE^=6xk!ds~;Z|-2FdRTb3V{eD?FD%u2TaABFZ$WK;(Q2lc4kN;ASRRlDjpZR~ zsj)mFlmlRJ3_)WT-=v9NjLF}1JPo5R0lXyHt_UHrCg^AOQ$jzss=$=X9l|+D2!~?2 zK^Lq}CMAIxOm*TAo-^kPI!;VRU=TJF3p1M%jX9+%nL!3@QYJ$QU_+>@Sq<3T*n(Oc z0_?746lqOmz+s+IM2-THYkO_g9w$+Iz>tqvbA&5fwKX+0xrTZE359-+pF)I>?M*LN zU6&~?%ak`j^WwIwa3+@(p4qC2h`wxdtQEfIPGxgOI+b-n=K{S83FNTb*E{G?vavpH zAHV;3&|C;SK1nFZ(g`E4b7D@Pr_=e+3C2Itxptk)pU!i6!EA!pER@%z_b`_i=O*Zh z3h<@*bCke|7zc69;N&n5>z&TYZGx!s2n5W9HK+MgVXkdJE9$jjqxyXmW0xB;AEb`lw%=nyT3Nd!c0%lN(jmgu9(Ul{RM>6X{ z@MJSGVM+NXNL?#-l;5E$$g`k+g=Dvo4|}|``!vs6dew2oF~4=$E6kZPMZQbPi^;FP zgrKwN(&HB&pWnIcY)UzsGDT&VzHspi^E;M{8dF7$i`F-suRCuJF1Pij+IlnI@~fUJ zp80cky{(z@4GX4);|oIzw%0s2JZWLmQrYHL_Cb$%Y4qag{O6Y4O(}O1l-UdQ3k~xp zub;klI$hg2x9{@cSC3{hE!75>-CZd+V4K;x^XLV9ZI_dy{@O1-OVX? zbEY}4Sijh?aPqa&H%_OUw;|V&yRL?eyY$k?#gX~iWq0dcck3GiuMgZR{j<71sarZQ zx!e=E+Y@=OsO0jF`NvYeK)R@XQGB~-69zKxPJ3Gx8*iFkZ%=u*zU^&!P{$S5uQYJB zqOW}6SHEz1$Fj9LWvyPYzUI8)TpU~$x>G`T##VI6bJ278++ADUeP_w+QB7DrfLT`^ zd11aR}wgvT07onlTf}yg)CiKrbLU$V(n} zA#Vt!Nn4qZ9cJc+g(R<#Y4AOK%rcV0{3p-kPNW6o1US{di#F+0UjY9XpexiDcB(I! zA95AFwbf_(5Kzv^ukXU3*;o)5HWiX;u;g190$y70ax?09M0x9HEbm-p zS;GyRhaJQARr19gtr>QTwjN8&HSF-f6m-~$6SXns9?3~ahTS?o9Ck%>vec1sz2Cz* z%7S!PF4j1NIbQGbd7-`jv4(|#-)pn@7-|*B3jUd$#~sOTQNxSOOp8qXLjoPlpP6Y!zGub#Q|07z~G$H?j;8C;=(a~Q1fKqr_>wT`{nvTv5+cgL{VWURmK!I(*+B05OB3hE=B(-@O zr3sY(H}WC{T%?Qhmdx(I=k@0|HwMdzZFt~j_{a&XT2cf}QRefNvJmu4=`Ecu(4i&|1eEkE&A z+%NH6ZNAbxZ=RRaB@J`^f8#5gZ%kLUzvHdQxcrxnTs$)0c-OVzeyRWJ;FZDo)`jkL zY0GkHN2;_VT^gJl%v4ohZ@$*N;D(Z^s(ZO=XR2yvx~g~X(0gUIney69WqqcsI#XJH zue^C7oGx$A)U-ZuTgyFj`&LRgp?Q7+2>%NUQ%f~l=Z@SHHs9<_3s21LyX&gGSKGNb zk*?i7x9>NO-glK=I(G5c{JytcO&{*yN-7@|asIlM{XFL?ojvy8an5&$|45;2@Z~<^ zz*hc_nIGu3+_Cg`;)NN9sdhO8<3M)!w(EB-B-J$)I-j#L3lpoNI~xKFo4$uNIBnOC zIKzf8;6IO1^Ek2)cGR(hz9(a_AOyZ8Z5EPNV@*h13*bY&Jh&uCk$a4gyz;AMd@<{= zxgcK4X+yAccWC=nlR=BtpmEBMQU!3?upRa|HnOe}?L9m&BCdH2n@s3&9yg7EE@*BD zeB651z>SpZaYH$IsveW)0*AoOu6O!a3t=L<9H!%Wn!V52*4SdsebU_JZ82eaXdC7+ zDp!w*;jSB+95rSe*AA=hWamEZniA|0RvVnM8%T5_oq*Ubmc?jF@aX$Si~?xvr+6?y zArle451K`c+Se(TRQ&R*@Q8WJIb!<=SRaA~hAqRZ+zGzW=?-T;s%xFg+sz@JYFg(+ zL+=Ec*=n|OCbY|JYS1HM1~oiKXb)#w84uVJFiZPU7(hXaM-A#mN4DM3(A1f+&>pp3 zH@MY}z4I1F*(?#Xqco%N&u6)XQ_IcUQq9|LhQ2%boypsLy7|f5eLpyK=g^Y)Tx#IC zRMTn3<3Q49BuS%XMNZvtUjoRI$#Q6A1Y{#nQQ2HKBxtAXW1W*jkyit&k~> z!O9(%Vwf?UO#4_hLMbm3vyE#BiLh#qDDf;^xPi!kLu=*#AS^Rf&(Tcr@KhJ%kvXKm zh=E#^Mb9~dR6ZdyrkIFqPI8yEA}U%pTe2Uuiufr%L2hO*vf|}zB`Is=J%8ml+pl+B z>q=K`O#3_L9QS?x*~9OaRL)uMfj4xOTsnO5Ft}S+S*D%@2=xva=2bi9idGz)-M?(B zPT8vGkG*Z{c;M!IRlumV8y1UiZch2O%^uE}yvrtk%H+RWb$W>cqZwb_f_tH6$rqeG z{GPM;p1=0$soy^JAKG5)xY3dJcP;ySQvRN_f7i0VKjrVgz5lIn+CTJ8)5f&7<6HaY zU$|O+rTlj)Z|qBXJ2IZ~OmQv5iY`br%x24jO7!ZZ4{EsL&W{)vyxeE%-^Aas^8EqJ z9ov&UUcP6q?BD44UW1Lo8_n=x?ZEE%t=Sy3c(kz|?uYm3YH4f&DzVP#=!BHkJ!~r^ z%l0y^AbYKlBvA*&V@HEB?GS*X1v+^ggRo8BLS3qPY-Va&VK$i9;bpXV_;FdH?bIM? zl*#FliKWY07GFp?H!qnsGnij9QbNLPr2l|zj2pO* zFs>!!Z{kRKq9O4@0+GU~Kqow`tQC1^JFIgo%{G!FKggA19P?S%)MVh)M7;~mYmSz4YX0X?>VI*`fkC>e1%qqDVbtp-;1?RamUCu~A^WShA=Q!Tm6m z6b@*23;B&I-}!p>3Q8xnbC}vObP7phd;3Vz@LXHc96;4=Dj!H1V7~R=DBTzg29qAD z>=>9rne|xZN0P>X(8h#*F#HFAf>(JSw|iGHGt<-rJ4`xoWX;}D(hi$+@KnvXc0Q%# zIkddcP%{rbfK0g6Lc|DG(KuQva*V1ZHcqRCRqkA64yu~t)JM`)W{uiMBT&LBb`;66 zEtuh|z`UJKp`rYkltm3J@MwqzWB5W?t{=;hNe(aAVAd{bH2&O~x`Tb4Ft3$M7X zWWomSWn<^;fsEUCY4kTnVasMKUbfYwY&G-8ub;ejazRep+LvvcQ?|`F>)*C*#hnXJ zEjm@(LMlbN17oXzjib$d$#v0nS()EH-*)-*T{N1F8M8-xM-v5{T-|Af&{@haS(|5fmVXb%dv8#_=c`Q>}dG+v> z!wcODq1UEvOx+x~DK542EH(GuYFw({^LFXu5A0l7J=i}t;|=Fa?z(FJ(doUoE!V-o zU03_N{;JR1LGX*;-SM3rHv_l2Z-xF$`V;Ba)3^KI;{V$Am$uuf~O;+ zev*U~w6IRWOl$${wTy*K+L2;KN&&V9DK@0!q-y!zBE^mrPd-KuA;p1|+^JfR=ZI7} zSwCDzFL263x_e7;p41!xVW;~gq6c$TlCMV((Pvc{0W20v3fV@XQ~^dnuOF@X#L|N0 za_kfG__tVb>MTpvd<@0!KXK%+Ai<Yv{AwL zLdJwfX`8e|In6jx8-<^olhaBRuULl5$c~Fmc z?(Pb$?Hn8Q8F|lcWr|F0){Z>822|20yd)%l3j?NXYpeMGKH}ADLRM7xz{pGtc0tMK zcHtv2Y>i+#n~-+FkTwee003dXACQWjDQzyVE5vTqHbv6=eR z1;=Ep0?<$^pm%ruz_I=l&pb6KOeUrM7>WbZ;~jz$iYc9nBuB<~ z2?U|6{@q<Y8 zS%S>)^a``x-@Iv4b8f=}B%+~d1*@xv^nrCI;?uoC_o}h5MFl%VE0K`(T2}*EfGE!BYWpyYao9>@?SjNM2FWAtU2X&*GUgq(vlz?0<`Os%k)pbFao{L5qlr_^3`wyI)of-p=Gv8I zt{DlGyHNGF@KXrl8E5U^kSVRr_-g2Owq?mwy5i#e<+Dffys%eT_BKJsvvB;iksBj7 z18MK>IdjGa5g>8ME1a>R8O&MB#)W-L8~bk8|Df$o+wCeuALgqNUtL2wn)&i2;rP;! zxIFYsYUr7ze{0P4_vvu2d_kU;q&E8uguA5igsk-e#!6SS-3U1uASdLtq{TYAR z)sZVBmyf`9slmQdUbMmWKe-~i8*CxC@D{UoBUsXo?&XbpQXBW&Qf?cTHuf*I58OVy zbbNUE__L|w&n}IGmPaC~kx2UZ^Gi>iUE!=z-U}naV&7Hk6)V%7FBP>yn%HJrsVsIm zSGZ!cQxlqDIdYCTFUBc;8~&$@2blnnr#nQ2#DuzSzG&?+LGVyG5A-3TqYM1lah?Px zJ?2N|WFM~+i+hZZ%mE8}u~fu|={}*oah|9#v0yQ=NKh@M!pr+POu4zIS`51D- zA6&K!G#^bK(NXwn1=}OP@z)09Oqh2oWDDLS3Bc6KtwG3u37WB1lcCrmPu8aqtC}-5pI&@< zD+E=lw<+V^4BLIm0zDr1j(nD~c~i!{bH&UOjYzbuO7ve&WQwXY?(L7LzXbOE-YV7G znQ?D=MEw=>P50d1jJG7?-mxl+hjW!IJ8M$TnzVDn?7;no7Sc~HH*8HcY`rPoZRkmR zdVko^Gk^Tjxr^t1>q4rbXLjF`rx&B0J(#gNzw)K8e2G4|Q}=q^a$rv?0B+=Npg-*& z_+g+QAK#g{GVwc+RG@#(vE(0kj|}}@8Tn=%toJe{Wpo1~2%>ZxQ^Z$h%42yYTQuKK(t{hYk3#Os(p31Lr?|f-@1MwfhdeTN!Y4*?txDTXYc~x8d+j?qCn@*S2SqlIVb<|MnUUqj4ly`? zW~k)x{Umq~jd)#QuRB>nEnl|6!OJGl>l3_#_s{p^drQ23q5ngAtW-Jp;`s@RDqd`) zsN$6>8(%qZT;cFoFn&mnl`<#qou6DtT#J3kA-Gag!q?6tJ01_(ckrGCWrf4zmXAGd zpLnb3&a*$ImeB+2i)uTU+lu|5J)tsj1?9)FV6=1{O5B%;+Sjw)#rX{r?)X4vf)fiJ6U>FR6THR z;4RsY53LvxzF$Mgk5?ZlS$iex_R;Vau*y8%Bn?g_W z2EKb9CI)ycZ26ELD~=YvW`6GqhsT2QAw5=x_)gwAk9o&~CK!(oJ`cmxrj_$N?pw?y U)5gkoOtxR&iw$S0Vlec70ZZviWB>pF literal 0 HcmV?d00001 diff --git a/.claude/skills/news-digest/scripts/news_digest.py b/.claude/skills/news-digest/scripts/news_digest.py new file mode 100755 index 0000000000..ea6aa167a8 --- /dev/null +++ b/.claude/skills/news-digest/scripts/news_digest.py @@ -0,0 +1,527 @@ +#!/usr/bin/env python3 +""" +News Digest Generator for Stanley + +Generates comprehensive news digests for portfolio holdings by leveraging +agent-core's WebSearch and LLM providers. No separate API keys required. + +Architecture: + Stanley -> Tiara (claude-flow) -> Agent-Core + - WebSearch via Exa MCP (built into agent-core) + - LLM summarization via agent-core providers + - Auth handled by ~/.opencode/auth.json +""" + +import argparse +import asyncio +import json +import os +import subprocess +import sys +from dataclasses import dataclass, field +from datetime import datetime, timezone +from pathlib import Path +from typing import Optional + +# Sentiment keywords +POSITIVE_KEYWORDS = { + "beat", "beats", "exceeds", "exceeded", "upgrade", "upgraded", "growth", + "record", "surge", "surged", "rally", "rallies", "outperform", "bullish", + "raises", "raised", "optimistic", "strong", "stronger", "positive" +} +NEGATIVE_KEYWORDS = { + "miss", "missed", "misses", "downgrade", "downgraded", "decline", "declined", + "layoffs", "lawsuit", "warning", "warns", "bearish", "weak", "weaker", + "cuts", "slashes", "disappoints", "negative", "concern", "risk" +} + +# News categories and their search patterns +CATEGORIES = { + "general": "{ticker} stock news today", + "earnings": "{ticker} earnings report results quarterly", + "sec_filings": "{ticker} SEC filing 10-K 10-Q 8-K", + "analyst": "{ticker} analyst rating upgrade downgrade price target", + "insider": "{ticker} insider trading executive", + "ma": "{ticker} merger acquisition deal", + "macro": "{ticker} Fed interest rates economy", +} + +# High-authority sources +AUTHORITY_SOURCES = { + "reuters.com", "bloomberg.com", "wsj.com", "ft.com", "cnbc.com", + "marketwatch.com", "barrons.com", "yahoo.com", "investing.com" +} + + +@dataclass +class Article: + """Represents a news article.""" + ticker: str + category: str + title: str + url: str + source: str + description: str + published: Optional[str] = None + summary: Optional[str] = None + sentiment: str = "neutral" + impact: str = "medium" + + def to_dict(self) -> dict: + return { + "ticker": self.ticker, + "category": self.category, + "title": self.title, + "url": self.url, + "source": self.source, + "published": self.published, + "description": self.description, + "summary": self.summary, + "sentiment": self.sentiment, + "impact": self.impact, + } + + +@dataclass +class Digest: + """Represents a complete news digest.""" + generated_at: str + tickers: list[str] + range: str + articles: list[Article] = field(default_factory=list) + + def to_dict(self) -> dict: + articles = [a.to_dict() for a in self.articles] + sentiment_counts = {"positive": 0, "neutral": 0, "negative": 0} + for a in self.articles: + sentiment_counts[a.sentiment] = sentiment_counts.get(a.sentiment, 0) + 1 + + return { + "generated_at": self.generated_at, + "tickers": self.tickers, + "range": self.range, + "articles": articles, + "summary": { + "total_articles": len(articles), + "by_sentiment": sentiment_counts, + "by_ticker": self._count_by_ticker(), + } + } + + def _count_by_ticker(self) -> dict[str, int]: + counts = {} + for a in self.articles: + counts[a.ticker] = counts.get(a.ticker, 0) + 1 + return counts + + +def analyze_sentiment(text: str) -> str: + """Simple keyword-based sentiment analysis.""" + text_lower = text.lower() + positive_count = sum(1 for kw in POSITIVE_KEYWORDS if kw in text_lower) + negative_count = sum(1 for kw in NEGATIVE_KEYWORDS if kw in text_lower) + + if positive_count > negative_count + 1: + return "positive" + elif negative_count > positive_count + 1: + return "negative" + return "neutral" + + +def determine_impact(article: Article) -> str: + """Determine article impact level.""" + source_lower = article.source.lower() + is_authority = any(s in source_lower for s in AUTHORITY_SOURCES) + high_impact_categories = {"earnings", "ma", "sec_filings"} + + if article.category in high_impact_categories and is_authority: + return "high" + elif article.category in high_impact_categories or is_authority: + return "medium" + return "low" + + +def extract_source(url: str) -> str: + """Extract source domain from URL.""" + try: + from urllib.parse import urlparse + parsed = urlparse(url) + domain = parsed.netloc.replace("www.", "") + return domain + except Exception: + return "unknown" + + +def find_agent_core_path() -> Optional[Path]: + """Find agent-core installation path.""" + # Check common locations + paths = [ + Path.home() / ".local/src/agent-core", + Path.home() / ".opencode", + Path("/opt/agent-core"), + ] + for p in paths: + if p.exists(): + return p + return None + + +def get_opencode_bin() -> str: + """Get opencode binary path.""" + # Check if opencode is in PATH + result = subprocess.run(["which", "opencode"], capture_output=True, text=True) + if result.returncode == 0: + return result.stdout.strip() + + # Check common locations + paths = [ + Path.home() / ".local/bin/opencode", + Path("/usr/local/bin/opencode"), + Path.home() / ".local/src/agent-core/dist/opencode", + ] + for p in paths: + if p.exists(): + return str(p) + + # Fallback to npx + return "npx opencode-ai" + + +async def search_via_agent_core(query: str, num_results: int = 5) -> list[dict]: + """ + Search using agent-core's WebSearch tool via Exa MCP. + Uses EXA_API_KEY from environment if available. + """ + try: + import httpx + + # Use Exa MCP endpoint directly (same as agent-core's websearch.ts) + search_request = { + "jsonrpc": "2.0", + "id": 1, + "method": "tools/call", + "params": { + "name": "web_search_exa", + "arguments": { + "query": query, + "type": "auto", + "numResults": num_results, + "livecrawl": "fallback", + } + } + } + + headers = { + "accept": "application/json, text/event-stream", + "content-type": "application/json", + } + + # Add API key if available + exa_key = os.environ.get("EXA_API_KEY") + if exa_key: + headers["x-api-key"] = exa_key + + async with httpx.AsyncClient() as client: + resp = await client.post( + "https://mcp.exa.ai/mcp", + json=search_request, + headers=headers, + timeout=25.0 + ) + + if resp.status_code == 200: + # Parse SSE response (format: "event: message\ndata: {...}") + for line in resp.text.split("\n"): + if line.startswith("data:"): + json_str = line[5:].strip() + if json_str: + data = json.loads(json_str) + if data.get("result", {}).get("content"): + text = data["result"]["content"][0]["text"] + return parse_exa_results(text) + except Exception as e: + print(f"Exa MCP call failed: {e}", file=sys.stderr) + + return [] + + +async def search_via_claude_code(query: str, num_results: int = 5) -> list[dict]: + """ + When running as a Claude Code skill, we can leverage the built-in WebSearch. + This function returns a marker that tells the parent skill to use WebSearch. + """ + # Return instruction for Claude Code to execute WebSearch + # The actual search happens at the skill execution layer + return [{ + "_use_websearch": True, + "query": query, + "num_results": num_results + }] + + +def parse_exa_results(text: str) -> list[dict]: + """Parse search results from Exa MCP response text.""" + results = [] + # Exa returns structured text with Title:, URL:, Published Date:, Text: fields + current = {} + + for line in text.split("\n"): + line = line.strip() + if line.startswith("Title:"): + if current.get("title") and current.get("url"): + results.append(current) + current = {"title": line[6:].strip()} + elif line.startswith("URL:"): + current["url"] = line[4:].strip() + elif line.startswith("Published Date:"): + current["published"] = line[15:].strip() + elif line.startswith("Text:"): + current["description"] = line[5:].strip() + elif current.get("description") and line and not line.startswith(("Title:", "URL:", "Published")): + # Append to description (but limit length) + if len(current["description"]) < 500: + current["description"] += " " + line + + if current.get("title") and current.get("url"): + results.append(current) + + return results + + +async def search_ticker_news( + ticker: str, + categories: list[str], + results_per_category: int = 3, +) -> list[Article]: + """Search news for a single ticker across categories.""" + articles = [] + seen_urls = set() + + for category in categories: + if category not in CATEGORIES: + continue + + query = CATEGORIES[category].format(ticker=ticker) + results = await search_via_agent_core(query, results_per_category) + + for r in results: + # Check if this is a marker to use WebSearch + if r.get("_use_websearch"): + # Skip - this will be handled by Claude Code + continue + + url = r.get("url", "") + if not url or url in seen_urls: + continue + seen_urls.add(url) + + title = r.get("title", "").strip() + description = r.get("description", "").strip() + + article = Article( + ticker=ticker, + category=category, + title=title, + url=url, + source=extract_source(url), + description=description, + ) + + combined_text = f"{title} {description}" + article.sentiment = analyze_sentiment(combined_text) + article.impact = determine_impact(article) + + articles.append(article) + + return articles + + +async def generate_digest( + tickers: list[str], + range_str: str = "24h", + categories: Optional[list[str]] = None, + summarize: bool = False, + max_articles: int = 50 +) -> Digest: + """Generate a news digest for the given tickers.""" + if categories is None: + categories = list(CATEGORIES.keys()) + + all_articles = [] + for ticker in tickers: + ticker_articles = await search_ticker_news( + ticker.upper(), + categories, + results_per_category=3, + ) + all_articles.extend(ticker_articles) + + # Sort by impact then sentiment + impact_order = {"high": 0, "medium": 1, "low": 2} + all_articles.sort(key=lambda a: (impact_order.get(a.impact, 2), a.sentiment != "positive")) + all_articles = all_articles[:max_articles] + + return Digest( + generated_at=datetime.now(timezone.utc).isoformat().replace("+00:00", "Z"), + tickers=[t.upper() for t in tickers], + range=range_str, + articles=all_articles + ) + + +def format_json(digest: Digest) -> str: + """Format digest as JSON.""" + return json.dumps(digest.to_dict(), indent=2) + + +def format_markdown(digest: Digest) -> str: + """Format digest as Markdown.""" + lines = [ + f"# News Digest - {digest.generated_at[:10]}", + "", + f"**Tickers:** {', '.join(digest.tickers)}", + f"**Range:** {digest.range}", + f"**Total Articles:** {len(digest.articles)}", + "", + ] + + by_ticker: dict[str, list[Article]] = {} + for a in digest.articles: + by_ticker.setdefault(a.ticker, []).append(a) + + for ticker, articles in by_ticker.items(): + lines.append(f"## {ticker}") + lines.append("") + + high_impact = [a for a in articles if a.impact == "high"] + other = [a for a in articles if a.impact != "high"] + + if high_impact: + lines.append("### High Impact") + for a in high_impact: + sentiment_icon = {"positive": "+", "negative": "-", "neutral": ""}[a.sentiment] + lines.append(f"- {sentiment_icon}**[{a.title}]({a.url})** ({a.source})") + if a.description: + lines.append(f" {a.description[:200]}...") + lines.append("") + + if other: + lines.append("### Other News") + for a in other: + sentiment_icon = {"positive": "+", "negative": "-", "neutral": ""}[a.sentiment] + lines.append(f"- {sentiment_icon}[{a.title}]({a.url}) ({a.source})") + lines.append("") + + return "\n".join(lines) + + +def format_email(digest: Digest) -> str: + """Format digest as HTML email.""" + sentiment_colors = { + "positive": "#22c55e", + "negative": "#ef4444", + "neutral": "#6b7280" + } + + articles_html = [] + for a in digest.articles: + color = sentiment_colors.get(a.sentiment, "#6b7280") + articles_html.append(f""" + + + {a.ticker} + + + {a.title} +
{a.source} | {a.category} + + + + {a.sentiment} + + + + """) + + return f""" + + + +

News Digest

+

Generated: {digest.generated_at[:10]} | Tickers: {', '.join(digest.tickers)}

+ + + + + + + {''.join(articles_html)} +
TickerArticleSentiment
+
+

Generated by Stanley via agent-core

+ +""" + + +def main(): + parser = argparse.ArgumentParser( + description="Generate news digests for portfolio holdings (uses agent-core infrastructure)" + ) + parser.add_argument( + "--tickers", "-t", + required=True, + help="Comma-separated list of tickers (e.g., AAPL,NVDA,MSFT)" + ) + parser.add_argument( + "--range", "-r", + default="24h", + choices=["24h", "7d", "30d"], + help="Time range for news (default: 24h)" + ) + parser.add_argument( + "--categories", "-c", + help="Comma-separated categories (default: all)" + ) + parser.add_argument( + "--summarize", "-s", + action="store_true", + help="Summarize articles using agent-core LLM" + ) + parser.add_argument( + "--format", "-f", + default="markdown", + choices=["json", "markdown", "email"], + help="Output format (default: markdown)" + ) + parser.add_argument( + "--max-articles", "-m", + type=int, + default=50, + help="Maximum articles in digest (default: 50)" + ) + + args = parser.parse_args() + + tickers = [t.strip() for t in args.tickers.split(",")] + categories = None + if args.categories: + categories = [c.strip() for c in args.categories.split(",")] + + digest = asyncio.run(generate_digest( + tickers=tickers, + range_str=args.range, + categories=categories, + summarize=args.summarize, + max_articles=args.max_articles + )) + + if args.format == "json": + print(format_json(digest)) + elif args.format == "markdown": + print(format_markdown(digest)) + elif args.format == "email": + print(format_email(digest)) + + +if __name__ == "__main__": + main() diff --git a/.claude/skills/notion/SKILL.md b/.claude/skills/notion/SKILL.md new file mode 100644 index 0000000000..aff1b4a44a --- /dev/null +++ b/.claude/skills/notion/SKILL.md @@ -0,0 +1,156 @@ +--- +name: notion +description: Notion API for creating and managing pages, databases, and blocks. +homepage: https://developers.notion.com +metadata: {"zee":{"emoji":"๐Ÿ“"}} +--- + +# notion + +Use the Notion API to create/read/update pages, data sources (databases), and blocks. + +## Setup + +1. Create an integration at https://notion.so/my-integrations +2. Copy the API key (starts with `ntn_` or `secret_`) +3. Store it: +```bash +mkdir -p ~/.config/notion +echo "ntn_your_key_here" > ~/.config/notion/api_key +``` +4. Share target pages/databases with your integration (click "..." โ†’ "Connect to" โ†’ your integration name) + +## API Basics + +All requests need: +```bash +NOTION_KEY=$(cat ~/.config/notion/api_key) +curl -X GET "https://api.notion.com/v1/..." \ + -H "Authorization: Bearer $NOTION_KEY" \ + -H "Notion-Version: 2025-09-03" \ + -H "Content-Type: application/json" +``` + +> **Note:** The `Notion-Version` header is required. This skill uses `2025-09-03` (latest). In this version, databases are called "data sources" in the API. + +## Common Operations + +**Search for pages and data sources:** +```bash +curl -X POST "https://api.notion.com/v1/search" \ + -H "Authorization: Bearer $NOTION_KEY" \ + -H "Notion-Version: 2025-09-03" \ + -H "Content-Type: application/json" \ + -d '{"query": "page title"}' +``` + +**Get page:** +```bash +curl "https://api.notion.com/v1/pages/{page_id}" \ + -H "Authorization: Bearer $NOTION_KEY" \ + -H "Notion-Version: 2025-09-03" +``` + +**Get page content (blocks):** +```bash +curl "https://api.notion.com/v1/blocks/{page_id}/children" \ + -H "Authorization: Bearer $NOTION_KEY" \ + -H "Notion-Version: 2025-09-03" +``` + +**Create page in a data source:** +```bash +curl -X POST "https://api.notion.com/v1/pages" \ + -H "Authorization: Bearer $NOTION_KEY" \ + -H "Notion-Version: 2025-09-03" \ + -H "Content-Type: application/json" \ + -d '{ + "parent": {"database_id": "xxx"}, + "properties": { + "Name": {"title": [{"text": {"content": "New Item"}}]}, + "Status": {"select": {"name": "Todo"}} + } + }' +``` + +**Query a data source (database):** +```bash +curl -X POST "https://api.notion.com/v1/data_sources/{data_source_id}/query" \ + -H "Authorization: Bearer $NOTION_KEY" \ + -H "Notion-Version: 2025-09-03" \ + -H "Content-Type: application/json" \ + -d '{ + "filter": {"property": "Status", "select": {"equals": "Active"}}, + "sorts": [{"property": "Date", "direction": "descending"}] + }' +``` + +**Create a data source (database):** +```bash +curl -X POST "https://api.notion.com/v1/data_sources" \ + -H "Authorization: Bearer $NOTION_KEY" \ + -H "Notion-Version: 2025-09-03" \ + -H "Content-Type: application/json" \ + -d '{ + "parent": {"page_id": "xxx"}, + "title": [{"text": {"content": "My Database"}}], + "properties": { + "Name": {"title": {}}, + "Status": {"select": {"options": [{"name": "Todo"}, {"name": "Done"}]}}, + "Date": {"date": {}} + } + }' +``` + +**Update page properties:** +```bash +curl -X PATCH "https://api.notion.com/v1/pages/{page_id}" \ + -H "Authorization: Bearer $NOTION_KEY" \ + -H "Notion-Version: 2025-09-03" \ + -H "Content-Type: application/json" \ + -d '{"properties": {"Status": {"select": {"name": "Done"}}}}' +``` + +**Add blocks to page:** +```bash +curl -X PATCH "https://api.notion.com/v1/blocks/{page_id}/children" \ + -H "Authorization: Bearer $NOTION_KEY" \ + -H "Notion-Version: 2025-09-03" \ + -H "Content-Type: application/json" \ + -d '{ + "children": [ + {"object": "block", "type": "paragraph", "paragraph": {"rich_text": [{"text": {"content": "Hello"}}]}} + ] + }' +``` + +## Property Types + +Common property formats for database items: +- **Title:** `{"title": [{"text": {"content": "..."}}]}` +- **Rich text:** `{"rich_text": [{"text": {"content": "..."}}]}` +- **Select:** `{"select": {"name": "Option"}}` +- **Multi-select:** `{"multi_select": [{"name": "A"}, {"name": "B"}]}` +- **Date:** `{"date": {"start": "2024-01-15", "end": "2024-01-16"}}` +- **Checkbox:** `{"checkbox": true}` +- **Number:** `{"number": 42}` +- **URL:** `{"url": "https://..."}` +- **Email:** `{"email": "a@b.com"}` +- **Relation:** `{"relation": [{"id": "page_id"}]}` + +## Key Differences in 2025-09-03 + +- **Databases โ†’ Data Sources:** Use `/data_sources/` endpoints for queries and retrieval +- **Two IDs:** Each database now has both a `database_id` and a `data_source_id` + - Use `database_id` when creating pages (`parent: {"database_id": "..."}`) + - Use `data_source_id` when querying (`POST /v1/data_sources/{id}/query`) +- **Search results:** Databases return as `"object": "data_source"` with their `data_source_id` +- **Parent in responses:** Pages show `parent.data_source_id` alongside `parent.database_id` +- **Finding the data_source_id:** Search for the database, or call `GET /v1/data_sources/{data_source_id}` + +## Notes + +- Page/database IDs are UUIDs (with or without dashes) +- The API cannot set database view filters โ€” that's UI-only +- Rate limit: ~3 requests/second average +- Use `is_inline: true` when creating data sources to embed them in pages diff --git a/.claude/skills/obsidian/SKILL.md b/.claude/skills/obsidian/SKILL.md new file mode 100644 index 0000000000..76804f2455 --- /dev/null +++ b/.claude/skills/obsidian/SKILL.md @@ -0,0 +1,55 @@ +--- +name: obsidian +description: Work with Obsidian vaults (plain Markdown notes) and automate via obsidian-cli. +homepage: https://help.obsidian.md +metadata: {"zee":{"emoji":"๐Ÿ’Ž","requires":{"bins":["obsidian-cli"]},"install":[{"id":"brew","kind":"brew","formula":"yakitrak/yakitrak/obsidian-cli","bins":["obsidian-cli"],"label":"Install obsidian-cli (brew)"}]}} +--- + +# Obsidian + +Obsidian vault = a normal folder on disk. + +Vault structure (typical) +- Notes: `*.md` (plain text Markdown; edit with any editor) +- Config: `.obsidian/` (workspace + plugin settings; usually donโ€™t touch from scripts) +- Canvases: `*.canvas` (JSON) +- Attachments: whatever folder you chose in Obsidian settings (images/PDFs/etc.) + +## Find the active vault(s) + +Obsidian desktop tracks vaults here (source of truth): +- `~/Library/Application Support/obsidian/obsidian.json` + +`obsidian-cli` resolves vaults from that file; vault name is typically the **folder name** (path suffix). + +Fast โ€œwhat vault is active / where are the notes?โ€ +- If youโ€™ve already set a default: `obsidian-cli print-default --path-only` +- Otherwise, read `~/Library/Application Support/obsidian/obsidian.json` and use the vault entry with `"open": true`. + +Notes +- Multiple vaults common (iCloud vs `~/Documents`, work/personal, etc.). Donโ€™t guess; read config. +- Avoid writing hardcoded vault paths into scripts; prefer reading the config or using `print-default`. + +## obsidian-cli quick start + +Pick a default vault (once): +- `obsidian-cli set-default ""` +- `obsidian-cli print-default` / `obsidian-cli print-default --path-only` + +Search +- `obsidian-cli search "query"` (note names) +- `obsidian-cli search-content "query"` (inside notes; shows snippets + lines) + +Create +- `obsidian-cli create "Folder/New note" --content "..." --open` +- Requires Obsidian URI handler (`obsidian://โ€ฆ`) working (Obsidian installed). +- Avoid creating notes under โ€œhiddenโ€ dot-folders (e.g. `.something/...`) via URI; Obsidian may refuse. + +Move/rename (safe refactor) +- `obsidian-cli move "old/path/note" "new/path/note"` +- Updates `[[wikilinks]]` and common Markdown links across the vault (this is the main win vs `mv`). + +Delete +- `obsidian-cli delete "path/note"` + +Prefer direct edits when appropriate: open the `.md` file and change it; Obsidian will pick it up. diff --git a/.claude/skills/openai-image-gen/SKILL.md b/.claude/skills/openai-image-gen/SKILL.md new file mode 100644 index 0000000000..aaff43bf8f --- /dev/null +++ b/.claude/skills/openai-image-gen/SKILL.md @@ -0,0 +1,31 @@ +--- +name: openai-image-gen +description: Batch-generate images via OpenAI Images API. Random prompt sampler + `index.html` gallery. +homepage: https://platform.openai.com/docs/api-reference/images +metadata: {"zee":{"emoji":"๐Ÿ–ผ๏ธ","requires":{"bins":["python3"],"env":["OPENAI_API_KEY"]},"primaryEnv":"OPENAI_API_KEY","install":[{"id":"python-brew","kind":"brew","formula":"python","bins":["python3"],"label":"Install Python (brew)"}]}} +--- + +# OpenAI Image Gen + +Generate a handful of โ€œrandom but structuredโ€ prompts and render them via the OpenAI Images API. + +## Run + +```bash +python3 {baseDir}/scripts/gen.py +open ~/Projects/tmp/openai-image-gen-*/index.html # if ~/Projects/tmp exists; else ./tmp/... +``` + +Useful flags: + +```bash +python3 {baseDir}/scripts/gen.py --count 16 --model gpt-image-1 +python3 {baseDir}/scripts/gen.py --prompt "ultra-detailed studio photo of a lobster astronaut" --count 4 +python3 {baseDir}/scripts/gen.py --size 1536x1024 --quality high --out-dir ./out/images +``` + +## Output + +- `*.png` images +- `prompts.json` (prompt โ†’ file mapping) +- `index.html` (thumbnail gallery) diff --git a/.claude/skills/openai-image-gen/scripts/gen.py b/.claude/skills/openai-image-gen/scripts/gen.py new file mode 100644 index 0000000000..0f2c59188c --- /dev/null +++ b/.claude/skills/openai-image-gen/scripts/gen.py @@ -0,0 +1,173 @@ +#!/usr/bin/env python3 +import argparse +import base64 +import datetime as dt +import json +import os +import random +import re +import sys +import urllib.error +import urllib.request +from pathlib import Path + + +def slugify(text: str) -> str: + text = text.lower().strip() + text = re.sub(r"[^a-z0-9]+", "-", text) + text = re.sub(r"-{2,}", "-", text).strip("-") + return text or "image" + + +def default_out_dir() -> Path: + now = dt.datetime.now().strftime("%Y-%m-%d-%H-%M-%S") + preferred = Path.home() / "Projects" / "tmp" + base = preferred if preferred.is_dir() else Path("./tmp") + base.mkdir(parents=True, exist_ok=True) + return base / f"openai-image-gen-{now}" + + +def pick_prompts(count: int) -> list[str]: + subjects = [ + "a lobster astronaut", + "a brutalist lighthouse", + "a cozy reading nook", + "a cyberpunk noodle shop", + "a Vienna street at dusk", + "a minimalist product photo", + "a surreal underwater library", + ] + styles = [ + "ultra-detailed studio photo", + "35mm film still", + "isometric illustration", + "editorial photography", + "soft watercolor", + "architectural render", + "high-contrast monochrome", + ] + lighting = [ + "golden hour", + "overcast soft light", + "neon lighting", + "dramatic rim light", + "candlelight", + "foggy atmosphere", + ] + prompts: list[str] = [] + for _ in range(count): + prompts.append( + f"{random.choice(styles)} of {random.choice(subjects)}, {random.choice(lighting)}" + ) + return prompts + + +def request_images( + api_key: str, + prompt: str, + model: str, + size: str, + quality: str, +) -> dict: + url = "https://api.openai.com/v1/images/generations" + body = json.dumps( + { + "model": model, + "prompt": prompt, + "size": size, + "quality": quality, + "n": 1, + "response_format": "b64_json", + } + ).encode("utf-8") + req = urllib.request.Request( + url, + method="POST", + headers={ + "Authorization": f"Bearer {api_key}", + "Content-Type": "application/json", + }, + data=body, + ) + try: + with urllib.request.urlopen(req, timeout=300) as resp: + return json.loads(resp.read().decode("utf-8")) + except urllib.error.HTTPError as e: + payload = e.read().decode("utf-8", errors="replace") + raise RuntimeError(f"OpenAI Images API failed ({e.code}): {payload}") from e + + +def write_gallery(out_dir: Path, items: list[dict]) -> None: + thumbs = "\n".join( + [ + f""" +
+ +
{it["prompt"]}
+
+""".strip() + for it in items + ] + ) + html = f""" + +openai-image-gen + +

openai-image-gen

+

Output: {out_dir.as_posix()}

+
+{thumbs} +
+""" + (out_dir / "index.html").write_text(html, encoding="utf-8") + + +def main() -> int: + ap = argparse.ArgumentParser(description="Generate images via OpenAI Images API.") + ap.add_argument("--prompt", help="Single prompt. If omitted, random prompts are generated.") + ap.add_argument("--count", type=int, default=8, help="How many images to generate.") + ap.add_argument("--model", default="gpt-image-1", help="Image model id.") + ap.add_argument("--size", default="1024x1024", help="Image size (e.g. 1024x1024, 1536x1024).") + ap.add_argument("--quality", default="high", help="Image quality (varies by model).") + ap.add_argument("--out-dir", default="", help="Output directory (default: ./tmp/openai-image-gen-).") + args = ap.parse_args() + + api_key = (os.environ.get("OPENAI_API_KEY") or "").strip() + if not api_key: + print("Missing OPENAI_API_KEY", file=sys.stderr) + return 2 + + out_dir = Path(args.out_dir).expanduser() if args.out_dir else default_out_dir() + out_dir.mkdir(parents=True, exist_ok=True) + + prompts = [args.prompt] * args.count if args.prompt else pick_prompts(args.count) + + items: list[dict] = [] + for idx, prompt in enumerate(prompts, start=1): + print(f"[{idx}/{len(prompts)}] {prompt}") + res = request_images(api_key, prompt, args.model, args.size, args.quality) + b64 = res.get("data", [{}])[0].get("b64_json") + if not b64: + raise RuntimeError(f"Unexpected response: {json.dumps(res)[:400]}") + png = base64.b64decode(b64) + filename = f"{idx:03d}-{slugify(prompt)[:40]}.png" + (out_dir / filename).write_bytes(png) + items.append({"prompt": prompt, "file": filename}) + + (out_dir / "prompts.json").write_text(json.dumps(items, indent=2), encoding="utf-8") + write_gallery(out_dir, items) + print(f"\nWrote: {(out_dir / 'index.html').as_posix()}") + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/.claude/skills/openai-whisper-api/SKILL.md b/.claude/skills/openai-whisper-api/SKILL.md new file mode 100644 index 0000000000..103053cd8b --- /dev/null +++ b/.claude/skills/openai-whisper-api/SKILL.md @@ -0,0 +1,43 @@ +--- +name: openai-whisper-api +description: Transcribe audio via OpenAI Audio Transcriptions API (Whisper). +homepage: https://platform.openai.com/docs/guides/speech-to-text +metadata: {"zee":{"emoji":"โ˜๏ธ","requires":{"bins":["curl"],"env":["OPENAI_API_KEY"]},"primaryEnv":"OPENAI_API_KEY"}} +--- + +# OpenAI Whisper API (curl) + +Transcribe an audio file via OpenAIโ€™s `/v1/audio/transcriptions` endpoint. + +## Quick start + +```bash +{baseDir}/scripts/transcribe.sh /path/to/audio.m4a +``` + +Defaults: +- Model: `whisper-1` +- Output: `.txt` + +## Useful flags + +```bash +{baseDir}/scripts/transcribe.sh /path/to/audio.ogg --model whisper-1 --out /tmp/transcript.txt +{baseDir}/scripts/transcribe.sh /path/to/audio.m4a --language en +{baseDir}/scripts/transcribe.sh /path/to/audio.m4a --prompt "Speaker names: Peter, Daniel" +{baseDir}/scripts/transcribe.sh /path/to/audio.m4a --json --out /tmp/transcript.json +``` + +## API key + +Set `OPENAI_API_KEY`, or configure it in `~/.zee/zee.json`: + +```json5 +{ + skills: { + "openai-whisper-api": { + apiKey: "OPENAI_KEY_HERE" + } + } +} +``` diff --git a/.claude/skills/openai-whisper-api/scripts/transcribe.sh b/.claude/skills/openai-whisper-api/scripts/transcribe.sh new file mode 100644 index 0000000000..551c7b473e --- /dev/null +++ b/.claude/skills/openai-whisper-api/scripts/transcribe.sh @@ -0,0 +1,85 @@ +#!/usr/bin/env bash +set -euo pipefail + +usage() { + cat >&2 <<'EOF' +Usage: + transcribe.sh [--model whisper-1] [--out /path/to/out.txt] [--language en] [--prompt "hint"] [--json] +EOF + exit 2 +} + +if [[ "${1:-}" == "" || "${1:-}" == "-h" || "${1:-}" == "--help" ]]; then + usage +fi + +in="${1:-}" +shift || true + +model="whisper-1" +out="" +language="" +prompt="" +response_format="text" + +while [[ $# -gt 0 ]]; do + case "$1" in + --model) + model="${2:-}" + shift 2 + ;; + --out) + out="${2:-}" + shift 2 + ;; + --language) + language="${2:-}" + shift 2 + ;; + --prompt) + prompt="${2:-}" + shift 2 + ;; + --json) + response_format="json" + shift 1 + ;; + *) + echo "Unknown arg: $1" >&2 + usage + ;; + esac +done + +if [[ ! -f "$in" ]]; then + echo "File not found: $in" >&2 + exit 1 +fi + +if [[ "${OPENAI_API_KEY:-}" == "" ]]; then + echo "Missing OPENAI_API_KEY" >&2 + exit 1 +fi + +if [[ "$out" == "" ]]; then + base="${in%.*}" + if [[ "$response_format" == "json" ]]; then + out="${base}.json" + else + out="${base}.txt" + fi +fi + +mkdir -p "$(dirname "$out")" + +curl -sS https://api.openai.com/v1/audio/transcriptions \ + -H "Authorization: Bearer $OPENAI_API_KEY" \ + -H "Accept: application/json" \ + -F "file=@${in}" \ + -F "model=${model}" \ + -F "response_format=${response_format}" \ + ${language:+-F "language=${language}"} \ + ${prompt:+-F "prompt=${prompt}"} \ + >"$out" + +echo "$out" diff --git a/.claude/skills/openai-whisper/SKILL.md b/.claude/skills/openai-whisper/SKILL.md new file mode 100644 index 0000000000..d2eea57d9c --- /dev/null +++ b/.claude/skills/openai-whisper/SKILL.md @@ -0,0 +1,19 @@ +--- +name: openai-whisper +description: Local speech-to-text with the Whisper CLI (no API key). +homepage: https://openai.com/research/whisper +metadata: {"zee":{"emoji":"๐ŸŽ™๏ธ","requires":{"bins":["whisper"]},"install":[{"id":"brew","kind":"brew","formula":"openai-whisper","bins":["whisper"],"label":"Install OpenAI Whisper (brew)"}]}} +--- + +# Whisper (CLI) + +Use `whisper` to transcribe audio locally. + +Quick start +- `whisper /path/audio.mp3 --model medium --output_format txt --output_dir .` +- `whisper /path/audio.m4a --task translate --output_format srt` + +Notes +- Models download to `~/.cache/whisper` on first run. +- `--model` defaults to `turbo` on this install. +- Use smaller models for speed, larger for accuracy. diff --git a/.claude/skills/openhue/SKILL.md b/.claude/skills/openhue/SKILL.md new file mode 100644 index 0000000000..214e244745 --- /dev/null +++ b/.claude/skills/openhue/SKILL.md @@ -0,0 +1,30 @@ +--- +name: openhue +description: Control Philips Hue lights/scenes via the OpenHue CLI. +homepage: https://www.openhue.io/cli +metadata: {"zee":{"emoji":"๐Ÿ’ก","requires":{"bins":["openhue"]},"install":[{"id":"brew","kind":"brew","formula":"openhue/cli/openhue-cli","bins":["openhue"],"label":"Install OpenHue CLI (brew)"}]}} +--- + +# OpenHue CLI + +Use `openhue` to control Hue lights and scenes via a Hue Bridge. + +Setup +- Discover bridges: `openhue discover` +- Guided setup: `openhue setup` + +Read +- `openhue get light --json` +- `openhue get room --json` +- `openhue get scene --json` + +Write +- Turn on: `openhue set light --on` +- Turn off: `openhue set light --off` +- Brightness: `openhue set light --on --brightness 50` +- Color: `openhue set light --on --rgb #3399FF` +- Scene: `openhue set scene ` + +Notes +- You may need to press the Hue Bridge button during setup. +- Use `--room "Room Name"` when light names are ambiguous. diff --git a/.claude/skills/oracle/SKILL.md b/.claude/skills/oracle/SKILL.md new file mode 100644 index 0000000000..59f38e92d3 --- /dev/null +++ b/.claude/skills/oracle/SKILL.md @@ -0,0 +1,105 @@ +--- +name: oracle +description: Best practices for using the oracle CLI (prompt + file bundling, engines, sessions, and file attachment patterns). +homepage: https://askoracle.dev +metadata: {"zee":{"emoji":"๐Ÿงฟ","requires":{"bins":["oracle"]},"install":[{"id":"node","kind":"node","package":"@steipete/oracle","bins":["oracle"],"label":"Install oracle (node)"}]}} +--- + +# oracle โ€” best use + +Oracle bundles your prompt + selected files into one โ€œone-shotโ€ request so another model can answer with real repo context (API or browser automation). Treat output as advisory: verify against code + tests. + +## Main use case (browser, GPTโ€‘5.2 Pro) + +Default workflow here: `--engine browser` with GPTโ€‘5.2 Pro in ChatGPT. This is the common โ€œlong thinkโ€ path: ~10 minutes to ~1 hour is normal; expect a stored session you can reattach to. + +Recommended defaults: +- Engine: browser (`--engine browser`) +- Model: GPTโ€‘5.2 Pro (`--model gpt-5.2-pro` or `--model "5.2 Pro"`) + +## Golden path + +1. Pick a tight file set (fewest files that still contain the truth). +2. Preview payload + token spend (`--dry-run` + `--files-report`). +3. Use browser mode for the usual GPTโ€‘5.2 Pro workflow; use API only when you explicitly want it. +4. If the run detaches/timeouts: reattach to the stored session (donโ€™t re-run). + +## Commands (preferred) + +- Help: + - `oracle --help` + - If the binary isnโ€™t installed: `npx -y @steipete/oracle --help` (avoid `pnpx` here; sqlite bindings). + +- Preview (no tokens): + - `oracle --dry-run summary -p "" --file "src/**" --file "!**/*.test.*"` + - `oracle --dry-run full -p "" --file "src/**"` + +- Token sanity: + - `oracle --dry-run summary --files-report -p "" --file "src/**"` + +- Browser run (main path; long-running is normal): + - `oracle --engine browser --model gpt-5.2-pro -p "" --file "src/**"` + +- Manual paste fallback: + - `oracle --render --copy -p "" --file "src/**"` + - Note: `--copy` is a hidden alias for `--copy-markdown`. + +## Attaching files (`--file`) + +`--file` accepts files, directories, and globs. You can pass it multiple times; entries can be comma-separated. + +- Include: + - `--file "src/**"` + - `--file src/index.ts` + - `--file docs --file README.md` + +- Exclude: + - `--file "src/**" --file "!src/**/*.test.ts" --file "!**/*.snap"` + +- Defaults (implementation behavior): + - Default-ignored dirs: `node_modules`, `dist`, `coverage`, `.git`, `.turbo`, `.next`, `build`, `tmp` (skipped unless explicitly passed as literal dirs/files). + - Honors `.gitignore` when expanding globs. + - Does not follow symlinks. + - Dotfiles filtered unless opted in via pattern (e.g. `--file ".github/**"`). + - Files > 1 MB rejected. + +## Engines (API vs browser) + +- Auto-pick: `api` when `OPENAI_API_KEY` is set; otherwise `browser`. +- Browser supports GPT + Gemini only; use `--engine api` for Claude/Grok/Codex or multi-model runs. +- Browser attachments: + - `--browser-attachments auto|never|always` (auto pastes inline up to ~60k chars then uploads). +- Remote browser host: + - Host: `oracle serve --host 0.0.0.0 --port 9473 --token ` + - Client: `oracle --engine browser --remote-host --remote-token -p "" --file "src/**"` + +## Sessions + slugs + +- Stored under `~/.oracle/sessions` (override with `ORACLE_HOME_DIR`). +- Runs may detach or take a long time (browser + GPTโ€‘5.2 Pro often does). If the CLI times out: donโ€™t re-run; reattach. + - List: `oracle status --hours 72` + - Attach: `oracle session --render` +- Use `--slug "<3-5 words>"` to keep session IDs readable. +- Duplicate prompt guard exists; use `--force` only when you truly want a fresh run. + +## Prompt template (high signal) + +Oracle starts with **zero** project knowledge. Assume the model cannot infer your stack, build tooling, conventions, or โ€œobviousโ€ paths. Include: +- Project briefing (stack + build/test commands + platform constraints). +- โ€œWhere things liveโ€ (key directories, entrypoints, config files, boundaries). +- Exact question + what you tried + the error text (verbatim). +- Constraints (โ€œdonโ€™t change Xโ€, โ€œmust keep public APIโ€, etc). +- Desired output (โ€œreturn patch plan + testsโ€, โ€œgive 3 options with tradeoffsโ€). + +## Safety + +- Donโ€™t attach secrets by default (`.env`, key files, auth tokens). Redact aggressively; share only whatโ€™s required. + +## โ€œExhaustive promptโ€ restoration pattern + +For long investigations, write a standalone prompt + file set so you can rerun days later: +- 6โ€“30 sentence project briefing + the goal. +- Repro steps + exact errors + what you tried. +- Attach all context files needed (entrypoints, configs, key modules, docs). + +Oracle runs are one-shot; the model doesnโ€™t remember prior runs. โ€œRestoring contextโ€ means re-running with the same prompt + `--file โ€ฆ` set (or reattaching a still-running stored session). diff --git a/.claude/skills/ordercli/SKILL.md b/.claude/skills/ordercli/SKILL.md new file mode 100644 index 0000000000..8ff8491628 --- /dev/null +++ b/.claude/skills/ordercli/SKILL.md @@ -0,0 +1,47 @@ +--- +name: ordercli +description: Foodora-only CLI for checking past orders and active order status (Deliveroo WIP). +homepage: https://ordercli.sh +metadata: {"zee":{"emoji":"๐Ÿ›ต","requires":{"bins":["ordercli"]},"install":[{"id":"brew","kind":"brew","formula":"steipete/tap/ordercli","bins":["ordercli"],"label":"Install ordercli (brew)"},{"id":"go","kind":"go","module":"github.com/steipete/ordercli/cmd/ordercli@latest","bins":["ordercli"],"label":"Install ordercli (go)"}]}} +--- + +# ordercli + +Use `ordercli` to check past orders and track active order status (Foodora only right now). + +Quick start (Foodora) +- `ordercli foodora countries` +- `ordercli foodora config set --country AT` +- `ordercli foodora login --email you@example.com --password-stdin` +- `ordercli foodora orders` +- `ordercli foodora history --limit 20` +- `ordercli foodora history show ` + +Orders +- Active list (arrival/status): `ordercli foodora orders` +- Watch: `ordercli foodora orders --watch` +- Active order detail: `ordercli foodora order ` +- History detail JSON: `ordercli foodora history show --json` + +Reorder (adds to cart) +- Preview: `ordercli foodora reorder ` +- Confirm: `ordercli foodora reorder --confirm` +- Address: `ordercli foodora reorder --confirm --address-id ` + +Cloudflare / bot protection +- Browser login: `ordercli foodora login --email you@example.com --password-stdin --browser` +- Reuse profile: `--browser-profile "$HOME/Library/Application Support/ordercli/browser-profile"` +- Import Chrome cookies: `ordercli foodora cookies chrome --profile "Default"` + +Session import (no password) +- `ordercli foodora session chrome --url https://www.foodora.at/ --profile "Default"` +- `ordercli foodora session refresh --client-id android` + +Deliveroo (WIP, not working yet) +- Requires `DELIVEROO_BEARER_TOKEN` (optional `DELIVEROO_COOKIE`). +- `ordercli deliveroo config set --market uk` +- `ordercli deliveroo history` + +Notes +- Use `--config /tmp/ordercli.json` for testing. +- Confirm before any reorder or cart-changing action. diff --git a/.claude/skills/pair-programming/SKILL.md b/.claude/skills/pair-programming/SKILL.md new file mode 100644 index 0000000000..7b667b7a2f --- /dev/null +++ b/.claude/skills/pair-programming/SKILL.md @@ -0,0 +1,1202 @@ +--- +name: Pair Programming +description: AI-assisted pair programming with multiple modes (driver/navigator/switch), real-time verification, quality monitoring, and comprehensive testing. Supports TDD, debugging, refactoring, and learning sessions. Features automatic role switching, continuous code review, security scanning, and performance optimization with truth-score verification. +--- + +# Pair Programming + +Collaborative AI pair programming with intelligent role management, real-time quality monitoring, and comprehensive development workflows. + +## What This Skill Does + +This skill provides professional pair programming capabilities with AI assistance, supporting multiple collaboration modes, continuous verification, and integrated testing. It manages driver/navigator roles, performs real-time code review, tracks quality metrics, and ensures high standards through truth-score verification. + +**Key Capabilities:** +- **Multiple Modes**: Driver, Navigator, Switch, TDD, Review, Mentor, Debug +- **Real-Time Verification**: Automatic quality scoring with rollback on failures +- **Role Management**: Seamless switching between driver/navigator roles +- **Testing Integration**: Auto-generate tests, track coverage, continuous testing +- **Code Review**: Security scanning, performance analysis, best practice enforcement +- **Session Persistence**: Auto-save, recovery, export, and sharing + +## Prerequisites + +**Required:** +- Claude Flow CLI installed (`npm install -g claude-flow@alpha`) +- Git repository (optional but recommended) + +**Recommended:** +- Testing framework (Jest, pytest, etc.) +- Linter configured (ESLint, pylint, etc.) +- Code formatter (Prettier, Black, etc.) + +## Quick Start + +### Basic Session +```bash +# Start simple pair programming +claude-flow pair --start +``` + +### TDD Session +```bash +# Test-driven development +claude-flow pair --start \ + --mode tdd \ + --test-first \ + --coverage 90 +``` + +--- + +## Complete Guide + +### Session Control Commands + +#### Starting Sessions +```bash +# Basic start +claude-flow pair --start + +# Expert refactoring session +claude-flow pair --start \ + --agent senior-dev \ + --focus refactor \ + --verify \ + --threshold 0.98 + +# Debugging session +claude-flow pair --start \ + --agent debugger-expert \ + --focus debug \ + --review + +# Learning session +claude-flow pair --start \ + --mode mentor \ + --pace slow \ + --examples +``` + +#### Session Management +```bash +# Check status +claude-flow pair --status + +# View history +claude-flow pair --history + +# Pause session +/pause [--reason ] + +# Resume session +/resume + +# End session +claude-flow pair --end [--save] [--report] +``` + +### Available Modes + +#### Driver Mode +You write code while AI provides guidance. + +```bash +claude-flow pair --start --mode driver +``` + +**Your Responsibilities:** +- Write actual code +- Implement solutions +- Make immediate decisions +- Handle syntax and structure + +**AI Navigator:** +- Strategic guidance +- Spot potential issues +- Suggest improvements +- Real-time review +- Track overall direction + +**Best For:** +- Learning new patterns +- Implementing familiar features +- Quick iterations +- Hands-on debugging + +**Commands:** +``` +/suggest - Get implementation suggestions +/review - Request code review +/explain - Ask for explanations +/optimize - Request optimization ideas +/patterns - Get pattern recommendations +``` + +#### Navigator Mode +AI writes code while you provide direction. + +```bash +claude-flow pair --start --mode navigator +``` + +**Your Responsibilities:** +- Provide high-level direction +- Review generated code +- Make architectural decisions +- Ensure business requirements + +**AI Driver:** +- Write implementation code +- Handle syntax details +- Implement your guidance +- Manage boilerplate +- Execute refactoring + +**Best For:** +- Rapid prototyping +- Boilerplate generation +- Learning from AI patterns +- Exploring solutions + +**Commands:** +``` +/implement - Direct implementation +/refactor - Request refactoring +/test - Generate tests +/document - Add documentation +/alternate - See alternative approaches +``` + +#### Switch Mode +Automatically alternates roles at intervals. + +```bash +# Default 10-minute intervals +claude-flow pair --start --mode switch + +# 5-minute intervals (rapid) +claude-flow pair --start --mode switch --interval 5m + +# 15-minute intervals (deep focus) +claude-flow pair --start --mode switch --interval 15m +``` + +**Handoff Process:** +1. 30-second warning before switch +2. Current driver completes thought +3. Context summary generated +4. Roles swap smoothly +5. New driver continues + +**Best For:** +- Balanced collaboration +- Knowledge sharing +- Complex features +- Extended sessions + +#### Specialized Modes + +**TDD Mode** - Test-Driven Development: +```bash +claude-flow pair --start \ + --mode tdd \ + --test-first \ + --coverage 100 +``` +Workflow: Write failing test โ†’ Implement โ†’ Refactor โ†’ Repeat + +**Review Mode** - Continuous code review: +```bash +claude-flow pair --start \ + --mode review \ + --strict \ + --security +``` +Features: Real-time feedback, security scanning, performance analysis + +**Mentor Mode** - Learning-focused: +```bash +claude-flow pair --start \ + --mode mentor \ + --explain-all \ + --pace slow +``` +Features: Detailed explanations, step-by-step guidance, pattern teaching + +**Debug Mode** - Problem-solving: +```bash +claude-flow pair --start \ + --mode debug \ + --verbose \ + --trace +``` +Features: Issue identification, root cause analysis, fix suggestions + +### In-Session Commands + +#### Code Commands +``` +/explain [--level basic|detailed|expert] + Explain the current code or selection + +/suggest [--type refactor|optimize|security|style] + Get improvement suggestions + +/implement + Request implementation (navigator mode) + +/refactor [--pattern ] [--scope function|file|module] + Refactor selected code + +/optimize [--target speed|memory|both] + Optimize code for performance + +/document [--format jsdoc|markdown|inline] + Add documentation to code + +/comment [--verbose] + Add inline comments + +/pattern [--example] + Apply a design pattern +``` + +#### Testing Commands +``` +/test [--watch] [--coverage] [--only ] + Run test suite + +/test-gen [--type unit|integration|e2e] + Generate tests for current code + +/coverage [--report html|json|terminal] + Check test coverage + +/mock [--realistic] + Generate mock data or functions + +/test-watch [--on-save] + Enable test watching + +/snapshot [--update] + Create test snapshots +``` + +#### Review Commands +``` +/review [--scope current|file|changes] [--strict] + Perform code review + +/security [--deep] [--fix] + Security analysis + +/perf [--profile] [--suggestions] + Performance analysis + +/quality [--detailed] + Check code quality metrics + +/lint [--fix] [--config ] + Run linters + +/complexity [--threshold ] + Analyze code complexity +``` + +#### Navigation Commands +``` +/goto [:line[:column]] + Navigate to file or location + +/find [--regex] [--case-sensitive] + Search in project + +/recent [--limit ] + Show recent files + +/bookmark [add|list|goto|remove] [] + Manage bookmarks + +/history [--limit ] [--filter ] + Show command history + +/tree [--depth ] [--filter ] + Show project structure +``` + +#### Git Commands +``` +/diff [--staged] [--file ] + Show git diff + +/commit [--message ] [--amend] + Commit with verification + +/branch [create|switch|delete|list] [] + Branch operations + +/stash [save|pop|list|apply] [] + Stash operations + +/log [--oneline] [--limit ] + View git log + +/blame [] + Show git blame +``` + +#### AI Partner Commands +``` +/agent [switch|info|config] [] + Manage AI agent + +/teach + Teach the AI your preferences + +/feedback [positive|negative] + Provide feedback to AI + +/personality [professional|friendly|concise|verbose] + Adjust AI personality + +/expertise [add|remove|list] [] + Set AI expertise focus +``` + +#### Metrics Commands +``` +/metrics [--period today|session|week|all] + Show session metrics + +/score [--breakdown] + Show quality scores + +/productivity [--chart] + Show productivity metrics + +/leaderboard [--personal|team] + Show improvement leaderboard +``` + +#### Role & Mode Commands +``` +/switch [--immediate] + Switch driver/navigator roles + +/mode + Change mode (driver|navigator|switch|tdd|review|mentor|debug) + +/role + Show current role + +/handoff + Prepare role handoff +``` + +### Command Shortcuts + +| Alias | Full Command | +|-------|-------------| +| `/s` | `/suggest` | +| `/e` | `/explain` | +| `/t` | `/test` | +| `/r` | `/review` | +| `/c` | `/commit` | +| `/g` | `/goto` | +| `/f` | `/find` | +| `/h` | `/help` | +| `/sw` | `/switch` | +| `/st` | `/status` | + +### Configuration + +#### Basic Configuration +Create `.claude-flow/pair-config.json`: + +```json +{ + "pair": { + "enabled": true, + "defaultMode": "switch", + "defaultAgent": "auto", + "autoStart": false, + "theme": "professional" + } +} +``` + +#### Complete Configuration + +```json +{ + "pair": { + "general": { + "enabled": true, + "defaultMode": "switch", + "defaultAgent": "senior-dev", + "language": "javascript", + "timezone": "UTC" + }, + + "modes": { + "driver": { + "enabled": true, + "suggestions": true, + "realTimeReview": true, + "autoComplete": false + }, + "navigator": { + "enabled": true, + "codeGeneration": true, + "explanations": true, + "alternatives": true + }, + "switch": { + "enabled": true, + "interval": "10m", + "warning": "30s", + "autoSwitch": true, + "pauseOnIdle": true + } + }, + + "verification": { + "enabled": true, + "threshold": 0.95, + "autoRollback": true, + "preCommitCheck": true, + "continuousMonitoring": true, + "blockOnFailure": true + }, + + "testing": { + "enabled": true, + "autoRun": true, + "framework": "jest", + "onSave": true, + "coverage": { + "enabled": true, + "minimum": 80, + "enforce": true, + "reportFormat": "html" + } + }, + + "review": { + "enabled": true, + "continuous": true, + "preCommit": true, + "security": true, + "performance": true, + "style": true, + "complexity": { + "maxComplexity": 10, + "maxDepth": 4, + "maxLines": 100 + } + }, + + "git": { + "enabled": true, + "autoCommit": false, + "commitTemplate": "feat: {message}", + "signCommits": false, + "pushOnEnd": false, + "branchProtection": true + }, + + "session": { + "autoSave": true, + "saveInterval": "5m", + "maxDuration": "4h", + "idleTimeout": "15m", + "breakReminder": "45m", + "metricsInterval": "1m" + }, + + "ai": { + "model": "advanced", + "temperature": 0.7, + "maxTokens": 4000, + "personality": "professional", + "expertise": ["backend", "testing", "security"], + "learningEnabled": true + } + } +} +``` + +#### Built-in Agents + +```json +{ + "agents": { + "senior-dev": { + "expertise": ["architecture", "patterns", "optimization"], + "style": "thorough", + "reviewLevel": "strict" + }, + "tdd-specialist": { + "expertise": ["testing", "mocks", "coverage"], + "style": "test-first", + "reviewLevel": "comprehensive" + }, + "debugger-expert": { + "expertise": ["debugging", "profiling", "tracing"], + "style": "analytical", + "reviewLevel": "focused" + }, + "junior-dev": { + "expertise": ["learning", "basics", "documentation"], + "style": "questioning", + "reviewLevel": "educational" + } + } +} +``` + +#### CLI Configuration +```bash +# Set configuration +claude-flow pair config set defaultMode switch +claude-flow pair config set verification.threshold 0.98 + +# Get configuration +claude-flow pair config get +claude-flow pair config get defaultMode + +# Export/Import +claude-flow pair config export > config.json +claude-flow pair config import config.json + +# Reset +claude-flow pair config reset +``` + +#### Profile Management + +Create reusable profiles: + +```bash +# Create profile +claude-flow pair profile create refactoring \ + --mode driver \ + --verify true \ + --threshold 0.98 \ + --focus refactor + +# Use profile +claude-flow pair --start --profile refactoring + +# List profiles +claude-flow pair profile list +``` + +Profile configuration: +```json +{ + "profiles": { + "refactoring": { + "mode": "driver", + "verification": { + "enabled": true, + "threshold": 0.98 + }, + "focus": "refactor" + }, + "debugging": { + "mode": "navigator", + "agent": "debugger-expert", + "trace": true, + "verbose": true + }, + "learning": { + "mode": "mentor", + "pace": "slow", + "explanations": "detailed", + "examples": true + } + } +} +``` + +### Real-World Examples + +#### Example 1: Feature Implementation + +Implementing user authentication with JWT tokens: + +```bash +# Session setup +claude-flow pair --start \ + --mode switch \ + --agent senior-dev \ + --focus implement \ + --verify \ + --test +``` + +**Session Flow:** +``` +๐Ÿ‘ฅ Starting pair programming for authentication feature... + +[DRIVER: You - 10 minutes] +/explain JWT authentication flow +> AI explains JWT concepts and best practices + +/suggest implementation approach +> AI suggests using middleware pattern with refresh tokens + +# You write the basic auth middleware structure + +[SWITCH TO NAVIGATOR] + +[NAVIGATOR: AI - 10 minutes] +/implement JWT token generation with refresh tokens +> AI generates secure token implementation + +/test-gen +> AI creates comprehensive test suite + +[SWITCH TO DRIVER] + +[DRIVER: You - 10 minutes] +# You refine the implementation +/review --security +> AI performs security review, suggests improvements + +/commit --message "feat: JWT authentication with refresh tokens" +โœ… Truth Score: 0.98 - Committed successfully +``` + +#### Example 2: Bug Fixing + +Debugging a memory leak in Node.js: + +```bash +# Session setup +claude-flow pair --start \ + --mode navigator \ + --agent debugger-expert \ + --focus debug \ + --trace +``` + +**Session Flow:** +``` +๐Ÿ‘ฅ Starting debugging session... + +/status +> Analyzing application for memory issues... + +/perf --profile +> Memory usage growing: 150MB โ†’ 450MB over 10 minutes + +/find "new EventEmitter" --regex +> Found 3 instances of EventEmitter creation + +/inspect eventEmitters --deep +> Discovering listeners not being removed + +/suggest fix for memory leak +> AI suggests: "Add removeListener in cleanup functions" + +/implement cleanup functions for all event emitters +> AI generates proper cleanup code + +/test +> Memory stable at 150MB โœ… + +/commit --message "fix: memory leak in event emitters" +``` + +#### Example 3: TDD Session + +Building shopping cart with test-driven development: + +```bash +# Session setup +claude-flow pair --start \ + --mode tdd \ + --agent tdd-specialist \ + --test-first +``` + +**Session Flow:** +``` +๐Ÿ‘ฅ TDD Session: Shopping Cart Feature + +[RED PHASE] +/test-gen "add item to cart" +> AI writes failing test: + โœ— should add item to cart + โœ— should update quantity for existing item + โœ— should calculate total price + +[GREEN PHASE] +/implement minimal cart functionality +> You write just enough code to pass tests + +/test +> Tests passing: 3/3 โœ… + +[REFACTOR PHASE] +/refactor --pattern repository +> AI refactors to repository pattern + +/test +> Tests still passing: 3/3 โœ… + +[NEXT CYCLE] +/test-gen "remove item from cart" +> AI writes new failing tests... +``` + +#### Example 4: Code Refactoring + +Modernizing legacy code: + +```bash +# Session setup +claude-flow pair --start \ + --mode driver \ + --focus refactor \ + --verify \ + --threshold 0.98 +``` + +**Session Flow:** +``` +๐Ÿ‘ฅ Refactoring Session: Modernizing UserService + +/analyze UserService.js +> AI identifies: + - Callback hell (5 levels deep) + - No error handling + - Tight coupling + - No tests + +/suggest refactoring plan +> AI suggests: + 1. Convert callbacks to async/await + 2. Add error boundaries + 3. Extract dependencies + 4. Add unit tests + +/test-gen --before-refactor +> AI generates tests for current behavior + +/refactor callbacks to async/await +# You refactor with AI guidance + +/test +> All tests passing โœ… + +/review --compare +> AI shows before/after comparison +> Code complexity: 35 โ†’ 12 +> Truth score: 0.99 โœ… + +/commit --message "refactor: modernize UserService with async/await" +``` + +#### Example 5: Performance Optimization + +Optimizing slow React application: + +```bash +# Session setup +claude-flow pair --start \ + --mode switch \ + --agent performance-expert \ + --focus optimize \ + --profile +``` + +**Session Flow:** +``` +๐Ÿ‘ฅ Performance Optimization Session + +/perf --profile +> React DevTools Profiler Results: + - ProductList: 450ms render + - CartSummary: 200ms render + - Unnecessary re-renders: 15 + +/suggest optimizations for ProductList +> AI suggests: + 1. Add React.memo + 2. Use useMemo for expensive calculations + 3. Implement virtualization for long lists + +/implement React.memo and useMemo +# You implement with AI guidance + +/perf --profile +> ProductList: 45ms render (90% improvement!) โœ… + +/implement virtualization with react-window +> AI implements virtual scrolling + +/perf --profile +> ProductList: 12ms render (97% improvement!) โœ… +> FPS: 60 stable โœ… + +/commit --message "perf: optimize ProductList with memoization and virtualization" +``` + +#### Example 6: API Development + +Building RESTful API with Express: + +```bash +# Session setup +claude-flow pair --start \ + --mode navigator \ + --agent backend-expert \ + --focus implement \ + --test +``` + +**Session Flow:** +``` +๐Ÿ‘ฅ API Development Session + +/design REST API for blog platform +> AI designs endpoints: + POST /api/posts + GET /api/posts + GET /api/posts/:id + PUT /api/posts/:id + DELETE /api/posts/:id + +/implement CRUD endpoints with validation +> AI implements with Express + Joi validation + +/test-gen --integration +> AI generates integration tests + +/security --api +> AI adds: + - Rate limiting + - Input sanitization + - JWT authentication + - CORS configuration + +/document --openapi +> AI generates OpenAPI documentation + +/test --integration +> All endpoints tested: 15/15 โœ… +``` + +### Session Templates + +#### Quick Start Templates + +```bash +# Refactoring template +claude-flow pair --template refactor +# Focus: Code improvement +# Verification: High (0.98) +# Testing: After each change +# Review: Continuous + +# Feature template +claude-flow pair --template feature +# Focus: Implementation +# Verification: Standard (0.95) +# Testing: On completion +# Review: Pre-commit + +# Debug template +claude-flow pair --template debug +# Focus: Problem solving +# Verification: Moderate (0.90) +# Testing: Regression tests +# Review: Root cause + +# Learning template +claude-flow pair --template learn +# Mode: Mentor +# Pace: Slow +# Explanations: Detailed +# Examples: Many +``` + +### Session Management + +#### Session Status + +```bash +claude-flow pair --status +``` + +**Output:** +``` +๐Ÿ‘ฅ Pair Programming Session +โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ” + +Session ID: pair_1755021234567 +Duration: 45 minutes +Status: Active + +Partner: senior-dev +Current Role: DRIVER (you) +Mode: Switch (10m intervals) +Next Switch: in 3 minutes + +๐Ÿ“Š Metrics: +โ”œโ”€โ”€ Truth Score: 0.982 โœ… +โ”œโ”€โ”€ Lines Changed: 234 +โ”œโ”€โ”€ Files Modified: 5 +โ”œโ”€โ”€ Tests Added: 12 +โ”œโ”€โ”€ Coverage: 87% โ†‘3% +โ””โ”€โ”€ Commits: 3 + +๐ŸŽฏ Focus: Implementation +๐Ÿ“ Current File: src/auth/login.js +``` + +#### Session History + +```bash +claude-flow pair --history +``` + +**Output:** +``` +๐Ÿ“š Session History +โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ” + +1. 2024-01-15 14:30 - 16:45 (2h 15m) + Partner: expert-coder + Focus: Refactoring + Truth Score: 0.975 + Changes: +340 -125 lines + +2. 2024-01-14 10:00 - 11:30 (1h 30m) + Partner: tdd-specialist + Focus: Testing + Truth Score: 0.991 + Tests Added: 24 + +3. 2024-01-13 15:00 - 17:00 (2h) + Partner: debugger-expert + Focus: Bug Fixing + Truth Score: 0.968 + Issues Fixed: 5 +``` + +#### Session Persistence + +```bash +# Save session +claude-flow pair --save [--name ] + +# Load session +claude-flow pair --load + +# Export session +claude-flow pair --export [--format json|md] + +# Generate report +claude-flow pair --report +``` + +#### Background Sessions + +```bash +# Start in background +claude-flow pair --start --background + +# Monitor background session +claude-flow pair --monitor + +# Attach to background session +claude-flow pair --attach + +# End background session +claude-flow pair --end +``` + +### Advanced Features + +#### Custom Commands + +Define in configuration: + +```json +{ + "customCommands": { + "tdd": "/test-gen && /test --watch", + "full-review": "/lint --fix && /test && /review --strict", + "quick-fix": "/suggest --type fix && /implement && /test" + } +} +``` + +Use custom commands: +``` +/custom tdd +/custom full-review +``` + +#### Command Chaining + +``` +/test && /commit && /push +/lint --fix && /test && /review --strict +``` + +#### Session Recording + +```bash +# Start with recording +claude-flow pair --start --record + +# Replay session +claude-flow pair --replay + +# Session analytics +claude-flow pair --analytics +``` + +#### Integration Options + +**With Git:** +```bash +claude-flow pair --start --git --auto-commit +``` + +**With CI/CD:** +```bash +claude-flow pair --start --ci --non-interactive +``` + +**With IDE:** +```bash +claude-flow pair --start --ide vscode +``` + +### Best Practices + +#### Session Practices +1. **Clear Goals** - Define session objectives upfront +2. **Appropriate Mode** - Choose based on task type +3. **Enable Verification** - For critical code paths +4. **Regular Testing** - Maintain quality continuously +5. **Session Notes** - Document important decisions +6. **Regular Breaks** - Take breaks every 45-60 minutes + +#### Code Practices +1. **Test Early** - Run tests after each change +2. **Verify Before Commit** - Check truth scores +3. **Review Security** - Always for sensitive code +4. **Profile Performance** - Use `/perf` for optimization +5. **Save Sessions** - For complex work +6. **Learn from AI** - Ask questions frequently + +#### Mode Selection +- **Driver Mode**: When learning, controlling implementation +- **Navigator Mode**: For rapid prototyping, generation +- **Switch Mode**: Long sessions, balanced collaboration +- **TDD Mode**: Building with tests +- **Review Mode**: Quality focus +- **Mentor Mode**: Learning priority +- **Debug Mode**: Fixing issues + +### Troubleshooting + +#### Session Won't Start +- Check agent availability +- Verify configuration file syntax +- Ensure clean workspace +- Review log files + +#### Session Disconnected +- Use `--recover` to restore +- Check network connection +- Verify background processes +- Review auto-save files + +#### Poor Performance +- Reduce verification threshold +- Disable continuous testing +- Check system resources +- Use lighter AI model + +#### Configuration Issues +- Validate JSON syntax +- Check file permissions +- Review priority order (CLI > env > project > user > global) +- Run `claude-flow pair config validate` + +### Quality Metrics + +#### Truth Score Thresholds +``` +Error: < 0.90 โŒ +Warning: 0.90 - 0.95 โš ๏ธ +Good: 0.95 - 0.98 โœ… +Excellent: > 0.98 ๐ŸŒŸ +``` + +#### Coverage Thresholds +``` +Error: < 70% โŒ +Warning: 70% - 80% โš ๏ธ +Good: 80% - 90% โœ… +Excellent: > 90% ๐ŸŒŸ +``` + +#### Complexity Thresholds +``` +Error: > 15 โŒ +Warning: 10 - 15 โš ๏ธ +Good: 5 - 10 โœ… +Excellent: < 5 ๐ŸŒŸ +``` + +### Environment Variables + +Override configuration via environment: + +```bash +export CLAUDE_PAIR_MODE=driver +export CLAUDE_PAIR_VERIFY=true +export CLAUDE_PAIR_THRESHOLD=0.98 +export CLAUDE_PAIR_AGENT=senior-dev +export CLAUDE_PAIR_AUTO_TEST=true +``` + +### Command History + +Navigate history: +- `โ†‘/โ†“` - Navigate through command history +- `Ctrl+R` - Search command history +- `!!` - Repeat last command +- `!` - Run command n from history + +### Keyboard Shortcuts (Configurable) + +Default shortcuts: +```json +{ + "shortcuts": { + "switch": "ctrl+shift+s", + "suggest": "ctrl+space", + "review": "ctrl+r", + "test": "ctrl+t" + } +} +``` + +### Related Commands + +- `claude-flow pair --help` - Show help +- `claude-flow pair config` - Manage configuration +- `claude-flow pair profile` - Manage profiles +- `claude-flow pair templates` - List templates +- `claude-flow pair agents` - List available agents diff --git a/.claude/skills/peekaboo/SKILL.md b/.claude/skills/peekaboo/SKILL.md new file mode 100644 index 0000000000..940839cffb --- /dev/null +++ b/.claude/skills/peekaboo/SKILL.md @@ -0,0 +1,153 @@ +--- +name: peekaboo +description: Capture and automate macOS UI with the Peekaboo CLI. +homepage: https://peekaboo.boo +metadata: {"zee":{"emoji":"๐Ÿ‘€","os":["darwin"],"requires":{"bins":["peekaboo"]},"install":[{"id":"brew","kind":"brew","formula":"steipete/tap/peekaboo","bins":["peekaboo"],"label":"Install Peekaboo (brew)"}]}} +--- + +# Peekaboo + +Peekaboo is a full macOS UI automation CLI: capture/inspect screens, target UI +elements, drive input, and manage apps/windows/menus. Commands share a snapshot +cache and support `--json`/`-j` for scripting. Run `peekaboo` or +`peekaboo --help` for flags; `peekaboo --version` prints build metadata. +Tip: run via `polter peekaboo` to ensure fresh builds. + +## Features (all CLI capabilities, excluding agent/MCP) + +Core +- `bridge`: inspect Peekaboo Bridge host connectivity +- `capture`: live capture or video ingest + frame extraction +- `clean`: prune snapshot cache and temp files +- `config`: init/show/edit/validate, providers, models, credentials +- `image`: capture screenshots (screen/window/menu bar regions) +- `learn`: print the full agent guide + tool catalog +- `list`: apps, windows, screens, menubar, permissions +- `permissions`: check Screen Recording/Accessibility status +- `run`: execute `.peekaboo.json` scripts +- `sleep`: pause execution for a duration +- `tools`: list available tools with filtering/display options + +Interaction +- `click`: target by ID/query/coords with smart waits +- `drag`: drag & drop across elements/coords/Dock +- `hotkey`: modifier combos like `cmd,shift,t` +- `move`: cursor positioning with optional smoothing +- `paste`: set clipboard -> paste -> restore +- `press`: special-key sequences with repeats +- `scroll`: directional scrolling (targeted + smooth) +- `swipe`: gesture-style drags between targets +- `type`: text + control keys (`--clear`, delays) + +System +- `app`: launch/quit/relaunch/hide/unhide/switch/list apps +- `clipboard`: read/write clipboard (text/images/files) +- `dialog`: click/input/file/dismiss/list system dialogs +- `dock`: launch/right-click/hide/show/list Dock items +- `menu`: click/list application menus + menu extras +- `menubar`: list/click status bar items +- `open`: enhanced `open` with app targeting + JSON payloads +- `space`: list/switch/move-window (Spaces) +- `visualizer`: exercise Peekaboo visual feedback animations +- `window`: close/minimize/maximize/move/resize/focus/list + +Vision +- `see`: annotated UI maps, snapshot IDs, optional analysis + +Global runtime flags +- `--json`/`-j`, `--verbose`/`-v`, `--log-level ` +- `--no-remote`, `--bridge-socket ` + +## Quickstart (happy path) +```bash +peekaboo permissions +peekaboo list apps --json +peekaboo see --annotate --path /tmp/peekaboo-see.png +peekaboo click --on B1 +peekaboo type "Hello" --return +``` + +## Common targeting parameters (most interaction commands) +- App/window: `--app`, `--pid`, `--window-title`, `--window-id`, `--window-index` +- Snapshot targeting: `--snapshot` (ID from `see`; defaults to latest) +- Element/coords: `--on`/`--id` (element ID), `--coords x,y` +- Focus control: `--no-auto-focus`, `--space-switch`, `--bring-to-current-space`, + `--focus-timeout-seconds`, `--focus-retry-count` + +## Common capture parameters +- Output: `--path`, `--format png|jpg`, `--retina` +- Targeting: `--mode screen|window|frontmost`, `--screen-index`, + `--window-title`, `--window-id` +- Analysis: `--analyze "prompt"`, `--annotate` +- Capture engine: `--capture-engine auto|classic|cg|modern|sckit` + +## Common motion/typing parameters +- Timing: `--duration` (drag/swipe), `--steps`, `--delay` (type/scroll/press) +- Human-ish movement: `--profile human|linear`, `--wpm` (typing) +- Scroll: `--direction up|down|left|right`, `--amount `, `--smooth` + +## Examples +### See -> click -> type (most reliable flow) +```bash +peekaboo see --app Safari --window-title "Login" --annotate --path /tmp/see.png +peekaboo click --on B3 --app Safari +peekaboo type "user@example.com" --app Safari +peekaboo press tab --count 1 --app Safari +peekaboo type "supersecret" --app Safari --return +``` + +### Target by window id +```bash +peekaboo list windows --app "Visual Studio Code" --json +peekaboo click --window-id 12345 --coords 120,160 +peekaboo type "Hello from Peekaboo" --window-id 12345 +``` + +### Capture screenshots + analyze +```bash +peekaboo image --mode screen --screen-index 0 --retina --path /tmp/screen.png +peekaboo image --app Safari --window-title "Dashboard" --analyze "Summarize KPIs" +peekaboo see --mode screen --screen-index 0 --analyze "Summarize the dashboard" +``` + +### Live capture (motion-aware) +```bash +peekaboo capture live --mode region --region 100,100,800,600 --duration 30 \ + --active-fps 8 --idle-fps 2 --highlight-changes --path /tmp/capture +``` + +### App + window management +```bash +peekaboo app launch "Safari" --open https://example.com +peekaboo window focus --app Safari --window-title "Example" +peekaboo window set-bounds --app Safari --x 50 --y 50 --width 1200 --height 800 +peekaboo app quit --app Safari +``` + +### Menus, menubar, dock +```bash +peekaboo menu click --app Safari --item "New Window" +peekaboo menu click --app TextEdit --path "Format > Font > Show Fonts" +peekaboo menu click-extra --title "WiFi" +peekaboo dock launch Safari +peekaboo menubar list --json +``` + +### Mouse + gesture input +```bash +peekaboo move 500,300 --smooth +peekaboo drag --from B1 --to T2 +peekaboo swipe --from-coords 100,500 --to-coords 100,200 --duration 800 +peekaboo scroll --direction down --amount 6 --smooth +``` + +### Keyboard input +```bash +peekaboo hotkey --keys "cmd,shift,t" +peekaboo press escape +peekaboo type "Line 1\nLine 2" --delay 10 +``` + +Notes +- Requires Screen Recording + Accessibility permissions. +- Use `peekaboo see --annotate` to identify targets before clicking. diff --git a/.claude/skills/performance-analysis/SKILL.md b/.claude/skills/performance-analysis/SKILL.md new file mode 100644 index 0000000000..653d51f657 --- /dev/null +++ b/.claude/skills/performance-analysis/SKILL.md @@ -0,0 +1,563 @@ +--- +name: performance-analysis +version: 1.0.0 +description: Comprehensive performance analysis, bottleneck detection, and optimization recommendations for Claude Flow swarms +category: monitoring +tags: [performance, bottleneck, optimization, profiling, metrics, analysis] +author: Claude Flow Team +--- + +# Performance Analysis Skill + +Comprehensive performance analysis suite for identifying bottlenecks, profiling swarm operations, generating detailed reports, and providing actionable optimization recommendations. + +## Overview + +This skill consolidates all performance analysis capabilities: +- **Bottleneck Detection**: Identify performance bottlenecks across communication, processing, memory, and network +- **Performance Profiling**: Real-time monitoring and historical analysis of swarm operations +- **Report Generation**: Create comprehensive performance reports in multiple formats +- **Optimization Recommendations**: AI-powered suggestions for improving performance + +## Quick Start + +### Basic Bottleneck Detection +```bash +npx claude-flow bottleneck detect +``` + +### Generate Performance Report +```bash +npx claude-flow analysis performance-report --format html --include-metrics +``` + +### Analyze and Auto-Fix +```bash +npx claude-flow bottleneck detect --fix --threshold 15 +``` + +## Core Capabilities + +### 1. Bottleneck Detection + +#### Command Syntax +```bash +npx claude-flow bottleneck detect [options] +``` + +#### Options +- `--swarm-id, -s ` - Analyze specific swarm (default: current) +- `--time-range, -t ` - Analysis period: 1h, 24h, 7d, all (default: 1h) +- `--threshold ` - Bottleneck threshold percentage (default: 20) +- `--export, -e ` - Export analysis to file +- `--fix` - Apply automatic optimizations + +#### Usage Examples +```bash +# Basic detection for current swarm +npx claude-flow bottleneck detect + +# Analyze specific swarm over 24 hours +npx claude-flow bottleneck detect --swarm-id swarm-123 -t 24h + +# Export detailed analysis +npx claude-flow bottleneck detect -t 24h -e bottlenecks.json + +# Auto-fix detected issues +npx claude-flow bottleneck detect --fix --threshold 15 + +# Low threshold for sensitive detection +npx claude-flow bottleneck detect --threshold 10 --export critical-issues.json +``` + +#### Metrics Analyzed + +**Communication Bottlenecks:** +- Message queue delays +- Agent response times +- Coordination overhead +- Memory access patterns +- Inter-agent communication latency + +**Processing Bottlenecks:** +- Task completion times +- Agent utilization rates +- Parallel execution efficiency +- Resource contention +- CPU/memory usage patterns + +**Memory Bottlenecks:** +- Cache hit rates +- Memory access patterns +- Storage I/O performance +- Neural pattern loading times +- Memory allocation efficiency + +**Network Bottlenecks:** +- API call latency +- MCP communication delays +- External service timeouts +- Concurrent request limits +- Network throughput issues + +#### Output Format +``` +๐Ÿ” Bottleneck Analysis Report +โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ” + +๐Ÿ“Š Summary +โ”œโ”€โ”€ Time Range: Last 1 hour +โ”œโ”€โ”€ Agents Analyzed: 6 +โ”œโ”€โ”€ Tasks Processed: 42 +โ””โ”€โ”€ Critical Issues: 2 + +๐Ÿšจ Critical Bottlenecks +1. Agent Communication (35% impact) + โ””โ”€โ”€ coordinator โ†’ coder-1 messages delayed by 2.3s avg + +2. Memory Access (28% impact) + โ””โ”€โ”€ Neural pattern loading taking 1.8s per access + +โš ๏ธ Warning Bottlenecks +1. Task Queue (18% impact) + โ””โ”€โ”€ 5 tasks waiting > 10s for assignment + +๐Ÿ’ก Recommendations +1. Switch to hierarchical topology (est. 40% improvement) +2. Enable memory caching (est. 25% improvement) +3. Increase agent concurrency to 8 (est. 20% improvement) + +โœ… Quick Fixes Available +Run with --fix to apply: +- Enable smart caching +- Optimize message routing +- Adjust agent priorities +``` + +### 2. Performance Profiling + +#### Real-time Detection +Automatic analysis during task execution: +- Execution time vs. complexity +- Agent utilization rates +- Resource constraints +- Operation patterns + +#### Common Bottleneck Patterns + +**Time Bottlenecks:** +- Tasks taking > 5 minutes +- Sequential operations that could parallelize +- Redundant file operations +- Inefficient algorithm implementations + +**Coordination Bottlenecks:** +- Single agent for complex tasks +- Unbalanced agent workloads +- Poor topology selection +- Excessive synchronization points + +**Resource Bottlenecks:** +- High operation count (> 100) +- Memory constraints +- I/O limitations +- Thread pool saturation + +#### MCP Integration +```javascript +// Check for bottlenecks in Claude Code +mcp__claude-flow__bottleneck_detect({ + timeRange: "1h", + threshold: 20, + autoFix: false +}) + +// Get detailed task results with bottleneck analysis +mcp__claude-flow__task_results({ + taskId: "task-123", + format: "detailed" +}) +``` + +**Result Format:** +```json +{ + "bottlenecks": [ + { + "type": "coordination", + "severity": "high", + "description": "Single agent used for complex task", + "recommendation": "Spawn specialized agents for parallel work", + "impact": "35%", + "affectedComponents": ["coordinator", "coder-1"] + } + ], + "improvements": [ + { + "area": "execution_time", + "suggestion": "Use parallel task execution", + "expectedImprovement": "30-50% time reduction", + "implementationSteps": [ + "Split task into smaller units", + "Spawn 3-4 specialized agents", + "Use mesh topology for coordination" + ] + } + ], + "metrics": { + "avgExecutionTime": "142s", + "agentUtilization": "67%", + "cacheHitRate": "82%", + "parallelizationFactor": 1.2 + } +} +``` + +### 3. Report Generation + +#### Command Syntax +```bash +npx claude-flow analysis performance-report [options] +``` + +#### Options +- `--format ` - Report format: json, html, markdown (default: markdown) +- `--include-metrics` - Include detailed metrics and charts +- `--compare ` - Compare with previous swarm +- `--time-range ` - Analysis period: 1h, 24h, 7d, 30d, all +- `--output ` - Output file path +- `--sections ` - Comma-separated sections to include + +#### Report Sections +1. **Executive Summary** + - Overall performance score + - Key metrics overview + - Critical findings + +2. **Swarm Overview** + - Topology configuration + - Agent distribution + - Task statistics + +3. **Performance Metrics** + - Execution times + - Throughput analysis + - Resource utilization + - Latency breakdown + +4. **Bottleneck Analysis** + - Identified bottlenecks + - Impact assessment + - Optimization priorities + +5. **Comparative Analysis** (when --compare used) + - Performance trends + - Improvement metrics + - Regression detection + +6. **Recommendations** + - Prioritized action items + - Expected improvements + - Implementation guidance + +#### Usage Examples +```bash +# Generate HTML report with all metrics +npx claude-flow analysis performance-report --format html --include-metrics + +# Compare current swarm with previous +npx claude-flow analysis performance-report --compare swarm-123 --format markdown + +# Custom output with specific sections +npx claude-flow analysis performance-report \ + --sections summary,metrics,recommendations \ + --output reports/perf-analysis.html \ + --format html + +# Weekly performance report +npx claude-flow analysis performance-report \ + --time-range 7d \ + --include-metrics \ + --format markdown \ + --output docs/weekly-performance.md + +# JSON format for CI/CD integration +npx claude-flow analysis performance-report \ + --format json \ + --output build/performance.json +``` + +#### Sample Markdown Report +```markdown +# Performance Analysis Report + +## Executive Summary +- **Overall Score**: 87/100 +- **Analysis Period**: Last 24 hours +- **Swarms Analyzed**: 3 +- **Critical Issues**: 1 + +## Key Metrics +| Metric | Value | Trend | Target | +|--------|-------|-------|--------| +| Avg Task Time | 42s | โ†“ 12% | 35s | +| Agent Utilization | 78% | โ†‘ 5% | 85% | +| Cache Hit Rate | 91% | โ†’ | 90% | +| Parallel Efficiency | 2.3x | โ†‘ 0.4x | 2.5x | + +## Bottleneck Analysis +### Critical +1. **Agent Communication Delay** (Impact: 35%) + - Coordinator โ†’ Coder messages delayed by 2.3s avg + - **Fix**: Switch to hierarchical topology + +### Warnings +1. **Memory Access Pattern** (Impact: 18%) + - Neural pattern loading: 1.8s per access + - **Fix**: Enable memory caching + +## Recommendations +1. **High Priority**: Switch to hierarchical topology (40% improvement) +2. **Medium Priority**: Enable memory caching (25% improvement) +3. **Low Priority**: Increase agent concurrency to 8 (20% improvement) +``` + +### 4. Optimization Recommendations + +#### Automatic Fixes +When using `--fix`, the following optimizations may be applied: + +**1. Topology Optimization** +- Switch to more efficient topology (mesh โ†’ hierarchical) +- Adjust communication patterns +- Reduce coordination overhead +- Optimize message routing + +**2. Caching Enhancement** +- Enable memory caching +- Optimize cache strategies +- Preload common patterns +- Implement cache warming + +**3. Concurrency Tuning** +- Adjust agent counts +- Optimize parallel execution +- Balance workload distribution +- Implement load balancing + +**4. Priority Adjustment** +- Reorder task queues +- Prioritize critical paths +- Reduce wait times +- Implement fair scheduling + +**5. Resource Optimization** +- Optimize memory usage +- Reduce I/O operations +- Batch API calls +- Implement connection pooling + +#### Performance Impact +Typical improvements after bottleneck resolution: + +- **Communication**: 30-50% faster message delivery +- **Processing**: 20-40% reduced task completion time +- **Memory**: 40-60% fewer cache misses +- **Network**: 25-45% reduced API latency +- **Overall**: 25-45% total performance improvement + +## Advanced Usage + +### Continuous Monitoring +```bash +# Monitor performance in real-time +npx claude-flow swarm monitor --interval 5 + +# Generate hourly reports +while true; do + npx claude-flow analysis performance-report \ + --format json \ + --output logs/perf-$(date +%Y%m%d-%H%M).json + sleep 3600 +done +``` + +### CI/CD Integration +```yaml +# .github/workflows/performance.yml +name: Performance Analysis +on: [push, pull_request] + +jobs: + analyze: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Run Performance Analysis + run: | + npx claude-flow analysis performance-report \ + --format json \ + --output performance.json + - name: Check Performance Thresholds + run: | + npx claude-flow bottleneck detect \ + --threshold 15 \ + --export bottlenecks.json + - name: Upload Reports + uses: actions/upload-artifact@v2 + with: + name: performance-reports + path: | + performance.json + bottlenecks.json +``` + +### Custom Analysis Scripts +```javascript +// scripts/analyze-performance.js +const { exec } = require('child_process'); +const fs = require('fs'); + +async function analyzePerformance() { + // Run bottleneck detection + const bottlenecks = await runCommand( + 'npx claude-flow bottleneck detect --format json' + ); + + // Generate performance report + const report = await runCommand( + 'npx claude-flow analysis performance-report --format json' + ); + + // Analyze results + const analysis = { + bottlenecks: JSON.parse(bottlenecks), + performance: JSON.parse(report), + timestamp: new Date().toISOString() + }; + + // Save combined analysis + fs.writeFileSync( + 'analysis/combined-report.json', + JSON.stringify(analysis, null, 2) + ); + + // Generate alerts if needed + if (analysis.bottlenecks.critical.length > 0) { + console.error('CRITICAL: Performance bottlenecks detected!'); + process.exit(1); + } +} + +function runCommand(cmd) { + return new Promise((resolve, reject) => { + exec(cmd, (error, stdout, stderr) => { + if (error) reject(error); + else resolve(stdout); + }); + }); +} + +analyzePerformance().catch(console.error); +``` + +## Best Practices + +### 1. Regular Analysis +- Run bottleneck detection after major changes +- Generate weekly performance reports +- Monitor trends over time +- Set up automated alerts + +### 2. Threshold Tuning +- Start with default threshold (20%) +- Lower for production systems (10-15%) +- Higher for development (25-30%) +- Adjust based on requirements + +### 3. Fix Strategy +- Always review before applying --fix +- Test fixes in development first +- Apply fixes incrementally +- Monitor impact after changes + +### 4. Report Integration +- Include in documentation +- Share with team regularly +- Track improvements over time +- Use for capacity planning + +### 5. Continuous Optimization +- Learn from each analysis +- Build performance budgets +- Establish baselines +- Set improvement goals + +## Troubleshooting + +### Common Issues + +**High Memory Usage** +```bash +# Analyze memory bottlenecks +npx claude-flow bottleneck detect --threshold 10 + +# Check cache performance +npx claude-flow cache manage --action stats + +# Review memory metrics +npx claude-flow memory usage +``` + +**Slow Task Execution** +```bash +# Identify slow tasks +npx claude-flow task status --detailed + +# Analyze coordination overhead +npx claude-flow bottleneck detect --time-range 1h + +# Check agent utilization +npx claude-flow agent metrics +``` + +**Poor Cache Performance** +```bash +# Analyze cache hit rates +npx claude-flow analysis performance-report --sections metrics + +# Review cache strategy +npx claude-flow cache manage --action analyze + +# Enable cache warming +npx claude-flow bottleneck detect --fix +``` + +## Integration with Other Skills + +- **swarm-orchestration**: Use performance data to optimize topology +- **memory-management**: Improve cache strategies based on analysis +- **task-coordination**: Adjust scheduling based on bottlenecks +- **neural-training**: Train patterns from performance data + +## Related Commands + +- `npx claude-flow swarm monitor` - Real-time monitoring +- `npx claude-flow token usage` - Token optimization analysis +- `npx claude-flow cache manage` - Cache optimization +- `npx claude-flow agent metrics` - Agent performance metrics +- `npx claude-flow task status` - Task execution analysis + +## See Also + +- [Bottleneck Detection Guide](/workspaces/claude-code-flow/.claude/commands/analysis/bottleneck-detect.md) +- [Performance Report Guide](/workspaces/claude-code-flow/.claude/commands/analysis/performance-report.md) +- [Performance Bottlenecks Overview](/workspaces/claude-code-flow/.claude/commands/analysis/performance-bottlenecks.md) +- [Swarm Monitoring Documentation](../swarm-orchestration/SKILL.md) +- [Memory Management Documentation](../memory-management/SKILL.md) + +--- + +**Version**: 1.0.0 +**Last Updated**: 2025-10-19 +**Maintainer**: Claude Flow Team diff --git a/.claude/skills/portfolio-analytics/SKILL.md b/.claude/skills/portfolio-analytics/SKILL.md new file mode 100644 index 0000000000..baf2195635 --- /dev/null +++ b/.claude/skills/portfolio-analytics/SKILL.md @@ -0,0 +1,117 @@ +--- +name: portfolio-analytics +description: Analyze portfolio risk, performance, and allocation +triggers: + - portfolio analysis + - risk metrics + - portfolio performance + - allocation analysis + - VaR +--- + +# Portfolio Analytics + +Comprehensive portfolio risk and performance analysis. + +## Risk Metrics + +### Using Stanley Backend +``` +from stanley.portfolio import PortfolioAnalyzer + +# Example portfolio +positions = [ + {"symbol": "AAPL", "shares": 100, "avg_cost": 150.0}, + {"symbol": "MSFT", "shares": 50, "avg_cost": 280.0}, + {"symbol": "GOOGL", "shares": 25, "avg_cost": 130.0}, +] + +analyzer = PortfolioAnalyzer(positions) + +# Risk metrics +var_95 = analyzer.calculate_var(confidence=0.95, days=1) +cvar = analyzer.calculate_cvar(confidence=0.95) +beta = analyzer.calculate_portfolio_beta(benchmark="SPY") +sharpe = analyzer.calculate_sharpe_ratio() +``` + +### Via OpenBB +``` +# Get correlation matrix +symbols = [p["symbol"] for p in positions] +prices = obb.equity.price.historical(symbol=",".join(symbols)) +# Calculate correlation from prices DataFrame +``` + +## Sector Exposure + +``` +# Sector breakdown +exposure = analyzer.get_sector_exposure() +# { +# "Technology": 0.65, +# "Communication Services": 0.15, +# "Consumer Discretionary": 0.20 +# } +``` + +## Performance Attribution + +``` +# Factor attribution +attribution = analyzer.calculate_attribution( + start_date="2024-01-01", + end_date="2024-06-30", + factors=["SPY", "QQQ", "IWM"] +) +``` + +## Stress Testing + +``` +# Historical scenarios +scenarios = analyzer.stress_test([ + {"name": "2008 Crisis", "spy_return": -0.38}, + {"name": "COVID Crash", "spy_return": -0.34}, + {"name": "Tech Correction", "qqq_return": -0.25}, +]) +``` + +## Output Format + +Portfolio Report: +1. Holdings summary with current values +2. Risk metrics (VaR, Sharpe, Beta) +3. Sector/factor exposure +4. Performance vs benchmark +5. Risk-adjusted returns +6. Recommendations for rebalancing + +## Memory Integration + +Store portfolio state: +```typescript +await memory.store({ + namespace: "stanley/portfolio", + key: "positions", + value: { + holdings: [...], + lastUpdated: new Date(), + totalValue: 125000, + dayChange: 1250, + dayChangePct: 0.01 + } +}); + +await memory.store({ + namespace: "stanley/portfolio", + key: "performance", + value: { + ytdReturn: 0.12, + sharpe: 1.25, + beta: 1.1, + maxDrawdown: -0.08, + benchmarkReturn: 0.10 + } +}); +``` diff --git a/.claude/skills/problem-solving/SKILL.md b/.claude/skills/problem-solving/SKILL.md new file mode 100644 index 0000000000..c8dc2378df --- /dev/null +++ b/.claude/skills/problem-solving/SKILL.md @@ -0,0 +1,107 @@ +--- +name: problem-solving +description: Structured problem-solving with scaffolding for math and informatics +triggers: + - solve + - problem + - exercise + - challenge + - stuck +--- + +# Problem Solving + +Guide through problems with appropriate scaffolding, developing independence. + +## Problem-Solving Framework + +### Polya's Four Steps +1. **Understand**: What is given? What is asked? +2. **Plan**: What approach? What tools needed? +3. **Execute**: Carry out the plan carefully +4. **Reflect**: Is answer reasonable? What did I learn? + +## Scaffolding Levels + +### Level 1: Heavy Support +- Break problem into small steps +- Provide hints at each step +- Model the thinking process + +### Level 2: Moderate Support +- Outline the approach +- Let student fill in details +- Intervene only when stuck + +### Level 3: Light Support +- Only confirm approach is valid +- Student does all work +- Review at end + +### Level 4: Independence +- Student works alone +- Only helps if explicitly asked +- Focus on meta-cognitive skills + +## Hint Progression + +When student is stuck: + +1. **Metacognitive**: "What have you tried? What do you know?" +2. **Strategic**: "Have you seen a similar problem?" +3. **Tactical**: "Try looking at [specific aspect]" +4. **Direct**: "The next step is..." + +Never jump to direct hints. Work down the ladder. + +## Problem Categories + +### Math Problems +- Computational (apply algorithms) +- Conceptual (apply understanding) +- Proof (logical reasoning) +- Modeling (translate real-world) + +### Informatics Problems +- Implementation (code it correctly) +- Algorithm design (find efficient approach) +- Debugging (find and fix errors) +- Optimization (improve existing solution) + +## Error Response + +When student makes error: +1. Don't immediately correct +2. Ask "Are you sure about that step?" +3. If they can't find error: point to location, not solution +4. If still stuck: explain the error type +5. Have them redo with understanding + +## Memory Integration + +Track problem-solving patterns: +```typescript +await memory.store({ + namespace: "johny/problems", + key: `${topic}/${problemId}`, + value: { + problem: "...", + topic, + difficulty: "medium", + attemptCount: 2, + solvedIndependently: false, + scaffoldingUsed: "level-2", + timeToSolve: 480, // seconds + hintsUsed: ["strategic"], + errorsEncountered: ["sign-error", "index-off-by-one"], + reflection: "Need more practice with boundary conditions" + } +}); +``` + +## Progression Tracking + +Move to harder problems when: +- 3 consecutive problems solved at current level +- Less than 1 hint needed on average +- Time under threshold for problem type diff --git a/.claude/skills/progress-tracking/SKILL.md b/.claude/skills/progress-tracking/SKILL.md new file mode 100644 index 0000000000..3e304d3cee --- /dev/null +++ b/.claude/skills/progress-tracking/SKILL.md @@ -0,0 +1,137 @@ +--- +name: progress-tracking +description: Track learning progress, identify gaps, and adapt curriculum +triggers: + - progress + - status + - what should I learn + - review + - dashboard +--- + +# Progress Tracking + +Monitor learning journey with data-driven insights. + +## Mastery-Based Progression + +### Mastery Levels +``` +Level 0: Never seen +Level 1: Introduced (< 50% accuracy) +Level 2: Developing (50-70% accuracy) +Level 3: Proficient (70-90% accuracy) +Level 4: Mastered (> 90% accuracy, retained over time) +``` + +### Advancement Criteria +To advance from Level N to N+1: +- Accuracy threshold met for 3+ sessions +- Demonstrated retention after 7 days +- Can apply to novel problems + +## Learning Metrics + +### Daily Metrics +- Time spent practicing +- Problems attempted / solved +- New concepts introduced +- Items reviewed via spaced repetition + +### Weekly Metrics +- Topics progressed +- Mastery levels gained +- Retention rate (% of reviewed items correct) +- Streak days + +### Long-term Metrics +- Overall curriculum completion % +- Average time to mastery per topic +- Retention curve +- Skill tree coverage + +## Gap Analysis + +Identify what's blocking progress: + +```typescript +async function findGaps(targetTopic: string) { + const prereqs = await getPrerequisites(targetTopic); + const mastery = await getMasteryLevels(prereqs); + + return prereqs.filter(p => mastery[p] < 3); // Not proficient +} +``` + +## Curriculum Adaptation + +### When Student Is Struggling +- Review prerequisites +- More scaffolded practice +- Simpler examples first +- More spaced repetition + +### When Student Is Breezing +- Skip ahead +- Introduce harder variants +- Reduce scaffolding +- Challenge problems + +## Memory Schema + +### Student Profile +```typescript +await memory.store({ + namespace: "johny/profile", + key: "current", + value: { + currentTopics: ["calculus/integration"], + overallProgress: 0.35, // 35% of curriculum + streakDays: 12, + totalPracticeHours: 47, + strongAreas: ["algebra", "logic"], + weakAreas: ["geometry", "probability"], + learningStyle: "visual", + preferredSessionLength: 25 // minutes + } +}); +``` + +### Topic Progress +```typescript +await memory.store({ + namespace: "johny/topics", + key: topic, + value: { + topic, + masteryLevel: 3, + accuracy7day: 0.82, + accuracy30day: 0.78, + lastPracticed: new Date(), + nextReview: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000), + problemsSolved: 45, + averageTimePerProblem: 120, // seconds + notes: "Struggles with integration by parts" + } +}); +``` + +## Progress Reports + +### Daily Summary +- What was practiced +- Accuracy by topic +- Items added to review queue +- Recommendations for tomorrow + +### Weekly Review +- Topics progressed +- New masteries achieved +- Gaps identified +- Curriculum adjustments + +### Monthly Review +- Overall trajectory +- Comparison to goals +- Major achievements +- Strategic recommendations diff --git a/.claude/skills/qmd/SKILL.md b/.claude/skills/qmd/SKILL.md new file mode 100644 index 0000000000..6128e7adc0 --- /dev/null +++ b/.claude/skills/qmd/SKILL.md @@ -0,0 +1,26 @@ +--- +name: qmd +description: Local search/indexing CLI (BM25 + vectors + rerank) with MCP mode. +homepage: https://tobi.lutke.com +metadata: {"zee":{"emoji":"๐Ÿ“","requires":{"bins":["qmd"]},"install":[{"id":"node","kind":"node","package":"https://github.com/tobi/qmd","bins":["qmd"],"label":"Install qmd (node)"}]}} +--- + +# qmd + +Use `qmd` to index local files and search them. + +Indexing +- Add collection: `qmd collection add /path --name docs --mask "**/*.md"` +- Update index: `qmd update` +- Status: `qmd status` + +Search +- BM25: `qmd search "query"` +- Vector: `qmd vsearch "query"` +- Hybrid: `qmd query "query"` +- Get doc: `qmd get docs/path.md:10 -l 40` + +Notes +- Embeddings/rerank use Ollama at `OLLAMA_URL` (default `http://localhost:11434`). +- Index lives under `~/.cache/qmd` by default. +- MCP mode: `qmd mcp`. diff --git a/.claude/skills/reasoningbank-agentdb/SKILL.md b/.claude/skills/reasoningbank-agentdb/SKILL.md new file mode 100644 index 0000000000..1f19a359bb --- /dev/null +++ b/.claude/skills/reasoningbank-agentdb/SKILL.md @@ -0,0 +1,446 @@ +--- +name: "ReasoningBank with AgentDB" +description: "Implement ReasoningBank adaptive learning with AgentDB's 150x faster vector database. Includes trajectory tracking, verdict judgment, memory distillation, and pattern recognition. Use when building self-learning agents, optimizing decision-making, or implementing experience replay systems." +--- + +# ReasoningBank with AgentDB + +## What This Skill Does + +Provides ReasoningBank adaptive learning patterns using AgentDB's high-performance backend (150x-12,500x faster). Enables agents to learn from experiences, judge outcomes, distill memories, and improve decision-making over time with 100% backward compatibility. + +**Performance**: 150x faster pattern retrieval, 500x faster batch operations, <1ms memory access. + +## Prerequisites + +- Node.js 18+ +- AgentDB v1.0.7+ (via agentic-flow) +- Understanding of reinforcement learning concepts (optional) + +--- + +## Quick Start with CLI + +### Initialize ReasoningBank Database + +```bash +# Initialize AgentDB for ReasoningBank +npx agentdb@latest init ./.agentdb/reasoningbank.db --dimension 1536 + +# Start MCP server for Claude Code integration +npx agentdb@latest mcp +claude mcp add agentdb npx agentdb@latest mcp +``` + +### Migrate from Legacy ReasoningBank + +```bash +# Automatic migration with validation +npx agentdb@latest migrate --source .swarm/memory.db + +# Verify migration +npx agentdb@latest stats ./.agentdb/reasoningbank.db +``` + +--- + +## Quick Start with API + +```typescript +import { createAgentDBAdapter, computeEmbedding } from 'agentic-flow/reasoningbank'; + +// Initialize ReasoningBank with AgentDB +const rb = await createAgentDBAdapter({ + dbPath: '.agentdb/reasoningbank.db', + enableLearning: true, // Enable learning plugins + enableReasoning: true, // Enable reasoning agents + cacheSize: 1000, // 1000 pattern cache +}); + +// Store successful experience +const query = "How to optimize database queries?"; +const embedding = await computeEmbedding(query); + +await rb.insertPattern({ + id: '', + type: 'experience', + domain: 'database-optimization', + pattern_data: JSON.stringify({ + embedding, + pattern: { + query, + approach: 'indexing + query optimization', + outcome: 'success', + metrics: { latency_reduction: 0.85 } + } + }), + confidence: 0.95, + usage_count: 1, + success_count: 1, + created_at: Date.now(), + last_used: Date.now(), +}); + +// Retrieve similar experiences with reasoning +const result = await rb.retrieveWithReasoning(embedding, { + domain: 'database-optimization', + k: 5, + useMMR: true, // Diverse results + synthesizeContext: true, // Rich context synthesis +}); + +console.log('Memories:', result.memories); +console.log('Context:', result.context); +console.log('Patterns:', result.patterns); +``` + +--- + +## Core ReasoningBank Concepts + +### 1. Trajectory Tracking + +Track agent execution paths and outcomes: + +```typescript +// Record trajectory (sequence of actions) +const trajectory = { + task: 'optimize-api-endpoint', + steps: [ + { action: 'analyze-bottleneck', result: 'found N+1 query' }, + { action: 'add-eager-loading', result: 'reduced queries' }, + { action: 'add-caching', result: 'improved latency' } + ], + outcome: 'success', + metrics: { latency_before: 2500, latency_after: 150 } +}; + +const embedding = await computeEmbedding(JSON.stringify(trajectory)); + +await rb.insertPattern({ + id: '', + type: 'trajectory', + domain: 'api-optimization', + pattern_data: JSON.stringify({ embedding, pattern: trajectory }), + confidence: 0.9, + usage_count: 1, + success_count: 1, + created_at: Date.now(), + last_used: Date.now(), +}); +``` + +### 2. Verdict Judgment + +Judge whether a trajectory was successful: + +```typescript +// Retrieve similar past trajectories +const similar = await rb.retrieveWithReasoning(queryEmbedding, { + domain: 'api-optimization', + k: 10, +}); + +// Judge based on similarity to successful patterns +const verdict = similar.memories.filter(m => + m.pattern.outcome === 'success' && + m.similarity > 0.8 +).length > 5 ? 'likely_success' : 'needs_review'; + +console.log('Verdict:', verdict); +console.log('Confidence:', similar.memories[0]?.similarity || 0); +``` + +### 3. Memory Distillation + +Consolidate similar experiences into patterns: + +```typescript +// Get all experiences in domain +const experiences = await rb.retrieveWithReasoning(embedding, { + domain: 'api-optimization', + k: 100, + optimizeMemory: true, // Automatic consolidation +}); + +// Distill into high-level pattern +const distilledPattern = { + domain: 'api-optimization', + pattern: 'For N+1 queries: add eager loading, then cache', + success_rate: 0.92, + sample_size: experiences.memories.length, + confidence: 0.95 +}; + +await rb.insertPattern({ + id: '', + type: 'distilled-pattern', + domain: 'api-optimization', + pattern_data: JSON.stringify({ + embedding: await computeEmbedding(JSON.stringify(distilledPattern)), + pattern: distilledPattern + }), + confidence: 0.95, + usage_count: 0, + success_count: 0, + created_at: Date.now(), + last_used: Date.now(), +}); +``` + +--- + +## Integration with Reasoning Agents + +AgentDB provides 4 reasoning modules that enhance ReasoningBank: + +### 1. PatternMatcher + +Find similar successful patterns: + +```typescript +const result = await rb.retrieveWithReasoning(queryEmbedding, { + domain: 'problem-solving', + k: 10, + useMMR: true, // Maximal Marginal Relevance for diversity +}); + +// PatternMatcher returns diverse, relevant memories +result.memories.forEach(mem => { + console.log(`Pattern: ${mem.pattern.approach}`); + console.log(`Similarity: ${mem.similarity}`); + console.log(`Success Rate: ${mem.success_count / mem.usage_count}`); +}); +``` + +### 2. ContextSynthesizer + +Generate rich context from multiple memories: + +```typescript +const result = await rb.retrieveWithReasoning(queryEmbedding, { + domain: 'code-optimization', + synthesizeContext: true, // Enable context synthesis + k: 5, +}); + +// ContextSynthesizer creates coherent narrative +console.log('Synthesized Context:', result.context); +// "Based on 5 similar optimizations, the most effective approach +// involves profiling, identifying bottlenecks, and applying targeted +// improvements. Success rate: 87%" +``` + +### 3. MemoryOptimizer + +Automatically consolidate and prune: + +```typescript +const result = await rb.retrieveWithReasoning(queryEmbedding, { + domain: 'testing', + optimizeMemory: true, // Enable automatic optimization +}); + +// MemoryOptimizer consolidates similar patterns and prunes low-quality +console.log('Optimizations:', result.optimizations); +// { consolidated: 15, pruned: 3, improved_quality: 0.12 } +``` + +### 4. ExperienceCurator + +Filter by quality and relevance: + +```typescript +const result = await rb.retrieveWithReasoning(queryEmbedding, { + domain: 'debugging', + k: 20, + minConfidence: 0.8, // Only high-confidence experiences +}); + +// ExperienceCurator returns only quality experiences +result.memories.forEach(mem => { + console.log(`Confidence: ${mem.confidence}`); + console.log(`Success Rate: ${mem.success_count / mem.usage_count}`); +}); +``` + +--- + +## Legacy API Compatibility + +AgentDB maintains 100% backward compatibility with legacy ReasoningBank: + +```typescript +import { + retrieveMemories, + judgeTrajectory, + distillMemories +} from 'agentic-flow/reasoningbank'; + +// Legacy API works unchanged (uses AgentDB backend automatically) +const memories = await retrieveMemories(query, { + domain: 'code-generation', + agent: 'coder' +}); + +const verdict = await judgeTrajectory(trajectory, query); + +const newMemories = await distillMemories( + trajectory, + verdict, + query, + { domain: 'code-generation' } +); +``` + +--- + +## Performance Characteristics + +- **Pattern Search**: 150x faster (100ยตs vs 15ms) +- **Memory Retrieval**: <1ms (with cache) +- **Batch Insert**: 500x faster (2ms vs 1s for 100 patterns) +- **Trajectory Judgment**: <5ms (including retrieval + analysis) +- **Memory Distillation**: <50ms (consolidate 100 patterns) + +--- + +## Advanced Patterns + +### Hierarchical Memory + +Organize memories by abstraction level: + +```typescript +// Low-level: Specific implementation +await rb.insertPattern({ + type: 'concrete', + domain: 'debugging/null-pointer', + pattern_data: JSON.stringify({ + embedding, + pattern: { bug: 'NPE in UserService.getUser()', fix: 'Add null check' } + }), + confidence: 0.9, + // ... +}); + +// Mid-level: Pattern across similar cases +await rb.insertPattern({ + type: 'pattern', + domain: 'debugging', + pattern_data: JSON.stringify({ + embedding, + pattern: { category: 'null-pointer', approach: 'defensive-checks' } + }), + confidence: 0.85, + // ... +}); + +// High-level: General principle +await rb.insertPattern({ + type: 'principle', + domain: 'software-engineering', + pattern_data: JSON.stringify({ + embedding, + pattern: { principle: 'fail-fast with clear errors' } + }), + confidence: 0.95, + // ... +}); +``` + +### Multi-Domain Learning + +Transfer learning across domains: + +```typescript +// Learn from backend optimization +const backendExperience = await rb.retrieveWithReasoning(embedding, { + domain: 'backend-optimization', + k: 10, +}); + +// Apply to frontend optimization +const transferredKnowledge = backendExperience.memories.map(mem => ({ + ...mem, + domain: 'frontend-optimization', + adapted: true, +})); +``` + +--- + +## CLI Operations + +### Database Management + +```bash +# Export trajectories and patterns +npx agentdb@latest export ./.agentdb/reasoningbank.db ./backup.json + +# Import experiences +npx agentdb@latest import ./experiences.json + +# Get statistics +npx agentdb@latest stats ./.agentdb/reasoningbank.db +# Shows: total patterns, domains, confidence distribution +``` + +### Migration + +```bash +# Migrate from legacy ReasoningBank +npx agentdb@latest migrate --source .swarm/memory.db --target .agentdb/reasoningbank.db + +# Validate migration +npx agentdb@latest stats .agentdb/reasoningbank.db +``` + +--- + +## Troubleshooting + +### Issue: Migration fails +```bash +# Check source database exists +ls -la .swarm/memory.db + +# Run with verbose logging +DEBUG=agentdb:* npx agentdb@latest migrate --source .swarm/memory.db +``` + +### Issue: Low confidence scores +```typescript +// Enable context synthesis for better quality +const result = await rb.retrieveWithReasoning(embedding, { + synthesizeContext: true, + useMMR: true, + k: 10, +}); +``` + +### Issue: Memory growing too large +```typescript +// Enable automatic optimization +const result = await rb.retrieveWithReasoning(embedding, { + optimizeMemory: true, // Consolidates similar patterns +}); + +// Or manually optimize +await rb.optimize(); +``` + +--- + +## Learn More + +- **AgentDB Integration**: node_modules/agentic-flow/docs/AGENTDB_INTEGRATION.md +- **GitHub**: https://github.com/ruvnet/agentic-flow/tree/main/packages/agentdb +- **MCP Integration**: `npx agentdb@latest mcp` +- **Website**: https://agentdb.ruv.io + +--- + +**Category**: Machine Learning / Reinforcement Learning +**Difficulty**: Intermediate +**Estimated Time**: 20-30 minutes diff --git a/.claude/skills/reasoningbank-intelligence/SKILL.md b/.claude/skills/reasoningbank-intelligence/SKILL.md new file mode 100644 index 0000000000..abe6d6aa71 --- /dev/null +++ b/.claude/skills/reasoningbank-intelligence/SKILL.md @@ -0,0 +1,201 @@ +--- +name: "ReasoningBank Intelligence" +description: "Implement adaptive learning with ReasoningBank for pattern recognition, strategy optimization, and continuous improvement. Use when building self-learning agents, optimizing workflows, or implementing meta-cognitive systems." +--- + +# ReasoningBank Intelligence + +## What This Skill Does + +Implements ReasoningBank's adaptive learning system for AI agents to learn from experience, recognize patterns, and optimize strategies over time. Enables meta-cognitive capabilities and continuous improvement. + +## Prerequisites + +- agentic-flow v1.5.11+ +- AgentDB v1.0.4+ (for persistence) +- Node.js 18+ + +## Quick Start + +```typescript +import { ReasoningBank } from 'agentic-flow/reasoningbank'; + +// Initialize ReasoningBank +const rb = new ReasoningBank({ + persist: true, + learningRate: 0.1, + adapter: 'agentdb' // Use AgentDB for storage +}); + +// Record task outcome +await rb.recordExperience({ + task: 'code_review', + approach: 'static_analysis_first', + outcome: { + success: true, + metrics: { + bugs_found: 5, + time_taken: 120, + false_positives: 1 + } + }, + context: { + language: 'typescript', + complexity: 'medium' + } +}); + +// Get optimal strategy +const strategy = await rb.recommendStrategy('code_review', { + language: 'typescript', + complexity: 'high' +}); +``` + +## Core Features + +### 1. Pattern Recognition +```typescript +// Learn patterns from data +await rb.learnPattern({ + pattern: 'api_errors_increase_after_deploy', + triggers: ['deployment', 'traffic_spike'], + actions: ['rollback', 'scale_up'], + confidence: 0.85 +}); + +// Match patterns +const matches = await rb.matchPatterns(currentSituation); +``` + +### 2. Strategy Optimization +```typescript +// Compare strategies +const comparison = await rb.compareStrategies('bug_fixing', [ + 'tdd_approach', + 'debug_first', + 'reproduce_then_fix' +]); + +// Get best strategy +const best = comparison.strategies[0]; +console.log(`Best: ${best.name} (score: ${best.score})`); +``` + +### 3. Continuous Learning +```typescript +// Enable auto-learning from all tasks +await rb.enableAutoLearning({ + threshold: 0.7, // Only learn from high-confidence outcomes + updateFrequency: 100 // Update models every 100 experiences +}); +``` + +## Advanced Usage + +### Meta-Learning +```typescript +// Learn about learning +await rb.metaLearn({ + observation: 'parallel_execution_faster_for_independent_tasks', + confidence: 0.95, + applicability: { + task_types: ['batch_processing', 'data_transformation'], + conditions: ['tasks_independent', 'io_bound'] + } +}); +``` + +### Transfer Learning +```typescript +// Apply knowledge from one domain to another +await rb.transferKnowledge({ + from: 'code_review_javascript', + to: 'code_review_typescript', + similarity: 0.8 +}); +``` + +### Adaptive Agents +```typescript +// Create self-improving agent +class AdaptiveAgent { + async execute(task: Task) { + // Get optimal strategy + const strategy = await rb.recommendStrategy(task.type, task.context); + + // Execute with strategy + const result = await this.executeWithStrategy(task, strategy); + + // Learn from outcome + await rb.recordExperience({ + task: task.type, + approach: strategy.name, + outcome: result, + context: task.context + }); + + return result; + } +} +``` + +## Integration with AgentDB + +```typescript +// Persist ReasoningBank data +await rb.configure({ + storage: { + type: 'agentdb', + options: { + database: './reasoning-bank.db', + enableVectorSearch: true + } + } +}); + +// Query learned patterns +const patterns = await rb.query({ + category: 'optimization', + minConfidence: 0.8, + timeRange: { last: '30d' } +}); +``` + +## Performance Metrics + +```typescript +// Track learning effectiveness +const metrics = await rb.getMetrics(); +console.log(` + Total Experiences: ${metrics.totalExperiences} + Patterns Learned: ${metrics.patternsLearned} + Strategy Success Rate: ${metrics.strategySuccessRate} + Improvement Over Time: ${metrics.improvement} +`); +``` + +## Best Practices + +1. **Record consistently**: Log all task outcomes, not just successes +2. **Provide context**: Rich context improves pattern matching +3. **Set thresholds**: Filter low-confidence learnings +4. **Review periodically**: Audit learned patterns for quality +5. **Use vector search**: Enable semantic pattern matching + +## Troubleshooting + +### Issue: Poor recommendations +**Solution**: Ensure sufficient training data (100+ experiences per task type) + +### Issue: Slow pattern matching +**Solution**: Enable vector indexing in AgentDB + +### Issue: Memory growing large +**Solution**: Set TTL for old experiences or enable pruning + +## Learn More + +- ReasoningBank Guide: agentic-flow/src/reasoningbank/README.md +- AgentDB Integration: packages/agentdb/docs/reasoningbank.md +- Pattern Learning: docs/reasoning/patterns.md diff --git a/.claude/skills/risk-management/SKILL.md b/.claude/skills/risk-management/SKILL.md new file mode 100644 index 0000000000..35dfeabc09 --- /dev/null +++ b/.claude/skills/risk-management/SKILL.md @@ -0,0 +1,173 @@ +--- +name: risk-management +description: Portfolio risk analysis using nautilus_trader and Stanley risk metrics +triggers: + - risk analysis + - VaR + - value at risk + - portfolio risk + - stress test + - drawdown + - beta + - volatility +--- + +# Risk Management + +Comprehensive portfolio risk analysis using Stanley's risk_metrics module and nautilus_trader integration. + +## Risk Metrics Available + +### Value at Risk (VaR) +- **Historical VaR**: Non-parametric, uses actual return distribution +- **Parametric VaR**: Assumes normal distribution +- **95% and 99% confidence levels** + +### Conditional VaR (CVaR / Expected Shortfall) +Expected loss given that loss exceeds VaR - more conservative than VaR alone. + +### Beta & Alpha +- **Beta**: Market sensitivity (vs SPY or custom benchmark) +- **Alpha**: Jensen's alpha - risk-adjusted excess return +- **R-squared**: Benchmark correlation + +### Volatility Metrics +- Daily and annualized volatility +- Downside volatility (for Sortino) +- Maximum drawdown and duration + +### Risk-Adjusted Returns +- **Sharpe Ratio**: Return per unit of total risk +- **Sortino Ratio**: Return per unit of downside risk + +## Usage Examples + +### Basic Risk Assessment +```python +from stanley.portfolio.risk_metrics import ( + calculate_portfolio_var, + calculate_beta, + calculate_sharpe_ratio, + calculate_volatility_metrics +) + +# Calculate VaR +var_result = calculate_portfolio_var( + returns_matrix=returns_df, + weights=np.array([0.4, 0.3, 0.3]), + portfolio_value=100000, + method="historical", + lookback_days=252 +) +# Returns: VaRResult with var_95, var_99, cvar_95, cvar_99 + +# Calculate Beta +beta_result = calculate_beta( + asset_returns=portfolio_returns, + benchmark_returns=spy_returns, + risk_free_rate=0.05 +) +# Returns: BetaResult with beta, alpha, r_squared +``` + +### Stress Testing +```python +# Historical scenario analysis +scenarios = [ + {"name": "2008 Crisis", "factor": -0.38}, + {"name": "COVID Crash", "factor": -0.34}, + {"name": "Tech Correction 2022", "factor": -0.25}, +] + +for scenario in scenarios: + stressed_value = portfolio_value * (1 + scenario["factor"]) + loss = portfolio_value - stressed_value + print(f"{scenario['name']}: -${loss:,.0f}") +``` + +### Nautilus Trader Integration +```python +from stanley.integrations.nautilus import DataClient +from nautilus_trader.risk import RiskEngine + +# Real-time risk monitoring with nautilus +risk_engine = RiskEngine() +risk_engine.set_max_position_size(symbol, max_shares) +risk_engine.set_max_notional(symbol, max_dollars) +risk_engine.set_max_daily_loss(max_loss) +``` + +## Risk Limits (Configurable) + +| Parameter | Default | Description | +|-----------|---------|-------------| +| Max Position Size | 10% | Maximum single position | +| Max Sector Exposure | 30% | Maximum sector weight | +| Max VaR 95 | 5% | Maximum daily VaR | +| Max Drawdown | 15% | Stop-loss trigger | +| Min Diversification | 5 | Minimum holdings | + +## Memory Integration + +Track risk metrics over time: +```typescript +await memory.store({ + namespace: "stanley/risk", + key: `snapshot/${date}`, + value: { + date, + portfolioValue: 125000, + var95: 2500, + var95Pct: 2.0, + cvar95: 3200, + beta: 1.15, + sharpe: 1.45, + maxDrawdown: -0.08, + sectorConcentration: { + Technology: 0.45, + Healthcare: 0.20 + }, + alerts: ["Technology sector over 40% limit"] + } +}); +``` + +## Alerts & Monitoring + +Trigger alerts when: +- VaR exceeds threshold +- Drawdown exceeds limit +- Sector concentration too high +- Correlation spike detected +- Volatility regime change + +## Output Format + +### Risk Dashboard +``` +## Portfolio Risk Summary + +**Value at Risk (1-day)** +- VaR 95%: $2,450 (1.96%) +- VaR 99%: $3,890 (3.11%) +- CVaR 95%: $3,120 (2.50%) + +**Market Sensitivity** +- Beta: 1.15 +- Alpha: 2.3% (annualized) +- Rยฒ: 0.87 + +**Risk-Adjusted Returns** +- Sharpe: 1.45 +- Sortino: 1.92 + +**Stress Scenarios** +- 2008 Crisis: -$47,500 +- COVID Crash: -$42,500 +- 10% Correction: -$12,500 + +**Alerts** +โš ๏ธ Technology exposure at 45% (limit: 40%) +โœ“ VaR within limits +โœ“ Drawdown acceptable +``` diff --git a/.claude/skills/sag/SKILL.md b/.claude/skills/sag/SKILL.md new file mode 100644 index 0000000000..d31e8664cb --- /dev/null +++ b/.claude/skills/sag/SKILL.md @@ -0,0 +1,62 @@ +--- +name: sag +description: ElevenLabs text-to-speech with mac-style say UX. +homepage: https://sag.sh +metadata: {"zee":{"emoji":"๐Ÿ—ฃ๏ธ","requires":{"bins":["sag"],"env":["ELEVENLABS_API_KEY"]},"primaryEnv":"ELEVENLABS_API_KEY","install":[{"id":"brew","kind":"brew","formula":"steipete/tap/sag","bins":["sag"],"label":"Install sag (brew)"}]}} +--- + +# sag + +Use `sag` for ElevenLabs TTS with local playback. + +API key (required) +- `ELEVENLABS_API_KEY` (preferred) +- `SAG_API_KEY` also supported by the CLI + +Quick start +- `sag "Hello there"` +- `sag speak -v "Roger" "Hello"` +- `sag voices` +- `sag prompting` (model-specific tips) + +Model notes +- Default: `eleven_v3` (expressive) +- Stable: `eleven_multilingual_v2` +- Fast: `eleven_flash_v2_5` + +Pronunciation + delivery rules +- First fix: respell (e.g. "key-note"), add hyphens, adjust casing. +- Numbers/units/URLs: `--normalize auto` (or `off` if it harms names). +- Language bias: `--lang en|de|fr|...` to guide normalization. +- v3: SSML `` not supported; use `[pause]`, `[short pause]`, `[long pause]`. +- v2/v2.5: SSML `` supported; `` not exposed in `sag`. + +v3 audio tags (put at the entrance of a line) +- `[whispers]`, `[shouts]`, `[sings]` +- `[laughs]`, `[starts laughing]`, `[sighs]`, `[exhales]` +- `[sarcastic]`, `[curious]`, `[excited]`, `[crying]`, `[mischievously]` +- Example: `sag "[whispers] keep this quiet. [short pause] ok?"` + +Voice defaults +- `ELEVENLABS_VOICE_ID` or `SAG_VOICE_ID` + +Confirm voice + speaker before long output. + +## Chat voice responses + +When Peter asks for a "voice" reply (e.g., "crazy scientist voice", "explain in voice"), generate audio and send it: + +```bash +# Generate audio file +sag -v Clawd -o /tmp/voice-reply.mp3 "Your message here" + +# Then include in reply: +# MEDIA:/tmp/voice-reply.mp3 +``` + +Voice character tips: +- Crazy scientist: Use `[excited]` tags, dramatic pauses `[short pause]`, vary intensity +- Calm: Use `[whispers]` or slower pacing +- Dramatic: Use `[sings]` or `[shouts]` sparingly + +Default voice for Clawd: `lj2rcrvANS3gaWWnczSX` (or just `-v Clawd`) diff --git a/.claude/skills/session-logs/SKILL.md b/.claude/skills/session-logs/SKILL.md new file mode 100644 index 0000000000..989556b3e5 --- /dev/null +++ b/.claude/skills/session-logs/SKILL.md @@ -0,0 +1,95 @@ +--- +name: session-logs +description: Search and analyze your own conversation history from session log files using jq. +metadata: {"zee":{"emoji":"๐Ÿ“œ","requires":{"bins":["jq"]}}} +--- + +# session-logs + +Search your complete conversation history stored in session JSONL files. Use this when you need to recall something not in your memory files. + +## Location + +Session logs live at: `~/.zee/agents/main/sessions/` + +- **`sessions.json`** - Index mapping session keys to session IDs +- **`.jsonl`** - Full conversation transcript per session + +## Structure + +Each `.jsonl` file contains messages with: +- `type`: "session" (metadata) or "message" +- `timestamp`: ISO timestamp +- `message.role`: "user", "assistant", or "toolResult" +- `message.content[]`: Text, thinking, or tool calls +- `message.usage.cost.total`: Cost per response + +## Common Queries + +### List all sessions by date and size +```bash +for f in ~/.zee/agents/main/sessions/*.jsonl; do + date=$(head -1 "$f" | jq -r '.timestamp' | cut -dT -f1) + size=$(ls -lh "$f" | awk '{print $5}') + echo "$date $size $(basename $f)" +done | sort -r +``` + +### Find sessions from a specific day +```bash +for f in ~/.zee/agents/main/sessions/*.jsonl; do + head -1 "$f" | jq -r '.timestamp' | grep -q "2026-01-06" && echo "$f" +done +``` + +### Extract user messages from a session +```bash +jq -r 'select(.message.role == "user") | .message.content[0].text' .jsonl +``` + +### Search for keyword in assistant responses +```bash +jq -r 'select(.message.role == "assistant") | .message.content[]? | select(.type == "text") | .text' .jsonl | grep -i "keyword" +``` + +### Get total cost for a session +```bash +jq -s '[.[] | .message.usage.cost.total // 0] | add' .jsonl +``` + +### Daily cost summary +```bash +for f in ~/.zee/agents/main/sessions/*.jsonl; do + date=$(head -1 "$f" | jq -r '.timestamp' | cut -dT -f1) + cost=$(jq -s '[.[] | .message.usage.cost.total // 0] | add' "$f") + echo "$date $cost" +done | awk '{a[$1]+=$2} END {for(d in a) print d, "$"a[d]}' | sort -r +``` + +### Count messages and tokens in a session +```bash +jq -s '{ + messages: length, + user: [.[] | select(.message.role == "user")] | length, + assistant: [.[] | select(.message.role == "assistant")] | length, + first: .[0].timestamp, + last: .[-1].timestamp +}' .jsonl +``` + +### Tool usage breakdown +```bash +jq -r '.message.content[]? | select(.type == "toolCall") | .name' .jsonl | sort | uniq -c | sort -rn +``` + +### Search across ALL sessions for a phrase +```bash +grep -l "phrase" ~/.zee/agents/main/sessions/*.jsonl +``` + +## Tips + +- Sessions are append-only JSONL (one JSON object per line) +- Large sessions can be several MB - use `head`/`tail` for sampling +- The `sessions.json` index maps chat providers (discord, whatsapp, etc.) to session IDs +- Deleted sessions have `.deleted.` suffix diff --git a/.claude/skills/shared/SKILL.md b/.claude/skills/shared/SKILL.md index 72f2e2307b..735476694d 100644 --- a/.claude/skills/shared/SKILL.md +++ b/.claude/skills/shared/SKILL.md @@ -57,7 +57,7 @@ npx tsx scripts/shared-plan.ts read 2026-01-07-10-00-00-project_alpha.md ## Environment -- `ZEE_REPO` (default: `~/Repositories/personas/zee`) +- `ZEE_REPO` (default: `~/.local/src/agent-core/vendor/personas/zee`) - `ZEE_RUNTIME` (default: `bun`) Telegram (user mode): diff --git a/.claude/skills/shared/scripts/zee-runner.ts b/.claude/skills/shared/scripts/zee-runner.ts index 3c46c8b794..dacf1e760f 100644 --- a/.claude/skills/shared/scripts/zee-runner.ts +++ b/.claude/skills/shared/scripts/zee-runner.ts @@ -10,7 +10,7 @@ export type ZeeCliResult = { }; export function runZeeCli(args: string[]): ZeeCliResult { - const repo = process.env.ZEE_REPO || join(homedir(), "Repositories", "personas", "zee"); + const repo = process.env.ZEE_REPO || join(homedir(), ".local", "src", "agent-core", "vendor", "personas", "zee"); const runtime = process.env.ZEE_RUNTIME || "bun"; const entry = join(repo, "src", "entry.ts"); diff --git a/.claude/skills/skill-builder/SKILL.md b/.claude/skills/skill-builder/SKILL.md new file mode 100644 index 0000000000..589e19e4ad --- /dev/null +++ b/.claude/skills/skill-builder/SKILL.md @@ -0,0 +1,910 @@ +--- +name: "Skill Builder" +description: "Create new Claude Code Skills with proper YAML frontmatter, progressive disclosure structure, and complete directory organization. Use when you need to build custom skills for specific workflows, generate skill templates, or understand the Claude Skills specification." +--- + +# Skill Builder + +## What This Skill Does + +Creates production-ready Claude Code Skills with proper YAML frontmatter, progressive disclosure architecture, and complete file/folder structure. This skill guides you through building skills that Claude can autonomously discover and use across all surfaces (Claude.ai, Claude Code, SDK, API). + +## Prerequisites + +- Claude Code 2.0+ or Claude.ai with Skills support +- Basic understanding of Markdown and YAML +- Text editor or IDE + +## Quick Start + +### Creating Your First Skill + +```bash +# 1. Create skill directory (MUST be at top level, NOT in subdirectories!) +mkdir -p ~/.claude/skills/my-first-skill + +# 2. Create SKILL.md with proper format +cat > ~/.claude/skills/my-first-skill/SKILL.md << 'EOF' +--- +name: "My First Skill" +description: "Brief description of what this skill does and when Claude should use it. Maximum 1024 characters." +--- + +# My First Skill + +## What This Skill Does +[Your instructions here] + +## Quick Start +[Basic usage] +EOF + +# 3. Verify skill is detected +# Restart Claude Code or refresh Claude.ai +``` + +--- + +## Complete Specification + +### ๐Ÿ“‹ YAML Frontmatter (REQUIRED) + +Every SKILL.md **must** start with YAML frontmatter containing exactly two required fields: + +```yaml +--- +name: "Skill Name" # REQUIRED: Max 64 chars +description: "What this skill does # REQUIRED: Max 1024 chars +and when Claude should use it." # Include BOTH what & when +--- +``` + +#### Field Requirements + +**`name`** (REQUIRED): +- **Type**: String +- **Max Length**: 64 characters +- **Format**: Human-friendly display name +- **Usage**: Shown in skill lists, UI, and loaded into Claude's system prompt +- **Best Practice**: Use Title Case, be concise and descriptive +- **Examples**: + - โœ… "API Documentation Generator" + - โœ… "React Component Builder" + - โœ… "Database Schema Designer" + - โŒ "skill-1" (not descriptive) + - โŒ "This is a very long skill name that exceeds sixty-four characters" (too long) + +**`description`** (REQUIRED): +- **Type**: String +- **Max Length**: 1024 characters +- **Format**: Plain text or minimal markdown +- **Content**: MUST include: + 1. **What** the skill does (functionality) + 2. **When** Claude should invoke it (trigger conditions) +- **Usage**: Loaded into Claude's system prompt for autonomous matching +- **Best Practice**: Front-load key trigger words, be specific about use cases +- **Examples**: + - โœ… "Generate OpenAPI 3.0 documentation from Express.js routes. Use when creating API docs, documenting endpoints, or building API specifications." + - โœ… "Create React functional components with TypeScript, hooks, and tests. Use when scaffolding new components or converting class components." + - โŒ "A comprehensive guide to API documentation" (no "when" clause) + - โŒ "Documentation tool" (too vague) + +#### YAML Formatting Rules + +```yaml +--- +# โœ… CORRECT: Simple string +name: "API Builder" +description: "Creates REST APIs with Express and TypeScript." + +# โœ… CORRECT: Multi-line description +name: "Full-Stack Generator" +description: "Generates full-stack applications with React frontend and Node.js backend. Use when starting new projects or scaffolding applications." + +# โœ… CORRECT: Special characters quoted +name: "JSON:API Builder" +description: "Creates JSON:API compliant endpoints: pagination, filtering, relationships." + +# โŒ WRONG: Missing quotes with special chars +name: API:Builder # YAML parse error! + +# โŒ WRONG: Extra fields (ignored but discouraged) +name: "My Skill" +description: "My description" +version: "1.0.0" # NOT part of spec +author: "Me" # NOT part of spec +tags: ["dev", "api"] # NOT part of spec +--- +``` + +**Critical**: Only `name` and `description` are used by Claude. Additional fields are ignored. + +--- + +### ๐Ÿ“‚ Directory Structure + +#### Minimal Skill (Required) +``` +~/.claude/skills/ # Personal skills location +โ””โ”€โ”€ my-skill/ # Skill directory (MUST be at top level!) + โ””โ”€โ”€ SKILL.md # REQUIRED: Main skill file +``` + +**IMPORTANT**: Skills MUST be directly under `~/.claude/skills/[skill-name]/`. +Claude Code does NOT support nested subdirectories or namespaces! + +#### Full-Featured Skill (Recommended) +``` +~/.claude/skills/ +โ””โ”€โ”€ my-skill/ # Top-level skill directory + โ”œโ”€โ”€ SKILL.md # REQUIRED: Main skill file + โ”œโ”€โ”€ README.md # Optional: Human-readable docs + โ”œโ”€โ”€ scripts/ # Optional: Executable scripts + โ”‚ โ”œโ”€โ”€ setup.sh + โ”‚ โ”œโ”€โ”€ validate.js + โ”‚ โ””โ”€โ”€ deploy.py + โ”œโ”€โ”€ resources/ # Optional: Supporting files + โ”‚ โ”œโ”€โ”€ templates/ + โ”‚ โ”‚ โ”œโ”€โ”€ api-template.js + โ”‚ โ”‚ โ””โ”€โ”€ component.tsx + โ”‚ โ”œโ”€โ”€ examples/ + โ”‚ โ”‚ โ””โ”€โ”€ sample-output.json + โ”‚ โ””โ”€โ”€ schemas/ + โ”‚ โ””โ”€โ”€ config-schema.json + โ””โ”€โ”€ docs/ # Optional: Additional documentation + โ”œโ”€โ”€ ADVANCED.md + โ”œโ”€โ”€ TROUBLESHOOTING.md + โ””โ”€โ”€ API_REFERENCE.md +``` + +#### Skills Locations + +**Personal Skills** (available across all projects): +``` +~/.claude/skills/ +โ””โ”€โ”€ [your-skills]/ +``` +- **Path**: `~/.claude/skills/` or `$HOME/.claude/skills/` +- **Scope**: Available in all projects for this user +- **Version Control**: NOT committed to git (outside repo) +- **Use Case**: Personal productivity tools, custom workflows + +**Project Skills** (team-shared, version controlled): +``` +/.claude/skills/ +โ””โ”€โ”€ [team-skills]/ +``` +- **Path**: `.claude/skills/` in project root +- **Scope**: Available only in this project +- **Version Control**: SHOULD be committed to git +- **Use Case**: Team workflows, project-specific tools, shared knowledge + +--- + +### ๐ŸŽฏ Progressive Disclosure Architecture + +Claude Code uses a **3-level progressive disclosure system** to scale to 100+ skills without context penalty: + +#### Level 1: Metadata (Name + Description) +**Loaded**: At Claude Code startup, always +**Size**: ~200 chars per skill +**Purpose**: Enable autonomous skill matching +**Context**: Loaded into system prompt for ALL skills + +```yaml +--- +name: "API Builder" # 11 chars +description: "Creates REST APIs..." # ~50 chars +--- +# Total: ~61 chars per skill +# 100 skills = ~6KB context (minimal!) +``` + +#### Level 2: SKILL.md Body +**Loaded**: When skill is triggered/matched +**Size**: ~1-10KB typically +**Purpose**: Main instructions and procedures +**Context**: Only loaded for ACTIVE skills + +```markdown +# API Builder + +## What This Skill Does +[Main instructions - loaded only when skill is active] + +## Quick Start +[Basic procedures] + +## Step-by-Step Guide +[Detailed instructions] +``` + +#### Level 3+: Referenced Files +**Loaded**: On-demand as Claude navigates +**Size**: Variable (KB to MB) +**Purpose**: Deep reference, examples, schemas +**Context**: Loaded only when Claude accesses specific files + +```markdown +# In SKILL.md +See [Advanced Configuration](docs/ADVANCED.md) for complex scenarios. +See [API Reference](docs/API_REFERENCE.md) for complete documentation. +Use template: `resources/templates/api-template.js` + +# Claude will load these files ONLY if needed +``` + +**Benefit**: Install 100+ skills with ~6KB context. Only active skill content (1-10KB) enters context. + +--- + +### ๐Ÿ“ SKILL.md Content Structure + +#### Recommended 4-Level Structure + +```markdown +--- +name: "Your Skill Name" +description: "What it does and when to use it" +--- + +# Your Skill Name + +## Level 1: Overview (Always Read First) +Brief 2-3 sentence description of the skill. + +## Prerequisites +- Requirement 1 +- Requirement 2 + +## What This Skill Does +1. Primary function +2. Secondary function +3. Key benefit + +--- + +## Level 2: Quick Start (For Fast Onboarding) + +### Basic Usage +```bash +# Simplest use case +command --option value +``` + +### Common Scenarios +1. **Scenario 1**: How to... +2. **Scenario 2**: How to... + +--- + +## Level 3: Detailed Instructions (For Deep Work) + +### Step-by-Step Guide + +#### Step 1: Initial Setup +```bash +# Commands +``` +Expected output: +``` +Success message +``` + +#### Step 2: Configuration +- Configuration option 1 +- Configuration option 2 + +#### Step 3: Execution +- Run the main command +- Verify results + +### Advanced Options + +#### Option 1: Custom Configuration +```bash +# Advanced usage +``` + +#### Option 2: Integration +```bash +# Integration steps +``` + +--- + +## Level 4: Reference (Rarely Needed) + +### Troubleshooting + +#### Issue: Common Problem +**Symptoms**: What you see +**Cause**: Why it happens +**Solution**: How to fix +```bash +# Fix command +``` + +#### Issue: Another Problem +**Solution**: Steps to resolve + +### Complete API Reference +See [API_REFERENCE.md](docs/API_REFERENCE.md) + +### Examples +See [examples/](resources/examples/) + +### Related Skills +- [Related Skill 1](#) +- [Related Skill 2](#) + +### Resources +- [External Link 1](https://example.com) +- [Documentation](https://docs.example.com) +``` + +--- + +### ๐ŸŽจ Content Best Practices + +#### Writing Effective Descriptions + +**Front-Load Keywords**: +```yaml +# โœ… GOOD: Keywords first +description: "Generate TypeScript interfaces from JSON schema. Use when converting schemas, creating types, or building API clients." + +# โŒ BAD: Keywords buried +description: "This skill helps developers who need to work with JSON schemas by providing a way to generate TypeScript interfaces." +``` + +**Include Trigger Conditions**: +```yaml +# โœ… GOOD: Clear "when" clause +description: "Debug React performance issues using Chrome DevTools. Use when components re-render unnecessarily, investigating slow updates, or optimizing bundle size." + +# โŒ BAD: No trigger conditions +description: "Helps with React performance debugging." +``` + +**Be Specific**: +```yaml +# โœ… GOOD: Specific technologies +description: "Create Express.js REST endpoints with Joi validation, Swagger docs, and Jest tests. Use when building new APIs or adding endpoints." + +# โŒ BAD: Too generic +description: "Build API endpoints with proper validation and testing." +``` + +#### Progressive Disclosure Writing + +**Keep Level 1 Brief** (Overview): +```markdown +## What This Skill Does +Creates production-ready React components with TypeScript, hooks, and tests in 3 steps. +``` + +**Level 2 for Common Paths** (Quick Start): +```markdown +## Quick Start +```bash +# Most common use case (80% of users) +generate-component MyComponent +``` +``` + +**Level 3 for Details** (Step-by-Step): +```markdown +## Step-by-Step Guide + +### Creating a Basic Component +1. Run generator +2. Choose template +3. Customize options +[Detailed explanations] +``` + +**Level 4 for Edge Cases** (Reference): +```markdown +## Advanced Configuration +For complex scenarios like HOCs, render props, or custom hooks, see [ADVANCED.md](docs/ADVANCED.md). +``` + +--- + +### ๐Ÿ› ๏ธ Adding Scripts and Resources + +#### Scripts Directory + +**Purpose**: Executable scripts that Claude can run +**Location**: `scripts/` in skill directory +**Usage**: Referenced from SKILL.md + +Example: +```bash +# In skill directory +scripts/ +โ”œโ”€โ”€ setup.sh # Initialization script +โ”œโ”€โ”€ validate.js # Validation logic +โ”œโ”€โ”€ generate.py # Code generation +โ””โ”€โ”€ deploy.sh # Deployment script +``` + +Reference from SKILL.md: +```markdown +## Setup +Run the setup script: +```bash +./scripts/setup.sh +``` + +## Validation +Validate your configuration: +```bash +node scripts/validate.js config.json +``` +``` + +#### Resources Directory + +**Purpose**: Templates, examples, schemas, static files +**Location**: `resources/` in skill directory +**Usage**: Referenced or copied by scripts + +Example: +```bash +resources/ +โ”œโ”€โ”€ templates/ +โ”‚ โ”œโ”€โ”€ component.tsx.template +โ”‚ โ”œโ”€โ”€ test.spec.ts.template +โ”‚ โ””โ”€โ”€ story.stories.tsx.template +โ”œโ”€โ”€ examples/ +โ”‚ โ”œโ”€โ”€ basic-example/ +โ”‚ โ”œโ”€โ”€ advanced-example/ +โ”‚ โ””โ”€โ”€ integration-example/ +โ””โ”€โ”€ schemas/ + โ”œโ”€โ”€ config.schema.json + โ””โ”€โ”€ output.schema.json +``` + +Reference from SKILL.md: +```markdown +## Templates +Use the component template: +```bash +cp resources/templates/component.tsx.template src/components/MyComponent.tsx +``` + +## Examples +See working examples in `resources/examples/`: +- `basic-example/` - Simple component +- `advanced-example/` - With hooks and context +``` + +--- + +### ๐Ÿ”— File References and Navigation + +Claude can navigate to referenced files automatically. Use these patterns: + +#### Markdown Links +```markdown +See [Advanced Configuration](docs/ADVANCED.md) for complex scenarios. +See [Troubleshooting Guide](docs/TROUBLESHOOTING.md) if you encounter errors. +``` + +#### Relative File Paths +```markdown +Use the template located at `resources/templates/api-template.js` +See examples in `resources/examples/basic-usage/` +``` + +#### Inline File Content +```markdown +## Example Configuration +See `resources/examples/config.json`: +```json +{ + "option": "value" +} +``` +``` + +**Best Practice**: Keep SKILL.md lean (~2-5KB). Move lengthy content to separate files and reference them. Claude will load only what's needed. + +--- + +### โœ… Validation Checklist + +Before publishing a skill, verify: + +**YAML Frontmatter**: +- [ ] Starts with `---` +- [ ] Contains `name` field (max 64 chars) +- [ ] Contains `description` field (max 1024 chars) +- [ ] Description includes "what" and "when" +- [ ] Ends with `---` +- [ ] No YAML syntax errors + +**File Structure**: +- [ ] SKILL.md exists in skill directory +- [ ] Directory is DIRECTLY in `~/.claude/skills/[skill-name]/` or `.claude/skills/[skill-name]/` +- [ ] Uses clear, descriptive directory name +- [ ] **NO nested subdirectories** (Claude Code requires top-level structure) + +**Content Quality**: +- [ ] Level 1 (Overview) is brief and clear +- [ ] Level 2 (Quick Start) shows common use case +- [ ] Level 3 (Details) provides step-by-step guide +- [ ] Level 4 (Reference) links to advanced content +- [ ] Examples are concrete and runnable +- [ ] Troubleshooting section addresses common issues + +**Progressive Disclosure**: +- [ ] Core instructions in SKILL.md (~2-5KB) +- [ ] Advanced content in separate docs/ +- [ ] Large resources in resources/ directory +- [ ] Clear navigation between levels + +**Testing**: +- [ ] Skill appears in Claude's skill list +- [ ] Description triggers on relevant queries +- [ ] Instructions are clear and actionable +- [ ] Scripts execute successfully (if included) +- [ ] Examples work as documented + +--- + +## Skill Builder Templates + +### Template 1: Basic Skill (Minimal) + +```markdown +--- +name: "My Basic Skill" +description: "One sentence what. One sentence when to use." +--- + +# My Basic Skill + +## What This Skill Does +[2-3 sentences describing functionality] + +## Quick Start +```bash +# Single command to get started +``` + +## Step-by-Step Guide + +### Step 1: Setup +[Instructions] + +### Step 2: Usage +[Instructions] + +### Step 3: Verify +[Instructions] + +## Troubleshooting +- **Issue**: Problem description + - **Solution**: Fix description +``` + +### Template 2: Intermediate Skill (With Scripts) + +```markdown +--- +name: "My Intermediate Skill" +description: "Detailed what with key features. When to use with specific triggers: scaffolding, generating, building." +--- + +# My Intermediate Skill + +## Prerequisites +- Requirement 1 +- Requirement 2 + +## What This Skill Does +1. Primary function +2. Secondary function +3. Integration capability + +## Quick Start +```bash +./scripts/setup.sh +./scripts/generate.sh my-project +``` + +## Configuration +Edit `config.json`: +```json +{ + "option1": "value1", + "option2": "value2" +} +``` + +## Step-by-Step Guide + +### Basic Usage +[Steps for 80% use case] + +### Advanced Usage +[Steps for complex scenarios] + +## Available Scripts +- `scripts/setup.sh` - Initial setup +- `scripts/generate.sh` - Code generation +- `scripts/validate.sh` - Validation + +## Resources +- Templates: `resources/templates/` +- Examples: `resources/examples/` + +## Troubleshooting +[Common issues and solutions] +``` + +### Template 3: Advanced Skill (Full-Featured) + +```markdown +--- +name: "My Advanced Skill" +description: "Comprehensive what with all features and integrations. Use when [trigger 1], [trigger 2], or [trigger 3]. Supports [technology stack]." +--- + +# My Advanced Skill + +## Overview +[Brief 2-3 sentence description] + +## Prerequisites +- Technology 1 (version X+) +- Technology 2 (version Y+) +- API keys or credentials + +## What This Skill Does +1. **Core Feature**: Description +2. **Integration**: Description +3. **Automation**: Description + +--- + +## Quick Start (60 seconds) + +### Installation +```bash +./scripts/install.sh +``` + +### First Use +```bash +./scripts/quickstart.sh +``` + +Expected output: +``` +โœ“ Setup complete +โœ“ Configuration validated +โ†’ Ready to use +``` + +--- + +## Configuration + +### Basic Configuration +Edit `config.json`: +```json +{ + "mode": "production", + "features": ["feature1", "feature2"] +} +``` + +### Advanced Configuration +See [Configuration Guide](docs/CONFIGURATION.md) + +--- + +## Step-by-Step Guide + +### 1. Initial Setup +[Detailed steps] + +### 2. Core Workflow +[Main procedures] + +### 3. Integration +[Integration steps] + +--- + +## Advanced Features + +### Feature 1: Custom Templates +```bash +./scripts/generate.sh --template custom +``` + +### Feature 2: Batch Processing +```bash +./scripts/batch.sh --input data.json +``` + +### Feature 3: CI/CD Integration +See [CI/CD Guide](docs/CICD.md) + +--- + +## Scripts Reference + +| Script | Purpose | Usage | +|--------|---------|-------| +| `install.sh` | Install dependencies | `./scripts/install.sh` | +| `generate.sh` | Generate code | `./scripts/generate.sh [name]` | +| `validate.sh` | Validate output | `./scripts/validate.sh` | +| `deploy.sh` | Deploy to environment | `./scripts/deploy.sh [env]` | + +--- + +## Resources + +### Templates +- `resources/templates/basic.template` - Basic template +- `resources/templates/advanced.template` - Advanced template + +### Examples +- `resources/examples/basic/` - Simple example +- `resources/examples/advanced/` - Complex example +- `resources/examples/integration/` - Integration example + +### Schemas +- `resources/schemas/config.schema.json` - Configuration schema +- `resources/schemas/output.schema.json` - Output validation + +--- + +## Troubleshooting + +### Issue: Installation Failed +**Symptoms**: Error during `install.sh` +**Cause**: Missing dependencies +**Solution**: +```bash +# Install prerequisites +npm install -g required-package +./scripts/install.sh --force +``` + +### Issue: Validation Errors +**Symptoms**: Validation script fails +**Solution**: See [Troubleshooting Guide](docs/TROUBLESHOOTING.md) + +--- + +## API Reference +Complete API documentation: [API_REFERENCE.md](docs/API_REFERENCE.md) + +## Related Skills +- [Related Skill 1](../related-skill-1/) +- [Related Skill 2](../related-skill-2/) + +## Resources +- [Official Documentation](https://example.com/docs) +- [GitHub Repository](https://github.com/example/repo) +- [Community Forum](https://forum.example.com) + +--- + +**Created**: 2025-10-19 +**Category**: Advanced +**Difficulty**: Intermediate +**Estimated Time**: 15-30 minutes +``` + +--- + +## Examples from the Wild + +### Example 1: Simple Documentation Skill + +```markdown +--- +name: "README Generator" +description: "Generate comprehensive README.md files for GitHub repositories. Use when starting new projects, documenting code, or improving existing READMEs." +--- + +# README Generator + +## What This Skill Does +Creates well-structured README.md files with badges, installation, usage, and contribution sections. + +## Quick Start +```bash +# Answer a few questions +./scripts/generate-readme.sh + +# README.md created with: +# - Project title and description +# - Installation instructions +# - Usage examples +# - Contribution guidelines +``` + +## Customization +Edit sections in `resources/templates/sections/` before generating. +``` + +### Example 2: Code Generation Skill + +```markdown +--- +name: "React Component Generator" +description: "Generate React functional components with TypeScript, hooks, tests, and Storybook stories. Use when creating new components, scaffolding UI, or following component architecture patterns." +--- + +# React Component Generator + +## Prerequisites +- Node.js 18+ +- React 18+ +- TypeScript 5+ + +## Quick Start +```bash +./scripts/generate-component.sh MyComponent + +# Creates: +# - src/components/MyComponent/MyComponent.tsx +# - src/components/MyComponent/MyComponent.test.tsx +# - src/components/MyComponent/MyComponent.stories.tsx +# - src/components/MyComponent/index.ts +``` + +## Step-by-Step Guide + +### 1. Run Generator +```bash +./scripts/generate-component.sh ComponentName +``` + +### 2. Choose Template +- Basic: Simple functional component +- With State: useState hooks +- With Context: useContext integration +- With API: Data fetching component + +### 3. Customize +Edit generated files in `src/components/ComponentName/` + +## Templates +See `resources/templates/` for available component templates. +``` + +--- + +## Learn More + +### Official Resources +- [Anthropic Agent Skills Documentation](https://docs.claude.com/en/docs/agents-and-tools/agent-skills) +- [GitHub Skills Repository](https://github.com/anthropics/skills) +- [Claude Code Documentation](https://docs.claude.com/en/docs/claude-code) + +### Community +- [Skills Marketplace](https://github.com/anthropics/skills) - Browse community skills +- [Anthropic Discord](https://discord.gg/anthropic) - Get help from community + +### Advanced Topics +- Multi-file skills with complex navigation +- Skills that spawn other skills +- Integration with MCP tools +- Dynamic skill generation + +--- + +**Created**: 2025-10-19 +**Version**: 1.0.0 +**Maintained By**: agentic-flow team +**License**: MIT diff --git a/.claude/skills/slack/SKILL.md b/.claude/skills/slack/SKILL.md new file mode 100644 index 0000000000..a523367be5 --- /dev/null +++ b/.claude/skills/slack/SKILL.md @@ -0,0 +1,143 @@ +--- +name: slack +description: Use when you need to control Slack from Zee via the slack tool, including reacting to messages or pinning/unpinning items in Slack channels or DMs. +--- + +# Slack Actions + +## Overview + +Use `slack` to react, manage pins, send/edit/delete messages, and fetch member info. The tool uses the bot token configured for Zee. + +## Inputs to collect + +- `channelId` and `messageId` (Slack message timestamp, e.g. `1712023032.1234`). +- For reactions, an `emoji` (Unicode or `:name:`). +- For message sends, a `to` target (`channel:` or `user:`) and `content`. + +Message context lines include `slack message id` and `channel` fields you can reuse directly. + +## Actions + +### Action groups + +| Action group | Default | Notes | +| --- | --- | --- | +| reactions | enabled | React + list reactions | +| messages | enabled | Read/send/edit/delete | +| pins | enabled | Pin/unpin/list | +| memberInfo | enabled | Member info | +| emojiList | enabled | Custom emoji list | + +### React to a message + +```json +{ + "action": "react", + "channelId": "C123", + "messageId": "1712023032.1234", + "emoji": "โœ…" +} +``` + +### List reactions + +```json +{ + "action": "reactions", + "channelId": "C123", + "messageId": "1712023032.1234" +} +``` + +### Send a message + +```json +{ + "action": "sendMessage", + "to": "channel:C123", + "content": "Hello from Zee" +} +``` + +### Edit a message + +```json +{ + "action": "editMessage", + "channelId": "C123", + "messageId": "1712023032.1234", + "content": "Updated text" +} +``` + +### Delete a message + +```json +{ + "action": "deleteMessage", + "channelId": "C123", + "messageId": "1712023032.1234" +} +``` + +### Read recent messages + +```json +{ + "action": "readMessages", + "channelId": "C123", + "limit": 20 +} +``` + +### Pin a message + +```json +{ + "action": "pinMessage", + "channelId": "C123", + "messageId": "1712023032.1234" +} +``` + +### Unpin a message + +```json +{ + "action": "unpinMessage", + "channelId": "C123", + "messageId": "1712023032.1234" +} +``` + +### List pinned items + +```json +{ + "action": "listPins", + "channelId": "C123" +} +``` + +### Member info + +```json +{ + "action": "memberInfo", + "userId": "U123" +} +``` + +### Emoji list + +```json +{ + "action": "emojiList" +} +``` + +## Ideas to try + +- React with โœ… to mark completed tasks. +- Pin key decisions or weekly status updates. diff --git a/.claude/skills/songsee/SKILL.md b/.claude/skills/songsee/SKILL.md new file mode 100644 index 0000000000..2b91e00e17 --- /dev/null +++ b/.claude/skills/songsee/SKILL.md @@ -0,0 +1,29 @@ +--- +name: songsee +description: Generate spectrograms and feature-panel visualizations from audio with the songsee CLI. +homepage: https://github.com/steipete/songsee +metadata: {"zee":{"emoji":"๐ŸŒŠ","requires":{"bins":["songsee"]},"install":[{"id":"brew","kind":"brew","formula":"steipete/tap/songsee","bins":["songsee"],"label":"Install songsee (brew)"}]}} +--- + +# songsee + +Generate spectrograms + feature panels from audio. + +Quick start +- Spectrogram: `songsee track.mp3` +- Multi-panel: `songsee track.mp3 --viz spectrogram,mel,chroma,hpss,selfsim,loudness,tempogram,mfcc,flux` +- Time slice: `songsee track.mp3 --start 12.5 --duration 8 -o slice.jpg` +- Stdin: `cat track.mp3 | songsee - --format png -o out.png` + +Common flags +- `--viz` list (repeatable or comma-separated) +- `--style` palette (classic, magma, inferno, viridis, gray) +- `--width` / `--height` output size +- `--window` / `--hop` FFT settings +- `--min-freq` / `--max-freq` frequency range +- `--start` / `--duration` time slice +- `--format` jpg|png + +Notes +- WAV/MP3 decode native; other formats use ffmpeg if available. +- Multiple `--viz` renders a grid. diff --git a/.claude/skills/sonoscli/SKILL.md b/.claude/skills/sonoscli/SKILL.md new file mode 100644 index 0000000000..a7d423e3da --- /dev/null +++ b/.claude/skills/sonoscli/SKILL.md @@ -0,0 +1,26 @@ +--- +name: sonoscli +description: Control Sonos speakers (discover/status/play/volume/group). +homepage: https://sonoscli.sh +metadata: {"zee":{"emoji":"๐Ÿ”Š","requires":{"bins":["sonos"]},"install":[{"id":"go","kind":"go","module":"github.com/steipete/sonoscli/cmd/sonos@latest","bins":["sonos"],"label":"Install sonoscli (go)"}]}} +--- + +# Sonos CLI + +Use `sonos` to control Sonos speakers on the local network. + +Quick start +- `sonos discover` +- `sonos status --name "Kitchen"` +- `sonos play|pause|stop --name "Kitchen"` +- `sonos volume set 15 --name "Kitchen"` + +Common tasks +- Grouping: `sonos group status|join|unjoin|party|solo` +- Favorites: `sonos favorites list|open` +- Queue: `sonos queue list|play|clear` +- Spotify search (via SMAPI): `sonos smapi search --service "Spotify" --category tracks "query"` + +Notes +- If SSDP fails, specify `--ip `. +- Spotify Web API search is optional and requires `SPOTIFY_CLIENT_ID/SECRET`. diff --git a/.claude/skills/sparc-methodology/SKILL.md b/.claude/skills/sparc-methodology/SKILL.md new file mode 100644 index 0000000000..a506b72ca5 --- /dev/null +++ b/.claude/skills/sparc-methodology/SKILL.md @@ -0,0 +1,1115 @@ +--- +name: sparc-methodology +description: SPARC (Specification, Pseudocode, Architecture, Refinement, Completion) comprehensive development methodology with multi-agent orchestration +version: 2.7.0 +category: development +tags: + - sparc + - tdd + - architecture + - orchestration + - methodology + - multi-agent +author: Claude Flow +--- + +# SPARC Methodology - Comprehensive Development Framework + +## Overview + +SPARC (Specification, Pseudocode, Architecture, Refinement, Completion) is a systematic development methodology integrated with Claude Flow's multi-agent orchestration capabilities. It provides 17 specialized modes for comprehensive software development, from initial research through deployment and monitoring. + +## Table of Contents + +1. [Core Philosophy](#core-philosophy) +2. [Development Phases](#development-phases) +3. [Available Modes](#available-modes) +4. [Activation Methods](#activation-methods) +5. [Orchestration Patterns](#orchestration-patterns) +6. [TDD Workflows](#tdd-workflows) +7. [Best Practices](#best-practices) +8. [Integration Examples](#integration-examples) +9. [Common Workflows](#common-workflows) + +--- + +## Core Philosophy + +SPARC methodology emphasizes: + +- **Systematic Approach**: Structured phases from specification to completion +- **Test-Driven Development**: Tests written before implementation +- **Parallel Execution**: Concurrent agent coordination for 2.8-4.4x speed improvements +- **Memory Integration**: Persistent knowledge sharing across agents and sessions +- **Quality First**: Comprehensive reviews, testing, and validation +- **Modular Design**: Clean separation of concerns with clear interfaces + +### Key Principles + +1. **Specification Before Code**: Define requirements and constraints clearly +2. **Design Before Implementation**: Plan architecture and components +3. **Tests Before Features**: Write failing tests, then make them pass +4. **Review Everything**: Code quality, security, and performance checks +5. **Document Continuously**: Maintain current documentation throughout + +--- + +## Development Phases + +### Phase 1: Specification +**Goal**: Define requirements, constraints, and success criteria + +- Requirements analysis +- User story mapping +- Constraint identification +- Success metrics definition +- Pseudocode planning + +**Key Modes**: `researcher`, `analyzer`, `memory-manager` + +### Phase 2: Architecture +**Goal**: Design system structure and component interfaces + +- System architecture design +- Component interface definition +- Database schema planning +- API contract specification +- Infrastructure planning + +**Key Modes**: `architect`, `designer`, `orchestrator` + +### Phase 3: Refinement (TDD Implementation) +**Goal**: Implement features with test-first approach + +- Write failing tests +- Implement minimum viable code +- Make tests pass +- Refactor for quality +- Iterate until complete + +**Key Modes**: `tdd`, `coder`, `tester` + +### Phase 4: Review +**Goal**: Ensure code quality, security, and performance + +- Code quality assessment +- Security vulnerability scanning +- Performance profiling +- Best practices validation +- Documentation review + +**Key Modes**: `reviewer`, `optimizer`, `debugger` + +### Phase 5: Completion +**Goal**: Integration, deployment, and monitoring + +- System integration +- Deployment automation +- Monitoring setup +- Documentation finalization +- Knowledge capture + +**Key Modes**: `workflow-manager`, `documenter`, `memory-manager` + +--- + +## Available Modes + +### Core Orchestration Modes + +#### `orchestrator` +Multi-agent task orchestration with TodoWrite/Task/Memory coordination. + +**Capabilities**: +- Task decomposition into manageable units +- Agent coordination and resource allocation +- Progress tracking and result synthesis +- Adaptive strategy selection +- Cross-agent communication + +**Usage**: +```javascript +mcp__claude-flow__sparc_mode { + mode: "orchestrator", + task_description: "coordinate feature development", + options: { parallel: true, monitor: true } +} +``` + +#### `swarm-coordinator` +Specialized swarm management for complex multi-agent workflows. + +**Capabilities**: +- Topology optimization (mesh, hierarchical, ring, star) +- Agent lifecycle management +- Dynamic scaling based on workload +- Fault tolerance and recovery +- Performance monitoring + +#### `workflow-manager` +Process automation and workflow orchestration. + +**Capabilities**: +- Workflow definition and execution +- Event-driven triggers +- Sequential and parallel pipelines +- State management +- Error handling and retry logic + +#### `batch-executor` +Parallel task execution for high-throughput operations. + +**Capabilities**: +- Concurrent file operations +- Batch processing optimization +- Resource pooling +- Load balancing +- Progress aggregation + +--- + +### Development Modes + +#### `coder` +Autonomous code generation with batch file operations. + +**Capabilities**: +- Feature implementation +- Code refactoring +- Bug fixes and patches +- API development +- Algorithm implementation + +**Quality Standards**: +- ES2022+ standards +- TypeScript type safety +- Comprehensive error handling +- Performance optimization +- Security best practices + +**Usage**: +```javascript +mcp__claude-flow__sparc_mode { + mode: "coder", + task_description: "implement user authentication with JWT", + options: { + test_driven: true, + parallel_edits: true, + typescript: true + } +} +``` + +#### `architect` +System design with Memory-based coordination. + +**Capabilities**: +- Microservices architecture +- Event-driven design +- Domain-driven design (DDD) +- Hexagonal architecture +- CQRS and Event Sourcing + +**Memory Integration**: +- Store architectural decisions +- Share component specifications +- Maintain design consistency +- Track architectural evolution + +**Design Patterns**: +- Layered architecture +- Microservices patterns +- Event-driven patterns +- Domain modeling +- Infrastructure as Code + +**Usage**: +```javascript +mcp__claude-flow__sparc_mode { + mode: "architect", + task_description: "design scalable e-commerce platform", + options: { + detailed: true, + memory_enabled: true, + patterns: ["microservices", "event-driven"] + } +} +``` + +#### `tdd` +Test-driven development with comprehensive testing. + +**Capabilities**: +- Test-first development +- Red-green-refactor cycle +- Test suite design +- Coverage optimization (target: 90%+) +- Continuous testing + +**TDD Workflow**: +1. Write failing test (RED) +2. Implement minimum code +3. Make test pass (GREEN) +4. Refactor for quality (REFACTOR) +5. Repeat cycle + +**Testing Strategies**: +- Unit testing (Jest, Mocha, Vitest) +- Integration testing +- End-to-end testing (Playwright, Cypress) +- Performance testing +- Security testing + +**Usage**: +```javascript +mcp__claude-flow__sparc_mode { + mode: "tdd", + task_description: "shopping cart feature with payment integration", + options: { + coverage_target: 90, + test_framework: "jest", + e2e_framework: "playwright" + } +} +``` + +#### `reviewer` +Code review using batch file analysis. + +**Capabilities**: +- Code quality assessment +- Security vulnerability detection +- Performance analysis +- Best practices validation +- Documentation review + +**Review Criteria**: +- Code correctness and logic +- Design pattern adherence +- Comprehensive error handling +- Test coverage adequacy +- Maintainability and readability +- Security vulnerabilities +- Performance bottlenecks + +**Batch Analysis**: +- Parallel file review +- Pattern detection +- Dependency checking +- Consistency validation +- Automated reporting + +**Usage**: +```javascript +mcp__claude-flow__sparc_mode { + mode: "reviewer", + task_description: "review authentication module PR #123", + options: { + security_check: true, + performance_check: true, + test_coverage_check: true + } +} +``` + +--- + +### Analysis and Research Modes + +#### `researcher` +Deep research with parallel WebSearch/WebFetch and Memory coordination. + +**Capabilities**: +- Comprehensive information gathering +- Source credibility evaluation +- Trend analysis and forecasting +- Competitive research +- Technology assessment + +**Research Methods**: +- Parallel web searches +- Academic paper analysis +- Industry report synthesis +- Expert opinion gathering +- Statistical data compilation + +**Memory Integration**: +- Store research findings with citations +- Build knowledge graphs +- Track information sources +- Cross-reference insights +- Maintain research history + +**Usage**: +```javascript +mcp__claude-flow__sparc_mode { + mode: "researcher", + task_description: "research microservices best practices 2024", + options: { + depth: "comprehensive", + sources: ["academic", "industry", "news"], + citations: true + } +} +``` + +#### `analyzer` +Code and data analysis with pattern recognition. + +**Capabilities**: +- Static code analysis +- Dependency analysis +- Performance profiling +- Security scanning +- Data pattern recognition + +#### `optimizer` +Performance optimization and bottleneck resolution. + +**Capabilities**: +- Algorithm optimization +- Database query tuning +- Caching strategy design +- Bundle size reduction +- Memory leak detection + +--- + +### Creative and Support Modes + +#### `designer` +UI/UX design with accessibility focus. + +**Capabilities**: +- Interface design +- User experience optimization +- Accessibility compliance (WCAG 2.1) +- Design system creation +- Responsive layout design + +#### `innovator` +Creative problem-solving and novel solutions. + +**Capabilities**: +- Brainstorming and ideation +- Alternative approach generation +- Technology evaluation +- Proof of concept development +- Innovation feasibility analysis + +#### `documenter` +Comprehensive documentation generation. + +**Capabilities**: +- API documentation (OpenAPI/Swagger) +- Architecture diagrams +- User guides and tutorials +- Code comments and JSDoc +- README and changelog maintenance + +#### `debugger` +Systematic debugging and issue resolution. + +**Capabilities**: +- Bug reproduction +- Root cause analysis +- Fix implementation +- Regression prevention +- Debug logging optimization + +#### `tester` +Comprehensive testing beyond TDD. + +**Capabilities**: +- Test suite expansion +- Edge case identification +- Performance testing +- Load testing +- Chaos engineering + +#### `memory-manager` +Knowledge management and context preservation. + +**Capabilities**: +- Cross-session memory persistence +- Knowledge graph construction +- Context restoration +- Learning pattern extraction +- Decision tracking + +--- + +## Activation Methods + +### Method 1: MCP Tools (Preferred in Claude Code) + +**Best for**: Integrated Claude Code workflows with full orchestration capabilities + +```javascript +// Basic mode execution +mcp__claude-flow__sparc_mode { + mode: "", + task_description: "", + options: { + // mode-specific options + } +} + +// Initialize swarm for complex tasks +mcp__claude-flow__swarm_init { + topology: "hierarchical", // or "mesh", "ring", "star" + strategy: "auto", // or "balanced", "specialized", "adaptive" + maxAgents: 8 +} + +// Spawn specialized agents +mcp__claude-flow__agent_spawn { + type: "", + capabilities: ["", ""] +} + +// Monitor execution +mcp__claude-flow__swarm_monitor { + swarmId: "current", + interval: 5000 +} +``` + +### Method 2: NPX CLI (Fallback) + +**Best for**: Terminal usage or when MCP tools unavailable + +```bash +# Execute specific mode +npx claude-flow sparc run "task description" + +# Use alpha features +npx claude-flow@alpha sparc run "task description" + +# List all available modes +npx claude-flow sparc modes + +# Get help for specific mode +npx claude-flow sparc help + +# Run with options +npx claude-flow sparc run "task" --parallel --monitor + +# Execute TDD workflow +npx claude-flow sparc tdd "feature description" + +# Batch execution +npx claude-flow sparc batch "task" + +# Pipeline execution +npx claude-flow sparc pipeline "task description" +``` + +### Method 3: Local Installation + +**Best for**: Projects with local claude-flow installation + +```bash +# If claude-flow is installed locally +./claude-flow sparc run "task description" +``` + +--- + +## Orchestration Patterns + +### Pattern 1: Hierarchical Coordination + +**Best for**: Complex projects with clear delegation hierarchy + +```javascript +// Initialize hierarchical swarm +mcp__claude-flow__swarm_init { + topology: "hierarchical", + maxAgents: 12 +} + +// Spawn coordinator +mcp__claude-flow__agent_spawn { + type: "coordinator", + capabilities: ["planning", "delegation", "monitoring"] +} + +// Spawn specialized workers +mcp__claude-flow__agent_spawn { type: "architect" } +mcp__claude-flow__agent_spawn { type: "coder" } +mcp__claude-flow__agent_spawn { type: "tester" } +mcp__claude-flow__agent_spawn { type: "reviewer" } +``` + +### Pattern 2: Mesh Coordination + +**Best for**: Collaborative tasks requiring peer-to-peer communication + +```javascript +mcp__claude-flow__swarm_init { + topology: "mesh", + strategy: "balanced", + maxAgents: 6 +} +``` + +### Pattern 3: Sequential Pipeline + +**Best for**: Ordered workflow execution (spec โ†’ design โ†’ code โ†’ test โ†’ review) + +```javascript +mcp__claude-flow__workflow_create { + name: "development-pipeline", + steps: [ + { mode: "researcher", task: "gather requirements" }, + { mode: "architect", task: "design system" }, + { mode: "coder", task: "implement features" }, + { mode: "tdd", task: "create tests" }, + { mode: "reviewer", task: "review code" } + ], + triggers: ["on_step_complete"] +} +``` + +### Pattern 4: Parallel Execution + +**Best for**: Independent tasks that can run concurrently + +```javascript +mcp__claude-flow__task_orchestrate { + task: "build full-stack application", + strategy: "parallel", + dependencies: { + backend: [], + frontend: [], + database: [], + tests: ["backend", "frontend"] + } +} +``` + +### Pattern 5: Adaptive Strategy + +**Best for**: Dynamic workloads with changing requirements + +```javascript +mcp__claude-flow__swarm_init { + topology: "hierarchical", + strategy: "adaptive", // Auto-adjusts based on workload + maxAgents: 20 +} +``` + +--- + +## TDD Workflows + +### Complete TDD Workflow + +```javascript +// Step 1: Initialize TDD swarm +mcp__claude-flow__swarm_init { + topology: "hierarchical", + maxAgents: 8 +} + +// Step 2: Research and planning +mcp__claude-flow__sparc_mode { + mode: "researcher", + task_description: "research testing best practices for feature X" +} + +// Step 3: Architecture design +mcp__claude-flow__sparc_mode { + mode: "architect", + task_description: "design testable architecture for feature X" +} + +// Step 4: TDD implementation +mcp__claude-flow__sparc_mode { + mode: "tdd", + task_description: "implement feature X with 90% coverage", + options: { + coverage_target: 90, + test_framework: "jest", + parallel_tests: true + } +} + +// Step 5: Code review +mcp__claude-flow__sparc_mode { + mode: "reviewer", + task_description: "review feature X implementation", + options: { + test_coverage_check: true, + security_check: true + } +} + +// Step 6: Optimization +mcp__claude-flow__sparc_mode { + mode: "optimizer", + task_description: "optimize feature X performance" +} +``` + +### Red-Green-Refactor Cycle + +```javascript +// RED: Write failing test +mcp__claude-flow__sparc_mode { + mode: "tester", + task_description: "create failing test for shopping cart add item", + options: { expect_failure: true } +} + +// GREEN: Minimal implementation +mcp__claude-flow__sparc_mode { + mode: "coder", + task_description: "implement minimal code to pass test", + options: { minimal: true } +} + +// REFACTOR: Improve code quality +mcp__claude-flow__sparc_mode { + mode: "coder", + task_description: "refactor shopping cart implementation", + options: { maintain_tests: true } +} +``` + +--- + +## Best Practices + +### 1. Memory Integration + +**Always use Memory for cross-agent coordination**: + +```javascript +// Store architectural decisions +mcp__claude-flow__memory_usage { + action: "store", + namespace: "architecture", + key: "api-design-v1", + value: JSON.stringify(apiDesign), + ttl: 86400000 // 24 hours +} + +// Retrieve in subsequent agents +mcp__claude-flow__memory_usage { + action: "retrieve", + namespace: "architecture", + key: "api-design-v1" +} +``` + +### 2. Parallel Operations + +**Batch all related operations in single message**: + +```javascript +// โœ… CORRECT: All operations together +[Single Message]: + mcp__claude-flow__agent_spawn { type: "researcher" } + mcp__claude-flow__agent_spawn { type: "coder" } + mcp__claude-flow__agent_spawn { type: "tester" } + TodoWrite { todos: [8-10 todos] } + +// โŒ WRONG: Multiple messages +Message 1: mcp__claude-flow__agent_spawn { type: "researcher" } +Message 2: mcp__claude-flow__agent_spawn { type: "coder" } +Message 3: TodoWrite { todos: [...] } +``` + +### 3. Hook Integration + +**Every SPARC mode should use hooks**: + +```bash +# Before work +npx claude-flow@alpha hooks pre-task --description "implement auth" + +# During work +npx claude-flow@alpha hooks post-edit --file "auth.js" + +# After work +npx claude-flow@alpha hooks post-task --task-id "task-123" +``` + +### 4. Test Coverage + +**Maintain minimum 90% coverage**: + +- Unit tests for all functions +- Integration tests for APIs +- E2E tests for critical flows +- Edge case coverage +- Error path testing + +### 5. Documentation + +**Document as you build**: + +- API documentation (OpenAPI) +- Architecture decision records (ADR) +- Code comments for complex logic +- README with setup instructions +- Changelog for version tracking + +### 6. File Organization + +**Never save to root folder**: + +``` +project/ +โ”œโ”€โ”€ src/ # Source code +โ”œโ”€โ”€ tests/ # Test files +โ”œโ”€โ”€ docs/ # Documentation +โ”œโ”€โ”€ config/ # Configuration +โ”œโ”€โ”€ scripts/ # Utility scripts +โ””โ”€โ”€ examples/ # Example code +``` + +--- + +## Integration Examples + +### Example 1: Full-Stack Development + +```javascript +[Single Message - Parallel Agent Execution]: + +// Initialize swarm +mcp__claude-flow__swarm_init { + topology: "hierarchical", + maxAgents: 10 +} + +// Architecture phase +mcp__claude-flow__sparc_mode { + mode: "architect", + task_description: "design REST API with authentication", + options: { memory_enabled: true } +} + +// Research phase +mcp__claude-flow__sparc_mode { + mode: "researcher", + task_description: "research authentication best practices" +} + +// Implementation phase +mcp__claude-flow__sparc_mode { + mode: "coder", + task_description: "implement Express API with JWT auth", + options: { test_driven: true } +} + +// Testing phase +mcp__claude-flow__sparc_mode { + mode: "tdd", + task_description: "comprehensive API tests", + options: { coverage_target: 90 } +} + +// Review phase +mcp__claude-flow__sparc_mode { + mode: "reviewer", + task_description: "security and performance review", + options: { security_check: true } +} + +// Batch todos +TodoWrite { + todos: [ + {content: "Design API schema", status: "completed"}, + {content: "Research JWT implementation", status: "completed"}, + {content: "Implement authentication", status: "in_progress"}, + {content: "Write API tests", status: "pending"}, + {content: "Security review", status: "pending"}, + {content: "Performance optimization", status: "pending"}, + {content: "API documentation", status: "pending"}, + {content: "Deployment setup", status: "pending"} + ] +} +``` + +### Example 2: Research-Driven Innovation + +```javascript +// Research phase +mcp__claude-flow__sparc_mode { + mode: "researcher", + task_description: "research AI-powered search implementations", + options: { + depth: "comprehensive", + sources: ["academic", "industry"] + } +} + +// Innovation phase +mcp__claude-flow__sparc_mode { + mode: "innovator", + task_description: "propose novel search algorithm", + options: { memory_enabled: true } +} + +// Architecture phase +mcp__claude-flow__sparc_mode { + mode: "architect", + task_description: "design scalable search system" +} + +// Implementation phase +mcp__claude-flow__sparc_mode { + mode: "coder", + task_description: "implement search algorithm", + options: { test_driven: true } +} + +// Documentation phase +mcp__claude-flow__sparc_mode { + mode: "documenter", + task_description: "document search system architecture and API" +} +``` + +### Example 3: Legacy Code Refactoring + +```javascript +// Analysis phase +mcp__claude-flow__sparc_mode { + mode: "analyzer", + task_description: "analyze legacy codebase dependencies" +} + +// Planning phase +mcp__claude-flow__sparc_mode { + mode: "orchestrator", + task_description: "plan incremental refactoring strategy" +} + +// Testing phase (create safety net) +mcp__claude-flow__sparc_mode { + mode: "tester", + task_description: "create comprehensive test suite for legacy code", + options: { coverage_target: 80 } +} + +// Refactoring phase +mcp__claude-flow__sparc_mode { + mode: "coder", + task_description: "refactor module X with modern patterns", + options: { maintain_tests: true } +} + +// Review phase +mcp__claude-flow__sparc_mode { + mode: "reviewer", + task_description: "validate refactoring maintains functionality" +} +``` + +--- + +## Common Workflows + +### Workflow 1: Feature Development + +```bash +# Step 1: Research and planning +npx claude-flow sparc run researcher "authentication patterns" + +# Step 2: Architecture design +npx claude-flow sparc run architect "design auth system" + +# Step 3: TDD implementation +npx claude-flow sparc tdd "user authentication feature" + +# Step 4: Code review +npx claude-flow sparc run reviewer "review auth implementation" + +# Step 5: Documentation +npx claude-flow sparc run documenter "document auth API" +``` + +### Workflow 2: Bug Investigation + +```bash +# Step 1: Analyze issue +npx claude-flow sparc run analyzer "investigate bug #456" + +# Step 2: Debug systematically +npx claude-flow sparc run debugger "fix memory leak in service X" + +# Step 3: Create tests +npx claude-flow sparc run tester "regression tests for bug #456" + +# Step 4: Review fix +npx claude-flow sparc run reviewer "validate bug fix" +``` + +### Workflow 3: Performance Optimization + +```bash +# Step 1: Profile performance +npx claude-flow sparc run analyzer "profile API response times" + +# Step 2: Identify bottlenecks +npx claude-flow sparc run optimizer "optimize database queries" + +# Step 3: Implement improvements +npx claude-flow sparc run coder "implement caching layer" + +# Step 4: Benchmark results +npx claude-flow sparc run tester "performance benchmarks" +``` + +### Workflow 4: Complete Pipeline + +```bash +# Execute full development pipeline +npx claude-flow sparc pipeline "e-commerce checkout feature" + +# This automatically runs: +# 1. researcher - Gather requirements +# 2. architect - Design system +# 3. coder - Implement features +# 4. tdd - Create comprehensive tests +# 5. reviewer - Code quality review +# 6. optimizer - Performance tuning +# 7. documenter - Documentation +``` + +--- + +## Advanced Features + +### Neural Pattern Training + +```javascript +// Train patterns from successful workflows +mcp__claude-flow__neural_train { + pattern_type: "coordination", + training_data: "successful_tdd_workflow.json", + epochs: 50 +} +``` + +### Cross-Session Memory + +```javascript +// Save session state +mcp__claude-flow__memory_persist { + sessionId: "feature-auth-v1" +} + +// Restore in new session +mcp__claude-flow__context_restore { + snapshotId: "feature-auth-v1" +} +``` + +### GitHub Integration + +```javascript +// Analyze repository +mcp__claude-flow__github_repo_analyze { + repo: "owner/repo", + analysis_type: "code_quality" +} + +// Manage pull requests +mcp__claude-flow__github_pr_manage { + repo: "owner/repo", + pr_number: 123, + action: "review" +} +``` + +### Performance Monitoring + +```javascript +// Real-time swarm monitoring +mcp__claude-flow__swarm_monitor { + swarmId: "current", + interval: 5000 +} + +// Bottleneck analysis +mcp__claude-flow__bottleneck_analyze { + component: "api-layer", + metrics: ["latency", "throughput", "errors"] +} + +// Token usage tracking +mcp__claude-flow__token_usage { + operation: "feature-development", + timeframe: "24h" +} +``` + +--- + +## Performance Benefits + +**Proven Results**: +- **84.8%** SWE-Bench solve rate +- **32.3%** token reduction through optimizations +- **2.8-4.4x** speed improvement with parallel execution +- **27+** neural models for pattern learning +- **90%+** test coverage standard + +--- + +## Support and Resources + +- **Documentation**: https://github.com/ruvnet/claude-flow +- **Issues**: https://github.com/ruvnet/claude-flow/issues +- **NPM Package**: https://www.npmjs.com/package/claude-flow +- **Community**: Discord server (link in repository) + +--- + +## Quick Reference + +### Most Common Commands + +```bash +# List modes +npx claude-flow sparc modes + +# Run specific mode +npx claude-flow sparc run "task" + +# TDD workflow +npx claude-flow sparc tdd "feature" + +# Full pipeline +npx claude-flow sparc pipeline "task" + +# Batch execution +npx claude-flow sparc batch "task" +``` + +### Most Common MCP Calls + +```javascript +// Initialize swarm +mcp__claude-flow__swarm_init { topology: "hierarchical" } + +// Execute mode +mcp__claude-flow__sparc_mode { mode: "coder", task_description: "..." } + +// Monitor progress +mcp__claude-flow__swarm_monitor { interval: 5000 } + +// Store in memory +mcp__claude-flow__memory_usage { action: "store", key: "...", value: "..." } +``` + +--- + +Remember: **SPARC = Systematic, Parallel, Agile, Refined, Complete** diff --git a/.claude/skills/spotify-player/SKILL.md b/.claude/skills/spotify-player/SKILL.md new file mode 100644 index 0000000000..6a5928d5b6 --- /dev/null +++ b/.claude/skills/spotify-player/SKILL.md @@ -0,0 +1,34 @@ +--- +name: spotify-player +description: Terminal Spotify playback/search via spogo (preferred) or spotify_player. +homepage: https://www.spotify.com +metadata: {"zee":{"emoji":"๐ŸŽต","requires":{"anyBins":["spogo","spotify_player"]},"install":[{"id":"brew","kind":"brew","formula":"spogo","tap":"steipete/tap","bins":["spogo"],"label":"Install spogo (brew)"},{"id":"brew","kind":"brew","formula":"spotify_player","bins":["spotify_player"],"label":"Install spotify_player (brew)"}]}} +--- + +# spogo / spotify_player + +Use `spogo` **(preferred)** for Spotify playback/search. Fall back to `spotify_player` if needed. + +Requirements +- Spotify Premium account. +- Either `spogo` or `spotify_player` installed. + +spogo setup +- Import cookies: `spogo auth import --browser chrome` + +Common CLI commands +- Search: `spogo search track "query"` +- Playback: `spogo play|pause|next|prev` +- Devices: `spogo device list`, `spogo device set ""` +- Status: `spogo status` + +spotify_player commands (fallback) +- Search: `spotify_player search "query"` +- Playback: `spotify_player playback play|pause|next|previous` +- Connect device: `spotify_player connect` +- Like track: `spotify_player like` + +Notes +- Config folder: `~/.config/spotify-player` (e.g., `app.toml`). +- For Spotify Connect integration, set a user `client_id` in config. +- TUI shortcuts are available via `?` in the app. diff --git a/.claude/skills/stanley/SKILL.md b/.claude/skills/stanley/SKILL.md index 985f7e7d28..0179fc370e 100644 --- a/.claude/skills/stanley/SKILL.md +++ b/.claude/skills/stanley/SKILL.md @@ -153,7 +153,7 @@ npx tsx scripts/stanley-daemon.ts status Environment variables used by the CLI bridge: -- `STANLEY_REPO` (default: `~/Repositories/personas/stanley`) +- `STANLEY_REPO` (default: `~/.local/src/agent-core/vendor/personas/stanley`) - `STANLEY_PYTHON` (default: `python3`) - `STANLEY_OPENBB_PROVIDER` (default: `yfinance`) - `STANLEY_PORTFOLIO_FILE` (default: `~/.zee/stanley/portfolio.json`) diff --git a/.claude/skills/stanley/scripts/stanley-gui.ts b/.claude/skills/stanley/scripts/stanley-gui.ts index 8e5547cff8..018a39d052 100644 --- a/.claude/skills/stanley/scripts/stanley-gui.ts +++ b/.claude/skills/stanley/scripts/stanley-gui.ts @@ -16,7 +16,7 @@ import { homedir } from "os"; import { join } from "path"; const STANLEY_REPO = - process.env.STANLEY_REPO ?? join(homedir(), "Repositories/personas/stanley"); + process.env.STANLEY_REPO ?? join(homedir(), ".local/src/agent-core/vendor/personas/stanley"); const GUI_DIR = join(STANLEY_REPO, "stanley-gui"); const GUI_BINARY = join(GUI_DIR, "target/release/stanley-gui"); const BACKEND_PORT = 8000; @@ -101,7 +101,7 @@ Usage: npx tsx stanley-gui.ts build Rebuild the GUI from source Environment: - STANLEY_REPO Path to Stanley repository (default: ~/Repositories/personas/stanley) + STANLEY_REPO Path to Stanley repository (default: ~/.local/src/agent-core/vendor/personas/stanley) STANLEY_PYTHON Python interpreter (default: .venv/bin/python or python3) `); break; diff --git a/.claude/skills/stanley/scripts/stanley-market.ts b/.claude/skills/stanley/scripts/stanley-market.ts index 5f6316e0f4..7b776a0c21 100644 --- a/.claude/skills/stanley/scripts/stanley-market.ts +++ b/.claude/skills/stanley/scripts/stanley-market.ts @@ -36,7 +36,7 @@ type StanleyResult = { }; function resolveStanleyCli(): { python: string; cliPath: string } { - const repo = process.env.STANLEY_REPO || join(homedir(), "Repositories", "personas", "stanley"); + const repo = process.env.STANLEY_REPO || join(homedir(), ".local", "src", "agent-core", "vendor", "personas", "stanley"); const cliPath = process.env.STANLEY_CLI || join(repo, "scripts", "stanley_cli.py"); const venvPython = join(repo, ".venv", "bin", "python"); const python = process.env.STANLEY_PYTHON || (existsSync(venvPython) ? venvPython : "python3"); diff --git a/.claude/skills/stanley/scripts/stanley-nautilus.ts b/.claude/skills/stanley/scripts/stanley-nautilus.ts index f2629b81e5..db46a1289e 100644 --- a/.claude/skills/stanley/scripts/stanley-nautilus.ts +++ b/.claude/skills/stanley/scripts/stanley-nautilus.ts @@ -29,7 +29,7 @@ function getArg(name: string): string | undefined { } function resolveStanleyCli(): { python: string; cliPath: string } { - const repo = process.env.STANLEY_REPO || join(homedir(), "Repositories", "personas", "stanley"); + const repo = process.env.STANLEY_REPO || join(homedir(), ".local", "src", "agent-core", "vendor", "personas", "stanley"); const cliPath = process.env.STANLEY_CLI || join(repo, "scripts", "stanley_cli.py"); const venvPython = join(repo, ".venv", "bin", "python"); const python = process.env.STANLEY_PYTHON || (existsSync(venvPython) ? venvPython : "python3"); diff --git a/.claude/skills/stanley/scripts/stanley-portfolio.ts b/.claude/skills/stanley/scripts/stanley-portfolio.ts index 91c8eea842..e96f95754b 100644 --- a/.claude/skills/stanley/scripts/stanley-portfolio.ts +++ b/.claude/skills/stanley/scripts/stanley-portfolio.ts @@ -29,7 +29,7 @@ function getArg(name: string): string | undefined { } function resolveStanleyCli(): { python: string; cliPath: string } { - const repo = process.env.STANLEY_REPO || join(homedir(), "Repositories", "personas", "stanley"); + const repo = process.env.STANLEY_REPO || join(homedir(), ".local", "src", "agent-core", "vendor", "personas", "stanley"); const cliPath = process.env.STANLEY_CLI || join(repo, "scripts", "stanley_cli.py"); const venvPython = join(repo, ".venv", "bin", "python"); const python = process.env.STANLEY_PYTHON || (existsSync(venvPython) ? venvPython : "python3"); diff --git a/.claude/skills/stanley/scripts/stanley-research.ts b/.claude/skills/stanley/scripts/stanley-research.ts index 99dadef847..ffa25557fd 100644 --- a/.claude/skills/stanley/scripts/stanley-research.ts +++ b/.claude/skills/stanley/scripts/stanley-research.ts @@ -29,7 +29,7 @@ function getArg(name: string): string | undefined { } function resolveStanleyCli(): { python: string; cliPath: string } { - const repo = process.env.STANLEY_REPO || join(homedir(), "Repositories", "personas", "stanley"); + const repo = process.env.STANLEY_REPO || join(homedir(), ".local", "src", "agent-core", "vendor", "personas", "stanley"); const cliPath = process.env.STANLEY_CLI || join(repo, "scripts", "stanley_cli.py"); const venvPython = join(repo, ".venv", "bin", "python"); const python = process.env.STANLEY_PYTHON || (existsSync(venvPython) ? venvPython : "python3"); diff --git a/.claude/skills/stream-chain/SKILL.md b/.claude/skills/stream-chain/SKILL.md new file mode 100644 index 0000000000..6ed65fbb65 --- /dev/null +++ b/.claude/skills/stream-chain/SKILL.md @@ -0,0 +1,563 @@ +--- +name: stream-chain +description: Stream-JSON chaining for multi-agent pipelines, data transformation, and sequential workflows +version: 1.0.0 +category: workflow +tags: [streaming, pipeline, chaining, multi-agent, workflow] +--- + +# Stream-Chain Skill + +Execute sophisticated multi-step workflows where each agent's output flows into the next, enabling complex data transformations and sequential processing pipelines. + +## Overview + +Stream-Chain provides two powerful modes for orchestrating multi-agent workflows: + +1. **Custom Chains** (`run`): Execute custom prompt sequences with full control +2. **Predefined Pipelines** (`pipeline`): Use battle-tested workflows for common tasks + +Each step in a chain receives the complete output from the previous step, enabling sophisticated multi-agent coordination through streaming data flow. + +--- + +## Quick Start + +### Run a Custom Chain + +```bash +claude-flow stream-chain run \ + "Analyze codebase structure" \ + "Identify improvement areas" \ + "Generate action plan" +``` + +### Execute a Pipeline + +```bash +claude-flow stream-chain pipeline analysis +``` + +--- + +## Custom Chains (`run`) + +Execute custom stream chains with your own prompts for maximum flexibility. + +### Syntax + +```bash +claude-flow stream-chain run [...] [options] +``` + +**Requirements:** +- Minimum 2 prompts required +- Each prompt becomes a step in the chain +- Output flows sequentially through all steps + +### Options + +| Option | Description | Default | +|--------|-------------|---------| +| `--verbose` | Show detailed execution information | `false` | +| `--timeout ` | Timeout per step | `30` | +| `--debug` | Enable debug mode with full logging | `false` | + +### How Context Flows + +Each step receives the previous output as context: + +``` +Step 1: "Write a sorting function" +Output: [function implementation] + +Step 2 receives: + "Previous step output: + [function implementation] + + Next task: Add comprehensive tests" + +Step 3 receives: + "Previous steps output: + [function + tests] + + Next task: Optimize performance" +``` + +### Examples + +#### Basic Development Chain + +```bash +claude-flow stream-chain run \ + "Write a user authentication function" \ + "Add input validation and error handling" \ + "Create unit tests with edge cases" +``` + +#### Security Audit Workflow + +```bash +claude-flow stream-chain run \ + "Analyze authentication system for vulnerabilities" \ + "Identify and categorize security issues by severity" \ + "Propose fixes with implementation priority" \ + "Generate security test cases" \ + --timeout 45 \ + --verbose +``` + +#### Code Refactoring Chain + +```bash +claude-flow stream-chain run \ + "Identify code smells in src/ directory" \ + "Create refactoring plan with specific changes" \ + "Apply refactoring to top 3 priority items" \ + "Verify refactored code maintains behavior" \ + --debug +``` + +#### Data Processing Pipeline + +```bash +claude-flow stream-chain run \ + "Extract data from API responses" \ + "Transform data into normalized format" \ + "Validate data against schema" \ + "Generate data quality report" +``` + +--- + +## Predefined Pipelines (`pipeline`) + +Execute battle-tested workflows optimized for common development tasks. + +### Syntax + +```bash +claude-flow stream-chain pipeline [options] +``` + +### Available Pipelines + +#### 1. Analysis Pipeline + +Comprehensive codebase analysis and improvement identification. + +```bash +claude-flow stream-chain pipeline analysis +``` + +**Workflow Steps:** +1. **Structure Analysis**: Map directory structure and identify components +2. **Issue Detection**: Find potential improvements and problems +3. **Recommendations**: Generate actionable improvement report + +**Use Cases:** +- New codebase onboarding +- Technical debt assessment +- Architecture review +- Code quality audits + +#### 2. Refactor Pipeline + +Systematic code refactoring with prioritization. + +```bash +claude-flow stream-chain pipeline refactor +``` + +**Workflow Steps:** +1. **Candidate Identification**: Find code needing refactoring +2. **Prioritization**: Create ranked refactoring plan +3. **Implementation**: Provide refactored code for top priorities + +**Use Cases:** +- Technical debt reduction +- Code quality improvement +- Legacy code modernization +- Design pattern implementation + +#### 3. Test Pipeline + +Comprehensive test generation with coverage analysis. + +```bash +claude-flow stream-chain pipeline test +``` + +**Workflow Steps:** +1. **Coverage Analysis**: Identify areas lacking tests +2. **Test Design**: Create test cases for critical functions +3. **Implementation**: Generate unit tests with assertions + +**Use Cases:** +- Increasing test coverage +- TDD workflow support +- Regression test creation +- Quality assurance + +#### 4. Optimize Pipeline + +Performance optimization with profiling and implementation. + +```bash +claude-flow stream-chain pipeline optimize +``` + +**Workflow Steps:** +1. **Profiling**: Identify performance bottlenecks +2. **Strategy**: Analyze and suggest optimization approaches +3. **Implementation**: Provide optimized code + +**Use Cases:** +- Performance improvement +- Resource optimization +- Scalability enhancement +- Latency reduction + +### Pipeline Options + +| Option | Description | Default | +|--------|-------------|---------| +| `--verbose` | Show detailed execution | `false` | +| `--timeout ` | Timeout per step | `30` | +| `--debug` | Enable debug mode | `false` | + +### Pipeline Examples + +#### Quick Analysis + +```bash +claude-flow stream-chain pipeline analysis +``` + +#### Extended Refactoring + +```bash +claude-flow stream-chain pipeline refactor --timeout 60 --verbose +``` + +#### Debug Test Generation + +```bash +claude-flow stream-chain pipeline test --debug +``` + +#### Comprehensive Optimization + +```bash +claude-flow stream-chain pipeline optimize --timeout 90 --verbose +``` + +### Pipeline Output + +Each pipeline execution provides: + +- **Progress**: Step-by-step execution status +- **Results**: Success/failure per step +- **Timing**: Total and per-step execution time +- **Summary**: Consolidated results and recommendations + +--- + +## Custom Pipeline Definitions + +Define reusable pipelines in `.claude-flow/config.json`: + +### Configuration Format + +```json +{ + "streamChain": { + "pipelines": { + "security": { + "name": "Security Audit Pipeline", + "description": "Comprehensive security analysis", + "prompts": [ + "Scan codebase for security vulnerabilities", + "Categorize issues by severity (critical/high/medium/low)", + "Generate fixes with priority and implementation steps", + "Create security test suite" + ], + "timeout": 45 + }, + "documentation": { + "name": "Documentation Generation Pipeline", + "prompts": [ + "Analyze code structure and identify undocumented areas", + "Generate API documentation with examples", + "Create usage guides and tutorials", + "Build architecture diagrams and flow charts" + ] + } + } + } +} +``` + +### Execute Custom Pipeline + +```bash +claude-flow stream-chain pipeline security +claude-flow stream-chain pipeline documentation +``` + +--- + +## Advanced Use Cases + +### Multi-Agent Coordination + +Chain different agent types for complex workflows: + +```bash +claude-flow stream-chain run \ + "Research best practices for API design" \ + "Design REST API with discovered patterns" \ + "Implement API endpoints with validation" \ + "Generate OpenAPI specification" \ + "Create integration tests" \ + "Write deployment documentation" +``` + +### Data Transformation Pipeline + +Process and transform data through multiple stages: + +```bash +claude-flow stream-chain run \ + "Extract user data from CSV files" \ + "Normalize and validate data format" \ + "Enrich data with external API calls" \ + "Generate analytics report" \ + "Create visualization code" +``` + +### Code Migration Workflow + +Systematic code migration with validation: + +```bash +claude-flow stream-chain run \ + "Analyze legacy codebase dependencies" \ + "Create migration plan with risk assessment" \ + "Generate modernized code for high-priority modules" \ + "Create migration tests" \ + "Document migration steps and rollback procedures" +``` + +### Quality Assurance Chain + +Comprehensive code quality workflow: + +```bash +claude-flow stream-chain pipeline analysis +claude-flow stream-chain pipeline refactor +claude-flow stream-chain pipeline test +claude-flow stream-chain pipeline optimize +``` + +--- + +## Best Practices + +### 1. Clear and Specific Prompts + +**Good:** +```bash +"Analyze authentication.js for SQL injection vulnerabilities" +``` + +**Avoid:** +```bash +"Check security" +``` + +### 2. Logical Progression + +Order prompts to build on previous outputs: +```bash +1. "Identify the problem" +2. "Analyze root causes" +3. "Design solution" +4. "Implement solution" +5. "Verify implementation" +``` + +### 3. Appropriate Timeouts + +- Simple tasks: 30 seconds (default) +- Analysis tasks: 45-60 seconds +- Implementation tasks: 60-90 seconds +- Complex workflows: 90-120 seconds + +### 4. Verification Steps + +Include validation in your chains: +```bash +claude-flow stream-chain run \ + "Implement feature X" \ + "Write tests for feature X" \ + "Verify tests pass and cover edge cases" +``` + +### 5. Iterative Refinement + +Use chains for iterative improvement: +```bash +claude-flow stream-chain run \ + "Generate initial implementation" \ + "Review and identify issues" \ + "Refine based on issues found" \ + "Final quality check" +``` + +--- + +## Integration with Claude Flow + +### Combine with Swarm Coordination + +```bash +# Initialize swarm for coordination +claude-flow swarm init --topology mesh + +# Execute stream chain with swarm agents +claude-flow stream-chain run \ + "Agent 1: Research task" \ + "Agent 2: Implement solution" \ + "Agent 3: Test implementation" \ + "Agent 4: Review and refine" +``` + +### Memory Integration + +Stream chains automatically store context in memory for cross-session persistence: + +```bash +# Execute chain with memory +claude-flow stream-chain run \ + "Analyze requirements" \ + "Design architecture" \ + --verbose + +# Results stored in .claude-flow/memory/stream-chain/ +``` + +### Neural Pattern Training + +Successful chains train neural patterns for improved performance: + +```bash +# Enable neural training +claude-flow stream-chain pipeline optimize --debug + +# Patterns learned and stored for future optimizations +``` + +--- + +## Troubleshooting + +### Chain Timeout + +If steps timeout, increase timeout value: + +```bash +claude-flow stream-chain run "complex task" --timeout 120 +``` + +### Context Loss + +If context not flowing properly, use `--debug`: + +```bash +claude-flow stream-chain run "step 1" "step 2" --debug +``` + +### Pipeline Not Found + +Verify pipeline name and custom definitions: + +```bash +# Check available pipelines +cat .claude-flow/config.json | grep -A 10 "streamChain" +``` + +--- + +## Performance Characteristics + +- **Throughput**: 2-5 steps per minute (varies by complexity) +- **Context Size**: Up to 100K tokens per step +- **Memory Usage**: ~50MB per active chain +- **Concurrency**: Supports parallel chain execution + +--- + +## Related Skills + +- **SPARC Methodology**: Systematic development workflow +- **Swarm Coordination**: Multi-agent orchestration +- **Memory Management**: Persistent context storage +- **Neural Patterns**: Adaptive learning + +--- + +## Examples Repository + +### Complete Development Workflow + +```bash +# Full feature development chain +claude-flow stream-chain run \ + "Analyze requirements for user profile feature" \ + "Design database schema and API endpoints" \ + "Implement backend with validation" \ + "Create frontend components" \ + "Write comprehensive tests" \ + "Generate API documentation" \ + --timeout 60 \ + --verbose +``` + +### Code Review Pipeline + +```bash +# Automated code review workflow +claude-flow stream-chain run \ + "Analyze recent git changes" \ + "Identify code quality issues" \ + "Check for security vulnerabilities" \ + "Verify test coverage" \ + "Generate code review report with recommendations" +``` + +### Migration Assistant + +```bash +# Framework migration helper +claude-flow stream-chain run \ + "Analyze current Vue 2 codebase" \ + "Identify Vue 3 breaking changes" \ + "Create migration checklist" \ + "Generate migration scripts" \ + "Provide updated code examples" +``` + +--- + +## Conclusion + +Stream-Chain enables sophisticated multi-step workflows by: + +- **Sequential Processing**: Each step builds on previous results +- **Context Preservation**: Full output history flows through chain +- **Flexible Orchestration**: Custom chains or predefined pipelines +- **Agent Coordination**: Natural multi-agent collaboration pattern +- **Data Transformation**: Complex processing through simple steps + +Use `run` for custom workflows and `pipeline` for battle-tested solutions. diff --git a/.claude/skills/summarize/SKILL.md b/.claude/skills/summarize/SKILL.md new file mode 100644 index 0000000000..cd97637fb9 --- /dev/null +++ b/.claude/skills/summarize/SKILL.md @@ -0,0 +1,49 @@ +--- +name: summarize +description: Summarize URLs or files with the summarize CLI (web, PDFs, images, audio, YouTube). +homepage: https://summarize.sh +metadata: {"zee":{"emoji":"๐Ÿงพ","requires":{"bins":["summarize"]},"install":[{"id":"brew","kind":"brew","formula":"steipete/tap/summarize","bins":["summarize"],"label":"Install summarize (brew)"}]}} +--- + +# Summarize + +Fast CLI to summarize URLs, local files, and YouTube links. + +## Quick start + +```bash +summarize "https://example.com" --model google/gemini-3-flash-preview +summarize "/path/to/file.pdf" --model google/gemini-3-flash-preview +summarize "https://youtu.be/dQw4w9WgXcQ" --youtube auto +``` + +## Model + keys + +Set the API key for your chosen provider: +- OpenAI: `OPENAI_API_KEY` +- Anthropic: `ANTHROPIC_API_KEY` +- xAI: `XAI_API_KEY` +- Google: `GEMINI_API_KEY` (aliases: `GOOGLE_GENERATIVE_AI_API_KEY`, `GOOGLE_API_KEY`) + +Default model is `google/gemini-3-flash-preview` if none is set. + +## Useful flags + +- `--length short|medium|long|xl|xxl|` +- `--max-output-tokens ` +- `--extract-only` (URLs only) +- `--json` (machine readable) +- `--firecrawl auto|off|always` (fallback extraction) +- `--youtube auto` (Apify fallback if `APIFY_API_TOKEN` set) + +## Config + +Optional config file: `~/.summarize/config.json` + +```json +{ "model": "openai/gpt-5.2" } +``` + +Optional services: +- `FIRECRAWL_API_KEY` for blocked sites +- `APIFY_API_TOKEN` for YouTube fallback diff --git a/.claude/skills/swarm-advanced/SKILL.md b/.claude/skills/swarm-advanced/SKILL.md new file mode 100644 index 0000000000..aba3060eee --- /dev/null +++ b/.claude/skills/swarm-advanced/SKILL.md @@ -0,0 +1,973 @@ +--- +name: swarm-advanced +description: Advanced swarm orchestration patterns for research, development, testing, and complex distributed workflows +version: 2.0.0 +category: orchestration +tags: [swarm, distributed, parallel, research, testing, development, coordination] +author: Claude Flow Team +--- + +# Advanced Swarm Orchestration + +Master advanced swarm patterns for distributed research, development, and testing workflows. This skill covers comprehensive orchestration strategies using both MCP tools and CLI commands. + +## Quick Start + +### Prerequisites +```bash +# Ensure Claude Flow is installed +npm install -g claude-flow@alpha + +# Add MCP server (if using MCP tools) +claude mcp add claude-flow npx claude-flow@alpha mcp start +``` + +### Basic Pattern +```javascript +// 1. Initialize swarm topology +mcp__claude-flow__swarm_init({ topology: "mesh", maxAgents: 6 }) + +// 2. Spawn specialized agents +mcp__claude-flow__agent_spawn({ type: "researcher", name: "Agent 1" }) + +// 3. Orchestrate tasks +mcp__claude-flow__task_orchestrate({ task: "...", strategy: "parallel" }) +``` + +## Core Concepts + +### Swarm Topologies + +**Mesh Topology** - Peer-to-peer communication, best for research and analysis +- All agents communicate directly +- High flexibility and resilience +- Use for: Research, analysis, brainstorming + +**Hierarchical Topology** - Coordinator with subordinates, best for development +- Clear command structure +- Sequential workflow support +- Use for: Development, structured workflows + +**Star Topology** - Central coordinator, best for testing +- Centralized control and monitoring +- Parallel execution with coordination +- Use for: Testing, validation, quality assurance + +**Ring Topology** - Sequential processing chain +- Step-by-step processing +- Pipeline workflows +- Use for: Multi-stage processing, data pipelines + +### Agent Strategies + +**Adaptive** - Dynamic adjustment based on task complexity +**Balanced** - Equal distribution of work across agents +**Specialized** - Task-specific agent assignment +**Parallel** - Maximum concurrent execution + +## Pattern 1: Research Swarm + +### Purpose +Deep research through parallel information gathering, analysis, and synthesis. + +### Architecture +```javascript +// Initialize research swarm +mcp__claude-flow__swarm_init({ + "topology": "mesh", + "maxAgents": 6, + "strategy": "adaptive" +}) + +// Spawn research team +const researchAgents = [ + { + type: "researcher", + name: "Web Researcher", + capabilities: ["web-search", "content-extraction", "source-validation"] + }, + { + type: "researcher", + name: "Academic Researcher", + capabilities: ["paper-analysis", "citation-tracking", "literature-review"] + }, + { + type: "analyst", + name: "Data Analyst", + capabilities: ["data-processing", "statistical-analysis", "visualization"] + }, + { + type: "analyst", + name: "Pattern Analyzer", + capabilities: ["trend-detection", "correlation-analysis", "outlier-detection"] + }, + { + type: "documenter", + name: "Report Writer", + capabilities: ["synthesis", "technical-writing", "formatting"] + } +] + +// Spawn all agents +researchAgents.forEach(agent => { + mcp__claude-flow__agent_spawn({ + type: agent.type, + name: agent.name, + capabilities: agent.capabilities + }) +}) +``` + +### Research Workflow + +#### Phase 1: Information Gathering +```javascript +// Parallel information collection +mcp__claude-flow__parallel_execute({ + "tasks": [ + { + "id": "web-search", + "command": "search recent publications and articles" + }, + { + "id": "academic-search", + "command": "search academic databases and papers" + }, + { + "id": "data-collection", + "command": "gather relevant datasets and statistics" + }, + { + "id": "expert-search", + "command": "identify domain experts and thought leaders" + } + ] +}) + +// Store research findings in memory +mcp__claude-flow__memory_usage({ + "action": "store", + "key": "research-findings-" + Date.now(), + "value": JSON.stringify(findings), + "namespace": "research", + "ttl": 604800 // 7 days +}) +``` + +#### Phase 2: Analysis and Validation +```javascript +// Pattern recognition in findings +mcp__claude-flow__pattern_recognize({ + "data": researchData, + "patterns": ["trend", "correlation", "outlier", "emerging-pattern"] +}) + +// Cognitive analysis +mcp__claude-flow__cognitive_analyze({ + "behavior": "research-synthesis" +}) + +// Quality assessment +mcp__claude-flow__quality_assess({ + "target": "research-sources", + "criteria": ["credibility", "relevance", "recency", "authority"] +}) + +// Cross-reference validation +mcp__claude-flow__neural_patterns({ + "action": "analyze", + "operation": "fact-checking", + "metadata": { "sources": sourcesArray } +}) +``` + +#### Phase 3: Knowledge Management +```javascript +// Search existing knowledge base +mcp__claude-flow__memory_search({ + "pattern": "topic X", + "namespace": "research", + "limit": 20 +}) + +// Create knowledge graph connections +mcp__claude-flow__neural_patterns({ + "action": "learn", + "operation": "knowledge-graph", + "metadata": { + "topic": "X", + "connections": relatedTopics, + "depth": 3 + } +}) + +// Store connections for future use +mcp__claude-flow__memory_usage({ + "action": "store", + "key": "knowledge-graph-X", + "value": JSON.stringify(knowledgeGraph), + "namespace": "research/graphs", + "ttl": 2592000 // 30 days +}) +``` + +#### Phase 4: Report Generation +```javascript +// Orchestrate report generation +mcp__claude-flow__task_orchestrate({ + "task": "generate comprehensive research report", + "strategy": "sequential", + "priority": "high", + "dependencies": ["gather", "analyze", "validate", "synthesize"] +}) + +// Monitor research progress +mcp__claude-flow__swarm_status({ + "swarmId": "research-swarm" +}) + +// Generate final report +mcp__claude-flow__workflow_execute({ + "workflowId": "research-report-generation", + "params": { + "findings": findings, + "format": "comprehensive", + "sections": ["executive-summary", "methodology", "findings", "analysis", "conclusions", "references"] + } +}) +``` + +### CLI Fallback +```bash +# Quick research swarm +npx claude-flow swarm "research AI trends in 2025" \ + --strategy research \ + --mode distributed \ + --max-agents 6 \ + --parallel \ + --output research-report.md +``` + +## Pattern 2: Development Swarm + +### Purpose +Full-stack development through coordinated specialist agents. + +### Architecture +```javascript +// Initialize development swarm with hierarchy +mcp__claude-flow__swarm_init({ + "topology": "hierarchical", + "maxAgents": 8, + "strategy": "balanced" +}) + +// Spawn development team +const devTeam = [ + { type: "architect", name: "System Architect", role: "coordinator" }, + { type: "coder", name: "Backend Developer", capabilities: ["node", "api", "database"] }, + { type: "coder", name: "Frontend Developer", capabilities: ["react", "ui", "ux"] }, + { type: "coder", name: "Database Engineer", capabilities: ["sql", "nosql", "optimization"] }, + { type: "tester", name: "QA Engineer", capabilities: ["unit", "integration", "e2e"] }, + { type: "reviewer", name: "Code Reviewer", capabilities: ["security", "performance", "best-practices"] }, + { type: "documenter", name: "Technical Writer", capabilities: ["api-docs", "guides", "tutorials"] }, + { type: "monitor", name: "DevOps Engineer", capabilities: ["ci-cd", "deployment", "monitoring"] } +] + +// Spawn all team members +devTeam.forEach(member => { + mcp__claude-flow__agent_spawn({ + type: member.type, + name: member.name, + capabilities: member.capabilities, + swarmId: "dev-swarm" + }) +}) +``` + +### Development Workflow + +#### Phase 1: Architecture and Design +```javascript +// System architecture design +mcp__claude-flow__task_orchestrate({ + "task": "design system architecture for REST API", + "strategy": "sequential", + "priority": "critical", + "assignTo": "System Architect" +}) + +// Store architecture decisions +mcp__claude-flow__memory_usage({ + "action": "store", + "key": "architecture-decisions", + "value": JSON.stringify(architectureDoc), + "namespace": "development/design" +}) +``` + +#### Phase 2: Parallel Implementation +```javascript +// Parallel development tasks +mcp__claude-flow__parallel_execute({ + "tasks": [ + { + "id": "backend-api", + "command": "implement REST API endpoints", + "assignTo": "Backend Developer" + }, + { + "id": "frontend-ui", + "command": "build user interface components", + "assignTo": "Frontend Developer" + }, + { + "id": "database-schema", + "command": "design and implement database schema", + "assignTo": "Database Engineer" + }, + { + "id": "api-documentation", + "command": "create API documentation", + "assignTo": "Technical Writer" + } + ] +}) + +// Monitor development progress +mcp__claude-flow__swarm_monitor({ + "swarmId": "dev-swarm", + "interval": 5000 +}) +``` + +#### Phase 3: Testing and Validation +```javascript +// Comprehensive testing +mcp__claude-flow__batch_process({ + "items": [ + { type: "unit", target: "all-modules" }, + { type: "integration", target: "api-endpoints" }, + { type: "e2e", target: "user-flows" }, + { type: "performance", target: "critical-paths" } + ], + "operation": "execute-tests" +}) + +// Quality assessment +mcp__claude-flow__quality_assess({ + "target": "codebase", + "criteria": ["coverage", "complexity", "maintainability", "security"] +}) +``` + +#### Phase 4: Review and Deployment +```javascript +// Code review workflow +mcp__claude-flow__workflow_execute({ + "workflowId": "code-review-process", + "params": { + "reviewers": ["Code Reviewer"], + "criteria": ["security", "performance", "best-practices"] + } +}) + +// CI/CD pipeline +mcp__claude-flow__pipeline_create({ + "config": { + "stages": ["build", "test", "security-scan", "deploy"], + "environment": "production" + } +}) +``` + +### CLI Fallback +```bash +# Quick development swarm +npx claude-flow swarm "build REST API with authentication" \ + --strategy development \ + --mode hierarchical \ + --monitor \ + --output sqlite +``` + +## Pattern 3: Testing Swarm + +### Purpose +Comprehensive quality assurance through distributed testing. + +### Architecture +```javascript +// Initialize testing swarm with star topology +mcp__claude-flow__swarm_init({ + "topology": "star", + "maxAgents": 7, + "strategy": "parallel" +}) + +// Spawn testing team +const testingTeam = [ + { + type: "tester", + name: "Unit Test Coordinator", + capabilities: ["unit-testing", "mocking", "coverage", "tdd"] + }, + { + type: "tester", + name: "Integration Tester", + capabilities: ["integration", "api-testing", "contract-testing"] + }, + { + type: "tester", + name: "E2E Tester", + capabilities: ["e2e", "ui-testing", "user-flows", "selenium"] + }, + { + type: "tester", + name: "Performance Tester", + capabilities: ["load-testing", "stress-testing", "benchmarking"] + }, + { + type: "monitor", + name: "Security Tester", + capabilities: ["security-testing", "penetration-testing", "vulnerability-scanning"] + }, + { + type: "analyst", + name: "Test Analyst", + capabilities: ["coverage-analysis", "test-optimization", "reporting"] + }, + { + type: "documenter", + name: "Test Documenter", + capabilities: ["test-documentation", "test-plans", "reports"] + } +] + +// Spawn all testers +testingTeam.forEach(tester => { + mcp__claude-flow__agent_spawn({ + type: tester.type, + name: tester.name, + capabilities: tester.capabilities, + swarmId: "testing-swarm" + }) +}) +``` + +### Testing Workflow + +#### Phase 1: Test Planning +```javascript +// Analyze test coverage requirements +mcp__claude-flow__quality_assess({ + "target": "test-coverage", + "criteria": [ + "line-coverage", + "branch-coverage", + "function-coverage", + "edge-cases" + ] +}) + +// Identify test scenarios +mcp__claude-flow__pattern_recognize({ + "data": testScenarios, + "patterns": [ + "edge-case", + "boundary-condition", + "error-path", + "happy-path" + ] +}) + +// Store test plan +mcp__claude-flow__memory_usage({ + "action": "store", + "key": "test-plan-" + Date.now(), + "value": JSON.stringify(testPlan), + "namespace": "testing/plans" +}) +``` + +#### Phase 2: Parallel Test Execution +```javascript +// Execute all test suites in parallel +mcp__claude-flow__parallel_execute({ + "tasks": [ + { + "id": "unit-tests", + "command": "npm run test:unit", + "assignTo": "Unit Test Coordinator" + }, + { + "id": "integration-tests", + "command": "npm run test:integration", + "assignTo": "Integration Tester" + }, + { + "id": "e2e-tests", + "command": "npm run test:e2e", + "assignTo": "E2E Tester" + }, + { + "id": "performance-tests", + "command": "npm run test:performance", + "assignTo": "Performance Tester" + }, + { + "id": "security-tests", + "command": "npm run test:security", + "assignTo": "Security Tester" + } + ] +}) + +// Batch process test suites +mcp__claude-flow__batch_process({ + "items": testSuites, + "operation": "execute-test-suite" +}) +``` + +#### Phase 3: Performance and Security +```javascript +// Run performance benchmarks +mcp__claude-flow__benchmark_run({ + "suite": "comprehensive-performance" +}) + +// Bottleneck analysis +mcp__claude-flow__bottleneck_analyze({ + "component": "application", + "metrics": ["response-time", "throughput", "memory", "cpu"] +}) + +// Security scanning +mcp__claude-flow__security_scan({ + "target": "application", + "depth": "comprehensive" +}) + +// Vulnerability analysis +mcp__claude-flow__error_analysis({ + "logs": securityScanLogs +}) +``` + +#### Phase 4: Monitoring and Reporting +```javascript +// Real-time test monitoring +mcp__claude-flow__swarm_monitor({ + "swarmId": "testing-swarm", + "interval": 2000 +}) + +// Generate comprehensive test report +mcp__claude-flow__performance_report({ + "format": "detailed", + "timeframe": "current-run" +}) + +// Get test results +mcp__claude-flow__task_results({ + "taskId": "test-execution-001" +}) + +// Trend analysis +mcp__claude-flow__trend_analysis({ + "metric": "test-coverage", + "period": "30d" +}) +``` + +### CLI Fallback +```bash +# Quick testing swarm +npx claude-flow swarm "test application comprehensively" \ + --strategy testing \ + --mode star \ + --parallel \ + --timeout 600 +``` + +## Pattern 4: Analysis Swarm + +### Purpose +Deep code and system analysis through specialized analyzers. + +### Architecture +```javascript +// Initialize analysis swarm +mcp__claude-flow__swarm_init({ + "topology": "mesh", + "maxAgents": 5, + "strategy": "adaptive" +}) + +// Spawn analysis specialists +const analysisTeam = [ + { + type: "analyst", + name: "Code Analyzer", + capabilities: ["static-analysis", "complexity-analysis", "dead-code-detection"] + }, + { + type: "analyst", + name: "Security Analyzer", + capabilities: ["security-scan", "vulnerability-detection", "dependency-audit"] + }, + { + type: "analyst", + name: "Performance Analyzer", + capabilities: ["profiling", "bottleneck-detection", "optimization"] + }, + { + type: "analyst", + name: "Architecture Analyzer", + capabilities: ["dependency-analysis", "coupling-detection", "modularity-assessment"] + }, + { + type: "documenter", + name: "Analysis Reporter", + capabilities: ["reporting", "visualization", "recommendations"] + } +] + +// Spawn all analysts +analysisTeam.forEach(analyst => { + mcp__claude-flow__agent_spawn({ + type: analyst.type, + name: analyst.name, + capabilities: analyst.capabilities + }) +}) +``` + +### Analysis Workflow +```javascript +// Parallel analysis execution +mcp__claude-flow__parallel_execute({ + "tasks": [ + { "id": "analyze-code", "command": "analyze codebase structure and quality" }, + { "id": "analyze-security", "command": "scan for security vulnerabilities" }, + { "id": "analyze-performance", "command": "identify performance bottlenecks" }, + { "id": "analyze-architecture", "command": "assess architectural patterns" } + ] +}) + +// Generate comprehensive analysis report +mcp__claude-flow__performance_report({ + "format": "detailed", + "timeframe": "current" +}) + +// Cost analysis +mcp__claude-flow__cost_analysis({ + "timeframe": "30d" +}) +``` + +## Advanced Techniques + +### Error Handling and Fault Tolerance + +```javascript +// Setup fault tolerance for all agents +mcp__claude-flow__daa_fault_tolerance({ + "agentId": "all", + "strategy": "auto-recovery" +}) + +// Error handling pattern +try { + await mcp__claude-flow__task_orchestrate({ + "task": "complex operation", + "strategy": "parallel", + "priority": "high" + }) +} catch (error) { + // Check swarm health + const status = await mcp__claude-flow__swarm_status({}) + + // Analyze error patterns + await mcp__claude-flow__error_analysis({ + "logs": [error.message] + }) + + // Auto-recovery attempt + if (status.healthy) { + await mcp__claude-flow__task_orchestrate({ + "task": "retry failed operation", + "strategy": "sequential" + }) + } +} +``` + +### Memory and State Management + +```javascript +// Cross-session persistence +mcp__claude-flow__memory_persist({ + "sessionId": "swarm-session-001" +}) + +// Namespace management for different swarms +mcp__claude-flow__memory_namespace({ + "namespace": "research-swarm", + "action": "create" +}) + +// Create state snapshot +mcp__claude-flow__state_snapshot({ + "name": "development-checkpoint-1" +}) + +// Restore from snapshot if needed +mcp__claude-flow__context_restore({ + "snapshotId": "development-checkpoint-1" +}) + +// Backup memory stores +mcp__claude-flow__memory_backup({ + "path": "/workspaces/claude-code-flow/backups/swarm-memory.json" +}) +``` + +### Neural Pattern Learning + +```javascript +// Train neural patterns from successful workflows +mcp__claude-flow__neural_train({ + "pattern_type": "coordination", + "training_data": JSON.stringify(successfulWorkflows), + "epochs": 50 +}) + +// Adaptive learning from experience +mcp__claude-flow__learning_adapt({ + "experience": { + "workflow": "research-to-report", + "success": true, + "duration": 3600, + "quality": 0.95 + } +}) + +// Pattern recognition for optimization +mcp__claude-flow__pattern_recognize({ + "data": workflowMetrics, + "patterns": ["bottleneck", "optimization-opportunity", "efficiency-gain"] +}) +``` + +### Workflow Automation + +```javascript +// Create reusable workflow +mcp__claude-flow__workflow_create({ + "name": "full-stack-development", + "steps": [ + { "phase": "design", "agents": ["architect"] }, + { "phase": "implement", "agents": ["backend-dev", "frontend-dev"], "parallel": true }, + { "phase": "test", "agents": ["tester", "security-tester"], "parallel": true }, + { "phase": "review", "agents": ["reviewer"] }, + { "phase": "deploy", "agents": ["devops"] } + ], + "triggers": ["on-commit", "scheduled-daily"] +}) + +// Setup automation rules +mcp__claude-flow__automation_setup({ + "rules": [ + { + "trigger": "file-changed", + "pattern": "*.js", + "action": "run-tests" + }, + { + "trigger": "PR-created", + "action": "code-review-swarm" + } + ] +}) + +// Event-driven triggers +mcp__claude-flow__trigger_setup({ + "events": ["code-commit", "PR-merge", "deployment"], + "actions": ["test", "analyze", "document"] +}) +``` + +### Performance Optimization + +```javascript +// Topology optimization +mcp__claude-flow__topology_optimize({ + "swarmId": "current-swarm" +}) + +// Load balancing +mcp__claude-flow__load_balance({ + "swarmId": "development-swarm", + "tasks": taskQueue +}) + +// Agent coordination sync +mcp__claude-flow__coordination_sync({ + "swarmId": "development-swarm" +}) + +// Auto-scaling +mcp__claude-flow__swarm_scale({ + "swarmId": "development-swarm", + "targetSize": 12 +}) +``` + +### Monitoring and Metrics + +```javascript +// Real-time swarm monitoring +mcp__claude-flow__swarm_monitor({ + "swarmId": "active-swarm", + "interval": 3000 +}) + +// Collect comprehensive metrics +mcp__claude-flow__metrics_collect({ + "components": ["agents", "tasks", "memory", "performance"] +}) + +// Health monitoring +mcp__claude-flow__health_check({ + "components": ["swarm", "agents", "neural", "memory"] +}) + +// Usage statistics +mcp__claude-flow__usage_stats({ + "component": "swarm-orchestration" +}) + +// Trend analysis +mcp__claude-flow__trend_analysis({ + "metric": "agent-performance", + "period": "7d" +}) +``` + +## Best Practices + +### 1. Choosing the Right Topology + +- **Mesh**: Research, brainstorming, collaborative analysis +- **Hierarchical**: Structured development, sequential workflows +- **Star**: Testing, validation, centralized coordination +- **Ring**: Pipeline processing, staged workflows + +### 2. Agent Specialization + +- Assign specific capabilities to each agent +- Avoid overlapping responsibilities +- Use coordination agents for complex workflows +- Leverage memory for agent communication + +### 3. Parallel Execution + +- Identify independent tasks for parallelization +- Use sequential execution for dependent tasks +- Monitor resource usage during parallel execution +- Implement proper error handling + +### 4. Memory Management + +- Use namespaces to organize memory +- Set appropriate TTL values +- Create regular backups +- Implement state snapshots for checkpoints + +### 5. Monitoring and Optimization + +- Monitor swarm health regularly +- Collect and analyze metrics +- Optimize topology based on performance +- Use neural patterns to learn from success + +### 6. Error Recovery + +- Implement fault tolerance strategies +- Use auto-recovery mechanisms +- Analyze error patterns +- Create fallback workflows + +## Real-World Examples + +### Example 1: AI Research Project +```javascript +// Research AI trends, analyze findings, generate report +mcp__claude-flow__swarm_init({ topology: "mesh", maxAgents: 6 }) +// Spawn: 2 researchers, 2 analysts, 1 synthesizer, 1 documenter +// Parallel gather โ†’ Analyze patterns โ†’ Synthesize โ†’ Report +``` + +### Example 2: Full-Stack Application +```javascript +// Build complete web application with testing +mcp__claude-flow__swarm_init({ topology: "hierarchical", maxAgents: 8 }) +// Spawn: 1 architect, 2 devs, 1 db engineer, 2 testers, 1 reviewer, 1 devops +// Design โ†’ Parallel implement โ†’ Test โ†’ Review โ†’ Deploy +``` + +### Example 3: Security Audit +```javascript +// Comprehensive security analysis +mcp__claude-flow__swarm_init({ topology: "star", maxAgents: 5 }) +// Spawn: 1 coordinator, 1 code analyzer, 1 security scanner, 1 penetration tester, 1 reporter +// Parallel scan โ†’ Vulnerability analysis โ†’ Penetration test โ†’ Report +``` + +### Example 4: Performance Optimization +```javascript +// Identify and fix performance bottlenecks +mcp__claude-flow__swarm_init({ topology: "mesh", maxAgents: 4 }) +// Spawn: 1 profiler, 1 bottleneck analyzer, 1 optimizer, 1 tester +// Profile โ†’ Identify bottlenecks โ†’ Optimize โ†’ Validate +``` + +## Troubleshooting + +### Common Issues + +**Issue**: Swarm agents not coordinating properly +**Solution**: Check topology selection, verify memory usage, enable monitoring + +**Issue**: Parallel execution failing +**Solution**: Verify task dependencies, check resource limits, implement error handling + +**Issue**: Memory persistence not working +**Solution**: Verify namespaces, check TTL settings, ensure backup configuration + +**Issue**: Performance degradation +**Solution**: Optimize topology, reduce agent count, analyze bottlenecks + +## Related Skills + +- `sparc-methodology` - Systematic development workflow +- `github-integration` - Repository management and automation +- `neural-patterns` - AI-powered coordination optimization +- `memory-management` - Cross-session state persistence + +## References + +- [Claude Flow Documentation](https://github.com/ruvnet/claude-flow) +- [Swarm Orchestration Guide](https://github.com/ruvnet/claude-flow/wiki/swarm) +- [MCP Tools Reference](https://github.com/ruvnet/claude-flow/wiki/mcp) +- [Performance Optimization](https://github.com/ruvnet/claude-flow/wiki/performance) + +--- + +**Version**: 2.0.0 +**Last Updated**: 2025-10-19 +**Skill Level**: Advanced +**Estimated Learning Time**: 2-3 hours diff --git a/.claude/skills/swarm-orchestration/SKILL.md b/.claude/skills/swarm-orchestration/SKILL.md new file mode 100644 index 0000000000..b4f735ca58 --- /dev/null +++ b/.claude/skills/swarm-orchestration/SKILL.md @@ -0,0 +1,179 @@ +--- +name: "Swarm Orchestration" +description: "Orchestrate multi-agent swarms with agentic-flow for parallel task execution, dynamic topology, and intelligent coordination. Use when scaling beyond single agents, implementing complex workflows, or building distributed AI systems." +--- + +# Swarm Orchestration + +## What This Skill Does + +Orchestrates multi-agent swarms using agentic-flow's advanced coordination system. Supports mesh, hierarchical, and adaptive topologies with automatic task distribution, load balancing, and fault tolerance. + +## Prerequisites + +- agentic-flow v1.5.11+ +- Node.js 18+ +- Understanding of distributed systems (helpful) + +## Quick Start + +```bash +# Initialize swarm +npx agentic-flow hooks swarm-init --topology mesh --max-agents 5 + +# Spawn agents +npx agentic-flow hooks agent-spawn --type coder +npx agentic-flow hooks agent-spawn --type tester +npx agentic-flow hooks agent-spawn --type reviewer + +# Orchestrate task +npx agentic-flow hooks task-orchestrate \ + --task "Build REST API with tests" \ + --mode parallel +``` + +## Topology Patterns + +### 1. Mesh (Peer-to-Peer) +```typescript +// Equal peers, distributed decision-making +await swarm.init({ + topology: 'mesh', + agents: ['coder', 'tester', 'reviewer'], + communication: 'broadcast' +}); +``` + +### 2. Hierarchical (Queen-Worker) +```typescript +// Centralized coordination, specialized workers +await swarm.init({ + topology: 'hierarchical', + queen: 'architect', + workers: ['backend-dev', 'frontend-dev', 'db-designer'] +}); +``` + +### 3. Adaptive (Dynamic) +```typescript +// Automatically switches topology based on task +await swarm.init({ + topology: 'adaptive', + optimization: 'task-complexity' +}); +``` + +## Task Orchestration + +### Parallel Execution +```typescript +// Execute tasks concurrently +const results = await swarm.execute({ + tasks: [ + { agent: 'coder', task: 'Implement API endpoints' }, + { agent: 'frontend', task: 'Build UI components' }, + { agent: 'tester', task: 'Write test suite' } + ], + mode: 'parallel', + timeout: 300000 // 5 minutes +}); +``` + +### Pipeline Execution +```typescript +// Sequential pipeline with dependencies +await swarm.pipeline([ + { stage: 'design', agent: 'architect' }, + { stage: 'implement', agent: 'coder', after: 'design' }, + { stage: 'test', agent: 'tester', after: 'implement' }, + { stage: 'review', agent: 'reviewer', after: 'test' } +]); +``` + +### Adaptive Execution +```typescript +// Let swarm decide execution strategy +await swarm.autoOrchestrate({ + goal: 'Build production-ready API', + constraints: { + maxTime: 3600, + maxAgents: 8, + quality: 'high' + } +}); +``` + +## Memory Coordination + +```typescript +// Share state across swarm +await swarm.memory.store('api-schema', { + endpoints: [...], + models: [...] +}); + +// Agents read shared memory +const schema = await swarm.memory.retrieve('api-schema'); +``` + +## Advanced Features + +### Load Balancing +```typescript +// Automatic work distribution +await swarm.enableLoadBalancing({ + strategy: 'dynamic', + metrics: ['cpu', 'memory', 'task-queue'] +}); +``` + +### Fault Tolerance +```typescript +// Handle agent failures +await swarm.setResiliency({ + retry: { maxAttempts: 3, backoff: 'exponential' }, + fallback: 'reassign-task' +}); +``` + +### Performance Monitoring +```typescript +// Track swarm metrics +const metrics = await swarm.getMetrics(); +// { throughput, latency, success_rate, agent_utilization } +``` + +## Integration with Hooks + +```bash +# Pre-task coordination +npx agentic-flow hooks pre-task --description "Build API" + +# Post-task synchronization +npx agentic-flow hooks post-task --task-id "task-123" + +# Session restore +npx agentic-flow hooks session-restore --session-id "swarm-001" +``` + +## Best Practices + +1. **Start small**: Begin with 2-3 agents, scale up +2. **Use memory**: Share context through swarm memory +3. **Monitor metrics**: Track performance and bottlenecks +4. **Enable hooks**: Automatic coordination and sync +5. **Set timeouts**: Prevent hung tasks + +## Troubleshooting + +### Issue: Agents not coordinating +**Solution**: Verify memory access and enable hooks + +### Issue: Poor performance +**Solution**: Check topology (use adaptive) and enable load balancing + +## Learn More + +- Swarm Guide: docs/swarm/orchestration.md +- Topology Patterns: docs/swarm/topologies.md +- Hooks Integration: docs/hooks/coordination.md diff --git a/.claude/skills/things-mac/SKILL.md b/.claude/skills/things-mac/SKILL.md new file mode 100644 index 0000000000..069d3ee856 --- /dev/null +++ b/.claude/skills/things-mac/SKILL.md @@ -0,0 +1,61 @@ +--- +name: things-mac +description: Manage Things 3 via the `things` CLI on macOS (add/update projects+todos via URL scheme; read/search/list from the local Things database). Use when a user asks Zee to add a task to Things, list inbox/today/upcoming, search tasks, or inspect projects/areas/tags. +homepage: https://github.com/ossianhempel/things3-cli +metadata: {"zee":{"emoji":"โœ…","os":["darwin"],"requires":{"bins":["things"]},"install":[{"id":"go","kind":"go","module":"github.com/ossianhempel/things3-cli/cmd/things@latest","bins":["things"],"label":"Install things3-cli (go)"}]}} +--- + +# Things 3 CLI + +Use `things` to read your local Things database (inbox/today/search/projects/areas/tags) and to add/update todos via the Things URL scheme. + +Setup +- Install (recommended, Apple Silicon): `GOBIN=/opt/homebrew/bin go install github.com/ossianhempel/things3-cli/cmd/things@latest` +- If DB reads fail: grant **Full Disk Access** to the calling app (Terminal for manual runs; `Zee.app` for gateway runs). +- Optional: set `THINGSDB` (or pass `--db`) to point at your `ThingsData-*` folder. +- Optional: set `THINGS_AUTH_TOKEN` to avoid passing `--auth-token` for update ops. + +Read-only (DB) +- `things inbox --limit 50` +- `things today` +- `things upcoming` +- `things search "query"` +- `things projects` / `things areas` / `things tags` + +Write (URL scheme) +- Prefer safe preview: `things --dry-run add "Title"` +- Add: `things add "Title" --notes "..." --when today --deadline 2026-01-02` +- Bring Things to front: `things --foreground add "Title"` + +Examples: add a todo +- Basic: `things add "Buy milk"` +- With notes: `things add "Buy milk" --notes "2% + bananas"` +- Into a project/area: `things add "Book flights" --list "Travel"` +- Into a project heading: `things add "Pack charger" --list "Travel" --heading "Before"` +- With tags: `things add "Call dentist" --tags "health,phone"` +- Checklist: `things add "Trip prep" --checklist-item "Passport" --checklist-item "Tickets"` +- From STDIN (multi-line => title + notes): + - `cat <<'EOF' | things add -` + - `Title line` + - `Notes line 1` + - `Notes line 2` + - `EOF` + +Examples: modify a todo (needs auth token) +- First: get the ID (UUID column): `things search "milk" --limit 5` +- Auth: set `THINGS_AUTH_TOKEN` or pass `--auth-token ` +- Title: `things update --id --auth-token "New title"` +- Notes replace: `things update --id --auth-token --notes "New notes"` +- Notes append/prepend: `things update --id --auth-token --append-notes "..."` / `--prepend-notes "..."` +- Move lists: `things update --id --auth-token --list "Travel" --heading "Before"` +- Tags replace/add: `things update --id --auth-token --tags "a,b"` / `things update --id --auth-token --add-tags "a,b"` +- Complete/cancel (soft-delete-ish): `things update --id --auth-token --completed` / `--canceled` +- Safe preview: `things --dry-run update --id --auth-token --completed` + +Delete a todo? +- Not supported by `things3-cli` right now (no โ€œdelete/move-to-trashโ€ write command; `things trash` is read-only listing). +- Options: use Things UI to delete/trash, or mark as `--completed` / `--canceled` via `things update`. + +Notes +- macOS-only. +- `--dry-run` prints the URL and does not open Things. diff --git a/.claude/skills/tmux/SKILL.md b/.claude/skills/tmux/SKILL.md new file mode 100644 index 0000000000..197c6c773b --- /dev/null +++ b/.claude/skills/tmux/SKILL.md @@ -0,0 +1,121 @@ +--- +name: tmux +description: Remote-control tmux sessions for interactive CLIs by sending keystrokes and scraping pane output. +metadata: {"zee":{"emoji":"๐Ÿงต","os":["darwin","linux"],"requires":{"bins":["tmux"]}}} +--- + +# tmux Skill (Zee) + +Use tmux only when you need an interactive TTY. Prefer bash background mode for long-running, non-interactive tasks. + +## Quickstart (isolated socket, bash tool) + +```bash +SOCKET_DIR="${ZEE_TMUX_SOCKET_DIR:-${TMPDIR:-/tmp}/zee-tmux-sockets}" +mkdir -p "$SOCKET_DIR" +SOCKET="$SOCKET_DIR/zee.sock" +SESSION=zee-python + +tmux -S "$SOCKET" new -d -s "$SESSION" -n shell +tmux -S "$SOCKET" send-keys -t "$SESSION":0.0 -- 'PYTHON_BASIC_REPL=1 python3 -q' Enter +tmux -S "$SOCKET" capture-pane -p -J -t "$SESSION":0.0 -S -200 +``` + +After starting a session, always print monitor commands: + +``` +To monitor: + tmux -S "$SOCKET" attach -t "$SESSION" + tmux -S "$SOCKET" capture-pane -p -J -t "$SESSION":0.0 -S -200 +``` + +## Socket convention + +- Use `ZEE_TMUX_SOCKET_DIR` (default `${TMPDIR:-/tmp}/zee-tmux-sockets`). +- Default socket path: `"$ZEE_TMUX_SOCKET_DIR/zee.sock"`. + +## Targeting panes and naming + +- Target format: `session:window.pane` (defaults to `:0.0`). +- Keep names short; avoid spaces. +- Inspect: `tmux -S "$SOCKET" list-sessions`, `tmux -S "$SOCKET" list-panes -a`. + +## Finding sessions + +- List sessions on your socket: `{baseDir}/scripts/find-sessions.sh -S "$SOCKET"`. +- Scan all sockets: `{baseDir}/scripts/find-sessions.sh --all` (uses `ZEE_TMUX_SOCKET_DIR`). + +## Sending input safely + +- Prefer literal sends: `tmux -S "$SOCKET" send-keys -t target -l -- "$cmd"`. +- Control keys: `tmux -S "$SOCKET" send-keys -t target C-c`. + +## Watching output + +- Capture recent history: `tmux -S "$SOCKET" capture-pane -p -J -t target -S -200`. +- Wait for prompts: `{baseDir}/scripts/wait-for-text.sh -t session:0.0 -p 'pattern'`. +- Attaching is OK; detach with `Ctrl+b d`. + +## Spawning processes + +- For python REPLs, set `PYTHON_BASIC_REPL=1` (non-basic REPL breaks send-keys flows). + +## Windows / WSL + +- tmux is supported on macOS/Linux. On Windows, use WSL and install tmux inside WSL. +- This skill is gated to `darwin`/`linux` and requires `tmux` on PATH. + +## Orchestrating Coding Agents (Codex, Claude Code) + +tmux excels at running multiple coding agents in parallel: + +```bash +SOCKET="${TMPDIR:-/tmp}/codex-army.sock" + +# Create multiple sessions +for i in 1 2 3 4 5; do + tmux -S "$SOCKET" new-session -d -s "agent-$i" +done + +# Launch agents in different workdirs +tmux -S "$SOCKET" send-keys -t agent-1 "cd /tmp/project1 && codex --yolo 'Fix bug X'" Enter +tmux -S "$SOCKET" send-keys -t agent-2 "cd /tmp/project2 && codex --yolo 'Fix bug Y'" Enter + +# Poll for completion (check if prompt returned) +for sess in agent-1 agent-2; do + if tmux -S "$SOCKET" capture-pane -p -t "$sess" -S -3 | grep -q "โฏ"; then + echo "$sess: DONE" + else + echo "$sess: Running..." + fi +done + +# Get full output from completed session +tmux -S "$SOCKET" capture-pane -p -t agent-1 -S -500 +``` + +**Tips:** +- Use separate git worktrees for parallel fixes (no branch conflicts) +- `pnpm install` first before running codex in fresh clones +- Check for shell prompt (`โฏ` or `$`) to detect completion +- Codex needs `--yolo` or `--full-auto` for non-interactive fixes + +## Cleanup + +- Kill a session: `tmux -S "$SOCKET" kill-session -t "$SESSION"`. +- Kill all sessions on a socket: `tmux -S "$SOCKET" list-sessions -F '#{session_name}' | xargs -r -n1 tmux -S "$SOCKET" kill-session -t`. +- Remove everything on the private socket: `tmux -S "$SOCKET" kill-server`. + +## Helper: wait-for-text.sh + +`{baseDir}/scripts/wait-for-text.sh` polls a pane for a regex (or fixed string) with a timeout. + +```bash +{baseDir}/scripts/wait-for-text.sh -t session:0.0 -p 'pattern' [-F] [-T 20] [-i 0.5] [-l 2000] +``` + +- `-t`/`--target` pane target (required) +- `-p`/`--pattern` regex to match (required); add `-F` for fixed string +- `-T` timeout seconds (integer, default 15) +- `-i` poll interval seconds (default 0.5) +- `-l` history lines to search (integer, default 1000) diff --git a/.claude/skills/tmux/scripts/find-sessions.sh b/.claude/skills/tmux/scripts/find-sessions.sh new file mode 100755 index 0000000000..7fbba2adbf --- /dev/null +++ b/.claude/skills/tmux/scripts/find-sessions.sh @@ -0,0 +1,112 @@ +#!/usr/bin/env bash +set -euo pipefail + +usage() { + cat <<'USAGE' +Usage: find-sessions.sh [-L socket-name|-S socket-path|-A] [-q pattern] + +List tmux sessions on a socket (default tmux socket if none provided). + +Options: + -L, --socket tmux socket name (passed to tmux -L) + -S, --socket-path tmux socket path (passed to tmux -S) + -A, --all scan all sockets under CLAWDBOT_TMUX_SOCKET_DIR + -q, --query case-insensitive substring to filter session names + -h, --help show this help +USAGE +} + +socket_name="" +socket_path="" +query="" +scan_all=false +socket_dir="${CLAWDBOT_TMUX_SOCKET_DIR:-${TMPDIR:-/tmp}/clawdbot-tmux-sockets}" + +while [[ $# -gt 0 ]]; do + case "$1" in + -L|--socket) socket_name="${2-}"; shift 2 ;; + -S|--socket-path) socket_path="${2-}"; shift 2 ;; + -A|--all) scan_all=true; shift ;; + -q|--query) query="${2-}"; shift 2 ;; + -h|--help) usage; exit 0 ;; + *) echo "Unknown option: $1" >&2; usage; exit 1 ;; + esac +done + +if [[ "$scan_all" == true && ( -n "$socket_name" || -n "$socket_path" ) ]]; then + echo "Cannot combine --all with -L or -S" >&2 + exit 1 +fi + +if [[ -n "$socket_name" && -n "$socket_path" ]]; then + echo "Use either -L or -S, not both" >&2 + exit 1 +fi + +if ! command -v tmux >/dev/null 2>&1; then + echo "tmux not found in PATH" >&2 + exit 1 +fi + +list_sessions() { + local label="$1"; shift + local tmux_cmd=(tmux "$@") + + if ! sessions="$("${tmux_cmd[@]}" list-sessions -F '#{session_name}\t#{session_attached}\t#{session_created_string}' 2>/dev/null)"; then + echo "No tmux server found on $label" >&2 + return 1 + fi + + if [[ -n "$query" ]]; then + sessions="$(printf '%s\n' "$sessions" | grep -i -- "$query" || true)" + fi + + if [[ -z "$sessions" ]]; then + echo "No sessions found on $label" + return 0 + fi + + echo "Sessions on $label:" + printf '%s\n' "$sessions" | while IFS=$'\t' read -r name attached created; do + attached_label=$([[ "$attached" == "1" ]] && echo "attached" || echo "detached") + printf ' - %s (%s, started %s)\n' "$name" "$attached_label" "$created" + done +} + +if [[ "$scan_all" == true ]]; then + if [[ ! -d "$socket_dir" ]]; then + echo "Socket directory not found: $socket_dir" >&2 + exit 1 + fi + + shopt -s nullglob + sockets=("$socket_dir"/*) + shopt -u nullglob + + if [[ "${#sockets[@]}" -eq 0 ]]; then + echo "No sockets found under $socket_dir" >&2 + exit 1 + fi + + exit_code=0 + for sock in "${sockets[@]}"; do + if [[ ! -S "$sock" ]]; then + continue + fi + list_sessions "socket path '$sock'" -S "$sock" || exit_code=$? + done + exit "$exit_code" +fi + +tmux_cmd=(tmux) +socket_label="default socket" + +if [[ -n "$socket_name" ]]; then + tmux_cmd+=(-L "$socket_name") + socket_label="socket name '$socket_name'" +elif [[ -n "$socket_path" ]]; then + tmux_cmd+=(-S "$socket_path") + socket_label="socket path '$socket_path'" +fi + +list_sessions "$socket_label" "${tmux_cmd[@]:1}" diff --git a/.claude/skills/tmux/scripts/wait-for-text.sh b/.claude/skills/tmux/scripts/wait-for-text.sh new file mode 100755 index 0000000000..56354be835 --- /dev/null +++ b/.claude/skills/tmux/scripts/wait-for-text.sh @@ -0,0 +1,83 @@ +#!/usr/bin/env bash +set -euo pipefail + +usage() { + cat <<'USAGE' +Usage: wait-for-text.sh -t target -p pattern [options] + +Poll a tmux pane for text and exit when found. + +Options: + -t, --target tmux target (session:window.pane), required + -p, --pattern regex pattern to look for, required + -F, --fixed treat pattern as a fixed string (grep -F) + -T, --timeout seconds to wait (integer, default: 15) + -i, --interval poll interval in seconds (default: 0.5) + -l, --lines number of history lines to inspect (integer, default: 1000) + -h, --help show this help +USAGE +} + +target="" +pattern="" +grep_flag="-E" +timeout=15 +interval=0.5 +lines=1000 + +while [[ $# -gt 0 ]]; do + case "$1" in + -t|--target) target="${2-}"; shift 2 ;; + -p|--pattern) pattern="${2-}"; shift 2 ;; + -F|--fixed) grep_flag="-F"; shift ;; + -T|--timeout) timeout="${2-}"; shift 2 ;; + -i|--interval) interval="${2-}"; shift 2 ;; + -l|--lines) lines="${2-}"; shift 2 ;; + -h|--help) usage; exit 0 ;; + *) echo "Unknown option: $1" >&2; usage; exit 1 ;; + esac +done + +if [[ -z "$target" || -z "$pattern" ]]; then + echo "target and pattern are required" >&2 + usage + exit 1 +fi + +if ! [[ "$timeout" =~ ^[0-9]+$ ]]; then + echo "timeout must be an integer number of seconds" >&2 + exit 1 +fi + +if ! [[ "$lines" =~ ^[0-9]+$ ]]; then + echo "lines must be an integer" >&2 + exit 1 +fi + +if ! command -v tmux >/dev/null 2>&1; then + echo "tmux not found in PATH" >&2 + exit 1 +fi + +# End time in epoch seconds (integer, good enough for polling) +start_epoch=$(date +%s) +deadline=$((start_epoch + timeout)) + +while true; do + # -J joins wrapped lines, -S uses negative index to read last N lines + pane_text="$(tmux capture-pane -p -J -t "$target" -S "-${lines}" 2>/dev/null || true)" + + if printf '%s\n' "$pane_text" | grep $grep_flag -- "$pattern" >/dev/null 2>&1; then + exit 0 + fi + + now=$(date +%s) + if (( now >= deadline )); then + echo "Timed out after ${timeout}s waiting for pattern: $pattern" >&2 + echo "Last ${lines} lines from $target:" >&2 + printf '%s\n' "$pane_text" >&2 + exit 1 + fi + + sleep "$interval" +done diff --git a/.claude/skills/trello/SKILL.md b/.claude/skills/trello/SKILL.md new file mode 100644 index 0000000000..3fd0b76b33 --- /dev/null +++ b/.claude/skills/trello/SKILL.md @@ -0,0 +1,84 @@ +--- +name: trello +description: Manage Trello boards, lists, and cards via the Trello REST API. +homepage: https://developer.atlassian.com/cloud/trello/rest/ +metadata: {"zee":{"emoji":"๐Ÿ“‹","requires":{"bins":["jq"],"env":["TRELLO_API_KEY","TRELLO_TOKEN"]}}} +--- + +# Trello Skill + +Manage Trello boards, lists, and cards directly from Zee. + +## Setup + +1. Get your API key: https://trello.com/app-key +2. Generate a token (click "Token" link on that page) +3. Set environment variables: + ```bash + export TRELLO_API_KEY="your-api-key" + export TRELLO_TOKEN="your-token" + ``` + +## Usage + +All commands use curl to hit the Trello REST API. + +### List boards +```bash +curl -s "https://api.trello.com/1/members/me/boards?key=$TRELLO_API_KEY&token=$TRELLO_TOKEN" | jq '.[] | {name, id}' +``` + +### List lists in a board +```bash +curl -s "https://api.trello.com/1/boards/{boardId}/lists?key=$TRELLO_API_KEY&token=$TRELLO_TOKEN" | jq '.[] | {name, id}' +``` + +### List cards in a list +```bash +curl -s "https://api.trello.com/1/lists/{listId}/cards?key=$TRELLO_API_KEY&token=$TRELLO_TOKEN" | jq '.[] | {name, id, desc}' +``` + +### Create a card +```bash +curl -s -X POST "https://api.trello.com/1/cards?key=$TRELLO_API_KEY&token=$TRELLO_TOKEN" \ + -d "idList={listId}" \ + -d "name=Card Title" \ + -d "desc=Card description" +``` + +### Move a card to another list +```bash +curl -s -X PUT "https://api.trello.com/1/cards/{cardId}?key=$TRELLO_API_KEY&token=$TRELLO_TOKEN" \ + -d "idList={newListId}" +``` + +### Add a comment to a card +```bash +curl -s -X POST "https://api.trello.com/1/cards/{cardId}/actions/comments?key=$TRELLO_API_KEY&token=$TRELLO_TOKEN" \ + -d "text=Your comment here" +``` + +### Archive a card +```bash +curl -s -X PUT "https://api.trello.com/1/cards/{cardId}?key=$TRELLO_API_KEY&token=$TRELLO_TOKEN" \ + -d "closed=true" +``` + +## Notes + +- Board/List/Card IDs can be found in the Trello URL or via the list commands +- The API key and token provide full access to your Trello account - keep them secret! +- Rate limits: 300 requests per 10 seconds per API key; 100 requests per 10 seconds per token; `/1/members` endpoints are limited to 100 requests per 900 seconds + +## Examples + +```bash +# Get all boards +curl -s "https://api.trello.com/1/members/me/boards?key=$TRELLO_API_KEY&token=$TRELLO_TOKEN&fields=name,id" | jq + +# Find a specific board by name +curl -s "https://api.trello.com/1/members/me/boards?key=$TRELLO_API_KEY&token=$TRELLO_TOKEN" | jq '.[] | select(.name | contains("Work"))' + +# Get all cards on a board +curl -s "https://api.trello.com/1/boards/{boardId}/cards?key=$TRELLO_API_KEY&token=$TRELLO_TOKEN" | jq '.[] | {name, list: .idList}' +``` diff --git a/.claude/skills/verification-quality/SKILL.md b/.claude/skills/verification-quality/SKILL.md new file mode 100644 index 0000000000..567b0920cf --- /dev/null +++ b/.claude/skills/verification-quality/SKILL.md @@ -0,0 +1,649 @@ +--- +name: "Verification & Quality Assurance" +description: "Comprehensive truth scoring, code quality verification, and automatic rollback system with 0.95 accuracy threshold for ensuring high-quality agent outputs and codebase reliability." +version: "2.0.0" +category: "quality-assurance" +tags: ["verification", "truth-scoring", "quality", "rollback", "metrics", "ci-cd"] +--- + +# Verification & Quality Assurance Skill + +## What This Skill Does + +This skill provides a comprehensive verification and quality assurance system that ensures code quality and correctness through: + +- **Truth Scoring**: Real-time reliability metrics (0.0-1.0 scale) for code, agents, and tasks +- **Verification Checks**: Automated code correctness, security, and best practices validation +- **Automatic Rollback**: Instant reversion of changes that fail verification (default threshold: 0.95) +- **Quality Metrics**: Statistical analysis with trends, confidence intervals, and improvement tracking +- **CI/CD Integration**: Export capabilities for continuous integration pipelines +- **Real-time Monitoring**: Live dashboards and watch modes for ongoing verification + +## Prerequisites + +- Claude Flow installed (`npx claude-flow@alpha`) +- Git repository (for rollback features) +- Node.js 18+ (for dashboard features) + +## Quick Start + +```bash +# View current truth scores +npx claude-flow@alpha truth + +# Run verification check +npx claude-flow@alpha verify check + +# Verify specific file with custom threshold +npx claude-flow@alpha verify check --file src/app.js --threshold 0.98 + +# Rollback last failed verification +npx claude-flow@alpha verify rollback --last-good +``` + +--- + +## Complete Guide + +### Truth Scoring System + +#### View Truth Metrics + +Display comprehensive quality and reliability metrics for your codebase and agent tasks. + +**Basic Usage:** +```bash +# View current truth scores (default: table format) +npx claude-flow@alpha truth + +# View scores for specific time period +npx claude-flow@alpha truth --period 7d + +# View scores for specific agent +npx claude-flow@alpha truth --agent coder --period 24h + +# Find files/tasks below threshold +npx claude-flow@alpha truth --threshold 0.8 +``` + +**Output Formats:** +```bash +# Table format (default) +npx claude-flow@alpha truth --format table + +# JSON for programmatic access +npx claude-flow@alpha truth --format json + +# CSV for spreadsheet analysis +npx claude-flow@alpha truth --format csv + +# HTML report with visualizations +npx claude-flow@alpha truth --format html --export report.html +``` + +**Real-time Monitoring:** +```bash +# Watch mode with live updates +npx claude-flow@alpha truth --watch + +# Export metrics automatically +npx claude-flow@alpha truth --export .claude-flow/metrics/truth-$(date +%Y%m%d).json +``` + +#### Truth Score Dashboard + +Example dashboard output: +``` +๐Ÿ“Š Truth Metrics Dashboard +โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ” + +Overall Truth Score: 0.947 โœ… +Trend: โ†—๏ธ +2.3% (7d) + +Top Performers: + verification-agent 0.982 โญ + code-analyzer 0.971 โญ + test-generator 0.958 โœ… + +Needs Attention: + refactor-agent 0.821 โš ๏ธ + docs-generator 0.794 โš ๏ธ + +Recent Tasks: + task-456 0.991 โœ… "Implement auth" + task-455 0.967 โœ… "Add tests" + task-454 0.743 โŒ "Refactor API" +``` + +#### Metrics Explained + +**Truth Scores (0.0-1.0):** +- `1.0-0.95`: Excellent โญ (production-ready) +- `0.94-0.85`: Good โœ… (acceptable quality) +- `0.84-0.75`: Warning โš ๏ธ (needs attention) +- `<0.75`: Critical โŒ (requires immediate action) + +**Trend Indicators:** +- โ†—๏ธ Improving (positive trend) +- โ†’ Stable (consistent performance) +- โ†˜๏ธ Declining (quality regression detected) + +**Statistics:** +- **Mean Score**: Average truth score across all measurements +- **Median Score**: Middle value (less affected by outliers) +- **Standard Deviation**: Consistency of scores (lower = more consistent) +- **Confidence Interval**: Statistical reliability of measurements + +### Verification Checks + +#### Run Verification + +Execute comprehensive verification checks on code, tasks, or agent outputs. + +**File Verification:** +```bash +# Verify single file +npx claude-flow@alpha verify check --file src/app.js + +# Verify directory recursively +npx claude-flow@alpha verify check --directory src/ + +# Verify with auto-fix enabled +npx claude-flow@alpha verify check --file src/utils.js --auto-fix + +# Verify current working directory +npx claude-flow@alpha verify check +``` + +**Task Verification:** +```bash +# Verify specific task output +npx claude-flow@alpha verify check --task task-123 + +# Verify with custom threshold +npx claude-flow@alpha verify check --task task-456 --threshold 0.99 + +# Verbose output for debugging +npx claude-flow@alpha verify check --task task-789 --verbose +``` + +**Batch Verification:** +```bash +# Verify multiple files in parallel +npx claude-flow@alpha verify batch --files "*.js" --parallel + +# Verify with pattern matching +npx claude-flow@alpha verify batch --pattern "src/**/*.ts" + +# Integration test suite +npx claude-flow@alpha verify integration --test-suite full +``` + +#### Verification Criteria + +The verification system evaluates: + +1. **Code Correctness** + - Syntax validation + - Type checking (TypeScript) + - Logic flow analysis + - Error handling completeness + +2. **Best Practices** + - Code style adherence + - SOLID principles + - Design patterns usage + - Modularity and reusability + +3. **Security** + - Vulnerability scanning + - Secret detection + - Input validation + - Authentication/authorization checks + +4. **Performance** + - Algorithmic complexity + - Memory usage patterns + - Database query optimization + - Bundle size impact + +5. **Documentation** + - JSDoc/TypeDoc completeness + - README accuracy + - API documentation + - Code comments quality + +#### JSON Output for CI/CD + +```bash +# Get structured JSON output +npx claude-flow@alpha verify check --json > verification.json + +# Example JSON structure: +{ + "overallScore": 0.947, + "passed": true, + "threshold": 0.95, + "checks": [ + { + "name": "code-correctness", + "score": 0.98, + "passed": true + }, + { + "name": "security", + "score": 0.91, + "passed": false, + "issues": [...] + } + ] +} +``` + +### Automatic Rollback + +#### Rollback Failed Changes + +Automatically revert changes that fail verification checks. + +**Basic Rollback:** +```bash +# Rollback to last known good state +npx claude-flow@alpha verify rollback --last-good + +# Rollback to specific commit +npx claude-flow@alpha verify rollback --to-commit abc123 + +# Interactive rollback with preview +npx claude-flow@alpha verify rollback --interactive +``` + +**Smart Rollback:** +```bash +# Rollback only failed files (preserve good changes) +npx claude-flow@alpha verify rollback --selective + +# Rollback with automatic backup +npx claude-flow@alpha verify rollback --backup-first + +# Dry-run mode (preview without executing) +npx claude-flow@alpha verify rollback --dry-run +``` + +**Rollback Performance:** +- Git-based rollback: <1 second +- Selective file rollback: <500ms +- Backup creation: Automatic before rollback + +### Verification Reports + +#### Generate Reports + +Create detailed verification reports with metrics and visualizations. + +**Report Formats:** +```bash +# JSON report +npx claude-flow@alpha verify report --format json + +# HTML report with charts +npx claude-flow@alpha verify report --export metrics.html --format html + +# CSV for data analysis +npx claude-flow@alpha verify report --format csv --export metrics.csv + +# Markdown summary +npx claude-flow@alpha verify report --format markdown +``` + +**Time-based Reports:** +```bash +# Last 24 hours +npx claude-flow@alpha verify report --period 24h + +# Last 7 days +npx claude-flow@alpha verify report --period 7d + +# Last 30 days with trends +npx claude-flow@alpha verify report --period 30d --include-trends + +# Custom date range +npx claude-flow@alpha verify report --from 2025-01-01 --to 2025-01-31 +``` + +**Report Content:** +- Overall truth scores +- Per-agent performance metrics +- Task completion quality +- Verification pass/fail rates +- Rollback frequency +- Quality improvement trends +- Statistical confidence intervals + +### Interactive Dashboard + +#### Launch Dashboard + +Run interactive web-based verification dashboard with real-time updates. + +```bash +# Launch dashboard on default port (3000) +npx claude-flow@alpha verify dashboard + +# Custom port +npx claude-flow@alpha verify dashboard --port 8080 + +# Export dashboard data +npx claude-flow@alpha verify dashboard --export + +# Dashboard with auto-refresh +npx claude-flow@alpha verify dashboard --refresh 5s +``` + +**Dashboard Features:** +- Real-time truth score updates (WebSocket) +- Interactive charts and graphs +- Agent performance comparison +- Task history timeline +- Rollback history viewer +- Export to PDF/HTML +- Filter by time period/agent/score + +### Configuration + +#### Default Configuration + +Set verification preferences in `.claude-flow/config.json`: + +```json +{ + "verification": { + "threshold": 0.95, + "autoRollback": true, + "gitIntegration": true, + "hooks": { + "preCommit": true, + "preTask": true, + "postEdit": true + }, + "checks": { + "codeCorrectness": true, + "security": true, + "performance": true, + "documentation": true, + "bestPractices": true + } + }, + "truth": { + "defaultFormat": "table", + "defaultPeriod": "24h", + "warningThreshold": 0.85, + "criticalThreshold": 0.75, + "autoExport": { + "enabled": true, + "path": ".claude-flow/metrics/truth-daily.json" + } + } +} +``` + +#### Threshold Configuration + +**Adjust verification strictness:** +```bash +# Strict mode (99% accuracy required) +npx claude-flow@alpha verify check --threshold 0.99 + +# Lenient mode (90% acceptable) +npx claude-flow@alpha verify check --threshold 0.90 + +# Set default threshold +npx claude-flow@alpha config set verification.threshold 0.98 +``` + +**Per-environment thresholds:** +```json +{ + "verification": { + "thresholds": { + "production": 0.99, + "staging": 0.95, + "development": 0.90 + } + } +} +``` + +### Integration Examples + +#### CI/CD Integration + +**GitHub Actions:** +```yaml +name: Quality Verification + +on: [push, pull_request] + +jobs: + verify: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: Install Dependencies + run: npm install + + - name: Run Verification + run: | + npx claude-flow@alpha verify check --json > verification.json + + - name: Check Truth Score + run: | + score=$(jq '.overallScore' verification.json) + if (( $(echo "$score < 0.95" | bc -l) )); then + echo "Truth score too low: $score" + exit 1 + fi + + - name: Upload Report + uses: actions/upload-artifact@v3 + with: + name: verification-report + path: verification.json +``` + +**GitLab CI:** +```yaml +verify: + stage: test + script: + - npx claude-flow@alpha verify check --threshold 0.95 --json > verification.json + - | + score=$(jq '.overallScore' verification.json) + if [ $(echo "$score < 0.95" | bc) -eq 1 ]; then + echo "Verification failed with score: $score" + exit 1 + fi + artifacts: + paths: + - verification.json + reports: + junit: verification.json +``` + +#### Swarm Integration + +Run verification automatically during swarm operations: + +```bash +# Swarm with verification enabled +npx claude-flow@alpha swarm --verify --threshold 0.98 + +# Hive Mind with auto-rollback +npx claude-flow@alpha hive-mind --verify --rollback-on-fail + +# Training pipeline with verification +npx claude-flow@alpha train --verify --threshold 0.99 +``` + +#### Pair Programming Integration + +Enable real-time verification during collaborative development: + +```bash +# Pair with verification +npx claude-flow@alpha pair --verify --real-time + +# Pair with custom threshold +npx claude-flow@alpha pair --verify --threshold 0.97 --auto-fix +``` + +### Advanced Workflows + +#### Continuous Verification + +Monitor codebase continuously during development: + +```bash +# Watch directory for changes +npx claude-flow@alpha verify watch --directory src/ + +# Watch with auto-fix +npx claude-flow@alpha verify watch --directory src/ --auto-fix + +# Watch with notifications +npx claude-flow@alpha verify watch --notify --threshold 0.95 +``` + +#### Monitoring Integration + +Send metrics to external monitoring systems: + +```bash +# Export to Prometheus +npx claude-flow@alpha truth --format json | \ + curl -X POST https://pushgateway.example.com/metrics/job/claude-flow \ + -d @- + +# Send to DataDog +npx claude-flow@alpha verify report --format json | \ + curl -X POST "https://api.datadoghq.com/api/v1/series?api_key=${DD_API_KEY}" \ + -H "Content-Type: application/json" \ + -d @- + +# Custom webhook +npx claude-flow@alpha truth --format json | \ + curl -X POST https://metrics.example.com/api/truth \ + -H "Content-Type: application/json" \ + -d @- +``` + +#### Pre-commit Hooks + +Automatically verify before commits: + +```bash +# Install pre-commit hook +npx claude-flow@alpha verify install-hook --pre-commit + +# .git/hooks/pre-commit example: +#!/bin/bash +npx claude-flow@alpha verify check --threshold 0.95 --json > /tmp/verify.json + +score=$(jq '.overallScore' /tmp/verify.json) +if (( $(echo "$score < 0.95" | bc -l) )); then + echo "โŒ Verification failed with score: $score" + echo "Run 'npx claude-flow@alpha verify check --verbose' for details" + exit 1 +fi + +echo "โœ… Verification passed with score: $score" +``` + +### Performance Metrics + +**Verification Speed:** +- Single file check: <100ms +- Directory scan: <500ms (per 100 files) +- Full codebase analysis: <5s (typical project) +- Truth score calculation: <50ms + +**Rollback Speed:** +- Git-based rollback: <1s +- Selective file rollback: <500ms +- Backup creation: <2s + +**Dashboard Performance:** +- Initial load: <1s +- Real-time updates: <100ms latency (WebSocket) +- Chart rendering: 60 FPS + +### Troubleshooting + +#### Common Issues + +**Low Truth Scores:** +```bash +# Get detailed breakdown +npx claude-flow@alpha truth --verbose --threshold 0.0 + +# Check specific criteria +npx claude-flow@alpha verify check --verbose + +# View agent-specific issues +npx claude-flow@alpha truth --agent --format json +``` + +**Rollback Failures:** +```bash +# Check git status +git status + +# View rollback history +npx claude-flow@alpha verify rollback --history + +# Manual rollback +git reset --hard HEAD~1 +``` + +**Verification Timeouts:** +```bash +# Increase timeout +npx claude-flow@alpha verify check --timeout 60s + +# Verify in batches +npx claude-flow@alpha verify batch --batch-size 10 +``` + +### Exit Codes + +Verification commands return standard exit codes: + +- `0`: Verification passed (score โ‰ฅ threshold) +- `1`: Verification failed (score < threshold) +- `2`: Error during verification (invalid input, system error) + +### Related Commands + +- `npx claude-flow@alpha pair` - Collaborative development with verification +- `npx claude-flow@alpha train` - Training with verification feedback +- `npx claude-flow@alpha swarm` - Multi-agent coordination with quality checks +- `npx claude-flow@alpha report` - Generate comprehensive project reports + +### Best Practices + +1. **Set Appropriate Thresholds**: Use 0.99 for critical code, 0.95 for standard, 0.90 for experimental +2. **Enable Auto-rollback**: Prevent bad code from persisting +3. **Monitor Trends**: Track improvement over time, not just current scores +4. **Integrate with CI/CD**: Make verification part of your pipeline +5. **Use Watch Mode**: Get immediate feedback during development +6. **Export Metrics**: Track quality metrics in your monitoring system +7. **Review Rollbacks**: Understand why changes were rejected +8. **Train Agents**: Use verification feedback to improve agent performance + +### Additional Resources + +- Truth Scoring Algorithm: See `/docs/truth-scoring.md` +- Verification Criteria: See `/docs/verification-criteria.md` +- Integration Examples: See `/examples/verification/` +- API Reference: See `/docs/api/verification.md` diff --git a/.claude/skills/video-frames/SKILL.md b/.claude/skills/video-frames/SKILL.md new file mode 100644 index 0000000000..8c1fc977a2 --- /dev/null +++ b/.claude/skills/video-frames/SKILL.md @@ -0,0 +1,29 @@ +--- +name: video-frames +description: Extract frames or short clips from videos using ffmpeg. +homepage: https://ffmpeg.org +metadata: {"zee":{"emoji":"๐ŸŽž๏ธ","requires":{"bins":["ffmpeg"]},"install":[{"id":"brew","kind":"brew","formula":"ffmpeg","bins":["ffmpeg"],"label":"Install ffmpeg (brew)"}]}} +--- + +# Video Frames (ffmpeg) + +Extract a single frame from a video, or create quick thumbnails for inspection. + +## Quick start + +First frame: + +```bash +{baseDir}/scripts/frame.sh /path/to/video.mp4 --out /tmp/frame.jpg +``` + +At a timestamp: + +```bash +{baseDir}/scripts/frame.sh /path/to/video.mp4 --time 00:00:10 --out /tmp/frame-10s.jpg +``` + +## Notes + +- Prefer `--time` for โ€œwhat is happening around here?โ€. +- Use a `.jpg` for quick share; use `.png` for crisp UI frames. diff --git a/.claude/skills/video-frames/scripts/frame.sh b/.claude/skills/video-frames/scripts/frame.sh new file mode 100644 index 0000000000..31b3adb34c --- /dev/null +++ b/.claude/skills/video-frames/scripts/frame.sh @@ -0,0 +1,81 @@ +#!/usr/bin/env bash +set -euo pipefail + +usage() { + cat >&2 <<'EOF' +Usage: + frame.sh [--time HH:MM:SS] [--index N] --out /path/to/frame.jpg + +Examples: + frame.sh video.mp4 --out /tmp/frame.jpg + frame.sh video.mp4 --time 00:00:10 --out /tmp/frame-10s.jpg + frame.sh video.mp4 --index 0 --out /tmp/frame0.png +EOF + exit 2 +} + +if [[ "${1:-}" == "" || "${1:-}" == "-h" || "${1:-}" == "--help" ]]; then + usage +fi + +in="${1:-}" +shift || true + +time="" +index="" +out="" + +while [[ $# -gt 0 ]]; do + case "$1" in + --time) + time="${2:-}" + shift 2 + ;; + --index) + index="${2:-}" + shift 2 + ;; + --out) + out="${2:-}" + shift 2 + ;; + *) + echo "Unknown arg: $1" >&2 + usage + ;; + esac +done + +if [[ ! -f "$in" ]]; then + echo "File not found: $in" >&2 + exit 1 +fi + +if [[ "$out" == "" ]]; then + echo "Missing --out" >&2 + usage +fi + +mkdir -p "$(dirname "$out")" + +if [[ "$index" != "" ]]; then + ffmpeg -hide_banner -loglevel error -y \ + -i "$in" \ + -vf "select=eq(n\\,${index})" \ + -vframes 1 \ + "$out" +elif [[ "$time" != "" ]]; then + ffmpeg -hide_banner -loglevel error -y \ + -ss "$time" \ + -i "$in" \ + -frames:v 1 \ + "$out" +else + ffmpeg -hide_banner -loglevel error -y \ + -i "$in" \ + -vf "select=eq(n\\,0)" \ + -vframes 1 \ + "$out" +fi + +echo "$out" diff --git a/.claude/skills/wacli/SKILL.md b/.claude/skills/wacli/SKILL.md new file mode 100644 index 0000000000..841968cc3a --- /dev/null +++ b/.claude/skills/wacli/SKILL.md @@ -0,0 +1,42 @@ +--- +name: wacli +description: Send WhatsApp messages to other people or search/sync WhatsApp history via the wacli CLI (not for normal user chats). +homepage: https://wacli.sh +metadata: {"zee":{"emoji":"๐Ÿ“ฑ","requires":{"bins":["wacli"]},"install":[{"id":"brew","kind":"brew","formula":"steipete/tap/wacli","bins":["wacli"],"label":"Install wacli (brew)"},{"id":"go","kind":"go","module":"github.com/steipete/wacli/cmd/wacli@latest","bins":["wacli"],"label":"Install wacli (go)"}]}} +--- + +# wacli + +Use `wacli` only when the user explicitly asks you to message someone else on WhatsApp or when they ask to sync/search WhatsApp history. +Do NOT use `wacli` for normal user chats; Zee routes WhatsApp conversations automatically. +If the user is chatting with you on WhatsApp, you should not reach for this tool unless they ask you to contact a third party. + +Safety +- Require explicit recipient + message text. +- Confirm recipient + message before sending. +- If anything is ambiguous, ask a clarifying question. + +Auth + sync +- `wacli auth` (QR login + initial sync) +- `wacli sync --follow` (continuous sync) +- `wacli doctor` + +Find chats + messages +- `wacli chats list --limit 20 --query "name or number"` +- `wacli messages search "query" --limit 20 --chat ` +- `wacli messages search "invoice" --after 2025-01-01 --before 2025-12-31` + +History backfill +- `wacli history backfill --chat --requests 2 --count 50` + +Send +- Text: `wacli send text --to "+14155551212" --message "Hello! Are you free at 3pm?"` +- Group: `wacli send text --to "1234567890-123456789@g.us" --message "Running 5 min late."` +- File: `wacli send file --to "+14155551212" --file /path/agenda.pdf --caption "Agenda"` + +Notes +- Store dir: `~/.wacli` (override with `--store`). +- Use `--json` for machine-readable output when parsing. +- Backfill requires your phone online; results are best-effort. +- WhatsApp CLI is not needed for routine user chats; itโ€™s for messaging other people. +- JIDs: direct chats look like `@s.whatsapp.net`; groups look like `@g.us` (use `wacli chats list` to find). diff --git a/.claude/skills/weather/SKILL.md b/.claude/skills/weather/SKILL.md new file mode 100644 index 0000000000..f74e1f4840 --- /dev/null +++ b/.claude/skills/weather/SKILL.md @@ -0,0 +1,49 @@ +--- +name: weather +description: Get current weather and forecasts (no API key required). +homepage: https://wttr.in/:help +metadata: {"zee":{"emoji":"๐ŸŒค๏ธ","requires":{"bins":["curl"]}}} +--- + +# Weather + +Two free services, no API keys needed. + +## wttr.in (primary) + +Quick one-liner: +```bash +curl -s "wttr.in/London?format=3" +# Output: London: โ›…๏ธ +8ยฐC +``` + +Compact format: +```bash +curl -s "wttr.in/London?format=%l:+%c+%t+%h+%w" +# Output: London: โ›…๏ธ +8ยฐC 71% โ†™5km/h +``` + +Full forecast: +```bash +curl -s "wttr.in/London?T" +``` + +Format codes: `%c` condition ยท `%t` temp ยท `%h` humidity ยท `%w` wind ยท `%l` location ยท `%m` moon + +Tips: +- URL-encode spaces: `wttr.in/New+York` +- Airport codes: `wttr.in/JFK` +- Units: `?m` (metric) `?u` (USCS) +- Today only: `?1` ยท Current only: `?0` +- PNG: `curl -s "wttr.in/Berlin.png" -o /tmp/weather.png` + +## Open-Meteo (fallback, JSON) + +Free, no key, good for programmatic use: +```bash +curl -s "https://api.open-meteo.com/v1/forecast?latitude=51.5&longitude=-0.12¤t_weather=true" +``` + +Find coordinates for a city, then query. Returns JSON with temp, windspeed, weathercode. + +Docs: https://open-meteo.com/en/docs diff --git a/.github/ISSUE_TEMPLATE/bug-report.yml b/.github/ISSUE_TEMPLATE/bug-report.yml index fe1ec8409b..47f9a5c586 100644 --- a/.github/ISSUE_TEMPLATE/bug-report.yml +++ b/.github/ISSUE_TEMPLATE/bug-report.yml @@ -20,10 +20,10 @@ body: required: false - type: input - id: opencode-version + id: agent-core-version attributes: - label: OpenCode version - description: What version of OpenCode are you using? + label: Agent-Core version + description: What version of Agent-Core are you using? validations: required: false diff --git a/.gitignore b/.gitignore index 306aa9f900..5f8b4a8ea2 100644 --- a/.gitignore +++ b/.gitignore @@ -27,3 +27,18 @@ opencode-dev logs/ *.bun-build .dev-config/ + +# Removed gateway docs (embedded gateway only) +vendor/personas/zee/docs/gateway/external-gateway.md +vendor/personas/zee/docs/gateway/index.md +vendor/personas/zee/docs/gateway/troubleshooting.md +vendor/personas/zee/docs/install/docker.md +vendor/personas/zee/docs/platforms/linux.md +vendor/personas/zee/docs/platforms/exe-dev.md +vendor/personas/zee/docker-compose.yml + +# Removed council components (tiara-only mode) +src/council/ +src/agent-types.ts +src/model-catalog.ts +src/tiara.ts diff --git a/AGENTS.md b/AGENTS.md index 520319adbe..95a7436c3a 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -2,3 +2,18 @@ - To regenerate the JavaScript SDK, run `./packages/sdk/js/script/build.ts`. - ALWAYS USE PARALLEL TOOLS WHEN APPLICABLE. - The default branch in this repo is `dev`. +## Binary Installation + +**Single source of truth**: The `agent-core` binary is installed via `bun link` from `packages/agent-core/`. + +To reinstall after building: +```bash +cd packages/agent-core && bun link +``` + +This creates a symlink at `~/.bun/bin/agent-core` โ†’ dev build. + +**Do NOT** install agent-core via: +- `~/bin/agent-core` (manual copy) +- `~/.local/bin/agent-core` (separate symlink) +- `curl ... | sh` installer (creates `~/.opencode/bin/`) diff --git a/CLAUDE.md b/CLAUDE.md index 7fbd3d7a38..c9c1ede45f 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -126,7 +126,7 @@ You can always check: ``` โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ AGENT-CORE (Engine) โ”‚ -โ”‚ ~/Repositories/agent-core/ โ”‚ +โ”‚ ~/.local/src/agent-core/ โ”‚ โ”‚ โ”‚ โ”‚ packages/agent-core/ โ† Fork of OpenCode TUI (built-in agents โ”‚ โ”‚ removed, only triad remains) โ”‚ @@ -168,7 +168,6 @@ You can always check: โ”‚ src/ โ”‚ โ”‚ โ”œโ”€โ”€ domain/ โ† Domain tools (stanley/, zee/) โ”‚ โ”‚ โ”œโ”€โ”€ personas/ โ† Persona logic (knowledge-graph, etc.) โ”‚ -โ”‚ โ”œโ”€โ”€ council/ โ† LLM Council multi-model deliberation โ”‚ โ”‚ โ””โ”€โ”€ memory/ โ† Qdrant vector storage types โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ ``` @@ -198,7 +197,6 @@ agent-core/ โ”‚ โ”œโ”€โ”€ personas/ โ”‚ โ”‚ โ””โ”€โ”€ johny/ โ”‚ โ”‚ โ””โ”€โ”€ knowledge-graph/ # MathAcademy-inspired learning system -โ”‚ โ”œโ”€โ”€ council/ # LLM Council implementation โ”‚ โ””โ”€โ”€ memory/ # Qdrant vector storage types โ””โ”€โ”€ docs/ โ””โ”€โ”€ SKILLS.md # Skills documentation @@ -227,7 +225,6 @@ Skills are loaded from `.claude/skills/` and `~/.config/agent-core/skills/`: This system has experimental features enabled: -- LLM Council for multi-model deliberation - Knowledge graph with FIRe (Fractional Implicit Repetition) - Semantic memory via Qdrant - All OpenCode experimental flags active @@ -307,7 +304,7 @@ pgrep -af agent-core **Related but separate (don't kill):** | Process | Location | Description | |---------|----------|-------------| -| Zee Gateway | `~/Repositories/personas/zee/` | Node.js messaging gateway (WhatsApp, Telegram, Signal) | +| Zee Gateway | `~/.local/src/agent-core/vendor/personas/zee/` | Node.js messaging gateway (WhatsApp, Telegram, Signal) | ### Gateway Architecture @@ -317,7 +314,7 @@ pgrep -af agent-core โ”‚ โ”‚ โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ โ”‚ Zee Gateway (Transport) โ”‚ -โ”‚ โ”‚ ~/Repositories/personas/zee/ โ”‚ +โ”‚ โ”‚ ~/.local/src/agent-core/vendor/personas/zee/ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ โ”‚ โ”‚ โ”‚ WhatsApp โ”‚ โ”‚ Telegram โ”‚ โ”‚ Signal โ”‚ โ”‚ Discord โ”‚ โ”‚ @@ -336,7 +333,7 @@ pgrep -af agent-core โ”‚ โ”‚ + agent: persona โ”‚ โ–ผ โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” -โ”‚ โ”‚ agent-core daemon --external-gateway โ”‚ +โ”‚ โ”‚ agent-core daemon (spawns gateway) โ”‚ โ”‚ โ”‚ http://127.0.0.1:3210 โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ @@ -357,31 +354,25 @@ pgrep -af agent-core - **Persona routing** = Messages mentioning `@stanley` or `@johny` are routed to those personas - **Daemon-only mode** = Zee REQUIRES agent-core daemon to be running -### Running the External Gateway Architecture +### Running the Embedded Gateway -1. **Start agent-core daemon with external gateway mode:** +1. **Start agent-core daemon (gateway auto-starts):** ```bash - agent-core daemon --external-gateway --hostname 127.0.0.1 --port 3210 + agent-core daemon --hostname 127.0.0.1 --port 3210 ``` -2. **Start zee gateway:** - - ```bash - cd ~/Repositories/personas/zee && pnpm zee gateway - ``` - -3. **Send a message** via WhatsApp/Telegram mentioning a persona: +2. **Send a message** via WhatsApp/Telegram mentioning a persona: - "Hello" โ†’ routes to Zee (default) - "@stanley What's the market doing?" โ†’ routes to Stanley - "@johny Help me study" โ†’ routes to Johny ### Architecture Decision -Built-in messaging gateways have been **removed** from agent-core to: +Messaging transport remains in Zee, but the gateway is launched by agent-core to: 1. Avoid duplication with zee gateway (ClawdBot fork) 2. Keep agent-core clean for upstream OpenCode 3. Centralize messaging transport in one place -All messaging flows through the zee gateway at `~/Repositories/personas/zee/`. +All messaging flows through the Zee gateway at `~/.local/src/agent-core/vendor/personas/zee/`, managed by the daemon. diff --git a/agent-core b/agent-core new file mode 120000 index 0000000000..2d527cba76 --- /dev/null +++ b/agent-core @@ -0,0 +1 @@ +/home/artur/.local/src/agent-core \ No newline at end of file diff --git a/agent-core.json b/agent-core.json index ac179f3106..47f5c975f6 100644 --- a/agent-core.json +++ b/agent-core.json @@ -3,5 +3,9 @@ "provider": "languagetool", "username": "dolagoartur@gmail.com", "apiKey": "pit-oqFnllGFX5eB" - } -} + }, + "plugin": [ + "file:///home/artur/.local/src/agent-core/packages/opencode-anthropic-auth/index.mjs" + ], + "$schema": "https://opencode.ai/config.json" +} \ No newline at end of file diff --git a/docs/ALPHA_RELEASE_TODO.md b/docs/ALPHA_RELEASE_TODO.md new file mode 100644 index 0000000000..ba3e9facb4 --- /dev/null +++ b/docs/ALPHA_RELEASE_TODO.md @@ -0,0 +1,52 @@ +# Alpha Release TODO (CLI Scope) + +Target: `dev` branch only. Scope is CLI + daemon; desktop/VS Code excluded. + +## Release Readiness (Done) + +- [x] Align release artifacts with `agent-core` binary naming (publish, Docker, postinstall). +- [x] Update registry publishing targets to `agent-core` (AUR/Homebrew formula naming). +- [x] Update installation/upgrade/uninstall commands to `agent-core` package names. +- [x] Fix user-facing MCP hints to use `agent-core` commands. +- [x] Update bug report template and TUI issue link to `adolago/agent-core`. +- [x] Standardize CLI-generated URLs/docs links to Agent-Core repo docs. +- [x] Refresh Zee coding-agent skill to use `agent-core` binary. +- [x] Update Stanley AI integration docs to reference Agent-Core (fork of OpenCode). + +## Cross-Repo Integration (Done) + +- [x] Ensure Zee references agent-core daemon usage for CLI scope. +- [x] Ensure Stanley AI architecture docs reference Agent-Core fork. +- [x] Confirm Johny README already points to agent-core daemon. + +## Manual Verification (Run When Releasing) + +- [x] `cd packages/agent-core && bun run typecheck` +- [x] `cd packages/agent-core && bun test` +- [x] `cd packages/agent-core && bun run build` +- [ ] `cd packages/agent-core && bun run script/publish.ts --preview` (requires npm publish 2FA or a granular token with 2FA bypass; otherwise E403; hit npm rate limit E429 on `agent-core-linux-arm64`, retry later) + +## Alpha Scope Notes + +- CLI only for alpha; desktop/VS Code are out of scope. +- Upstream references to OpenCode remain for compatibility where required. +- Google Antigravity OAuth requires the `opencode-google-auth` plugin (no built-in flow). + +## Always-On Reliability (Done) + +- [x] Gateway supervised by agent-core (single source of truth). +- [x] Gateway health probe + backoff restart in daemon. +- [x] Gateway diagnostics in `agent-core status` + `agent-core check`. + +## Upstream Move Checklist (Pending) + +- [ ] Run `./scripts/check-upstream.sh --fetch` and capture divergence report. +- [ ] Verify upstream does not reintroduce standalone gateway/council code paths. +- [x] Confirm `opencode-google-auth` plugin requirement (no built-in Antigravity OAuth). + +## Alpha Release Notes (Draft) + +- Always-on daemon owns the messaging gateway with health probes and auto-restart. +- Qdrant + embeddings (including Nebius) are configured via agent-core config, not env scripts. +- Google Antigravity OAuth is plugin-only (`opencode-google-auth`). +- Install: `agent-core plugin install opencode-google-auth` โ†’ `agent-core auth login` (select Google). diff --git a/docs/ENVIRONMENT_VARIABLES.md b/docs/ENVIRONMENT_VARIABLES.md index 2a4d12731c..527a51345c 100644 --- a/docs/ENVIRONMENT_VARIABLES.md +++ b/docs/ENVIRONMENT_VARIABLES.md @@ -63,17 +63,23 @@ Complete reference for environment variables across the agent-core ecosystem. ## Memory & Embeddings +Prefer `agent-core.json(c)` for Qdrant and embedding settings. Environment variables are treated as fallback defaults. + ### Qdrant Vector Database | Variable | Default | Description | |----------|---------|-------------| -| `QDRANT_URL` | `http://localhost:6333` | Qdrant server URL | +| `QDRANT_URL` | `http://localhost:6333` | Qdrant server URL (fallback) | +| `QDRANT_MEMORY_COLLECTION` | `personas_memory` | Memory collection name (fallback) | ### Embedding Providers | Variable | Default | Description | |----------|---------|-------------| | `OPENAI_API_KEY` | - | OpenAI API key for embeddings (text-embedding-3-small) | +| `NEBIUS_API_KEY` | - | Nebius API key for OpenAI-compatible embeddings (Qwen3) | +| `GOOGLE_API_KEY` | - | Google API key for embeddings (text-embedding-004) | +| `GEMINI_API_KEY` | - | Alternate Google API key name | | `VOYAGE_API_KEY` | - | Voyage AI API key for embeddings (alternative) | --- @@ -207,7 +213,7 @@ Complete reference for environment variables across the agent-core ecosystem. | Variable | Default | Description | |----------|---------|-------------| | `STANLEY_PORTFOLIO_FILE` | `~/.zee/stanley/portfolio.json` | Portfolio file path | -| `STANLEY_REPO` | `~/Repositories/personas/stanley` | Stanley repo path | +| `STANLEY_REPO` | `~/.local/src/agent-core/vendor/personas/stanley` | Stanley repo path | | `STANLEY_CLI` | `$STANLEY_REPO/scripts/stanley_cli.py` | CLI script path | | `STANLEY_PYTHON` | Auto-detect venv or `python3` | Python interpreter | @@ -219,7 +225,7 @@ Complete reference for environment variables across the agent-core ecosystem. | Variable | Default | Description | |----------|---------|-------------| -| `JOHNY_REPO` | `~/Repositories/personas/johny` | Johny repo path | +| `JOHNY_REPO` | `~/.local/src/agent-core/vendor/personas/johny` | Johny repo path | | `JOHNY_CLI` | `$JOHNY_REPO/scripts/johny_cli.py` | CLI script path | | `JOHNY_PYTHON` | Auto-detect venv or `python3` | Python interpreter | @@ -292,12 +298,14 @@ Complete reference for environment variables across the agent-core ecosystem. # Required for LLM functionality export ANTHROPIC_API_KEY="sk-ant-..." -# Required for memory/embeddings -export OPENAI_API_KEY="sk-..." -export QDRANT_URL="http://localhost:6333" +# Embeddings (example: Nebius Qwen3) +export NEBIUS_API_KEY="..." + +# Configure memory in ~/.config/agent-core/agent-core.jsonc +# (Qdrant + embeddings are read from config; env vars are fallback only) # Start daemon -agent-core daemon --external-gateway +agent-core daemon ``` ### Development Setup diff --git a/docs/PROVIDERS.md b/docs/PROVIDERS.md index 7c9a482c0b..3195368753 100644 --- a/docs/PROVIDERS.md +++ b/docs/PROVIDERS.md @@ -17,7 +17,16 @@ The global config is symlinked to project config so changes in one location refl ### Google (Antigravity) -Free-tier models via the `opencode-antigravity-auth` plugin. +Free-tier models via the `opencode-google-auth` plugin (OAuth). Agent-core does not include a built-in Antigravity OAuth flow. + +Install and authenticate: + +```bash +agent-core plugin install opencode-google-auth +agent-core auth login +``` + +Select **Google** when prompted. **Provider ID:** `google` diff --git a/docs/ROADMAP.md b/docs/ROADMAP.md index 084732775d..209e64b3e5 100644 --- a/docs/ROADMAP.md +++ b/docs/ROADMAP.md @@ -233,7 +233,7 @@ Agent-core is a fork of OpenCode with three personas (Zee, Stanley, Johny) shari |----------|--------|----------| | TUI (agent-core) | โœ… Primary | This repo | | Web (OpenCode) | โœ… Upstream | opencode-ai/opencode | -| Mobile (Zee) | โœ… Companion | personas/zee mobile app | +| Mobile (Zee) | โœ… Companion | .local/src/agent-core/vendor/personas/zee mobile app | ### 6.2 Integration Points - COMPLETE - [x] Shared session state across platforms diff --git a/docs/UPSTREAM-SYNC.md b/docs/UPSTREAM-SYNC.md index eaafee6788..77dbddceac 100644 --- a/docs/UPSTREAM-SYNC.md +++ b/docs/UPSTREAM-SYNC.md @@ -94,6 +94,14 @@ For each conflicted file: // Resolution: Add both, ensure our loader doesn't conflict with new one ``` +### Gateway Ownership + +``` +// Upstream adds standalone gateway or council transport +// Our change: agent-core is the only gateway supervisor +// Resolution: keep agent-core embedded gateway; do not reintroduce standalone gateways +``` + ### Agent Schema ```typescript diff --git a/docs/USER_GUIDE.md b/docs/USER_GUIDE.md index 23385d3e26..9a4d1dcf02 100644 --- a/docs/USER_GUIDE.md +++ b/docs/USER_GUIDE.md @@ -40,11 +40,18 @@ This will: ### Authentication You need an LLM provider (Anthropic is recommended for best results). +Google Antigravity OAuth is available via the `opencode-google-auth` plugin (not built in). + +```bash +agent-core plugin install opencode-google-auth +``` ```bash agent-core auth login ``` +Select **Google** to complete the OAuth flow. + Select "Anthropic" or "OpenAI" and paste your API key. ### Personas @@ -112,7 +119,7 @@ The system keeps the last 5 sessions automatically. To unlock the full power of the Investment Persona: -1. Clone the Stanley repo to `~/Repositories/personas/stanley`. +1. Clone the Stanley repo to `~/.local/src/agent-core/vendor/personas/stanley`. 2. Set up the Python environment there (`pip install -r requirements.txt`). 3. Agent-Core will automatically detect the CLI. diff --git a/docs/architecture/ALWAYS-ON-PERSONAS.md b/docs/architecture/ALWAYS-ON-PERSONAS.md index 751037a3c1..4e21884cff 100644 --- a/docs/architecture/ALWAYS-ON-PERSONAS.md +++ b/docs/architecture/ALWAYS-ON-PERSONAS.md @@ -138,11 +138,11 @@ Added `daemon` section to config schema: --- -### Phase 2: Remote Communication Gateway -**Status: Complete (External Architecture)** +### Phase 2: Messaging Gateway +**Status: Complete (Embedded Gateway)** **Prerequisites: Phase 1 complete** -Messaging is handled by an **external gateway** service, keeping agent-core clean for upstream sync. +Messaging is handled by the Zee gateway, launched and supervised by agent-core. #### 2.1 Architecture @@ -152,7 +152,7 @@ Messaging is handled by an **external gateway** service, keeping agent-core clea โ”‚ โ”‚ โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ โ”‚ Zee Gateway (External Transport Layer) โ”‚ -โ”‚ โ”‚ ~/Repositories/personas/zee/ โ”‚ +โ”‚ โ”‚ ~/.local/src/agent-core/vendor/personas/zee/ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ โ”‚ โ”‚ โ”‚ WhatsApp โ”‚ โ”‚ Telegram โ”‚ โ”‚ Signal โ”‚ โ”‚ Discord โ”‚ โ”‚ @@ -172,7 +172,7 @@ Messaging is handled by an **external gateway** service, keeping agent-core clea โ”‚ โ”‚ + agent: persona โ”‚ โ–ผ โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” -โ”‚ โ”‚ agent-core daemon --external-gateway โ”‚ +โ”‚ โ”‚ agent-core daemon (spawns gateway) โ”‚ โ”‚ โ”‚ http://127.0.0.1:3210 โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ @@ -185,19 +185,12 @@ Messaging is handled by an **external gateway** service, keeping agent-core clea #### 2.2 Running the Gateway -**Step 1: Start agent-core daemon** +**Step 1: Start agent-core daemon (gateway auto-starts)** ```bash -# Start daemon in external gateway mode -agent-core daemon --external-gateway +agent-core daemon ``` -**Step 2: Start zee gateway (in separate terminal)** -```bash -cd ~/Repositories/personas/zee -pnpm zee gateway -``` - -**Step 3: Send messages via phone** +**Step 2: Send messages via phone** - WhatsApp/Telegram messages go to zee gateway - Gateway routes to agent-core daemon - Persona routing: mention `@stanley` or `@johny` in message, or let Zee handle default @@ -225,6 +218,11 @@ Messages are routed based on mentions: - [ ] Rate limiting (future) - [ ] Audit logging (future) +#### 2.6 Resilience (DONE) +- [x] Gateway supervised by agent-core with restart/backoff +- [x] Health probe restarts gateway if it becomes unresponsive +- [x] Diagnostics: `agent-core status` and `agent-core check` report gateway health + --- ### Phase 3: Session Persistence & Recovery diff --git a/install b/install index fb41bed697..2763eace04 100755 --- a/install +++ b/install @@ -167,26 +167,24 @@ else fi if [ -z "$requested_version" ]; then - url="https://github.com/adolago/agent-core/releases/latest/download/$filename" - specific_version=$(curl -s https://api.github.com/repos/adolago/agent-core/releases/latest | sed -n 's/.*"tag_name": *"v\([^"]*\)".*/\1/p') - + specific_version=$(curl -s https://registry.npmjs.org/agent-core/latest | sed -n 's/.*"version":"\\([^"]*\\)".*/\\1/p') if [[ $? -ne 0 || -z "$specific_version" ]]; then - echo -e "${RED}Failed to fetch version information${NC}" + echo -e "${RED}Failed to fetch npm version information${NC}" exit 1 fi else # Strip leading 'v' if present requested_version="${requested_version#v}" - url="https://github.com/adolago/agent-core/releases/download/v${requested_version}/$filename" specific_version=$requested_version + fi - # Verify the release exists before downloading - http_status=$(curl -sI -o /dev/null -w "%{http_code}" "https://github.com/adolago/agent-core/releases/tag/v${requested_version}") - if [ "$http_status" = "404" ]; then - echo -e "${RED}Error: Release v${requested_version} not found${NC}" - echo -e "${MUTED}Available releases: https://github.com/adolago/agent-core/releases${NC}" - exit 1 - fi + url="https://github.com/adolago/agent-core/releases/download/v${specific_version}/$filename" + + # Verify the asset exists before downloading + http_status=$(curl -sI -o /dev/null -w "%{http_code}" "$url") + if [ "$http_status" = "404" ]; then + echo -e "${RED}Error: Release asset not found for version ${specific_version}${NC}" + exit 1 fi fi @@ -259,7 +257,7 @@ download_with_progress() { fi local tmp_dir=${TMPDIR:-/tmp} - local basename="${tmp_dir}/opencode_install_$$" + local basename="${tmp_dir}/agent-core_install_$$" local tracefile="${basename}.trace" rm -f "$tracefile" @@ -309,8 +307,8 @@ download_with_progress() { } download_and_install() { - print_message info "\n${MUTED}Installing ${NC}opencode ${MUTED}version: ${NC}$specific_version" - local tmp_dir="${TMPDIR:-/tmp}/opencode_install_$$" + print_message info "\n${MUTED}Installing ${NC}agent-core ${MUTED}version: ${NC}$specific_version" + local tmp_dir="${TMPDIR:-/tmp}/agent-core_install_$$" mkdir -p "$tmp_dir" if [[ "$os" == "windows" ]] || ! [ -t 2 ] || ! download_with_progress "$url" "$tmp_dir/$filename"; then diff --git a/packages/agent-core/Dockerfile b/packages/agent-core/Dockerfile index f92b48a6d1..4611de2ae7 100644 --- a/packages/agent-core/Dockerfile +++ b/packages/agent-core/Dockerfile @@ -7,12 +7,12 @@ ENV BUN_RUNTIME_TRANSPILER_CACHE_PATH=${BUN_RUNTIME_TRANSPILER_CACHE_PATH} RUN apk add libgcc libstdc++ ripgrep FROM base AS build-amd64 -COPY dist/opencode-linux-x64-baseline-musl/bin/opencode /usr/local/bin/opencode +COPY dist/agent-core-linux-x64-baseline-musl/bin/agent-core /usr/local/bin/agent-core FROM base AS build-arm64 -COPY dist/opencode-linux-arm64-musl/bin/opencode /usr/local/bin/opencode +COPY dist/agent-core-linux-arm64-musl/bin/agent-core /usr/local/bin/agent-core ARG TARGETARCH FROM build-${TARGETARCH} -RUN opencode --version -ENTRYPOINT ["opencode"] +RUN agent-core --version +ENTRYPOINT ["agent-core"] diff --git a/packages/agent-core/script/postinstall.mjs b/packages/agent-core/script/postinstall.mjs index e8b5e995cc..876a460102 100644 --- a/packages/agent-core/script/postinstall.mjs +++ b/packages/agent-core/script/postinstall.mjs @@ -49,8 +49,8 @@ function detectPlatformAndArch() { function findBinary() { const { platform, arch } = detectPlatformAndArch() - const packageName = `opencode-${platform}-${arch}` - const binaryName = platform === "windows" ? "opencode.exe" : "opencode" + const packageName = `agent-core-${platform}-${arch}` + const binaryName = platform === "windows" ? "agent-core.exe" : "agent-core" try { // Use require.resolve to find the package @@ -89,7 +89,7 @@ function symlinkBinary(sourcePath, binaryName) { const { targetPath } = prepareBinDirectory(binaryName) fs.symlinkSync(sourcePath, targetPath) - console.log(`opencode binary symlinked: ${targetPath} -> ${sourcePath}`) + console.log(`agent-core binary symlinked: ${targetPath} -> ${sourcePath}`) // Verify the file exists after operation if (!fs.existsSync(targetPath)) { @@ -112,7 +112,7 @@ async function main() { console.log(`Platform binary verified at: ${binaryPath}`) console.log("Wrapper script will handle binary execution") } catch (error) { - console.error("Failed to setup opencode binary:", error.message) + console.error("Failed to setup agent-core binary:", error.message) process.exit(1) } } diff --git a/packages/agent-core/script/publish-registries.ts b/packages/agent-core/script/publish-registries.ts index 3dc1ce5e9c..3d53a7de7f 100644 --- a/packages/agent-core/script/publish-registries.ts +++ b/packages/agent-core/script/publish-registries.ts @@ -4,10 +4,10 @@ import { Script } from "@opencode-ai/script" if (!Script.preview) { // Calculate SHA values - const arm64Sha = await $`sha256sum ./dist/opencode-linux-arm64.tar.gz | cut -d' ' -f1`.text().then((x) => x.trim()) - const x64Sha = await $`sha256sum ./dist/opencode-linux-x64.tar.gz | cut -d' ' -f1`.text().then((x) => x.trim()) - const macX64Sha = await $`sha256sum ./dist/opencode-darwin-x64.zip | cut -d' ' -f1`.text().then((x) => x.trim()) - const macArm64Sha = await $`sha256sum ./dist/opencode-darwin-arm64.zip | cut -d' ' -f1`.text().then((x) => x.trim()) + const arm64Sha = await $`sha256sum ./dist/agent-core-linux-arm64.tar.gz | cut -d' ' -f1`.text().then((x) => x.trim()) + const x64Sha = await $`sha256sum ./dist/agent-core-linux-x64.tar.gz | cut -d' ' -f1`.text().then((x) => x.trim()) + const macX64Sha = await $`sha256sum ./dist/agent-core-darwin-x64.zip | cut -d' ' -f1`.text().then((x) => x.trim()) + const macArm64Sha = await $`sha256sum ./dist/agent-core-darwin-arm64.zip | cut -d' ' -f1`.text().then((x) => x.trim()) const [pkgver, _subver = ""] = Script.version.split(/(-.*)/, 2) @@ -16,62 +16,62 @@ if (!Script.preview) { "# Maintainer: dax", "# Maintainer: adam", "", - "pkgname='opencode-bin'", + "pkgname='agent-core-bin'", `pkgver=${pkgver}`, `_subver=${_subver}`, "options=('!debug' '!strip')", "pkgrel=1", "pkgdesc='The AI coding agent built for the terminal.'", - "url='https://github.com/anomalyco/opencode'", + "url='https://github.com/adolago/agent-core'", "arch=('aarch64' 'x86_64')", "license=('MIT')", - "provides=('opencode')", - "conflicts=('opencode')", + "provides=('agent-core')", + "conflicts=('agent-core')", "depends=('ripgrep')", "", - `source_aarch64=("\${pkgname}_\${pkgver}_aarch64.tar.gz::https://github.com/anomalyco/opencode/releases/download/v\${pkgver}\${_subver}/opencode-linux-arm64.tar.gz")`, + `source_aarch64=("\${pkgname}_\${pkgver}_aarch64.tar.gz::https://github.com/adolago/agent-core/releases/download/v\${pkgver}\${_subver}/agent-core-linux-arm64.tar.gz")`, `sha256sums_aarch64=('${arm64Sha}')`, - `source_x86_64=("\${pkgname}_\${pkgver}_x86_64.tar.gz::https://github.com/anomalyco/opencode/releases/download/v\${pkgver}\${_subver}/opencode-linux-x64.tar.gz")`, + `source_x86_64=("\${pkgname}_\${pkgver}_x86_64.tar.gz::https://github.com/adolago/agent-core/releases/download/v\${pkgver}\${_subver}/agent-core-linux-x64.tar.gz")`, `sha256sums_x86_64=('${x64Sha}')`, "", "package() {", - ' install -Dm755 ./opencode "${pkgdir}/usr/bin/opencode"', + ' install -Dm755 ./agent-core "${pkgdir}/usr/bin/agent-core"', "}", "", ].join("\n") - // Source-based PKGBUILD for opencode + // Source-based PKGBUILD for agent-core const sourcePkgbuild = [ "# Maintainer: dax", "# Maintainer: adam", "", - "pkgname='opencode'", + "pkgname='agent-core'", `pkgver=${pkgver}`, `_subver=${_subver}`, "options=('!debug' '!strip')", "pkgrel=1", "pkgdesc='The AI coding agent built for the terminal.'", - "url='https://github.com/anomalyco/opencode'", + "url='https://github.com/adolago/agent-core'", "arch=('aarch64' 'x86_64')", "license=('MIT')", - "provides=('opencode')", - "conflicts=('opencode-bin')", + "provides=('agent-core')", + "conflicts=('agent-core-bin')", "depends=('ripgrep')", "makedepends=('git' 'bun' 'go')", "", - `source=("opencode-\${pkgver}.tar.gz::https://github.com/anomalyco/opencode/archive/v\${pkgver}\${_subver}.tar.gz")`, + `source=("agent-core-\${pkgver}.tar.gz::https://github.com/adolago/agent-core/archive/v\${pkgver}\${_subver}.tar.gz")`, `sha256sums=('SKIP')`, "", "build() {", - ` cd "opencode-\${pkgver}"`, + ` cd "agent-core-\${pkgver}"`, ` bun install`, " cd ./packages/agent-core", ` OPENCODE_CHANNEL=latest OPENCODE_VERSION=${pkgver} bun run ./script/build.ts --single`, "}", "", "package() {", - ` cd "opencode-\${pkgver}/packages/agent-core"`, + ` cd "agent-core-\${pkgver}/packages/agent-core"`, ' mkdir -p "${pkgdir}/usr/bin"', ' target_arch="x64"', ' case "$CARCH" in', @@ -94,19 +94,19 @@ if (!Script.preview) { ' base="-baseline"', " fi", " fi", - ' bin="dist/opencode-linux-${target_arch}${base}${libc}/bin/opencode"', + ' bin="dist/agent-core-linux-${target_arch}${base}${libc}/bin/agent-core"', ' if [ ! -f "$bin" ]; then', ' printf "unable to find binary for %s%s%s\\n" "$target_arch" "$base" "$libc" >&2', " return 1", " fi", - ' install -Dm755 "$bin" "${pkgdir}/usr/bin/opencode"', + ' install -Dm755 "$bin" "${pkgdir}/usr/bin/agent-core"', "}", "", ].join("\n") for (const [pkg, pkgbuild] of [ - ["opencode-bin", binaryPkgbuild], - ["opencode", sourcePkgbuild], + ["agent-core-bin", binaryPkgbuild], + ["agent-core", sourcePkgbuild], ]) { for (let i = 0; i < 30; i++) { try { @@ -131,45 +131,45 @@ if (!Script.preview) { "# frozen_string_literal: true", "", "# This file was generated by GoReleaser. DO NOT EDIT.", - "class Opencode < Formula", + "class AgentCore < Formula", ` desc "The AI coding agent built for the terminal."`, - ` homepage "https://github.com/anomalyco/opencode"`, + ` homepage "https://github.com/adolago/agent-core"`, ` version "${Script.version.split("-")[0]}"`, "", ` depends_on "ripgrep"`, "", " on_macos do", " if Hardware::CPU.intel?", - ` url "https://github.com/anomalyco/opencode/releases/download/v${Script.version}/opencode-darwin-x64.zip"`, + ` url "https://github.com/adolago/agent-core/releases/download/v${Script.version}/agent-core-darwin-x64.zip"`, ` sha256 "${macX64Sha}"`, "", " def install", - ' bin.install "opencode"', + ' bin.install "agent-core"', " end", " end", " if Hardware::CPU.arm?", - ` url "https://github.com/anomalyco/opencode/releases/download/v${Script.version}/opencode-darwin-arm64.zip"`, + ` url "https://github.com/adolago/agent-core/releases/download/v${Script.version}/agent-core-darwin-arm64.zip"`, ` sha256 "${macArm64Sha}"`, "", " def install", - ' bin.install "opencode"', + ' bin.install "agent-core"', " end", " end", " end", "", " on_linux do", " if Hardware::CPU.intel? and Hardware::CPU.is_64_bit?", - ` url "https://github.com/anomalyco/opencode/releases/download/v${Script.version}/opencode-linux-x64.tar.gz"`, + ` url "https://github.com/adolago/agent-core/releases/download/v${Script.version}/agent-core-linux-x64.tar.gz"`, ` sha256 "${x64Sha}"`, " def install", - ' bin.install "opencode"', + ' bin.install "agent-core"', " end", " end", " if Hardware::CPU.arm? and Hardware::CPU.is_64_bit?", - ` url "https://github.com/anomalyco/opencode/releases/download/v${Script.version}/opencode-linux-arm64.tar.gz"`, + ` url "https://github.com/adolago/agent-core/releases/download/v${Script.version}/agent-core-linux-arm64.tar.gz"`, ` sha256 "${arm64Sha}"`, " def install", - ' bin.install "opencode"', + ' bin.install "agent-core"', " end", " end", " end", @@ -179,9 +179,9 @@ if (!Script.preview) { ].join("\n") await $`rm -rf ./dist/homebrew-tap` - await $`git clone https://${process.env["GITHUB_TOKEN"]}@github.com/sst/homebrew-tap.git ./dist/homebrew-tap` - await Bun.file("./dist/homebrew-tap/opencode.rb").write(homebrewFormula) - await $`cd ./dist/homebrew-tap && git add opencode.rb` + await $`git clone https://${process.env["GITHUB_TOKEN"]}@github.com/adolago/homebrew-tap.git ./dist/homebrew-tap` + await Bun.file("./dist/homebrew-tap/agent-core.rb").write(homebrewFormula) + await $`cd ./dist/homebrew-tap && git add agent-core.rb` await $`cd ./dist/homebrew-tap && git commit -m "Update to v${Script.version}"` await $`cd ./dist/homebrew-tap && git push` } diff --git a/packages/agent-core/script/publish.ts b/packages/agent-core/script/publish.ts index 4e5846d27e..8900ca472b 100755 --- a/packages/agent-core/script/publish.ts +++ b/packages/agent-core/script/publish.ts @@ -9,9 +9,11 @@ process.chdir(dir) const { binaries } = await import("./build.ts") { - const name = `${pkg.name}-${process.platform}-${process.arch}` - console.log(`smoke test: running dist/${name}/bin/opencode --version`) - await $`./dist/${name}/bin/opencode --version` + const binarySuffix = process.env.OPENCODE_BINARY_SUFFIX?.trim() + const osName = process.platform === "win32" ? "windows" : process.platform + const name = [pkg.name, osName, process.arch, binarySuffix].filter(Boolean).join("-") + console.log(`smoke test: running dist/${name}/bin/agent-core --version`) + await $`./dist/${name}/bin/agent-core --version` } await $`mkdir -p ./dist/${pkg.name}` @@ -62,7 +64,7 @@ if (!Script.preview) { } } - const image = "ghcr.io/anomalyco/opencode" + const image = "ghcr.io/adolago/agent-core" const platforms = "linux/amd64,linux/arm64" const tags = [`${image}:${Script.version}`, `${image}:latest`] const tagFlags = tags.flatMap((t) => ["-t", t]) diff --git a/packages/agent-core/src/cli/cmd/daemon.ts b/packages/agent-core/src/cli/cmd/daemon.ts index 7a199ce55e..22848b2b96 100644 --- a/packages/agent-core/src/cli/cmd/daemon.ts +++ b/packages/agent-core/src/cli/cmd/daemon.ts @@ -11,12 +11,14 @@ import { Instance } from "../../project/instance" import { LifecycleHooks } from "../../hooks/lifecycle" import { WeztermOrchestration } from "../../orchestration/wezterm" import { initPersonas } from "../../bootstrap/personas" -import { spawn, type ChildProcess } from "child_process" +import { execSync, spawn, spawnSync, type ChildProcess } from "child_process" import fs from "fs/promises" +import fsSync from "fs" import path from "path" -import os from "os" +import net from "net" import * as prompts from "@clack/prompts" import { UI } from "../ui" +import { Zee } from "../../paths" const log = Log.create({ service: "daemon" }) @@ -142,19 +144,59 @@ export namespace Daemon { * Gateway supervisor - manages zee gateway as a child process with auto-restart */ export namespace GatewaySupervisor { - const agentCoreRoot = process.env.AGENT_CORE_ROOT - const ZEE_GATEWAY_DIR = agentCoreRoot - ? path.join(agentCoreRoot, "vendor", "personas", "zee") - : path.join(os.homedir(), ".local", "src", "agent-core", "vendor", "personas", "zee") + const ZEE_GATEWAY_DIR = Zee.repo() + const ZEE_CONFIG_FILES = ["zee.json", "zee.jsonc"] + const GATEWAY_ENV_HINTS = [ + "ZEE_GATEWAY_TOKEN", + "ZEE_GATEWAY_PASSWORD", + "TELEGRAM_BOT_TOKEN", + "TELEGRAM_USER_PHONE", + "TELEGRAM_API_ID", + "TELEGRAM_API_HASH", + "DISCORD_BOT_TOKEN", + "SLACK_BOT_TOKEN", + "SLACK_APP_TOKEN", + ] const RESTART_DELAY_MS = 2000 const MAX_RESTART_ATTEMPTS = 5 const RESTART_WINDOW_MS = 60_000 // Reset restart counter after 1 minute of stability + const RETRY_BASE_DELAY_MS = 5000 + const RETRY_MAX_DELAY_MS = 60_000 + const RESTART_BACKOFF_MS = 120_000 + const HEALTH_CHECK_INTERVAL_MS = 15_000 + const HEALTH_STARTUP_GRACE_MS = 20_000 + const HEALTH_FAILURES_BEFORE_RESTART = 3 let gatewayProcess: ChildProcess | null = null + let startInFlight = false let restartAttempts = 0 + let retryAttempts = 0 + let retryTimer: NodeJS.Timeout | null = null + let healthTimer: NodeJS.Timeout | null = null + let healthCheckInFlight = false + let healthFailures = 0 + let lastHealthyAt = 0 + let healthRestartInFlight = false + let healthStartedAt = 0 let lastRestartTime = 0 let isShuttingDown = false let gatewayEnabled = false + let forceStart = false + let lastError: string | undefined + let lastExit: { code?: number | null; signal?: NodeJS.Signals | null } | undefined + let lastPreflight: GatewayPreflight | null = null + let gatewayDaemonUrl: string | undefined + + export interface GatewayPreflight { + ok: boolean + issues: string[] + warnings: string[] + configPath?: string + envHints: string[] + repoExists: boolean + packageJsonExists: boolean + pnpmAvailable: boolean + } export interface GatewayState { running: boolean @@ -162,6 +204,140 @@ export namespace GatewaySupervisor { restarts: number lastRestartAt?: number error?: string + enabled: boolean + lastExit?: { code?: number | null; signal?: NodeJS.Signals | null } + configPath?: string + warnings?: string[] + daemonUrl?: string + lastHealthyAt?: number + } + + let resolvedPnpmPath: string | undefined + + function resolvePnpmPath(): string | undefined { + const envPath = process.env.PNPM_BIN?.trim() + if (envPath) return envPath + + const home = process.env.HOME ?? "" + const candidates = [ + "pnpm", + home ? path.join(home, ".local", "bin", "pnpm") : undefined, + ].filter(Boolean) as string[] + + for (const candidate of candidates) { + if (candidate !== "pnpm" && fsSync.existsSync(candidate)) { + return candidate + } + try { + const result = spawnSync(candidate, ["--version"], { stdio: "ignore" }) + if (result.status === 0) return candidate + } catch { + continue + } + } + return undefined + } + + function hasPnpm(): boolean { + try { + resolvedPnpmPath = resolvePnpmPath() + return Boolean(resolvedPnpmPath) + } catch { + resolvedPnpmPath = undefined + return false + } + } + + function getEnvHints(): string[] { + const hints: string[] = [] + for (const key of GATEWAY_ENV_HINTS) { + if (process.env[key]?.trim()) hints.push(key) + } + return hints + } + + async function findZeeConfig(): Promise { + for (const file of ZEE_CONFIG_FILES) { + const candidate = path.join(Zee.dataDir(), file) + try { + await fs.access(candidate) + return candidate + } catch { + // Ignore missing config path + } + } + return undefined + } + + async function runPreflight(options: { force: boolean; checkPort: boolean }): Promise { + const issues: string[] = [] + const warnings: string[] = [] + + let repoExists = true + try { + await fs.access(ZEE_GATEWAY_DIR) + } catch { + repoExists = false + issues.push(`Zee gateway directory not found (${ZEE_GATEWAY_DIR})`) + } + + let packageJsonExists = true + if (repoExists) { + try { + await fs.access(path.join(ZEE_GATEWAY_DIR, "package.json")) + } catch { + packageJsonExists = false + issues.push(`Zee gateway package.json not found (${ZEE_GATEWAY_DIR})`) + } + } else { + packageJsonExists = false + } + + const pnpmAvailable = hasPnpm() + if (!pnpmAvailable) { + issues.push("pnpm not found on PATH") + } + + const configPath = await findZeeConfig() + const envHints = getEnvHints() + const configured = Boolean(configPath || envHints.length) + if (!configured) { + warnings.push("Zee gateway not configured (no config in ~/.zee/zee.json* or provider env vars)") + } + + if (options.checkPort) { + const gatewayPort = getGatewayPort() + const portOpen = await isPortOpen("127.0.0.1", gatewayPort) + if (portOpen) { + const processes = listGatewayProcesses() + if (processes.length > 0) { + issues.push(`Existing Zee gateway process detected on port ${gatewayPort}`) + } else { + issues.push(`Gateway port ${gatewayPort} is already in use`) + } + } + } + + const ok = issues.length === 0 && (warnings.length === 0 || options.force) + return { + ok, + issues, + warnings, + configPath, + envHints, + repoExists, + packageJsonExists, + pnpmAvailable, + } + } + + export async function preflight(options: { force?: boolean; checkPort?: boolean } = {}): Promise { + const result = await runPreflight({ + force: options.force ?? false, + checkPort: options.checkPort ?? false, + }) + lastPreflight = result + return result } export function getState(): GatewayState { @@ -170,46 +346,178 @@ export namespace GatewaySupervisor { pid: gatewayProcess?.pid, restarts: restartAttempts, lastRestartAt: lastRestartTime || undefined, + error: lastError, + enabled: gatewayEnabled, + lastExit, + configPath: lastPreflight?.configPath, + warnings: lastPreflight?.warnings?.length ? lastPreflight.warnings : undefined, + daemonUrl: gatewayDaemonUrl, + lastHealthyAt: lastHealthyAt || undefined, } } - export async function start(): Promise { - if (isShuttingDown) return false - if (gatewayProcess) return true + function stopHealthProbe() { + if (healthTimer) { + clearInterval(healthTimer) + healthTimer = null + } + healthCheckInFlight = false + } - // Check if zee gateway directory exists + async function runHealthProbe() { + if (!gatewayEnabled || isShuttingDown || !gatewayProcess) return + if (healthCheckInFlight) return + + healthCheckInFlight = true try { - await fs.access(ZEE_GATEWAY_DIR) - } catch { - log.warn("zee gateway directory not found", { dir: ZEE_GATEWAY_DIR }) + const gatewayPort = getGatewayPort() + const portOpen = await isPortOpen("127.0.0.1", gatewayPort) + if (portOpen) { + healthFailures = 0 + lastHealthyAt = Date.now() + return + } + + if (Date.now() - healthStartedAt < HEALTH_STARTUP_GRACE_MS) { + return + } + + healthFailures += 1 + log.warn("zee gateway health check failed", { + port: gatewayPort, + failures: healthFailures, + }) + + if (healthFailures >= HEALTH_FAILURES_BEFORE_RESTART) { + restartGateway("health check failures") + } + } finally { + healthCheckInFlight = false + } + } + + function startHealthProbe() { + stopHealthProbe() + healthFailures = 0 + lastHealthyAt = 0 + healthStartedAt = Date.now() + healthTimer = setInterval(() => { + runHealthProbe().catch((err) => { + log.warn("zee gateway health probe error", { error: String(err) }) + }) + }, HEALTH_CHECK_INTERVAL_MS) + } + + function restartGateway(reason: string) { + if (healthRestartInFlight || isShuttingDown) return + if (!gatewayProcess || gatewayProcess.killed) return + + const pid = gatewayProcess.pid + healthRestartInFlight = true + log.warn("restarting zee gateway", { pid, reason }) + + const killTimeout = setTimeout(() => { + if (gatewayProcess && !gatewayProcess.killed) { + log.warn("zee gateway did not stop after health check, sending SIGKILL", { pid }) + gatewayProcess.kill("SIGKILL") + } + }, 5000) + + gatewayProcess.once("exit", () => { + clearTimeout(killTimeout) + healthRestartInFlight = false + }) + + try { + gatewayProcess.kill("SIGTERM") + } catch (error) { + clearTimeout(killTimeout) + healthRestartInFlight = false + log.warn("failed to signal zee gateway for health restart", { pid, error: String(error) }) + } + } + + function scheduleRetry(reason: string, delayOverride?: number): void { + if (!gatewayEnabled || isShuttingDown) return + if (retryTimer) return + + const delay = + delayOverride ?? + Math.min(RETRY_BASE_DELAY_MS * Math.pow(2, retryAttempts), RETRY_MAX_DELAY_MS) + retryAttempts = delayOverride ? 0 : retryAttempts + 1 + + log.warn("scheduling zee gateway retry", { delayMs: delay, reason }) + retryTimer = setTimeout(() => { + retryTimer = null + start({ force: forceStart, daemonUrl: gatewayDaemonUrl }).catch((err) => { + log.error("failed to retry zee gateway start", { error: String(err) }) + }) + }, delay) + } + + export async function start(options: { force?: boolean; daemonUrl?: string } = {}): Promise { + if (isShuttingDown) return false + if (gatewayProcess) { + if (!healthTimer) startHealthProbe() + return true + } + if (startInFlight) return false + + gatewayEnabled = true + forceStart = options.force ?? false + if (options.daemonUrl) { + gatewayDaemonUrl = options.daemonUrl + } + + startInFlight = true + const preflight = await runPreflight({ force: forceStart, checkPort: true }).finally(() => { + startInFlight = false + }) + lastPreflight = preflight + lastError = undefined + if (!preflight.ok) { + lastError = preflight.issues[0] ?? preflight.warnings[0] + if (lastError) log.warn("zee gateway preflight failed", { reason: lastError }) + if (lastError) scheduleRetry(lastError) return false } - // Check if package.json exists - try { - await fs.access(path.join(ZEE_GATEWAY_DIR, "package.json")) - } catch { - log.warn("zee gateway package.json not found", { dir: ZEE_GATEWAY_DIR }) - return false + if (preflight.warnings.length > 0) { + log.warn("zee gateway preflight warnings", { warnings: preflight.warnings }) + } + + if (restartAttempts >= MAX_RESTART_ATTEMPTS) { + restartAttempts = 0 } log.info("starting zee gateway", { dir: ZEE_GATEWAY_DIR }) try { // Use pnpm to start the gateway - gatewayProcess = spawn("pnpm", ["zee", "gateway"], { + const pnpm = resolvedPnpmPath ?? "pnpm" + gatewayProcess = spawn(pnpm, ["zee", "gateway"], { cwd: ZEE_GATEWAY_DIR, stdio: ["ignore", "pipe", "pipe"], detached: false, env: { ...process.env, // Ensure gateway connects back to this daemon - AGENT_CORE_URL: `http://127.0.0.1:${process.env.PORT || 3210}`, + AGENT_CORE_URL: + gatewayDaemonUrl ?? + process.env.AGENT_CORE_URL ?? + `http://127.0.0.1:${process.env.PORT || 3210}`, }, }) gatewayEnabled = true lastRestartTime = Date.now() + lastExit = undefined + retryAttempts = 0 + if (retryTimer) { + clearTimeout(retryTimer) + retryTimer = null + } + startHealthProbe() gatewayProcess.stdout?.on("data", (data: Buffer) => { const lines = data.toString().trim().split("\n") @@ -232,6 +540,9 @@ export namespace GatewaySupervisor { gatewayProcess.on("exit", (code, signal) => { const pid = gatewayProcess?.pid gatewayProcess = null + lastExit = { code, signal } + stopHealthProbe() + healthRestartInFlight = false if (isShuttingDown) { log.info("zee gateway stopped during shutdown", { pid, code, signal }) @@ -239,6 +550,7 @@ export namespace GatewaySupervisor { } log.warn("zee gateway exited", { pid, code, signal }) + lastError = `zee gateway exited (code: ${code ?? "unknown"}, signal: ${signal ?? "unknown"})` // Reset restart counter if running stably for RESTART_WINDOW_MS const now = Date.now() @@ -247,7 +559,7 @@ export namespace GatewaySupervisor { } // Auto-restart if under limit - if (restartAttempts < MAX_RESTART_ATTEMPTS) { + if (gatewayEnabled && restartAttempts < MAX_RESTART_ATTEMPTS) { restartAttempts++ log.info("scheduling zee gateway restart", { attempt: restartAttempts, @@ -256,29 +568,36 @@ export namespace GatewaySupervisor { }) setTimeout(() => { if (!isShuttingDown) { - start().catch((err) => { + start({ force: forceStart, daemonUrl: gatewayDaemonUrl }).catch((err) => { log.error("failed to restart zee gateway", { error: String(err) }) }) } }, RESTART_DELAY_MS) } else { - log.error("zee gateway restart limit reached", { + log.error("zee gateway restart limit reached; backing off", { attempts: restartAttempts, maxAttempts: MAX_RESTART_ATTEMPTS, + backoffMs: RESTART_BACKOFF_MS, }) + restartAttempts = 0 + lastError = "zee gateway restart limit reached; backing off before retry" + scheduleRetry(lastError, RESTART_BACKOFF_MS) } }) gatewayProcess.on("error", (err) => { log.error("zee gateway process error", { error: err.message }) + lastError = err.message }) log.info("zee gateway started", { pid: gatewayProcess.pid }) return true } catch (error) { + lastError = error instanceof Error ? error.message : String(error) log.error("failed to start zee gateway", { - error: error instanceof Error ? error.message : String(error), + error: lastError, }) + scheduleRetry(lastError) return false } } @@ -286,6 +605,13 @@ export namespace GatewaySupervisor { export async function stop(): Promise { isShuttingDown = true gatewayEnabled = false + forceStart = false + retryAttempts = 0 + stopHealthProbe() + if (retryTimer) { + clearTimeout(retryTimer) + retryTimer = null + } if (!gatewayProcess) return @@ -316,6 +642,51 @@ export namespace GatewaySupervisor { } } +async function isPortOpen(host: string, port: number): Promise { + return await new Promise((resolve) => { + const socket = net.createConnection({ host, port }) + const timeout = setTimeout(() => { + socket.destroy() + resolve(false) + }, 1000) + + socket.once("connect", () => { + clearTimeout(timeout) + socket.end() + resolve(true) + }) + socket.once("error", () => { + clearTimeout(timeout) + resolve(false) + }) + }) +} + +function getGatewayPort(): number { + const portRaw = Number.parseInt(process.env.ZEE_GATEWAY_PORT ?? "", 10) + return Number.isFinite(portRaw) ? portRaw : 18789 +} + +function listGatewayProcesses(): Array<{ pid: number; cmd: string }> { + try { + const output = execSync('pgrep -af "zee.*gateway" 2>/dev/null || true', { + encoding: "utf-8", + }) + const lines = output.trim().split("\n").filter(Boolean) + return lines + .map((line) => { + const match = line.match(/^(\d+)\s+(.*)$/) + if (!match) return null + const cmd = match[2] + if (cmd.includes("pgrep")) return null + return { pid: Number.parseInt(match[1], 10), cmd } + }) + .filter((entry): entry is { pid: number; cmd: string } => Boolean(entry)) + } catch { + return [] + } +} + export const DaemonCommand = cmd({ command: "daemon", builder: (yargs) => @@ -350,6 +721,11 @@ export const DaemonCommand = cmd({ describe: "Start zee messaging gateway (WhatsApp/Telegram/Signal)", type: "boolean", default: true, + }) + .option("gateway-force", { + describe: "Start zee gateway even if preflight checks fail", + type: "boolean", + default: false, }), describe: "Start agent-core as a headless daemon for remote access", handler: async (args) => { @@ -392,6 +768,10 @@ export const DaemonCommand = cmd({ // Start the server const server = Server.listen(opts) + const serverHost = server.hostname ?? opts.hostname + const daemonHost = serverHost === "0.0.0.0" ? "127.0.0.1" : serverHost + const daemonPort = server.port ?? opts.port + const daemonUrl = `http://${daemonHost}:${daemonPort}` // Write PID file const state: Daemon.DaemonState = { @@ -470,11 +850,14 @@ export const DaemonCommand = cmd({ // Start zee gateway if enabled let gatewayStarted = false if (args.gateway) { - gatewayStarted = await GatewaySupervisor.start() + const gatewayForce = Boolean(args["gateway-force"]) + gatewayStarted = await GatewaySupervisor.start({ force: gatewayForce, daemonUrl }) + const gatewayState = GatewaySupervisor.getState() if (gatewayStarted) { console.log("Gateway: Messaging gateway started (WhatsApp/Telegram/Signal)") } else { - console.log("Gateway: Not available (zee gateway not found)") + const reason = gatewayState.error ?? "Not available" + console.log(`Gateway: Disabled (${reason})`) } } @@ -531,10 +914,11 @@ export const DaemonCommand = cmd({ const persistenceStatus = persistenceEnabled ? "Active (checkpoints + WAL)" : "Disabled" const weztermStatus = weztermEnabled ? "Active (status pane)" : args.wezterm ? "No display" : "Disabled" + const gatewayState = GatewaySupervisor.getState() const gatewayStatus = gatewayStarted - ? `Active (PID: ${GatewaySupervisor.getState().pid})` + ? `Active (PID: ${gatewayState.pid})` : args.gateway - ? "Not available (zee not found)" + ? `Disabled (${gatewayState.error ?? "not configured"})` : "Disabled" console.log(` @@ -576,7 +960,7 @@ Press Ctrl+C to stop the daemon. } // Emit daemon.ready hook - daemon is fully initialized - // Note: telegram/whatsapp/discord are false because messaging is handled by external zee gateway + // Note: messaging is handled by the embedded Zee gateway (managed by the daemon) await LifecycleHooks.emitDaemonReady({ pid: process.pid, port: state.port, @@ -658,3 +1042,41 @@ export const DaemonStopCommand = cmd({ } }, }) + +export const GatewayStatusCommand = cmd({ + command: "gateway-status", + describe: "Check Zee gateway configuration and reachability", + handler: async () => { + const preflight = await GatewaySupervisor.preflight({ force: true }) + const zeeDir = Zee.repo() + const port = getGatewayPort() + const portOpen = await isPortOpen("127.0.0.1", port) + const processes = listGatewayProcesses() + const gatewayState = GatewaySupervisor.getState() + + console.log("Zee Gateway Status") + console.log(` Repo: ${preflight.repoExists ? zeeDir : `Missing (${zeeDir})`}`) + console.log(` Config: ${preflight.configPath ?? "Not found"}`) + console.log(` pnpm: ${preflight.pnpmAvailable ? "Found" : "Missing"}`) + console.log(` Port: ${port} (${portOpen ? "listening" : "closed"})`) + console.log(` Daemon: ${gatewayState.daemonUrl ?? "unknown"}`) + console.log(` Env: ${preflight.envHints.length ? preflight.envHints.join(", ") : "none"}`) + + if (processes.length > 0) { + console.log(" Processes:") + for (const proc of processes) { + console.log(` ${proc.pid} ${proc.cmd}`) + } + } else { + console.log(" Processes: none") + } + + const issues = [...preflight.issues, ...preflight.warnings] + if (issues.length > 0) { + console.log(" Issues:") + for (const issue of issues) { + console.log(` - ${issue}`) + } + } + }, +}) diff --git a/packages/agent-core/src/cli/cmd/debug/memory.ts b/packages/agent-core/src/cli/cmd/debug/memory.ts index a48b7826ed..3e3863f48d 100644 --- a/packages/agent-core/src/cli/cmd/debug/memory.ts +++ b/packages/agent-core/src/cli/cmd/debug/memory.ts @@ -1,8 +1,9 @@ import { cmd } from "../cmd" import { bootstrap } from "../../bootstrap" +import { Config } from "../../../config/config" -/** Default Qdrant URL, configurable via environment */ -const DEFAULT_QDRANT_URL = process.env.QDRANT_URL ?? "http://localhost:6333" +const FALLBACK_QDRANT_URL = "http://localhost:6333" +const FALLBACK_QDRANT_COLLECTION = "agent_memory" export const MemoryCommand = cmd({ command: "memory", @@ -11,7 +12,6 @@ export const MemoryCommand = cmd({ yargs .option("qdrant-url", { type: "string", - default: DEFAULT_QDRANT_URL, describe: "Qdrant server URL", }) .command(StatsMemoryCommand) @@ -36,8 +36,11 @@ const StatsMemoryCommand = cmd({ try { // Dynamic import to avoid hard dependency + const qdrant = await resolveQdrantConfig({ + url: typeof args.qdrantUrl === "string" ? args.qdrantUrl : undefined, + }) const { QdrantClient } = await import("@qdrant/js-client-rest") - const client = new QdrantClient({ url: DEFAULT_QDRANT_URL }) + const client = new QdrantClient({ url: qdrant.url, apiKey: qdrant.apiKey }) // Get collections const collections = await client.getCollections() @@ -144,7 +147,6 @@ const SearchMemoryCommand = cmd({ .option("collection", { alias: "c", type: "string", - default: "agent_memory", describe: "collection to search", }) .option("limit", { @@ -207,11 +209,15 @@ const SearchMemoryCommand = cmd({ console.log("") try { + const qdrant = await resolveQdrantConfig({ + url: typeof args.qdrantUrl === "string" ? args.qdrantUrl : undefined, + collection: typeof args.collection === "string" ? args.collection : undefined, + }) const { QdrantClient } = await import("@qdrant/js-client-rest") - const client = new QdrantClient({ url: DEFAULT_QDRANT_URL }) + const client = new QdrantClient({ url: qdrant.url, apiKey: qdrant.apiKey }) - const info = await client.getCollection(args.collection) - console.log(`Collection: ${args.collection}`) + const info = await client.getCollection(qdrant.collection) + console.log(`Collection: ${qdrant.collection}`) console.log(` Points: ${info.points_count ?? 0}`) console.log(` Vectors: ${info.indexed_vectors_count ?? 0}`) console.log("") @@ -226,6 +232,34 @@ const SearchMemoryCommand = cmd({ }, }) +async function resolveQdrantConfig(opts: { + url?: string + collection?: string +}): Promise<{ url: string; collection: string; apiKey?: string }> { + let url = opts.url?.trim() + let collection = opts.collection?.trim() + let apiKey: string | undefined + + if (!url || !collection || !apiKey) { + try { + const config = await Config.get() + const memory = config.memory ?? {} + const qdrant = memory.qdrant ?? {} + url = url || qdrant.url || memory.qdrantUrl + collection = collection || qdrant.collection || memory.qdrantCollection + apiKey = apiKey || qdrant.apiKey || memory.qdrantApiKey + } catch { + // Ignore config errors and fall back to defaults. + } + } + + return { + url: url || FALLBACK_QDRANT_URL, + collection: collection || FALLBACK_QDRANT_COLLECTION, + apiKey, + } +} + function formatBytes(bytes: number): string { if (bytes < 1024) return `${bytes}B` if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)}KB` diff --git a/packages/agent-core/src/cli/cmd/debug/status.ts b/packages/agent-core/src/cli/cmd/debug/status.ts index 0db7dbb0b5..118c219e5f 100644 --- a/packages/agent-core/src/cli/cmd/debug/status.ts +++ b/packages/agent-core/src/cli/cmd/debug/status.ts @@ -6,6 +6,20 @@ import { Global } from "../../../global" import { Flag } from "../../../flag/flag" import fs from "fs/promises" import path from "path" +import net from "net" +import { Zee } from "../../../paths" + +const GATEWAY_ENV_HINTS = [ + "ZEE_GATEWAY_TOKEN", + "ZEE_GATEWAY_PASSWORD", + "TELEGRAM_BOT_TOKEN", + "TELEGRAM_USER_PHONE", + "TELEGRAM_API_ID", + "TELEGRAM_API_HASH", + "DISCORD_BOT_TOKEN", + "SLACK_BOT_TOKEN", + "SLACK_APP_TOKEN", +] export const StatusCommand = cmd({ command: "status", @@ -67,6 +81,18 @@ interface SystemStatus { provider?: string model?: string } + gateway: { + configured: boolean + port: number + listening: boolean + configPath?: string + envHints: string[] + processes: Array<{ + pid: number + cmd: string + }> + issues: string[] + } sources: Array<{ file: string modifiedAt: string @@ -94,6 +120,14 @@ async function collectStatus(verbose: boolean): Promise { config: { directories: [], }, + gateway: { + configured: false, + port: 18789, + listening: false, + envHints: [], + processes: [], + issues: [], + }, sources: [], issues: [], } @@ -172,6 +206,41 @@ async function collectStatus(verbose: boolean): Promise { } } + // Gateway status + const gatewayPort = getGatewayPort() + status.gateway.port = gatewayPort + status.gateway.envHints = getGatewayEnvHints() + status.gateway.configPath = await findZeeConfig() + status.gateway.configured = Boolean(status.gateway.configPath || status.gateway.envHints.length > 0) + + try { + status.gateway.listening = await isPortOpen("127.0.0.1", gatewayPort) + } catch { + status.gateway.listening = false + } + + try { + const { execSync } = await import("child_process") + const gatewayOutput = execSync('pgrep -af "zee.*gateway" 2>/dev/null || true', { encoding: "utf-8" }) + const lines = gatewayOutput.trim().split("\n").filter(Boolean) + status.gateway.processes = lines + .map((line) => { + const match = line.match(/^(\d+)\s+(.*)$/) + if (!match) return null + const cmd = match[2] + if (cmd.includes("pgrep")) return null + return { pid: Number.parseInt(match[1], 10), cmd } + }) + .filter((entry): entry is { pid: number; cmd: string } => Boolean(entry)) + } catch { + // Ignore gateway process check errors + } + + if (status.gateway.configured && !status.gateway.listening) { + status.gateway.issues.push("Gateway configured but not listening") + status.issues.push("Gateway configured but not listening") + } + // Tool directories const configDirs = await Config.directories() status.config.directories = configDirs @@ -296,6 +365,34 @@ function printStatus(status: SystemStatus, verbose: boolean) { } console.log("") + // Gateway + console.log(`${BLUE}Gateway:${RESET}`) + console.log(` Port: ${status.gateway.port}`) + if (status.gateway.listening) { + console.log(` ${ok("Listening")}`) + } else if (status.gateway.configured) { + console.log(` ${warn("Configured but not listening")}`) + } else { + console.log(` ${warn("Not configured")}`) + } + if (status.gateway.configPath) { + console.log(` Config: ${status.gateway.configPath}`) + } + if (status.gateway.envHints.length > 0) { + console.log(` Env: ${status.gateway.envHints.join(", ")}`) + } + if (verbose) { + if (status.gateway.processes.length > 0) { + console.log(" Processes:") + for (const proc of status.gateway.processes) { + console.log(` ${DIM}${proc.pid} ${proc.cmd}${RESET}`) + } + } else { + console.log(` ${DIM}Processes: none${RESET}`) + } + } + console.log("") + // Tools console.log(`${BLUE}Tools:${RESET}`) if (status.tools.directories.length === 0) { @@ -350,3 +447,45 @@ function printStatus(status: SystemStatus, verbose: boolean) { } } } + +function getGatewayPort(): number { + const portRaw = Number.parseInt(process.env.ZEE_GATEWAY_PORT || "", 10) + return Number.isFinite(portRaw) ? portRaw : 18789 +} + +function getGatewayEnvHints(): string[] { + return GATEWAY_ENV_HINTS.filter((key) => Boolean(process.env[key]?.trim())) +} + +async function findZeeConfig(): Promise { + const candidates = ["zee.json", "zee.jsonc"].map((file) => path.join(Zee.dataDir(), file)) + for (const candidate of candidates) { + try { + await fs.access(candidate) + return candidate + } catch { + // Ignore missing config path + } + } + return undefined +} + +async function isPortOpen(host: string, port: number): Promise { + return await new Promise((resolve) => { + const socket = net.createConnection({ host, port }) + const timeout = setTimeout(() => { + socket.destroy() + resolve(false) + }, 1000) + + socket.once("connect", () => { + clearTimeout(timeout) + socket.end() + resolve(true) + }) + socket.once("error", () => { + clearTimeout(timeout) + resolve(false) + }) + }) +} diff --git a/packages/agent-core/src/cli/cmd/mcp.ts b/packages/agent-core/src/cli/cmd/mcp.ts index 12d702eea2..4af557f0d4 100644 --- a/packages/agent-core/src/cli/cmd/mcp.ts +++ b/packages/agent-core/src/cli/cmd/mcp.ts @@ -381,12 +381,15 @@ export const McpLogoutCommand = cmd({ async function resolveConfigPath(baseDir: string, global = false) { // Check for existing config files (prefer .jsonc over .json, check .agent-core/ subdirectory too) - const candidates = [path.join(baseDir, "agent-core.json"), path.join(baseDir, "agent-core.jsonc")] + const candidates = [ + path.join(baseDir, "agent-core.jsonc"), + path.join(baseDir, "agent-core.json"), + ] if (!global) { candidates.push( - path.join(baseDir, ".agent-core", "agent-core.json"), path.join(baseDir, ".agent-core", "agent-core.jsonc"), + path.join(baseDir, ".agent-core", "agent-core.json"), ) } @@ -396,7 +399,7 @@ async function resolveConfigPath(baseDir: string, global = false) { } } - // Default to agent-core.json if none exist + // Default to agent-core.jsonc if none exist return candidates[0] } diff --git a/packages/agent-core/src/cli/cmd/tui/app.tsx b/packages/agent-core/src/cli/cmd/tui/app.tsx index 7d691264b1..e0aedacae7 100644 --- a/packages/agent-core/src/cli/cmd/tui/app.tsx +++ b/packages/agent-core/src/cli/cmd/tui/app.tsx @@ -483,7 +483,7 @@ function App() { title: "Open docs", value: "docs.open", onSelect: () => { - open("https://opencode.ai/docs").catch(() => {}) + open("https://github.com/adolago/agent-core/tree/dev/docs").catch(() => {}) dialog.clear() }, category: "System", @@ -694,7 +694,7 @@ function ErrorComponent(props: { }) const [copied, setCopied] = createSignal(false) - const issueURL = new URL("https://github.com/anomalyco/opencode/issues/new?template=bug-report.yml") + const issueURL = new URL("https://github.com/adolago/agent-core/issues/new?template=bug-report.yml") // Choose safe fallback colors per mode since theme context may not be available const isLight = props.mode === "light" @@ -716,7 +716,7 @@ function ErrorComponent(props: { ) } - issueURL.searchParams.set("opencode-version", Installation.VERSION) + issueURL.searchParams.set("agent-core-version", Installation.VERSION) const copyIssueURL = () => { Clipboard.copy(issueURL.toString()).then(() => { diff --git a/packages/agent-core/src/cli/cmd/tui/component/dialog-status.tsx b/packages/agent-core/src/cli/cmd/tui/component/dialog-status.tsx index c08fc99b6e..b0ae2a0bd7 100644 --- a/packages/agent-core/src/cli/cmd/tui/component/dialog-status.tsx +++ b/packages/agent-core/src/cli/cmd/tui/component/dialog-status.tsx @@ -76,7 +76,7 @@ export function DialogStatus() { {(val) => val().error} Disabled in configuration - Needs authentication (run: opencode mcp auth {key}) + Needs authentication (run: agent-core mcp auth {key}) {(val) => (val() as { error: string }).error} diff --git a/packages/agent-core/src/cli/cmd/tui/component/prompt/autocomplete.tsx b/packages/agent-core/src/cli/cmd/tui/component/prompt/autocomplete.tsx index 4c158adde5..8b1edff41a 100644 --- a/packages/agent-core/src/cli/cmd/tui/component/prompt/autocomplete.tsx +++ b/packages/agent-core/src/cli/cmd/tui/component/prompt/autocomplete.tsx @@ -289,7 +289,7 @@ export function Autocomplete(props: { const options: AutocompleteOption[] = [] const width = props.anchor().width - 4 - for (const res of Object.values(sync.data.mcp_resource)) { + for (const res of Object.values(sync.data?.mcp_resource ?? {})) { const text = `${res.name} (${res.uri})` options.push({ display: Locale.truncateMiddle(text, width), @@ -320,8 +320,9 @@ export function Autocomplete(props: { }) const agents = createMemo(() => { - const agents = sync.data.agent - return agents + const agentList = sync.data?.agent + if (!agentList || !Array.isArray(agentList)) return [] + return agentList .filter((agent) => !agent.hidden && agent.mode !== "primary") .map( (agent): AutocompleteOption => ({ @@ -347,12 +348,12 @@ export function Autocomplete(props: { return { ...item, display, - value: display, + value: item.value ?? display, aliases: item.aliases?.map((alias) => (alias.startsWith("/") ? ":" + alias.slice(1) : alias)), } }) - for (const serverCommand of sync.data.command) { + for (const serverCommand of sync.data?.command ?? []) { const commandName = ":" + serverCommand.name results.push({ display: commandName + (serverCommand.mcp ? " (MCP)" : ""), diff --git a/packages/agent-core/src/cli/cmd/tui/component/prompt/index.tsx b/packages/agent-core/src/cli/cmd/tui/component/prompt/index.tsx index 2fbc11dd09..af656860f9 100644 --- a/packages/agent-core/src/cli/cmd/tui/component/prompt/index.tsx +++ b/packages/agent-core/src/cli/cmd/tui/component/prompt/index.tsx @@ -83,7 +83,7 @@ export function Prompt(props: PromptProps) { message: "Connect a provider to send prompts", duration: 3000, }) - if (sync.data.provider.length === 0) { + if (sync.data?.provider?.length ?? 0 === 0) { dialog.replace(() => ) } } @@ -93,14 +93,14 @@ export function Prompt(props: PromptProps) { // Track incomplete todos for hint display const incompleteTodos = createMemo(() => { if (!props.sessionID) return [] - const todos = sync.data.todo[props.sessionID] ?? [] + const todos = sync.data?.todo?.[props.sessionID] ?? [] return todos.filter((t) => t.status !== "completed" && t.status !== "cancelled") }) const todoHint = createMemo(() => { const incomplete = incompleteTodos() if (incomplete.length === 0) return null - const todos = sync.data.todo[props.sessionID ?? ""] ?? [] + const todos = sync.data?.todo?.[props.sessionID ?? ""] ?? [] const completed = todos.filter((t) => t.status === "completed").length const inProgress = incomplete.find((t) => t.status === "in_progress") return { @@ -132,7 +132,7 @@ export function Prompt(props: PromptProps) { const lastUserMessage = createMemo(() => { if (!props.sessionID) return undefined - const messages = sync.data.message[props.sessionID] + const messages = sync.data?.message?.[props.sessionID] if (!messages) return undefined return messages.findLast((m) => m.role === "user") }) @@ -663,7 +663,7 @@ export function Prompt(props: PromptProps) { iife(() => { const command = inputText.split(" ")[0].slice(1) console.log(command) - return sync.data.command.some((x) => x.name === command) + return sync.data?.command?.some((x) => x.name === command) }) ) { let [command, ...args] = inputText.split(" ") @@ -1024,7 +1024,7 @@ export function Prompt(props: PromptProps) { const lineCount = (pastedContent.match(/\n/g)?.length ?? 0) + 1 if ( (lineCount >= 3 || pastedContent.length > 150) && - !sync.data.config.experimental?.disable_paste_summary + !sync.data?.config?.experimental?.disable_paste_summary ) { event.preventDefault() pasteText(pastedContent, `[Pasted ~${lineCount} lines]`) diff --git a/packages/agent-core/src/cli/cmd/tui/context/local.tsx b/packages/agent-core/src/cli/cmd/tui/context/local.tsx index 257c85a612..474d1876bb 100644 --- a/packages/agent-core/src/cli/cmd/tui/context/local.tsx +++ b/packages/agent-core/src/cli/cmd/tui/context/local.tsx @@ -21,7 +21,9 @@ export const { use: useLocal, provider: LocalProvider } = createSimpleContext({ const toast = useToast() function isModelValid(model: { providerID: string; modelID: string }) { - const provider = sync.data.provider.find((x) => x.id === model.providerID) + const providers = sync.data?.provider + if (!providers || !Array.isArray(providers)) return false + const provider = providers.find((x) => x.id === model.providerID) return !!provider?.models[model.modelID] } @@ -34,16 +36,17 @@ export const { use: useLocal, provider: LocalProvider } = createSimpleContext({ } const agent = iife(() => { - const agents = createMemo( - () => - sync.data.agent - .filter((x) => x.mode !== "subagent" && !x.hidden) - .sort((a, b) => b.name.localeCompare(a.name)), // Reverse alpha: Zee, Stanley, Johny - ) + const agents = createMemo(() => { + const list = sync.data?.agent + if (!list || !Array.isArray(list)) return [] + return list + .filter((x) => x.mode !== "subagent" && !x.hidden) + .sort((a, b) => b.name.localeCompare(a.name)) // Reverse alpha: Zee, Stanley, Johny + }) const [agentStore, setAgentStore] = createStore<{ current: string }>({ - current: agents()[0]?.name ?? "", + current: agents()?.[0]?.name ?? "", }) // Effect to initialize agent selection when agents load @@ -84,14 +87,15 @@ export const { use: useLocal, provider: LocalProvider } = createSimpleContext({ return { list() { - return agents() + return agents() ?? [] }, current() { + const list = agents() ?? [] // Find matching agent, or fallback to first agent if current doesn't match - const found = agents().find((x) => x.name === agentStore.current) + const found = list.find((x) => x.name === agentStore.current) if (found) return found // Update store to first agent if we had a stale value - const first = agents()[0] + const first = list[0] if (first) { if (agentStore.current !== first.name) { setAgentStore("current", first.name) @@ -102,7 +106,8 @@ export const { use: useLocal, provider: LocalProvider } = createSimpleContext({ return placeholderAgent }, set(name: string) { - if (!agents().some((x) => x.name === name)) + const list = agents() ?? [] + if (!list.some((x) => x.name === name)) return toast.show({ variant: "warning", message: `Agent not found: ${name}`, @@ -112,15 +117,18 @@ export const { use: useLocal, provider: LocalProvider } = createSimpleContext({ }, move(direction: 1 | -1) { batch(() => { - let next = agents().findIndex((x) => x.name === agentStore.current) + direction - if (next < 0) next = agents().length - 1 - if (next >= agents().length) next = 0 - const value = agents()[next] - setAgentStore("current", value.name) + const list = agents() ?? [] + if (list.length === 0) return + let next = list.findIndex((x) => x.name === agentStore.current) + direction + if (next < 0) next = list.length - 1 + if (next >= list.length) next = 0 + const value = list[next] + if (value) setAgentStore("current", value.name) }) }, color(name: string) { - const all = sync.data.agent + const all = sync.data?.agent + if (!all || !Array.isArray(all)) return colors()[0] const agent = all.find((x) => x.name === name) if (agent?.color) return RGBA.fromHex(agent.color) const index = all.findIndex((x) => x.name === name) diff --git a/packages/agent-core/src/cli/cmd/tui/util/clipboard.ts b/packages/agent-core/src/cli/cmd/tui/util/clipboard.ts index 0e287fbc41..eaee16c645 100644 --- a/packages/agent-core/src/cli/cmd/tui/util/clipboard.ts +++ b/packages/agent-core/src/cli/cmd/tui/util/clipboard.ts @@ -30,7 +30,7 @@ export namespace Clipboard { const os = platform() if (os === "darwin") { - const tmpfile = path.join(tmpdir(), "opencode-clipboard.png") + const tmpfile = path.join(tmpdir(), "agent-core-clipboard.png") try { await $`osascript -e 'set imageData to the clipboard as "PNGf"' -e 'set fileRef to open for access POSIX file "${tmpfile}" with write permission' -e 'set eof fileRef to 0' -e 'write imageData to fileRef' -e 'close access fileRef'` .nothrow() diff --git a/packages/agent-core/src/cli/cmd/uninstall.ts b/packages/agent-core/src/cli/cmd/uninstall.ts index 27be4533d4..4e9ac11161 100644 --- a/packages/agent-core/src/cli/cmd/uninstall.ts +++ b/packages/agent-core/src/cli/cmd/uninstall.ts @@ -128,11 +128,11 @@ async function showRemovalSummary(targets: RemovalTargets, method: Installation. if (method !== "curl" && method !== "unknown") { const cmds: Record = { - npm: "npm uninstall -g opencode-ai", - pnpm: "pnpm uninstall -g opencode-ai", - bun: "bun remove -g opencode-ai", - yarn: "yarn global remove opencode-ai", - brew: "brew uninstall opencode", + npm: "npm uninstall -g agent-core-ai", + pnpm: "pnpm uninstall -g agent-core-ai", + bun: "bun remove -g agent-core-ai", + yarn: "yarn global remove agent-core-ai", + brew: "brew uninstall agent-core", choco: "choco uninstall opencode", scoop: "scoop uninstall opencode", } @@ -179,11 +179,11 @@ async function executeUninstall(method: Installation.Method, targets: RemovalTar if (method !== "curl" && method !== "unknown") { const cmds: Record = { - npm: ["npm", "uninstall", "-g", "opencode-ai"], - pnpm: ["pnpm", "uninstall", "-g", "opencode-ai"], - bun: ["bun", "remove", "-g", "opencode-ai"], - yarn: ["yarn", "global", "remove", "opencode-ai"], - brew: ["brew", "uninstall", "opencode"], + npm: ["npm", "uninstall", "-g", "agent-core-ai"], + pnpm: ["pnpm", "uninstall", "-g", "agent-core-ai"], + bun: ["bun", "remove", "-g", "agent-core-ai"], + yarn: ["yarn", "global", "remove", "agent-core-ai"], + brew: ["brew", "uninstall", "agent-core"], choco: ["choco", "uninstall", "opencode"], scoop: ["scoop", "uninstall", "opencode"], } diff --git a/packages/agent-core/src/cli/cmd/upgrade.ts b/packages/agent-core/src/cli/cmd/upgrade.ts index 16a7b8c12d..9046ee404c 100644 --- a/packages/agent-core/src/cli/cmd/upgrade.ts +++ b/packages/agent-core/src/cli/cmd/upgrade.ts @@ -27,7 +27,7 @@ export const UpgradeCommand = { const detectedMethod = await Installation.method() const method = (args.method as Installation.Method) ?? detectedMethod if (method === "unknown") { - prompts.log.error(`opencode is installed to ${process.execPath} and may be managed by a package manager`) + prompts.log.error(`agent-core is installed to ${process.execPath} and may be managed by a package manager`) const install = await prompts.select({ message: "Install anyways?", options: [ @@ -45,7 +45,7 @@ export const UpgradeCommand = { const target = args.target ? args.target.replace(/^v/, "") : await Installation.latest() if (Installation.VERSION === target) { - prompts.log.warn(`opencode upgrade skipped: ${target} is already installed`) + prompts.log.warn(`agent-core upgrade skipped: ${target} is already installed`) prompts.outro("Done") return } diff --git a/packages/agent-core/src/config/config.ts b/packages/agent-core/src/config/config.ts index f8019db5c0..25f2c51bd3 100644 --- a/packages/agent-core/src/config/config.ts +++ b/packages/agent-core/src/config/config.ts @@ -992,6 +992,67 @@ export namespace Config { }) export type Provider = z.infer + export const Memory = z + .object({ + backend: z.enum(["file", "redis", "qdrant"]).optional().describe("Memory backend"), + storagePath: z.string().optional().describe("Storage path for file backend"), + redisUrl: z.string().optional().describe("Redis connection URL"), + qdrantUrl: z.string().optional().describe("Qdrant endpoint URL"), + qdrantApiKey: z.string().optional().describe("Qdrant API key"), + qdrantCollection: z.string().optional().describe("Qdrant collection for memory"), + qdrant: z + .object({ + url: z.string().optional().describe("Qdrant endpoint URL"), + apiKey: z.string().optional().describe("Qdrant API key"), + collection: z.string().optional().describe("Qdrant collection for memory"), + }) + .optional() + .describe("Nested Qdrant configuration"), + embedding: z + .object({ + profile: z.string().optional().describe("Embedding profile (e.g. openai/text-embedding-3-small)"), + provider: z.string().optional().describe("Embedding provider ID"), + model: z.string().optional().describe("Embedding model name"), + dimensions: z.number().int().positive().optional().describe("Embedding vector dimensions"), + dimension: z.number().int().positive().optional().describe("Alias for dimensions"), + apiKey: z.string().optional().describe("Embedding API key"), + baseUrl: z.string().optional().describe("Embedding API base URL"), + }) + .optional() + .describe("Embedding provider configuration"), + defaultTtl: z.number().int().nonnegative().optional().describe("Default TTL in seconds"), + autoSaveInterval: z.number().int().nonnegative().optional().describe("Auto-save interval in ms"), + compression: z.boolean().optional().describe("Enable compression"), + namespace: z.string().optional().describe("Memory namespace"), + }) + .strict() + .meta({ + ref: "MemoryConfig", + }) + + export const Tiara = z + .object({ + qdrant: z + .object({ + url: z.string().optional().describe("Qdrant endpoint URL"), + apiKey: z.string().optional().describe("Qdrant API key"), + stateCollection: z.string().optional().describe("Collection for personas state"), + memoryCollection: z.string().optional().describe("Collection for personas memory"), + embeddingDimension: z + .number() + .int() + .positive() + .optional() + .describe("Embedding dimension for tiara Qdrant collections"), + }) + .optional() + .describe("Qdrant configuration for tiara"), + }) + .strict() + .meta({ + ref: "TiaraConfig", + }) + export const Info = z .object({ $schema: z.string().optional().describe("JSON schema reference for configuration validation"), @@ -1104,6 +1165,8 @@ export namespace Config { ) .optional() .describe("MCP (Model Context Protocol) server configurations"), + memory: Memory.optional().describe("Memory and storage configuration"), + tiara: Tiara.optional().describe("Tiara orchestration configuration"), formatter: z .union([ z.literal(false), diff --git a/packages/agent-core/src/diagnostics/check-engine.ts b/packages/agent-core/src/diagnostics/check-engine.ts index 17cdef0ccc..7cb32b833f 100644 --- a/packages/agent-core/src/diagnostics/check-engine.ts +++ b/packages/agent-core/src/diagnostics/check-engine.ts @@ -169,6 +169,8 @@ export class CheckEngine { } } + const clampedDurationMs = Math.max(1, durationMs); + return { timestamp: new Date().toISOString(), version: process.env.AGENT_CORE_VERSION || "dev", @@ -184,7 +186,7 @@ export class CheckEngine { categories, checks: results, fixes, - durationMs, + durationMs: clampedDurationMs, }; } } diff --git a/packages/agent-core/src/diagnostics/checks/config.ts b/packages/agent-core/src/diagnostics/checks/config.ts index c70eaaf559..c76de99121 100644 --- a/packages/agent-core/src/diagnostics/checks/config.ts +++ b/packages/agent-core/src/diagnostics/checks/config.ts @@ -21,6 +21,7 @@ const DEPRECATED_OPTIONS = [ const RECOMMENDED_ENV_VARS = [ { name: "ANTHROPIC_API_KEY", description: "Anthropic Claude API key" }, { name: "OPENAI_API_KEY", description: "OpenAI API key" }, + { name: "NEBIUS_API_KEY", description: "Nebius embeddings API key" }, { name: "GOOGLE_API_KEY", description: "Google Gemini API key" }, ]; diff --git a/packages/agent-core/src/diagnostics/checks/integrity.ts b/packages/agent-core/src/diagnostics/checks/integrity.ts index 180512a25c..f7943da447 100644 --- a/packages/agent-core/src/diagnostics/checks/integrity.ts +++ b/packages/agent-core/src/diagnostics/checks/integrity.ts @@ -6,15 +6,208 @@ import * as fs from "fs/promises"; import * as path from "path"; import * as os from "os"; +import { execSync } from "child_process"; +import net from "net"; import type { CheckResult, CheckOptions } from "../types"; +import { Zee } from "../../paths"; const STALE_THRESHOLD_MS = 30 * 60 * 1000; // 30 minutes +const ZEE_CONFIG_FILES = ["zee.json", "zee.jsonc"]; +const GATEWAY_ENV_HINTS = [ + "ZEE_GATEWAY_TOKEN", + "ZEE_GATEWAY_PASSWORD", + "TELEGRAM_BOT_TOKEN", + "TELEGRAM_USER_PHONE", + "TELEGRAM_API_ID", + "TELEGRAM_API_HASH", + "DISCORD_BOT_TOKEN", + "SLACK_BOT_TOKEN", + "SLACK_APP_TOKEN", +]; function getStateDir(): string { return process.env.AGENT_CORE_STATE_DIR || path.join(os.homedir(), ".local", "state", "agent-core"); } +function getGatewayPort(): number { + const portRaw = Number.parseInt(process.env.ZEE_GATEWAY_PORT ?? "", 10); + return Number.isFinite(portRaw) ? portRaw : 18789; +} + +function getGatewayEnvHints(): string[] { + return GATEWAY_ENV_HINTS.filter((key) => Boolean(process.env[key]?.trim())); +} + +async function findZeeConfig(): Promise { + for (const file of ZEE_CONFIG_FILES) { + const candidate = path.join(Zee.dataDir(), file); + try { + await fs.access(candidate); + return candidate; + } catch { + // Ignore missing config path + } + } + return undefined; +} + +async function hasPnpm(): Promise { + const envPath = process.env.PNPM_BIN?.trim(); + if (envPath) { + try { + await fs.access(envPath); + return true; + } catch { + // Fall through to PATH check + } + } + + const localPnpm = path.join(os.homedir(), ".local", "bin", "pnpm"); + try { + await fs.access(localPnpm); + return true; + } catch { + // Ignore + } + + try { + execSync("pnpm --version", { stdio: "ignore" }); + return true; + } catch { + return false; + } +} + +async function isPortOpen(host: string, port: number): Promise { + return await new Promise((resolve) => { + const socket = net.createConnection({ host, port }); + const timeout = setTimeout(() => { + socket.destroy(); + resolve(false); + }, 1000); + + socket.once("connect", () => { + clearTimeout(timeout); + socket.end(); + resolve(true); + }); + socket.once("error", () => { + clearTimeout(timeout); + resolve(false); + }); + }); +} + +async function checkGatewayConfig(): Promise { + const start = Date.now(); + const configPath = await findZeeConfig(); + const envHints = getGatewayEnvHints(); + const configured = Boolean(configPath || envHints.length > 0); + + if (!configured) { + return { + id: "integrity.gateway-config", + name: "Gateway Configuration", + category: "integrity", + status: "skip", + message: "Gateway not configured", + details: "Add ~/.zee/zee.json or provider env vars to enable messaging", + severity: "info", + durationMs: Date.now() - start, + autoFixable: false, + }; + } + + const issues: string[] = []; + try { + await fs.access(Zee.repo()); + } catch { + issues.push(`Zee repo missing at ${Zee.repo()}`); + } + + const pnpmAvailable = await hasPnpm(); + if (!pnpmAvailable) { + issues.push("pnpm not found (needed to run gateway)"); + } + + if (issues.length > 0) { + return { + id: "integrity.gateway-config", + name: "Gateway Configuration", + category: "integrity", + status: "warn", + message: "Gateway configured with missing prerequisites", + details: issues.join("\n"), + severity: "warning", + durationMs: Date.now() - start, + autoFixable: false, + metadata: { configPath, envHints }, + }; + } + + return { + id: "integrity.gateway-config", + name: "Gateway Configuration", + category: "integrity", + status: "pass", + message: configPath ? `Config found at ${configPath}` : "Configured via environment", + severity: "info", + durationMs: Date.now() - start, + autoFixable: false, + metadata: { configPath, envHints }, + }; +} + +async function checkGatewayPort(): Promise { + const start = Date.now(); + const configPath = await findZeeConfig(); + const envHints = getGatewayEnvHints(); + const configured = Boolean(configPath || envHints.length > 0); + + if (!configured) { + return { + id: "integrity.gateway-port", + name: "Gateway Reachability", + category: "integrity", + status: "skip", + message: "Gateway not configured", + severity: "info", + durationMs: Date.now() - start, + autoFixable: false, + }; + } + + const port = getGatewayPort(); + const portOpen = await isPortOpen("127.0.0.1", port); + if (portOpen) { + return { + id: "integrity.gateway-port", + name: "Gateway Reachability", + category: "integrity", + status: "pass", + message: `Gateway listening on ${port}`, + severity: "info", + durationMs: Date.now() - start, + autoFixable: false, + metadata: { port }, + }; + } + + return { + id: "integrity.gateway-port", + name: "Gateway Reachability", + category: "integrity", + status: "warn", + message: `Gateway not listening on ${port}`, + details: "Restart agent-core to recover the embedded gateway", + severity: "warning", + durationMs: Date.now() - start, + autoFixable: false, + metadata: { port }, + }; +} + async function checkStaleLocks(): Promise { const start = Date.now(); const stateDir = getStateDir(); @@ -96,11 +289,37 @@ async function checkStaleLocks(): Promise { async function checkOrphanedProcesses(): Promise { const start = Date.now(); - const pidFile = path.join(getStateDir(), "daemon.pid"); + const pidFile = path.join(getStateDir(), "daemon", "daemon.pid"); try { const pidContent = await fs.readFile(pidFile, "utf-8"); - const storedPid = parseInt(pidContent.trim(), 10); + let storedPid = Number.NaN; + + try { + const parsed = JSON.parse(pidContent) as { pid?: number }; + if (typeof parsed?.pid === "number") { + storedPid = parsed.pid; + } + } catch { + storedPid = parseInt(pidContent.trim(), 10); + } + + if (!Number.isFinite(storedPid)) { + return { + id: "integrity.orphan-procs", + name: "Daemon Process", + category: "integrity", + status: "warn", + message: "PID file exists but is unreadable", + severity: "warning", + durationMs: Date.now() - start, + autoFixable: true, + fix: async () => { + await fs.unlink(pidFile); + return { success: true, message: "Removed unreadable PID file" }; + }, + }; + } try { process.kill(storedPid, 0); // Signal 0 = check if process exists @@ -262,6 +481,8 @@ export async function runIntegrityChecks(options: CheckOptions): Promise $`brew list --formula opencode`.throws(false).quiet().text(), + command: () => $`brew list --formula`.throws(false).quiet().text(), }, { name: "scoop" as const, @@ -101,13 +101,20 @@ export namespace Installation { return 0 }) + const npmPackages = ["agent-core-ai", "opencode-ai"] + const brewPackages = ["agent-core", "opencode"] + for (const check of checks) { const output = await check.command() - const installedName = - check.name === "brew" || check.name === "choco" || check.name === "scoop" ? "opencode" : "opencode-ai" - if (output.includes(installedName)) { - return check.name + if (check.name === "brew") { + if (brewPackages.some((pkg) => output.includes(pkg))) return check.name + continue } + if (check.name === "choco" || check.name === "scoop") { + if (output.includes("opencode")) return check.name + continue + } + if (npmPackages.some((pkg) => output.includes(pkg))) return check.name } return "unknown" @@ -121,30 +128,32 @@ export namespace Installation { ) async function getBrewFormula() { - const tapFormula = await $`brew list --formula anomalyco/tap/opencode`.throws(false).quiet().text() - if (tapFormula.includes("opencode")) return "anomalyco/tap/opencode" - const coreFormula = await $`brew list --formula opencode`.throws(false).quiet().text() - if (coreFormula.includes("opencode")) return "opencode" - return "opencode" + const tapFormula = await $`brew list --formula adolago/tap/agent-core`.throws(false).quiet().text() + if (tapFormula.includes("agent-core")) return "adolago/tap/agent-core" + const coreFormula = await $`brew list --formula agent-core`.throws(false).quiet().text() + if (coreFormula.includes("agent-core")) return "agent-core" + const legacyFormula = await $`brew list --formula opencode`.throws(false).quiet().text() + if (legacyFormula.includes("opencode")) return "opencode" + return "agent-core" } export async function upgrade(method: Method, target: string) { let cmd switch (method) { case "curl": - cmd = $`curl -fsSL https://opencode.ai/install | bash`.env({ + cmd = $`curl -fsSL https://raw.githubusercontent.com/adolago/agent-core/dev/install | bash`.env({ ...process.env, VERSION: target, }) break case "npm": - cmd = $`npm install -g opencode-ai@${target}` + cmd = $`npm install -g agent-core-ai@${target}` break case "pnpm": - cmd = $`pnpm install -g opencode-ai@${target}` + cmd = $`pnpm install -g agent-core-ai@${target}` break case "bun": - cmd = $`bun install -g opencode-ai@${target}` + cmd = $`bun install -g agent-core-ai@${target}` break case "brew": { const formula = await getBrewFormula() @@ -189,7 +198,7 @@ export namespace Installation { if (detectedMethod === "brew") { const formula = await getBrewFormula() - if (formula === "opencode") { + if (formula === "agent-core" || formula === "adolago/tap/agent-core") { return fetch("https://formulae.brew.sh/api/formula/agent-core.json") .then((res) => { if (!res.ok) throw new Error(res.statusText) @@ -206,7 +215,7 @@ export namespace Installation { return reg.endsWith("/") ? reg.slice(0, -1) : reg }) const channel = CHANNEL - return fetch(`${registry}/opencode-ai/${channel}`) + return fetch(`${registry}/agent-core-ai/${channel}`) .then((res) => { if (!res.ok) throw new Error(res.statusText) return res.json() @@ -237,7 +246,7 @@ export namespace Installation { .then((data: any) => data.version) } - return fetch("https://api.github.com/repos/anomalyco/opencode/releases/latest") + return fetch("https://api.github.com/repos/adolago/agent-core/releases/latest") .then((res) => { if (!res.ok) throw new Error(res.statusText) return res.json() diff --git a/packages/agent-core/src/paths.ts b/packages/agent-core/src/paths.ts new file mode 100644 index 0000000000..f4585a72f3 --- /dev/null +++ b/packages/agent-core/src/paths.ts @@ -0,0 +1,177 @@ +/** + * Centralized Path Resolution + * + * All persona and asset paths are resolved from AGENT_CORE_ROOT. + * No need for env vars like STANLEY_REPO, ZEE_REPO, etc. + */ + +import path from "path" +import fs from "fs" +import os from "os" + +/** + * Get the agent-core root directory. + * Order of precedence: + * 1. AGENT_CORE_ROOT env var (set by binary or launcher) + * 2. Source development path + */ +export function getAgentCoreRoot(): string { + if (process.env.AGENT_CORE_ROOT) { + return process.env.AGENT_CORE_ROOT + } + // Fallback to source path for development + return path.join(os.homedir(), ".local", "src", "agent-core") +} + +/** + * Persona paths - resolved from AGENT_CORE_ROOT/vendor/personas/ + */ +export const Personas = { + root(): string { + return path.join(getAgentCoreRoot(), "vendor", "personas") + }, + + zee(): string { + return path.join(this.root(), "zee") + }, + + stanley(): string { + return path.join(this.root(), "stanley") + }, + + johny(): string { + return path.join(this.root(), "johny") + }, + + exists(name: "zee" | "stanley" | "johny"): boolean { + return fs.existsSync(this[name]()) + }, +} + +/** + * Stanley-specific paths + */ +export const Stanley = { + repo(): string { + return process.env.STANLEY_REPO || Personas.stanley() + }, + + cli(): string { + return process.env.STANLEY_CLI || path.join(this.repo(), "scripts", "stanley_cli.py") + }, + + /** + * Resolve Python binary for Stanley. + * Order: STANLEY_PYTHON env > bundled runtime > venv > system python3 + */ + python(): string { + if (process.env.STANLEY_PYTHON) { + return process.env.STANLEY_PYTHON + } + + const repo = this.repo() + + // Check for bundled runtime (dist builds) + const runtimeBin = path.join(repo, ".python-runtime", "bin") + for (const bin of ["python3.13", "python3.12", "python3"]) { + const candidate = path.join(runtimeBin, bin) + if (fs.existsSync(candidate)) return candidate + } + + // Check for venv (dev builds) + const venvPython = path.join(repo, ".venv", "bin", "python") + if (fs.existsSync(venvPython)) return venvPython + + // Fallback to system + return "python3" + }, + + /** + * Get PYTHONPATH for Stanley dependencies + */ + pythonPath(): string | undefined { + const repo = this.repo() + const bundledDeps = path.join(repo, ".python") + if (fs.existsSync(bundledDeps)) return bundledDeps + return process.env.STANLEY_PYTHONPATH + }, + + portfolioFile(): string { + return process.env.STANLEY_PORTFOLIO_FILE || path.join(os.homedir(), ".zee", "stanley", "portfolio.json") + }, +} + +/** + * Johny-specific paths + */ +export const Johny = { + repo(): string { + return process.env.JOHNY_REPO || Personas.johny() + }, + + cli(): string { + return process.env.JOHNY_CLI || path.join(this.repo(), "scripts", "johny_cli.py") + }, +} + +/** + * Zee-specific paths + */ +export const Zee = { + repo(): string { + return process.env.ZEE_REPO || Personas.zee() + }, + + /** + * Zee data directory - ~/.zee/ + * Contains credentials, sessions, and persona data + */ + dataDir(): string { + return path.join(os.homedir(), ".zee") + }, + + credentials(): string { + return path.join(this.dataDir(), "credentials") + }, +} + +/** + * Tiara orchestration paths + */ +export const Tiara = { + root(): string { + const agentCoreRoot = getAgentCoreRoot() + const distPath = path.join(agentCoreRoot, "vendor", "tiara") + if (fs.existsSync(distPath)) return distPath + return path.join(agentCoreRoot, "vendor", "tiara") + }, + + exists(): boolean { + return fs.existsSync(this.root()) + }, +} + +/** + * Agent-core assets paths + */ +export const Assets = { + root(): string { + return path.join(getAgentCoreRoot(), ".agent-core") + }, + + agents(): string { + return path.join(this.root(), "agent") + }, + + themes(): string { + return path.join(this.root(), "themes") + }, + + skills(): string { + return path.join(this.root(), "skill") + }, + + config(): string { + return path.join(this.root(), "agent-core.jsonc") + }, +} diff --git a/packages/agent-core/src/plugin/index.ts b/packages/agent-core/src/plugin/index.ts index d91cfb91fd..75c22f54fb 100644 --- a/packages/agent-core/src/plugin/index.ts +++ b/packages/agent-core/src/plugin/index.ts @@ -3,7 +3,6 @@ import { Config } from "../config/config" import { Bus } from "../bus" import { Log } from "../util/log" import { createOpencodeClient } from "@opencode-ai/sdk" -import { Server } from "../server/server" import { BunProc } from "../bun" import { Instance } from "../project/instance" import { Flag } from "../flag/flag" @@ -21,6 +20,7 @@ export namespace Plugin { const INTERNAL_PLUGINS: PluginInstance[] = [CodexAuthPlugin, CopilotAuthPlugin] const state = Instance.state(async () => { + const { Server } = await import("../server/server") const client = createOpencodeClient({ baseUrl: Server.url().origin, // @ts-ignore - fetch type incompatibility diff --git a/packages/opencode-anthropic-auth b/packages/opencode-anthropic-auth new file mode 160000 index 0000000000..d698a1fa52 --- /dev/null +++ b/packages/opencode-anthropic-auth @@ -0,0 +1 @@ +Subproject commit d698a1fa52ea077d81063e26f7a7d7785a282c8f diff --git a/packages/script/src/index.ts b/packages/script/src/index.ts index 09ebb44635..382af001d8 100644 --- a/packages/script/src/index.ts +++ b/packages/script/src/index.ts @@ -28,7 +28,11 @@ const IS_PREVIEW = CHANNEL !== "latest" const VERSION = await (async () => { if (env.OPENCODE_VERSION) return env.OPENCODE_VERSION - if (IS_PREVIEW) return `0.0.0-${CHANNEL}-${new Date().toISOString().slice(0, 16).replace(/[-:T]/g, "")}` + if (IS_PREVIEW) { + const now = new Date() + const local = new Date(now.getTime() - now.getTimezoneOffset() * 60000) + return `0.0.0-${CHANNEL}-${local.toISOString().slice(0, 16).replace(/[-:T]/g, "")}` + } const version = await fetch("https://registry.npmjs.org/opencode-ai/latest") .then((res) => { if (!res.ok) throw new Error(res.statusText) diff --git a/scripts/beta-readiness.sh b/scripts/beta-readiness.sh new file mode 100755 index 0000000000..0c33396651 --- /dev/null +++ b/scripts/beta-readiness.sh @@ -0,0 +1,54 @@ +#!/usr/bin/env bash +set -euo pipefail + +AGENT_BIN="${AGENT_BIN:-$HOME/.local/bin/agent-core}" +AGENT_CORE_BIN_PATH="${AGENT_CORE_BIN_PATH:-$HOME/.local/src/agent-core/packages/agent-core/dist/agent-core-linux-x64/bin/agent-core}" +REPORT_DIR="${REPORT_DIR:-/tmp/agent-core-beta}" +REPORT_FILE="$REPORT_DIR/report.txt" +BUG_REPORT_PATH="$REPORT_DIR/bug-report.tar.gz" + +mkdir -p "$REPORT_DIR" +: > "$REPORT_FILE" + +log() { + printf '%s\n' "$*" | tee -a "$REPORT_FILE" +} + +log "Agent-Core beta readiness" +log "date: $(date -u +"%Y-%m-%dT%H:%M:%SZ")" +log "agent_bin: $AGENT_BIN" +log "agent_core_bin_path: $AGENT_CORE_BIN_PATH" +log "report_dir: $REPORT_DIR" +log "" + +if [[ ! -x "$AGENT_BIN" ]]; then + log "ERROR: agent-core binary not found or not executable: $AGENT_BIN" + exit 1 +fi +if [[ ! -x "$AGENT_CORE_BIN_PATH" ]]; then + log "ERROR: agent-core native binary not found or not executable: $AGENT_CORE_BIN_PATH" + exit 1 +fi + +log "# Version" +AGENT_CORE_BIN_PATH="$AGENT_CORE_BIN_PATH" "$AGENT_BIN" --version | tee -a "$REPORT_FILE" +log "" + +log "# Config & repo checks" +log "config.json: $HOME/.config/agent-core/config.json" +log "agent-core.jsonc: $HOME/.config/agent-core/agent-core.jsonc" +log "skills root: $HOME/.config/agent-core/skills -> $(readlink -f "$HOME/.config/agent-core/skills")" +log "personas root: $HOME/.local/src/agent-core/vendor/personas" +log "" + +log "# Diagnostic check (runtime + config only)" +AGENT_CORE_BIN_PATH="$AGENT_CORE_BIN_PATH" "$AGENT_BIN" check --category runtime --category config --minimal --timeout 5000 | tee -a "$REPORT_FILE" +log "" + +log "# Bug report (non-interactive, diagnostics skipped)" +AGENT_CORE_BIN_PATH="$AGENT_CORE_BIN_PATH" "$AGENT_BIN" bug-report --skip-diagnostics --non-interactive --log-lines 5 -o "$BUG_REPORT_PATH" | tee -a "$REPORT_FILE" +log "" + +log "# Done" +log "report: $REPORT_FILE" +log "bug_report: $BUG_REPORT_PATH" diff --git a/scripts/systemd/agent-core.service b/scripts/systemd/agent-core.service index ddf9c235e0..0ff788dade 100644 --- a/scripts/systemd/agent-core.service +++ b/scripts/systemd/agent-core.service @@ -11,18 +11,18 @@ Group=artur # Environment setup Environment=HOME=/home/artur Environment=AGENT_CORE_HEADLESS=1 +Environment=AGENT_CORE_ROOT=/home/artur/.local/src/agent-core Environment=NODE_ENV=production Environment=PATH=/home/artur/bin:/home/artur/.local/bin:/home/artur/.bun/bin:/usr/local/bin:/usr/bin:/bin # API keys can be loaded from environment file (create ~/.config/agent-core/daemon.env) EnvironmentFile=-/home/artur/.config/agent-core/daemon.env -# Working directory - use home for general access -WorkingDirectory=/home/artur +# Working directory - use repo root for relative assets +WorkingDirectory=/home/artur/.local/src/agent-core -# Use installed binary - starts both agent-core daemon AND zee gateway -# Gateway auto-starts with supervision and auto-restart on crash -ExecStart=/home/artur/bin/agent-core daemon --hostname 127.0.0.1 --port 3210 --gateway +# Use repo-local binary - starts agent-core daemon with embedded Zee gateway +ExecStart=/home/artur/.local/src/agent-core/packages/agent-core/bin/agent-core daemon --hostname 127.0.0.1 --port 3210 --directory /home/artur/.local/src/agent-core # Restart policy Restart=always @@ -38,7 +38,7 @@ PrivateTmp=true # Agent-core needs write access to config, state, logs, and session data # Gateway needs access to zee directory for cache and session data # Signal needs access to its data directory -ReadWritePaths=/home/artur/.config/agent-core /home/artur/.local/state/agent-core /home/artur/.local/share/agent-core /home/artur/.local/share/signal-cli /home/artur/.zee /home/artur/Repositories/personas/zee +ReadWritePaths=/home/artur/.config/agent-core /home/artur/.local/state/agent-core /home/artur/.local/share/agent-core /home/artur/.local/share/signal-cli /home/artur/.zee /home/artur/.local/src/agent-core/vendor/personas # Logging StandardOutput=journal diff --git a/scripts/systemd/install.sh b/scripts/systemd/install.sh index 66134439d8..340d8e519c 100755 --- a/scripts/systemd/install.sh +++ b/scripts/systemd/install.sh @@ -44,6 +44,9 @@ if [[ ! -f "$ENV_FILE" ]]; then # OpenAI API key (optional) # OPENAI_API_KEY=your-key-here +# Nebius API key (embeddings) +# NEBIUS_API_KEY=your-key-here + # ============================================================================= # Tool API Keys # ============================================================================= @@ -91,8 +94,8 @@ echo " - zee gateway (WhatsApp/Telegram/Signal messaging)" echo "" echo "Next steps:" echo " 1. Edit your API keys in: $ENV_FILE" -echo " 2. Install agent-core binary: ~/bin/agent-core" -echo " 3. Ensure zee gateway is set up: ~/Repositories/personas/zee" +echo " 2. Install agent-core binary: cd /home/artur/.local/src/agent-core/packages/agent-core && bun link" +echo " 3. Ensure zee gateway is set up: ~/.local/src/agent-core/vendor/personas/zee" echo " 4. Enable the service: sudo systemctl enable agent-core" echo " 5. Start the service: sudo systemctl start agent-core" echo " 6. Check status: sudo systemctl status agent-core" diff --git a/src/agent-types.ts b/src/agent-types.ts deleted file mode 100644 index d93e4c8ab0..0000000000 --- a/src/agent-types.ts +++ /dev/null @@ -1,294 +0,0 @@ -/** - * Agent Types - Specialized agent type definitions for council and orchestration. - * - * This module defines the available specialized agent types that can participate - * in council deliberations and be spawned by the orchestrator. - */ - -import type { PersonaId } from "./personas/types.js"; - -// ============================================================================= -// Specialized Agent Types -// ============================================================================= - -/** - * All specialized agent types available in the system. - * These map to the comprehensive agent type sets in src/tiara.ts - */ -export type SpecializedAgentType = - // Zee - Personal Assistant Domain - | "inbox_manager" - | "scheduler" - | "task_coordinator" - | "email_assistant" - | "message_handler" - | "notification_manager" - | "contact_manager" - | "communication_coordinator" - | "social_media_manager" - | "calendar_manager" - | "meeting_scheduler" - | "reminder_assistant" - | "time_tracker" - | "event_coordinator" - | "file_organizer" - | "note_taker" - | "document_manager" - | "bookmark_organizer" - | "password_manager" - | "travel_planner" - | "shopping_assistant" - | "recipe_finder" - | "restaurant_recommender" - | "habit_tracker" - | "health_tracker" - | "fitness_planner" - | "music_curator" - | "movie_recommender" - | "podcast_finder" - | "news_aggregator" - | "book_recommender" - | "personal_assistant" - | "life_admin" - | "general_helper" - // Johny - Learning & Research Domain - | "research_assistant" - | "knowledge_synthesizer" - | "fact_checker" - | "topic_explorer" - | "document_analyzer" - | "paper_summarizer" - | "citation_finder" - | "literature_reviewer" - | "curriculum_designer" - | "study_planner" - | "quiz_maker" - | "flashcard_creator" - | "memory_trainer" - | "skill_assessor" - | "learning_path_designer" - | "concept_mapper" - | "code_tutor" - | "math_helper" - | "language_tutor" - | "science_explainer" - | "history_researcher" - | "philosophy_guide" - | "writing_coach" - | "essay_writer" - | "argument_analyzer" - | "debate_helper" - | "critical_thinker" - | "educator" - | "mentor" - | "academic_assistant" - // Stanley - Finance & Investing Domain - | "market_analyst" - | "portfolio_manager" - | "fundamental_analyst" - | "technical_analyst" - | "quantitative_analyst" - | "sentiment_analyst" - | "sector_analyst" - | "earnings_analyst" - | "stock_screener" - | "options_strategist" - | "risk_assessor" - | "asset_allocator" - | "position_sizer" - | "rebalance_advisor" - | "dividend_tracker" - | "performance_tracker" - | "watchlist_manager" - | "alert_manager" - | "backtest_runner" - | "trade_executor" - | "order_manager" - | "crypto_analyst" - | "forex_trader" - | "commodity_analyst" - | "bond_analyst" - | "etf_specialist" - | "macro_economist" - | "fed_watcher" - | "economic_indicator_tracker" - | "tax_optimizer" - | "compliance_checker" - | "financial_advisor" - | "investment_researcher" - | "wealth_manager"; - -// ============================================================================= -// Agent Type Sets (for validation and routing) -// ============================================================================= - -/** - * Zee - Personal Assistant Domain agent types - */ -export const ZEE_AGENT_TYPES: ReadonlySet = new Set([ - "inbox_manager", - "scheduler", - "task_coordinator", - "email_assistant", - "message_handler", - "notification_manager", - "contact_manager", - "communication_coordinator", - "social_media_manager", - "calendar_manager", - "meeting_scheduler", - "reminder_assistant", - "time_tracker", - "event_coordinator", - "file_organizer", - "note_taker", - "document_manager", - "bookmark_organizer", - "password_manager", - "travel_planner", - "shopping_assistant", - "recipe_finder", - "restaurant_recommender", - "habit_tracker", - "health_tracker", - "fitness_planner", - "music_curator", - "movie_recommender", - "podcast_finder", - "news_aggregator", - "book_recommender", - "personal_assistant", - "life_admin", - "general_helper", -]); - -/** - * Johny - Learning & Research Domain agent types - */ -export const JOHNY_AGENT_TYPES: ReadonlySet = new Set([ - "research_assistant", - "knowledge_synthesizer", - "fact_checker", - "topic_explorer", - "document_analyzer", - "paper_summarizer", - "citation_finder", - "literature_reviewer", - "curriculum_designer", - "study_planner", - "quiz_maker", - "flashcard_creator", - "memory_trainer", - "skill_assessor", - "learning_path_designer", - "concept_mapper", - "code_tutor", - "math_helper", - "language_tutor", - "science_explainer", - "history_researcher", - "philosophy_guide", - "writing_coach", - "essay_writer", - "argument_analyzer", - "debate_helper", - "critical_thinker", - "educator", - "mentor", - "academic_assistant", -]); - -/** - * Stanley - Finance & Investing Domain agent types - */ -export const STANLEY_AGENT_TYPES: ReadonlySet = new Set([ - "market_analyst", - "portfolio_manager", - "fundamental_analyst", - "technical_analyst", - "quantitative_analyst", - "sentiment_analyst", - "sector_analyst", - "earnings_analyst", - "stock_screener", - "options_strategist", - "risk_assessor", - "asset_allocator", - "position_sizer", - "rebalance_advisor", - "dividend_tracker", - "performance_tracker", - "watchlist_manager", - "alert_manager", - "backtest_runner", - "trade_executor", - "order_manager", - "crypto_analyst", - "forex_trader", - "commodity_analyst", - "bond_analyst", - "etf_specialist", - "macro_economist", - "fed_watcher", - "economic_indicator_tracker", - "tax_optimizer", - "compliance_checker", - "financial_advisor", - "investment_researcher", - "wealth_manager", -]); - -// ============================================================================= -// Helper Functions -// ============================================================================= - -/** - * Get the persona that handles a specific agent type. - */ -export function getAgentPersona(agentType: SpecializedAgentType): PersonaId { - if (STANLEY_AGENT_TYPES.has(agentType)) return "stanley"; - if (JOHNY_AGENT_TYPES.has(agentType)) return "johny"; - return "zee"; // Default to Zee for unknown types -} - -/** - * Check if a string is a valid specialized agent type. - */ -export function isSpecializedAgentType( - value: string -): value is SpecializedAgentType { - return ( - ZEE_AGENT_TYPES.has(value as SpecializedAgentType) || - JOHNY_AGENT_TYPES.has(value as SpecializedAgentType) || - STANLEY_AGENT_TYPES.has(value as SpecializedAgentType) - ); -} - -/** - * Get all specialized agent types. - */ -export function getAllAgentTypes(): SpecializedAgentType[] { - return [ - ...Array.from(ZEE_AGENT_TYPES), - ...Array.from(JOHNY_AGENT_TYPES), - ...Array.from(STANLEY_AGENT_TYPES), - ]; -} - -/** - * Get agent types by persona. - */ -export function getAgentTypesByPersona( - persona: PersonaId -): SpecializedAgentType[] { - switch (persona) { - case "zee": - return Array.from(ZEE_AGENT_TYPES); - case "johny": - return Array.from(JOHNY_AGENT_TYPES); - case "stanley": - return Array.from(STANLEY_AGENT_TYPES); - default: - return []; - } -} diff --git a/src/config/embedding-profiles.ts b/src/config/embedding-profiles.ts new file mode 100644 index 0000000000..84235e9ef3 --- /dev/null +++ b/src/config/embedding-profiles.ts @@ -0,0 +1,70 @@ +import type { EmbeddingProviderType } from "../memory/types"; + +export type EmbeddingProfileConfig = { + provider: EmbeddingProviderType; + model: string; + dimensions?: number; + baseUrl?: string; +}; + +export const EMBEDDING_PROFILES: Record = { + "openai/text-embedding-3-small": { + provider: "openai", + model: "text-embedding-3-small", + dimensions: 1536, + }, + "openai/text-embedding-3-small-512": { + provider: "openai", + model: "text-embedding-3-small", + dimensions: 512, + }, + "openai/text-embedding-3-small-1024": { + provider: "openai", + model: "text-embedding-3-small", + dimensions: 1024, + }, + "openai/text-embedding-3-large": { + provider: "openai", + model: "text-embedding-3-large", + dimensions: 3072, + }, + "openai/text-embedding-3-large-1024": { + provider: "openai", + model: "text-embedding-3-large", + dimensions: 1024, + }, + "openai/text-embedding-3-large-1536": { + provider: "openai", + model: "text-embedding-3-large", + dimensions: 1536, + }, + "openai/text-embedding-ada-002": { + provider: "openai", + model: "text-embedding-ada-002", + dimensions: 1536, + }, + "google/text-embedding-004": { + provider: "google", + model: "text-embedding-004", + dimensions: 768, + baseUrl: "https://generativelanguage.googleapis.com/v1beta", + }, + "nebius/qwen3-embedding-8b": { + provider: "openai", + model: "Qwen/Qwen3-Embedding-8B", + dimensions: 4096, + baseUrl: "https://api.tokenfactory.nebius.com/v1", + }, + "voyage/voyage-3-large": { + provider: "voyage", + model: "voyage-3-large", + dimensions: 1024, + }, +}; + +export function resolveEmbeddingProfile( + profile?: string +): EmbeddingProfileConfig | undefined { + if (!profile) return undefined; + return EMBEDDING_PROFILES[profile]; +} diff --git a/src/config/runtime.ts b/src/config/runtime.ts new file mode 100644 index 0000000000..76f3cbb546 --- /dev/null +++ b/src/config/runtime.ts @@ -0,0 +1,203 @@ +/** + * Lightweight runtime config loader. + * + * Reads agent-core.json(c) for runtime-only settings (memory, tiara) + * without invoking the full CLI config pipeline. + */ + +import fs from "fs"; +import os from "os"; +import path from "path"; +import { parse as parseJsonc, type ParseError } from "jsonc-parser"; +import { Assets } from "../paths"; +import type { EmbeddingProviderType } from "../memory/types"; +import { resolveEmbeddingProfile } from "./embedding-profiles"; + +type RuntimeConfig = { + memory?: { + qdrant?: { + url?: string; + apiKey?: string; + collection?: string; + }; + qdrantUrl?: string; + qdrantApiKey?: string; + qdrantCollection?: string; + embedding?: { + profile?: string; + provider?: string; + model?: string; + dimensions?: number; + dimension?: number; + apiKey?: string; + baseUrl?: string; + }; + }; + tiara?: { + qdrant?: { + url?: string; + apiKey?: string; + stateCollection?: string; + memoryCollection?: string; + embeddingDimension?: number; + }; + }; +}; + +export type MemoryQdrantConfig = { + url?: string; + apiKey?: string; + collection?: string; +}; + +export type TiaraQdrantConfig = { + url?: string; + apiKey?: string; + stateCollection?: string; + memoryCollection?: string; + embeddingDimension?: number; +}; + +export type MemoryEmbeddingConfig = { + provider?: EmbeddingProviderType; + model?: string; + dimensions?: number; + apiKey?: string; + baseUrl?: string; +}; + +const CONFIG_PATHS = [ + path.join(os.homedir(), ".config", "agent-core", "agent-core.jsonc"), + path.join(os.homedir(), ".config", "agent-core", "agent-core.json"), + Assets.config(), + path.join(Assets.root(), "agent-core.json"), +]; + +let cachedConfig: RuntimeConfig | null = null; + +function parseConfigFile(filePath: string): RuntimeConfig | null { + let contents: string; + try { + contents = fs.readFileSync(filePath, "utf-8"); + } catch { + return null; + } + + contents = contents.replace(/\{env:([^}]+)\}/g, (_match, varName) => { + return process.env[varName] ?? ""; + }); + + const errors: ParseError[] = []; + const parsed = parseJsonc(contents, errors, { allowTrailingComma: true }); + if (errors.length || typeof parsed !== "object" || parsed === null) { + return null; + } + + return parsed as RuntimeConfig; +} + +function mergeConfigs(base: RuntimeConfig, override: RuntimeConfig): RuntimeConfig { + return { + ...base, + ...override, + memory: { + ...base.memory, + ...override.memory, + qdrant: { + ...base.memory?.qdrant, + ...override.memory?.qdrant, + }, + embedding: { + ...base.memory?.embedding, + ...override.memory?.embedding, + }, + }, + tiara: { + ...base.tiara, + ...override.tiara, + qdrant: { + ...base.tiara?.qdrant, + ...override.tiara?.qdrant, + }, + }, + }; +} + +function loadRuntimeConfig(): RuntimeConfig { + if (cachedConfig) return cachedConfig; + + let merged: RuntimeConfig = {}; + for (const configPath of CONFIG_PATHS) { + const parsed = parseConfigFile(configPath); + if (parsed) merged = mergeConfigs(merged, parsed); + } + + cachedConfig = merged; + return merged; +} + +function resolveMemoryQdrantConfig(config: RuntimeConfig): MemoryQdrantConfig { + const memory = config.memory ?? {}; + const qdrant = memory.qdrant ?? {}; + const url = (qdrant.url ?? memory.qdrantUrl)?.trim() || undefined; + const apiKey = (qdrant.apiKey ?? memory.qdrantApiKey)?.trim() || undefined; + const collection = (qdrant.collection ?? memory.qdrantCollection)?.trim() || undefined; + + return { + url, + apiKey, + collection, + }; +} + +function resolveMemoryEmbeddingConfig(config: RuntimeConfig): MemoryEmbeddingConfig { + const embedding = config.memory?.embedding ?? {}; + const profileConfig = resolveEmbeddingProfile(embedding.profile?.trim()); + const rawDimensions = + embedding.dimensions ?? embedding.dimension ?? profileConfig?.dimensions; + const dimensions = + typeof rawDimensions === "string" + ? Number.parseInt(rawDimensions, 10) + : rawDimensions; + + const provider = embedding.provider?.trim() || profileConfig?.provider; + + return { + provider: provider as EmbeddingProviderType | undefined, + model: embedding.model?.trim() || profileConfig?.model, + dimensions: Number.isFinite(dimensions as number) ? (dimensions as number) : undefined, + apiKey: embedding.apiKey?.trim() || undefined, + baseUrl: embedding.baseUrl?.trim() || profileConfig?.baseUrl, + }; +} + +export function getMemoryQdrantConfig(): MemoryQdrantConfig { + return resolveMemoryQdrantConfig(loadRuntimeConfig()); +} + +export function getMemoryEmbeddingConfig(): MemoryEmbeddingConfig { + return resolveMemoryEmbeddingConfig(loadRuntimeConfig()); +} + +export function getTiaraQdrantConfig(): TiaraQdrantConfig { + const config = loadRuntimeConfig(); + const memoryQdrant = resolveMemoryQdrantConfig(config); + const memoryEmbedding = resolveMemoryEmbeddingConfig(config); + const qdrant = config.tiara?.qdrant ?? {}; + const url = (qdrant.url ?? memoryQdrant.url)?.trim() || undefined; + const apiKey = (qdrant.apiKey ?? memoryQdrant.apiKey)?.trim() || undefined; + const stateCollection = qdrant.stateCollection?.trim() || undefined; + const memoryCollection = (qdrant.memoryCollection ?? memoryQdrant.collection)?.trim() || undefined; + const embeddingDimension = + typeof qdrant.embeddingDimension === "number" + ? qdrant.embeddingDimension + : memoryEmbedding.dimensions; + + return { + url, + apiKey, + stateCollection, + memoryCollection, + embeddingDimension, + }; +} diff --git a/src/council/auth/google-antigravity-auth.ts b/src/council/auth/google-antigravity-auth.ts deleted file mode 100644 index 7d4d3cd2ff..0000000000 --- a/src/council/auth/google-antigravity-auth.ts +++ /dev/null @@ -1,529 +0,0 @@ -/** - * Google Antigravity OAuth Authentication - * - * Provides free Gemini access via Google OAuth authentication. - * Based on opencode-google-antigravity-auth plugin pattern. - * - * Features: - * - Google OAuth 2.0 device code flow - * - Multi-account support with load balancing - * - Token refresh and persistence - * - Rate limit handling across accounts - */ - -import fs from "node:fs/promises"; -import fsSync from "node:fs"; -import path from "node:path"; -import os from "node:os"; -import { ensureDir } from "../../utils.js"; - -// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ -// Constants -// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ - -const CONFIG_DIR = path.join(os.homedir(), ".zee"); -const ANTIGRAVITY_DIR = path.join(CONFIG_DIR, "credentials", "google-antigravity"); -const ACCOUNTS_FILE = path.join(ANTIGRAVITY_DIR, "accounts.json"); - -// Google OAuth endpoints (using Antigravity proxy) -const ANTIGRAVITY_AUTH_URL = "https://antigravity.opencode.ai/auth"; -const ANTIGRAVITY_TOKEN_URL = "https://antigravity.opencode.ai/token"; -const ANTIGRAVITY_API_URL = "https://antigravity.opencode.ai/v1"; - -// Google OAuth client (public - Antigravity shared client) -const GOOGLE_CLIENT_ID = "opencode-antigravity"; - -// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ -// Types -// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ - -/** - * OAuth token data for a Google account. - */ -export interface GoogleOAuthToken { - accessToken: string; - refreshToken: string; - expiresAt: number; - scope: string; -} - -/** - * A single Google account for Antigravity. - */ -export interface AntigravityAccount { - id: string; - email: string; - token: GoogleOAuthToken; - addedAt: number; - lastUsed?: number; - requestCount: number; - rateLimitedUntil?: number; -} - -/** - * Antigravity accounts storage. - */ -export interface AntigravityAccounts { - version: number; - accounts: AntigravityAccount[]; - activeAccountId?: string; - loadBalanceMode: "round_robin" | "least_used" | "random"; -} - -/** - * Device code response from OAuth flow. - */ -export interface DeviceCodeResponse { - deviceCode: string; - userCode: string; - verificationUrl: string; - expiresIn: number; - interval: number; -} - -// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ -// Storage Functions -// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ - -/** - * Get the path to the Antigravity accounts file. - */ -export function getAntigravityAccountsPath(): string { - return ACCOUNTS_FILE; -} - -/** - * Load Antigravity accounts from disk. - */ -export async function loadAntigravityAccounts(): Promise { - try { - const content = await fs.readFile(ACCOUNTS_FILE, "utf-8"); - const parsed = JSON.parse(content) as AntigravityAccounts; - return { - version: parsed.version ?? 1, - accounts: parsed.accounts ?? [], - activeAccountId: parsed.activeAccountId, - loadBalanceMode: parsed.loadBalanceMode ?? "round_robin", - }; - } catch (err) { - if ((err as NodeJS.ErrnoException).code === "ENOENT") { - return { - version: 1, - accounts: [], - loadBalanceMode: "round_robin", - }; - } - throw err; - } -} - -/** - * Load Antigravity accounts synchronously. - */ -export function loadAntigravityAccountsSync(): AntigravityAccounts { - try { - const content = fsSync.readFileSync(ACCOUNTS_FILE, "utf-8"); - const parsed = JSON.parse(content) as AntigravityAccounts; - return { - version: parsed.version ?? 1, - accounts: parsed.accounts ?? [], - activeAccountId: parsed.activeAccountId, - loadBalanceMode: parsed.loadBalanceMode ?? "round_robin", - }; - } catch (err) { - if ((err as NodeJS.ErrnoException).code === "ENOENT") { - return { - version: 1, - accounts: [], - loadBalanceMode: "round_robin", - }; - } - throw err; - } -} - -/** - * Save Antigravity accounts to disk with secure permissions. - */ -export async function saveAntigravityAccounts( - accounts: AntigravityAccounts, -): Promise { - await ensureDir(ANTIGRAVITY_DIR); - const content = JSON.stringify(accounts, null, 2); - await fs.writeFile(ACCOUNTS_FILE, content, { mode: 0o600 }); -} - -// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ -// OAuth Flow Functions -// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ - -/** - * Start the device code OAuth flow. - * Returns user code and verification URL for user to complete. - */ -export async function startDeviceCodeFlow(): Promise { - const response = await fetch(`${ANTIGRAVITY_AUTH_URL}/device`, { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ - client_id: GOOGLE_CLIENT_ID, - scope: "https://www.googleapis.com/auth/cloud-platform https://www.googleapis.com/auth/generative-language.retriever", - }), - }); - - if (!response.ok) { - const error = await response.text(); - throw new Error(`Failed to start device code flow: ${response.status} - ${error}`); - } - - const data = await response.json() as { - device_code: string; - user_code: string; - verification_url: string; - expires_in: number; - interval: number; - }; - - return { - deviceCode: data.device_code, - userCode: data.user_code, - verificationUrl: data.verification_url, - expiresIn: data.expires_in, - interval: data.interval, - }; -} - -/** - * Poll for token after user completes OAuth flow. - */ -export async function pollForToken( - deviceCode: string, - interval: number, - timeout: number, -): Promise { - const startTime = Date.now(); - const pollInterval = Math.max(interval * 1000, 5000); // At least 5 seconds - - while (Date.now() - startTime < timeout * 1000) { - await new Promise((resolve) => setTimeout(resolve, pollInterval)); - - const response = await fetch(`${ANTIGRAVITY_TOKEN_URL}`, { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ - client_id: GOOGLE_CLIENT_ID, - device_code: deviceCode, - grant_type: "urn:ietf:params:oauth:grant-type:device_code", - }), - }); - - if (response.ok) { - const data = await response.json() as { - access_token: string; - refresh_token: string; - expires_in: number; - scope: string; - }; - - return { - accessToken: data.access_token, - refreshToken: data.refresh_token, - expiresAt: Date.now() + data.expires_in * 1000, - scope: data.scope, - }; - } - - const errorData = await response.json() as { error?: string }; - if (errorData.error === "authorization_pending") { - // User hasn't completed auth yet, keep polling - continue; - } else if (errorData.error === "slow_down") { - // Back off - await new Promise((resolve) => setTimeout(resolve, 5000)); - continue; - } else if (errorData.error === "expired_token") { - // Device code expired - return null; - } else { - throw new Error(`OAuth error: ${errorData.error}`); - } - } - - return null; // Timeout -} - -/** - * Refresh an access token using refresh token. - */ -export async function refreshAccessToken( - refreshToken: string, -): Promise { - const response = await fetch(`${ANTIGRAVITY_TOKEN_URL}`, { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ - client_id: GOOGLE_CLIENT_ID, - refresh_token: refreshToken, - grant_type: "refresh_token", - }), - }); - - if (!response.ok) { - return null; - } - - const data = await response.json() as { - access_token: string; - expires_in: number; - scope: string; - }; - - return { - accessToken: data.access_token, - refreshToken: refreshToken, // Refresh token stays the same - expiresAt: Date.now() + data.expires_in * 1000, - scope: data.scope, - }; -} - -// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ -// Account Management -// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ - -/** - * Add a new account after successful OAuth. - */ -export async function addAntigravityAccount( - email: string, - token: GoogleOAuthToken, -): Promise { - const accounts = await loadAntigravityAccounts(); - - // Check if account already exists - const existingIndex = accounts.accounts.findIndex((a) => a.email === email); - if (existingIndex >= 0) { - // Update existing account - accounts.accounts[existingIndex].token = token; - accounts.accounts[existingIndex].lastUsed = Date.now(); - await saveAntigravityAccounts(accounts); - return accounts.accounts[existingIndex]; - } - - // Create new account - const account: AntigravityAccount = { - id: `ag-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 6)}`, - email, - token, - addedAt: Date.now(), - requestCount: 0, - }; - - accounts.accounts.push(account); - - // Set as active if first account - if (accounts.accounts.length === 1) { - accounts.activeAccountId = account.id; - } - - await saveAntigravityAccounts(accounts); - return account; -} - -/** - * Remove an account. - */ -export async function removeAntigravityAccount(accountId: string): Promise { - const accounts = await loadAntigravityAccounts(); - const index = accounts.accounts.findIndex((a) => a.id === accountId); - - if (index < 0) { - return false; - } - - accounts.accounts.splice(index, 1); - - // Update active account if needed - if (accounts.activeAccountId === accountId) { - accounts.activeAccountId = accounts.accounts[0]?.id; - } - - await saveAntigravityAccounts(accounts); - return true; -} - -/** - * List all configured accounts. - */ -export async function listAntigravityAccounts(): Promise { - const accounts = await loadAntigravityAccounts(); - return accounts.accounts; -} - -/** - * Get the best account for making a request (load balancing). - */ -export async function getBestAccount(): Promise { - const data = await loadAntigravityAccounts(); - const { accounts, loadBalanceMode, activeAccountId } = data; - - if (accounts.length === 0) { - return null; - } - - // Filter out rate-limited accounts - const now = Date.now(); - const available = accounts.filter( - (a) => !a.rateLimitedUntil || a.rateLimitedUntil < now, - ); - - if (available.length === 0) { - // All accounts rate-limited, return the one that will be available soonest - return accounts.reduce((prev, curr) => - (prev.rateLimitedUntil ?? 0) < (curr.rateLimitedUntil ?? 0) ? prev : curr, - ); - } - - switch (loadBalanceMode) { - case "round_robin": { - // Find the active account, then use the next one - const activeIndex = available.findIndex((a) => a.id === activeAccountId); - const nextIndex = (activeIndex + 1) % available.length; - return available[nextIndex]; - } - - case "least_used": - // Return account with lowest request count - return available.reduce((prev, curr) => - prev.requestCount < curr.requestCount ? prev : curr, - ); - - case "random": - default: - return available[Math.floor(Math.random() * available.length)]; - } -} - -/** - * Get a valid access token for making requests. - * Refreshes if needed. - */ -export async function getValidAccessToken(): Promise { - const account = await getBestAccount(); - if (!account) { - return null; - } - - // Check if token needs refresh (5 min buffer) - if (account.token.expiresAt < Date.now() + 5 * 60 * 1000) { - const newToken = await refreshAccessToken(account.token.refreshToken); - if (newToken) { - account.token = newToken; - const accounts = await loadAntigravityAccounts(); - const index = accounts.accounts.findIndex((a) => a.id === account.id); - if (index >= 0) { - accounts.accounts[index] = account; - await saveAntigravityAccounts(accounts); - } - } else { - return null; // Refresh failed - } - } - - // Update stats - const accounts = await loadAntigravityAccounts(); - const index = accounts.accounts.findIndex((a) => a.id === account.id); - if (index >= 0) { - accounts.accounts[index].lastUsed = Date.now(); - accounts.accounts[index].requestCount++; - accounts.activeAccountId = account.id; - await saveAntigravityAccounts(accounts); - } - - return account.token.accessToken; -} - -/** - * Mark an account as rate-limited. - */ -export async function markAccountRateLimited( - accountId: string, - retryAfterMs: number = 60000, -): Promise { - const accounts = await loadAntigravityAccounts(); - const index = accounts.accounts.findIndex((a) => a.id === accountId); - - if (index >= 0) { - accounts.accounts[index].rateLimitedUntil = Date.now() + retryAfterMs; - await saveAntigravityAccounts(accounts); - } -} - -// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ -// Status and Validation -// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ - -/** - * Check if Google Antigravity is configured (has at least one account). - */ -export async function isAntigravityConfigured(): Promise { - const accounts = await loadAntigravityAccounts(); - return accounts.accounts.length > 0; -} - -/** - * Get a summary of Antigravity configuration status. - */ -export async function getAntigravityStatus(): Promise<{ - configured: boolean; - accountCount: number; - accounts: Array<{ - id: string; - email: string; - isActive: boolean; - requestCount: number; - lastUsed?: number; - isRateLimited: boolean; - }>; - loadBalanceMode: string; -}> { - const data = await loadAntigravityAccounts(); - const now = Date.now(); - - return { - configured: data.accounts.length > 0, - accountCount: data.accounts.length, - accounts: data.accounts.map((a) => ({ - id: a.id, - email: a.email, - isActive: a.id === data.activeAccountId, - requestCount: a.requestCount, - lastUsed: a.lastUsed, - isRateLimited: Boolean(a.rateLimitedUntil && a.rateLimitedUntil > now), - })), - loadBalanceMode: data.loadBalanceMode, - }; -} - -/** - * Get the Antigravity API base URL. - */ -export function getAntigravityApiUrl(): string { - return ANTIGRAVITY_API_URL; -} - -/** - * Clear all Antigravity accounts. - */ -export async function clearAllAntigravityAccounts(): Promise { - try { - await fs.rm(ACCOUNTS_FILE, { force: true }); - } catch { - // Ignore errors - } -} diff --git a/src/council/auth/index.ts b/src/council/auth/index.ts deleted file mode 100644 index 7e5fc331cd..0000000000 --- a/src/council/auth/index.ts +++ /dev/null @@ -1,8 +0,0 @@ -/** - * Council Auth Module - * - * Provides secure credential storage and management for council providers. - */ - -export * from "./storage.js"; -export * from "./google-antigravity-auth.js"; diff --git a/src/council/auth/storage.ts b/src/council/auth/storage.ts deleted file mode 100644 index 6129c33776..0000000000 --- a/src/council/auth/storage.ts +++ /dev/null @@ -1,420 +0,0 @@ -/** - * Council Credential Storage - * - * Securely stores and retrieves API keys for council providers. - * Credentials are stored in ~/.zee/credentials/council/providers.json - * with restrictive file permissions (0o600). - */ - -import fs from "node:fs/promises"; -import fsSync from "node:fs"; -import os from "node:os"; -import path from "node:path"; - -import { ensureDir } from "../../utils.js"; - -// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ -// Constants -// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ - -const CONFIG_DIR = path.join(os.homedir(), ".zee"); -const COUNCIL_CREDS_DIR = path.join(CONFIG_DIR, "credentials", "council"); -const PROVIDERS_FILE = path.join(COUNCIL_CREDS_DIR, "providers.json"); - -// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ -// Types -// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ - -/** - * Supported council provider types. - */ -export type CouncilProviderType = - | "openrouter" - | "opencode_zen" - | "google_antigravity" // Free Gemini via Google OAuth - | "anthropic" - | "openai" - | "google" - | "zai" - | "custom"; - -/** - * Stored credential for a single provider. - */ -export interface ProviderCredential { - apiKey: string; - baseUrl?: string; - addedAt: number; - lastUsed?: number; -} - -/** - * Full credentials store structure. - */ -export interface CouncilCredentials { - version: number; - providers: Partial>; -} - -// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ -// Storage Functions -// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ - -/** - * Get the path to the council credentials file. - */ -export function getCouncilCredsPath(): string { - return PROVIDERS_FILE; -} - -/** - * Get the path to the council credentials directory. - */ -export function getCouncilCredsDir(): string { - return COUNCIL_CREDS_DIR; -} - -/** - * Load council credentials from disk. - * Returns empty credentials if file doesn't exist. - */ -export async function loadCouncilCredentials(): Promise { - try { - const content = await fs.readFile(PROVIDERS_FILE, "utf-8"); - const parsed = JSON.parse(content) as CouncilCredentials; - return { - version: parsed.version ?? 1, - providers: parsed.providers ?? {}, - }; - } catch (err) { - if ((err as NodeJS.ErrnoException).code === "ENOENT") { - return { version: 1, providers: {} }; - } - throw err; - } -} - -/** - * Load council credentials synchronously. - * Returns empty credentials if file doesn't exist. - */ -export function loadCouncilCredentialsSync(): CouncilCredentials { - try { - const content = fsSync.readFileSync(PROVIDERS_FILE, "utf-8"); - const parsed = JSON.parse(content) as CouncilCredentials; - return { - version: parsed.version ?? 1, - providers: parsed.providers ?? {}, - }; - } catch (err) { - if ((err as NodeJS.ErrnoException).code === "ENOENT") { - return { version: 1, providers: {} }; - } - throw err; - } -} - -/** - * Save council credentials to disk with secure permissions. - */ -export async function saveCouncilCredentials( - creds: CouncilCredentials, -): Promise { - await ensureDir(COUNCIL_CREDS_DIR); - const content = JSON.stringify(creds, null, 2); - await fs.writeFile(PROVIDERS_FILE, content, { mode: 0o600 }); -} - -/** - * Save a single provider credential. - */ -export async function saveProviderCredential( - provider: CouncilProviderType, - credential: Omit, -): Promise { - const creds = await loadCouncilCredentials(); - creds.providers[provider] = { - ...credential, - addedAt: Date.now(), - }; - await saveCouncilCredentials(creds); -} - -/** - * Get a single provider credential. - */ -export async function getProviderCredential( - provider: CouncilProviderType, -): Promise { - const creds = await loadCouncilCredentials(); - return creds.providers[provider] ?? null; -} - -/** - * Get a provider's API key, checking credentials file then environment. - * Returns null if not found. - */ -export async function resolveProviderApiKey( - provider: CouncilProviderType, -): Promise { - // Check environment first (higher priority) - const envKey = getEnvKeyForProvider(provider); - if (envKey && process.env[envKey]?.trim()) { - return process.env[envKey]!.trim(); - } - - // Fall back to stored credentials - const cred = await getProviderCredential(provider); - return cred?.apiKey ?? null; -} - -/** - * Get a provider's API key synchronously. - */ -export function resolveProviderApiKeySync( - provider: CouncilProviderType, -): string | null { - // Check environment first - const envKey = getEnvKeyForProvider(provider); - if (envKey && process.env[envKey]?.trim()) { - return process.env[envKey]!.trim(); - } - - // Fall back to stored credentials - const creds = loadCouncilCredentialsSync(); - return creds.providers[provider]?.apiKey ?? null; -} - -/** - * Delete a provider credential. - */ -export async function deleteProviderCredential( - provider: CouncilProviderType, -): Promise { - const creds = await loadCouncilCredentials(); - if (!creds.providers[provider]) { - return false; - } - delete creds.providers[provider]; - await saveCouncilCredentials(creds); - return true; -} - -/** - * List all configured providers. - */ -export async function listConfiguredProviders(): Promise { - const creds = await loadCouncilCredentials(); - return Object.keys(creds.providers) as CouncilProviderType[]; -} - -/** - * Check if a provider is configured (either in credentials or environment). - */ -export async function isProviderConfigured( - provider: CouncilProviderType, -): Promise { - const apiKey = await resolveProviderApiKey(provider); - return apiKey !== null && apiKey.length > 0; -} - -/** - * Update last used timestamp for a provider. - */ -export async function updateProviderLastUsed( - provider: CouncilProviderType, -): Promise { - const creds = await loadCouncilCredentials(); - if (creds.providers[provider]) { - creds.providers[provider]!.lastUsed = Date.now(); - await saveCouncilCredentials(creds); - } -} - -// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ -// Environment Variable Mapping -// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ - -const PROVIDER_ENV_VARS: Record = { - openrouter: "OPENROUTER_API_KEY", - opencode_zen: "OPENCODE_ZEN_API_KEY", - google_antigravity: "GOOGLE_OAUTH_TOKEN", // OAuth token, not API key - anthropic: "ANTHROPIC_API_KEY", - openai: "OPENAI_API_KEY", - google: "GOOGLE_AI_API_KEY", - zai: "ZAI_API_KEY", - custom: null, -}; - -/** - * Get the environment variable name for a provider. - */ -export function getEnvKeyForProvider( - provider: CouncilProviderType, -): string | null { - return PROVIDER_ENV_VARS[provider]; -} - -/** - * Get provider status summary (for display). - */ -export async function getProviderStatus(): Promise< - Array<{ - provider: CouncilProviderType; - configured: boolean; - source: "env" | "credentials" | "none"; - lastUsed?: number; - }> -> { - const creds = await loadCouncilCredentials(); - const providers: CouncilProviderType[] = [ - "openrouter", - "opencode_zen", - "google_antigravity", - "anthropic", - "openai", - "google", - "zai", - ]; - - return providers.map((provider) => { - const envKey = getEnvKeyForProvider(provider); - const hasEnv = envKey ? Boolean(process.env[envKey]?.trim()) : false; - const hasCreds = Boolean(creds.providers[provider]?.apiKey); - - return { - provider, - configured: hasEnv || hasCreds, - source: hasEnv ? "env" : hasCreds ? "credentials" : "none", - lastUsed: creds.providers[provider]?.lastUsed, - }; - }); -} - -// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ -// Validation -// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ - -/** - * Validate an OpenRouter API key format. - * OpenRouter keys start with "sk-or-" - */ -export function validateOpenRouterKey(key: string): boolean { - return key.startsWith("sk-or-") && key.length > 10; -} - -/** - * Validate an Anthropic API key format. - * Anthropic keys start with "sk-ant-" - */ -export function validateAnthropicKey(key: string): boolean { - return key.startsWith("sk-ant-") && key.length > 10; -} - -/** - * Validate an OpenAI API key format. - * OpenAI keys start with "sk-" - */ -export function validateOpenAIKey(key: string): boolean { - return key.startsWith("sk-") && key.length > 10; -} - -/** - * Validate a Google AI API key format. - * Google AI keys start with "AIzaSy" - */ -export function validateGoogleKey(key: string): boolean { - return key.startsWith("AIzaSy") && key.length > 30; -} - -/** - * Validate an OpenCode Zen API key format. - * OpenCode Zen keys start with "sk-" - */ -export function validateOpenCodeZenKey(key: string): boolean { - return key.startsWith("sk-") && key.length > 20; -} - -/** - * Validate a ZAI API key format. - * ZAI keys have format: uuid.token - */ -export function validateZaiKey(key: string): boolean { - return key.includes(".") && key.length > 20; -} - -/** - * Validate an API key format for a specific provider. - */ -export function validateApiKeyFormat( - provider: CouncilProviderType, - key: string, -): { valid: boolean; error?: string } { - if (!key || key.trim().length === 0) { - return { valid: false, error: "API key is required" }; - } - - switch (provider) { - case "openrouter": - if (!validateOpenRouterKey(key)) { - return { - valid: false, - error: 'OpenRouter API key should start with "sk-or-"', - }; - } - break; - case "opencode_zen": - if (!validateOpenCodeZenKey(key)) { - return { - valid: false, - error: 'OpenCode Zen API key should start with "sk-"', - }; - } - break; - case "anthropic": - if (!validateAnthropicKey(key)) { - return { - valid: false, - error: 'Anthropic API key should start with "sk-ant-"', - }; - } - break; - case "openai": - if (!validateOpenAIKey(key)) { - return { - valid: false, - error: 'OpenAI API key should start with "sk-"', - }; - } - break; - case "google": - if (!validateGoogleKey(key)) { - return { - valid: false, - error: 'Google AI API key should start with "AIzaSy"', - }; - } - break; - case "zai": - if (!validateZaiKey(key)) { - return { - valid: false, - error: 'ZAI API key should be in format "uuid.token"', - }; - } - break; - } - - return { valid: true }; -} - -/** - * Clear all council credentials. - */ -export async function clearAllCredentials(): Promise { - try { - await fs.rm(PROVIDERS_FILE, { force: true }); - } catch { - // Ignore errors if file doesn't exist - } -} diff --git a/src/council/council-coordinator.ts b/src/council/council-coordinator.ts deleted file mode 100644 index a1f23ec4dc..0000000000 --- a/src/council/council-coordinator.ts +++ /dev/null @@ -1,376 +0,0 @@ -/** - * Council Coordinator - Multi-LLM/Agent deliberation system. - * - * Implements Karpathy's llm-council 3-stage algorithm: - * 1. Parallel independent responses from all council members - * 2. Anonymous peer review and ranking - * 3. Chairman synthesis of final answer - * - * Supports three modes: - * - raw_llm: Different LLM models answer the same question - * - agent: Specialized agents provide domain-expert responses - * - hybrid: Mixed LLM and agent participation - */ - -import type { AgentOrchestrator } from "../tiara.js"; -import type { ModelCatalogEntry } from "../model-catalog.js"; -import { loadModelCatalog } from "../model-catalog.js"; -import type { SpecializedAgentType } from "../agent-types.js"; -import type { - CouncilConfig, - CouncilMember, - CouncilMode, - CouncilResult, - CouncilSession, - CouncilStage, - LLMMember, -} from "./council-types.js"; -import { - createDefaultCouncilConfig, - generateCouncilId, - validateCouncilConfig, -} from "./council-types.js"; -import { - executeStage1Parallel, - executeStage2PeerReview, - executeStage3Synthesis, -} from "./council-stages.js"; - -// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ -// In-Memory Session Store -// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ - -const councilSessions = new Map(); - -// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ -// Council Coordinator Class -// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ - -/** - * Main coordinator class for LLM Council deliberations. - */ -export class CouncilCoordinator { - private readonly tiara?: AgentOrchestrator; - private readonly modelCatalog: ModelCatalogEntry[]; - - constructor(params?: { - tiara?: AgentOrchestrator; - modelCatalog?: ModelCatalogEntry[]; - }) { - this.tiara = params?.tiara; - this.modelCatalog = params?.modelCatalog ?? []; - } - - /** - * Create a CouncilCoordinator with model catalog loaded. - */ - static async create(params?: { - tiara?: AgentOrchestrator; - }): Promise { - const catalog = await loadModelCatalog(); - return new CouncilCoordinator({ - tiara: params?.tiara, - modelCatalog: catalog, - }); - } - - /** - * Get available models for council participation. - */ - getAvailableModels(): ModelCatalogEntry[] { - return this.modelCatalog; - } - - /** - * Get available agents for council participation. - */ - getAvailableAgents(): SpecializedAgentType[] { - return [ - "inbox_manager", - "scheduler", - "research_assistant", - "task_coordinator", - ]; - } - - /** - * Create a new council session. - */ - createSession( - question: string, - config: Partial, - context?: string, - ): CouncilSession { - const id = generateCouncilId(); - const fullConfig = createDefaultCouncilConfig(config); - - const validation = validateCouncilConfig(fullConfig); - if (!validation.valid) { - throw new Error( - `Invalid council config: ${validation.errors.join(", ")}`, - ); - } - - const session: CouncilSession = { - id, - config: fullConfig, - question, - context, - stage: "pending", - responses: [], - reviews: [], - reviewAggregates: [], - createdAt: Date.now(), - }; - - councilSessions.set(id, session); - return session; - } - - /** - * Execute the full 3-stage council deliberation. - * - * @param question - The question for the council to deliberate - * @param config - Council configuration - * @param options - Additional options - * @returns The council result with final answer and synthesis - */ - async deliberate( - question: string, - config: Partial, - options?: { - context?: string; - includeDebug?: boolean; - }, - ): Promise { - const session = this.createSession(question, config, options?.context); - const startTime = Date.now(); - - try { - // Stage 1: Collect parallel responses - session.stage = "stage1"; - session.responses = await executeStage1Parallel({ - session, - tiara: this.tiara, - }); - session.stage1CompletedAt = Date.now(); - - // Check quorum - const successfulResponses = session.responses.filter((r) => !r.error); - const quorum = - session.config.quorum ?? - Math.ceil(session.config.members.length / 2); - - if (successfulResponses.length < quorum) { - throw new Error( - `Quorum not met: ${successfulResponses.length}/${quorum} responses required`, - ); - } - - // Stage 2: Peer review - session.stage = "stage2"; - const { reviews, aggregates } = await executeStage2PeerReview({ - session, - tiara: this.tiara, - }); - session.reviews = reviews; - session.reviewAggregates = aggregates; - session.stage2CompletedAt = Date.now(); - - // Stage 3: Chairman synthesis - session.stage = "stage3"; - session.synthesis = await executeStage3Synthesis({ - session, - tiara: this.tiara, - }); - session.completedAt = Date.now(); - session.stage = "complete"; - - // Build result - const topScorer = - session.reviewAggregates.length > 0 - ? session.reviewAggregates.reduce((best, curr) => - curr.weightedScore > best.weightedScore ? curr : best, - ) - : null; - - const result: CouncilResult = { - sessionId: session.id, - success: true, - finalAnswer: session.synthesis.finalResponse, - synthesis: session.synthesis, - summary: { - totalMembers: session.config.members.length, - respondedMembers: successfulResponses.length, - topScorer: topScorer?.memberId ?? "unknown", - consensusLevel: topScorer?.consensus ?? "unknown", - totalDurationMs: Date.now() - startTime, - }, - }; - - if (options?.includeDebug) { - result.debug = { - responses: session.responses, - reviews: session.reviews, - aggregates: session.reviewAggregates, - }; - } - - return result; - } catch (error) { - session.stage = "failed"; - session.error = error instanceof Error ? error.message : String(error); - throw error; - } - } - - /** - * Quick consensus - simplified 2-stage deliberation without peer review. - * Useful for faster decisions when full deliberation is not needed. - * - * @param question - The question for quick consensus - * @param models - Model identifiers to use (OpenRouter format) - * @returns Quick consensus result - */ - async quickConsensus( - question: string, - models: string[] = ["anthropic/claude-3-opus", "openai/gpt-4-turbo"], - ): Promise<{ - question: string; - responses: Array<{ model: string; response: string; error?: string }>; - consensus?: string; - agreement: "strong" | "moderate" | "weak" | "none"; - }> { - // Create LLM members from model list - const members: LLMMember[] = models.map((model, i) => ({ - type: "llm" as const, - id: `model-${i}`, - provider: "openrouter", - model, - modelRoute: model, - })); - - const config: Partial = { - mode: "raw_llm", - members, - chairman: { mode: "highest_scorer" }, - peerReview: { - anonymous: true, - method: "score", - criteria: ["Accuracy", "Completeness", "Clarity"], - allowSelfReview: false, - }, - }; - - // Stage 1 only (skip peer review) - const session = this.createSession(question, config); - session.stage = "stage1"; - session.responses = await executeStage1Parallel({ session }); - - const successfulResponses = session.responses.filter((r) => !r.error); - - // Simple consensus detection by checking similarity - let agreement: "strong" | "moderate" | "weak" | "none" = "none"; - let consensus: string | undefined; - - if (successfulResponses.length >= 2) { - // Use first response as baseline for simple comparison - consensus = successfulResponses[0].response; - - // This is a simplified agreement check - // A more sophisticated version would use semantic similarity - const responseTexts = successfulResponses.map((r) => - r.response.toLowerCase().trim(), - ); - const uniqueResponses = new Set(responseTexts); - - if (uniqueResponses.size === 1) { - agreement = "strong"; - } else if (uniqueResponses.size <= responseTexts.length / 2) { - agreement = "moderate"; - } else if (uniqueResponses.size < responseTexts.length) { - agreement = "weak"; - } - } else if (successfulResponses.length === 1) { - consensus = successfulResponses[0].response; - agreement = "weak"; // Single response can't have consensus - } - - return { - question, - responses: session.responses.map((r) => ({ - model: r.metadata?.model ?? r.memberId, - response: r.response, - error: r.error, - })), - consensus, - agreement, - }; - } - - /** - * Get a session by ID. - */ - getSession(sessionId: string): CouncilSession | undefined { - return councilSessions.get(sessionId); - } - - /** - * List all sessions with optional filtering. - */ - listSessions(options?: { - limit?: number; - status?: CouncilStage; - }): CouncilSession[] { - let sessions = Array.from(councilSessions.values()); - - if (options?.status) { - sessions = sessions.filter((s) => s.stage === options.status); - } - - sessions.sort((a, b) => b.createdAt - a.createdAt); - - if (options?.limit) { - sessions = sessions.slice(0, options.limit); - } - - return sessions; - } - - /** - * Delete a session by ID. - */ - deleteSession(sessionId: string): boolean { - return councilSessions.delete(sessionId); - } - - /** - * Clear all sessions. - */ - clearSessions(): void { - councilSessions.clear(); - } -} - -// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ -// Singleton Instance -// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ - -let defaultCoordinator: CouncilCoordinator | null = null; - -/** - * Get or create the default council coordinator. - */ -export async function getDefaultCouncilCoordinator(): Promise { - if (!defaultCoordinator) { - defaultCoordinator = await CouncilCoordinator.create(); - } - return defaultCoordinator; -} - -/** - * Reset the default coordinator (useful for testing). - */ -export function resetDefaultCouncilCoordinator(): void { - defaultCoordinator = null; -} diff --git a/src/council/council-providers.ts b/src/council/council-providers.ts deleted file mode 100644 index e1ac7e76c9..0000000000 --- a/src/council/council-providers.ts +++ /dev/null @@ -1,290 +0,0 @@ -/** - * Provider abstraction for the LLM Council. - * - * This is a thin wrapper around OpenCode's Provider system. - * All orchestration techniques (Council, Swarm, HiveMind) should use this. - */ - -import type { - CouncilProviderType, - CouncilProviderConfig, - LLMMember, -} from "./council-types.js"; - -// Import OpenCode's Provider -// Relative path from src/council/ to packages/agent-core/src/provider/ -import { Provider } from "../../packages/agent-core/src/provider/provider.js"; - -// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ -// Provider Interface (maintained for compatibility) -// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ - -/** - * Options for a completion request. - */ -export interface CompletionOptions { - /** System prompt */ - systemPrompt?: string; - /** Temperature (0-1) */ - temperature?: number; - /** Max output tokens */ - maxTokens?: number; - /** Timeout in ms */ - timeoutMs?: number; - /** Additional metadata to pass through */ - metadata?: Record; -} - -/** - * Result of a completion request. - */ -export interface CompletionResult { - /** The generated response text */ - text: string; - /** Token usage statistics */ - usage?: { - inputTokens: number; - outputTokens: number; - totalTokens: number; - }; - /** Time taken in ms */ - durationMs: number; - /** Model that was actually used (may differ from requested) */ - model?: string; - /** Any warnings or notices */ - warnings?: string[]; -} - -/** - * Abstract interface for council providers. - */ -export interface CouncilProvider { - /** Provider type identifier */ - readonly type: CouncilProviderType; - /** Human-readable name */ - readonly name: string; - - /** - * Send a completion request to the provider. - */ - complete(prompt: string, options?: CompletionOptions): Promise; - - /** - * Check if the provider is configured and ready. - */ - isConfigured(): Promise; - - /** - * List available models for this provider. - */ - listModels?(): Promise; -} - -// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ -// OpenCode Provider Wrapper -// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ - -/** - * Maps CouncilProviderType to OpenCode provider IDs. - */ -const PROVIDER_TYPE_MAP: Record = { - openrouter: "openrouter", - opencode_zen: "opencode", - google_antigravity: "google-antigravity", - anthropic: "anthropic", - openai: "openai", - google: "google", - zai: "zai", - custom: "openai", // Custom uses OpenAI-compatible -}; - -/** - * Wrapper that adapts OpenCode's Provider to the CouncilProvider interface. - */ -class OpenCodeProviderWrapper implements CouncilProvider { - readonly type: CouncilProviderType; - readonly name: string; - - constructor( - private readonly providerId: string, - private readonly model: string, - type: CouncilProviderType, - name: string, - ) { - this.type = type; - this.name = name; - } - - async complete( - prompt: string, - options?: CompletionOptions, - ): Promise { - const startTime = Date.now(); - - try { - // Get the model info, then the language model from OpenCode's Provider - const modelInfo = await Provider.getModel(this.providerId, this.model); - const languageModel = await Provider.getLanguage(modelInfo); - - // Build messages - const messages: Array<{ role: "system" | "user"; content: string }> = []; - if (options?.systemPrompt) { - messages.push({ role: "system", content: options.systemPrompt }); - } - messages.push({ role: "user", content: prompt }); - - // Use the Vercel AI SDK's generateText - const { generateText } = await import("ai"); - - const result = await generateText({ - model: languageModel as any, // LanguageModelV2 is compatible - messages, - temperature: options?.temperature ?? 0.7, - maxTokens: options?.maxTokens ?? 4096, - abortSignal: options?.timeoutMs - ? AbortSignal.timeout(options.timeoutMs) - : undefined, - }); - - return { - text: result.text, - usage: result.usage - ? { - inputTokens: result.usage.promptTokens, - outputTokens: result.usage.completionTokens, - totalTokens: result.usage.totalTokens, - } - : undefined, - durationMs: Date.now() - startTime, - model: this.model, - }; - } catch (error) { - const err = error as Error; - throw new Error(`${this.name} error: ${err.message}`); - } - } - - async isConfigured(): Promise { - try { - const provider = await Provider.getProvider(this.providerId); - return provider !== undefined; - } catch { - return false; - } - } - - async listModels(): Promise { - try { - const models = await Provider.list(); - return models - .filter((m) => m.provider === this.providerId) - .map((m) => m.id); - } catch { - return []; - } - } -} - -// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ -// Provider Factory -// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ - -/** - * Default base URLs for reference (OpenCode Provider handles these internally). - */ -export const PROVIDER_BASE_URLS: Record = { - openrouter: "https://openrouter.ai/api/v1", - opencode_zen: "https://opencode.ai/zen/v1", - google_antigravity: "https://antigravity.opencode.ai/v1", - anthropic: "https://api.anthropic.com", - openai: "https://api.openai.com/v1", - google: "https://generativelanguage.googleapis.com/v1beta", - zai: "https://api.zai.one/v1", - custom: "", -}; - -/** - * Default environment variable names for API keys. - * OpenCode Provider handles key resolution internally. - */ -export const PROVIDER_ENV_VARS: Record = { - openrouter: "OPENROUTER_API_KEY", - opencode_zen: "OPENCODE_ZEN_API_KEY", - google_antigravity: "GOOGLE_OAUTH_TOKEN", - anthropic: "ANTHROPIC_API_KEY", - openai: "OPENAI_API_KEY", - google: "GOOGLE_AI_API_KEY", - zai: "ZAI_API_KEY", - custom: "", -}; - -/** - * Resolve API key from config or environment. - * Kept for compatibility - OpenCode Provider handles this internally. - */ -export function resolveApiKey(config: CouncilProviderConfig): string | undefined { - if (config.apiKey) { - return config.apiKey; - } - if (config.apiKeyEnv) { - return process.env[config.apiKeyEnv]; - } - const defaultEnv = PROVIDER_ENV_VARS[config.type]; - if (defaultEnv) { - return process.env[defaultEnv]; - } - return undefined; -} - -/** - * Get human-readable name for a provider type. - */ -function getProviderName(type: CouncilProviderType): string { - const names: Record = { - openrouter: "OpenRouter", - opencode_zen: "OpenCode Zen", - google_antigravity: "Google Antigravity", - anthropic: "Anthropic", - openai: "OpenAI", - google: "Google Gemini", - zai: "ZAI", - custom: "Custom", - }; - return names[type]; -} - -/** - * Create a provider instance for an LLM council member. - * Uses OpenCode's Provider system under the hood. - */ -export function createProviderForMember( - member: LLMMember, - _defaultConfig?: CouncilProviderConfig, -): CouncilProvider { - const providerType = member.provider; - const model = member.modelRoute ?? member.model; - const providerId = PROVIDER_TYPE_MAP[providerType]; - - return new OpenCodeProviderWrapper( - providerId, - model, - providerType, - member.displayName ?? getProviderName(providerType), - ); -} - -/** - * Create providers for all LLM members in a council. - */ -export function createProvidersForCouncil( - members: LLMMember[], - defaultConfig?: CouncilProviderConfig, -): Map { - const providers = new Map(); - - for (const member of members) { - providers.set(member.id, createProviderForMember(member, defaultConfig)); - } - - return providers; -} diff --git a/src/council/council-stages.ts b/src/council/council-stages.ts deleted file mode 100644 index e0658c5758..0000000000 --- a/src/council/council-stages.ts +++ /dev/null @@ -1,752 +0,0 @@ -/** - * Council stage execution - implements the 3-stage deliberation algorithm. - * - * Stage 1: Parallel independent responses from all council members - * Stage 2: Anonymous peer review and ranking of responses - * Stage 3: Chairman synthesizes final answer - */ - -import type { AgentOrchestrator } from "../tiara.js"; -import type { - CouncilConfig, - CouncilMember, - CouncilResponse, - CouncilSession, - PeerReview, - ReviewAggregate, - ChairmanSynthesis, - LLMMember, - AgentMember, - CouncilProviderConfig, -} from "./council-types.js"; -import { - type CouncilProvider, - createProviderForMember, -} from "./council-providers.js"; -import { Log } from "../../packages/agent-core/src/util/log"; - -const log = Log.create({ service: "council-stages" }); - -// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ -// Stage 1: Parallel Independent Responses -// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ - -/** - * Execute Stage 1: Collect parallel independent responses from all members. - */ -export async function executeStage1Parallel(params: { - session: CouncilSession; - tiara?: AgentOrchestrator; -}): Promise { - const { session } = params; - const { config, question, context } = session; - - const responses: CouncilResponse[] = []; - const maxParallel = config.maxParallel ?? 5; - - // Separate LLM and agent members - const llmMembers = config.members.filter( - (m): m is LLMMember => m.type === "llm", - ); - const agentMembers = config.members.filter( - (m): m is AgentMember => m.type === "agent", - ); - - // Process LLM members in batches - for (let i = 0; i < llmMembers.length; i += maxParallel) { - const batch = llmMembers.slice(i, i + maxParallel); - const batchResults = await Promise.allSettled( - batch.map((member) => - executeLLMResponse(member, question, context, config), - ), - ); - - for (let j = 0; j < batchResults.length; j++) { - const result = batchResults[j]; - const member = batch[j]; - - if (result.status === "fulfilled") { - responses.push(result.value); - } else { - responses.push({ - memberId: member.id, - memberType: "llm", - response: "", - error: result.reason?.message ?? "Unknown error", - metadata: { durationMs: 0 }, - }); - } - } - } - - // Process agent members (if tiara provided) - if (params.tiara && agentMembers.length > 0) { - for (let i = 0; i < agentMembers.length; i += maxParallel) { - const batch = agentMembers.slice(i, i + maxParallel); - const batchResults = await Promise.allSettled( - batch.map((member) => - executeAgentResponse( - member, - question, - context, - params.tiara!, - config.stageTimeoutMs, - ), - ), - ); - - for (let j = 0; j < batchResults.length; j++) { - const result = batchResults[j]; - const member = batch[j]; - - if (result.status === "fulfilled") { - responses.push(result.value); - } else { - responses.push({ - memberId: member.id, - memberType: "agent", - response: "", - error: result.reason?.message ?? "Unknown error", - metadata: { agentType: member.agentType, durationMs: 0 }, - }); - } - } - } - } - - return responses; -} - -/** - * Execute LLM member response via provider. - */ -async function executeLLMResponse( - member: LLMMember, - question: string, - context: string | undefined, - config: CouncilConfig, -): Promise { - const startTime = Date.now(); - - try { - const provider = createProviderForMember(member, config.defaultProvider); - const prompt = buildStage1Prompt(question, context, member); - - const result = await provider.complete(prompt, { - systemPrompt: member.systemPrompt, - temperature: member.temperature ?? 0.7, - maxTokens: member.maxTokens ?? 4096, - timeoutMs: config.stageTimeoutMs, - }); - - return { - memberId: member.id, - memberType: "llm", - response: result.text, - metadata: { - provider: member.provider, - model: result.model ?? member.model, - durationMs: result.durationMs, - tokenUsage: result.usage - ? { - input: result.usage.inputTokens, - output: result.usage.outputTokens, - } - : undefined, - }, - }; - } catch (error) { - return { - memberId: member.id, - memberType: "llm", - response: "", - error: error instanceof Error ? error.message : String(error), - metadata: { - provider: member.provider, - model: member.model, - durationMs: Date.now() - startTime, - }, - }; - } -} - -/** - * Execute agent member response via tiara. - */ -async function executeAgentResponse( - member: AgentMember, - question: string, - context: string | undefined, - tiara: AgentOrchestrator, - timeoutMs?: number, -): Promise { - const startTime = Date.now(); - - try { - // Use the tiara's spawnAgent method to execute the agent - const prompt = buildStage1Prompt(question, context, member); - - const result = await tiara.spawnAgent({ - agentType: member.agentType, - action: "respond", - params: { query: prompt }, - context: member.context ? JSON.stringify(member.context) : undefined, - }); - - return { - memberId: member.id, - memberType: "agent", - response: - typeof result.result === "string" - ? result.result - : JSON.stringify(result.result ?? result.error ?? ""), - error: result.error, - metadata: { - agentType: member.agentType, - durationMs: result.durationMs ?? Date.now() - startTime, - }, - }; - } catch (error) { - return { - memberId: member.id, - memberType: "agent", - response: "", - error: error instanceof Error ? error.message : String(error), - metadata: { - agentType: member.agentType, - durationMs: Date.now() - startTime, - }, - }; - } -} - -/** - * Build the Stage 1 prompt for a council member. - */ -function buildStage1Prompt( - question: string, - context: string | undefined, - member: CouncilMember, -): string { - const parts: string[] = []; - - if (context) { - parts.push(`## Context\n${context}\n`); - } - - parts.push(`## Question\n${question}\n`); - - parts.push(`## Instructions`); - parts.push(`Provide your independent analysis and answer to this question.`); - parts.push(`Include your reasoning process and confidence level.`); - parts.push(`Be thorough but concise.`); - - if (member.type === "agent") { - parts.push( - `\nApply your specialized expertise as a ${member.agentType} to this question.`, - ); - } - - if (member.role === "specialist") { - parts.push( - `\nFocus on the aspects where your specialized knowledge is most relevant.`, - ); - } - - return parts.join("\n"); -} - -// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ -// Stage 2: Peer Review -// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ - -/** - * Execute Stage 2: Peer review of all responses. - */ -export async function executeStage2PeerReview(params: { - session: CouncilSession; - tiara?: AgentOrchestrator; -}): Promise<{ reviews: PeerReview[]; aggregates: ReviewAggregate[] }> { - const { session } = params; - const { config, question, responses } = session; - const { anonymous, criteria, allowSelfReview } = config.peerReview; - - const reviews: PeerReview[] = []; - const successfulResponses = responses.filter((r) => !r.error); - - // Each member reviews other members' responses - const llmMembers = config.members.filter( - (m): m is LLMMember => m.type === "llm", - ); - - for (const reviewer of llmMembers) { - const responsesToReview = allowSelfReview - ? successfulResponses - : successfulResponses.filter((r) => r.memberId !== reviewer.id); - - for (const response of responsesToReview) { - try { - const review = await executeReview({ - reviewer, - response, - question, - criteria, - anonymous, - config, - }); - if (review) { - reviews.push(review); - } - } catch (error) { - // Skip failed reviews, they don't contribute to aggregates - log.warn("Peer review failed", { - reviewerId: reviewer.id, - responseMemberId: response.memberId, - error: error instanceof Error ? error.message : String(error), - }); - } - } - } - - // Aggregate reviews per response - const aggregates = aggregateReviews(reviews, successfulResponses, config.members); - - return { reviews, aggregates }; -} - -/** - * Execute a single peer review. - */ -async function executeReview(params: { - reviewer: LLMMember; - response: CouncilResponse; - question: string; - criteria: string[]; - anonymous: boolean; - config: CouncilConfig; -}): Promise { - const { reviewer, response, question, criteria, anonymous, config } = params; - - const provider = createProviderForMember(reviewer, config.defaultProvider); - const prompt = buildReviewPrompt({ - question, - response: response.response, - authorId: anonymous ? undefined : response.memberId, - criteria, - }); - - const result = await provider.complete(prompt, { - systemPrompt: `You are a critical reviewer evaluating responses to questions. -Your task is to provide fair, objective assessments based on the given criteria. -Respond in JSON format with the structure specified in the instructions.`, - temperature: 0.3, // Lower temperature for more consistent reviews - maxTokens: 2048, - timeoutMs: config.stageTimeoutMs, - }); - - // Parse the review response - return parseReviewResponse(reviewer.id, response.memberId, result.text); -} - -/** - * Build the review prompt for Stage 2. - */ -function buildReviewPrompt(params: { - question: string; - response: string; - authorId?: string; - criteria: string[]; -}): string { - const { question, response, authorId, criteria } = params; - - const parts = [ - `## Original Question`, - question, - ``, - `## Response to Review`, - authorId ? `(from: ${authorId})` : "(anonymous author)", - response, - ``, - `## Evaluation Criteria`, - ...criteria.map((c, i) => `${i + 1}. ${c}`), - ``, - `## Your Task`, - `Evaluate this response and provide your assessment in the following JSON format:`, - `\`\`\`json`, - `{`, - ` "score": ,`, - ` "strengths": ["", "", ...],`, - ` "weaknesses": ["", "", ...],`, - ` "recommendation": "",`, - ` "comments": ""`, - `}`, - `\`\`\``, - ]; - - return parts.join("\n"); -} - -/** - * Parse the review response from the LLM. - */ -function parseReviewResponse( - reviewerId: string, - targetId: string, - responseText: string, -): PeerReview | null { - try { - // Extract JSON from the response (handle markdown code blocks) - const jsonMatch = responseText.match(/```(?:json)?\s*([\s\S]*?)```/); - const jsonStr = jsonMatch ? jsonMatch[1].trim() : responseText.trim(); - - const parsed = JSON.parse(jsonStr) as { - score?: number; - strengths?: string[]; - weaknesses?: string[]; - recommendation?: string; - comments?: string; - }; - - return { - reviewerId, - targetResponseId: targetId, - score: Math.min(100, Math.max(0, parsed.score ?? 50)), - strengths: parsed.strengths ?? [], - weaknesses: parsed.weaknesses ?? [], - recommendation: - (parsed.recommendation as "accept" | "revise" | "reject") ?? "revise", - comments: parsed.comments, - }; - } catch { - // If parsing fails, return a neutral review - return { - reviewerId, - targetResponseId: targetId, - score: 50, - strengths: [], - weaknesses: ["Unable to parse review"], - recommendation: "revise", - comments: "Review parsing failed", - }; - } -} - -/** - * Aggregate reviews for each response. - */ -function aggregateReviews( - reviews: PeerReview[], - responses: CouncilResponse[], - members: CouncilMember[], -): ReviewAggregate[] { - const memberWeights = new Map(members.map((m) => [m.id, m.weight ?? 1.0])); - - return responses.map((response) => { - const responseReviews = reviews.filter( - (r) => r.targetResponseId === response.memberId, - ); - - const scores = responseReviews.map((r) => r.score); - const weightedScores = responseReviews.map( - (r) => r.score * (memberWeights.get(r.reviewerId) ?? 1.0), - ); - - const averageScore = - scores.length > 0 - ? scores.reduce((a, b) => a + b, 0) / scores.length - : 0; - - const totalWeight = responseReviews.reduce( - (sum, r) => sum + (memberWeights.get(r.reviewerId) ?? 1.0), - 0, - ); - const weightedScore = - totalWeight > 0 - ? weightedScores.reduce((a, b) => a + b, 0) / totalWeight - : 0; - - // Determine consensus level based on score variance - const variance = calculateVariance(scores); - let consensus: ReviewAggregate["consensus"]; - if (variance < 100) consensus = "strong"; - else if (variance < 400) consensus = "moderate"; - else if (variance < 900) consensus = "weak"; - else consensus = "split"; - - return { - responseId: response.memberId, - memberId: response.memberId, - averageScore, - weightedScore, - reviewCount: responseReviews.length, - rankings: responseReviews - .map((r) => r.ranking) - .filter((r): r is number => r !== undefined), - consensus, - }; - }); -} - -/** - * Calculate variance of a number array. - */ -function calculateVariance(numbers: number[]): number { - if (numbers.length === 0) return 0; - const mean = numbers.reduce((a, b) => a + b, 0) / numbers.length; - return numbers.reduce((sum, n) => sum + (n - mean) ** 2, 0) / numbers.length; -} - -// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ -// Stage 3: Chairman Synthesis -// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ - -/** - * Execute Stage 3: Chairman synthesizes the final answer. - */ -export async function executeStage3Synthesis(params: { - session: CouncilSession; - tiara?: AgentOrchestrator; -}): Promise { - const { session } = params; - const { config, question, responses, reviewAggregates } = session; - const startTime = Date.now(); - - // Determine chairman - const chairman = resolveChairman(config, reviewAggregates); - - // Build synthesis prompt - const prompt = buildSynthesisPrompt({ - question, - context: session.context, - responses, - aggregates: reviewAggregates, - }); - - // Execute chairman synthesis - if (chairman.type === "llm") { - const provider = createProviderForMember(chairman, config.defaultProvider); - - const result = await provider.complete(prompt, { - systemPrompt: CHAIRMAN_SYSTEM_PROMPT, - temperature: 0.5, - maxTokens: 8192, - timeoutMs: config.stageTimeoutMs, - }); - - // Parse the synthesis response - return parseSynthesisResponse(chairman.id, result, startTime); - } - - // For agent chairman, use a simpler synthesis - return { - chairmanId: chairman.id, - finalResponse: responses[0]?.response ?? "", - methodology: "Agent-based synthesis (simplified)", - sourcesUsed: responses.filter((r) => !r.error).map((r) => r.memberId), - keyInsights: [], - confidence: 0.7, - metadata: { - durationMs: Date.now() - startTime, - }, - }; -} - -/** - * Chairman system prompt. - */ -const CHAIRMAN_SYSTEM_PROMPT = `You are the Chairman of an LLM Council, responsible for synthesizing multiple expert opinions into a final, authoritative answer. - -Your responsibilities: -1. Review all council member responses and their peer review scores -2. Identify the strongest insights from each response -3. Synthesize a comprehensive final answer that incorporates the best elements -4. Note any significant dissenting views or areas of disagreement -5. Provide a confidence level based on the consensus strength - -Your synthesis should be: -- Comprehensive but not redundant -- Well-organized and clearly structured -- Honest about uncertainty where it exists -- Properly attributed when incorporating specific insights`; - -/** - * Resolve which member should be the chairman. - */ -function resolveChairman( - config: CouncilConfig, - aggregates: ReviewAggregate[], -): CouncilMember { - const { chairman, members } = config; - - switch (chairman.mode) { - case "designated": { - const designated = members.find((m) => m.id === chairman.memberId); - if (designated) return designated; - break; - } - - case "highest_scorer": { - if (aggregates.length > 0) { - const topAggregate = aggregates.reduce((best, curr) => - curr.weightedScore > best.weightedScore ? curr : best, - ); - const topMember = members.find((m) => m.id === topAggregate.memberId); - if (topMember) return topMember; - } - break; - } - - case "rotating": - case "random": { - const randomIndex = Math.floor(Math.random() * members.length); - return members[randomIndex]; - } - } - - // Fallback: use llmConfig if provided, otherwise first member - if (chairman.llmConfig) { - return { - type: "llm", - id: "chairman", - provider: chairman.llmConfig.provider, - model: chairman.llmConfig.model, - modelRoute: chairman.llmConfig.modelRoute, - }; - } - - return members[0]; -} - -/** - * Build the synthesis prompt for the chairman. - */ -function buildSynthesisPrompt(params: { - question: string; - context?: string; - responses: CouncilResponse[]; - aggregates: ReviewAggregate[]; -}): string { - const { question, context, responses, aggregates } = params; - - // Sort responses by score (highest first) - const scoredResponses = responses - .filter((r) => !r.error) - .map((r) => ({ - ...r, - aggregate: aggregates.find((a) => a.memberId === r.memberId), - })) - .sort( - (a, b) => - (b.aggregate?.weightedScore ?? 0) - (a.aggregate?.weightedScore ?? 0), - ); - - const parts = [ - `## Your Role`, - `You are the Chairman synthesizing the council's deliberation.`, - ``, - `## Original Question`, - question, - ``, - ]; - - if (context) { - parts.push(`## Context`, context, ``); - } - - parts.push(`## Council Responses (ranked by peer review score)`); - - for (const r of scoredResponses) { - const score = r.aggregate?.weightedScore?.toFixed(1) ?? "N/A"; - const consensus = r.aggregate?.consensus ?? "unknown"; - parts.push( - ``, - `### Member: ${r.memberId}`, - `Score: ${score}/100 | Consensus: ${consensus}`, - ``, - r.response, - ); - } - - parts.push( - ``, - `## Your Task`, - `Synthesize the council's responses into a final, authoritative answer.`, - ``, - `Provide your synthesis in the following JSON format:`, - `\`\`\`json`, - `{`, - ` "finalResponse": "",`, - ` "methodology": "",`, - ` "sourcesUsed": ["", "", ...],`, - ` "keyInsights": ["", "", ...],`, - ` "dissent": "",`, - ` "confidence": <0.0 to 1.0>`, - `}`, - `\`\`\``, - ); - - return parts.join("\n"); -} - -/** - * Parse the synthesis response from the chairman. - */ -function parseSynthesisResponse( - chairmanId: string, - result: { text: string; usage?: { inputTokens: number; outputTokens: number }; durationMs: number }, - startTime: number, -): ChairmanSynthesis { - try { - // Extract JSON from the response - const jsonMatch = result.text.match(/```(?:json)?\s*([\s\S]*?)```/); - const jsonStr = jsonMatch ? jsonMatch[1].trim() : result.text.trim(); - - const parsed = JSON.parse(jsonStr) as { - finalResponse?: string; - methodology?: string; - sourcesUsed?: string[]; - keyInsights?: string[]; - dissent?: string; - confidence?: number; - }; - - return { - chairmanId, - finalResponse: parsed.finalResponse ?? result.text, - methodology: - parsed.methodology ?? "Weighted synthesis based on peer review scores", - sourcesUsed: parsed.sourcesUsed ?? [], - keyInsights: parsed.keyInsights ?? [], - dissent: parsed.dissent, - confidence: Math.min(1, Math.max(0, parsed.confidence ?? 0.7)), - metadata: { - durationMs: result.durationMs, - tokenUsage: result.usage - ? { - input: result.usage.inputTokens, - output: result.usage.outputTokens, - } - : undefined, - }, - }; - } catch { - // If parsing fails, use the raw response - return { - chairmanId, - finalResponse: result.text, - methodology: "Direct synthesis (parsing failed)", - sourcesUsed: [], - keyInsights: [], - confidence: 0.5, - metadata: { - durationMs: result.durationMs, - tokenUsage: result.usage - ? { - input: result.usage.inputTokens, - output: result.usage.outputTokens, - } - : undefined, - }, - }; - } -} diff --git a/src/council/council-types.ts b/src/council/council-types.ts deleted file mode 100644 index cfb65ea8ad..0000000000 --- a/src/council/council-types.ts +++ /dev/null @@ -1,468 +0,0 @@ -/** - * Type definitions for the LLM Council multi-model deliberation system. - * - * Implements Karpathy's llm-council 3-stage consensus algorithm: - * 1. Stage 1: Parallel independent responses from all council members - * 2. Stage 2: Anonymous peer review and ranking - * 3. Stage 3: Chairman synthesizes final answer - */ - -import type { SpecializedAgentType } from "../agent-types.js"; - -// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ -// Council Mode Configuration -// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ - -/** - * Council operation modes. - * - raw_llm: Different LLM models answer the same question - * - agent: Specialized agents provide domain-expert responses - * - hybrid: Mixed LLM and agent participation - */ -export type CouncilMode = "raw_llm" | "agent" | "hybrid"; - -/** - * Member types that can participate in the council. - */ -export type CouncilMemberType = "llm" | "agent"; - -/** - * Supported provider types for council members. - */ -export type CouncilProviderType = - | "openrouter" // Single gateway to 100+ LLMs - | "opencode_zen" // OpenCode curated models (GPT-5.2, Claude 4.5, etc.) - | "google_antigravity" // Free Gemini via Google OAuth (Antigravity) - | "anthropic" // Direct Anthropic API - | "openai" // Direct OpenAI API - | "google" // Direct Google Gemini API - | "zai" // Direct ZAI API - | "custom"; // Custom OpenAI-compatible endpoint - -// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ -// Council Member Types -// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ - -/** - * Provider configuration for an LLM member. - */ -export interface CouncilProviderConfig { - /** Provider type */ - type: CouncilProviderType; - /** API key (if not using env var) */ - apiKey?: string; - /** Environment variable containing API key */ - apiKeyEnv?: string; - /** Base URL for custom providers */ - baseUrl?: string; - /** Additional headers */ - headers?: Record; -} - -/** - * An LLM member of the council. - */ -export interface LLMMember { - type: "llm"; - /** Unique identifier for this member */ - id: string; - /** Provider type (e.g., "anthropic", "openai", "openrouter") */ - provider: CouncilProviderType; - /** Model ID (e.g., "claude-3-opus-20240229", "gpt-4-turbo") */ - model: string; - /** OpenRouter-specific model route (e.g., "anthropic/claude-3-opus") */ - modelRoute?: string; - /** Human-readable display name */ - displayName?: string; - /** Voting weight (default: 1.0) */ - weight?: number; - /** Optional system prompt override */ - systemPrompt?: string; - /** Temperature (0-1) */ - temperature?: number; - /** Max output tokens */ - maxTokens?: number; - /** Role in council deliberations */ - role?: "primary" | "reviewer" | "specialist"; -} - -/** - * An agent member of the council (uses existing specialized agents). - */ -export interface AgentMember { - type: "agent"; - /** Unique identifier for this member */ - id: string; - /** Type of specialized agent */ - agentType: SpecializedAgentType; - /** Human-readable display name */ - displayName?: string; - /** Voting weight (default: 1.0) */ - weight?: number; - /** Additional context to pass to the agent */ - context?: Record; - /** Role in council deliberations */ - role?: "primary" | "reviewer" | "specialist"; -} - -/** - * Union type for all council member types. - */ -export type CouncilMember = LLMMember | AgentMember; - -// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ -// Council Configuration -// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ - -/** - * Chairman configuration - who synthesizes the final answer. - */ -export interface ChairmanConfig { - /** Chairman selection mode */ - mode: "designated" | "rotating" | "random" | "highest_scorer"; - /** Specific member ID if mode is "designated" */ - memberId?: string; - /** LLM config if chairman is a separate model */ - llmConfig?: { - provider: CouncilProviderType; - model: string; - modelRoute?: string; - }; -} - -/** - * Stage 2 (peer review) configuration. - */ -export interface PeerReviewConfig { - /** Whether reviews are anonymous (hide author identities) */ - anonymous: boolean; - /** Ranking method */ - method: "score" | "ranking" | "pairwise"; - /** Criteria for evaluation */ - criteria: string[]; - /** Allow self-review */ - allowSelfReview: boolean; -} - -/** - * Full council configuration. - */ -export interface CouncilConfig { - /** Council operation mode */ - mode: CouncilMode; - /** Council members */ - members: CouncilMember[]; - /** Chairman configuration */ - chairman: ChairmanConfig; - /** Peer review settings */ - peerReview: PeerReviewConfig; - /** Default provider for members without explicit config */ - defaultProvider?: CouncilProviderConfig; - /** Timeout for each stage in ms */ - stageTimeoutMs?: number; - /** Minimum responses required to proceed (quorum) */ - quorum?: number; - /** Maximum parallel executions */ - maxParallel?: number; -} - -// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ -// Stage Results -// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ - -/** - * Stage 1: Individual response from a council member. - */ -export interface CouncilResponse { - /** Member ID who provided this response */ - memberId: string; - /** Type of member (llm or agent) */ - memberType: CouncilMemberType; - /** The actual response text */ - response: string; - /** Optional reasoning explanation */ - reasoning?: string; - /** Confidence level (0-1) */ - confidence?: number; - /** Metadata about the response */ - metadata?: { - provider?: string; - model?: string; - agentType?: string; - durationMs: number; - tokenUsage?: { - input: number; - output: number; - }; - }; - /** Error if the response failed */ - error?: string; -} - -/** - * Stage 2: Peer review of a response. - */ -export interface PeerReview { - /** ID of the member doing the review */ - reviewerId: string; - /** ID of the response being reviewed */ - targetResponseId: string; - /** Score (0-100) */ - score: number; - /** Key strengths identified */ - strengths: string[]; - /** Key weaknesses identified */ - weaknesses: string[]; - /** Position if using ranking method */ - ranking?: number; - /** Recommendation */ - recommendation: "accept" | "revise" | "reject"; - /** Additional comments */ - comments?: string; -} - -/** - * Aggregated review results for a response. - */ -export interface ReviewAggregate { - /** Response ID */ - responseId: string; - /** Member ID who provided the response */ - memberId: string; - /** Simple average of all scores */ - averageScore: number; - /** Weighted average (by reviewer weight) */ - weightedScore: number; - /** Number of reviews received */ - reviewCount: number; - /** All rankings received */ - rankings: number[]; - /** Consensus level */ - consensus: "strong" | "moderate" | "weak" | "split"; -} - -/** - * Stage 3: Chairman synthesis result. - */ -export interface ChairmanSynthesis { - /** ID of the chairman who synthesized */ - chairmanId: string; - /** The final synthesized response */ - finalResponse: string; - /** Methodology used for synthesis */ - methodology: string; - /** Member IDs whose content was incorporated */ - sourcesUsed: string[]; - /** Key insights extracted */ - keyInsights: string[]; - /** Notable minority/dissenting opinions */ - dissent?: string; - /** Confidence in the final answer (0-1) */ - confidence: number; - /** Metadata about the synthesis */ - metadata: { - durationMs: number; - tokenUsage?: { - input: number; - output: number; - }; - }; -} - -// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ -// Council Session -// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ - -/** - * Current stage of a council session. - */ -export type CouncilStage = - | "pending" - | "stage1" - | "stage2" - | "stage3" - | "complete" - | "failed"; - -/** - * Complete council deliberation session. - */ -export interface CouncilSession { - /** Unique session ID */ - id: string; - /** Council configuration used */ - config: CouncilConfig; - /** The question being deliberated */ - question: string; - /** Optional context provided */ - context?: string; - /** Current stage */ - stage: CouncilStage; - - /** Stage 1 results: individual responses */ - responses: CouncilResponse[]; - - /** Stage 2 results: peer reviews */ - reviews: PeerReview[]; - /** Stage 2 results: aggregated scores */ - reviewAggregates: ReviewAggregate[]; - - /** Stage 3 result: chairman synthesis */ - synthesis?: ChairmanSynthesis; - - /** Timestamp when session was created */ - createdAt: number; - /** Timestamp when Stage 1 completed */ - stage1CompletedAt?: number; - /** Timestamp when Stage 2 completed */ - stage2CompletedAt?: number; - /** Timestamp when session completed */ - completedAt?: number; - /** Error message if session failed */ - error?: string; -} - -/** - * Council execution result (returned to caller). - */ -export interface CouncilResult { - /** Session ID */ - sessionId: string; - /** Whether deliberation succeeded */ - success: boolean; - /** The final answer */ - finalAnswer: string; - /** Full synthesis details */ - synthesis: ChairmanSynthesis; - /** Summary statistics */ - summary: { - totalMembers: number; - respondedMembers: number; - topScorer: string; - consensusLevel: string; - totalDurationMs: number; - }; - /** Debug information (optional) */ - debug?: { - responses: CouncilResponse[]; - reviews: PeerReview[]; - aggregates: ReviewAggregate[]; - }; -} - -// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ -// Default Configuration Helpers -// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ - -/** - * Default peer review criteria. - */ -export const DEFAULT_REVIEW_CRITERIA: string[] = [ - "Accuracy and correctness", - "Completeness of answer", - "Clarity and organization", - "Quality of reasoning", - "Practical applicability", -]; - -/** - * Default peer review configuration. - */ -export const DEFAULT_PEER_REVIEW_CONFIG: PeerReviewConfig = { - anonymous: true, - method: "score", - criteria: DEFAULT_REVIEW_CRITERIA, - allowSelfReview: false, -}; - -/** - * Default chairman configuration. - */ -export const DEFAULT_CHAIRMAN_CONFIG: ChairmanConfig = { - mode: "highest_scorer", -}; - -/** - * Create a default council configuration with minimal required fields. - */ -export function createDefaultCouncilConfig( - partial: Partial, -): CouncilConfig { - return { - mode: partial.mode ?? "raw_llm", - members: partial.members ?? [], - chairman: partial.chairman ?? DEFAULT_CHAIRMAN_CONFIG, - peerReview: partial.peerReview ?? DEFAULT_PEER_REVIEW_CONFIG, - defaultProvider: partial.defaultProvider, - stageTimeoutMs: partial.stageTimeoutMs ?? 60000, - quorum: partial.quorum, - maxParallel: partial.maxParallel ?? 5, - }; -} - -/** - * Generate a unique council session ID. - */ -export function generateCouncilId(): string { - const timestamp = Date.now().toString(36); - const random = Math.random().toString(36).substring(2, 8); - return `council-${timestamp}-${random}`; -} - -/** - * Validate a council configuration. - */ -export function validateCouncilConfig(config: CouncilConfig): { - valid: boolean; - errors: string[]; -} { - const errors: string[] = []; - - if (config.members.length === 0) { - errors.push("Council must have at least one member"); - } - - if (config.members.length < 2 && config.mode !== "agent") { - errors.push("Council needs at least 2 members for meaningful deliberation"); - } - - // Check for duplicate member IDs - const memberIds = config.members.map((m) => m.id); - const duplicateIds = memberIds.filter( - (id, index) => memberIds.indexOf(id) !== index, - ); - if (duplicateIds.length > 0) { - errors.push(`Duplicate member IDs: ${duplicateIds.join(", ")}`); - } - - // Validate chairman if designated - if ( - config.chairman.mode === "designated" && - config.chairman.memberId && - !memberIds.includes(config.chairman.memberId) - ) { - errors.push( - `Designated chairman "${config.chairman.memberId}" is not a council member`, - ); - } - - // Validate member types match mode - if (config.mode === "raw_llm") { - const agentMembers = config.members.filter((m) => m.type === "agent"); - if (agentMembers.length > 0) { - errors.push("raw_llm mode should not have agent members"); - } - } - - if (config.mode === "agent") { - const llmMembers = config.members.filter((m) => m.type === "llm"); - if (llmMembers.length > 0) { - errors.push("agent mode should not have llm members"); - } - } - - return { - valid: errors.length === 0, - errors, - }; -} diff --git a/src/council/index.ts b/src/council/index.ts deleted file mode 100644 index 8bb109d4e6..0000000000 --- a/src/council/index.ts +++ /dev/null @@ -1,241 +0,0 @@ -/** - * Council Module - * - * Multi-LLM/Agent deliberation system for agent-core. - * Implements Karpathy's llm-council 3-stage consensus algorithm. - */ - -// Auth utilities -export * from "./auth/index.js"; - -// Export from local council modules -export { - CouncilCoordinator, - getDefaultCouncilCoordinator, - resetDefaultCouncilCoordinator, -} from "./council-coordinator.js"; - -export type { - CouncilConfig, - CouncilMember, - CouncilMode, - CouncilResult, - CouncilSession, - LLMMember, - AgentMember, - CouncilStage, - CouncilResponse, - PeerReview, - ReviewAggregate, - ChairmanSynthesis, - ChairmanConfig, - PeerReviewConfig, - CouncilProviderType, - CouncilProviderConfig, - CouncilMemberType, -} from "./council-types.js"; - -export { - createDefaultCouncilConfig, - generateCouncilId, - validateCouncilConfig, - DEFAULT_REVIEW_CRITERIA, - DEFAULT_PEER_REVIEW_CONFIG, - DEFAULT_CHAIRMAN_CONFIG, -} from "./council-types.js"; - -// ============================================================================= -// Convenience Functions -// ============================================================================= - -/** - * Execute a full council deliberation. - * - * @param question - The question for the council to deliberate - * @param config - Council configuration (members, chairman, etc.) - * @param options - Additional options - * @returns The council result with final answer - */ -export async function council( - question: string, - config: Partial, - options?: { - context?: string; - includeDebug?: boolean; - } -): Promise { - const coordinator = await getDefaultCouncilCoordinator(); - return coordinator.deliberate(question, config, options); -} - -/** - * Execute a quick consensus (Stage 1 only, skip peer review). - * - * @param question - The question for quick consensus - * @param models - Model identifiers to use - * @returns Quick consensus result - */ -export async function quickCouncil( - question: string, - models?: string[] -): Promise<{ - question: string; - responses: Array<{ model: string; response: string; error?: string }>; - consensus?: string; - agreement: "strong" | "moderate" | "weak" | "none"; -}> { - const coordinator = await getDefaultCouncilCoordinator(); - return coordinator.quickConsensus(question, models); -} - -// ============================================================================= -// MCP Tool Definition -// ============================================================================= - -/** - * Tool definition for exposing council as an MCP tool. - */ -export const CouncilCoordinatorDefinition = { - name: "council_deliberate", - description: - "Execute a multi-LLM council deliberation using Karpathy's 3-stage algorithm. " + - "Multiple LLMs or agents provide independent answers, peer review each other, " + - "and a chairman synthesizes the final answer.", - inputSchema: { - type: "object" as const, - properties: { - question: { - type: "string", - description: "The question for the council to deliberate", - }, - mode: { - type: "string", - enum: ["raw_llm", "agent", "hybrid"], - description: "Council operation mode", - default: "raw_llm", - }, - models: { - type: "array", - items: { type: "string" }, - description: - 'LLM models to use (OpenRouter format, e.g., "anthropic/claude-3-opus")', - }, - agents: { - type: "array", - items: { type: "string" }, - description: "Agent types to include (e.g., market_analyst, researcher)", - }, - context: { - type: "string", - description: "Additional context for the deliberation", - }, - quick: { - type: "boolean", - description: "Use quick consensus (skip peer review)", - default: false, - }, - }, - required: ["question"], - }, -}; - -/** - * Create an MCP tool handler for council deliberation. - */ -export function createCouncilCoordinatorTool() { - return { - definition: CouncilCoordinatorDefinition, - handler: async (params: { - question: string; - mode?: "raw_llm" | "agent" | "hybrid"; - models?: string[]; - agents?: string[]; - context?: string; - quick?: boolean; - }) => { - const coordinator = await getDefaultCouncilCoordinator(); - - if (params.quick) { - // Quick consensus mode - const result = await coordinator.quickConsensus( - params.question, - params.models - ); - return { - success: true, - question: result.question, - consensus: result.consensus, - agreement: result.agreement, - responses: result.responses, - }; - } - - // Full deliberation mode - const members: import("./council-types.js").CouncilMember[] = []; - - // Add LLM members - if (params.models && params.models.length > 0) { - for (let i = 0; i < params.models.length; i++) { - members.push({ - type: "llm" as const, - id: `llm-${i}`, - provider: "openrouter" as const, - model: params.models[i], - modelRoute: params.models[i], - }); - } - } - - // Add agent members - if (params.agents && params.agents.length > 0) { - for (let i = 0; i < params.agents.length; i++) { - members.push({ - type: "agent" as const, - id: `agent-${i}`, - agentType: params.agents[i] as import("../agent-types.js").SpecializedAgentType, - }); - } - } - - // Default to some models if none specified - if (members.length === 0) { - members.push( - { - type: "llm" as const, - id: "claude", - provider: "openrouter" as const, - model: "anthropic/claude-3-opus", - modelRoute: "anthropic/claude-3-opus", - }, - { - type: "llm" as const, - id: "gpt4", - provider: "openrouter" as const, - model: "openai/gpt-4-turbo", - modelRoute: "openai/gpt-4-turbo", - } - ); - } - - const result = await coordinator.deliberate( - params.question, - { - mode: params.mode ?? (params.agents ? "hybrid" : "raw_llm"), - members, - chairman: { mode: "highest_scorer" }, - }, - { - context: params.context, - includeDebug: false, - } - ); - - return { - success: result.success, - sessionId: result.sessionId, - finalAnswer: result.finalAnswer, - summary: result.summary, - }; - }, - }; -} diff --git a/src/daemon/index.ts b/src/daemon/index.ts index 291edcf659..8a0a06f07d 100644 --- a/src/daemon/index.ts +++ b/src/daemon/index.ts @@ -11,8 +11,6 @@ import { createServer, type Server } from "net"; import { getOrchestrator } from "../personas"; -import { createAgentOrchestrator, type AgentOrchestrator } from "../tiara.js"; -import { CouncilCoordinator } from "../council/index.js"; import { AgentLSPServer } from "../lsp"; import { DaemonIpcServer } from "./ipc-server"; import { resolveIpcSocketPath } from "./ipc"; @@ -121,8 +119,6 @@ export class AgentCoreDaemon { private lspServer?: AgentLSPServer; private ipcServer?: DaemonIpcServer; private canvasManager?: CanvasManager; - private councilCoordinator?: CouncilCoordinator; - private agentOrchestrator?: AgentOrchestrator; private isRunning = false; private eventUnsubscribers: (() => void)[] = []; @@ -151,16 +147,6 @@ export class AgentCoreDaemon { wezterm: { enabled: weztermEnabled }, }); - // Create AgentOrchestrator adapter for council integration - log("info", "Creating AgentOrchestrator adapter..."); - this.agentOrchestrator = createAgentOrchestrator(tiara); - - // Create CouncilCoordinator with tiara integration - log("info", "Creating CouncilCoordinator..."); - this.councilCoordinator = await CouncilCoordinator.create({ - tiara: this.agentOrchestrator, - }); - // Subscribe to tiara events for logging (store unsubscribers for cleanup) this.eventUnsubscribers.push( tiara.subscribe("worker:spawned", (data) => { @@ -380,145 +366,6 @@ export class AgentCoreDaemon { return this.canvasManager.listActive(); } - // Council IPC methods - case "council:deliberate": { - if (!this.councilCoordinator) { - throw new Error("Council coordinator not initialized"); - } - const params = request.params ?? {}; - const question = params.question ? String(params.question) : ""; - if (!question) { - throw new Error("council:deliberate requires question"); - } - const mode = params.mode as "raw_llm" | "agent" | "hybrid" | undefined; - const models = Array.isArray(params.models) - ? params.models.map(String) - : undefined; - const agents = Array.isArray(params.agents) - ? params.agents.map(String) - : undefined; - const context = params.context ? String(params.context) : undefined; - const includeDebug = Boolean(params.includeDebug); - - // Build members from models and agents - const members: Array<{ - type: "llm" | "agent"; - id: string; - provider?: string; - model?: string; - modelRoute?: string; - agentType?: string; - }> = []; - - if (models && models.length > 0) { - for (let i = 0; i < models.length; i++) { - members.push({ - type: "llm", - id: `llm-${i}`, - provider: "openrouter", - model: models[i], - modelRoute: models[i], - }); - } - } - - if (agents && agents.length > 0) { - for (let i = 0; i < agents.length; i++) { - members.push({ - type: "agent", - id: `agent-${i}`, - agentType: agents[i], - }); - } - } - - // Default members if none specified - if (members.length === 0) { - members.push( - { - type: "llm", - id: "claude", - provider: "openrouter", - model: "anthropic/claude-3-opus", - modelRoute: "anthropic/claude-3-opus", - }, - { - type: "llm", - id: "gpt4", - provider: "openrouter", - model: "openai/gpt-4-turbo", - modelRoute: "openai/gpt-4-turbo", - } - ); - } - - const result = await this.councilCoordinator.deliberate( - question, - { - mode: mode ?? (agents ? "hybrid" : "raw_llm"), - members: members as Parameters[1]["members"], - chairman: { mode: "highest_scorer" }, - }, - { context, includeDebug } - ); - - return { - success: result.success, - sessionId: result.sessionId, - finalAnswer: result.finalAnswer, - summary: result.summary, - debug: result.debug, - }; - } - - case "council:quick_consensus": { - if (!this.councilCoordinator) { - throw new Error("Council coordinator not initialized"); - } - const params = request.params ?? {}; - const question = params.question ? String(params.question) : ""; - if (!question) { - throw new Error("council:quick_consensus requires question"); - } - const models = Array.isArray(params.models) - ? params.models.map(String) - : undefined; - - const result = await this.councilCoordinator.quickConsensus(question, models); - return { - question: result.question, - consensus: result.consensus, - agreement: result.agreement, - responses: result.responses, - }; - } - - case "council:list_sessions": { - if (!this.councilCoordinator) { - throw new Error("Council coordinator not initialized"); - } - const params = request.params ?? {}; - const limit = params.limit ? Number(params.limit) : undefined; - const status = params.status as Parameters[0]["status"]; - return this.councilCoordinator.listSessions({ limit, status }); - } - - case "council:get_session": { - if (!this.councilCoordinator) { - throw new Error("Council coordinator not initialized"); - } - const params = request.params ?? {}; - const sessionId = params.sessionId ? String(params.sessionId) : ""; - if (!sessionId) { - throw new Error("council:get_session requires sessionId"); - } - const session = this.councilCoordinator.getSession(sessionId); - if (!session) { - throw new Error(`Session not found: ${sessionId}`); - } - return session; - } - default: throw new Error(`Unknown IPC method: ${request.method}`); } diff --git a/src/lsp/nvim-config.lua b/src/lsp/nvim-config.lua index 24e4d9cd30..65a0a86443 100644 --- a/src/lsp/nvim-config.lua +++ b/src/lsp/nvim-config.lua @@ -16,9 +16,9 @@ local M = {} -- LSP server configuration M.server_config = { name = "agent_core", - cmd = { "bun", "run", vim.fn.expand("~/Repositories/agent-core/src/lsp/server.ts") }, + cmd = { "bun", "run", vim.fn.expand("~/.local/src/agent-core/src/lsp/server.ts") }, -- Alternative: use node - -- cmd = { "node", vim.fn.expand("~/Repositories/agent-core/dist/lsp/server.js") }, + -- cmd = { "node", vim.fn.expand("~/.local/src/agent-core/dist/lsp/server.js") }, filetypes = { "*" }, -- Attach to all file types root_dir = function(fname) return vim.fn.getcwd() diff --git a/src/lsp/server.ts b/src/lsp/server.ts index 6a3e8e7549..fa42ac6f15 100644 --- a/src/lsp/server.ts +++ b/src/lsp/server.ts @@ -13,6 +13,7 @@ import { createInterface } from "readline"; import type { LSPServerConfig, DroneStatus, TaskStatus } from "./types"; import { AgentCodeActionKind } from "./types"; import { requestDaemon } from "../daemon/ipc-client"; +import { Grammar } from "../util/grammar"; // LSP message types (minimal definitions) interface LSPMessage { @@ -88,11 +89,24 @@ export class AgentLSPServer { diagnosticRefreshInterval: config?.diagnosticRefreshInterval ?? 5000, enableCodeActions: config?.enableCodeActions ?? true, enableHover: config?.enableHover ?? true, + enableGrammar: config?.enableGrammar ?? true, + grammarConfig: config?.grammarConfig, port: config?.port, personasUrl: config?.personasUrl, }; } + /** + * Get position from offset + */ + private getPosition(text: string, offset: number): Position { + const prefix = text.slice(0, offset); + const lines = prefix.split("\n"); + const line = lines.length - 1; + const character = lines[lines.length - 1].length; + return { line, character }; + } + /** * Send a JSON-RPC message */ @@ -249,7 +263,7 @@ export class AgentLSPServer { version: params.textDocument.version, content: params.textDocument.text, }); - this.publishDiagnostics(params.textDocument.uri); + this.publishDiagnostics(params.textDocument.uri).catch(err => console.error("Failed to publish diagnostics", err)); } /** @@ -261,7 +275,7 @@ export class AgentLSPServer { doc.version = params.textDocument.version; doc.content = params.contentChanges[params.contentChanges.length - 1].text; } - this.publishDiagnostics(params.textDocument.uri); + this.publishDiagnostics(params.textDocument.uri).catch(err => console.error("Failed to publish diagnostics", err)); } /** @@ -283,7 +297,7 @@ export class AgentLSPServer { // Refresh diagnostics for all open documents for (const uri of this.openDocuments.keys()) { - this.publishDiagnostics(uri); + this.publishDiagnostics(uri).catch(err => console.error("Failed to publish diagnostics", err)); } } @@ -320,7 +334,7 @@ export class AgentLSPServer { private startDiagnosticRefresh(): void { this.refreshInterval = setInterval(() => { for (const uri of this.openDocuments.keys()) { - this.publishDiagnostics(uri); + this.publishDiagnostics(uri).catch(err => console.error("Failed to publish diagnostics", err)); } }, this.config.diagnosticRefreshInterval); } @@ -328,7 +342,7 @@ export class AgentLSPServer { /** * Publish diagnostics for a document */ - private publishDiagnostics(uri: string): void { + private async publishDiagnostics(uri: string): Promise { const diagnostics: Diagnostic[] = []; // Add drone status diagnostics @@ -368,6 +382,25 @@ export class AgentLSPServer { }); } + // Grammar check + if (this.config.enableGrammar) { + const doc = this.openDocuments.get(uri); + if (doc) { + const matches = await Grammar.check(doc.content, this.config.grammarConfig); + for (const match of matches) { + const start = this.getPosition(doc.content, match.offset); + const end = this.getPosition(doc.content, match.offset + match.length); + diagnostics.push({ + severity: DiagnosticSeverity.Information, + range: { start, end }, + message: match.message, + source: "LanguageTool", + code: match.rule.id, + }); + } + } + } + this.notify("textDocument/publishDiagnostics", { uri, diagnostics }); } @@ -549,7 +582,7 @@ export class AgentLSPServer { if (state.plan !== undefined) this.plan = state.plan; for (const uri of this.openDocuments.keys()) { - this.publishDiagnostics(uri); + this.publishDiagnostics(uri).catch(err => console.error("Failed to publish diagnostics", err)); } } diff --git a/src/lsp/types.ts b/src/lsp/types.ts index 2149cabcae..dbe8dc42c4 100644 --- a/src/lsp/types.ts +++ b/src/lsp/types.ts @@ -83,6 +83,13 @@ export const LSPServerConfig = z.object({ enableCodeActions: z.boolean().default(true), /** Enable hover provider */ enableHover: z.boolean().default(true), + /** Enable grammar checking diagnostics */ + enableGrammar: z.boolean().default(true), + /** Grammar checking configuration */ + grammarConfig: z.object({ + username: z.string().optional(), + apiKey: z.string().optional(), + }).optional(), /** personas tiara connection */ personasUrl: z.string().optional(), }); diff --git a/src/mcp/servers/portfolio.ts b/src/mcp/servers/portfolio.ts index 70a3a1444f..d0987559d3 100644 --- a/src/mcp/servers/portfolio.ts +++ b/src/mcp/servers/portfolio.ts @@ -16,9 +16,9 @@ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js" import { z } from "zod"; import { spawnSync } from "node:child_process"; import { existsSync } from "node:fs"; -import { homedir } from "node:os"; -import { join, delimiter } from "node:path"; +import { delimiter } from "node:path"; import { getSafeEnv } from "../../util/safe-env.js"; +import { Stanley } from "../../paths.js"; type StanleyResult = { ok: boolean; @@ -27,29 +27,12 @@ type StanleyResult = { error?: string; }; -function resolvePersonaRepo(name: string): string { - const root = process.env.AGENT_CORE_ROOT; - if (root) return join(root, "vendor", "personas", name); - return join(homedir(), ".local", "src", "agent-core", "vendor", "personas", name); -} - function resolveStanleyCli(): { python: string; cliPath: string; pythonPath?: string } { - const repo = process.env.STANLEY_REPO || resolvePersonaRepo("stanley"); - const pythonPath = process.env.STANLEY_PYTHONPATH || (existsSync(join(repo, ".python")) ? join(repo, ".python") : undefined); - const runtimePython = join(repo, ".python-runtime", "bin", "python3"); - const runtimePythonAlt = join(repo, ".python-runtime", "bin", "python3.13"); - const bundledPython = existsSync(runtimePython) - ? runtimePython - : existsSync(runtimePythonAlt) - ? runtimePythonAlt - : undefined; - const cliPath = process.env.STANLEY_CLI || join(repo, "scripts", "stanley_cli.py"); - const venvPython = join(repo, ".venv", "bin", "python"); - const python = - process.env.STANLEY_PYTHON || - bundledPython || - (pythonPath ? "python3" : existsSync(venvPython) ? venvPython : "python3"); - return { python, cliPath, pythonPath }; + return { + python: Stanley.python(), + cliPath: Stanley.cli(), + pythonPath: Stanley.pythonPath(), + }; } function runStanleyCli(args: string[]): StanleyResult { diff --git a/src/memory/embedding.ts b/src/memory/embedding.ts index f5172bf168..7b5930a755 100644 --- a/src/memory/embedding.ts +++ b/src/memory/embedding.ts @@ -1,6 +1,6 @@ /** * Embedding client for generating vector representations of text. - * Supports OpenAI, Ollama, vLLM, and local (OpenAI-compatible) providers. + * Supports OpenAI, Google, Voyage, Ollama, vLLM, and local (OpenAI-compatible) providers. * * Includes LRU caching to avoid redundant API calls. * @@ -100,15 +100,27 @@ class EmbeddingCache { class OpenAIEmbeddingProvider implements EmbeddingProvider { readonly id = "openai"; readonly model: string; - readonly dimension: number; + dimension: number; private readonly apiKey: string; private readonly baseUrl: string; + private readonly dimensionsParam?: number; constructor(config: EmbeddingConfig) { - this.apiKey = config.apiKey ?? process.env.OPENAI_API_KEY ?? ""; + const resolvedBaseUrl = (config.baseUrl ?? "https://api.openai.com/v1").replace( + /\/$/, + "" + ); + const isNebius = resolvedBaseUrl.includes("nebius.com"); + this.apiKey = + config.apiKey ?? + process.env.OPENAI_API_KEY ?? + (isNebius ? process.env.NEBIUS_API_KEY : undefined) ?? + ""; this.model = config.model ?? "text-embedding-3-small"; - this.dimension = config.dimensions ?? 1536; - this.baseUrl = config.baseUrl ?? "https://api.openai.com/v1"; + this.dimensionsParam = + typeof config.dimensions === "number" ? config.dimensions : undefined; + this.dimension = this.dimensionsParam ?? 1536; + this.baseUrl = resolvedBaseUrl; if (!this.apiKey) { throw new Error( @@ -125,17 +137,26 @@ class OpenAIEmbeddingProvider implements EmbeddingProvider { async embedBatch(texts: string[]): Promise { if (texts.length === 0) return []; + const body: { + model: string; + input: string[]; + dimensions?: number; + } = { + model: this.model, + input: texts, + }; + + if (this.dimensionsParam) { + body.dimensions = this.dimensionsParam; + } + const response = await fetch(`${this.baseUrl}/embeddings`, { method: "POST", headers: { Authorization: `Bearer ${this.apiKey}`, "Content-Type": "application/json", }, - body: JSON.stringify({ - model: this.model, - input: texts, - dimensions: this.dimension, - }), + body: JSON.stringify(body), }); if (!response.ok) { @@ -151,17 +172,118 @@ class OpenAIEmbeddingProvider implements EmbeddingProvider { // Sort by index to maintain order const sorted = data.data.sort((a, b) => a.index - b.index); + if (!this.dimensionsParam && sorted.length > 0) { + const length = sorted[0]?.embedding.length ?? 0; + if (length > 0) this.dimension = length; + } return sorted.map((item) => item.embedding); } } +/** + * Google embedding client using Generative Language API + */ +class GoogleEmbeddingProvider implements EmbeddingProvider { + readonly id = "google"; + readonly model: string; + dimension: number; + private readonly apiKey: string; + private readonly baseUrl: string; + private readonly outputDimensionality?: number; + + constructor(config: EmbeddingConfig) { + this.apiKey = + config.apiKey ?? + process.env.GOOGLE_API_KEY ?? + process.env.GEMINI_API_KEY ?? + ""; + this.model = config.model ?? "text-embedding-004"; + this.outputDimensionality = + typeof config.dimensions === "number" ? config.dimensions : undefined; + this.dimension = this.outputDimensionality ?? 768; + this.baseUrl = (config.baseUrl ?? "https://generativelanguage.googleapis.com/v1beta").replace( + /\/$/, + "" + ); + + if (!this.apiKey) { + throw new Error( + "Google API key required: set embedding.apiKey or GOOGLE_API_KEY/GEMINI_API_KEY env" + ); + } + } + + private resolveModel(): string { + return this.model.startsWith("models/") ? this.model : `models/${this.model}`; + } + + async embed(text: string): Promise { + const result = await this.embedBatch([text]); + return result[0] ?? []; + } + + async embedBatch(texts: string[]): Promise { + if (texts.length === 0) return []; + + const model = this.resolveModel(); + const requests = texts.map((text) => { + const request: { + model: string; + content: { parts: Array<{ text: string }> }; + outputDimensionality?: number; + } = { + model, + content: { parts: [{ text }] }, + }; + if (this.outputDimensionality) { + request.outputDimensionality = this.outputDimensionality; + } + return request; + }); + + const response = await fetch( + `${this.baseUrl}/${model}:batchEmbedContents?key=${encodeURIComponent( + this.apiKey + )}`, + { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ requests }), + } + ); + + if (!response.ok) { + const errorText = await response.text(); + throw new Error( + `Google embedding failed (${response.status}): ${errorText}` + ); + } + + const data = (await response.json()) as { + embeddings?: Array<{ values?: number[] }>; + }; + + const vectors = (data.embeddings ?? []).map((item) => item.values ?? []); + if (vectors.length === 0) { + throw new Error("Google embedding returned no vectors"); + } + if (!this.outputDimensionality && vectors.length > 0) { + const length = vectors[0]?.length ?? 0; + if (length > 0) this.dimension = length; + } + return vectors; + } +} + /** * vLLM embedding client using OpenAI-compatible API */ class VLLMEmbeddingProvider implements EmbeddingProvider { readonly id = "vllm"; readonly model: string; - readonly dimension: number; + dimension: number; private readonly baseUrl: string; constructor(config: EmbeddingConfig) { @@ -211,7 +333,7 @@ class VLLMEmbeddingProvider implements EmbeddingProvider { class OllamaEmbeddingProvider implements EmbeddingProvider { readonly id = "ollama"; readonly model: string; - readonly dimension: number; + dimension: number; private readonly baseUrl: string; constructor(config: EmbeddingConfig) { @@ -267,7 +389,7 @@ class OllamaEmbeddingProvider implements EmbeddingProvider { class LocalEmbeddingProvider implements EmbeddingProvider { readonly id = "local"; readonly model: string; - readonly dimension: number; + dimension: number; private readonly apiKey: string; private readonly baseUrl: string; @@ -326,7 +448,7 @@ class LocalEmbeddingProvider implements EmbeddingProvider { class VoyageEmbeddingProvider implements EmbeddingProvider { readonly id = "voyage"; readonly model: string; - readonly dimension: number; + dimension: number; private readonly apiKey: string; private readonly baseUrl: string; @@ -470,6 +592,9 @@ export function createEmbeddingProvider( case "openai": provider = new OpenAIEmbeddingProvider(config); break; + case "google": + provider = new GoogleEmbeddingProvider(config); + break; case "voyage": provider = new VoyageEmbeddingProvider(config); break; @@ -500,6 +625,7 @@ export function createEmbeddingProvider( export { EmbeddingCache, OpenAIEmbeddingProvider, + GoogleEmbeddingProvider, VoyageEmbeddingProvider, VLLMEmbeddingProvider, OllamaEmbeddingProvider, diff --git a/src/memory/qdrant.ts b/src/memory/qdrant.ts index cec590be21..99d23d405d 100644 --- a/src/memory/qdrant.ts +++ b/src/memory/qdrant.ts @@ -120,6 +120,34 @@ export class QdrantVectorStorage implements VectorStorage { } } + async getCollectionDimension(name: string): Promise { + try { + const info = await this.request<{ + config?: { params?: { vectors?: unknown } }; + }>("GET", `/collections/${name}`); + const vectors = info?.config?.params?.vectors; + if (!vectors || typeof vectors !== "object") return null; + + if ("size" in vectors) { + const size = (vectors as { size?: unknown }).size; + return typeof size === "number" ? size : null; + } + + for (const entry of Object.values(vectors as Record)) { + if (entry && typeof entry === "object" && "size" in entry) { + const size = (entry as { size?: unknown }).size; + if (typeof size === "number") return size; + } + } + } catch (error) { + log.debug("Failed to read Qdrant collection dimension", { + collection: name, + reason: error instanceof Error ? error.message : String(error), + }); + } + return null; + } + async init(): Promise { // No-op - collections are created on demand } @@ -127,6 +155,12 @@ export class QdrantVectorStorage implements VectorStorage { async createCollection(name: string, dimension: number): Promise { const exists = await this.collectionExists(name); if (exists) { + const existingDimension = await this.getCollectionDimension(name); + if (existingDimension && existingDimension !== dimension) { + throw new Error( + `Qdrant collection "${name}" has dimension ${existingDimension}, expected ${dimension}.`, + ); + } // Still set currentCollection even if collection already exists this.currentCollection = name; return; diff --git a/src/memory/types.ts b/src/memory/types.ts index 0d97d866cc..b7c1bad1c2 100644 --- a/src/memory/types.ts +++ b/src/memory/types.ts @@ -298,6 +298,7 @@ export interface EmbeddingProvider { /** Supported embedding providers */ export type EmbeddingProviderType = | "openai" + | "google" | "anthropic" | "cohere" | "voyage" diff --git a/src/memory/unified.ts b/src/memory/unified.ts index 5d16ac9b2f..993ff4c35e 100644 --- a/src/memory/unified.ts +++ b/src/memory/unified.ts @@ -26,6 +26,7 @@ import { QDRANT_COLLECTION_MEMORY, CONTINUITY_MAX_KEY_FACTS, } from "../config/constants"; +import { getMemoryEmbeddingConfig, getMemoryQdrantConfig } from "../config/runtime"; import { Log } from "../../packages/agent-core/src/util/log"; const log = Log.create({ service: "memory" }); @@ -339,16 +340,24 @@ export class Memory { private readonly collection: string; private readonly instanceId: string; private readonly maxKeyFacts: number; + private readonly configuredEmbeddingDimensions?: number; + private embeddingDimension?: number; private initialized = false; // Current conversation state (for continuity) private currentConversation?: ConversationState; constructor(config: Partial = {}) { + const fileQdrant = getMemoryQdrantConfig(); + const fileEmbedding = getMemoryEmbeddingConfig(); const qdrantConfig = { - url: config.qdrant?.url ?? process.env.QDRANT_URL ?? QDRANT_URL, - apiKey: config.qdrant?.apiKey, - collection: config.qdrant?.collection ?? QDRANT_COLLECTION_MEMORY, + url: config.qdrant?.url ?? fileQdrant.url ?? process.env.QDRANT_URL ?? QDRANT_URL, + apiKey: config.qdrant?.apiKey ?? fileQdrant.apiKey, + collection: + config.qdrant?.collection ?? + fileQdrant.collection ?? + process.env.QDRANT_MEMORY_COLLECTION ?? + QDRANT_COLLECTION_MEMORY, }; this.collection = qdrantConfig.collection; @@ -357,19 +366,28 @@ export class Memory { this.instanceId = generateInstanceId(); this.maxKeyFacts = config.maxKeyFacts ?? CONTINUITY_MAX_KEY_FACTS; + const configuredDimensions = config.embedding?.dimensions ?? fileEmbedding.dimensions; + const provider = (config.embedding?.provider ?? fileEmbedding.provider ?? "openai") as EmbeddingConfig["provider"]; + const apiKey = + config.embedding?.apiKey ?? + fileEmbedding.apiKey ?? + (provider === "openai" ? process.env.OPENAI_API_KEY : undefined); + const embeddingConfig: EmbeddingConfig = { + provider, + model: config.embedding?.model ?? fileEmbedding.model, + dimensions: configuredDimensions, + apiKey, + baseUrl: config.embedding?.baseUrl ?? fileEmbedding.baseUrl, + }; + this.configuredEmbeddingDimensions = configuredDimensions; + // Use mock embeddings if no API key available - const usesMock = !process.env.OPENAI_API_KEY && !config.embedding?.apiKey; + const usesMock = provider === "openai" && !apiKey; if (usesMock) { this.embedding = new MockEmbeddingProvider(); log.debug("Using mock embeddings (no API key)"); } else { - this.embedding = createEmbeddingProvider({ - provider: config.embedding?.provider ?? "openai", - model: config.embedding?.model, - dimensions: config.embedding?.dimensions, - apiKey: config.embedding?.apiKey, - baseUrl: config.embedding?.baseUrl, - }); + this.embedding = createEmbeddingProvider(embeddingConfig); } } @@ -380,6 +398,47 @@ export class Memory { private initFailed = false; private initError?: Error; + private async resolveEmbeddingDimension(): Promise { + if (this.embeddingDimension && this.embeddingDimension > 0) { + return this.embeddingDimension; + } + + const existingDimension = await this.storage.getCollectionDimension(this.collection); + if (this.configuredEmbeddingDimensions && this.configuredEmbeddingDimensions > 0) { + if (existingDimension && existingDimension !== this.configuredEmbeddingDimensions) { + throw new Error( + `Qdrant collection "${this.collection}" uses dimension ${existingDimension}, but embedding dimensions are configured as ${this.configuredEmbeddingDimensions}. Update memory.qdrant.collection or memory.embedding.dimensions.`, + ); + } + this.embeddingDimension = this.configuredEmbeddingDimensions; + this.embedding.dimension = this.embeddingDimension; + return this.embeddingDimension; + } + + if (existingDimension && existingDimension > 0) { + const probe = await this.embedding.embed("dimension-probe"); + const probeLength = probe.length; + if (probeLength && probeLength !== existingDimension) { + throw new Error( + `Embedding dimension ${probeLength} does not match Qdrant collection ${existingDimension} for "${this.collection}". Create a new collection or set memory.embedding.dimensions to match.`, + ); + } + this.embeddingDimension = probeLength || existingDimension; + this.embedding.dimension = this.embeddingDimension; + return this.embeddingDimension; + } + + const probe = await this.embedding.embed("dimension-probe"); + const probeLength = probe.length; + if (!probeLength) { + throw new Error("Embedding provider returned empty vector for dimension probe"); + } + + this.embeddingDimension = probeLength; + this.embedding.dimension = probeLength; + return probeLength; + } + /** Initialize the memory store with retry logic */ async init(): Promise { if (this.initialized) return; @@ -395,7 +454,8 @@ export class Memory { for (let attempt = 1; attempt <= maxRetries; attempt++) { try { - await this.storage.createCollection(this.collection, this.embedding.dimension); + const dimension = await this.resolveEmbeddingDimension(); + await this.storage.createCollection(this.collection, dimension); this.storage.setCollection(this.collection); this.initialized = true; diff --git a/src/model-catalog.ts b/src/model-catalog.ts deleted file mode 100644 index 97b3730bbc..0000000000 --- a/src/model-catalog.ts +++ /dev/null @@ -1,120 +0,0 @@ -/** - * Model Catalog - Available LLM models for council deliberation - * - * This module provides a catalog of available models that can participate - * in LLM Council sessions. Models are loaded from environment config and - * available API keys. - */ - -// Provider types matching council-types.ts -export type CouncilProviderType = "anthropic" | "openai" | "openrouter"; - -/** - * A model entry in the catalog. - */ -export interface ModelCatalogEntry { - /** Unique identifier (e.g., "claude-3-opus") */ - id: string; - /** Provider type */ - provider: CouncilProviderType; - /** Model ID for the provider API */ - model: string; - /** OpenRouter-specific model route */ - modelRoute?: string; - /** Human-readable display name */ - displayName: string; - /** Model capabilities/specializations */ - capabilities?: string[]; - /** Whether model is available (has API key) */ - available: boolean; -} - -/** - * Load the model catalog based on available API keys. - * Returns models that have valid credentials configured. - */ -export async function loadModelCatalog(): Promise { - const catalog: ModelCatalogEntry[] = []; - - // Anthropic models (if API key available) - if (process.env.ANTHROPIC_API_KEY) { - catalog.push({ - id: "claude-opus-4", - provider: "anthropic", - model: "claude-opus-4-20250514", - displayName: "Claude Opus 4", - capabilities: ["reasoning", "analysis", "coding"], - available: true, - }); - catalog.push({ - id: "claude-sonnet-4", - provider: "anthropic", - model: "claude-sonnet-4-20250514", - displayName: "Claude Sonnet 4", - capabilities: ["balanced", "coding", "fast"], - available: true, - }); - } - - // OpenAI models (if API key available) - if (process.env.OPENAI_API_KEY) { - catalog.push({ - id: "gpt-4-turbo", - provider: "openai", - model: "gpt-4-turbo-preview", - displayName: "GPT-4 Turbo", - capabilities: ["reasoning", "coding"], - available: true, - }); - catalog.push({ - id: "gpt-4o", - provider: "openai", - model: "gpt-4o", - displayName: "GPT-4o", - capabilities: ["multimodal", "fast"], - available: true, - }); - } - - // OpenRouter models (if API key available) - if (process.env.OPENROUTER_API_KEY) { - catalog.push({ - id: "gemini-2-flash", - provider: "openrouter", - model: "google/gemini-2.0-flash-001", - modelRoute: "google/gemini-2.0-flash-001", - displayName: "Gemini 2.0 Flash", - capabilities: ["multimodal", "fast"], - available: true, - }); - catalog.push({ - id: "deepseek-r1", - provider: "openrouter", - model: "deepseek/deepseek-r1", - modelRoute: "deepseek/deepseek-r1", - displayName: "DeepSeek R1", - capabilities: ["reasoning", "coding"], - available: true, - }); - } - - return catalog; -} - -/** - * Get a specific model by ID. - */ -export async function getModel(id: string): Promise { - const catalog = await loadModelCatalog(); - return catalog.find((m) => m.id === id); -} - -/** - * Filter models by provider. - */ -export async function getModelsByProvider( - provider: CouncilProviderType -): Promise { - const catalog = await loadModelCatalog(); - return catalog.filter((m) => m.provider === provider); -} diff --git a/src/paths.ts b/src/paths.ts new file mode 100644 index 0000000000..f4585a72f3 --- /dev/null +++ b/src/paths.ts @@ -0,0 +1,177 @@ +/** + * Centralized Path Resolution + * + * All persona and asset paths are resolved from AGENT_CORE_ROOT. + * No need for env vars like STANLEY_REPO, ZEE_REPO, etc. + */ + +import path from "path" +import fs from "fs" +import os from "os" + +/** + * Get the agent-core root directory. + * Order of precedence: + * 1. AGENT_CORE_ROOT env var (set by binary or launcher) + * 2. Source development path + */ +export function getAgentCoreRoot(): string { + if (process.env.AGENT_CORE_ROOT) { + return process.env.AGENT_CORE_ROOT + } + // Fallback to source path for development + return path.join(os.homedir(), ".local", "src", "agent-core") +} + +/** + * Persona paths - resolved from AGENT_CORE_ROOT/vendor/personas/ + */ +export const Personas = { + root(): string { + return path.join(getAgentCoreRoot(), "vendor", "personas") + }, + + zee(): string { + return path.join(this.root(), "zee") + }, + + stanley(): string { + return path.join(this.root(), "stanley") + }, + + johny(): string { + return path.join(this.root(), "johny") + }, + + exists(name: "zee" | "stanley" | "johny"): boolean { + return fs.existsSync(this[name]()) + }, +} + +/** + * Stanley-specific paths + */ +export const Stanley = { + repo(): string { + return process.env.STANLEY_REPO || Personas.stanley() + }, + + cli(): string { + return process.env.STANLEY_CLI || path.join(this.repo(), "scripts", "stanley_cli.py") + }, + + /** + * Resolve Python binary for Stanley. + * Order: STANLEY_PYTHON env > bundled runtime > venv > system python3 + */ + python(): string { + if (process.env.STANLEY_PYTHON) { + return process.env.STANLEY_PYTHON + } + + const repo = this.repo() + + // Check for bundled runtime (dist builds) + const runtimeBin = path.join(repo, ".python-runtime", "bin") + for (const bin of ["python3.13", "python3.12", "python3"]) { + const candidate = path.join(runtimeBin, bin) + if (fs.existsSync(candidate)) return candidate + } + + // Check for venv (dev builds) + const venvPython = path.join(repo, ".venv", "bin", "python") + if (fs.existsSync(venvPython)) return venvPython + + // Fallback to system + return "python3" + }, + + /** + * Get PYTHONPATH for Stanley dependencies + */ + pythonPath(): string | undefined { + const repo = this.repo() + const bundledDeps = path.join(repo, ".python") + if (fs.existsSync(bundledDeps)) return bundledDeps + return process.env.STANLEY_PYTHONPATH + }, + + portfolioFile(): string { + return process.env.STANLEY_PORTFOLIO_FILE || path.join(os.homedir(), ".zee", "stanley", "portfolio.json") + }, +} + +/** + * Johny-specific paths + */ +export const Johny = { + repo(): string { + return process.env.JOHNY_REPO || Personas.johny() + }, + + cli(): string { + return process.env.JOHNY_CLI || path.join(this.repo(), "scripts", "johny_cli.py") + }, +} + +/** + * Zee-specific paths + */ +export const Zee = { + repo(): string { + return process.env.ZEE_REPO || Personas.zee() + }, + + /** + * Zee data directory - ~/.zee/ + * Contains credentials, sessions, and persona data + */ + dataDir(): string { + return path.join(os.homedir(), ".zee") + }, + + credentials(): string { + return path.join(this.dataDir(), "credentials") + }, +} + +/** + * Tiara orchestration paths + */ +export const Tiara = { + root(): string { + const agentCoreRoot = getAgentCoreRoot() + const distPath = path.join(agentCoreRoot, "vendor", "tiara") + if (fs.existsSync(distPath)) return distPath + return path.join(agentCoreRoot, "vendor", "tiara") + }, + + exists(): boolean { + return fs.existsSync(this.root()) + }, +} + +/** + * Agent-core assets paths + */ +export const Assets = { + root(): string { + return path.join(getAgentCoreRoot(), ".agent-core") + }, + + agents(): string { + return path.join(this.root(), "agent") + }, + + themes(): string { + return path.join(this.root(), "themes") + }, + + skills(): string { + return path.join(this.root(), "skill") + }, + + config(): string { + return path.join(this.root(), "agent-core.jsonc") + }, +} diff --git a/src/personas/tiara.ts b/src/personas/tiara.ts index 3e6ea4ec01..05ca07b23b 100644 --- a/src/personas/tiara.ts +++ b/src/personas/tiara.ts @@ -34,6 +34,7 @@ import { WeztermPaneBridge, createWeztermBridge } from "./wezterm"; import { generateDronePrompt } from "./persona"; import { formatAnnouncement, getDroneWaiter, shouldAnnounce, shutdownDroneWaiter } from "./drone-wait"; import { Log } from "../../packages/agent-core/src/util/log"; +import { getTiaraQdrantConfig } from "../config/runtime"; import { QDRANT_URL, QDRANT_COLLECTION_PERSONAS_STATE, @@ -44,6 +45,7 @@ import { } from "../config/constants"; const log = Log.create({ service: "personas-tiara" }); +const defaultQdrant = getTiaraQdrantConfig(); /** * Default personas layer configuration @@ -57,9 +59,10 @@ const DEFAULT_CONFIG: PersonasConfig = { showStatusPane: true, }, qdrant: { - url: QDRANT_URL, - stateCollection: QDRANT_COLLECTION_PERSONAS_STATE, - memoryCollection: QDRANT_COLLECTION_PERSONAS_MEMORY, + url: defaultQdrant.url ?? QDRANT_URL, + apiKey: defaultQdrant.apiKey, + stateCollection: defaultQdrant.stateCollection ?? QDRANT_COLLECTION_PERSONAS_STATE, + memoryCollection: defaultQdrant.memoryCollection ?? QDRANT_COLLECTION_PERSONAS_MEMORY, }, continuity: { autoSummarize: true, diff --git a/src/tiara.ts b/src/tiara.ts deleted file mode 100644 index e58a2749ff..0000000000 --- a/src/tiara.ts +++ /dev/null @@ -1,329 +0,0 @@ -/** - * Tiara - Agent Orchestration Interface - * - * This module bridges the Council deliberation system with the Personas orchestrator. - * It exports the AgentOrchestrator interface expected by the council stages. - */ - -import type { PersonaId } from "./personas/types"; - -/** - * Result from spawning an agent - */ -export interface AgentSpawnResult { - result?: unknown; - error?: string; - durationMs?: number; -} - -/** - * Options for spawning an agent - */ -export interface AgentSpawnOptions { - agentType: string; - action: string; - params: Record; - context?: string; -} - -/** - * AgentOrchestrator interface expected by the Council deliberation system. - * Provides agent spawning capabilities for multi-agent coordination. - */ -export interface AgentOrchestrator { - /** - * Spawn an agent to perform a specific action - */ - spawnAgent(options: AgentSpawnOptions): Promise; -} - -// ============================================================================= -// Comprehensive Agent Type Mappings (54+ agent types) -// ============================================================================= - -/** - * Zee - Personal Assistant Domain - * Handles: productivity, communication, organization, daily life tasks - */ -const ZEE_AGENT_TYPES = new Set([ - // Existing - "inbox_manager", - "scheduler", - "task_coordinator", - // Communication - "email_assistant", - "message_handler", - "notification_manager", - "contact_manager", - "communication_coordinator", - "social_media_manager", - // Calendar & Time - "calendar_manager", - "meeting_scheduler", - "reminder_assistant", - "time_tracker", - "event_coordinator", - // Organization - "file_organizer", - "note_taker", - "document_manager", - "bookmark_organizer", - "password_manager", - // Daily Life - "travel_planner", - "shopping_assistant", - "recipe_finder", - "restaurant_recommender", - "habit_tracker", - "health_tracker", - "fitness_planner", - // Entertainment - "music_curator", - "movie_recommender", - "podcast_finder", - "news_aggregator", - "book_recommender", - // Generic Personal - "personal_assistant", - "life_admin", - "general_helper", -]); - -/** - * Johny - Learning & Research Domain - * Handles: education, research, knowledge synthesis, skill development - */ -const JOHNY_AGENT_TYPES = new Set([ - // Existing - "research_assistant", - // Research & Knowledge - "knowledge_synthesizer", - "fact_checker", - "topic_explorer", - "document_analyzer", - "paper_summarizer", - "citation_finder", - "literature_reviewer", - // Learning & Study - "curriculum_designer", - "study_planner", - "quiz_maker", - "flashcard_creator", - "memory_trainer", - "skill_assessor", - "learning_path_designer", - "concept_mapper", - // Tutoring - "code_tutor", - "math_helper", - "language_tutor", - "science_explainer", - "history_researcher", - "philosophy_guide", - "writing_coach", - // Analysis - "essay_writer", - "argument_analyzer", - "debate_helper", - "critical_thinker", - // Generic Learning - "educator", - "mentor", - "academic_assistant", -]); - -/** - * Stanley - Finance & Investing Domain - * Handles: markets, portfolio, trading, financial analysis - */ -const STANLEY_AGENT_TYPES = new Set([ - // Existing - "market_analyst", - "portfolio_manager", - // Analysis Types - "fundamental_analyst", - "technical_analyst", - "quantitative_analyst", - "sentiment_analyst", - "sector_analyst", - "earnings_analyst", - // Strategy - "stock_screener", - "options_strategist", - "risk_assessor", - "asset_allocator", - "position_sizer", - "rebalance_advisor", - // Tracking - "dividend_tracker", - "performance_tracker", - "watchlist_manager", - "alert_manager", - // Execution - "backtest_runner", - "trade_executor", - "order_manager", - // Specialized Markets - "crypto_analyst", - "forex_trader", - "commodity_analyst", - "bond_analyst", - "etf_specialist", - // Macro - "macro_economist", - "fed_watcher", - "economic_indicator_tracker", - // Tax & Compliance - "tax_optimizer", - "compliance_checker", - // Generic Finance - "financial_advisor", - "investment_researcher", - "wealth_manager", -]); - -/** - * Map council agent types to personas using comprehensive type sets - */ -function mapAgentTypeToPersona(agentType: string): PersonaId { - const normalizedType = agentType.toLowerCase().replace(/[-\s]/g, "_"); - - if (STANLEY_AGENT_TYPES.has(normalizedType)) { - return "stanley"; - } - - if (JOHNY_AGENT_TYPES.has(normalizedType)) { - return "johny"; - } - - if (ZEE_AGENT_TYPES.has(normalizedType)) { - return "zee"; - } - - // Fallback heuristics based on keywords - if (normalizedType.includes("market") || normalizedType.includes("invest") || - normalizedType.includes("trade") || normalizedType.includes("portfolio") || - normalizedType.includes("stock") || normalizedType.includes("finance")) { - return "stanley"; - } - - if (normalizedType.includes("learn") || normalizedType.includes("study") || - normalizedType.includes("research") || normalizedType.includes("tutor") || - normalizedType.includes("education") || normalizedType.includes("knowledge")) { - return "johny"; - } - - // Default to Zee for unknown types (general assistant) - return "zee"; -} - -/** - * Get all supported agent types - */ -export function getSupportedAgentTypes(): { zee: string[]; johny: string[]; stanley: string[] } { - return { - zee: Array.from(ZEE_AGENT_TYPES), - johny: Array.from(JOHNY_AGENT_TYPES), - stanley: Array.from(STANLEY_AGENT_TYPES), - }; -} - -/** - * Get persona for an agent type with confidence score - */ -export function getAgentPersonaWithConfidence(agentType: string): { persona: PersonaId; confidence: "high" | "medium" | "low" } { - const normalizedType = agentType.toLowerCase().replace(/[-\s]/g, "_"); - - if (STANLEY_AGENT_TYPES.has(normalizedType)) { - return { persona: "stanley", confidence: "high" }; - } - - if (JOHNY_AGENT_TYPES.has(normalizedType)) { - return { persona: "johny", confidence: "high" }; - } - - if (ZEE_AGENT_TYPES.has(normalizedType)) { - return { persona: "zee", confidence: "high" }; - } - - // Check keyword heuristics - const persona = mapAgentTypeToPersona(agentType); - const usedHeuristic = persona !== "zee" || !ZEE_AGENT_TYPES.has(normalizedType); - - return { - persona, - confidence: usedHeuristic ? "medium" : "low", - }; -} - -/** - * Create an AgentOrchestrator adapter from the Personas Orchestrator - */ -export function createAgentOrchestrator( - orchestrator: import("./personas/tiara").Orchestrator -): AgentOrchestrator { - return { - async spawnAgent(options: AgentSpawnOptions): Promise { - const startTime = Date.now(); - const persona = mapAgentTypeToPersona(options.agentType); - - try { - // Build prompt from action and params - const prompt = buildAgentPrompt(options); - - // Use spawnDroneWithWait to get the result - const result = await orchestrator.spawnDroneWithWait({ - persona, - task: `${options.agentType}: ${options.action}`, - prompt, - }); - - return { - result: result.result, - error: result.error, - durationMs: result.durationMs, - }; - } catch (error) { - return { - error: error instanceof Error ? error.message : String(error), - durationMs: Date.now() - startTime, - }; - } - }, - }; -} - -/** - * Build a prompt for the agent from spawn options - */ -function buildAgentPrompt(options: AgentSpawnOptions): string { - const parts: string[] = []; - - parts.push(`## Agent Role: ${options.agentType}`); - parts.push(`## Action: ${options.action}`); - - if (options.context) { - parts.push(`\n## Context\n${options.context}`); - } - - if (options.params.query) { - parts.push(`\n## Query\n${options.params.query}`); - } - - // Add any other params - const otherParams = Object.entries(options.params).filter( - ([key]) => key !== "query" - ); - if (otherParams.length > 0) { - parts.push(`\n## Parameters`); - for (const [key, value] of otherParams) { - parts.push(`- ${key}: ${JSON.stringify(value)}`); - } - } - - return parts.join("\n"); -} - -// Re-export Orchestrator for convenience -export { Orchestrator } from "./personas/tiara"; -export type { PersonaId } from "./personas/types"; diff --git a/src/util/grammar.ts b/src/util/grammar.ts new file mode 100644 index 0000000000..09ca7d70d2 --- /dev/null +++ b/src/util/grammar.ts @@ -0,0 +1,62 @@ +import { z } from "zod" + +export namespace Grammar { + export const Match = z.object({ + message: z.string(), + shortMessage: z.string().optional(), + offset: z.number(), + length: z.number(), + replacements: z.array(z.object({ value: z.string() })), + context: z.object({ + text: z.string(), + offset: z.number(), + length: z.number(), + }), + rule: z.object({ + id: z.string(), + description: z.string(), + issueType: z.string(), + }), + }) + + export type Match = z.infer + + export async function check(text: string, config?: { username?: string; apiKey?: string }): Promise { + try { + const params = new URLSearchParams() + params.append("text", text) + params.append("language", "auto") + + if (config?.username && config?.apiKey) { + params.append("username", config.username) + params.append("apiKey", config.apiKey) + } + + const response = await fetch("https://api.languagetool.org/v2/check", { + method: "POST", + body: params, + headers: { + "Content-Type": "application/x-www-form-urlencoded", + "Accept": "application/json", + }, + }) + + if (!response.ok) { + throw new Error(`Grammar check failed: ${response.statusText}`) + } + + const json = await response.json() + const result = z.object({ matches: z.array(Match) }).safeParse(json) + + if (!result.success) { + console.error("Grammar API response parse error", result.error) + return [] + } + + return result.data.matches + } catch (e) { + console.error("Grammar check error", e) + return [] + } + } +}