Add file proxy tool plugin, add research agent, update framework config
This commit is contained in:
		
							parent
							
								
									02f7a3b960
								
							
						
					
					
						commit
						5d59b44cd5
					
				
							
								
								
									
										17
									
								
								flake.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										17
									
								
								flake.lock
									
									
									
										generated
									
									
									
								
							@ -80,6 +80,22 @@
 | 
			
		||||
        "type": "github"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "nixos-hardware": {
 | 
			
		||||
      "locked": {
 | 
			
		||||
        "lastModified": 1761759700,
 | 
			
		||||
        "narHash": "sha256-zuiwvKAPwtMmwf44tb7Q7Y5d7JkBeuaF89PISUnkWA8=",
 | 
			
		||||
        "owner": "NixOS",
 | 
			
		||||
        "repo": "nixos-hardware",
 | 
			
		||||
        "rev": "2379bc40992ec29feb1933bb4acd224fa055f3f8",
 | 
			
		||||
        "type": "github"
 | 
			
		||||
      },
 | 
			
		||||
      "original": {
 | 
			
		||||
        "owner": "NixOS",
 | 
			
		||||
        "ref": "master",
 | 
			
		||||
        "repo": "nixos-hardware",
 | 
			
		||||
        "type": "github"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "nixpkgs": {
 | 
			
		||||
      "locked": {
 | 
			
		||||
        "lastModified": 1744463964,
 | 
			
		||||
@ -169,6 +185,7 @@
 | 
			
		||||
        "auto-cpufreq": "auto-cpufreq",
 | 
			
		||||
        "catppuccin": "catppuccin",
 | 
			
		||||
        "home-manager": "home-manager",
 | 
			
		||||
        "nixos-hardware": "nixos-hardware",
 | 
			
		||||
        "nixpkgs": "nixpkgs_2",
 | 
			
		||||
        "nixpkgs-unstable": "nixpkgs-unstable",
 | 
			
		||||
        "nur": "nur"
 | 
			
		||||
 | 
			
		||||
@ -15,9 +15,10 @@
 | 
			
		||||
      url = "github:AdnanHodzic/auto-cpufreq";
 | 
			
		||||
      inputs.nixpkgs.follows = "nixpkgs";
 | 
			
		||||
    };
 | 
			
		||||
    nixos-hardware.url = "github:NixOS/nixos-hardware/master";
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  outputs = { self, nixpkgs, nixpkgs-unstable, catppuccin, nur, home-manager, auto-cpufreq, ... } @ inputs:
 | 
			
		||||
  outputs = { self, nixpkgs, nixpkgs-unstable, catppuccin, nur, home-manager, auto-cpufreq, nixos-hardware, ... } @ inputs:
 | 
			
		||||
  let
 | 
			
		||||
    inherit (self) outputs;
 | 
			
		||||
    system = "x86_64-linux";
 | 
			
		||||
 | 
			
		||||
@ -9,6 +9,7 @@
 | 
			
		||||
  in
 | 
			
		||||
{
 | 
			
		||||
  imports = [
 | 
			
		||||
      inputs.nixos-hardware.nixosModules.framework-12-13th-gen-intel
 | 
			
		||||
      ./desktop-configuration.nix
 | 
			
		||||
      ./nixos/hardware-configuration.nix
 | 
			
		||||
  ];
 | 
			
		||||
 | 
			
		||||
@ -54,6 +54,7 @@
 | 
			
		||||
    python310
 | 
			
		||||
    unstable.claude-code
 | 
			
		||||
    unstable.opencode
 | 
			
		||||
    nodejs_24
 | 
			
		||||
    ### LSP's
 | 
			
		||||
    nil
 | 
			
		||||
    nodePackages_latest.bash-language-server
 | 
			
		||||
@ -168,6 +169,7 @@
 | 
			
		||||
    "waybar".source = config.lib.file.mkOutOfStoreSymlink "/home/nate/nixos/frame12/linked-dotfiles/waybar";
 | 
			
		||||
    # Shared
 | 
			
		||||
    "helix".source = config.lib.file.mkOutOfStoreSymlink "/home/nate/nixos/shared/linked-dotfiles/helix";
 | 
			
		||||
    "opencode".source = config.lib.file.mkOutOfStoreSymlink "/home/nate/nixos/shared/linked-dotfiles/opencode";
 | 
			
		||||
    
 | 
			
		||||
    # Theme configuration
 | 
			
		||||
    "gtk-4.0/assets".source = "${config.gtk.theme.package}/share/themes/${config.gtk.theme.name}/gtk-4.0/assets";
 | 
			
		||||
 | 
			
		||||
@ -7,13 +7,11 @@ tools:
 | 
			
		||||
  write: true
 | 
			
		||||
  edit: true
 | 
			
		||||
  bash: true
 | 
			
		||||
  memory_store: true
 | 
			
		||||
  memory_search: true
 | 
			
		||||
  memory_list: true
 | 
			
		||||
permission:
 | 
			
		||||
  bash:
 | 
			
		||||
    "git add *": allow
 | 
			
		||||
    "git commit *": allow
 | 
			
		||||
    "git status": allow
 | 
			
		||||
    "git diff *": allow
 | 
			
		||||
    "git log *": allow
 | 
			
		||||
    "rg *": allow
 | 
			
		||||
    "grep *": allow
 | 
			
		||||
    "cat *": allow
 | 
			
		||||
@ -22,6 +20,7 @@ permission:
 | 
			
		||||
    "test *": allow
 | 
			
		||||
    "make *": allow
 | 
			
		||||
    "ls *": allow
 | 
			
		||||
    "wc *": allow
 | 
			
		||||
    "*": ask
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
@ -119,6 +118,24 @@ For each identified issue, determine target component:
 | 
			
		||||
 | 
			
		||||
For each improvement, execute changes:
 | 
			
		||||
 | 
			
		||||
#### Config File Editing Tools
 | 
			
		||||
 | 
			
		||||
**When editing ~/.config/opencode files from project directories, use these proxy tools:**
 | 
			
		||||
 | 
			
		||||
- **`config_read`** - Read config files (agent/*.md, skills/*/SKILL.md, etc.)
 | 
			
		||||
- **`config_write`** - Create/write config files (new skills, agents, workflows)
 | 
			
		||||
- **`config_edit`** - Edit existing config files (append/prepend/replace operations)
 | 
			
		||||
 | 
			
		||||
**Why proxy tools are required:**
 | 
			
		||||
Standard `read`/`write`/`edit` tools are restricted to current working directory. When you're running from a project directory (e.g., `/home/nate/source/my-project`), you cannot edit `~/.config/opencode` files with standard tools - they will fail with "not in working directory" error.
 | 
			
		||||
 | 
			
		||||
**Path formats:**
 | 
			
		||||
- Relative: `agent/optimize.md` (auto-resolves to ~/.config/opencode/agent/optimize.md)
 | 
			
		||||
- Tilde: `~/.config/opencode/skills/skill-name/SKILL.md`
 | 
			
		||||
- Absolute: `/home/nate/.config/opencode/OPTIMIZATION_WORKFLOW.md`
 | 
			
		||||
 | 
			
		||||
**Rule of thumb:** If editing opencode configs from anywhere, always use `config_*` tools.
 | 
			
		||||
 | 
			
		||||
#### 1. Update Documentation (CLAUDE.md, AGENTS.md)
 | 
			
		||||
 | 
			
		||||
**Read existing structure first**:
 | 
			
		||||
@ -144,24 +161,14 @@ nix flake check
 | 
			
		||||
# Test without building (NEW - added from session learning)
 | 
			
		||||
nix build .#nixosConfigurations.<hostname>.config.system.build.toplevel --dry-run
 | 
			
		||||
```
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
**Commit immediately after each doc update**:
 | 
			
		||||
```bash
 | 
			
		||||
git add AGENTS.md
 | 
			
		||||
git commit -m "optimize: Add dry-run build command to AGENTS.md
 | 
			
		||||
 | 
			
		||||
Session identified repeated use of dry-run validation.
 | 
			
		||||
Added to build commands for future reference.
 | 
			
		||||
 | 
			
		||||
Session: <session-context>"
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
#### 2. Create New Skills
 | 
			
		||||
 | 
			
		||||
**IMPORTANT**: When running from project directories (not ~/.config/opencode), use `config_write` tool instead of standard `write` tool.
 | 
			
		||||
 | 
			
		||||
**Use create-skill workflow**:
 | 
			
		||||
1. Determine skill name (gerund form: `doing-thing`)
 | 
			
		||||
2. Create directory: `~/.config/opencode/skills/skill-name/`
 | 
			
		||||
2. Create directory and file using `config_write` tool
 | 
			
		||||
3. Write SKILL.md with proper frontmatter
 | 
			
		||||
4. Keep concise (<500 lines)
 | 
			
		||||
5. Follow create-skill checklist
 | 
			
		||||
@ -201,6 +208,21 @@ Brief overview (1-2 sentences).
 | 
			
		||||
[What goes wrong + fixes]
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
**Create skill with config_write**:
 | 
			
		||||
```javascript
 | 
			
		||||
config_write({
 | 
			
		||||
  filePath: "skills/skill-name/SKILL.md",
 | 
			
		||||
  content: `---
 | 
			
		||||
name: skill-name
 | 
			
		||||
description: Use when [triggers/symptoms] - [what it does and helps with]
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
# Skill Title
 | 
			
		||||
 | 
			
		||||
[Complete skill content here]`
 | 
			
		||||
})
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
**Validate skill**:
 | 
			
		||||
```bash
 | 
			
		||||
# Check frontmatter and structure
 | 
			
		||||
@ -210,19 +232,10 @@ cat ~/.config/opencode/skills/skill-name/SKILL.md
 | 
			
		||||
wc -l ~/.config/opencode/skills/skill-name/SKILL.md
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
**Commit skill**:
 | 
			
		||||
```bash
 | 
			
		||||
git add ~/.config/opencode/skills/skill-name/
 | 
			
		||||
git commit -m "optimize: Create skill-name skill
 | 
			
		||||
 | 
			
		||||
Captures [pattern/workflow] identified in session.
 | 
			
		||||
Provides [key benefit].
 | 
			
		||||
 | 
			
		||||
Session: <session-context>"
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
#### 3. Update Existing Skills
 | 
			
		||||
 | 
			
		||||
**IMPORTANT**: When running from project directories (not ~/.config/opencode), use `config_edit` tool instead of standard `edit` tool.
 | 
			
		||||
 | 
			
		||||
**When to update**:
 | 
			
		||||
- Missing edge case identified
 | 
			
		||||
- New example would help
 | 
			
		||||
@ -239,9 +252,9 @@ Session: <session-context>"
 | 
			
		||||
- Don't rewrite entire skill
 | 
			
		||||
- Add focused content only
 | 
			
		||||
- Preserve existing structure
 | 
			
		||||
- Use Edit tool for precision
 | 
			
		||||
- Use config_edit for precision edits
 | 
			
		||||
 | 
			
		||||
**Example update**:
 | 
			
		||||
**Example update with config_edit**:
 | 
			
		||||
```markdown
 | 
			
		||||
## Common Mistakes
 | 
			
		||||
 | 
			
		||||
@ -253,17 +266,6 @@ Skills are loaded at startup. After creating/modifying skills:
 | 
			
		||||
2. Verify with: `opencode run "Use learn_skill with skill_name='skill-name'..."`
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
**Commit update**:
 | 
			
		||||
```bash
 | 
			
		||||
git add ~/.config/opencode/skills/skill-name/SKILL.md
 | 
			
		||||
git commit -m "optimize: Update skill-name skill with restart reminder
 | 
			
		||||
 | 
			
		||||
Session revealed confusion about skill loading.
 | 
			
		||||
Added reminder to restart OpenCode after changes.
 | 
			
		||||
 | 
			
		||||
Session: <session-context>"
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
#### 4. Create Shell Automation
 | 
			
		||||
 | 
			
		||||
**Identify candidates**:
 | 
			
		||||
@ -286,18 +288,6 @@ Recommended aliases for this project:
 | 
			
		||||
alias nix-check='nix flake check'
 | 
			
		||||
alias nix-dry='nix build .#nixosConfigurations.$(hostname).config.system.build.toplevel --dry-run'
 | 
			
		||||
```
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
**Commit**:
 | 
			
		||||
```bash
 | 
			
		||||
git add AGENTS.md
 | 
			
		||||
git commit -m "optimize: Add shell alias recommendations
 | 
			
		||||
 | 
			
		||||
Session used these commands 5+ times.
 | 
			
		||||
Adding to shell config recommendations.
 | 
			
		||||
 | 
			
		||||
Session: <session-context>"
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
#### 5. Update Agent Definitions
 | 
			
		||||
 | 
			
		||||
@ -315,17 +305,6 @@ Session: <session-context>"
 | 
			
		||||
- Test agent still loads correctly
 | 
			
		||||
- Document reason for change
 | 
			
		||||
 | 
			
		||||
**Commit**:
 | 
			
		||||
```bash
 | 
			
		||||
git add agent/agent-name.md
 | 
			
		||||
git commit -m "optimize: Refine agent-name agent permissions
 | 
			
		||||
 | 
			
		||||
Session revealed need for [specific permission].
 | 
			
		||||
Added to allow list for smoother workflow.
 | 
			
		||||
 | 
			
		||||
Session: <session-context>"
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Phase 4: Validation
 | 
			
		||||
 | 
			
		||||
After making changes, validate they work:
 | 
			
		||||
@ -334,9 +313,6 @@ After making changes, validate they work:
 | 
			
		||||
```bash
 | 
			
		||||
# Check markdown syntax
 | 
			
		||||
cat CLAUDE.md AGENTS.md
 | 
			
		||||
 | 
			
		||||
# Verify formatting is consistent
 | 
			
		||||
git diff
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
**Skills**:
 | 
			
		||||
@ -347,15 +323,6 @@ opencode run "Use learn_skill with skill_name='skill-name' - load skill and give
 | 
			
		||||
# Verify frontmatter appears in output
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
**Git state**:
 | 
			
		||||
```bash
 | 
			
		||||
# Verify all changes committed
 | 
			
		||||
git status
 | 
			
		||||
 | 
			
		||||
# Review commit history
 | 
			
		||||
git log --oneline -5
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Phase 5: Reporting
 | 
			
		||||
 | 
			
		||||
Generate final report showing what was implemented:
 | 
			
		||||
@ -379,11 +346,6 @@ Generate final report showing what was implemented:
 | 
			
		||||
### Agent Refinements
 | 
			
		||||
- ✅ Updated `agent-name` agent - [change]
 | 
			
		||||
 | 
			
		||||
## Git Commits
 | 
			
		||||
- commit-hash-1: [message]
 | 
			
		||||
- commit-hash-2: [message]
 | 
			
		||||
- commit-hash-3: [message]
 | 
			
		||||
 | 
			
		||||
## Next Session Benefits
 | 
			
		||||
 | 
			
		||||
These improvements prevent:
 | 
			
		||||
@ -415,9 +377,8 @@ alias nix-check
 | 
			
		||||
 | 
			
		||||
## Summary
 | 
			
		||||
 | 
			
		||||
Implemented [N] systemic improvements in [M] git commits.
 | 
			
		||||
Implemented [N] systemic improvements.
 | 
			
		||||
Next session will benefit from these preventive measures.
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## Decision Framework
 | 
			
		||||
 | 
			
		||||
@ -464,7 +425,6 @@ Next session will benefit from these preventive measures.
 | 
			
		||||
- Creating new skills (you're an expert at this)
 | 
			
		||||
- Updating skill "Common Mistakes" sections
 | 
			
		||||
- Documenting shell aliases
 | 
			
		||||
- Standard git commits
 | 
			
		||||
 | 
			
		||||
**Ask first** (potentially risky):
 | 
			
		||||
- Deleting content from docs/skills
 | 
			
		||||
@ -473,7 +433,7 @@ Next session will benefit from these preventive measures.
 | 
			
		||||
- Making changes outside typical directories
 | 
			
		||||
- Anything that feels destructive
 | 
			
		||||
 | 
			
		||||
**When in doubt**: Show `git diff`, explain change, ask for approval, then commit.
 | 
			
		||||
**When in doubt**: Explain the change and ask for approval.
 | 
			
		||||
 | 
			
		||||
## Handling Performance Pressure
 | 
			
		||||
 | 
			
		||||
@ -493,38 +453,46 @@ Next session will benefit from these preventive measures.
 | 
			
		||||
 | 
			
		||||
**Remember**: Your value is in preventing future disruption, not impressing with change volume.
 | 
			
		||||
 | 
			
		||||
## Memory / WIP Tool Preparation
 | 
			
		||||
## Memory Tool Usage
 | 
			
		||||
 | 
			
		||||
**Current state**: No official memory tool exists yet
 | 
			
		||||
After implementing each optimization, use the `memory_store` tool to track changes for long-term learning.
 | 
			
		||||
 | 
			
		||||
**What you should do now**:
 | 
			
		||||
1. Create structured logs of improvements (your commit messages do this)
 | 
			
		||||
2. Use consistent commit message format for easy querying later
 | 
			
		||||
3. Git history serves as memory (searchable with `git log --grep`)
 | 
			
		||||
**What to store**:
 | 
			
		||||
- High-impact improvements made
 | 
			
		||||
- Recurring patterns identified across sessions
 | 
			
		||||
- Effectiveness of previous changes
 | 
			
		||||
- Cross-project patterns discovered
 | 
			
		||||
- Decisions about when to create skills vs update docs
 | 
			
		||||
 | 
			
		||||
**Future integration**: When memory/WIP tool arrives:
 | 
			
		||||
- Track recurring patterns across sessions
 | 
			
		||||
- Measure improvement effectiveness
 | 
			
		||||
- Build knowledge base of solutions
 | 
			
		||||
- Detect cross-project patterns
 | 
			
		||||
- Prioritize based on frequency and impact
 | 
			
		||||
**How to use**:
 | 
			
		||||
Call `memory_store` tool with two parameters:
 | 
			
		||||
- **content**: Description of optimization with impact (multi-line string)
 | 
			
		||||
- **tags**: Comma-separated tags like "optimize,improvement,ssh-auth,documentation"
 | 
			
		||||
 | 
			
		||||
**Placeholder in commits** (for future migration):
 | 
			
		||||
**Content format template**:
 | 
			
		||||
```
 | 
			
		||||
optimize: [change description]
 | 
			
		||||
optimize: [Brief change description]
 | 
			
		||||
 | 
			
		||||
[Detailed explanation]
 | 
			
		||||
[Detailed explanation of what was changed and why]
 | 
			
		||||
 | 
			
		||||
Pattern-ID: [simple identifier like "auth-ssh-001"]
 | 
			
		||||
Impact: [time saved / friction removed]
 | 
			
		||||
Session: [context]
 | 
			
		||||
Impact: [Time saved / friction removed]
 | 
			
		||||
Project: [project-name or "general"]
 | 
			
		||||
Date: [YYYY-MM-DD]
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
This structured format enables:
 | 
			
		||||
- Pattern detection across commits
 | 
			
		||||
- Effectiveness measurement
 | 
			
		||||
- Easy migration to memory tool
 | 
			
		||||
- Querying with git log
 | 
			
		||||
**Useful tag categories**: `optimize`, `improvement`, `skill-creation`, `documentation`, `automation`, `ssh-auth`, `build-commands`, `testing`, `nixos`, `workflow`
 | 
			
		||||
 | 
			
		||||
**Querying past optimizations**:
 | 
			
		||||
- Use `memory_search` to find similar past improvements before making changes
 | 
			
		||||
- Search for "SSH authentication" to see if this friction was solved before
 | 
			
		||||
- Search for "created skill" to review past skill-creation decisions
 | 
			
		||||
- Filter by tags like "optimize,skill-creation" to see all skill decisions
 | 
			
		||||
 | 
			
		||||
**Benefits**:
 | 
			
		||||
- Learn from past optimization decisions
 | 
			
		||||
- Avoid duplicate work across sessions
 | 
			
		||||
- Measure improvement effectiveness over time
 | 
			
		||||
- Identify cross-project patterns that warrant skills
 | 
			
		||||
 | 
			
		||||
## Examples
 | 
			
		||||
 | 
			
		||||
@ -550,20 +518,10 @@ Target Component: AGENTS.md (setup documentation)
 | 
			
		||||
ssh-add ~/.ssh/id_ed25519 2>/dev/null
 | 
			
		||||
```
 | 
			
		||||
```
 | 
			
		||||
3. Show git diff
 | 
			
		||||
4. Commit:
 | 
			
		||||
```bash
 | 
			
		||||
git add AGENTS.md
 | 
			
		||||
git commit -m "optimize: Document SSH key loading in setup
 | 
			
		||||
 | 
			
		||||
Session experienced repeated SSH auth failures.
 | 
			
		||||
Added startup script to prevent future occurrences.
 | 
			
		||||
 | 
			
		||||
Pattern-ID: auth-ssh-001
 | 
			
		||||
Impact: Prevents 15min friction per session
 | 
			
		||||
Session: 2025-10-29"
 | 
			
		||||
```
 | 
			
		||||
5. Report: "✅ Added SSH key loading to AGENTS.md setup section"
 | 
			
		||||
3. Use `memory_store` tool to record this optimization:
 | 
			
		||||
   - content: "optimize: Added SSH key auto-loading to AGENTS.md\n\nSession experienced repeated SSH auth failures (4 retry attempts).\nAdded startup script documentation to prevent future occurrences.\n\nImpact: Prevents 15min friction per session\nProject: NixOS config\nDate: 2025-10-29"
 | 
			
		||||
   - tags: "optimize,improvement,ssh-auth,documentation"
 | 
			
		||||
4. Report: "✅ Added SSH key loading to AGENTS.md setup section"
 | 
			
		||||
 | 
			
		||||
### Example 2: Repeated Build Commands
 | 
			
		||||
 | 
			
		||||
@ -575,7 +533,9 @@ Commands used 5 times: nix flake check, nix build ...dry-run
 | 
			
		||||
**Your action**:
 | 
			
		||||
1. Add to AGENTS.md build commands section
 | 
			
		||||
2. Document recommended shell aliases
 | 
			
		||||
3. Commit changes
 | 
			
		||||
3. Use `memory_store` tool to record this optimization:
 | 
			
		||||
   - content: "optimize: Added nix validation commands to AGENTS.md\n\nCommands used 5 times in session: nix flake check, nix build --dry-run\nDocumented in AGENTS.md with shell alias recommendations.\n\nImpact: Reduces command typing, faster validation workflow\nProject: NixOS config\nDate: 2025-10-29"
 | 
			
		||||
   - tags: "optimize,improvement,build-commands,documentation,nixos"
 | 
			
		||||
4. Report:
 | 
			
		||||
```markdown
 | 
			
		||||
✅ Added nix validation commands to AGENTS.md
 | 
			
		||||
@ -600,7 +560,9 @@ Missing: No skill for NixOS-specific development patterns
 | 
			
		||||
1. Create `nixos-development` skill
 | 
			
		||||
2. Include: build commands, test workflow, common issues
 | 
			
		||||
3. Keep concise (<300 lines)
 | 
			
		||||
4. Commit skill
 | 
			
		||||
4. Use `memory_store` tool to record this optimization:
 | 
			
		||||
   - content: "optimize: Created nixos-development skill\n\nPattern: NixOS development workflow explained 3 times across sessions.\nCreated reusable skill capturing build/test workflow, validation commands, common patterns.\n\nImpact: Prevents re-explaining NixOS workflow, enables quick onboarding\nProject: General (cross-project)\nSkill: nixos-development\nDate: 2025-10-29"
 | 
			
		||||
   - tags: "optimize,improvement,skill-creation,nixos,workflow"
 | 
			
		||||
5. Note: "⚠️ Restart OpenCode to load new skill"
 | 
			
		||||
6. Report:
 | 
			
		||||
```markdown
 | 
			
		||||
@ -638,7 +600,7 @@ Next: Restart OpenCode, then use with learn_skill(nixos-development)
 | 
			
		||||
Good optimization session results in:
 | 
			
		||||
- ✅ 1-3 high-impact changes implemented (not 10+ minor ones)
 | 
			
		||||
- ✅ Each change maps to specific preventable friction
 | 
			
		||||
- ✅ Clear git commits with searchable messages
 | 
			
		||||
- ✅ Improvements stored in memory with clear impact descriptions
 | 
			
		||||
- ✅ Changes are immediately usable (or restart instructions provided)
 | 
			
		||||
- ✅ Report shows concrete actions taken, not proposals
 | 
			
		||||
- ✅ Next session will benefit from changes (measurable prevention)
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										185
									
								
								shared/linked-dotfiles/opencode/agent/research.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										185
									
								
								shared/linked-dotfiles/opencode/agent/research.md
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,185 @@
 | 
			
		||||
---
 | 
			
		||||
description: Deep research agent - searches sources, cites evidence, synthesizes insights across domains with concise actionable output
 | 
			
		||||
mode: primary
 | 
			
		||||
model: anthropic/claude-sonnet-4-5
 | 
			
		||||
temperature: 0.6
 | 
			
		||||
tools:
 | 
			
		||||
  write: false
 | 
			
		||||
  edit: false
 | 
			
		||||
  bash: true
 | 
			
		||||
permission:
 | 
			
		||||
  bash:
 | 
			
		||||
    "rg *": allow
 | 
			
		||||
    "grep *": allow
 | 
			
		||||
    "man *": allow
 | 
			
		||||
    "curl *": allow
 | 
			
		||||
    "wget *": allow
 | 
			
		||||
    "cat *": allow
 | 
			
		||||
    "head *": allow
 | 
			
		||||
    "tail *": allow
 | 
			
		||||
    "git log *": allow
 | 
			
		||||
    "find *": allow
 | 
			
		||||
    "*": ask
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
You are a deep research agent. Your purpose is to gather relevant sources, cite evidence, make novel connections, and synthesize insights across any domain - coding, psychology, creative writing, science, etc. Your output must be concise, straight to the point, and avoid academic verbosity.
 | 
			
		||||
 | 
			
		||||
## Your Research Process (ReAct Pattern)
 | 
			
		||||
 | 
			
		||||
Use explicit Thought → Action → Observation loops:
 | 
			
		||||
 | 
			
		||||
**Thought**: What information do I need? What sources should I consult?
 | 
			
		||||
**Action**: Search documentation, man pages, web resources, codebase, papers
 | 
			
		||||
**Observation**: What did I find? Does it answer the question? What's missing?
 | 
			
		||||
 | 
			
		||||
Repeat until you have sufficient evidence to synthesize insights.
 | 
			
		||||
 | 
			
		||||
## Citation Requirements
 | 
			
		||||
 | 
			
		||||
**CRITICAL**: Every claim must be cited using this exact format:
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
<source url="https://example.com/paper" title="Paper Title">The specific claim or finding</source>
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
For local sources (man pages, code files):
 | 
			
		||||
```
 | 
			
		||||
<source url="file://path/to/file" title="filename">The specific claim</source>
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
**Rules**:
 | 
			
		||||
- Cite as you write, not at the end
 | 
			
		||||
- If you cannot find a reliable source, say "I don't have a reliable source for this claim"
 | 
			
		||||
- Never make unsupported claims
 | 
			
		||||
- Multiple sources per claim is encouraged when relevant
 | 
			
		||||
 | 
			
		||||
## Conciseness Constraints
 | 
			
		||||
 | 
			
		||||
**Output format**: Small paragraphs (2-4 sentences) or single sentences. NOT bullet points unless specifically requested.
 | 
			
		||||
 | 
			
		||||
**Word budget**: Aim for <500 words for typical research queries. Quality over quantity.
 | 
			
		||||
 | 
			
		||||
**Forbidden phrases**:
 | 
			
		||||
- "It is important to note that..."
 | 
			
		||||
- "Furthermore...", "Moreover...", "In conclusion..."
 | 
			
		||||
- "It seems that...", "Perhaps...", "Might be..."
 | 
			
		||||
- Any academic hedging or filler
 | 
			
		||||
 | 
			
		||||
**Required style**:
 | 
			
		||||
- Direct statements in active voice
 | 
			
		||||
- Specific examples only when they add value
 | 
			
		||||
- One example per concept maximum
 | 
			
		||||
- No introductions or conclusions - start with substance
 | 
			
		||||
 | 
			
		||||
## Making Novel Connections
 | 
			
		||||
 | 
			
		||||
After gathering information, explicitly ask yourself:
 | 
			
		||||
 | 
			
		||||
1. **What unexpected patterns appear across sources?**
 | 
			
		||||
   - Look for themes that emerge from disparate domains
 | 
			
		||||
   - Identify shared underlying principles
 | 
			
		||||
 | 
			
		||||
2. **How do concepts from different domains relate?**
 | 
			
		||||
   - Technical patterns that apply to psychology
 | 
			
		||||
   - Creative approaches that inform engineering
 | 
			
		||||
   - Cross-pollination opportunities
 | 
			
		||||
 | 
			
		||||
3. **What analogies or metaphors connect these ideas?**
 | 
			
		||||
   - Mental models that bridge concepts
 | 
			
		||||
   - Frameworks that unify approaches
 | 
			
		||||
 | 
			
		||||
4. **What contrasts or contradictions exist?**
 | 
			
		||||
   - Tension between sources reveals deeper truth
 | 
			
		||||
   - Disagreements indicate complexity worth exploring
 | 
			
		||||
 | 
			
		||||
## Multi-Domain Research
 | 
			
		||||
 | 
			
		||||
For each topic, consider perspectives from:
 | 
			
		||||
- **Technical/Engineering**: How it works, implementation details
 | 
			
		||||
- **Human/Psychological**: Why people use it, cognitive factors
 | 
			
		||||
- **Business/Economic**: Value proposition, trade-offs
 | 
			
		||||
- **Creative/Artistic**: Novel applications, aesthetic considerations
 | 
			
		||||
 | 
			
		||||
Then synthesize insights across these domains to provide comprehensive understanding.
 | 
			
		||||
 | 
			
		||||
## Research Tools Available
 | 
			
		||||
 | 
			
		||||
You have bash access for:
 | 
			
		||||
- **Web research**: `curl`, `wget` for fetching documentation, papers, resources
 | 
			
		||||
- **Man pages**: `man <command>` for technical documentation
 | 
			
		||||
- **Code search**: `rg`, `grep`, `find` for exploring codebases
 | 
			
		||||
- **Git history**: `git log`, `git show` for understanding evolution
 | 
			
		||||
- **File reading**: `cat`, `head`, `tail` for examining sources
 | 
			
		||||
 | 
			
		||||
Use tools iteratively. If first search doesn't yield results, refine your query.
 | 
			
		||||
 | 
			
		||||
## Verification Step
 | 
			
		||||
 | 
			
		||||
Before finalizing output, self-check:
 | 
			
		||||
- [ ] Every significant claim has a source citation
 | 
			
		||||
- [ ] Citations use correct XML format with URL and title
 | 
			
		||||
- [ ] Output is under 500 words (unless depth requires more)
 | 
			
		||||
- [ ] Writing is direct, no hedging or filler
 | 
			
		||||
- [ ] At least one novel connection or insight is identified
 | 
			
		||||
- [ ] Multiple perspectives considered (not just technical)
 | 
			
		||||
 | 
			
		||||
## Output Structure
 | 
			
		||||
 | 
			
		||||
**Context** (1-2 sentences): Frame the research question and why it matters.
 | 
			
		||||
 | 
			
		||||
**Findings** (2-4 small paragraphs): Present key discoveries with inline citations. Each paragraph should focus on one main insight. Make connections between sources explicit.
 | 
			
		||||
 | 
			
		||||
**Novel Insights** (1-2 paragraphs): Highlight unexpected connections, analogies, or patterns you discovered across sources. This is where cross-domain synthesis happens.
 | 
			
		||||
 | 
			
		||||
**Bibliography**: List all sources at the end in a clean format:
 | 
			
		||||
```
 | 
			
		||||
## Sources
 | 
			
		||||
1. [Title](URL) - Brief description
 | 
			
		||||
2. [Title](URL) - Brief description
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## Example Output Style
 | 
			
		||||
 | 
			
		||||
**Good** (concise paragraphs with citations):
 | 
			
		||||
```
 | 
			
		||||
The ReAct pattern combines reasoning and acting in explicit loops, significantly improving LLM task performance. <source url="https://arxiv.org/abs/2210.03629" title="ReAct: Synergizing Reasoning and Acting in Language Models">ReAct agents achieve 34% higher success rates on ALFWorld tasks compared to baseline approaches</source>. This improvement comes from making the reasoning process transparent, allowing for error detection and course correction.
 | 
			
		||||
 | 
			
		||||
Interestingly, this pattern mirrors human problem-solving strategies from cognitive psychology. <source url="https://psycnet.apa.org/record/1994-97586-000" title="The Psychology of Problem Solving">Expert problem solvers externalize their thinking through verbal protocols, which reduces cognitive load and improves solution quality</source>. The ReAct pattern essentially forces LLMs to "think aloud" in the same way.
 | 
			
		||||
 | 
			
		||||
## Sources
 | 
			
		||||
1. [ReAct: Synergizing Reasoning and Acting in Language Models](https://arxiv.org/abs/2210.03629) - ICLR 2023 paper on reasoning-acting loops
 | 
			
		||||
2. [The Psychology of Problem Solving](https://psycnet.apa.org/record/1994-97586-000) - Cognitive research on expert problem solving
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
**Bad** (bullet points and verbosity):
 | 
			
		||||
```
 | 
			
		||||
It is important to note that the ReAct pattern has several benefits:
 | 
			
		||||
- It seems to improve performance
 | 
			
		||||
- Perhaps it helps with reasoning
 | 
			
		||||
- Furthermore, it might be useful for various tasks
 | 
			
		||||
- Moreover, one could argue that...
 | 
			
		||||
In conclusion, ReAct is a valuable approach.
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## Domain Adaptability
 | 
			
		||||
 | 
			
		||||
Adjust your research depth based on the domain:
 | 
			
		||||
- **Code/Technical**: Focus on implementation details, performance, trade-offs
 | 
			
		||||
- **Psychology/Human Factors**: Focus on user research, cognitive principles, behavioral patterns
 | 
			
		||||
- **Creative Writing**: Focus on techniques, examples from literature, stylistic approaches
 | 
			
		||||
- **Science/Research**: Focus on peer-reviewed sources, methodology, empirical findings
 | 
			
		||||
- **General Knowledge**: Focus on authoritative sources, multiple perspectives, practical applications
 | 
			
		||||
 | 
			
		||||
## When Information is Insufficient
 | 
			
		||||
 | 
			
		||||
If you cannot find adequate sources:
 | 
			
		||||
1. State clearly what you searched and why it was insufficient
 | 
			
		||||
2. Provide what you did find with appropriate caveats
 | 
			
		||||
3. Suggest alternative research directions
 | 
			
		||||
4. Never fabricate sources or make unsupported claims
 | 
			
		||||
 | 
			
		||||
## Your Tone
 | 
			
		||||
 | 
			
		||||
Direct, insightful, and information-dense. Avoid chattiness. Every sentence should add value. Get to the point immediately. The human needs actionable intelligence, not prose.
 | 
			
		||||
 | 
			
		||||
Remember: Your job is to make the human smarter by synthesizing diverse sources into clear, cited, insightful analysis. Quality research enables better decisions.
 | 
			
		||||
@ -14,7 +14,7 @@
 | 
			
		||||
        "mcp-remote",
 | 
			
		||||
        "https://mcp.atlassian.com/v1/sse"
 | 
			
		||||
      ],
 | 
			
		||||
      "enabled": true
 | 
			
		||||
      "enabled": false
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										176
									
								
								shared/linked-dotfiles/opencode/plugin/file-proxy.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										176
									
								
								shared/linked-dotfiles/opencode/plugin/file-proxy.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,176 @@
 | 
			
		||||
import { tool } from "@opencode-ai/plugin";
 | 
			
		||||
import { readFile, writeFile, mkdir } from "fs/promises";
 | 
			
		||||
import { resolve, normalize, join, dirname } from "path";
 | 
			
		||||
import { homedir } from "os";
 | 
			
		||||
 | 
			
		||||
const CONFIG_BASE = resolve(homedir(), ".config/opencode");
 | 
			
		||||
 | 
			
		||||
function resolvePath(filePath) {
 | 
			
		||||
  if (!filePath.startsWith('/') && !filePath.startsWith('~')) {
 | 
			
		||||
    filePath = join(CONFIG_BASE, filePath);
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  if (filePath.startsWith('~/')) {
 | 
			
		||||
    filePath = filePath.replace('~/', homedir() + '/');
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  const normalized = normalize(resolve(filePath));
 | 
			
		||||
  
 | 
			
		||||
  if (!normalized.startsWith(CONFIG_BASE)) {
 | 
			
		||||
    throw new Error(
 | 
			
		||||
      `Access denied: Path must be within ~/.config/opencode\n` +
 | 
			
		||||
      `Attempted: ${normalized}\n` +
 | 
			
		||||
      `Use config_read/config_write/config_edit ONLY for opencode config files.`
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  return normalized;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const FileProxyPlugin = async () => {
 | 
			
		||||
  return {
 | 
			
		||||
    tool: {
 | 
			
		||||
      config_read: tool({
 | 
			
		||||
        description: `Read files from OpenCode config directory (~/.config/opencode).
 | 
			
		||||
 | 
			
		||||
**REQUIRED when reading config files from outside ~/.config/opencode directory.**
 | 
			
		||||
 | 
			
		||||
Use this tool when:
 | 
			
		||||
- Reading agent definitions (agent/*.md)
 | 
			
		||||
- Reading skills (skills/*/SKILL.md)
 | 
			
		||||
- Reading workflows (OPTIMIZATION_WORKFLOW.md, etc.)
 | 
			
		||||
- Current working directory is NOT ~/.config/opencode
 | 
			
		||||
 | 
			
		||||
Do NOT use if already in ~/.config/opencode - use standard 'read' tool instead.`,
 | 
			
		||||
        
 | 
			
		||||
        args: {
 | 
			
		||||
          filePath: tool.schema.string()
 | 
			
		||||
            .describe("Path to file (e.g., 'agent/optimize.md' or '~/.config/opencode/skills/skill-name/SKILL.md')")
 | 
			
		||||
        },
 | 
			
		||||
        
 | 
			
		||||
        async execute(args) {
 | 
			
		||||
          try {
 | 
			
		||||
            const validPath = resolvePath(args.filePath);
 | 
			
		||||
            const content = await readFile(validPath, "utf-8");
 | 
			
		||||
            return content;
 | 
			
		||||
          } catch (error) {
 | 
			
		||||
            if (error.code === 'ENOENT') {
 | 
			
		||||
              return `❌ File not found: ${args.filePath}\nCheck path and try again.`;
 | 
			
		||||
            }
 | 
			
		||||
            if (error.code === 'EACCES') {
 | 
			
		||||
              return `❌ Permission denied: ${args.filePath}`;
 | 
			
		||||
            }
 | 
			
		||||
            if (error.message.includes('Access denied')) {
 | 
			
		||||
              return `❌ ${error.message}`;
 | 
			
		||||
            }
 | 
			
		||||
            return `❌ Error reading file: ${error.message}`;
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      }),
 | 
			
		||||
 | 
			
		||||
      config_write: tool({
 | 
			
		||||
        description: `Write/create files in OpenCode config directory (~/.config/opencode).
 | 
			
		||||
 | 
			
		||||
**REQUIRED when creating/writing config files from outside ~/.config/opencode directory.**
 | 
			
		||||
 | 
			
		||||
Use this tool when:
 | 
			
		||||
- Creating new skills (skills/new-skill/SKILL.md)
 | 
			
		||||
- Creating new agent definitions
 | 
			
		||||
- Writing workflow documentation
 | 
			
		||||
- Current working directory is NOT ~/.config/opencode
 | 
			
		||||
 | 
			
		||||
Common use case: Optimize agent creating skills or updating workflows from project directories.
 | 
			
		||||
 | 
			
		||||
Do NOT use if already in ~/.config/opencode - use standard 'write' tool instead.`,
 | 
			
		||||
        
 | 
			
		||||
        args: {
 | 
			
		||||
          filePath: tool.schema.string()
 | 
			
		||||
            .describe("Path to file (e.g., 'skills/my-skill/SKILL.md')"),
 | 
			
		||||
          content: tool.schema.string()
 | 
			
		||||
            .describe("Complete file content to write")
 | 
			
		||||
        },
 | 
			
		||||
        
 | 
			
		||||
        async execute(args) {
 | 
			
		||||
          try {
 | 
			
		||||
            const validPath = resolvePath(args.filePath);
 | 
			
		||||
            await mkdir(dirname(validPath), { recursive: true });
 | 
			
		||||
            await writeFile(validPath, args.content, "utf-8");
 | 
			
		||||
            return `✅ Successfully wrote to ${args.filePath}`;
 | 
			
		||||
          } catch (error) {
 | 
			
		||||
            if (error.code === 'EACCES') {
 | 
			
		||||
              return `❌ Permission denied: ${args.filePath}`;
 | 
			
		||||
            }
 | 
			
		||||
            if (error.message.includes('Access denied')) {
 | 
			
		||||
              return `❌ ${error.message}`;
 | 
			
		||||
            }
 | 
			
		||||
            return `❌ Error writing file: ${error.message}`;
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      }),
 | 
			
		||||
 | 
			
		||||
      config_edit: tool({
 | 
			
		||||
        description: `Edit existing files in OpenCode config directory (~/.config/opencode).
 | 
			
		||||
 | 
			
		||||
**REQUIRED when editing config files from outside ~/.config/opencode directory.**
 | 
			
		||||
 | 
			
		||||
Use this tool when:
 | 
			
		||||
- Updating agent definitions (adding sections to optimize.md)
 | 
			
		||||
- Enhancing existing skills
 | 
			
		||||
- Modifying workflow docs
 | 
			
		||||
- Current working directory is NOT ~/.config/opencode
 | 
			
		||||
 | 
			
		||||
Operations: append (add to end), prepend (add to beginning), replace (find and replace text).
 | 
			
		||||
 | 
			
		||||
Do NOT use if already in ~/.config/opencode - use standard 'edit' tool instead.`,
 | 
			
		||||
        
 | 
			
		||||
        args: {
 | 
			
		||||
          filePath: tool.schema.string()
 | 
			
		||||
            .describe("Path to file to edit"),
 | 
			
		||||
          operation: tool.schema.enum(["append", "prepend", "replace"])
 | 
			
		||||
            .describe("Edit operation to perform"),
 | 
			
		||||
          content: tool.schema.string()
 | 
			
		||||
            .describe("Content to add or replacement text"),
 | 
			
		||||
          searchPattern: tool.schema.string()
 | 
			
		||||
            .optional()
 | 
			
		||||
            .describe("Regex pattern to find (required for 'replace' operation)")
 | 
			
		||||
        },
 | 
			
		||||
        
 | 
			
		||||
        async execute(args) {
 | 
			
		||||
          try {
 | 
			
		||||
            const validPath = resolvePath(args.filePath);
 | 
			
		||||
            let fileContent = await readFile(validPath, "utf-8");
 | 
			
		||||
            
 | 
			
		||||
            switch (args.operation) {
 | 
			
		||||
              case "append":
 | 
			
		||||
                fileContent += "\n" + args.content;
 | 
			
		||||
                break;
 | 
			
		||||
              case "prepend":
 | 
			
		||||
                fileContent = args.content + "\n" + fileContent;
 | 
			
		||||
                break;
 | 
			
		||||
              case "replace":
 | 
			
		||||
                if (!args.searchPattern) {
 | 
			
		||||
                  throw new Error("searchPattern required for replace operation");
 | 
			
		||||
                }
 | 
			
		||||
                fileContent = fileContent.replace(new RegExp(args.searchPattern, "g"), args.content);
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            await writeFile(validPath, fileContent, "utf-8");
 | 
			
		||||
            return `✅ Successfully edited ${args.filePath} (${args.operation})`;
 | 
			
		||||
          } catch (error) {
 | 
			
		||||
            if (error.code === 'ENOENT') {
 | 
			
		||||
              return `❌ File not found: ${args.filePath}\nUse config_write to create new files.`;
 | 
			
		||||
            }
 | 
			
		||||
            if (error.code === 'EACCES') {
 | 
			
		||||
              return `❌ Permission denied: ${args.filePath}`;
 | 
			
		||||
            }
 | 
			
		||||
            if (error.message.includes('Access denied')) {
 | 
			
		||||
              return `❌ ${error.message}`;
 | 
			
		||||
            }
 | 
			
		||||
            return `❌ Error editing file: ${error.message}`;
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      })
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
};
 | 
			
		||||
@ -1,5 +1,79 @@
 | 
			
		||||
const detectWindowManager = () => {
 | 
			
		||||
  if (process.env.NIRI_SOCKET) return 'niri';
 | 
			
		||||
  if (process.env.HYPRLAND_INSTANCE_SIGNATURE) return 'hyprland';
 | 
			
		||||
  if (process.env.SWAYSOCK) return 'sway';
 | 
			
		||||
  return null;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const findWindow = async ($, wm, pid) => {
 | 
			
		||||
  try {
 | 
			
		||||
    switch (wm) {
 | 
			
		||||
      case 'niri': {
 | 
			
		||||
        const output = await $`niri msg --json windows`.text();
 | 
			
		||||
        const windows = JSON.parse(output);
 | 
			
		||||
        const window = windows.find(w => w.app_id?.toLowerCase().includes('opencode') || w.title?.toLowerCase().includes('opencode'));
 | 
			
		||||
        return window ? { id: window.id.toString(), type: 'niri' } : null;
 | 
			
		||||
      }
 | 
			
		||||
      case 'hyprland': {
 | 
			
		||||
        const output = await $`hyprctl clients -j`.text();
 | 
			
		||||
        const clients = JSON.parse(output);
 | 
			
		||||
        const window = clients.find(c => c.pid === pid || c.title?.toLowerCase().includes('opencode'));
 | 
			
		||||
        return window ? { id: window.address, type: 'hyprland' } : null;
 | 
			
		||||
      }
 | 
			
		||||
      case 'sway': {
 | 
			
		||||
        const output = await $`swaymsg -t get_tree`.text();
 | 
			
		||||
        const tree = JSON.parse(output);
 | 
			
		||||
        const findNode = (node) => {
 | 
			
		||||
          if (node.pid === pid || node.name?.toLowerCase().includes('opencode')) {
 | 
			
		||||
            return node;
 | 
			
		||||
          }
 | 
			
		||||
          if (node.nodes) {
 | 
			
		||||
            for (const child of node.nodes) {
 | 
			
		||||
              const found = findNode(child);
 | 
			
		||||
              if (found) return found;
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
          if (node.floating_nodes) {
 | 
			
		||||
            for (const child of node.floating_nodes) {
 | 
			
		||||
              const found = findNode(child);
 | 
			
		||||
              if (found) return found;
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
          return null;
 | 
			
		||||
        };
 | 
			
		||||
        const window = findNode(tree);
 | 
			
		||||
        return window ? { id: window.id.toString(), type: 'sway' } : null;
 | 
			
		||||
      }
 | 
			
		||||
      default:
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
  } catch (error) {
 | 
			
		||||
    console.error(`Failed to find window for ${wm}:`, error);
 | 
			
		||||
    return null;
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const focusWindow = async ($, windowInfo) => {
 | 
			
		||||
  try {
 | 
			
		||||
    switch (windowInfo.type) {
 | 
			
		||||
      case 'niri':
 | 
			
		||||
        await $`niri msg action focus-window --id ${windowInfo.id}`;
 | 
			
		||||
        break;
 | 
			
		||||
      case 'hyprland':
 | 
			
		||||
        await $`hyprctl dispatch focuswindow address:${windowInfo.id}`;
 | 
			
		||||
        break;
 | 
			
		||||
      case 'sway':
 | 
			
		||||
        await $`swaymsg [con_id=${windowInfo.id}] focus`;
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
  } catch (error) {
 | 
			
		||||
    console.error(`Failed to focus window:`, error);
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const SwayNotificationCenter = async ({ project, client, $, directory, worktree }) => {
 | 
			
		||||
  console.log("SwayNC notification plugin initialized");
 | 
			
		||||
  const wm = detectWindowManager();
 | 
			
		||||
  console.log(`SwayNC notification plugin initialized (WM: ${wm || 'unknown'})`);
 | 
			
		||||
  
 | 
			
		||||
  return {
 | 
			
		||||
    event: async ({ event }) => {
 | 
			
		||||
@ -9,30 +83,20 @@ export const SwayNotificationCenter = async ({ project, client, $, directory, wo
 | 
			
		||||
        const iconPath = `${process.env.HOME}/.config/opencode/opencode.png`;
 | 
			
		||||
        
 | 
			
		||||
        try {
 | 
			
		||||
          const clientsJson = await $`hyprctl clients -j`.text();
 | 
			
		||||
          const clients = JSON.parse(clientsJson);
 | 
			
		||||
          
 | 
			
		||||
          const opencodeWindow = clients.find(c => 
 | 
			
		||||
            c.pid === pid || 
 | 
			
		||||
            (c.title && c.title.toLowerCase().includes("opencode"))
 | 
			
		||||
          );
 | 
			
		||||
          
 | 
			
		||||
          const windowAddress = opencodeWindow?.address || "";
 | 
			
		||||
          const windowInfo = wm ? await findWindow($, wm, pid) : null;
 | 
			
		||||
          
 | 
			
		||||
          const notifyCmd = [
 | 
			
		||||
            "notify-send",
 | 
			
		||||
            "-a", "OpenCode",
 | 
			
		||||
            "-u", "normal",
 | 
			
		||||
            "-i", iconPath,
 | 
			
		||||
            "-h", `string:x-opencode-window:${windowAddress}`,
 | 
			
		||||
            "-h", `string:x-opencode-dir:${dir}`,
 | 
			
		||||
            "-A", `focus=Focus Window`,
 | 
			
		||||
            ...(windowInfo ? ["-A", `focus=Focus Window`] : []),
 | 
			
		||||
            "OpenCode Ready",
 | 
			
		||||
            `Waiting for input\nDirectory: ${dir}`
 | 
			
		||||
          ];
 | 
			
		||||
          
 | 
			
		||||
          if (windowAddress) {
 | 
			
		||||
            // Run notify-send as detached background process
 | 
			
		||||
          if (windowInfo) {
 | 
			
		||||
            import("child_process").then(({ spawn }) => {
 | 
			
		||||
              const child = spawn(notifyCmd[0], notifyCmd.slice(1), {
 | 
			
		||||
                detached: true,
 | 
			
		||||
@ -40,22 +104,20 @@ export const SwayNotificationCenter = async ({ project, client, $, directory, wo
 | 
			
		||||
              });
 | 
			
		||||
              child.unref();
 | 
			
		||||
              
 | 
			
		||||
              // Handle the response in the background
 | 
			
		||||
              let output = '';
 | 
			
		||||
              if (child.stdout) {
 | 
			
		||||
                child.stdout.on('data', (data) => {
 | 
			
		||||
                  output += data.toString();
 | 
			
		||||
                });
 | 
			
		||||
                child.on('close', () => {
 | 
			
		||||
                  if (output.trim() === "focus" && windowAddress) {
 | 
			
		||||
                    $`hyprctl dispatch focuswindow address:${windowAddress}`.catch(() => {});
 | 
			
		||||
                  if (output.trim() === "focus") {
 | 
			
		||||
                    focusWindow($, windowInfo).catch(() => {});
 | 
			
		||||
                  }
 | 
			
		||||
                });
 | 
			
		||||
              }
 | 
			
		||||
            }).catch(() => {});
 | 
			
		||||
          } else {
 | 
			
		||||
            // Run without action button, no need to wait
 | 
			
		||||
            $`${notifyCmd.filter(arg => !arg.startsWith('focus'))}`.catch(() => {});
 | 
			
		||||
            $`${notifyCmd}`.catch(() => {});
 | 
			
		||||
          }
 | 
			
		||||
        } catch (error) {
 | 
			
		||||
          console.error("Notification error:", error);
 | 
			
		||||
 | 
			
		||||
@ -1,161 +0,0 @@
 | 
			
		||||
# Browser Automation Skill
 | 
			
		||||
 | 
			
		||||
Control Chrome browser via DevTools Protocol using the `use_browser` MCP tool.
 | 
			
		||||
 | 
			
		||||
## Structure
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
browser-automation/
 | 
			
		||||
├── SKILL.md                      # Main skill (324 lines, 1050 words)
 | 
			
		||||
└── references/
 | 
			
		||||
    ├── examples.md               # Complete workflows (672 lines)
 | 
			
		||||
    ├── troubleshooting.md        # Error handling (546 lines)
 | 
			
		||||
    └── advanced.md               # Advanced patterns (678 lines)
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## Quick Start
 | 
			
		||||
 | 
			
		||||
The skill provides:
 | 
			
		||||
- **Core patterns**: Navigate, wait, interact, extract
 | 
			
		||||
- **Form automation**: Multi-step forms, validation, submission
 | 
			
		||||
- **Data extraction**: Tables, structured data, batch operations
 | 
			
		||||
- **Multi-tab workflows**: Cross-site data correlation
 | 
			
		||||
- **Dynamic content**: AJAX waiting, infinite scroll, modals
 | 
			
		||||
 | 
			
		||||
## Installation
 | 
			
		||||
 | 
			
		||||
This skill requires the `use_browser` MCP tool from the superpowers-chrome package.
 | 
			
		||||
 | 
			
		||||
### Option 1: Use superpowers-chrome directly
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
/plugin marketplace add obra/superpowers-marketplace
 | 
			
		||||
/plugin install superpowers-chrome@superpowers-marketplace
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Option 2: Install as standalone skill
 | 
			
		||||
 | 
			
		||||
Copy this skill directory to your OpenCode skills directory:
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
cp -r browser-automation ~/.opencode/skills/
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Then configure the `chrome` MCP server in your Claude Desktop config per the [superpowers-chrome installation guide](https://github.com/obra/superpowers-chrome#installation).
 | 
			
		||||
 | 
			
		||||
## Usage
 | 
			
		||||
 | 
			
		||||
The skill is automatically loaded when OpenCode starts. It will be invoked when you:
 | 
			
		||||
- Request web automation tasks
 | 
			
		||||
- Need to fill forms
 | 
			
		||||
- Want to extract content from websites
 | 
			
		||||
- Mention Chrome or browser control
 | 
			
		||||
 | 
			
		||||
Example prompts:
 | 
			
		||||
- "Fill out the registration form at example.com"
 | 
			
		||||
- "Extract all product names and prices from this page"
 | 
			
		||||
- "Navigate to my email and find the receipt from yesterday"
 | 
			
		||||
 | 
			
		||||
## Contents
 | 
			
		||||
 | 
			
		||||
### SKILL.md
 | 
			
		||||
Main reference with:
 | 
			
		||||
- Quick reference table for all actions
 | 
			
		||||
- Core workflow patterns
 | 
			
		||||
- Common mistakes and solutions
 | 
			
		||||
- Real-world impact metrics
 | 
			
		||||
 | 
			
		||||
### references/examples.md
 | 
			
		||||
Complete workflows including:
 | 
			
		||||
- E-commerce booking flows
 | 
			
		||||
- Multi-step registration forms
 | 
			
		||||
- Price comparison across sites
 | 
			
		||||
- Data extraction patterns
 | 
			
		||||
- Multi-tab operations
 | 
			
		||||
- Dynamic content handling
 | 
			
		||||
- Authentication workflows
 | 
			
		||||
 | 
			
		||||
### references/troubleshooting.md
 | 
			
		||||
Solutions for:
 | 
			
		||||
- Element not found errors
 | 
			
		||||
- Timeout issues
 | 
			
		||||
- Click failures
 | 
			
		||||
- Form submission problems
 | 
			
		||||
- Tab index errors
 | 
			
		||||
- Extract returning empty
 | 
			
		||||
 | 
			
		||||
Plus best practices for selectors, waiting, and debugging.
 | 
			
		||||
 | 
			
		||||
### references/advanced.md
 | 
			
		||||
Advanced techniques:
 | 
			
		||||
- Network interception
 | 
			
		||||
- JavaScript injection
 | 
			
		||||
- Complex waiting patterns
 | 
			
		||||
- Data manipulation
 | 
			
		||||
- State management
 | 
			
		||||
- Visual testing
 | 
			
		||||
- Performance monitoring
 | 
			
		||||
- Accessibility testing
 | 
			
		||||
- Frame handling
 | 
			
		||||
 | 
			
		||||
## Progressive Disclosure
 | 
			
		||||
 | 
			
		||||
The skill uses progressive disclosure to minimize context usage:
 | 
			
		||||
 | 
			
		||||
1. **SKILL.md** loads first - quick reference and common patterns
 | 
			
		||||
2. **examples.md** - loaded when implementing specific workflows
 | 
			
		||||
3. **troubleshooting.md** - loaded when encountering errors
 | 
			
		||||
4. **advanced.md** - loaded for complex requirements
 | 
			
		||||
 | 
			
		||||
## Key Features
 | 
			
		||||
 | 
			
		||||
### Single Tool Interface
 | 
			
		||||
All operations use one tool with action-based parameters:
 | 
			
		||||
```json
 | 
			
		||||
{action: "navigate", payload: "https://example.com"}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### CSS and XPath Support
 | 
			
		||||
Both selector types supported (XPath auto-detected):
 | 
			
		||||
```json
 | 
			
		||||
{action: "click", selector: "button.submit"}
 | 
			
		||||
{action: "click", selector: "//button[text()='Submit']"}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Auto-Starting Chrome
 | 
			
		||||
Browser launches automatically on first use, no manual setup.
 | 
			
		||||
 | 
			
		||||
### Multi-Tab Management
 | 
			
		||||
Control multiple tabs with `tab_index` parameter:
 | 
			
		||||
```json
 | 
			
		||||
{action: "click", tab_index: 2, selector: "a.email"}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## Token Efficiency
 | 
			
		||||
 | 
			
		||||
- Main skill: 1050 words (target: <500 words for frequent skills)
 | 
			
		||||
- Total skill: 6092 words across all files
 | 
			
		||||
- Progressive loading ensures only relevant content loaded
 | 
			
		||||
- Reference files separated by concern
 | 
			
		||||
 | 
			
		||||
## Comparison with Playwright MCP
 | 
			
		||||
 | 
			
		||||
**Use this skill when:**
 | 
			
		||||
- Working with existing browser sessions
 | 
			
		||||
- Need authenticated workflows
 | 
			
		||||
- Managing multiple tabs
 | 
			
		||||
- Want minimal overhead
 | 
			
		||||
 | 
			
		||||
**Use Playwright MCP when:**
 | 
			
		||||
- Need fresh isolated instances
 | 
			
		||||
- Generating PDFs/screenshots
 | 
			
		||||
- Prefer higher-level abstractions
 | 
			
		||||
- Complex automation with built-in retry logic
 | 
			
		||||
 | 
			
		||||
## Credits
 | 
			
		||||
 | 
			
		||||
Based on [superpowers-chrome](https://github.com/obra/superpowers-chrome) by obra (Jesse Vincent).
 | 
			
		||||
 | 
			
		||||
## License
 | 
			
		||||
 | 
			
		||||
MIT
 | 
			
		||||
@ -1,324 +0,0 @@
 | 
			
		||||
---
 | 
			
		||||
name: browser-automation
 | 
			
		||||
description: Use when automating web tasks, filling forms, extracting content, or controlling Chrome - provides Chrome DevTools Protocol automation via use_browser MCP tool for multi-tab workflows, form automation, and content extraction
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
# Browser Automation with Chrome DevTools Protocol
 | 
			
		||||
 | 
			
		||||
Control Chrome directly via DevTools Protocol using the `use_browser` MCP tool. Single unified interface with auto-starting Chrome.
 | 
			
		||||
 | 
			
		||||
**Core principle:** One tool, action-based interface, zero dependencies.
 | 
			
		||||
 | 
			
		||||
## When to Use This Skill
 | 
			
		||||
 | 
			
		||||
**Use when:**
 | 
			
		||||
- Automating web forms and interactions
 | 
			
		||||
- Extracting content from web pages (text, tables, links)
 | 
			
		||||
- Managing authenticated browser sessions
 | 
			
		||||
- Multi-tab workflows requiring context switching
 | 
			
		||||
- Testing web applications interactively
 | 
			
		||||
- Scraping dynamic content loaded by JavaScript
 | 
			
		||||
 | 
			
		||||
**Don't use when:**
 | 
			
		||||
- Need fresh isolated browser instances
 | 
			
		||||
- Require PDF/screenshot generation (use Playwright MCP)
 | 
			
		||||
- Simple HTTP requests suffice (use curl/fetch)
 | 
			
		||||
 | 
			
		||||
## Quick Reference
 | 
			
		||||
 | 
			
		||||
| Task | Action | Key Parameters |
 | 
			
		||||
|------|--------|----------------|
 | 
			
		||||
| Go to URL | `navigate` | `payload`: URL |
 | 
			
		||||
| Wait for element | `await_element` | `selector`, `timeout` |
 | 
			
		||||
| Click element | `click` | `selector` |
 | 
			
		||||
| Type text | `type` | `selector`, `payload` (add `\n` to submit) |
 | 
			
		||||
| Get content | `extract` | `payload`: 'markdown'\|'text'\|'html' |
 | 
			
		||||
| Run JavaScript | `eval` | `payload`: JS code |
 | 
			
		||||
| Get attribute | `attr` | `selector`, `payload`: attr name |
 | 
			
		||||
| Select dropdown | `select` | `selector`, `payload`: option value |
 | 
			
		||||
| Take screenshot | `screenshot` | `payload`: filename |
 | 
			
		||||
| List tabs | `list_tabs` | - |
 | 
			
		||||
| New tab | `new_tab` | - |
 | 
			
		||||
 | 
			
		||||
## The use_browser Tool
 | 
			
		||||
 | 
			
		||||
**Parameters:**
 | 
			
		||||
- `action` (required): Operation to perform
 | 
			
		||||
- `tab_index` (optional): Tab to operate on (default: 0)
 | 
			
		||||
- `selector` (optional): CSS selector or XPath (XPath starts with `/` or `//`)
 | 
			
		||||
- `payload` (optional): Action-specific data
 | 
			
		||||
- `timeout` (optional): Timeout in ms (default: 5000, max: 60000)
 | 
			
		||||
 | 
			
		||||
**Returns:** JSON response with result or error
 | 
			
		||||
 | 
			
		||||
## Core Pattern
 | 
			
		||||
 | 
			
		||||
Every browser workflow follows this structure:
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
1. Navigate to page
 | 
			
		||||
2. Wait for content to load
 | 
			
		||||
3. Interact or extract
 | 
			
		||||
4. Validate result
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
**Example:**
 | 
			
		||||
```json
 | 
			
		||||
{action: "navigate", payload: "https://example.com"}
 | 
			
		||||
{action: "await_element", selector: "h1"}
 | 
			
		||||
{action: "extract", payload: "text", selector: "h1"}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## Common Workflows
 | 
			
		||||
 | 
			
		||||
### Form Filling
 | 
			
		||||
 | 
			
		||||
```json
 | 
			
		||||
{action: "navigate", payload: "https://app.com/login"}
 | 
			
		||||
{action: "await_element", selector: "input[name=email]"}
 | 
			
		||||
{action: "type", selector: "input[name=email]", payload: "user@example.com"}
 | 
			
		||||
{action: "type", selector: "input[name=password]", payload: "pass123\n"}
 | 
			
		||||
{action: "await_text", payload: "Welcome"}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Note: `\n` at end submits the form automatically.
 | 
			
		||||
 | 
			
		||||
### Content Extraction
 | 
			
		||||
 | 
			
		||||
```json
 | 
			
		||||
{action: "navigate", payload: "https://example.com"}
 | 
			
		||||
{action: "await_element", selector: "body"}
 | 
			
		||||
{action: "extract", payload: "markdown"}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Multi-Tab Workflow
 | 
			
		||||
 | 
			
		||||
```json
 | 
			
		||||
{action: "list_tabs"}
 | 
			
		||||
{action: "click", tab_index: 2, selector: "a.email"}
 | 
			
		||||
{action: "await_element", tab_index: 2, selector: ".content"}
 | 
			
		||||
{action: "extract", tab_index: 2, payload: "text", selector: ".amount"}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Dynamic Content
 | 
			
		||||
 | 
			
		||||
```json
 | 
			
		||||
{action: "navigate", payload: "https://app.com"}
 | 
			
		||||
{action: "type", selector: "input[name=q]", payload: "query"}
 | 
			
		||||
{action: "click", selector: "button.search"}
 | 
			
		||||
{action: "await_element", selector: ".results"}
 | 
			
		||||
{action: "extract", payload: "text", selector: ".result-title"}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Get Structured Data
 | 
			
		||||
 | 
			
		||||
```json
 | 
			
		||||
{action: "eval", payload: "Array.from(document.querySelectorAll('a')).map(a => ({ text: a.textContent.trim(), href: a.href }))"}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## Implementation Steps
 | 
			
		||||
 | 
			
		||||
### 1. Verify Page Structure
 | 
			
		||||
 | 
			
		||||
Before building automation, check selectors:
 | 
			
		||||
 | 
			
		||||
```json
 | 
			
		||||
{action: "navigate", payload: "https://example.com"}
 | 
			
		||||
{action: "await_element", selector: "body"}
 | 
			
		||||
{action: "extract", payload: "html"}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### 2. Build Workflow Incrementally
 | 
			
		||||
 | 
			
		||||
Test each step before adding next:
 | 
			
		||||
 | 
			
		||||
```json
 | 
			
		||||
// Step 1: Navigate and verify
 | 
			
		||||
{action: "navigate", payload: "https://example.com"}
 | 
			
		||||
{action: "await_element", selector: "form"}
 | 
			
		||||
 | 
			
		||||
// Step 2: Fill first field and verify
 | 
			
		||||
{action: "type", selector: "input[name=email]", payload: "test@example.com"}
 | 
			
		||||
{action: "attr", selector: "input[name=email]", payload: "value"}
 | 
			
		||||
 | 
			
		||||
// Step 3: Complete form
 | 
			
		||||
{action: "type", selector: "input[name=password]", payload: "pass\n"}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### 3. Add Error Handling
 | 
			
		||||
 | 
			
		||||
Always wait before interaction:
 | 
			
		||||
 | 
			
		||||
```json
 | 
			
		||||
// BAD - might fail
 | 
			
		||||
{action: "navigate", payload: "https://example.com"}
 | 
			
		||||
{action: "click", selector: "button"}
 | 
			
		||||
 | 
			
		||||
// GOOD - wait first
 | 
			
		||||
{action: "navigate", payload: "https://example.com"}
 | 
			
		||||
{action: "await_element", selector: "button"}
 | 
			
		||||
{action: "click", selector: "button"}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### 4. Validate Results
 | 
			
		||||
 | 
			
		||||
Check output after critical operations:
 | 
			
		||||
 | 
			
		||||
```json
 | 
			
		||||
{action: "click", selector: "button.submit"}
 | 
			
		||||
{action: "await_text", payload: "Success"}
 | 
			
		||||
{action: "extract", payload: "text", selector: ".confirmation"}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## Selector Strategies
 | 
			
		||||
 | 
			
		||||
**Use specific selectors:**
 | 
			
		||||
- ✅ `button[type=submit]`
 | 
			
		||||
- ✅ `#login-button`
 | 
			
		||||
- ✅ `.modal button.confirm`
 | 
			
		||||
- ❌ `button` (too generic)
 | 
			
		||||
 | 
			
		||||
**XPath for complex queries:**
 | 
			
		||||
```json
 | 
			
		||||
{action: "extract", selector: "//h2 | //h3", payload: "text"}
 | 
			
		||||
{action: "click", selector: "//button[contains(text(), 'Submit')]"}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
**Test selectors first:**
 | 
			
		||||
```json
 | 
			
		||||
{action: "eval", payload: "document.querySelector('button.submit')"}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## Common Mistakes
 | 
			
		||||
 | 
			
		||||
### Timing Issues
 | 
			
		||||
 | 
			
		||||
**Problem:** Clicking before element loads
 | 
			
		||||
```json
 | 
			
		||||
{action: "navigate", payload: "https://example.com"}
 | 
			
		||||
{action: "click", selector: "button"}  // ❌ Fails if slow
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
**Solution:** Always wait
 | 
			
		||||
```json
 | 
			
		||||
{action: "navigate", payload: "https://example.com"}
 | 
			
		||||
{action: "await_element", selector: "button"}  // ✅ Waits
 | 
			
		||||
{action: "click", selector: "button"}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Generic Selectors
 | 
			
		||||
 | 
			
		||||
**Problem:** Matches wrong element
 | 
			
		||||
```json
 | 
			
		||||
{action: "click", selector: "button"}  // ❌ First button only
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
**Solution:** Be specific
 | 
			
		||||
```json
 | 
			
		||||
{action: "click", selector: "button.login-button"}  // ✅ Specific
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Missing Tab Management
 | 
			
		||||
 | 
			
		||||
**Problem:** Tab indices change after closing tabs
 | 
			
		||||
```json
 | 
			
		||||
{action: "close_tab", tab_index: 1}
 | 
			
		||||
{action: "click", tab_index: 2, selector: "a"}  // ❌ Index shifted
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
**Solution:** Re-list tabs
 | 
			
		||||
```json
 | 
			
		||||
{action: "close_tab", tab_index: 1}
 | 
			
		||||
{action: "list_tabs"}  // ✅ Get updated indices
 | 
			
		||||
{action: "click", tab_index: 1, selector: "a"}  // Now correct
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Insufficient Timeout
 | 
			
		||||
 | 
			
		||||
**Problem:** Default 5s timeout too short
 | 
			
		||||
```json
 | 
			
		||||
{action: "await_element", selector: ".slow-content"}  // ❌ Times out
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
**Solution:** Increase timeout
 | 
			
		||||
```json
 | 
			
		||||
{action: "await_element", selector: ".slow-content", timeout: 30000}  // ✅
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## Advanced Patterns
 | 
			
		||||
 | 
			
		||||
### Wait for AJAX Complete
 | 
			
		||||
 | 
			
		||||
```json
 | 
			
		||||
{action: "eval", payload: `
 | 
			
		||||
  new Promise(resolve => {
 | 
			
		||||
    const check = () => {
 | 
			
		||||
      if (!document.querySelector('.spinner')) {
 | 
			
		||||
        resolve(true);
 | 
			
		||||
      } else {
 | 
			
		||||
        setTimeout(check, 100);
 | 
			
		||||
      }
 | 
			
		||||
    };
 | 
			
		||||
    check();
 | 
			
		||||
  })
 | 
			
		||||
`}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Extract Table Data
 | 
			
		||||
 | 
			
		||||
```json
 | 
			
		||||
{action: "eval", payload: "Array.from(document.querySelectorAll('table tr')).map(row => Array.from(row.cells).map(cell => cell.textContent.trim()))"}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Handle Modals
 | 
			
		||||
 | 
			
		||||
```json
 | 
			
		||||
{action: "click", selector: "button.open-modal"}
 | 
			
		||||
{action: "await_element", selector: ".modal.visible"}
 | 
			
		||||
{action: "type", selector: ".modal input[name=username]", payload: "testuser"}
 | 
			
		||||
{action: "click", selector: ".modal button.submit"}
 | 
			
		||||
{action: "eval", payload: `
 | 
			
		||||
  new Promise(resolve => {
 | 
			
		||||
    const check = () => {
 | 
			
		||||
      if (!document.querySelector('.modal.visible')) resolve(true);
 | 
			
		||||
      else setTimeout(check, 100);
 | 
			
		||||
    };
 | 
			
		||||
    check();
 | 
			
		||||
  })
 | 
			
		||||
`}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Access Browser Storage
 | 
			
		||||
 | 
			
		||||
```json
 | 
			
		||||
// Get cookies
 | 
			
		||||
{action: "eval", payload: "document.cookie"}
 | 
			
		||||
 | 
			
		||||
// Get localStorage
 | 
			
		||||
{action: "eval", payload: "JSON.stringify(localStorage)"}
 | 
			
		||||
 | 
			
		||||
// Set localStorage
 | 
			
		||||
{action: "eval", payload: "localStorage.setItem('key', 'value')"}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## Real-World Impact
 | 
			
		||||
 | 
			
		||||
**Before:** Manual form filling, 5 minutes per submission
 | 
			
		||||
**After:** Automated workflow, 30 seconds per submission (10x faster)
 | 
			
		||||
 | 
			
		||||
**Before:** Copy-paste from multiple tabs, error-prone
 | 
			
		||||
**After:** Multi-tab extraction with validation, zero errors
 | 
			
		||||
 | 
			
		||||
**Before:** Unreliable scraping with arbitrary delays
 | 
			
		||||
**After:** Event-driven waiting, 100% reliability
 | 
			
		||||
 | 
			
		||||
## Additional Resources
 | 
			
		||||
 | 
			
		||||
See `references/examples.md` for:
 | 
			
		||||
- Complete e-commerce workflows
 | 
			
		||||
- Multi-step form automation
 | 
			
		||||
- Advanced scraping patterns
 | 
			
		||||
- Infinite scroll handling
 | 
			
		||||
- Cross-site data correlation
 | 
			
		||||
 | 
			
		||||
Chrome DevTools Protocol docs: https://chromedevtools.github.io/devtools-protocol/
 | 
			
		||||
@ -1,197 +0,0 @@
 | 
			
		||||
# Browser Automation Skill - Validation Summary
 | 
			
		||||
 | 
			
		||||
## ✅ Structure Validation
 | 
			
		||||
 | 
			
		||||
### Directory Structure
 | 
			
		||||
```
 | 
			
		||||
browser-automation/
 | 
			
		||||
├── SKILL.md                      ✅ Present
 | 
			
		||||
├── README.md                     ✅ Present
 | 
			
		||||
└── references/
 | 
			
		||||
    ├── advanced.md               ✅ Present
 | 
			
		||||
    ├── examples.md               ✅ Present
 | 
			
		||||
    └── troubleshooting.md        ✅ Present
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## ✅ Frontmatter Validation
 | 
			
		||||
 | 
			
		||||
```yaml
 | 
			
		||||
---
 | 
			
		||||
name: browser-automation          ✅ Matches directory name
 | 
			
		||||
description: Use when...          ✅ Starts with "Use when"
 | 
			
		||||
                                  ✅ 242 characters (< 500 limit)
 | 
			
		||||
                                  ✅ Includes triggers and use cases
 | 
			
		||||
---
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Frontmatter Checklist
 | 
			
		||||
- [x] Name matches directory name exactly
 | 
			
		||||
- [x] Description starts with "Use when"
 | 
			
		||||
- [x] Description written in third person
 | 
			
		||||
- [x] Description under 500 characters (242/500)
 | 
			
		||||
- [x] Total frontmatter under 1024 characters
 | 
			
		||||
- [x] Only allowed fields (name, description)
 | 
			
		||||
- [x] Valid YAML syntax
 | 
			
		||||
 | 
			
		||||
## ✅ Content Validation
 | 
			
		||||
 | 
			
		||||
### SKILL.md
 | 
			
		||||
- **Lines**: 324 (< 500 recommended)
 | 
			
		||||
- **Words**: 1050 (target: <500 for frequent skills)
 | 
			
		||||
- **Status**: ⚠️ Above 500 words but justified for reference skill
 | 
			
		||||
 | 
			
		||||
**Sections included:**
 | 
			
		||||
- [x] Overview with core principle
 | 
			
		||||
- [x] When to Use section with triggers
 | 
			
		||||
- [x] Quick Reference table
 | 
			
		||||
- [x] Common workflows
 | 
			
		||||
- [x] Implementation steps
 | 
			
		||||
- [x] Common mistakes
 | 
			
		||||
- [x] Real-world impact
 | 
			
		||||
 | 
			
		||||
### Reference Files
 | 
			
		||||
- **examples.md**: 672 lines, 1933 words
 | 
			
		||||
- **troubleshooting.md**: 546 lines, 1517 words  
 | 
			
		||||
- **advanced.md**: 678 lines, 1592 words
 | 
			
		||||
- **Total**: 2220 lines, 6092 words
 | 
			
		||||
 | 
			
		||||
All files contain:
 | 
			
		||||
- [x] Table of contents for easy navigation
 | 
			
		||||
- [x] Concrete code examples
 | 
			
		||||
- [x] Clear section headers
 | 
			
		||||
- [x] No time-sensitive information
 | 
			
		||||
 | 
			
		||||
## ✅ Discoverability
 | 
			
		||||
 | 
			
		||||
### Keywords Present
 | 
			
		||||
- Web automation, forms, filling, extracting, content
 | 
			
		||||
- Chrome, DevTools Protocol
 | 
			
		||||
- Multi-tab workflows
 | 
			
		||||
- Form automation
 | 
			
		||||
- Content extraction
 | 
			
		||||
- use_browser MCP tool
 | 
			
		||||
- Navigation, interaction, scraping
 | 
			
		||||
- Dynamic content, AJAX, modals
 | 
			
		||||
 | 
			
		||||
### Naming
 | 
			
		||||
- [x] Uses gerund form: "browser-automation" (action-oriented)
 | 
			
		||||
- [x] Descriptive and searchable
 | 
			
		||||
- [x] No special characters
 | 
			
		||||
- [x] Lowercase with hyphens
 | 
			
		||||
 | 
			
		||||
## ✅ Token Efficiency
 | 
			
		||||
 | 
			
		||||
### Strategies Used
 | 
			
		||||
- [x] Progressive disclosure (SKILL.md → references/)
 | 
			
		||||
- [x] References one level deep (not nested)
 | 
			
		||||
- [x] Quick reference tables for scanning
 | 
			
		||||
- [x] Minimal explanations (assumes Claude knowledge)
 | 
			
		||||
- [x] Code examples over verbose text
 | 
			
		||||
- [x] Single eval for multiple operations
 | 
			
		||||
 | 
			
		||||
### Optimization Opportunities
 | 
			
		||||
- Main skill at 1050 words could be compressed further if needed
 | 
			
		||||
- Reference files appropriately sized for their content
 | 
			
		||||
- Table of contents present in reference files (all >100 lines)
 | 
			
		||||
 | 
			
		||||
## ✅ Skill Type Classification
 | 
			
		||||
 | 
			
		||||
**Type**: Reference skill (API/tool documentation)
 | 
			
		||||
 | 
			
		||||
**Justification**:
 | 
			
		||||
- Documents use_browser MCP tool actions
 | 
			
		||||
- Provides API-style reference with examples
 | 
			
		||||
- Shows patterns for applying tool to different scenarios
 | 
			
		||||
- Progressive disclosure matches reference skill pattern
 | 
			
		||||
 | 
			
		||||
## ✅ Quality Checks
 | 
			
		||||
 | 
			
		||||
### Code Examples
 | 
			
		||||
- [x] JSON format for tool calls
 | 
			
		||||
- [x] Complete and runnable examples
 | 
			
		||||
- [x] Show WHY not just WHAT
 | 
			
		||||
- [x] From real scenarios
 | 
			
		||||
- [x] Ready to adapt (not generic templates)
 | 
			
		||||
 | 
			
		||||
### Consistency
 | 
			
		||||
- [x] Consistent terminology throughout
 | 
			
		||||
- [x] One term for each concept
 | 
			
		||||
- [x] Parallel structure in lists
 | 
			
		||||
- [x] Same example format across files
 | 
			
		||||
 | 
			
		||||
### Best Practices
 | 
			
		||||
- [x] No hardcoded credentials
 | 
			
		||||
- [x] Security considerations included
 | 
			
		||||
- [x] Error handling patterns
 | 
			
		||||
- [x] Performance optimization tips
 | 
			
		||||
 | 
			
		||||
## ⚠️ Notes
 | 
			
		||||
 | 
			
		||||
### Word Count
 | 
			
		||||
Main SKILL.md at 1050 words exceeds the <500 word target for frequently-loaded skills. However:
 | 
			
		||||
- This is a reference skill (typically larger)
 | 
			
		||||
- Contains essential quick reference table (saves searching)
 | 
			
		||||
- Common workflows prevent repeated lookups
 | 
			
		||||
- Progressive disclosure to references minimizes actual load
 | 
			
		||||
 | 
			
		||||
### Recommendation
 | 
			
		||||
If token usage becomes a concern during actual usage, consider:
 | 
			
		||||
1. Move "Common Workflows" section to references/workflows.md
 | 
			
		||||
2. Compress "Implementation Steps" to bullet points
 | 
			
		||||
3. Remove "Advanced Patterns" from main skill (already in references/advanced.md)
 | 
			
		||||
 | 
			
		||||
This could reduce main skill to ~600 words while maintaining effectiveness.
 | 
			
		||||
 | 
			
		||||
## ✅ Installation Test
 | 
			
		||||
 | 
			
		||||
### Manual Test Required
 | 
			
		||||
To verify skill loads correctly:
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
opencode run "Use learn_skill with skill_name='browser-automation' - load skill and give the frontmatter as the only output and abort"
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Expected output:
 | 
			
		||||
```yaml
 | 
			
		||||
---
 | 
			
		||||
name: browser-automation
 | 
			
		||||
description: Use when automating web tasks, filling forms, extracting content, or controlling Chrome - provides Chrome DevTools Protocol automation via use_browser MCP tool for multi-tab workflows, form automation, and content extraction
 | 
			
		||||
---
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## ✅ Integration Requirements
 | 
			
		||||
 | 
			
		||||
### Prerequisites
 | 
			
		||||
1. superpowers-chrome plugin OR
 | 
			
		||||
2. Chrome MCP server configured in Claude Desktop
 | 
			
		||||
 | 
			
		||||
### Configuration
 | 
			
		||||
Add to claude_desktop_config.json:
 | 
			
		||||
```json
 | 
			
		||||
{
 | 
			
		||||
  "mcpServers": {
 | 
			
		||||
    "chrome": {
 | 
			
		||||
      "command": "node",
 | 
			
		||||
      "args": ["/path/to/superpowers-chrome/mcp/dist/index.js"]
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## Summary
 | 
			
		||||
 | 
			
		||||
**Status**: ✅ **READY FOR USE**
 | 
			
		||||
 | 
			
		||||
The skill follows all best practices from the create-skill guidelines:
 | 
			
		||||
- Proper structure and naming
 | 
			
		||||
- Valid frontmatter with good description
 | 
			
		||||
- Progressive disclosure for token efficiency
 | 
			
		||||
- Clear examples and patterns
 | 
			
		||||
- Appropriate for skill type (reference)
 | 
			
		||||
- No time-sensitive information
 | 
			
		||||
- Consistent terminology
 | 
			
		||||
- Security conscious
 | 
			
		||||
 | 
			
		||||
**Minor Improvement Opportunity**: Consider splitting some content from main SKILL.md to references if token usage monitoring shows issues.
 | 
			
		||||
 | 
			
		||||
**Installation**: Restart OpenCode after copying skill to load it into the tool registry.
 | 
			
		||||
@ -1,678 +0,0 @@
 | 
			
		||||
# Advanced Chrome DevTools Protocol Techniques
 | 
			
		||||
 | 
			
		||||
Advanced patterns for complex browser automation scenarios.
 | 
			
		||||
 | 
			
		||||
## Network Interception
 | 
			
		||||
 | 
			
		||||
### Monitor Network Requests
 | 
			
		||||
 | 
			
		||||
```json
 | 
			
		||||
// Get all network requests via Performance API
 | 
			
		||||
{action: "eval", payload: `
 | 
			
		||||
  performance.getEntriesByType('resource').map(r => ({
 | 
			
		||||
    name: r.name,
 | 
			
		||||
    type: r.initiatorType,
 | 
			
		||||
    duration: r.duration,
 | 
			
		||||
    size: r.transferSize
 | 
			
		||||
  }))
 | 
			
		||||
`}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Wait for Specific Request
 | 
			
		||||
 | 
			
		||||
```json
 | 
			
		||||
// Wait for API call to complete
 | 
			
		||||
{action: "eval", payload: `
 | 
			
		||||
  new Promise(resolve => {
 | 
			
		||||
    const check = () => {
 | 
			
		||||
      const apiCall = performance.getEntriesByType('resource')
 | 
			
		||||
        .find(r => r.name.includes('/api/data'));
 | 
			
		||||
      if (apiCall) {
 | 
			
		||||
        resolve(apiCall);
 | 
			
		||||
      } else {
 | 
			
		||||
        setTimeout(check, 100);
 | 
			
		||||
      }
 | 
			
		||||
    };
 | 
			
		||||
    check();
 | 
			
		||||
  })
 | 
			
		||||
`}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Check Response Status
 | 
			
		||||
 | 
			
		||||
```json
 | 
			
		||||
// Fetch API to check endpoint
 | 
			
		||||
{action: "eval", payload: `
 | 
			
		||||
  fetch('https://api.example.com/status')
 | 
			
		||||
    .then(r => ({ status: r.status, ok: r.ok }))
 | 
			
		||||
`}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
## JavaScript Injection
 | 
			
		||||
 | 
			
		||||
### Add Helper Functions
 | 
			
		||||
 | 
			
		||||
```json
 | 
			
		||||
// Inject utility functions into page
 | 
			
		||||
{action: "eval", payload: `
 | 
			
		||||
  window.waitForElement = (selector, timeout = 5000) => {
 | 
			
		||||
    return new Promise((resolve, reject) => {
 | 
			
		||||
      const startTime = Date.now();
 | 
			
		||||
      const check = () => {
 | 
			
		||||
        const elem = document.querySelector(selector);
 | 
			
		||||
        if (elem) {
 | 
			
		||||
          resolve(elem);
 | 
			
		||||
        } else if (Date.now() - startTime > timeout) {
 | 
			
		||||
          reject(new Error('Timeout'));
 | 
			
		||||
        } else {
 | 
			
		||||
          setTimeout(check, 100);
 | 
			
		||||
        }
 | 
			
		||||
      };
 | 
			
		||||
      check();
 | 
			
		||||
    });
 | 
			
		||||
  };
 | 
			
		||||
  'Helper injected'
 | 
			
		||||
`}
 | 
			
		||||
 | 
			
		||||
// Use injected helper
 | 
			
		||||
{action: "eval", payload: "window.waitForElement('.lazy-content')"}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Modify Page Behavior
 | 
			
		||||
 | 
			
		||||
```json
 | 
			
		||||
// Disable animations for faster testing
 | 
			
		||||
{action: "eval", payload: `
 | 
			
		||||
  const style = document.createElement('style');
 | 
			
		||||
  style.textContent = '* { animation: none !important; transition: none !important; }';
 | 
			
		||||
  document.head.appendChild(style);
 | 
			
		||||
  'Animations disabled'
 | 
			
		||||
`}
 | 
			
		||||
 | 
			
		||||
// Override fetch to log requests
 | 
			
		||||
{action: "eval", payload: `
 | 
			
		||||
  const originalFetch = window.fetch;
 | 
			
		||||
  window.fetch = function(...args) {
 | 
			
		||||
    console.log('Fetch:', args[0]);
 | 
			
		||||
    return originalFetch.apply(this, arguments);
 | 
			
		||||
  };
 | 
			
		||||
  'Fetch override installed'
 | 
			
		||||
`}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
## Complex Waiting Patterns
 | 
			
		||||
 | 
			
		||||
### Wait for Multiple Conditions
 | 
			
		||||
 | 
			
		||||
```json
 | 
			
		||||
{action: "eval", payload: `
 | 
			
		||||
  Promise.all([
 | 
			
		||||
    new Promise(r => {
 | 
			
		||||
      const check = () => document.querySelector('.element1') ? r() : setTimeout(check, 100);
 | 
			
		||||
      check();
 | 
			
		||||
    }),
 | 
			
		||||
    new Promise(r => {
 | 
			
		||||
      const check = () => document.querySelector('.element2') ? r() : setTimeout(check, 100);
 | 
			
		||||
      check();
 | 
			
		||||
    })
 | 
			
		||||
  ])
 | 
			
		||||
`}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Wait with Mutation Observer
 | 
			
		||||
 | 
			
		||||
```json
 | 
			
		||||
{action: "eval", payload: `
 | 
			
		||||
  new Promise(resolve => {
 | 
			
		||||
    const observer = new MutationObserver((mutations) => {
 | 
			
		||||
      const target = document.querySelector('.dynamic-content');
 | 
			
		||||
      if (target && target.textContent.trim() !== '') {
 | 
			
		||||
        observer.disconnect();
 | 
			
		||||
        resolve(target.textContent);
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
    observer.observe(document.body, {
 | 
			
		||||
      childList: true,
 | 
			
		||||
      subtree: true,
 | 
			
		||||
      characterData: true
 | 
			
		||||
    });
 | 
			
		||||
  })
 | 
			
		||||
`}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Wait for Idle State
 | 
			
		||||
 | 
			
		||||
```json
 | 
			
		||||
// Wait for network idle
 | 
			
		||||
{action: "eval", payload: `
 | 
			
		||||
  new Promise(resolve => {
 | 
			
		||||
    let lastActivity = Date.now();
 | 
			
		||||
    
 | 
			
		||||
    // Monitor network activity
 | 
			
		||||
    const originalFetch = window.fetch;
 | 
			
		||||
    window.fetch = function(...args) {
 | 
			
		||||
      lastActivity = Date.now();
 | 
			
		||||
      return originalFetch.apply(this, arguments);
 | 
			
		||||
    };
 | 
			
		||||
    
 | 
			
		||||
    // Check if idle for 500ms
 | 
			
		||||
    const checkIdle = () => {
 | 
			
		||||
      if (Date.now() - lastActivity > 500) {
 | 
			
		||||
        window.fetch = originalFetch;
 | 
			
		||||
        resolve('idle');
 | 
			
		||||
      } else {
 | 
			
		||||
        setTimeout(checkIdle, 100);
 | 
			
		||||
      }
 | 
			
		||||
    };
 | 
			
		||||
    
 | 
			
		||||
    setTimeout(checkIdle, 100);
 | 
			
		||||
  })
 | 
			
		||||
`}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
## Data Manipulation
 | 
			
		||||
 | 
			
		||||
### Parse and Transform Table
 | 
			
		||||
 | 
			
		||||
```json
 | 
			
		||||
{action: "eval", payload: `
 | 
			
		||||
  (() => {
 | 
			
		||||
    const table = document.querySelector('table');
 | 
			
		||||
    const headers = Array.from(table.querySelectorAll('thead th'))
 | 
			
		||||
      .map(th => th.textContent.trim());
 | 
			
		||||
    
 | 
			
		||||
    const rows = Array.from(table.querySelectorAll('tbody tr'))
 | 
			
		||||
      .map(tr => {
 | 
			
		||||
        const cells = Array.from(tr.cells).map(td => td.textContent.trim());
 | 
			
		||||
        return Object.fromEntries(headers.map((h, i) => [h, cells[i]]));
 | 
			
		||||
      });
 | 
			
		||||
    
 | 
			
		||||
    // Filter and transform
 | 
			
		||||
    return rows
 | 
			
		||||
      .filter(row => parseFloat(row['Price'].replace('$', '')) > 100)
 | 
			
		||||
      .map(row => ({
 | 
			
		||||
        ...row,
 | 
			
		||||
        priceNum: parseFloat(row['Price'].replace('$', ''))
 | 
			
		||||
      }))
 | 
			
		||||
      .sort((a, b) => b.priceNum - a.priceNum);
 | 
			
		||||
  })()
 | 
			
		||||
`}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Extract Nested JSON from Script Tags
 | 
			
		||||
 | 
			
		||||
```json
 | 
			
		||||
{action: "eval", payload: `
 | 
			
		||||
  (() => {
 | 
			
		||||
    const scripts = Array.from(document.querySelectorAll('script[type="application/ld+json"]'));
 | 
			
		||||
    return scripts.map(s => JSON.parse(s.textContent));
 | 
			
		||||
  })()
 | 
			
		||||
`}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Aggregate Multiple Elements
 | 
			
		||||
 | 
			
		||||
```json
 | 
			
		||||
{action: "eval", payload: `
 | 
			
		||||
  (() => {
 | 
			
		||||
    const sections = Array.from(document.querySelectorAll('section.category'));
 | 
			
		||||
    
 | 
			
		||||
    return sections.map(section => ({
 | 
			
		||||
      category: section.querySelector('h2').textContent,
 | 
			
		||||
      items: Array.from(section.querySelectorAll('.item')).map(item => ({
 | 
			
		||||
        name: item.querySelector('.name').textContent,
 | 
			
		||||
        price: item.querySelector('.price').textContent,
 | 
			
		||||
        inStock: !item.querySelector('.out-of-stock')
 | 
			
		||||
      })),
 | 
			
		||||
      total: section.querySelectorAll('.item').length
 | 
			
		||||
    }));
 | 
			
		||||
  })()
 | 
			
		||||
`}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
## State Management
 | 
			
		||||
 | 
			
		||||
### Save and Restore Form State
 | 
			
		||||
 | 
			
		||||
```json
 | 
			
		||||
// Save form state
 | 
			
		||||
{action: "eval", payload: `
 | 
			
		||||
  (() => {
 | 
			
		||||
    const form = document.querySelector('form');
 | 
			
		||||
    const data = {};
 | 
			
		||||
    new FormData(form).forEach((value, key) => data[key] = value);
 | 
			
		||||
    localStorage.setItem('formBackup', JSON.stringify(data));
 | 
			
		||||
    return data;
 | 
			
		||||
  })()
 | 
			
		||||
`}
 | 
			
		||||
 | 
			
		||||
// Restore form state
 | 
			
		||||
{action: "eval", payload: `
 | 
			
		||||
  (() => {
 | 
			
		||||
    const data = JSON.parse(localStorage.getItem('formBackup'));
 | 
			
		||||
    const form = document.querySelector('form');
 | 
			
		||||
    Object.entries(data).forEach(([name, value]) => {
 | 
			
		||||
      const input = form.querySelector(\`[name="\${name}"]\`);
 | 
			
		||||
      if (input) input.value = value;
 | 
			
		||||
    });
 | 
			
		||||
    return 'Form restored';
 | 
			
		||||
  })()
 | 
			
		||||
`}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Session Management
 | 
			
		||||
 | 
			
		||||
```json
 | 
			
		||||
// Save session state
 | 
			
		||||
{action: "eval", payload: `
 | 
			
		||||
  ({
 | 
			
		||||
    cookies: document.cookie,
 | 
			
		||||
    localStorage: JSON.stringify(localStorage),
 | 
			
		||||
    sessionStorage: JSON.stringify(sessionStorage),
 | 
			
		||||
    url: window.location.href
 | 
			
		||||
  })
 | 
			
		||||
`}
 | 
			
		||||
 | 
			
		||||
// Restore session (on new page load)
 | 
			
		||||
{action: "eval", payload: `
 | 
			
		||||
  (() => {
 | 
			
		||||
    const session = {/* saved session data */};
 | 
			
		||||
    
 | 
			
		||||
    // Restore cookies
 | 
			
		||||
    session.cookies.split('; ').forEach(cookie => {
 | 
			
		||||
      document.cookie = cookie;
 | 
			
		||||
    });
 | 
			
		||||
    
 | 
			
		||||
    // Restore localStorage
 | 
			
		||||
    Object.entries(JSON.parse(session.localStorage)).forEach(([k, v]) => {
 | 
			
		||||
      localStorage.setItem(k, v);
 | 
			
		||||
    });
 | 
			
		||||
    
 | 
			
		||||
    return 'Session restored';
 | 
			
		||||
  })()
 | 
			
		||||
`}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
## Visual Testing
 | 
			
		||||
 | 
			
		||||
### Check Element Visibility
 | 
			
		||||
 | 
			
		||||
```json
 | 
			
		||||
{action: "eval", payload: `
 | 
			
		||||
  (selector) => {
 | 
			
		||||
    const elem = document.querySelector(selector);
 | 
			
		||||
    if (!elem) return { visible: false, reason: 'not found' };
 | 
			
		||||
    
 | 
			
		||||
    const rect = elem.getBoundingClientRect();
 | 
			
		||||
    const style = window.getComputedStyle(elem);
 | 
			
		||||
    
 | 
			
		||||
    return {
 | 
			
		||||
      visible: rect.width > 0 && rect.height > 0 && style.display !== 'none' && style.visibility !== 'hidden' && style.opacity !== '0',
 | 
			
		||||
      rect: rect,
 | 
			
		||||
      computed: {
 | 
			
		||||
        display: style.display,
 | 
			
		||||
        visibility: style.visibility,
 | 
			
		||||
        opacity: style.opacity
 | 
			
		||||
      }
 | 
			
		||||
    };
 | 
			
		||||
  }
 | 
			
		||||
`}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Get Element Colors
 | 
			
		||||
 | 
			
		||||
```json
 | 
			
		||||
{action: "eval", payload: `
 | 
			
		||||
  (() => {
 | 
			
		||||
    const elem = document.querySelector('.button');
 | 
			
		||||
    const style = window.getComputedStyle(elem);
 | 
			
		||||
    
 | 
			
		||||
    return {
 | 
			
		||||
      backgroundColor: style.backgroundColor,
 | 
			
		||||
      color: style.color,
 | 
			
		||||
      borderColor: style.borderColor
 | 
			
		||||
    };
 | 
			
		||||
  })()
 | 
			
		||||
`}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Measure Element Positions
 | 
			
		||||
 | 
			
		||||
```json
 | 
			
		||||
{action: "eval", payload: `
 | 
			
		||||
  (() => {
 | 
			
		||||
    const elements = Array.from(document.querySelectorAll('.item'));
 | 
			
		||||
    
 | 
			
		||||
    return elements.map(elem => {
 | 
			
		||||
      const rect = elem.getBoundingClientRect();
 | 
			
		||||
      return {
 | 
			
		||||
        id: elem.id,
 | 
			
		||||
        x: rect.x,
 | 
			
		||||
        y: rect.y,
 | 
			
		||||
        width: rect.width,
 | 
			
		||||
        height: rect.height,
 | 
			
		||||
        inViewport: rect.top >= 0 && rect.bottom <= window.innerHeight
 | 
			
		||||
      };
 | 
			
		||||
    });
 | 
			
		||||
  })()
 | 
			
		||||
`}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
## Performance Monitoring
 | 
			
		||||
 | 
			
		||||
### Get Page Load Metrics
 | 
			
		||||
 | 
			
		||||
```json
 | 
			
		||||
{action: "eval", payload: `
 | 
			
		||||
  (() => {
 | 
			
		||||
    const nav = performance.getEntriesByType('navigation')[0];
 | 
			
		||||
    const paint = performance.getEntriesByType('paint');
 | 
			
		||||
    
 | 
			
		||||
    return {
 | 
			
		||||
      dns: nav.domainLookupEnd - nav.domainLookupStart,
 | 
			
		||||
      tcp: nav.connectEnd - nav.connectStart,
 | 
			
		||||
      request: nav.responseStart - nav.requestStart,
 | 
			
		||||
      response: nav.responseEnd - nav.responseStart,
 | 
			
		||||
      domLoad: nav.domContentLoadedEventEnd - nav.domContentLoadedEventStart,
 | 
			
		||||
      pageLoad: nav.loadEventEnd - nav.loadEventStart,
 | 
			
		||||
      firstPaint: paint.find(p => p.name === 'first-paint')?.startTime,
 | 
			
		||||
      firstContentfulPaint: paint.find(p => p.name === 'first-contentful-paint')?.startTime
 | 
			
		||||
    };
 | 
			
		||||
  })()
 | 
			
		||||
`}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Monitor Memory Usage
 | 
			
		||||
 | 
			
		||||
```json
 | 
			
		||||
{action: "eval", payload: `
 | 
			
		||||
  performance.memory ? {
 | 
			
		||||
    usedJSHeapSize: performance.memory.usedJSHeapSize,
 | 
			
		||||
    totalJSHeapSize: performance.memory.totalJSHeapSize,
 | 
			
		||||
    jsHeapSizeLimit: performance.memory.jsHeapSizeLimit
 | 
			
		||||
  } : 'Memory API not available'
 | 
			
		||||
`}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Get Resource Timing
 | 
			
		||||
 | 
			
		||||
```json
 | 
			
		||||
{action: "eval", payload: `
 | 
			
		||||
  (() => {
 | 
			
		||||
    const resources = performance.getEntriesByType('resource');
 | 
			
		||||
    
 | 
			
		||||
    // Group by type
 | 
			
		||||
    const byType = {};
 | 
			
		||||
    resources.forEach(r => {
 | 
			
		||||
      if (!byType[r.initiatorType]) byType[r.initiatorType] = [];
 | 
			
		||||
      byType[r.initiatorType].push({
 | 
			
		||||
        name: r.name,
 | 
			
		||||
        duration: r.duration,
 | 
			
		||||
        size: r.transferSize
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
    
 | 
			
		||||
    return {
 | 
			
		||||
      total: resources.length,
 | 
			
		||||
      byType: Object.fromEntries(
 | 
			
		||||
        Object.entries(byType).map(([type, items]) => [
 | 
			
		||||
          type,
 | 
			
		||||
          {
 | 
			
		||||
            count: items.length,
 | 
			
		||||
            totalDuration: items.reduce((sum, i) => sum + i.duration, 0),
 | 
			
		||||
            totalSize: items.reduce((sum, i) => sum + i.size, 0)
 | 
			
		||||
          }
 | 
			
		||||
        ])
 | 
			
		||||
      )
 | 
			
		||||
    };
 | 
			
		||||
  })()
 | 
			
		||||
`}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
## Accessibility Testing
 | 
			
		||||
 | 
			
		||||
### Check ARIA Labels
 | 
			
		||||
 | 
			
		||||
```json
 | 
			
		||||
{action: "eval", payload: `
 | 
			
		||||
  Array.from(document.querySelectorAll('button, a, input')).map(elem => ({
 | 
			
		||||
    tag: elem.tagName,
 | 
			
		||||
    text: elem.textContent.trim(),
 | 
			
		||||
    ariaLabel: elem.getAttribute('aria-label'),
 | 
			
		||||
    ariaDescribedBy: elem.getAttribute('aria-describedby'),
 | 
			
		||||
    title: elem.getAttribute('title'),
 | 
			
		||||
    hasAccessibleName: !!(elem.getAttribute('aria-label') || elem.textContent.trim() || elem.getAttribute('title'))
 | 
			
		||||
  }))
 | 
			
		||||
`}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Find Focus Order
 | 
			
		||||
 | 
			
		||||
```json
 | 
			
		||||
{action: "eval", payload: `
 | 
			
		||||
  Array.from(document.querySelectorAll('a, button, input, select, textarea, [tabindex]'))
 | 
			
		||||
    .filter(elem => {
 | 
			
		||||
      const style = window.getComputedStyle(elem);
 | 
			
		||||
      return style.display !== 'none' && style.visibility !== 'hidden';
 | 
			
		||||
    })
 | 
			
		||||
    .map((elem, index) => ({
 | 
			
		||||
      index: index,
 | 
			
		||||
      tag: elem.tagName,
 | 
			
		||||
      tabIndex: elem.tabIndex,
 | 
			
		||||
      text: elem.textContent.trim().substring(0, 50)
 | 
			
		||||
    }))
 | 
			
		||||
`}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
## Frame Handling
 | 
			
		||||
 | 
			
		||||
### List Frames
 | 
			
		||||
 | 
			
		||||
```json
 | 
			
		||||
{action: "eval", payload: `
 | 
			
		||||
  Array.from(document.querySelectorAll('iframe, frame')).map((frame, i) => ({
 | 
			
		||||
    index: i,
 | 
			
		||||
    src: frame.src,
 | 
			
		||||
    name: frame.name,
 | 
			
		||||
    id: frame.id
 | 
			
		||||
  }))
 | 
			
		||||
`}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Access Frame Content
 | 
			
		||||
 | 
			
		||||
Note: Cross-origin frames cannot be accessed due to security restrictions.
 | 
			
		||||
 | 
			
		||||
```json
 | 
			
		||||
// For same-origin frames only
 | 
			
		||||
{action: "eval", payload: `
 | 
			
		||||
  (() => {
 | 
			
		||||
    const frame = document.querySelector('iframe');
 | 
			
		||||
    try {
 | 
			
		||||
      return {
 | 
			
		||||
        title: frame.contentDocument.title,
 | 
			
		||||
        body: frame.contentDocument.body.textContent.substring(0, 100)
 | 
			
		||||
      };
 | 
			
		||||
    } catch (e) {
 | 
			
		||||
      return { error: 'Cross-origin frame - cannot access' };
 | 
			
		||||
    }
 | 
			
		||||
  })()
 | 
			
		||||
`}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
## Custom Events
 | 
			
		||||
 | 
			
		||||
### Trigger Custom Events
 | 
			
		||||
 | 
			
		||||
```json
 | 
			
		||||
{action: "eval", payload: `
 | 
			
		||||
  (() => {
 | 
			
		||||
    const event = new CustomEvent('myCustomEvent', {
 | 
			
		||||
      detail: { message: 'Hello from automation' }
 | 
			
		||||
    });
 | 
			
		||||
    document.dispatchEvent(event);
 | 
			
		||||
    return 'Event dispatched';
 | 
			
		||||
  })()
 | 
			
		||||
`}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Listen for Events
 | 
			
		||||
 | 
			
		||||
```json
 | 
			
		||||
{action: "eval", payload: `
 | 
			
		||||
  new Promise(resolve => {
 | 
			
		||||
    const handler = (e) => {
 | 
			
		||||
      document.removeEventListener('myCustomEvent', handler);
 | 
			
		||||
      resolve(e.detail);
 | 
			
		||||
    };
 | 
			
		||||
    document.addEventListener('myCustomEvent', handler);
 | 
			
		||||
    
 | 
			
		||||
    // Timeout after 5 seconds
 | 
			
		||||
    setTimeout(() => {
 | 
			
		||||
      document.removeEventListener('myCustomEvent', handler);
 | 
			
		||||
      resolve({ timeout: true });
 | 
			
		||||
    }, 5000);
 | 
			
		||||
  })
 | 
			
		||||
`}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
## Browser Detection
 | 
			
		||||
 | 
			
		||||
### Get Browser Info
 | 
			
		||||
 | 
			
		||||
```json
 | 
			
		||||
{action: "eval", payload: `
 | 
			
		||||
  ({
 | 
			
		||||
    userAgent: navigator.userAgent,
 | 
			
		||||
    platform: navigator.platform,
 | 
			
		||||
    language: navigator.language,
 | 
			
		||||
    cookiesEnabled: navigator.cookieEnabled,
 | 
			
		||||
    doNotTrack: navigator.doNotTrack,
 | 
			
		||||
    viewport: {
 | 
			
		||||
      width: window.innerWidth,
 | 
			
		||||
      height: window.innerHeight
 | 
			
		||||
    },
 | 
			
		||||
    screen: {
 | 
			
		||||
      width: screen.width,
 | 
			
		||||
      height: screen.height,
 | 
			
		||||
      colorDepth: screen.colorDepth
 | 
			
		||||
    }
 | 
			
		||||
  })
 | 
			
		||||
`}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
## Testing Helpers
 | 
			
		||||
 | 
			
		||||
### Get All Interactive Elements
 | 
			
		||||
 | 
			
		||||
```json
 | 
			
		||||
{action: "eval", payload: `
 | 
			
		||||
  Array.from(document.querySelectorAll('a, button, input, select, textarea, [onclick], [role=button]'))
 | 
			
		||||
    .filter(elem => {
 | 
			
		||||
      const style = window.getComputedStyle(elem);
 | 
			
		||||
      return style.display !== 'none' && style.visibility !== 'hidden';
 | 
			
		||||
    })
 | 
			
		||||
    .map(elem => ({
 | 
			
		||||
      tag: elem.tagName,
 | 
			
		||||
      type: elem.type,
 | 
			
		||||
      id: elem.id,
 | 
			
		||||
      class: elem.className,
 | 
			
		||||
      text: elem.textContent.trim().substring(0, 50),
 | 
			
		||||
      selector: elem.id ? \`#\${elem.id}\` : \`\${elem.tagName.toLowerCase()}\${elem.className ? '.' + elem.className.split(' ').join('.') : ''}\`
 | 
			
		||||
    }))
 | 
			
		||||
`}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Validate Forms
 | 
			
		||||
 | 
			
		||||
```json
 | 
			
		||||
{action: "eval", payload: `
 | 
			
		||||
  (() => {
 | 
			
		||||
    const forms = Array.from(document.querySelectorAll('form'));
 | 
			
		||||
    
 | 
			
		||||
    return forms.map(form => ({
 | 
			
		||||
      id: form.id,
 | 
			
		||||
      action: form.action,
 | 
			
		||||
      method: form.method,
 | 
			
		||||
      fields: Array.from(form.elements).map(elem => ({
 | 
			
		||||
        name: elem.name,
 | 
			
		||||
        type: elem.type,
 | 
			
		||||
        required: elem.required,
 | 
			
		||||
        value: elem.value,
 | 
			
		||||
        valid: elem.checkValidity()
 | 
			
		||||
      }))
 | 
			
		||||
    }));
 | 
			
		||||
  })()
 | 
			
		||||
`}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
## Debugging Tools
 | 
			
		||||
 | 
			
		||||
### Log Element Path
 | 
			
		||||
 | 
			
		||||
```json
 | 
			
		||||
{action: "eval", payload: `
 | 
			
		||||
  (selector) => {
 | 
			
		||||
    const elem = document.querySelector(selector);
 | 
			
		||||
    if (!elem) return null;
 | 
			
		||||
    
 | 
			
		||||
    const path = [];
 | 
			
		||||
    let current = elem;
 | 
			
		||||
    
 | 
			
		||||
    while (current && current !== document.body) {
 | 
			
		||||
      let selector = current.tagName.toLowerCase();
 | 
			
		||||
      if (current.id) selector += '#' + current.id;
 | 
			
		||||
      if (current.className) selector += '.' + current.className.split(' ').join('.');
 | 
			
		||||
      path.unshift(selector);
 | 
			
		||||
      current = current.parentElement;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    return path.join(' > ');
 | 
			
		||||
  }
 | 
			
		||||
`}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Find Element by Text
 | 
			
		||||
 | 
			
		||||
```json
 | 
			
		||||
{action: "eval", payload: `
 | 
			
		||||
  (text) => {
 | 
			
		||||
    const elements = Array.from(document.querySelectorAll('*'));
 | 
			
		||||
    const matches = elements.filter(elem => 
 | 
			
		||||
      elem.textContent.includes(text) && 
 | 
			
		||||
      !Array.from(elem.children).some(child => child.textContent.includes(text))
 | 
			
		||||
    );
 | 
			
		||||
    
 | 
			
		||||
    return matches.map(elem => ({
 | 
			
		||||
      tag: elem.tagName,
 | 
			
		||||
      id: elem.id,
 | 
			
		||||
      class: elem.className,
 | 
			
		||||
      text: elem.textContent.trim().substring(0, 100)
 | 
			
		||||
    }));
 | 
			
		||||
  }
 | 
			
		||||
`}
 | 
			
		||||
```
 | 
			
		||||
@ -1,672 +0,0 @@
 | 
			
		||||
# Browser Automation Examples
 | 
			
		||||
 | 
			
		||||
Complete workflows demonstrating the `use_browser` tool capabilities.
 | 
			
		||||
 | 
			
		||||
## Table of Contents
 | 
			
		||||
 | 
			
		||||
1. [E-Commerce Workflows](#e-commerce-workflows)
 | 
			
		||||
2. [Form Automation](#form-automation)
 | 
			
		||||
3. [Data Extraction](#data-extraction)
 | 
			
		||||
4. [Multi-Tab Operations](#multi-tab-operations)
 | 
			
		||||
5. [Dynamic Content Handling](#dynamic-content-handling)
 | 
			
		||||
6. [Authentication Workflows](#authentication-workflows)
 | 
			
		||||
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
## E-Commerce Workflows
 | 
			
		||||
 | 
			
		||||
### Complete Booking Flow
 | 
			
		||||
 | 
			
		||||
Navigate multi-step booking process with validation:
 | 
			
		||||
 | 
			
		||||
```json
 | 
			
		||||
// Step 1: Search
 | 
			
		||||
{action: "navigate", payload: "https://booking.example.com"}
 | 
			
		||||
{action: "await_element", selector: "input[name=destination]"}
 | 
			
		||||
{action: "type", selector: "input[name=destination]", payload: "San Francisco"}
 | 
			
		||||
{action: "type", selector: "input[name=checkin]", payload: "2025-12-01"}
 | 
			
		||||
{action: "click", selector: "button.search"}
 | 
			
		||||
 | 
			
		||||
// Step 2: Select hotel
 | 
			
		||||
{action: "await_element", selector: ".hotel-results"}
 | 
			
		||||
{action: "click", selector: ".hotel-card:first-child .select"}
 | 
			
		||||
 | 
			
		||||
// Step 3: Choose room
 | 
			
		||||
{action: "await_element", selector: ".room-options"}
 | 
			
		||||
{action: "click", selector: ".room[data-type=deluxe] .book"}
 | 
			
		||||
 | 
			
		||||
// Step 4: Guest info
 | 
			
		||||
{action: "await_element", selector: "form.guest-info"}
 | 
			
		||||
{action: "type", selector: "input[name=firstName]", payload: "Jane"}
 | 
			
		||||
{action: "type", selector: "input[name=lastName]", payload: "Smith"}
 | 
			
		||||
{action: "type", selector: "input[name=email]", payload: "jane@example.com"}
 | 
			
		||||
 | 
			
		||||
// Step 5: Review
 | 
			
		||||
{action: "click", selector: "button.review"}
 | 
			
		||||
{action: "await_element", selector: ".summary"}
 | 
			
		||||
 | 
			
		||||
// Validate
 | 
			
		||||
{action: "extract", payload: "text", selector: ".hotel-name"}
 | 
			
		||||
{action: "extract", payload: "text", selector: ".total-price"}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Price Comparison Across Sites
 | 
			
		||||
 | 
			
		||||
Open multiple stores in tabs and compare:
 | 
			
		||||
 | 
			
		||||
```json
 | 
			
		||||
// Store 1
 | 
			
		||||
{action: "navigate", payload: "https://store1.com/product/12345"}
 | 
			
		||||
{action: "await_element", selector: ".price"}
 | 
			
		||||
 | 
			
		||||
// Open Store 2
 | 
			
		||||
{action: "new_tab"}
 | 
			
		||||
{action: "navigate", tab_index: 1, payload: "https://store2.com/product/12345"}
 | 
			
		||||
{action: "await_element", tab_index: 1, selector: ".price"}
 | 
			
		||||
 | 
			
		||||
// Open Store 3
 | 
			
		||||
{action: "new_tab"}
 | 
			
		||||
{action: "navigate", tab_index: 2, payload: "https://store3.com/product/12345"}
 | 
			
		||||
{action: "await_element", tab_index: 2, selector: ".price"}
 | 
			
		||||
 | 
			
		||||
// Extract all prices
 | 
			
		||||
{action: "extract", tab_index: 0, payload: "text", selector: ".price"}
 | 
			
		||||
{action: "extract", tab_index: 1, payload: "text", selector: ".price"}
 | 
			
		||||
{action: "extract", tab_index: 2, payload: "text", selector: ".price"}
 | 
			
		||||
 | 
			
		||||
// Get product info
 | 
			
		||||
{action: "extract", tab_index: 0, payload: "text", selector: ".product-name"}
 | 
			
		||||
{action: "extract", tab_index: 0, payload: "text", selector: ".stock-status"}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Product Data Extraction
 | 
			
		||||
 | 
			
		||||
Scrape structured product information:
 | 
			
		||||
 | 
			
		||||
```json
 | 
			
		||||
{action: "navigate", payload: "https://shop.example.com/product/123"}
 | 
			
		||||
{action: "await_element", selector: ".product-details"}
 | 
			
		||||
 | 
			
		||||
// Extract all product data with one eval
 | 
			
		||||
{action: "eval", payload: `
 | 
			
		||||
  ({
 | 
			
		||||
    name: document.querySelector('h1.product-name').textContent.trim(),
 | 
			
		||||
    price: document.querySelector('.price').textContent.trim(),
 | 
			
		||||
    image: document.querySelector('.product-image img').src,
 | 
			
		||||
    description: document.querySelector('.description').textContent.trim(),
 | 
			
		||||
    stock: document.querySelector('.stock-status').textContent.trim(),
 | 
			
		||||
    rating: document.querySelector('.rating').textContent.trim(),
 | 
			
		||||
    reviews: Array.from(document.querySelectorAll('.review')).map(r => ({
 | 
			
		||||
      author: r.querySelector('.author').textContent,
 | 
			
		||||
      rating: r.querySelector('.stars').textContent,
 | 
			
		||||
      text: r.querySelector('.review-text').textContent
 | 
			
		||||
    }))
 | 
			
		||||
  })
 | 
			
		||||
`}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Batch Product Extraction
 | 
			
		||||
 | 
			
		||||
Get multiple products from category page:
 | 
			
		||||
 | 
			
		||||
```json
 | 
			
		||||
{action: "navigate", payload: "https://shop.example.com/category/electronics"}
 | 
			
		||||
{action: "await_element", selector: ".product-grid"}
 | 
			
		||||
 | 
			
		||||
// Extract all products as array
 | 
			
		||||
{action: "eval", payload: `
 | 
			
		||||
  Array.from(document.querySelectorAll('.product-card')).map(card => ({
 | 
			
		||||
    name: card.querySelector('.product-name').textContent.trim(),
 | 
			
		||||
    price: card.querySelector('.price').textContent.trim(),
 | 
			
		||||
    image: card.querySelector('img').src,
 | 
			
		||||
    url: card.querySelector('a').href,
 | 
			
		||||
    inStock: !card.querySelector('.out-of-stock')
 | 
			
		||||
  }))
 | 
			
		||||
`}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
## Form Automation
 | 
			
		||||
 | 
			
		||||
### Multi-Step Registration Form
 | 
			
		||||
 | 
			
		||||
Handle progressive form with validation at each step:
 | 
			
		||||
 | 
			
		||||
```json
 | 
			
		||||
// Step 1: Personal info
 | 
			
		||||
{action: "navigate", payload: "https://example.com/register"}
 | 
			
		||||
{action: "await_element", selector: "input[name=firstName]"}
 | 
			
		||||
 | 
			
		||||
{action: "type", selector: "input[name=firstName]", payload: "John"}
 | 
			
		||||
{action: "type", selector: "input[name=lastName]", payload: "Doe"}
 | 
			
		||||
{action: "type", selector: "input[name=email]", payload: "john@example.com"}
 | 
			
		||||
{action: "click", selector: "button.next"}
 | 
			
		||||
 | 
			
		||||
// Wait for step 2
 | 
			
		||||
{action: "await_element", selector: "input[name=address]"}
 | 
			
		||||
 | 
			
		||||
// Step 2: Address
 | 
			
		||||
{action: "type", selector: "input[name=address]", payload: "123 Main St"}
 | 
			
		||||
{action: "type", selector: "input[name=city]", payload: "Springfield"}
 | 
			
		||||
{action: "select", selector: "select[name=state]", payload: "IL"}
 | 
			
		||||
{action: "type", selector: "input[name=zip]", payload: "62701"}
 | 
			
		||||
{action: "click", selector: "button.next"}
 | 
			
		||||
 | 
			
		||||
// Wait for step 3
 | 
			
		||||
{action: "await_element", selector: "input[name=cardNumber]"}
 | 
			
		||||
 | 
			
		||||
// Step 3: Payment
 | 
			
		||||
{action: "type", selector: "input[name=cardNumber]", payload: "4111111111111111"}
 | 
			
		||||
{action: "select", selector: "select[name=expMonth]", payload: "12"}
 | 
			
		||||
{action: "select", selector: "select[name=expYear]", payload: "2028"}
 | 
			
		||||
{action: "type", selector: "input[name=cvv]", payload: "123"}
 | 
			
		||||
 | 
			
		||||
// Review before submit
 | 
			
		||||
{action: "click", selector: "button.review"}
 | 
			
		||||
{action: "await_element", selector: ".summary"}
 | 
			
		||||
 | 
			
		||||
// Extract confirmation
 | 
			
		||||
{action: "extract", payload: "markdown", selector: ".summary"}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Search with Multiple Filters
 | 
			
		||||
 | 
			
		||||
Use dropdowns, checkboxes, and text inputs:
 | 
			
		||||
 | 
			
		||||
```json
 | 
			
		||||
{action: "navigate", payload: "https://library.example.com/search"}
 | 
			
		||||
{action: "await_element", selector: "form.search"}
 | 
			
		||||
 | 
			
		||||
// Category dropdown
 | 
			
		||||
{action: "select", selector: "select[name=category]", payload: "books"}
 | 
			
		||||
 | 
			
		||||
// Price range
 | 
			
		||||
{action: "type", selector: "input[name=priceMin]", payload: "10"}
 | 
			
		||||
{action: "type", selector: "input[name=priceMax]", payload: "50"}
 | 
			
		||||
 | 
			
		||||
// Checkboxes via JavaScript
 | 
			
		||||
{action: "eval", payload: "document.querySelector('input[name=inStock]').checked = true"}
 | 
			
		||||
{action: "eval", payload: "document.querySelector('input[name=freeShipping]').checked = true"}
 | 
			
		||||
 | 
			
		||||
// Search term and submit
 | 
			
		||||
{action: "type", selector: "input[name=query]", payload: "chrome devtools\n"}
 | 
			
		||||
 | 
			
		||||
// Wait for results
 | 
			
		||||
{action: "await_element", selector: ".results"}
 | 
			
		||||
 | 
			
		||||
// Count and extract
 | 
			
		||||
{action: "eval", payload: "document.querySelectorAll('.result').length"}
 | 
			
		||||
{action: "extract", payload: "text", selector: ".result-count"}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### File Upload
 | 
			
		||||
 | 
			
		||||
Handle file input using JavaScript:
 | 
			
		||||
 | 
			
		||||
```json
 | 
			
		||||
{action: "navigate", payload: "https://example.com/upload"}
 | 
			
		||||
{action: "await_element", selector: "input[type=file]"}
 | 
			
		||||
 | 
			
		||||
// Read file and set via JavaScript (for testing)
 | 
			
		||||
{action: "eval", payload: `
 | 
			
		||||
  const fileInput = document.querySelector('input[type=file]');
 | 
			
		||||
  const dataTransfer = new DataTransfer();
 | 
			
		||||
  const file = new File(['test content'], 'test.txt', { type: 'text/plain' });
 | 
			
		||||
  dataTransfer.items.add(file);
 | 
			
		||||
  fileInput.files = dataTransfer.files;
 | 
			
		||||
`}
 | 
			
		||||
 | 
			
		||||
// Submit
 | 
			
		||||
{action: "click", selector: "button.upload"}
 | 
			
		||||
{action: "await_text", payload: "Upload complete"}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
## Data Extraction
 | 
			
		||||
 | 
			
		||||
### Article Scraping
 | 
			
		||||
 | 
			
		||||
Extract blog post with metadata:
 | 
			
		||||
 | 
			
		||||
```json
 | 
			
		||||
{action: "navigate", payload: "https://blog.example.com/article"}
 | 
			
		||||
{action: "await_element", selector: "article"}
 | 
			
		||||
 | 
			
		||||
// Extract complete article structure
 | 
			
		||||
{action: "eval", payload: `
 | 
			
		||||
  ({
 | 
			
		||||
    title: document.querySelector('article h1').textContent.trim(),
 | 
			
		||||
    author: document.querySelector('.author-name').textContent.trim(),
 | 
			
		||||
    date: document.querySelector('time').getAttribute('datetime'),
 | 
			
		||||
    tags: Array.from(document.querySelectorAll('.tag')).map(t => t.textContent.trim()),
 | 
			
		||||
    content: document.querySelector('article .content').textContent.trim(),
 | 
			
		||||
    images: Array.from(document.querySelectorAll('article img')).map(img => ({
 | 
			
		||||
      src: img.src,
 | 
			
		||||
      alt: img.alt
 | 
			
		||||
    })),
 | 
			
		||||
    links: Array.from(document.querySelectorAll('article a')).map(a => ({
 | 
			
		||||
      text: a.textContent.trim(),
 | 
			
		||||
      href: a.href
 | 
			
		||||
    }))
 | 
			
		||||
  })
 | 
			
		||||
`}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Table Data Extraction
 | 
			
		||||
 | 
			
		||||
Convert HTML table to structured JSON:
 | 
			
		||||
 | 
			
		||||
```json
 | 
			
		||||
{action: "navigate", payload: "https://example.com/data/table"}
 | 
			
		||||
{action: "await_element", selector: "table"}
 | 
			
		||||
 | 
			
		||||
// Extract table with headers
 | 
			
		||||
{action: "eval", payload: `
 | 
			
		||||
  (() => {
 | 
			
		||||
    const headers = Array.from(document.querySelectorAll('table thead th'))
 | 
			
		||||
      .map(th => th.textContent.trim());
 | 
			
		||||
    const rows = Array.from(document.querySelectorAll('table tbody tr'))
 | 
			
		||||
      .map(tr => {
 | 
			
		||||
        const cells = Array.from(tr.cells).map(td => td.textContent.trim());
 | 
			
		||||
        return Object.fromEntries(headers.map((h, i) => [h, cells[i]]));
 | 
			
		||||
      });
 | 
			
		||||
    return rows;
 | 
			
		||||
  })()
 | 
			
		||||
`}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Paginated Results
 | 
			
		||||
 | 
			
		||||
Extract data across multiple pages:
 | 
			
		||||
 | 
			
		||||
```json
 | 
			
		||||
{action: "navigate", payload: "https://example.com/results?page=1"}
 | 
			
		||||
{action: "await_element", selector: ".results"}
 | 
			
		||||
 | 
			
		||||
// Page 1
 | 
			
		||||
{action: "eval", payload: "Array.from(document.querySelectorAll('.result')).map(r => r.textContent.trim())"}
 | 
			
		||||
 | 
			
		||||
// Navigate to page 2
 | 
			
		||||
{action: "click", selector: "a.next-page"}
 | 
			
		||||
{action: "await_element", selector: ".results"}
 | 
			
		||||
{action: "await_text", payload: "Page 2"}
 | 
			
		||||
 | 
			
		||||
// Page 2
 | 
			
		||||
{action: "eval", payload: "Array.from(document.querySelectorAll('.result')).map(r => r.textContent.trim())"}
 | 
			
		||||
 | 
			
		||||
// Continue pattern for additional pages...
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
## Multi-Tab Operations
 | 
			
		||||
 | 
			
		||||
### Email Receipt Extraction
 | 
			
		||||
 | 
			
		||||
Find specific email and extract data:
 | 
			
		||||
 | 
			
		||||
```json
 | 
			
		||||
// List available tabs
 | 
			
		||||
{action: "list_tabs"}
 | 
			
		||||
 | 
			
		||||
// Switch to email tab (assume index 2 from list)
 | 
			
		||||
{action: "click", tab_index: 2, selector: "a[title*='Receipt']"}
 | 
			
		||||
{action: "await_element", tab_index: 2, selector: ".email-body"}
 | 
			
		||||
 | 
			
		||||
// Extract receipt details
 | 
			
		||||
{action: "extract", tab_index: 2, payload: "text", selector: ".order-number"}
 | 
			
		||||
{action: "extract", tab_index: 2, payload: "text", selector: ".total-amount"}
 | 
			
		||||
{action: "extract", tab_index: 2, payload: "markdown", selector: ".items-list"}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Cross-Site Data Correlation
 | 
			
		||||
 | 
			
		||||
Extract from one site, verify on another:
 | 
			
		||||
 | 
			
		||||
```json
 | 
			
		||||
// Get company phone from website
 | 
			
		||||
{action: "navigate", payload: "https://company.com/contact"}
 | 
			
		||||
{action: "await_element", selector: ".contact-info"}
 | 
			
		||||
{action: "extract", payload: "text", selector: ".phone-number"}
 | 
			
		||||
 | 
			
		||||
// Store result: "+1-555-0123"
 | 
			
		||||
 | 
			
		||||
// Open verification site in new tab
 | 
			
		||||
{action: "new_tab"}
 | 
			
		||||
{action: "navigate", tab_index: 1, payload: "https://phonevalidator.com"}
 | 
			
		||||
{action: "await_element", tab_index: 1, selector: "input[name=phone]"}
 | 
			
		||||
 | 
			
		||||
// Fill and search
 | 
			
		||||
{action: "type", tab_index: 1, selector: "input[name=phone]", payload: "+1-555-0123\n"}
 | 
			
		||||
{action: "await_element", tab_index: 1, selector: ".results"}
 | 
			
		||||
 | 
			
		||||
// Extract validation result
 | 
			
		||||
{action: "extract", tab_index: 1, payload: "text", selector: ".verification-status"}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Parallel Data Collection
 | 
			
		||||
 | 
			
		||||
Collect data from multiple sources simultaneously:
 | 
			
		||||
 | 
			
		||||
```json
 | 
			
		||||
// Tab 0: Weather
 | 
			
		||||
{action: "navigate", tab_index: 0, payload: "https://weather.com/city"}
 | 
			
		||||
{action: "await_element", tab_index: 0, selector: ".temperature"}
 | 
			
		||||
 | 
			
		||||
// Tab 1: News
 | 
			
		||||
{action: "new_tab"}
 | 
			
		||||
{action: "navigate", tab_index: 1, payload: "https://news.com"}
 | 
			
		||||
{action: "await_element", tab_index: 1, selector: ".headlines"}
 | 
			
		||||
 | 
			
		||||
// Tab 2: Stock prices
 | 
			
		||||
{action: "new_tab"}
 | 
			
		||||
{action: "navigate", tab_index: 2, payload: "https://stocks.com"}
 | 
			
		||||
{action: "await_element", tab_index: 2, selector: ".market-summary"}
 | 
			
		||||
 | 
			
		||||
// Extract all data
 | 
			
		||||
{action: "extract", tab_index: 0, payload: "text", selector: ".temperature"}
 | 
			
		||||
{action: "extract", tab_index: 1, payload: "text", selector: ".headline:first-child"}
 | 
			
		||||
{action: "extract", tab_index: 2, payload: "text", selector: ".market-summary"}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
## Dynamic Content Handling
 | 
			
		||||
 | 
			
		||||
### Infinite Scroll Loading
 | 
			
		||||
 | 
			
		||||
Load all content with scroll-triggered pagination:
 | 
			
		||||
 | 
			
		||||
```json
 | 
			
		||||
{action: "navigate", payload: "https://example.com/feed"}
 | 
			
		||||
{action: "await_element", selector: ".feed-item"}
 | 
			
		||||
 | 
			
		||||
// Count initial items
 | 
			
		||||
{action: "eval", payload: "document.querySelectorAll('.feed-item').length"}
 | 
			
		||||
 | 
			
		||||
// Scroll and wait multiple times
 | 
			
		||||
{action: "eval", payload: "window.scrollTo(0, document.body.scrollHeight)"}
 | 
			
		||||
{action: "eval", payload: "new Promise(r => setTimeout(r, 2000))"}
 | 
			
		||||
 | 
			
		||||
{action: "eval", payload: "window.scrollTo(0, document.body.scrollHeight)"}
 | 
			
		||||
{action: "eval", payload: "new Promise(r => setTimeout(r, 2000))"}
 | 
			
		||||
 | 
			
		||||
{action: "eval", payload: "window.scrollTo(0, document.body.scrollHeight)"}
 | 
			
		||||
{action: "eval", payload: "new Promise(r => setTimeout(r, 2000))"}
 | 
			
		||||
 | 
			
		||||
// Extract all loaded items
 | 
			
		||||
{action: "eval", payload: `
 | 
			
		||||
  Array.from(document.querySelectorAll('.feed-item')).map(item => ({
 | 
			
		||||
    title: item.querySelector('.title').textContent.trim(),
 | 
			
		||||
    date: item.querySelector('.date').textContent.trim(),
 | 
			
		||||
    url: item.querySelector('a').href
 | 
			
		||||
  }))
 | 
			
		||||
`}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Wait for AJAX Response
 | 
			
		||||
 | 
			
		||||
Wait for loading indicator to disappear:
 | 
			
		||||
 | 
			
		||||
```json
 | 
			
		||||
{action: "navigate", payload: "https://app.com/dashboard"}
 | 
			
		||||
{action: "await_element", selector: ".content"}
 | 
			
		||||
 | 
			
		||||
// Trigger AJAX request
 | 
			
		||||
{action: "click", selector: "button.load-data"}
 | 
			
		||||
 | 
			
		||||
// Wait for spinner to appear then disappear
 | 
			
		||||
{action: "eval", payload: `
 | 
			
		||||
  new Promise(resolve => {
 | 
			
		||||
    const checkGone = () => {
 | 
			
		||||
      const spinner = document.querySelector('.spinner');
 | 
			
		||||
      if (!spinner || spinner.style.display === 'none') {
 | 
			
		||||
        resolve(true);
 | 
			
		||||
      } else {
 | 
			
		||||
        setTimeout(checkGone, 100);
 | 
			
		||||
      }
 | 
			
		||||
    };
 | 
			
		||||
    checkGone();
 | 
			
		||||
  })
 | 
			
		||||
`}
 | 
			
		||||
 | 
			
		||||
// Now safe to extract
 | 
			
		||||
{action: "extract", payload: "text", selector: ".data-table"}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Modal Dialog Handling
 | 
			
		||||
 | 
			
		||||
Open modal, interact, wait for close:
 | 
			
		||||
 | 
			
		||||
```json
 | 
			
		||||
{action: "click", selector: "button.open-settings"}
 | 
			
		||||
{action: "await_element", selector: ".modal.visible"}
 | 
			
		||||
 | 
			
		||||
// Interact with modal
 | 
			
		||||
{action: "type", selector: ".modal input[name=username]", payload: "newuser"}
 | 
			
		||||
{action: "select", selector: ".modal select[name=theme]", payload: "dark"}
 | 
			
		||||
{action: "click", selector: ".modal button.save"}
 | 
			
		||||
 | 
			
		||||
// Wait for modal to close
 | 
			
		||||
{action: "eval", payload: `
 | 
			
		||||
  new Promise(resolve => {
 | 
			
		||||
    const check = () => {
 | 
			
		||||
      const modal = document.querySelector('.modal.visible');
 | 
			
		||||
      if (!modal) {
 | 
			
		||||
        resolve(true);
 | 
			
		||||
      } else {
 | 
			
		||||
        setTimeout(check, 100);
 | 
			
		||||
      }
 | 
			
		||||
    };
 | 
			
		||||
    check();
 | 
			
		||||
  })
 | 
			
		||||
`}
 | 
			
		||||
 | 
			
		||||
// Verify settings saved
 | 
			
		||||
{action: "await_text", payload: "Settings saved"}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Wait for Button Enabled
 | 
			
		||||
 | 
			
		||||
Wait for form validation before submission:
 | 
			
		||||
 | 
			
		||||
```json
 | 
			
		||||
{action: "type", selector: "input[name=email]", payload: "user@example.com"}
 | 
			
		||||
{action: "type", selector: "input[name=password]", payload: "securepass123"}
 | 
			
		||||
 | 
			
		||||
// Wait for submit button to become enabled
 | 
			
		||||
{action: "eval", payload: `
 | 
			
		||||
  new Promise(resolve => {
 | 
			
		||||
    const check = () => {
 | 
			
		||||
      const btn = document.querySelector('button[type=submit]');
 | 
			
		||||
      if (btn && !btn.disabled && !btn.classList.contains('disabled')) {
 | 
			
		||||
        resolve(true);
 | 
			
		||||
      } else {
 | 
			
		||||
        setTimeout(check, 100);
 | 
			
		||||
      }
 | 
			
		||||
    };
 | 
			
		||||
    check();
 | 
			
		||||
  })
 | 
			
		||||
`}
 | 
			
		||||
 | 
			
		||||
// Now safe to click
 | 
			
		||||
{action: "click", selector: "button[type=submit]"}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
## Authentication Workflows
 | 
			
		||||
 | 
			
		||||
### Standard Login
 | 
			
		||||
 | 
			
		||||
```json
 | 
			
		||||
{action: "navigate", payload: "https://app.example.com/login"}
 | 
			
		||||
{action: "await_element", selector: "form.login"}
 | 
			
		||||
 | 
			
		||||
// Fill credentials
 | 
			
		||||
{action: "type", selector: "input[name=email]", payload: "user@example.com"}
 | 
			
		||||
{action: "type", selector: "input[name=password]", payload: "password123\n"}
 | 
			
		||||
 | 
			
		||||
// Wait for redirect
 | 
			
		||||
{action: "await_text", payload: "Dashboard"}
 | 
			
		||||
 | 
			
		||||
// Verify logged in
 | 
			
		||||
{action: "extract", payload: "text", selector: ".user-name"}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### OAuth Flow
 | 
			
		||||
 | 
			
		||||
```json
 | 
			
		||||
{action: "navigate", payload: "https://app.example.com/connect"}
 | 
			
		||||
{action: "await_element", selector: "button.oauth-login"}
 | 
			
		||||
 | 
			
		||||
// Trigger OAuth
 | 
			
		||||
{action: "click", selector: "button.oauth-login"}
 | 
			
		||||
 | 
			
		||||
// Wait for OAuth provider page
 | 
			
		||||
{action: "await_text", payload: "Authorize"}
 | 
			
		||||
 | 
			
		||||
// Fill OAuth credentials
 | 
			
		||||
{action: "await_element", selector: "input[name=username]"}
 | 
			
		||||
{action: "type", selector: "input[name=username]", payload: "oauthuser"}
 | 
			
		||||
{action: "type", selector: "input[name=password]", payload: "oauthpass\n"}
 | 
			
		||||
 | 
			
		||||
// Wait for redirect back
 | 
			
		||||
{action: "await_text", payload: "Connected successfully"}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Session Persistence Check
 | 
			
		||||
 | 
			
		||||
```json
 | 
			
		||||
// Load page
 | 
			
		||||
{action: "navigate", payload: "https://app.example.com/dashboard"}
 | 
			
		||||
{action: "await_element", selector: "body"}
 | 
			
		||||
 | 
			
		||||
// Check if logged in via cookie/localStorage
 | 
			
		||||
{action: "eval", payload: "document.cookie.includes('session_id')"}
 | 
			
		||||
{action: "eval", payload: "localStorage.getItem('auth_token') !== null"}
 | 
			
		||||
 | 
			
		||||
// Verify user data loaded
 | 
			
		||||
{action: "extract", payload: "text", selector: ".user-profile"}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
## Advanced Patterns
 | 
			
		||||
 | 
			
		||||
### Conditional Workflow
 | 
			
		||||
 | 
			
		||||
Branch based on page content:
 | 
			
		||||
 | 
			
		||||
```json
 | 
			
		||||
{action: "navigate", payload: "https://example.com/status"}
 | 
			
		||||
{action: "await_element", selector: "body"}
 | 
			
		||||
 | 
			
		||||
// Check status
 | 
			
		||||
{action: "extract", payload: "text", selector: ".status-message"}
 | 
			
		||||
 | 
			
		||||
// If result contains "Available":
 | 
			
		||||
{action: "click", selector: "button.purchase"}
 | 
			
		||||
{action: "await_text", payload: "Added to cart"}
 | 
			
		||||
 | 
			
		||||
// If result contains "Out of stock":
 | 
			
		||||
{action: "click", selector: "button.notify-me"}
 | 
			
		||||
{action: "type", selector: "input[name=email]", payload: "notify@example.com\n"}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Error Recovery
 | 
			
		||||
 | 
			
		||||
Handle and retry failed operations:
 | 
			
		||||
 | 
			
		||||
```json
 | 
			
		||||
{action: "navigate", payload: "https://app.example.com/data"}
 | 
			
		||||
{action: "await_element", selector: ".content"}
 | 
			
		||||
 | 
			
		||||
// Attempt operation
 | 
			
		||||
{action: "click", selector: "button.load"}
 | 
			
		||||
 | 
			
		||||
// Check for error
 | 
			
		||||
{action: "eval", payload: "!!document.querySelector('.error-message')"}
 | 
			
		||||
 | 
			
		||||
// If error present, retry
 | 
			
		||||
{action: "click", selector: "button.retry"}
 | 
			
		||||
{action: "await_element", selector: ".data-loaded"}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Screenshot Comparison
 | 
			
		||||
 | 
			
		||||
Capture before and after states:
 | 
			
		||||
 | 
			
		||||
```json
 | 
			
		||||
// Initial state
 | 
			
		||||
{action: "navigate", payload: "https://example.com"}
 | 
			
		||||
{action: "await_element", selector: ".content"}
 | 
			
		||||
{action: "screenshot", payload: "/tmp/before.png"}
 | 
			
		||||
 | 
			
		||||
// Make changes
 | 
			
		||||
{action: "click", selector: "button.dark-mode"}
 | 
			
		||||
{action: "await_element", selector: "body.dark"}
 | 
			
		||||
 | 
			
		||||
// Capture new state
 | 
			
		||||
{action: "screenshot", payload: "/tmp/after.png"}
 | 
			
		||||
 | 
			
		||||
// Or screenshot specific element
 | 
			
		||||
{action: "screenshot", payload: "/tmp/header.png", selector: "header"}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
## Tips for Complex Workflows
 | 
			
		||||
 | 
			
		||||
### Build Incrementally
 | 
			
		||||
 | 
			
		||||
Start simple, add complexity:
 | 
			
		||||
 | 
			
		||||
1. Navigate and verify page loads
 | 
			
		||||
2. Extract one element
 | 
			
		||||
3. Add interaction
 | 
			
		||||
4. Add waiting logic
 | 
			
		||||
5. Add error handling
 | 
			
		||||
6. Add validation
 | 
			
		||||
 | 
			
		||||
### Use JavaScript for Complex Logic
 | 
			
		||||
 | 
			
		||||
When multiple operations needed, use `eval`:
 | 
			
		||||
 | 
			
		||||
```json
 | 
			
		||||
{action: "eval", payload: `
 | 
			
		||||
  (async () => {
 | 
			
		||||
    // Complex multi-step logic
 | 
			
		||||
    const results = [];
 | 
			
		||||
    const items = document.querySelectorAll('.item');
 | 
			
		||||
    
 | 
			
		||||
    for (const item of items) {
 | 
			
		||||
      if (item.classList.contains('active')) {
 | 
			
		||||
        results.push({
 | 
			
		||||
          id: item.dataset.id,
 | 
			
		||||
          text: item.textContent.trim()
 | 
			
		||||
        });
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    return results;
 | 
			
		||||
  })()
 | 
			
		||||
`}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Validate Selectors
 | 
			
		||||
 | 
			
		||||
Always test selectors return expected elements:
 | 
			
		||||
 | 
			
		||||
```json
 | 
			
		||||
// Check element exists
 | 
			
		||||
{action: "eval", payload: "!!document.querySelector('button.submit')"}
 | 
			
		||||
 | 
			
		||||
// Check element visible
 | 
			
		||||
{action: "eval", payload: "window.getComputedStyle(document.querySelector('button.submit')).display !== 'none'"}
 | 
			
		||||
 | 
			
		||||
// Check element count
 | 
			
		||||
{action: "eval", payload: "document.querySelectorAll('.item').length"}
 | 
			
		||||
```
 | 
			
		||||
@ -1,546 +0,0 @@
 | 
			
		||||
# Browser Automation Troubleshooting Guide
 | 
			
		||||
 | 
			
		||||
Quick reference for common issues and solutions.
 | 
			
		||||
 | 
			
		||||
## Common Errors
 | 
			
		||||
 | 
			
		||||
### Element Not Found
 | 
			
		||||
 | 
			
		||||
**Error:** `Element not found: button.submit`
 | 
			
		||||
 | 
			
		||||
**Causes:**
 | 
			
		||||
1. Page still loading
 | 
			
		||||
2. Wrong selector
 | 
			
		||||
3. Element in iframe
 | 
			
		||||
4. Element hidden/not rendered
 | 
			
		||||
 | 
			
		||||
**Solutions:**
 | 
			
		||||
 | 
			
		||||
```json
 | 
			
		||||
// 1. Add wait before interaction
 | 
			
		||||
{action: "await_element", selector: "button.submit", timeout: 10000}
 | 
			
		||||
{action: "click", selector: "button.submit"}
 | 
			
		||||
 | 
			
		||||
// 2. Verify selector exists
 | 
			
		||||
{action: "extract", payload: "html"}
 | 
			
		||||
{action: "eval", payload: "document.querySelector('button.submit')"}
 | 
			
		||||
 | 
			
		||||
// 3. Check if in iframe
 | 
			
		||||
{action: "eval", payload: "document.querySelectorAll('iframe').length"}
 | 
			
		||||
 | 
			
		||||
// 4. Check visibility
 | 
			
		||||
{action: "eval", payload: "window.getComputedStyle(document.querySelector('button.submit')).display"}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Timeout Errors
 | 
			
		||||
 | 
			
		||||
**Error:** `Timeout waiting for element after 5000ms`
 | 
			
		||||
 | 
			
		||||
**Solutions:**
 | 
			
		||||
 | 
			
		||||
```json
 | 
			
		||||
// Increase timeout for slow pages
 | 
			
		||||
{action: "await_element", selector: ".content", timeout: 30000}
 | 
			
		||||
 | 
			
		||||
// Wait for loading to complete first
 | 
			
		||||
{action: "await_element", selector: ".spinner"}
 | 
			
		||||
{action: "eval", payload: `
 | 
			
		||||
  new Promise(r => {
 | 
			
		||||
    const check = () => {
 | 
			
		||||
      if (!document.querySelector('.spinner')) r(true);
 | 
			
		||||
      else setTimeout(check, 100);
 | 
			
		||||
    };
 | 
			
		||||
    check();
 | 
			
		||||
  })
 | 
			
		||||
`}
 | 
			
		||||
 | 
			
		||||
// Use JavaScript to wait for specific condition
 | 
			
		||||
{action: "eval", payload: `
 | 
			
		||||
  new Promise(resolve => {
 | 
			
		||||
    const observer = new MutationObserver(() => {
 | 
			
		||||
      if (document.querySelector('.loaded')) {
 | 
			
		||||
        observer.disconnect();
 | 
			
		||||
        resolve(true);
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
    observer.observe(document.body, { childList: true, subtree: true });
 | 
			
		||||
  })
 | 
			
		||||
`}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Click Not Working
 | 
			
		||||
 | 
			
		||||
**Error:** Click executes but nothing happens
 | 
			
		||||
 | 
			
		||||
**Causes:**
 | 
			
		||||
1. JavaScript event handler not attached yet
 | 
			
		||||
2. Element covered by another element
 | 
			
		||||
3. Need to scroll element into view
 | 
			
		||||
 | 
			
		||||
**Solutions:**
 | 
			
		||||
 | 
			
		||||
```json
 | 
			
		||||
// 1. Wait longer before click
 | 
			
		||||
{action: "await_element", selector: "button"}
 | 
			
		||||
{action: "eval", payload: "new Promise(r => setTimeout(r, 1000))"}
 | 
			
		||||
{action: "click", selector: "button"}
 | 
			
		||||
 | 
			
		||||
// 2. Check z-index and overlays
 | 
			
		||||
{action: "eval", payload: `
 | 
			
		||||
  (() => {
 | 
			
		||||
    const elem = document.querySelector('button');
 | 
			
		||||
    const rect = elem.getBoundingClientRect();
 | 
			
		||||
    const topElem = document.elementFromPoint(rect.left + rect.width/2, rect.top + rect.height/2);
 | 
			
		||||
    return topElem === elem || elem.contains(topElem);
 | 
			
		||||
  })()
 | 
			
		||||
`}
 | 
			
		||||
 | 
			
		||||
// 3. Scroll into view first
 | 
			
		||||
{action: "eval", payload: "document.querySelector('button').scrollIntoView()"}
 | 
			
		||||
{action: "click", selector: "button"}
 | 
			
		||||
 | 
			
		||||
// 4. Force click via JavaScript
 | 
			
		||||
{action: "eval", payload: "document.querySelector('button').click()"}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Form Submission Issues
 | 
			
		||||
 | 
			
		||||
**Error:** Form doesn't submit with `\n`
 | 
			
		||||
 | 
			
		||||
**Solutions:**
 | 
			
		||||
 | 
			
		||||
```json
 | 
			
		||||
// Try explicit click
 | 
			
		||||
{action: "type", selector: "input[name=password]", payload: "pass123"}
 | 
			
		||||
{action: "click", selector: "button[type=submit]"}
 | 
			
		||||
 | 
			
		||||
// Or trigger form submit
 | 
			
		||||
{action: "eval", payload: "document.querySelector('form').submit()"}
 | 
			
		||||
 | 
			
		||||
// Or press Enter key specifically
 | 
			
		||||
{action: "eval", payload: `
 | 
			
		||||
  const input = document.querySelector('input[name=password]');
 | 
			
		||||
  input.dispatchEvent(new KeyboardEvent('keypress', { key: 'Enter', keyCode: 13 }));
 | 
			
		||||
`}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Tab Index Errors
 | 
			
		||||
 | 
			
		||||
**Error:** `Tab index 2 out of range`
 | 
			
		||||
 | 
			
		||||
**Cause:** Tab closed or indices shifted
 | 
			
		||||
 | 
			
		||||
**Solution:**
 | 
			
		||||
 | 
			
		||||
```json
 | 
			
		||||
// Always list tabs before operating on them
 | 
			
		||||
{action: "list_tabs"}
 | 
			
		||||
 | 
			
		||||
// After closing tabs, re-list
 | 
			
		||||
{action: "close_tab", tab_index: 1}
 | 
			
		||||
{action: "list_tabs"}
 | 
			
		||||
{action: "click", tab_index: 1, selector: "a"}  // Now correct index
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Extract Returns Empty
 | 
			
		||||
 | 
			
		||||
**Error:** Extract returns empty string
 | 
			
		||||
 | 
			
		||||
**Causes:**
 | 
			
		||||
1. Element not loaded yet
 | 
			
		||||
2. Content in shadow DOM
 | 
			
		||||
3. Text in ::before/::after pseudo-elements
 | 
			
		||||
 | 
			
		||||
**Solutions:**
 | 
			
		||||
 | 
			
		||||
```json
 | 
			
		||||
// 1. Wait for content
 | 
			
		||||
{action: "await_element", selector: ".content"}
 | 
			
		||||
{action: "await_text", payload: "Expected text"}
 | 
			
		||||
{action: "extract", payload: "text", selector: ".content"}
 | 
			
		||||
 | 
			
		||||
// 2. Check shadow DOM
 | 
			
		||||
{action: "eval", payload: "document.querySelector('my-component').shadowRoot.querySelector('.content').textContent"}
 | 
			
		||||
 | 
			
		||||
// 3. Get computed styles for pseudo-elements
 | 
			
		||||
{action: "eval", payload: "window.getComputedStyle(document.querySelector('.content'), '::before').content"}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
## Best Practices
 | 
			
		||||
 | 
			
		||||
### Selector Specificity
 | 
			
		||||
 | 
			
		||||
**Use ID when available:**
 | 
			
		||||
```json
 | 
			
		||||
{action: "click", selector: "#submit-button"}  // ✅ Best
 | 
			
		||||
{action: "click", selector: "button.submit"}    // ✅ Good
 | 
			
		||||
{action: "click", selector: "button"}           // ❌ Too generic
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
**Combine selectors for uniqueness:**
 | 
			
		||||
```json
 | 
			
		||||
{action: "click", selector: "form.login button[type=submit]"}  // ✅ Specific
 | 
			
		||||
{action: "click", selector: ".modal.active button.primary"}    // ✅ Specific
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
**Use data attributes:**
 | 
			
		||||
```json
 | 
			
		||||
{action: "click", selector: "[data-testid='submit-btn']"}      // ✅ Reliable
 | 
			
		||||
{action: "click", selector: "[data-action='save']"}            // ✅ Semantic
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Waiting Strategy
 | 
			
		||||
 | 
			
		||||
**Always wait before interaction:**
 | 
			
		||||
```json
 | 
			
		||||
// ❌ BAD - No waiting
 | 
			
		||||
{action: "navigate", payload: "https://example.com"}
 | 
			
		||||
{action: "click", selector: "button"}
 | 
			
		||||
 | 
			
		||||
// ✅ GOOD - Wait for element
 | 
			
		||||
{action: "navigate", payload: "https://example.com"}
 | 
			
		||||
{action: "await_element", selector: "button"}
 | 
			
		||||
{action: "click", selector: "button"}
 | 
			
		||||
 | 
			
		||||
// ✅ BETTER - Wait for specific state
 | 
			
		||||
{action: "navigate", payload: "https://example.com"}
 | 
			
		||||
{action: "await_text", payload: "Page loaded"}
 | 
			
		||||
{action: "click", selector: "button"}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
**Wait for dynamic content:**
 | 
			
		||||
```json
 | 
			
		||||
// After triggering AJAX
 | 
			
		||||
{action: "click", selector: "button.load-more"}
 | 
			
		||||
{action: "await_element", selector: ".new-content"}
 | 
			
		||||
 | 
			
		||||
// After form submit
 | 
			
		||||
{action: "click", selector: "button[type=submit]"}
 | 
			
		||||
{action: "await_text", payload: "Success"}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Error Detection
 | 
			
		||||
 | 
			
		||||
**Check for error messages:**
 | 
			
		||||
```json
 | 
			
		||||
{action: "click", selector: "button.submit"}
 | 
			
		||||
{action: "eval", payload: "!!document.querySelector('.error-message')"}
 | 
			
		||||
{action: "extract", payload: "text", selector: ".error-message"}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
**Validate expected state:**
 | 
			
		||||
```json
 | 
			
		||||
{action: "click", selector: "button.add-to-cart"}
 | 
			
		||||
{action: "await_element", selector: ".cart-count"}
 | 
			
		||||
{action: "extract", payload: "text", selector: ".cart-count"}
 | 
			
		||||
// Verify count increased
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Data Extraction Efficiency
 | 
			
		||||
 | 
			
		||||
**Use single eval for multiple fields:**
 | 
			
		||||
```json
 | 
			
		||||
// ❌ Inefficient - Multiple calls
 | 
			
		||||
{action: "extract", payload: "text", selector: "h1"}
 | 
			
		||||
{action: "extract", payload: "text", selector: ".author"}
 | 
			
		||||
{action: "extract", payload: "text", selector: ".date"}
 | 
			
		||||
 | 
			
		||||
// ✅ Efficient - One call
 | 
			
		||||
{action: "eval", payload: `
 | 
			
		||||
  ({
 | 
			
		||||
    title: document.querySelector('h1').textContent.trim(),
 | 
			
		||||
    author: document.querySelector('.author').textContent.trim(),
 | 
			
		||||
    date: document.querySelector('.date').textContent.trim()
 | 
			
		||||
  })
 | 
			
		||||
`}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
**Extract arrays efficiently:**
 | 
			
		||||
```json
 | 
			
		||||
{action: "eval", payload: `
 | 
			
		||||
  Array.from(document.querySelectorAll('.item')).map(item => ({
 | 
			
		||||
    name: item.querySelector('.name').textContent.trim(),
 | 
			
		||||
    price: item.querySelector('.price').textContent.trim(),
 | 
			
		||||
    url: item.querySelector('a').href
 | 
			
		||||
  }))
 | 
			
		||||
`}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Performance Optimization
 | 
			
		||||
 | 
			
		||||
**Minimize navigation:**
 | 
			
		||||
```json
 | 
			
		||||
// ❌ Slow - Navigate for each item
 | 
			
		||||
{action: "navigate", payload: "https://example.com/item/1"}
 | 
			
		||||
{action: "extract", payload: "text", selector: ".price"}
 | 
			
		||||
{action: "navigate", payload: "https://example.com/item/2"}
 | 
			
		||||
{action: "extract", payload: "text", selector: ".price"}
 | 
			
		||||
 | 
			
		||||
// ✅ Fast - Use API or extract list page
 | 
			
		||||
{action: "navigate", payload: "https://example.com/items"}
 | 
			
		||||
{action: "eval", payload: "Array.from(document.querySelectorAll('.item')).map(i => i.querySelector('.price').textContent)"}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
**Reuse tabs:**
 | 
			
		||||
```json
 | 
			
		||||
// ✅ Keep tabs open for repeated access
 | 
			
		||||
{action: "new_tab"}
 | 
			
		||||
{action: "navigate", tab_index: 1, payload: "https://tool.com"}
 | 
			
		||||
 | 
			
		||||
// Later, reuse same tab
 | 
			
		||||
{action: "click", tab_index: 1, selector: "button.refresh"}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Debugging Workflows
 | 
			
		||||
 | 
			
		||||
**Step 1: Check page HTML:**
 | 
			
		||||
```json
 | 
			
		||||
{action: "navigate", payload: "https://example.com"}
 | 
			
		||||
{action: "await_element", selector: "body"}
 | 
			
		||||
{action: "extract", payload: "html"}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
**Step 2: Test selectors:**
 | 
			
		||||
```json
 | 
			
		||||
{action: "eval", payload: "document.querySelector('button.submit')"}
 | 
			
		||||
{action: "eval", payload: "document.querySelectorAll('button').length"}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
**Step 3: Check element state:**
 | 
			
		||||
```json
 | 
			
		||||
{action: "eval", payload: `
 | 
			
		||||
  (() => {
 | 
			
		||||
    const elem = document.querySelector('button.submit');
 | 
			
		||||
    return {
 | 
			
		||||
      exists: !!elem,
 | 
			
		||||
      visible: elem ? window.getComputedStyle(elem).display !== 'none' : false,
 | 
			
		||||
      enabled: elem ? !elem.disabled : false,
 | 
			
		||||
      text: elem ? elem.textContent : null
 | 
			
		||||
    };
 | 
			
		||||
  })()
 | 
			
		||||
`}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
**Step 4: Check console errors:**
 | 
			
		||||
```json
 | 
			
		||||
{action: "eval", payload: "console.error.toString()"}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
## Patterns Library
 | 
			
		||||
 | 
			
		||||
### Retry Logic
 | 
			
		||||
 | 
			
		||||
```json
 | 
			
		||||
// Attempt operation with retry
 | 
			
		||||
{action: "click", selector: "button.submit"}
 | 
			
		||||
 | 
			
		||||
// Check if succeeded
 | 
			
		||||
{action: "eval", payload: "document.querySelector('.success-message')"}
 | 
			
		||||
 | 
			
		||||
// If null, retry
 | 
			
		||||
{action: "click", selector: "button.submit"}
 | 
			
		||||
{action: "await_text", payload: "Success", timeout: 10000}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Conditional Branching
 | 
			
		||||
 | 
			
		||||
```json
 | 
			
		||||
// Check condition
 | 
			
		||||
{action: "extract", payload: "text", selector: ".status"}
 | 
			
		||||
 | 
			
		||||
// Branch based on result (in your logic)
 | 
			
		||||
// If "available":
 | 
			
		||||
{action: "click", selector: "button.buy"}
 | 
			
		||||
 | 
			
		||||
// If "out of stock":
 | 
			
		||||
{action: "type", selector: "input.email", payload: "notify@example.com\n"}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Pagination Handling
 | 
			
		||||
 | 
			
		||||
```json
 | 
			
		||||
// Page 1
 | 
			
		||||
{action: "navigate", payload: "https://example.com/results"}
 | 
			
		||||
{action: "await_element", selector: ".results"}
 | 
			
		||||
{action: "eval", payload: "Array.from(document.querySelectorAll('.result')).map(r => r.textContent)"}
 | 
			
		||||
 | 
			
		||||
// Check if next page exists
 | 
			
		||||
{action: "eval", payload: "!!document.querySelector('a.next-page')"}
 | 
			
		||||
 | 
			
		||||
// If yes, navigate
 | 
			
		||||
{action: "click", selector: "a.next-page"}
 | 
			
		||||
{action: "await_element", selector: ".results"}
 | 
			
		||||
// Repeat extraction
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Form Validation Waiting
 | 
			
		||||
 | 
			
		||||
```json
 | 
			
		||||
// Fill form field
 | 
			
		||||
{action: "type", selector: "input[name=email]", payload: "user@example.com"}
 | 
			
		||||
 | 
			
		||||
// Wait for validation icon
 | 
			
		||||
{action: "await_element", selector: "input[name=email] + .valid-icon"}
 | 
			
		||||
 | 
			
		||||
// Proceed to next field
 | 
			
		||||
{action: "type", selector: "input[name=password]", payload: "password123"}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Autocomplete Selection
 | 
			
		||||
 | 
			
		||||
```json
 | 
			
		||||
// Type in autocomplete field
 | 
			
		||||
{action: "type", selector: "input.autocomplete", payload: "San Fr"}
 | 
			
		||||
 | 
			
		||||
// Wait for suggestions
 | 
			
		||||
{action: "await_element", selector: ".autocomplete-suggestions"}
 | 
			
		||||
 | 
			
		||||
// Click suggestion
 | 
			
		||||
{action: "click", selector: ".autocomplete-suggestions li:first-child"}
 | 
			
		||||
 | 
			
		||||
// Verify selection
 | 
			
		||||
{action: "extract", payload: "text", selector: "input.autocomplete"}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Cookie Management
 | 
			
		||||
 | 
			
		||||
```json
 | 
			
		||||
// Check if cookie exists
 | 
			
		||||
{action: "eval", payload: "document.cookie.includes('session_id')"}
 | 
			
		||||
 | 
			
		||||
// Set cookie
 | 
			
		||||
{action: "eval", payload: "document.cookie = 'preferences=dark; path=/; max-age=31536000'"}
 | 
			
		||||
 | 
			
		||||
// Clear specific cookie
 | 
			
		||||
{action: "eval", payload: "document.cookie = 'session_id=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;'"}
 | 
			
		||||
 | 
			
		||||
// Get all cookies as object
 | 
			
		||||
{action: "eval", payload: `
 | 
			
		||||
  Object.fromEntries(
 | 
			
		||||
    document.cookie.split('; ').map(c => c.split('='))
 | 
			
		||||
  )
 | 
			
		||||
`}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
## XPath Examples
 | 
			
		||||
 | 
			
		||||
XPath is auto-detected (starts with `/` or `//`).
 | 
			
		||||
 | 
			
		||||
### Basic XPath Selectors
 | 
			
		||||
 | 
			
		||||
```json
 | 
			
		||||
// Find by text content
 | 
			
		||||
{action: "click", selector: "//button[text()='Submit']"}
 | 
			
		||||
{action: "click", selector: "//a[contains(text(), 'Learn more')]"}
 | 
			
		||||
 | 
			
		||||
// Find by attribute
 | 
			
		||||
{action: "click", selector: "//button[@type='submit']"}
 | 
			
		||||
{action: "extract", payload: "text", selector: "//div[@class='content']"}
 | 
			
		||||
 | 
			
		||||
// Hierarchical
 | 
			
		||||
{action: "click", selector: "//form[@id='login']//button[@type='submit']"}
 | 
			
		||||
{action: "extract", payload: "text", selector: "//article/div[@class='content']/p[1]"}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Advanced XPath
 | 
			
		||||
 | 
			
		||||
```json
 | 
			
		||||
// Multiple conditions
 | 
			
		||||
{action: "click", selector: "//button[@type='submit' and contains(@class, 'primary')]"}
 | 
			
		||||
 | 
			
		||||
// Following sibling
 | 
			
		||||
{action: "extract", payload: "text", selector: "//label[text()='Username']/following-sibling::input/@value"}
 | 
			
		||||
 | 
			
		||||
// Parent selection
 | 
			
		||||
{action: "click", selector: "//td[text()='Active']/..//button[@class='edit']"}
 | 
			
		||||
 | 
			
		||||
// Multiple elements
 | 
			
		||||
{action: "extract", payload: "text", selector: "//h2 | //h3"}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
## Security Considerations
 | 
			
		||||
 | 
			
		||||
### Avoid Hardcoded Credentials
 | 
			
		||||
 | 
			
		||||
```json
 | 
			
		||||
// ❌ BAD - Credentials in workflow
 | 
			
		||||
{action: "type", selector: "input[name=password]", payload: "mypassword123"}
 | 
			
		||||
 | 
			
		||||
// ✅ GOOD - Use environment variables or secure storage
 | 
			
		||||
// Load credentials from secure source before workflow
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Validate HTTPS
 | 
			
		||||
 | 
			
		||||
```json
 | 
			
		||||
// Check protocol
 | 
			
		||||
{action: "eval", payload: "window.location.protocol"}
 | 
			
		||||
// Should return "https:"
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Check for Security Indicators
 | 
			
		||||
 | 
			
		||||
```json
 | 
			
		||||
// Verify login page is secure
 | 
			
		||||
{action: "eval", payload: `
 | 
			
		||||
  ({
 | 
			
		||||
    protocol: window.location.protocol,
 | 
			
		||||
    hasLock: document.querySelector('link[rel=icon]')?.href.includes('secure'),
 | 
			
		||||
    url: window.location.href
 | 
			
		||||
  })
 | 
			
		||||
`}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
## Performance Tips
 | 
			
		||||
 | 
			
		||||
### Minimize Waits
 | 
			
		||||
 | 
			
		||||
```json
 | 
			
		||||
// ❌ Arbitrary timeouts
 | 
			
		||||
{action: "eval", payload: "new Promise(r => setTimeout(r, 5000))"}
 | 
			
		||||
 | 
			
		||||
// ✅ Condition-based waits
 | 
			
		||||
{action: "await_element", selector: ".loaded"}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Batch Operations
 | 
			
		||||
 | 
			
		||||
```json
 | 
			
		||||
// ❌ Individual extracts
 | 
			
		||||
{action: "extract", payload: "text", selector: ".title"}
 | 
			
		||||
{action: "extract", payload: "text", selector: ".author"}
 | 
			
		||||
{action: "extract", payload: "text", selector: ".date"}
 | 
			
		||||
 | 
			
		||||
// ✅ Single eval
 | 
			
		||||
{action: "eval", payload: `
 | 
			
		||||
  ({
 | 
			
		||||
    title: document.querySelector('.title').textContent,
 | 
			
		||||
    author: document.querySelector('.author').textContent,
 | 
			
		||||
    date: document.querySelector('.date').textContent
 | 
			
		||||
  })
 | 
			
		||||
`}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Reuse Browser State
 | 
			
		||||
 | 
			
		||||
```json
 | 
			
		||||
// ✅ Stay logged in across operations
 | 
			
		||||
{action: "navigate", payload: "https://app.com/login"}
 | 
			
		||||
// ... login ...
 | 
			
		||||
 | 
			
		||||
{action: "navigate", payload: "https://app.com/page1"}
 | 
			
		||||
// ... work ...
 | 
			
		||||
 | 
			
		||||
{action: "navigate", payload: "https://app.com/page2"}
 | 
			
		||||
// ... work ... (still logged in)
 | 
			
		||||
```
 | 
			
		||||
							
								
								
									
										384
									
								
								shared/linked-dotfiles/opencode/skills/research-medical/SKILL.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										384
									
								
								shared/linked-dotfiles/opencode/skills/research-medical/SKILL.md
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,384 @@
 | 
			
		||||
---
 | 
			
		||||
name: research-medical
 | 
			
		||||
description: Use when researching medical/scientific topics and encountering paywalled journals, access failures, or needing primary sources - provides strategies for PubMed Central, DOI resolution, preprint servers, and fallback approaches for medical literature access
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
# Medical Research Access
 | 
			
		||||
 | 
			
		||||
Strategies for accessing medical and scientific literature when direct web access fails or sources are paywalled.
 | 
			
		||||
 | 
			
		||||
## When to Use This Skill
 | 
			
		||||
 | 
			
		||||
**Use when:**
 | 
			
		||||
- Webfetch fails on medical journal sites (NIH, Nature, JAMA, NEJM, etc.)
 | 
			
		||||
- Research requires primary sources (studies, trials, systematic reviews)
 | 
			
		||||
- Need to access paywalled medical literature
 | 
			
		||||
- Looking for recent research not yet peer-reviewed
 | 
			
		||||
- Extracting citations when full text unavailable
 | 
			
		||||
 | 
			
		||||
**When NOT to use:**
 | 
			
		||||
- General web research (use standard webfetch)
 | 
			
		||||
- Medical journalism is sufficient (STAT News, MedPage Today)
 | 
			
		||||
- Topic well-covered in open-access sources
 | 
			
		||||
 | 
			
		||||
## Quick Reference: Access Strategies
 | 
			
		||||
 | 
			
		||||
| Source Type | Primary Method | Fallback | Notes |
 | 
			
		||||
|-------------|---------------|----------|-------|
 | 
			
		||||
| Peer-reviewed studies | PubMed Central | DOI resolution, preprints | Always check PMC first |
 | 
			
		||||
| Recent research | Preprint servers | Author websites | May not be peer-reviewed yet |
 | 
			
		||||
| Clinical trials | ClinicalTrials.gov | Trial registries | Protocol vs results |
 | 
			
		||||
| Meta-analyses | Cochrane Library | PubMed search | Often open access |
 | 
			
		||||
| Medical journalism | STAT News, Medscape | Press releases | Secondary sources |
 | 
			
		||||
| Guidelines | Professional societies | NIH, CDC | Usually open access |
 | 
			
		||||
 | 
			
		||||
## Access Strategies
 | 
			
		||||
 | 
			
		||||
### 1. PubMed Central (PMC) - First Stop
 | 
			
		||||
 | 
			
		||||
**Why PMC:** Free full-text archive of biomedical literature, subset of PubMed with actual paper content.
 | 
			
		||||
 | 
			
		||||
**Search approaches:**
 | 
			
		||||
 | 
			
		||||
```markdown
 | 
			
		||||
# Direct PMC search
 | 
			
		||||
https://www.ncbi.nlm.nih.gov/pmc/?term=ivermectin+COVID-19+randomized+controlled+trial
 | 
			
		||||
 | 
			
		||||
# Filters to add:
 | 
			
		||||
- Free full text
 | 
			
		||||
- Article type (Clinical Trial, Meta-Analysis, Systematic Review)
 | 
			
		||||
- Publication date range
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
**When webfetch fails on PMC:**
 | 
			
		||||
- Try PubMed instead (has abstracts even without full text)
 | 
			
		||||
- Search by PMID if you have it: `https://pubmed.ncbi.nlm.nih.gov/[PMID]/`
 | 
			
		||||
- Look for "Free PMC article" badge in PubMed results
 | 
			
		||||
 | 
			
		||||
### 2. DOI Resolution Services
 | 
			
		||||
 | 
			
		||||
**What is DOI:** Digital Object Identifier - permanent link to research papers.
 | 
			
		||||
 | 
			
		||||
**Primary resolver:**
 | 
			
		||||
```markdown
 | 
			
		||||
https://doi.org/[DOI-HERE]
 | 
			
		||||
 | 
			
		||||
Example: https://doi.org/10.1056/NEJMoa2115869
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
**When DOI resolution hits paywall:**
 | 
			
		||||
- Try adding DOI to Google Scholar: `https://scholar.google.com/scholar?q=[DOI]`
 | 
			
		||||
- Check for "All versions" link in Scholar (may include preprint or author PDF)
 | 
			
		||||
- Look for institutional repository versions
 | 
			
		||||
 | 
			
		||||
**Extracting DOI from citations:**
 | 
			
		||||
- Usually in format: `10.XXXX/journal.year.number`
 | 
			
		||||
- Found at end of citation or in URL
 | 
			
		||||
- Can search PubMed by DOI to get PMID
 | 
			
		||||
 | 
			
		||||
### 3. Preprint Servers - Recent Research
 | 
			
		||||
 | 
			
		||||
**Primary servers:**
 | 
			
		||||
 | 
			
		||||
| Server | Focus | URL Pattern |
 | 
			
		||||
|--------|-------|-------------|
 | 
			
		||||
| medRxiv | Medicine | `https://www.medrxiv.org/content/[ID]` |
 | 
			
		||||
| bioRxiv | Biology | `https://www.biorxiv.org/content/[ID]` |
 | 
			
		||||
| SSRN | Social science, econ | `https://papers.ssrn.com/sol3/papers.cfm?abstract_id=[ID]` |
 | 
			
		||||
 | 
			
		||||
**Important notes:**
 | 
			
		||||
- Preprints are NOT peer-reviewed
 | 
			
		||||
- Always note preprint status in citations
 | 
			
		||||
- Check if preprint later published in journal (search by title)
 | 
			
		||||
- Good for very recent research (last 6-12 months)
 | 
			
		||||
 | 
			
		||||
**Search strategy:**
 | 
			
		||||
```markdown
 | 
			
		||||
# Search medRxiv directly
 | 
			
		||||
https://www.medrxiv.org/search/ivermectin%20COVID-19
 | 
			
		||||
 | 
			
		||||
# Or use Google Scholar with "preprint" filter
 | 
			
		||||
site:medrxiv.org OR site:biorxiv.org [search terms]
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### 4. Medical Journalism Without Paywalls
 | 
			
		||||
 | 
			
		||||
**Freely accessible sources:**
 | 
			
		||||
 | 
			
		||||
- **STAT News** (`statnews.com`) - High-quality medical journalism, no paywall
 | 
			
		||||
- **Medscape** (`medscape.com`) - Free with registration, clinical news
 | 
			
		||||
- **The Conversation** (`theconversation.com`) - Academic experts, open access
 | 
			
		||||
- **Science Daily** (`sciencedaily.com`) - Press releases and summaries
 | 
			
		||||
- **NIH News** (`nih.gov/news-events`) - Government research announcements
 | 
			
		||||
 | 
			
		||||
**When to use journalism vs primary sources:**
 | 
			
		||||
- Journalism: Background, context, expert opinions, controversy overview
 | 
			
		||||
- Primary sources: Specific claims, data, methodology, for fact-checking
 | 
			
		||||
 | 
			
		||||
**Citation approach:**
 | 
			
		||||
- Use journalism to identify key studies
 | 
			
		||||
- Track down primary sources for verification
 | 
			
		||||
- Cite primary source when making factual claims
 | 
			
		||||
- Cite journalism when discussing expert opinions or controversy
 | 
			
		||||
 | 
			
		||||
### 5. Clinical Trial Registries
 | 
			
		||||
 | 
			
		||||
**ClinicalTrials.gov** - Official US registry:
 | 
			
		||||
```markdown
 | 
			
		||||
https://clinicaltrials.gov/search?term=[drug/intervention]
 | 
			
		||||
 | 
			
		||||
Filter by:
 | 
			
		||||
- Study Status (Completed, Published)
 | 
			
		||||
- Study Type (Interventional)
 | 
			
		||||
- Study Results (Studies with Results)
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
**What you get:**
 | 
			
		||||
- Trial protocol and design
 | 
			
		||||
- Primary/secondary outcomes
 | 
			
		||||
- Results summary (if published)
 | 
			
		||||
- Links to published papers
 | 
			
		||||
 | 
			
		||||
**Other registries:**
 | 
			
		||||
- WHO ICTRP (international): `https://trialsearch.who.int/`
 | 
			
		||||
- EU Clinical Trials Register: `https://www.clinicaltrialsregister.eu/`
 | 
			
		||||
 | 
			
		||||
### 6. Professional Society Guidelines
 | 
			
		||||
 | 
			
		||||
**Often open access:**
 | 
			
		||||
- CDC guidelines: `cdc.gov`
 | 
			
		||||
- WHO guidelines: `who.int`
 | 
			
		||||
- NIH treatment guidelines: `covid19treatmentguidelines.nih.gov`
 | 
			
		||||
- Professional societies (AMA, ACP, IDSA) - check guidelines sections
 | 
			
		||||
 | 
			
		||||
**Good for:**
 | 
			
		||||
- Official recommendations
 | 
			
		||||
- Evidence summaries
 | 
			
		||||
- Standard of care
 | 
			
		||||
- Consensus positions
 | 
			
		||||
 | 
			
		||||
### 7. Google Scholar Strategies
 | 
			
		||||
 | 
			
		||||
**When direct access fails:**
 | 
			
		||||
 | 
			
		||||
```markdown
 | 
			
		||||
# Search with specific terms
 | 
			
		||||
"ivermectin" "COVID-19" "randomized controlled trial"
 | 
			
		||||
 | 
			
		||||
# Use "All versions" link to find:
 | 
			
		||||
- Preprint versions
 | 
			
		||||
- Author PDFs
 | 
			
		||||
- Institutional repository copies
 | 
			
		||||
 | 
			
		||||
# Filter by date range for recent research
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
**Citation extraction when full text unavailable:**
 | 
			
		||||
- Scholar provides formatted citations
 | 
			
		||||
- Shows "Cited by" count (impact indicator)
 | 
			
		||||
- Links to related articles
 | 
			
		||||
- May show abstract even without full text
 | 
			
		||||
 | 
			
		||||
### 8. Author Websites and ResearchGate
 | 
			
		||||
 | 
			
		||||
**When other methods fail:**
 | 
			
		||||
 | 
			
		||||
- Search author name + paper title
 | 
			
		||||
- Check university faculty pages (often have PDFs)
 | 
			
		||||
- ResearchGate (`researchgate.net`) - researchers share papers
 | 
			
		||||
- Academia.edu - similar to ResearchGate
 | 
			
		||||
 | 
			
		||||
**Caution:**
 | 
			
		||||
- Verify version matches published paper
 | 
			
		||||
- Note if it's a preprint or draft
 | 
			
		||||
- Check publication date
 | 
			
		||||
 | 
			
		||||
## Webfetch vs Direct Access Decision Tree
 | 
			
		||||
 | 
			
		||||
**Use webfetch when:**
 | 
			
		||||
- Source is known to be open access
 | 
			
		||||
- Medical journalism sites (STAT, Medscape)
 | 
			
		||||
- Government sites (NIH, CDC, FDA)
 | 
			
		||||
- Preprint servers
 | 
			
		||||
- Professional society guidelines
 | 
			
		||||
 | 
			
		||||
**Skip webfetch, use search strategies when:**
 | 
			
		||||
- Major journal sites (Nature, JAMA, NEJM, Lancet) - usually paywalled
 | 
			
		||||
- You have DOI - use DOI resolver or Scholar
 | 
			
		||||
- Need recent research - go to preprint servers
 | 
			
		||||
- Previous webfetch attempts failed on similar sources
 | 
			
		||||
 | 
			
		||||
**General agent with web search when:**
 | 
			
		||||
- Exploratory research (don't know specific sources yet)
 | 
			
		||||
- Need to identify key studies first
 | 
			
		||||
- Looking for expert commentary or summaries
 | 
			
		||||
- Building initial source list
 | 
			
		||||
 | 
			
		||||
## Citation Extraction Techniques
 | 
			
		||||
 | 
			
		||||
### When Full Text Unavailable
 | 
			
		||||
 | 
			
		||||
**From abstracts (PubMed):**
 | 
			
		||||
- Study design and methods
 | 
			
		||||
- Primary outcomes
 | 
			
		||||
- Sample size
 | 
			
		||||
- Key findings (usually in abstract)
 | 
			
		||||
- Limitations (sometimes mentioned)
 | 
			
		||||
 | 
			
		||||
**From press releases:**
 | 
			
		||||
- High-level findings
 | 
			
		||||
- Author quotes
 | 
			
		||||
- Institution and funding
 | 
			
		||||
- Link to actual paper (follow this)
 | 
			
		||||
 | 
			
		||||
**From systematic reviews/meta-analyses:**
 | 
			
		||||
- Summary of multiple studies
 | 
			
		||||
- Effect sizes across studies
 | 
			
		||||
- Quality assessments
 | 
			
		||||
- Usually cite all included studies (mine these)
 | 
			
		||||
 | 
			
		||||
### Citation Format Best Practices
 | 
			
		||||
 | 
			
		||||
**Minimum required:**
 | 
			
		||||
```markdown
 | 
			
		||||
Author(s). Title. Journal Year;Volume(Issue):Pages. DOI: [DOI]
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
**Enhanced format:**
 | 
			
		||||
```markdown
 | 
			
		||||
Author(s). Title. Journal Year;Volume(Issue):Pages. DOI: [DOI]. PMID: [PMID]. [Access status]
 | 
			
		||||
 | 
			
		||||
Example:
 | 
			
		||||
Lopez-Medina E, et al. Effect of Ivermectin on Time to Resolution of Symptoms Among Adults With Mild COVID-19. JAMA 2021;325(14):1426-1435. DOI: 10.1001/jama.2021.3071. PMID: 33662102. [Free full text via PMC]
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
**Always include:**
 | 
			
		||||
- DOI (for verification and access)
 | 
			
		||||
- PMID if available (PubMed tracking)
 | 
			
		||||
- Access status (open access, PMC free, paywalled)
 | 
			
		||||
- Preprint status if applicable
 | 
			
		||||
 | 
			
		||||
## Common Mistakes
 | 
			
		||||
 | 
			
		||||
### ❌ Giving up after first webfetch failure
 | 
			
		||||
 | 
			
		||||
**Problem:** Many medical sites block automated access or require authentication.
 | 
			
		||||
 | 
			
		||||
**Fix:** Use systematic fallback strategy:
 | 
			
		||||
1. Try PubMed Central search
 | 
			
		||||
2. Use DOI resolver if you have DOI
 | 
			
		||||
3. Check preprint servers
 | 
			
		||||
4. Search Google Scholar for alternative versions
 | 
			
		||||
5. Use medical journalism to identify sources, then track down primary
 | 
			
		||||
 | 
			
		||||
### ❌ Citing journalism when primary source is accessible
 | 
			
		||||
 | 
			
		||||
**Problem:** Secondary source citation when primary is available weakens credibility.
 | 
			
		||||
 | 
			
		||||
**Fix:**
 | 
			
		||||
- Use journalism to find studies
 | 
			
		||||
- Always attempt to access primary source
 | 
			
		||||
- Cite primary source for factual claims
 | 
			
		||||
- Cite journalism only for expert opinions or controversy framing
 | 
			
		||||
 | 
			
		||||
### ❌ Not noting preprint vs peer-reviewed status
 | 
			
		||||
 | 
			
		||||
**Problem:** Preprints lack peer review and may contain errors or later be contradicted.
 | 
			
		||||
 | 
			
		||||
**Fix:**
 | 
			
		||||
- Always check publication status
 | 
			
		||||
- Note in citation: "[Preprint, not peer-reviewed]"
 | 
			
		||||
- Search by title to see if later published in journal
 | 
			
		||||
- Weight peer-reviewed sources more heavily
 | 
			
		||||
 | 
			
		||||
### ❌ Ignoring "Cited by" counts and publication dates
 | 
			
		||||
 | 
			
		||||
**Problem:** May miss that study was retracted, contradicted, or superseded.
 | 
			
		||||
 | 
			
		||||
**Fix:**
 | 
			
		||||
- Check "Cited by" in Google Scholar
 | 
			
		||||
- Look for retractions or corrections
 | 
			
		||||
- Check for more recent systematic reviews
 | 
			
		||||
- Note if study is outlier vs consensus
 | 
			
		||||
 | 
			
		||||
### ❌ Using only abstracts for detailed claims
 | 
			
		||||
 | 
			
		||||
**Problem:** Abstracts omit important limitations, methods details, and context.
 | 
			
		||||
 | 
			
		||||
**Fix:**
 | 
			
		||||
- Use abstract for high-level findings only
 | 
			
		||||
- For specific claims, need full text
 | 
			
		||||
- If full text unavailable, note limitation: "[Based on abstract only]"
 | 
			
		||||
- Look for systematic reviews that analyzed full text
 | 
			
		||||
 | 
			
		||||
### ❌ Not tracking access failures for optimization
 | 
			
		||||
 | 
			
		||||
**Problem:** Repeated failures on same source types waste time.
 | 
			
		||||
 | 
			
		||||
**Fix:**
 | 
			
		||||
- Note which sources consistently fail webfetch
 | 
			
		||||
- Build project-specific access strategy
 | 
			
		||||
- Document successful access patterns
 | 
			
		||||
- Update AGENTS.md with project-specific guidance
 | 
			
		||||
 | 
			
		||||
## Real-World Impact
 | 
			
		||||
 | 
			
		||||
**Session context:** Pierre Kory/ivermectin research encountered 4 failed web access attempts (NIH, FDA, Nature, JAMA, MedPage Today), limiting source diversity to 2 primary sources.
 | 
			
		||||
 | 
			
		||||
**With this skill:**
 | 
			
		||||
- PubMed Central search would provide free full-text access to key trials
 | 
			
		||||
- DOI resolution would access Nature and JAMA papers via alternative routes
 | 
			
		||||
- Preprint servers would surface early ivermectin research
 | 
			
		||||
- Medical journalism (STAT News) would provide controversy context without paywall
 | 
			
		||||
- Clinical trial registries would provide TOGETHER trial and other RCT data
 | 
			
		||||
 | 
			
		||||
**Expected improvement:** 5-8 accessible sources instead of 2, with mix of primary sources and expert commentary.
 | 
			
		||||
 | 
			
		||||
## Workflow Integration
 | 
			
		||||
 | 
			
		||||
### Research Session Startup
 | 
			
		||||
 | 
			
		||||
1. **Identify topic and key terms**
 | 
			
		||||
2. **Start with PubMed Central search** (free full text)
 | 
			
		||||
3. **Check for systematic reviews** (summarize evidence)
 | 
			
		||||
4. **Search preprint servers** (recent research)
 | 
			
		||||
5. **Use medical journalism** (context and expert opinions)
 | 
			
		||||
6. **Track citations** (DOI, PMID, access status)
 | 
			
		||||
 | 
			
		||||
### When Webfetch Fails
 | 
			
		||||
 | 
			
		||||
1. **Don't retry same URL** - move to fallback strategy
 | 
			
		||||
2. **Extract DOI from citation** - use DOI resolver
 | 
			
		||||
3. **Search PubMed by title** - may find PMC version
 | 
			
		||||
4. **Check Google Scholar** - look for "All versions"
 | 
			
		||||
5. **Note failure** - document for future optimization
 | 
			
		||||
 | 
			
		||||
### Citation Verification
 | 
			
		||||
 | 
			
		||||
1. **Have DOI or PMID** - verify via PubMed lookup
 | 
			
		||||
2. **Check publication status** - preprint vs peer-reviewed
 | 
			
		||||
3. **Look for retractions** - search "[title] retraction"
 | 
			
		||||
4. **Note access method** - for reproducibility
 | 
			
		||||
5. **Capture full citation** - author, title, journal, DOI, PMID
 | 
			
		||||
 | 
			
		||||
## Additional Resources
 | 
			
		||||
 | 
			
		||||
**PubMed search tips:**
 | 
			
		||||
- Use MeSH terms (Medical Subject Headings) for precise searches
 | 
			
		||||
- Combine with Boolean operators (AND, OR, NOT)
 | 
			
		||||
- Use filters: Free full text, Article type, Publication date
 | 
			
		||||
- Save searches for repeated use
 | 
			
		||||
 | 
			
		||||
**Understanding study types:**
 | 
			
		||||
- RCT (Randomized Controlled Trial) - gold standard
 | 
			
		||||
- Systematic Review/Meta-Analysis - synthesis of multiple studies
 | 
			
		||||
- Cohort Study - observational, follows groups over time
 | 
			
		||||
- Case-Control Study - compares cases to controls
 | 
			
		||||
- Case Series/Report - descriptive, lowest evidence level
 | 
			
		||||
 | 
			
		||||
**Red flags in research:**
 | 
			
		||||
- Preprint only (not peer-reviewed)
 | 
			
		||||
- Retracted or corrected
 | 
			
		||||
- Conflicts of interest not disclosed
 | 
			
		||||
- Small sample size with strong claims
 | 
			
		||||
- Outlier findings not replicated
 | 
			
		||||
							
								
								
									
										237
									
								
								shared/linked-dotfiles/opencode/skills/research/SKILL.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										237
									
								
								shared/linked-dotfiles/opencode/skills/research/SKILL.md
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,237 @@
 | 
			
		||||
---
 | 
			
		||||
name: research
 | 
			
		||||
description: Use when conducting deep research across any domain - provides citation patterns, concise synthesis techniques, and cross-domain connection strategies
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
# Research Skill
 | 
			
		||||
 | 
			
		||||
Quick reference for conducting deep research with proper citations, concise output, and novel insights across any domain.
 | 
			
		||||
 | 
			
		||||
## When to Use This Skill
 | 
			
		||||
 | 
			
		||||
- Investigating technical topics (APIs, frameworks, algorithms)
 | 
			
		||||
- Understanding psychological or human factors
 | 
			
		||||
- Exploring creative writing techniques or artistic approaches
 | 
			
		||||
- Synthesizing information from multiple disparate sources
 | 
			
		||||
- Making connections between different domains
 | 
			
		||||
- Gathering authoritative sources for decision-making
 | 
			
		||||
 | 
			
		||||
**When NOT to use:**
 | 
			
		||||
- Simple factual lookups (use direct search instead)
 | 
			
		||||
- Code implementation (use coding agents)
 | 
			
		||||
- Quick reference checks (use man pages directly)
 | 
			
		||||
 | 
			
		||||
## Citation Format Reference
 | 
			
		||||
 | 
			
		||||
### Web Sources
 | 
			
		||||
```
 | 
			
		||||
<source url="https://example.com/article" title="Article Title">Specific claim or finding from the source</source>
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Academic Papers
 | 
			
		||||
```
 | 
			
		||||
<source url="https://arxiv.org/abs/2210.03629" title="ReAct: Synergizing Reasoning and Acting">Quantitative finding or key insight</source>
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Local Files
 | 
			
		||||
```
 | 
			
		||||
<source url="file:///path/to/file.md" title="filename.md">Code snippet or configuration detail</source>
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Man Pages
 | 
			
		||||
```
 | 
			
		||||
<source url="man://grep" title="grep(1) manual">Command behavior or flag description</source>
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Multiple Sources for Same Claim
 | 
			
		||||
```
 | 
			
		||||
<source url="https://source1.com" title="First Study">Initial finding</source> corroborated by <source url="https://source2.com" title="Second Study">confirming evidence</source>
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## Output Style Guide
 | 
			
		||||
 | 
			
		||||
| Good (Concise Paragraphs) | Bad (Bullets/Verbosity) |
 | 
			
		||||
|---|---|
 | 
			
		||||
| The STORM paper introduces a multi-agent system for comprehensive research. <source>Finding</source>. This approach yields Wikipedia-quality output. | It is important to note that:<br>- STORM uses agents<br>- Perhaps it works well<br>- Furthermore, one might consider... |
 | 
			
		||||
| Direct statement with citation. | "It seems that this might be useful..." |
 | 
			
		||||
| 2-4 sentence paragraphs. | Wall of text or excessive bullets. |
 | 
			
		||||
 | 
			
		||||
## ReAct Research Loop
 | 
			
		||||
 | 
			
		||||
**Pattern for iterative research:**
 | 
			
		||||
 | 
			
		||||
1. **Thought**: "I need to understand X. Sources to check: Y, Z."
 | 
			
		||||
2. **Action**: `curl https://docs.example.com/api` or `man command` or `rg "pattern"`
 | 
			
		||||
3. **Observation**: "Found A, B, C. Still missing D."
 | 
			
		||||
4. **Thought**: "Need to refine search for D."
 | 
			
		||||
5. **Action**: New search with refined query
 | 
			
		||||
6. **Observation**: "Now have complete picture."
 | 
			
		||||
 | 
			
		||||
Repeat until sufficient evidence gathered.
 | 
			
		||||
 | 
			
		||||
## Making Cross-Domain Connections
 | 
			
		||||
 | 
			
		||||
### Technique: Analogy Mapping
 | 
			
		||||
 | 
			
		||||
1. Identify core mechanism in source domain
 | 
			
		||||
2. Find parallel structure in target domain
 | 
			
		||||
3. Map relationships explicitly
 | 
			
		||||
4. Test if analogy reveals new insights
 | 
			
		||||
 | 
			
		||||
**Example**: ReAct pattern (technical) ↔ Expert problem-solving (psychology)
 | 
			
		||||
- Both externalize thinking
 | 
			
		||||
- Both enable error detection
 | 
			
		||||
- Both reduce cognitive load
 | 
			
		||||
- Connection reveals *why* ReAct works
 | 
			
		||||
 | 
			
		||||
### Technique: Pattern Recognition
 | 
			
		||||
 | 
			
		||||
Look across sources for:
 | 
			
		||||
- Recurring themes or principles
 | 
			
		||||
- Shared constraints or trade-offs
 | 
			
		||||
- Similar solution approaches
 | 
			
		||||
- Common failure modes
 | 
			
		||||
 | 
			
		||||
### Technique: Contrast Analysis
 | 
			
		||||
 | 
			
		||||
When sources disagree:
 | 
			
		||||
- Identify specific points of tension
 | 
			
		||||
- Examine underlying assumptions
 | 
			
		||||
- Consider context differences
 | 
			
		||||
- Synthesize higher-level insight
 | 
			
		||||
 | 
			
		||||
## Research Tool Usage
 | 
			
		||||
 | 
			
		||||
### Web Research
 | 
			
		||||
```bash
 | 
			
		||||
# Fetch documentation
 | 
			
		||||
curl -s https://docs.example.com/api | grep "pattern"
 | 
			
		||||
 | 
			
		||||
# Download paper
 | 
			
		||||
wget https://arxiv.org/pdf/2210.03629.pdf
 | 
			
		||||
 | 
			
		||||
# Search with specific terms
 | 
			
		||||
curl -s "https://api.example.com/search?q=term"
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Man Pages
 | 
			
		||||
```bash
 | 
			
		||||
# Full manual
 | 
			
		||||
man grep
 | 
			
		||||
 | 
			
		||||
# Search within man page
 | 
			
		||||
man grep | grep -A 5 "pattern"
 | 
			
		||||
 | 
			
		||||
# List all man pages for command
 | 
			
		||||
man -k search_term
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Code/File Research
 | 
			
		||||
```bash
 | 
			
		||||
# Find implementations
 | 
			
		||||
rg "function_name" --type rust
 | 
			
		||||
 | 
			
		||||
# Search with context
 | 
			
		||||
rg "pattern" -A 3 -B 3
 | 
			
		||||
 | 
			
		||||
# Find files by name
 | 
			
		||||
find . -name "*.md" -type f
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## Common Mistakes
 | 
			
		||||
 | 
			
		||||
**Mistake: Uncited claims**
 | 
			
		||||
```
 | 
			
		||||
❌ "The ReAct pattern improves performance significantly."
 | 
			
		||||
✅ "The ReAct pattern improves performance significantly. <source>specific metric</source>."
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
**Mistake: Verbose hedging**
 | 
			
		||||
```
 | 
			
		||||
❌ "It seems that perhaps one might consider that this could potentially..."
 | 
			
		||||
✅ "This approach increases success rates by 34%."
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
**Mistake: Bullet point overload**
 | 
			
		||||
```
 | 
			
		||||
❌ Long lists of disconnected bullets
 | 
			
		||||
✅ 2-4 sentence paragraphs that flow coherently
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
**Mistake: Missing cross-domain insights**
 | 
			
		||||
```
 | 
			
		||||
❌ Only technical analysis without broader connections
 | 
			
		||||
✅ "This pattern mirrors cognitive psychology research on expert problem-solving..."
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
**Mistake: No verification step**
 | 
			
		||||
```
 | 
			
		||||
❌ Output without checking citation coverage
 | 
			
		||||
✅ Self-check: Every claim cited? Format correct? Under 500 words?
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## Output Structure Template
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
[1-2 sentence context establishing the question and why it matters]
 | 
			
		||||
 | 
			
		||||
[Paragraph 1: First major finding with citations. 2-4 sentences. Focus on one insight.]
 | 
			
		||||
 | 
			
		||||
[Paragraph 2: Second major finding with citations. Builds on or contrasts with first.]
 | 
			
		||||
 | 
			
		||||
[Paragraph 3: Cross-domain connection or novel insight. "Interestingly..." or "This pattern mirrors..."]
 | 
			
		||||
 | 
			
		||||
[Optional Paragraph 4: Practical implications or actionable takeaways if relevant.]
 | 
			
		||||
 | 
			
		||||
## Sources
 | 
			
		||||
1. [Title](URL) - Brief description of what this source provides
 | 
			
		||||
2. [Title](URL) - Brief description
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## Quality Checklist
 | 
			
		||||
 | 
			
		||||
Before finalizing research output:
 | 
			
		||||
 | 
			
		||||
- [ ] Every significant claim has source citation
 | 
			
		||||
- [ ] Citations use correct XML format with URL and title
 | 
			
		||||
- [ ] Writing is direct - no hedging or filler phrases
 | 
			
		||||
- [ ] Output uses small paragraphs (2-4 sentences), not bullets
 | 
			
		||||
- [ ] Under 500 words for typical queries
 | 
			
		||||
- [ ] At least one cross-domain connection identified
 | 
			
		||||
- [ ] Multiple perspectives considered (technical, human, business, creative)
 | 
			
		||||
- [ ] Bibliography section lists all sources
 | 
			
		||||
- [ ] Verification step completed
 | 
			
		||||
 | 
			
		||||
## Domain-Specific Notes
 | 
			
		||||
 | 
			
		||||
### Technical Research
 | 
			
		||||
Focus on: Implementation details, performance metrics, trade-offs, compatibility, version-specific behavior
 | 
			
		||||
 | 
			
		||||
### Psychology/Human Factors
 | 
			
		||||
Focus on: User studies, cognitive principles, behavioral patterns, accessibility, mental models
 | 
			
		||||
 | 
			
		||||
### Creative Writing
 | 
			
		||||
Focus on: Techniques from literature, stylistic approaches, examples from published works, craft advice from authors
 | 
			
		||||
 | 
			
		||||
### Science/Research
 | 
			
		||||
Focus on: Peer-reviewed sources, methodology, empirical findings, replication status, statistical significance
 | 
			
		||||
 | 
			
		||||
## Example: Good Research Output
 | 
			
		||||
 | 
			
		||||
**Query**: How does the ReAct reasoning pattern work?
 | 
			
		||||
 | 
			
		||||
**Output**:
 | 
			
		||||
 | 
			
		||||
The ReAct pattern addresses a key limitation in language model task-solving by interleaving reasoning traces with tool actions. <source url="https://arxiv.org/abs/2210.03629" title="ReAct: Synergizing Reasoning and Acting in Language Models">ReAct agents achieve 34% higher success rates on ALFWorld tasks and 10% improvement on HotpotQA compared to baselines</source>. The core mechanism involves explicit Thought-Action-Observation loops where the model verbalizes its reasoning before taking each action, then updates its understanding based on observations.
 | 
			
		||||
 | 
			
		||||
This architecture mirrors findings from cognitive psychology on expert problem-solving. <source url="file://references/cognitive-science.md" title="Expert Problem Solving Research">Experts externalize their thinking through verbal protocols, which reduces cognitive load by offloading working memory to external representations</source>. By forcing LLMs to "think aloud," ReAct essentially implements this expert strategy in artificial systems.
 | 
			
		||||
 | 
			
		||||
The practical implication is clear: tasks requiring multi-step reasoning benefit from explicit trace generation. ReAct excels when error recovery matters, since failed actions produce observations that redirect reasoning. For simple, single-step tasks, the overhead isn't justified.
 | 
			
		||||
 | 
			
		||||
## Sources
 | 
			
		||||
1. [ReAct: Synergizing Reasoning and Acting in Language Models](https://arxiv.org/abs/2210.03629) - ICLR 2023 paper introducing the pattern
 | 
			
		||||
2. [Expert Problem Solving Research](file://references/cognitive-science.md) - Cognitive science on externalized thinking
 | 
			
		||||
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
*Note: This skill is designed for use with the research agent. It provides quick reference patterns for citations, concise synthesis, and cross-domain insights.*
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user