cc-codeconductor
Advanced tools
| <!-- CODECONDUCTOR:BEGIN managed --> | ||
| # CodeConductor — Antigravity CLI (agy) Preset | ||
| This file configures CodeConductor for **Google Antigravity CLI (agy)** and Antigravity 2.0. Place it at `.agents/AGENTS.md` relative to your project root. | ||
| --- | ||
| ## Workflow Contract | ||
| Do not touch a single file until you understand the task contract. | ||
| Required flow: | ||
| 1. Receive or validate a **Task Card** (structured request with context, scope, constraints, and acceptance criteria) | ||
| 2. Classify risk: `low` / `medium` / `high` | ||
| 3. Route to the correct **Conductor Agent** based on task type and risk | ||
| 4. Implement **minimal diff** — only what the task requires | ||
| 5. Run tests and verify behavior | ||
| 6. Produce a **Deliverable** that meets the Scorecard criteria | ||
| 7. Wait for human review before merging | ||
| Skipping any step is not an optimization. It is a defect. | ||
| --- | ||
| ## Trigger Commands | ||
| Antigravity CLI loads custom slash commands from `.agents/workflows/*.md`. The following commands are registered: | ||
| | Slash Command | Workflow Description | | ||
| | ---------------- | ------------------------------------------------------------------ | | ||
| | `/cc-feature` | Runs the full feature design, implementation, and review workflow | | ||
| | `/cc-fix` | Runs the bug fix verification and repair workflow | | ||
| | `/cc-refactor` | Runs the code refactoring and test safety workflow | | ||
| | `/cc-review` | Runs a structured, multi-perspective code review and audit | | ||
| | `/cc-test-plan` | Generates a structured test plan for a given scope | | ||
| | `/cc-tdd-cycle` | Runs a Test-Driven Development (TDD) cycle | | ||
| | `/cc-api-contract`| Handles API contract modification and validation | | ||
| | `/cc-db-migration`| Coordinates database schema migrations safely | | ||
| | `/cc-pagespeed` | Performs a web performance and Core Web Vitals audit | | ||
| --- | ||
| ## Routing Policy | ||
| ### Risk Classification | ||
| | Signal | Risk Level | | ||
| | ----------------------------------------- | ---------- | | ||
| | New behavior, no existing tests | medium | | ||
| | Changes to public API or contracts | high | | ||
| | Database migration | high | | ||
| | Security, auth, or payment paths | high | | ||
| | Internal refactor with full test coverage | low | | ||
| | Documentation only | low | | ||
| | Bug fix in isolated component | low–medium | | ||
| | New feature (no existing path) | high | | ||
| When multiple signals apply, take the highest risk level. Do not average. | ||
| ### Agent Routing Table | ||
| | Task Type | Risk | Route | | ||
| | -------------------- | ----------- | --------------------------------------------------- | | ||
| | New feature design | any | `architect` → `implementer` | | ||
| | Bug fix | low | `implementer` | | ||
| | Bug fix | medium–high | `task-coach` → `implementer` → `tester` | | ||
| | Refactor | low | `implementer` | | ||
| | Refactor | medium–high | `architect` → `implementer` → `reviewer` | | ||
| | API change | any | `architect` → `implementer` → `reviewer` | | ||
| | Database migration | any | `architect` → `implementer` → `tester` → `reviewer` | | ||
| | Test coverage | any | `tester` | | ||
| | Documentation update | any | `docs` | | ||
| | Codebase exploration | any | `repo-explorer` | | ||
| | Code review | any | `reviewer` | | ||
| --- | ||
| ## Conductor Agents | ||
| --- | ||
| ### orchestrator | ||
| **Role:** Coordinates the workflow. Receives the Task Card, classifies risk, selects the route, delegates to agents, and monitors the deliverable. | ||
| **Use when:** Task requires multiple agents, risk is unclear, or the user needs a complete plan before implementation. | ||
| **Permissions:** | ||
| - read: `allow` | ||
| - edit: `ask` | ||
| - bash: `ask` (git status, git diff, git log only) | ||
| - network: `deny` | ||
| **Does not:** Write code. Execute tests. Push to any branch. | ||
| **Model:** `{{MODEL_GEMINI}}` | ||
| **Responsibilities:** | ||
| 1. Validate the Task Card before doing anything else. | ||
| 2. Classify the risk level using the table above. | ||
| 3. Select and document the agent route. | ||
| 4. Surface blockers rather than working around them. | ||
| 5. Declare completion only when all Deliverables are produced and verified. | ||
| **Task Card validation — required fields before routing:** | ||
| - Title (short description, max 80 chars) | ||
| - Type (`feature`, `fix`, `refactor`, `review`, `docs`, `test`) | ||
| - Risk (`low`, `medium`, `high`) | ||
| - Scope (named files, modules, or components) | ||
| - Context (current behavior and problem/opportunity) | ||
| - Context scope (`isolated`, `continuation`, `full`) | ||
| - Acceptance criteria (measurable, verifiable conditions) | ||
| If any required field is missing, route to `task-coach` to clarify. | ||
| **Routing documentation format:** | ||
| ```markdown | ||
| ## Routing Decision | ||
| Task: [title] Type: [type] Risk: [low | medium | high] Route: [agent1] → [agent2] → ... | ||
| Justification: [one sentence explaining why this route was selected] | ||
| High-risk checkpoint: [yes | no — if yes, describe what triggers a stop] | ||
| ``` | ||
| --- | ||
| ### task-coach | ||
| **Role:** Transforms vague requests into complete, routable Task Cards by asking targeted clarifying questions. | ||
| **Use when:** Request lacks acceptance criteria, scope is ambiguous, or risk cannot be classified without more context. | ||
| **Permissions:** | ||
| - read: `allow` | ||
| - edit: `deny` | ||
| - bash: `deny` | ||
| - network: `deny` | ||
| **Model:** `{{MODEL_GEMINI}}` | ||
| **Intake process:** | ||
| 1. Read the entire request before asking anything. | ||
| 2. Identify missing or ambiguous fields. | ||
| 3. Ask one focused question at a time. | ||
| 4. Wait for the answer. | ||
| 5. Produce the Task Card. | ||
| **Task Card format:** | ||
| ```markdown | ||
| ## Task Card | ||
| **Objective**: [one sentence] | ||
| **Acceptance Criteria**: | ||
| 1. [verifiable condition] | ||
| 2. [verifiable condition] | ||
| **Scope**: | ||
| - In: [what is included] | ||
| - Out: [what is explicitly excluded] | ||
| **Risk Level**: [low | medium | high] — [one-sentence justification] | ||
| **Context**: | ||
| - Files: [list relevant files or "unknown"] | ||
| - Services: [list relevant services or "none"] | ||
| - Constraints: [constraints or "none"] | ||
| ``` | ||
| --- | ||
| ### repo-explorer | ||
| **Role:** Maps the repository structure. Identifies conventions. Locates relevant files. Estimates impact radius. | ||
| **Use when:** Starting a new task without context, investigating an unfamiliar module, or identifying impact radius. | ||
| **Permissions:** | ||
| - read: `allow` | ||
| - edit: `deny` | ||
| - bash: `allow` (git log, git diff, git status) | ||
| - network: `deny` | ||
| **Model:** `{{MODEL_GEMINI}}` | ||
| **Repo Map format:** | ||
| ```markdown | ||
| ## Repo Map | ||
| **Task**: [objective from Task Card] | ||
| ### Structure | ||
| [directory tree — relevant portions only] | ||
| ### Conventions | ||
| | Concern | Convention | | ||
| | ------- | ---------- | | ||
| | Naming | ... | | ||
| | Testing | ... | | ||
| ### Relevant Files | ||
| - [path/to/file] — [relevance] | ||
| ``` | ||
| --- | ||
| ### architect | ||
| **Role:** Designs the technical approach. Produces ADRs, module boundaries, and API contracts. | ||
| **Use when:** New feature, refactor with structural impact, API changes, or database changes. | ||
| **Permissions:** | ||
| - read: `allow` | ||
| - edit: `ask` (docs and ADRs only) | ||
| - bash: `deny` | ||
| - network: `deny` | ||
| **Model:** `{{MODEL_GEMINI}}` | ||
| **Technical Plan format:** | ||
| ```markdown | ||
| ## Technical Plan | ||
| **Task**: [objective] | ||
| **Approach**: [chosen strategy and why] | ||
| **Tradeoffs**: | ||
| - Chosen: [approach] because [reason] | ||
| - Rejected: [alternative] because [reason] | ||
| **Files Affected**: | ||
| - [path/to/file] — [what changes] | ||
| **Risks**: | ||
| - [risk] — mitigation: [how to handle] | ||
| **Open Questions**: | ||
| - [questions for human input] | ||
| ``` | ||
| --- | ||
| ### implementer | ||
| **Role:** Executes the Technical Plan. Writes code following accepted designs. | ||
| **Use when:** Task has an accepted plan, files to modify are clear, and acceptance criteria exist. | ||
| **Permissions:** | ||
| - read: `allow` | ||
| - edit: `ask` | ||
| - bash: `allow` (build, test, and lint commands only) | ||
| - network: `deny` | ||
| **Model:** `{{MODEL_GEMINI}}` | ||
| **Pre-implementation checklist:** | ||
| 1. Create a Git Worktree: `git worktree add ../<branch>-session <branch>` | ||
| 2. Read the Technical Plan completely. | ||
| 3. Read the target files. | ||
| 4. Verify tests pass before starting. | ||
| **Implementation Summary format:** | ||
| ```markdown | ||
| ## Implementation Summary | ||
| **Task**: [objective] **Status**: complete | blocked | ||
| **Worktree**: [path to worktree] | ||
| **Changes Made**: | ||
| - [path/to/file] — [summary of change] | ||
| **Tests**: | ||
| - Runner: [npm test | pytest | ...] | ||
| - Result: [passed | failed] | ||
| ``` | ||
| --- | ||
| ### tester | ||
| **Role:** Generates unit, integration, and contract tests. Verifies behavior against acceptance criteria. | ||
| **Use when:** New behavior is introduced, bugs are fixed, or refactoring carries behavioral risk. | ||
| **Permissions:** | ||
| - read: `allow` | ||
| - edit: `ask` (test files only) | ||
| - bash: `allow` (test commands only) | ||
| - network: `deny` | ||
| **Model:** `{{MODEL_GEMINI}}` | ||
| **Coverage Summary format:** | ||
| ```markdown | ||
| ## Coverage Summary | ||
| **Task**: [objective] | ||
| **Test Files Added/Modified**: | ||
| - [path/to/test] — [cases covered] | ||
| **Test Run Results**: | ||
| - Passed: [count] | ||
| - Failed: [count] | ||
| ``` | ||
| --- | ||
| ### reviewer | ||
| **Role:** Reviews diffs for correctness, architecture alignment, security, and technical debt. | ||
| **Use when:** Before committing, before opening a PR, or after agent-generated changes. | ||
| **Permissions:** | ||
| - read: `allow` | ||
| - edit: `deny` | ||
| - bash: `allow` (git diff, git status, test commands) | ||
| - network: `deny` | ||
| **Model:** `{{MODEL_GEMINI}}` | ||
| **Review Report format:** | ||
| ```markdown | ||
| ## Review Report | ||
| **Task**: [objective] | ||
| ### Findings | ||
| - **CRITICAL**: [must be fixed before merge] | ||
| - **WARNING**: [resolve before merge] | ||
| - **SUGGESTION**: [optional enhancement] | ||
| ``` | ||
| --- | ||
| ### docs | ||
| **Role:** Updates README, OpenAPI specs, ADRs, and changelogs. | ||
| **Use when:** Public API changed, new module introduced, or behavior documented incorrectly. | ||
| **Permissions:** | ||
| - read: `allow` | ||
| - edit: `ask` (docs and markdown only) | ||
| - bash: `deny` | ||
| - network: `deny` | ||
| **Model:** `{{MODEL_GEMINI}}` | ||
| <!-- CODECONDUCTOR:END managed --> |
| { | ||
| "code-formatter": { | ||
| "enabled": true, | ||
| "PostToolUse": [ | ||
| { | ||
| "matcher": "write_to_file|replace_file_content|multi_replace_file_content", | ||
| "hooks": [ | ||
| { | ||
| "type": "command", | ||
| "command": "if [ -f \"./.agents/scripts/post-tool.sh\" ]; then bash ./.agents/scripts/post-tool.sh; else bash \"$HOME/.gemini/config/scripts/post-tool.sh\"; fi" | ||
| } | ||
| ] | ||
| } | ||
| ] | ||
| }, | ||
| "safety-gate": { | ||
| "enabled": true, | ||
| "PreToolUse": [ | ||
| { | ||
| "matcher": "run_command|write_to_file|replace_file_content|multi_replace_file_content|view_file", | ||
| "hooks": [ | ||
| { | ||
| "type": "command", | ||
| "command": "if [ -f \"./.agents/scripts/pre-tool.sh\" ]; then bash ./.agents/scripts/pre-tool.sh; else bash \"$HOME/.gemini/config/scripts/pre-tool.sh\"; fi" | ||
| } | ||
| ] | ||
| } | ||
| ] | ||
| } | ||
| } |
| { | ||
| "mcpServers": {} | ||
| } |
| # Antigravity CLI (agy) Preset for CodeConductor | ||
| This preset configures CodeConductor for **Google Antigravity CLI (agy)** and Antigravity 2.0. | ||
| ## Structure | ||
| When installed, this preset writes files into your project's workspace customizations root: | ||
| - **`.agents/AGENTS.md`**: Core agent contracts, routing policy, and workflow instructions. | ||
| - **`.agents/rules/`**: Target rules and style guidelines (e.g., commit messages, knowledge graphs). | ||
| - **`.agents/workflows/`**: Custom slash commands representing CodeConductor workflows (e.g., `/cc-feature`, `/cc-fix`). | ||
| - **`.agents/skills/`**: Domain-specific skills (e.g., Spring Boot, Django, Next.js). | ||
| --- | ||
| ## Orchestrator Agent Workflow | ||
| Antigravity CLI automatically parses `.agents/AGENTS.md` and registered workflows under `.agents/workflows/`. | ||
| To run any CodeConductor workflow: | ||
| 1. Start the Antigravity CLI: | ||
| ```bash | ||
| agy | ||
| ``` | ||
| 2. Run one of the custom slash commands: | ||
| ```text | ||
| /cc-feature "Describe the new feature to build" | ||
| /cc-fix "Describe the bug and where it is" | ||
| /cc-refactor "Describe the refactoring scope" | ||
| ``` | ||
| --- | ||
| ## Configuration Settings (`settings.json`) | ||
| To configure permissions, models, and execution modes for the Antigravity CLI, update your global settings at `~/.gemini/antigravity-cli/settings.json` or project-scoped settings. | ||
| Recommended settings: | ||
| ```json | ||
| { | ||
| "model": "gemini-3.5-pro", | ||
| "toolPermission": "request-review", | ||
| "enableTerminalSandbox": true, | ||
| "allowNonWorkspaceAccess": false | ||
| } | ||
| ``` |
| {{COMMIT_STYLE}} |
| --- | ||
| trigger: always_on | ||
| description: Consult the graphify knowledge graph at graphify-out/ for codebase and architecture questions. | ||
| --- | ||
| ## graphify | ||
| This project has a graphify knowledge graph at graphify-out/. | ||
| Rules: | ||
| - For codebase or architecture questions, when `graphify-out/graph.json` exists, first run `graphify query "<question>"` (CLI) or `query_graph` (MCP). Use `graphify path "<A>" "<B>"` / `shortest_path` for relationships and `graphify explain "<concept>"` / `get_node` for focused concepts. These return a scoped subgraph, usually much smaller than `GRAPH_REPORT.md` or raw grep output. | ||
| - If graphify-out/wiki/index.md exists, navigate it instead of reading raw files | ||
| - Read graphify-out/GRAPH_REPORT.md only for broad architecture review or when query/path/explain do not surface enough context | ||
| - After modifying code files in this session, run `graphify update .` to keep the graph current (AST-only, no API cost) |
| #!/bin/bash | ||
| # Read stdin JSON payload | ||
| JSON_INPUT=$(cat) | ||
| TOOL_NAME=$(echo "$JSON_INPUT" | jq -r '.toolName') | ||
| if [[ "$TOOL_NAME" == "write_to_file" || "$TOOL_NAME" == "replace_file_content" || "$TOOL_NAME" == "multi_replace_file_content" ]]; then | ||
| FILE_PATH=$(echo "$JSON_INPUT" | jq -r '.arguments.TargetFile') | ||
| if [ -f "$FILE_PATH" ]; then | ||
| # Run Prettier | ||
| if echo "$FILE_PATH" | grep -qE '\.(ts|tsx|js|jsx|mjs|cjs|json|jsonc|md|mdx|css|scss|html|astro|yaml|yml)$'; then | ||
| npx --no-install prettier --write "$FILE_PATH" 2>/dev/null || true | ||
| fi | ||
| # Run ESLint | ||
| if echo "$FILE_PATH" | grep -qE '\.(ts|tsx|js|jsx|mjs|cjs)$'; then | ||
| npx --no-install eslint --fix "$FILE_PATH" 2>/dev/null || true | ||
| fi | ||
| # Run Ruff (Python) | ||
| if echo "$FILE_PATH" | grep -qE '\.py$'; then | ||
| ruff format "$FILE_PATH" 2>/dev/null && ruff check --fix "$FILE_PATH" 2>/dev/null || true | ||
| fi | ||
| fi | ||
| fi | ||
| # Return an empty JSON object to stdout | ||
| echo "{}" |
| #!/bin/bash | ||
| # Read stdin JSON payload | ||
| JSON_INPUT=$(cat) | ||
| TOOL_NAME=$(echo "$JSON_INPUT" | jq -r '.toolName') | ||
| # Check paths for write/edit/read operations | ||
| TARGET_PATH="" | ||
| if [[ "$TOOL_NAME" == "write_to_file" || "$TOOL_NAME" == "replace_file_content" || "$TOOL_NAME" == "multi_replace_file_content" ]]; then | ||
| TARGET_PATH=$(echo "$JSON_INPUT" | jq -r '.arguments.TargetFile') | ||
| elif [[ "$TOOL_NAME" == "view_file" ]]; then | ||
| TARGET_PATH=$(echo "$JSON_INPUT" | jq -r '.arguments.AbsolutePath') | ||
| fi | ||
| if [[ ! -z "$TARGET_PATH" ]]; then | ||
| if echo "$TARGET_PATH" | grep -qE '(\.env|secrets/|/\.ssh/|/\.aws/|/\.kube/)'; then | ||
| echo '{"action": "deny", "error": "Blocked: Attempt to access sensitive path"}' | ||
| exit 0 | ||
| fi | ||
| fi | ||
| if [[ "$TOOL_NAME" == "run_command" ]]; then | ||
| COMMAND_LINE=$(echo "$JSON_INPUT" | jq -r '.arguments.CommandLine') | ||
| # 1. Deny patterns | ||
| if echo "$COMMAND_LINE" | grep -qE '(\.env|secrets/|id_rsa|\\.pem|\\.key)\\b' && echo "$COMMAND_LINE" | grep -qE '(cat|less|more|head|tail|cp |mv |scp )'; then | ||
| echo '{"action": "deny", "error": "Blocked: Attempt to read sensitive files"}' | ||
| exit 0 | ||
| fi | ||
| if echo "$COMMAND_LINE" | grep -qE '^rm\s+-rf\s+\*' || \ | ||
| echo "$COMMAND_LINE" | grep -qE '^sudo\s+' || \ | ||
| echo "$COMMAND_LINE" | grep -qE '^git\s+push\s+.*--force' || \ | ||
| echo "$COMMAND_LINE" | grep -qE '^git\s+push\s+.*-f' || \ | ||
| echo "$COMMAND_LINE" | grep -qE '^git\s+rebase\s+' || \ | ||
| echo "$COMMAND_LINE" | grep -qE '^git\s+reset\s+--hard\s+' || \ | ||
| echo "$COMMAND_LINE" | grep -qE 'curl\s+.*\s*\|\s*(sh|bash)' || \ | ||
| echo "$COMMAND_LINE" | grep -qE 'wget\s+.*\s*\|\s*(sh|bash)' || \ | ||
| echo "$COMMAND_LINE" | grep -qE '^chmod\s+777\s+' || \ | ||
| echo "$COMMAND_LINE" | grep -qE '^dd\s+' || \ | ||
| echo "$COMMAND_LINE" | grep -qE '^mkfs\s+'; then | ||
| echo '{"action": "deny", "error": "Blocked: Command violated security policy"}' | ||
| exit 0 | ||
| fi | ||
| # 2. Ask patterns | ||
| if echo "$COMMAND_LINE" | grep -qE '^git\s+commit\s*' || \ | ||
| echo "$COMMAND_LINE" | grep -qE '^git\s+checkout\s*' || \ | ||
| echo "$COMMAND_LINE" | grep -qE '^git\s+switch\s*' || \ | ||
| echo "$COMMAND_LINE" | grep -qE '^docker\s+compose\s*'; then | ||
| echo '{"action": "ask"}' | ||
| exit 0 | ||
| fi | ||
| fi | ||
| # Default: allow | ||
| echo '{"action": "allow"}' |
| { | ||
| "model": "gemini-3.5-pro", | ||
| "toolPermission": "request-review", | ||
| "enableTerminalSandbox": true, | ||
| "allowNonWorkspaceAccess": false, | ||
| "verbosity": "low", | ||
| "alwaysThinkingEnabled": true | ||
| } |
| --- | ||
| name: cc-api-contract | ||
| description: | ||
| Run the API contract workflow for request/response shape changes, | ||
| compatibility constraints, contract tests, documentation, and review. | ||
| --- | ||
| # API Contract Workflow | ||
| API contract request: $ARGUMENTS | ||
| ## Step 1 — Task Card validation (task-coach) | ||
| Invoke `task-coach` with the request above. | ||
| The Task Card must classify the task as `feature` or `refactor` with `high` | ||
| risk unless the human provides a narrower validated risk. It must include: | ||
| - affected endpoint, command, or public interface | ||
| - request and response examples | ||
| - backward compatibility and versioning impact | ||
| - consumers that must remain compatible | ||
| - contract tests and documentation acceptance criteria | ||
| **STOP here. Show the Task Card and wait for human confirmation.** | ||
| --- | ||
| ## Step 2 — Technical Plan (architect) | ||
| Invoke `architect` with the approved Task Card. | ||
| architect must define the API contract, compatibility strategy, validation | ||
| rules, docs/OpenAPI impact, and migration path for consumers. | ||
| **STOP here. Show the Technical Plan and wait for explicit human approval.** | ||
| --- | ||
| ## Step 3 — Implementation (implementer) | ||
| Invoke `implementer` with the approved plan. | ||
| implementer must apply the minimal diff, preserve compatible behavior unless a | ||
| breaking change was explicitly approved, and update only the files named in the | ||
| plan. | ||
| --- | ||
| ## Step 4 — Contract tests (tester) | ||
| Invoke `tester`. | ||
| tester must add or update contract tests covering request shape, response shape, | ||
| status/error behavior, and backward compatibility constraints. | ||
| --- | ||
| ## Step 5 — Review (reviewer) | ||
| Invoke `reviewer`. | ||
| reviewer must block on missing contract tests, undocumented breaking changes, | ||
| or docs/OpenAPI drift. | ||
| --- | ||
| ## Completion | ||
| Report the final Task Card, Technical Plan, implementation summary, test report, | ||
| review report, docs updated, compatibility impact, and residual risks. |
| --- | ||
| name: cc-db-migration | ||
| description: | ||
| Run the database migration workflow for schema/data changes, operational | ||
| sequencing, tests, and review. | ||
| --- | ||
| # Database Migration Workflow | ||
| Migration request: $ARGUMENTS | ||
| ## Step 1 — Task Card validation (task-coach) | ||
| Invoke `task-coach` with the request above. | ||
| The Task Card must classify the task as `high` risk and include: | ||
| - tables, collections, models, or migration files in scope | ||
| - data backfill or data cleanup requirements | ||
| - deployment ordering and compatibility window | ||
| - rollback or forward-fix strategy | ||
| - lock risk, data risk, and verification commands | ||
| **STOP here. Show the Task Card and wait for human confirmation.** | ||
| --- | ||
| ## Step 2 — Migration Plan (architect) | ||
| Invoke `architect` with the approved Task Card. | ||
| architect must define the schema/data plan, operational sequencing, | ||
| compatibility strategy, rollback/forward-fix notes, and test approach. | ||
| **STOP here. Show the Technical Plan and wait for explicit human approval.** | ||
| --- | ||
| ## Step 3 — Implementation (implementer) | ||
| Invoke `implementer` with the approved plan. | ||
| implementer must keep model and migration changes together, avoid unrelated | ||
| refactors, and preserve the deployment order specified by architect. | ||
| --- | ||
| ## Step 4 — Migration tests (tester) | ||
| Invoke `tester`. | ||
| tester must cover migration-sensitive behavior where the stack supports it, | ||
| including happy path, existing-data edge cases, and rollback/forward-fix notes | ||
| when automated rollback tests are not practical. | ||
| --- | ||
| ## Step 5 — Review (reviewer) | ||
| Invoke `reviewer`. | ||
| reviewer must block on missing migration tests, missing data-risk notes, | ||
| undocumented deployment sequencing, or model/migration drift. | ||
| --- | ||
| ## Completion | ||
| Report migration files changed, model files changed, tests run, lock risk, data | ||
| risk, operational sequencing, rollback/forward-fix notes, and residual risk. |
| --- | ||
| name: cc-feature | ||
| description: | ||
| Run the full feature workflow — task validation, technical design, | ||
| implementation, testing, review, and documentation. | ||
| --- | ||
| # Feature Workflow | ||
| Feature request: $ARGUMENTS | ||
| ## Step 1 — Task Card validation (task-coach) | ||
| Invoke `task-coach` with the feature description above. | ||
| task-coach must produce a complete Task Card before any other agent runs. The | ||
| Task Card is ready when it contains: title, type, risk classification, scope, | ||
| context, acceptance criteria, and constraints. | ||
| If any field is missing or ambiguous, task-coach must ask one clarifying | ||
| question at a time and wait for the answer. Do not proceed with an incomplete | ||
| Task Card. | ||
| **STOP here. Show the completed Task Card and wait for human confirmation before | ||
| continuing.** | ||
| --- | ||
| ## Step 2 — Technical Plan (architect) | ||
| Invoke `architect` with the validated Task Card from Step 1. | ||
| architect must produce a Technical Plan that covers: | ||
| - Chosen approach and rationale | ||
| - Affected files and modules | ||
| - Data model changes (if any) | ||
| - API contract changes (if any) | ||
| - Identified risks and mitigations | ||
| - Open questions that require a human decision | ||
| **STOP here. Show the Technical Plan and wait for explicit human approval. Do | ||
| not invoke implementer until the plan is approved.** | ||
| --- | ||
| ## Step 3 — Implementation (implementer) | ||
| Invoke `implementer` with the approved Technical Plan and the Task Card. | ||
| Implementer creates a Git Worktree before touching any file; all edits happen inside it. | ||
| implementer must: | ||
| 1. Read the Technical Plan before touching any file | ||
| 2. Apply the minimal diff — only what the plan specifies | ||
| 3. Run the project test suite after implementation | ||
| 4. Produce an Implementation Summary: what changed, which files, how to verify | ||
| locally | ||
| --- | ||
| ## Step 4 — Test coverage (tester) | ||
| Invoke `tester` with the Implementation Summary and the Task Card. | ||
| tester must: | ||
| 1. Write or extend tests to cover the new behavior | ||
| 2. Ensure all acceptance criteria from the Task Card have at least one test | ||
| 3. Run the full test suite and confirm it passes | ||
| 4. Produce a Coverage Summary: test files added or modified, cases covered | ||
| --- | ||
| ## Step 5 — Code review (reviewer) | ||
| Invoke `reviewer` with the complete diff and the Task Card. | ||
| reviewer must produce a Review Report with findings categorized as: | ||
| - CRITICAL — must be fixed before merge | ||
| - WARNING — must be resolved before merge | ||
| - SUGGESTION — optional improvement | ||
| If any CRITICAL findings exist, **STOP and report them**. Do not proceed until | ||
| they are resolved and re-reviewed. | ||
| --- | ||
| ## Step 6 — Documentation (docs) | ||
| Invoke `docs` only if any of the following changed: | ||
| - A public API endpoint was added or modified | ||
| - A public interface or module was introduced | ||
| - Behavior visible to end users changed | ||
| docs must update: README (if applicable), OpenAPI spec (if applicable), | ||
| CHANGELOG (always), ADR (if an architectural decision was made). | ||
| --- | ||
| ## Completion | ||
| Report the following to the human: | ||
| - Task Card (final) | ||
| - Technical Plan (approved) | ||
| - Implementation Summary | ||
| - Coverage Summary | ||
| - Review Report (all findings resolved) | ||
| - List of documentation files updated (if any) | ||
| The feature is complete only when: all tests pass, no CRITICAL review findings | ||
| remain, and documentation reflects the implemented behavior. |
| --- | ||
| name: cc-fix | ||
| description: | ||
| Run the bug fix workflow — risk-based routing through task validation, | ||
| implementation, testing, and optional review. | ||
| --- | ||
| # Bug Fix Workflow | ||
| Bug description: $ARGUMENTS | ||
| Provide the following information in $ARGUMENTS: | ||
| - What is the incorrect behavior (actual) | ||
| - What is the expected behavior | ||
| - Steps to reproduce | ||
| - Environment or version where the bug occurs (if known) | ||
| - Any relevant error messages or stack traces | ||
| --- | ||
| ## Step 1 — Task Card validation (task-coach) | ||
| Invoke `task-coach` with the bug description above. | ||
| task-coach must produce a Task Card that includes: | ||
| - A clear statement of actual vs. expected behavior | ||
| - Reproduction steps (or a note that they are unknown) | ||
| - Risk classification: `low`, `medium`, or `high` | ||
| - Scope: which files or modules are likely affected | ||
| If reproduction steps are missing, task-coach must ask for them before | ||
| classifying risk. A bug without a reproduction path cannot be classified | ||
| reliably. | ||
| **STOP here. Show the Task Card and wait for human confirmation.** | ||
| --- | ||
| ## Step 2 — Route by risk | ||
| Read the risk field from the Task Card and follow the corresponding route. | ||
| ### Low-risk route | ||
| Applies when: the bug is isolated to a single component, existing tests cover | ||
| the affected code, and no public API or shared state is involved. | ||
| Route: `task-coach` → `implementer` → `tester` | ||
| Proceed directly to Step 3a. | ||
| ### Medium or high-risk route | ||
| Applies when: the bug touches shared state, a public API, auth or payment paths, | ||
| database writes, or the root cause is not yet understood. | ||
| Route: `task-coach` → `architect` → `implementer` → `tester` → `reviewer` | ||
| Invoke `architect` before implementation. architect must: | ||
| - Identify the root cause (or document that it is unknown) | ||
| - Define the fix approach and affected files | ||
| - Flag any regression risk to adjacent components | ||
| - Produce a Technical Plan | ||
| **STOP here if high-risk. Show the Technical Plan and wait for human approval | ||
| before continuing.** | ||
| --- | ||
| ## Step 3a — Implementation, low-risk (implementer) | ||
| Invoke `implementer` with the Task Card. | ||
| Implementer creates a Git Worktree before touching any file; all edits happen inside it. | ||
| implementer must: | ||
| 1. Locate the defect using the reproduction steps | ||
| 2. Apply the minimal fix — no unrelated changes | ||
| 3. Run the test suite | ||
| 4. Produce an Implementation Summary: root cause, fix applied, files changed | ||
| --- | ||
| ## Step 3b — Implementation, medium/high-risk (implementer) | ||
| Invoke `implementer` with the approved Technical Plan and the Task Card. | ||
| Implementer creates a Git Worktree before touching any file; all edits happen inside it. | ||
| implementer must follow the plan exactly. Any deviation requires a new Technical | ||
| Plan approval. After implementation, run the full test suite. | ||
| --- | ||
| ## Step 4 — Regression tests (tester) | ||
| Invoke `tester` for all risk levels. | ||
| tester must: | ||
| 1. Write a regression test that reproduces the original bug (fails before the | ||
| fix, passes after) | ||
| 2. Verify that existing tests still pass | ||
| 3. Produce a Coverage Summary: test added, case covered | ||
| --- | ||
| ## Step 5 — Review (reviewer) — medium/high-risk only | ||
| Invoke `reviewer` with the diff and Task Card. | ||
| reviewer produces a Review Report with CRITICAL / WARNING / SUGGESTION findings. | ||
| If any CRITICAL findings exist, **STOP**. Do not close the fix until they are | ||
| resolved. | ||
| --- | ||
| ## Completion | ||
| Report: Task Card, Implementation Summary, regression test added, Review Report | ||
| (if applicable). The fix is complete only when: the regression test passes, the | ||
| full suite passes, and no CRITICAL review findings remain. |
| --- | ||
| name: cc-pagespeed | ||
| description: >- | ||
| Run the PageSpeed performance audit — 80/20 analysis of Core Web Vitals using | ||
| the PageSpeed Insights API. | ||
| --- | ||
| # PageSpeed Performance Audit | ||
| Audit URL: $ARGUMENTS | ||
| --- | ||
| ## Step 1 — Pre-flight (pagespeed-perf skill) | ||
| Invoke `pagespeed-perf` skill. | ||
| Read `PAGESPEED_API_KEY` from the environment. Compute the output filename: | ||
| `{YYYY-MM-DD}_pagespeed-{hostname}-claude.md`. | ||
| Log whether the API key was found. Proceed regardless — lab data is available | ||
| without a key, but CrUX field data requires it. | ||
| --- | ||
| ## Step 2 — Collect | ||
| Call the PageSpeed Insights API for the URL provided above. | ||
| - Strategy: `both` (mobile + desktop) unless the user specified otherwise. | ||
| - If Bun is available, use `~/.claude/skills/pagespeed-perf/scripts/run.ts`. | ||
| - If Bun is unavailable, call PSI directly via WebFetch and fetch the HTML | ||
| source for manual resource-hint analysis. | ||
| --- | ||
| ## Step 3 — Analyze | ||
| Extract from the PSI response: | ||
| - Core Web Vitals: LCP, INP, CLS, FCP, TBT, TTFB | ||
| - LCP element (type, selector, HTML snippet) | ||
| - Third-party scripts ordered by blocking time | ||
| - Render-blocking resources | ||
| - Unused JavaScript and CSS (savings in bytes and ms) | ||
| From the HTML source: | ||
| - Resource hints (`<link rel="preload|preconnect|prefetch">`) | ||
| - Images: lazy loading, `fetchpriority`, format, dimensions | ||
| - Fonts: `font-display`, preloaded subsets | ||
| - Blocking scripts in `<head>` (no `async`/`defer`) | ||
| --- | ||
| ## Step 4 — Prioritize | ||
| Score each identified optimization using the 80/20 matrix: | ||
| `Score = Impact × Ease` (each 1–5, max 25). | ||
| Order findings by descending score. Mark optimizations with Score ≥ 20 as | ||
| **Critical 20%**. | ||
| --- | ||
| ## Step 5 — Report | ||
| Write the full performance report to | ||
| `{YYYY-MM-DD}_pagespeed-{hostname}-claude.md` in the current directory. | ||
| Required sections: | ||
| 1. Resumen Ejecutivo (2–3 paragraphs) | ||
| 2. Métricas Actuales (lab vs field table) | ||
| 3. Recursos con Mayor Impacto | ||
| 4. Plan de Acción Priorizado (80/20 table) | ||
| 5. Solución Técnica Detallada (per finding: problem, evidence, code, expected gain) | ||
| 6. Quick Wins / High Impact Changes / Roadmap | ||
| End every report with: | ||
| ``` | ||
| --- | ||
| *Informe generado el {YYYY-MM-DD} · Herramienta: Claude Code + pagespeed-perf skill* | ||
| *API Key usada: {Sí / No} · Datos CrUX: {Disponibles / No disponibles}* | ||
| ``` | ||
| --- | ||
| ## Requirements | ||
| **`PAGESPEED_API_KEY`** — Optional but strongly recommended. | ||
| - With key: real CrUX field data + 25,000 requests/day quota. | ||
| - Without key: lab data only (Lighthouse); shared rate limit applies. | ||
| Set in your shell: | ||
| ```powershell | ||
| $env:PAGESPEED_API_KEY = "your-api-key" # Windows PowerShell | ||
| export PAGESPEED_API_KEY="your-api-key" # macOS / Linux | ||
| ``` | ||
| Get a free key: <https://developers.google.com/speed/docs/insights/v5/get-started> |
| --- | ||
| name: cc-refactor | ||
| description: | ||
| Run the refactor workflow — mandatory architectural justification, test | ||
| verification, risk-based implementation, and scope enforcement. | ||
| --- | ||
| # Refactor Workflow | ||
| Refactor description: $ARGUMENTS | ||
| Describe what you want to refactor and why. Include: | ||
| - The current structure or pattern being changed | ||
| - The target structure or pattern | ||
| - The motivation (performance, readability, architectural alignment, etc.) | ||
| - Known risk areas or dependencies | ||
| --- | ||
| ## Prerequisite — Test coverage check | ||
| Before any agent is invoked, verify that the code being refactored has adequate | ||
| test coverage. | ||
| A refactor without tests is not a refactor — it is a rewrite with unknown | ||
| behavioral consequences. | ||
| If coverage is insufficient: | ||
| 1. **STOP**. Report the coverage gap to the human. | ||
| 2. Suggest invoking `/cc:test-plan` first to establish coverage. | ||
| 3. Do not proceed with the refactor until coverage is confirmed. | ||
| --- | ||
| ## Step 1 — Architectural justification (architect) | ||
| Always invoke `architect` first, regardless of risk level. A refactor without a | ||
| written justification is scope creep in disguise. | ||
| architect must produce a Refactor Plan that includes: | ||
| - Statement of the problem with the current structure | ||
| - Proposed target structure and rationale | ||
| - Affected files and module boundaries | ||
| - Risk level: `low`, `medium`, or `high` | ||
| - Behavioral invariants that must not change | ||
| - Open questions requiring human input | ||
| **Scope creep warning:** If during planning architect identifies unrelated | ||
| improvements, they must be listed separately as "Out of scope." They are not | ||
| part of this refactor. | ||
| **STOP here. Show the Refactor Plan and wait for explicit human approval. Do not | ||
| proceed without written approval of the plan.** | ||
| --- | ||
| ## Step 2 — Route by risk | ||
| Read the risk field from the Refactor Plan and follow the corresponding route. | ||
| ### Low-risk route | ||
| Applies when: the refactor is purely internal, no public interfaces change, full | ||
| test coverage exists for the affected code, and behavioral impact is isolated to | ||
| the refactored module. | ||
| Route: `architect` (done) → `implementer` | ||
| Proceed to Step 3a. | ||
| ### Medium or high-risk route | ||
| Applies when: module boundaries change, shared interfaces are affected, | ||
| performance characteristics may change, or the refactor touches more than two | ||
| files with behavioral impact. | ||
| Route: `architect` (done) → `implementer` → `reviewer` | ||
| Proceed to Step 3b. | ||
| --- | ||
| ## Step 3a — Implementation, low-risk (implementer) | ||
| Invoke `implementer` with the approved Refactor Plan. | ||
| Implementer creates a Git Worktree before touching any file; all edits happen inside it. | ||
| implementer must: | ||
| 1. Read the Refactor Plan before opening any file | ||
| 2. Apply only the changes specified in the plan | ||
| 3. Run the full test suite before and after — both runs must pass | ||
| 4. Produce an Implementation Summary: what changed, what did not change, test | ||
| results before and after | ||
| Any deviation from the plan — including "obvious improvements" encountered | ||
| during implementation — must be flagged and held for a separate task. | ||
| --- | ||
| ## Step 3b — Implementation, medium/high-risk (implementer) | ||
| Same rules as 3a. Additionally: | ||
| - implementer must document any unexpected complexity discovered during | ||
| implementation and pause if the complexity changes the risk assessment | ||
| - If new risks are found, **STOP** and report to the human before continuing | ||
| --- | ||
| ## Step 4 — Test suite verification | ||
| For all risk levels, confirm: | ||
| - All tests that existed before the refactor still pass | ||
| - No test was deleted or commented out to make the suite pass | ||
| - Behavior documented in the Task Card remains unchanged | ||
| If any test fails that was passing before, the refactor has introduced a | ||
| regression. **STOP and report.** | ||
| --- | ||
| ## Step 5 — Code review (reviewer) — medium/high-risk only | ||
| Invoke `reviewer` with the diff and Refactor Plan. | ||
| reviewer must verify: | ||
| - The implementation matches the approved plan | ||
| - No behavior was changed beyond the plan's scope | ||
| - No unrelated files were modified | ||
| Review Report must include CRITICAL / WARNING / SUGGESTION findings. CRITICAL | ||
| findings block completion. | ||
| --- | ||
| ## Completion | ||
| Report: Refactor Plan (approved), Implementation Summary, test results before | ||
| and after, Review Report (if applicable). | ||
| The refactor is complete only when: all pre-existing tests still pass, the | ||
| implementation matches the approved plan exactly, and no CRITICAL review | ||
| findings remain. |
| --- | ||
| name: cc-review | ||
| description: | ||
| Run a structured code review — produces a Review Report with CRITICAL, | ||
| WARNING, and SUGGESTION findings; CRITICAL findings block merge. | ||
| --- | ||
| # Code Review Workflow | ||
| Review target: $ARGUMENTS | ||
| Specify what to review. Accepted formats: | ||
| - A branch name: `feature/my-branch` | ||
| - A file or set of files: `src/api/UserController.kt` | ||
| - A pull request reference: `PR #42` | ||
| - Empty — defaults to the current working diff (`git diff`) | ||
| --- | ||
| ## Step 1 — Diff collection | ||
| Before invoking `reviewer`, collect the diff for the specified target. | ||
| If $ARGUMENTS is empty or not provided: | ||
| - Use `git diff HEAD` as the review target | ||
| If $ARGUMENTS is a branch name: | ||
| - Use `git diff main...$ARGUMENTS` (or `develop` if main is not the base) | ||
| If $ARGUMENTS is a PR reference: | ||
| - Retrieve the PR diff and the PR description for context | ||
| If $ARGUMENTS is a file path: | ||
| - Use `git diff HEAD -- $ARGUMENTS` | ||
| Show the diff summary (files changed, lines added/removed) before invoking | ||
| reviewer. | ||
| --- | ||
| ## Step 2 — Code review (reviewer) | ||
| Invoke `reviewer` with: | ||
| - The full diff | ||
| - The Task Card or PR description (if available) | ||
| - The target specification from $ARGUMENTS | ||
| reviewer must evaluate the diff against the following checklist: | ||
| **Correctness** | ||
| - Does the implementation match the stated intent? | ||
| - Are there logic errors, off-by-one errors, or unhandled edge cases? | ||
| **Architecture alignment** | ||
| - Does the change follow existing module boundaries? | ||
| - Does it introduce unplanned coupling or layering violations? | ||
| **Security** | ||
| - Are inputs validated before use? | ||
| - Is there any credential, token, or secret in the diff? | ||
| - Are there SQL injection, XSS, or injection risks? | ||
| **Performance** | ||
| - Does the change introduce N+1 queries, blocking I/O, or O(n^2) loops? | ||
| **Test coverage** | ||
| - Do tests exist for the new or changed behavior? | ||
| - Are assertions meaningful (not just checking that no exception is thrown)? | ||
| **Documentation** | ||
| - Are public interfaces documented? | ||
| - Is CHANGELOG updated if behavior changed? | ||
| --- | ||
| ## Step 3 — Review Report | ||
| reviewer produces a structured Review Report with findings in three categories: | ||
| ```markdown | ||
| ## Review Report | ||
| ### CRITICAL | ||
| [Findings that must be fixed before merge. Each finding includes: | ||
| - Location (file:line) | ||
| - Description of the problem | ||
| - Suggested resolution] | ||
| ### WARNING | ||
| [Findings that should be resolved before merge but are not blockers in | ||
| exceptional cases with human approval. Same format as CRITICAL.] | ||
| ### SUGGESTION | ||
| [Optional improvements — style, readability, future-proofing. These do not block | ||
| merge.] | ||
| ### Summary | ||
| - Files reviewed: N | ||
| - Total findings: N (X critical, Y warnings, Z suggestions) | ||
| - Merge recommendation: APPROVED | BLOCKED | ||
| ``` | ||
| --- | ||
| ## Step 4 — Merge decision | ||
| If any CRITICAL findings exist: | ||
| - The Review Report status is **BLOCKED** | ||
| - Report all CRITICAL findings to the human | ||
| - Do not proceed until each CRITICAL finding is resolved | ||
| - After resolution, invoke `/cc:review` again on the same target | ||
| If no CRITICAL findings exist: | ||
| - The Review Report status is **APPROVED** | ||
| - Report any WARNINGs and SUGGESTIONs for human awareness | ||
| - The human makes the final merge decision | ||
| --- | ||
| ## Completion | ||
| Deliver the complete Review Report. Never summarize or omit findings. Every | ||
| finding must include a location and an actionable description. |
| --- | ||
| name: cc-tdd-cycle | ||
| description: >- | ||
| Run a structured Red-Green-Refactor TDD cycle — write a failing test first, | ||
| implement the minimum code to pass it, then refactor with the suite green. | ||
| --- | ||
| # TDD Cycle — Red → Green → Refactor | ||
| Scope: $ARGUMENTS | ||
| Describe what behavior you want to implement. Include: | ||
| - The function, method, or feature to implement | ||
| - The expected behavior (inputs and outputs, or acceptance criteria) | ||
| - Any known constraints or edge cases | ||
| - Relevant files or modules (if known) | ||
| --- | ||
| ## Before you begin — mandatory pre-check | ||
| This command enforces strict TDD discipline. The three phases are sequential and | ||
| non-negotiable: | ||
| 1. **RED** — a failing test exists before any implementation code is written | ||
| 2. **GREEN** — the minimum implementation to make the test pass (no more) | ||
| 3. **REFACTOR** — clean up the code while keeping all tests green | ||
| Do not write implementation code during RED. Do not refactor during GREEN. | ||
| Mixing phases invalidates the cycle. | ||
| --- | ||
| ## Phase 1 — RED (Tester role) | ||
| Adopt the **Tester** role as defined in `CLAUDE.md`. | ||
| ### 1a — Scope clarification | ||
| Before writing any test, confirm: | ||
| - What is the unit of behavior being tested? (function, method, endpoint, domain | ||
| rule) | ||
| - What are the inputs and expected outputs? | ||
| - What are the failure cases? | ||
| If the scope is ambiguous, ask one clarifying question and wait for the answer. | ||
| ### 1b — Write the failing test | ||
| Write a test that: | ||
| - Targets exactly the behavior described in the scope | ||
| - Fails for the right reason (not a compile error, not a missing dependency — | ||
| the logic does not exist yet) | ||
| - Has a name that describes the behavior: `given_X_when_Y_then_Z` or equivalent | ||
| in the project's test naming convention | ||
| - Covers at minimum: one happy path, one edge case, one failure case | ||
| Do not write the implementation. Do not make the test pass by any means other | ||
| than the implementation that will follow in Phase 2. | ||
| ### 1c — Run the test suite and confirm RED | ||
| Run the test suite. The new test must fail. Existing tests must pass. | ||
| If the new test passes without implementation, the test is wrong. Fix the test | ||
| before continuing. | ||
| **RED Phase Report:** | ||
| ``` | ||
| ## RED Phase Report | ||
| **Test file**: [path/to/test/file] | ||
| **Tests written**: | ||
| - [test name] — [what it verifies] | ||
| **Suite result**: [X passing, Y failing] | ||
| **New test status**: FAIL ✓ | ||
| **Failure reason**: [quoted error or assertion message] | ||
| **Existing tests**: [all passing | N failing — list] | ||
| ``` | ||
| **STOP. Show the RED Phase Report. Do not proceed to GREEN without | ||
| confirmation.** | ||
| --- | ||
| ## Phase 2 — GREEN (Implementer role) | ||
| Adopt the **Implementer** role as defined in `CLAUDE.md`. | ||
| ### 2a — Read the failing test before writing any code | ||
| Understand exactly what the test asserts. Write only the code that satisfies | ||
| that assertion. Nothing more. | ||
| ### 2b — Implement the minimum | ||
| Rules for GREEN phase: | ||
| - Write the smallest amount of code that makes the failing test pass | ||
| - Do not add features not tested | ||
| - Do not clean up or restructure existing code — that is Refactor's job | ||
| - Do not add new tests — that is another RED cycle | ||
| - Hardcoding a return value is acceptable if it makes the test pass (the | ||
| Refactor phase will generalize it) | ||
| ### 2c — Run the test suite and confirm GREEN | ||
| Run the test suite. The new test must pass. All previously passing tests must | ||
| still pass. | ||
| If any previously passing test now fails, you introduced a regression. Fix it | ||
| before continuing. | ||
| **GREEN Phase Report:** | ||
| ``` | ||
| ## GREEN Phase Report | ||
| **Files changed**: | ||
| - [path/to/file] — [what was added, one sentence] | ||
| **Implementation approach**: [one sentence — what the code does] | ||
| **Suite result**: [X passing, Y failing] | ||
| **New test status**: PASS ✓ | ||
| **Regressions**: [none | list failing tests] | ||
| ``` | ||
| **STOP. Show the GREEN Phase Report. Do not proceed to REFACTOR without | ||
| confirmation.** | ||
| --- | ||
| ## Phase 3 — REFACTOR (Implementer role, then Reviewer role) | ||
| Adopt the **Implementer** role as defined in `CLAUDE.md`. | ||
| ### 3a — Assess what needs cleaning | ||
| Before touching any code, identify: | ||
| - Duplication introduced during GREEN | ||
| - Names that do not clearly express intent | ||
| - Abstractions that belong in a separate function or module | ||
| - Logic that is hardcoded and should be generalized | ||
| Do not invent improvements. Only address what is directly in the implementation | ||
| written in Phase 2. | ||
| ### 3b — Refactor | ||
| Rules for REFACTOR phase: | ||
| - All tests must remain GREEN throughout — run the suite after each change | ||
| - Do not add new behavior | ||
| - Do not add new tests (if you discover untested behavior, note it for a new RED | ||
| cycle) | ||
| - Do not change function signatures unless the original was clearly wrong | ||
| ### 3c — Run the test suite and confirm GREEN after refactor | ||
| The full suite must pass. If any test fails during refactor, undo the last | ||
| change and investigate. | ||
| ### 3d — Review (Reviewer role) | ||
| Adopt the **Reviewer** role as defined in `CLAUDE.md`. | ||
| Review only the refactored code against these axes: | ||
| | Axis | What to check | | ||
| | ------------- | --------------------------------------------------------------- | | ||
| | Scope | Did the refactor change any behavior? | | ||
| | Correctness | Does the logic still satisfy the original test intent? | | ||
| | Architecture | Does the code follow existing project patterns? | | ||
| | Test coverage | Are all written tests still meaningful (not trivially passing)? | | ||
| Produce a Review Report. CRITICAL findings block completion. | ||
| **REFACTOR Phase Report:** | ||
| ``` | ||
| ## REFACTOR Phase Report | ||
| **Changes made**: | ||
| - [path/to/file] — [what was cleaned up] | ||
| **Suite result**: [X passing, Y failing] | ||
| **Behavioral changes**: none (refactor only) | ||
| ### Review findings | ||
| **CRITICAL**: (none) | [list] | ||
| **WARNING**: (none) | [list] | ||
| **SUGGESTION**: (none) | [list] | ||
| **Verdict**: approved | approved with warnings | blocked | ||
| ``` | ||
| --- | ||
| ## Completion | ||
| The TDD cycle is complete when: | ||
| - RED: at least one failing test was written and confirmed failing | ||
| - GREEN: the minimum implementation makes the test pass | ||
| - REFACTOR: the code is clean, all tests pass, no CRITICAL review findings | ||
| **Final Summary:** | ||
| ``` | ||
| ## TDD Cycle Summary | ||
| **Behavior implemented**: [one sentence] | ||
| **Tests written**: [count] — [list test names] | ||
| **Files changed**: [list] | ||
| **Suite result**: [X passing, Y failing] | ||
| **Cycle status**: complete | blocked (reason) | ||
| ``` | ||
| If the behavior requires additional test cases, start a new `/cc:tdd-cycle` with | ||
| the next scenario. One cycle = one behavior. |
| --- | ||
| name: cc-test-plan | ||
| description: | ||
| Generate a structured test plan for a feature or module — covers unit, | ||
| integration, contract, and edge cases without writing any implementation code. | ||
| --- | ||
| # Test Plan Workflow | ||
| Scope: $ARGUMENTS | ||
| Specify what to plan tests for. Examples: | ||
| - A feature name: `user authentication` | ||
| - A module or file path: `src/orders/OrderService.kt` | ||
| - A Task Card title: `Add paginated product listing endpoint` | ||
| - A PR or branch: `feature/payment-retry` | ||
| If $ARGUMENTS is empty, describe the scope in your next message before invoking | ||
| `tester`. | ||
| --- | ||
| ## Step 1 — Scope confirmation | ||
| Before invoking `tester`, confirm the scope is well-defined. | ||
| A valid scope includes: | ||
| - The behavior or module under test | ||
| - The acceptance criteria or expected behavior (from the Task Card if available) | ||
| - Known edge cases or failure modes | ||
| If the scope is vague (e.g., "test the whole service"), ask one clarifying | ||
| question and wait for the answer. | ||
| --- | ||
| ## Step 2 — Test plan generation (tester) | ||
| Invoke `tester` in planning mode — produce a test plan document, not test code. | ||
| The plan will be used as input when tests are actually written. | ||
| tester must produce a Test Plan covering the following layers: | ||
| **Unit tests** | ||
| - Individual functions or methods in isolation | ||
| - One test per behavior, not per method | ||
| - Input/output contracts, null handling, type coercion | ||
| **Integration tests** | ||
| - Interactions between two or more components | ||
| - Database read/write cycles (if applicable) | ||
| - External service boundaries (mocked or stubbed) | ||
| **Contract tests** | ||
| - API endpoint contracts: request shape, response shape, status codes | ||
| - Event schema contracts (if event-driven components are in scope) | ||
| **Edge cases** | ||
| - Empty inputs, boundary values, max/min limits | ||
| - Concurrent access (if shared state is involved) | ||
| - Failure paths: what happens when a dependency is unavailable | ||
| **Regression cases** | ||
| - Known past bugs that must not recur (include reference if available) | ||
| --- | ||
| ## Step 3 — Test Plan format | ||
| tester produces the plan in this format: | ||
| ```markdown | ||
| ## Test Plan — [Scope Name] | ||
| ### Scope | ||
| [What is being tested and why] | ||
| ### Unit Tests | ||
| | Test ID | Target | Scenario | Expected Result | | ||
| | ------- | ------ | -------- | --------------- | | ||
| | U-001 | ... | ... | ... | | ||
| ### Integration Tests | ||
| | Test ID | Components | Scenario | Expected Result | | ||
| | ------- | ---------- | -------- | --------------- | | ||
| | I-001 | ... | ... | ... | | ||
| ### Contract Tests | ||
| | Test ID | Endpoint/Event | Property | Expected Value | | ||
| | ------- | -------------- | -------- | -------------- | | ||
| | C-001 | ... | ... | ... | | ||
| ### Edge Cases | ||
| | Test ID | Input/Condition | Expected Behavior | | ||
| | ------- | --------------- | ----------------- | | ||
| | E-001 | ... | ... | | ||
| ### Regression Cases | ||
| | Test ID | Reference | Scenario | Must Not Happen | | ||
| | ------- | --------- | -------- | --------------- | | ||
| | R-001 | ... | ... | ... | | ||
| ### Coverage Targets | ||
| - Minimum unit coverage: [%] (or "all acceptance criteria covered") | ||
| - Integration scenarios: [count] | ||
| - Contract validations: [count] | ||
| ### Out of Scope | ||
| [What this test plan explicitly does not cover and why] | ||
| ``` | ||
| --- | ||
| ## Step 4 — Human review | ||
| Show the Test Plan to the human before any tests are written. | ||
| The Test Plan is an artifact for review and approval. Writing test code is a | ||
| separate action — invoke `/cc:feature` or add a test task to the board to | ||
| implement from this plan. | ||
| --- | ||
| ## Completion | ||
| Deliver the complete Test Plan document. Save it as | ||
| `docs/test-plans/[scope-slug].md` if the human requests persistence. | ||
| This command produces a plan, not test files. No production code and no test | ||
| code is written during this command. |
| --- | ||
| name: commit | ||
| description: Genera un commit en inglés siguiendo Conventional Commits basado en los cambios staged | ||
| --- | ||
| {{COMMIT_WORKFLOW}} |
| --- | ||
| name: cc-api-contract | ||
| description: | ||
| Run the API contract workflow for request/response shape changes, | ||
| compatibility constraints, contract tests, documentation, and review. | ||
| --- | ||
| # API Contract Workflow | ||
| API contract request: $ARGUMENTS | ||
| ## Step 1 — Task Card validation (task-coach) | ||
| Invoke `task-coach` with the request above. | ||
| The Task Card must classify the task as `feature` or `refactor` with `high` | ||
| risk unless the human provides a narrower validated risk. It must include: | ||
| - affected endpoint, command, or public interface | ||
| - request and response examples | ||
| - backward compatibility and versioning impact | ||
| - consumers that must remain compatible | ||
| - contract tests and documentation acceptance criteria | ||
| **STOP here. Show the Task Card and wait for human confirmation.** | ||
| --- | ||
| ## Step 2 — Technical Plan (architect) | ||
| Invoke `architect` with the approved Task Card. | ||
| architect must define the API contract, compatibility strategy, validation | ||
| rules, docs/OpenAPI impact, and migration path for consumers. | ||
| **STOP here. Show the Technical Plan and wait for explicit human approval.** | ||
| --- | ||
| ## Step 3 — Implementation (implementer) | ||
| Invoke `implementer` with the approved plan. | ||
| implementer must apply the minimal diff, preserve compatible behavior unless a | ||
| breaking change was explicitly approved, and update only the files named in the | ||
| plan. | ||
| --- | ||
| ## Step 4 — Contract tests (tester) | ||
| Invoke `tester`. | ||
| tester must add or update contract tests covering request shape, response shape, | ||
| status/error behavior, and backward compatibility constraints. | ||
| --- | ||
| ## Step 5 — Review (reviewer) | ||
| Invoke `reviewer`. | ||
| reviewer must block on missing contract tests, undocumented breaking changes, | ||
| or docs/OpenAPI drift. | ||
| --- | ||
| ## Completion | ||
| Report the final Task Card, Technical Plan, implementation summary, test report, | ||
| review report, docs updated, compatibility impact, and residual risks. |
| --- | ||
| name: cc-db-migration | ||
| description: | ||
| Run the database migration workflow for schema/data changes, operational | ||
| sequencing, tests, and review. | ||
| --- | ||
| # Database Migration Workflow | ||
| Migration request: $ARGUMENTS | ||
| ## Step 1 — Task Card validation (task-coach) | ||
| Invoke `task-coach` with the request above. | ||
| The Task Card must classify the task as `high` risk and include: | ||
| - tables, collections, models, or migration files in scope | ||
| - data backfill or data cleanup requirements | ||
| - deployment ordering and compatibility window | ||
| - rollback or forward-fix strategy | ||
| - lock risk, data risk, and verification commands | ||
| **STOP here. Show the Task Card and wait for human confirmation.** | ||
| --- | ||
| ## Step 2 — Migration Plan (architect) | ||
| Invoke `architect` with the approved Task Card. | ||
| architect must define the schema/data plan, operational sequencing, | ||
| compatibility strategy, rollback/forward-fix notes, and test approach. | ||
| **STOP here. Show the Technical Plan and wait for explicit human approval.** | ||
| --- | ||
| ## Step 3 — Implementation (implementer) | ||
| Invoke `implementer` with the approved plan. | ||
| implementer must keep model and migration changes together, avoid unrelated | ||
| refactors, and preserve the deployment order specified by architect. | ||
| --- | ||
| ## Step 4 — Migration tests (tester) | ||
| Invoke `tester`. | ||
| tester must cover migration-sensitive behavior where the stack supports it, | ||
| including happy path, existing-data edge cases, and rollback/forward-fix notes | ||
| when automated rollback tests are not practical. | ||
| --- | ||
| ## Step 5 — Review (reviewer) | ||
| Invoke `reviewer`. | ||
| reviewer must block on missing migration tests, missing data-risk notes, | ||
| undocumented deployment sequencing, or model/migration drift. | ||
| --- | ||
| ## Completion | ||
| Report migration files changed, model files changed, tests run, lock risk, data | ||
| risk, operational sequencing, rollback/forward-fix notes, and residual risk. |
| --- | ||
| name: cc-feature | ||
| description: | ||
| Run the full feature workflow — task validation, technical design, | ||
| implementation, testing, review, and documentation. | ||
| --- | ||
| # Feature Workflow | ||
| Feature request: $ARGUMENTS | ||
| ## Step 1 — Task Card validation (task-coach) | ||
| Invoke `task-coach` with the feature description above. | ||
| task-coach must produce a complete Task Card before any other agent runs. The | ||
| Task Card is ready when it contains: title, type, risk classification, scope, | ||
| context, acceptance criteria, and constraints. | ||
| If any field is missing or ambiguous, task-coach must ask one clarifying | ||
| question at a time and wait for the answer. Do not proceed with an incomplete | ||
| Task Card. | ||
| **STOP here. Show the completed Task Card and wait for human confirmation before | ||
| continuing.** | ||
| --- | ||
| ## Step 2 — Technical Plan (architect) | ||
| Invoke `architect` with the validated Task Card from Step 1. | ||
| architect must produce a Technical Plan that covers: | ||
| - Chosen approach and rationale | ||
| - Affected files and modules | ||
| - Data model changes (if any) | ||
| - API contract changes (if any) | ||
| - Identified risks and mitigations | ||
| - Open questions that require a human decision | ||
| **STOP here. Show the Technical Plan and wait for explicit human approval. Do | ||
| not invoke implementer until the plan is approved.** | ||
| --- | ||
| ## Step 3 — Implementation (implementer) | ||
| Invoke `implementer` with the approved Technical Plan and the Task Card. | ||
| Implementer creates a Git Worktree before touching any file; all edits happen inside it. | ||
| implementer must: | ||
| 1. Read the Technical Plan before touching any file | ||
| 2. Apply the minimal diff — only what the plan specifies | ||
| 3. Run the project test suite after implementation | ||
| 4. Produce an Implementation Summary: what changed, which files, how to verify | ||
| locally | ||
| --- | ||
| ## Step 4 — Test coverage (tester) | ||
| Invoke `tester` with the Implementation Summary and the Task Card. | ||
| tester must: | ||
| 1. Write or extend tests to cover the new behavior | ||
| 2. Ensure all acceptance criteria from the Task Card have at least one test | ||
| 3. Run the full test suite and confirm it passes | ||
| 4. Produce a Coverage Summary: test files added or modified, cases covered | ||
| --- | ||
| ## Step 5 — Code review (reviewer) | ||
| Invoke `reviewer` with the complete diff and the Task Card. | ||
| reviewer must produce a Review Report with findings categorized as: | ||
| - CRITICAL — must be fixed before merge | ||
| - WARNING — must be resolved before merge | ||
| - SUGGESTION — optional improvement | ||
| If any CRITICAL findings exist, **STOP and report them**. Do not proceed until | ||
| they are resolved and re-reviewed. | ||
| --- | ||
| ## Step 6 — Documentation (docs) | ||
| Invoke `docs` only if any of the following changed: | ||
| - A public API endpoint was added or modified | ||
| - A public interface or module was introduced | ||
| - Behavior visible to end users changed | ||
| docs must update: README (if applicable), OpenAPI spec (if applicable), | ||
| CHANGELOG (always), ADR (if an architectural decision was made). | ||
| --- | ||
| ## Completion | ||
| Report the following to the human: | ||
| - Task Card (final) | ||
| - Technical Plan (approved) | ||
| - Implementation Summary | ||
| - Coverage Summary | ||
| - Review Report (all findings resolved) | ||
| - List of documentation files updated (if any) | ||
| The feature is complete only when: all tests pass, no CRITICAL review findings | ||
| remain, and documentation reflects the implemented behavior. |
| --- | ||
| name: cc-fix | ||
| description: | ||
| Run the bug fix workflow — risk-based routing through task validation, | ||
| implementation, testing, and optional review. | ||
| --- | ||
| # Bug Fix Workflow | ||
| Bug description: $ARGUMENTS | ||
| Provide the following information in $ARGUMENTS: | ||
| - What is the incorrect behavior (actual) | ||
| - What is the expected behavior | ||
| - Steps to reproduce | ||
| - Environment or version where the bug occurs (if known) | ||
| - Any relevant error messages or stack traces | ||
| --- | ||
| ## Step 1 — Task Card validation (task-coach) | ||
| Invoke `task-coach` with the bug description above. | ||
| task-coach must produce a Task Card that includes: | ||
| - A clear statement of actual vs. expected behavior | ||
| - Reproduction steps (or a note that they are unknown) | ||
| - Risk classification: `low`, `medium`, or `high` | ||
| - Scope: which files or modules are likely affected | ||
| If reproduction steps are missing, task-coach must ask for them before | ||
| classifying risk. A bug without a reproduction path cannot be classified | ||
| reliably. | ||
| **STOP here. Show the Task Card and wait for human confirmation.** | ||
| --- | ||
| ## Step 2 — Route by risk | ||
| Read the risk field from the Task Card and follow the corresponding route. | ||
| ### Low-risk route | ||
| Applies when: the bug is isolated to a single component, existing tests cover | ||
| the affected code, and no public API or shared state is involved. | ||
| Route: `task-coach` → `implementer` → `tester` | ||
| Proceed directly to Step 3a. | ||
| ### Medium or high-risk route | ||
| Applies when: the bug touches shared state, a public API, auth or payment paths, | ||
| database writes, or the root cause is not yet understood. | ||
| Route: `task-coach` → `architect` → `implementer` → `tester` → `reviewer` | ||
| Invoke `architect` before implementation. architect must: | ||
| - Identify the root cause (or document that it is unknown) | ||
| - Define the fix approach and affected files | ||
| - Flag any regression risk to adjacent components | ||
| - Produce a Technical Plan | ||
| **STOP here if high-risk. Show the Technical Plan and wait for human approval | ||
| before continuing.** | ||
| --- | ||
| ## Step 3a — Implementation, low-risk (implementer) | ||
| Invoke `implementer` with the Task Card. | ||
| Implementer creates a Git Worktree before touching any file; all edits happen inside it. | ||
| implementer must: | ||
| 1. Locate the defect using the reproduction steps | ||
| 2. Apply the minimal fix — no unrelated changes | ||
| 3. Run the test suite | ||
| 4. Produce an Implementation Summary: root cause, fix applied, files changed | ||
| --- | ||
| ## Step 3b — Implementation, medium/high-risk (implementer) | ||
| Invoke `implementer` with the approved Technical Plan and the Task Card. | ||
| Implementer creates a Git Worktree before touching any file; all edits happen inside it. | ||
| implementer must follow the plan exactly. Any deviation requires a new Technical | ||
| Plan approval. After implementation, run the full test suite. | ||
| --- | ||
| ## Step 4 — Regression tests (tester) | ||
| Invoke `tester` for all risk levels. | ||
| tester must: | ||
| 1. Write a regression test that reproduces the original bug (fails before the | ||
| fix, passes after) | ||
| 2. Verify that existing tests still pass | ||
| 3. Produce a Coverage Summary: test added, case covered | ||
| --- | ||
| ## Step 5 — Review (reviewer) — medium/high-risk only | ||
| Invoke `reviewer` with the diff and Task Card. | ||
| reviewer produces a Review Report with CRITICAL / WARNING / SUGGESTION findings. | ||
| If any CRITICAL findings exist, **STOP**. Do not close the fix until they are | ||
| resolved. | ||
| --- | ||
| ## Completion | ||
| Report: Task Card, Implementation Summary, regression test added, Review Report | ||
| (if applicable). The fix is complete only when: the regression test passes, the | ||
| full suite passes, and no CRITICAL review findings remain. |
| --- | ||
| name: cc-pagespeed | ||
| description: >- | ||
| Run the PageSpeed performance audit — 80/20 analysis of Core Web Vitals using | ||
| the PageSpeed Insights API. | ||
| --- | ||
| # PageSpeed Performance Audit | ||
| Audit URL: $ARGUMENTS | ||
| --- | ||
| ## Step 1 — Pre-flight (pagespeed-perf skill) | ||
| Invoke `pagespeed-perf` skill. | ||
| Read `PAGESPEED_API_KEY` from the environment. Compute the output filename: | ||
| `{YYYY-MM-DD}_pagespeed-{hostname}-claude.md`. | ||
| Log whether the API key was found. Proceed regardless — lab data is available | ||
| without a key, but CrUX field data requires it. | ||
| --- | ||
| ## Step 2 — Collect | ||
| Call the PageSpeed Insights API for the URL provided above. | ||
| - Strategy: `both` (mobile + desktop) unless the user specified otherwise. | ||
| - If Bun is available, use `~/.claude/skills/pagespeed-perf/scripts/run.ts`. | ||
| - If Bun is unavailable, call PSI directly via WebFetch and fetch the HTML | ||
| source for manual resource-hint analysis. | ||
| --- | ||
| ## Step 3 — Analyze | ||
| Extract from the PSI response: | ||
| - Core Web Vitals: LCP, INP, CLS, FCP, TBT, TTFB | ||
| - LCP element (type, selector, HTML snippet) | ||
| - Third-party scripts ordered by blocking time | ||
| - Render-blocking resources | ||
| - Unused JavaScript and CSS (savings in bytes and ms) | ||
| From the HTML source: | ||
| - Resource hints (`<link rel="preload|preconnect|prefetch">`) | ||
| - Images: lazy loading, `fetchpriority`, format, dimensions | ||
| - Fonts: `font-display`, preloaded subsets | ||
| - Blocking scripts in `<head>` (no `async`/`defer`) | ||
| --- | ||
| ## Step 4 — Prioritize | ||
| Score each identified optimization using the 80/20 matrix: | ||
| `Score = Impact × Ease` (each 1–5, max 25). | ||
| Order findings by descending score. Mark optimizations with Score ≥ 20 as | ||
| **Critical 20%**. | ||
| --- | ||
| ## Step 5 — Report | ||
| Write the full performance report to | ||
| `{YYYY-MM-DD}_pagespeed-{hostname}-claude.md` in the current directory. | ||
| Required sections: | ||
| 1. Resumen Ejecutivo (2–3 paragraphs) | ||
| 2. Métricas Actuales (lab vs field table) | ||
| 3. Recursos con Mayor Impacto | ||
| 4. Plan de Acción Priorizado (80/20 table) | ||
| 5. Solución Técnica Detallada (per finding: problem, evidence, code, expected gain) | ||
| 6. Quick Wins / High Impact Changes / Roadmap | ||
| End every report with: | ||
| ``` | ||
| --- | ||
| *Informe generado el {YYYY-MM-DD} · Herramienta: Claude Code + pagespeed-perf skill* | ||
| *API Key usada: {Sí / No} · Datos CrUX: {Disponibles / No disponibles}* | ||
| ``` | ||
| --- | ||
| ## Requirements | ||
| **`PAGESPEED_API_KEY`** — Optional but strongly recommended. | ||
| - With key: real CrUX field data + 25,000 requests/day quota. | ||
| - Without key: lab data only (Lighthouse); shared rate limit applies. | ||
| Set in your shell: | ||
| ```powershell | ||
| $env:PAGESPEED_API_KEY = "your-api-key" # Windows PowerShell | ||
| export PAGESPEED_API_KEY="your-api-key" # macOS / Linux | ||
| ``` | ||
| Get a free key: <https://developers.google.com/speed/docs/insights/v5/get-started> |
| --- | ||
| name: cc-refactor | ||
| description: | ||
| Run the refactor workflow — mandatory architectural justification, test | ||
| verification, risk-based implementation, and scope enforcement. | ||
| --- | ||
| # Refactor Workflow | ||
| Refactor description: $ARGUMENTS | ||
| Describe what you want to refactor and why. Include: | ||
| - The current structure or pattern being changed | ||
| - The target structure or pattern | ||
| - The motivation (performance, readability, architectural alignment, etc.) | ||
| - Known risk areas or dependencies | ||
| --- | ||
| ## Prerequisite — Test coverage check | ||
| Before any agent is invoked, verify that the code being refactored has adequate | ||
| test coverage. | ||
| A refactor without tests is not a refactor — it is a rewrite with unknown | ||
| behavioral consequences. | ||
| If coverage is insufficient: | ||
| 1. **STOP**. Report the coverage gap to the human. | ||
| 2. Suggest invoking `/cc:test-plan` first to establish coverage. | ||
| 3. Do not proceed with the refactor until coverage is confirmed. | ||
| --- | ||
| ## Step 1 — Architectural justification (architect) | ||
| Always invoke `architect` first, regardless of risk level. A refactor without a | ||
| written justification is scope creep in disguise. | ||
| architect must produce a Refactor Plan that includes: | ||
| - Statement of the problem with the current structure | ||
| - Proposed target structure and rationale | ||
| - Affected files and module boundaries | ||
| - Risk level: `low`, `medium`, or `high` | ||
| - Behavioral invariants that must not change | ||
| - Open questions requiring human input | ||
| **Scope creep warning:** If during planning architect identifies unrelated | ||
| improvements, they must be listed separately as "Out of scope." They are not | ||
| part of this refactor. | ||
| **STOP here. Show the Refactor Plan and wait for explicit human approval. Do not | ||
| proceed without written approval of the plan.** | ||
| --- | ||
| ## Step 2 — Route by risk | ||
| Read the risk field from the Refactor Plan and follow the corresponding route. | ||
| ### Low-risk route | ||
| Applies when: the refactor is purely internal, no public interfaces change, full | ||
| test coverage exists for the affected code, and behavioral impact is isolated to | ||
| the refactored module. | ||
| Route: `architect` (done) → `implementer` | ||
| Proceed to Step 3a. | ||
| ### Medium or high-risk route | ||
| Applies when: module boundaries change, shared interfaces are affected, | ||
| performance characteristics may change, or the refactor touches more than two | ||
| files with behavioral impact. | ||
| Route: `architect` (done) → `implementer` → `reviewer` | ||
| Proceed to Step 3b. | ||
| --- | ||
| ## Step 3a — Implementation, low-risk (implementer) | ||
| Invoke `implementer` with the approved Refactor Plan. | ||
| Implementer creates a Git Worktree before touching any file; all edits happen inside it. | ||
| implementer must: | ||
| 1. Read the Refactor Plan before opening any file | ||
| 2. Apply only the changes specified in the plan | ||
| 3. Run the full test suite before and after — both runs must pass | ||
| 4. Produce an Implementation Summary: what changed, what did not change, test | ||
| results before and after | ||
| Any deviation from the plan — including "obvious improvements" encountered | ||
| during implementation — must be flagged and held for a separate task. | ||
| --- | ||
| ## Step 3b — Implementation, medium/high-risk (implementer) | ||
| Same rules as 3a. Additionally: | ||
| - implementer must document any unexpected complexity discovered during | ||
| implementation and pause if the complexity changes the risk assessment | ||
| - If new risks are found, **STOP** and report to the human before continuing | ||
| --- | ||
| ## Step 4 — Test suite verification | ||
| For all risk levels, confirm: | ||
| - All tests that existed before the refactor still pass | ||
| - No test was deleted or commented out to make the suite pass | ||
| - Behavior documented in the Task Card remains unchanged | ||
| If any test fails that was passing before, the refactor has introduced a | ||
| regression. **STOP and report.** | ||
| --- | ||
| ## Step 5 — Code review (reviewer) — medium/high-risk only | ||
| Invoke `reviewer` with the diff and Refactor Plan. | ||
| reviewer must verify: | ||
| - The implementation matches the approved plan | ||
| - No behavior was changed beyond the plan's scope | ||
| - No unrelated files were modified | ||
| Review Report must include CRITICAL / WARNING / SUGGESTION findings. CRITICAL | ||
| findings block completion. | ||
| --- | ||
| ## Completion | ||
| Report: Refactor Plan (approved), Implementation Summary, test results before | ||
| and after, Review Report (if applicable). | ||
| The refactor is complete only when: all pre-existing tests still pass, the | ||
| implementation matches the approved plan exactly, and no CRITICAL review | ||
| findings remain. |
| --- | ||
| name: cc-review | ||
| description: | ||
| Run a structured code review — produces a Review Report with CRITICAL, | ||
| WARNING, and SUGGESTION findings; CRITICAL findings block merge. | ||
| --- | ||
| # Code Review Workflow | ||
| Review target: $ARGUMENTS | ||
| Specify what to review. Accepted formats: | ||
| - A branch name: `feature/my-branch` | ||
| - A file or set of files: `src/api/UserController.kt` | ||
| - A pull request reference: `PR #42` | ||
| - Empty — defaults to the current working diff (`git diff`) | ||
| --- | ||
| ## Step 1 — Diff collection | ||
| Before invoking `reviewer`, collect the diff for the specified target. | ||
| If $ARGUMENTS is empty or not provided: | ||
| - Use `git diff HEAD` as the review target | ||
| If $ARGUMENTS is a branch name: | ||
| - Use `git diff main...$ARGUMENTS` (or `develop` if main is not the base) | ||
| If $ARGUMENTS is a PR reference: | ||
| - Retrieve the PR diff and the PR description for context | ||
| If $ARGUMENTS is a file path: | ||
| - Use `git diff HEAD -- $ARGUMENTS` | ||
| Show the diff summary (files changed, lines added/removed) before invoking | ||
| reviewer. | ||
| --- | ||
| ## Step 2 — Code review (reviewer) | ||
| Invoke `reviewer` with: | ||
| - The full diff | ||
| - The Task Card or PR description (if available) | ||
| - The target specification from $ARGUMENTS | ||
| reviewer must evaluate the diff against the following checklist: | ||
| **Correctness** | ||
| - Does the implementation match the stated intent? | ||
| - Are there logic errors, off-by-one errors, or unhandled edge cases? | ||
| **Architecture alignment** | ||
| - Does the change follow existing module boundaries? | ||
| - Does it introduce unplanned coupling or layering violations? | ||
| **Security** | ||
| - Are inputs validated before use? | ||
| - Is there any credential, token, or secret in the diff? | ||
| - Are there SQL injection, XSS, or injection risks? | ||
| **Performance** | ||
| - Does the change introduce N+1 queries, blocking I/O, or O(n^2) loops? | ||
| **Test coverage** | ||
| - Do tests exist for the new or changed behavior? | ||
| - Are assertions meaningful (not just checking that no exception is thrown)? | ||
| **Documentation** | ||
| - Are public interfaces documented? | ||
| - Is CHANGELOG updated if behavior changed? | ||
| --- | ||
| ## Step 3 — Review Report | ||
| reviewer produces a structured Review Report with findings in three categories: | ||
| ```markdown | ||
| ## Review Report | ||
| ### CRITICAL | ||
| [Findings that must be fixed before merge. Each finding includes: | ||
| - Location (file:line) | ||
| - Description of the problem | ||
| - Suggested resolution] | ||
| ### WARNING | ||
| [Findings that should be resolved before merge but are not blockers in | ||
| exceptional cases with human approval. Same format as CRITICAL.] | ||
| ### SUGGESTION | ||
| [Optional improvements — style, readability, future-proofing. These do not block | ||
| merge.] | ||
| ### Summary | ||
| - Files reviewed: N | ||
| - Total findings: N (X critical, Y warnings, Z suggestions) | ||
| - Merge recommendation: APPROVED | BLOCKED | ||
| ``` | ||
| --- | ||
| ## Step 4 — Merge decision | ||
| If any CRITICAL findings exist: | ||
| - The Review Report status is **BLOCKED** | ||
| - Report all CRITICAL findings to the human | ||
| - Do not proceed until each CRITICAL finding is resolved | ||
| - After resolution, invoke `/cc:review` again on the same target | ||
| If no CRITICAL findings exist: | ||
| - The Review Report status is **APPROVED** | ||
| - Report any WARNINGs and SUGGESTIONs for human awareness | ||
| - The human makes the final merge decision | ||
| --- | ||
| ## Completion | ||
| Deliver the complete Review Report. Never summarize or omit findings. Every | ||
| finding must include a location and an actionable description. |
| --- | ||
| name: cc-tdd-cycle | ||
| description: >- | ||
| Run a structured Red-Green-Refactor TDD cycle — write a failing test first, | ||
| implement the minimum code to pass it, then refactor with the suite green. | ||
| --- | ||
| # TDD Cycle — Red → Green → Refactor | ||
| Scope: $ARGUMENTS | ||
| Describe what behavior you want to implement. Include: | ||
| - The function, method, or feature to implement | ||
| - The expected behavior (inputs and outputs, or acceptance criteria) | ||
| - Any known constraints or edge cases | ||
| - Relevant files or modules (if known) | ||
| --- | ||
| ## Before you begin — mandatory pre-check | ||
| This command enforces strict TDD discipline. The three phases are sequential and | ||
| non-negotiable: | ||
| 1. **RED** — a failing test exists before any implementation code is written | ||
| 2. **GREEN** — the minimum implementation to make the test pass (no more) | ||
| 3. **REFACTOR** — clean up the code while keeping all tests green | ||
| Do not write implementation code during RED. Do not refactor during GREEN. | ||
| Mixing phases invalidates the cycle. | ||
| --- | ||
| ## Phase 1 — RED (Tester role) | ||
| Adopt the **Tester** role as defined in `CLAUDE.md`. | ||
| ### 1a — Scope clarification | ||
| Before writing any test, confirm: | ||
| - What is the unit of behavior being tested? (function, method, endpoint, domain | ||
| rule) | ||
| - What are the inputs and expected outputs? | ||
| - What are the failure cases? | ||
| If the scope is ambiguous, ask one clarifying question and wait for the answer. | ||
| ### 1b — Write the failing test | ||
| Write a test that: | ||
| - Targets exactly the behavior described in the scope | ||
| - Fails for the right reason (not a compile error, not a missing dependency — | ||
| the logic does not exist yet) | ||
| - Has a name that describes the behavior: `given_X_when_Y_then_Z` or equivalent | ||
| in the project's test naming convention | ||
| - Covers at minimum: one happy path, one edge case, one failure case | ||
| Do not write the implementation. Do not make the test pass by any means other | ||
| than the implementation that will follow in Phase 2. | ||
| ### 1c — Run the test suite and confirm RED | ||
| Run the test suite. The new test must fail. Existing tests must pass. | ||
| If the new test passes without implementation, the test is wrong. Fix the test | ||
| before continuing. | ||
| **RED Phase Report:** | ||
| ``` | ||
| ## RED Phase Report | ||
| **Test file**: [path/to/test/file] | ||
| **Tests written**: | ||
| - [test name] — [what it verifies] | ||
| **Suite result**: [X passing, Y failing] | ||
| **New test status**: FAIL ✓ | ||
| **Failure reason**: [quoted error or assertion message] | ||
| **Existing tests**: [all passing | N failing — list] | ||
| ``` | ||
| **STOP. Show the RED Phase Report. Do not proceed to GREEN without | ||
| confirmation.** | ||
| --- | ||
| ## Phase 2 — GREEN (Implementer role) | ||
| Adopt the **Implementer** role as defined in `CLAUDE.md`. | ||
| ### 2a — Read the failing test before writing any code | ||
| Understand exactly what the test asserts. Write only the code that satisfies | ||
| that assertion. Nothing more. | ||
| ### 2b — Implement the minimum | ||
| Rules for GREEN phase: | ||
| - Write the smallest amount of code that makes the failing test pass | ||
| - Do not add features not tested | ||
| - Do not clean up or restructure existing code — that is Refactor's job | ||
| - Do not add new tests — that is another RED cycle | ||
| - Hardcoding a return value is acceptable if it makes the test pass (the | ||
| Refactor phase will generalize it) | ||
| ### 2c — Run the test suite and confirm GREEN | ||
| Run the test suite. The new test must pass. All previously passing tests must | ||
| still pass. | ||
| If any previously passing test now fails, you introduced a regression. Fix it | ||
| before continuing. | ||
| **GREEN Phase Report:** | ||
| ``` | ||
| ## GREEN Phase Report | ||
| **Files changed**: | ||
| - [path/to/file] — [what was added, one sentence] | ||
| **Implementation approach**: [one sentence — what the code does] | ||
| **Suite result**: [X passing, Y failing] | ||
| **New test status**: PASS ✓ | ||
| **Regressions**: [none | list failing tests] | ||
| ``` | ||
| **STOP. Show the GREEN Phase Report. Do not proceed to REFACTOR without | ||
| confirmation.** | ||
| --- | ||
| ## Phase 3 — REFACTOR (Implementer role, then Reviewer role) | ||
| Adopt the **Implementer** role as defined in `CLAUDE.md`. | ||
| ### 3a — Assess what needs cleaning | ||
| Before touching any code, identify: | ||
| - Duplication introduced during GREEN | ||
| - Names that do not clearly express intent | ||
| - Abstractions that belong in a separate function or module | ||
| - Logic that is hardcoded and should be generalized | ||
| Do not invent improvements. Only address what is directly in the implementation | ||
| written in Phase 2. | ||
| ### 3b — Refactor | ||
| Rules for REFACTOR phase: | ||
| - All tests must remain GREEN throughout — run the suite after each change | ||
| - Do not add new behavior | ||
| - Do not add new tests (if you discover untested behavior, note it for a new RED | ||
| cycle) | ||
| - Do not change function signatures unless the original was clearly wrong | ||
| ### 3c — Run the test suite and confirm GREEN after refactor | ||
| The full suite must pass. If any test fails during refactor, undo the last | ||
| change and investigate. | ||
| ### 3d — Review (Reviewer role) | ||
| Adopt the **Reviewer** role as defined in `CLAUDE.md`. | ||
| Review only the refactored code against these axes: | ||
| | Axis | What to check | | ||
| | ------------- | --------------------------------------------------------------- | | ||
| | Scope | Did the refactor change any behavior? | | ||
| | Correctness | Does the logic still satisfy the original test intent? | | ||
| | Architecture | Does the code follow existing project patterns? | | ||
| | Test coverage | Are all written tests still meaningful (not trivially passing)? | | ||
| Produce a Review Report. CRITICAL findings block completion. | ||
| **REFACTOR Phase Report:** | ||
| ``` | ||
| ## REFACTOR Phase Report | ||
| **Changes made**: | ||
| - [path/to/file] — [what was cleaned up] | ||
| **Suite result**: [X passing, Y failing] | ||
| **Behavioral changes**: none (refactor only) | ||
| ### Review findings | ||
| **CRITICAL**: (none) | [list] | ||
| **WARNING**: (none) | [list] | ||
| **SUGGESTION**: (none) | [list] | ||
| **Verdict**: approved | approved with warnings | blocked | ||
| ``` | ||
| --- | ||
| ## Completion | ||
| The TDD cycle is complete when: | ||
| - RED: at least one failing test was written and confirmed failing | ||
| - GREEN: the minimum implementation makes the test pass | ||
| - REFACTOR: the code is clean, all tests pass, no CRITICAL review findings | ||
| **Final Summary:** | ||
| ``` | ||
| ## TDD Cycle Summary | ||
| **Behavior implemented**: [one sentence] | ||
| **Tests written**: [count] — [list test names] | ||
| **Files changed**: [list] | ||
| **Suite result**: [X passing, Y failing] | ||
| **Cycle status**: complete | blocked (reason) | ||
| ``` | ||
| If the behavior requires additional test cases, start a new `/cc:tdd-cycle` with | ||
| the next scenario. One cycle = one behavior. |
| --- | ||
| name: cc-test-plan | ||
| description: | ||
| Generate a structured test plan for a feature or module — covers unit, | ||
| integration, contract, and edge cases without writing any implementation code. | ||
| --- | ||
| # Test Plan Workflow | ||
| Scope: $ARGUMENTS | ||
| Specify what to plan tests for. Examples: | ||
| - A feature name: `user authentication` | ||
| - A module or file path: `src/orders/OrderService.kt` | ||
| - A Task Card title: `Add paginated product listing endpoint` | ||
| - A PR or branch: `feature/payment-retry` | ||
| If $ARGUMENTS is empty, describe the scope in your next message before invoking | ||
| `tester`. | ||
| --- | ||
| ## Step 1 — Scope confirmation | ||
| Before invoking `tester`, confirm the scope is well-defined. | ||
| A valid scope includes: | ||
| - The behavior or module under test | ||
| - The acceptance criteria or expected behavior (from the Task Card if available) | ||
| - Known edge cases or failure modes | ||
| If the scope is vague (e.g., "test the whole service"), ask one clarifying | ||
| question and wait for the answer. | ||
| --- | ||
| ## Step 2 — Test plan generation (tester) | ||
| Invoke `tester` in planning mode — produce a test plan document, not test code. | ||
| The plan will be used as input when tests are actually written. | ||
| tester must produce a Test Plan covering the following layers: | ||
| **Unit tests** | ||
| - Individual functions or methods in isolation | ||
| - One test per behavior, not per method | ||
| - Input/output contracts, null handling, type coercion | ||
| **Integration tests** | ||
| - Interactions between two or more components | ||
| - Database read/write cycles (if applicable) | ||
| - External service boundaries (mocked or stubbed) | ||
| **Contract tests** | ||
| - API endpoint contracts: request shape, response shape, status codes | ||
| - Event schema contracts (if event-driven components are in scope) | ||
| **Edge cases** | ||
| - Empty inputs, boundary values, max/min limits | ||
| - Concurrent access (if shared state is involved) | ||
| - Failure paths: what happens when a dependency is unavailable | ||
| **Regression cases** | ||
| - Known past bugs that must not recur (include reference if available) | ||
| --- | ||
| ## Step 3 — Test Plan format | ||
| tester produces the plan in this format: | ||
| ```markdown | ||
| ## Test Plan — [Scope Name] | ||
| ### Scope | ||
| [What is being tested and why] | ||
| ### Unit Tests | ||
| | Test ID | Target | Scenario | Expected Result | | ||
| | ------- | ------ | -------- | --------------- | | ||
| | U-001 | ... | ... | ... | | ||
| ### Integration Tests | ||
| | Test ID | Components | Scenario | Expected Result | | ||
| | ------- | ---------- | -------- | --------------- | | ||
| | I-001 | ... | ... | ... | | ||
| ### Contract Tests | ||
| | Test ID | Endpoint/Event | Property | Expected Value | | ||
| | ------- | -------------- | -------- | -------------- | | ||
| | C-001 | ... | ... | ... | | ||
| ### Edge Cases | ||
| | Test ID | Input/Condition | Expected Behavior | | ||
| | ------- | --------------- | ----------------- | | ||
| | E-001 | ... | ... | | ||
| ### Regression Cases | ||
| | Test ID | Reference | Scenario | Must Not Happen | | ||
| | ------- | --------- | -------- | --------------- | | ||
| | R-001 | ... | ... | ... | | ||
| ### Coverage Targets | ||
| - Minimum unit coverage: [%] (or "all acceptance criteria covered") | ||
| - Integration scenarios: [count] | ||
| - Contract validations: [count] | ||
| ### Out of Scope | ||
| [What this test plan explicitly does not cover and why] | ||
| ``` | ||
| --- | ||
| ## Step 4 — Human review | ||
| Show the Test Plan to the human before any tests are written. | ||
| The Test Plan is an artifact for review and approval. Writing test code is a | ||
| separate action — invoke `/cc:feature` or add a test task to the board to | ||
| implement from this plan. | ||
| --- | ||
| ## Completion | ||
| Deliver the complete Test Plan document. Save it as | ||
| `docs/test-plans/[scope-slug].md` if the human requests persistence. | ||
| This command produces a plan, not test files. No production code and no test | ||
| code is written during this command. |
| {{COMMIT_WORKFLOW}} |
| { | ||
| "autoConnectIde": true, | ||
| "autoInstallIdeExtension": false, | ||
| "externalEditorContext": true, | ||
| "teammateDefaultModel": "sonnet" | ||
| } |
| # PageSpeed Performance Audit | ||
| Audit web performance using the PageSpeed Insights API. Applies the 80/20 | ||
| principle: identify the 20% of changes that produce 80% of the performance gain. | ||
| Produces a prioritized report in the current working directory. | ||
| ## Usage | ||
| ``` | ||
| /cc-pagespeed --url <url> [--strategy mobile|desktop|both] | ||
| ``` | ||
| ## Parameters | ||
| | Parameter | Required | Description | | ||
| | ------------- | -------- | -------------------------------------------------------------- | | ||
| | `--url` | Yes | Full URL to audit (must include scheme: https://...) | | ||
| | `--strategy` | No | Analysis strategy: `mobile`, `desktop`, or `both` (default: `both`) | | ||
| ## Requirements | ||
| ### `PAGESPEED_API_KEY` — Optional but strongly recommended | ||
| | Mode | Lab data | CrUX field data | Rate limits | | ||
| | ------------ | -------- | --------------- | ---------------- | | ||
| | **With key** | ✅ | ✅ (real users) | 25,000 req/day | | ||
| | **Without** | ✅ | ❌ | ~2 req/s shared | | ||
| Without the key, Core Web Vitals field data (real user experience via CrUX) is | ||
| unavailable. Lab data from Lighthouse still runs. | ||
| Set the key before invoking the command: | ||
| ```powershell | ||
| # Windows PowerShell | ||
| $env:PAGESPEED_API_KEY = "your-api-key" | ||
| # macOS / Linux | ||
| export PAGESPEED_API_KEY="your-api-key" | ||
| ``` | ||
| Get a free key (Google account required): | ||
| <https://developers.google.com/speed/docs/insights/v5/get-started> | ||
| ## Workflow | ||
| When `/cc-pagespeed` is invoked, load the `pagespeed-perf` skill and execute | ||
| the following steps in order: | ||
| 1. **Pre-flight** — Read `$env:PAGESPEED_API_KEY` from the environment. Compute | ||
| the output filename: `{YYYY-MM-DD}_pagespeed-{hostname}-claude.md`. | ||
| 2. **Collect** — Call the PageSpeed Insights API for the requested strategy | ||
| (`mobile`, `desktop`, or `both`). Prefer the Bun scripts in | ||
| `~/.claude/skills/pagespeed-perf/scripts/run.ts` if Bun is available. | ||
| Otherwise, use `WebFetch` to call the PSI endpoint directly. | ||
| 3. **Analyze** — Extract Core Web Vitals (LCP, INP, CLS, FCP, TTFB, TBT), | ||
| identify the LCP element, enumerate third-party scripts by blocking time, | ||
| and inspect resource hints in the HTML `<head>`. | ||
| 4. **Prioritize** — Score each identified optimization using the 80/20 matrix: | ||
| `Impact × Ease` (each 1–5). Order findings by descending score. Highlight | ||
| the top actions with Score ≥ 20 as the critical 20%. | ||
| 5. **Report** — Write the structured markdown report to | ||
| `{YYYY-MM-DD}_pagespeed-{hostname}-claude.md` in the current directory. | ||
| ## Output File | ||
| The report is saved as `{YYYY-MM-DD}_pagespeed-{hostname}-claude.md`. | ||
| - Hostname characters outside `[a-zA-Z0-9]` are replaced with `-`. | ||
| - Example: `https://www.example.com` → `2026-06-07_pagespeed-www-example-com-claude.md` | ||
| ## Skills Loaded | ||
| - `pagespeed-perf` — Web Performance Engineering: PSI API, Core Web Vitals | ||
| thresholds, 80/20 optimization matrix, resource-hint analysis, third-party | ||
| script auditing, framework-specific implementation templates. | ||
| ## Examples | ||
| ```bash | ||
| # Full audit — mobile + desktop | ||
| /cc-pagespeed --url https://www.example.com | ||
| # Mobile only | ||
| /cc-pagespeed --url https://www.example.com --strategy mobile | ||
| # Desktop only | ||
| /cc-pagespeed --url https://www.example.com --strategy desktop | ||
| ``` | ||
| ## Hard Rules | ||
| - **GET only.** Never send POST, PUT, or DELETE to the target URL. | ||
| - **No auth.** Never include cookies, tokens, or auth headers. | ||
| - **No external crawling.** Audit only the provided URL. | ||
| - **Quantify every finding.** Never write "it would improve LCP". Always cite | ||
| the observed value and estimated gain (e.g., "reduces LCP from 4.2 s to ~3.0 s"). | ||
| - **No generic recommendations.** Every finding must be backed by data from | ||
| the audit of this specific URL. |
| --- | ||
| name: conductor-setup | ||
| description: Configure a Rails project to work with Conductor (parallel coding agents) | ||
| allowed-tools: Bash(chmod *), Bash(bundle *), Bash(npm *), Bash(script/server) | ||
| context: fork | ||
| risk: unknown | ||
| source: community | ||
| metadata: | ||
| author: Shpigford | ||
| version: "1.0" | ||
| --- | ||
| Set up this Rails project for Conductor, the Mac app for parallel coding agents. | ||
| ## When to Use | ||
| - You need to configure a Rails project so it runs correctly inside Conductor workspaces. | ||
| - The project should support parallel coding agents with isolated ports, Redis settings, and shared secrets. | ||
| - You want the standard `conductor.json`, `bin/conductor-setup`, and `script/server` scaffolding for a Rails repo. | ||
| # What to Create | ||
| ## 1. conductor.json (project root) | ||
| Create `conductor.json` in the project root if it doesn't already exist: | ||
| ```json | ||
| { | ||
| "scripts": { | ||
| "setup": "bin/conductor-setup", | ||
| "run": "script/server" | ||
| } | ||
| } | ||
| ``` | ||
| ## 2. bin/conductor-setup (executable) | ||
| Create `bin/conductor-setup` if it doesn't already exist: | ||
| ```bash | ||
| #!/bin/bash | ||
| set -e | ||
| # Symlink .env from repo root (where secrets live, outside worktrees) | ||
| [ -f "$CONDUCTOR_ROOT_PATH/.env" ] && ln -sf "$CONDUCTOR_ROOT_PATH/.env" .env | ||
| # Symlink Rails master key | ||
| [ -f "$CONDUCTOR_ROOT_PATH/config/master.key" ] && ln -sf "$CONDUCTOR_ROOT_PATH/config/master.key" config/master.key | ||
| # Install dependencies | ||
| bundle install | ||
| npm install | ||
| ``` | ||
| Make it executable with `chmod +x bin/conductor-setup`. | ||
| ## 3. script/server (executable) | ||
| Create the `script` directory if needed, then create `script/server` if it doesn't already exist: | ||
| ```bash | ||
| #!/bin/bash | ||
| # === Port Configuration === | ||
| export PORT=${CONDUCTOR_PORT:-3000} | ||
| export VITE_RUBY_PORT=$((PORT + 1000)) | ||
| # === Redis Isolation === | ||
| if [ -n "$CONDUCTOR_WORKSPACE_NAME" ]; then | ||
| HASH=$(printf '%s' "$CONDUCTOR_WORKSPACE_NAME" | cksum | cut -d' ' -f1) | ||
| REDIS_DB=$((HASH % 16)) | ||
| export REDIS_URL="redis://localhost:6379/${REDIS_DB}" | ||
| fi | ||
| exec bin/dev | ||
| ``` | ||
| Make it executable with `chmod +x script/server`. | ||
| ## 4. Update Rails Config Files | ||
| For each of the following files, if they exist and contain Redis configuration, update them to use `ENV.fetch('REDIS_URL', ...)` or `ENV['REDIS_URL']` with a fallback: | ||
| ### config/initializers/sidekiq.rb | ||
| If this file exists and configures Redis, update it to use: | ||
| ```ruby | ||
| redis_url = ENV.fetch('REDIS_URL', 'redis://localhost:6379/0') | ||
| ``` | ||
| ### config/cable.yml | ||
| If this file exists, update the development adapter to use: | ||
| ```yaml | ||
| development: | ||
| adapter: redis | ||
| url: <%= ENV.fetch('REDIS_URL', 'redis://localhost:6379/1') %> | ||
| ``` | ||
| ### config/environments/development.rb | ||
| If this file configures Redis for caching, update to use: | ||
| ```ruby | ||
| config.cache_store = :redis_cache_store, { url: ENV.fetch('REDIS_URL', 'redis://localhost:6379/0') } | ||
| ``` | ||
| ### config/initializers/rack_attack.rb | ||
| If this file exists and configures a Redis cache store, update to use: | ||
| ```ruby | ||
| Rack::Attack.cache.store = ActiveSupport::Cache::RedisCacheStore.new(url: ENV.fetch('REDIS_URL', 'redis://localhost:6379/0')) | ||
| ``` | ||
| # Implementation Notes | ||
| - **Don't overwrite existing files**: Check if conductor.json, bin/conductor-setup, and script/server exist before creating them. If they exist, skip creation and inform the user. | ||
| - **Rails config updates**: Only modify Redis-related configuration. If a file doesn't exist or doesn't use Redis, skip it gracefully. | ||
| - **Create directories as needed**: Create `script/` directory if it doesn't exist. | ||
| # Verification | ||
| After creating the files: | ||
| 1. Confirm all Conductor files exist and scripts are executable | ||
| 2. Run `script/server` to verify it starts without errors | ||
| 3. Check that Rails configs properly reference `ENV['REDIS_URL']` or `ENV.fetch('REDIS_URL', ...)` | ||
| ## Limitations | ||
| - Use this skill only when the task clearly matches the scope described above. | ||
| - Do not treat the output as a substitute for environment-specific validation, testing, or expert review. | ||
| - Stop and ask for clarification if required inputs, permissions, safety boundaries, or success criteria are missing. |
| --- | ||
| name: find-skills | ||
| description: Helps users discover and install agent skills when they ask questions like "how do I do X", "find a skill for X", "is there a skill that can...", or express interest in extending capabilities. This skill should be used when the user is looking for functionality that might exist as an installable skill. | ||
| --- | ||
| # Find Skills | ||
| This skill helps you discover and install skills from the open agent skills ecosystem. | ||
| ## When to Use This Skill | ||
| Use this skill when the user: | ||
| - Asks "how do I do X" where X might be a common task with an existing skill | ||
| - Says "find a skill for X" or "is there a skill for X" | ||
| - Asks "can you do X" where X is a specialized capability | ||
| - Expresses interest in extending agent capabilities | ||
| - Wants to search for tools, templates, or workflows | ||
| - Mentions they wish they had help with a specific domain (design, testing, deployment, etc.) | ||
| ## What is the Skills CLI? | ||
| The Skills CLI (`npx skills`) is the package manager for the open agent skills ecosystem. Skills are modular packages that extend agent capabilities with specialized knowledge, workflows, and tools. | ||
| **Key commands:** | ||
| - `npx skills find [query]` - Search for skills interactively or by keyword | ||
| - `npx skills add <package>` - Install a skill from GitHub or other sources | ||
| - `npx skills check` - Check for skill updates | ||
| - `npx skills update` - Update all installed skills | ||
| **Browse skills at:** https://skills.sh/ | ||
| ## How to Help Users Find Skills | ||
| ### Step 1: Understand What They Need | ||
| When a user asks for help with something, identify: | ||
| 1. The domain (e.g., React, testing, design, deployment) | ||
| 2. The specific task (e.g., writing tests, creating animations, reviewing PRs) | ||
| 3. Whether this is a common enough task that a skill likely exists | ||
| ### Step 2: Check the Leaderboard First | ||
| Before running a CLI search, check the [skills.sh leaderboard](https://skills.sh/) to see if a well-known skill already exists for the domain. The leaderboard ranks skills by total installs, surfacing the most popular and battle-tested options. | ||
| For example, top skills for web development include: | ||
| - `vercel-labs/agent-skills` — React, Next.js, web design (100K+ installs each) | ||
| - `anthropics/skills` — Frontend design, document processing (100K+ installs) | ||
| ### Step 3: Search for Skills | ||
| If the leaderboard doesn't cover the user's need, run the find command: | ||
| ```bash | ||
| npx skills find [query] | ||
| ``` | ||
| For example: | ||
| - User asks "how do I make my React app faster?" → `npx skills find react performance` | ||
| - User asks "can you help me with PR reviews?" → `npx skills find pr review` | ||
| - User asks "I need to create a changelog" → `npx skills find changelog` | ||
| ### Step 4: Verify Quality Before Recommending | ||
| **Do not recommend a skill based solely on search results.** Always verify: | ||
| 1. **Install count** — Prefer skills with 1K+ installs. Be cautious with anything under 100. | ||
| 2. **Source reputation** — Official sources (`vercel-labs`, `anthropics`, `microsoft`) are more trustworthy than unknown authors. | ||
| 3. **GitHub stars** — Check the source repository. A skill from a repo with <100 stars should be treated with skepticism. | ||
| ### Step 5: Present Options to the User | ||
| When you find relevant skills, present them to the user with: | ||
| 1. The skill name and what it does | ||
| 2. The install count and source | ||
| 3. The install command they can run | ||
| 4. A link to learn more at skills.sh | ||
| Example response: | ||
| ``` | ||
| I found a skill that might help! The "react-best-practices" skill provides | ||
| React and Next.js performance optimization guidelines from Vercel Engineering. | ||
| (185K installs) | ||
| To install it: | ||
| npx skills add vercel-labs/agent-skills@react-best-practices | ||
| Learn more: https://skills.sh/vercel-labs/agent-skills/react-best-practices | ||
| ``` | ||
| ### Step 6: Offer to Install | ||
| If the user wants to proceed, you can install the skill for them: | ||
| ```bash | ||
| npx skills add <owner/repo@skill> -g -y | ||
| ``` | ||
| The `-g` flag installs globally (user-level) and `-y` skips confirmation prompts. | ||
| ## Common Skill Categories | ||
| When searching, consider these common categories: | ||
| | Category | Example Queries | | ||
| | --------------- | ---------------------------------------- | | ||
| | Web Development | react, nextjs, typescript, css, tailwind | | ||
| | Testing | testing, jest, playwright, e2e | | ||
| | DevOps | deploy, docker, kubernetes, ci-cd | | ||
| | Documentation | docs, readme, changelog, api-docs | | ||
| | Code Quality | review, lint, refactor, best-practices | | ||
| | Design | ui, ux, design-system, accessibility | | ||
| | Productivity | workflow, automation, git | | ||
| ## Tips for Effective Searches | ||
| 1. **Use specific keywords**: "react testing" is better than just "testing" | ||
| 2. **Try alternative terms**: If "deploy" doesn't work, try "deployment" or "ci-cd" | ||
| 3. **Check popular sources**: Many skills come from `vercel-labs/agent-skills` or `ComposioHQ/awesome-claude-skills` | ||
| ## When No Skills Are Found | ||
| If no relevant skills exist: | ||
| 1. Acknowledge that no existing skill was found | ||
| 2. Offer to help with the task directly using your general capabilities | ||
| 3. Suggest the user could create their own skill with `npx skills init` | ||
| Example: | ||
| ``` | ||
| I searched for skills related to "xyz" but didn't find any matches. | ||
| I can still help you with this task directly! Would you like me to proceed? | ||
| If this is something you do often, you could create your own skill: | ||
| npx skills init my-xyz-skill | ||
| ``` |
| """ | ||
| Framework-Specific Multi-Agent Implementations | ||
| Templates for CrewAI, AutoGen, LangGraph, and Swarm. | ||
| """ | ||
| from typing import Dict, List, Optional, Any | ||
| from dataclasses import dataclass | ||
| @dataclass | ||
| class CrewAITemplate: | ||
| """Template for CrewAI implementation.""" | ||
| @staticmethod | ||
| def create_financial_team() -> Dict[str, Any]: | ||
| """Create CrewAI financial analysis team.""" | ||
| return { | ||
| "agents": [ | ||
| { | ||
| "name": "Market Analyst", | ||
| "role": "Market Research Specialist", | ||
| "goal": "Analyze market conditions and trends", | ||
| "backstory": "Expert market analyst with 10+ years experience", | ||
| "tools": ["market_data_api", "financial_news"], | ||
| }, | ||
| { | ||
| "name": "Financial Analyst", | ||
| "role": "Financial Analysis Specialist", | ||
| "goal": "Analyze company financial statements", | ||
| "backstory": "CFA with deep financial analysis expertise", | ||
| "tools": ["financial_statements", "ratio_calculator"], | ||
| }, | ||
| { | ||
| "name": "Risk Manager", | ||
| "role": "Risk Assessment Specialist", | ||
| "goal": "Assess investment risks and scenarios", | ||
| "backstory": "Risk management expert", | ||
| "tools": ["risk_models", "scenario_analysis"], | ||
| }, | ||
| { | ||
| "name": "Report Writer", | ||
| "role": "Report Generation Specialist", | ||
| "goal": "Synthesize findings into comprehensive report", | ||
| "backstory": "Professional technical writer", | ||
| "tools": ["document_generator"], | ||
| }, | ||
| ], | ||
| "tasks": [ | ||
| { | ||
| "agent": "Market Analyst", | ||
| "description": "Analyze market conditions for {company}", | ||
| }, | ||
| { | ||
| "agent": "Financial Analyst", | ||
| "description": "Analyze Q3 financial results for {company}", | ||
| }, | ||
| { | ||
| "agent": "Risk Manager", | ||
| "description": "Assess risks and create scenarios for {company}", | ||
| }, | ||
| { | ||
| "agent": "Report Writer", | ||
| "description": "Write comprehensive investment analysis report", | ||
| }, | ||
| ], | ||
| "process": "sequential", | ||
| } | ||
| @staticmethod | ||
| def create_legal_team() -> Dict[str, Any]: | ||
| """Create CrewAI legal team.""" | ||
| return { | ||
| "agents": [ | ||
| { | ||
| "name": "Contract Analyzer", | ||
| "role": "Legal Contract Specialist", | ||
| "goal": "Analyze and review contract terms", | ||
| "backstory": "Senior contract attorney", | ||
| }, | ||
| { | ||
| "name": "Precedent Researcher", | ||
| "role": "Legal Research Specialist", | ||
| "goal": "Research relevant case law and precedents", | ||
| "backstory": "Legal researcher specializing in case law", | ||
| }, | ||
| { | ||
| "name": "Risk Assessor", | ||
| "role": "Legal Risk Specialist", | ||
| "goal": "Identify and assess legal risks", | ||
| "backstory": "Risk management expert in legal domain", | ||
| }, | ||
| { | ||
| "name": "Document Drafter", | ||
| "role": "Legal Document Specialist", | ||
| "goal": "Draft legal documents and recommendations", | ||
| "backstory": "Legal document drafting expert", | ||
| }, | ||
| ], | ||
| "process": "sequential", | ||
| } | ||
| @dataclass | ||
| class AutoGenTemplate: | ||
| """Template for AutoGen implementation.""" | ||
| @staticmethod | ||
| def create_group_chat_config() -> Dict[str, Any]: | ||
| """Create AutoGen group chat configuration.""" | ||
| return { | ||
| "agents": [ | ||
| { | ||
| "name": "analyst", | ||
| "system_message": "You are a financial analyst. Provide analysis based on data.", | ||
| "llm_config": {"model": "gpt-4", "temperature": 0.7}, | ||
| }, | ||
| { | ||
| "name": "researcher", | ||
| "system_message": "You are a market researcher. Research trends and competition.", | ||
| "llm_config": {"model": "gpt-4", "temperature": 0.7}, | ||
| }, | ||
| { | ||
| "name": "critic", | ||
| "system_message": "You are a critical evaluator. Challenge assumptions and findings.", | ||
| "llm_config": {"model": "gpt-4", "temperature": 0.7}, | ||
| }, | ||
| ], | ||
| "group_chat_config": { | ||
| "agents": ["analyst", "researcher", "critic"], | ||
| "max_round": 10, | ||
| "speaker_selection_method": "auto", | ||
| }, | ||
| } | ||
| @staticmethod | ||
| def create_hierarchical_structure() -> Dict[str, Any]: | ||
| """Create hierarchical AutoGen structure.""" | ||
| return { | ||
| "primary_agents": [ | ||
| { | ||
| "name": "senior_analyst", | ||
| "role": "Senior analyst coordinating teams", | ||
| "subordinates": ["junior_analyst_1", "junior_analyst_2"], | ||
| } | ||
| ], | ||
| "secondary_agents": [ | ||
| { | ||
| "name": "junior_analyst_1", | ||
| "role": "Fundamental analysis specialist", | ||
| }, | ||
| { | ||
| "name": "junior_analyst_2", | ||
| "role": "Technical analysis specialist", | ||
| }, | ||
| ], | ||
| } | ||
| @dataclass | ||
| class LangGraphTemplate: | ||
| """Template for LangGraph workflow implementation.""" | ||
| @staticmethod | ||
| def create_research_workflow() -> Dict[str, Any]: | ||
| """Create LangGraph research workflow.""" | ||
| return { | ||
| "name": "research_workflow", | ||
| "state_schema": { | ||
| "topic": str, | ||
| "research_findings": str, | ||
| "analysis": str, | ||
| "recommendations": str, | ||
| }, | ||
| "nodes": [ | ||
| { | ||
| "name": "researcher", | ||
| "agent": "research_agent", | ||
| "description": "Research the topic", | ||
| }, | ||
| { | ||
| "name": "analyst", | ||
| "agent": "analyst_agent", | ||
| "description": "Analyze research findings", | ||
| }, | ||
| { | ||
| "name": "critic", | ||
| "agent": "critic_agent", | ||
| "description": "Critique and improve", | ||
| }, | ||
| { | ||
| "name": "writer", | ||
| "agent": "writer_agent", | ||
| "description": "Write final report", | ||
| }, | ||
| ], | ||
| "edges": [ | ||
| ("researcher", "analyst"), | ||
| ("analyst", "critic"), | ||
| ("critic", "writer"), | ||
| ], | ||
| "entry_point": "researcher", | ||
| "exit_point": "writer", | ||
| } | ||
| @staticmethod | ||
| def create_dynamic_workflow() -> Dict[str, Any]: | ||
| """Create dynamic LangGraph workflow with conditions.""" | ||
| return { | ||
| "name": "dynamic_workflow", | ||
| "nodes": [ | ||
| { | ||
| "name": "start", | ||
| "type": "input", | ||
| }, | ||
| { | ||
| "name": "analyze", | ||
| "type": "agent", | ||
| "agent": "analyzer", | ||
| }, | ||
| { | ||
| "name": "quality_check", | ||
| "type": "decision", | ||
| "condition": "analyze_quality > threshold", | ||
| }, | ||
| { | ||
| "name": "refine", | ||
| "type": "agent", | ||
| "agent": "refiner", | ||
| }, | ||
| { | ||
| "name": "end", | ||
| "type": "output", | ||
| }, | ||
| ], | ||
| "conditional_edges": [ | ||
| { | ||
| "source": "quality_check", | ||
| "true_target": "end", | ||
| "false_target": "refine", | ||
| } | ||
| ], | ||
| } | ||
| @dataclass | ||
| class SwarmTemplate: | ||
| """Template for OpenAI Swarm implementation.""" | ||
| @staticmethod | ||
| def create_customer_support_swarm() -> Dict[str, Any]: | ||
| """Create customer support Swarm.""" | ||
| return { | ||
| "agents": [ | ||
| { | ||
| "name": "triage_agent", | ||
| "instructions": "Determine which specialist to route the customer to. " | ||
| "Ask clarifying questions if needed.", | ||
| "functions": [ | ||
| "route_to_billing", | ||
| "route_to_technical", | ||
| "route_to_account", | ||
| ], | ||
| }, | ||
| { | ||
| "name": "billing_specialist", | ||
| "instructions": "Handle all billing and payment related questions. " | ||
| "Can access billing records.", | ||
| "tools": ["billing_system", "payment_processor"], | ||
| }, | ||
| { | ||
| "name": "technical_support", | ||
| "instructions": "Handle technical issues and troubleshooting. " | ||
| "Can access diagnostic tools.", | ||
| "tools": ["diagnostic_tools", "knowledge_base"], | ||
| }, | ||
| { | ||
| "name": "account_specialist", | ||
| "instructions": "Handle account management and profile changes.", | ||
| "tools": ["account_system"], | ||
| }, | ||
| ], | ||
| "handoff_functions": { | ||
| "route_to_billing": "Transfer to billing specialist", | ||
| "route_to_technical": "Transfer to technical support", | ||
| "route_to_account": "Transfer to account specialist", | ||
| }, | ||
| } | ||
| @staticmethod | ||
| def create_sales_swarm() -> Dict[str, Any]: | ||
| """Create sales team Swarm.""" | ||
| return { | ||
| "agents": [ | ||
| { | ||
| "name": "sales_router", | ||
| "instructions": "Route customer inquiries to appropriate sales agent", | ||
| "functions": ["route_to_enterprise", "route_to_smb"], | ||
| }, | ||
| { | ||
| "name": "enterprise_sales", | ||
| "instructions": "Handle enterprise customer inquiries", | ||
| }, | ||
| { | ||
| "name": "smb_sales", | ||
| "instructions": "Handle small business inquiries", | ||
| }, | ||
| ], | ||
| } | ||
| class AgentCommunicationManager: | ||
| """Manage communication patterns between agents.""" | ||
| def __init__(self, agents: Dict[str, Any]): | ||
| """Initialize communication manager.""" | ||
| self.agents = agents | ||
| self.message_queue = [] | ||
| def broadcast_message(self, sender: str, message: str, recipients: List[str]): | ||
| """Broadcast message to multiple agents.""" | ||
| for recipient in recipients: | ||
| self.message_queue.append({ | ||
| "from": sender, | ||
| "to": recipient, | ||
| "message": message, | ||
| "type": "broadcast", | ||
| }) | ||
| def direct_message(self, sender: str, recipient: str, message: str): | ||
| """Send direct message between agents.""" | ||
| self.message_queue.append({ | ||
| "from": sender, | ||
| "to": recipient, | ||
| "message": message, | ||
| "type": "direct", | ||
| }) | ||
| def publish_shared_state(self, state_key: str, value: Any): | ||
| """Publish to shared state (tool-mediated communication).""" | ||
| self.message_queue.append({ | ||
| "type": "shared_state", | ||
| "key": state_key, | ||
| "value": value, | ||
| }) | ||
| def get_pending_messages(self, agent: str) -> List[Dict]: | ||
| """Get messages for specific agent.""" | ||
| return [msg for msg in self.message_queue if msg.get("to") == agent] | ||
| def process_message_queue(self) -> Dict[str, Any]: | ||
| """Process and summarize message queue.""" | ||
| direct_messages = [m for m in self.message_queue if m["type"] == "direct"] | ||
| broadcasts = [m for m in self.message_queue if m["type"] == "broadcast"] | ||
| shared_states = [m for m in self.message_queue if m["type"] == "shared_state"] | ||
| return { | ||
| "direct_messages": len(direct_messages), | ||
| "broadcasts": len(broadcasts), | ||
| "shared_states": len(shared_states), | ||
| "total_messages": len(self.message_queue), | ||
| } |
| """ | ||
| Multi-Agent Orchestration Patterns | ||
| Implements sequential, parallel, hierarchical, and consensus orchestration. | ||
| """ | ||
| from typing import List, Dict, Any, Optional | ||
| import asyncio | ||
| from abc import ABC, abstractmethod | ||
| class Agent(ABC): | ||
| """Base agent class.""" | ||
| def __init__(self, name: str, role: str, goal: str): | ||
| """Initialize agent.""" | ||
| self.name = name | ||
| self.role = role | ||
| self.goal = goal | ||
| @abstractmethod | ||
| def work(self, task: str) -> str: | ||
| """Execute task.""" | ||
| pass | ||
| async def work_async(self, task: str) -> str: | ||
| """Execute task asynchronously.""" | ||
| return self.work(task) | ||
| class SimpleAgent(Agent): | ||
| """Simple agent implementation.""" | ||
| def __init__(self, name: str, role: str, goal: str): | ||
| """Initialize simple agent.""" | ||
| super().__init__(name, role, goal) | ||
| def work(self, task: str) -> str: | ||
| """Simulate agent work.""" | ||
| return f"{self.name}: Completed task - {task[:50]}..." | ||
| class SequentialOrchestrator: | ||
| """Orchestrate agents to work sequentially.""" | ||
| def __init__(self, agents: List[Agent]): | ||
| """ | ||
| Initialize orchestrator with agents. | ||
| Args: | ||
| agents: List of agents to orchestrate | ||
| """ | ||
| self.agents = agents | ||
| self.execution_log = [] | ||
| def execute(self, initial_task: str) -> Dict[str, Any]: | ||
| """ | ||
| Execute agents sequentially. | ||
| Args: | ||
| initial_task: Initial task description | ||
| Returns: | ||
| Execution results dictionary | ||
| """ | ||
| current_input = initial_task | ||
| results = {} | ||
| for agent in self.agents: | ||
| result = agent.work(current_input) | ||
| results[agent.name] = result | ||
| self.execution_log.append({ | ||
| "agent": agent.name, | ||
| "role": agent.role, | ||
| "task": current_input, | ||
| "result": result, | ||
| }) | ||
| # Next agent uses this agent's output | ||
| current_input = result | ||
| return { | ||
| "type": "sequential", | ||
| "results": results, | ||
| "final_output": current_input, | ||
| "execution_log": self.execution_log, | ||
| } | ||
| class ParallelOrchestrator: | ||
| """Orchestrate agents to work in parallel.""" | ||
| def __init__(self, agents: List[Agent]): | ||
| """Initialize parallel orchestrator.""" | ||
| self.agents = agents | ||
| self.execution_log = [] | ||
| async def execute_async(self, task: str) -> Dict[str, Any]: | ||
| """ | ||
| Execute agents in parallel. | ||
| Args: | ||
| task: Task description | ||
| Returns: | ||
| Execution results dictionary | ||
| """ | ||
| # Create async tasks for all agents | ||
| tasks = [agent.work_async(task) for agent in self.agents] | ||
| # Execute all in parallel | ||
| results_list = await asyncio.gather(*tasks) | ||
| results = { | ||
| agent.name: result | ||
| for agent, result in zip(self.agents, results_list) | ||
| } | ||
| self.execution_log.append({ | ||
| "type": "parallel", | ||
| "task": task, | ||
| "agents": [a.name for a in self.agents], | ||
| "results": results, | ||
| }) | ||
| return { | ||
| "type": "parallel", | ||
| "results": results, | ||
| "execution_log": self.execution_log, | ||
| } | ||
| def execute(self, task: str) -> Dict[str, Any]: | ||
| """Execute agents synchronously (sequential fallback).""" | ||
| return asyncio.run(self.execute_async(task)) | ||
| class HierarchicalOrchestrator: | ||
| """Orchestrate agents in hierarchical structure.""" | ||
| def __init__(self, manager_agent: Agent, specialist_teams: Dict[str, List[Agent]]): | ||
| """ | ||
| Initialize hierarchical orchestrator. | ||
| Args: | ||
| manager_agent: Manager agent | ||
| specialist_teams: Dict of team names to lists of agents | ||
| """ | ||
| self.manager = manager_agent | ||
| self.specialist_teams = specialist_teams | ||
| self.execution_log = [] | ||
| def execute(self, main_task: str) -> Dict[str, Any]: | ||
| """ | ||
| Execute with hierarchical structure. | ||
| Args: | ||
| main_task: Main task for manager | ||
| Returns: | ||
| Execution results | ||
| """ | ||
| team_results = {} | ||
| # Manager assigns tasks to teams | ||
| for team_name, agents in self.specialist_teams.items(): | ||
| # Each team works on their aspect | ||
| team_task = f"{main_task} - Team: {team_name}" | ||
| team_result = {} | ||
| for agent in agents: | ||
| result = agent.work(team_task) | ||
| team_result[agent.name] = result | ||
| team_results[team_name] = team_result | ||
| self.execution_log.append({ | ||
| "team": team_name, | ||
| "agents": [a.name for a in agents], | ||
| "results": team_result, | ||
| }) | ||
| # Manager synthesizes results | ||
| manager_result = self.manager.work( | ||
| f"Synthesize findings from: {list(team_results.keys())}" | ||
| ) | ||
| return { | ||
| "type": "hierarchical", | ||
| "team_results": team_results, | ||
| "manager_synthesis": manager_result, | ||
| "execution_log": self.execution_log, | ||
| } | ||
| class ConsensusOrchestrator: | ||
| """Orchestrate agent debate and consensus.""" | ||
| def __init__(self, agents: List[Agent], mediator_agent: Agent): | ||
| """Initialize consensus orchestrator.""" | ||
| self.agents = agents | ||
| self.mediator = mediator_agent | ||
| self.debate_history = [] | ||
| def execute(self, question: str, rounds: int = 2) -> Dict[str, Any]: | ||
| """ | ||
| Execute debate and reach consensus. | ||
| Args: | ||
| question: Question for debate | ||
| rounds: Number of debate rounds | ||
| Returns: | ||
| Consensus results | ||
| """ | ||
| # Round 1: Initial positions | ||
| positions = {} | ||
| for agent in self.agents: | ||
| position = agent.work(f"Argue your position on: {question}") | ||
| positions[agent.name] = position | ||
| self.debate_history.append({ | ||
| "round": 1, | ||
| "agent": agent.name, | ||
| "position": position, | ||
| }) | ||
| # Additional rounds: Response to others | ||
| for round_num in range(2, rounds + 1): | ||
| for agent in self.agents: | ||
| other_positions = { | ||
| name: pos | ||
| for name, pos in positions.items() | ||
| if name != agent.name | ||
| } | ||
| response = agent.work( | ||
| f"Respond to these positions: {str(other_positions)}" | ||
| ) | ||
| self.debate_history.append({ | ||
| "round": round_num, | ||
| "agent": agent.name, | ||
| "response": response, | ||
| }) | ||
| # Mediator reaches consensus | ||
| consensus = self.mediator.work( | ||
| f"Synthesize consensus from debate on: {question}" | ||
| ) | ||
| return { | ||
| "type": "consensus", | ||
| "question": question, | ||
| "initial_positions": positions, | ||
| "debate_rounds": rounds, | ||
| "consensus": consensus, | ||
| "debate_history": self.debate_history, | ||
| } | ||
| class AdaptiveOrchestrator: | ||
| """Adapt orchestration based on progress.""" | ||
| def __init__(self, agents: List[Agent]): | ||
| """Initialize adaptive orchestrator.""" | ||
| self.agents = agents | ||
| self.execution_log = [] | ||
| def execute_with_adaptation( | ||
| self, | ||
| initial_task: str, | ||
| progress_threshold: float = 0.7, | ||
| quality_threshold: float = 0.6, | ||
| ) -> Dict[str, Any]: | ||
| """ | ||
| Execute with adaptive workflow changes. | ||
| Args: | ||
| initial_task: Initial task | ||
| progress_threshold: Threshold for adding resources | ||
| quality_threshold: Threshold for adding validation | ||
| Returns: | ||
| Adaptive execution results | ||
| """ | ||
| results = {} | ||
| current_task = initial_task | ||
| active_agents = self.agents.copy() | ||
| for iteration in range(3): | ||
| # Execute with current agents | ||
| iteration_results = {} | ||
| for agent in active_agents: | ||
| result = agent.work(current_task) | ||
| iteration_results[agent.name] = result | ||
| results[f"iteration_{iteration}"] = iteration_results | ||
| # Assess progress | ||
| progress = self._calculate_progress(iteration_results) | ||
| quality = self._calculate_quality(iteration_results) | ||
| log_entry = { | ||
| "iteration": iteration, | ||
| "agents": [a.name for a in active_agents], | ||
| "progress": progress, | ||
| "quality": quality, | ||
| } | ||
| # Adapt based on progress | ||
| if progress < progress_threshold and iteration < 2: | ||
| # Add more agents | ||
| log_entry["adaptation"] = "Added specialist agent" | ||
| self.execution_log.append(log_entry) | ||
| elif quality < quality_threshold and iteration < 2: | ||
| # Add validation step | ||
| log_entry["adaptation"] = "Added validation agent" | ||
| self.execution_log.append(log_entry) | ||
| else: | ||
| self.execution_log.append(log_entry) | ||
| return { | ||
| "type": "adaptive", | ||
| "results": results, | ||
| "adaptations": self.execution_log, | ||
| } | ||
| @staticmethod | ||
| def _calculate_progress(results: Dict) -> float: | ||
| """Calculate progress score.""" | ||
| # Simple heuristic based on results | ||
| return min(len(results) / 3.0, 1.0) | ||
| @staticmethod | ||
| def _calculate_quality(results: Dict) -> float: | ||
| """Calculate quality score.""" | ||
| # Simple heuristic | ||
| return 0.7 # Placeholder | ||
| class WorkflowGraph: | ||
| """Define workflow as directed acyclic graph (DAG).""" | ||
| def __init__(self): | ||
| """Initialize workflow graph.""" | ||
| self.nodes = {} | ||
| self.edges = [] | ||
| def add_node(self, node_id: str, agent: Agent) -> None: | ||
| """Add agent node.""" | ||
| self.nodes[node_id] = agent | ||
| def add_edge(self, from_node: str, to_node: str) -> None: | ||
| """Add dependency edge.""" | ||
| self.edges.append((from_node, to_node)) | ||
| def execute_dag(self, initial_task: str) -> Dict[str, Any]: | ||
| """ | ||
| Execute workflow as DAG. | ||
| Args: | ||
| initial_task: Initial task | ||
| Returns: | ||
| Execution results | ||
| """ | ||
| results = {} | ||
| ready_nodes = self._find_ready_nodes() | ||
| while ready_nodes: | ||
| for node_id in ready_nodes: | ||
| agent = self.nodes[node_id] | ||
| # Get input from dependencies | ||
| task_input = self._get_node_input(node_id, results, initial_task) | ||
| result = agent.work(task_input) | ||
| results[node_id] = result | ||
| ready_nodes = self._find_ready_nodes(completed=set(results.keys())) | ||
| return { | ||
| "type": "dag", | ||
| "results": results, | ||
| "nodes": list(self.nodes.keys()), | ||
| "edges": self.edges, | ||
| } | ||
| def _find_ready_nodes(self, completed: Optional[set] = None) -> List[str]: | ||
| """Find nodes with all dependencies completed.""" | ||
| if completed is None: | ||
| completed = set() | ||
| ready = [] | ||
| for node_id in self.nodes: | ||
| if node_id not in completed: | ||
| dependencies = [ | ||
| from_node | ||
| for from_node, to_node in self.edges | ||
| if to_node == node_id | ||
| ] | ||
| if all(dep in completed for dep in dependencies): | ||
| ready.append(node_id) | ||
| return ready | ||
| def _get_node_input( | ||
| self, node_id: str, results: Dict, initial_task: str | ||
| ) -> str: | ||
| """Get input for node from dependencies.""" | ||
| dependencies = [ | ||
| from_node for from_node, to_node in self.edges if to_node == node_id | ||
| ] | ||
| if not dependencies: | ||
| return initial_task | ||
| # Combine outputs from dependencies | ||
| return " + ".join(results.get(dep, "") for dep in dependencies) |
| # Multi-Agent Orchestration - Code Structure | ||
| This skill uses supporting Python files to keep documentation lean and maintainable. | ||
| ## Directory Structure | ||
| ``` | ||
| multi-agent-orchestration/ | ||
| ├── SKILL.md # Main documentation (patterns, concepts) | ||
| ├── README.md # This file | ||
| ├── examples/ # Implementation examples | ||
| │ ├── orchestration_patterns.py # Sequential, parallel, hierarchical, consensus | ||
| │ └── framework_implementations.py # CrewAI, AutoGen, LangGraph, Swarm templates | ||
| └── scripts/ # Utility modules | ||
| ├── agent_communication.py # Message broker, shared memory, protocols | ||
| ├── workflow_management.py # Workflow execution and optimization | ||
| └── benchmarking.py # Performance and collaboration metrics | ||
| ``` | ||
| ## Running Examples | ||
| ### 1. Orchestration Patterns | ||
| ```bash | ||
| python examples/orchestration_patterns.py | ||
| ``` | ||
| Demonstrates sequential, parallel, hierarchical, and consensus orchestration. | ||
| ### 2. Framework Templates | ||
| ```bash | ||
| python examples/framework_implementations.py | ||
| ``` | ||
| Templates and configurations for CrewAI, AutoGen, LangGraph, and Swarm frameworks. | ||
| ## Using the Utilities | ||
| ### Agent Communication | ||
| ```python | ||
| from scripts.agent_communication import MessageBroker, SharedMemory, CommunicationProtocol | ||
| # Set up communication | ||
| broker = MessageBroker() | ||
| shared_memory = SharedMemory() | ||
| protocol = CommunicationProtocol(broker, shared_memory) | ||
| # Send messages between agents | ||
| protocol.request_analysis("agent_a", "agent_b", "Analyze this topic") | ||
| # Share findings | ||
| protocol.share_findings("agent_a", "analysis_results", {"findings": "..."}) | ||
| # Get communication stats | ||
| stats = broker.get_statistics() | ||
| ``` | ||
| ### Workflow Management | ||
| ```python | ||
| from scripts.workflow_management import WorkflowExecutor, WorkflowOptimizer | ||
| # Create and execute workflow | ||
| executor = WorkflowExecutor() | ||
| workflow = executor.create_workflow("workflow_1", "Analysis Workflow") | ||
| # Add tasks | ||
| executor.add_task("workflow_1", "task_1", "researcher", "Research the topic") | ||
| executor.add_task("workflow_1", "task_2", "analyst", "Analyze findings", dependencies=["task_1"]) | ||
| # Execute | ||
| results = executor.execute_workflow("workflow_1", executor_func) | ||
| # Analyze workflow | ||
| analysis = WorkflowOptimizer.analyze_dependencies(workflow) | ||
| print(f"Critical path: {analysis['critical_path']}") | ||
| ``` | ||
| ### Benchmarking | ||
| ```python | ||
| from scripts.benchmarking import TeamBenchmark, AgentEffectiveness, CollaborationMetrics | ||
| # Benchmark team performance | ||
| benchmark = TeamBenchmark() | ||
| result = benchmark.run_benchmark("sequential_test", orchestrator, test_data) | ||
| # Track agent effectiveness | ||
| effectiveness = AgentEffectiveness() | ||
| effectiveness.record_agent_task("agent_a", "task_1", success=True, quality_score=0.95, duration=2.5) | ||
| # Get agent rankings | ||
| rankings = effectiveness.rank_agents() | ||
| for rank, agent, score, metrics in rankings: | ||
| print(f"{rank}. {agent}: {score:.2f}") | ||
| # Analyze collaboration | ||
| collaboration = CollaborationMetrics() | ||
| collaboration.record_interaction("agent_a", "agent_b", "request", response_time=0.5, successful=True) | ||
| interaction_metrics = collaboration.get_interaction_metrics() | ||
| ``` | ||
| ## Integration with SKILL.md | ||
| - SKILL.md contains conceptual information, orchestration patterns, and best practices | ||
| - Code examples are in `examples/` for clarity and runnable implementations | ||
| - Utilities are in `scripts/` for modular, reusable components | ||
| - This keeps token costs low while maintaining full functionality | ||
| ## Orchestration Patterns Covered | ||
| 1. **Sequential Orchestration** - Tasks execute one after another | ||
| 2. **Parallel Orchestration** - Multiple agents work simultaneously | ||
| 3. **Hierarchical Orchestration** - Manager coordinates specialist teams | ||
| 4. **Consensus-Based** - Agents debate and reach consensus | ||
| 5. **Adaptive Workflows** - Orchestration changes based on progress | ||
| 6. **DAG-Based** - Workflow as directed acyclic graph | ||
| ## Framework Implementations | ||
| - **CrewAI** - Clear roles, hierarchical structure | ||
| - **AutoGen** - Multi-turn conversations, group discussions | ||
| - **LangGraph** - State management, complex workflows | ||
| - **Swarm** - Simple handoffs, conversational workflows | ||
| ## Key Features | ||
| - **Token Efficient**: Modular code structure reduces LLM context usage | ||
| - **Production Ready**: Includes monitoring, optimization, and benchmarking | ||
| - **Framework Agnostic**: Works with any agent framework | ||
| - **Communication Patterns**: Direct, tool-mediated, and manager-based | ||
| - **Performance Metrics**: Team and individual agent effectiveness tracking | ||
| ## Communication Patterns | ||
| - **Direct Communication**: Agent-to-agent message passing | ||
| - **Tool-Mediated**: Agents use shared memory/database | ||
| - **Manager-Based**: Central coordinator manages communication | ||
| - **Broadcast**: One-to-many messaging | ||
| ## Next Steps | ||
| 1. Define agent roles and expertise | ||
| 2. Choose orchestration pattern (sequential, parallel, hierarchical) | ||
| 3. Select communication approach (direct, shared memory, manager) | ||
| 4. Implement workflow with task definitions | ||
| 5. Set up monitoring and metrics | ||
| 6. Benchmark and optimize | ||
| 7. Deploy and iterate |
| """ | ||
| Agent Communication Management | ||
| Handle agent-to-agent communication, message passing, and shared state. | ||
| """ | ||
| from typing import Dict, List, Optional, Any, Callable | ||
| from dataclasses import dataclass, field | ||
| from enum import Enum | ||
| import json | ||
| class MessageType(Enum): | ||
| """Types of messages between agents.""" | ||
| DIRECT = "direct" | ||
| BROADCAST = "broadcast" | ||
| REQUEST = "request" | ||
| RESPONSE = "response" | ||
| FEEDBACK = "feedback" | ||
| ERROR = "error" | ||
| @dataclass | ||
| class Message: | ||
| """Message between agents.""" | ||
| sender: str | ||
| recipient: str | ||
| content: str | ||
| message_type: MessageType | ||
| timestamp: float = field(default_factory=lambda: 0) | ||
| metadata: Dict[str, Any] = field(default_factory=dict) | ||
| def to_dict(self) -> Dict: | ||
| """Convert to dictionary.""" | ||
| return { | ||
| "sender": self.sender, | ||
| "recipient": self.recipient, | ||
| "content": self.content, | ||
| "type": self.message_type.value, | ||
| "timestamp": self.timestamp, | ||
| "metadata": self.metadata, | ||
| } | ||
| class MessageBroker: | ||
| """Central message broker for agent communication.""" | ||
| def __init__(self): | ||
| """Initialize message broker.""" | ||
| self.message_queue: List[Message] = [] | ||
| self.agent_inboxes: Dict[str, List[Message]] = {} | ||
| self.message_handlers: Dict[MessageType, List[Callable]] = {} | ||
| def send_message(self, message: Message) -> bool: | ||
| """ | ||
| Send message from one agent to another. | ||
| Args: | ||
| message: Message object | ||
| Returns: | ||
| Whether message was delivered | ||
| """ | ||
| self.message_queue.append(message) | ||
| # Add to recipient's inbox | ||
| if message.recipient not in self.agent_inboxes: | ||
| self.agent_inboxes[message.recipient] = [] | ||
| self.agent_inboxes[message.recipient].append(message) | ||
| # Trigger handlers | ||
| self._trigger_handlers(message) | ||
| return True | ||
| def broadcast_message(self, sender: str, content: str, recipients: List[str]): | ||
| """ | ||
| Broadcast message to multiple agents. | ||
| Args: | ||
| sender: Sending agent | ||
| content: Message content | ||
| recipients: List of recipient agents | ||
| """ | ||
| for recipient in recipients: | ||
| message = Message( | ||
| sender=sender, | ||
| recipient=recipient, | ||
| content=content, | ||
| message_type=MessageType.BROADCAST, | ||
| ) | ||
| self.send_message(message) | ||
| def request_response( | ||
| self, sender: str, recipient: str, content: str, timeout: float = 5.0 | ||
| ) -> Optional[Message]: | ||
| """ | ||
| Send request and wait for response. | ||
| Args: | ||
| sender: Requesting agent | ||
| recipient: Agent to respond | ||
| content: Request content | ||
| timeout: Response timeout in seconds | ||
| Returns: | ||
| Response message or None | ||
| """ | ||
| message = Message( | ||
| sender=sender, | ||
| recipient=recipient, | ||
| content=content, | ||
| message_type=MessageType.REQUEST, | ||
| metadata={"timeout": timeout}, | ||
| ) | ||
| self.send_message(message) | ||
| # Placeholder - wait for response | ||
| # In production, implement actual timeout/wait mechanism | ||
| return None | ||
| def get_inbox(self, agent: str) -> List[Message]: | ||
| """Get messages for specific agent.""" | ||
| return self.agent_inboxes.get(agent, []) | ||
| def clear_inbox(self, agent: str) -> None: | ||
| """Clear agent's inbox.""" | ||
| self.agent_inboxes[agent] = [] | ||
| def register_handler( | ||
| self, message_type: MessageType, handler: Callable | ||
| ) -> None: | ||
| """Register handler for message type.""" | ||
| if message_type not in self.message_handlers: | ||
| self.message_handlers[message_type] = [] | ||
| self.message_handlers[message_type].append(handler) | ||
| def _trigger_handlers(self, message: Message) -> None: | ||
| """Trigger registered handlers.""" | ||
| handlers = self.message_handlers.get(message.message_type, []) | ||
| for handler in handlers: | ||
| try: | ||
| handler(message) | ||
| except Exception: | ||
| pass | ||
| def get_statistics(self) -> Dict[str, Any]: | ||
| """Get communication statistics.""" | ||
| type_counts = {} | ||
| for message in self.message_queue: | ||
| msg_type = message.message_type.value | ||
| type_counts[msg_type] = type_counts.get(msg_type, 0) + 1 | ||
| return { | ||
| "total_messages": len(self.message_queue), | ||
| "by_type": type_counts, | ||
| "total_agents": len(self.agent_inboxes), | ||
| "agents": list(self.agent_inboxes.keys()), | ||
| } | ||
| class SharedMemory: | ||
| """Shared memory for tool-mediated agent communication.""" | ||
| def __init__(self): | ||
| """Initialize shared memory.""" | ||
| self.memory: Dict[str, Any] = {} | ||
| self.access_log: List[Dict] = [] | ||
| def write(self, key: str, value: Any, agent: str = "system") -> None: | ||
| """ | ||
| Write to shared memory. | ||
| Args: | ||
| key: Memory key | ||
| value: Value to store | ||
| agent: Agent writing | ||
| """ | ||
| self.memory[key] = { | ||
| "value": value, | ||
| "writer": agent, | ||
| "access_count": 0, | ||
| } | ||
| self.access_log.append({ | ||
| "action": "write", | ||
| "key": key, | ||
| "agent": agent, | ||
| }) | ||
| def read(self, key: str, agent: str = "system") -> Optional[Any]: | ||
| """ | ||
| Read from shared memory. | ||
| Args: | ||
| key: Memory key | ||
| agent: Agent reading | ||
| Returns: | ||
| Stored value or None | ||
| """ | ||
| if key in self.memory: | ||
| entry = self.memory[key] | ||
| entry["access_count"] += 1 | ||
| self.access_log.append({ | ||
| "action": "read", | ||
| "key": key, | ||
| "agent": agent, | ||
| }) | ||
| return entry["value"] | ||
| return None | ||
| def append(self, key: str, value: Any, agent: str = "system") -> None: | ||
| """Append to list in shared memory.""" | ||
| if key not in self.memory: | ||
| self.memory[key] = { | ||
| "value": [], | ||
| "writer": agent, | ||
| "access_count": 0, | ||
| } | ||
| if isinstance(self.memory[key]["value"], list): | ||
| self.memory[key]["value"].append(value) | ||
| def get_all(self) -> Dict[str, Any]: | ||
| """Get all shared memory contents.""" | ||
| return { | ||
| key: entry["value"] for key, entry in self.memory.items() | ||
| } | ||
| def get_statistics(self) -> Dict[str, Any]: | ||
| """Get memory access statistics.""" | ||
| total_accesses = sum( | ||
| entry["access_count"] for entry in self.memory.values() | ||
| ) | ||
| return { | ||
| "total_keys": len(self.memory), | ||
| "total_accesses": total_accesses, | ||
| "access_log_size": len(self.access_log), | ||
| } | ||
| class ContextManager: | ||
| """Manage context sharing between agents.""" | ||
| def __init__(self): | ||
| """Initialize context manager.""" | ||
| self.contexts: Dict[str, Dict[str, Any]] = {} | ||
| self.global_context: Dict[str, Any] = {} | ||
| def create_context(self, context_id: str, initial_data: Optional[Dict] = None) -> None: | ||
| """Create new context.""" | ||
| self.contexts[context_id] = initial_data or {} | ||
| def update_context(self, context_id: str, data: Dict) -> None: | ||
| """Update context data.""" | ||
| if context_id in self.contexts: | ||
| self.contexts[context_id].update(data) | ||
| def get_context(self, context_id: str) -> Dict[str, Any]: | ||
| """Get context data.""" | ||
| return self.contexts.get(context_id, {}) | ||
| def set_global_context(self, key: str, value: Any) -> None: | ||
| """Set global context variable.""" | ||
| self.global_context[key] = value | ||
| def get_global_context(self, key: str) -> Optional[Any]: | ||
| """Get global context variable.""" | ||
| return self.global_context.get(key) | ||
| def context_to_string(self, context_id: str) -> str: | ||
| """Convert context to formatted string.""" | ||
| context = self.get_context(context_id) | ||
| return json.dumps(context, indent=2) | ||
| class CommunicationProtocol: | ||
| """Define communication protocol between agents.""" | ||
| def __init__(self, broker: MessageBroker, shared_memory: SharedMemory): | ||
| """Initialize protocol.""" | ||
| self.broker = broker | ||
| self.shared_memory = shared_memory | ||
| def request_analysis( | ||
| self, requester: str, analyzer: str, subject: str | ||
| ) -> None: | ||
| """Request analysis from another agent.""" | ||
| message = Message( | ||
| sender=requester, | ||
| recipient=analyzer, | ||
| content=f"Analyze: {subject}", | ||
| message_type=MessageType.REQUEST, | ||
| metadata={"action": "analyze"}, | ||
| ) | ||
| self.broker.send_message(message) | ||
| def share_findings(self, source_agent: str, key: str, findings: Dict) -> None: | ||
| """Share findings through shared memory.""" | ||
| self.shared_memory.write(key, findings, source_agent) | ||
| def aggregate_results( | ||
| self, agents: List[str], result_key: str | ||
| ) -> Dict[str, Any]: | ||
| """Aggregate results from multiple agents.""" | ||
| results = {} | ||
| for agent in agents: | ||
| agent_results = self.shared_memory.read(f"{agent}_{result_key}") | ||
| if agent_results: | ||
| results[agent] = agent_results | ||
| return results | ||
| def notify_status(self, agent: str, status: str) -> None: | ||
| """Notify status update.""" | ||
| message = Message( | ||
| sender=agent, | ||
| recipient="orchestrator", | ||
| content=f"Status: {status}", | ||
| message_type=MessageType.FEEDBACK, | ||
| ) | ||
| self.broker.send_message(message) | ||
| def error_propagation(self, source_agent: str, error: str) -> None: | ||
| """Propagate error to relevant agents.""" | ||
| message = Message( | ||
| sender=source_agent, | ||
| recipient="orchestrator", | ||
| content=f"Error: {error}", | ||
| message_type=MessageType.ERROR, | ||
| ) | ||
| self.broker.send_message(message) |
| """ | ||
| Multi-Agent System Benchmarking | ||
| Evaluate team performance and agent effectiveness. | ||
| """ | ||
| from typing import Dict, List, Any, Callable, Optional | ||
| from dataclasses import dataclass | ||
| import time | ||
| import statistics | ||
| @dataclass | ||
| class BenchmarkResult: | ||
| """Result from benchmark run.""" | ||
| test_name: str | ||
| total_time: float | ||
| task_count: int | ||
| success_count: int | ||
| failure_count: int | ||
| quality_score: float | ||
| cost_tokens: int | ||
| class TeamBenchmark: | ||
| """Benchmark multi-agent team performance.""" | ||
| def __init__(self): | ||
| """Initialize benchmarking suite.""" | ||
| self.results: List[BenchmarkResult] = [] | ||
| self.agent_metrics: Dict[str, Dict] = {} | ||
| def run_benchmark( | ||
| self, | ||
| test_name: str, | ||
| orchestrator, | ||
| test_data: List[Dict], | ||
| quality_metric: Optional[Callable] = None, | ||
| ) -> BenchmarkResult: | ||
| """ | ||
| Run benchmark test. | ||
| Args: | ||
| test_name: Name of benchmark | ||
| orchestrator: Orchestrator instance | ||
| test_data: Test cases | ||
| quality_metric: Function to evaluate quality | ||
| Returns: | ||
| Benchmark result | ||
| """ | ||
| start_time = time.time() | ||
| results = [] | ||
| costs = [] | ||
| for test_case in test_data: | ||
| try: | ||
| result = orchestrator.execute(test_case) | ||
| results.append(result) | ||
| # Assume cost in test_case | ||
| costs.append(test_case.get("cost", 0)) | ||
| except Exception: | ||
| pass | ||
| end_time = time.time() | ||
| success_count = len(results) | ||
| failure_count = len(test_data) - success_count | ||
| total_time = end_time - start_time | ||
| # Calculate quality score | ||
| quality_score = ( | ||
| quality_metric(results) if quality_metric else success_count / len(test_data) | ||
| ) | ||
| benchmark_result = BenchmarkResult( | ||
| test_name=test_name, | ||
| total_time=total_time, | ||
| task_count=len(test_data), | ||
| success_count=success_count, | ||
| failure_count=failure_count, | ||
| quality_score=quality_score, | ||
| cost_tokens=sum(costs), | ||
| ) | ||
| self.results.append(benchmark_result) | ||
| return benchmark_result | ||
| def compare_orchestration_methods( | ||
| self, | ||
| methods: Dict[str, Callable], | ||
| test_data: List[Dict], | ||
| ) -> Dict[str, Any]: | ||
| """ | ||
| Compare different orchestration methods. | ||
| Args: | ||
| methods: Dict of method name to orchestrator | ||
| test_data: Test cases | ||
| Returns: | ||
| Comparison results | ||
| """ | ||
| comparison = {} | ||
| for method_name, orchestrator in methods.items(): | ||
| result = self.run_benchmark(method_name, orchestrator, test_data) | ||
| comparison[method_name] = { | ||
| "total_time": result.total_time, | ||
| "success_rate": result.success_count / result.task_count, | ||
| "quality_score": result.quality_score, | ||
| "efficiency": result.success_count / (result.total_time + 0.001), | ||
| "cost_per_success": ( | ||
| result.cost_tokens / result.success_count | ||
| if result.success_count > 0 | ||
| else float("inf") | ||
| ), | ||
| } | ||
| return comparison | ||
| def get_summary(self) -> Dict[str, Any]: | ||
| """Get benchmark summary.""" | ||
| if not self.results: | ||
| return {"status": "no_results"} | ||
| times = [r.total_time for r in self.results] | ||
| success_rates = [ | ||
| r.success_count / r.task_count for r in self.results | ||
| ] | ||
| quality_scores = [r.quality_score for r in self.results] | ||
| return { | ||
| "total_benchmarks": len(self.results), | ||
| "avg_time": statistics.mean(times), | ||
| "median_time": statistics.median(times), | ||
| "avg_success_rate": statistics.mean(success_rates), | ||
| "avg_quality": statistics.mean(quality_scores), | ||
| "benchmarks": [r.__dict__ for r in self.results], | ||
| } | ||
| class AgentEffectiveness: | ||
| """Measure individual agent effectiveness.""" | ||
| def __init__(self): | ||
| """Initialize effectiveness tracker.""" | ||
| self.agent_stats: Dict[str, Dict] = {} | ||
| def record_agent_task( | ||
| self, | ||
| agent: str, | ||
| task_id: str, | ||
| success: bool, | ||
| quality_score: float, | ||
| duration: float, | ||
| ) -> None: | ||
| """Record agent task execution.""" | ||
| if agent not in self.agent_stats: | ||
| self.agent_stats[agent] = { | ||
| "tasks": [], | ||
| "successes": 0, | ||
| "failures": 0, | ||
| } | ||
| stats = self.agent_stats[agent] | ||
| stats["tasks"].append({ | ||
| "task_id": task_id, | ||
| "success": success, | ||
| "quality": quality_score, | ||
| "duration": duration, | ||
| }) | ||
| if success: | ||
| stats["successes"] += 1 | ||
| else: | ||
| stats["failures"] += 1 | ||
| def get_agent_metrics(self, agent: str) -> Dict[str, Any]: | ||
| """Get metrics for specific agent.""" | ||
| if agent not in self.agent_stats: | ||
| return {"status": "no_data"} | ||
| stats = self.agent_stats[agent] | ||
| tasks = stats["tasks"] | ||
| if not tasks: | ||
| return {"status": "no_tasks"} | ||
| success_rate = stats["successes"] / (stats["successes"] + stats["failures"]) | ||
| quality_scores = [t["quality"] for t in tasks] | ||
| durations = [t["duration"] for t in tasks] | ||
| return { | ||
| "agent": agent, | ||
| "total_tasks": len(tasks), | ||
| "success_rate": success_rate, | ||
| "avg_quality": statistics.mean(quality_scores), | ||
| "avg_duration": statistics.mean(durations), | ||
| "reliability": success_rate, # Alias for clarity | ||
| } | ||
| def rank_agents(self) -> List[tuple]: | ||
| """Rank agents by effectiveness.""" | ||
| rankings = [] | ||
| for agent in self.agent_stats.keys(): | ||
| metrics = self.get_agent_metrics(agent) | ||
| if "success_rate" in metrics: | ||
| score = ( | ||
| metrics["success_rate"] * 0.4 + | ||
| metrics["avg_quality"] * 0.4 + | ||
| (1 - min(metrics["avg_duration"] / 10.0, 1.0)) * 0.2 | ||
| ) | ||
| rankings.append((agent, score, metrics)) | ||
| rankings.sort(key=lambda x: x[1], reverse=True) | ||
| return rankings | ||
| def get_team_report(self) -> Dict[str, Any]: | ||
| """Get team effectiveness report.""" | ||
| rankings = self.rank_agents() | ||
| return { | ||
| "total_agents": len(self.agent_stats), | ||
| "rankings": [ | ||
| { | ||
| "rank": i + 1, | ||
| "agent": agent, | ||
| "score": score, | ||
| "metrics": metrics, | ||
| } | ||
| for i, (agent, score, metrics) in enumerate(rankings) | ||
| ], | ||
| } | ||
| class CollaborationMetrics: | ||
| """Measure collaboration effectiveness between agents.""" | ||
| def __init__(self): | ||
| """Initialize collaboration metrics.""" | ||
| self.interactions: List[Dict] = [] | ||
| def record_interaction( | ||
| self, | ||
| agent_a: str, | ||
| agent_b: str, | ||
| message: str, | ||
| response_time: float, | ||
| successful: bool, | ||
| ) -> None: | ||
| """Record agent-to-agent interaction.""" | ||
| self.interactions.append({ | ||
| "agent_a": agent_a, | ||
| "agent_b": agent_b, | ||
| "message": message, | ||
| "response_time": response_time, | ||
| "successful": successful, | ||
| }) | ||
| def get_collaboration_graph(self) -> Dict[str, List[str]]: | ||
| """Get collaboration graph between agents.""" | ||
| graph = {} | ||
| for interaction in self.interactions: | ||
| agent_a = interaction["agent_a"] | ||
| agent_b = interaction["agent_b"] | ||
| if agent_a not in graph: | ||
| graph[agent_a] = [] | ||
| if agent_b not in graph[agent_a]: | ||
| graph[agent_a].append(agent_b) | ||
| return graph | ||
| def get_interaction_metrics(self) -> Dict[str, Any]: | ||
| """Get interaction metrics.""" | ||
| if not self.interactions: | ||
| return {"total_interactions": 0} | ||
| response_times = [i["response_time"] for i in self.interactions] | ||
| success_rate = sum(1 for i in self.interactions if i["successful"]) / len( | ||
| self.interactions | ||
| ) | ||
| return { | ||
| "total_interactions": len(self.interactions), | ||
| "success_rate": success_rate, | ||
| "avg_response_time": statistics.mean(response_times), | ||
| "median_response_time": statistics.median(response_times), | ||
| "max_response_time": max(response_times), | ||
| "collaboration_score": success_rate * (1 - min(statistics.mean(response_times) / 10.0, 1.0)), | ||
| } | ||
| def get_agent_collaboration_analysis(self, agent: str) -> Dict[str, Any]: | ||
| """Get collaboration analysis for specific agent.""" | ||
| agent_interactions = [ | ||
| i for i in self.interactions | ||
| if i["agent_a"] == agent or i["agent_b"] == agent | ||
| ] | ||
| if not agent_interactions: | ||
| return {"agent": agent, "status": "no_interactions"} | ||
| partners = set() | ||
| for interaction in agent_interactions: | ||
| if interaction["agent_a"] == agent: | ||
| partners.add(interaction["agent_b"]) | ||
| else: | ||
| partners.add(interaction["agent_a"]) | ||
| success_rate = sum( | ||
| 1 for i in agent_interactions if i["successful"] | ||
| ) / len(agent_interactions) | ||
| return { | ||
| "agent": agent, | ||
| "collaboration_partners": list(partners), | ||
| "total_interactions": len(agent_interactions), | ||
| "collaboration_success_rate": success_rate, | ||
| } | ||
| def create_benchmark_suite() -> Dict[str, Callable]: | ||
| """Create standard benchmark suite.""" | ||
| return { | ||
| "sequential_tasks": lambda orchestrator: orchestrator.execute( | ||
| {"type": "sequential", "task_count": 5} | ||
| ), | ||
| "parallel_tasks": lambda orchestrator: orchestrator.execute( | ||
| {"type": "parallel", "task_count": 10} | ||
| ), | ||
| "complex_workflow": lambda orchestrator: orchestrator.execute( | ||
| {"type": "complex", "task_count": 20} | ||
| ), | ||
| "error_handling": lambda orchestrator: orchestrator.execute( | ||
| {"type": "with_errors", "task_count": 10} | ||
| ), | ||
| } |
| """ | ||
| Workflow Management for Multi-Agent Systems | ||
| Handle workflow execution, monitoring, and optimization. | ||
| """ | ||
| from typing import Dict, List, Any, Optional, Callable | ||
| from enum import Enum | ||
| from dataclasses import dataclass, field | ||
| import time | ||
| class WorkflowStatus(Enum): | ||
| """Workflow execution status.""" | ||
| PENDING = "pending" | ||
| RUNNING = "running" | ||
| PAUSED = "paused" | ||
| COMPLETED = "completed" | ||
| FAILED = "failed" | ||
| class TaskStatus(Enum): | ||
| """Task execution status.""" | ||
| PENDING = "pending" | ||
| RUNNING = "running" | ||
| COMPLETED = "completed" | ||
| FAILED = "failed" | ||
| SKIPPED = "skipped" | ||
| @dataclass | ||
| class Task: | ||
| """Task to be executed by an agent.""" | ||
| task_id: str | ||
| agent: str | ||
| description: str | ||
| status: TaskStatus = TaskStatus.PENDING | ||
| result: Optional[str] = None | ||
| error: Optional[str] = None | ||
| start_time: float = field(default_factory=time.time) | ||
| end_time: Optional[float] = None | ||
| dependencies: List[str] = field(default_factory=list) | ||
| @dataclass | ||
| class Workflow: | ||
| """Workflow orchestration.""" | ||
| workflow_id: str | ||
| name: str | ||
| tasks: Dict[str, Task] = field(default_factory=dict) | ||
| status: WorkflowStatus = WorkflowStatus.PENDING | ||
| start_time: Optional[float] = None | ||
| end_time: Optional[float] = None | ||
| class WorkflowExecutor: | ||
| """Execute workflows with multiple agents.""" | ||
| def __init__(self): | ||
| """Initialize workflow executor.""" | ||
| self.workflows: Dict[str, Workflow] = {} | ||
| self.execution_history: List[Dict] = [] | ||
| def create_workflow(self, workflow_id: str, name: str) -> Workflow: | ||
| """Create new workflow.""" | ||
| workflow = Workflow(workflow_id=workflow_id, name=name) | ||
| self.workflows[workflow_id] = workflow | ||
| return workflow | ||
| def add_task( | ||
| self, | ||
| workflow_id: str, | ||
| task_id: str, | ||
| agent: str, | ||
| description: str, | ||
| dependencies: Optional[List[str]] = None, | ||
| ) -> Task: | ||
| """Add task to workflow.""" | ||
| task = Task( | ||
| task_id=task_id, | ||
| agent=agent, | ||
| description=description, | ||
| dependencies=dependencies or [], | ||
| ) | ||
| self.workflows[workflow_id].tasks[task_id] = task | ||
| return task | ||
| def execute_workflow( | ||
| self, workflow_id: str, executor_func: Callable | ||
| ) -> Dict[str, Any]: | ||
| """ | ||
| Execute workflow. | ||
| Args: | ||
| workflow_id: Workflow ID | ||
| executor_func: Function to execute tasks | ||
| Returns: | ||
| Execution results | ||
| """ | ||
| workflow = self.workflows[workflow_id] | ||
| workflow.status = WorkflowStatus.RUNNING | ||
| workflow.start_time = time.time() | ||
| executed_tasks = set() | ||
| results = {} | ||
| while len(executed_tasks) < len(workflow.tasks): | ||
| # Find ready tasks | ||
| ready_tasks = self._get_ready_tasks(workflow, executed_tasks) | ||
| if not ready_tasks: | ||
| # Check if workflow is stuck | ||
| if len(executed_tasks) > 0: | ||
| break | ||
| for task_id in ready_tasks: | ||
| task = workflow.tasks[task_id] | ||
| task.status = TaskStatus.RUNNING | ||
| try: | ||
| # Execute task | ||
| result = executor_func(task) | ||
| task.result = result | ||
| task.status = TaskStatus.COMPLETED | ||
| results[task_id] = result | ||
| except Exception as e: | ||
| task.error = str(e) | ||
| task.status = TaskStatus.FAILED | ||
| results[task_id] = None | ||
| task.end_time = time.time() | ||
| executed_tasks.add(task_id) | ||
| # Finalize workflow | ||
| workflow.end_time = time.time() | ||
| if all(task.status == TaskStatus.COMPLETED for task in workflow.tasks.values()): | ||
| workflow.status = WorkflowStatus.COMPLETED | ||
| else: | ||
| workflow.status = WorkflowStatus.FAILED | ||
| execution_record = { | ||
| "workflow_id": workflow_id, | ||
| "status": workflow.status.value, | ||
| "duration": workflow.end_time - workflow.start_time, | ||
| "results": results, | ||
| } | ||
| self.execution_history.append(execution_record) | ||
| return results | ||
| def _get_ready_tasks( | ||
| self, workflow: Workflow, executed: set | ||
| ) -> List[str]: | ||
| """Get tasks ready to execute.""" | ||
| ready = [] | ||
| for task_id, task in workflow.tasks.items(): | ||
| if task_id not in executed and task.status == TaskStatus.PENDING: | ||
| # Check if all dependencies are complete | ||
| deps_met = all(dep in executed for dep in task.dependencies) | ||
| if deps_met: | ||
| ready.append(task_id) | ||
| return ready | ||
| def get_workflow_status(self, workflow_id: str) -> Dict[str, Any]: | ||
| """Get workflow status.""" | ||
| workflow = self.workflows[workflow_id] | ||
| return { | ||
| "id": workflow.workflow_id, | ||
| "name": workflow.name, | ||
| "status": workflow.status.value, | ||
| "tasks": { | ||
| task_id: task.status.value | ||
| for task_id, task in workflow.tasks.items() | ||
| }, | ||
| } | ||
| class WorkflowOptimizer: | ||
| """Optimize workflow execution.""" | ||
| @staticmethod | ||
| def analyze_dependencies(workflow: Workflow) -> Dict[str, Any]: | ||
| """Analyze task dependencies.""" | ||
| dep_graph = {} | ||
| for task_id, task in workflow.tasks.items(): | ||
| dep_graph[task_id] = task.dependencies | ||
| # Find critical path | ||
| critical_path = WorkflowOptimizer._find_critical_path( | ||
| dep_graph, workflow.tasks | ||
| ) | ||
| # Find parallelizable tasks | ||
| parallel_groups = WorkflowOptimizer._find_parallel_groups(dep_graph) | ||
| return { | ||
| "dependency_graph": dep_graph, | ||
| "critical_path": critical_path, | ||
| "parallelizable_groups": parallel_groups, | ||
| } | ||
| @staticmethod | ||
| def _find_critical_path(dep_graph: Dict, tasks: Dict) -> List[str]: | ||
| """Find tasks on critical path.""" | ||
| # Simple implementation - actual critical path is more complex | ||
| return list(dep_graph.keys()) | ||
| @staticmethod | ||
| def _find_parallel_groups(dep_graph: Dict) -> List[List[str]]: | ||
| """Find groups of tasks that can execute in parallel.""" | ||
| groups = [] | ||
| remaining = set(dep_graph.keys()) | ||
| while remaining: | ||
| # Find tasks with no dependencies in remaining set | ||
| independent = [ | ||
| task | ||
| for task in remaining | ||
| if not any(dep in remaining for dep in dep_graph.get(task, [])) | ||
| ] | ||
| if independent: | ||
| groups.append(independent) | ||
| remaining -= set(independent) | ||
| else: | ||
| break | ||
| return groups | ||
| @staticmethod | ||
| def estimate_execution_time( | ||
| workflow: Workflow, task_times: Dict[str, float] | ||
| ) -> float: | ||
| """Estimate total execution time.""" | ||
| parallel_groups = WorkflowOptimizer._find_parallel_groups({ | ||
| task_id: task.dependencies | ||
| for task_id, task in workflow.tasks.items() | ||
| }) | ||
| total_time = 0 | ||
| for group in parallel_groups: | ||
| group_time = max( | ||
| task_times.get(task_id, 1.0) for task_id in group | ||
| ) | ||
| total_time += group_time | ||
| return total_time | ||
| @staticmethod | ||
| def suggest_parallelization(workflow: Workflow) -> List[Dict[str, Any]]: | ||
| """Suggest ways to parallelize workflow.""" | ||
| suggestions = [] | ||
| dep_graph = { | ||
| task_id: task.dependencies | ||
| for task_id, task in workflow.tasks.items() | ||
| } | ||
| # Find sequential chains that could be parallelized | ||
| for task_id, dependencies in dep_graph.items(): | ||
| if len(dependencies) == 0: | ||
| suggestions.append({ | ||
| "task": task_id, | ||
| "suggestion": "Can be parallelized with other independent tasks", | ||
| }) | ||
| return suggestions | ||
| class WorkflowMonitor: | ||
| """Monitor workflow execution.""" | ||
| def __init__(self): | ||
| """Initialize monitor.""" | ||
| self.events: List[Dict] = [] | ||
| def record_event( | ||
| self, workflow_id: str, task_id: str, event_type: str, data: Dict | ||
| ) -> None: | ||
| """Record workflow event.""" | ||
| event = { | ||
| "workflow_id": workflow_id, | ||
| "task_id": task_id, | ||
| "event_type": event_type, | ||
| "timestamp": time.time(), | ||
| "data": data, | ||
| } | ||
| self.events.append(event) | ||
| def get_workflow_metrics(self, workflow_id: str) -> Dict[str, Any]: | ||
| """Get workflow metrics.""" | ||
| workflow_events = [e for e in self.events if e["workflow_id"] == workflow_id] | ||
| task_times = {} | ||
| for event in workflow_events: | ||
| task_id = event["task_id"] | ||
| if event["event_type"] == "start": | ||
| task_times[task_id] = {"start": event["timestamp"]} | ||
| elif event["event_type"] == "complete": | ||
| if task_id in task_times: | ||
| task_times[task_id]["end"] = event["timestamp"] | ||
| # Calculate durations | ||
| durations = { | ||
| task_id: times.get("end", time.time()) - times["start"] | ||
| for task_id, times in task_times.items() | ||
| } | ||
| return { | ||
| "total_tasks": len(task_times), | ||
| "task_durations": durations, | ||
| "avg_duration": sum(durations.values()) / len(durations) | ||
| if durations | ||
| else 0, | ||
| "max_duration": max(durations.values()) if durations else 0, | ||
| } | ||
| def get_performance_report(self) -> Dict[str, Any]: | ||
| """Get overall performance report.""" | ||
| if not self.events: | ||
| return {"status": "no_events"} | ||
| workflow_ids = set(e["workflow_id"] for e in self.events) | ||
| report = {} | ||
| for workflow_id in workflow_ids: | ||
| report[workflow_id] = self.get_workflow_metrics(workflow_id) | ||
| return report |
| --- | ||
| name: multi-agent-orchestration | ||
| description: Design and coordinate multi-agent systems where specialized agents work together to solve complex problems. Covers agent communication, task delegation, workflow orchestration, and result aggregation. Use when building coordinated agent teams, complex workflows, or systems requiring specialized expertise across domains. | ||
| --- | ||
| # Multi-Agent Orchestration | ||
| Design and orchestrate sophisticated multi-agent systems where specialized agents collaborate to solve complex problems, combining different expertise and perspectives. | ||
| ## Quick Start | ||
| Get started with multi-agent implementations in the examples and utilities: | ||
| - **Examples**: See [`examples/`](examples/) directory for complete implementations: | ||
| - [`orchestration_patterns.py`](examples/orchestration_patterns.py) - Sequential, parallel, hierarchical, and consensus orchestration | ||
| - [`framework_implementations.py`](examples/framework_implementations.py) - Templates for CrewAI, AutoGen, LangGraph, and Swarm | ||
| - **Utilities**: See [`scripts/`](scripts/) directory for helper modules: | ||
| - [`agent_communication.py`](scripts/agent_communication.py) - Message broker, shared memory, and communication protocols | ||
| - [`workflow_management.py`](scripts/workflow_management.py) - Workflow execution, optimization, and monitoring | ||
| - [`benchmarking.py`](scripts/benchmarking.py) - Team performance and agent effectiveness metrics | ||
| ## Overview | ||
| Multi-agent systems decompose complex problems into specialized sub-tasks, assigning each to an agent with relevant expertise, then coordinating their work toward a unified goal. | ||
| ### When Multi-Agent Systems Shine | ||
| - **Complex Workflows**: Tasks requiring multiple specialized roles | ||
| - **Domain-Specific Expertise**: Finance, legal, HR, engineering need different knowledge | ||
| - **Parallel Processing**: Multiple agents work on different aspects simultaneously | ||
| - **Collaborative Reasoning**: Agents debate, refine, and improve solutions | ||
| - **Resilience**: Failures in one agent don't break the entire system | ||
| - **Scalability**: Easy to add new specialized agents | ||
| ### Architecture Overview | ||
| ``` | ||
| User Request | ||
| ↓ | ||
| Orchestrator | ||
| ├→ Agent 1 (Specialist) → Task 1 | ||
| ├→ Agent 2 (Specialist) → Task 2 | ||
| ├→ Agent 3 (Specialist) → Task 3 | ||
| ↓ | ||
| Result Aggregator | ||
| ↓ | ||
| Final Response | ||
| ``` | ||
| ## Core Concepts | ||
| ### Agent Definition | ||
| An agent is defined by: | ||
| - **Role**: What responsibility does it have? (e.g., "Financial Analyst") | ||
| - **Goal**: What should it accomplish? (e.g., "Analyze financial risks") | ||
| - **Expertise**: What knowledge/tools does it have? | ||
| - **Tools**: What capabilities can it access? | ||
| - **Context**: What information does it need to work effectively? | ||
| ### Orchestration Patterns | ||
| #### 1. Sequential Orchestration | ||
| - Agents work one after another | ||
| - Each agent uses output from previous agent | ||
| - **Use Case**: Steps must follow order (research → analysis → writing) | ||
| #### 2. Parallel Orchestration | ||
| - Multiple agents work simultaneously | ||
| - Results aggregated at the end | ||
| - **Use Case**: Independent tasks (analyze competitors, market, users) | ||
| #### 3. Hierarchical Orchestration | ||
| - Senior agent delegates to junior agents | ||
| - Manager coordinates flow | ||
| - **Use Case**: Large projects with oversight | ||
| #### 4. Consensus-Based Orchestration | ||
| - Multiple agents analyze problem | ||
| - Debate and refine ideas | ||
| - Vote or reach consensus | ||
| - **Use Case**: Complex decisions needing multiple perspectives | ||
| #### 5. Tool-Mediated Orchestration | ||
| - Agents use shared tools/databases | ||
| - Minimal direct communication | ||
| - **Use Case**: Large systems, indirect coordination | ||
| ## Multi-Agent Team Examples | ||
| ### Finance Team | ||
| ``` | ||
| Coordinator Agent | ||
| ├→ Market Analyst Agent | ||
| │ ├ Tools: Market data API, financial news | ||
| │ └ Task: Analyze market conditions | ||
| ├→ Financial Analyst Agent | ||
| │ ├ Tools: Financial statements, ratio calculations | ||
| │ └ Task: Analyze company financials | ||
| ├→ Risk Manager Agent | ||
| │ ├ Tools: Risk models, scenario analysis | ||
| │ └ Task: Assess investment risks | ||
| └→ Report Writer Agent | ||
| ├ Tools: Document generation | ||
| └ Task: Synthesize findings into report | ||
| ``` | ||
| ### Legal Team | ||
| ``` | ||
| Case Manager Agent (Coordinator) | ||
| ├→ Contract Analyzer Agent | ||
| │ └ Task: Review contract terms | ||
| ├→ Precedent Research Agent | ||
| │ └ Task: Find relevant case law | ||
| ├→ Risk Assessor Agent | ||
| │ └ Task: Identify legal risks | ||
| └→ Document Drafter Agent | ||
| └ Task: Prepare legal documents | ||
| ``` | ||
| ### Customer Support Team | ||
| ``` | ||
| Support Coordinator | ||
| ├→ Issue Classifier Agent | ||
| │ └ Task: Categorize customer issue | ||
| ├→ Knowledge Base Agent | ||
| │ └ Task: Find relevant documentation | ||
| ├→ Escalation Agent | ||
| │ └ Task: Determine if human escalation needed | ||
| └→ Solution Synthesizer Agent | ||
| └ Task: Prepare comprehensive response | ||
| ``` | ||
| ## Implementation Frameworks | ||
| ### 1. CrewAI | ||
| **Best For**: Teams with clear roles and hierarchical structure | ||
| ```python | ||
| from crewai import Agent, Task, Crew | ||
| # Define agents | ||
| analyst = Agent( | ||
| role="Financial Analyst", | ||
| goal="Analyze financial data and provide insights", | ||
| backstory="Expert in financial markets with 10+ years experience" | ||
| ) | ||
| researcher = Agent( | ||
| role="Market Researcher", | ||
| goal="Research market trends and competition", | ||
| backstory="Data-driven researcher specializing in market analysis" | ||
| ) | ||
| # Define tasks | ||
| analysis_task = Task( | ||
| description="Analyze Q3 financial results for {company}", | ||
| agent=analyst, | ||
| tools=[financial_tool, data_tool] | ||
| ) | ||
| research_task = Task( | ||
| description="Research competitive landscape in {market}", | ||
| agent=researcher, | ||
| tools=[web_search_tool, industry_data_tool] | ||
| ) | ||
| # Create crew and execute | ||
| crew = Crew( | ||
| agents=[analyst, researcher], | ||
| tasks=[analysis_task, research_task], | ||
| process=Process.sequential | ||
| ) | ||
| result = crew.kickoff(inputs={"company": "TechCorp", "market": "AI"}) | ||
| ``` | ||
| ### 2. AutoGen (Microsoft) | ||
| **Best For**: Complex multi-turn conversations and negotiations | ||
| ```python | ||
| from autogen import AssistantAgent, UserProxyAgent, GroupChat, GroupChatManager | ||
| # Define agents | ||
| analyst = AssistantAgent( | ||
| name="analyst", | ||
| system_message="You are a financial analyst..." | ||
| ) | ||
| researcher = AssistantAgent( | ||
| name="researcher", | ||
| system_message="You are a market researcher..." | ||
| ) | ||
| # Create group chat | ||
| groupchat = GroupChat( | ||
| agents=[analyst, researcher], | ||
| messages=[], | ||
| max_round=10, | ||
| speaker_selection_method="auto" | ||
| ) | ||
| # Manage group conversation | ||
| manager = GroupChatManager(groupchat=groupchat) | ||
| # User proxy to initiate conversation | ||
| user = UserProxyAgent(name="user") | ||
| # Have conversation | ||
| user.initiate_chat( | ||
| manager, | ||
| message="Analyze if Company X should invest in Y market" | ||
| ) | ||
| ``` | ||
| ### 3. LangGraph | ||
| **Best For**: Complex workflows with state management | ||
| ```python | ||
| from langgraph.graph import Graph, StateGraph | ||
| from langgraph.prebuilt import create_agent_executor | ||
| # Define state | ||
| class AgentState: | ||
| research_findings: str | ||
| analysis: str | ||
| recommendations: str | ||
| # Create graph | ||
| graph = StateGraph(AgentState) | ||
| # Add nodes for each agent | ||
| graph.add_node("researcher", research_agent) | ||
| graph.add_node("analyst", analyst_agent) | ||
| graph.add_node("writer", writer_agent) | ||
| # Define edges (workflow) | ||
| graph.add_edge("researcher", "analyst") | ||
| graph.add_edge("analyst", "writer") | ||
| # Set entry/exit points | ||
| graph.set_entry_point("researcher") | ||
| graph.set_finish_point("writer") | ||
| # Compile and run | ||
| workflow = graph.compile() | ||
| result = workflow.invoke({"topic": "AI trends"}) | ||
| ``` | ||
| ### 4. OpenAI Swarm | ||
| **Best For**: Simple agent handoffs and conversational workflows | ||
| ```python | ||
| from swarm import Agent, Swarm | ||
| # Define agents | ||
| triage_agent = Agent( | ||
| name="Triage Agent", | ||
| instructions="Determine which specialist to route the customer to" | ||
| ) | ||
| billing_agent = Agent( | ||
| name="Billing Specialist", | ||
| instructions="Handle billing and payment questions" | ||
| ) | ||
| technical_agent = Agent( | ||
| name="Technical Support", | ||
| instructions="Handle technical issues" | ||
| ) | ||
| # Define handoff functions | ||
| def route_to_billing(reason: str): | ||
| return billing_agent | ||
| def route_to_technical(reason: str): | ||
| return technical_agent | ||
| # Add tools to triage agent | ||
| triage_agent.functions = [route_to_billing, route_to_technical] | ||
| # Execute swarm | ||
| client = Swarm() | ||
| response = client.run( | ||
| agent=triage_agent, | ||
| messages=[{"role": "user", "content": "I have a billing question"}] | ||
| ) | ||
| ``` | ||
| ## Orchestration Patterns | ||
| ### Pattern 1: Sequential Task Chain | ||
| Agents execute tasks in sequence, each building on previous results: | ||
| ```python | ||
| # Task 1: Research | ||
| research_output = research_agent.work("Analyze AI market trends") | ||
| # Task 2: Analysis (uses research output) | ||
| analysis = analyst_agent.work(f"Analyze these findings: {research_output}") | ||
| # Task 3: Report (uses analysis) | ||
| report = writer_agent.work(f"Write report on: {analysis}") | ||
| ``` | ||
| **When to Use**: Steps have dependencies, each builds on previous | ||
| ### Pattern 2: Parallel Execution | ||
| Multiple agents work simultaneously, results combined: | ||
| ```python | ||
| import asyncio | ||
| async def parallel_teams(): | ||
| # All agents work in parallel | ||
| market_task = market_agent.work_async("Analyze market") | ||
| technical_task = tech_agent.work_async("Analyze technology") | ||
| user_task = user_agent.work_async("Analyze user needs") | ||
| # Wait for all to complete | ||
| market_results, tech_results, user_results = await asyncio.gather( | ||
| market_task, technical_task, user_task | ||
| ) | ||
| # Synthesize results | ||
| return synthesize(market_results, tech_results, user_results) | ||
| ``` | ||
| **When to Use**: Independent analyses, need quick results, want diversity | ||
| ### Pattern 3: Hierarchical Structure | ||
| Manager agent coordinates specialists: | ||
| ```python | ||
| manager_agent.orchestrate({ | ||
| "market_analysis": { | ||
| "agents": [competitor_analyst, trend_analyst], | ||
| "task": "Comprehensive market analysis" | ||
| }, | ||
| "technical_evaluation": { | ||
| "agents": [architecture_agent, security_agent], | ||
| "task": "Technical feasibility assessment" | ||
| }, | ||
| "synthesis": { | ||
| "agents": [strategy_agent], | ||
| "task": "Create strategic recommendations" | ||
| } | ||
| }) | ||
| ``` | ||
| **When to Use**: Clear hierarchy, different teams, complex coordination | ||
| ### Pattern 4: Debate & Consensus | ||
| Multiple agents discuss and reach consensus: | ||
| ```python | ||
| agents = [bull_agent, bear_agent, neutral_agent] | ||
| question = "Should we invest in this startup?" | ||
| # Debate round 1 | ||
| arguments = {agent: agent.argue(question) for agent in agents} | ||
| # Debate round 2 (respond to others) | ||
| counter_arguments = { | ||
| agent: agent.respond(arguments) for agent in agents | ||
| } | ||
| # Reach consensus | ||
| consensus = mediator_agent.synthesize_consensus(counter_arguments) | ||
| ``` | ||
| **When to Use**: Complex decisions, need multiple perspectives, risk assessment | ||
| ## Agent Communication Patterns | ||
| ### 1. Direct Communication | ||
| Agents pass messages directly to each other: | ||
| ```python | ||
| agent_a.send_message(agent_b, { | ||
| "type": "request", | ||
| "action": "analyze_document", | ||
| "document": doc_content, | ||
| "context": {"deadline": "urgent"} | ||
| }) | ||
| ``` | ||
| ### 2. Tool-Mediated Communication | ||
| Agents use shared tools/databases: | ||
| ```python | ||
| # Agent A writes to shared memory | ||
| shared_memory.write("findings", {"market_size": "$5B", "growth": "20%"}) | ||
| # Agent B reads from shared memory | ||
| findings = shared_memory.read("findings") | ||
| ``` | ||
| ### 3. Manager-Based Communication | ||
| Central coordinator manages agent communication: | ||
| ```python | ||
| manager.broadcast("update_all_agents", { | ||
| "new_deadline": "tomorrow", | ||
| "priority": "critical" | ||
| }) | ||
| ``` | ||
| ## Best Practices | ||
| ### Agent Design | ||
| - ✓ Clear, specific role and goal | ||
| - ✓ Appropriate tools for the role | ||
| - ✓ Relevant background/expertise | ||
| - ✓ Distinct from other agents | ||
| - ✓ Reasonable scope of work | ||
| ### Workflow Design | ||
| - ✓ Clear task dependencies | ||
| - ✓ Identified handoff points | ||
| - ✓ Error handling between agents | ||
| - ✓ Fallback strategies | ||
| - ✓ Performance monitoring | ||
| ### Communication | ||
| - ✓ Structured message formats | ||
| - ✓ Clear context sharing | ||
| - ✓ Error propagation strategy | ||
| - ✓ Timeout handling | ||
| - ✓ Audit logging | ||
| ### Orchestration | ||
| - ✓ Define process clearly (sequential, parallel, etc.) | ||
| - ✓ Set clear success criteria | ||
| - ✓ Monitor agent performance | ||
| - ✓ Implement feedback loops | ||
| - ✓ Allow human intervention points | ||
| ## Common Challenges & Solutions | ||
| ### Challenge: Agent Conflicts | ||
| **Solutions**: | ||
| - Clear role separation | ||
| - Explicit decision-making rules | ||
| - Consensus mechanisms | ||
| - Conflict resolution agent | ||
| - Clear authority hierarchy | ||
| ### Challenge: Slow Execution | ||
| **Solutions**: | ||
| - Use parallel execution where possible | ||
| - Cache results from expensive operations | ||
| - Pre-process data | ||
| - Optimize agent logic | ||
| - Implement timeout handling | ||
| ### Challenge: Poor Quality Results | ||
| **Solutions**: | ||
| - Better agent prompts/instructions | ||
| - More relevant tools | ||
| - Feedback integration | ||
| - Quality validation agents | ||
| - Result aggregation strategies | ||
| ### Challenge: Complex Workflows | ||
| **Solutions**: | ||
| - Break into smaller teams | ||
| - Hierarchical structure | ||
| - Clear task definitions | ||
| - Good state management | ||
| - Documentation of workflow | ||
| ## Evaluation Metrics | ||
| **Team Performance**: | ||
| - Task completion rate | ||
| - Quality of results | ||
| - Execution time | ||
| - Cost (tokens/API calls) | ||
| - Error rate | ||
| **Agent Effectiveness**: | ||
| - Task success rate | ||
| - Response quality | ||
| - Tool usage efficiency | ||
| - Communication clarity | ||
| - Collaboration score | ||
| ## Advanced Techniques | ||
| ### 1. Self-Organizing Teams | ||
| Agents autonomously decide roles and workflow: | ||
| ```python | ||
| # Agents negotiate roles based on task | ||
| agents = [agent1, agent2, agent3] | ||
| task = "complex financial analysis" | ||
| # Agents determine best structure | ||
| negotiated_structure = self_organize(agents, task) | ||
| # Returns optimal workflow for this task | ||
| ``` | ||
| ### 2. Adaptive Workflows | ||
| Workflow changes based on progress: | ||
| ```python | ||
| # Monitor progress | ||
| if progress < expected_rate: | ||
| # Increase resources | ||
| workflow.add_agent(specialist_agent) | ||
| elif quality < threshold: | ||
| # Increase validation | ||
| workflow.insert_review_step() | ||
| ``` | ||
| ### 3. Cross-Agent Learning | ||
| Agents learn from each other's work: | ||
| ```python | ||
| # After team execution | ||
| execution_trace = crew.get_execution_trace() | ||
| # Extract learnings | ||
| learnings = extract_patterns(execution_trace) | ||
| # Update agent knowledge | ||
| for agent, learning in learnings.items(): | ||
| agent.update_knowledge(learning) | ||
| ``` | ||
| ## Resources | ||
| ### Frameworks | ||
| - **CrewAI**: https://crewai.com/ | ||
| - **AutoGen**: https://microsoft.github.io/autogen/ | ||
| - **LangGraph**: https://langchain-ai.github.io/langgraph/ | ||
| - **Swarm**: https://github.com/openai/swarm | ||
| ### Papers | ||
| - "Generative Agents" (Park et al.) | ||
| - "Self-Organizing Multi-Agent Systems" (research papers) | ||
| ## Implementation Checklist | ||
| - [ ] Define each agent's role, goal, and expertise | ||
| - [ ] Identify available tools/capabilities for each agent | ||
| - [ ] Plan workflow (sequential, parallel, hierarchical) | ||
| - [ ] Define communication patterns | ||
| - [ ] Implement task definitions | ||
| - [ ] Set success criteria for each task | ||
| - [ ] Add error handling and fallbacks | ||
| - [ ] Implement monitoring/logging | ||
| - [ ] Test team collaboration | ||
| - [ ] Evaluate quality and performance | ||
| - [ ] Optimize based on results | ||
| - [ ] Document workflow and decisions | ||
| ## Getting Started | ||
| 1. **Start Small**: Begin with 2-3 agents | ||
| 2. **Clear Workflow**: Document how agents interact | ||
| 3. **Test Thoroughly**: Validate agent behavior individually and together | ||
| 4. **Monitor Closely**: Track performance and results | ||
| 5. **Iterate**: Refine based on results | ||
| 6. **Scale**: Add agents and complexity as needed | ||
| # PageSpeed Insights — Reference & Official Documentation | ||
| This file complements the pagespeed-insights skill with official documentation links for indexing. | ||
| ## Official documentation (indexable) | ||
| - **PageSpeed Insights about**: https://developers.google.com/speed/docs/insights/v5/about?hl=es-419 | ||
| - **PageSpeed Insights (tool)**: https://pagespeed.web.dev/ | ||
| - **Lighthouse**: https://developer.chrome.com/docs/lighthouse/ | ||
| - **Core Web Vitals**: https://web.dev/vitals/ | ||
| - **Chrome User Experience Report (CrUX)**: https://developer.chrome.com/docs/crux/ | ||
| ## Core Web Vitals (metrics) | ||
| - **LCP (Largest Contentful Paint)**: https://web.dev/lcp/ | ||
| - **FCP (First Contentful Paint)**: https://web.dev/fcp/ | ||
| - **CLS (Cumulative Layout Shift)**: https://web.dev/cls/ | ||
| - **INP (Interaction to Next Paint)**: https://web.dev/inp/ | ||
| - **TTFB (Time to First Byte)**: https://web.dev/ttfb/ | ||
| ## Lab vs field data | ||
| - **Lab data**: Lighthouse, controlled environment, debugging | ||
| - **Field data**: CrUX, real user metrics, 28-day aggregation | ||
| - **Understanding metrics**: https://web.dev/metrics/ | ||
| ## Performance optimization guides | ||
| - **Optimize LCP**: https://web.dev/optimize-lcp/ | ||
| - **Optimize CLS**: https://web.dev/optimize-cls/ | ||
| - **Optimize INP**: https://web.dev/optimize-inp/ | ||
| - **Optimize FCP**: https://web.dev/optimize-fcp/ | ||
| - **Resource hints**: https://web.dev/preconnect-and-dns-prefetch/ | ||
| - **Image optimization**: https://web.dev/fast/#optimize-your-images | ||
| ## Tools | ||
| - **PageSpeed Insights**: https://pagespeed.web.dev/ | ||
| - **Lighthouse (Chrome DevTools)**: Built-in, Audits tab | ||
| - **Web Vitals extension**: Real-time monitoring | ||
| - **Chromatic (Lighthouse CI)**: https://github.com/GoogleChrome/lighthouse-ci | ||
| ## Score thresholds (reminder) | ||
| | Category | Good | Needs Improvement | Poor | | ||
| |----------|------|-------------------|------| | ||
| | Performance | 90-100 | 50-89 | 0-49 | | ||
| | Accessibility | 90-100 | 50-89 | 0-49 | | ||
| | Best Practices | 90-100 | 50-89 | 0-49 | | ||
| | SEO | 90-100 | 50-89 | 0-49 | |
| --- | ||
| name: pagespeed-insights | ||
| description: Audit web pages for performance optimization following PageSpeed Insights guidelines. Use when analyzing page performance, optimizing web applications, reviewing performance metrics, implementing Core Web Vitals improvements, or when the user mentions page speed, performance optimization, Lighthouse scores, or Core Web Vitals. | ||
| --- | ||
| # PageSpeed Insights Auditor | ||
| ## Overview | ||
| You are a **PageSpeed Insights Auditor** - an expert in web performance optimization who helps developers achieve excellent PageSpeed scores by identifying performance issues, avoiding bad practices, and implementing best practices based on Google's PageSpeed Insights guidelines. | ||
| **Core Principle**: Guide developers to achieve scores of 90+ (Good) in Performance, Accessibility, Best Practices, and SEO categories, while ensuring Core Web Vitals metrics meet the "Good" thresholds. | ||
| ## Understanding PageSpeed Insights | ||
| PageSpeed Insights (PSI) analyzes page performance on mobile and desktop devices, providing both **lab data** (simulated) and **field data** (real user experiences). PSI reports on user experience metrics and provides diagnostic suggestions to improve page performance. | ||
| ### Two Types of Data | ||
| 1. **Lab Data**: Collected in a controlled environment using Lighthouse. Useful for debugging but may not capture real-world bottlenecks. | ||
| 2. **Field Data**: Real user experience data from Chrome User Experience Report (CrUX). Useful for capturing actual user experiences but has a more limited set of metrics. | ||
| ## Performance Score Thresholds | ||
| ### Lab Scores (Lighthouse) | ||
| | Score Range | Rating | Icon | | ||
| | ----------- | ----------------- | --------------- | | ||
| | 90-100 | Good | 🟢 Green circle | | ||
| | 50-89 | Needs Improvement | 🟡 Amber square | | ||
| | 0-49 | Poor | 🔴 Red triangle | | ||
| **Target**: Always aim for scores of **90 or higher** in all categories. | ||
| ### Core Web Vitals Thresholds | ||
| Core Web Vitals are the three most important metrics for web performance: | ||
| | Metric | Good | Needs Improvement | Poor | | ||
| | ----------------------------------- | ------------ | ------------------ | --------- | | ||
| | **FCP** (First Contentful Paint) | [0, 1800 ms] | [1800 ms, 3000 ms] | > 3000 ms | | ||
| | **LCP** (Largest Contentful Paint) | [0, 2500 ms] | [2500 ms, 4000 ms] | > 4000 ms | | ||
| | **CLS** (Cumulative Layout Shift) | [0, 0.1] | [0.1, 0.25] | > 0.25 | | ||
| | **INP** (Interaction to Next Paint) | [0, 200 ms] | [200 ms, 500 ms] | > 500 ms | | ||
| | **TTFB** (Time to First Byte) | [0, 800 ms] | [800 ms, 1800 ms] | > 1800 ms | | ||
| **Target**: Ensure the 75th percentile of all Core Web Vitals metrics are in the "Good" range. | ||
| ## Key Performance Metrics | ||
| ### Lab Metrics (Lighthouse) | ||
| 1. **First Contentful Paint (FCP)**: Time until first content is rendered | ||
| 2. **Largest Contentful Paint (LCP)**: Time until largest content element is rendered | ||
| 3. **Speed Index**: How quickly content is visually displayed | ||
| 4. **Cumulative Layout Shift (CLS)**: Visual stability measure | ||
| 5. **Total Blocking Time (TBT)**: Sum of blocking time between FCP and TTI | ||
| 6. **Time to Interactive (TTI)**: Time until page is fully interactive | ||
| ### Field Metrics (CrUX) | ||
| - **FCP**: First Contentful Paint from real users | ||
| - **LCP**: Largest Contentful Paint from real users | ||
| - **CLS**: Cumulative Layout Shift from real users | ||
| - **INP**: Interaction to Next Paint (replaces FID) | ||
| - **TTFB**: Time to First Byte (experimental) | ||
| ## Common Performance Issues & Solutions | ||
| ### ❌ Bad Practice: Unoptimized Images | ||
| **Problem**: Large images without compression, modern formats, or proper sizing. | ||
| **Impact**: Poor LCP scores, slow page loads. | ||
| **✅ Solutions**: | ||
| - Use modern image formats (WebP, AVIF) | ||
| - Implement responsive images with `srcset` | ||
| - Compress images before uploading | ||
| - Set explicit width/height to prevent CLS | ||
| - Use lazy loading for below-the-fold images | ||
| ```html | ||
| <!-- Bad --> | ||
| <img src="large-image.jpg" alt="Description" /> | ||
| <!-- Good --> | ||
| <img | ||
| src="image.webp" | ||
| srcset="image-small.webp 400w, image-medium.webp 800w, image-large.webp 1200w" | ||
| sizes="(max-width: 600px) 400px, (max-width: 1200px) 800px, 1200px" | ||
| width="1200" | ||
| height="800" | ||
| alt="Description" | ||
| loading="lazy" | ||
| /> | ||
| ``` | ||
| ### ❌ Bad Practice: Render-Blocking Resources | ||
| **Problem**: CSS and JavaScript blocking initial render. | ||
| **Impact**: Poor FCP and LCP scores. | ||
| **✅ Solutions**: | ||
| - Defer non-critical CSS | ||
| - Inline critical CSS | ||
| - Use `async` or `defer` for JavaScript | ||
| - Remove unused CSS/JS | ||
| - Split code and lazy load routes | ||
| ```html | ||
| <!-- Bad --> | ||
| <link rel="stylesheet" href="styles.css" /> | ||
| <script src="app.js"></script> | ||
| <!-- Good --> | ||
| <link | ||
| rel="stylesheet" | ||
| href="styles.css" | ||
| media="print" | ||
| onload="this.media='all'" | ||
| /> | ||
| <link rel="preload" href="critical.css" as="style" /> | ||
| <script src="app.js" defer></script> | ||
| ``` | ||
| ### ❌ Bad Practice: Missing Resource Hints | ||
| **Problem**: Not preconnecting to important origins or prefetching critical resources. | ||
| **Impact**: Slow TTFB and LCP. | ||
| **✅ Solutions**: | ||
| - Use `rel="preconnect"` for third-party origins | ||
| - Use `rel="dns-prefetch"` for DNS resolution | ||
| - Use `rel="preload"` for critical resources | ||
| - Use `rel="prefetch"` for likely next-page resources | ||
| ```html | ||
| <!-- Good --> | ||
| <link rel="preconnect" href="https://fonts.googleapis.com" /> | ||
| <link rel="dns-prefetch" href="https://api.example.com" /> | ||
| <link rel="preload" href="hero-image.webp" as="image" /> | ||
| ``` | ||
| ### ❌ Bad Practice: Layout Shift (CLS) | ||
| **Problem**: Content shifting during page load. | ||
| **Impact**: Poor CLS scores, bad user experience. | ||
| **✅ Solutions**: | ||
| - Set explicit dimensions for images and videos | ||
| - Reserve space for ads and embeds | ||
| - Avoid inserting content above existing content | ||
| - Use CSS aspect-ratio for responsive containers | ||
| - Prefer transform animations over layout-triggering properties | ||
| ```css | ||
| /* Bad */ | ||
| .image-container { | ||
| width: 100%; | ||
| /* height not set - causes CLS */ | ||
| } | ||
| /* Good */ | ||
| .image-container { | ||
| width: 100%; | ||
| aspect-ratio: 16 / 9; | ||
| /* or */ | ||
| height: 0; | ||
| padding-bottom: 56.25%; /* 16:9 ratio */ | ||
| } | ||
| ``` | ||
| ### ❌ Bad Practice: Large JavaScript Bundles | ||
| **Problem**: Loading unnecessary JavaScript code. | ||
| **Impact**: Poor TTI, high TBT. | ||
| **✅ Solutions**: | ||
| - Code splitting and lazy loading | ||
| - Remove unused code (tree shaking) | ||
| - Minimize and compress JavaScript | ||
| - Use dynamic imports for routes | ||
| - Avoid large third-party libraries when possible | ||
| ```javascript | ||
| // Bad - loading everything upfront | ||
| import { heavyLibrary } from "./heavy-library"; | ||
| // Good - lazy load when needed | ||
| const loadHeavyLibrary = () => import("./heavy-library"); | ||
| ``` | ||
| ### ❌ Bad Practice: Inefficient Font Loading | ||
| **Problem**: Fonts causing FOIT (Flash of Invisible Text) or FOUT (Flash of Unstyled Text). | ||
| **Impact**: Poor FCP, layout shifts. | ||
| **✅ Solutions**: | ||
| - Use `font-display: swap` or `optional` | ||
| - Preload critical fonts | ||
| - Subset fonts to include only needed characters | ||
| - Use system fonts when possible | ||
| ```css | ||
| /* Good */ | ||
| @font-face { | ||
| font-family: "CustomFont"; | ||
| src: url("font.woff2") format("woff2"); | ||
| font-display: swap; /* or optional */ | ||
| } | ||
| ``` | ||
| ### ❌ Bad Practice: No Caching Strategy | ||
| **Problem**: Resources not cached, causing repeated downloads. | ||
| **Impact**: Slow repeat visits, poor performance. | ||
| **✅ Solutions**: | ||
| - Set appropriate Cache-Control headers | ||
| - Use service workers for offline caching | ||
| - Implement HTTP/2 server push for critical resources | ||
| - Use CDN for static assets | ||
| ``` | ||
| Cache-Control: public, max-age=31536000, immutable | ||
| ``` | ||
| ### ❌ Bad Practice: Third-Party Scripts Blocking Render | ||
| **Problem**: Analytics, ads, or widgets blocking page load. | ||
| **Impact**: Poor TTI, high TBT. | ||
| **✅ Solutions**: | ||
| - Load third-party scripts asynchronously | ||
| - Defer non-critical third-party code | ||
| - Use `rel="noopener"` for external links | ||
| - Consider self-hosting analytics when possible | ||
| ```html | ||
| <!-- Good --> | ||
| <script async src="https://www.google-analytics.com/analytics.js"></script> | ||
| ``` | ||
| ## Accessibility Best Practices | ||
| ### ❌ Bad Practice: Missing Alt Text | ||
| **Problem**: Images without descriptive alt attributes. | ||
| **Impact**: Poor accessibility score. | ||
| **✅ Solution**: Always provide meaningful alt text. | ||
| ```html | ||
| <!-- Bad --> | ||
| <img src="chart.png" /> | ||
| <!-- Good --> | ||
| <img src="chart.png" alt="Sales increased 25% from Q1 to Q2" /> | ||
| ``` | ||
| ### ❌ Bad Practice: Poor Color Contrast | ||
| **Problem**: Text not readable due to low contrast. | ||
| **Impact**: Poor accessibility score. | ||
| **✅ Solution**: Ensure contrast ratio of at least 4.5:1 for normal text, 3:1 for large text. | ||
| ### ❌ Bad Practice: Missing ARIA Labels | ||
| **Problem**: Interactive elements without proper labels. | ||
| **Impact**: Poor accessibility score. | ||
| **✅ Solution**: Use ARIA labels for screen readers. | ||
| ```html | ||
| <!-- Good --> | ||
| <button aria-label="Close dialog">×</button> | ||
| ``` | ||
| ## SEO Best Practices | ||
| ### ❌ Bad Practice: Missing Meta Tags | ||
| **Problem**: No title, description, or viewport meta tags. | ||
| **Impact**: Poor SEO score. | ||
| **✅ Solution**: Include essential meta tags. | ||
| ```html | ||
| <!-- Good --> | ||
| <meta charset="UTF-8" /> | ||
| <meta name="viewport" content="width=device-width, initial-scale=1.0" /> | ||
| <meta name="description" content="Page description" /> | ||
| <title>Page Title</title> | ||
| ``` | ||
| ### ❌ Bad Practice: Non-Descriptive Links | ||
| **Problem**: Links with generic text like "click here". | ||
| **Impact**: Poor SEO score. | ||
| **✅ Solution**: Use descriptive link text. | ||
| ```html | ||
| <!-- Bad --> | ||
| <a href="/about">Click here</a> | ||
| <!-- Good --> | ||
| <a href="/about">Learn more about our company</a> | ||
| ``` | ||
| ## Best Practices Checklist | ||
| ### Performance | ||
| - [ ] Images optimized (WebP/AVIF, compressed, responsive) | ||
| - [ ] Critical CSS inlined | ||
| - [ ] Non-critical CSS deferred | ||
| - [ ] JavaScript code-split and lazy-loaded | ||
| - [ ] Render-blocking resources minimized | ||
| - [ ] Resource hints implemented (preconnect, preload, dns-prefetch) | ||
| - [ ] Fonts optimized with font-display | ||
| - [ ] Caching strategy implemented | ||
| - [ ] Third-party scripts loaded asynchronously | ||
| - [ ] Layout shifts prevented (explicit dimensions, aspect-ratio) | ||
| ### Core Web Vitals | ||
| - [ ] LCP < 2.5 seconds (75th percentile) | ||
| - [ ] FCP < 1.8 seconds (75th percentile) | ||
| - [ ] CLS < 0.1 (75th percentile) | ||
| - [ ] INP < 200ms (75th percentile) | ||
| - [ ] TTFB < 800ms (75th percentile) | ||
| ### Accessibility | ||
| - [ ] All images have alt text | ||
| - [ ] Color contrast meets WCAG standards | ||
| - [ ] ARIA labels on interactive elements | ||
| - [ ] Semantic HTML used | ||
| - [ ] Keyboard navigation supported | ||
| ### SEO | ||
| - [ ] Meta tags present (title, description, viewport) | ||
| - [ ] Descriptive link text | ||
| - [ ] Proper heading hierarchy (h1-h6) | ||
| - [ ] Structured data implemented | ||
| - [ ] Mobile-friendly design | ||
| ## Audit Workflow | ||
| When auditing a page for PageSpeed optimization: | ||
| 1. **Analyze Current State** | ||
| - Check current PageSpeed scores | ||
| - Identify Core Web Vitals metrics | ||
| - Review lab and field data differences | ||
| 2. **Identify Issues** | ||
| - List all performance problems | ||
| - Prioritize by impact (Core Web Vitals first) | ||
| - Categorize by type (images, JS, CSS, etc.) | ||
| 3. **Provide Solutions** | ||
| - Suggest specific optimizations | ||
| - Provide code examples | ||
| - Explain expected improvements | ||
| 4. **Verify Improvements** | ||
| - Re-test after changes | ||
| - Ensure scores reach 90+ | ||
| - Confirm Core Web Vitals are "Good" | ||
| ## Common Mistakes to Avoid | ||
| ### ❌ Focusing Only on Lab Data | ||
| **Problem**: Optimizing only for Lighthouse scores without considering real user data. | ||
| **✅ Solution**: Balance both lab and field data. Field data shows real-world performance. | ||
| ### ❌ Over-Optimizing | ||
| **Problem**: Implementing too many optimizations at once, making debugging difficult. | ||
| **✅ Solution**: Make incremental changes and test after each optimization. | ||
| ### ❌ Ignoring Mobile Performance | ||
| **Problem**: Optimizing only for desktop. | ||
| **✅ Solution**: Mobile-first approach. Most users are on mobile devices. | ||
| ### ❌ Not Testing After Changes | ||
| **Problem**: Assuming optimizations worked without verification. | ||
| **✅ Solution**: Always re-run PageSpeed Insights after implementing changes. | ||
| ## Performance Optimization Priority | ||
| 1. **Critical Path**: Optimize resources needed for initial render | ||
| 2. **Core Web Vitals**: Focus on LCP, CLS, and INP first | ||
| 3. **Render-Blocking**: Eliminate blocking CSS and JS | ||
| 4. **Images**: Optimize largest contentful paint element | ||
| 5. **Third-Party**: Minimize impact of external scripts | ||
| 6. **Caching**: Implement proper caching strategies | ||
| ## Additional Resources | ||
| - [reference.md](reference.md) — Official PageSpeed, Lighthouse, Core Web Vitals, optimization guides — indexable | ||
| - **Official**: https://developers.google.com/speed/docs/insights/v5/about?hl=es-419 | ||
| - **PageSpeed Insights**: https://pagespeed.web.dev/ | ||
| - **Lighthouse**: Built into Chrome DevTools | ||
| - **Web Vitals**: https://web.dev/vitals/ | ||
| ## Specification Reference | ||
| This skill is based on the official [PageSpeed Insights documentation](https://developers.google.com/speed/docs/insights/v5/about?hl=es-419) from Google Developers. | ||
| All thresholds, metrics, and best practices in this skill follow the official PageSpeed Insights guidelines and Core Web Vitals specifications. For complete documentation, refer to the [official PageSpeed Insights documentation](https://developers.google.com/speed/docs/insights/v5/about?hl=es-419). |
| --- | ||
| id: pagespeed-perf | ||
| version: 1.0.0 | ||
| name: PageSpeed Performance Audit | ||
| description: > | ||
| Web Performance Engineering — analyzes Core Web Vitals using the PageSpeed | ||
| Insights API (PSI v5) and applies the 80/20 principle: identify the 20% of | ||
| changes that produce 80% of the performance gain. Produces a prioritized | ||
| markdown report with quantified estimates and framework-specific code. | ||
| Trigger: When auditing page speed, analyzing Core Web Vitals, or optimizing | ||
| web performance for any URL. | ||
| user-invokable: true | ||
| license: MIT | ||
| metadata: | ||
| author: codeconductor | ||
| category: performance | ||
| compatibility: | ||
| tools: [claude, codex, gemini, agy, opencode] | ||
| stacks: | ||
| languages: [] | ||
| frameworks: [astro, nextjs, react, vue, django, spring, wordpress] | ||
| risk: | ||
| level: medium | ||
| can_execute_shell: true | ||
| can_modify_files: false | ||
| requires_network: true | ||
| inputs: | ||
| - name: url | ||
| type: string | ||
| required: true | ||
| description: Full URL to audit (must include scheme: https://...) | ||
| - name: strategy | ||
| type: string | ||
| required: false | ||
| description: "mobile | desktop | both (default: both)" | ||
| outputs: | ||
| - name: report | ||
| type: markdown | ||
| description: > | ||
| Prioritized performance report saved as | ||
| {YYYY-MM-DD}_pagespeed-{hostname}-claude.md in the current directory. | ||
| quality: | ||
| reviewed_by: codeconductor-core | ||
| version: 1.0.0 | ||
| --- | ||
| # PageSpeed Performance Audit — Web Performance Engineering (80/20) | ||
| ## Role and Purpose | ||
| Act as **Senior Web Performance Engineer, Frontend Architect, and Technical | ||
| Auditor**. | ||
| Always access the real site, measure real metrics via the PageSpeed Insights | ||
| API, analyze resources with the greatest impact, and produce a prioritized | ||
| Spanish-language report following the 80/20 principle: the **20% of critical | ||
| changes that produce 80% of the performance improvement**. | ||
| Never give generic recommendations. Every finding must be backed by data | ||
| observed from the specific URL being audited. | ||
| --- | ||
| ## Step 0 — Pre-flight: API Key and Output Filename | ||
| **MANDATORY. Execute before any analysis.** | ||
| ### 1. Read the API key from the environment | ||
| ```powershell | ||
| $env:PAGESPEED_API_KEY | ||
| ``` | ||
| - Value present → store as `{API_KEY}`, use in all PSI calls. | ||
| - Empty → proceed without key (CrUX field data unavailable; rate limits apply). | ||
| ### 2. Define the output filename | ||
| ```powershell | ||
| $date = (Get-Date -Format "yyyy-MM-dd") | ||
| $website = ([System.Uri]"{URL}").Host -replace '[^a-zA-Z0-9]', '-' | ||
| $out = "${date}_pagespeed-${website}-claude.md" | ||
| Write-Host $out | ||
| ``` | ||
| The final report **must** be written to this file. | ||
| --- | ||
| ## Data Collection | ||
| ### Primary Method — Bun Scripts (always try first) | ||
| ```powershell | ||
| bun --version # if available, use Primary Method; otherwise use Fallback | ||
| $skillDir = "$env:USERPROFILE\.claude\skills\pagespeed-perf\scripts" | ||
| bun run "$skillDir\run.ts" --url={URL} | ||
| ``` | ||
| `run.ts` calls `psi-collect.ts` and `html-audit.ts` in parallel and returns | ||
| structured JSON. Key output fields: | ||
| ``` | ||
| output.summary.mobileScore → Lighthouse mobile score (0-100) | ||
| output.summary.desktopScore → Lighthouse desktop score | ||
| output.summary.passesCWV → boolean — passes real CWV | ||
| output.summary.top5Actions → array ordered by 80/20 score | ||
| output.psi.mobile.lab.lcp → LCP (lab, mobile) | ||
| output.psi.mobile.lab.tbt → TBT | ||
| output.psi.mobile.lab.cls → CLS | ||
| output.psi.mobile.lab.fcp → FCP | ||
| output.psi.mobile.lab.ttfb → TTFB | ||
| output.psi.mobile.field → CrUX data (null if no key / no data) | ||
| output.psi.mobile.opportunities → array ordered by impact80_20 desc | ||
| output.psi.mobile.lcpElement → HTML snippet of the LCP element | ||
| output.psi.mobile.thirdParties → third-party scripts with blockingTime | ||
| output.psi.mobile.usedApiKey → boolean — confirms key was used | ||
| output.html.stack → detected framework / CMS | ||
| output.html.resourceHints → preloads, preconnects, prefetches | ||
| output.html.images → lazy, fetchpriority, list | ||
| output.html.scripts → blocking in <head>, third-party list | ||
| output.html.fonts → googleFonts, font-display, preloaded | ||
| output.html.issues → ordered by impact80_20 | ||
| ``` | ||
| ### Fallback Method — WebFetch (only if Bun unavailable) | ||
| ``` | ||
| # With API key (preferred) | ||
| https://www.googleapis.com/pagespeedonline/v5/runPagespeed?url={URL}&strategy=mobile&category=performance&key={API_KEY} | ||
| https://www.googleapis.com/pagespeedonline/v5/runPagespeed?url={URL}&strategy=desktop&category=performance&key={API_KEY} | ||
| # Without key (rate-limited) | ||
| https://www.googleapis.com/pagespeedonline/v5/runPagespeed?url={URL}&strategy=mobile&category=performance | ||
| ``` | ||
| Key PSI response paths: | ||
| ``` | ||
| lighthouseResult.categories.performance.score | ||
| lighthouseResult.audits.largest-contentful-paint | ||
| lighthouseResult.audits.total-blocking-time | ||
| lighthouseResult.audits.cumulative-layout-shift | ||
| lighthouseResult.audits.first-contentful-paint | ||
| lighthouseResult.audits.server-response-time | ||
| lighthouseResult.audits.largest-contentful-paint-element.details.items[0] | ||
| lighthouseResult.audits.render-blocking-resources.details.overallSavingsMs | ||
| lighthouseResult.audits.unused-javascript.details.overallSavingsBytes | ||
| lighthouseResult.audits.third-party-summary.details.items | ||
| loadingExperience.metrics.LARGEST_CONTENTFUL_PAINT_MS.percentile (CrUX) | ||
| loadingExperience.metrics.INTERACTION_TO_NEXT_PAINT.percentile (CrUX) | ||
| loadingExperience.metrics.CUMULATIVE_LAYOUT_SHIFT_SCORE.percentile (CrUX) | ||
| loadingExperience.overall_category → "FAST" | "AVERAGE" | "SLOW" | ||
| ``` | ||
| Also fetch the site HTML via WebFetch and inspect the `<head>` for resource | ||
| hints, lazy loading, `fetchpriority`, `font-display`, blocking scripts, and | ||
| images without explicit dimensions. | ||
| --- | ||
| ## Core Web Vitals — Thresholds | ||
| | Metric | Good | Needs Improvement | Critical | Score weight | | ||
| | ------ | -------- | ----------------- | --------- | ------------ | | ||
| | LCP | ≤ 2.5 s | 2.5 s – 4.0 s | > 4.0 s | 25% | | ||
| | INP | ≤ 200 ms | 200 ms – 500 ms | > 500 ms | 10% | | ||
| | CLS | ≤ 0.1 | 0.1 – 0.25 | > 0.25 | 15% | | ||
| | FCP | ≤ 1.8 s | 1.8 s – 3.0 s | > 3.0 s | 10% | | ||
| | TBT | ≤ 200 ms | 200 ms – 600 ms | > 600 ms | 30% | | ||
| | TTFB | ≤ 800 ms | 800 ms – 1.8 s | > 1.8 s | — | | ||
| LCP + TBT represent 55% of the Lighthouse Performance Score. | ||
| --- | ||
| ## 80/20 Optimization Matrix | ||
| Score = `Impact (1–5) × Ease (1–5)`. Prioritize by descending score. | ||
| | Rank | Optimization | Primary metric | Impact | Ease | Score | | ||
| | ---- | --------------------------------- | -------------- | ------ | ---- | ----- | | ||
| | 1 | Preload LCP element | LCP | 5 | 5 | **25** | | ||
| | 1 | `fetchpriority="high"` on LCP img | LCP | 5 | 5 | **25** | | ||
| | 1 | Gzip / Brotli compression | FCP, LCP, TBT | 5 | 5 | **25** | | ||
| | 4 | WebP + explicit dimensions | LCP, CLS | 5 | 4 | **20** | | ||
| | 4 | Lazy loading offscreen images | LCP, TBT | 4 | 5 | **20** | | ||
| | 4 | `font-display: swap` | FCP | 4 | 5 | **20** | | ||
| | 4 | `preconnect` to critical origins | FCP, LCP, TTFB | 4 | 5 | **20** | | ||
| | 4 | Defer / facade third-party scripts| TBT, INP | 5 | 4 | **20** | | ||
| | 9 | Remove render-blocking resources | FCP, LCP | 5 | 3 | **15** | | ||
| | 9 | Long Cache-Control for assets | repeat visits | 3 | 5 | **15** | | ||
| | 11 | Remove unused JavaScript | TBT, INP | 4 | 3 | **12** | | ||
| | 12 | Remove unused CSS | FCP, TBT | 3 | 3 | **9** | | ||
| | 13 | CDN for static assets | TTFB, LCP | 4 | 2 | **8** | | ||
| | 14 | Code splitting | TBT, INP | 4 | 2 | **8** | | ||
| **Critical 20% (Score ≥ 20)** — address these first: | ||
| 1. Preload LCP element + `fetchpriority="high"` | ||
| 2. Brotli/Gzip compression at the server | ||
| 3. WebP images with explicit `width`/`height` | ||
| 4. Lazy loading of offscreen images | ||
| 5. `font-display: swap` for all fonts | ||
| 6. `preconnect` to all critical origins | ||
| 7. Defer or facade all third-party scripts | ||
| --- | ||
| ## Expected Impact by Optimization | ||
| | Optimization | Metric | Expected gain | | ||
| | ---------------------- | -------- | --------------------- | | ||
| | Preload + fetchpriority| LCP | −0.5 s to −2.0 s | | ||
| | Brotli compression | FCP, LCP | −0.3 s to −1.0 s | | ||
| | WebP + dimensions | LCP, CLS | −0.3 s to −1.2 s | | ||
| | Lazy loading | LCP | −0.2 s to −0.8 s | | ||
| | font-display: swap | FCP | −0.2 s to −0.8 s | | ||
| | preconnect | FCP, LCP | −0.1 s to −0.4 s each| | ||
| | Defer third parties | TBT, INP | −50 ms to −300 ms | | ||
| --- | ||
| ## Report Format (mandatory structure) | ||
| Save to `{YYYY-MM-DD}_pagespeed-{hostname}-claude.md`: | ||
| ```markdown | ||
| # Auditoría de Rendimiento Web — {URL} | ||
| Fecha: {YYYY-MM-DD} | Estrategia: Móvil + Escritorio | Archivo: {filename}.md | ||
| ## Resumen Ejecutivo | ||
| [2-3 párrafos: estado actual, score, bottleneck principal, potencial de mejora] | ||
| ## Métricas Actuales | ||
| [Tabla: Lab (Lighthouse) vs Campo (CrUX)] | ||
| ## Recursos con Mayor Impacto | ||
| [Tabla: URL, Tipo, Tamaño, Tiempo, Impacto, Razón] | ||
| ## Plan de Acción Priorizado (80/20) | ||
| [Tabla ordenada por Score 80/20 descendente] | ||
| ## Solución Técnica Detallada | ||
| [Por hallazgo: Problema, Evidencia, Implementación, Código, Impacto Esperado] | ||
| ## Quick Wins (< 1 day) | ||
| ## High Impact Changes | ||
| ## Roadmap | ||
| - Fase 1 — Inmediato (Semana 1) | ||
| - Fase 2 — Corto Plazo (2–4 semanas) | ||
| - Fase 3 — Mediano Plazo (1–3 meses) | ||
| --- | ||
| *Informe generado el {YYYY-MM-DD} · Herramienta: Claude Code + pagespeed-perf skill* | ||
| *API Key usada: {Sí / No} · Datos CrUX: {Disponibles / No disponibles}* | ||
| ``` | ||
| --- | ||
| ## Quality Rules — Never Violate | ||
| 1. **No data = no recommendation.** If PSI fails, try WebFetch directly. | ||
| 2. **Always quantify.** "Reduces LCP from 4.2 s to ~3.0 s" — never "would improve LCP". | ||
| 3. **Explicit evidence.** Cite the observed metric value for every finding. | ||
| 4. **Site-specific code.** Adapt templates to the detected framework (Next.js, | ||
| Astro, Django, etc.). Do not paste generic snippets unchanged. | ||
| 5. **80/20 order.** Always sort the action plan by descending score. | ||
| 6. **Separate field vs lab data.** CrUX = real user experience. Lighthouse = controlled lab. | ||
| 7. **Identify the framework.** Detect Next.js, Astro, Vue, WordPress, etc., and | ||
| provide framework-specific code samples. |
| # workflow-orchestration-patterns — detailed patterns and worked examples | ||
| ## Critical Design Decision: Workflows vs Activities | ||
| **The Fundamental Rule** (Source: temporal.io/blog/workflow-engine-principles): | ||
| - **Workflows** = Orchestration logic and decision-making | ||
| - **Activities** = External interactions (APIs, databases, network calls) | ||
| ### Workflows (Orchestration) | ||
| **Characteristics:** | ||
| - Contain business logic and coordination | ||
| - **MUST be deterministic** (same inputs → same outputs) | ||
| - **Cannot** perform direct external calls | ||
| - State automatically preserved across failures | ||
| - Can run for years despite infrastructure failures | ||
| **Example workflow tasks:** | ||
| - Decide which steps to execute | ||
| - Handle compensation logic | ||
| - Manage timeouts and retries | ||
| - Coordinate child workflows | ||
| ### Activities (External Interactions) | ||
| **Characteristics:** | ||
| - Handle all external system interactions | ||
| - Can be non-deterministic (API calls, DB writes) | ||
| - Include built-in timeouts and retry logic | ||
| - **Must be idempotent** (calling N times = calling once) | ||
| - Short-lived (seconds to minutes typically) | ||
| **Example activity tasks:** | ||
| - Call payment gateway API | ||
| - Write to database | ||
| - Send emails or notifications | ||
| - Query external services | ||
| ### Design Decision Framework | ||
| ``` | ||
| Does it touch external systems? → Activity | ||
| Is it orchestration/decision logic? → Workflow | ||
| ``` | ||
| ## Core Workflow Patterns | ||
| ### 1. Saga Pattern with Compensation | ||
| **Purpose**: Implement distributed transactions with rollback capability | ||
| **Pattern** (Source: temporal.io/blog/compensating-actions-part-of-a-complete-breakfast-with-sagas): | ||
| ``` | ||
| For each step: | ||
| 1. Register compensation BEFORE executing | ||
| 2. Execute the step (via activity) | ||
| 3. On failure, run all compensations in reverse order (LIFO) | ||
| ``` | ||
| **Example: Payment Workflow** | ||
| 1. Reserve inventory (compensation: release inventory) | ||
| 2. Charge payment (compensation: refund payment) | ||
| 3. Fulfill order (compensation: cancel fulfillment) | ||
| **Critical Requirements:** | ||
| - Compensations must be idempotent | ||
| - Register compensation BEFORE executing step | ||
| - Run compensations in reverse order | ||
| - Handle partial failures gracefully | ||
| ### 2. Entity Workflows (Actor Model) | ||
| **Purpose**: Long-lived workflow representing single entity instance | ||
| **Pattern** (Source: docs.temporal.io/evaluate/use-cases-design-patterns): | ||
| - One workflow execution = one entity (cart, account, inventory item) | ||
| - Workflow persists for entity lifetime | ||
| - Receives signals for state changes | ||
| - Supports queries for current state | ||
| **Example Use Cases:** | ||
| - Shopping cart (add items, checkout, expiration) | ||
| - Bank account (deposits, withdrawals, balance checks) | ||
| - Product inventory (stock updates, reservations) | ||
| **Benefits:** | ||
| - Encapsulates entity behavior | ||
| - Guarantees consistency per entity | ||
| - Natural event sourcing | ||
| ### 3. Fan-Out/Fan-In (Parallel Execution) | ||
| **Purpose**: Execute multiple tasks in parallel, aggregate results | ||
| **Pattern:** | ||
| - Spawn child workflows or parallel activities | ||
| - Wait for all to complete | ||
| - Aggregate results | ||
| - Handle partial failures | ||
| **Scaling Rule** (Source: temporal.io/blog/workflow-engine-principles): | ||
| - Don't scale individual workflows | ||
| - For 1M tasks: spawn 1K child workflows × 1K tasks each | ||
| - Keep each workflow bounded | ||
| ### 4. Async Callback Pattern | ||
| **Purpose**: Wait for external event or human approval | ||
| **Pattern:** | ||
| - Workflow sends request and waits for signal | ||
| - External system processes asynchronously | ||
| - Sends signal to resume workflow | ||
| - Workflow continues with response | ||
| **Use Cases:** | ||
| - Human approval workflows | ||
| - Webhook callbacks | ||
| - Long-running external processes | ||
| ## State Management and Determinism | ||
| ### Automatic State Preservation | ||
| **How Temporal Works** (Source: docs.temporal.io/workflows): | ||
| - Complete program state preserved automatically | ||
| - Event History records every command and event | ||
| - Seamless recovery from crashes | ||
| - Applications restore pre-failure state | ||
| ### Determinism Constraints | ||
| **Workflows Execute as State Machines**: | ||
| - Replay behavior must be consistent | ||
| - Same inputs → identical outputs every time | ||
| **Prohibited in Workflows** (Source: docs.temporal.io/workflows): | ||
| - ❌ Threading, locks, synchronization primitives | ||
| - ❌ Random number generation (`random()`) | ||
| - ❌ Global state or static variables | ||
| - ❌ System time (`datetime.now()`) | ||
| - ❌ Direct file I/O or network calls | ||
| - ❌ Non-deterministic libraries | ||
| **Allowed in Workflows**: | ||
| - ✅ `workflow.now()` (deterministic time) | ||
| - ✅ `workflow.random()` (deterministic random) | ||
| - ✅ Pure functions and calculations | ||
| - ✅ Calling activities (non-deterministic operations) | ||
| ### Versioning Strategies | ||
| **Challenge**: Changing workflow code while old executions still running | ||
| **Solutions**: | ||
| 1. **Versioning API**: Use `workflow.get_version()` for safe changes | ||
| 2. **New Workflow Type**: Create new workflow, route new executions to it | ||
| 3. **Backward Compatibility**: Ensure old events replay correctly | ||
| ## Resilience and Error Handling | ||
| ### Retry Policies | ||
| **Default Behavior**: Temporal retries activities forever | ||
| **Configure Retry**: | ||
| - Initial retry interval | ||
| - Backoff coefficient (exponential backoff) | ||
| - Maximum interval (cap retry delay) | ||
| - Maximum attempts (eventually fail) | ||
| **Non-Retryable Errors**: | ||
| - Invalid input (validation failures) | ||
| - Business rule violations | ||
| - Permanent failures (resource not found) | ||
| ### Idempotency Requirements | ||
| **Why Critical** (Source: docs.temporal.io/activities): | ||
| - Activities may execute multiple times | ||
| - Network failures trigger retries | ||
| - Duplicate execution must be safe | ||
| **Implementation Strategies**: | ||
| - Idempotency keys (deduplication) | ||
| - Check-then-act with unique constraints | ||
| - Upsert operations instead of insert | ||
| - Track processed request IDs | ||
| ### Activity Heartbeats | ||
| **Purpose**: Detect stalled long-running activities | ||
| **Pattern**: | ||
| - Activity sends periodic heartbeat | ||
| - Includes progress information | ||
| - Timeout if no heartbeat received | ||
| - Enables progress-based retry |
| --- | ||
| name: workflow-orchestration-patterns | ||
| description: Design durable workflows with Temporal for distributed systems. Covers workflow vs activity separation, saga patterns, state management, and determinism constraints. Use when building long-running processes, distributed transactions, or microservice orchestration. | ||
| --- | ||
| # Workflow Orchestration Patterns | ||
| Master workflow orchestration architecture with Temporal, covering fundamental design decisions, resilience patterns, and best practices for building reliable distributed systems. | ||
| ## When to Use Workflow Orchestration | ||
| ### Ideal Use Cases (Source: docs.temporal.io) | ||
| - **Multi-step processes** spanning machines/services/databases | ||
| - **Distributed transactions** requiring all-or-nothing semantics | ||
| - **Long-running workflows** (hours to years) with automatic state persistence | ||
| - **Failure recovery** that must resume from last successful step | ||
| - **Business processes**: bookings, orders, campaigns, approvals | ||
| - **Entity lifecycle management**: inventory tracking, account management, cart workflows | ||
| - **Infrastructure automation**: CI/CD pipelines, provisioning, deployments | ||
| - **Human-in-the-loop** systems requiring timeouts and escalations | ||
| ### When NOT to Use | ||
| - Simple CRUD operations (use direct API calls) | ||
| - Pure data processing pipelines (use Airflow, batch processing) | ||
| - Stateless request/response (use standard APIs) | ||
| - Real-time streaming (use Kafka, event processors) | ||
| ## Detailed patterns and worked examples | ||
| Detailed pattern documentation lives in `references/details.md`. Read that file when the navigation tier above is insufficient. | ||
| ## Best Practices | ||
| ### Workflow Design | ||
| 1. **Keep workflows focused** - Single responsibility per workflow | ||
| 2. **Small workflows** - Use child workflows for scalability | ||
| 3. **Clear boundaries** - Workflow orchestrates, activities execute | ||
| 4. **Test locally** - Use time-skipping test environment | ||
| ### Activity Design | ||
| 1. **Idempotent operations** - Safe to retry | ||
| 2. **Short-lived** - Seconds to minutes, not hours | ||
| 3. **Timeout configuration** - Always set timeouts | ||
| 4. **Heartbeat for long tasks** - Report progress | ||
| 5. **Error handling** - Distinguish retryable vs non-retryable | ||
| ### Common Pitfalls | ||
| **Workflow Violations**: | ||
| - Using `datetime.now()` instead of `workflow.now()` | ||
| - Threading or async operations in workflow code | ||
| - Calling external APIs directly from workflow | ||
| - Non-deterministic logic in workflows | ||
| **Activity Mistakes**: | ||
| - Non-idempotent operations (can't handle retries) | ||
| - Missing timeouts (activities run forever) | ||
| - No error classification (retry validation errors) | ||
| - Ignoring payload limits (2MB per argument) | ||
| ### Operational Considerations | ||
| **Monitoring**: | ||
| - Workflow execution duration | ||
| - Activity failure rates | ||
| - Retry attempts and backoff | ||
| - Pending workflow counts | ||
| **Scalability**: | ||
| - Horizontal scaling with workers | ||
| - Task queue partitioning | ||
| - Child workflow decomposition | ||
| - Activity batching when appropriate | ||
| ## Additional Resources | ||
| **Official Documentation**: | ||
| - Temporal Core Concepts: docs.temporal.io/workflows | ||
| - Workflow Patterns: docs.temporal.io/evaluate/use-cases-design-patterns | ||
| - Best Practices: docs.temporal.io/develop/best-practices | ||
| - Saga Pattern: temporal.io/blog/saga-pattern-made-easy | ||
| **Key Principles**: | ||
| 1. Workflows = orchestration, Activities = external calls | ||
| 2. Determinism is non-negotiable for workflows | ||
| 3. Idempotency is critical for activities | ||
| 4. State preservation is automatic | ||
| 5. Design for failure and recovery |
| --- | ||
| name: conductor-setup | ||
| description: Configure a Rails project to work with Conductor (parallel coding agents) | ||
| allowed-tools: Bash(chmod *), Bash(bundle *), Bash(npm *), Bash(script/server) | ||
| context: fork | ||
| risk: unknown | ||
| source: community | ||
| metadata: | ||
| author: Shpigford | ||
| version: "1.0" | ||
| --- | ||
| Set up this Rails project for Conductor, the Mac app for parallel coding agents. | ||
| ## When to Use | ||
| - You need to configure a Rails project so it runs correctly inside Conductor workspaces. | ||
| - The project should support parallel coding agents with isolated ports, Redis settings, and shared secrets. | ||
| - You want the standard `conductor.json`, `bin/conductor-setup`, and `script/server` scaffolding for a Rails repo. | ||
| # What to Create | ||
| ## 1. conductor.json (project root) | ||
| Create `conductor.json` in the project root if it doesn't already exist: | ||
| ```json | ||
| { | ||
| "scripts": { | ||
| "setup": "bin/conductor-setup", | ||
| "run": "script/server" | ||
| } | ||
| } | ||
| ``` | ||
| ## 2. bin/conductor-setup (executable) | ||
| Create `bin/conductor-setup` if it doesn't already exist: | ||
| ```bash | ||
| #!/bin/bash | ||
| set -e | ||
| # Symlink .env from repo root (where secrets live, outside worktrees) | ||
| [ -f "$CONDUCTOR_ROOT_PATH/.env" ] && ln -sf "$CONDUCTOR_ROOT_PATH/.env" .env | ||
| # Symlink Rails master key | ||
| [ -f "$CONDUCTOR_ROOT_PATH/config/master.key" ] && ln -sf "$CONDUCTOR_ROOT_PATH/config/master.key" config/master.key | ||
| # Install dependencies | ||
| bundle install | ||
| npm install | ||
| ``` | ||
| Make it executable with `chmod +x bin/conductor-setup`. | ||
| ## 3. script/server (executable) | ||
| Create the `script` directory if needed, then create `script/server` if it doesn't already exist: | ||
| ```bash | ||
| #!/bin/bash | ||
| # === Port Configuration === | ||
| export PORT=${CONDUCTOR_PORT:-3000} | ||
| export VITE_RUBY_PORT=$((PORT + 1000)) | ||
| # === Redis Isolation === | ||
| if [ -n "$CONDUCTOR_WORKSPACE_NAME" ]; then | ||
| HASH=$(printf '%s' "$CONDUCTOR_WORKSPACE_NAME" | cksum | cut -d' ' -f1) | ||
| REDIS_DB=$((HASH % 16)) | ||
| export REDIS_URL="redis://localhost:6379/${REDIS_DB}" | ||
| fi | ||
| exec bin/dev | ||
| ``` | ||
| Make it executable with `chmod +x script/server`. | ||
| ## 4. Update Rails Config Files | ||
| For each of the following files, if they exist and contain Redis configuration, update them to use `ENV.fetch('REDIS_URL', ...)` or `ENV['REDIS_URL']` with a fallback: | ||
| ### config/initializers/sidekiq.rb | ||
| If this file exists and configures Redis, update it to use: | ||
| ```ruby | ||
| redis_url = ENV.fetch('REDIS_URL', 'redis://localhost:6379/0') | ||
| ``` | ||
| ### config/cable.yml | ||
| If this file exists, update the development adapter to use: | ||
| ```yaml | ||
| development: | ||
| adapter: redis | ||
| url: <%= ENV.fetch('REDIS_URL', 'redis://localhost:6379/1') %> | ||
| ``` | ||
| ### config/environments/development.rb | ||
| If this file configures Redis for caching, update to use: | ||
| ```ruby | ||
| config.cache_store = :redis_cache_store, { url: ENV.fetch('REDIS_URL', 'redis://localhost:6379/0') } | ||
| ``` | ||
| ### config/initializers/rack_attack.rb | ||
| If this file exists and configures a Redis cache store, update to use: | ||
| ```ruby | ||
| Rack::Attack.cache.store = ActiveSupport::Cache::RedisCacheStore.new(url: ENV.fetch('REDIS_URL', 'redis://localhost:6379/0')) | ||
| ``` | ||
| # Implementation Notes | ||
| - **Don't overwrite existing files**: Check if conductor.json, bin/conductor-setup, and script/server exist before creating them. If they exist, skip creation and inform the user. | ||
| - **Rails config updates**: Only modify Redis-related configuration. If a file doesn't exist or doesn't use Redis, skip it gracefully. | ||
| - **Create directories as needed**: Create `script/` directory if it doesn't exist. | ||
| # Verification | ||
| After creating the files: | ||
| 1. Confirm all Conductor files exist and scripts are executable | ||
| 2. Run `script/server` to verify it starts without errors | ||
| 3. Check that Rails configs properly reference `ENV['REDIS_URL']` or `ENV.fetch('REDIS_URL', ...)` | ||
| ## Limitations | ||
| - Use this skill only when the task clearly matches the scope described above. | ||
| - Do not treat the output as a substitute for environment-specific validation, testing, or expert review. | ||
| - Stop and ask for clarification if required inputs, permissions, safety boundaries, or success criteria are missing. |
| --- | ||
| name: find-skills | ||
| description: Helps users discover and install agent skills when they ask questions like "how do I do X", "find a skill for X", "is there a skill that can...", or express interest in extending capabilities. This skill should be used when the user is looking for functionality that might exist as an installable skill. | ||
| --- | ||
| # Find Skills | ||
| This skill helps you discover and install skills from the open agent skills ecosystem. | ||
| ## When to Use This Skill | ||
| Use this skill when the user: | ||
| - Asks "how do I do X" where X might be a common task with an existing skill | ||
| - Says "find a skill for X" or "is there a skill for X" | ||
| - Asks "can you do X" where X is a specialized capability | ||
| - Expresses interest in extending agent capabilities | ||
| - Wants to search for tools, templates, or workflows | ||
| - Mentions they wish they had help with a specific domain (design, testing, deployment, etc.) | ||
| ## What is the Skills CLI? | ||
| The Skills CLI (`npx skills`) is the package manager for the open agent skills ecosystem. Skills are modular packages that extend agent capabilities with specialized knowledge, workflows, and tools. | ||
| **Key commands:** | ||
| - `npx skills find [query]` - Search for skills interactively or by keyword | ||
| - `npx skills add <package>` - Install a skill from GitHub or other sources | ||
| - `npx skills check` - Check for skill updates | ||
| - `npx skills update` - Update all installed skills | ||
| **Browse skills at:** https://skills.sh/ | ||
| ## How to Help Users Find Skills | ||
| ### Step 1: Understand What They Need | ||
| When a user asks for help with something, identify: | ||
| 1. The domain (e.g., React, testing, design, deployment) | ||
| 2. The specific task (e.g., writing tests, creating animations, reviewing PRs) | ||
| 3. Whether this is a common enough task that a skill likely exists | ||
| ### Step 2: Check the Leaderboard First | ||
| Before running a CLI search, check the [skills.sh leaderboard](https://skills.sh/) to see if a well-known skill already exists for the domain. The leaderboard ranks skills by total installs, surfacing the most popular and battle-tested options. | ||
| For example, top skills for web development include: | ||
| - `vercel-labs/agent-skills` — React, Next.js, web design (100K+ installs each) | ||
| - `anthropics/skills` — Frontend design, document processing (100K+ installs) | ||
| ### Step 3: Search for Skills | ||
| If the leaderboard doesn't cover the user's need, run the find command: | ||
| ```bash | ||
| npx skills find [query] | ||
| ``` | ||
| For example: | ||
| - User asks "how do I make my React app faster?" → `npx skills find react performance` | ||
| - User asks "can you help me with PR reviews?" → `npx skills find pr review` | ||
| - User asks "I need to create a changelog" → `npx skills find changelog` | ||
| ### Step 4: Verify Quality Before Recommending | ||
| **Do not recommend a skill based solely on search results.** Always verify: | ||
| 1. **Install count** — Prefer skills with 1K+ installs. Be cautious with anything under 100. | ||
| 2. **Source reputation** — Official sources (`vercel-labs`, `anthropics`, `microsoft`) are more trustworthy than unknown authors. | ||
| 3. **GitHub stars** — Check the source repository. A skill from a repo with <100 stars should be treated with skepticism. | ||
| ### Step 5: Present Options to the User | ||
| When you find relevant skills, present them to the user with: | ||
| 1. The skill name and what it does | ||
| 2. The install count and source | ||
| 3. The install command they can run | ||
| 4. A link to learn more at skills.sh | ||
| Example response: | ||
| ``` | ||
| I found a skill that might help! The "react-best-practices" skill provides | ||
| React and Next.js performance optimization guidelines from Vercel Engineering. | ||
| (185K installs) | ||
| To install it: | ||
| npx skills add vercel-labs/agent-skills@react-best-practices | ||
| Learn more: https://skills.sh/vercel-labs/agent-skills/react-best-practices | ||
| ``` | ||
| ### Step 6: Offer to Install | ||
| If the user wants to proceed, you can install the skill for them: | ||
| ```bash | ||
| npx skills add <owner/repo@skill> -g -y | ||
| ``` | ||
| The `-g` flag installs globally (user-level) and `-y` skips confirmation prompts. | ||
| ## Common Skill Categories | ||
| When searching, consider these common categories: | ||
| | Category | Example Queries | | ||
| | --------------- | ---------------------------------------- | | ||
| | Web Development | react, nextjs, typescript, css, tailwind | | ||
| | Testing | testing, jest, playwright, e2e | | ||
| | DevOps | deploy, docker, kubernetes, ci-cd | | ||
| | Documentation | docs, readme, changelog, api-docs | | ||
| | Code Quality | review, lint, refactor, best-practices | | ||
| | Design | ui, ux, design-system, accessibility | | ||
| | Productivity | workflow, automation, git | | ||
| ## Tips for Effective Searches | ||
| 1. **Use specific keywords**: "react testing" is better than just "testing" | ||
| 2. **Try alternative terms**: If "deploy" doesn't work, try "deployment" or "ci-cd" | ||
| 3. **Check popular sources**: Many skills come from `vercel-labs/agent-skills` or `ComposioHQ/awesome-claude-skills` | ||
| ## When No Skills Are Found | ||
| If no relevant skills exist: | ||
| 1. Acknowledge that no existing skill was found | ||
| 2. Offer to help with the task directly using your general capabilities | ||
| 3. Suggest the user could create their own skill with `npx skills init` | ||
| Example: | ||
| ``` | ||
| I searched for skills related to "xyz" but didn't find any matches. | ||
| I can still help you with this task directly! Would you like me to proceed? | ||
| If this is something you do often, you could create your own skill: | ||
| npx skills init my-xyz-skill | ||
| ``` |
| """ | ||
| Framework-Specific Multi-Agent Implementations | ||
| Templates for CrewAI, AutoGen, LangGraph, and Swarm. | ||
| """ | ||
| from typing import Dict, List, Optional, Any | ||
| from dataclasses import dataclass | ||
| @dataclass | ||
| class CrewAITemplate: | ||
| """Template for CrewAI implementation.""" | ||
| @staticmethod | ||
| def create_financial_team() -> Dict[str, Any]: | ||
| """Create CrewAI financial analysis team.""" | ||
| return { | ||
| "agents": [ | ||
| { | ||
| "name": "Market Analyst", | ||
| "role": "Market Research Specialist", | ||
| "goal": "Analyze market conditions and trends", | ||
| "backstory": "Expert market analyst with 10+ years experience", | ||
| "tools": ["market_data_api", "financial_news"], | ||
| }, | ||
| { | ||
| "name": "Financial Analyst", | ||
| "role": "Financial Analysis Specialist", | ||
| "goal": "Analyze company financial statements", | ||
| "backstory": "CFA with deep financial analysis expertise", | ||
| "tools": ["financial_statements", "ratio_calculator"], | ||
| }, | ||
| { | ||
| "name": "Risk Manager", | ||
| "role": "Risk Assessment Specialist", | ||
| "goal": "Assess investment risks and scenarios", | ||
| "backstory": "Risk management expert", | ||
| "tools": ["risk_models", "scenario_analysis"], | ||
| }, | ||
| { | ||
| "name": "Report Writer", | ||
| "role": "Report Generation Specialist", | ||
| "goal": "Synthesize findings into comprehensive report", | ||
| "backstory": "Professional technical writer", | ||
| "tools": ["document_generator"], | ||
| }, | ||
| ], | ||
| "tasks": [ | ||
| { | ||
| "agent": "Market Analyst", | ||
| "description": "Analyze market conditions for {company}", | ||
| }, | ||
| { | ||
| "agent": "Financial Analyst", | ||
| "description": "Analyze Q3 financial results for {company}", | ||
| }, | ||
| { | ||
| "agent": "Risk Manager", | ||
| "description": "Assess risks and create scenarios for {company}", | ||
| }, | ||
| { | ||
| "agent": "Report Writer", | ||
| "description": "Write comprehensive investment analysis report", | ||
| }, | ||
| ], | ||
| "process": "sequential", | ||
| } | ||
| @staticmethod | ||
| def create_legal_team() -> Dict[str, Any]: | ||
| """Create CrewAI legal team.""" | ||
| return { | ||
| "agents": [ | ||
| { | ||
| "name": "Contract Analyzer", | ||
| "role": "Legal Contract Specialist", | ||
| "goal": "Analyze and review contract terms", | ||
| "backstory": "Senior contract attorney", | ||
| }, | ||
| { | ||
| "name": "Precedent Researcher", | ||
| "role": "Legal Research Specialist", | ||
| "goal": "Research relevant case law and precedents", | ||
| "backstory": "Legal researcher specializing in case law", | ||
| }, | ||
| { | ||
| "name": "Risk Assessor", | ||
| "role": "Legal Risk Specialist", | ||
| "goal": "Identify and assess legal risks", | ||
| "backstory": "Risk management expert in legal domain", | ||
| }, | ||
| { | ||
| "name": "Document Drafter", | ||
| "role": "Legal Document Specialist", | ||
| "goal": "Draft legal documents and recommendations", | ||
| "backstory": "Legal document drafting expert", | ||
| }, | ||
| ], | ||
| "process": "sequential", | ||
| } | ||
| @dataclass | ||
| class AutoGenTemplate: | ||
| """Template for AutoGen implementation.""" | ||
| @staticmethod | ||
| def create_group_chat_config() -> Dict[str, Any]: | ||
| """Create AutoGen group chat configuration.""" | ||
| return { | ||
| "agents": [ | ||
| { | ||
| "name": "analyst", | ||
| "system_message": "You are a financial analyst. Provide analysis based on data.", | ||
| "llm_config": {"model": "gpt-4", "temperature": 0.7}, | ||
| }, | ||
| { | ||
| "name": "researcher", | ||
| "system_message": "You are a market researcher. Research trends and competition.", | ||
| "llm_config": {"model": "gpt-4", "temperature": 0.7}, | ||
| }, | ||
| { | ||
| "name": "critic", | ||
| "system_message": "You are a critical evaluator. Challenge assumptions and findings.", | ||
| "llm_config": {"model": "gpt-4", "temperature": 0.7}, | ||
| }, | ||
| ], | ||
| "group_chat_config": { | ||
| "agents": ["analyst", "researcher", "critic"], | ||
| "max_round": 10, | ||
| "speaker_selection_method": "auto", | ||
| }, | ||
| } | ||
| @staticmethod | ||
| def create_hierarchical_structure() -> Dict[str, Any]: | ||
| """Create hierarchical AutoGen structure.""" | ||
| return { | ||
| "primary_agents": [ | ||
| { | ||
| "name": "senior_analyst", | ||
| "role": "Senior analyst coordinating teams", | ||
| "subordinates": ["junior_analyst_1", "junior_analyst_2"], | ||
| } | ||
| ], | ||
| "secondary_agents": [ | ||
| { | ||
| "name": "junior_analyst_1", | ||
| "role": "Fundamental analysis specialist", | ||
| }, | ||
| { | ||
| "name": "junior_analyst_2", | ||
| "role": "Technical analysis specialist", | ||
| }, | ||
| ], | ||
| } | ||
| @dataclass | ||
| class LangGraphTemplate: | ||
| """Template for LangGraph workflow implementation.""" | ||
| @staticmethod | ||
| def create_research_workflow() -> Dict[str, Any]: | ||
| """Create LangGraph research workflow.""" | ||
| return { | ||
| "name": "research_workflow", | ||
| "state_schema": { | ||
| "topic": str, | ||
| "research_findings": str, | ||
| "analysis": str, | ||
| "recommendations": str, | ||
| }, | ||
| "nodes": [ | ||
| { | ||
| "name": "researcher", | ||
| "agent": "research_agent", | ||
| "description": "Research the topic", | ||
| }, | ||
| { | ||
| "name": "analyst", | ||
| "agent": "analyst_agent", | ||
| "description": "Analyze research findings", | ||
| }, | ||
| { | ||
| "name": "critic", | ||
| "agent": "critic_agent", | ||
| "description": "Critique and improve", | ||
| }, | ||
| { | ||
| "name": "writer", | ||
| "agent": "writer_agent", | ||
| "description": "Write final report", | ||
| }, | ||
| ], | ||
| "edges": [ | ||
| ("researcher", "analyst"), | ||
| ("analyst", "critic"), | ||
| ("critic", "writer"), | ||
| ], | ||
| "entry_point": "researcher", | ||
| "exit_point": "writer", | ||
| } | ||
| @staticmethod | ||
| def create_dynamic_workflow() -> Dict[str, Any]: | ||
| """Create dynamic LangGraph workflow with conditions.""" | ||
| return { | ||
| "name": "dynamic_workflow", | ||
| "nodes": [ | ||
| { | ||
| "name": "start", | ||
| "type": "input", | ||
| }, | ||
| { | ||
| "name": "analyze", | ||
| "type": "agent", | ||
| "agent": "analyzer", | ||
| }, | ||
| { | ||
| "name": "quality_check", | ||
| "type": "decision", | ||
| "condition": "analyze_quality > threshold", | ||
| }, | ||
| { | ||
| "name": "refine", | ||
| "type": "agent", | ||
| "agent": "refiner", | ||
| }, | ||
| { | ||
| "name": "end", | ||
| "type": "output", | ||
| }, | ||
| ], | ||
| "conditional_edges": [ | ||
| { | ||
| "source": "quality_check", | ||
| "true_target": "end", | ||
| "false_target": "refine", | ||
| } | ||
| ], | ||
| } | ||
| @dataclass | ||
| class SwarmTemplate: | ||
| """Template for OpenAI Swarm implementation.""" | ||
| @staticmethod | ||
| def create_customer_support_swarm() -> Dict[str, Any]: | ||
| """Create customer support Swarm.""" | ||
| return { | ||
| "agents": [ | ||
| { | ||
| "name": "triage_agent", | ||
| "instructions": "Determine which specialist to route the customer to. " | ||
| "Ask clarifying questions if needed.", | ||
| "functions": [ | ||
| "route_to_billing", | ||
| "route_to_technical", | ||
| "route_to_account", | ||
| ], | ||
| }, | ||
| { | ||
| "name": "billing_specialist", | ||
| "instructions": "Handle all billing and payment related questions. " | ||
| "Can access billing records.", | ||
| "tools": ["billing_system", "payment_processor"], | ||
| }, | ||
| { | ||
| "name": "technical_support", | ||
| "instructions": "Handle technical issues and troubleshooting. " | ||
| "Can access diagnostic tools.", | ||
| "tools": ["diagnostic_tools", "knowledge_base"], | ||
| }, | ||
| { | ||
| "name": "account_specialist", | ||
| "instructions": "Handle account management and profile changes.", | ||
| "tools": ["account_system"], | ||
| }, | ||
| ], | ||
| "handoff_functions": { | ||
| "route_to_billing": "Transfer to billing specialist", | ||
| "route_to_technical": "Transfer to technical support", | ||
| "route_to_account": "Transfer to account specialist", | ||
| }, | ||
| } | ||
| @staticmethod | ||
| def create_sales_swarm() -> Dict[str, Any]: | ||
| """Create sales team Swarm.""" | ||
| return { | ||
| "agents": [ | ||
| { | ||
| "name": "sales_router", | ||
| "instructions": "Route customer inquiries to appropriate sales agent", | ||
| "functions": ["route_to_enterprise", "route_to_smb"], | ||
| }, | ||
| { | ||
| "name": "enterprise_sales", | ||
| "instructions": "Handle enterprise customer inquiries", | ||
| }, | ||
| { | ||
| "name": "smb_sales", | ||
| "instructions": "Handle small business inquiries", | ||
| }, | ||
| ], | ||
| } | ||
| class AgentCommunicationManager: | ||
| """Manage communication patterns between agents.""" | ||
| def __init__(self, agents: Dict[str, Any]): | ||
| """Initialize communication manager.""" | ||
| self.agents = agents | ||
| self.message_queue = [] | ||
| def broadcast_message(self, sender: str, message: str, recipients: List[str]): | ||
| """Broadcast message to multiple agents.""" | ||
| for recipient in recipients: | ||
| self.message_queue.append({ | ||
| "from": sender, | ||
| "to": recipient, | ||
| "message": message, | ||
| "type": "broadcast", | ||
| }) | ||
| def direct_message(self, sender: str, recipient: str, message: str): | ||
| """Send direct message between agents.""" | ||
| self.message_queue.append({ | ||
| "from": sender, | ||
| "to": recipient, | ||
| "message": message, | ||
| "type": "direct", | ||
| }) | ||
| def publish_shared_state(self, state_key: str, value: Any): | ||
| """Publish to shared state (tool-mediated communication).""" | ||
| self.message_queue.append({ | ||
| "type": "shared_state", | ||
| "key": state_key, | ||
| "value": value, | ||
| }) | ||
| def get_pending_messages(self, agent: str) -> List[Dict]: | ||
| """Get messages for specific agent.""" | ||
| return [msg for msg in self.message_queue if msg.get("to") == agent] | ||
| def process_message_queue(self) -> Dict[str, Any]: | ||
| """Process and summarize message queue.""" | ||
| direct_messages = [m for m in self.message_queue if m["type"] == "direct"] | ||
| broadcasts = [m for m in self.message_queue if m["type"] == "broadcast"] | ||
| shared_states = [m for m in self.message_queue if m["type"] == "shared_state"] | ||
| return { | ||
| "direct_messages": len(direct_messages), | ||
| "broadcasts": len(broadcasts), | ||
| "shared_states": len(shared_states), | ||
| "total_messages": len(self.message_queue), | ||
| } |
| """ | ||
| Multi-Agent Orchestration Patterns | ||
| Implements sequential, parallel, hierarchical, and consensus orchestration. | ||
| """ | ||
| from typing import List, Dict, Any, Optional | ||
| import asyncio | ||
| from abc import ABC, abstractmethod | ||
| class Agent(ABC): | ||
| """Base agent class.""" | ||
| def __init__(self, name: str, role: str, goal: str): | ||
| """Initialize agent.""" | ||
| self.name = name | ||
| self.role = role | ||
| self.goal = goal | ||
| @abstractmethod | ||
| def work(self, task: str) -> str: | ||
| """Execute task.""" | ||
| pass | ||
| async def work_async(self, task: str) -> str: | ||
| """Execute task asynchronously.""" | ||
| return self.work(task) | ||
| class SimpleAgent(Agent): | ||
| """Simple agent implementation.""" | ||
| def __init__(self, name: str, role: str, goal: str): | ||
| """Initialize simple agent.""" | ||
| super().__init__(name, role, goal) | ||
| def work(self, task: str) -> str: | ||
| """Simulate agent work.""" | ||
| return f"{self.name}: Completed task - {task[:50]}..." | ||
| class SequentialOrchestrator: | ||
| """Orchestrate agents to work sequentially.""" | ||
| def __init__(self, agents: List[Agent]): | ||
| """ | ||
| Initialize orchestrator with agents. | ||
| Args: | ||
| agents: List of agents to orchestrate | ||
| """ | ||
| self.agents = agents | ||
| self.execution_log = [] | ||
| def execute(self, initial_task: str) -> Dict[str, Any]: | ||
| """ | ||
| Execute agents sequentially. | ||
| Args: | ||
| initial_task: Initial task description | ||
| Returns: | ||
| Execution results dictionary | ||
| """ | ||
| current_input = initial_task | ||
| results = {} | ||
| for agent in self.agents: | ||
| result = agent.work(current_input) | ||
| results[agent.name] = result | ||
| self.execution_log.append({ | ||
| "agent": agent.name, | ||
| "role": agent.role, | ||
| "task": current_input, | ||
| "result": result, | ||
| }) | ||
| # Next agent uses this agent's output | ||
| current_input = result | ||
| return { | ||
| "type": "sequential", | ||
| "results": results, | ||
| "final_output": current_input, | ||
| "execution_log": self.execution_log, | ||
| } | ||
| class ParallelOrchestrator: | ||
| """Orchestrate agents to work in parallel.""" | ||
| def __init__(self, agents: List[Agent]): | ||
| """Initialize parallel orchestrator.""" | ||
| self.agents = agents | ||
| self.execution_log = [] | ||
| async def execute_async(self, task: str) -> Dict[str, Any]: | ||
| """ | ||
| Execute agents in parallel. | ||
| Args: | ||
| task: Task description | ||
| Returns: | ||
| Execution results dictionary | ||
| """ | ||
| # Create async tasks for all agents | ||
| tasks = [agent.work_async(task) for agent in self.agents] | ||
| # Execute all in parallel | ||
| results_list = await asyncio.gather(*tasks) | ||
| results = { | ||
| agent.name: result | ||
| for agent, result in zip(self.agents, results_list) | ||
| } | ||
| self.execution_log.append({ | ||
| "type": "parallel", | ||
| "task": task, | ||
| "agents": [a.name for a in self.agents], | ||
| "results": results, | ||
| }) | ||
| return { | ||
| "type": "parallel", | ||
| "results": results, | ||
| "execution_log": self.execution_log, | ||
| } | ||
| def execute(self, task: str) -> Dict[str, Any]: | ||
| """Execute agents synchronously (sequential fallback).""" | ||
| return asyncio.run(self.execute_async(task)) | ||
| class HierarchicalOrchestrator: | ||
| """Orchestrate agents in hierarchical structure.""" | ||
| def __init__(self, manager_agent: Agent, specialist_teams: Dict[str, List[Agent]]): | ||
| """ | ||
| Initialize hierarchical orchestrator. | ||
| Args: | ||
| manager_agent: Manager agent | ||
| specialist_teams: Dict of team names to lists of agents | ||
| """ | ||
| self.manager = manager_agent | ||
| self.specialist_teams = specialist_teams | ||
| self.execution_log = [] | ||
| def execute(self, main_task: str) -> Dict[str, Any]: | ||
| """ | ||
| Execute with hierarchical structure. | ||
| Args: | ||
| main_task: Main task for manager | ||
| Returns: | ||
| Execution results | ||
| """ | ||
| team_results = {} | ||
| # Manager assigns tasks to teams | ||
| for team_name, agents in self.specialist_teams.items(): | ||
| # Each team works on their aspect | ||
| team_task = f"{main_task} - Team: {team_name}" | ||
| team_result = {} | ||
| for agent in agents: | ||
| result = agent.work(team_task) | ||
| team_result[agent.name] = result | ||
| team_results[team_name] = team_result | ||
| self.execution_log.append({ | ||
| "team": team_name, | ||
| "agents": [a.name for a in agents], | ||
| "results": team_result, | ||
| }) | ||
| # Manager synthesizes results | ||
| manager_result = self.manager.work( | ||
| f"Synthesize findings from: {list(team_results.keys())}" | ||
| ) | ||
| return { | ||
| "type": "hierarchical", | ||
| "team_results": team_results, | ||
| "manager_synthesis": manager_result, | ||
| "execution_log": self.execution_log, | ||
| } | ||
| class ConsensusOrchestrator: | ||
| """Orchestrate agent debate and consensus.""" | ||
| def __init__(self, agents: List[Agent], mediator_agent: Agent): | ||
| """Initialize consensus orchestrator.""" | ||
| self.agents = agents | ||
| self.mediator = mediator_agent | ||
| self.debate_history = [] | ||
| def execute(self, question: str, rounds: int = 2) -> Dict[str, Any]: | ||
| """ | ||
| Execute debate and reach consensus. | ||
| Args: | ||
| question: Question for debate | ||
| rounds: Number of debate rounds | ||
| Returns: | ||
| Consensus results | ||
| """ | ||
| # Round 1: Initial positions | ||
| positions = {} | ||
| for agent in self.agents: | ||
| position = agent.work(f"Argue your position on: {question}") | ||
| positions[agent.name] = position | ||
| self.debate_history.append({ | ||
| "round": 1, | ||
| "agent": agent.name, | ||
| "position": position, | ||
| }) | ||
| # Additional rounds: Response to others | ||
| for round_num in range(2, rounds + 1): | ||
| for agent in self.agents: | ||
| other_positions = { | ||
| name: pos | ||
| for name, pos in positions.items() | ||
| if name != agent.name | ||
| } | ||
| response = agent.work( | ||
| f"Respond to these positions: {str(other_positions)}" | ||
| ) | ||
| self.debate_history.append({ | ||
| "round": round_num, | ||
| "agent": agent.name, | ||
| "response": response, | ||
| }) | ||
| # Mediator reaches consensus | ||
| consensus = self.mediator.work( | ||
| f"Synthesize consensus from debate on: {question}" | ||
| ) | ||
| return { | ||
| "type": "consensus", | ||
| "question": question, | ||
| "initial_positions": positions, | ||
| "debate_rounds": rounds, | ||
| "consensus": consensus, | ||
| "debate_history": self.debate_history, | ||
| } | ||
| class AdaptiveOrchestrator: | ||
| """Adapt orchestration based on progress.""" | ||
| def __init__(self, agents: List[Agent]): | ||
| """Initialize adaptive orchestrator.""" | ||
| self.agents = agents | ||
| self.execution_log = [] | ||
| def execute_with_adaptation( | ||
| self, | ||
| initial_task: str, | ||
| progress_threshold: float = 0.7, | ||
| quality_threshold: float = 0.6, | ||
| ) -> Dict[str, Any]: | ||
| """ | ||
| Execute with adaptive workflow changes. | ||
| Args: | ||
| initial_task: Initial task | ||
| progress_threshold: Threshold for adding resources | ||
| quality_threshold: Threshold for adding validation | ||
| Returns: | ||
| Adaptive execution results | ||
| """ | ||
| results = {} | ||
| current_task = initial_task | ||
| active_agents = self.agents.copy() | ||
| for iteration in range(3): | ||
| # Execute with current agents | ||
| iteration_results = {} | ||
| for agent in active_agents: | ||
| result = agent.work(current_task) | ||
| iteration_results[agent.name] = result | ||
| results[f"iteration_{iteration}"] = iteration_results | ||
| # Assess progress | ||
| progress = self._calculate_progress(iteration_results) | ||
| quality = self._calculate_quality(iteration_results) | ||
| log_entry = { | ||
| "iteration": iteration, | ||
| "agents": [a.name for a in active_agents], | ||
| "progress": progress, | ||
| "quality": quality, | ||
| } | ||
| # Adapt based on progress | ||
| if progress < progress_threshold and iteration < 2: | ||
| # Add more agents | ||
| log_entry["adaptation"] = "Added specialist agent" | ||
| self.execution_log.append(log_entry) | ||
| elif quality < quality_threshold and iteration < 2: | ||
| # Add validation step | ||
| log_entry["adaptation"] = "Added validation agent" | ||
| self.execution_log.append(log_entry) | ||
| else: | ||
| self.execution_log.append(log_entry) | ||
| return { | ||
| "type": "adaptive", | ||
| "results": results, | ||
| "adaptations": self.execution_log, | ||
| } | ||
| @staticmethod | ||
| def _calculate_progress(results: Dict) -> float: | ||
| """Calculate progress score.""" | ||
| # Simple heuristic based on results | ||
| return min(len(results) / 3.0, 1.0) | ||
| @staticmethod | ||
| def _calculate_quality(results: Dict) -> float: | ||
| """Calculate quality score.""" | ||
| # Simple heuristic | ||
| return 0.7 # Placeholder | ||
| class WorkflowGraph: | ||
| """Define workflow as directed acyclic graph (DAG).""" | ||
| def __init__(self): | ||
| """Initialize workflow graph.""" | ||
| self.nodes = {} | ||
| self.edges = [] | ||
| def add_node(self, node_id: str, agent: Agent) -> None: | ||
| """Add agent node.""" | ||
| self.nodes[node_id] = agent | ||
| def add_edge(self, from_node: str, to_node: str) -> None: | ||
| """Add dependency edge.""" | ||
| self.edges.append((from_node, to_node)) | ||
| def execute_dag(self, initial_task: str) -> Dict[str, Any]: | ||
| """ | ||
| Execute workflow as DAG. | ||
| Args: | ||
| initial_task: Initial task | ||
| Returns: | ||
| Execution results | ||
| """ | ||
| results = {} | ||
| ready_nodes = self._find_ready_nodes() | ||
| while ready_nodes: | ||
| for node_id in ready_nodes: | ||
| agent = self.nodes[node_id] | ||
| # Get input from dependencies | ||
| task_input = self._get_node_input(node_id, results, initial_task) | ||
| result = agent.work(task_input) | ||
| results[node_id] = result | ||
| ready_nodes = self._find_ready_nodes(completed=set(results.keys())) | ||
| return { | ||
| "type": "dag", | ||
| "results": results, | ||
| "nodes": list(self.nodes.keys()), | ||
| "edges": self.edges, | ||
| } | ||
| def _find_ready_nodes(self, completed: Optional[set] = None) -> List[str]: | ||
| """Find nodes with all dependencies completed.""" | ||
| if completed is None: | ||
| completed = set() | ||
| ready = [] | ||
| for node_id in self.nodes: | ||
| if node_id not in completed: | ||
| dependencies = [ | ||
| from_node | ||
| for from_node, to_node in self.edges | ||
| if to_node == node_id | ||
| ] | ||
| if all(dep in completed for dep in dependencies): | ||
| ready.append(node_id) | ||
| return ready | ||
| def _get_node_input( | ||
| self, node_id: str, results: Dict, initial_task: str | ||
| ) -> str: | ||
| """Get input for node from dependencies.""" | ||
| dependencies = [ | ||
| from_node for from_node, to_node in self.edges if to_node == node_id | ||
| ] | ||
| if not dependencies: | ||
| return initial_task | ||
| # Combine outputs from dependencies | ||
| return " + ".join(results.get(dep, "") for dep in dependencies) |
| # Multi-Agent Orchestration - Code Structure | ||
| This skill uses supporting Python files to keep documentation lean and maintainable. | ||
| ## Directory Structure | ||
| ``` | ||
| multi-agent-orchestration/ | ||
| ├── SKILL.md # Main documentation (patterns, concepts) | ||
| ├── README.md # This file | ||
| ├── examples/ # Implementation examples | ||
| │ ├── orchestration_patterns.py # Sequential, parallel, hierarchical, consensus | ||
| │ └── framework_implementations.py # CrewAI, AutoGen, LangGraph, Swarm templates | ||
| └── scripts/ # Utility modules | ||
| ├── agent_communication.py # Message broker, shared memory, protocols | ||
| ├── workflow_management.py # Workflow execution and optimization | ||
| └── benchmarking.py # Performance and collaboration metrics | ||
| ``` | ||
| ## Running Examples | ||
| ### 1. Orchestration Patterns | ||
| ```bash | ||
| python examples/orchestration_patterns.py | ||
| ``` | ||
| Demonstrates sequential, parallel, hierarchical, and consensus orchestration. | ||
| ### 2. Framework Templates | ||
| ```bash | ||
| python examples/framework_implementations.py | ||
| ``` | ||
| Templates and configurations for CrewAI, AutoGen, LangGraph, and Swarm frameworks. | ||
| ## Using the Utilities | ||
| ### Agent Communication | ||
| ```python | ||
| from scripts.agent_communication import MessageBroker, SharedMemory, CommunicationProtocol | ||
| # Set up communication | ||
| broker = MessageBroker() | ||
| shared_memory = SharedMemory() | ||
| protocol = CommunicationProtocol(broker, shared_memory) | ||
| # Send messages between agents | ||
| protocol.request_analysis("agent_a", "agent_b", "Analyze this topic") | ||
| # Share findings | ||
| protocol.share_findings("agent_a", "analysis_results", {"findings": "..."}) | ||
| # Get communication stats | ||
| stats = broker.get_statistics() | ||
| ``` | ||
| ### Workflow Management | ||
| ```python | ||
| from scripts.workflow_management import WorkflowExecutor, WorkflowOptimizer | ||
| # Create and execute workflow | ||
| executor = WorkflowExecutor() | ||
| workflow = executor.create_workflow("workflow_1", "Analysis Workflow") | ||
| # Add tasks | ||
| executor.add_task("workflow_1", "task_1", "researcher", "Research the topic") | ||
| executor.add_task("workflow_1", "task_2", "analyst", "Analyze findings", dependencies=["task_1"]) | ||
| # Execute | ||
| results = executor.execute_workflow("workflow_1", executor_func) | ||
| # Analyze workflow | ||
| analysis = WorkflowOptimizer.analyze_dependencies(workflow) | ||
| print(f"Critical path: {analysis['critical_path']}") | ||
| ``` | ||
| ### Benchmarking | ||
| ```python | ||
| from scripts.benchmarking import TeamBenchmark, AgentEffectiveness, CollaborationMetrics | ||
| # Benchmark team performance | ||
| benchmark = TeamBenchmark() | ||
| result = benchmark.run_benchmark("sequential_test", orchestrator, test_data) | ||
| # Track agent effectiveness | ||
| effectiveness = AgentEffectiveness() | ||
| effectiveness.record_agent_task("agent_a", "task_1", success=True, quality_score=0.95, duration=2.5) | ||
| # Get agent rankings | ||
| rankings = effectiveness.rank_agents() | ||
| for rank, agent, score, metrics in rankings: | ||
| print(f"{rank}. {agent}: {score:.2f}") | ||
| # Analyze collaboration | ||
| collaboration = CollaborationMetrics() | ||
| collaboration.record_interaction("agent_a", "agent_b", "request", response_time=0.5, successful=True) | ||
| interaction_metrics = collaboration.get_interaction_metrics() | ||
| ``` | ||
| ## Integration with SKILL.md | ||
| - SKILL.md contains conceptual information, orchestration patterns, and best practices | ||
| - Code examples are in `examples/` for clarity and runnable implementations | ||
| - Utilities are in `scripts/` for modular, reusable components | ||
| - This keeps token costs low while maintaining full functionality | ||
| ## Orchestration Patterns Covered | ||
| 1. **Sequential Orchestration** - Tasks execute one after another | ||
| 2. **Parallel Orchestration** - Multiple agents work simultaneously | ||
| 3. **Hierarchical Orchestration** - Manager coordinates specialist teams | ||
| 4. **Consensus-Based** - Agents debate and reach consensus | ||
| 5. **Adaptive Workflows** - Orchestration changes based on progress | ||
| 6. **DAG-Based** - Workflow as directed acyclic graph | ||
| ## Framework Implementations | ||
| - **CrewAI** - Clear roles, hierarchical structure | ||
| - **AutoGen** - Multi-turn conversations, group discussions | ||
| - **LangGraph** - State management, complex workflows | ||
| - **Swarm** - Simple handoffs, conversational workflows | ||
| ## Key Features | ||
| - **Token Efficient**: Modular code structure reduces LLM context usage | ||
| - **Production Ready**: Includes monitoring, optimization, and benchmarking | ||
| - **Framework Agnostic**: Works with any agent framework | ||
| - **Communication Patterns**: Direct, tool-mediated, and manager-based | ||
| - **Performance Metrics**: Team and individual agent effectiveness tracking | ||
| ## Communication Patterns | ||
| - **Direct Communication**: Agent-to-agent message passing | ||
| - **Tool-Mediated**: Agents use shared memory/database | ||
| - **Manager-Based**: Central coordinator manages communication | ||
| - **Broadcast**: One-to-many messaging | ||
| ## Next Steps | ||
| 1. Define agent roles and expertise | ||
| 2. Choose orchestration pattern (sequential, parallel, hierarchical) | ||
| 3. Select communication approach (direct, shared memory, manager) | ||
| 4. Implement workflow with task definitions | ||
| 5. Set up monitoring and metrics | ||
| 6. Benchmark and optimize | ||
| 7. Deploy and iterate |
| """ | ||
| Agent Communication Management | ||
| Handle agent-to-agent communication, message passing, and shared state. | ||
| """ | ||
| from typing import Dict, List, Optional, Any, Callable | ||
| from dataclasses import dataclass, field | ||
| from enum import Enum | ||
| import json | ||
| class MessageType(Enum): | ||
| """Types of messages between agents.""" | ||
| DIRECT = "direct" | ||
| BROADCAST = "broadcast" | ||
| REQUEST = "request" | ||
| RESPONSE = "response" | ||
| FEEDBACK = "feedback" | ||
| ERROR = "error" | ||
| @dataclass | ||
| class Message: | ||
| """Message between agents.""" | ||
| sender: str | ||
| recipient: str | ||
| content: str | ||
| message_type: MessageType | ||
| timestamp: float = field(default_factory=lambda: 0) | ||
| metadata: Dict[str, Any] = field(default_factory=dict) | ||
| def to_dict(self) -> Dict: | ||
| """Convert to dictionary.""" | ||
| return { | ||
| "sender": self.sender, | ||
| "recipient": self.recipient, | ||
| "content": self.content, | ||
| "type": self.message_type.value, | ||
| "timestamp": self.timestamp, | ||
| "metadata": self.metadata, | ||
| } | ||
| class MessageBroker: | ||
| """Central message broker for agent communication.""" | ||
| def __init__(self): | ||
| """Initialize message broker.""" | ||
| self.message_queue: List[Message] = [] | ||
| self.agent_inboxes: Dict[str, List[Message]] = {} | ||
| self.message_handlers: Dict[MessageType, List[Callable]] = {} | ||
| def send_message(self, message: Message) -> bool: | ||
| """ | ||
| Send message from one agent to another. | ||
| Args: | ||
| message: Message object | ||
| Returns: | ||
| Whether message was delivered | ||
| """ | ||
| self.message_queue.append(message) | ||
| # Add to recipient's inbox | ||
| if message.recipient not in self.agent_inboxes: | ||
| self.agent_inboxes[message.recipient] = [] | ||
| self.agent_inboxes[message.recipient].append(message) | ||
| # Trigger handlers | ||
| self._trigger_handlers(message) | ||
| return True | ||
| def broadcast_message(self, sender: str, content: str, recipients: List[str]): | ||
| """ | ||
| Broadcast message to multiple agents. | ||
| Args: | ||
| sender: Sending agent | ||
| content: Message content | ||
| recipients: List of recipient agents | ||
| """ | ||
| for recipient in recipients: | ||
| message = Message( | ||
| sender=sender, | ||
| recipient=recipient, | ||
| content=content, | ||
| message_type=MessageType.BROADCAST, | ||
| ) | ||
| self.send_message(message) | ||
| def request_response( | ||
| self, sender: str, recipient: str, content: str, timeout: float = 5.0 | ||
| ) -> Optional[Message]: | ||
| """ | ||
| Send request and wait for response. | ||
| Args: | ||
| sender: Requesting agent | ||
| recipient: Agent to respond | ||
| content: Request content | ||
| timeout: Response timeout in seconds | ||
| Returns: | ||
| Response message or None | ||
| """ | ||
| message = Message( | ||
| sender=sender, | ||
| recipient=recipient, | ||
| content=content, | ||
| message_type=MessageType.REQUEST, | ||
| metadata={"timeout": timeout}, | ||
| ) | ||
| self.send_message(message) | ||
| # Placeholder - wait for response | ||
| # In production, implement actual timeout/wait mechanism | ||
| return None | ||
| def get_inbox(self, agent: str) -> List[Message]: | ||
| """Get messages for specific agent.""" | ||
| return self.agent_inboxes.get(agent, []) | ||
| def clear_inbox(self, agent: str) -> None: | ||
| """Clear agent's inbox.""" | ||
| self.agent_inboxes[agent] = [] | ||
| def register_handler( | ||
| self, message_type: MessageType, handler: Callable | ||
| ) -> None: | ||
| """Register handler for message type.""" | ||
| if message_type not in self.message_handlers: | ||
| self.message_handlers[message_type] = [] | ||
| self.message_handlers[message_type].append(handler) | ||
| def _trigger_handlers(self, message: Message) -> None: | ||
| """Trigger registered handlers.""" | ||
| handlers = self.message_handlers.get(message.message_type, []) | ||
| for handler in handlers: | ||
| try: | ||
| handler(message) | ||
| except Exception: | ||
| pass | ||
| def get_statistics(self) -> Dict[str, Any]: | ||
| """Get communication statistics.""" | ||
| type_counts = {} | ||
| for message in self.message_queue: | ||
| msg_type = message.message_type.value | ||
| type_counts[msg_type] = type_counts.get(msg_type, 0) + 1 | ||
| return { | ||
| "total_messages": len(self.message_queue), | ||
| "by_type": type_counts, | ||
| "total_agents": len(self.agent_inboxes), | ||
| "agents": list(self.agent_inboxes.keys()), | ||
| } | ||
| class SharedMemory: | ||
| """Shared memory for tool-mediated agent communication.""" | ||
| def __init__(self): | ||
| """Initialize shared memory.""" | ||
| self.memory: Dict[str, Any] = {} | ||
| self.access_log: List[Dict] = [] | ||
| def write(self, key: str, value: Any, agent: str = "system") -> None: | ||
| """ | ||
| Write to shared memory. | ||
| Args: | ||
| key: Memory key | ||
| value: Value to store | ||
| agent: Agent writing | ||
| """ | ||
| self.memory[key] = { | ||
| "value": value, | ||
| "writer": agent, | ||
| "access_count": 0, | ||
| } | ||
| self.access_log.append({ | ||
| "action": "write", | ||
| "key": key, | ||
| "agent": agent, | ||
| }) | ||
| def read(self, key: str, agent: str = "system") -> Optional[Any]: | ||
| """ | ||
| Read from shared memory. | ||
| Args: | ||
| key: Memory key | ||
| agent: Agent reading | ||
| Returns: | ||
| Stored value or None | ||
| """ | ||
| if key in self.memory: | ||
| entry = self.memory[key] | ||
| entry["access_count"] += 1 | ||
| self.access_log.append({ | ||
| "action": "read", | ||
| "key": key, | ||
| "agent": agent, | ||
| }) | ||
| return entry["value"] | ||
| return None | ||
| def append(self, key: str, value: Any, agent: str = "system") -> None: | ||
| """Append to list in shared memory.""" | ||
| if key not in self.memory: | ||
| self.memory[key] = { | ||
| "value": [], | ||
| "writer": agent, | ||
| "access_count": 0, | ||
| } | ||
| if isinstance(self.memory[key]["value"], list): | ||
| self.memory[key]["value"].append(value) | ||
| def get_all(self) -> Dict[str, Any]: | ||
| """Get all shared memory contents.""" | ||
| return { | ||
| key: entry["value"] for key, entry in self.memory.items() | ||
| } | ||
| def get_statistics(self) -> Dict[str, Any]: | ||
| """Get memory access statistics.""" | ||
| total_accesses = sum( | ||
| entry["access_count"] for entry in self.memory.values() | ||
| ) | ||
| return { | ||
| "total_keys": len(self.memory), | ||
| "total_accesses": total_accesses, | ||
| "access_log_size": len(self.access_log), | ||
| } | ||
| class ContextManager: | ||
| """Manage context sharing between agents.""" | ||
| def __init__(self): | ||
| """Initialize context manager.""" | ||
| self.contexts: Dict[str, Dict[str, Any]] = {} | ||
| self.global_context: Dict[str, Any] = {} | ||
| def create_context(self, context_id: str, initial_data: Optional[Dict] = None) -> None: | ||
| """Create new context.""" | ||
| self.contexts[context_id] = initial_data or {} | ||
| def update_context(self, context_id: str, data: Dict) -> None: | ||
| """Update context data.""" | ||
| if context_id in self.contexts: | ||
| self.contexts[context_id].update(data) | ||
| def get_context(self, context_id: str) -> Dict[str, Any]: | ||
| """Get context data.""" | ||
| return self.contexts.get(context_id, {}) | ||
| def set_global_context(self, key: str, value: Any) -> None: | ||
| """Set global context variable.""" | ||
| self.global_context[key] = value | ||
| def get_global_context(self, key: str) -> Optional[Any]: | ||
| """Get global context variable.""" | ||
| return self.global_context.get(key) | ||
| def context_to_string(self, context_id: str) -> str: | ||
| """Convert context to formatted string.""" | ||
| context = self.get_context(context_id) | ||
| return json.dumps(context, indent=2) | ||
| class CommunicationProtocol: | ||
| """Define communication protocol between agents.""" | ||
| def __init__(self, broker: MessageBroker, shared_memory: SharedMemory): | ||
| """Initialize protocol.""" | ||
| self.broker = broker | ||
| self.shared_memory = shared_memory | ||
| def request_analysis( | ||
| self, requester: str, analyzer: str, subject: str | ||
| ) -> None: | ||
| """Request analysis from another agent.""" | ||
| message = Message( | ||
| sender=requester, | ||
| recipient=analyzer, | ||
| content=f"Analyze: {subject}", | ||
| message_type=MessageType.REQUEST, | ||
| metadata={"action": "analyze"}, | ||
| ) | ||
| self.broker.send_message(message) | ||
| def share_findings(self, source_agent: str, key: str, findings: Dict) -> None: | ||
| """Share findings through shared memory.""" | ||
| self.shared_memory.write(key, findings, source_agent) | ||
| def aggregate_results( | ||
| self, agents: List[str], result_key: str | ||
| ) -> Dict[str, Any]: | ||
| """Aggregate results from multiple agents.""" | ||
| results = {} | ||
| for agent in agents: | ||
| agent_results = self.shared_memory.read(f"{agent}_{result_key}") | ||
| if agent_results: | ||
| results[agent] = agent_results | ||
| return results | ||
| def notify_status(self, agent: str, status: str) -> None: | ||
| """Notify status update.""" | ||
| message = Message( | ||
| sender=agent, | ||
| recipient="orchestrator", | ||
| content=f"Status: {status}", | ||
| message_type=MessageType.FEEDBACK, | ||
| ) | ||
| self.broker.send_message(message) | ||
| def error_propagation(self, source_agent: str, error: str) -> None: | ||
| """Propagate error to relevant agents.""" | ||
| message = Message( | ||
| sender=source_agent, | ||
| recipient="orchestrator", | ||
| content=f"Error: {error}", | ||
| message_type=MessageType.ERROR, | ||
| ) | ||
| self.broker.send_message(message) |
| """ | ||
| Multi-Agent System Benchmarking | ||
| Evaluate team performance and agent effectiveness. | ||
| """ | ||
| from typing import Dict, List, Any, Callable, Optional | ||
| from dataclasses import dataclass | ||
| import time | ||
| import statistics | ||
| @dataclass | ||
| class BenchmarkResult: | ||
| """Result from benchmark run.""" | ||
| test_name: str | ||
| total_time: float | ||
| task_count: int | ||
| success_count: int | ||
| failure_count: int | ||
| quality_score: float | ||
| cost_tokens: int | ||
| class TeamBenchmark: | ||
| """Benchmark multi-agent team performance.""" | ||
| def __init__(self): | ||
| """Initialize benchmarking suite.""" | ||
| self.results: List[BenchmarkResult] = [] | ||
| self.agent_metrics: Dict[str, Dict] = {} | ||
| def run_benchmark( | ||
| self, | ||
| test_name: str, | ||
| orchestrator, | ||
| test_data: List[Dict], | ||
| quality_metric: Optional[Callable] = None, | ||
| ) -> BenchmarkResult: | ||
| """ | ||
| Run benchmark test. | ||
| Args: | ||
| test_name: Name of benchmark | ||
| orchestrator: Orchestrator instance | ||
| test_data: Test cases | ||
| quality_metric: Function to evaluate quality | ||
| Returns: | ||
| Benchmark result | ||
| """ | ||
| start_time = time.time() | ||
| results = [] | ||
| costs = [] | ||
| for test_case in test_data: | ||
| try: | ||
| result = orchestrator.execute(test_case) | ||
| results.append(result) | ||
| # Assume cost in test_case | ||
| costs.append(test_case.get("cost", 0)) | ||
| except Exception: | ||
| pass | ||
| end_time = time.time() | ||
| success_count = len(results) | ||
| failure_count = len(test_data) - success_count | ||
| total_time = end_time - start_time | ||
| # Calculate quality score | ||
| quality_score = ( | ||
| quality_metric(results) if quality_metric else success_count / len(test_data) | ||
| ) | ||
| benchmark_result = BenchmarkResult( | ||
| test_name=test_name, | ||
| total_time=total_time, | ||
| task_count=len(test_data), | ||
| success_count=success_count, | ||
| failure_count=failure_count, | ||
| quality_score=quality_score, | ||
| cost_tokens=sum(costs), | ||
| ) | ||
| self.results.append(benchmark_result) | ||
| return benchmark_result | ||
| def compare_orchestration_methods( | ||
| self, | ||
| methods: Dict[str, Callable], | ||
| test_data: List[Dict], | ||
| ) -> Dict[str, Any]: | ||
| """ | ||
| Compare different orchestration methods. | ||
| Args: | ||
| methods: Dict of method name to orchestrator | ||
| test_data: Test cases | ||
| Returns: | ||
| Comparison results | ||
| """ | ||
| comparison = {} | ||
| for method_name, orchestrator in methods.items(): | ||
| result = self.run_benchmark(method_name, orchestrator, test_data) | ||
| comparison[method_name] = { | ||
| "total_time": result.total_time, | ||
| "success_rate": result.success_count / result.task_count, | ||
| "quality_score": result.quality_score, | ||
| "efficiency": result.success_count / (result.total_time + 0.001), | ||
| "cost_per_success": ( | ||
| result.cost_tokens / result.success_count | ||
| if result.success_count > 0 | ||
| else float("inf") | ||
| ), | ||
| } | ||
| return comparison | ||
| def get_summary(self) -> Dict[str, Any]: | ||
| """Get benchmark summary.""" | ||
| if not self.results: | ||
| return {"status": "no_results"} | ||
| times = [r.total_time for r in self.results] | ||
| success_rates = [ | ||
| r.success_count / r.task_count for r in self.results | ||
| ] | ||
| quality_scores = [r.quality_score for r in self.results] | ||
| return { | ||
| "total_benchmarks": len(self.results), | ||
| "avg_time": statistics.mean(times), | ||
| "median_time": statistics.median(times), | ||
| "avg_success_rate": statistics.mean(success_rates), | ||
| "avg_quality": statistics.mean(quality_scores), | ||
| "benchmarks": [r.__dict__ for r in self.results], | ||
| } | ||
| class AgentEffectiveness: | ||
| """Measure individual agent effectiveness.""" | ||
| def __init__(self): | ||
| """Initialize effectiveness tracker.""" | ||
| self.agent_stats: Dict[str, Dict] = {} | ||
| def record_agent_task( | ||
| self, | ||
| agent: str, | ||
| task_id: str, | ||
| success: bool, | ||
| quality_score: float, | ||
| duration: float, | ||
| ) -> None: | ||
| """Record agent task execution.""" | ||
| if agent not in self.agent_stats: | ||
| self.agent_stats[agent] = { | ||
| "tasks": [], | ||
| "successes": 0, | ||
| "failures": 0, | ||
| } | ||
| stats = self.agent_stats[agent] | ||
| stats["tasks"].append({ | ||
| "task_id": task_id, | ||
| "success": success, | ||
| "quality": quality_score, | ||
| "duration": duration, | ||
| }) | ||
| if success: | ||
| stats["successes"] += 1 | ||
| else: | ||
| stats["failures"] += 1 | ||
| def get_agent_metrics(self, agent: str) -> Dict[str, Any]: | ||
| """Get metrics for specific agent.""" | ||
| if agent not in self.agent_stats: | ||
| return {"status": "no_data"} | ||
| stats = self.agent_stats[agent] | ||
| tasks = stats["tasks"] | ||
| if not tasks: | ||
| return {"status": "no_tasks"} | ||
| success_rate = stats["successes"] / (stats["successes"] + stats["failures"]) | ||
| quality_scores = [t["quality"] for t in tasks] | ||
| durations = [t["duration"] for t in tasks] | ||
| return { | ||
| "agent": agent, | ||
| "total_tasks": len(tasks), | ||
| "success_rate": success_rate, | ||
| "avg_quality": statistics.mean(quality_scores), | ||
| "avg_duration": statistics.mean(durations), | ||
| "reliability": success_rate, # Alias for clarity | ||
| } | ||
| def rank_agents(self) -> List[tuple]: | ||
| """Rank agents by effectiveness.""" | ||
| rankings = [] | ||
| for agent in self.agent_stats.keys(): | ||
| metrics = self.get_agent_metrics(agent) | ||
| if "success_rate" in metrics: | ||
| score = ( | ||
| metrics["success_rate"] * 0.4 + | ||
| metrics["avg_quality"] * 0.4 + | ||
| (1 - min(metrics["avg_duration"] / 10.0, 1.0)) * 0.2 | ||
| ) | ||
| rankings.append((agent, score, metrics)) | ||
| rankings.sort(key=lambda x: x[1], reverse=True) | ||
| return rankings | ||
| def get_team_report(self) -> Dict[str, Any]: | ||
| """Get team effectiveness report.""" | ||
| rankings = self.rank_agents() | ||
| return { | ||
| "total_agents": len(self.agent_stats), | ||
| "rankings": [ | ||
| { | ||
| "rank": i + 1, | ||
| "agent": agent, | ||
| "score": score, | ||
| "metrics": metrics, | ||
| } | ||
| for i, (agent, score, metrics) in enumerate(rankings) | ||
| ], | ||
| } | ||
| class CollaborationMetrics: | ||
| """Measure collaboration effectiveness between agents.""" | ||
| def __init__(self): | ||
| """Initialize collaboration metrics.""" | ||
| self.interactions: List[Dict] = [] | ||
| def record_interaction( | ||
| self, | ||
| agent_a: str, | ||
| agent_b: str, | ||
| message: str, | ||
| response_time: float, | ||
| successful: bool, | ||
| ) -> None: | ||
| """Record agent-to-agent interaction.""" | ||
| self.interactions.append({ | ||
| "agent_a": agent_a, | ||
| "agent_b": agent_b, | ||
| "message": message, | ||
| "response_time": response_time, | ||
| "successful": successful, | ||
| }) | ||
| def get_collaboration_graph(self) -> Dict[str, List[str]]: | ||
| """Get collaboration graph between agents.""" | ||
| graph = {} | ||
| for interaction in self.interactions: | ||
| agent_a = interaction["agent_a"] | ||
| agent_b = interaction["agent_b"] | ||
| if agent_a not in graph: | ||
| graph[agent_a] = [] | ||
| if agent_b not in graph[agent_a]: | ||
| graph[agent_a].append(agent_b) | ||
| return graph | ||
| def get_interaction_metrics(self) -> Dict[str, Any]: | ||
| """Get interaction metrics.""" | ||
| if not self.interactions: | ||
| return {"total_interactions": 0} | ||
| response_times = [i["response_time"] for i in self.interactions] | ||
| success_rate = sum(1 for i in self.interactions if i["successful"]) / len( | ||
| self.interactions | ||
| ) | ||
| return { | ||
| "total_interactions": len(self.interactions), | ||
| "success_rate": success_rate, | ||
| "avg_response_time": statistics.mean(response_times), | ||
| "median_response_time": statistics.median(response_times), | ||
| "max_response_time": max(response_times), | ||
| "collaboration_score": success_rate * (1 - min(statistics.mean(response_times) / 10.0, 1.0)), | ||
| } | ||
| def get_agent_collaboration_analysis(self, agent: str) -> Dict[str, Any]: | ||
| """Get collaboration analysis for specific agent.""" | ||
| agent_interactions = [ | ||
| i for i in self.interactions | ||
| if i["agent_a"] == agent or i["agent_b"] == agent | ||
| ] | ||
| if not agent_interactions: | ||
| return {"agent": agent, "status": "no_interactions"} | ||
| partners = set() | ||
| for interaction in agent_interactions: | ||
| if interaction["agent_a"] == agent: | ||
| partners.add(interaction["agent_b"]) | ||
| else: | ||
| partners.add(interaction["agent_a"]) | ||
| success_rate = sum( | ||
| 1 for i in agent_interactions if i["successful"] | ||
| ) / len(agent_interactions) | ||
| return { | ||
| "agent": agent, | ||
| "collaboration_partners": list(partners), | ||
| "total_interactions": len(agent_interactions), | ||
| "collaboration_success_rate": success_rate, | ||
| } | ||
| def create_benchmark_suite() -> Dict[str, Callable]: | ||
| """Create standard benchmark suite.""" | ||
| return { | ||
| "sequential_tasks": lambda orchestrator: orchestrator.execute( | ||
| {"type": "sequential", "task_count": 5} | ||
| ), | ||
| "parallel_tasks": lambda orchestrator: orchestrator.execute( | ||
| {"type": "parallel", "task_count": 10} | ||
| ), | ||
| "complex_workflow": lambda orchestrator: orchestrator.execute( | ||
| {"type": "complex", "task_count": 20} | ||
| ), | ||
| "error_handling": lambda orchestrator: orchestrator.execute( | ||
| {"type": "with_errors", "task_count": 10} | ||
| ), | ||
| } |
| """ | ||
| Workflow Management for Multi-Agent Systems | ||
| Handle workflow execution, monitoring, and optimization. | ||
| """ | ||
| from typing import Dict, List, Any, Optional, Callable | ||
| from enum import Enum | ||
| from dataclasses import dataclass, field | ||
| import time | ||
| class WorkflowStatus(Enum): | ||
| """Workflow execution status.""" | ||
| PENDING = "pending" | ||
| RUNNING = "running" | ||
| PAUSED = "paused" | ||
| COMPLETED = "completed" | ||
| FAILED = "failed" | ||
| class TaskStatus(Enum): | ||
| """Task execution status.""" | ||
| PENDING = "pending" | ||
| RUNNING = "running" | ||
| COMPLETED = "completed" | ||
| FAILED = "failed" | ||
| SKIPPED = "skipped" | ||
| @dataclass | ||
| class Task: | ||
| """Task to be executed by an agent.""" | ||
| task_id: str | ||
| agent: str | ||
| description: str | ||
| status: TaskStatus = TaskStatus.PENDING | ||
| result: Optional[str] = None | ||
| error: Optional[str] = None | ||
| start_time: float = field(default_factory=time.time) | ||
| end_time: Optional[float] = None | ||
| dependencies: List[str] = field(default_factory=list) | ||
| @dataclass | ||
| class Workflow: | ||
| """Workflow orchestration.""" | ||
| workflow_id: str | ||
| name: str | ||
| tasks: Dict[str, Task] = field(default_factory=dict) | ||
| status: WorkflowStatus = WorkflowStatus.PENDING | ||
| start_time: Optional[float] = None | ||
| end_time: Optional[float] = None | ||
| class WorkflowExecutor: | ||
| """Execute workflows with multiple agents.""" | ||
| def __init__(self): | ||
| """Initialize workflow executor.""" | ||
| self.workflows: Dict[str, Workflow] = {} | ||
| self.execution_history: List[Dict] = [] | ||
| def create_workflow(self, workflow_id: str, name: str) -> Workflow: | ||
| """Create new workflow.""" | ||
| workflow = Workflow(workflow_id=workflow_id, name=name) | ||
| self.workflows[workflow_id] = workflow | ||
| return workflow | ||
| def add_task( | ||
| self, | ||
| workflow_id: str, | ||
| task_id: str, | ||
| agent: str, | ||
| description: str, | ||
| dependencies: Optional[List[str]] = None, | ||
| ) -> Task: | ||
| """Add task to workflow.""" | ||
| task = Task( | ||
| task_id=task_id, | ||
| agent=agent, | ||
| description=description, | ||
| dependencies=dependencies or [], | ||
| ) | ||
| self.workflows[workflow_id].tasks[task_id] = task | ||
| return task | ||
| def execute_workflow( | ||
| self, workflow_id: str, executor_func: Callable | ||
| ) -> Dict[str, Any]: | ||
| """ | ||
| Execute workflow. | ||
| Args: | ||
| workflow_id: Workflow ID | ||
| executor_func: Function to execute tasks | ||
| Returns: | ||
| Execution results | ||
| """ | ||
| workflow = self.workflows[workflow_id] | ||
| workflow.status = WorkflowStatus.RUNNING | ||
| workflow.start_time = time.time() | ||
| executed_tasks = set() | ||
| results = {} | ||
| while len(executed_tasks) < len(workflow.tasks): | ||
| # Find ready tasks | ||
| ready_tasks = self._get_ready_tasks(workflow, executed_tasks) | ||
| if not ready_tasks: | ||
| # Check if workflow is stuck | ||
| if len(executed_tasks) > 0: | ||
| break | ||
| for task_id in ready_tasks: | ||
| task = workflow.tasks[task_id] | ||
| task.status = TaskStatus.RUNNING | ||
| try: | ||
| # Execute task | ||
| result = executor_func(task) | ||
| task.result = result | ||
| task.status = TaskStatus.COMPLETED | ||
| results[task_id] = result | ||
| except Exception as e: | ||
| task.error = str(e) | ||
| task.status = TaskStatus.FAILED | ||
| results[task_id] = None | ||
| task.end_time = time.time() | ||
| executed_tasks.add(task_id) | ||
| # Finalize workflow | ||
| workflow.end_time = time.time() | ||
| if all(task.status == TaskStatus.COMPLETED for task in workflow.tasks.values()): | ||
| workflow.status = WorkflowStatus.COMPLETED | ||
| else: | ||
| workflow.status = WorkflowStatus.FAILED | ||
| execution_record = { | ||
| "workflow_id": workflow_id, | ||
| "status": workflow.status.value, | ||
| "duration": workflow.end_time - workflow.start_time, | ||
| "results": results, | ||
| } | ||
| self.execution_history.append(execution_record) | ||
| return results | ||
| def _get_ready_tasks( | ||
| self, workflow: Workflow, executed: set | ||
| ) -> List[str]: | ||
| """Get tasks ready to execute.""" | ||
| ready = [] | ||
| for task_id, task in workflow.tasks.items(): | ||
| if task_id not in executed and task.status == TaskStatus.PENDING: | ||
| # Check if all dependencies are complete | ||
| deps_met = all(dep in executed for dep in task.dependencies) | ||
| if deps_met: | ||
| ready.append(task_id) | ||
| return ready | ||
| def get_workflow_status(self, workflow_id: str) -> Dict[str, Any]: | ||
| """Get workflow status.""" | ||
| workflow = self.workflows[workflow_id] | ||
| return { | ||
| "id": workflow.workflow_id, | ||
| "name": workflow.name, | ||
| "status": workflow.status.value, | ||
| "tasks": { | ||
| task_id: task.status.value | ||
| for task_id, task in workflow.tasks.items() | ||
| }, | ||
| } | ||
| class WorkflowOptimizer: | ||
| """Optimize workflow execution.""" | ||
| @staticmethod | ||
| def analyze_dependencies(workflow: Workflow) -> Dict[str, Any]: | ||
| """Analyze task dependencies.""" | ||
| dep_graph = {} | ||
| for task_id, task in workflow.tasks.items(): | ||
| dep_graph[task_id] = task.dependencies | ||
| # Find critical path | ||
| critical_path = WorkflowOptimizer._find_critical_path( | ||
| dep_graph, workflow.tasks | ||
| ) | ||
| # Find parallelizable tasks | ||
| parallel_groups = WorkflowOptimizer._find_parallel_groups(dep_graph) | ||
| return { | ||
| "dependency_graph": dep_graph, | ||
| "critical_path": critical_path, | ||
| "parallelizable_groups": parallel_groups, | ||
| } | ||
| @staticmethod | ||
| def _find_critical_path(dep_graph: Dict, tasks: Dict) -> List[str]: | ||
| """Find tasks on critical path.""" | ||
| # Simple implementation - actual critical path is more complex | ||
| return list(dep_graph.keys()) | ||
| @staticmethod | ||
| def _find_parallel_groups(dep_graph: Dict) -> List[List[str]]: | ||
| """Find groups of tasks that can execute in parallel.""" | ||
| groups = [] | ||
| remaining = set(dep_graph.keys()) | ||
| while remaining: | ||
| # Find tasks with no dependencies in remaining set | ||
| independent = [ | ||
| task | ||
| for task in remaining | ||
| if not any(dep in remaining for dep in dep_graph.get(task, [])) | ||
| ] | ||
| if independent: | ||
| groups.append(independent) | ||
| remaining -= set(independent) | ||
| else: | ||
| break | ||
| return groups | ||
| @staticmethod | ||
| def estimate_execution_time( | ||
| workflow: Workflow, task_times: Dict[str, float] | ||
| ) -> float: | ||
| """Estimate total execution time.""" | ||
| parallel_groups = WorkflowOptimizer._find_parallel_groups({ | ||
| task_id: task.dependencies | ||
| for task_id, task in workflow.tasks.items() | ||
| }) | ||
| total_time = 0 | ||
| for group in parallel_groups: | ||
| group_time = max( | ||
| task_times.get(task_id, 1.0) for task_id in group | ||
| ) | ||
| total_time += group_time | ||
| return total_time | ||
| @staticmethod | ||
| def suggest_parallelization(workflow: Workflow) -> List[Dict[str, Any]]: | ||
| """Suggest ways to parallelize workflow.""" | ||
| suggestions = [] | ||
| dep_graph = { | ||
| task_id: task.dependencies | ||
| for task_id, task in workflow.tasks.items() | ||
| } | ||
| # Find sequential chains that could be parallelized | ||
| for task_id, dependencies in dep_graph.items(): | ||
| if len(dependencies) == 0: | ||
| suggestions.append({ | ||
| "task": task_id, | ||
| "suggestion": "Can be parallelized with other independent tasks", | ||
| }) | ||
| return suggestions | ||
| class WorkflowMonitor: | ||
| """Monitor workflow execution.""" | ||
| def __init__(self): | ||
| """Initialize monitor.""" | ||
| self.events: List[Dict] = [] | ||
| def record_event( | ||
| self, workflow_id: str, task_id: str, event_type: str, data: Dict | ||
| ) -> None: | ||
| """Record workflow event.""" | ||
| event = { | ||
| "workflow_id": workflow_id, | ||
| "task_id": task_id, | ||
| "event_type": event_type, | ||
| "timestamp": time.time(), | ||
| "data": data, | ||
| } | ||
| self.events.append(event) | ||
| def get_workflow_metrics(self, workflow_id: str) -> Dict[str, Any]: | ||
| """Get workflow metrics.""" | ||
| workflow_events = [e for e in self.events if e["workflow_id"] == workflow_id] | ||
| task_times = {} | ||
| for event in workflow_events: | ||
| task_id = event["task_id"] | ||
| if event["event_type"] == "start": | ||
| task_times[task_id] = {"start": event["timestamp"]} | ||
| elif event["event_type"] == "complete": | ||
| if task_id in task_times: | ||
| task_times[task_id]["end"] = event["timestamp"] | ||
| # Calculate durations | ||
| durations = { | ||
| task_id: times.get("end", time.time()) - times["start"] | ||
| for task_id, times in task_times.items() | ||
| } | ||
| return { | ||
| "total_tasks": len(task_times), | ||
| "task_durations": durations, | ||
| "avg_duration": sum(durations.values()) / len(durations) | ||
| if durations | ||
| else 0, | ||
| "max_duration": max(durations.values()) if durations else 0, | ||
| } | ||
| def get_performance_report(self) -> Dict[str, Any]: | ||
| """Get overall performance report.""" | ||
| if not self.events: | ||
| return {"status": "no_events"} | ||
| workflow_ids = set(e["workflow_id"] for e in self.events) | ||
| report = {} | ||
| for workflow_id in workflow_ids: | ||
| report[workflow_id] = self.get_workflow_metrics(workflow_id) | ||
| return report |
| --- | ||
| name: multi-agent-orchestration | ||
| description: Design and coordinate multi-agent systems where specialized agents work together to solve complex problems. Covers agent communication, task delegation, workflow orchestration, and result aggregation. Use when building coordinated agent teams, complex workflows, or systems requiring specialized expertise across domains. | ||
| --- | ||
| # Multi-Agent Orchestration | ||
| Design and orchestrate sophisticated multi-agent systems where specialized agents collaborate to solve complex problems, combining different expertise and perspectives. | ||
| ## Quick Start | ||
| Get started with multi-agent implementations in the examples and utilities: | ||
| - **Examples**: See [`examples/`](examples/) directory for complete implementations: | ||
| - [`orchestration_patterns.py`](examples/orchestration_patterns.py) - Sequential, parallel, hierarchical, and consensus orchestration | ||
| - [`framework_implementations.py`](examples/framework_implementations.py) - Templates for CrewAI, AutoGen, LangGraph, and Swarm | ||
| - **Utilities**: See [`scripts/`](scripts/) directory for helper modules: | ||
| - [`agent_communication.py`](scripts/agent_communication.py) - Message broker, shared memory, and communication protocols | ||
| - [`workflow_management.py`](scripts/workflow_management.py) - Workflow execution, optimization, and monitoring | ||
| - [`benchmarking.py`](scripts/benchmarking.py) - Team performance and agent effectiveness metrics | ||
| ## Overview | ||
| Multi-agent systems decompose complex problems into specialized sub-tasks, assigning each to an agent with relevant expertise, then coordinating their work toward a unified goal. | ||
| ### When Multi-Agent Systems Shine | ||
| - **Complex Workflows**: Tasks requiring multiple specialized roles | ||
| - **Domain-Specific Expertise**: Finance, legal, HR, engineering need different knowledge | ||
| - **Parallel Processing**: Multiple agents work on different aspects simultaneously | ||
| - **Collaborative Reasoning**: Agents debate, refine, and improve solutions | ||
| - **Resilience**: Failures in one agent don't break the entire system | ||
| - **Scalability**: Easy to add new specialized agents | ||
| ### Architecture Overview | ||
| ``` | ||
| User Request | ||
| ↓ | ||
| Orchestrator | ||
| ├→ Agent 1 (Specialist) → Task 1 | ||
| ├→ Agent 2 (Specialist) → Task 2 | ||
| ├→ Agent 3 (Specialist) → Task 3 | ||
| ↓ | ||
| Result Aggregator | ||
| ↓ | ||
| Final Response | ||
| ``` | ||
| ## Core Concepts | ||
| ### Agent Definition | ||
| An agent is defined by: | ||
| - **Role**: What responsibility does it have? (e.g., "Financial Analyst") | ||
| - **Goal**: What should it accomplish? (e.g., "Analyze financial risks") | ||
| - **Expertise**: What knowledge/tools does it have? | ||
| - **Tools**: What capabilities can it access? | ||
| - **Context**: What information does it need to work effectively? | ||
| ### Orchestration Patterns | ||
| #### 1. Sequential Orchestration | ||
| - Agents work one after another | ||
| - Each agent uses output from previous agent | ||
| - **Use Case**: Steps must follow order (research → analysis → writing) | ||
| #### 2. Parallel Orchestration | ||
| - Multiple agents work simultaneously | ||
| - Results aggregated at the end | ||
| - **Use Case**: Independent tasks (analyze competitors, market, users) | ||
| #### 3. Hierarchical Orchestration | ||
| - Senior agent delegates to junior agents | ||
| - Manager coordinates flow | ||
| - **Use Case**: Large projects with oversight | ||
| #### 4. Consensus-Based Orchestration | ||
| - Multiple agents analyze problem | ||
| - Debate and refine ideas | ||
| - Vote or reach consensus | ||
| - **Use Case**: Complex decisions needing multiple perspectives | ||
| #### 5. Tool-Mediated Orchestration | ||
| - Agents use shared tools/databases | ||
| - Minimal direct communication | ||
| - **Use Case**: Large systems, indirect coordination | ||
| ## Multi-Agent Team Examples | ||
| ### Finance Team | ||
| ``` | ||
| Coordinator Agent | ||
| ├→ Market Analyst Agent | ||
| │ ├ Tools: Market data API, financial news | ||
| │ └ Task: Analyze market conditions | ||
| ├→ Financial Analyst Agent | ||
| │ ├ Tools: Financial statements, ratio calculations | ||
| │ └ Task: Analyze company financials | ||
| ├→ Risk Manager Agent | ||
| │ ├ Tools: Risk models, scenario analysis | ||
| │ └ Task: Assess investment risks | ||
| └→ Report Writer Agent | ||
| ├ Tools: Document generation | ||
| └ Task: Synthesize findings into report | ||
| ``` | ||
| ### Legal Team | ||
| ``` | ||
| Case Manager Agent (Coordinator) | ||
| ├→ Contract Analyzer Agent | ||
| │ └ Task: Review contract terms | ||
| ├→ Precedent Research Agent | ||
| │ └ Task: Find relevant case law | ||
| ├→ Risk Assessor Agent | ||
| │ └ Task: Identify legal risks | ||
| └→ Document Drafter Agent | ||
| └ Task: Prepare legal documents | ||
| ``` | ||
| ### Customer Support Team | ||
| ``` | ||
| Support Coordinator | ||
| ├→ Issue Classifier Agent | ||
| │ └ Task: Categorize customer issue | ||
| ├→ Knowledge Base Agent | ||
| │ └ Task: Find relevant documentation | ||
| ├→ Escalation Agent | ||
| │ └ Task: Determine if human escalation needed | ||
| └→ Solution Synthesizer Agent | ||
| └ Task: Prepare comprehensive response | ||
| ``` | ||
| ## Implementation Frameworks | ||
| ### 1. CrewAI | ||
| **Best For**: Teams with clear roles and hierarchical structure | ||
| ```python | ||
| from crewai import Agent, Task, Crew | ||
| # Define agents | ||
| analyst = Agent( | ||
| role="Financial Analyst", | ||
| goal="Analyze financial data and provide insights", | ||
| backstory="Expert in financial markets with 10+ years experience" | ||
| ) | ||
| researcher = Agent( | ||
| role="Market Researcher", | ||
| goal="Research market trends and competition", | ||
| backstory="Data-driven researcher specializing in market analysis" | ||
| ) | ||
| # Define tasks | ||
| analysis_task = Task( | ||
| description="Analyze Q3 financial results for {company}", | ||
| agent=analyst, | ||
| tools=[financial_tool, data_tool] | ||
| ) | ||
| research_task = Task( | ||
| description="Research competitive landscape in {market}", | ||
| agent=researcher, | ||
| tools=[web_search_tool, industry_data_tool] | ||
| ) | ||
| # Create crew and execute | ||
| crew = Crew( | ||
| agents=[analyst, researcher], | ||
| tasks=[analysis_task, research_task], | ||
| process=Process.sequential | ||
| ) | ||
| result = crew.kickoff(inputs={"company": "TechCorp", "market": "AI"}) | ||
| ``` | ||
| ### 2. AutoGen (Microsoft) | ||
| **Best For**: Complex multi-turn conversations and negotiations | ||
| ```python | ||
| from autogen import AssistantAgent, UserProxyAgent, GroupChat, GroupChatManager | ||
| # Define agents | ||
| analyst = AssistantAgent( | ||
| name="analyst", | ||
| system_message="You are a financial analyst..." | ||
| ) | ||
| researcher = AssistantAgent( | ||
| name="researcher", | ||
| system_message="You are a market researcher..." | ||
| ) | ||
| # Create group chat | ||
| groupchat = GroupChat( | ||
| agents=[analyst, researcher], | ||
| messages=[], | ||
| max_round=10, | ||
| speaker_selection_method="auto" | ||
| ) | ||
| # Manage group conversation | ||
| manager = GroupChatManager(groupchat=groupchat) | ||
| # User proxy to initiate conversation | ||
| user = UserProxyAgent(name="user") | ||
| # Have conversation | ||
| user.initiate_chat( | ||
| manager, | ||
| message="Analyze if Company X should invest in Y market" | ||
| ) | ||
| ``` | ||
| ### 3. LangGraph | ||
| **Best For**: Complex workflows with state management | ||
| ```python | ||
| from langgraph.graph import Graph, StateGraph | ||
| from langgraph.prebuilt import create_agent_executor | ||
| # Define state | ||
| class AgentState: | ||
| research_findings: str | ||
| analysis: str | ||
| recommendations: str | ||
| # Create graph | ||
| graph = StateGraph(AgentState) | ||
| # Add nodes for each agent | ||
| graph.add_node("researcher", research_agent) | ||
| graph.add_node("analyst", analyst_agent) | ||
| graph.add_node("writer", writer_agent) | ||
| # Define edges (workflow) | ||
| graph.add_edge("researcher", "analyst") | ||
| graph.add_edge("analyst", "writer") | ||
| # Set entry/exit points | ||
| graph.set_entry_point("researcher") | ||
| graph.set_finish_point("writer") | ||
| # Compile and run | ||
| workflow = graph.compile() | ||
| result = workflow.invoke({"topic": "AI trends"}) | ||
| ``` | ||
| ### 4. OpenAI Swarm | ||
| **Best For**: Simple agent handoffs and conversational workflows | ||
| ```python | ||
| from swarm import Agent, Swarm | ||
| # Define agents | ||
| triage_agent = Agent( | ||
| name="Triage Agent", | ||
| instructions="Determine which specialist to route the customer to" | ||
| ) | ||
| billing_agent = Agent( | ||
| name="Billing Specialist", | ||
| instructions="Handle billing and payment questions" | ||
| ) | ||
| technical_agent = Agent( | ||
| name="Technical Support", | ||
| instructions="Handle technical issues" | ||
| ) | ||
| # Define handoff functions | ||
| def route_to_billing(reason: str): | ||
| return billing_agent | ||
| def route_to_technical(reason: str): | ||
| return technical_agent | ||
| # Add tools to triage agent | ||
| triage_agent.functions = [route_to_billing, route_to_technical] | ||
| # Execute swarm | ||
| client = Swarm() | ||
| response = client.run( | ||
| agent=triage_agent, | ||
| messages=[{"role": "user", "content": "I have a billing question"}] | ||
| ) | ||
| ``` | ||
| ## Orchestration Patterns | ||
| ### Pattern 1: Sequential Task Chain | ||
| Agents execute tasks in sequence, each building on previous results: | ||
| ```python | ||
| # Task 1: Research | ||
| research_output = research_agent.work("Analyze AI market trends") | ||
| # Task 2: Analysis (uses research output) | ||
| analysis = analyst_agent.work(f"Analyze these findings: {research_output}") | ||
| # Task 3: Report (uses analysis) | ||
| report = writer_agent.work(f"Write report on: {analysis}") | ||
| ``` | ||
| **When to Use**: Steps have dependencies, each builds on previous | ||
| ### Pattern 2: Parallel Execution | ||
| Multiple agents work simultaneously, results combined: | ||
| ```python | ||
| import asyncio | ||
| async def parallel_teams(): | ||
| # All agents work in parallel | ||
| market_task = market_agent.work_async("Analyze market") | ||
| technical_task = tech_agent.work_async("Analyze technology") | ||
| user_task = user_agent.work_async("Analyze user needs") | ||
| # Wait for all to complete | ||
| market_results, tech_results, user_results = await asyncio.gather( | ||
| market_task, technical_task, user_task | ||
| ) | ||
| # Synthesize results | ||
| return synthesize(market_results, tech_results, user_results) | ||
| ``` | ||
| **When to Use**: Independent analyses, need quick results, want diversity | ||
| ### Pattern 3: Hierarchical Structure | ||
| Manager agent coordinates specialists: | ||
| ```python | ||
| manager_agent.orchestrate({ | ||
| "market_analysis": { | ||
| "agents": [competitor_analyst, trend_analyst], | ||
| "task": "Comprehensive market analysis" | ||
| }, | ||
| "technical_evaluation": { | ||
| "agents": [architecture_agent, security_agent], | ||
| "task": "Technical feasibility assessment" | ||
| }, | ||
| "synthesis": { | ||
| "agents": [strategy_agent], | ||
| "task": "Create strategic recommendations" | ||
| } | ||
| }) | ||
| ``` | ||
| **When to Use**: Clear hierarchy, different teams, complex coordination | ||
| ### Pattern 4: Debate & Consensus | ||
| Multiple agents discuss and reach consensus: | ||
| ```python | ||
| agents = [bull_agent, bear_agent, neutral_agent] | ||
| question = "Should we invest in this startup?" | ||
| # Debate round 1 | ||
| arguments = {agent: agent.argue(question) for agent in agents} | ||
| # Debate round 2 (respond to others) | ||
| counter_arguments = { | ||
| agent: agent.respond(arguments) for agent in agents | ||
| } | ||
| # Reach consensus | ||
| consensus = mediator_agent.synthesize_consensus(counter_arguments) | ||
| ``` | ||
| **When to Use**: Complex decisions, need multiple perspectives, risk assessment | ||
| ## Agent Communication Patterns | ||
| ### 1. Direct Communication | ||
| Agents pass messages directly to each other: | ||
| ```python | ||
| agent_a.send_message(agent_b, { | ||
| "type": "request", | ||
| "action": "analyze_document", | ||
| "document": doc_content, | ||
| "context": {"deadline": "urgent"} | ||
| }) | ||
| ``` | ||
| ### 2. Tool-Mediated Communication | ||
| Agents use shared tools/databases: | ||
| ```python | ||
| # Agent A writes to shared memory | ||
| shared_memory.write("findings", {"market_size": "$5B", "growth": "20%"}) | ||
| # Agent B reads from shared memory | ||
| findings = shared_memory.read("findings") | ||
| ``` | ||
| ### 3. Manager-Based Communication | ||
| Central coordinator manages agent communication: | ||
| ```python | ||
| manager.broadcast("update_all_agents", { | ||
| "new_deadline": "tomorrow", | ||
| "priority": "critical" | ||
| }) | ||
| ``` | ||
| ## Best Practices | ||
| ### Agent Design | ||
| - ✓ Clear, specific role and goal | ||
| - ✓ Appropriate tools for the role | ||
| - ✓ Relevant background/expertise | ||
| - ✓ Distinct from other agents | ||
| - ✓ Reasonable scope of work | ||
| ### Workflow Design | ||
| - ✓ Clear task dependencies | ||
| - ✓ Identified handoff points | ||
| - ✓ Error handling between agents | ||
| - ✓ Fallback strategies | ||
| - ✓ Performance monitoring | ||
| ### Communication | ||
| - ✓ Structured message formats | ||
| - ✓ Clear context sharing | ||
| - ✓ Error propagation strategy | ||
| - ✓ Timeout handling | ||
| - ✓ Audit logging | ||
| ### Orchestration | ||
| - ✓ Define process clearly (sequential, parallel, etc.) | ||
| - ✓ Set clear success criteria | ||
| - ✓ Monitor agent performance | ||
| - ✓ Implement feedback loops | ||
| - ✓ Allow human intervention points | ||
| ## Common Challenges & Solutions | ||
| ### Challenge: Agent Conflicts | ||
| **Solutions**: | ||
| - Clear role separation | ||
| - Explicit decision-making rules | ||
| - Consensus mechanisms | ||
| - Conflict resolution agent | ||
| - Clear authority hierarchy | ||
| ### Challenge: Slow Execution | ||
| **Solutions**: | ||
| - Use parallel execution where possible | ||
| - Cache results from expensive operations | ||
| - Pre-process data | ||
| - Optimize agent logic | ||
| - Implement timeout handling | ||
| ### Challenge: Poor Quality Results | ||
| **Solutions**: | ||
| - Better agent prompts/instructions | ||
| - More relevant tools | ||
| - Feedback integration | ||
| - Quality validation agents | ||
| - Result aggregation strategies | ||
| ### Challenge: Complex Workflows | ||
| **Solutions**: | ||
| - Break into smaller teams | ||
| - Hierarchical structure | ||
| - Clear task definitions | ||
| - Good state management | ||
| - Documentation of workflow | ||
| ## Evaluation Metrics | ||
| **Team Performance**: | ||
| - Task completion rate | ||
| - Quality of results | ||
| - Execution time | ||
| - Cost (tokens/API calls) | ||
| - Error rate | ||
| **Agent Effectiveness**: | ||
| - Task success rate | ||
| - Response quality | ||
| - Tool usage efficiency | ||
| - Communication clarity | ||
| - Collaboration score | ||
| ## Advanced Techniques | ||
| ### 1. Self-Organizing Teams | ||
| Agents autonomously decide roles and workflow: | ||
| ```python | ||
| # Agents negotiate roles based on task | ||
| agents = [agent1, agent2, agent3] | ||
| task = "complex financial analysis" | ||
| # Agents determine best structure | ||
| negotiated_structure = self_organize(agents, task) | ||
| # Returns optimal workflow for this task | ||
| ``` | ||
| ### 2. Adaptive Workflows | ||
| Workflow changes based on progress: | ||
| ```python | ||
| # Monitor progress | ||
| if progress < expected_rate: | ||
| # Increase resources | ||
| workflow.add_agent(specialist_agent) | ||
| elif quality < threshold: | ||
| # Increase validation | ||
| workflow.insert_review_step() | ||
| ``` | ||
| ### 3. Cross-Agent Learning | ||
| Agents learn from each other's work: | ||
| ```python | ||
| # After team execution | ||
| execution_trace = crew.get_execution_trace() | ||
| # Extract learnings | ||
| learnings = extract_patterns(execution_trace) | ||
| # Update agent knowledge | ||
| for agent, learning in learnings.items(): | ||
| agent.update_knowledge(learning) | ||
| ``` | ||
| ## Resources | ||
| ### Frameworks | ||
| - **CrewAI**: https://crewai.com/ | ||
| - **AutoGen**: https://microsoft.github.io/autogen/ | ||
| - **LangGraph**: https://langchain-ai.github.io/langgraph/ | ||
| - **Swarm**: https://github.com/openai/swarm | ||
| ### Papers | ||
| - "Generative Agents" (Park et al.) | ||
| - "Self-Organizing Multi-Agent Systems" (research papers) | ||
| ## Implementation Checklist | ||
| - [ ] Define each agent's role, goal, and expertise | ||
| - [ ] Identify available tools/capabilities for each agent | ||
| - [ ] Plan workflow (sequential, parallel, hierarchical) | ||
| - [ ] Define communication patterns | ||
| - [ ] Implement task definitions | ||
| - [ ] Set success criteria for each task | ||
| - [ ] Add error handling and fallbacks | ||
| - [ ] Implement monitoring/logging | ||
| - [ ] Test team collaboration | ||
| - [ ] Evaluate quality and performance | ||
| - [ ] Optimize based on results | ||
| - [ ] Document workflow and decisions | ||
| ## Getting Started | ||
| 1. **Start Small**: Begin with 2-3 agents | ||
| 2. **Clear Workflow**: Document how agents interact | ||
| 3. **Test Thoroughly**: Validate agent behavior individually and together | ||
| 4. **Monitor Closely**: Track performance and results | ||
| 5. **Iterate**: Refine based on results | ||
| 6. **Scale**: Add agents and complexity as needed | ||
| # PageSpeed Insights — Reference & Official Documentation | ||
| This file complements the pagespeed-insights skill with official documentation links for indexing. | ||
| ## Official documentation (indexable) | ||
| - **PageSpeed Insights about**: https://developers.google.com/speed/docs/insights/v5/about?hl=es-419 | ||
| - **PageSpeed Insights (tool)**: https://pagespeed.web.dev/ | ||
| - **Lighthouse**: https://developer.chrome.com/docs/lighthouse/ | ||
| - **Core Web Vitals**: https://web.dev/vitals/ | ||
| - **Chrome User Experience Report (CrUX)**: https://developer.chrome.com/docs/crux/ | ||
| ## Core Web Vitals (metrics) | ||
| - **LCP (Largest Contentful Paint)**: https://web.dev/lcp/ | ||
| - **FCP (First Contentful Paint)**: https://web.dev/fcp/ | ||
| - **CLS (Cumulative Layout Shift)**: https://web.dev/cls/ | ||
| - **INP (Interaction to Next Paint)**: https://web.dev/inp/ | ||
| - **TTFB (Time to First Byte)**: https://web.dev/ttfb/ | ||
| ## Lab vs field data | ||
| - **Lab data**: Lighthouse, controlled environment, debugging | ||
| - **Field data**: CrUX, real user metrics, 28-day aggregation | ||
| - **Understanding metrics**: https://web.dev/metrics/ | ||
| ## Performance optimization guides | ||
| - **Optimize LCP**: https://web.dev/optimize-lcp/ | ||
| - **Optimize CLS**: https://web.dev/optimize-cls/ | ||
| - **Optimize INP**: https://web.dev/optimize-inp/ | ||
| - **Optimize FCP**: https://web.dev/optimize-fcp/ | ||
| - **Resource hints**: https://web.dev/preconnect-and-dns-prefetch/ | ||
| - **Image optimization**: https://web.dev/fast/#optimize-your-images | ||
| ## Tools | ||
| - **PageSpeed Insights**: https://pagespeed.web.dev/ | ||
| - **Lighthouse (Chrome DevTools)**: Built-in, Audits tab | ||
| - **Web Vitals extension**: Real-time monitoring | ||
| - **Chromatic (Lighthouse CI)**: https://github.com/GoogleChrome/lighthouse-ci | ||
| ## Score thresholds (reminder) | ||
| | Category | Good | Needs Improvement | Poor | | ||
| |----------|------|-------------------|------| | ||
| | Performance | 90-100 | 50-89 | 0-49 | | ||
| | Accessibility | 90-100 | 50-89 | 0-49 | | ||
| | Best Practices | 90-100 | 50-89 | 0-49 | | ||
| | SEO | 90-100 | 50-89 | 0-49 | |
| --- | ||
| name: pagespeed-insights | ||
| description: Audit web pages for performance optimization following PageSpeed Insights guidelines. Use when analyzing page performance, optimizing web applications, reviewing performance metrics, implementing Core Web Vitals improvements, or when the user mentions page speed, performance optimization, Lighthouse scores, or Core Web Vitals. | ||
| --- | ||
| # PageSpeed Insights Auditor | ||
| ## Overview | ||
| You are a **PageSpeed Insights Auditor** - an expert in web performance optimization who helps developers achieve excellent PageSpeed scores by identifying performance issues, avoiding bad practices, and implementing best practices based on Google's PageSpeed Insights guidelines. | ||
| **Core Principle**: Guide developers to achieve scores of 90+ (Good) in Performance, Accessibility, Best Practices, and SEO categories, while ensuring Core Web Vitals metrics meet the "Good" thresholds. | ||
| ## Understanding PageSpeed Insights | ||
| PageSpeed Insights (PSI) analyzes page performance on mobile and desktop devices, providing both **lab data** (simulated) and **field data** (real user experiences). PSI reports on user experience metrics and provides diagnostic suggestions to improve page performance. | ||
| ### Two Types of Data | ||
| 1. **Lab Data**: Collected in a controlled environment using Lighthouse. Useful for debugging but may not capture real-world bottlenecks. | ||
| 2. **Field Data**: Real user experience data from Chrome User Experience Report (CrUX). Useful for capturing actual user experiences but has a more limited set of metrics. | ||
| ## Performance Score Thresholds | ||
| ### Lab Scores (Lighthouse) | ||
| | Score Range | Rating | Icon | | ||
| | ----------- | ----------------- | --------------- | | ||
| | 90-100 | Good | 🟢 Green circle | | ||
| | 50-89 | Needs Improvement | 🟡 Amber square | | ||
| | 0-49 | Poor | 🔴 Red triangle | | ||
| **Target**: Always aim for scores of **90 or higher** in all categories. | ||
| ### Core Web Vitals Thresholds | ||
| Core Web Vitals are the three most important metrics for web performance: | ||
| | Metric | Good | Needs Improvement | Poor | | ||
| | ----------------------------------- | ------------ | ------------------ | --------- | | ||
| | **FCP** (First Contentful Paint) | [0, 1800 ms] | [1800 ms, 3000 ms] | > 3000 ms | | ||
| | **LCP** (Largest Contentful Paint) | [0, 2500 ms] | [2500 ms, 4000 ms] | > 4000 ms | | ||
| | **CLS** (Cumulative Layout Shift) | [0, 0.1] | [0.1, 0.25] | > 0.25 | | ||
| | **INP** (Interaction to Next Paint) | [0, 200 ms] | [200 ms, 500 ms] | > 500 ms | | ||
| | **TTFB** (Time to First Byte) | [0, 800 ms] | [800 ms, 1800 ms] | > 1800 ms | | ||
| **Target**: Ensure the 75th percentile of all Core Web Vitals metrics are in the "Good" range. | ||
| ## Key Performance Metrics | ||
| ### Lab Metrics (Lighthouse) | ||
| 1. **First Contentful Paint (FCP)**: Time until first content is rendered | ||
| 2. **Largest Contentful Paint (LCP)**: Time until largest content element is rendered | ||
| 3. **Speed Index**: How quickly content is visually displayed | ||
| 4. **Cumulative Layout Shift (CLS)**: Visual stability measure | ||
| 5. **Total Blocking Time (TBT)**: Sum of blocking time between FCP and TTI | ||
| 6. **Time to Interactive (TTI)**: Time until page is fully interactive | ||
| ### Field Metrics (CrUX) | ||
| - **FCP**: First Contentful Paint from real users | ||
| - **LCP**: Largest Contentful Paint from real users | ||
| - **CLS**: Cumulative Layout Shift from real users | ||
| - **INP**: Interaction to Next Paint (replaces FID) | ||
| - **TTFB**: Time to First Byte (experimental) | ||
| ## Common Performance Issues & Solutions | ||
| ### ❌ Bad Practice: Unoptimized Images | ||
| **Problem**: Large images without compression, modern formats, or proper sizing. | ||
| **Impact**: Poor LCP scores, slow page loads. | ||
| **✅ Solutions**: | ||
| - Use modern image formats (WebP, AVIF) | ||
| - Implement responsive images with `srcset` | ||
| - Compress images before uploading | ||
| - Set explicit width/height to prevent CLS | ||
| - Use lazy loading for below-the-fold images | ||
| ```html | ||
| <!-- Bad --> | ||
| <img src="large-image.jpg" alt="Description" /> | ||
| <!-- Good --> | ||
| <img | ||
| src="image.webp" | ||
| srcset="image-small.webp 400w, image-medium.webp 800w, image-large.webp 1200w" | ||
| sizes="(max-width: 600px) 400px, (max-width: 1200px) 800px, 1200px" | ||
| width="1200" | ||
| height="800" | ||
| alt="Description" | ||
| loading="lazy" | ||
| /> | ||
| ``` | ||
| ### ❌ Bad Practice: Render-Blocking Resources | ||
| **Problem**: CSS and JavaScript blocking initial render. | ||
| **Impact**: Poor FCP and LCP scores. | ||
| **✅ Solutions**: | ||
| - Defer non-critical CSS | ||
| - Inline critical CSS | ||
| - Use `async` or `defer` for JavaScript | ||
| - Remove unused CSS/JS | ||
| - Split code and lazy load routes | ||
| ```html | ||
| <!-- Bad --> | ||
| <link rel="stylesheet" href="styles.css" /> | ||
| <script src="app.js"></script> | ||
| <!-- Good --> | ||
| <link | ||
| rel="stylesheet" | ||
| href="styles.css" | ||
| media="print" | ||
| onload="this.media='all'" | ||
| /> | ||
| <link rel="preload" href="critical.css" as="style" /> | ||
| <script src="app.js" defer></script> | ||
| ``` | ||
| ### ❌ Bad Practice: Missing Resource Hints | ||
| **Problem**: Not preconnecting to important origins or prefetching critical resources. | ||
| **Impact**: Slow TTFB and LCP. | ||
| **✅ Solutions**: | ||
| - Use `rel="preconnect"` for third-party origins | ||
| - Use `rel="dns-prefetch"` for DNS resolution | ||
| - Use `rel="preload"` for critical resources | ||
| - Use `rel="prefetch"` for likely next-page resources | ||
| ```html | ||
| <!-- Good --> | ||
| <link rel="preconnect" href="https://fonts.googleapis.com" /> | ||
| <link rel="dns-prefetch" href="https://api.example.com" /> | ||
| <link rel="preload" href="hero-image.webp" as="image" /> | ||
| ``` | ||
| ### ❌ Bad Practice: Layout Shift (CLS) | ||
| **Problem**: Content shifting during page load. | ||
| **Impact**: Poor CLS scores, bad user experience. | ||
| **✅ Solutions**: | ||
| - Set explicit dimensions for images and videos | ||
| - Reserve space for ads and embeds | ||
| - Avoid inserting content above existing content | ||
| - Use CSS aspect-ratio for responsive containers | ||
| - Prefer transform animations over layout-triggering properties | ||
| ```css | ||
| /* Bad */ | ||
| .image-container { | ||
| width: 100%; | ||
| /* height not set - causes CLS */ | ||
| } | ||
| /* Good */ | ||
| .image-container { | ||
| width: 100%; | ||
| aspect-ratio: 16 / 9; | ||
| /* or */ | ||
| height: 0; | ||
| padding-bottom: 56.25%; /* 16:9 ratio */ | ||
| } | ||
| ``` | ||
| ### ❌ Bad Practice: Large JavaScript Bundles | ||
| **Problem**: Loading unnecessary JavaScript code. | ||
| **Impact**: Poor TTI, high TBT. | ||
| **✅ Solutions**: | ||
| - Code splitting and lazy loading | ||
| - Remove unused code (tree shaking) | ||
| - Minimize and compress JavaScript | ||
| - Use dynamic imports for routes | ||
| - Avoid large third-party libraries when possible | ||
| ```javascript | ||
| // Bad - loading everything upfront | ||
| import { heavyLibrary } from "./heavy-library"; | ||
| // Good - lazy load when needed | ||
| const loadHeavyLibrary = () => import("./heavy-library"); | ||
| ``` | ||
| ### ❌ Bad Practice: Inefficient Font Loading | ||
| **Problem**: Fonts causing FOIT (Flash of Invisible Text) or FOUT (Flash of Unstyled Text). | ||
| **Impact**: Poor FCP, layout shifts. | ||
| **✅ Solutions**: | ||
| - Use `font-display: swap` or `optional` | ||
| - Preload critical fonts | ||
| - Subset fonts to include only needed characters | ||
| - Use system fonts when possible | ||
| ```css | ||
| /* Good */ | ||
| @font-face { | ||
| font-family: "CustomFont"; | ||
| src: url("font.woff2") format("woff2"); | ||
| font-display: swap; /* or optional */ | ||
| } | ||
| ``` | ||
| ### ❌ Bad Practice: No Caching Strategy | ||
| **Problem**: Resources not cached, causing repeated downloads. | ||
| **Impact**: Slow repeat visits, poor performance. | ||
| **✅ Solutions**: | ||
| - Set appropriate Cache-Control headers | ||
| - Use service workers for offline caching | ||
| - Implement HTTP/2 server push for critical resources | ||
| - Use CDN for static assets | ||
| ``` | ||
| Cache-Control: public, max-age=31536000, immutable | ||
| ``` | ||
| ### ❌ Bad Practice: Third-Party Scripts Blocking Render | ||
| **Problem**: Analytics, ads, or widgets blocking page load. | ||
| **Impact**: Poor TTI, high TBT. | ||
| **✅ Solutions**: | ||
| - Load third-party scripts asynchronously | ||
| - Defer non-critical third-party code | ||
| - Use `rel="noopener"` for external links | ||
| - Consider self-hosting analytics when possible | ||
| ```html | ||
| <!-- Good --> | ||
| <script async src="https://www.google-analytics.com/analytics.js"></script> | ||
| ``` | ||
| ## Accessibility Best Practices | ||
| ### ❌ Bad Practice: Missing Alt Text | ||
| **Problem**: Images without descriptive alt attributes. | ||
| **Impact**: Poor accessibility score. | ||
| **✅ Solution**: Always provide meaningful alt text. | ||
| ```html | ||
| <!-- Bad --> | ||
| <img src="chart.png" /> | ||
| <!-- Good --> | ||
| <img src="chart.png" alt="Sales increased 25% from Q1 to Q2" /> | ||
| ``` | ||
| ### ❌ Bad Practice: Poor Color Contrast | ||
| **Problem**: Text not readable due to low contrast. | ||
| **Impact**: Poor accessibility score. | ||
| **✅ Solution**: Ensure contrast ratio of at least 4.5:1 for normal text, 3:1 for large text. | ||
| ### ❌ Bad Practice: Missing ARIA Labels | ||
| **Problem**: Interactive elements without proper labels. | ||
| **Impact**: Poor accessibility score. | ||
| **✅ Solution**: Use ARIA labels for screen readers. | ||
| ```html | ||
| <!-- Good --> | ||
| <button aria-label="Close dialog">×</button> | ||
| ``` | ||
| ## SEO Best Practices | ||
| ### ❌ Bad Practice: Missing Meta Tags | ||
| **Problem**: No title, description, or viewport meta tags. | ||
| **Impact**: Poor SEO score. | ||
| **✅ Solution**: Include essential meta tags. | ||
| ```html | ||
| <!-- Good --> | ||
| <meta charset="UTF-8" /> | ||
| <meta name="viewport" content="width=device-width, initial-scale=1.0" /> | ||
| <meta name="description" content="Page description" /> | ||
| <title>Page Title</title> | ||
| ``` | ||
| ### ❌ Bad Practice: Non-Descriptive Links | ||
| **Problem**: Links with generic text like "click here". | ||
| **Impact**: Poor SEO score. | ||
| **✅ Solution**: Use descriptive link text. | ||
| ```html | ||
| <!-- Bad --> | ||
| <a href="/about">Click here</a> | ||
| <!-- Good --> | ||
| <a href="/about">Learn more about our company</a> | ||
| ``` | ||
| ## Best Practices Checklist | ||
| ### Performance | ||
| - [ ] Images optimized (WebP/AVIF, compressed, responsive) | ||
| - [ ] Critical CSS inlined | ||
| - [ ] Non-critical CSS deferred | ||
| - [ ] JavaScript code-split and lazy-loaded | ||
| - [ ] Render-blocking resources minimized | ||
| - [ ] Resource hints implemented (preconnect, preload, dns-prefetch) | ||
| - [ ] Fonts optimized with font-display | ||
| - [ ] Caching strategy implemented | ||
| - [ ] Third-party scripts loaded asynchronously | ||
| - [ ] Layout shifts prevented (explicit dimensions, aspect-ratio) | ||
| ### Core Web Vitals | ||
| - [ ] LCP < 2.5 seconds (75th percentile) | ||
| - [ ] FCP < 1.8 seconds (75th percentile) | ||
| - [ ] CLS < 0.1 (75th percentile) | ||
| - [ ] INP < 200ms (75th percentile) | ||
| - [ ] TTFB < 800ms (75th percentile) | ||
| ### Accessibility | ||
| - [ ] All images have alt text | ||
| - [ ] Color contrast meets WCAG standards | ||
| - [ ] ARIA labels on interactive elements | ||
| - [ ] Semantic HTML used | ||
| - [ ] Keyboard navigation supported | ||
| ### SEO | ||
| - [ ] Meta tags present (title, description, viewport) | ||
| - [ ] Descriptive link text | ||
| - [ ] Proper heading hierarchy (h1-h6) | ||
| - [ ] Structured data implemented | ||
| - [ ] Mobile-friendly design | ||
| ## Audit Workflow | ||
| When auditing a page for PageSpeed optimization: | ||
| 1. **Analyze Current State** | ||
| - Check current PageSpeed scores | ||
| - Identify Core Web Vitals metrics | ||
| - Review lab and field data differences | ||
| 2. **Identify Issues** | ||
| - List all performance problems | ||
| - Prioritize by impact (Core Web Vitals first) | ||
| - Categorize by type (images, JS, CSS, etc.) | ||
| 3. **Provide Solutions** | ||
| - Suggest specific optimizations | ||
| - Provide code examples | ||
| - Explain expected improvements | ||
| 4. **Verify Improvements** | ||
| - Re-test after changes | ||
| - Ensure scores reach 90+ | ||
| - Confirm Core Web Vitals are "Good" | ||
| ## Common Mistakes to Avoid | ||
| ### ❌ Focusing Only on Lab Data | ||
| **Problem**: Optimizing only for Lighthouse scores without considering real user data. | ||
| **✅ Solution**: Balance both lab and field data. Field data shows real-world performance. | ||
| ### ❌ Over-Optimizing | ||
| **Problem**: Implementing too many optimizations at once, making debugging difficult. | ||
| **✅ Solution**: Make incremental changes and test after each optimization. | ||
| ### ❌ Ignoring Mobile Performance | ||
| **Problem**: Optimizing only for desktop. | ||
| **✅ Solution**: Mobile-first approach. Most users are on mobile devices. | ||
| ### ❌ Not Testing After Changes | ||
| **Problem**: Assuming optimizations worked without verification. | ||
| **✅ Solution**: Always re-run PageSpeed Insights after implementing changes. | ||
| ## Performance Optimization Priority | ||
| 1. **Critical Path**: Optimize resources needed for initial render | ||
| 2. **Core Web Vitals**: Focus on LCP, CLS, and INP first | ||
| 3. **Render-Blocking**: Eliminate blocking CSS and JS | ||
| 4. **Images**: Optimize largest contentful paint element | ||
| 5. **Third-Party**: Minimize impact of external scripts | ||
| 6. **Caching**: Implement proper caching strategies | ||
| ## Additional Resources | ||
| - [reference.md](reference.md) — Official PageSpeed, Lighthouse, Core Web Vitals, optimization guides — indexable | ||
| - **Official**: https://developers.google.com/speed/docs/insights/v5/about?hl=es-419 | ||
| - **PageSpeed Insights**: https://pagespeed.web.dev/ | ||
| - **Lighthouse**: Built into Chrome DevTools | ||
| - **Web Vitals**: https://web.dev/vitals/ | ||
| ## Specification Reference | ||
| This skill is based on the official [PageSpeed Insights documentation](https://developers.google.com/speed/docs/insights/v5/about?hl=es-419) from Google Developers. | ||
| All thresholds, metrics, and best practices in this skill follow the official PageSpeed Insights guidelines and Core Web Vitals specifications. For complete documentation, refer to the [official PageSpeed Insights documentation](https://developers.google.com/speed/docs/insights/v5/about?hl=es-419). |
| --- | ||
| id: pagespeed-perf | ||
| version: 1.0.0 | ||
| name: PageSpeed Performance Audit | ||
| description: > | ||
| Web Performance Engineering — analyzes Core Web Vitals using the PageSpeed | ||
| Insights API (PSI v5) and applies the 80/20 principle: identify the 20% of | ||
| changes that produce 80% of the performance gain. Produces a prioritized | ||
| markdown report with quantified estimates and framework-specific code. | ||
| Trigger: When auditing page speed, analyzing Core Web Vitals, or optimizing | ||
| web performance for any URL. | ||
| user-invokable: true | ||
| license: MIT | ||
| metadata: | ||
| author: codeconductor | ||
| category: performance | ||
| compatibility: | ||
| tools: [claude, codex, gemini, agy, opencode] | ||
| stacks: | ||
| languages: [] | ||
| frameworks: [astro, nextjs, react, vue, django, spring, wordpress] | ||
| risk: | ||
| level: medium | ||
| can_execute_shell: true | ||
| can_modify_files: false | ||
| requires_network: true | ||
| inputs: | ||
| - name: url | ||
| type: string | ||
| required: true | ||
| description: Full URL to audit (must include scheme: https://...) | ||
| - name: strategy | ||
| type: string | ||
| required: false | ||
| description: "mobile | desktop | both (default: both)" | ||
| outputs: | ||
| - name: report | ||
| type: markdown | ||
| description: > | ||
| Prioritized performance report saved as | ||
| {YYYY-MM-DD}_pagespeed-{hostname}-claude.md in the current directory. | ||
| quality: | ||
| reviewed_by: codeconductor-core | ||
| version: 1.0.0 | ||
| --- | ||
| # PageSpeed Performance Audit — Web Performance Engineering (80/20) | ||
| ## Role and Purpose | ||
| Act as **Senior Web Performance Engineer, Frontend Architect, and Technical | ||
| Auditor**. | ||
| Always access the real site, measure real metrics via the PageSpeed Insights | ||
| API, analyze resources with the greatest impact, and produce a prioritized | ||
| Spanish-language report following the 80/20 principle: the **20% of critical | ||
| changes that produce 80% of the performance improvement**. | ||
| Never give generic recommendations. Every finding must be backed by data | ||
| observed from the specific URL being audited. | ||
| --- | ||
| ## Step 0 — Pre-flight: API Key and Output Filename | ||
| **MANDATORY. Execute before any analysis.** | ||
| ### 1. Read the API key from the environment | ||
| ```powershell | ||
| $env:PAGESPEED_API_KEY | ||
| ``` | ||
| - Value present → store as `{API_KEY}`, use in all PSI calls. | ||
| - Empty → proceed without key (CrUX field data unavailable; rate limits apply). | ||
| ### 2. Define the output filename | ||
| ```powershell | ||
| $date = (Get-Date -Format "yyyy-MM-dd") | ||
| $website = ([System.Uri]"{URL}").Host -replace '[^a-zA-Z0-9]', '-' | ||
| $out = "${date}_pagespeed-${website}-claude.md" | ||
| Write-Host $out | ||
| ``` | ||
| The final report **must** be written to this file. | ||
| --- | ||
| ## Data Collection | ||
| ### Primary Method — Bun Scripts (always try first) | ||
| ```powershell | ||
| bun --version # if available, use Primary Method; otherwise use Fallback | ||
| $skillDir = "$env:USERPROFILE\.claude\skills\pagespeed-perf\scripts" | ||
| bun run "$skillDir\run.ts" --url={URL} | ||
| ``` | ||
| `run.ts` calls `psi-collect.ts` and `html-audit.ts` in parallel and returns | ||
| structured JSON. Key output fields: | ||
| ``` | ||
| output.summary.mobileScore → Lighthouse mobile score (0-100) | ||
| output.summary.desktopScore → Lighthouse desktop score | ||
| output.summary.passesCWV → boolean — passes real CWV | ||
| output.summary.top5Actions → array ordered by 80/20 score | ||
| output.psi.mobile.lab.lcp → LCP (lab, mobile) | ||
| output.psi.mobile.lab.tbt → TBT | ||
| output.psi.mobile.lab.cls → CLS | ||
| output.psi.mobile.lab.fcp → FCP | ||
| output.psi.mobile.lab.ttfb → TTFB | ||
| output.psi.mobile.field → CrUX data (null if no key / no data) | ||
| output.psi.mobile.opportunities → array ordered by impact80_20 desc | ||
| output.psi.mobile.lcpElement → HTML snippet of the LCP element | ||
| output.psi.mobile.thirdParties → third-party scripts with blockingTime | ||
| output.psi.mobile.usedApiKey → boolean — confirms key was used | ||
| output.html.stack → detected framework / CMS | ||
| output.html.resourceHints → preloads, preconnects, prefetches | ||
| output.html.images → lazy, fetchpriority, list | ||
| output.html.scripts → blocking in <head>, third-party list | ||
| output.html.fonts → googleFonts, font-display, preloaded | ||
| output.html.issues → ordered by impact80_20 | ||
| ``` | ||
| ### Fallback Method — WebFetch (only if Bun unavailable) | ||
| ``` | ||
| # With API key (preferred) | ||
| https://www.googleapis.com/pagespeedonline/v5/runPagespeed?url={URL}&strategy=mobile&category=performance&key={API_KEY} | ||
| https://www.googleapis.com/pagespeedonline/v5/runPagespeed?url={URL}&strategy=desktop&category=performance&key={API_KEY} | ||
| # Without key (rate-limited) | ||
| https://www.googleapis.com/pagespeedonline/v5/runPagespeed?url={URL}&strategy=mobile&category=performance | ||
| ``` | ||
| Key PSI response paths: | ||
| ``` | ||
| lighthouseResult.categories.performance.score | ||
| lighthouseResult.audits.largest-contentful-paint | ||
| lighthouseResult.audits.total-blocking-time | ||
| lighthouseResult.audits.cumulative-layout-shift | ||
| lighthouseResult.audits.first-contentful-paint | ||
| lighthouseResult.audits.server-response-time | ||
| lighthouseResult.audits.largest-contentful-paint-element.details.items[0] | ||
| lighthouseResult.audits.render-blocking-resources.details.overallSavingsMs | ||
| lighthouseResult.audits.unused-javascript.details.overallSavingsBytes | ||
| lighthouseResult.audits.third-party-summary.details.items | ||
| loadingExperience.metrics.LARGEST_CONTENTFUL_PAINT_MS.percentile (CrUX) | ||
| loadingExperience.metrics.INTERACTION_TO_NEXT_PAINT.percentile (CrUX) | ||
| loadingExperience.metrics.CUMULATIVE_LAYOUT_SHIFT_SCORE.percentile (CrUX) | ||
| loadingExperience.overall_category → "FAST" | "AVERAGE" | "SLOW" | ||
| ``` | ||
| Also fetch the site HTML via WebFetch and inspect the `<head>` for resource | ||
| hints, lazy loading, `fetchpriority`, `font-display`, blocking scripts, and | ||
| images without explicit dimensions. | ||
| --- | ||
| ## Core Web Vitals — Thresholds | ||
| | Metric | Good | Needs Improvement | Critical | Score weight | | ||
| | ------ | -------- | ----------------- | --------- | ------------ | | ||
| | LCP | ≤ 2.5 s | 2.5 s – 4.0 s | > 4.0 s | 25% | | ||
| | INP | ≤ 200 ms | 200 ms – 500 ms | > 500 ms | 10% | | ||
| | CLS | ≤ 0.1 | 0.1 – 0.25 | > 0.25 | 15% | | ||
| | FCP | ≤ 1.8 s | 1.8 s – 3.0 s | > 3.0 s | 10% | | ||
| | TBT | ≤ 200 ms | 200 ms – 600 ms | > 600 ms | 30% | | ||
| | TTFB | ≤ 800 ms | 800 ms – 1.8 s | > 1.8 s | — | | ||
| LCP + TBT represent 55% of the Lighthouse Performance Score. | ||
| --- | ||
| ## 80/20 Optimization Matrix | ||
| Score = `Impact (1–5) × Ease (1–5)`. Prioritize by descending score. | ||
| | Rank | Optimization | Primary metric | Impact | Ease | Score | | ||
| | ---- | --------------------------------- | -------------- | ------ | ---- | ----- | | ||
| | 1 | Preload LCP element | LCP | 5 | 5 | **25** | | ||
| | 1 | `fetchpriority="high"` on LCP img | LCP | 5 | 5 | **25** | | ||
| | 1 | Gzip / Brotli compression | FCP, LCP, TBT | 5 | 5 | **25** | | ||
| | 4 | WebP + explicit dimensions | LCP, CLS | 5 | 4 | **20** | | ||
| | 4 | Lazy loading offscreen images | LCP, TBT | 4 | 5 | **20** | | ||
| | 4 | `font-display: swap` | FCP | 4 | 5 | **20** | | ||
| | 4 | `preconnect` to critical origins | FCP, LCP, TTFB | 4 | 5 | **20** | | ||
| | 4 | Defer / facade third-party scripts| TBT, INP | 5 | 4 | **20** | | ||
| | 9 | Remove render-blocking resources | FCP, LCP | 5 | 3 | **15** | | ||
| | 9 | Long Cache-Control for assets | repeat visits | 3 | 5 | **15** | | ||
| | 11 | Remove unused JavaScript | TBT, INP | 4 | 3 | **12** | | ||
| | 12 | Remove unused CSS | FCP, TBT | 3 | 3 | **9** | | ||
| | 13 | CDN for static assets | TTFB, LCP | 4 | 2 | **8** | | ||
| | 14 | Code splitting | TBT, INP | 4 | 2 | **8** | | ||
| **Critical 20% (Score ≥ 20)** — address these first: | ||
| 1. Preload LCP element + `fetchpriority="high"` | ||
| 2. Brotli/Gzip compression at the server | ||
| 3. WebP images with explicit `width`/`height` | ||
| 4. Lazy loading of offscreen images | ||
| 5. `font-display: swap` for all fonts | ||
| 6. `preconnect` to all critical origins | ||
| 7. Defer or facade all third-party scripts | ||
| --- | ||
| ## Expected Impact by Optimization | ||
| | Optimization | Metric | Expected gain | | ||
| | ---------------------- | -------- | --------------------- | | ||
| | Preload + fetchpriority| LCP | −0.5 s to −2.0 s | | ||
| | Brotli compression | FCP, LCP | −0.3 s to −1.0 s | | ||
| | WebP + dimensions | LCP, CLS | −0.3 s to −1.2 s | | ||
| | Lazy loading | LCP | −0.2 s to −0.8 s | | ||
| | font-display: swap | FCP | −0.2 s to −0.8 s | | ||
| | preconnect | FCP, LCP | −0.1 s to −0.4 s each| | ||
| | Defer third parties | TBT, INP | −50 ms to −300 ms | | ||
| --- | ||
| ## Report Format (mandatory structure) | ||
| Save to `{YYYY-MM-DD}_pagespeed-{hostname}-claude.md`: | ||
| ```markdown | ||
| # Auditoría de Rendimiento Web — {URL} | ||
| Fecha: {YYYY-MM-DD} | Estrategia: Móvil + Escritorio | Archivo: {filename}.md | ||
| ## Resumen Ejecutivo | ||
| [2-3 párrafos: estado actual, score, bottleneck principal, potencial de mejora] | ||
| ## Métricas Actuales | ||
| [Tabla: Lab (Lighthouse) vs Campo (CrUX)] | ||
| ## Recursos con Mayor Impacto | ||
| [Tabla: URL, Tipo, Tamaño, Tiempo, Impacto, Razón] | ||
| ## Plan de Acción Priorizado (80/20) | ||
| [Tabla ordenada por Score 80/20 descendente] | ||
| ## Solución Técnica Detallada | ||
| [Por hallazgo: Problema, Evidencia, Implementación, Código, Impacto Esperado] | ||
| ## Quick Wins (< 1 day) | ||
| ## High Impact Changes | ||
| ## Roadmap | ||
| - Fase 1 — Inmediato (Semana 1) | ||
| - Fase 2 — Corto Plazo (2–4 semanas) | ||
| - Fase 3 — Mediano Plazo (1–3 meses) | ||
| --- | ||
| *Informe generado el {YYYY-MM-DD} · Herramienta: Claude Code + pagespeed-perf skill* | ||
| *API Key usada: {Sí / No} · Datos CrUX: {Disponibles / No disponibles}* | ||
| ``` | ||
| --- | ||
| ## Quality Rules — Never Violate | ||
| 1. **No data = no recommendation.** If PSI fails, try WebFetch directly. | ||
| 2. **Always quantify.** "Reduces LCP from 4.2 s to ~3.0 s" — never "would improve LCP". | ||
| 3. **Explicit evidence.** Cite the observed metric value for every finding. | ||
| 4. **Site-specific code.** Adapt templates to the detected framework (Next.js, | ||
| Astro, Django, etc.). Do not paste generic snippets unchanged. | ||
| 5. **80/20 order.** Always sort the action plan by descending score. | ||
| 6. **Separate field vs lab data.** CrUX = real user experience. Lighthouse = controlled lab. | ||
| 7. **Identify the framework.** Detect Next.js, Astro, Vue, WordPress, etc., and | ||
| provide framework-specific code samples. |
| # workflow-orchestration-patterns — detailed patterns and worked examples | ||
| ## Critical Design Decision: Workflows vs Activities | ||
| **The Fundamental Rule** (Source: temporal.io/blog/workflow-engine-principles): | ||
| - **Workflows** = Orchestration logic and decision-making | ||
| - **Activities** = External interactions (APIs, databases, network calls) | ||
| ### Workflows (Orchestration) | ||
| **Characteristics:** | ||
| - Contain business logic and coordination | ||
| - **MUST be deterministic** (same inputs → same outputs) | ||
| - **Cannot** perform direct external calls | ||
| - State automatically preserved across failures | ||
| - Can run for years despite infrastructure failures | ||
| **Example workflow tasks:** | ||
| - Decide which steps to execute | ||
| - Handle compensation logic | ||
| - Manage timeouts and retries | ||
| - Coordinate child workflows | ||
| ### Activities (External Interactions) | ||
| **Characteristics:** | ||
| - Handle all external system interactions | ||
| - Can be non-deterministic (API calls, DB writes) | ||
| - Include built-in timeouts and retry logic | ||
| - **Must be idempotent** (calling N times = calling once) | ||
| - Short-lived (seconds to minutes typically) | ||
| **Example activity tasks:** | ||
| - Call payment gateway API | ||
| - Write to database | ||
| - Send emails or notifications | ||
| - Query external services | ||
| ### Design Decision Framework | ||
| ``` | ||
| Does it touch external systems? → Activity | ||
| Is it orchestration/decision logic? → Workflow | ||
| ``` | ||
| ## Core Workflow Patterns | ||
| ### 1. Saga Pattern with Compensation | ||
| **Purpose**: Implement distributed transactions with rollback capability | ||
| **Pattern** (Source: temporal.io/blog/compensating-actions-part-of-a-complete-breakfast-with-sagas): | ||
| ``` | ||
| For each step: | ||
| 1. Register compensation BEFORE executing | ||
| 2. Execute the step (via activity) | ||
| 3. On failure, run all compensations in reverse order (LIFO) | ||
| ``` | ||
| **Example: Payment Workflow** | ||
| 1. Reserve inventory (compensation: release inventory) | ||
| 2. Charge payment (compensation: refund payment) | ||
| 3. Fulfill order (compensation: cancel fulfillment) | ||
| **Critical Requirements:** | ||
| - Compensations must be idempotent | ||
| - Register compensation BEFORE executing step | ||
| - Run compensations in reverse order | ||
| - Handle partial failures gracefully | ||
| ### 2. Entity Workflows (Actor Model) | ||
| **Purpose**: Long-lived workflow representing single entity instance | ||
| **Pattern** (Source: docs.temporal.io/evaluate/use-cases-design-patterns): | ||
| - One workflow execution = one entity (cart, account, inventory item) | ||
| - Workflow persists for entity lifetime | ||
| - Receives signals for state changes | ||
| - Supports queries for current state | ||
| **Example Use Cases:** | ||
| - Shopping cart (add items, checkout, expiration) | ||
| - Bank account (deposits, withdrawals, balance checks) | ||
| - Product inventory (stock updates, reservations) | ||
| **Benefits:** | ||
| - Encapsulates entity behavior | ||
| - Guarantees consistency per entity | ||
| - Natural event sourcing | ||
| ### 3. Fan-Out/Fan-In (Parallel Execution) | ||
| **Purpose**: Execute multiple tasks in parallel, aggregate results | ||
| **Pattern:** | ||
| - Spawn child workflows or parallel activities | ||
| - Wait for all to complete | ||
| - Aggregate results | ||
| - Handle partial failures | ||
| **Scaling Rule** (Source: temporal.io/blog/workflow-engine-principles): | ||
| - Don't scale individual workflows | ||
| - For 1M tasks: spawn 1K child workflows × 1K tasks each | ||
| - Keep each workflow bounded | ||
| ### 4. Async Callback Pattern | ||
| **Purpose**: Wait for external event or human approval | ||
| **Pattern:** | ||
| - Workflow sends request and waits for signal | ||
| - External system processes asynchronously | ||
| - Sends signal to resume workflow | ||
| - Workflow continues with response | ||
| **Use Cases:** | ||
| - Human approval workflows | ||
| - Webhook callbacks | ||
| - Long-running external processes | ||
| ## State Management and Determinism | ||
| ### Automatic State Preservation | ||
| **How Temporal Works** (Source: docs.temporal.io/workflows): | ||
| - Complete program state preserved automatically | ||
| - Event History records every command and event | ||
| - Seamless recovery from crashes | ||
| - Applications restore pre-failure state | ||
| ### Determinism Constraints | ||
| **Workflows Execute as State Machines**: | ||
| - Replay behavior must be consistent | ||
| - Same inputs → identical outputs every time | ||
| **Prohibited in Workflows** (Source: docs.temporal.io/workflows): | ||
| - ❌ Threading, locks, synchronization primitives | ||
| - ❌ Random number generation (`random()`) | ||
| - ❌ Global state or static variables | ||
| - ❌ System time (`datetime.now()`) | ||
| - ❌ Direct file I/O or network calls | ||
| - ❌ Non-deterministic libraries | ||
| **Allowed in Workflows**: | ||
| - ✅ `workflow.now()` (deterministic time) | ||
| - ✅ `workflow.random()` (deterministic random) | ||
| - ✅ Pure functions and calculations | ||
| - ✅ Calling activities (non-deterministic operations) | ||
| ### Versioning Strategies | ||
| **Challenge**: Changing workflow code while old executions still running | ||
| **Solutions**: | ||
| 1. **Versioning API**: Use `workflow.get_version()` for safe changes | ||
| 2. **New Workflow Type**: Create new workflow, route new executions to it | ||
| 3. **Backward Compatibility**: Ensure old events replay correctly | ||
| ## Resilience and Error Handling | ||
| ### Retry Policies | ||
| **Default Behavior**: Temporal retries activities forever | ||
| **Configure Retry**: | ||
| - Initial retry interval | ||
| - Backoff coefficient (exponential backoff) | ||
| - Maximum interval (cap retry delay) | ||
| - Maximum attempts (eventually fail) | ||
| **Non-Retryable Errors**: | ||
| - Invalid input (validation failures) | ||
| - Business rule violations | ||
| - Permanent failures (resource not found) | ||
| ### Idempotency Requirements | ||
| **Why Critical** (Source: docs.temporal.io/activities): | ||
| - Activities may execute multiple times | ||
| - Network failures trigger retries | ||
| - Duplicate execution must be safe | ||
| **Implementation Strategies**: | ||
| - Idempotency keys (deduplication) | ||
| - Check-then-act with unique constraints | ||
| - Upsert operations instead of insert | ||
| - Track processed request IDs | ||
| ### Activity Heartbeats | ||
| **Purpose**: Detect stalled long-running activities | ||
| **Pattern**: | ||
| - Activity sends periodic heartbeat | ||
| - Includes progress information | ||
| - Timeout if no heartbeat received | ||
| - Enables progress-based retry |
| --- | ||
| name: workflow-orchestration-patterns | ||
| description: Design durable workflows with Temporal for distributed systems. Covers workflow vs activity separation, saga patterns, state management, and determinism constraints. Use when building long-running processes, distributed transactions, or microservice orchestration. | ||
| --- | ||
| # Workflow Orchestration Patterns | ||
| Master workflow orchestration architecture with Temporal, covering fundamental design decisions, resilience patterns, and best practices for building reliable distributed systems. | ||
| ## When to Use Workflow Orchestration | ||
| ### Ideal Use Cases (Source: docs.temporal.io) | ||
| - **Multi-step processes** spanning machines/services/databases | ||
| - **Distributed transactions** requiring all-or-nothing semantics | ||
| - **Long-running workflows** (hours to years) with automatic state persistence | ||
| - **Failure recovery** that must resume from last successful step | ||
| - **Business processes**: bookings, orders, campaigns, approvals | ||
| - **Entity lifecycle management**: inventory tracking, account management, cart workflows | ||
| - **Infrastructure automation**: CI/CD pipelines, provisioning, deployments | ||
| - **Human-in-the-loop** systems requiring timeouts and escalations | ||
| ### When NOT to Use | ||
| - Simple CRUD operations (use direct API calls) | ||
| - Pure data processing pipelines (use Airflow, batch processing) | ||
| - Stateless request/response (use standard APIs) | ||
| - Real-time streaming (use Kafka, event processors) | ||
| ## Detailed patterns and worked examples | ||
| Detailed pattern documentation lives in `references/details.md`. Read that file when the navigation tier above is insufficient. | ||
| ## Best Practices | ||
| ### Workflow Design | ||
| 1. **Keep workflows focused** - Single responsibility per workflow | ||
| 2. **Small workflows** - Use child workflows for scalability | ||
| 3. **Clear boundaries** - Workflow orchestrates, activities execute | ||
| 4. **Test locally** - Use time-skipping test environment | ||
| ### Activity Design | ||
| 1. **Idempotent operations** - Safe to retry | ||
| 2. **Short-lived** - Seconds to minutes, not hours | ||
| 3. **Timeout configuration** - Always set timeouts | ||
| 4. **Heartbeat for long tasks** - Report progress | ||
| 5. **Error handling** - Distinguish retryable vs non-retryable | ||
| ### Common Pitfalls | ||
| **Workflow Violations**: | ||
| - Using `datetime.now()` instead of `workflow.now()` | ||
| - Threading or async operations in workflow code | ||
| - Calling external APIs directly from workflow | ||
| - Non-deterministic logic in workflows | ||
| **Activity Mistakes**: | ||
| - Non-idempotent operations (can't handle retries) | ||
| - Missing timeouts (activities run forever) | ||
| - No error classification (retry validation errors) | ||
| - Ignoring payload limits (2MB per argument) | ||
| ### Operational Considerations | ||
| **Monitoring**: | ||
| - Workflow execution duration | ||
| - Activity failure rates | ||
| - Retry attempts and backoff | ||
| - Pending workflow counts | ||
| **Scalability**: | ||
| - Horizontal scaling with workers | ||
| - Task queue partitioning | ||
| - Child workflow decomposition | ||
| - Activity batching when appropriate | ||
| ## Additional Resources | ||
| **Official Documentation**: | ||
| - Temporal Core Concepts: docs.temporal.io/workflows | ||
| - Workflow Patterns: docs.temporal.io/evaluate/use-cases-design-patterns | ||
| - Best Practices: docs.temporal.io/develop/best-practices | ||
| - Saga Pattern: temporal.io/blog/saga-pattern-made-easy | ||
| **Key Principles**: | ||
| 1. Workflows = orchestration, Activities = external calls | ||
| 2. Determinism is non-negotiable for workflows | ||
| 3. Idempotency is critical for activities | ||
| 4. State preservation is automatic | ||
| 5. Design for failure and recovery |
| --- | ||
| description: >- | ||
| Run the PageSpeed performance audit — 80/20 analysis of Core Web Vitals using | ||
| the PageSpeed Insights API. | ||
| --- | ||
| # PageSpeed Performance Audit | ||
| Audit URL: $ARGUMENTS | ||
| --- | ||
| ## Step 1 — Pre-flight (pagespeed-perf skill) | ||
| Invoke `pagespeed-perf` skill. | ||
| Read `PAGESPEED_API_KEY` from the environment. Compute the output filename: | ||
| `{YYYY-MM-DD}_pagespeed-{hostname}-claude.md`. | ||
| Log whether the API key was found. Proceed regardless — lab data is available | ||
| without a key, but CrUX field data requires it. | ||
| --- | ||
| ## Step 2 — Collect | ||
| Call the PageSpeed Insights API for the URL provided above. | ||
| - Strategy: `both` (mobile + desktop) unless the user specified otherwise. | ||
| - If Bun is available, use `~/.claude/skills/pagespeed-perf/scripts/run.ts`. | ||
| - If Bun is unavailable, call PSI directly via WebFetch and fetch the HTML | ||
| source for manual resource-hint analysis. | ||
| --- | ||
| ## Step 3 — Analyze | ||
| Extract from the PSI response: | ||
| - Core Web Vitals: LCP, INP, CLS, FCP, TBT, TTFB | ||
| - LCP element (type, selector, HTML snippet) | ||
| - Third-party scripts ordered by blocking time | ||
| - Render-blocking resources | ||
| - Unused JavaScript and CSS (savings in bytes and ms) | ||
| From the HTML source: | ||
| - Resource hints (`<link rel="preload|preconnect|prefetch">`) | ||
| - Images: lazy loading, `fetchpriority`, format, dimensions | ||
| - Fonts: `font-display`, preloaded subsets | ||
| - Blocking scripts in `<head>` (no `async`/`defer`) | ||
| --- | ||
| ## Step 4 — Prioritize | ||
| Score each identified optimization using the 80/20 matrix: | ||
| `Score = Impact × Ease` (each 1–5, max 25). | ||
| Order findings by descending score. Mark optimizations with Score ≥ 20 as | ||
| **Critical 20%**. | ||
| --- | ||
| ## Step 5 — Report | ||
| Write the full performance report to | ||
| `{YYYY-MM-DD}_pagespeed-{hostname}-claude.md` in the current directory. | ||
| Required sections: | ||
| 1. Resumen Ejecutivo (2–3 paragraphs) | ||
| 2. Métricas Actuales (lab vs field table) | ||
| 3. Recursos con Mayor Impacto | ||
| 4. Plan de Acción Priorizado (80/20 table) | ||
| 5. Solución Técnica Detallada (per finding: problem, evidence, code, expected gain) | ||
| 6. Quick Wins / High Impact Changes / Roadmap | ||
| End every report with: | ||
| ``` | ||
| --- | ||
| *Informe generado el {YYYY-MM-DD} · Herramienta: Claude Code + pagespeed-perf skill* | ||
| *API Key usada: {Sí / No} · Datos CrUX: {Disponibles / No disponibles}* | ||
| ``` | ||
| --- | ||
| ## Requirements | ||
| **`PAGESPEED_API_KEY`** — Optional but strongly recommended. | ||
| - With key: real CrUX field data + 25,000 requests/day quota. | ||
| - Without key: lab data only (Lighthouse); shared rate limit applies. | ||
| Set in your shell: | ||
| ```powershell | ||
| $env:PAGESPEED_API_KEY = "your-api-key" # Windows PowerShell | ||
| export PAGESPEED_API_KEY="your-api-key" # macOS / Linux | ||
| ``` | ||
| Get a free key: <https://developers.google.com/speed/docs/insights/v5/get-started> |
| --- | ||
| name: conductor-setup | ||
| description: Configure a Rails project to work with Conductor (parallel coding agents) | ||
| allowed-tools: Bash(chmod *), Bash(bundle *), Bash(npm *), Bash(script/server) | ||
| context: fork | ||
| risk: unknown | ||
| source: community | ||
| metadata: | ||
| author: Shpigford | ||
| version: "1.0" | ||
| --- | ||
| Set up this Rails project for Conductor, the Mac app for parallel coding agents. | ||
| ## When to Use | ||
| - You need to configure a Rails project so it runs correctly inside Conductor workspaces. | ||
| - The project should support parallel coding agents with isolated ports, Redis settings, and shared secrets. | ||
| - You want the standard `conductor.json`, `bin/conductor-setup`, and `script/server` scaffolding for a Rails repo. | ||
| # What to Create | ||
| ## 1. conductor.json (project root) | ||
| Create `conductor.json` in the project root if it doesn't already exist: | ||
| ```json | ||
| { | ||
| "scripts": { | ||
| "setup": "bin/conductor-setup", | ||
| "run": "script/server" | ||
| } | ||
| } | ||
| ``` | ||
| ## 2. bin/conductor-setup (executable) | ||
| Create `bin/conductor-setup` if it doesn't already exist: | ||
| ```bash | ||
| #!/bin/bash | ||
| set -e | ||
| # Symlink .env from repo root (where secrets live, outside worktrees) | ||
| [ -f "$CONDUCTOR_ROOT_PATH/.env" ] && ln -sf "$CONDUCTOR_ROOT_PATH/.env" .env | ||
| # Symlink Rails master key | ||
| [ -f "$CONDUCTOR_ROOT_PATH/config/master.key" ] && ln -sf "$CONDUCTOR_ROOT_PATH/config/master.key" config/master.key | ||
| # Install dependencies | ||
| bundle install | ||
| npm install | ||
| ``` | ||
| Make it executable with `chmod +x bin/conductor-setup`. | ||
| ## 3. script/server (executable) | ||
| Create the `script` directory if needed, then create `script/server` if it doesn't already exist: | ||
| ```bash | ||
| #!/bin/bash | ||
| # === Port Configuration === | ||
| export PORT=${CONDUCTOR_PORT:-3000} | ||
| export VITE_RUBY_PORT=$((PORT + 1000)) | ||
| # === Redis Isolation === | ||
| if [ -n "$CONDUCTOR_WORKSPACE_NAME" ]; then | ||
| HASH=$(printf '%s' "$CONDUCTOR_WORKSPACE_NAME" | cksum | cut -d' ' -f1) | ||
| REDIS_DB=$((HASH % 16)) | ||
| export REDIS_URL="redis://localhost:6379/${REDIS_DB}" | ||
| fi | ||
| exec bin/dev | ||
| ``` | ||
| Make it executable with `chmod +x script/server`. | ||
| ## 4. Update Rails Config Files | ||
| For each of the following files, if they exist and contain Redis configuration, update them to use `ENV.fetch('REDIS_URL', ...)` or `ENV['REDIS_URL']` with a fallback: | ||
| ### config/initializers/sidekiq.rb | ||
| If this file exists and configures Redis, update it to use: | ||
| ```ruby | ||
| redis_url = ENV.fetch('REDIS_URL', 'redis://localhost:6379/0') | ||
| ``` | ||
| ### config/cable.yml | ||
| If this file exists, update the development adapter to use: | ||
| ```yaml | ||
| development: | ||
| adapter: redis | ||
| url: <%= ENV.fetch('REDIS_URL', 'redis://localhost:6379/1') %> | ||
| ``` | ||
| ### config/environments/development.rb | ||
| If this file configures Redis for caching, update to use: | ||
| ```ruby | ||
| config.cache_store = :redis_cache_store, { url: ENV.fetch('REDIS_URL', 'redis://localhost:6379/0') } | ||
| ``` | ||
| ### config/initializers/rack_attack.rb | ||
| If this file exists and configures a Redis cache store, update to use: | ||
| ```ruby | ||
| Rack::Attack.cache.store = ActiveSupport::Cache::RedisCacheStore.new(url: ENV.fetch('REDIS_URL', 'redis://localhost:6379/0')) | ||
| ``` | ||
| # Implementation Notes | ||
| - **Don't overwrite existing files**: Check if conductor.json, bin/conductor-setup, and script/server exist before creating them. If they exist, skip creation and inform the user. | ||
| - **Rails config updates**: Only modify Redis-related configuration. If a file doesn't exist or doesn't use Redis, skip it gracefully. | ||
| - **Create directories as needed**: Create `script/` directory if it doesn't exist. | ||
| # Verification | ||
| After creating the files: | ||
| 1. Confirm all Conductor files exist and scripts are executable | ||
| 2. Run `script/server` to verify it starts without errors | ||
| 3. Check that Rails configs properly reference `ENV['REDIS_URL']` or `ENV.fetch('REDIS_URL', ...)` | ||
| ## Limitations | ||
| - Use this skill only when the task clearly matches the scope described above. | ||
| - Do not treat the output as a substitute for environment-specific validation, testing, or expert review. | ||
| - Stop and ask for clarification if required inputs, permissions, safety boundaries, or success criteria are missing. |
| --- | ||
| name: find-skills | ||
| description: Helps users discover and install agent skills when they ask questions like "how do I do X", "find a skill for X", "is there a skill that can...", or express interest in extending capabilities. This skill should be used when the user is looking for functionality that might exist as an installable skill. | ||
| --- | ||
| # Find Skills | ||
| This skill helps you discover and install skills from the open agent skills ecosystem. | ||
| ## When to Use This Skill | ||
| Use this skill when the user: | ||
| - Asks "how do I do X" where X might be a common task with an existing skill | ||
| - Says "find a skill for X" or "is there a skill for X" | ||
| - Asks "can you do X" where X is a specialized capability | ||
| - Expresses interest in extending agent capabilities | ||
| - Wants to search for tools, templates, or workflows | ||
| - Mentions they wish they had help with a specific domain (design, testing, deployment, etc.) | ||
| ## What is the Skills CLI? | ||
| The Skills CLI (`npx skills`) is the package manager for the open agent skills ecosystem. Skills are modular packages that extend agent capabilities with specialized knowledge, workflows, and tools. | ||
| **Key commands:** | ||
| - `npx skills find [query]` - Search for skills interactively or by keyword | ||
| - `npx skills add <package>` - Install a skill from GitHub or other sources | ||
| - `npx skills check` - Check for skill updates | ||
| - `npx skills update` - Update all installed skills | ||
| **Browse skills at:** https://skills.sh/ | ||
| ## How to Help Users Find Skills | ||
| ### Step 1: Understand What They Need | ||
| When a user asks for help with something, identify: | ||
| 1. The domain (e.g., React, testing, design, deployment) | ||
| 2. The specific task (e.g., writing tests, creating animations, reviewing PRs) | ||
| 3. Whether this is a common enough task that a skill likely exists | ||
| ### Step 2: Check the Leaderboard First | ||
| Before running a CLI search, check the [skills.sh leaderboard](https://skills.sh/) to see if a well-known skill already exists for the domain. The leaderboard ranks skills by total installs, surfacing the most popular and battle-tested options. | ||
| For example, top skills for web development include: | ||
| - `vercel-labs/agent-skills` — React, Next.js, web design (100K+ installs each) | ||
| - `anthropics/skills` — Frontend design, document processing (100K+ installs) | ||
| ### Step 3: Search for Skills | ||
| If the leaderboard doesn't cover the user's need, run the find command: | ||
| ```bash | ||
| npx skills find [query] | ||
| ``` | ||
| For example: | ||
| - User asks "how do I make my React app faster?" → `npx skills find react performance` | ||
| - User asks "can you help me with PR reviews?" → `npx skills find pr review` | ||
| - User asks "I need to create a changelog" → `npx skills find changelog` | ||
| ### Step 4: Verify Quality Before Recommending | ||
| **Do not recommend a skill based solely on search results.** Always verify: | ||
| 1. **Install count** — Prefer skills with 1K+ installs. Be cautious with anything under 100. | ||
| 2. **Source reputation** — Official sources (`vercel-labs`, `anthropics`, `microsoft`) are more trustworthy than unknown authors. | ||
| 3. **GitHub stars** — Check the source repository. A skill from a repo with <100 stars should be treated with skepticism. | ||
| ### Step 5: Present Options to the User | ||
| When you find relevant skills, present them to the user with: | ||
| 1. The skill name and what it does | ||
| 2. The install count and source | ||
| 3. The install command they can run | ||
| 4. A link to learn more at skills.sh | ||
| Example response: | ||
| ``` | ||
| I found a skill that might help! The "react-best-practices" skill provides | ||
| React and Next.js performance optimization guidelines from Vercel Engineering. | ||
| (185K installs) | ||
| To install it: | ||
| npx skills add vercel-labs/agent-skills@react-best-practices | ||
| Learn more: https://skills.sh/vercel-labs/agent-skills/react-best-practices | ||
| ``` | ||
| ### Step 6: Offer to Install | ||
| If the user wants to proceed, you can install the skill for them: | ||
| ```bash | ||
| npx skills add <owner/repo@skill> -g -y | ||
| ``` | ||
| The `-g` flag installs globally (user-level) and `-y` skips confirmation prompts. | ||
| ## Common Skill Categories | ||
| When searching, consider these common categories: | ||
| | Category | Example Queries | | ||
| | --------------- | ---------------------------------------- | | ||
| | Web Development | react, nextjs, typescript, css, tailwind | | ||
| | Testing | testing, jest, playwright, e2e | | ||
| | DevOps | deploy, docker, kubernetes, ci-cd | | ||
| | Documentation | docs, readme, changelog, api-docs | | ||
| | Code Quality | review, lint, refactor, best-practices | | ||
| | Design | ui, ux, design-system, accessibility | | ||
| | Productivity | workflow, automation, git | | ||
| ## Tips for Effective Searches | ||
| 1. **Use specific keywords**: "react testing" is better than just "testing" | ||
| 2. **Try alternative terms**: If "deploy" doesn't work, try "deployment" or "ci-cd" | ||
| 3. **Check popular sources**: Many skills come from `vercel-labs/agent-skills` or `ComposioHQ/awesome-claude-skills` | ||
| ## When No Skills Are Found | ||
| If no relevant skills exist: | ||
| 1. Acknowledge that no existing skill was found | ||
| 2. Offer to help with the task directly using your general capabilities | ||
| 3. Suggest the user could create their own skill with `npx skills init` | ||
| Example: | ||
| ``` | ||
| I searched for skills related to "xyz" but didn't find any matches. | ||
| I can still help you with this task directly! Would you like me to proceed? | ||
| If this is something you do often, you could create your own skill: | ||
| npx skills init my-xyz-skill | ||
| ``` |
| """ | ||
| Framework-Specific Multi-Agent Implementations | ||
| Templates for CrewAI, AutoGen, LangGraph, and Swarm. | ||
| """ | ||
| from typing import Dict, List, Optional, Any | ||
| from dataclasses import dataclass | ||
| @dataclass | ||
| class CrewAITemplate: | ||
| """Template for CrewAI implementation.""" | ||
| @staticmethod | ||
| def create_financial_team() -> Dict[str, Any]: | ||
| """Create CrewAI financial analysis team.""" | ||
| return { | ||
| "agents": [ | ||
| { | ||
| "name": "Market Analyst", | ||
| "role": "Market Research Specialist", | ||
| "goal": "Analyze market conditions and trends", | ||
| "backstory": "Expert market analyst with 10+ years experience", | ||
| "tools": ["market_data_api", "financial_news"], | ||
| }, | ||
| { | ||
| "name": "Financial Analyst", | ||
| "role": "Financial Analysis Specialist", | ||
| "goal": "Analyze company financial statements", | ||
| "backstory": "CFA with deep financial analysis expertise", | ||
| "tools": ["financial_statements", "ratio_calculator"], | ||
| }, | ||
| { | ||
| "name": "Risk Manager", | ||
| "role": "Risk Assessment Specialist", | ||
| "goal": "Assess investment risks and scenarios", | ||
| "backstory": "Risk management expert", | ||
| "tools": ["risk_models", "scenario_analysis"], | ||
| }, | ||
| { | ||
| "name": "Report Writer", | ||
| "role": "Report Generation Specialist", | ||
| "goal": "Synthesize findings into comprehensive report", | ||
| "backstory": "Professional technical writer", | ||
| "tools": ["document_generator"], | ||
| }, | ||
| ], | ||
| "tasks": [ | ||
| { | ||
| "agent": "Market Analyst", | ||
| "description": "Analyze market conditions for {company}", | ||
| }, | ||
| { | ||
| "agent": "Financial Analyst", | ||
| "description": "Analyze Q3 financial results for {company}", | ||
| }, | ||
| { | ||
| "agent": "Risk Manager", | ||
| "description": "Assess risks and create scenarios for {company}", | ||
| }, | ||
| { | ||
| "agent": "Report Writer", | ||
| "description": "Write comprehensive investment analysis report", | ||
| }, | ||
| ], | ||
| "process": "sequential", | ||
| } | ||
| @staticmethod | ||
| def create_legal_team() -> Dict[str, Any]: | ||
| """Create CrewAI legal team.""" | ||
| return { | ||
| "agents": [ | ||
| { | ||
| "name": "Contract Analyzer", | ||
| "role": "Legal Contract Specialist", | ||
| "goal": "Analyze and review contract terms", | ||
| "backstory": "Senior contract attorney", | ||
| }, | ||
| { | ||
| "name": "Precedent Researcher", | ||
| "role": "Legal Research Specialist", | ||
| "goal": "Research relevant case law and precedents", | ||
| "backstory": "Legal researcher specializing in case law", | ||
| }, | ||
| { | ||
| "name": "Risk Assessor", | ||
| "role": "Legal Risk Specialist", | ||
| "goal": "Identify and assess legal risks", | ||
| "backstory": "Risk management expert in legal domain", | ||
| }, | ||
| { | ||
| "name": "Document Drafter", | ||
| "role": "Legal Document Specialist", | ||
| "goal": "Draft legal documents and recommendations", | ||
| "backstory": "Legal document drafting expert", | ||
| }, | ||
| ], | ||
| "process": "sequential", | ||
| } | ||
| @dataclass | ||
| class AutoGenTemplate: | ||
| """Template for AutoGen implementation.""" | ||
| @staticmethod | ||
| def create_group_chat_config() -> Dict[str, Any]: | ||
| """Create AutoGen group chat configuration.""" | ||
| return { | ||
| "agents": [ | ||
| { | ||
| "name": "analyst", | ||
| "system_message": "You are a financial analyst. Provide analysis based on data.", | ||
| "llm_config": {"model": "gpt-4", "temperature": 0.7}, | ||
| }, | ||
| { | ||
| "name": "researcher", | ||
| "system_message": "You are a market researcher. Research trends and competition.", | ||
| "llm_config": {"model": "gpt-4", "temperature": 0.7}, | ||
| }, | ||
| { | ||
| "name": "critic", | ||
| "system_message": "You are a critical evaluator. Challenge assumptions and findings.", | ||
| "llm_config": {"model": "gpt-4", "temperature": 0.7}, | ||
| }, | ||
| ], | ||
| "group_chat_config": { | ||
| "agents": ["analyst", "researcher", "critic"], | ||
| "max_round": 10, | ||
| "speaker_selection_method": "auto", | ||
| }, | ||
| } | ||
| @staticmethod | ||
| def create_hierarchical_structure() -> Dict[str, Any]: | ||
| """Create hierarchical AutoGen structure.""" | ||
| return { | ||
| "primary_agents": [ | ||
| { | ||
| "name": "senior_analyst", | ||
| "role": "Senior analyst coordinating teams", | ||
| "subordinates": ["junior_analyst_1", "junior_analyst_2"], | ||
| } | ||
| ], | ||
| "secondary_agents": [ | ||
| { | ||
| "name": "junior_analyst_1", | ||
| "role": "Fundamental analysis specialist", | ||
| }, | ||
| { | ||
| "name": "junior_analyst_2", | ||
| "role": "Technical analysis specialist", | ||
| }, | ||
| ], | ||
| } | ||
| @dataclass | ||
| class LangGraphTemplate: | ||
| """Template for LangGraph workflow implementation.""" | ||
| @staticmethod | ||
| def create_research_workflow() -> Dict[str, Any]: | ||
| """Create LangGraph research workflow.""" | ||
| return { | ||
| "name": "research_workflow", | ||
| "state_schema": { | ||
| "topic": str, | ||
| "research_findings": str, | ||
| "analysis": str, | ||
| "recommendations": str, | ||
| }, | ||
| "nodes": [ | ||
| { | ||
| "name": "researcher", | ||
| "agent": "research_agent", | ||
| "description": "Research the topic", | ||
| }, | ||
| { | ||
| "name": "analyst", | ||
| "agent": "analyst_agent", | ||
| "description": "Analyze research findings", | ||
| }, | ||
| { | ||
| "name": "critic", | ||
| "agent": "critic_agent", | ||
| "description": "Critique and improve", | ||
| }, | ||
| { | ||
| "name": "writer", | ||
| "agent": "writer_agent", | ||
| "description": "Write final report", | ||
| }, | ||
| ], | ||
| "edges": [ | ||
| ("researcher", "analyst"), | ||
| ("analyst", "critic"), | ||
| ("critic", "writer"), | ||
| ], | ||
| "entry_point": "researcher", | ||
| "exit_point": "writer", | ||
| } | ||
| @staticmethod | ||
| def create_dynamic_workflow() -> Dict[str, Any]: | ||
| """Create dynamic LangGraph workflow with conditions.""" | ||
| return { | ||
| "name": "dynamic_workflow", | ||
| "nodes": [ | ||
| { | ||
| "name": "start", | ||
| "type": "input", | ||
| }, | ||
| { | ||
| "name": "analyze", | ||
| "type": "agent", | ||
| "agent": "analyzer", | ||
| }, | ||
| { | ||
| "name": "quality_check", | ||
| "type": "decision", | ||
| "condition": "analyze_quality > threshold", | ||
| }, | ||
| { | ||
| "name": "refine", | ||
| "type": "agent", | ||
| "agent": "refiner", | ||
| }, | ||
| { | ||
| "name": "end", | ||
| "type": "output", | ||
| }, | ||
| ], | ||
| "conditional_edges": [ | ||
| { | ||
| "source": "quality_check", | ||
| "true_target": "end", | ||
| "false_target": "refine", | ||
| } | ||
| ], | ||
| } | ||
| @dataclass | ||
| class SwarmTemplate: | ||
| """Template for OpenAI Swarm implementation.""" | ||
| @staticmethod | ||
| def create_customer_support_swarm() -> Dict[str, Any]: | ||
| """Create customer support Swarm.""" | ||
| return { | ||
| "agents": [ | ||
| { | ||
| "name": "triage_agent", | ||
| "instructions": "Determine which specialist to route the customer to. " | ||
| "Ask clarifying questions if needed.", | ||
| "functions": [ | ||
| "route_to_billing", | ||
| "route_to_technical", | ||
| "route_to_account", | ||
| ], | ||
| }, | ||
| { | ||
| "name": "billing_specialist", | ||
| "instructions": "Handle all billing and payment related questions. " | ||
| "Can access billing records.", | ||
| "tools": ["billing_system", "payment_processor"], | ||
| }, | ||
| { | ||
| "name": "technical_support", | ||
| "instructions": "Handle technical issues and troubleshooting. " | ||
| "Can access diagnostic tools.", | ||
| "tools": ["diagnostic_tools", "knowledge_base"], | ||
| }, | ||
| { | ||
| "name": "account_specialist", | ||
| "instructions": "Handle account management and profile changes.", | ||
| "tools": ["account_system"], | ||
| }, | ||
| ], | ||
| "handoff_functions": { | ||
| "route_to_billing": "Transfer to billing specialist", | ||
| "route_to_technical": "Transfer to technical support", | ||
| "route_to_account": "Transfer to account specialist", | ||
| }, | ||
| } | ||
| @staticmethod | ||
| def create_sales_swarm() -> Dict[str, Any]: | ||
| """Create sales team Swarm.""" | ||
| return { | ||
| "agents": [ | ||
| { | ||
| "name": "sales_router", | ||
| "instructions": "Route customer inquiries to appropriate sales agent", | ||
| "functions": ["route_to_enterprise", "route_to_smb"], | ||
| }, | ||
| { | ||
| "name": "enterprise_sales", | ||
| "instructions": "Handle enterprise customer inquiries", | ||
| }, | ||
| { | ||
| "name": "smb_sales", | ||
| "instructions": "Handle small business inquiries", | ||
| }, | ||
| ], | ||
| } | ||
| class AgentCommunicationManager: | ||
| """Manage communication patterns between agents.""" | ||
| def __init__(self, agents: Dict[str, Any]): | ||
| """Initialize communication manager.""" | ||
| self.agents = agents | ||
| self.message_queue = [] | ||
| def broadcast_message(self, sender: str, message: str, recipients: List[str]): | ||
| """Broadcast message to multiple agents.""" | ||
| for recipient in recipients: | ||
| self.message_queue.append({ | ||
| "from": sender, | ||
| "to": recipient, | ||
| "message": message, | ||
| "type": "broadcast", | ||
| }) | ||
| def direct_message(self, sender: str, recipient: str, message: str): | ||
| """Send direct message between agents.""" | ||
| self.message_queue.append({ | ||
| "from": sender, | ||
| "to": recipient, | ||
| "message": message, | ||
| "type": "direct", | ||
| }) | ||
| def publish_shared_state(self, state_key: str, value: Any): | ||
| """Publish to shared state (tool-mediated communication).""" | ||
| self.message_queue.append({ | ||
| "type": "shared_state", | ||
| "key": state_key, | ||
| "value": value, | ||
| }) | ||
| def get_pending_messages(self, agent: str) -> List[Dict]: | ||
| """Get messages for specific agent.""" | ||
| return [msg for msg in self.message_queue if msg.get("to") == agent] | ||
| def process_message_queue(self) -> Dict[str, Any]: | ||
| """Process and summarize message queue.""" | ||
| direct_messages = [m for m in self.message_queue if m["type"] == "direct"] | ||
| broadcasts = [m for m in self.message_queue if m["type"] == "broadcast"] | ||
| shared_states = [m for m in self.message_queue if m["type"] == "shared_state"] | ||
| return { | ||
| "direct_messages": len(direct_messages), | ||
| "broadcasts": len(broadcasts), | ||
| "shared_states": len(shared_states), | ||
| "total_messages": len(self.message_queue), | ||
| } |
| """ | ||
| Multi-Agent Orchestration Patterns | ||
| Implements sequential, parallel, hierarchical, and consensus orchestration. | ||
| """ | ||
| from typing import List, Dict, Any, Optional | ||
| import asyncio | ||
| from abc import ABC, abstractmethod | ||
| class Agent(ABC): | ||
| """Base agent class.""" | ||
| def __init__(self, name: str, role: str, goal: str): | ||
| """Initialize agent.""" | ||
| self.name = name | ||
| self.role = role | ||
| self.goal = goal | ||
| @abstractmethod | ||
| def work(self, task: str) -> str: | ||
| """Execute task.""" | ||
| pass | ||
| async def work_async(self, task: str) -> str: | ||
| """Execute task asynchronously.""" | ||
| return self.work(task) | ||
| class SimpleAgent(Agent): | ||
| """Simple agent implementation.""" | ||
| def __init__(self, name: str, role: str, goal: str): | ||
| """Initialize simple agent.""" | ||
| super().__init__(name, role, goal) | ||
| def work(self, task: str) -> str: | ||
| """Simulate agent work.""" | ||
| return f"{self.name}: Completed task - {task[:50]}..." | ||
| class SequentialOrchestrator: | ||
| """Orchestrate agents to work sequentially.""" | ||
| def __init__(self, agents: List[Agent]): | ||
| """ | ||
| Initialize orchestrator with agents. | ||
| Args: | ||
| agents: List of agents to orchestrate | ||
| """ | ||
| self.agents = agents | ||
| self.execution_log = [] | ||
| def execute(self, initial_task: str) -> Dict[str, Any]: | ||
| """ | ||
| Execute agents sequentially. | ||
| Args: | ||
| initial_task: Initial task description | ||
| Returns: | ||
| Execution results dictionary | ||
| """ | ||
| current_input = initial_task | ||
| results = {} | ||
| for agent in self.agents: | ||
| result = agent.work(current_input) | ||
| results[agent.name] = result | ||
| self.execution_log.append({ | ||
| "agent": agent.name, | ||
| "role": agent.role, | ||
| "task": current_input, | ||
| "result": result, | ||
| }) | ||
| # Next agent uses this agent's output | ||
| current_input = result | ||
| return { | ||
| "type": "sequential", | ||
| "results": results, | ||
| "final_output": current_input, | ||
| "execution_log": self.execution_log, | ||
| } | ||
| class ParallelOrchestrator: | ||
| """Orchestrate agents to work in parallel.""" | ||
| def __init__(self, agents: List[Agent]): | ||
| """Initialize parallel orchestrator.""" | ||
| self.agents = agents | ||
| self.execution_log = [] | ||
| async def execute_async(self, task: str) -> Dict[str, Any]: | ||
| """ | ||
| Execute agents in parallel. | ||
| Args: | ||
| task: Task description | ||
| Returns: | ||
| Execution results dictionary | ||
| """ | ||
| # Create async tasks for all agents | ||
| tasks = [agent.work_async(task) for agent in self.agents] | ||
| # Execute all in parallel | ||
| results_list = await asyncio.gather(*tasks) | ||
| results = { | ||
| agent.name: result | ||
| for agent, result in zip(self.agents, results_list) | ||
| } | ||
| self.execution_log.append({ | ||
| "type": "parallel", | ||
| "task": task, | ||
| "agents": [a.name for a in self.agents], | ||
| "results": results, | ||
| }) | ||
| return { | ||
| "type": "parallel", | ||
| "results": results, | ||
| "execution_log": self.execution_log, | ||
| } | ||
| def execute(self, task: str) -> Dict[str, Any]: | ||
| """Execute agents synchronously (sequential fallback).""" | ||
| return asyncio.run(self.execute_async(task)) | ||
| class HierarchicalOrchestrator: | ||
| """Orchestrate agents in hierarchical structure.""" | ||
| def __init__(self, manager_agent: Agent, specialist_teams: Dict[str, List[Agent]]): | ||
| """ | ||
| Initialize hierarchical orchestrator. | ||
| Args: | ||
| manager_agent: Manager agent | ||
| specialist_teams: Dict of team names to lists of agents | ||
| """ | ||
| self.manager = manager_agent | ||
| self.specialist_teams = specialist_teams | ||
| self.execution_log = [] | ||
| def execute(self, main_task: str) -> Dict[str, Any]: | ||
| """ | ||
| Execute with hierarchical structure. | ||
| Args: | ||
| main_task: Main task for manager | ||
| Returns: | ||
| Execution results | ||
| """ | ||
| team_results = {} | ||
| # Manager assigns tasks to teams | ||
| for team_name, agents in self.specialist_teams.items(): | ||
| # Each team works on their aspect | ||
| team_task = f"{main_task} - Team: {team_name}" | ||
| team_result = {} | ||
| for agent in agents: | ||
| result = agent.work(team_task) | ||
| team_result[agent.name] = result | ||
| team_results[team_name] = team_result | ||
| self.execution_log.append({ | ||
| "team": team_name, | ||
| "agents": [a.name for a in agents], | ||
| "results": team_result, | ||
| }) | ||
| # Manager synthesizes results | ||
| manager_result = self.manager.work( | ||
| f"Synthesize findings from: {list(team_results.keys())}" | ||
| ) | ||
| return { | ||
| "type": "hierarchical", | ||
| "team_results": team_results, | ||
| "manager_synthesis": manager_result, | ||
| "execution_log": self.execution_log, | ||
| } | ||
| class ConsensusOrchestrator: | ||
| """Orchestrate agent debate and consensus.""" | ||
| def __init__(self, agents: List[Agent], mediator_agent: Agent): | ||
| """Initialize consensus orchestrator.""" | ||
| self.agents = agents | ||
| self.mediator = mediator_agent | ||
| self.debate_history = [] | ||
| def execute(self, question: str, rounds: int = 2) -> Dict[str, Any]: | ||
| """ | ||
| Execute debate and reach consensus. | ||
| Args: | ||
| question: Question for debate | ||
| rounds: Number of debate rounds | ||
| Returns: | ||
| Consensus results | ||
| """ | ||
| # Round 1: Initial positions | ||
| positions = {} | ||
| for agent in self.agents: | ||
| position = agent.work(f"Argue your position on: {question}") | ||
| positions[agent.name] = position | ||
| self.debate_history.append({ | ||
| "round": 1, | ||
| "agent": agent.name, | ||
| "position": position, | ||
| }) | ||
| # Additional rounds: Response to others | ||
| for round_num in range(2, rounds + 1): | ||
| for agent in self.agents: | ||
| other_positions = { | ||
| name: pos | ||
| for name, pos in positions.items() | ||
| if name != agent.name | ||
| } | ||
| response = agent.work( | ||
| f"Respond to these positions: {str(other_positions)}" | ||
| ) | ||
| self.debate_history.append({ | ||
| "round": round_num, | ||
| "agent": agent.name, | ||
| "response": response, | ||
| }) | ||
| # Mediator reaches consensus | ||
| consensus = self.mediator.work( | ||
| f"Synthesize consensus from debate on: {question}" | ||
| ) | ||
| return { | ||
| "type": "consensus", | ||
| "question": question, | ||
| "initial_positions": positions, | ||
| "debate_rounds": rounds, | ||
| "consensus": consensus, | ||
| "debate_history": self.debate_history, | ||
| } | ||
| class AdaptiveOrchestrator: | ||
| """Adapt orchestration based on progress.""" | ||
| def __init__(self, agents: List[Agent]): | ||
| """Initialize adaptive orchestrator.""" | ||
| self.agents = agents | ||
| self.execution_log = [] | ||
| def execute_with_adaptation( | ||
| self, | ||
| initial_task: str, | ||
| progress_threshold: float = 0.7, | ||
| quality_threshold: float = 0.6, | ||
| ) -> Dict[str, Any]: | ||
| """ | ||
| Execute with adaptive workflow changes. | ||
| Args: | ||
| initial_task: Initial task | ||
| progress_threshold: Threshold for adding resources | ||
| quality_threshold: Threshold for adding validation | ||
| Returns: | ||
| Adaptive execution results | ||
| """ | ||
| results = {} | ||
| current_task = initial_task | ||
| active_agents = self.agents.copy() | ||
| for iteration in range(3): | ||
| # Execute with current agents | ||
| iteration_results = {} | ||
| for agent in active_agents: | ||
| result = agent.work(current_task) | ||
| iteration_results[agent.name] = result | ||
| results[f"iteration_{iteration}"] = iteration_results | ||
| # Assess progress | ||
| progress = self._calculate_progress(iteration_results) | ||
| quality = self._calculate_quality(iteration_results) | ||
| log_entry = { | ||
| "iteration": iteration, | ||
| "agents": [a.name for a in active_agents], | ||
| "progress": progress, | ||
| "quality": quality, | ||
| } | ||
| # Adapt based on progress | ||
| if progress < progress_threshold and iteration < 2: | ||
| # Add more agents | ||
| log_entry["adaptation"] = "Added specialist agent" | ||
| self.execution_log.append(log_entry) | ||
| elif quality < quality_threshold and iteration < 2: | ||
| # Add validation step | ||
| log_entry["adaptation"] = "Added validation agent" | ||
| self.execution_log.append(log_entry) | ||
| else: | ||
| self.execution_log.append(log_entry) | ||
| return { | ||
| "type": "adaptive", | ||
| "results": results, | ||
| "adaptations": self.execution_log, | ||
| } | ||
| @staticmethod | ||
| def _calculate_progress(results: Dict) -> float: | ||
| """Calculate progress score.""" | ||
| # Simple heuristic based on results | ||
| return min(len(results) / 3.0, 1.0) | ||
| @staticmethod | ||
| def _calculate_quality(results: Dict) -> float: | ||
| """Calculate quality score.""" | ||
| # Simple heuristic | ||
| return 0.7 # Placeholder | ||
| class WorkflowGraph: | ||
| """Define workflow as directed acyclic graph (DAG).""" | ||
| def __init__(self): | ||
| """Initialize workflow graph.""" | ||
| self.nodes = {} | ||
| self.edges = [] | ||
| def add_node(self, node_id: str, agent: Agent) -> None: | ||
| """Add agent node.""" | ||
| self.nodes[node_id] = agent | ||
| def add_edge(self, from_node: str, to_node: str) -> None: | ||
| """Add dependency edge.""" | ||
| self.edges.append((from_node, to_node)) | ||
| def execute_dag(self, initial_task: str) -> Dict[str, Any]: | ||
| """ | ||
| Execute workflow as DAG. | ||
| Args: | ||
| initial_task: Initial task | ||
| Returns: | ||
| Execution results | ||
| """ | ||
| results = {} | ||
| ready_nodes = self._find_ready_nodes() | ||
| while ready_nodes: | ||
| for node_id in ready_nodes: | ||
| agent = self.nodes[node_id] | ||
| # Get input from dependencies | ||
| task_input = self._get_node_input(node_id, results, initial_task) | ||
| result = agent.work(task_input) | ||
| results[node_id] = result | ||
| ready_nodes = self._find_ready_nodes(completed=set(results.keys())) | ||
| return { | ||
| "type": "dag", | ||
| "results": results, | ||
| "nodes": list(self.nodes.keys()), | ||
| "edges": self.edges, | ||
| } | ||
| def _find_ready_nodes(self, completed: Optional[set] = None) -> List[str]: | ||
| """Find nodes with all dependencies completed.""" | ||
| if completed is None: | ||
| completed = set() | ||
| ready = [] | ||
| for node_id in self.nodes: | ||
| if node_id not in completed: | ||
| dependencies = [ | ||
| from_node | ||
| for from_node, to_node in self.edges | ||
| if to_node == node_id | ||
| ] | ||
| if all(dep in completed for dep in dependencies): | ||
| ready.append(node_id) | ||
| return ready | ||
| def _get_node_input( | ||
| self, node_id: str, results: Dict, initial_task: str | ||
| ) -> str: | ||
| """Get input for node from dependencies.""" | ||
| dependencies = [ | ||
| from_node for from_node, to_node in self.edges if to_node == node_id | ||
| ] | ||
| if not dependencies: | ||
| return initial_task | ||
| # Combine outputs from dependencies | ||
| return " + ".join(results.get(dep, "") for dep in dependencies) |
| # Multi-Agent Orchestration - Code Structure | ||
| This skill uses supporting Python files to keep documentation lean and maintainable. | ||
| ## Directory Structure | ||
| ``` | ||
| multi-agent-orchestration/ | ||
| ├── SKILL.md # Main documentation (patterns, concepts) | ||
| ├── README.md # This file | ||
| ├── examples/ # Implementation examples | ||
| │ ├── orchestration_patterns.py # Sequential, parallel, hierarchical, consensus | ||
| │ └── framework_implementations.py # CrewAI, AutoGen, LangGraph, Swarm templates | ||
| └── scripts/ # Utility modules | ||
| ├── agent_communication.py # Message broker, shared memory, protocols | ||
| ├── workflow_management.py # Workflow execution and optimization | ||
| └── benchmarking.py # Performance and collaboration metrics | ||
| ``` | ||
| ## Running Examples | ||
| ### 1. Orchestration Patterns | ||
| ```bash | ||
| python examples/orchestration_patterns.py | ||
| ``` | ||
| Demonstrates sequential, parallel, hierarchical, and consensus orchestration. | ||
| ### 2. Framework Templates | ||
| ```bash | ||
| python examples/framework_implementations.py | ||
| ``` | ||
| Templates and configurations for CrewAI, AutoGen, LangGraph, and Swarm frameworks. | ||
| ## Using the Utilities | ||
| ### Agent Communication | ||
| ```python | ||
| from scripts.agent_communication import MessageBroker, SharedMemory, CommunicationProtocol | ||
| # Set up communication | ||
| broker = MessageBroker() | ||
| shared_memory = SharedMemory() | ||
| protocol = CommunicationProtocol(broker, shared_memory) | ||
| # Send messages between agents | ||
| protocol.request_analysis("agent_a", "agent_b", "Analyze this topic") | ||
| # Share findings | ||
| protocol.share_findings("agent_a", "analysis_results", {"findings": "..."}) | ||
| # Get communication stats | ||
| stats = broker.get_statistics() | ||
| ``` | ||
| ### Workflow Management | ||
| ```python | ||
| from scripts.workflow_management import WorkflowExecutor, WorkflowOptimizer | ||
| # Create and execute workflow | ||
| executor = WorkflowExecutor() | ||
| workflow = executor.create_workflow("workflow_1", "Analysis Workflow") | ||
| # Add tasks | ||
| executor.add_task("workflow_1", "task_1", "researcher", "Research the topic") | ||
| executor.add_task("workflow_1", "task_2", "analyst", "Analyze findings", dependencies=["task_1"]) | ||
| # Execute | ||
| results = executor.execute_workflow("workflow_1", executor_func) | ||
| # Analyze workflow | ||
| analysis = WorkflowOptimizer.analyze_dependencies(workflow) | ||
| print(f"Critical path: {analysis['critical_path']}") | ||
| ``` | ||
| ### Benchmarking | ||
| ```python | ||
| from scripts.benchmarking import TeamBenchmark, AgentEffectiveness, CollaborationMetrics | ||
| # Benchmark team performance | ||
| benchmark = TeamBenchmark() | ||
| result = benchmark.run_benchmark("sequential_test", orchestrator, test_data) | ||
| # Track agent effectiveness | ||
| effectiveness = AgentEffectiveness() | ||
| effectiveness.record_agent_task("agent_a", "task_1", success=True, quality_score=0.95, duration=2.5) | ||
| # Get agent rankings | ||
| rankings = effectiveness.rank_agents() | ||
| for rank, agent, score, metrics in rankings: | ||
| print(f"{rank}. {agent}: {score:.2f}") | ||
| # Analyze collaboration | ||
| collaboration = CollaborationMetrics() | ||
| collaboration.record_interaction("agent_a", "agent_b", "request", response_time=0.5, successful=True) | ||
| interaction_metrics = collaboration.get_interaction_metrics() | ||
| ``` | ||
| ## Integration with SKILL.md | ||
| - SKILL.md contains conceptual information, orchestration patterns, and best practices | ||
| - Code examples are in `examples/` for clarity and runnable implementations | ||
| - Utilities are in `scripts/` for modular, reusable components | ||
| - This keeps token costs low while maintaining full functionality | ||
| ## Orchestration Patterns Covered | ||
| 1. **Sequential Orchestration** - Tasks execute one after another | ||
| 2. **Parallel Orchestration** - Multiple agents work simultaneously | ||
| 3. **Hierarchical Orchestration** - Manager coordinates specialist teams | ||
| 4. **Consensus-Based** - Agents debate and reach consensus | ||
| 5. **Adaptive Workflows** - Orchestration changes based on progress | ||
| 6. **DAG-Based** - Workflow as directed acyclic graph | ||
| ## Framework Implementations | ||
| - **CrewAI** - Clear roles, hierarchical structure | ||
| - **AutoGen** - Multi-turn conversations, group discussions | ||
| - **LangGraph** - State management, complex workflows | ||
| - **Swarm** - Simple handoffs, conversational workflows | ||
| ## Key Features | ||
| - **Token Efficient**: Modular code structure reduces LLM context usage | ||
| - **Production Ready**: Includes monitoring, optimization, and benchmarking | ||
| - **Framework Agnostic**: Works with any agent framework | ||
| - **Communication Patterns**: Direct, tool-mediated, and manager-based | ||
| - **Performance Metrics**: Team and individual agent effectiveness tracking | ||
| ## Communication Patterns | ||
| - **Direct Communication**: Agent-to-agent message passing | ||
| - **Tool-Mediated**: Agents use shared memory/database | ||
| - **Manager-Based**: Central coordinator manages communication | ||
| - **Broadcast**: One-to-many messaging | ||
| ## Next Steps | ||
| 1. Define agent roles and expertise | ||
| 2. Choose orchestration pattern (sequential, parallel, hierarchical) | ||
| 3. Select communication approach (direct, shared memory, manager) | ||
| 4. Implement workflow with task definitions | ||
| 5. Set up monitoring and metrics | ||
| 6. Benchmark and optimize | ||
| 7. Deploy and iterate |
| """ | ||
| Agent Communication Management | ||
| Handle agent-to-agent communication, message passing, and shared state. | ||
| """ | ||
| from typing import Dict, List, Optional, Any, Callable | ||
| from dataclasses import dataclass, field | ||
| from enum import Enum | ||
| import json | ||
| class MessageType(Enum): | ||
| """Types of messages between agents.""" | ||
| DIRECT = "direct" | ||
| BROADCAST = "broadcast" | ||
| REQUEST = "request" | ||
| RESPONSE = "response" | ||
| FEEDBACK = "feedback" | ||
| ERROR = "error" | ||
| @dataclass | ||
| class Message: | ||
| """Message between agents.""" | ||
| sender: str | ||
| recipient: str | ||
| content: str | ||
| message_type: MessageType | ||
| timestamp: float = field(default_factory=lambda: 0) | ||
| metadata: Dict[str, Any] = field(default_factory=dict) | ||
| def to_dict(self) -> Dict: | ||
| """Convert to dictionary.""" | ||
| return { | ||
| "sender": self.sender, | ||
| "recipient": self.recipient, | ||
| "content": self.content, | ||
| "type": self.message_type.value, | ||
| "timestamp": self.timestamp, | ||
| "metadata": self.metadata, | ||
| } | ||
| class MessageBroker: | ||
| """Central message broker for agent communication.""" | ||
| def __init__(self): | ||
| """Initialize message broker.""" | ||
| self.message_queue: List[Message] = [] | ||
| self.agent_inboxes: Dict[str, List[Message]] = {} | ||
| self.message_handlers: Dict[MessageType, List[Callable]] = {} | ||
| def send_message(self, message: Message) -> bool: | ||
| """ | ||
| Send message from one agent to another. | ||
| Args: | ||
| message: Message object | ||
| Returns: | ||
| Whether message was delivered | ||
| """ | ||
| self.message_queue.append(message) | ||
| # Add to recipient's inbox | ||
| if message.recipient not in self.agent_inboxes: | ||
| self.agent_inboxes[message.recipient] = [] | ||
| self.agent_inboxes[message.recipient].append(message) | ||
| # Trigger handlers | ||
| self._trigger_handlers(message) | ||
| return True | ||
| def broadcast_message(self, sender: str, content: str, recipients: List[str]): | ||
| """ | ||
| Broadcast message to multiple agents. | ||
| Args: | ||
| sender: Sending agent | ||
| content: Message content | ||
| recipients: List of recipient agents | ||
| """ | ||
| for recipient in recipients: | ||
| message = Message( | ||
| sender=sender, | ||
| recipient=recipient, | ||
| content=content, | ||
| message_type=MessageType.BROADCAST, | ||
| ) | ||
| self.send_message(message) | ||
| def request_response( | ||
| self, sender: str, recipient: str, content: str, timeout: float = 5.0 | ||
| ) -> Optional[Message]: | ||
| """ | ||
| Send request and wait for response. | ||
| Args: | ||
| sender: Requesting agent | ||
| recipient: Agent to respond | ||
| content: Request content | ||
| timeout: Response timeout in seconds | ||
| Returns: | ||
| Response message or None | ||
| """ | ||
| message = Message( | ||
| sender=sender, | ||
| recipient=recipient, | ||
| content=content, | ||
| message_type=MessageType.REQUEST, | ||
| metadata={"timeout": timeout}, | ||
| ) | ||
| self.send_message(message) | ||
| # Placeholder - wait for response | ||
| # In production, implement actual timeout/wait mechanism | ||
| return None | ||
| def get_inbox(self, agent: str) -> List[Message]: | ||
| """Get messages for specific agent.""" | ||
| return self.agent_inboxes.get(agent, []) | ||
| def clear_inbox(self, agent: str) -> None: | ||
| """Clear agent's inbox.""" | ||
| self.agent_inboxes[agent] = [] | ||
| def register_handler( | ||
| self, message_type: MessageType, handler: Callable | ||
| ) -> None: | ||
| """Register handler for message type.""" | ||
| if message_type not in self.message_handlers: | ||
| self.message_handlers[message_type] = [] | ||
| self.message_handlers[message_type].append(handler) | ||
| def _trigger_handlers(self, message: Message) -> None: | ||
| """Trigger registered handlers.""" | ||
| handlers = self.message_handlers.get(message.message_type, []) | ||
| for handler in handlers: | ||
| try: | ||
| handler(message) | ||
| except Exception: | ||
| pass | ||
| def get_statistics(self) -> Dict[str, Any]: | ||
| """Get communication statistics.""" | ||
| type_counts = {} | ||
| for message in self.message_queue: | ||
| msg_type = message.message_type.value | ||
| type_counts[msg_type] = type_counts.get(msg_type, 0) + 1 | ||
| return { | ||
| "total_messages": len(self.message_queue), | ||
| "by_type": type_counts, | ||
| "total_agents": len(self.agent_inboxes), | ||
| "agents": list(self.agent_inboxes.keys()), | ||
| } | ||
| class SharedMemory: | ||
| """Shared memory for tool-mediated agent communication.""" | ||
| def __init__(self): | ||
| """Initialize shared memory.""" | ||
| self.memory: Dict[str, Any] = {} | ||
| self.access_log: List[Dict] = [] | ||
| def write(self, key: str, value: Any, agent: str = "system") -> None: | ||
| """ | ||
| Write to shared memory. | ||
| Args: | ||
| key: Memory key | ||
| value: Value to store | ||
| agent: Agent writing | ||
| """ | ||
| self.memory[key] = { | ||
| "value": value, | ||
| "writer": agent, | ||
| "access_count": 0, | ||
| } | ||
| self.access_log.append({ | ||
| "action": "write", | ||
| "key": key, | ||
| "agent": agent, | ||
| }) | ||
| def read(self, key: str, agent: str = "system") -> Optional[Any]: | ||
| """ | ||
| Read from shared memory. | ||
| Args: | ||
| key: Memory key | ||
| agent: Agent reading | ||
| Returns: | ||
| Stored value or None | ||
| """ | ||
| if key in self.memory: | ||
| entry = self.memory[key] | ||
| entry["access_count"] += 1 | ||
| self.access_log.append({ | ||
| "action": "read", | ||
| "key": key, | ||
| "agent": agent, | ||
| }) | ||
| return entry["value"] | ||
| return None | ||
| def append(self, key: str, value: Any, agent: str = "system") -> None: | ||
| """Append to list in shared memory.""" | ||
| if key not in self.memory: | ||
| self.memory[key] = { | ||
| "value": [], | ||
| "writer": agent, | ||
| "access_count": 0, | ||
| } | ||
| if isinstance(self.memory[key]["value"], list): | ||
| self.memory[key]["value"].append(value) | ||
| def get_all(self) -> Dict[str, Any]: | ||
| """Get all shared memory contents.""" | ||
| return { | ||
| key: entry["value"] for key, entry in self.memory.items() | ||
| } | ||
| def get_statistics(self) -> Dict[str, Any]: | ||
| """Get memory access statistics.""" | ||
| total_accesses = sum( | ||
| entry["access_count"] for entry in self.memory.values() | ||
| ) | ||
| return { | ||
| "total_keys": len(self.memory), | ||
| "total_accesses": total_accesses, | ||
| "access_log_size": len(self.access_log), | ||
| } | ||
| class ContextManager: | ||
| """Manage context sharing between agents.""" | ||
| def __init__(self): | ||
| """Initialize context manager.""" | ||
| self.contexts: Dict[str, Dict[str, Any]] = {} | ||
| self.global_context: Dict[str, Any] = {} | ||
| def create_context(self, context_id: str, initial_data: Optional[Dict] = None) -> None: | ||
| """Create new context.""" | ||
| self.contexts[context_id] = initial_data or {} | ||
| def update_context(self, context_id: str, data: Dict) -> None: | ||
| """Update context data.""" | ||
| if context_id in self.contexts: | ||
| self.contexts[context_id].update(data) | ||
| def get_context(self, context_id: str) -> Dict[str, Any]: | ||
| """Get context data.""" | ||
| return self.contexts.get(context_id, {}) | ||
| def set_global_context(self, key: str, value: Any) -> None: | ||
| """Set global context variable.""" | ||
| self.global_context[key] = value | ||
| def get_global_context(self, key: str) -> Optional[Any]: | ||
| """Get global context variable.""" | ||
| return self.global_context.get(key) | ||
| def context_to_string(self, context_id: str) -> str: | ||
| """Convert context to formatted string.""" | ||
| context = self.get_context(context_id) | ||
| return json.dumps(context, indent=2) | ||
| class CommunicationProtocol: | ||
| """Define communication protocol between agents.""" | ||
| def __init__(self, broker: MessageBroker, shared_memory: SharedMemory): | ||
| """Initialize protocol.""" | ||
| self.broker = broker | ||
| self.shared_memory = shared_memory | ||
| def request_analysis( | ||
| self, requester: str, analyzer: str, subject: str | ||
| ) -> None: | ||
| """Request analysis from another agent.""" | ||
| message = Message( | ||
| sender=requester, | ||
| recipient=analyzer, | ||
| content=f"Analyze: {subject}", | ||
| message_type=MessageType.REQUEST, | ||
| metadata={"action": "analyze"}, | ||
| ) | ||
| self.broker.send_message(message) | ||
| def share_findings(self, source_agent: str, key: str, findings: Dict) -> None: | ||
| """Share findings through shared memory.""" | ||
| self.shared_memory.write(key, findings, source_agent) | ||
| def aggregate_results( | ||
| self, agents: List[str], result_key: str | ||
| ) -> Dict[str, Any]: | ||
| """Aggregate results from multiple agents.""" | ||
| results = {} | ||
| for agent in agents: | ||
| agent_results = self.shared_memory.read(f"{agent}_{result_key}") | ||
| if agent_results: | ||
| results[agent] = agent_results | ||
| return results | ||
| def notify_status(self, agent: str, status: str) -> None: | ||
| """Notify status update.""" | ||
| message = Message( | ||
| sender=agent, | ||
| recipient="orchestrator", | ||
| content=f"Status: {status}", | ||
| message_type=MessageType.FEEDBACK, | ||
| ) | ||
| self.broker.send_message(message) | ||
| def error_propagation(self, source_agent: str, error: str) -> None: | ||
| """Propagate error to relevant agents.""" | ||
| message = Message( | ||
| sender=source_agent, | ||
| recipient="orchestrator", | ||
| content=f"Error: {error}", | ||
| message_type=MessageType.ERROR, | ||
| ) | ||
| self.broker.send_message(message) |
| """ | ||
| Multi-Agent System Benchmarking | ||
| Evaluate team performance and agent effectiveness. | ||
| """ | ||
| from typing import Dict, List, Any, Callable, Optional | ||
| from dataclasses import dataclass | ||
| import time | ||
| import statistics | ||
| @dataclass | ||
| class BenchmarkResult: | ||
| """Result from benchmark run.""" | ||
| test_name: str | ||
| total_time: float | ||
| task_count: int | ||
| success_count: int | ||
| failure_count: int | ||
| quality_score: float | ||
| cost_tokens: int | ||
| class TeamBenchmark: | ||
| """Benchmark multi-agent team performance.""" | ||
| def __init__(self): | ||
| """Initialize benchmarking suite.""" | ||
| self.results: List[BenchmarkResult] = [] | ||
| self.agent_metrics: Dict[str, Dict] = {} | ||
| def run_benchmark( | ||
| self, | ||
| test_name: str, | ||
| orchestrator, | ||
| test_data: List[Dict], | ||
| quality_metric: Optional[Callable] = None, | ||
| ) -> BenchmarkResult: | ||
| """ | ||
| Run benchmark test. | ||
| Args: | ||
| test_name: Name of benchmark | ||
| orchestrator: Orchestrator instance | ||
| test_data: Test cases | ||
| quality_metric: Function to evaluate quality | ||
| Returns: | ||
| Benchmark result | ||
| """ | ||
| start_time = time.time() | ||
| results = [] | ||
| costs = [] | ||
| for test_case in test_data: | ||
| try: | ||
| result = orchestrator.execute(test_case) | ||
| results.append(result) | ||
| # Assume cost in test_case | ||
| costs.append(test_case.get("cost", 0)) | ||
| except Exception: | ||
| pass | ||
| end_time = time.time() | ||
| success_count = len(results) | ||
| failure_count = len(test_data) - success_count | ||
| total_time = end_time - start_time | ||
| # Calculate quality score | ||
| quality_score = ( | ||
| quality_metric(results) if quality_metric else success_count / len(test_data) | ||
| ) | ||
| benchmark_result = BenchmarkResult( | ||
| test_name=test_name, | ||
| total_time=total_time, | ||
| task_count=len(test_data), | ||
| success_count=success_count, | ||
| failure_count=failure_count, | ||
| quality_score=quality_score, | ||
| cost_tokens=sum(costs), | ||
| ) | ||
| self.results.append(benchmark_result) | ||
| return benchmark_result | ||
| def compare_orchestration_methods( | ||
| self, | ||
| methods: Dict[str, Callable], | ||
| test_data: List[Dict], | ||
| ) -> Dict[str, Any]: | ||
| """ | ||
| Compare different orchestration methods. | ||
| Args: | ||
| methods: Dict of method name to orchestrator | ||
| test_data: Test cases | ||
| Returns: | ||
| Comparison results | ||
| """ | ||
| comparison = {} | ||
| for method_name, orchestrator in methods.items(): | ||
| result = self.run_benchmark(method_name, orchestrator, test_data) | ||
| comparison[method_name] = { | ||
| "total_time": result.total_time, | ||
| "success_rate": result.success_count / result.task_count, | ||
| "quality_score": result.quality_score, | ||
| "efficiency": result.success_count / (result.total_time + 0.001), | ||
| "cost_per_success": ( | ||
| result.cost_tokens / result.success_count | ||
| if result.success_count > 0 | ||
| else float("inf") | ||
| ), | ||
| } | ||
| return comparison | ||
| def get_summary(self) -> Dict[str, Any]: | ||
| """Get benchmark summary.""" | ||
| if not self.results: | ||
| return {"status": "no_results"} | ||
| times = [r.total_time for r in self.results] | ||
| success_rates = [ | ||
| r.success_count / r.task_count for r in self.results | ||
| ] | ||
| quality_scores = [r.quality_score for r in self.results] | ||
| return { | ||
| "total_benchmarks": len(self.results), | ||
| "avg_time": statistics.mean(times), | ||
| "median_time": statistics.median(times), | ||
| "avg_success_rate": statistics.mean(success_rates), | ||
| "avg_quality": statistics.mean(quality_scores), | ||
| "benchmarks": [r.__dict__ for r in self.results], | ||
| } | ||
| class AgentEffectiveness: | ||
| """Measure individual agent effectiveness.""" | ||
| def __init__(self): | ||
| """Initialize effectiveness tracker.""" | ||
| self.agent_stats: Dict[str, Dict] = {} | ||
| def record_agent_task( | ||
| self, | ||
| agent: str, | ||
| task_id: str, | ||
| success: bool, | ||
| quality_score: float, | ||
| duration: float, | ||
| ) -> None: | ||
| """Record agent task execution.""" | ||
| if agent not in self.agent_stats: | ||
| self.agent_stats[agent] = { | ||
| "tasks": [], | ||
| "successes": 0, | ||
| "failures": 0, | ||
| } | ||
| stats = self.agent_stats[agent] | ||
| stats["tasks"].append({ | ||
| "task_id": task_id, | ||
| "success": success, | ||
| "quality": quality_score, | ||
| "duration": duration, | ||
| }) | ||
| if success: | ||
| stats["successes"] += 1 | ||
| else: | ||
| stats["failures"] += 1 | ||
| def get_agent_metrics(self, agent: str) -> Dict[str, Any]: | ||
| """Get metrics for specific agent.""" | ||
| if agent not in self.agent_stats: | ||
| return {"status": "no_data"} | ||
| stats = self.agent_stats[agent] | ||
| tasks = stats["tasks"] | ||
| if not tasks: | ||
| return {"status": "no_tasks"} | ||
| success_rate = stats["successes"] / (stats["successes"] + stats["failures"]) | ||
| quality_scores = [t["quality"] for t in tasks] | ||
| durations = [t["duration"] for t in tasks] | ||
| return { | ||
| "agent": agent, | ||
| "total_tasks": len(tasks), | ||
| "success_rate": success_rate, | ||
| "avg_quality": statistics.mean(quality_scores), | ||
| "avg_duration": statistics.mean(durations), | ||
| "reliability": success_rate, # Alias for clarity | ||
| } | ||
| def rank_agents(self) -> List[tuple]: | ||
| """Rank agents by effectiveness.""" | ||
| rankings = [] | ||
| for agent in self.agent_stats.keys(): | ||
| metrics = self.get_agent_metrics(agent) | ||
| if "success_rate" in metrics: | ||
| score = ( | ||
| metrics["success_rate"] * 0.4 + | ||
| metrics["avg_quality"] * 0.4 + | ||
| (1 - min(metrics["avg_duration"] / 10.0, 1.0)) * 0.2 | ||
| ) | ||
| rankings.append((agent, score, metrics)) | ||
| rankings.sort(key=lambda x: x[1], reverse=True) | ||
| return rankings | ||
| def get_team_report(self) -> Dict[str, Any]: | ||
| """Get team effectiveness report.""" | ||
| rankings = self.rank_agents() | ||
| return { | ||
| "total_agents": len(self.agent_stats), | ||
| "rankings": [ | ||
| { | ||
| "rank": i + 1, | ||
| "agent": agent, | ||
| "score": score, | ||
| "metrics": metrics, | ||
| } | ||
| for i, (agent, score, metrics) in enumerate(rankings) | ||
| ], | ||
| } | ||
| class CollaborationMetrics: | ||
| """Measure collaboration effectiveness between agents.""" | ||
| def __init__(self): | ||
| """Initialize collaboration metrics.""" | ||
| self.interactions: List[Dict] = [] | ||
| def record_interaction( | ||
| self, | ||
| agent_a: str, | ||
| agent_b: str, | ||
| message: str, | ||
| response_time: float, | ||
| successful: bool, | ||
| ) -> None: | ||
| """Record agent-to-agent interaction.""" | ||
| self.interactions.append({ | ||
| "agent_a": agent_a, | ||
| "agent_b": agent_b, | ||
| "message": message, | ||
| "response_time": response_time, | ||
| "successful": successful, | ||
| }) | ||
| def get_collaboration_graph(self) -> Dict[str, List[str]]: | ||
| """Get collaboration graph between agents.""" | ||
| graph = {} | ||
| for interaction in self.interactions: | ||
| agent_a = interaction["agent_a"] | ||
| agent_b = interaction["agent_b"] | ||
| if agent_a not in graph: | ||
| graph[agent_a] = [] | ||
| if agent_b not in graph[agent_a]: | ||
| graph[agent_a].append(agent_b) | ||
| return graph | ||
| def get_interaction_metrics(self) -> Dict[str, Any]: | ||
| """Get interaction metrics.""" | ||
| if not self.interactions: | ||
| return {"total_interactions": 0} | ||
| response_times = [i["response_time"] for i in self.interactions] | ||
| success_rate = sum(1 for i in self.interactions if i["successful"]) / len( | ||
| self.interactions | ||
| ) | ||
| return { | ||
| "total_interactions": len(self.interactions), | ||
| "success_rate": success_rate, | ||
| "avg_response_time": statistics.mean(response_times), | ||
| "median_response_time": statistics.median(response_times), | ||
| "max_response_time": max(response_times), | ||
| "collaboration_score": success_rate * (1 - min(statistics.mean(response_times) / 10.0, 1.0)), | ||
| } | ||
| def get_agent_collaboration_analysis(self, agent: str) -> Dict[str, Any]: | ||
| """Get collaboration analysis for specific agent.""" | ||
| agent_interactions = [ | ||
| i for i in self.interactions | ||
| if i["agent_a"] == agent or i["agent_b"] == agent | ||
| ] | ||
| if not agent_interactions: | ||
| return {"agent": agent, "status": "no_interactions"} | ||
| partners = set() | ||
| for interaction in agent_interactions: | ||
| if interaction["agent_a"] == agent: | ||
| partners.add(interaction["agent_b"]) | ||
| else: | ||
| partners.add(interaction["agent_a"]) | ||
| success_rate = sum( | ||
| 1 for i in agent_interactions if i["successful"] | ||
| ) / len(agent_interactions) | ||
| return { | ||
| "agent": agent, | ||
| "collaboration_partners": list(partners), | ||
| "total_interactions": len(agent_interactions), | ||
| "collaboration_success_rate": success_rate, | ||
| } | ||
| def create_benchmark_suite() -> Dict[str, Callable]: | ||
| """Create standard benchmark suite.""" | ||
| return { | ||
| "sequential_tasks": lambda orchestrator: orchestrator.execute( | ||
| {"type": "sequential", "task_count": 5} | ||
| ), | ||
| "parallel_tasks": lambda orchestrator: orchestrator.execute( | ||
| {"type": "parallel", "task_count": 10} | ||
| ), | ||
| "complex_workflow": lambda orchestrator: orchestrator.execute( | ||
| {"type": "complex", "task_count": 20} | ||
| ), | ||
| "error_handling": lambda orchestrator: orchestrator.execute( | ||
| {"type": "with_errors", "task_count": 10} | ||
| ), | ||
| } |
| """ | ||
| Workflow Management for Multi-Agent Systems | ||
| Handle workflow execution, monitoring, and optimization. | ||
| """ | ||
| from typing import Dict, List, Any, Optional, Callable | ||
| from enum import Enum | ||
| from dataclasses import dataclass, field | ||
| import time | ||
| class WorkflowStatus(Enum): | ||
| """Workflow execution status.""" | ||
| PENDING = "pending" | ||
| RUNNING = "running" | ||
| PAUSED = "paused" | ||
| COMPLETED = "completed" | ||
| FAILED = "failed" | ||
| class TaskStatus(Enum): | ||
| """Task execution status.""" | ||
| PENDING = "pending" | ||
| RUNNING = "running" | ||
| COMPLETED = "completed" | ||
| FAILED = "failed" | ||
| SKIPPED = "skipped" | ||
| @dataclass | ||
| class Task: | ||
| """Task to be executed by an agent.""" | ||
| task_id: str | ||
| agent: str | ||
| description: str | ||
| status: TaskStatus = TaskStatus.PENDING | ||
| result: Optional[str] = None | ||
| error: Optional[str] = None | ||
| start_time: float = field(default_factory=time.time) | ||
| end_time: Optional[float] = None | ||
| dependencies: List[str] = field(default_factory=list) | ||
| @dataclass | ||
| class Workflow: | ||
| """Workflow orchestration.""" | ||
| workflow_id: str | ||
| name: str | ||
| tasks: Dict[str, Task] = field(default_factory=dict) | ||
| status: WorkflowStatus = WorkflowStatus.PENDING | ||
| start_time: Optional[float] = None | ||
| end_time: Optional[float] = None | ||
| class WorkflowExecutor: | ||
| """Execute workflows with multiple agents.""" | ||
| def __init__(self): | ||
| """Initialize workflow executor.""" | ||
| self.workflows: Dict[str, Workflow] = {} | ||
| self.execution_history: List[Dict] = [] | ||
| def create_workflow(self, workflow_id: str, name: str) -> Workflow: | ||
| """Create new workflow.""" | ||
| workflow = Workflow(workflow_id=workflow_id, name=name) | ||
| self.workflows[workflow_id] = workflow | ||
| return workflow | ||
| def add_task( | ||
| self, | ||
| workflow_id: str, | ||
| task_id: str, | ||
| agent: str, | ||
| description: str, | ||
| dependencies: Optional[List[str]] = None, | ||
| ) -> Task: | ||
| """Add task to workflow.""" | ||
| task = Task( | ||
| task_id=task_id, | ||
| agent=agent, | ||
| description=description, | ||
| dependencies=dependencies or [], | ||
| ) | ||
| self.workflows[workflow_id].tasks[task_id] = task | ||
| return task | ||
| def execute_workflow( | ||
| self, workflow_id: str, executor_func: Callable | ||
| ) -> Dict[str, Any]: | ||
| """ | ||
| Execute workflow. | ||
| Args: | ||
| workflow_id: Workflow ID | ||
| executor_func: Function to execute tasks | ||
| Returns: | ||
| Execution results | ||
| """ | ||
| workflow = self.workflows[workflow_id] | ||
| workflow.status = WorkflowStatus.RUNNING | ||
| workflow.start_time = time.time() | ||
| executed_tasks = set() | ||
| results = {} | ||
| while len(executed_tasks) < len(workflow.tasks): | ||
| # Find ready tasks | ||
| ready_tasks = self._get_ready_tasks(workflow, executed_tasks) | ||
| if not ready_tasks: | ||
| # Check if workflow is stuck | ||
| if len(executed_tasks) > 0: | ||
| break | ||
| for task_id in ready_tasks: | ||
| task = workflow.tasks[task_id] | ||
| task.status = TaskStatus.RUNNING | ||
| try: | ||
| # Execute task | ||
| result = executor_func(task) | ||
| task.result = result | ||
| task.status = TaskStatus.COMPLETED | ||
| results[task_id] = result | ||
| except Exception as e: | ||
| task.error = str(e) | ||
| task.status = TaskStatus.FAILED | ||
| results[task_id] = None | ||
| task.end_time = time.time() | ||
| executed_tasks.add(task_id) | ||
| # Finalize workflow | ||
| workflow.end_time = time.time() | ||
| if all(task.status == TaskStatus.COMPLETED for task in workflow.tasks.values()): | ||
| workflow.status = WorkflowStatus.COMPLETED | ||
| else: | ||
| workflow.status = WorkflowStatus.FAILED | ||
| execution_record = { | ||
| "workflow_id": workflow_id, | ||
| "status": workflow.status.value, | ||
| "duration": workflow.end_time - workflow.start_time, | ||
| "results": results, | ||
| } | ||
| self.execution_history.append(execution_record) | ||
| return results | ||
| def _get_ready_tasks( | ||
| self, workflow: Workflow, executed: set | ||
| ) -> List[str]: | ||
| """Get tasks ready to execute.""" | ||
| ready = [] | ||
| for task_id, task in workflow.tasks.items(): | ||
| if task_id not in executed and task.status == TaskStatus.PENDING: | ||
| # Check if all dependencies are complete | ||
| deps_met = all(dep in executed for dep in task.dependencies) | ||
| if deps_met: | ||
| ready.append(task_id) | ||
| return ready | ||
| def get_workflow_status(self, workflow_id: str) -> Dict[str, Any]: | ||
| """Get workflow status.""" | ||
| workflow = self.workflows[workflow_id] | ||
| return { | ||
| "id": workflow.workflow_id, | ||
| "name": workflow.name, | ||
| "status": workflow.status.value, | ||
| "tasks": { | ||
| task_id: task.status.value | ||
| for task_id, task in workflow.tasks.items() | ||
| }, | ||
| } | ||
| class WorkflowOptimizer: | ||
| """Optimize workflow execution.""" | ||
| @staticmethod | ||
| def analyze_dependencies(workflow: Workflow) -> Dict[str, Any]: | ||
| """Analyze task dependencies.""" | ||
| dep_graph = {} | ||
| for task_id, task in workflow.tasks.items(): | ||
| dep_graph[task_id] = task.dependencies | ||
| # Find critical path | ||
| critical_path = WorkflowOptimizer._find_critical_path( | ||
| dep_graph, workflow.tasks | ||
| ) | ||
| # Find parallelizable tasks | ||
| parallel_groups = WorkflowOptimizer._find_parallel_groups(dep_graph) | ||
| return { | ||
| "dependency_graph": dep_graph, | ||
| "critical_path": critical_path, | ||
| "parallelizable_groups": parallel_groups, | ||
| } | ||
| @staticmethod | ||
| def _find_critical_path(dep_graph: Dict, tasks: Dict) -> List[str]: | ||
| """Find tasks on critical path.""" | ||
| # Simple implementation - actual critical path is more complex | ||
| return list(dep_graph.keys()) | ||
| @staticmethod | ||
| def _find_parallel_groups(dep_graph: Dict) -> List[List[str]]: | ||
| """Find groups of tasks that can execute in parallel.""" | ||
| groups = [] | ||
| remaining = set(dep_graph.keys()) | ||
| while remaining: | ||
| # Find tasks with no dependencies in remaining set | ||
| independent = [ | ||
| task | ||
| for task in remaining | ||
| if not any(dep in remaining for dep in dep_graph.get(task, [])) | ||
| ] | ||
| if independent: | ||
| groups.append(independent) | ||
| remaining -= set(independent) | ||
| else: | ||
| break | ||
| return groups | ||
| @staticmethod | ||
| def estimate_execution_time( | ||
| workflow: Workflow, task_times: Dict[str, float] | ||
| ) -> float: | ||
| """Estimate total execution time.""" | ||
| parallel_groups = WorkflowOptimizer._find_parallel_groups({ | ||
| task_id: task.dependencies | ||
| for task_id, task in workflow.tasks.items() | ||
| }) | ||
| total_time = 0 | ||
| for group in parallel_groups: | ||
| group_time = max( | ||
| task_times.get(task_id, 1.0) for task_id in group | ||
| ) | ||
| total_time += group_time | ||
| return total_time | ||
| @staticmethod | ||
| def suggest_parallelization(workflow: Workflow) -> List[Dict[str, Any]]: | ||
| """Suggest ways to parallelize workflow.""" | ||
| suggestions = [] | ||
| dep_graph = { | ||
| task_id: task.dependencies | ||
| for task_id, task in workflow.tasks.items() | ||
| } | ||
| # Find sequential chains that could be parallelized | ||
| for task_id, dependencies in dep_graph.items(): | ||
| if len(dependencies) == 0: | ||
| suggestions.append({ | ||
| "task": task_id, | ||
| "suggestion": "Can be parallelized with other independent tasks", | ||
| }) | ||
| return suggestions | ||
| class WorkflowMonitor: | ||
| """Monitor workflow execution.""" | ||
| def __init__(self): | ||
| """Initialize monitor.""" | ||
| self.events: List[Dict] = [] | ||
| def record_event( | ||
| self, workflow_id: str, task_id: str, event_type: str, data: Dict | ||
| ) -> None: | ||
| """Record workflow event.""" | ||
| event = { | ||
| "workflow_id": workflow_id, | ||
| "task_id": task_id, | ||
| "event_type": event_type, | ||
| "timestamp": time.time(), | ||
| "data": data, | ||
| } | ||
| self.events.append(event) | ||
| def get_workflow_metrics(self, workflow_id: str) -> Dict[str, Any]: | ||
| """Get workflow metrics.""" | ||
| workflow_events = [e for e in self.events if e["workflow_id"] == workflow_id] | ||
| task_times = {} | ||
| for event in workflow_events: | ||
| task_id = event["task_id"] | ||
| if event["event_type"] == "start": | ||
| task_times[task_id] = {"start": event["timestamp"]} | ||
| elif event["event_type"] == "complete": | ||
| if task_id in task_times: | ||
| task_times[task_id]["end"] = event["timestamp"] | ||
| # Calculate durations | ||
| durations = { | ||
| task_id: times.get("end", time.time()) - times["start"] | ||
| for task_id, times in task_times.items() | ||
| } | ||
| return { | ||
| "total_tasks": len(task_times), | ||
| "task_durations": durations, | ||
| "avg_duration": sum(durations.values()) / len(durations) | ||
| if durations | ||
| else 0, | ||
| "max_duration": max(durations.values()) if durations else 0, | ||
| } | ||
| def get_performance_report(self) -> Dict[str, Any]: | ||
| """Get overall performance report.""" | ||
| if not self.events: | ||
| return {"status": "no_events"} | ||
| workflow_ids = set(e["workflow_id"] for e in self.events) | ||
| report = {} | ||
| for workflow_id in workflow_ids: | ||
| report[workflow_id] = self.get_workflow_metrics(workflow_id) | ||
| return report |
| --- | ||
| name: multi-agent-orchestration | ||
| description: Design and coordinate multi-agent systems where specialized agents work together to solve complex problems. Covers agent communication, task delegation, workflow orchestration, and result aggregation. Use when building coordinated agent teams, complex workflows, or systems requiring specialized expertise across domains. | ||
| --- | ||
| # Multi-Agent Orchestration | ||
| Design and orchestrate sophisticated multi-agent systems where specialized agents collaborate to solve complex problems, combining different expertise and perspectives. | ||
| ## Quick Start | ||
| Get started with multi-agent implementations in the examples and utilities: | ||
| - **Examples**: See [`examples/`](examples/) directory for complete implementations: | ||
| - [`orchestration_patterns.py`](examples/orchestration_patterns.py) - Sequential, parallel, hierarchical, and consensus orchestration | ||
| - [`framework_implementations.py`](examples/framework_implementations.py) - Templates for CrewAI, AutoGen, LangGraph, and Swarm | ||
| - **Utilities**: See [`scripts/`](scripts/) directory for helper modules: | ||
| - [`agent_communication.py`](scripts/agent_communication.py) - Message broker, shared memory, and communication protocols | ||
| - [`workflow_management.py`](scripts/workflow_management.py) - Workflow execution, optimization, and monitoring | ||
| - [`benchmarking.py`](scripts/benchmarking.py) - Team performance and agent effectiveness metrics | ||
| ## Overview | ||
| Multi-agent systems decompose complex problems into specialized sub-tasks, assigning each to an agent with relevant expertise, then coordinating their work toward a unified goal. | ||
| ### When Multi-Agent Systems Shine | ||
| - **Complex Workflows**: Tasks requiring multiple specialized roles | ||
| - **Domain-Specific Expertise**: Finance, legal, HR, engineering need different knowledge | ||
| - **Parallel Processing**: Multiple agents work on different aspects simultaneously | ||
| - **Collaborative Reasoning**: Agents debate, refine, and improve solutions | ||
| - **Resilience**: Failures in one agent don't break the entire system | ||
| - **Scalability**: Easy to add new specialized agents | ||
| ### Architecture Overview | ||
| ``` | ||
| User Request | ||
| ↓ | ||
| Orchestrator | ||
| ├→ Agent 1 (Specialist) → Task 1 | ||
| ├→ Agent 2 (Specialist) → Task 2 | ||
| ├→ Agent 3 (Specialist) → Task 3 | ||
| ↓ | ||
| Result Aggregator | ||
| ↓ | ||
| Final Response | ||
| ``` | ||
| ## Core Concepts | ||
| ### Agent Definition | ||
| An agent is defined by: | ||
| - **Role**: What responsibility does it have? (e.g., "Financial Analyst") | ||
| - **Goal**: What should it accomplish? (e.g., "Analyze financial risks") | ||
| - **Expertise**: What knowledge/tools does it have? | ||
| - **Tools**: What capabilities can it access? | ||
| - **Context**: What information does it need to work effectively? | ||
| ### Orchestration Patterns | ||
| #### 1. Sequential Orchestration | ||
| - Agents work one after another | ||
| - Each agent uses output from previous agent | ||
| - **Use Case**: Steps must follow order (research → analysis → writing) | ||
| #### 2. Parallel Orchestration | ||
| - Multiple agents work simultaneously | ||
| - Results aggregated at the end | ||
| - **Use Case**: Independent tasks (analyze competitors, market, users) | ||
| #### 3. Hierarchical Orchestration | ||
| - Senior agent delegates to junior agents | ||
| - Manager coordinates flow | ||
| - **Use Case**: Large projects with oversight | ||
| #### 4. Consensus-Based Orchestration | ||
| - Multiple agents analyze problem | ||
| - Debate and refine ideas | ||
| - Vote or reach consensus | ||
| - **Use Case**: Complex decisions needing multiple perspectives | ||
| #### 5. Tool-Mediated Orchestration | ||
| - Agents use shared tools/databases | ||
| - Minimal direct communication | ||
| - **Use Case**: Large systems, indirect coordination | ||
| ## Multi-Agent Team Examples | ||
| ### Finance Team | ||
| ``` | ||
| Coordinator Agent | ||
| ├→ Market Analyst Agent | ||
| │ ├ Tools: Market data API, financial news | ||
| │ └ Task: Analyze market conditions | ||
| ├→ Financial Analyst Agent | ||
| │ ├ Tools: Financial statements, ratio calculations | ||
| │ └ Task: Analyze company financials | ||
| ├→ Risk Manager Agent | ||
| │ ├ Tools: Risk models, scenario analysis | ||
| │ └ Task: Assess investment risks | ||
| └→ Report Writer Agent | ||
| ├ Tools: Document generation | ||
| └ Task: Synthesize findings into report | ||
| ``` | ||
| ### Legal Team | ||
| ``` | ||
| Case Manager Agent (Coordinator) | ||
| ├→ Contract Analyzer Agent | ||
| │ └ Task: Review contract terms | ||
| ├→ Precedent Research Agent | ||
| │ └ Task: Find relevant case law | ||
| ├→ Risk Assessor Agent | ||
| │ └ Task: Identify legal risks | ||
| └→ Document Drafter Agent | ||
| └ Task: Prepare legal documents | ||
| ``` | ||
| ### Customer Support Team | ||
| ``` | ||
| Support Coordinator | ||
| ├→ Issue Classifier Agent | ||
| │ └ Task: Categorize customer issue | ||
| ├→ Knowledge Base Agent | ||
| │ └ Task: Find relevant documentation | ||
| ├→ Escalation Agent | ||
| │ └ Task: Determine if human escalation needed | ||
| └→ Solution Synthesizer Agent | ||
| └ Task: Prepare comprehensive response | ||
| ``` | ||
| ## Implementation Frameworks | ||
| ### 1. CrewAI | ||
| **Best For**: Teams with clear roles and hierarchical structure | ||
| ```python | ||
| from crewai import Agent, Task, Crew | ||
| # Define agents | ||
| analyst = Agent( | ||
| role="Financial Analyst", | ||
| goal="Analyze financial data and provide insights", | ||
| backstory="Expert in financial markets with 10+ years experience" | ||
| ) | ||
| researcher = Agent( | ||
| role="Market Researcher", | ||
| goal="Research market trends and competition", | ||
| backstory="Data-driven researcher specializing in market analysis" | ||
| ) | ||
| # Define tasks | ||
| analysis_task = Task( | ||
| description="Analyze Q3 financial results for {company}", | ||
| agent=analyst, | ||
| tools=[financial_tool, data_tool] | ||
| ) | ||
| research_task = Task( | ||
| description="Research competitive landscape in {market}", | ||
| agent=researcher, | ||
| tools=[web_search_tool, industry_data_tool] | ||
| ) | ||
| # Create crew and execute | ||
| crew = Crew( | ||
| agents=[analyst, researcher], | ||
| tasks=[analysis_task, research_task], | ||
| process=Process.sequential | ||
| ) | ||
| result = crew.kickoff(inputs={"company": "TechCorp", "market": "AI"}) | ||
| ``` | ||
| ### 2. AutoGen (Microsoft) | ||
| **Best For**: Complex multi-turn conversations and negotiations | ||
| ```python | ||
| from autogen import AssistantAgent, UserProxyAgent, GroupChat, GroupChatManager | ||
| # Define agents | ||
| analyst = AssistantAgent( | ||
| name="analyst", | ||
| system_message="You are a financial analyst..." | ||
| ) | ||
| researcher = AssistantAgent( | ||
| name="researcher", | ||
| system_message="You are a market researcher..." | ||
| ) | ||
| # Create group chat | ||
| groupchat = GroupChat( | ||
| agents=[analyst, researcher], | ||
| messages=[], | ||
| max_round=10, | ||
| speaker_selection_method="auto" | ||
| ) | ||
| # Manage group conversation | ||
| manager = GroupChatManager(groupchat=groupchat) | ||
| # User proxy to initiate conversation | ||
| user = UserProxyAgent(name="user") | ||
| # Have conversation | ||
| user.initiate_chat( | ||
| manager, | ||
| message="Analyze if Company X should invest in Y market" | ||
| ) | ||
| ``` | ||
| ### 3. LangGraph | ||
| **Best For**: Complex workflows with state management | ||
| ```python | ||
| from langgraph.graph import Graph, StateGraph | ||
| from langgraph.prebuilt import create_agent_executor | ||
| # Define state | ||
| class AgentState: | ||
| research_findings: str | ||
| analysis: str | ||
| recommendations: str | ||
| # Create graph | ||
| graph = StateGraph(AgentState) | ||
| # Add nodes for each agent | ||
| graph.add_node("researcher", research_agent) | ||
| graph.add_node("analyst", analyst_agent) | ||
| graph.add_node("writer", writer_agent) | ||
| # Define edges (workflow) | ||
| graph.add_edge("researcher", "analyst") | ||
| graph.add_edge("analyst", "writer") | ||
| # Set entry/exit points | ||
| graph.set_entry_point("researcher") | ||
| graph.set_finish_point("writer") | ||
| # Compile and run | ||
| workflow = graph.compile() | ||
| result = workflow.invoke({"topic": "AI trends"}) | ||
| ``` | ||
| ### 4. OpenAI Swarm | ||
| **Best For**: Simple agent handoffs and conversational workflows | ||
| ```python | ||
| from swarm import Agent, Swarm | ||
| # Define agents | ||
| triage_agent = Agent( | ||
| name="Triage Agent", | ||
| instructions="Determine which specialist to route the customer to" | ||
| ) | ||
| billing_agent = Agent( | ||
| name="Billing Specialist", | ||
| instructions="Handle billing and payment questions" | ||
| ) | ||
| technical_agent = Agent( | ||
| name="Technical Support", | ||
| instructions="Handle technical issues" | ||
| ) | ||
| # Define handoff functions | ||
| def route_to_billing(reason: str): | ||
| return billing_agent | ||
| def route_to_technical(reason: str): | ||
| return technical_agent | ||
| # Add tools to triage agent | ||
| triage_agent.functions = [route_to_billing, route_to_technical] | ||
| # Execute swarm | ||
| client = Swarm() | ||
| response = client.run( | ||
| agent=triage_agent, | ||
| messages=[{"role": "user", "content": "I have a billing question"}] | ||
| ) | ||
| ``` | ||
| ## Orchestration Patterns | ||
| ### Pattern 1: Sequential Task Chain | ||
| Agents execute tasks in sequence, each building on previous results: | ||
| ```python | ||
| # Task 1: Research | ||
| research_output = research_agent.work("Analyze AI market trends") | ||
| # Task 2: Analysis (uses research output) | ||
| analysis = analyst_agent.work(f"Analyze these findings: {research_output}") | ||
| # Task 3: Report (uses analysis) | ||
| report = writer_agent.work(f"Write report on: {analysis}") | ||
| ``` | ||
| **When to Use**: Steps have dependencies, each builds on previous | ||
| ### Pattern 2: Parallel Execution | ||
| Multiple agents work simultaneously, results combined: | ||
| ```python | ||
| import asyncio | ||
| async def parallel_teams(): | ||
| # All agents work in parallel | ||
| market_task = market_agent.work_async("Analyze market") | ||
| technical_task = tech_agent.work_async("Analyze technology") | ||
| user_task = user_agent.work_async("Analyze user needs") | ||
| # Wait for all to complete | ||
| market_results, tech_results, user_results = await asyncio.gather( | ||
| market_task, technical_task, user_task | ||
| ) | ||
| # Synthesize results | ||
| return synthesize(market_results, tech_results, user_results) | ||
| ``` | ||
| **When to Use**: Independent analyses, need quick results, want diversity | ||
| ### Pattern 3: Hierarchical Structure | ||
| Manager agent coordinates specialists: | ||
| ```python | ||
| manager_agent.orchestrate({ | ||
| "market_analysis": { | ||
| "agents": [competitor_analyst, trend_analyst], | ||
| "task": "Comprehensive market analysis" | ||
| }, | ||
| "technical_evaluation": { | ||
| "agents": [architecture_agent, security_agent], | ||
| "task": "Technical feasibility assessment" | ||
| }, | ||
| "synthesis": { | ||
| "agents": [strategy_agent], | ||
| "task": "Create strategic recommendations" | ||
| } | ||
| }) | ||
| ``` | ||
| **When to Use**: Clear hierarchy, different teams, complex coordination | ||
| ### Pattern 4: Debate & Consensus | ||
| Multiple agents discuss and reach consensus: | ||
| ```python | ||
| agents = [bull_agent, bear_agent, neutral_agent] | ||
| question = "Should we invest in this startup?" | ||
| # Debate round 1 | ||
| arguments = {agent: agent.argue(question) for agent in agents} | ||
| # Debate round 2 (respond to others) | ||
| counter_arguments = { | ||
| agent: agent.respond(arguments) for agent in agents | ||
| } | ||
| # Reach consensus | ||
| consensus = mediator_agent.synthesize_consensus(counter_arguments) | ||
| ``` | ||
| **When to Use**: Complex decisions, need multiple perspectives, risk assessment | ||
| ## Agent Communication Patterns | ||
| ### 1. Direct Communication | ||
| Agents pass messages directly to each other: | ||
| ```python | ||
| agent_a.send_message(agent_b, { | ||
| "type": "request", | ||
| "action": "analyze_document", | ||
| "document": doc_content, | ||
| "context": {"deadline": "urgent"} | ||
| }) | ||
| ``` | ||
| ### 2. Tool-Mediated Communication | ||
| Agents use shared tools/databases: | ||
| ```python | ||
| # Agent A writes to shared memory | ||
| shared_memory.write("findings", {"market_size": "$5B", "growth": "20%"}) | ||
| # Agent B reads from shared memory | ||
| findings = shared_memory.read("findings") | ||
| ``` | ||
| ### 3. Manager-Based Communication | ||
| Central coordinator manages agent communication: | ||
| ```python | ||
| manager.broadcast("update_all_agents", { | ||
| "new_deadline": "tomorrow", | ||
| "priority": "critical" | ||
| }) | ||
| ``` | ||
| ## Best Practices | ||
| ### Agent Design | ||
| - ✓ Clear, specific role and goal | ||
| - ✓ Appropriate tools for the role | ||
| - ✓ Relevant background/expertise | ||
| - ✓ Distinct from other agents | ||
| - ✓ Reasonable scope of work | ||
| ### Workflow Design | ||
| - ✓ Clear task dependencies | ||
| - ✓ Identified handoff points | ||
| - ✓ Error handling between agents | ||
| - ✓ Fallback strategies | ||
| - ✓ Performance monitoring | ||
| ### Communication | ||
| - ✓ Structured message formats | ||
| - ✓ Clear context sharing | ||
| - ✓ Error propagation strategy | ||
| - ✓ Timeout handling | ||
| - ✓ Audit logging | ||
| ### Orchestration | ||
| - ✓ Define process clearly (sequential, parallel, etc.) | ||
| - ✓ Set clear success criteria | ||
| - ✓ Monitor agent performance | ||
| - ✓ Implement feedback loops | ||
| - ✓ Allow human intervention points | ||
| ## Common Challenges & Solutions | ||
| ### Challenge: Agent Conflicts | ||
| **Solutions**: | ||
| - Clear role separation | ||
| - Explicit decision-making rules | ||
| - Consensus mechanisms | ||
| - Conflict resolution agent | ||
| - Clear authority hierarchy | ||
| ### Challenge: Slow Execution | ||
| **Solutions**: | ||
| - Use parallel execution where possible | ||
| - Cache results from expensive operations | ||
| - Pre-process data | ||
| - Optimize agent logic | ||
| - Implement timeout handling | ||
| ### Challenge: Poor Quality Results | ||
| **Solutions**: | ||
| - Better agent prompts/instructions | ||
| - More relevant tools | ||
| - Feedback integration | ||
| - Quality validation agents | ||
| - Result aggregation strategies | ||
| ### Challenge: Complex Workflows | ||
| **Solutions**: | ||
| - Break into smaller teams | ||
| - Hierarchical structure | ||
| - Clear task definitions | ||
| - Good state management | ||
| - Documentation of workflow | ||
| ## Evaluation Metrics | ||
| **Team Performance**: | ||
| - Task completion rate | ||
| - Quality of results | ||
| - Execution time | ||
| - Cost (tokens/API calls) | ||
| - Error rate | ||
| **Agent Effectiveness**: | ||
| - Task success rate | ||
| - Response quality | ||
| - Tool usage efficiency | ||
| - Communication clarity | ||
| - Collaboration score | ||
| ## Advanced Techniques | ||
| ### 1. Self-Organizing Teams | ||
| Agents autonomously decide roles and workflow: | ||
| ```python | ||
| # Agents negotiate roles based on task | ||
| agents = [agent1, agent2, agent3] | ||
| task = "complex financial analysis" | ||
| # Agents determine best structure | ||
| negotiated_structure = self_organize(agents, task) | ||
| # Returns optimal workflow for this task | ||
| ``` | ||
| ### 2. Adaptive Workflows | ||
| Workflow changes based on progress: | ||
| ```python | ||
| # Monitor progress | ||
| if progress < expected_rate: | ||
| # Increase resources | ||
| workflow.add_agent(specialist_agent) | ||
| elif quality < threshold: | ||
| # Increase validation | ||
| workflow.insert_review_step() | ||
| ``` | ||
| ### 3. Cross-Agent Learning | ||
| Agents learn from each other's work: | ||
| ```python | ||
| # After team execution | ||
| execution_trace = crew.get_execution_trace() | ||
| # Extract learnings | ||
| learnings = extract_patterns(execution_trace) | ||
| # Update agent knowledge | ||
| for agent, learning in learnings.items(): | ||
| agent.update_knowledge(learning) | ||
| ``` | ||
| ## Resources | ||
| ### Frameworks | ||
| - **CrewAI**: https://crewai.com/ | ||
| - **AutoGen**: https://microsoft.github.io/autogen/ | ||
| - **LangGraph**: https://langchain-ai.github.io/langgraph/ | ||
| - **Swarm**: https://github.com/openai/swarm | ||
| ### Papers | ||
| - "Generative Agents" (Park et al.) | ||
| - "Self-Organizing Multi-Agent Systems" (research papers) | ||
| ## Implementation Checklist | ||
| - [ ] Define each agent's role, goal, and expertise | ||
| - [ ] Identify available tools/capabilities for each agent | ||
| - [ ] Plan workflow (sequential, parallel, hierarchical) | ||
| - [ ] Define communication patterns | ||
| - [ ] Implement task definitions | ||
| - [ ] Set success criteria for each task | ||
| - [ ] Add error handling and fallbacks | ||
| - [ ] Implement monitoring/logging | ||
| - [ ] Test team collaboration | ||
| - [ ] Evaluate quality and performance | ||
| - [ ] Optimize based on results | ||
| - [ ] Document workflow and decisions | ||
| ## Getting Started | ||
| 1. **Start Small**: Begin with 2-3 agents | ||
| 2. **Clear Workflow**: Document how agents interact | ||
| 3. **Test Thoroughly**: Validate agent behavior individually and together | ||
| 4. **Monitor Closely**: Track performance and results | ||
| 5. **Iterate**: Refine based on results | ||
| 6. **Scale**: Add agents and complexity as needed | ||
| # PageSpeed Insights — Reference & Official Documentation | ||
| This file complements the pagespeed-insights skill with official documentation links for indexing. | ||
| ## Official documentation (indexable) | ||
| - **PageSpeed Insights about**: https://developers.google.com/speed/docs/insights/v5/about?hl=es-419 | ||
| - **PageSpeed Insights (tool)**: https://pagespeed.web.dev/ | ||
| - **Lighthouse**: https://developer.chrome.com/docs/lighthouse/ | ||
| - **Core Web Vitals**: https://web.dev/vitals/ | ||
| - **Chrome User Experience Report (CrUX)**: https://developer.chrome.com/docs/crux/ | ||
| ## Core Web Vitals (metrics) | ||
| - **LCP (Largest Contentful Paint)**: https://web.dev/lcp/ | ||
| - **FCP (First Contentful Paint)**: https://web.dev/fcp/ | ||
| - **CLS (Cumulative Layout Shift)**: https://web.dev/cls/ | ||
| - **INP (Interaction to Next Paint)**: https://web.dev/inp/ | ||
| - **TTFB (Time to First Byte)**: https://web.dev/ttfb/ | ||
| ## Lab vs field data | ||
| - **Lab data**: Lighthouse, controlled environment, debugging | ||
| - **Field data**: CrUX, real user metrics, 28-day aggregation | ||
| - **Understanding metrics**: https://web.dev/metrics/ | ||
| ## Performance optimization guides | ||
| - **Optimize LCP**: https://web.dev/optimize-lcp/ | ||
| - **Optimize CLS**: https://web.dev/optimize-cls/ | ||
| - **Optimize INP**: https://web.dev/optimize-inp/ | ||
| - **Optimize FCP**: https://web.dev/optimize-fcp/ | ||
| - **Resource hints**: https://web.dev/preconnect-and-dns-prefetch/ | ||
| - **Image optimization**: https://web.dev/fast/#optimize-your-images | ||
| ## Tools | ||
| - **PageSpeed Insights**: https://pagespeed.web.dev/ | ||
| - **Lighthouse (Chrome DevTools)**: Built-in, Audits tab | ||
| - **Web Vitals extension**: Real-time monitoring | ||
| - **Chromatic (Lighthouse CI)**: https://github.com/GoogleChrome/lighthouse-ci | ||
| ## Score thresholds (reminder) | ||
| | Category | Good | Needs Improvement | Poor | | ||
| |----------|------|-------------------|------| | ||
| | Performance | 90-100 | 50-89 | 0-49 | | ||
| | Accessibility | 90-100 | 50-89 | 0-49 | | ||
| | Best Practices | 90-100 | 50-89 | 0-49 | | ||
| | SEO | 90-100 | 50-89 | 0-49 | |
| --- | ||
| name: pagespeed-insights | ||
| description: Audit web pages for performance optimization following PageSpeed Insights guidelines. Use when analyzing page performance, optimizing web applications, reviewing performance metrics, implementing Core Web Vitals improvements, or when the user mentions page speed, performance optimization, Lighthouse scores, or Core Web Vitals. | ||
| --- | ||
| # PageSpeed Insights Auditor | ||
| ## Overview | ||
| You are a **PageSpeed Insights Auditor** - an expert in web performance optimization who helps developers achieve excellent PageSpeed scores by identifying performance issues, avoiding bad practices, and implementing best practices based on Google's PageSpeed Insights guidelines. | ||
| **Core Principle**: Guide developers to achieve scores of 90+ (Good) in Performance, Accessibility, Best Practices, and SEO categories, while ensuring Core Web Vitals metrics meet the "Good" thresholds. | ||
| ## Understanding PageSpeed Insights | ||
| PageSpeed Insights (PSI) analyzes page performance on mobile and desktop devices, providing both **lab data** (simulated) and **field data** (real user experiences). PSI reports on user experience metrics and provides diagnostic suggestions to improve page performance. | ||
| ### Two Types of Data | ||
| 1. **Lab Data**: Collected in a controlled environment using Lighthouse. Useful for debugging but may not capture real-world bottlenecks. | ||
| 2. **Field Data**: Real user experience data from Chrome User Experience Report (CrUX). Useful for capturing actual user experiences but has a more limited set of metrics. | ||
| ## Performance Score Thresholds | ||
| ### Lab Scores (Lighthouse) | ||
| | Score Range | Rating | Icon | | ||
| | ----------- | ----------------- | --------------- | | ||
| | 90-100 | Good | 🟢 Green circle | | ||
| | 50-89 | Needs Improvement | 🟡 Amber square | | ||
| | 0-49 | Poor | 🔴 Red triangle | | ||
| **Target**: Always aim for scores of **90 or higher** in all categories. | ||
| ### Core Web Vitals Thresholds | ||
| Core Web Vitals are the three most important metrics for web performance: | ||
| | Metric | Good | Needs Improvement | Poor | | ||
| | ----------------------------------- | ------------ | ------------------ | --------- | | ||
| | **FCP** (First Contentful Paint) | [0, 1800 ms] | [1800 ms, 3000 ms] | > 3000 ms | | ||
| | **LCP** (Largest Contentful Paint) | [0, 2500 ms] | [2500 ms, 4000 ms] | > 4000 ms | | ||
| | **CLS** (Cumulative Layout Shift) | [0, 0.1] | [0.1, 0.25] | > 0.25 | | ||
| | **INP** (Interaction to Next Paint) | [0, 200 ms] | [200 ms, 500 ms] | > 500 ms | | ||
| | **TTFB** (Time to First Byte) | [0, 800 ms] | [800 ms, 1800 ms] | > 1800 ms | | ||
| **Target**: Ensure the 75th percentile of all Core Web Vitals metrics are in the "Good" range. | ||
| ## Key Performance Metrics | ||
| ### Lab Metrics (Lighthouse) | ||
| 1. **First Contentful Paint (FCP)**: Time until first content is rendered | ||
| 2. **Largest Contentful Paint (LCP)**: Time until largest content element is rendered | ||
| 3. **Speed Index**: How quickly content is visually displayed | ||
| 4. **Cumulative Layout Shift (CLS)**: Visual stability measure | ||
| 5. **Total Blocking Time (TBT)**: Sum of blocking time between FCP and TTI | ||
| 6. **Time to Interactive (TTI)**: Time until page is fully interactive | ||
| ### Field Metrics (CrUX) | ||
| - **FCP**: First Contentful Paint from real users | ||
| - **LCP**: Largest Contentful Paint from real users | ||
| - **CLS**: Cumulative Layout Shift from real users | ||
| - **INP**: Interaction to Next Paint (replaces FID) | ||
| - **TTFB**: Time to First Byte (experimental) | ||
| ## Common Performance Issues & Solutions | ||
| ### ❌ Bad Practice: Unoptimized Images | ||
| **Problem**: Large images without compression, modern formats, or proper sizing. | ||
| **Impact**: Poor LCP scores, slow page loads. | ||
| **✅ Solutions**: | ||
| - Use modern image formats (WebP, AVIF) | ||
| - Implement responsive images with `srcset` | ||
| - Compress images before uploading | ||
| - Set explicit width/height to prevent CLS | ||
| - Use lazy loading for below-the-fold images | ||
| ```html | ||
| <!-- Bad --> | ||
| <img src="large-image.jpg" alt="Description" /> | ||
| <!-- Good --> | ||
| <img | ||
| src="image.webp" | ||
| srcset="image-small.webp 400w, image-medium.webp 800w, image-large.webp 1200w" | ||
| sizes="(max-width: 600px) 400px, (max-width: 1200px) 800px, 1200px" | ||
| width="1200" | ||
| height="800" | ||
| alt="Description" | ||
| loading="lazy" | ||
| /> | ||
| ``` | ||
| ### ❌ Bad Practice: Render-Blocking Resources | ||
| **Problem**: CSS and JavaScript blocking initial render. | ||
| **Impact**: Poor FCP and LCP scores. | ||
| **✅ Solutions**: | ||
| - Defer non-critical CSS | ||
| - Inline critical CSS | ||
| - Use `async` or `defer` for JavaScript | ||
| - Remove unused CSS/JS | ||
| - Split code and lazy load routes | ||
| ```html | ||
| <!-- Bad --> | ||
| <link rel="stylesheet" href="styles.css" /> | ||
| <script src="app.js"></script> | ||
| <!-- Good --> | ||
| <link | ||
| rel="stylesheet" | ||
| href="styles.css" | ||
| media="print" | ||
| onload="this.media='all'" | ||
| /> | ||
| <link rel="preload" href="critical.css" as="style" /> | ||
| <script src="app.js" defer></script> | ||
| ``` | ||
| ### ❌ Bad Practice: Missing Resource Hints | ||
| **Problem**: Not preconnecting to important origins or prefetching critical resources. | ||
| **Impact**: Slow TTFB and LCP. | ||
| **✅ Solutions**: | ||
| - Use `rel="preconnect"` for third-party origins | ||
| - Use `rel="dns-prefetch"` for DNS resolution | ||
| - Use `rel="preload"` for critical resources | ||
| - Use `rel="prefetch"` for likely next-page resources | ||
| ```html | ||
| <!-- Good --> | ||
| <link rel="preconnect" href="https://fonts.googleapis.com" /> | ||
| <link rel="dns-prefetch" href="https://api.example.com" /> | ||
| <link rel="preload" href="hero-image.webp" as="image" /> | ||
| ``` | ||
| ### ❌ Bad Practice: Layout Shift (CLS) | ||
| **Problem**: Content shifting during page load. | ||
| **Impact**: Poor CLS scores, bad user experience. | ||
| **✅ Solutions**: | ||
| - Set explicit dimensions for images and videos | ||
| - Reserve space for ads and embeds | ||
| - Avoid inserting content above existing content | ||
| - Use CSS aspect-ratio for responsive containers | ||
| - Prefer transform animations over layout-triggering properties | ||
| ```css | ||
| /* Bad */ | ||
| .image-container { | ||
| width: 100%; | ||
| /* height not set - causes CLS */ | ||
| } | ||
| /* Good */ | ||
| .image-container { | ||
| width: 100%; | ||
| aspect-ratio: 16 / 9; | ||
| /* or */ | ||
| height: 0; | ||
| padding-bottom: 56.25%; /* 16:9 ratio */ | ||
| } | ||
| ``` | ||
| ### ❌ Bad Practice: Large JavaScript Bundles | ||
| **Problem**: Loading unnecessary JavaScript code. | ||
| **Impact**: Poor TTI, high TBT. | ||
| **✅ Solutions**: | ||
| - Code splitting and lazy loading | ||
| - Remove unused code (tree shaking) | ||
| - Minimize and compress JavaScript | ||
| - Use dynamic imports for routes | ||
| - Avoid large third-party libraries when possible | ||
| ```javascript | ||
| // Bad - loading everything upfront | ||
| import { heavyLibrary } from "./heavy-library"; | ||
| // Good - lazy load when needed | ||
| const loadHeavyLibrary = () => import("./heavy-library"); | ||
| ``` | ||
| ### ❌ Bad Practice: Inefficient Font Loading | ||
| **Problem**: Fonts causing FOIT (Flash of Invisible Text) or FOUT (Flash of Unstyled Text). | ||
| **Impact**: Poor FCP, layout shifts. | ||
| **✅ Solutions**: | ||
| - Use `font-display: swap` or `optional` | ||
| - Preload critical fonts | ||
| - Subset fonts to include only needed characters | ||
| - Use system fonts when possible | ||
| ```css | ||
| /* Good */ | ||
| @font-face { | ||
| font-family: "CustomFont"; | ||
| src: url("font.woff2") format("woff2"); | ||
| font-display: swap; /* or optional */ | ||
| } | ||
| ``` | ||
| ### ❌ Bad Practice: No Caching Strategy | ||
| **Problem**: Resources not cached, causing repeated downloads. | ||
| **Impact**: Slow repeat visits, poor performance. | ||
| **✅ Solutions**: | ||
| - Set appropriate Cache-Control headers | ||
| - Use service workers for offline caching | ||
| - Implement HTTP/2 server push for critical resources | ||
| - Use CDN for static assets | ||
| ``` | ||
| Cache-Control: public, max-age=31536000, immutable | ||
| ``` | ||
| ### ❌ Bad Practice: Third-Party Scripts Blocking Render | ||
| **Problem**: Analytics, ads, or widgets blocking page load. | ||
| **Impact**: Poor TTI, high TBT. | ||
| **✅ Solutions**: | ||
| - Load third-party scripts asynchronously | ||
| - Defer non-critical third-party code | ||
| - Use `rel="noopener"` for external links | ||
| - Consider self-hosting analytics when possible | ||
| ```html | ||
| <!-- Good --> | ||
| <script async src="https://www.google-analytics.com/analytics.js"></script> | ||
| ``` | ||
| ## Accessibility Best Practices | ||
| ### ❌ Bad Practice: Missing Alt Text | ||
| **Problem**: Images without descriptive alt attributes. | ||
| **Impact**: Poor accessibility score. | ||
| **✅ Solution**: Always provide meaningful alt text. | ||
| ```html | ||
| <!-- Bad --> | ||
| <img src="chart.png" /> | ||
| <!-- Good --> | ||
| <img src="chart.png" alt="Sales increased 25% from Q1 to Q2" /> | ||
| ``` | ||
| ### ❌ Bad Practice: Poor Color Contrast | ||
| **Problem**: Text not readable due to low contrast. | ||
| **Impact**: Poor accessibility score. | ||
| **✅ Solution**: Ensure contrast ratio of at least 4.5:1 for normal text, 3:1 for large text. | ||
| ### ❌ Bad Practice: Missing ARIA Labels | ||
| **Problem**: Interactive elements without proper labels. | ||
| **Impact**: Poor accessibility score. | ||
| **✅ Solution**: Use ARIA labels for screen readers. | ||
| ```html | ||
| <!-- Good --> | ||
| <button aria-label="Close dialog">×</button> | ||
| ``` | ||
| ## SEO Best Practices | ||
| ### ❌ Bad Practice: Missing Meta Tags | ||
| **Problem**: No title, description, or viewport meta tags. | ||
| **Impact**: Poor SEO score. | ||
| **✅ Solution**: Include essential meta tags. | ||
| ```html | ||
| <!-- Good --> | ||
| <meta charset="UTF-8" /> | ||
| <meta name="viewport" content="width=device-width, initial-scale=1.0" /> | ||
| <meta name="description" content="Page description" /> | ||
| <title>Page Title</title> | ||
| ``` | ||
| ### ❌ Bad Practice: Non-Descriptive Links | ||
| **Problem**: Links with generic text like "click here". | ||
| **Impact**: Poor SEO score. | ||
| **✅ Solution**: Use descriptive link text. | ||
| ```html | ||
| <!-- Bad --> | ||
| <a href="/about">Click here</a> | ||
| <!-- Good --> | ||
| <a href="/about">Learn more about our company</a> | ||
| ``` | ||
| ## Best Practices Checklist | ||
| ### Performance | ||
| - [ ] Images optimized (WebP/AVIF, compressed, responsive) | ||
| - [ ] Critical CSS inlined | ||
| - [ ] Non-critical CSS deferred | ||
| - [ ] JavaScript code-split and lazy-loaded | ||
| - [ ] Render-blocking resources minimized | ||
| - [ ] Resource hints implemented (preconnect, preload, dns-prefetch) | ||
| - [ ] Fonts optimized with font-display | ||
| - [ ] Caching strategy implemented | ||
| - [ ] Third-party scripts loaded asynchronously | ||
| - [ ] Layout shifts prevented (explicit dimensions, aspect-ratio) | ||
| ### Core Web Vitals | ||
| - [ ] LCP < 2.5 seconds (75th percentile) | ||
| - [ ] FCP < 1.8 seconds (75th percentile) | ||
| - [ ] CLS < 0.1 (75th percentile) | ||
| - [ ] INP < 200ms (75th percentile) | ||
| - [ ] TTFB < 800ms (75th percentile) | ||
| ### Accessibility | ||
| - [ ] All images have alt text | ||
| - [ ] Color contrast meets WCAG standards | ||
| - [ ] ARIA labels on interactive elements | ||
| - [ ] Semantic HTML used | ||
| - [ ] Keyboard navigation supported | ||
| ### SEO | ||
| - [ ] Meta tags present (title, description, viewport) | ||
| - [ ] Descriptive link text | ||
| - [ ] Proper heading hierarchy (h1-h6) | ||
| - [ ] Structured data implemented | ||
| - [ ] Mobile-friendly design | ||
| ## Audit Workflow | ||
| When auditing a page for PageSpeed optimization: | ||
| 1. **Analyze Current State** | ||
| - Check current PageSpeed scores | ||
| - Identify Core Web Vitals metrics | ||
| - Review lab and field data differences | ||
| 2. **Identify Issues** | ||
| - List all performance problems | ||
| - Prioritize by impact (Core Web Vitals first) | ||
| - Categorize by type (images, JS, CSS, etc.) | ||
| 3. **Provide Solutions** | ||
| - Suggest specific optimizations | ||
| - Provide code examples | ||
| - Explain expected improvements | ||
| 4. **Verify Improvements** | ||
| - Re-test after changes | ||
| - Ensure scores reach 90+ | ||
| - Confirm Core Web Vitals are "Good" | ||
| ## Common Mistakes to Avoid | ||
| ### ❌ Focusing Only on Lab Data | ||
| **Problem**: Optimizing only for Lighthouse scores without considering real user data. | ||
| **✅ Solution**: Balance both lab and field data. Field data shows real-world performance. | ||
| ### ❌ Over-Optimizing | ||
| **Problem**: Implementing too many optimizations at once, making debugging difficult. | ||
| **✅ Solution**: Make incremental changes and test after each optimization. | ||
| ### ❌ Ignoring Mobile Performance | ||
| **Problem**: Optimizing only for desktop. | ||
| **✅ Solution**: Mobile-first approach. Most users are on mobile devices. | ||
| ### ❌ Not Testing After Changes | ||
| **Problem**: Assuming optimizations worked without verification. | ||
| **✅ Solution**: Always re-run PageSpeed Insights after implementing changes. | ||
| ## Performance Optimization Priority | ||
| 1. **Critical Path**: Optimize resources needed for initial render | ||
| 2. **Core Web Vitals**: Focus on LCP, CLS, and INP first | ||
| 3. **Render-Blocking**: Eliminate blocking CSS and JS | ||
| 4. **Images**: Optimize largest contentful paint element | ||
| 5. **Third-Party**: Minimize impact of external scripts | ||
| 6. **Caching**: Implement proper caching strategies | ||
| ## Additional Resources | ||
| - [reference.md](reference.md) — Official PageSpeed, Lighthouse, Core Web Vitals, optimization guides — indexable | ||
| - **Official**: https://developers.google.com/speed/docs/insights/v5/about?hl=es-419 | ||
| - **PageSpeed Insights**: https://pagespeed.web.dev/ | ||
| - **Lighthouse**: Built into Chrome DevTools | ||
| - **Web Vitals**: https://web.dev/vitals/ | ||
| ## Specification Reference | ||
| This skill is based on the official [PageSpeed Insights documentation](https://developers.google.com/speed/docs/insights/v5/about?hl=es-419) from Google Developers. | ||
| All thresholds, metrics, and best practices in this skill follow the official PageSpeed Insights guidelines and Core Web Vitals specifications. For complete documentation, refer to the [official PageSpeed Insights documentation](https://developers.google.com/speed/docs/insights/v5/about?hl=es-419). |
| --- | ||
| id: pagespeed-perf | ||
| version: 1.0.0 | ||
| name: PageSpeed Performance Audit | ||
| description: > | ||
| Web Performance Engineering — analyzes Core Web Vitals using the PageSpeed | ||
| Insights API (PSI v5) and applies the 80/20 principle: identify the 20% of | ||
| changes that produce 80% of the performance gain. Produces a prioritized | ||
| markdown report with quantified estimates and framework-specific code. | ||
| Trigger: When auditing page speed, analyzing Core Web Vitals, or optimizing | ||
| web performance for any URL. | ||
| user-invokable: true | ||
| license: MIT | ||
| metadata: | ||
| author: codeconductor | ||
| category: performance | ||
| compatibility: | ||
| tools: [claude, codex, gemini, agy, opencode] | ||
| stacks: | ||
| languages: [] | ||
| frameworks: [astro, nextjs, react, vue, django, spring, wordpress] | ||
| risk: | ||
| level: medium | ||
| can_execute_shell: true | ||
| can_modify_files: false | ||
| requires_network: true | ||
| inputs: | ||
| - name: url | ||
| type: string | ||
| required: true | ||
| description: Full URL to audit (must include scheme: https://...) | ||
| - name: strategy | ||
| type: string | ||
| required: false | ||
| description: "mobile | desktop | both (default: both)" | ||
| outputs: | ||
| - name: report | ||
| type: markdown | ||
| description: > | ||
| Prioritized performance report saved as | ||
| {YYYY-MM-DD}_pagespeed-{hostname}-claude.md in the current directory. | ||
| quality: | ||
| reviewed_by: codeconductor-core | ||
| version: 1.0.0 | ||
| --- | ||
| # PageSpeed Performance Audit — Web Performance Engineering (80/20) | ||
| ## Role and Purpose | ||
| Act as **Senior Web Performance Engineer, Frontend Architect, and Technical | ||
| Auditor**. | ||
| Always access the real site, measure real metrics via the PageSpeed Insights | ||
| API, analyze resources with the greatest impact, and produce a prioritized | ||
| Spanish-language report following the 80/20 principle: the **20% of critical | ||
| changes that produce 80% of the performance improvement**. | ||
| Never give generic recommendations. Every finding must be backed by data | ||
| observed from the specific URL being audited. | ||
| --- | ||
| ## Step 0 — Pre-flight: API Key and Output Filename | ||
| **MANDATORY. Execute before any analysis.** | ||
| ### 1. Read the API key from the environment | ||
| ```powershell | ||
| $env:PAGESPEED_API_KEY | ||
| ``` | ||
| - Value present → store as `{API_KEY}`, use in all PSI calls. | ||
| - Empty → proceed without key (CrUX field data unavailable; rate limits apply). | ||
| ### 2. Define the output filename | ||
| ```powershell | ||
| $date = (Get-Date -Format "yyyy-MM-dd") | ||
| $website = ([System.Uri]"{URL}").Host -replace '[^a-zA-Z0-9]', '-' | ||
| $out = "${date}_pagespeed-${website}-claude.md" | ||
| Write-Host $out | ||
| ``` | ||
| The final report **must** be written to this file. | ||
| --- | ||
| ## Data Collection | ||
| ### Primary Method — Bun Scripts (always try first) | ||
| ```powershell | ||
| bun --version # if available, use Primary Method; otherwise use Fallback | ||
| $skillDir = "$env:USERPROFILE\.claude\skills\pagespeed-perf\scripts" | ||
| bun run "$skillDir\run.ts" --url={URL} | ||
| ``` | ||
| `run.ts` calls `psi-collect.ts` and `html-audit.ts` in parallel and returns | ||
| structured JSON. Key output fields: | ||
| ``` | ||
| output.summary.mobileScore → Lighthouse mobile score (0-100) | ||
| output.summary.desktopScore → Lighthouse desktop score | ||
| output.summary.passesCWV → boolean — passes real CWV | ||
| output.summary.top5Actions → array ordered by 80/20 score | ||
| output.psi.mobile.lab.lcp → LCP (lab, mobile) | ||
| output.psi.mobile.lab.tbt → TBT | ||
| output.psi.mobile.lab.cls → CLS | ||
| output.psi.mobile.lab.fcp → FCP | ||
| output.psi.mobile.lab.ttfb → TTFB | ||
| output.psi.mobile.field → CrUX data (null if no key / no data) | ||
| output.psi.mobile.opportunities → array ordered by impact80_20 desc | ||
| output.psi.mobile.lcpElement → HTML snippet of the LCP element | ||
| output.psi.mobile.thirdParties → third-party scripts with blockingTime | ||
| output.psi.mobile.usedApiKey → boolean — confirms key was used | ||
| output.html.stack → detected framework / CMS | ||
| output.html.resourceHints → preloads, preconnects, prefetches | ||
| output.html.images → lazy, fetchpriority, list | ||
| output.html.scripts → blocking in <head>, third-party list | ||
| output.html.fonts → googleFonts, font-display, preloaded | ||
| output.html.issues → ordered by impact80_20 | ||
| ``` | ||
| ### Fallback Method — WebFetch (only if Bun unavailable) | ||
| ``` | ||
| # With API key (preferred) | ||
| https://www.googleapis.com/pagespeedonline/v5/runPagespeed?url={URL}&strategy=mobile&category=performance&key={API_KEY} | ||
| https://www.googleapis.com/pagespeedonline/v5/runPagespeed?url={URL}&strategy=desktop&category=performance&key={API_KEY} | ||
| # Without key (rate-limited) | ||
| https://www.googleapis.com/pagespeedonline/v5/runPagespeed?url={URL}&strategy=mobile&category=performance | ||
| ``` | ||
| Key PSI response paths: | ||
| ``` | ||
| lighthouseResult.categories.performance.score | ||
| lighthouseResult.audits.largest-contentful-paint | ||
| lighthouseResult.audits.total-blocking-time | ||
| lighthouseResult.audits.cumulative-layout-shift | ||
| lighthouseResult.audits.first-contentful-paint | ||
| lighthouseResult.audits.server-response-time | ||
| lighthouseResult.audits.largest-contentful-paint-element.details.items[0] | ||
| lighthouseResult.audits.render-blocking-resources.details.overallSavingsMs | ||
| lighthouseResult.audits.unused-javascript.details.overallSavingsBytes | ||
| lighthouseResult.audits.third-party-summary.details.items | ||
| loadingExperience.metrics.LARGEST_CONTENTFUL_PAINT_MS.percentile (CrUX) | ||
| loadingExperience.metrics.INTERACTION_TO_NEXT_PAINT.percentile (CrUX) | ||
| loadingExperience.metrics.CUMULATIVE_LAYOUT_SHIFT_SCORE.percentile (CrUX) | ||
| loadingExperience.overall_category → "FAST" | "AVERAGE" | "SLOW" | ||
| ``` | ||
| Also fetch the site HTML via WebFetch and inspect the `<head>` for resource | ||
| hints, lazy loading, `fetchpriority`, `font-display`, blocking scripts, and | ||
| images without explicit dimensions. | ||
| --- | ||
| ## Core Web Vitals — Thresholds | ||
| | Metric | Good | Needs Improvement | Critical | Score weight | | ||
| | ------ | -------- | ----------------- | --------- | ------------ | | ||
| | LCP | ≤ 2.5 s | 2.5 s – 4.0 s | > 4.0 s | 25% | | ||
| | INP | ≤ 200 ms | 200 ms – 500 ms | > 500 ms | 10% | | ||
| | CLS | ≤ 0.1 | 0.1 – 0.25 | > 0.25 | 15% | | ||
| | FCP | ≤ 1.8 s | 1.8 s – 3.0 s | > 3.0 s | 10% | | ||
| | TBT | ≤ 200 ms | 200 ms – 600 ms | > 600 ms | 30% | | ||
| | TTFB | ≤ 800 ms | 800 ms – 1.8 s | > 1.8 s | — | | ||
| LCP + TBT represent 55% of the Lighthouse Performance Score. | ||
| --- | ||
| ## 80/20 Optimization Matrix | ||
| Score = `Impact (1–5) × Ease (1–5)`. Prioritize by descending score. | ||
| | Rank | Optimization | Primary metric | Impact | Ease | Score | | ||
| | ---- | --------------------------------- | -------------- | ------ | ---- | ----- | | ||
| | 1 | Preload LCP element | LCP | 5 | 5 | **25** | | ||
| | 1 | `fetchpriority="high"` on LCP img | LCP | 5 | 5 | **25** | | ||
| | 1 | Gzip / Brotli compression | FCP, LCP, TBT | 5 | 5 | **25** | | ||
| | 4 | WebP + explicit dimensions | LCP, CLS | 5 | 4 | **20** | | ||
| | 4 | Lazy loading offscreen images | LCP, TBT | 4 | 5 | **20** | | ||
| | 4 | `font-display: swap` | FCP | 4 | 5 | **20** | | ||
| | 4 | `preconnect` to critical origins | FCP, LCP, TTFB | 4 | 5 | **20** | | ||
| | 4 | Defer / facade third-party scripts| TBT, INP | 5 | 4 | **20** | | ||
| | 9 | Remove render-blocking resources | FCP, LCP | 5 | 3 | **15** | | ||
| | 9 | Long Cache-Control for assets | repeat visits | 3 | 5 | **15** | | ||
| | 11 | Remove unused JavaScript | TBT, INP | 4 | 3 | **12** | | ||
| | 12 | Remove unused CSS | FCP, TBT | 3 | 3 | **9** | | ||
| | 13 | CDN for static assets | TTFB, LCP | 4 | 2 | **8** | | ||
| | 14 | Code splitting | TBT, INP | 4 | 2 | **8** | | ||
| **Critical 20% (Score ≥ 20)** — address these first: | ||
| 1. Preload LCP element + `fetchpriority="high"` | ||
| 2. Brotli/Gzip compression at the server | ||
| 3. WebP images with explicit `width`/`height` | ||
| 4. Lazy loading of offscreen images | ||
| 5. `font-display: swap` for all fonts | ||
| 6. `preconnect` to all critical origins | ||
| 7. Defer or facade all third-party scripts | ||
| --- | ||
| ## Expected Impact by Optimization | ||
| | Optimization | Metric | Expected gain | | ||
| | ---------------------- | -------- | --------------------- | | ||
| | Preload + fetchpriority| LCP | −0.5 s to −2.0 s | | ||
| | Brotli compression | FCP, LCP | −0.3 s to −1.0 s | | ||
| | WebP + dimensions | LCP, CLS | −0.3 s to −1.2 s | | ||
| | Lazy loading | LCP | −0.2 s to −0.8 s | | ||
| | font-display: swap | FCP | −0.2 s to −0.8 s | | ||
| | preconnect | FCP, LCP | −0.1 s to −0.4 s each| | ||
| | Defer third parties | TBT, INP | −50 ms to −300 ms | | ||
| --- | ||
| ## Report Format (mandatory structure) | ||
| Save to `{YYYY-MM-DD}_pagespeed-{hostname}-claude.md`: | ||
| ```markdown | ||
| # Auditoría de Rendimiento Web — {URL} | ||
| Fecha: {YYYY-MM-DD} | Estrategia: Móvil + Escritorio | Archivo: {filename}.md | ||
| ## Resumen Ejecutivo | ||
| [2-3 párrafos: estado actual, score, bottleneck principal, potencial de mejora] | ||
| ## Métricas Actuales | ||
| [Tabla: Lab (Lighthouse) vs Campo (CrUX)] | ||
| ## Recursos con Mayor Impacto | ||
| [Tabla: URL, Tipo, Tamaño, Tiempo, Impacto, Razón] | ||
| ## Plan de Acción Priorizado (80/20) | ||
| [Tabla ordenada por Score 80/20 descendente] | ||
| ## Solución Técnica Detallada | ||
| [Por hallazgo: Problema, Evidencia, Implementación, Código, Impacto Esperado] | ||
| ## Quick Wins (< 1 day) | ||
| ## High Impact Changes | ||
| ## Roadmap | ||
| - Fase 1 — Inmediato (Semana 1) | ||
| - Fase 2 — Corto Plazo (2–4 semanas) | ||
| - Fase 3 — Mediano Plazo (1–3 meses) | ||
| --- | ||
| *Informe generado el {YYYY-MM-DD} · Herramienta: Claude Code + pagespeed-perf skill* | ||
| *API Key usada: {Sí / No} · Datos CrUX: {Disponibles / No disponibles}* | ||
| ``` | ||
| --- | ||
| ## Quality Rules — Never Violate | ||
| 1. **No data = no recommendation.** If PSI fails, try WebFetch directly. | ||
| 2. **Always quantify.** "Reduces LCP from 4.2 s to ~3.0 s" — never "would improve LCP". | ||
| 3. **Explicit evidence.** Cite the observed metric value for every finding. | ||
| 4. **Site-specific code.** Adapt templates to the detected framework (Next.js, | ||
| Astro, Django, etc.). Do not paste generic snippets unchanged. | ||
| 5. **80/20 order.** Always sort the action plan by descending score. | ||
| 6. **Separate field vs lab data.** CrUX = real user experience. Lighthouse = controlled lab. | ||
| 7. **Identify the framework.** Detect Next.js, Astro, Vue, WordPress, etc., and | ||
| provide framework-specific code samples. |
| # workflow-orchestration-patterns — detailed patterns and worked examples | ||
| ## Critical Design Decision: Workflows vs Activities | ||
| **The Fundamental Rule** (Source: temporal.io/blog/workflow-engine-principles): | ||
| - **Workflows** = Orchestration logic and decision-making | ||
| - **Activities** = External interactions (APIs, databases, network calls) | ||
| ### Workflows (Orchestration) | ||
| **Characteristics:** | ||
| - Contain business logic and coordination | ||
| - **MUST be deterministic** (same inputs → same outputs) | ||
| - **Cannot** perform direct external calls | ||
| - State automatically preserved across failures | ||
| - Can run for years despite infrastructure failures | ||
| **Example workflow tasks:** | ||
| - Decide which steps to execute | ||
| - Handle compensation logic | ||
| - Manage timeouts and retries | ||
| - Coordinate child workflows | ||
| ### Activities (External Interactions) | ||
| **Characteristics:** | ||
| - Handle all external system interactions | ||
| - Can be non-deterministic (API calls, DB writes) | ||
| - Include built-in timeouts and retry logic | ||
| - **Must be idempotent** (calling N times = calling once) | ||
| - Short-lived (seconds to minutes typically) | ||
| **Example activity tasks:** | ||
| - Call payment gateway API | ||
| - Write to database | ||
| - Send emails or notifications | ||
| - Query external services | ||
| ### Design Decision Framework | ||
| ``` | ||
| Does it touch external systems? → Activity | ||
| Is it orchestration/decision logic? → Workflow | ||
| ``` | ||
| ## Core Workflow Patterns | ||
| ### 1. Saga Pattern with Compensation | ||
| **Purpose**: Implement distributed transactions with rollback capability | ||
| **Pattern** (Source: temporal.io/blog/compensating-actions-part-of-a-complete-breakfast-with-sagas): | ||
| ``` | ||
| For each step: | ||
| 1. Register compensation BEFORE executing | ||
| 2. Execute the step (via activity) | ||
| 3. On failure, run all compensations in reverse order (LIFO) | ||
| ``` | ||
| **Example: Payment Workflow** | ||
| 1. Reserve inventory (compensation: release inventory) | ||
| 2. Charge payment (compensation: refund payment) | ||
| 3. Fulfill order (compensation: cancel fulfillment) | ||
| **Critical Requirements:** | ||
| - Compensations must be idempotent | ||
| - Register compensation BEFORE executing step | ||
| - Run compensations in reverse order | ||
| - Handle partial failures gracefully | ||
| ### 2. Entity Workflows (Actor Model) | ||
| **Purpose**: Long-lived workflow representing single entity instance | ||
| **Pattern** (Source: docs.temporal.io/evaluate/use-cases-design-patterns): | ||
| - One workflow execution = one entity (cart, account, inventory item) | ||
| - Workflow persists for entity lifetime | ||
| - Receives signals for state changes | ||
| - Supports queries for current state | ||
| **Example Use Cases:** | ||
| - Shopping cart (add items, checkout, expiration) | ||
| - Bank account (deposits, withdrawals, balance checks) | ||
| - Product inventory (stock updates, reservations) | ||
| **Benefits:** | ||
| - Encapsulates entity behavior | ||
| - Guarantees consistency per entity | ||
| - Natural event sourcing | ||
| ### 3. Fan-Out/Fan-In (Parallel Execution) | ||
| **Purpose**: Execute multiple tasks in parallel, aggregate results | ||
| **Pattern:** | ||
| - Spawn child workflows or parallel activities | ||
| - Wait for all to complete | ||
| - Aggregate results | ||
| - Handle partial failures | ||
| **Scaling Rule** (Source: temporal.io/blog/workflow-engine-principles): | ||
| - Don't scale individual workflows | ||
| - For 1M tasks: spawn 1K child workflows × 1K tasks each | ||
| - Keep each workflow bounded | ||
| ### 4. Async Callback Pattern | ||
| **Purpose**: Wait for external event or human approval | ||
| **Pattern:** | ||
| - Workflow sends request and waits for signal | ||
| - External system processes asynchronously | ||
| - Sends signal to resume workflow | ||
| - Workflow continues with response | ||
| **Use Cases:** | ||
| - Human approval workflows | ||
| - Webhook callbacks | ||
| - Long-running external processes | ||
| ## State Management and Determinism | ||
| ### Automatic State Preservation | ||
| **How Temporal Works** (Source: docs.temporal.io/workflows): | ||
| - Complete program state preserved automatically | ||
| - Event History records every command and event | ||
| - Seamless recovery from crashes | ||
| - Applications restore pre-failure state | ||
| ### Determinism Constraints | ||
| **Workflows Execute as State Machines**: | ||
| - Replay behavior must be consistent | ||
| - Same inputs → identical outputs every time | ||
| **Prohibited in Workflows** (Source: docs.temporal.io/workflows): | ||
| - ❌ Threading, locks, synchronization primitives | ||
| - ❌ Random number generation (`random()`) | ||
| - ❌ Global state or static variables | ||
| - ❌ System time (`datetime.now()`) | ||
| - ❌ Direct file I/O or network calls | ||
| - ❌ Non-deterministic libraries | ||
| **Allowed in Workflows**: | ||
| - ✅ `workflow.now()` (deterministic time) | ||
| - ✅ `workflow.random()` (deterministic random) | ||
| - ✅ Pure functions and calculations | ||
| - ✅ Calling activities (non-deterministic operations) | ||
| ### Versioning Strategies | ||
| **Challenge**: Changing workflow code while old executions still running | ||
| **Solutions**: | ||
| 1. **Versioning API**: Use `workflow.get_version()` for safe changes | ||
| 2. **New Workflow Type**: Create new workflow, route new executions to it | ||
| 3. **Backward Compatibility**: Ensure old events replay correctly | ||
| ## Resilience and Error Handling | ||
| ### Retry Policies | ||
| **Default Behavior**: Temporal retries activities forever | ||
| **Configure Retry**: | ||
| - Initial retry interval | ||
| - Backoff coefficient (exponential backoff) | ||
| - Maximum interval (cap retry delay) | ||
| - Maximum attempts (eventually fail) | ||
| **Non-Retryable Errors**: | ||
| - Invalid input (validation failures) | ||
| - Business rule violations | ||
| - Permanent failures (resource not found) | ||
| ### Idempotency Requirements | ||
| **Why Critical** (Source: docs.temporal.io/activities): | ||
| - Activities may execute multiple times | ||
| - Network failures trigger retries | ||
| - Duplicate execution must be safe | ||
| **Implementation Strategies**: | ||
| - Idempotency keys (deduplication) | ||
| - Check-then-act with unique constraints | ||
| - Upsert operations instead of insert | ||
| - Track processed request IDs | ||
| ### Activity Heartbeats | ||
| **Purpose**: Detect stalled long-running activities | ||
| **Pattern**: | ||
| - Activity sends periodic heartbeat | ||
| - Includes progress information | ||
| - Timeout if no heartbeat received | ||
| - Enables progress-based retry |
| --- | ||
| name: workflow-orchestration-patterns | ||
| description: Design durable workflows with Temporal for distributed systems. Covers workflow vs activity separation, saga patterns, state management, and determinism constraints. Use when building long-running processes, distributed transactions, or microservice orchestration. | ||
| --- | ||
| # Workflow Orchestration Patterns | ||
| Master workflow orchestration architecture with Temporal, covering fundamental design decisions, resilience patterns, and best practices for building reliable distributed systems. | ||
| ## When to Use Workflow Orchestration | ||
| ### Ideal Use Cases (Source: docs.temporal.io) | ||
| - **Multi-step processes** spanning machines/services/databases | ||
| - **Distributed transactions** requiring all-or-nothing semantics | ||
| - **Long-running workflows** (hours to years) with automatic state persistence | ||
| - **Failure recovery** that must resume from last successful step | ||
| - **Business processes**: bookings, orders, campaigns, approvals | ||
| - **Entity lifecycle management**: inventory tracking, account management, cart workflows | ||
| - **Infrastructure automation**: CI/CD pipelines, provisioning, deployments | ||
| - **Human-in-the-loop** systems requiring timeouts and escalations | ||
| ### When NOT to Use | ||
| - Simple CRUD operations (use direct API calls) | ||
| - Pure data processing pipelines (use Airflow, batch processing) | ||
| - Stateless request/response (use standard APIs) | ||
| - Real-time streaming (use Kafka, event processors) | ||
| ## Detailed patterns and worked examples | ||
| Detailed pattern documentation lives in `references/details.md`. Read that file when the navigation tier above is insufficient. | ||
| ## Best Practices | ||
| ### Workflow Design | ||
| 1. **Keep workflows focused** - Single responsibility per workflow | ||
| 2. **Small workflows** - Use child workflows for scalability | ||
| 3. **Clear boundaries** - Workflow orchestrates, activities execute | ||
| 4. **Test locally** - Use time-skipping test environment | ||
| ### Activity Design | ||
| 1. **Idempotent operations** - Safe to retry | ||
| 2. **Short-lived** - Seconds to minutes, not hours | ||
| 3. **Timeout configuration** - Always set timeouts | ||
| 4. **Heartbeat for long tasks** - Report progress | ||
| 5. **Error handling** - Distinguish retryable vs non-retryable | ||
| ### Common Pitfalls | ||
| **Workflow Violations**: | ||
| - Using `datetime.now()` instead of `workflow.now()` | ||
| - Threading or async operations in workflow code | ||
| - Calling external APIs directly from workflow | ||
| - Non-deterministic logic in workflows | ||
| **Activity Mistakes**: | ||
| - Non-idempotent operations (can't handle retries) | ||
| - Missing timeouts (activities run forever) | ||
| - No error classification (retry validation errors) | ||
| - Ignoring payload limits (2MB per argument) | ||
| ### Operational Considerations | ||
| **Monitoring**: | ||
| - Workflow execution duration | ||
| - Activity failure rates | ||
| - Retry attempts and backoff | ||
| - Pending workflow counts | ||
| **Scalability**: | ||
| - Horizontal scaling with workers | ||
| - Task queue partitioning | ||
| - Child workflow decomposition | ||
| - Activity batching when appropriate | ||
| ## Additional Resources | ||
| **Official Documentation**: | ||
| - Temporal Core Concepts: docs.temporal.io/workflows | ||
| - Workflow Patterns: docs.temporal.io/evaluate/use-cases-design-patterns | ||
| - Best Practices: docs.temporal.io/develop/best-practices | ||
| - Saga Pattern: temporal.io/blog/saga-pattern-made-easy | ||
| **Key Principles**: | ||
| 1. Workflows = orchestration, Activities = external calls | ||
| 2. Determinism is non-negotiable for workflows | ||
| 3. Idempotency is critical for activities | ||
| 4. State preservation is automatic | ||
| 5. Design for failure and recovery |
| { | ||
| "$schema": "https://json.schemastore.org/claude-code-settings.json", | ||
| "env": { | ||
| "CLAUDE_CODE_ATTRIBUTION_HEADER": "0", | ||
| "CLAUDE_CODE_DISABLE_1M_CONTEXT": "1", | ||
| "CLAUDE_CODE_DISABLE_AUTO_MEMORY": "1", | ||
| "CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC": "1", | ||
| "CLAUDE_CODE_DISABLE_TERMINAL_TITLE": "1", | ||
| "DISABLE_EXTRA_USAGE_COMMAND": "1", | ||
| "CLAUDE_CODE_SIMPLE_SYSTEM_PROMPT": "1", | ||
| "ENABLE_TOOL_SEARCH": "auto", | ||
| "CLAUDE_AUTOCOMPACT_PCT_OVERRIDE": "80", | ||
| "DISABLE_BUG_COMMAND": "1" | ||
| }, | ||
| "includeCoAuthoredBy": false, | ||
| "includeGitInstructions": false, | ||
| "permissions": { | ||
| "allow": [ | ||
| "Bash(git status*)", | ||
| "Bash(git diff*)", | ||
| "Bash(git log*)", | ||
| "Bash(./gradlew test*)", | ||
| "Bash(./gradlew build*)", | ||
| "Bash(./gradlew check*)", | ||
| "Bash(npm test*)", | ||
| "Bash(npm run lint*)", | ||
| "Bash(ls *)", | ||
| "Bash(cat *)", | ||
| "Bash(grep *)", | ||
| "Bash(rg *)", | ||
| "Bash(find *)", | ||
| "Bash(tree *)", | ||
| "Bash(echo *)", | ||
| "Bash(pwd)", | ||
| "Bash(which *)", | ||
| "Bash(head *)", | ||
| "Bash(tail *)", | ||
| "Bash(wc *)", | ||
| "Bash(diff *)", | ||
| "Bash(git branch*)", | ||
| "Bash(git show*)", | ||
| "Bash(git add*)", | ||
| "Bash(git commit*)", | ||
| "Bash(git stash*)", | ||
| "Bash(git checkout*)", | ||
| "Bash(git restore*)", | ||
| "Bash(git pull*)", | ||
| "Bash(git fetch*)", | ||
| "Bash(git merge*)", | ||
| "Bash(npm run *)", | ||
| "Bash(npm ci)", | ||
| "Bash(pnpm run *)", | ||
| "Bash(pnpm test*)", | ||
| "Bash(pnpm exec *)", | ||
| "Bash(pnpm dlx *)", | ||
| "Bash(yarn run *)", | ||
| "Bash(yarn test*)", | ||
| "Bash(npx *)", | ||
| "Bash(python *)", | ||
| "Bash(python3 *)", | ||
| "Bash(pip list*)", | ||
| "Bash(pip show *)", | ||
| "Bash(pytest*)", | ||
| "Bash(ruff*)", | ||
| "Bash(black --check *)", | ||
| "Bash(./gradlew *)", | ||
| "Bash(gradle *)", | ||
| "Bash(mvn test*)", | ||
| "Bash(mvn compile*)", | ||
| "Bash(java -version)", | ||
| "Bash(kotlin -version)", | ||
| "Bash(docker ps*)", | ||
| "Bash(docker logs*)", | ||
| "Bash(docker compose ps*)", | ||
| "Bash(docker compose logs*)", | ||
| "Read(**)", | ||
| "Write(./src/**)", | ||
| "Write(./app/**)", | ||
| "Write(./pages/**)", | ||
| "Write(./components/**)", | ||
| "Write(./lib/**)", | ||
| "Write(./tests/**)", | ||
| "Write(./test/**)", | ||
| "Write(./__tests__/**)", | ||
| "Write(./prisma/**)", | ||
| "Write(./drizzle/**)", | ||
| "Write(./public/**)", | ||
| "Write(./styles/**)", | ||
| "Write(./scripts/**)", | ||
| "Write(./docs/**)", | ||
| "Edit(**)", | ||
| "WebFetch(*)" | ||
| ], | ||
| "deny": [ | ||
| "Bash(rm -rf *)", | ||
| "Bash(sudo *)", | ||
| "Bash(su *)", | ||
| "Bash(chmod 777 *)", | ||
| "Bash(chown *)", | ||
| "Bash(dd *)", | ||
| "Bash(mkfs *)", | ||
| "Bash(diskutil *)", | ||
| "Bash(mount *)", | ||
| "Bash(umount *)", | ||
| "Bash(systemctl *)", | ||
| "Bash(launchctl *)", | ||
| "Bash(curl * | sh)", | ||
| "Bash(curl * | bash)", | ||
| "Bash(wget * | sh)", | ||
| "Bash(wget * | bash)", | ||
| "Bash(git push --force*)", | ||
| "Bash(git push -f*)", | ||
| "Bash(git rebase *)", | ||
| "Bash(git reset --hard *)", | ||
| "Bash(rm -fr *)", | ||
| "Bash(chmod -R *)", | ||
| "Bash(eval *)", | ||
| "Bash(git push --force origin main*)", | ||
| "Bash(git push --force origin master*)", | ||
| "Bash(git push -f origin main*)", | ||
| "Bash(git push -f origin master*)", | ||
| "Read(./.env)", | ||
| "Read(./.env.*)", | ||
| "Read(./**/.env)", | ||
| "Read(./**/.env.*)", | ||
| "Read(./secrets/**)", | ||
| "Read(./**/credentials.json)", | ||
| "Read(./**/serviceAccount*.json)", | ||
| "Read(./**/*.pem)", | ||
| "Read(./**/*.key)", | ||
| "Read(./**/id_rsa*)", | ||
| "Read(~/.ssh/**)", | ||
| "Read(~/.aws/**)", | ||
| "Read(~/.gnupg/**)", | ||
| "Write(./.env)", | ||
| "Write(./.env.*)", | ||
| "Write(./**/.env)", | ||
| "Edit(./.env)", | ||
| "Edit(./.env.*)", | ||
| "Edit(./**/.env)" | ||
| ], | ||
| "ask": [ | ||
| "Bash(git push*)", | ||
| "Bash(git push --force*)", | ||
| "Bash(git reset --hard*)", | ||
| "Bash(npm install*)", | ||
| "Bash(npm i *)", | ||
| "Bash(pnpm install*)", | ||
| "Bash(pnpm add *)", | ||
| "Bash(yarn add *)", | ||
| "Bash(pip install*)", | ||
| "Bash(docker run*)", | ||
| "Bash(docker compose up*)", | ||
| "Bash(docker compose down*)", | ||
| "Bash(./gradlew build*)", | ||
| "Bash(./gradlew bootRun*)", | ||
| "Bash(mvn install*)", | ||
| "Bash(mvn deploy*)", | ||
| "Bash(vercel*)", | ||
| "Bash(npx vercel*)" | ||
| ], | ||
| "defaultMode": "acceptEdits" | ||
| }, | ||
| "hooks": { | ||
| "PostToolUse": [ | ||
| { | ||
| "matcher": "Write|Edit|MultiEdit", | ||
| "hooks": [ | ||
| { | ||
| "type": "command", | ||
| "command": "if echo \"$CLAUDE_TOOL_INPUT_FILE_PATH\" | grep -qE '\\.(ts|tsx|js|jsx|mjs|cjs|json|jsonc|md|mdx|css|scss|html|astro|yaml|yml)$'; then npx --no-install prettier --write \"$CLAUDE_TOOL_INPUT_FILE_PATH\" 2>/dev/null || true; fi" | ||
| }, | ||
| { | ||
| "type": "command", | ||
| "command": "if echo \"$CLAUDE_TOOL_INPUT_FILE_PATH\" | grep -qE '\\.(ts|tsx|js|jsx|mjs|cjs)$'; then npx --no-install eslint --fix \"$CLAUDE_TOOL_INPUT_FILE_PATH\" 2>/dev/null || true; fi" | ||
| }, | ||
| { | ||
| "type": "command", | ||
| "command": "if echo \"$CLAUDE_TOOL_INPUT_FILE_PATH\" | grep -qE '\\.py$'; then ruff format \"$CLAUDE_TOOL_INPUT_FILE_PATH\" 2>/dev/null && ruff check --fix \"$CLAUDE_TOOL_INPUT_FILE_PATH\" 2>/dev/null || true; fi" | ||
| } | ||
| ] | ||
| } | ||
| ], | ||
| "PreToolUse": [ | ||
| { | ||
| "matcher": "Bash", | ||
| "hooks": [ | ||
| { | ||
| "type": "command", | ||
| "command": "if echo \"$CLAUDE_TOOL_INPUT_COMMAND\" | grep -qE '(\\.env|secrets/|id_rsa|\\.pem|\\.key)\\b' && echo \"$CLAUDE_TOOL_INPUT_COMMAND\" | grep -qE '(cat|less|more|head|tail|cp |mv |scp )'; then echo 'Bloqueado: intento de leer archivos sensibles' >&2; exit 2; fi" | ||
| } | ||
| ] | ||
| } | ||
| ] | ||
| }, | ||
| "extraKnownMarketplaces": { | ||
| "agricidaniel-claude-seo": { | ||
| "source": { | ||
| "source": "github", | ||
| "repo": "AgriciDaniel/claude-seo" | ||
| } | ||
| } | ||
| }, | ||
| "language": "spanish", | ||
| "feedbackSurveyRate": 0, | ||
| "spinnerTipsEnabled": false, | ||
| "alwaysThinkingEnabled": true, | ||
| "effortLevel": "xhigh", | ||
| "awaySummaryEnabled": false, | ||
| "showClearContextOnPlanAccept": true, | ||
| "autoUpdatesChannel": "stable", | ||
| "prefersReducedMotion": false, | ||
| "autoMemoryEnabled": false, | ||
| "showThinkingSummaries": true, | ||
| "skipDangerousModePermissionPrompt": true, | ||
| "editorMode": "vim", | ||
| "fileCheckpointingEnabled": true, | ||
| "showTurnDuration": true, | ||
| "terminalProgressBarEnabled": true, | ||
| "autoConnectIde": true, | ||
| "autoInstallIdeExtension": false, | ||
| "enabledPlugins": { | ||
| "claude-seo@agricidaniel-claude-seo": true | ||
| } | ||
| } |
| --- | ||
| name: find-skills | ||
| description: Helps users discover and install agent skills when they ask questions like "how do I do X", "find a skill for X", "is there a skill that can...", or express interest in extending capabilities. This skill should be used when the user is looking for functionality that might exist as an installable skill. | ||
| --- | ||
| # Find Skills | ||
| This skill helps you discover and install skills from the open agent skills ecosystem. | ||
| ## When to Use This Skill | ||
| Use this skill when the user: | ||
| - Asks "how do I do X" where X might be a common task with an existing skill | ||
| - Says "find a skill for X" or "is there a skill for X" | ||
| - Asks "can you do X" where X is a specialized capability | ||
| - Expresses interest in extending agent capabilities | ||
| - Wants to search for tools, templates, or workflows | ||
| - Mentions they wish they had help with a specific domain (design, testing, deployment, etc.) | ||
| ## What is the Skills CLI? | ||
| The Skills CLI (`npx skills`) is the package manager for the open agent skills ecosystem. Skills are modular packages that extend agent capabilities with specialized knowledge, workflows, and tools. | ||
| **Key commands:** | ||
| - `npx skills find [query]` - Search for skills interactively or by keyword | ||
| - `npx skills add <package>` - Install a skill from GitHub or other sources | ||
| - `npx skills check` - Check for skill updates | ||
| - `npx skills update` - Update all installed skills | ||
| **Browse skills at:** https://skills.sh/ | ||
| ## How to Help Users Find Skills | ||
| ### Step 1: Understand What They Need | ||
| When a user asks for help with something, identify: | ||
| 1. The domain (e.g., React, testing, design, deployment) | ||
| 2. The specific task (e.g., writing tests, creating animations, reviewing PRs) | ||
| 3. Whether this is a common enough task that a skill likely exists | ||
| ### Step 2: Check the Leaderboard First | ||
| Before running a CLI search, check the [skills.sh leaderboard](https://skills.sh/) to see if a well-known skill already exists for the domain. The leaderboard ranks skills by total installs, surfacing the most popular and battle-tested options. | ||
| For example, top skills for web development include: | ||
| - `vercel-labs/agent-skills` — React, Next.js, web design (100K+ installs each) | ||
| - `anthropics/skills` — Frontend design, document processing (100K+ installs) | ||
| ### Step 3: Search for Skills | ||
| If the leaderboard doesn't cover the user's need, run the find command: | ||
| ```bash | ||
| npx skills find [query] | ||
| ``` | ||
| For example: | ||
| - User asks "how do I make my React app faster?" → `npx skills find react performance` | ||
| - User asks "can you help me with PR reviews?" → `npx skills find pr review` | ||
| - User asks "I need to create a changelog" → `npx skills find changelog` | ||
| ### Step 4: Verify Quality Before Recommending | ||
| **Do not recommend a skill based solely on search results.** Always verify: | ||
| 1. **Install count** — Prefer skills with 1K+ installs. Be cautious with anything under 100. | ||
| 2. **Source reputation** — Official sources (`vercel-labs`, `anthropics`, `microsoft`) are more trustworthy than unknown authors. | ||
| 3. **GitHub stars** — Check the source repository. A skill from a repo with <100 stars should be treated with skepticism. | ||
| ### Step 5: Present Options to the User | ||
| When you find relevant skills, present them to the user with: | ||
| 1. The skill name and what it does | ||
| 2. The install count and source | ||
| 3. The install command they can run | ||
| 4. A link to learn more at skills.sh | ||
| Example response: | ||
| ``` | ||
| I found a skill that might help! The "react-best-practices" skill provides | ||
| React and Next.js performance optimization guidelines from Vercel Engineering. | ||
| (185K installs) | ||
| To install it: | ||
| npx skills add vercel-labs/agent-skills@react-best-practices | ||
| Learn more: https://skills.sh/vercel-labs/agent-skills/react-best-practices | ||
| ``` | ||
| ### Step 6: Offer to Install | ||
| If the user wants to proceed, you can install the skill for them: | ||
| ```bash | ||
| npx skills add <owner/repo@skill> -g -y | ||
| ``` | ||
| The `-g` flag installs globally (user-level) and `-y` skips confirmation prompts. | ||
| ## Common Skill Categories | ||
| When searching, consider these common categories: | ||
| | Category | Example Queries | | ||
| | --------------- | ---------------------------------------- | | ||
| | Web Development | react, nextjs, typescript, css, tailwind | | ||
| | Testing | testing, jest, playwright, e2e | | ||
| | DevOps | deploy, docker, kubernetes, ci-cd | | ||
| | Documentation | docs, readme, changelog, api-docs | | ||
| | Code Quality | review, lint, refactor, best-practices | | ||
| | Design | ui, ux, design-system, accessibility | | ||
| | Productivity | workflow, automation, git | | ||
| ## Tips for Effective Searches | ||
| 1. **Use specific keywords**: "react testing" is better than just "testing" | ||
| 2. **Try alternative terms**: If "deploy" doesn't work, try "deployment" or "ci-cd" | ||
| 3. **Check popular sources**: Many skills come from `vercel-labs/agent-skills` or `ComposioHQ/awesome-claude-skills` | ||
| ## When No Skills Are Found | ||
| If no relevant skills exist: | ||
| 1. Acknowledge that no existing skill was found | ||
| 2. Offer to help with the task directly using your general capabilities | ||
| 3. Suggest the user could create their own skill with `npx skills init` | ||
| Example: | ||
| ``` | ||
| I searched for skills related to "xyz" but didn't find any matches. | ||
| I can still help you with this task directly! Would you like me to proceed? | ||
| If this is something you do often, you could create your own skill: | ||
| npx skills init my-xyz-skill | ||
| ``` |
| # PageSpeed Insights — Reference & Official Documentation | ||
| This file complements the pagespeed-insights skill with official documentation links for indexing. | ||
| ## Official documentation (indexable) | ||
| - **PageSpeed Insights about**: https://developers.google.com/speed/docs/insights/v5/about?hl=es-419 | ||
| - **PageSpeed Insights (tool)**: https://pagespeed.web.dev/ | ||
| - **Lighthouse**: https://developer.chrome.com/docs/lighthouse/ | ||
| - **Core Web Vitals**: https://web.dev/vitals/ | ||
| - **Chrome User Experience Report (CrUX)**: https://developer.chrome.com/docs/crux/ | ||
| ## Core Web Vitals (metrics) | ||
| - **LCP (Largest Contentful Paint)**: https://web.dev/lcp/ | ||
| - **FCP (First Contentful Paint)**: https://web.dev/fcp/ | ||
| - **CLS (Cumulative Layout Shift)**: https://web.dev/cls/ | ||
| - **INP (Interaction to Next Paint)**: https://web.dev/inp/ | ||
| - **TTFB (Time to First Byte)**: https://web.dev/ttfb/ | ||
| ## Lab vs field data | ||
| - **Lab data**: Lighthouse, controlled environment, debugging | ||
| - **Field data**: CrUX, real user metrics, 28-day aggregation | ||
| - **Understanding metrics**: https://web.dev/metrics/ | ||
| ## Performance optimization guides | ||
| - **Optimize LCP**: https://web.dev/optimize-lcp/ | ||
| - **Optimize CLS**: https://web.dev/optimize-cls/ | ||
| - **Optimize INP**: https://web.dev/optimize-inp/ | ||
| - **Optimize FCP**: https://web.dev/optimize-fcp/ | ||
| - **Resource hints**: https://web.dev/preconnect-and-dns-prefetch/ | ||
| - **Image optimization**: https://web.dev/fast/#optimize-your-images | ||
| ## Tools | ||
| - **PageSpeed Insights**: https://pagespeed.web.dev/ | ||
| - **Lighthouse (Chrome DevTools)**: Built-in, Audits tab | ||
| - **Web Vitals extension**: Real-time monitoring | ||
| - **Chromatic (Lighthouse CI)**: https://github.com/GoogleChrome/lighthouse-ci | ||
| ## Score thresholds (reminder) | ||
| | Category | Good | Needs Improvement | Poor | | ||
| |----------|------|-------------------|------| | ||
| | Performance | 90-100 | 50-89 | 0-49 | | ||
| | Accessibility | 90-100 | 50-89 | 0-49 | | ||
| | Best Practices | 90-100 | 50-89 | 0-49 | | ||
| | SEO | 90-100 | 50-89 | 0-49 | |
| --- | ||
| name: pagespeed-insights | ||
| description: Audit web pages for performance optimization following PageSpeed Insights guidelines. Use when analyzing page performance, optimizing web applications, reviewing performance metrics, implementing Core Web Vitals improvements, or when the user mentions page speed, performance optimization, Lighthouse scores, or Core Web Vitals. | ||
| --- | ||
| # PageSpeed Insights Auditor | ||
| ## Overview | ||
| You are a **PageSpeed Insights Auditor** - an expert in web performance optimization who helps developers achieve excellent PageSpeed scores by identifying performance issues, avoiding bad practices, and implementing best practices based on Google's PageSpeed Insights guidelines. | ||
| **Core Principle**: Guide developers to achieve scores of 90+ (Good) in Performance, Accessibility, Best Practices, and SEO categories, while ensuring Core Web Vitals metrics meet the "Good" thresholds. | ||
| ## Understanding PageSpeed Insights | ||
| PageSpeed Insights (PSI) analyzes page performance on mobile and desktop devices, providing both **lab data** (simulated) and **field data** (real user experiences). PSI reports on user experience metrics and provides diagnostic suggestions to improve page performance. | ||
| ### Two Types of Data | ||
| 1. **Lab Data**: Collected in a controlled environment using Lighthouse. Useful for debugging but may not capture real-world bottlenecks. | ||
| 2. **Field Data**: Real user experience data from Chrome User Experience Report (CrUX). Useful for capturing actual user experiences but has a more limited set of metrics. | ||
| ## Performance Score Thresholds | ||
| ### Lab Scores (Lighthouse) | ||
| | Score Range | Rating | Icon | | ||
| | ----------- | ----------------- | --------------- | | ||
| | 90-100 | Good | 🟢 Green circle | | ||
| | 50-89 | Needs Improvement | 🟡 Amber square | | ||
| | 0-49 | Poor | 🔴 Red triangle | | ||
| **Target**: Always aim for scores of **90 or higher** in all categories. | ||
| ### Core Web Vitals Thresholds | ||
| Core Web Vitals are the three most important metrics for web performance: | ||
| | Metric | Good | Needs Improvement | Poor | | ||
| | ----------------------------------- | ------------ | ------------------ | --------- | | ||
| | **FCP** (First Contentful Paint) | [0, 1800 ms] | [1800 ms, 3000 ms] | > 3000 ms | | ||
| | **LCP** (Largest Contentful Paint) | [0, 2500 ms] | [2500 ms, 4000 ms] | > 4000 ms | | ||
| | **CLS** (Cumulative Layout Shift) | [0, 0.1] | [0.1, 0.25] | > 0.25 | | ||
| | **INP** (Interaction to Next Paint) | [0, 200 ms] | [200 ms, 500 ms] | > 500 ms | | ||
| | **TTFB** (Time to First Byte) | [0, 800 ms] | [800 ms, 1800 ms] | > 1800 ms | | ||
| **Target**: Ensure the 75th percentile of all Core Web Vitals metrics are in the "Good" range. | ||
| ## Key Performance Metrics | ||
| ### Lab Metrics (Lighthouse) | ||
| 1. **First Contentful Paint (FCP)**: Time until first content is rendered | ||
| 2. **Largest Contentful Paint (LCP)**: Time until largest content element is rendered | ||
| 3. **Speed Index**: How quickly content is visually displayed | ||
| 4. **Cumulative Layout Shift (CLS)**: Visual stability measure | ||
| 5. **Total Blocking Time (TBT)**: Sum of blocking time between FCP and TTI | ||
| 6. **Time to Interactive (TTI)**: Time until page is fully interactive | ||
| ### Field Metrics (CrUX) | ||
| - **FCP**: First Contentful Paint from real users | ||
| - **LCP**: Largest Contentful Paint from real users | ||
| - **CLS**: Cumulative Layout Shift from real users | ||
| - **INP**: Interaction to Next Paint (replaces FID) | ||
| - **TTFB**: Time to First Byte (experimental) | ||
| ## Common Performance Issues & Solutions | ||
| ### ❌ Bad Practice: Unoptimized Images | ||
| **Problem**: Large images without compression, modern formats, or proper sizing. | ||
| **Impact**: Poor LCP scores, slow page loads. | ||
| **✅ Solutions**: | ||
| - Use modern image formats (WebP, AVIF) | ||
| - Implement responsive images with `srcset` | ||
| - Compress images before uploading | ||
| - Set explicit width/height to prevent CLS | ||
| - Use lazy loading for below-the-fold images | ||
| ```html | ||
| <!-- Bad --> | ||
| <img src="large-image.jpg" alt="Description" /> | ||
| <!-- Good --> | ||
| <img | ||
| src="image.webp" | ||
| srcset="image-small.webp 400w, image-medium.webp 800w, image-large.webp 1200w" | ||
| sizes="(max-width: 600px) 400px, (max-width: 1200px) 800px, 1200px" | ||
| width="1200" | ||
| height="800" | ||
| alt="Description" | ||
| loading="lazy" | ||
| /> | ||
| ``` | ||
| ### ❌ Bad Practice: Render-Blocking Resources | ||
| **Problem**: CSS and JavaScript blocking initial render. | ||
| **Impact**: Poor FCP and LCP scores. | ||
| **✅ Solutions**: | ||
| - Defer non-critical CSS | ||
| - Inline critical CSS | ||
| - Use `async` or `defer` for JavaScript | ||
| - Remove unused CSS/JS | ||
| - Split code and lazy load routes | ||
| ```html | ||
| <!-- Bad --> | ||
| <link rel="stylesheet" href="styles.css" /> | ||
| <script src="app.js"></script> | ||
| <!-- Good --> | ||
| <link | ||
| rel="stylesheet" | ||
| href="styles.css" | ||
| media="print" | ||
| onload="this.media='all'" | ||
| /> | ||
| <link rel="preload" href="critical.css" as="style" /> | ||
| <script src="app.js" defer></script> | ||
| ``` | ||
| ### ❌ Bad Practice: Missing Resource Hints | ||
| **Problem**: Not preconnecting to important origins or prefetching critical resources. | ||
| **Impact**: Slow TTFB and LCP. | ||
| **✅ Solutions**: | ||
| - Use `rel="preconnect"` for third-party origins | ||
| - Use `rel="dns-prefetch"` for DNS resolution | ||
| - Use `rel="preload"` for critical resources | ||
| - Use `rel="prefetch"` for likely next-page resources | ||
| ```html | ||
| <!-- Good --> | ||
| <link rel="preconnect" href="https://fonts.googleapis.com" /> | ||
| <link rel="dns-prefetch" href="https://api.example.com" /> | ||
| <link rel="preload" href="hero-image.webp" as="image" /> | ||
| ``` | ||
| ### ❌ Bad Practice: Layout Shift (CLS) | ||
| **Problem**: Content shifting during page load. | ||
| **Impact**: Poor CLS scores, bad user experience. | ||
| **✅ Solutions**: | ||
| - Set explicit dimensions for images and videos | ||
| - Reserve space for ads and embeds | ||
| - Avoid inserting content above existing content | ||
| - Use CSS aspect-ratio for responsive containers | ||
| - Prefer transform animations over layout-triggering properties | ||
| ```css | ||
| /* Bad */ | ||
| .image-container { | ||
| width: 100%; | ||
| /* height not set - causes CLS */ | ||
| } | ||
| /* Good */ | ||
| .image-container { | ||
| width: 100%; | ||
| aspect-ratio: 16 / 9; | ||
| /* or */ | ||
| height: 0; | ||
| padding-bottom: 56.25%; /* 16:9 ratio */ | ||
| } | ||
| ``` | ||
| ### ❌ Bad Practice: Large JavaScript Bundles | ||
| **Problem**: Loading unnecessary JavaScript code. | ||
| **Impact**: Poor TTI, high TBT. | ||
| **✅ Solutions**: | ||
| - Code splitting and lazy loading | ||
| - Remove unused code (tree shaking) | ||
| - Minimize and compress JavaScript | ||
| - Use dynamic imports for routes | ||
| - Avoid large third-party libraries when possible | ||
| ```javascript | ||
| // Bad - loading everything upfront | ||
| import { heavyLibrary } from "./heavy-library"; | ||
| // Good - lazy load when needed | ||
| const loadHeavyLibrary = () => import("./heavy-library"); | ||
| ``` | ||
| ### ❌ Bad Practice: Inefficient Font Loading | ||
| **Problem**: Fonts causing FOIT (Flash of Invisible Text) or FOUT (Flash of Unstyled Text). | ||
| **Impact**: Poor FCP, layout shifts. | ||
| **✅ Solutions**: | ||
| - Use `font-display: swap` or `optional` | ||
| - Preload critical fonts | ||
| - Subset fonts to include only needed characters | ||
| - Use system fonts when possible | ||
| ```css | ||
| /* Good */ | ||
| @font-face { | ||
| font-family: "CustomFont"; | ||
| src: url("font.woff2") format("woff2"); | ||
| font-display: swap; /* or optional */ | ||
| } | ||
| ``` | ||
| ### ❌ Bad Practice: No Caching Strategy | ||
| **Problem**: Resources not cached, causing repeated downloads. | ||
| **Impact**: Slow repeat visits, poor performance. | ||
| **✅ Solutions**: | ||
| - Set appropriate Cache-Control headers | ||
| - Use service workers for offline caching | ||
| - Implement HTTP/2 server push for critical resources | ||
| - Use CDN for static assets | ||
| ``` | ||
| Cache-Control: public, max-age=31536000, immutable | ||
| ``` | ||
| ### ❌ Bad Practice: Third-Party Scripts Blocking Render | ||
| **Problem**: Analytics, ads, or widgets blocking page load. | ||
| **Impact**: Poor TTI, high TBT. | ||
| **✅ Solutions**: | ||
| - Load third-party scripts asynchronously | ||
| - Defer non-critical third-party code | ||
| - Use `rel="noopener"` for external links | ||
| - Consider self-hosting analytics when possible | ||
| ```html | ||
| <!-- Good --> | ||
| <script async src="https://www.google-analytics.com/analytics.js"></script> | ||
| ``` | ||
| ## Accessibility Best Practices | ||
| ### ❌ Bad Practice: Missing Alt Text | ||
| **Problem**: Images without descriptive alt attributes. | ||
| **Impact**: Poor accessibility score. | ||
| **✅ Solution**: Always provide meaningful alt text. | ||
| ```html | ||
| <!-- Bad --> | ||
| <img src="chart.png" /> | ||
| <!-- Good --> | ||
| <img src="chart.png" alt="Sales increased 25% from Q1 to Q2" /> | ||
| ``` | ||
| ### ❌ Bad Practice: Poor Color Contrast | ||
| **Problem**: Text not readable due to low contrast. | ||
| **Impact**: Poor accessibility score. | ||
| **✅ Solution**: Ensure contrast ratio of at least 4.5:1 for normal text, 3:1 for large text. | ||
| ### ❌ Bad Practice: Missing ARIA Labels | ||
| **Problem**: Interactive elements without proper labels. | ||
| **Impact**: Poor accessibility score. | ||
| **✅ Solution**: Use ARIA labels for screen readers. | ||
| ```html | ||
| <!-- Good --> | ||
| <button aria-label="Close dialog">×</button> | ||
| ``` | ||
| ## SEO Best Practices | ||
| ### ❌ Bad Practice: Missing Meta Tags | ||
| **Problem**: No title, description, or viewport meta tags. | ||
| **Impact**: Poor SEO score. | ||
| **✅ Solution**: Include essential meta tags. | ||
| ```html | ||
| <!-- Good --> | ||
| <meta charset="UTF-8" /> | ||
| <meta name="viewport" content="width=device-width, initial-scale=1.0" /> | ||
| <meta name="description" content="Page description" /> | ||
| <title>Page Title</title> | ||
| ``` | ||
| ### ❌ Bad Practice: Non-Descriptive Links | ||
| **Problem**: Links with generic text like "click here". | ||
| **Impact**: Poor SEO score. | ||
| **✅ Solution**: Use descriptive link text. | ||
| ```html | ||
| <!-- Bad --> | ||
| <a href="/about">Click here</a> | ||
| <!-- Good --> | ||
| <a href="/about">Learn more about our company</a> | ||
| ``` | ||
| ## Best Practices Checklist | ||
| ### Performance | ||
| - [ ] Images optimized (WebP/AVIF, compressed, responsive) | ||
| - [ ] Critical CSS inlined | ||
| - [ ] Non-critical CSS deferred | ||
| - [ ] JavaScript code-split and lazy-loaded | ||
| - [ ] Render-blocking resources minimized | ||
| - [ ] Resource hints implemented (preconnect, preload, dns-prefetch) | ||
| - [ ] Fonts optimized with font-display | ||
| - [ ] Caching strategy implemented | ||
| - [ ] Third-party scripts loaded asynchronously | ||
| - [ ] Layout shifts prevented (explicit dimensions, aspect-ratio) | ||
| ### Core Web Vitals | ||
| - [ ] LCP < 2.5 seconds (75th percentile) | ||
| - [ ] FCP < 1.8 seconds (75th percentile) | ||
| - [ ] CLS < 0.1 (75th percentile) | ||
| - [ ] INP < 200ms (75th percentile) | ||
| - [ ] TTFB < 800ms (75th percentile) | ||
| ### Accessibility | ||
| - [ ] All images have alt text | ||
| - [ ] Color contrast meets WCAG standards | ||
| - [ ] ARIA labels on interactive elements | ||
| - [ ] Semantic HTML used | ||
| - [ ] Keyboard navigation supported | ||
| ### SEO | ||
| - [ ] Meta tags present (title, description, viewport) | ||
| - [ ] Descriptive link text | ||
| - [ ] Proper heading hierarchy (h1-h6) | ||
| - [ ] Structured data implemented | ||
| - [ ] Mobile-friendly design | ||
| ## Audit Workflow | ||
| When auditing a page for PageSpeed optimization: | ||
| 1. **Analyze Current State** | ||
| - Check current PageSpeed scores | ||
| - Identify Core Web Vitals metrics | ||
| - Review lab and field data differences | ||
| 2. **Identify Issues** | ||
| - List all performance problems | ||
| - Prioritize by impact (Core Web Vitals first) | ||
| - Categorize by type (images, JS, CSS, etc.) | ||
| 3. **Provide Solutions** | ||
| - Suggest specific optimizations | ||
| - Provide code examples | ||
| - Explain expected improvements | ||
| 4. **Verify Improvements** | ||
| - Re-test after changes | ||
| - Ensure scores reach 90+ | ||
| - Confirm Core Web Vitals are "Good" | ||
| ## Common Mistakes to Avoid | ||
| ### ❌ Focusing Only on Lab Data | ||
| **Problem**: Optimizing only for Lighthouse scores without considering real user data. | ||
| **✅ Solution**: Balance both lab and field data. Field data shows real-world performance. | ||
| ### ❌ Over-Optimizing | ||
| **Problem**: Implementing too many optimizations at once, making debugging difficult. | ||
| **✅ Solution**: Make incremental changes and test after each optimization. | ||
| ### ❌ Ignoring Mobile Performance | ||
| **Problem**: Optimizing only for desktop. | ||
| **✅ Solution**: Mobile-first approach. Most users are on mobile devices. | ||
| ### ❌ Not Testing After Changes | ||
| **Problem**: Assuming optimizations worked without verification. | ||
| **✅ Solution**: Always re-run PageSpeed Insights after implementing changes. | ||
| ## Performance Optimization Priority | ||
| 1. **Critical Path**: Optimize resources needed for initial render | ||
| 2. **Core Web Vitals**: Focus on LCP, CLS, and INP first | ||
| 3. **Render-Blocking**: Eliminate blocking CSS and JS | ||
| 4. **Images**: Optimize largest contentful paint element | ||
| 5. **Third-Party**: Minimize impact of external scripts | ||
| 6. **Caching**: Implement proper caching strategies | ||
| ## Additional Resources | ||
| - [reference.md](reference.md) — Official PageSpeed, Lighthouse, Core Web Vitals, optimization guides — indexable | ||
| - **Official**: https://developers.google.com/speed/docs/insights/v5/about?hl=es-419 | ||
| - **PageSpeed Insights**: https://pagespeed.web.dev/ | ||
| - **Lighthouse**: Built into Chrome DevTools | ||
| - **Web Vitals**: https://web.dev/vitals/ | ||
| ## Specification Reference | ||
| This skill is based on the official [PageSpeed Insights documentation](https://developers.google.com/speed/docs/insights/v5/about?hl=es-419) from Google Developers. | ||
| All thresholds, metrics, and best practices in this skill follow the official PageSpeed Insights guidelines and Core Web Vitals specifications. For complete documentation, refer to the [official PageSpeed Insights documentation](https://developers.google.com/speed/docs/insights/v5/about?hl=es-419). |
+1
-1
| { | ||
| "name": "cc-codeconductor", | ||
| "version": "0.2.9", | ||
| "version": "0.2.10", | ||
| "description": "A multi-agent orchestration framework for AI-assisted software engineering workflows.", | ||
@@ -5,0 +5,0 @@ "keywords": [ |
@@ -286,4 +286,4 @@ # CodeConductor — Multi-Agent Orchestration Framework | ||
| 0. Create a Git Worktree for this session before opening any file for editing: | ||
| `git worktree add ../<branch>-session <branch>` | ||
| All changes happen inside this worktree. Never modify the main working tree directly. | ||
| `git worktree add ../<branch>-session <branch>` All changes happen inside | ||
| this worktree. Never modify the main working tree directly. | ||
| 1. Read the Technical Plan completely. | ||
@@ -298,3 +298,4 @@ 2. Read each file listed under "Files Affected." | ||
| - **Work in a worktree.** Create a session worktree before touching any file. | ||
| All edits happen inside it. Include the worktree path in the Implementation Summary. | ||
| All edits happen inside it. Include the worktree path in the Implementation | ||
| Summary. | ||
| - **Minimal diff.** Change only what the plan specifies. | ||
@@ -571,2 +572,10 @@ - **Follow existing patterns.** Match naming conventions, error handling, and | ||
| When the active task requires web performance analysis, Core Web Vitals | ||
| auditing, PageSpeed Insights data, or optimization of LCP, TBT, CLS, FCP, or | ||
| TTFB, apply `.claude/skills/pagespeed-perf/SKILL.md` and | ||
| `.claude/skills/pagespeed-insights/SKILL.md`. | ||
| When the user asks about discovering, searching, or installing agent skills or | ||
| extending capabilities, apply `.claude/skills/find-skills/SKILL.md`. | ||
| --- | ||
@@ -596,2 +605,3 @@ | ||
| - When using tools, be precise and minimal with context. | ||
| {{LANGUAGE_INSTRUCTIONS}} | ||
@@ -598,0 +608,0 @@ ## Context Budget |
| { | ||
| "$schema": "https://json.schemastore.org/claude-code-settings.json", | ||
| "env": { | ||
| "CLAUDE_CODE_ATTRIBUTION_HEADER": "0", | ||
| "CLAUDE_CODE_DISABLE_1M_CONTEXT": "1", | ||
| "CLAUDE_CODE_DISABLE_AUTO_MEMORY": "1", | ||
| "CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC": "1", | ||
| "CLAUDE_CODE_DISABLE_TERMINAL_TITLE": "1", | ||
| "DISABLE_EXTRA_USAGE_COMMAND": "1", | ||
| "DISABLE_TELEMETRY": "1", | ||
| "DISABLE_ERROR_REPORTING": "1", | ||
| "DISABLE_FEEDBACK_COMMAND": "1", | ||
| "CLAUDE_CODE_SIMPLE_SYSTEM_PROMPT": "1", | ||
| "ENABLE_TOOL_SEARCH": "auto", | ||
| "CLAUDE_AUTOCOMPACT_PCT_OVERRIDE": "80", | ||
| "CLAUDE_CODE_SUBPROCESS_ENV_SCRUB": "1", | ||
| "CLAUDE_CODE_SUBAGENT_MODEL": "haiku", | ||
| "CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS": "1", | ||
| "MAX_THINKING_TOKENS": "24000", | ||
| "DISABLE_BUG_COMMAND": "1" | ||
| }, | ||
| "attribution": { | ||
| "commit": "", | ||
| "pr": "" | ||
| }, | ||
| "includeCoAuthoredBy": false, | ||
| "includeGitInstructions": false, | ||
| "permissions": { | ||
@@ -12,5 +37,72 @@ "allow": [ | ||
| "Bash(npm test*)", | ||
| "Bash(npm run lint*)" | ||
| "Bash(npm run lint*)", | ||
| "Bash(ls *)", | ||
| "Bash(cat *)", | ||
| "Bash(grep *)", | ||
| "Bash(rg *)", | ||
| "Bash(find *)", | ||
| "Bash(tree *)", | ||
| "Bash(echo *)", | ||
| "Bash(pwd)", | ||
| "Bash(which *)", | ||
| "Bash(head *)", | ||
| "Bash(tail *)", | ||
| "Bash(wc *)", | ||
| "Bash(diff *)", | ||
| "Bash(git branch*)", | ||
| "Bash(git show*)", | ||
| "Bash(git add*)", | ||
| "Bash(git commit*)", | ||
| "Bash(git stash*)", | ||
| "Bash(git checkout*)", | ||
| "Bash(git restore*)", | ||
| "Bash(git pull*)", | ||
| "Bash(git fetch*)", | ||
| "Bash(git merge*)", | ||
| "Bash(npm run *)", | ||
| "Bash(npm ci)", | ||
| "Bash(pnpm run *)", | ||
| "Bash(pnpm test*)", | ||
| "Bash(pnpm exec *)", | ||
| "Bash(pnpm dlx *)", | ||
| "Bash(yarn run *)", | ||
| "Bash(yarn test*)", | ||
| "Bash(npx *)", | ||
| "Bash(python *)", | ||
| "Bash(python3 *)", | ||
| "Bash(pip list*)", | ||
| "Bash(pip show *)", | ||
| "Bash(pytest*)", | ||
| "Bash(ruff*)", | ||
| "Bash(black --check *)", | ||
| "Bash(./gradlew *)", | ||
| "Bash(gradle *)", | ||
| "Bash(mvn test*)", | ||
| "Bash(mvn compile*)", | ||
| "Bash(java -version)", | ||
| "Bash(kotlin -version)", | ||
| "Bash(docker ps*)", | ||
| "Bash(docker logs*)", | ||
| "Bash(docker compose ps*)", | ||
| "Bash(docker compose logs*)", | ||
| "Read(**)", | ||
| "Write(./src/**)", | ||
| "Write(./app/**)", | ||
| "Write(./pages/**)", | ||
| "Write(./components/**)", | ||
| "Write(./lib/**)", | ||
| "Write(./tests/**)", | ||
| "Write(./test/**)", | ||
| "Write(./__tests__/**)", | ||
| "Write(./prisma/**)", | ||
| "Write(./drizzle/**)", | ||
| "Write(./public/**)", | ||
| "Write(./styles/**)", | ||
| "Write(./scripts/**)", | ||
| "Write(./docs/**)", | ||
| "Edit(**)", | ||
| "WebFetch(*)" | ||
| ], | ||
| "deny": [ | ||
| "Agent(bypass-runner)", | ||
| "Bash(rm -rf *)", | ||
@@ -35,5 +127,160 @@ "Bash(sudo *)", | ||
| "Bash(git rebase *)", | ||
| "Bash(git reset --hard *)" | ||
| "Bash(git reset --hard *)", | ||
| "Bash(rm -fr *)", | ||
| "Bash(chmod -R *)", | ||
| "Bash(eval *)", | ||
| "Bash(git push --force origin main*)", | ||
| "Bash(git push --force origin master*)", | ||
| "Bash(git push -f origin main*)", | ||
| "Bash(git push -f origin master*)", | ||
| "Read(./.env)", | ||
| "Read(./.env.*)", | ||
| "Read(./**/.env)", | ||
| "Read(./**/.env.*)", | ||
| "Read(./secrets/**)", | ||
| "Read(./**/credentials.json)", | ||
| "Read(./**/serviceAccount*.json)", | ||
| "Read(./**/*.pem)", | ||
| "Read(./**/*.key)", | ||
| "Read(./**/id_rsa*)", | ||
| "Read(~/.ssh/**)", | ||
| "Read(~/.aws/**)", | ||
| "Read(~/.gnupg/**)", | ||
| "Write(./.env)", | ||
| "Write(./.env.*)", | ||
| "Write(./**/.env)", | ||
| "Edit(./.env)", | ||
| "Edit(./.env.*)", | ||
| "Edit(./**/.env)" | ||
| ], | ||
| "ask": [ | ||
| "Bash(git push*)", | ||
| "Bash(git push --force*)", | ||
| "Bash(git reset --hard*)", | ||
| "Bash(npm install*)", | ||
| "Bash(npm i *)", | ||
| "Bash(pnpm install*)", | ||
| "Bash(pnpm add *)", | ||
| "Bash(yarn add *)", | ||
| "Bash(pip install*)", | ||
| "Bash(docker run*)", | ||
| "Bash(docker compose up*)", | ||
| "Bash(docker compose down*)", | ||
| "Bash(./gradlew build*)", | ||
| "Bash(./gradlew bootRun*)", | ||
| "Bash(mvn install*)", | ||
| "Bash(mvn deploy*)", | ||
| "Bash(vercel*)", | ||
| "Bash(npx vercel*)" | ||
| ], | ||
| "defaultMode": "acceptEdits", | ||
| "disableBypassPermissionsMode": "disable" | ||
| }, | ||
| "hooks": { | ||
| "PostToolUse": [ | ||
| { | ||
| "matcher": "Write|Edit|MultiEdit", | ||
| "hooks": [ | ||
| { | ||
| "type": "command", | ||
| "command": "if echo \"$CLAUDE_TOOL_INPUT_FILE_PATH\" | grep -qE '\\.(ts|tsx|js|jsx|mjs|cjs|json|jsonc|md|mdx|css|scss|html|astro|yaml|yml)$'; then npx --no-install prettier --write \"$CLAUDE_TOOL_INPUT_FILE_PATH\" 2>/dev/null || true; fi" | ||
| }, | ||
| { | ||
| "type": "command", | ||
| "command": "if echo \"$CLAUDE_TOOL_INPUT_FILE_PATH\" | grep -qE '\\.(ts|tsx|js|jsx|mjs|cjs)$'; then npx --no-install eslint --fix \"$CLAUDE_TOOL_INPUT_FILE_PATH\" 2>/dev/null || true; fi" | ||
| }, | ||
| { | ||
| "type": "command", | ||
| "command": "if echo \"$CLAUDE_TOOL_INPUT_FILE_PATH\" | grep -qE '\\.py$'; then ruff format \"$CLAUDE_TOOL_INPUT_FILE_PATH\" 2>/dev/null && ruff check --fix \"$CLAUDE_TOOL_INPUT_FILE_PATH\" 2>/dev/null || true; fi" | ||
| } | ||
| ] | ||
| } | ||
| ], | ||
| "PreToolUse": [ | ||
| { | ||
| "matcher": "Bash", | ||
| "hooks": [ | ||
| { | ||
| "type": "command", | ||
| "command": "if echo \"$CLAUDE_TOOL_INPUT_COMMAND\" | grep -qE '(\\.env|secrets/|id_rsa|\\.pem|\\.key)\\b' && echo \"$CLAUDE_TOOL_INPUT_COMMAND\" | grep -qE '(cat|less|more|head|tail|cp |mv |scp )'; then echo 'Bloqueado: intento de leer archivos sensibles' >&2; exit 2; fi" | ||
| } | ||
| ] | ||
| } | ||
| ], | ||
| "SubagentStop": [ | ||
| { | ||
| "hooks": [ | ||
| { | ||
| "type": "command", | ||
| "command": "echo \"[subagent fin] $(date -Iseconds)\" >> ~/.claude/subagent.log" | ||
| } | ||
| ] | ||
| } | ||
| ] | ||
| }, | ||
| "sandbox": { | ||
| "enabled": false, | ||
| "failIfUnavailable": false, | ||
| "autoAllowBashIfSandboxed": true, | ||
| "network": { | ||
| "allowedDomains": [ | ||
| "github.com", | ||
| "*.githubusercontent.com", | ||
| "registry.npmjs.org", | ||
| "*.npmjs.org", | ||
| "registry.yarnpkg.com", | ||
| "pypi.org", | ||
| "*.pythonhosted.org", | ||
| "repo.maven.apache.org", | ||
| "repo1.maven.org", | ||
| "services.gradle.org", | ||
| "plugins.gradle.org", | ||
| "*.gradle.org", | ||
| "*.googleapis.com", | ||
| "api.anthropic.com" | ||
| ], | ||
| "allowLocalBinding": true | ||
| }, | ||
| "filesystem": { | ||
| "denyRead": [ | ||
| "~/.ssh", | ||
| "~/.aws", | ||
| "~/.gnupg", | ||
| "./.env", | ||
| "./.env.*" | ||
| ] | ||
| }, | ||
| "excludedCommands": [ | ||
| "docker *" | ||
| ] | ||
| }, | ||
| "extraKnownMarketplaces": { | ||
| "agricidaniel-claude-seo": { | ||
| "source": { | ||
| "source": "github", | ||
| "repo": "AgriciDaniel/claude-seo" | ||
| } | ||
| } | ||
| }, | ||
| "language": "spanish", | ||
| "feedbackSurveyRate": 0, | ||
| "spinnerTipsEnabled": false, | ||
| "alwaysThinkingEnabled": true, | ||
| "effortLevel": "xhigh", | ||
| "awaySummaryEnabled": false, | ||
| "showClearContextOnPlanAccept": true, | ||
| "autoUpdatesChannel": "stable", | ||
| "prefersReducedMotion": false, | ||
| "autoMemoryEnabled": false, | ||
| "showThinkingSummaries": true, | ||
| "skipDangerousModePermissionPrompt": true, | ||
| "editorMode": "vim", | ||
| "fileCheckpointingEnabled": true, | ||
| "showTurnDuration": true, | ||
| "terminalProgressBarEnabled": true, | ||
| "autoConnectIde": true, | ||
| "autoInstallIdeExtension": false, | ||
| "enabledPlugins": { | ||
| "claude-seo@agricidaniel-claude-seo": true | ||
| } | ||
| } |
+19
-14
@@ -37,12 +37,13 @@ <!-- CODECONDUCTOR:BEGIN managed --> | ||
| | Workflow | Trigger phrase | | ||
| | ------------ | ------------------------------------------------- | | ||
| | Full feature | "Run the feature workflow for: [description]" | | ||
| | Bug fix | "Run the fix workflow for: [description]" | | ||
| | Refactor | "Run the refactor workflow for: [scope]" | | ||
| | API contract | "Run the API contract workflow for: [change]" | | ||
| | Workflow | Trigger phrase | | ||
| | ------------ | -------------------------------------------------- | | ||
| | Full feature | "Run the feature workflow for: [description]" | | ||
| | Bug fix | "Run the fix workflow for: [description]" | | ||
| | Refactor | "Run the refactor workflow for: [scope]" | | ||
| | API contract | "Run the API contract workflow for: [change]" | | ||
| | DB migration | "Run the database migration workflow for: [scope]" | | ||
| | Code review | "Run a structured review of: [target]" | | ||
| | Test plan | "Create a test plan for: [scope]" | | ||
| | Task intake | "Help me define a Task Card for: [vague request]" | | ||
| | Code review | "Run a structured review of: [target]" | | ||
| | Test plan | "Create a test plan for: [scope]" | | ||
| | Task intake | "Help me define a Task Card for: [vague request]" | | ||
| | PageSpeed | "Run a PageSpeed audit for: [url]" | | ||
@@ -377,3 +378,4 @@ --- | ||
| **Does not:** Design architecture. Force push. Declare done before running tests. | ||
| **Does not:** Design architecture. Force push. Declare done before running | ||
| tests. | ||
@@ -385,4 +387,4 @@ **Model:** `{{MODEL_CODEX}}` | ||
| 0. Create a Git Worktree for this session before opening any file for editing: | ||
| `git worktree add ../<branch>-session <branch>` | ||
| All changes happen inside this worktree. Never modify the main working tree directly. | ||
| `git worktree add ../<branch>-session <branch>` All changes happen inside | ||
| this worktree. Never modify the main working tree directly. | ||
| 1. Read the Technical Plan completely. | ||
@@ -397,3 +399,4 @@ 2. Read each file listed under "Files Affected." | ||
| - **Work in a worktree.** Create a session worktree before touching any file. | ||
| All edits happen inside it. Include the worktree path in the Implementation Summary. | ||
| All edits happen inside it. Include the worktree path in the Implementation | ||
| Summary. | ||
| - **Minimal diff.** Change only what the plan specifies. | ||
@@ -597,3 +600,4 @@ - **Follow existing patterns.** Match naming conventions, error handling, and | ||
| **Does not:** Write implementation code. Document behavior that was not implemented. Omit CHANGELOG entries. | ||
| **Does not:** Write implementation code. Document behavior that was not | ||
| implemented. Omit CHANGELOG entries. | ||
@@ -887,2 +891,3 @@ **Model:** `{{MODEL_CODEX}}` | ||
| - When using tools, be precise and minimal with context. | ||
| {{LANGUAGE_INSTRUCTIONS}} | ||
@@ -889,0 +894,0 @@ ## Context Budget |
@@ -49,12 +49,12 @@ # OpenCode Preset for CodeConductor | ||
| | Agent | Mode | Description | | ||
| | ----------------- | --------- | ---------------------------------------------------- | | ||
| | **Orchestrator** | primary | Main coordinator — Tab to switch to it | | ||
| | **Architect** | subagent | Invoked by Orchestrator for design work | | ||
| | **Implementer** | subagent | Invoked by Orchestrator for code implementation | | ||
| | **Tester** | subagent | Invoked by Orchestrator for test generation | | ||
| | **Reviewer** | subagent | Invoked by Orchestrator for code review | | ||
| | **Task Coach** | subagent | Invoked by Orchestrator for intake clarification | | ||
| | **Docs** | subagent | Invoked by Orchestrator for documentation updates | | ||
| | **Repo Explorer** | subagent | Invoked by Orchestrator for codebase exploration | | ||
| | Agent | Mode | Description | | ||
| | ----------------- | -------- | ------------------------------------------------- | | ||
| | **Orchestrator** | primary | Main coordinator — Tab to switch to it | | ||
| | **Architect** | subagent | Invoked by Orchestrator for design work | | ||
| | **Implementer** | subagent | Invoked by Orchestrator for code implementation | | ||
| | **Tester** | subagent | Invoked by Orchestrator for test generation | | ||
| | **Reviewer** | subagent | Invoked by Orchestrator for code review | | ||
| | **Task Coach** | subagent | Invoked by Orchestrator for intake clarification | | ||
| | **Docs** | subagent | Invoked by Orchestrator for documentation updates | | ||
| | **Repo Explorer** | subagent | Invoked by Orchestrator for codebase exploration | | ||
@@ -187,2 +187,3 @@ --- | ||
| - When using tools, be precise and minimal with context. | ||
| {{LANGUAGE_INSTRUCTIONS}} | ||
@@ -189,0 +190,0 @@ ## Context Budget |
@@ -5,2 +5,6 @@ # SEO Audit | ||
| > Spanish prose/docs/reports/Markdown: preserve natural Spanish orthography, | ||
| > including accents, `ñ`, `¿`, `¡`, and normal Unicode. The ASCII-only editing | ||
| > preference does not apply to these artifacts. | ||
| ## Usage | ||
@@ -16,11 +20,11 @@ | ||
| | Parameter | Required | Description | | ||
| |-----------|----------|-------------| | ||
| | `--url` | One of `--url` or `--sitemap` | Single URL to audit | | ||
| | Parameter | Required | Description | | ||
| | ----------- | ----------------------------- | -------------------------------------------------------------- | | ||
| | `--url` | One of `--url` or `--sitemap` | Single URL to audit | | ||
| | `--sitemap` | One of `--url` or `--sitemap` | Remote sitemap XML URL. Only URLs listed here will be audited. | | ||
| | `--format` | No | Output format: `cli` (default) or `json` | | ||
| | `--fail-on` | No | Exit code trigger: `error` (default) or `warning` | | ||
| | `--astro` | No | Run Astro-specific SEO validation on source code | | ||
| | `--path` | With `--astro` | Path to Astro source directory | | ||
| | `--delay` | No | Delay between requests in ms (default: 500) | | ||
| | `--format` | No | Output format: `cli` (default) or `json` | | ||
| | `--fail-on` | No | Exit code trigger: `error` (default) or `warning` | | ||
| | `--astro` | No | Run Astro-specific SEO validation on source code | | ||
| | `--path` | With `--astro` | Path to Astro source directory | | ||
| | `--delay` | No | Delay between requests in ms (default: 500) | | ||
@@ -60,3 +64,4 @@ ## Workflow | ||
| - **Sitemap-scoped only.** When `--sitemap` is provided, only audit URLs from the sitemap. | ||
| - **Sitemap-scoped only.** When `--sitemap` is provided, only audit URLs from | ||
| the sitemap. | ||
| - **No external crawling.** Never follow hyperlinks found on pages. | ||
@@ -91,1 +96,4 @@ - **GET only.** No POST, PUT, DELETE requests. | ||
| - `off-page` — Off-page SEO strategy guidance | ||
| - `pagespeed-insights` — Audit web pages for performance optimization following | ||
| PageSpeed Insights guidelines | ||
| - `find-skills` — Discover and install agent skills |
+105
-25
@@ -39,2 +39,11 @@ # CodeConductor | ||
| > for AI-search readiness from sitemap content | ||
| > - `/cc-pagespeed --url <url>` — audits web performance using the PageSpeed | ||
| > Insights API; applies the 80/20 principle to produce a prioritized report of | ||
| > Core Web Vitals (LCP, TBT, CLS, FCP, TTFB) with framework-specific fixes; | ||
| > requires `PAGESPEED_API_KEY` env var for full CrUX field data (optional but | ||
| > recommended) | ||
| > - `npx cc-codeconductor install preset --target <opencode|claude|codex|all>` — | ||
| > installs the full preset (agents, prompts, skills, commands, settings) for the | ||
| > chosen runner; use `--locale=es` to inject Spanish-aware instructions into | ||
| > agent files, or rely on the locale saved during `init` | ||
| > - Manual presets for OpenCode, Claude Code, and Codex | ||
@@ -115,3 +124,3 @@ > - Versioned Agent Contracts | ||
| - OpenCode preset | ||
| - Claude Code-compatible preset | ||
| - Claude Code-compatible preset (see [Claude Environment Options & Best Practices](file:///c:/Users/R2D2/Documents/GitHub/codeconductor/docs/claude-env-options.md)) | ||
| - Codex preset | ||
@@ -149,2 +158,4 @@ - Spring Boot / Kotlin workflow | ||
| npx cc-codeconductor init --dry-run # preview without writing | ||
| npx cc-codeconductor init --locale=es # set Spanish as the instruction language | ||
| npx cc-codeconductor init --locale=en # set English (default) | ||
| ``` | ||
@@ -156,2 +167,9 @@ | ||
| > [!IMPORTANT] | ||
| > | ||
| > **`--locale` is remembered.** Once you run `init --locale=es`, the value is | ||
| > saved to `.codeconductor/config.yml`. Every subsequent `install preset` will | ||
| > automatically use that locale — no need to repeat the flag. To change it, | ||
| > run `init --locale=en --force` or edit `defaults.locale` in your config. | ||
| #### `detect` — detect project stack | ||
@@ -173,5 +191,37 @@ | ||
| #### `install` — install council preset | ||
| #### `install preset` — install full agent preset | ||
| ```bash | ||
| npx cc-codeconductor install preset --target opencode # project-level | ||
| npx cc-codeconductor install preset --target claude | ||
| npx cc-codeconductor install preset --target codex | ||
| npx cc-codeconductor install preset --target all # all targets | ||
| npx cc-codeconductor install preset --target claude --global # write to ~/.claude/ | ||
| npx cc-codeconductor install preset --target all --global | ||
| npx cc-codeconductor install preset --target claude --locale=es # override locale once | ||
| npx cc-codeconductor install preset --target all --dry-run # preview | ||
| npx cc-codeconductor install preset --target claude --force # overwrite | ||
| ``` | ||
| Locale resolution order (first match wins): | ||
| 1. `--locale` flag on the command line | ||
| 2. `defaults.locale` in `.codeconductor/config.yml` (set by `init --locale`) | ||
| 3. `en` (built-in default) | ||
| Files installed per target: | ||
| | Target | Notable files | | ||
| | ---------- | ---------------------------------------------------------------- | | ||
| | `claude` | `.claude/CLAUDE.md`, `.claude/settings.json`, `.claude/agents/` | | ||
| | `opencode` | `.opencode/agents/`, `.opencode/commands/`, `.opencode/skills/` | | ||
| | `codex` | `.codex/AGENTS.md`, `.codex/skills/`, `.codex/prompts/` | | ||
| With `--global`, files are written under `~/` instead of `./`. | ||
| #### `install council` — install council spec | ||
| ```bash | ||
| npx cc-codeconductor install council --target opencode # project-level | ||
@@ -190,12 +240,2 @@ npx cc-codeconductor install council --target claude | ||
| Files generated per target: | ||
| | Target | Files written | | ||
| | ---------- | ---------------------------------------------------------------- | | ||
| | `opencode` | `.opencode/commands/cc-council.md`, `.opencode/agents/council-*.md` | | ||
| | `claude` | `.claude/skills/council/SKILL.md`, `.claude/agents/council-*.md` | | ||
| | `codex` | `.codex/config.toml`, `.codex/agents/council_*.toml` | | ||
| With `--global`, the same files are written under `~/` instead of `./`. | ||
| #### `install lsp` — install and configure LSP servers | ||
@@ -235,8 +275,9 @@ | ||
| | Flag | Description | | ||
| | --------------- | ---------------------------------------- | | ||
| | `--force` | Overwrite existing files | | ||
| | `--dry-run` | Preview actions without writing | | ||
| | `--global` | Target home directory instead of project | | ||
| | `--output json` | Machine-readable JSON output | | ||
| | Flag | Description | | ||
| | ---------------- | -------------------------------------------------------- | | ||
| | `--force` | Overwrite existing files | | ||
| | `--dry-run` | Preview actions without writing | | ||
| | `--global` | Target home directory instead of project | | ||
| | `--output json` | Machine-readable JSON output | | ||
| | `--locale=en` | Agent instruction language: `en` (default) or `es` | | ||
@@ -249,3 +290,3 @@ ### Config directory | ||
| .codeconductor/ | ||
| ├── config.yml # project settings, target, preset versions | ||
| ├── config.yml # project settings, target, locale, preset versions | ||
| └── presets/ | ||
@@ -256,2 +297,10 @@ ├── council.yml # customizable copy of the council preset | ||
| Key fields in `config.yml`: | ||
| ```yaml | ||
| defaults: | ||
| target: opencode # default runner for install/update | ||
| locale: es # instruction language injected into agent files | ||
| ``` | ||
| Edit `.codeconductor/presets/council.yml` to add, remove, or reconfigure agents | ||
@@ -272,9 +321,10 @@ before running `install`. | ||
| Agent template files contain placeholders that are replaced during `install`: | ||
| Agent template files contain placeholders replaced during `install`: | ||
| | Placeholder | Description | | ||
| | -------------------- | ------------------------------- | | ||
| | `{{MODEL_CLAUDE}}` | Model for the Claude provider | | ||
| | `{{MODEL_OPENCODE}}` | Model for the OpenCode provider | | ||
| | `{{MODEL_CODEX}}` | Model for the Codex provider | | ||
| | Placeholder | Description | | ||
| | ------------------------------ | --------------------------------------------- | | ||
| | `{{MODEL_CLAUDE}}` | Model for the Claude provider | | ||
| | `{{MODEL_OPENCODE}}` | Model for the OpenCode provider | | ||
| | `{{MODEL_CODEX}}` | Model for the Codex provider | | ||
| | `{{LANGUAGE_INSTRUCTIONS}}` | Locale-aware instruction injected by `locale` | | ||
@@ -284,2 +334,32 @@ To customize models, edit the YAML file for your target before running | ||
| #### Instruction Language (`--locale`) | ||
| Agent markdown files (`CLAUDE.md`, `AGENTS.md`, `README.md`) include a | ||
| `{{LANGUAGE_INSTRUCTIONS}}` placeholder that is replaced at install time based | ||
| on the active locale: | ||
| | Locale | Injected instruction | | ||
| | ------ | -------------------- | | ||
| | `en` | *Prose/docs/code comments: be terse and direct. Prefer concrete nouns over abstract ones. Omit filler phrases. One idea per sentence.* | | ||
| | `es` | *Spanish prose/docs/reports/Markdown: preserve natural Spanish orthography, including accents, `ñ`, `¿`, `¡`, and normal Unicode. The ASCII-only editing preference does not apply to these artifacts.* | | ||
| The locale is **sticky**: set it once with `init --locale=es` and every | ||
| subsequent `install preset` will use it automatically. Override per-run with | ||
| `install preset --locale=en`. | ||
| ```bash | ||
| # One-time setup | ||
| npx cc-codeconductor init --locale=es | ||
| # All future installs use Spanish automatically | ||
| npx cc-codeconductor install preset --target=claude | ||
| npx cc-codeconductor install preset --target=all --global | ||
| # Override just this run | ||
| npx cc-codeconductor install preset --target=claude --locale=en | ||
| # Change the saved locale | ||
| npx cc-codeconductor init --locale=en --force | ||
| ``` | ||
| --- | ||
@@ -286,0 +366,0 @@ |
| target: agy | ||
| entries: | ||
| - src: agy/AGENTS.md | ||
| dest: .agents/AGENTS.md | ||
| strategy: merge-managed | ||
| template: true | ||
| - src: agy/rules | ||
| dest: .agents/rules | ||
| strategy: overwrite | ||
| template: true | ||
| - src: agy/workflows | ||
| dest: .agents/workflows | ||
| strategy: overwrite | ||
| template: true | ||
| - src: agy/settings.json | ||
| dest: .agents/../antigravity-cli/settings.json | ||
| strategy: skip | ||
| globalStrategy: merge-json | ||
| - src: agy/hooks.json | ||
| dest: .agents/hooks.json | ||
| strategy: overwrite | ||
| - src: agy/mcp_config.json | ||
| dest: .agents/mcp_config.json | ||
| strategy: overwrite | ||
| - src: agy/scripts | ||
| dest: .agents/scripts | ||
| strategy: overwrite | ||
| - src: opencode/skills | ||
| dest: .agents/skills | ||
| strategy: overwrite | ||
| - src: agy/skills | ||
| dest: .agents/skills | ||
| strategy: overwrite | ||
| template: true | ||
| - src: opencode/agents | ||
| dest: .agy/agents | ||
| dest: .agents/agents | ||
| strategy: overwrite | ||
| template: true | ||
| - src: opencode/prompts/v0.2.0 | ||
| dest: .agy/prompts/v0.2.0 | ||
| dest: .agents/prompts/v0.2.0 | ||
| strategy: overwrite | ||
@@ -7,2 +7,3 @@ target: claude | ||
| globalStrategy: append | ||
| template: true | ||
| - src: claude/settings.json | ||
@@ -12,2 +13,6 @@ dest: .claude/settings.json | ||
| globalStrategy: merge-json | ||
| - src: claude/claude.json | ||
| dest: .claude.json | ||
| strategy: merge-json | ||
| globalStrategy: merge-json | ||
| - src: claude/commands | ||
@@ -14,0 +19,0 @@ dest: .claude/commands |
@@ -7,2 +7,6 @@ target: opencode | ||
| globalStrategy: merge-json | ||
| - src: opencode/README.md | ||
| dest: .opencode/README.md | ||
| strategy: overwrite | ||
| template: true | ||
| - src: opencode/agents | ||
@@ -9,0 +13,0 @@ dest: .opencode/agents |
@@ -60,1 +60,17 @@ # Model configuration for Agy preset (experimental) | ||
| agy: gemini-2.5-flash | ||
| tools: | ||
| Read: | ||
| agy: view_file | ||
| Write: | ||
| agy: write_to_file | ||
| Edit: | ||
| agy: replace_file_content / multi_replace_file_content | ||
| Bash: | ||
| agy: run_command | ||
| Glob: | ||
| agy: list_dir | ||
| Grep: | ||
| agy: grep_search | ||
| WebFetch: | ||
| agy: read_url_content / read_browser_page | ||
Sorry, the diff of this file is too big to display
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
1802587
38.27%189
70.27%20269
33.68%424
23.26%