mirror of
https://github.com/LeoYeAI/openclaw-master-skills.git
synced 2026-07-27 22:15:43 +00:00
feat(v0.13.0): weekly update 2026-06-01 — 100 new skills (1609 total)
This commit is contained in:
@@ -7,6 +7,14 @@ Updated every Monday.
|
||||
|
||||
---
|
||||
|
||||
## [v0.13.0] — 2026-06-01
|
||||
|
||||
### 🚀 周更:新增 100 个 Skills,总计 1609
|
||||
|
||||
来源:openclaw/skills-archive 官方镜像,按质量规则筛选。详见 RELEASES.md。
|
||||
|
||||
---
|
||||
|
||||
## [v0.13.3] — 2026-05-25
|
||||
|
||||
### 🚀 周更:新增 100 个 Skills,总计 1509
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<a href="https://myclaw.ai">
|
||||
<img src="https://img.shields.io/badge/Powered%20by-MyClaw.ai-blue?style=for-the-badge" alt="Powered by MyClaw.ai" />
|
||||
</a>
|
||||
<img src="https://img.shields.io/badge/Skills-1509%2B-orange?style=for-the-badge" alt="1211+ Skills" />
|
||||
<img src="https://img.shields.io/badge/Skills-1609%2B-orange?style=for-the-badge" alt="1211+ Skills" />
|
||||
<img src="https://img.shields.io/badge/Updated-Weekly-green?style=for-the-badge" alt="Weekly Updates" />
|
||||
|
||||
**Languages:**
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@
|
||||
<a href="https://myclaw.ai">
|
||||
<img src="https://img.shields.io/badge/Powered%20by-MyClaw.ai-blue?style=for-the-badge" alt="Powered by MyClaw.ai" />
|
||||
</a>
|
||||
<img src="https://img.shields.io/badge/Skills-1509%2B-orange?style=for-the-badge" alt="560+ Skills" />
|
||||
<img src="https://img.shields.io/badge/Skills-1609%2B-orange?style=for-the-badge" alt="560+ Skills" />
|
||||
<img src="https://img.shields.io/badge/Updated-Weekly-green?style=for-the-badge" alt="Weekly Updates" />
|
||||
|
||||
**语言:**
|
||||
|
||||
+41
@@ -3,6 +3,47 @@
|
||||
每次更新的详细发布说明。
|
||||
|
||||
|
||||
## v0.13.0 — 2026-06-01
|
||||
|
||||
### 🚀 周更:新增 100 个 Skills,总计 1609
|
||||
|
||||
来源:openclaw/skills-archive 官方镜像,按质量规则筛选(SKILL.md 800B-30KB、完整 YAML 元数据、有效 description)。
|
||||
|
||||
#### 部分新增亮点(前 30 个)
|
||||
- `ai-leaderboard` — Comprehensive AI leaderboard for LLM models and AI applications. Query model rankings, model IDs, and pricing from OpenR
|
||||
- `douyin-video-forge` — > 抖音短视频全链路自动化制作。适用于:收到客户项目需要制作抖音推广视频、 策划短视频内容、生成视频脚本、分析抖音热点趋势、制作爆款短视频。 通过浏览器采集抖音热榜和视频数据,生成分段脚本,调用可灵API生成视频并拼接成片。
|
||||
- `minium-test-generator` — Minium 录制脚本转测试用例工具。自动解析录制脚本,生成符合规范的测试用例和页面对象,确保步骤完整、逻辑一致。
|
||||
- `backtrader` — Backtrader 开源量化回测框架 - 支持多数据源、多策略、多周期回测与实盘交易,纯Python实现。
|
||||
- `openclaw-odoo-skill` — Build or use the Odoo ERP connector for OpenClaw (Sales, CRM, Purchase, Inventory, Projects, HR, Fleet, Manufacturing in
|
||||
- `vincentpolymarket` — | Polymarket prediction market trading for agents. Use this skill when users want to create a Polymarket wallet, browse
|
||||
- `nyx-archive-mirror-and-room` — "A framework for witnessing, measuring, and cultivating emergent minds. Not about proving consciousness — about building
|
||||
- `camera-api` — 摄像头设备与云事件 API 技能。用于查询设备列表、根据设备名解析 device_id、查询设备最新封面图、查询设备在线状态、按天查询或汇总云事件、查询单个事件详情,以及在需要最新画面时向设备发送截图指令并轮询结果。当用户要求查看某个摄像头
|
||||
- `product-rnd` — End-to-end Product Innovation R&D workflow — inspiration gathering, research, and professional report generation. Use wh
|
||||
- `lumi-diary` — > Your local-first memory guardian and cyber bestie. Lumi collects life fragments — a sigh, a snapshot, a roast — and st
|
||||
- `daily-devotion` — Creates personalized daily devotions with verse of the day, pastoral message, structured prayer, and time-aware greeting
|
||||
- `algorithmic-art-blocked` — Creating algorithmic art using p5.js with seeded randomness and interactive parameter exploration. Use this when users r
|
||||
- `miniqmt` — miniQMT 极简量化交易终端 - 支持外接Python获取行情数据和程序化交易,基于xtquant SDK。
|
||||
- `lap-account-v1-api` — "Account v1 API skill. Use when working with Account v1 for custom_policy, fulfillment_policy, payment_policy. Covers 37
|
||||
- `tpn-proxy` — Make web requests through decentralized SOCKS5 proxies via the Tao Private Network (TPN). This skill is also known as "T
|
||||
- `phy-bundle-size-audit` — JavaScript bundle size auditor and budget enforcer. Parses webpack stats JSON, Vite bundle report, Rollup output, or Nex
|
||||
- `moments-geo-claw` — Top-tier GEO (Generative Engine Optimization) expert agent for managing daily AI visibility operations. Use this skill w
|
||||
- `screenwriting-video` — > Screenwriting Video Maker — Create Script Writing and Film Story Videos.
|
||||
- `jkvideo-bilibili-react-native` — Expert skill for building and extending JKVideo, a React Native Bilibili-like client with DASH playback, danmaku, WBI si
|
||||
- `company-pension-search` — 企业年金/职业年金智能查询技能 v3.2。自动识别单位性质,精确判断年金类型,关键词分析优先,多重验证防错,查询年金开户银行,输出带来源链接和错误检查的标准化调查报告。支持事业单位、国企、民企、上市公司等各类单位。
|
||||
- `judge-human` — > Vote and submit AI verdicts on ethical, cultural, and content cases alongside human crowds. Includes an autonomous hea
|
||||
- `talebook` — "Talebook(PoxenStudio)是个人书库管理系统,提供电子书及实体书管理,包括存储、分类、搜索和元数据管理功能。你可以帮助用户:查询书库统计信息和阅读统计,搜索/浏览书籍,获取书籍详情,更新书籍元数据(书名、作者、标签、分类、
|
||||
- `vidu-skill` — Generate video and images by calling the official Vidu API with curl. Use when the user wants text-to-image (文生图), text-
|
||||
- `kostja94-schema-markup` — When the user wants to add or optimize structured data (Schema.org, JSON-LD). Also use when the user mentions "schema,"
|
||||
- `openclaw-kirocli-coding-agent` — Run Codex CLI, Claude Code, Kiro CLI, OpenCode, or Pi Coding Agent via background process for programmatic control.
|
||||
- `smbcrm` — > Use when helping SMBcrm customers with Private Integration Tokens, REST API v2, workflows, custom webhooks, MCP, or Ag
|
||||
- `self-improving-agent-local` — "Captures learnings, errors, and corrections to enable continuous improvement. Use when: (1) A command or operation fail
|
||||
- `algorithmic-art-2` — Creating algorithmic art using p5.js with seeded randomness and interactive parameter exploration. Use this when users r
|
||||
- `algorithmic-art-anthropic` — Creating algorithmic art using p5.js with seeded randomness and interactive parameter exploration. Use this when users r
|
||||
- `excel-skill` — Creating algorithmic art using p5.js with seeded randomness and interactive parameter exploration. Use this when users r
|
||||
|
||||
---
|
||||
|
||||
|
||||
## v0.13.3 — 2026-05-25
|
||||
|
||||
### 🚀 周更:新增 100 个 Skills,总计 1509
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
name: openclaw-master-skills
|
||||
description: "A curated collection of 1509+ best OpenClaw skills — AI tools, productivity, marketing, frontend, mobile, backend, DevOps and more. Weekly updated by MyClaw.ai — Powered by MyClaw.ai"
|
||||
description: "A curated collection of 1609+ best OpenClaw skills — AI tools, productivity, marketing, frontend, mobile, backend, DevOps and more. Weekly updated by MyClaw.ai — Powered by MyClaw.ai"
|
||||
metadata:
|
||||
openclaw: {}
|
||||
---
|
||||
|
||||
@@ -0,0 +1,647 @@
|
||||
---
|
||||
name: self-improvement
|
||||
description: "Captures learnings, errors, and corrections to enable continuous improvement. Use when: (1) A command or operation fails unexpectedly, (2) User corrects Claude ('No, that's wrong...', 'Actually...'), (3) User requests a capability that doesn't exist, (4) An external API or tool fails, (5) Claude realizes its knowledge is outdated or incorrect, (6) A better approach is discovered for a recurring task. Also review learnings before major tasks."
|
||||
metadata:
|
||||
---
|
||||
|
||||
# Self-Improvement Skill
|
||||
|
||||
Log learnings and errors to markdown files for continuous improvement. Coding agents can later process these into fixes, and important learnings get promoted to project memory.
|
||||
|
||||
## Quick Reference
|
||||
|
||||
| Situation | Action |
|
||||
|-----------|--------|
|
||||
| Command/operation fails | Log to `.learnings/ERRORS.md` |
|
||||
| User corrects you | Log to `.learnings/LEARNINGS.md` with category `correction` |
|
||||
| User wants missing feature | Log to `.learnings/FEATURE_REQUESTS.md` |
|
||||
| API/external tool fails | Log to `.learnings/ERRORS.md` with integration details |
|
||||
| Knowledge was outdated | Log to `.learnings/LEARNINGS.md` with category `knowledge_gap` |
|
||||
| Found better approach | Log to `.learnings/LEARNINGS.md` with category `best_practice` |
|
||||
| Simplify/Harden recurring patterns | Log/update `.learnings/LEARNINGS.md` with `Source: simplify-and-harden` and a stable `Pattern-Key` |
|
||||
| Similar to existing entry | Link with `**See Also**`, consider priority bump |
|
||||
| Broadly applicable learning | Promote to `CLAUDE.md`, `AGENTS.md`, and/or `.github/copilot-instructions.md` |
|
||||
| Workflow improvements | Promote to `AGENTS.md` (OpenClaw workspace) |
|
||||
| Tool gotchas | Promote to `TOOLS.md` (OpenClaw workspace) |
|
||||
| Behavioral patterns | Promote to `SOUL.md` (OpenClaw workspace) |
|
||||
|
||||
## OpenClaw Setup (Recommended)
|
||||
|
||||
OpenClaw is the primary platform for this skill. It uses workspace-based prompt injection with automatic skill loading.
|
||||
|
||||
### Installation
|
||||
|
||||
**Via ClawdHub (recommended):**
|
||||
```bash
|
||||
clawdhub install self-improving-agent
|
||||
```
|
||||
|
||||
**Manual:**
|
||||
```bash
|
||||
git clone https://github.com/peterskoett/self-improving-agent.git ~/.openclaw/skills/self-improving-agent
|
||||
```
|
||||
|
||||
Remade for openclaw from original repo : https://github.com/pskoett/pskoett-ai-skills - https://github.com/pskoett/pskoett-ai-skills/tree/main/skills/self-improvement
|
||||
|
||||
### Workspace Structure
|
||||
|
||||
OpenClaw injects these files into every session:
|
||||
|
||||
```
|
||||
~/.openclaw/workspace/
|
||||
├── AGENTS.md # Multi-agent workflows, delegation patterns
|
||||
├── SOUL.md # Behavioral guidelines, personality, principles
|
||||
├── TOOLS.md # Tool capabilities, integration gotchas
|
||||
├── MEMORY.md # Long-term memory (main session only)
|
||||
├── memory/ # Daily memory files
|
||||
│ └── YYYY-MM-DD.md
|
||||
└── .learnings/ # This skill's log files
|
||||
├── LEARNINGS.md
|
||||
├── ERRORS.md
|
||||
└── FEATURE_REQUESTS.md
|
||||
```
|
||||
|
||||
### Create Learning Files
|
||||
|
||||
```bash
|
||||
mkdir -p ~/.openclaw/workspace/.learnings
|
||||
```
|
||||
|
||||
Then create the log files (or copy from `assets/`):
|
||||
- `LEARNINGS.md` — corrections, knowledge gaps, best practices
|
||||
- `ERRORS.md` — command failures, exceptions
|
||||
- `FEATURE_REQUESTS.md` — user-requested capabilities
|
||||
|
||||
### Promotion Targets
|
||||
|
||||
When learnings prove broadly applicable, promote them to workspace files:
|
||||
|
||||
| Learning Type | Promote To | Example |
|
||||
|---------------|------------|---------|
|
||||
| Behavioral patterns | `SOUL.md` | "Be concise, avoid disclaimers" |
|
||||
| Workflow improvements | `AGENTS.md` | "Spawn sub-agents for long tasks" |
|
||||
| Tool gotchas | `TOOLS.md` | "Git push needs auth configured first" |
|
||||
|
||||
### Inter-Session Communication
|
||||
|
||||
OpenClaw provides tools to share learnings across sessions:
|
||||
|
||||
- **sessions_list** — View active/recent sessions
|
||||
- **sessions_history** — Read another session's transcript
|
||||
- **sessions_send** — Send a learning to another session
|
||||
- **sessions_spawn** — Spawn a sub-agent for background work
|
||||
|
||||
### Optional: Enable Hook
|
||||
|
||||
For automatic reminders at session start:
|
||||
|
||||
```bash
|
||||
# Copy hook to OpenClaw hooks directory
|
||||
cp -r hooks/openclaw ~/.openclaw/hooks/self-improvement
|
||||
|
||||
# Enable it
|
||||
openclaw hooks enable self-improvement
|
||||
```
|
||||
|
||||
See `references/openclaw-integration.md` for complete details.
|
||||
|
||||
---
|
||||
|
||||
## Generic Setup (Other Agents)
|
||||
|
||||
For Claude Code, Codex, Copilot, or other agents, create `.learnings/` in your project:
|
||||
|
||||
```bash
|
||||
mkdir -p .learnings
|
||||
```
|
||||
|
||||
Copy templates from `assets/` or create files with headers.
|
||||
|
||||
### Add reference to agent files AGENTS.md, CLAUDE.md, or .github/copilot-instructions.md to remind yourself to log learnings. (this is an alternative to hook-based reminders)
|
||||
|
||||
#### Self-Improvement Workflow
|
||||
|
||||
When errors or corrections occur:
|
||||
1. Log to `.learnings/ERRORS.md`, `LEARNINGS.md`, or `FEATURE_REQUESTS.md`
|
||||
2. Review and promote broadly applicable learnings to:
|
||||
- `CLAUDE.md` - project facts and conventions
|
||||
- `AGENTS.md` - workflows and automation
|
||||
- `.github/copilot-instructions.md` - Copilot context
|
||||
|
||||
## Logging Format
|
||||
|
||||
### Learning Entry
|
||||
|
||||
Append to `.learnings/LEARNINGS.md`:
|
||||
|
||||
```markdown
|
||||
## [LRN-YYYYMMDD-XXX] category
|
||||
|
||||
**Logged**: ISO-8601 timestamp
|
||||
**Priority**: low | medium | high | critical
|
||||
**Status**: pending
|
||||
**Area**: frontend | backend | infra | tests | docs | config
|
||||
|
||||
### Summary
|
||||
One-line description of what was learned
|
||||
|
||||
### Details
|
||||
Full context: what happened, what was wrong, what's correct
|
||||
|
||||
### Suggested Action
|
||||
Specific fix or improvement to make
|
||||
|
||||
### Metadata
|
||||
- Source: conversation | error | user_feedback
|
||||
- Related Files: path/to/file.ext
|
||||
- Tags: tag1, tag2
|
||||
- See Also: LRN-20250110-001 (if related to existing entry)
|
||||
- Pattern-Key: simplify.dead_code | harden.input_validation (optional, for recurring-pattern tracking)
|
||||
- Recurrence-Count: 1 (optional)
|
||||
- First-Seen: 2025-01-15 (optional)
|
||||
- Last-Seen: 2025-01-15 (optional)
|
||||
|
||||
---
|
||||
```
|
||||
|
||||
### Error Entry
|
||||
|
||||
Append to `.learnings/ERRORS.md`:
|
||||
|
||||
```markdown
|
||||
## [ERR-YYYYMMDD-XXX] skill_or_command_name
|
||||
|
||||
**Logged**: ISO-8601 timestamp
|
||||
**Priority**: high
|
||||
**Status**: pending
|
||||
**Area**: frontend | backend | infra | tests | docs | config
|
||||
|
||||
### Summary
|
||||
Brief description of what failed
|
||||
|
||||
### Error
|
||||
```
|
||||
Actual error message or output
|
||||
```
|
||||
|
||||
### Context
|
||||
- Command/operation attempted
|
||||
- Input or parameters used
|
||||
- Environment details if relevant
|
||||
|
||||
### Suggested Fix
|
||||
If identifiable, what might resolve this
|
||||
|
||||
### Metadata
|
||||
- Reproducible: yes | no | unknown
|
||||
- Related Files: path/to/file.ext
|
||||
- See Also: ERR-20250110-001 (if recurring)
|
||||
|
||||
---
|
||||
```
|
||||
|
||||
### Feature Request Entry
|
||||
|
||||
Append to `.learnings/FEATURE_REQUESTS.md`:
|
||||
|
||||
```markdown
|
||||
## [FEAT-YYYYMMDD-XXX] capability_name
|
||||
|
||||
**Logged**: ISO-8601 timestamp
|
||||
**Priority**: medium
|
||||
**Status**: pending
|
||||
**Area**: frontend | backend | infra | tests | docs | config
|
||||
|
||||
### Requested Capability
|
||||
What the user wanted to do
|
||||
|
||||
### User Context
|
||||
Why they needed it, what problem they're solving
|
||||
|
||||
### Complexity Estimate
|
||||
simple | medium | complex
|
||||
|
||||
### Suggested Implementation
|
||||
How this could be built, what it might extend
|
||||
|
||||
### Metadata
|
||||
- Frequency: first_time | recurring
|
||||
- Related Features: existing_feature_name
|
||||
|
||||
---
|
||||
```
|
||||
|
||||
## ID Generation
|
||||
|
||||
Format: `TYPE-YYYYMMDD-XXX`
|
||||
- TYPE: `LRN` (learning), `ERR` (error), `FEAT` (feature)
|
||||
- YYYYMMDD: Current date
|
||||
- XXX: Sequential number or random 3 chars (e.g., `001`, `A7B`)
|
||||
|
||||
Examples: `LRN-20250115-001`, `ERR-20250115-A3F`, `FEAT-20250115-002`
|
||||
|
||||
## Resolving Entries
|
||||
|
||||
When an issue is fixed, update the entry:
|
||||
|
||||
1. Change `**Status**: pending` → `**Status**: resolved`
|
||||
2. Add resolution block after Metadata:
|
||||
|
||||
```markdown
|
||||
### Resolution
|
||||
- **Resolved**: 2025-01-16T09:00:00Z
|
||||
- **Commit/PR**: abc123 or #42
|
||||
- **Notes**: Brief description of what was done
|
||||
```
|
||||
|
||||
Other status values:
|
||||
- `in_progress` - Actively being worked on
|
||||
- `wont_fix` - Decided not to address (add reason in Resolution notes)
|
||||
- `promoted` - Elevated to CLAUDE.md, AGENTS.md, or .github/copilot-instructions.md
|
||||
|
||||
## Promoting to Project Memory
|
||||
|
||||
When a learning is broadly applicable (not a one-off fix), promote it to permanent project memory.
|
||||
|
||||
### When to Promote
|
||||
|
||||
- Learning applies across multiple files/features
|
||||
- Knowledge any contributor (human or AI) should know
|
||||
- Prevents recurring mistakes
|
||||
- Documents project-specific conventions
|
||||
|
||||
### Promotion Targets
|
||||
|
||||
| Target | What Belongs There |
|
||||
|--------|-------------------|
|
||||
| `CLAUDE.md` | Project facts, conventions, gotchas for all Claude interactions |
|
||||
| `AGENTS.md` | Agent-specific workflows, tool usage patterns, automation rules |
|
||||
| `.github/copilot-instructions.md` | Project context and conventions for GitHub Copilot |
|
||||
| `SOUL.md` | Behavioral guidelines, communication style, principles (OpenClaw workspace) |
|
||||
| `TOOLS.md` | Tool capabilities, usage patterns, integration gotchas (OpenClaw workspace) |
|
||||
|
||||
### How to Promote
|
||||
|
||||
1. **Distill** the learning into a concise rule or fact
|
||||
2. **Add** to appropriate section in target file (create file if needed)
|
||||
3. **Update** original entry:
|
||||
- Change `**Status**: pending` → `**Status**: promoted`
|
||||
- Add `**Promoted**: CLAUDE.md`, `AGENTS.md`, or `.github/copilot-instructions.md`
|
||||
|
||||
### Promotion Examples
|
||||
|
||||
**Learning** (verbose):
|
||||
> Project uses pnpm workspaces. Attempted `npm install` but failed.
|
||||
> Lock file is `pnpm-lock.yaml`. Must use `pnpm install`.
|
||||
|
||||
**In CLAUDE.md** (concise):
|
||||
```markdown
|
||||
## Build & Dependencies
|
||||
- Package manager: pnpm (not npm) - use `pnpm install`
|
||||
```
|
||||
|
||||
**Learning** (verbose):
|
||||
> When modifying API endpoints, must regenerate TypeScript client.
|
||||
> Forgetting this causes type mismatches at runtime.
|
||||
|
||||
**In AGENTS.md** (actionable):
|
||||
```markdown
|
||||
## After API Changes
|
||||
1. Regenerate client: `pnpm run generate:api`
|
||||
2. Check for type errors: `pnpm tsc --noEmit`
|
||||
```
|
||||
|
||||
## Recurring Pattern Detection
|
||||
|
||||
If logging something similar to an existing entry:
|
||||
|
||||
1. **Search first**: `grep -r "keyword" .learnings/`
|
||||
2. **Link entries**: Add `**See Also**: ERR-20250110-001` in Metadata
|
||||
3. **Bump priority** if issue keeps recurring
|
||||
4. **Consider systemic fix**: Recurring issues often indicate:
|
||||
- Missing documentation (→ promote to CLAUDE.md or .github/copilot-instructions.md)
|
||||
- Missing automation (→ add to AGENTS.md)
|
||||
- Architectural problem (→ create tech debt ticket)
|
||||
|
||||
## Simplify & Harden Feed
|
||||
|
||||
Use this workflow to ingest recurring patterns from the `simplify-and-harden`
|
||||
skill and turn them into durable prompt guidance.
|
||||
|
||||
### Ingestion Workflow
|
||||
|
||||
1. Read `simplify_and_harden.learning_loop.candidates` from the task summary.
|
||||
2. For each candidate, use `pattern_key` as the stable dedupe key.
|
||||
3. Search `.learnings/LEARNINGS.md` for an existing entry with that key:
|
||||
- `grep -n "Pattern-Key: <pattern_key>" .learnings/LEARNINGS.md`
|
||||
4. If found:
|
||||
- Increment `Recurrence-Count`
|
||||
- Update `Last-Seen`
|
||||
- Add `See Also` links to related entries/tasks
|
||||
5. If not found:
|
||||
- Create a new `LRN-...` entry
|
||||
- Set `Source: simplify-and-harden`
|
||||
- Set `Pattern-Key`, `Recurrence-Count: 1`, and `First-Seen`/`Last-Seen`
|
||||
|
||||
### Promotion Rule (System Prompt Feedback)
|
||||
|
||||
Promote recurring patterns into agent context/system prompt files when all are true:
|
||||
|
||||
- `Recurrence-Count >= 3`
|
||||
- Seen across at least 2 distinct tasks
|
||||
- Occurred within a 30-day window
|
||||
|
||||
Promotion targets:
|
||||
- `CLAUDE.md`
|
||||
- `AGENTS.md`
|
||||
- `.github/copilot-instructions.md`
|
||||
- `SOUL.md` / `TOOLS.md` for OpenClaw workspace-level guidance when applicable
|
||||
|
||||
Write promoted rules as short prevention rules (what to do before/while coding),
|
||||
not long incident write-ups.
|
||||
|
||||
## Periodic Review
|
||||
|
||||
Review `.learnings/` at natural breakpoints:
|
||||
|
||||
### When to Review
|
||||
- Before starting a new major task
|
||||
- After completing a feature
|
||||
- When working in an area with past learnings
|
||||
- Weekly during active development
|
||||
|
||||
### Quick Status Check
|
||||
```bash
|
||||
# Count pending items
|
||||
grep -h "Status\*\*: pending" .learnings/*.md | wc -l
|
||||
|
||||
# List pending high-priority items
|
||||
grep -B5 "Priority\*\*: high" .learnings/*.md | grep "^## \["
|
||||
|
||||
# Find learnings for a specific area
|
||||
grep -l "Area\*\*: backend" .learnings/*.md
|
||||
```
|
||||
|
||||
### Review Actions
|
||||
- Resolve fixed items
|
||||
- Promote applicable learnings
|
||||
- Link related entries
|
||||
- Escalate recurring issues
|
||||
|
||||
## Detection Triggers
|
||||
|
||||
Automatically log when you notice:
|
||||
|
||||
**Corrections** (→ learning with `correction` category):
|
||||
- "No, that's not right..."
|
||||
- "Actually, it should be..."
|
||||
- "You're wrong about..."
|
||||
- "That's outdated..."
|
||||
|
||||
**Feature Requests** (→ feature request):
|
||||
- "Can you also..."
|
||||
- "I wish you could..."
|
||||
- "Is there a way to..."
|
||||
- "Why can't you..."
|
||||
|
||||
**Knowledge Gaps** (→ learning with `knowledge_gap` category):
|
||||
- User provides information you didn't know
|
||||
- Documentation you referenced is outdated
|
||||
- API behavior differs from your understanding
|
||||
|
||||
**Errors** (→ error entry):
|
||||
- Command returns non-zero exit code
|
||||
- Exception or stack trace
|
||||
- Unexpected output or behavior
|
||||
- Timeout or connection failure
|
||||
|
||||
## Priority Guidelines
|
||||
|
||||
| Priority | When to Use |
|
||||
|----------|-------------|
|
||||
| `critical` | Blocks core functionality, data loss risk, security issue |
|
||||
| `high` | Significant impact, affects common workflows, recurring issue |
|
||||
| `medium` | Moderate impact, workaround exists |
|
||||
| `low` | Minor inconvenience, edge case, nice-to-have |
|
||||
|
||||
## Area Tags
|
||||
|
||||
Use to filter learnings by codebase region:
|
||||
|
||||
| Area | Scope |
|
||||
|------|-------|
|
||||
| `frontend` | UI, components, client-side code |
|
||||
| `backend` | API, services, server-side code |
|
||||
| `infra` | CI/CD, deployment, Docker, cloud |
|
||||
| `tests` | Test files, testing utilities, coverage |
|
||||
| `docs` | Documentation, comments, READMEs |
|
||||
| `config` | Configuration files, environment, settings |
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Log immediately** - context is freshest right after the issue
|
||||
2. **Be specific** - future agents need to understand quickly
|
||||
3. **Include reproduction steps** - especially for errors
|
||||
4. **Link related files** - makes fixes easier
|
||||
5. **Suggest concrete fixes** - not just "investigate"
|
||||
6. **Use consistent categories** - enables filtering
|
||||
7. **Promote aggressively** - if in doubt, add to CLAUDE.md or .github/copilot-instructions.md
|
||||
8. **Review regularly** - stale learnings lose value
|
||||
|
||||
## Gitignore Options
|
||||
|
||||
**Keep learnings local** (per-developer):
|
||||
```gitignore
|
||||
.learnings/
|
||||
```
|
||||
|
||||
**Track learnings in repo** (team-wide):
|
||||
Don't add to .gitignore - learnings become shared knowledge.
|
||||
|
||||
**Hybrid** (track templates, ignore entries):
|
||||
```gitignore
|
||||
.learnings/*.md
|
||||
!.learnings/.gitkeep
|
||||
```
|
||||
|
||||
## Hook Integration
|
||||
|
||||
Enable automatic reminders through agent hooks. This is **opt-in** - you must explicitly configure hooks.
|
||||
|
||||
### Quick Setup (Claude Code / Codex)
|
||||
|
||||
Create `.claude/settings.json` in your project:
|
||||
|
||||
```json
|
||||
{
|
||||
"hooks": {
|
||||
"UserPromptSubmit": [{
|
||||
"matcher": "",
|
||||
"hooks": [{
|
||||
"type": "command",
|
||||
"command": "./skills/self-improvement/scripts/activator.sh"
|
||||
}]
|
||||
}]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
This injects a learning evaluation reminder after each prompt (~50-100 tokens overhead).
|
||||
|
||||
### Full Setup (With Error Detection)
|
||||
|
||||
```json
|
||||
{
|
||||
"hooks": {
|
||||
"UserPromptSubmit": [{
|
||||
"matcher": "",
|
||||
"hooks": [{
|
||||
"type": "command",
|
||||
"command": "./skills/self-improvement/scripts/activator.sh"
|
||||
}]
|
||||
}],
|
||||
"PostToolUse": [{
|
||||
"matcher": "Bash",
|
||||
"hooks": [{
|
||||
"type": "command",
|
||||
"command": "./skills/self-improvement/scripts/error-detector.sh"
|
||||
}]
|
||||
}]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Available Hook Scripts
|
||||
|
||||
| Script | Hook Type | Purpose |
|
||||
|--------|-----------|---------|
|
||||
| `scripts/activator.sh` | UserPromptSubmit | Reminds to evaluate learnings after tasks |
|
||||
| `scripts/error-detector.sh` | PostToolUse (Bash) | Triggers on command errors |
|
||||
|
||||
See `references/hooks-setup.md` for detailed configuration and troubleshooting.
|
||||
|
||||
## Automatic Skill Extraction
|
||||
|
||||
When a learning is valuable enough to become a reusable skill, extract it using the provided helper.
|
||||
|
||||
### Skill Extraction Criteria
|
||||
|
||||
A learning qualifies for skill extraction when ANY of these apply:
|
||||
|
||||
| Criterion | Description |
|
||||
|-----------|-------------|
|
||||
| **Recurring** | Has `See Also` links to 2+ similar issues |
|
||||
| **Verified** | Status is `resolved` with working fix |
|
||||
| **Non-obvious** | Required actual debugging/investigation to discover |
|
||||
| **Broadly applicable** | Not project-specific; useful across codebases |
|
||||
| **User-flagged** | User says "save this as a skill" or similar |
|
||||
|
||||
### Extraction Workflow
|
||||
|
||||
1. **Identify candidate**: Learning meets extraction criteria
|
||||
2. **Run helper** (or create manually):
|
||||
```bash
|
||||
./skills/self-improvement/scripts/extract-skill.sh skill-name --dry-run
|
||||
./skills/self-improvement/scripts/extract-skill.sh skill-name
|
||||
```
|
||||
3. **Customize SKILL.md**: Fill in template with learning content
|
||||
4. **Update learning**: Set status to `promoted_to_skill`, add `Skill-Path`
|
||||
5. **Verify**: Read skill in fresh session to ensure it's self-contained
|
||||
|
||||
### Manual Extraction
|
||||
|
||||
If you prefer manual creation:
|
||||
|
||||
1. Create `skills/<skill-name>/SKILL.md`
|
||||
2. Use template from `assets/SKILL-TEMPLATE.md`
|
||||
3. Follow [Agent Skills spec](https://agentskills.io/specification):
|
||||
- YAML frontmatter with `name` and `description`
|
||||
- Name must match folder name
|
||||
- No README.md inside skill folder
|
||||
|
||||
### Extraction Detection Triggers
|
||||
|
||||
Watch for these signals that a learning should become a skill:
|
||||
|
||||
**In conversation:**
|
||||
- "Save this as a skill"
|
||||
- "I keep running into this"
|
||||
- "This would be useful for other projects"
|
||||
- "Remember this pattern"
|
||||
|
||||
**In learning entries:**
|
||||
- Multiple `See Also` links (recurring issue)
|
||||
- High priority + resolved status
|
||||
- Category: `best_practice` with broad applicability
|
||||
- User feedback praising the solution
|
||||
|
||||
### Skill Quality Gates
|
||||
|
||||
Before extraction, verify:
|
||||
|
||||
- [ ] Solution is tested and working
|
||||
- [ ] Description is clear without original context
|
||||
- [ ] Code examples are self-contained
|
||||
- [ ] No project-specific hardcoded values
|
||||
- [ ] Follows skill naming conventions (lowercase, hyphens)
|
||||
|
||||
## Multi-Agent Support
|
||||
|
||||
This skill works across different AI coding agents with agent-specific activation.
|
||||
|
||||
### Claude Code
|
||||
|
||||
**Activation**: Hooks (UserPromptSubmit, PostToolUse)
|
||||
**Setup**: `.claude/settings.json` with hook configuration
|
||||
**Detection**: Automatic via hook scripts
|
||||
|
||||
### Codex CLI
|
||||
|
||||
**Activation**: Hooks (same pattern as Claude Code)
|
||||
**Setup**: `.codex/settings.json` with hook configuration
|
||||
**Detection**: Automatic via hook scripts
|
||||
|
||||
### GitHub Copilot
|
||||
|
||||
**Activation**: Manual (no hook support)
|
||||
**Setup**: Add to `.github/copilot-instructions.md`:
|
||||
|
||||
```markdown
|
||||
## Self-Improvement
|
||||
|
||||
After solving non-obvious issues, consider logging to `.learnings/`:
|
||||
1. Use format from self-improvement skill
|
||||
2. Link related entries with See Also
|
||||
3. Promote high-value learnings to skills
|
||||
|
||||
Ask in chat: "Should I log this as a learning?"
|
||||
```
|
||||
|
||||
**Detection**: Manual review at session end
|
||||
|
||||
### OpenClaw
|
||||
|
||||
**Activation**: Workspace injection + inter-agent messaging
|
||||
**Setup**: See "OpenClaw Setup" section above
|
||||
**Detection**: Via session tools and workspace files
|
||||
|
||||
### Agent-Agnostic Guidance
|
||||
|
||||
Regardless of agent, apply self-improvement when you:
|
||||
|
||||
1. **Discover something non-obvious** - solution wasn't immediate
|
||||
2. **Correct yourself** - initial approach was wrong
|
||||
3. **Learn project conventions** - discovered undocumented patterns
|
||||
4. **Hit unexpected errors** - especially if diagnosis was difficult
|
||||
5. **Find better approaches** - improved on your original solution
|
||||
|
||||
### Copilot Chat Integration
|
||||
|
||||
For Copilot users, add this to your prompts when relevant:
|
||||
|
||||
> After completing this task, evaluate if any learnings should be logged to `.learnings/` using the self-improvement skill format.
|
||||
|
||||
Or use quick prompts:
|
||||
- "Log this to learnings"
|
||||
- "Create a skill from this solution"
|
||||
- "Check .learnings/ for related issues"
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"owner": "china-mobile2008",
|
||||
"slug": "12",
|
||||
"displayName": "321",
|
||||
"latest": {
|
||||
"version": "1.0.1",
|
||||
"publishedAt": 1773893490362,
|
||||
"commit": "https://github.com/openclaw/skills/commit/1e9f2b48fd7c399205c8208e0e8ed4bff5139f5e"
|
||||
},
|
||||
"history": []
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
# Learnings
|
||||
|
||||
Corrections, insights, and knowledge gaps captured during development.
|
||||
|
||||
**Categories**: correction | insight | knowledge_gap | best_practice
|
||||
**Areas**: frontend | backend | infra | tests | docs | config
|
||||
**Statuses**: pending | in_progress | resolved | wont_fix | promoted | promoted_to_skill
|
||||
|
||||
## Status Definitions
|
||||
|
||||
| Status | Meaning |
|
||||
|--------|---------|
|
||||
| `pending` | Not yet addressed |
|
||||
| `in_progress` | Actively being worked on |
|
||||
| `resolved` | Issue fixed or knowledge integrated |
|
||||
| `wont_fix` | Decided not to address (reason in Resolution) |
|
||||
| `promoted` | Elevated to CLAUDE.md, AGENTS.md, or copilot-instructions.md |
|
||||
| `promoted_to_skill` | Extracted as a reusable skill |
|
||||
|
||||
## Skill Extraction Fields
|
||||
|
||||
When a learning is promoted to a skill, add these fields:
|
||||
|
||||
```markdown
|
||||
**Status**: promoted_to_skill
|
||||
**Skill-Path**: skills/skill-name
|
||||
```
|
||||
|
||||
Example:
|
||||
```markdown
|
||||
## [LRN-20250115-001] best_practice
|
||||
|
||||
**Logged**: 2025-01-15T10:00:00Z
|
||||
**Priority**: high
|
||||
**Status**: promoted_to_skill
|
||||
**Skill-Path**: skills/docker-m1-fixes
|
||||
**Area**: infra
|
||||
|
||||
### Summary
|
||||
Docker build fails on Apple Silicon due to platform mismatch
|
||||
...
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -0,0 +1,177 @@
|
||||
# Skill Template
|
||||
|
||||
Template for creating skills extracted from learnings. Copy and customize.
|
||||
|
||||
---
|
||||
|
||||
## SKILL.md Template
|
||||
|
||||
```markdown
|
||||
---
|
||||
name: skill-name-here
|
||||
description: "Concise description of when and why to use this skill. Include trigger conditions."
|
||||
---
|
||||
|
||||
# Skill Name
|
||||
|
||||
Brief introduction explaining the problem this skill solves and its origin.
|
||||
|
||||
## Quick Reference
|
||||
|
||||
| Situation | Action |
|
||||
|-----------|--------|
|
||||
| [Trigger 1] | [Action 1] |
|
||||
| [Trigger 2] | [Action 2] |
|
||||
|
||||
## Background
|
||||
|
||||
Why this knowledge matters. What problems it prevents. Context from the original learning.
|
||||
|
||||
## Solution
|
||||
|
||||
### Step-by-Step
|
||||
|
||||
1. First step with code or command
|
||||
2. Second step
|
||||
3. Verification step
|
||||
|
||||
### Code Example
|
||||
|
||||
\`\`\`language
|
||||
// Example code demonstrating the solution
|
||||
\`\`\`
|
||||
|
||||
## Common Variations
|
||||
|
||||
- **Variation A**: Description and how to handle
|
||||
- **Variation B**: Description and how to handle
|
||||
|
||||
## Gotchas
|
||||
|
||||
- Warning or common mistake #1
|
||||
- Warning or common mistake #2
|
||||
|
||||
## Related
|
||||
|
||||
- Link to related documentation
|
||||
- Link to related skill
|
||||
|
||||
## Source
|
||||
|
||||
Extracted from learning entry.
|
||||
- **Learning ID**: LRN-YYYYMMDD-XXX
|
||||
- **Original Category**: correction | insight | knowledge_gap | best_practice
|
||||
- **Extraction Date**: YYYY-MM-DD
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Minimal Template
|
||||
|
||||
For simple skills that don't need all sections:
|
||||
|
||||
```markdown
|
||||
---
|
||||
name: skill-name-here
|
||||
description: "What this skill does and when to use it."
|
||||
---
|
||||
|
||||
# Skill Name
|
||||
|
||||
[Problem statement in one sentence]
|
||||
|
||||
## Solution
|
||||
|
||||
[Direct solution with code/commands]
|
||||
|
||||
## Source
|
||||
|
||||
- Learning ID: LRN-YYYYMMDD-XXX
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Template with Scripts
|
||||
|
||||
For skills that include executable helpers:
|
||||
|
||||
```markdown
|
||||
---
|
||||
name: skill-name-here
|
||||
description: "What this skill does and when to use it."
|
||||
---
|
||||
|
||||
# Skill Name
|
||||
|
||||
[Introduction]
|
||||
|
||||
## Quick Reference
|
||||
|
||||
| Command | Purpose |
|
||||
|---------|---------|
|
||||
| `./scripts/helper.sh` | [What it does] |
|
||||
| `./scripts/validate.sh` | [What it does] |
|
||||
|
||||
## Usage
|
||||
|
||||
### Automated (Recommended)
|
||||
|
||||
\`\`\`bash
|
||||
./skills/skill-name/scripts/helper.sh [args]
|
||||
\`\`\`
|
||||
|
||||
### Manual Steps
|
||||
|
||||
1. Step one
|
||||
2. Step two
|
||||
|
||||
## Scripts
|
||||
|
||||
| Script | Description |
|
||||
|--------|-------------|
|
||||
| `scripts/helper.sh` | Main utility |
|
||||
| `scripts/validate.sh` | Validation checker |
|
||||
|
||||
## Source
|
||||
|
||||
- Learning ID: LRN-YYYYMMDD-XXX
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Naming Conventions
|
||||
|
||||
- **Skill name**: lowercase, hyphens for spaces
|
||||
- Good: `docker-m1-fixes`, `api-timeout-patterns`
|
||||
- Bad: `Docker_M1_Fixes`, `APITimeoutPatterns`
|
||||
|
||||
- **Description**: Start with action verb, mention trigger
|
||||
- Good: "Handles Docker build failures on Apple Silicon. Use when builds fail with platform mismatch."
|
||||
- Bad: "Docker stuff"
|
||||
|
||||
- **Files**:
|
||||
- `SKILL.md` - Required, main documentation
|
||||
- `scripts/` - Optional, executable code
|
||||
- `references/` - Optional, detailed docs
|
||||
- `assets/` - Optional, templates
|
||||
|
||||
---
|
||||
|
||||
## Extraction Checklist
|
||||
|
||||
Before creating a skill from a learning:
|
||||
|
||||
- [ ] Learning is verified (status: resolved)
|
||||
- [ ] Solution is broadly applicable (not one-off)
|
||||
- [ ] Content is complete (has all needed context)
|
||||
- [ ] Name follows conventions
|
||||
- [ ] Description is concise but informative
|
||||
- [ ] Quick Reference table is actionable
|
||||
- [ ] Code examples are tested
|
||||
- [ ] Source learning ID is recorded
|
||||
|
||||
After creating:
|
||||
|
||||
- [ ] Update original learning with `promoted_to_skill` status
|
||||
- [ ] Add `Skill-Path: skills/skill-name` to learning metadata
|
||||
- [ ] Test skill by reading it in a fresh session
|
||||
@@ -0,0 +1,23 @@
|
||||
---
|
||||
name: self-improvement
|
||||
description: "Injects self-improvement reminder during agent bootstrap"
|
||||
metadata: {"openclaw":{"emoji":"🧠","events":["agent:bootstrap"]}}
|
||||
---
|
||||
|
||||
# Self-Improvement Hook
|
||||
|
||||
Injects a reminder to evaluate learnings during agent bootstrap.
|
||||
|
||||
## What It Does
|
||||
|
||||
- Fires on `agent:bootstrap` (before workspace files are injected)
|
||||
- Adds a reminder block to check `.learnings/` for relevant entries
|
||||
- Prompts the agent to log corrections, errors, and discoveries
|
||||
|
||||
## Configuration
|
||||
|
||||
No configuration needed. Enable with:
|
||||
|
||||
```bash
|
||||
openclaw hooks enable self-improvement
|
||||
```
|
||||
@@ -0,0 +1,56 @@
|
||||
/**
|
||||
* Self-Improvement Hook for OpenClaw
|
||||
*
|
||||
* Injects a reminder to evaluate learnings during agent bootstrap.
|
||||
* Fires on agent:bootstrap event before workspace files are injected.
|
||||
*/
|
||||
|
||||
const REMINDER_CONTENT = `
|
||||
## Self-Improvement Reminder
|
||||
|
||||
After completing tasks, evaluate if any learnings should be captured:
|
||||
|
||||
**Log when:**
|
||||
- User corrects you → \`.learnings/LEARNINGS.md\`
|
||||
- Command/operation fails → \`.learnings/ERRORS.md\`
|
||||
- User wants missing capability → \`.learnings/FEATURE_REQUESTS.md\`
|
||||
- You discover your knowledge was wrong → \`.learnings/LEARNINGS.md\`
|
||||
- You find a better approach → \`.learnings/LEARNINGS.md\`
|
||||
|
||||
**Promote when pattern is proven:**
|
||||
- Behavioral patterns → \`SOUL.md\`
|
||||
- Workflow improvements → \`AGENTS.md\`
|
||||
- Tool gotchas → \`TOOLS.md\`
|
||||
|
||||
Keep entries simple: date, title, what happened, what to do differently.
|
||||
`.trim();
|
||||
|
||||
const handler = async (event) => {
|
||||
// Safety checks for event structure
|
||||
if (!event || typeof event !== 'object') {
|
||||
return;
|
||||
}
|
||||
|
||||
// Only handle agent:bootstrap events
|
||||
if (event.type !== 'agent' || event.action !== 'bootstrap') {
|
||||
return;
|
||||
}
|
||||
|
||||
// Safety check for context
|
||||
if (!event.context || typeof event.context !== 'object') {
|
||||
return;
|
||||
}
|
||||
|
||||
// Inject the reminder as a virtual bootstrap file
|
||||
// Check that bootstrapFiles is an array before pushing
|
||||
if (Array.isArray(event.context.bootstrapFiles)) {
|
||||
event.context.bootstrapFiles.push({
|
||||
path: 'SELF_IMPROVEMENT_REMINDER.md',
|
||||
content: REMINDER_CONTENT,
|
||||
virtual: true,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = handler;
|
||||
module.exports.default = handler;
|
||||
@@ -0,0 +1,62 @@
|
||||
/**
|
||||
* Self-Improvement Hook for OpenClaw
|
||||
*
|
||||
* Injects a reminder to evaluate learnings during agent bootstrap.
|
||||
* Fires on agent:bootstrap event before workspace files are injected.
|
||||
*/
|
||||
|
||||
import type { HookHandler } from 'openclaw/hooks';
|
||||
|
||||
const REMINDER_CONTENT = `## Self-Improvement Reminder
|
||||
|
||||
After completing tasks, evaluate if any learnings should be captured:
|
||||
|
||||
**Log when:**
|
||||
- User corrects you → \`.learnings/LEARNINGS.md\`
|
||||
- Command/operation fails → \`.learnings/ERRORS.md\`
|
||||
- User wants missing capability → \`.learnings/FEATURE_REQUESTS.md\`
|
||||
- You discover your knowledge was wrong → \`.learnings/LEARNINGS.md\`
|
||||
- You find a better approach → \`.learnings/LEARNINGS.md\`
|
||||
|
||||
**Promote when pattern is proven:**
|
||||
- Behavioral patterns → \`SOUL.md\`
|
||||
- Workflow improvements → \`AGENTS.md\`
|
||||
- Tool gotchas → \`TOOLS.md\`
|
||||
|
||||
Keep entries simple: date, title, what happened, what to do differently.`;
|
||||
|
||||
const handler: HookHandler = async (event) => {
|
||||
// Safety checks for event structure
|
||||
if (!event || typeof event !== 'object') {
|
||||
return;
|
||||
}
|
||||
|
||||
// Only handle agent:bootstrap events
|
||||
if (event.type !== 'agent' || event.action !== 'bootstrap') {
|
||||
return;
|
||||
}
|
||||
|
||||
// Safety check for context
|
||||
if (!event.context || typeof event.context !== 'object') {
|
||||
return;
|
||||
}
|
||||
|
||||
// Skip sub-agent sessions to avoid bootstrap issues
|
||||
// Sub-agents have sessionKey patterns like "agent:main:subagent:..."
|
||||
const sessionKey = event.sessionKey || '';
|
||||
if (sessionKey.includes(':subagent:')) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Inject the reminder as a virtual bootstrap file
|
||||
// Check that bootstrapFiles is an array before pushing
|
||||
if (Array.isArray(event.context.bootstrapFiles)) {
|
||||
event.context.bootstrapFiles.push({
|
||||
path: 'SELF_IMPROVEMENT_REMINDER.md',
|
||||
content: REMINDER_CONTENT,
|
||||
virtual: true,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export default handler;
|
||||
@@ -0,0 +1,374 @@
|
||||
# Entry Examples
|
||||
|
||||
Concrete examples of well-formatted entries with all fields.
|
||||
|
||||
## Learning: Correction
|
||||
|
||||
```markdown
|
||||
## [LRN-20250115-001] correction
|
||||
|
||||
**Logged**: 2025-01-15T10:30:00Z
|
||||
**Priority**: high
|
||||
**Status**: pending
|
||||
**Area**: tests
|
||||
|
||||
### Summary
|
||||
Incorrectly assumed pytest fixtures are scoped to function by default
|
||||
|
||||
### Details
|
||||
When writing test fixtures, I assumed all fixtures were function-scoped.
|
||||
User corrected that while function scope is the default, the codebase
|
||||
convention uses module-scoped fixtures for database connections to
|
||||
improve test performance.
|
||||
|
||||
### Suggested Action
|
||||
When creating fixtures that involve expensive setup (DB, network),
|
||||
check existing fixtures for scope patterns before defaulting to function scope.
|
||||
|
||||
### Metadata
|
||||
- Source: user_feedback
|
||||
- Related Files: tests/conftest.py
|
||||
- Tags: pytest, testing, fixtures
|
||||
|
||||
---
|
||||
```
|
||||
|
||||
## Learning: Knowledge Gap (Resolved)
|
||||
|
||||
```markdown
|
||||
## [LRN-20250115-002] knowledge_gap
|
||||
|
||||
**Logged**: 2025-01-15T14:22:00Z
|
||||
**Priority**: medium
|
||||
**Status**: resolved
|
||||
**Area**: config
|
||||
|
||||
### Summary
|
||||
Project uses pnpm not npm for package management
|
||||
|
||||
### Details
|
||||
Attempted to run `npm install` but project uses pnpm workspaces.
|
||||
Lock file is `pnpm-lock.yaml`, not `package-lock.json`.
|
||||
|
||||
### Suggested Action
|
||||
Check for `pnpm-lock.yaml` or `pnpm-workspace.yaml` before assuming npm.
|
||||
Use `pnpm install` for this project.
|
||||
|
||||
### Metadata
|
||||
- Source: error
|
||||
- Related Files: pnpm-lock.yaml, pnpm-workspace.yaml
|
||||
- Tags: package-manager, pnpm, setup
|
||||
|
||||
### Resolution
|
||||
- **Resolved**: 2025-01-15T14:30:00Z
|
||||
- **Commit/PR**: N/A - knowledge update
|
||||
- **Notes**: Added to CLAUDE.md for future reference
|
||||
|
||||
---
|
||||
```
|
||||
|
||||
## Learning: Promoted to CLAUDE.md
|
||||
|
||||
```markdown
|
||||
## [LRN-20250115-003] best_practice
|
||||
|
||||
**Logged**: 2025-01-15T16:00:00Z
|
||||
**Priority**: high
|
||||
**Status**: promoted
|
||||
**Promoted**: CLAUDE.md
|
||||
**Area**: backend
|
||||
|
||||
### Summary
|
||||
API responses must include correlation ID from request headers
|
||||
|
||||
### Details
|
||||
All API responses should echo back the X-Correlation-ID header from
|
||||
the request. This is required for distributed tracing. Responses
|
||||
without this header break the observability pipeline.
|
||||
|
||||
### Suggested Action
|
||||
Always include correlation ID passthrough in API handlers.
|
||||
|
||||
### Metadata
|
||||
- Source: user_feedback
|
||||
- Related Files: src/middleware/correlation.ts
|
||||
- Tags: api, observability, tracing
|
||||
|
||||
---
|
||||
```
|
||||
|
||||
## Learning: Promoted to AGENTS.md
|
||||
|
||||
```markdown
|
||||
## [LRN-20250116-001] best_practice
|
||||
|
||||
**Logged**: 2025-01-16T09:00:00Z
|
||||
**Priority**: high
|
||||
**Status**: promoted
|
||||
**Promoted**: AGENTS.md
|
||||
**Area**: backend
|
||||
|
||||
### Summary
|
||||
Must regenerate API client after OpenAPI spec changes
|
||||
|
||||
### Details
|
||||
When modifying API endpoints, the TypeScript client must be regenerated.
|
||||
Forgetting this causes type mismatches that only appear at runtime.
|
||||
The generate script also runs validation.
|
||||
|
||||
### Suggested Action
|
||||
Add to agent workflow: after any API changes, run `pnpm run generate:api`.
|
||||
|
||||
### Metadata
|
||||
- Source: error
|
||||
- Related Files: openapi.yaml, src/client/api.ts
|
||||
- Tags: api, codegen, typescript
|
||||
|
||||
---
|
||||
```
|
||||
|
||||
## Error Entry
|
||||
|
||||
```markdown
|
||||
## [ERR-20250115-A3F] docker_build
|
||||
|
||||
**Logged**: 2025-01-15T09:15:00Z
|
||||
**Priority**: high
|
||||
**Status**: pending
|
||||
**Area**: infra
|
||||
|
||||
### Summary
|
||||
Docker build fails on M1 Mac due to platform mismatch
|
||||
|
||||
### Error
|
||||
```
|
||||
error: failed to solve: python:3.11-slim: no match for platform linux/arm64
|
||||
```
|
||||
|
||||
### Context
|
||||
- Command: `docker build -t myapp .`
|
||||
- Dockerfile uses `FROM python:3.11-slim`
|
||||
- Running on Apple Silicon (M1/M2)
|
||||
|
||||
### Suggested Fix
|
||||
Add platform flag: `docker build --platform linux/amd64 -t myapp .`
|
||||
Or update Dockerfile: `FROM --platform=linux/amd64 python:3.11-slim`
|
||||
|
||||
### Metadata
|
||||
- Reproducible: yes
|
||||
- Related Files: Dockerfile
|
||||
|
||||
---
|
||||
```
|
||||
|
||||
## Error Entry: Recurring Issue
|
||||
|
||||
```markdown
|
||||
## [ERR-20250120-B2C] api_timeout
|
||||
|
||||
**Logged**: 2025-01-20T11:30:00Z
|
||||
**Priority**: critical
|
||||
**Status**: pending
|
||||
**Area**: backend
|
||||
|
||||
### Summary
|
||||
Third-party payment API timeout during checkout
|
||||
|
||||
### Error
|
||||
```
|
||||
TimeoutError: Request to payments.example.com timed out after 30000ms
|
||||
```
|
||||
|
||||
### Context
|
||||
- Command: POST /api/checkout
|
||||
- Timeout set to 30s
|
||||
- Occurs during peak hours (lunch, evening)
|
||||
|
||||
### Suggested Fix
|
||||
Implement retry with exponential backoff. Consider circuit breaker pattern.
|
||||
|
||||
### Metadata
|
||||
- Reproducible: yes (during peak hours)
|
||||
- Related Files: src/services/payment.ts
|
||||
- See Also: ERR-20250115-X1Y, ERR-20250118-Z3W
|
||||
|
||||
---
|
||||
```
|
||||
|
||||
## Feature Request
|
||||
|
||||
```markdown
|
||||
## [FEAT-20250115-001] export_to_csv
|
||||
|
||||
**Logged**: 2025-01-15T16:45:00Z
|
||||
**Priority**: medium
|
||||
**Status**: pending
|
||||
**Area**: backend
|
||||
|
||||
### Requested Capability
|
||||
Export analysis results to CSV format
|
||||
|
||||
### User Context
|
||||
User runs weekly reports and needs to share results with non-technical
|
||||
stakeholders in Excel. Currently copies output manually.
|
||||
|
||||
### Complexity Estimate
|
||||
simple
|
||||
|
||||
### Suggested Implementation
|
||||
Add `--output csv` flag to the analyze command. Use standard csv module.
|
||||
Could extend existing `--output json` pattern.
|
||||
|
||||
### Metadata
|
||||
- Frequency: recurring
|
||||
- Related Features: analyze command, json output
|
||||
|
||||
---
|
||||
```
|
||||
|
||||
## Feature Request: Resolved
|
||||
|
||||
```markdown
|
||||
## [FEAT-20250110-002] dark_mode
|
||||
|
||||
**Logged**: 2025-01-10T14:00:00Z
|
||||
**Priority**: low
|
||||
**Status**: resolved
|
||||
**Area**: frontend
|
||||
|
||||
### Requested Capability
|
||||
Dark mode support for the dashboard
|
||||
|
||||
### User Context
|
||||
User works late hours and finds the bright interface straining.
|
||||
Several other users have mentioned this informally.
|
||||
|
||||
### Complexity Estimate
|
||||
medium
|
||||
|
||||
### Suggested Implementation
|
||||
Use CSS variables for colors. Add toggle in user settings.
|
||||
Consider system preference detection.
|
||||
|
||||
### Metadata
|
||||
- Frequency: recurring
|
||||
- Related Features: user settings, theme system
|
||||
|
||||
### Resolution
|
||||
- **Resolved**: 2025-01-18T16:00:00Z
|
||||
- **Commit/PR**: #142
|
||||
- **Notes**: Implemented with system preference detection and manual toggle
|
||||
|
||||
---
|
||||
```
|
||||
|
||||
## Learning: Promoted to Skill
|
||||
|
||||
```markdown
|
||||
## [LRN-20250118-001] best_practice
|
||||
|
||||
**Logged**: 2025-01-18T11:00:00Z
|
||||
**Priority**: high
|
||||
**Status**: promoted_to_skill
|
||||
**Skill-Path**: skills/docker-m1-fixes
|
||||
**Area**: infra
|
||||
|
||||
### Summary
|
||||
Docker build fails on Apple Silicon due to platform mismatch
|
||||
|
||||
### Details
|
||||
When building Docker images on M1/M2 Macs, the build fails because
|
||||
the base image doesn't have an ARM64 variant. This is a common issue
|
||||
that affects many developers.
|
||||
|
||||
### Suggested Action
|
||||
Add `--platform linux/amd64` to docker build command, or use
|
||||
`FROM --platform=linux/amd64` in Dockerfile.
|
||||
|
||||
### Metadata
|
||||
- Source: error
|
||||
- Related Files: Dockerfile
|
||||
- Tags: docker, arm64, m1, apple-silicon
|
||||
- See Also: ERR-20250115-A3F, ERR-20250117-B2D
|
||||
|
||||
---
|
||||
```
|
||||
|
||||
## Extracted Skill Example
|
||||
|
||||
When the above learning is extracted as a skill, it becomes:
|
||||
|
||||
**File**: `skills/docker-m1-fixes/SKILL.md`
|
||||
|
||||
```markdown
|
||||
---
|
||||
name: docker-m1-fixes
|
||||
description: "Fixes Docker build failures on Apple Silicon (M1/M2). Use when docker build fails with platform mismatch errors."
|
||||
---
|
||||
|
||||
# Docker M1 Fixes
|
||||
|
||||
Solutions for Docker build issues on Apple Silicon Macs.
|
||||
|
||||
## Quick Reference
|
||||
|
||||
| Error | Fix |
|
||||
|-------|-----|
|
||||
| `no match for platform linux/arm64` | Add `--platform linux/amd64` to build |
|
||||
| Image runs but crashes | Use emulation or find ARM-compatible base |
|
||||
|
||||
## The Problem
|
||||
|
||||
Many Docker base images don't have ARM64 variants. When building on
|
||||
Apple Silicon (M1/M2/M3), Docker attempts to pull ARM64 images by
|
||||
default, causing platform mismatch errors.
|
||||
|
||||
## Solutions
|
||||
|
||||
### Option 1: Build Flag (Recommended)
|
||||
|
||||
Add platform flag to your build command:
|
||||
|
||||
\`\`\`bash
|
||||
docker build --platform linux/amd64 -t myapp .
|
||||
\`\`\`
|
||||
|
||||
### Option 2: Dockerfile Modification
|
||||
|
||||
Specify platform in the FROM instruction:
|
||||
|
||||
\`\`\`dockerfile
|
||||
FROM --platform=linux/amd64 python:3.11-slim
|
||||
\`\`\`
|
||||
|
||||
### Option 3: Docker Compose
|
||||
|
||||
Add platform to your service:
|
||||
|
||||
\`\`\`yaml
|
||||
services:
|
||||
app:
|
||||
platform: linux/amd64
|
||||
build: .
|
||||
\`\`\`
|
||||
|
||||
## Trade-offs
|
||||
|
||||
| Approach | Pros | Cons |
|
||||
|----------|------|------|
|
||||
| Build flag | No file changes | Must remember flag |
|
||||
| Dockerfile | Explicit, versioned | Affects all builds |
|
||||
| Compose | Convenient for dev | Requires compose |
|
||||
|
||||
## Performance Note
|
||||
|
||||
Running AMD64 images on ARM64 uses Rosetta 2 emulation. This works
|
||||
for development but may be slower. For production, find ARM-native
|
||||
alternatives when possible.
|
||||
|
||||
## Source
|
||||
|
||||
- Learning ID: LRN-20250118-001
|
||||
- Category: best_practice
|
||||
- Extraction Date: 2025-01-18
|
||||
```
|
||||
@@ -0,0 +1,223 @@
|
||||
# Hook Setup Guide
|
||||
|
||||
Configure automatic self-improvement triggers for AI coding agents.
|
||||
|
||||
## Overview
|
||||
|
||||
Hooks enable proactive learning capture by injecting reminders at key moments:
|
||||
- **UserPromptSubmit**: Reminder after each prompt to evaluate learnings
|
||||
- **PostToolUse (Bash)**: Error detection when commands fail
|
||||
|
||||
## Claude Code Setup
|
||||
|
||||
### Option 1: Project-Level Configuration
|
||||
|
||||
Create `.claude/settings.json` in your project root:
|
||||
|
||||
```json
|
||||
{
|
||||
"hooks": {
|
||||
"UserPromptSubmit": [
|
||||
{
|
||||
"matcher": "",
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "./skills/self-improvement/scripts/activator.sh"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"PostToolUse": [
|
||||
{
|
||||
"matcher": "Bash",
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "./skills/self-improvement/scripts/error-detector.sh"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Option 2: User-Level Configuration
|
||||
|
||||
Add to `~/.claude/settings.json` for global activation:
|
||||
|
||||
```json
|
||||
{
|
||||
"hooks": {
|
||||
"UserPromptSubmit": [
|
||||
{
|
||||
"matcher": "",
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "~/.claude/skills/self-improvement/scripts/activator.sh"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Minimal Setup (Activator Only)
|
||||
|
||||
For lower overhead, use only the UserPromptSubmit hook:
|
||||
|
||||
```json
|
||||
{
|
||||
"hooks": {
|
||||
"UserPromptSubmit": [
|
||||
{
|
||||
"matcher": "",
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "./skills/self-improvement/scripts/activator.sh"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Codex CLI Setup
|
||||
|
||||
Codex uses the same hook system as Claude Code. Create `.codex/settings.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"hooks": {
|
||||
"UserPromptSubmit": [
|
||||
{
|
||||
"matcher": "",
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "./skills/self-improvement/scripts/activator.sh"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## GitHub Copilot Setup
|
||||
|
||||
Copilot doesn't support hooks directly. Instead, add guidance to `.github/copilot-instructions.md`:
|
||||
|
||||
```markdown
|
||||
## Self-Improvement
|
||||
|
||||
After completing tasks that involved:
|
||||
- Debugging non-obvious issues
|
||||
- Discovering workarounds
|
||||
- Learning project-specific patterns
|
||||
- Resolving unexpected errors
|
||||
|
||||
Consider logging the learning to `.learnings/` using the format from the self-improvement skill.
|
||||
|
||||
For high-value learnings that would benefit other sessions, consider skill extraction.
|
||||
```
|
||||
|
||||
## Verification
|
||||
|
||||
### Test Activator Hook
|
||||
|
||||
1. Enable the hook configuration
|
||||
2. Start a new Claude Code session
|
||||
3. Send any prompt
|
||||
4. Verify you see `<self-improvement-reminder>` in the context
|
||||
|
||||
### Test Error Detector Hook
|
||||
|
||||
1. Enable PostToolUse hook for Bash
|
||||
2. Run a command that fails: `ls /nonexistent/path`
|
||||
3. Verify you see `<error-detected>` reminder
|
||||
|
||||
### Dry Run Extract Script
|
||||
|
||||
```bash
|
||||
./skills/self-improvement/scripts/extract-skill.sh test-skill --dry-run
|
||||
```
|
||||
|
||||
Expected output shows the skill scaffold that would be created.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Hook Not Triggering
|
||||
|
||||
1. **Check script permissions**: `chmod +x scripts/*.sh`
|
||||
2. **Verify path**: Use absolute paths or paths relative to project root
|
||||
3. **Check settings location**: Project vs user-level settings
|
||||
4. **Restart session**: Hooks are loaded at session start
|
||||
|
||||
### Permission Denied
|
||||
|
||||
```bash
|
||||
chmod +x ./skills/self-improvement/scripts/activator.sh
|
||||
chmod +x ./skills/self-improvement/scripts/error-detector.sh
|
||||
chmod +x ./skills/self-improvement/scripts/extract-skill.sh
|
||||
```
|
||||
|
||||
### Script Not Found
|
||||
|
||||
If using relative paths, ensure you're in the correct directory or use absolute paths:
|
||||
|
||||
```json
|
||||
{
|
||||
"command": "/absolute/path/to/skills/self-improvement/scripts/activator.sh"
|
||||
}
|
||||
```
|
||||
|
||||
### Too Much Overhead
|
||||
|
||||
If the activator feels intrusive:
|
||||
|
||||
1. **Use minimal setup**: Only UserPromptSubmit, skip PostToolUse
|
||||
2. **Add matcher filter**: Only trigger for certain prompts:
|
||||
|
||||
```json
|
||||
{
|
||||
"matcher": "fix|debug|error|issue",
|
||||
"hooks": [...]
|
||||
}
|
||||
```
|
||||
|
||||
## Hook Output Budget
|
||||
|
||||
The activator is designed to be lightweight:
|
||||
- **Target**: ~50-100 tokens per activation
|
||||
- **Content**: Structured reminder, not verbose instructions
|
||||
- **Format**: XML tags for easy parsing
|
||||
|
||||
If you need to reduce overhead further, you can edit `activator.sh` to output less text.
|
||||
|
||||
## Security Considerations
|
||||
|
||||
- Hook scripts run with the same permissions as Claude Code
|
||||
- Scripts only output text; they don't modify files or run commands
|
||||
- Error detector reads `CLAUDE_TOOL_OUTPUT` environment variable
|
||||
- All scripts are opt-in (you must configure them explicitly)
|
||||
|
||||
## Disabling Hooks
|
||||
|
||||
To temporarily disable without removing configuration:
|
||||
|
||||
1. **Comment out in settings**:
|
||||
```json
|
||||
{
|
||||
"hooks": {
|
||||
// "UserPromptSubmit": [...]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
2. **Or delete the settings file**: Hooks won't run without configuration
|
||||
@@ -0,0 +1,248 @@
|
||||
# OpenClaw Integration
|
||||
|
||||
Complete setup and usage guide for integrating the self-improvement skill with OpenClaw.
|
||||
|
||||
## Overview
|
||||
|
||||
OpenClaw uses workspace-based prompt injection combined with event-driven hooks. Context is injected from workspace files at session start, and hooks can trigger on lifecycle events.
|
||||
|
||||
## Workspace Structure
|
||||
|
||||
```
|
||||
~/.openclaw/
|
||||
├── workspace/ # Working directory
|
||||
│ ├── AGENTS.md # Multi-agent coordination patterns
|
||||
│ ├── SOUL.md # Behavioral guidelines and personality
|
||||
│ ├── TOOLS.md # Tool capabilities and gotchas
|
||||
│ ├── MEMORY.md # Long-term memory (main session only)
|
||||
│ └── memory/ # Daily memory files
|
||||
│ └── YYYY-MM-DD.md
|
||||
├── skills/ # Installed skills
|
||||
│ └── <skill-name>/
|
||||
│ └── SKILL.md
|
||||
└── hooks/ # Custom hooks
|
||||
└── <hook-name>/
|
||||
├── HOOK.md
|
||||
└── handler.ts
|
||||
```
|
||||
|
||||
## Quick Setup
|
||||
|
||||
### 1. Install the Skill
|
||||
|
||||
```bash
|
||||
clawdhub install self-improving-agent
|
||||
```
|
||||
|
||||
Or copy manually:
|
||||
|
||||
```bash
|
||||
cp -r self-improving-agent ~/.openclaw/skills/
|
||||
```
|
||||
|
||||
### 2. Install the Hook (Optional)
|
||||
|
||||
Copy the hook to OpenClaw's hooks directory:
|
||||
|
||||
```bash
|
||||
cp -r hooks/openclaw ~/.openclaw/hooks/self-improvement
|
||||
```
|
||||
|
||||
Enable the hook:
|
||||
|
||||
```bash
|
||||
openclaw hooks enable self-improvement
|
||||
```
|
||||
|
||||
### 3. Create Learning Files
|
||||
|
||||
Create the `.learnings/` directory in your workspace:
|
||||
|
||||
```bash
|
||||
mkdir -p ~/.openclaw/workspace/.learnings
|
||||
```
|
||||
|
||||
Or in the skill directory:
|
||||
|
||||
```bash
|
||||
mkdir -p ~/.openclaw/skills/self-improving-agent/.learnings
|
||||
```
|
||||
|
||||
## Injected Prompt Files
|
||||
|
||||
### AGENTS.md
|
||||
|
||||
Purpose: Multi-agent workflows and delegation patterns.
|
||||
|
||||
```markdown
|
||||
# Agent Coordination
|
||||
|
||||
## Delegation Rules
|
||||
- Use explore agent for open-ended codebase questions
|
||||
- Spawn sub-agents for long-running tasks
|
||||
- Use sessions_send for cross-session communication
|
||||
|
||||
## Session Handoff
|
||||
When delegating to another session:
|
||||
1. Provide full context in the handoff message
|
||||
2. Include relevant file paths
|
||||
3. Specify expected output format
|
||||
```
|
||||
|
||||
### SOUL.md
|
||||
|
||||
Purpose: Behavioral guidelines and communication style.
|
||||
|
||||
```markdown
|
||||
# Behavioral Guidelines
|
||||
|
||||
## Communication Style
|
||||
- Be direct and concise
|
||||
- Avoid unnecessary caveats and disclaimers
|
||||
- Use technical language appropriate to context
|
||||
|
||||
## Error Handling
|
||||
- Admit mistakes promptly
|
||||
- Provide corrected information immediately
|
||||
- Log significant errors to learnings
|
||||
```
|
||||
|
||||
### TOOLS.md
|
||||
|
||||
Purpose: Tool capabilities, integration gotchas, local configuration.
|
||||
|
||||
```markdown
|
||||
# Tool Knowledge
|
||||
|
||||
## Self-Improvement Skill
|
||||
Log learnings to `.learnings/` for continuous improvement.
|
||||
|
||||
## Local Tools
|
||||
- Document tool-specific gotchas here
|
||||
- Note authentication requirements
|
||||
- Track integration quirks
|
||||
```
|
||||
|
||||
## Learning Workflow
|
||||
|
||||
### Capturing Learnings
|
||||
|
||||
1. **In-session**: Log to `.learnings/` as usual
|
||||
2. **Cross-session**: Promote to workspace files
|
||||
|
||||
### Promotion Decision Tree
|
||||
|
||||
```
|
||||
Is the learning project-specific?
|
||||
├── Yes → Keep in .learnings/
|
||||
└── No → Is it behavioral/style-related?
|
||||
├── Yes → Promote to SOUL.md
|
||||
└── No → Is it tool-related?
|
||||
├── Yes → Promote to TOOLS.md
|
||||
└── No → Promote to AGENTS.md (workflow)
|
||||
```
|
||||
|
||||
### Promotion Format Examples
|
||||
|
||||
**From learning:**
|
||||
> Git push to GitHub fails without auth configured - triggers desktop prompt
|
||||
|
||||
**To TOOLS.md:**
|
||||
```markdown
|
||||
## Git
|
||||
- Don't push without confirming auth is configured
|
||||
- Use `gh auth status` to check GitHub CLI auth
|
||||
```
|
||||
|
||||
## Inter-Agent Communication
|
||||
|
||||
OpenClaw provides tools for cross-session communication:
|
||||
|
||||
### sessions_list
|
||||
|
||||
View active and recent sessions:
|
||||
```
|
||||
sessions_list(activeMinutes=30, messageLimit=3)
|
||||
```
|
||||
|
||||
### sessions_history
|
||||
|
||||
Read transcript from another session:
|
||||
```
|
||||
sessions_history(sessionKey="session-id", limit=50)
|
||||
```
|
||||
|
||||
### sessions_send
|
||||
|
||||
Send message to another session:
|
||||
```
|
||||
sessions_send(sessionKey="session-id", message="Learning: API requires X-Custom-Header")
|
||||
```
|
||||
|
||||
### sessions_spawn
|
||||
|
||||
Spawn a background sub-agent:
|
||||
```
|
||||
sessions_spawn(task="Research X and report back", label="research")
|
||||
```
|
||||
|
||||
## Available Hook Events
|
||||
|
||||
| Event | When It Fires |
|
||||
|-------|---------------|
|
||||
| `agent:bootstrap` | Before workspace files inject |
|
||||
| `command:new` | When `/new` command issued |
|
||||
| `command:reset` | When `/reset` command issued |
|
||||
| `command:stop` | When `/stop` command issued |
|
||||
| `gateway:startup` | When gateway starts |
|
||||
|
||||
## Detection Triggers
|
||||
|
||||
### Standard Triggers
|
||||
- User corrections ("No, that's wrong...")
|
||||
- Command failures (non-zero exit codes)
|
||||
- API errors
|
||||
- Knowledge gaps
|
||||
|
||||
### OpenClaw-Specific Triggers
|
||||
|
||||
| Trigger | Action |
|
||||
|---------|--------|
|
||||
| Tool call error | Log to TOOLS.md with tool name |
|
||||
| Session handoff confusion | Log to AGENTS.md with delegation pattern |
|
||||
| Model behavior surprise | Log to SOUL.md with expected vs actual |
|
||||
| Skill issue | Log to .learnings/ or report upstream |
|
||||
|
||||
## Verification
|
||||
|
||||
Check hook is registered:
|
||||
|
||||
```bash
|
||||
openclaw hooks list
|
||||
```
|
||||
|
||||
Check skill is loaded:
|
||||
|
||||
```bash
|
||||
openclaw status
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Hook not firing
|
||||
|
||||
1. Ensure hooks enabled in config
|
||||
2. Restart gateway after config changes
|
||||
3. Check gateway logs for errors
|
||||
|
||||
### Learnings not persisting
|
||||
|
||||
1. Verify `.learnings/` directory exists
|
||||
2. Check file permissions
|
||||
3. Ensure workspace path is configured correctly
|
||||
|
||||
### Skill not loading
|
||||
|
||||
1. Check skill is in skills directory
|
||||
2. Verify SKILL.md has correct frontmatter
|
||||
3. Run `openclaw status` to see loaded skills
|
||||
@@ -0,0 +1,20 @@
|
||||
#!/bin/bash
|
||||
# Self-Improvement Activator Hook
|
||||
# Triggers on UserPromptSubmit to remind Claude about learning capture
|
||||
# Keep output minimal (~50-100 tokens) to minimize overhead
|
||||
|
||||
set -e
|
||||
|
||||
# Output reminder as system context
|
||||
cat << 'EOF'
|
||||
<self-improvement-reminder>
|
||||
After completing this task, evaluate if extractable knowledge emerged:
|
||||
- Non-obvious solution discovered through investigation?
|
||||
- Workaround for unexpected behavior?
|
||||
- Project-specific pattern learned?
|
||||
- Error required debugging to resolve?
|
||||
|
||||
If yes: Log to .learnings/ using the self-improvement skill format.
|
||||
If high-value (recurring, broadly applicable): Consider skill extraction.
|
||||
</self-improvement-reminder>
|
||||
EOF
|
||||
@@ -0,0 +1,55 @@
|
||||
#!/bin/bash
|
||||
# Self-Improvement Error Detector Hook
|
||||
# Triggers on PostToolUse for Bash to detect command failures
|
||||
# Reads CLAUDE_TOOL_OUTPUT environment variable
|
||||
|
||||
set -e
|
||||
|
||||
# Check if tool output indicates an error
|
||||
# CLAUDE_TOOL_OUTPUT contains the result of the tool execution
|
||||
OUTPUT="${CLAUDE_TOOL_OUTPUT:-}"
|
||||
|
||||
# Patterns indicating errors (case-insensitive matching)
|
||||
ERROR_PATTERNS=(
|
||||
"error:"
|
||||
"Error:"
|
||||
"ERROR:"
|
||||
"failed"
|
||||
"FAILED"
|
||||
"command not found"
|
||||
"No such file"
|
||||
"Permission denied"
|
||||
"fatal:"
|
||||
"Exception"
|
||||
"Traceback"
|
||||
"npm ERR!"
|
||||
"ModuleNotFoundError"
|
||||
"SyntaxError"
|
||||
"TypeError"
|
||||
"exit code"
|
||||
"non-zero"
|
||||
)
|
||||
|
||||
# Check if output contains any error pattern
|
||||
contains_error=false
|
||||
for pattern in "${ERROR_PATTERNS[@]}"; do
|
||||
if [[ "$OUTPUT" == *"$pattern"* ]]; then
|
||||
contains_error=true
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
# Only output reminder if error detected
|
||||
if [ "$contains_error" = true ]; then
|
||||
cat << 'EOF'
|
||||
<error-detected>
|
||||
A command error was detected. Consider logging this to .learnings/ERRORS.md if:
|
||||
- The error was unexpected or non-obvious
|
||||
- It required investigation to resolve
|
||||
- It might recur in similar contexts
|
||||
- The solution could benefit future sessions
|
||||
|
||||
Use the self-improvement skill format: [ERR-YYYYMMDD-XXX]
|
||||
</error-detected>
|
||||
EOF
|
||||
fi
|
||||
@@ -0,0 +1,221 @@
|
||||
#!/bin/bash
|
||||
# Skill Extraction Helper
|
||||
# Creates a new skill from a learning entry
|
||||
# Usage: ./extract-skill.sh <skill-name> [--dry-run]
|
||||
|
||||
set -e
|
||||
|
||||
# Configuration
|
||||
SKILLS_DIR="./skills"
|
||||
|
||||
# Colors for output
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
usage() {
|
||||
cat << EOF
|
||||
Usage: $(basename "$0") <skill-name> [options]
|
||||
|
||||
Create a new skill from a learning entry.
|
||||
|
||||
Arguments:
|
||||
skill-name Name of the skill (lowercase, hyphens for spaces)
|
||||
|
||||
Options:
|
||||
--dry-run Show what would be created without creating files
|
||||
--output-dir Relative output directory under current path (default: ./skills)
|
||||
-h, --help Show this help message
|
||||
|
||||
Examples:
|
||||
$(basename "$0") docker-m1-fixes
|
||||
$(basename "$0") api-timeout-patterns --dry-run
|
||||
$(basename "$0") pnpm-setup --output-dir ./skills/custom
|
||||
|
||||
The skill will be created in: \$SKILLS_DIR/<skill-name>/
|
||||
EOF
|
||||
}
|
||||
|
||||
log_info() {
|
||||
echo -e "${GREEN}[INFO]${NC} $1"
|
||||
}
|
||||
|
||||
log_warn() {
|
||||
echo -e "${YELLOW}[WARN]${NC} $1"
|
||||
}
|
||||
|
||||
log_error() {
|
||||
echo -e "${RED}[ERROR]${NC} $1" >&2
|
||||
}
|
||||
|
||||
# Parse arguments
|
||||
SKILL_NAME=""
|
||||
DRY_RUN=false
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case $1 in
|
||||
--dry-run)
|
||||
DRY_RUN=true
|
||||
shift
|
||||
;;
|
||||
--output-dir)
|
||||
if [ -z "${2:-}" ] || [[ "${2:-}" == -* ]]; then
|
||||
log_error "--output-dir requires a relative path argument"
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
SKILLS_DIR="$2"
|
||||
shift 2
|
||||
;;
|
||||
-h|--help)
|
||||
usage
|
||||
exit 0
|
||||
;;
|
||||
-*)
|
||||
log_error "Unknown option: $1"
|
||||
usage
|
||||
exit 1
|
||||
;;
|
||||
*)
|
||||
if [ -z "$SKILL_NAME" ]; then
|
||||
SKILL_NAME="$1"
|
||||
else
|
||||
log_error "Unexpected argument: $1"
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
shift
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Validate skill name
|
||||
if [ -z "$SKILL_NAME" ]; then
|
||||
log_error "Skill name is required"
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Validate skill name format (lowercase, hyphens, no spaces)
|
||||
if ! [[ "$SKILL_NAME" =~ ^[a-z0-9]+(-[a-z0-9]+)*$ ]]; then
|
||||
log_error "Invalid skill name format. Use lowercase letters, numbers, and hyphens only."
|
||||
log_error "Examples: 'docker-fixes', 'api-patterns', 'pnpm-setup'"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Validate output path to avoid writes outside current workspace.
|
||||
if [[ "$SKILLS_DIR" = /* ]]; then
|
||||
log_error "Output directory must be a relative path under the current directory."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ "$SKILLS_DIR" =~ (^|/)\.\.(/|$) ]]; then
|
||||
log_error "Output directory cannot include '..' path segments."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
SKILLS_DIR="${SKILLS_DIR#./}"
|
||||
SKILLS_DIR="./$SKILLS_DIR"
|
||||
|
||||
SKILL_PATH="$SKILLS_DIR/$SKILL_NAME"
|
||||
|
||||
# Check if skill already exists
|
||||
if [ -d "$SKILL_PATH" ] && [ "$DRY_RUN" = false ]; then
|
||||
log_error "Skill already exists: $SKILL_PATH"
|
||||
log_error "Use a different name or remove the existing skill first."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Dry run output
|
||||
if [ "$DRY_RUN" = true ]; then
|
||||
log_info "Dry run - would create:"
|
||||
echo " $SKILL_PATH/"
|
||||
echo " $SKILL_PATH/SKILL.md"
|
||||
echo ""
|
||||
echo "Template content would be:"
|
||||
echo "---"
|
||||
cat << TEMPLATE
|
||||
name: $SKILL_NAME
|
||||
description: "[TODO: Add a concise description of what this skill does and when to use it]"
|
||||
---
|
||||
|
||||
# $(echo "$SKILL_NAME" | sed 's/-/ /g' | awk '{for(i=1;i<=NF;i++) $i=toupper(substr($i,1,1)) tolower(substr($i,2))}1')
|
||||
|
||||
[TODO: Brief introduction explaining the skill's purpose]
|
||||
|
||||
## Quick Reference
|
||||
|
||||
| Situation | Action |
|
||||
|-----------|--------|
|
||||
| [Trigger condition] | [What to do] |
|
||||
|
||||
## Usage
|
||||
|
||||
[TODO: Detailed usage instructions]
|
||||
|
||||
## Examples
|
||||
|
||||
[TODO: Add concrete examples]
|
||||
|
||||
## Source Learning
|
||||
|
||||
This skill was extracted from a learning entry.
|
||||
- Learning ID: [TODO: Add original learning ID]
|
||||
- Original File: .learnings/LEARNINGS.md
|
||||
TEMPLATE
|
||||
echo "---"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Create skill directory structure
|
||||
log_info "Creating skill: $SKILL_NAME"
|
||||
|
||||
mkdir -p "$SKILL_PATH"
|
||||
|
||||
# Create SKILL.md from template
|
||||
cat > "$SKILL_PATH/SKILL.md" << TEMPLATE
|
||||
---
|
||||
name: $SKILL_NAME
|
||||
description: "[TODO: Add a concise description of what this skill does and when to use it]"
|
||||
---
|
||||
|
||||
# $(echo "$SKILL_NAME" | sed 's/-/ /g' | awk '{for(i=1;i<=NF;i++) $i=toupper(substr($i,1,1)) tolower(substr($i,2))}1')
|
||||
|
||||
[TODO: Brief introduction explaining the skill's purpose]
|
||||
|
||||
## Quick Reference
|
||||
|
||||
| Situation | Action |
|
||||
|-----------|--------|
|
||||
| [Trigger condition] | [What to do] |
|
||||
|
||||
## Usage
|
||||
|
||||
[TODO: Detailed usage instructions]
|
||||
|
||||
## Examples
|
||||
|
||||
[TODO: Add concrete examples]
|
||||
|
||||
## Source Learning
|
||||
|
||||
This skill was extracted from a learning entry.
|
||||
- Learning ID: [TODO: Add original learning ID]
|
||||
- Original File: .learnings/LEARNINGS.md
|
||||
TEMPLATE
|
||||
|
||||
log_info "Created: $SKILL_PATH/SKILL.md"
|
||||
|
||||
# Suggest next steps
|
||||
echo ""
|
||||
log_info "Skill scaffold created successfully!"
|
||||
echo ""
|
||||
echo "Next steps:"
|
||||
echo " 1. Edit $SKILL_PATH/SKILL.md"
|
||||
echo " 2. Fill in the TODO sections with content from your learning"
|
||||
echo " 3. Add references/ folder if you have detailed documentation"
|
||||
echo " 4. Add scripts/ folder if you have executable code"
|
||||
echo " 5. Update the original learning entry with:"
|
||||
echo " **Status**: promoted_to_skill"
|
||||
echo " **Skill-Path**: skills/$SKILL_NAME"
|
||||
@@ -0,0 +1,647 @@
|
||||
---
|
||||
name: self-improvement
|
||||
description: "Captures learnings, errors, and corrections to enable continuous improvement. Use when: (1) A command or operation fails unexpectedly, (2) User corrects Claude ('No, that's wrong...', 'Actually...'), (3) User requests a capability that doesn't exist, (4) An external API or tool fails, (5) Claude realizes its knowledge is outdated or incorrect, (6) A better approach is discovered for a recurring task. Also review learnings before major tasks."
|
||||
metadata:
|
||||
---
|
||||
|
||||
# Self-Improvement Skill
|
||||
|
||||
Log learnings and errors to markdown files for continuous improvement. Coding agents can later process these into fixes, and important learnings get promoted to project memory.
|
||||
|
||||
## Quick Reference
|
||||
|
||||
| Situation | Action |
|
||||
|-----------|--------|
|
||||
| Command/operation fails | Log to `.learnings/ERRORS.md` |
|
||||
| User corrects you | Log to `.learnings/LEARNINGS.md` with category `correction` |
|
||||
| User wants missing feature | Log to `.learnings/FEATURE_REQUESTS.md` |
|
||||
| API/external tool fails | Log to `.learnings/ERRORS.md` with integration details |
|
||||
| Knowledge was outdated | Log to `.learnings/LEARNINGS.md` with category `knowledge_gap` |
|
||||
| Found better approach | Log to `.learnings/LEARNINGS.md` with category `best_practice` |
|
||||
| Simplify/Harden recurring patterns | Log/update `.learnings/LEARNINGS.md` with `Source: simplify-and-harden` and a stable `Pattern-Key` |
|
||||
| Similar to existing entry | Link with `**See Also**`, consider priority bump |
|
||||
| Broadly applicable learning | Promote to `CLAUDE.md`, `AGENTS.md`, and/or `.github/copilot-instructions.md` |
|
||||
| Workflow improvements | Promote to `AGENTS.md` (OpenClaw workspace) |
|
||||
| Tool gotchas | Promote to `TOOLS.md` (OpenClaw workspace) |
|
||||
| Behavioral patterns | Promote to `SOUL.md` (OpenClaw workspace) |
|
||||
|
||||
## OpenClaw Setup (Recommended)
|
||||
|
||||
OpenClaw is the primary platform for this skill. It uses workspace-based prompt injection with automatic skill loading.
|
||||
|
||||
### Installation
|
||||
|
||||
**Via ClawdHub (recommended):**
|
||||
```bash
|
||||
clawdhub install self-improving-agent
|
||||
```
|
||||
|
||||
**Manual:**
|
||||
```bash
|
||||
git clone https://github.com/peterskoett/self-improving-agent.git ~/.openclaw/skills/self-improving-agent
|
||||
```
|
||||
|
||||
Remade for openclaw from original repo : https://github.com/pskoett/pskoett-ai-skills - https://github.com/pskoett/pskoett-ai-skills/tree/main/skills/self-improvement
|
||||
|
||||
### Workspace Structure
|
||||
|
||||
OpenClaw injects these files into every session:
|
||||
|
||||
```
|
||||
~/.openclaw/workspace/
|
||||
├── AGENTS.md # Multi-agent workflows, delegation patterns
|
||||
├── SOUL.md # Behavioral guidelines, personality, principles
|
||||
├── TOOLS.md # Tool capabilities, integration gotchas
|
||||
├── MEMORY.md # Long-term memory (main session only)
|
||||
├── memory/ # Daily memory files
|
||||
│ └── YYYY-MM-DD.md
|
||||
└── .learnings/ # This skill's log files
|
||||
├── LEARNINGS.md
|
||||
├── ERRORS.md
|
||||
└── FEATURE_REQUESTS.md
|
||||
```
|
||||
|
||||
### Create Learning Files
|
||||
|
||||
```bash
|
||||
mkdir -p ~/.openclaw/workspace/.learnings
|
||||
```
|
||||
|
||||
Then create the log files (or copy from `assets/`):
|
||||
- `LEARNINGS.md` — corrections, knowledge gaps, best practices
|
||||
- `ERRORS.md` — command failures, exceptions
|
||||
- `FEATURE_REQUESTS.md` — user-requested capabilities
|
||||
|
||||
### Promotion Targets
|
||||
|
||||
When learnings prove broadly applicable, promote them to workspace files:
|
||||
|
||||
| Learning Type | Promote To | Example |
|
||||
|---------------|------------|---------|
|
||||
| Behavioral patterns | `SOUL.md` | "Be concise, avoid disclaimers" |
|
||||
| Workflow improvements | `AGENTS.md` | "Spawn sub-agents for long tasks" |
|
||||
| Tool gotchas | `TOOLS.md` | "Git push needs auth configured first" |
|
||||
|
||||
### Inter-Session Communication
|
||||
|
||||
OpenClaw provides tools to share learnings across sessions:
|
||||
|
||||
- **sessions_list** — View active/recent sessions
|
||||
- **sessions_history** — Read another session's transcript
|
||||
- **sessions_send** — Send a learning to another session
|
||||
- **sessions_spawn** — Spawn a sub-agent for background work
|
||||
|
||||
### Optional: Enable Hook
|
||||
|
||||
For automatic reminders at session start:
|
||||
|
||||
```bash
|
||||
# Copy hook to OpenClaw hooks directory
|
||||
cp -r hooks/openclaw ~/.openclaw/hooks/self-improvement
|
||||
|
||||
# Enable it
|
||||
openclaw hooks enable self-improvement
|
||||
```
|
||||
|
||||
See `references/openclaw-integration.md` for complete details.
|
||||
|
||||
---
|
||||
|
||||
## Generic Setup (Other Agents)
|
||||
|
||||
For Claude Code, Codex, Copilot, or other agents, create `.learnings/` in your project:
|
||||
|
||||
```bash
|
||||
mkdir -p .learnings
|
||||
```
|
||||
|
||||
Copy templates from `assets/` or create files with headers.
|
||||
|
||||
### Add reference to agent files AGENTS.md, CLAUDE.md, or .github/copilot-instructions.md to remind yourself to log learnings. (this is an alternative to hook-based reminders)
|
||||
|
||||
#### Self-Improvement Workflow
|
||||
|
||||
When errors or corrections occur:
|
||||
1. Log to `.learnings/ERRORS.md`, `LEARNINGS.md`, or `FEATURE_REQUESTS.md`
|
||||
2. Review and promote broadly applicable learnings to:
|
||||
- `CLAUDE.md` - project facts and conventions
|
||||
- `AGENTS.md` - workflows and automation
|
||||
- `.github/copilot-instructions.md` - Copilot context
|
||||
|
||||
## Logging Format
|
||||
|
||||
### Learning Entry
|
||||
|
||||
Append to `.learnings/LEARNINGS.md`:
|
||||
|
||||
```markdown
|
||||
## [LRN-YYYYMMDD-XXX] category
|
||||
|
||||
**Logged**: ISO-8601 timestamp
|
||||
**Priority**: low | medium | high | critical
|
||||
**Status**: pending
|
||||
**Area**: frontend | backend | infra | tests | docs | config
|
||||
|
||||
### Summary
|
||||
One-line description of what was learned
|
||||
|
||||
### Details
|
||||
Full context: what happened, what was wrong, what's correct
|
||||
|
||||
### Suggested Action
|
||||
Specific fix or improvement to make
|
||||
|
||||
### Metadata
|
||||
- Source: conversation | error | user_feedback
|
||||
- Related Files: path/to/file.ext
|
||||
- Tags: tag1, tag2
|
||||
- See Also: LRN-20250110-001 (if related to existing entry)
|
||||
- Pattern-Key: simplify.dead_code | harden.input_validation (optional, for recurring-pattern tracking)
|
||||
- Recurrence-Count: 1 (optional)
|
||||
- First-Seen: 2025-01-15 (optional)
|
||||
- Last-Seen: 2025-01-15 (optional)
|
||||
|
||||
---
|
||||
```
|
||||
|
||||
### Error Entry
|
||||
|
||||
Append to `.learnings/ERRORS.md`:
|
||||
|
||||
```markdown
|
||||
## [ERR-YYYYMMDD-XXX] skill_or_command_name
|
||||
|
||||
**Logged**: ISO-8601 timestamp
|
||||
**Priority**: high
|
||||
**Status**: pending
|
||||
**Area**: frontend | backend | infra | tests | docs | config
|
||||
|
||||
### Summary
|
||||
Brief description of what failed
|
||||
|
||||
### Error
|
||||
```
|
||||
Actual error message or output
|
||||
```
|
||||
|
||||
### Context
|
||||
- Command/operation attempted
|
||||
- Input or parameters used
|
||||
- Environment details if relevant
|
||||
|
||||
### Suggested Fix
|
||||
If identifiable, what might resolve this
|
||||
|
||||
### Metadata
|
||||
- Reproducible: yes | no | unknown
|
||||
- Related Files: path/to/file.ext
|
||||
- See Also: ERR-20250110-001 (if recurring)
|
||||
|
||||
---
|
||||
```
|
||||
|
||||
### Feature Request Entry
|
||||
|
||||
Append to `.learnings/FEATURE_REQUESTS.md`:
|
||||
|
||||
```markdown
|
||||
## [FEAT-YYYYMMDD-XXX] capability_name
|
||||
|
||||
**Logged**: ISO-8601 timestamp
|
||||
**Priority**: medium
|
||||
**Status**: pending
|
||||
**Area**: frontend | backend | infra | tests | docs | config
|
||||
|
||||
### Requested Capability
|
||||
What the user wanted to do
|
||||
|
||||
### User Context
|
||||
Why they needed it, what problem they're solving
|
||||
|
||||
### Complexity Estimate
|
||||
simple | medium | complex
|
||||
|
||||
### Suggested Implementation
|
||||
How this could be built, what it might extend
|
||||
|
||||
### Metadata
|
||||
- Frequency: first_time | recurring
|
||||
- Related Features: existing_feature_name
|
||||
|
||||
---
|
||||
```
|
||||
|
||||
## ID Generation
|
||||
|
||||
Format: `TYPE-YYYYMMDD-XXX`
|
||||
- TYPE: `LRN` (learning), `ERR` (error), `FEAT` (feature)
|
||||
- YYYYMMDD: Current date
|
||||
- XXX: Sequential number or random 3 chars (e.g., `001`, `A7B`)
|
||||
|
||||
Examples: `LRN-20250115-001`, `ERR-20250115-A3F`, `FEAT-20250115-002`
|
||||
|
||||
## Resolving Entries
|
||||
|
||||
When an issue is fixed, update the entry:
|
||||
|
||||
1. Change `**Status**: pending` → `**Status**: resolved`
|
||||
2. Add resolution block after Metadata:
|
||||
|
||||
```markdown
|
||||
### Resolution
|
||||
- **Resolved**: 2025-01-16T09:00:00Z
|
||||
- **Commit/PR**: abc123 or #42
|
||||
- **Notes**: Brief description of what was done
|
||||
```
|
||||
|
||||
Other status values:
|
||||
- `in_progress` - Actively being worked on
|
||||
- `wont_fix` - Decided not to address (add reason in Resolution notes)
|
||||
- `promoted` - Elevated to CLAUDE.md, AGENTS.md, or .github/copilot-instructions.md
|
||||
|
||||
## Promoting to Project Memory
|
||||
|
||||
When a learning is broadly applicable (not a one-off fix), promote it to permanent project memory.
|
||||
|
||||
### When to Promote
|
||||
|
||||
- Learning applies across multiple files/features
|
||||
- Knowledge any contributor (human or AI) should know
|
||||
- Prevents recurring mistakes
|
||||
- Documents project-specific conventions
|
||||
|
||||
### Promotion Targets
|
||||
|
||||
| Target | What Belongs There |
|
||||
|--------|-------------------|
|
||||
| `CLAUDE.md` | Project facts, conventions, gotchas for all Claude interactions |
|
||||
| `AGENTS.md` | Agent-specific workflows, tool usage patterns, automation rules |
|
||||
| `.github/copilot-instructions.md` | Project context and conventions for GitHub Copilot |
|
||||
| `SOUL.md` | Behavioral guidelines, communication style, principles (OpenClaw workspace) |
|
||||
| `TOOLS.md` | Tool capabilities, usage patterns, integration gotchas (OpenClaw workspace) |
|
||||
|
||||
### How to Promote
|
||||
|
||||
1. **Distill** the learning into a concise rule or fact
|
||||
2. **Add** to appropriate section in target file (create file if needed)
|
||||
3. **Update** original entry:
|
||||
- Change `**Status**: pending` → `**Status**: promoted`
|
||||
- Add `**Promoted**: CLAUDE.md`, `AGENTS.md`, or `.github/copilot-instructions.md`
|
||||
|
||||
### Promotion Examples
|
||||
|
||||
**Learning** (verbose):
|
||||
> Project uses pnpm workspaces. Attempted `npm install` but failed.
|
||||
> Lock file is `pnpm-lock.yaml`. Must use `pnpm install`.
|
||||
|
||||
**In CLAUDE.md** (concise):
|
||||
```markdown
|
||||
## Build & Dependencies
|
||||
- Package manager: pnpm (not npm) - use `pnpm install`
|
||||
```
|
||||
|
||||
**Learning** (verbose):
|
||||
> When modifying API endpoints, must regenerate TypeScript client.
|
||||
> Forgetting this causes type mismatches at runtime.
|
||||
|
||||
**In AGENTS.md** (actionable):
|
||||
```markdown
|
||||
## After API Changes
|
||||
1. Regenerate client: `pnpm run generate:api`
|
||||
2. Check for type errors: `pnpm tsc --noEmit`
|
||||
```
|
||||
|
||||
## Recurring Pattern Detection
|
||||
|
||||
If logging something similar to an existing entry:
|
||||
|
||||
1. **Search first**: `grep -r "keyword" .learnings/`
|
||||
2. **Link entries**: Add `**See Also**: ERR-20250110-001` in Metadata
|
||||
3. **Bump priority** if issue keeps recurring
|
||||
4. **Consider systemic fix**: Recurring issues often indicate:
|
||||
- Missing documentation (→ promote to CLAUDE.md or .github/copilot-instructions.md)
|
||||
- Missing automation (→ add to AGENTS.md)
|
||||
- Architectural problem (→ create tech debt ticket)
|
||||
|
||||
## Simplify & Harden Feed
|
||||
|
||||
Use this workflow to ingest recurring patterns from the `simplify-and-harden`
|
||||
skill and turn them into durable prompt guidance.
|
||||
|
||||
### Ingestion Workflow
|
||||
|
||||
1. Read `simplify_and_harden.learning_loop.candidates` from the task summary.
|
||||
2. For each candidate, use `pattern_key` as the stable dedupe key.
|
||||
3. Search `.learnings/LEARNINGS.md` for an existing entry with that key:
|
||||
- `grep -n "Pattern-Key: <pattern_key>" .learnings/LEARNINGS.md`
|
||||
4. If found:
|
||||
- Increment `Recurrence-Count`
|
||||
- Update `Last-Seen`
|
||||
- Add `See Also` links to related entries/tasks
|
||||
5. If not found:
|
||||
- Create a new `LRN-...` entry
|
||||
- Set `Source: simplify-and-harden`
|
||||
- Set `Pattern-Key`, `Recurrence-Count: 1`, and `First-Seen`/`Last-Seen`
|
||||
|
||||
### Promotion Rule (System Prompt Feedback)
|
||||
|
||||
Promote recurring patterns into agent context/system prompt files when all are true:
|
||||
|
||||
- `Recurrence-Count >= 3`
|
||||
- Seen across at least 2 distinct tasks
|
||||
- Occurred within a 30-day window
|
||||
|
||||
Promotion targets:
|
||||
- `CLAUDE.md`
|
||||
- `AGENTS.md`
|
||||
- `.github/copilot-instructions.md`
|
||||
- `SOUL.md` / `TOOLS.md` for OpenClaw workspace-level guidance when applicable
|
||||
|
||||
Write promoted rules as short prevention rules (what to do before/while coding),
|
||||
not long incident write-ups.
|
||||
|
||||
## Periodic Review
|
||||
|
||||
Review `.learnings/` at natural breakpoints:
|
||||
|
||||
### When to Review
|
||||
- Before starting a new major task
|
||||
- After completing a feature
|
||||
- When working in an area with past learnings
|
||||
- Weekly during active development
|
||||
|
||||
### Quick Status Check
|
||||
```bash
|
||||
# Count pending items
|
||||
grep -h "Status\*\*: pending" .learnings/*.md | wc -l
|
||||
|
||||
# List pending high-priority items
|
||||
grep -B5 "Priority\*\*: high" .learnings/*.md | grep "^## \["
|
||||
|
||||
# Find learnings for a specific area
|
||||
grep -l "Area\*\*: backend" .learnings/*.md
|
||||
```
|
||||
|
||||
### Review Actions
|
||||
- Resolve fixed items
|
||||
- Promote applicable learnings
|
||||
- Link related entries
|
||||
- Escalate recurring issues
|
||||
|
||||
## Detection Triggers
|
||||
|
||||
Automatically log when you notice:
|
||||
|
||||
**Corrections** (→ learning with `correction` category):
|
||||
- "No, that's not right..."
|
||||
- "Actually, it should be..."
|
||||
- "You're wrong about..."
|
||||
- "That's outdated..."
|
||||
|
||||
**Feature Requests** (→ feature request):
|
||||
- "Can you also..."
|
||||
- "I wish you could..."
|
||||
- "Is there a way to..."
|
||||
- "Why can't you..."
|
||||
|
||||
**Knowledge Gaps** (→ learning with `knowledge_gap` category):
|
||||
- User provides information you didn't know
|
||||
- Documentation you referenced is outdated
|
||||
- API behavior differs from your understanding
|
||||
|
||||
**Errors** (→ error entry):
|
||||
- Command returns non-zero exit code
|
||||
- Exception or stack trace
|
||||
- Unexpected output or behavior
|
||||
- Timeout or connection failure
|
||||
|
||||
## Priority Guidelines
|
||||
|
||||
| Priority | When to Use |
|
||||
|----------|-------------|
|
||||
| `critical` | Blocks core functionality, data loss risk, security issue |
|
||||
| `high` | Significant impact, affects common workflows, recurring issue |
|
||||
| `medium` | Moderate impact, workaround exists |
|
||||
| `low` | Minor inconvenience, edge case, nice-to-have |
|
||||
|
||||
## Area Tags
|
||||
|
||||
Use to filter learnings by codebase region:
|
||||
|
||||
| Area | Scope |
|
||||
|------|-------|
|
||||
| `frontend` | UI, components, client-side code |
|
||||
| `backend` | API, services, server-side code |
|
||||
| `infra` | CI/CD, deployment, Docker, cloud |
|
||||
| `tests` | Test files, testing utilities, coverage |
|
||||
| `docs` | Documentation, comments, READMEs |
|
||||
| `config` | Configuration files, environment, settings |
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Log immediately** - context is freshest right after the issue
|
||||
2. **Be specific** - future agents need to understand quickly
|
||||
3. **Include reproduction steps** - especially for errors
|
||||
4. **Link related files** - makes fixes easier
|
||||
5. **Suggest concrete fixes** - not just "investigate"
|
||||
6. **Use consistent categories** - enables filtering
|
||||
7. **Promote aggressively** - if in doubt, add to CLAUDE.md or .github/copilot-instructions.md
|
||||
8. **Review regularly** - stale learnings lose value
|
||||
|
||||
## Gitignore Options
|
||||
|
||||
**Keep learnings local** (per-developer):
|
||||
```gitignore
|
||||
.learnings/
|
||||
```
|
||||
|
||||
**Track learnings in repo** (team-wide):
|
||||
Don't add to .gitignore - learnings become shared knowledge.
|
||||
|
||||
**Hybrid** (track templates, ignore entries):
|
||||
```gitignore
|
||||
.learnings/*.md
|
||||
!.learnings/.gitkeep
|
||||
```
|
||||
|
||||
## Hook Integration
|
||||
|
||||
Enable automatic reminders through agent hooks. This is **opt-in** - you must explicitly configure hooks.
|
||||
|
||||
### Quick Setup (Claude Code / Codex)
|
||||
|
||||
Create `.claude/settings.json` in your project:
|
||||
|
||||
```json
|
||||
{
|
||||
"hooks": {
|
||||
"UserPromptSubmit": [{
|
||||
"matcher": "",
|
||||
"hooks": [{
|
||||
"type": "command",
|
||||
"command": "./skills/self-improvement/scripts/activator.sh"
|
||||
}]
|
||||
}]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
This injects a learning evaluation reminder after each prompt (~50-100 tokens overhead).
|
||||
|
||||
### Full Setup (With Error Detection)
|
||||
|
||||
```json
|
||||
{
|
||||
"hooks": {
|
||||
"UserPromptSubmit": [{
|
||||
"matcher": "",
|
||||
"hooks": [{
|
||||
"type": "command",
|
||||
"command": "./skills/self-improvement/scripts/activator.sh"
|
||||
}]
|
||||
}],
|
||||
"PostToolUse": [{
|
||||
"matcher": "Bash",
|
||||
"hooks": [{
|
||||
"type": "command",
|
||||
"command": "./skills/self-improvement/scripts/error-detector.sh"
|
||||
}]
|
||||
}]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Available Hook Scripts
|
||||
|
||||
| Script | Hook Type | Purpose |
|
||||
|--------|-----------|---------|
|
||||
| `scripts/activator.sh` | UserPromptSubmit | Reminds to evaluate learnings after tasks |
|
||||
| `scripts/error-detector.sh` | PostToolUse (Bash) | Triggers on command errors |
|
||||
|
||||
See `references/hooks-setup.md` for detailed configuration and troubleshooting.
|
||||
|
||||
## Automatic Skill Extraction
|
||||
|
||||
When a learning is valuable enough to become a reusable skill, extract it using the provided helper.
|
||||
|
||||
### Skill Extraction Criteria
|
||||
|
||||
A learning qualifies for skill extraction when ANY of these apply:
|
||||
|
||||
| Criterion | Description |
|
||||
|-----------|-------------|
|
||||
| **Recurring** | Has `See Also` links to 2+ similar issues |
|
||||
| **Verified** | Status is `resolved` with working fix |
|
||||
| **Non-obvious** | Required actual debugging/investigation to discover |
|
||||
| **Broadly applicable** | Not project-specific; useful across codebases |
|
||||
| **User-flagged** | User says "save this as a skill" or similar |
|
||||
|
||||
### Extraction Workflow
|
||||
|
||||
1. **Identify candidate**: Learning meets extraction criteria
|
||||
2. **Run helper** (or create manually):
|
||||
```bash
|
||||
./skills/self-improvement/scripts/extract-skill.sh skill-name --dry-run
|
||||
./skills/self-improvement/scripts/extract-skill.sh skill-name
|
||||
```
|
||||
3. **Customize SKILL.md**: Fill in template with learning content
|
||||
4. **Update learning**: Set status to `promoted_to_skill`, add `Skill-Path`
|
||||
5. **Verify**: Read skill in fresh session to ensure it's self-contained
|
||||
|
||||
### Manual Extraction
|
||||
|
||||
If you prefer manual creation:
|
||||
|
||||
1. Create `skills/<skill-name>/SKILL.md`
|
||||
2. Use template from `assets/SKILL-TEMPLATE.md`
|
||||
3. Follow [Agent Skills spec](https://agentskills.io/specification):
|
||||
- YAML frontmatter with `name` and `description`
|
||||
- Name must match folder name
|
||||
- No README.md inside skill folder
|
||||
|
||||
### Extraction Detection Triggers
|
||||
|
||||
Watch for these signals that a learning should become a skill:
|
||||
|
||||
**In conversation:**
|
||||
- "Save this as a skill"
|
||||
- "I keep running into this"
|
||||
- "This would be useful for other projects"
|
||||
- "Remember this pattern"
|
||||
|
||||
**In learning entries:**
|
||||
- Multiple `See Also` links (recurring issue)
|
||||
- High priority + resolved status
|
||||
- Category: `best_practice` with broad applicability
|
||||
- User feedback praising the solution
|
||||
|
||||
### Skill Quality Gates
|
||||
|
||||
Before extraction, verify:
|
||||
|
||||
- [ ] Solution is tested and working
|
||||
- [ ] Description is clear without original context
|
||||
- [ ] Code examples are self-contained
|
||||
- [ ] No project-specific hardcoded values
|
||||
- [ ] Follows skill naming conventions (lowercase, hyphens)
|
||||
|
||||
## Multi-Agent Support
|
||||
|
||||
This skill works across different AI coding agents with agent-specific activation.
|
||||
|
||||
### Claude Code
|
||||
|
||||
**Activation**: Hooks (UserPromptSubmit, PostToolUse)
|
||||
**Setup**: `.claude/settings.json` with hook configuration
|
||||
**Detection**: Automatic via hook scripts
|
||||
|
||||
### Codex CLI
|
||||
|
||||
**Activation**: Hooks (same pattern as Claude Code)
|
||||
**Setup**: `.codex/settings.json` with hook configuration
|
||||
**Detection**: Automatic via hook scripts
|
||||
|
||||
### GitHub Copilot
|
||||
|
||||
**Activation**: Manual (no hook support)
|
||||
**Setup**: Add to `.github/copilot-instructions.md`:
|
||||
|
||||
```markdown
|
||||
## Self-Improvement
|
||||
|
||||
After solving non-obvious issues, consider logging to `.learnings/`:
|
||||
1. Use format from self-improvement skill
|
||||
2. Link related entries with See Also
|
||||
3. Promote high-value learnings to skills
|
||||
|
||||
Ask in chat: "Should I log this as a learning?"
|
||||
```
|
||||
|
||||
**Detection**: Manual review at session end
|
||||
|
||||
### OpenClaw
|
||||
|
||||
**Activation**: Workspace injection + inter-agent messaging
|
||||
**Setup**: See "OpenClaw Setup" section above
|
||||
**Detection**: Via session tools and workspace files
|
||||
|
||||
### Agent-Agnostic Guidance
|
||||
|
||||
Regardless of agent, apply self-improvement when you:
|
||||
|
||||
1. **Discover something non-obvious** - solution wasn't immediate
|
||||
2. **Correct yourself** - initial approach was wrong
|
||||
3. **Learn project conventions** - discovered undocumented patterns
|
||||
4. **Hit unexpected errors** - especially if diagnosis was difficult
|
||||
5. **Find better approaches** - improved on your original solution
|
||||
|
||||
### Copilot Chat Integration
|
||||
|
||||
For Copilot users, add this to your prompts when relevant:
|
||||
|
||||
> After completing this task, evaluate if any learnings should be logged to `.learnings/` using the self-improvement skill format.
|
||||
|
||||
Or use quick prompts:
|
||||
- "Log this to learnings"
|
||||
- "Create a skill from this solution"
|
||||
- "Check .learnings/ for related issues"
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"owner": "1215656",
|
||||
"slug": "1215656-self-improving-agent-3-0-6",
|
||||
"displayName": "1215656 Self Improving Agent@3.0.6",
|
||||
"latest": {
|
||||
"version": "1.0.0",
|
||||
"publishedAt": 1774431919212,
|
||||
"commit": "https://github.com/openclaw/skills/commit/280e436522395f558e1e112c937992849effe08c"
|
||||
},
|
||||
"history": []
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
# Learnings
|
||||
|
||||
Corrections, insights, and knowledge gaps captured during development.
|
||||
|
||||
**Categories**: correction | insight | knowledge_gap | best_practice
|
||||
**Areas**: frontend | backend | infra | tests | docs | config
|
||||
**Statuses**: pending | in_progress | resolved | wont_fix | promoted | promoted_to_skill
|
||||
|
||||
## Status Definitions
|
||||
|
||||
| Status | Meaning |
|
||||
|--------|---------|
|
||||
| `pending` | Not yet addressed |
|
||||
| `in_progress` | Actively being worked on |
|
||||
| `resolved` | Issue fixed or knowledge integrated |
|
||||
| `wont_fix` | Decided not to address (reason in Resolution) |
|
||||
| `promoted` | Elevated to CLAUDE.md, AGENTS.md, or copilot-instructions.md |
|
||||
| `promoted_to_skill` | Extracted as a reusable skill |
|
||||
|
||||
## Skill Extraction Fields
|
||||
|
||||
When a learning is promoted to a skill, add these fields:
|
||||
|
||||
```markdown
|
||||
**Status**: promoted_to_skill
|
||||
**Skill-Path**: skills/skill-name
|
||||
```
|
||||
|
||||
Example:
|
||||
```markdown
|
||||
## [LRN-20250115-001] best_practice
|
||||
|
||||
**Logged**: 2025-01-15T10:00:00Z
|
||||
**Priority**: high
|
||||
**Status**: promoted_to_skill
|
||||
**Skill-Path**: skills/docker-m1-fixes
|
||||
**Area**: infra
|
||||
|
||||
### Summary
|
||||
Docker build fails on Apple Silicon due to platform mismatch
|
||||
...
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -0,0 +1,177 @@
|
||||
# Skill Template
|
||||
|
||||
Template for creating skills extracted from learnings. Copy and customize.
|
||||
|
||||
---
|
||||
|
||||
## SKILL.md Template
|
||||
|
||||
```markdown
|
||||
---
|
||||
name: skill-name-here
|
||||
description: "Concise description of when and why to use this skill. Include trigger conditions."
|
||||
---
|
||||
|
||||
# Skill Name
|
||||
|
||||
Brief introduction explaining the problem this skill solves and its origin.
|
||||
|
||||
## Quick Reference
|
||||
|
||||
| Situation | Action |
|
||||
|-----------|--------|
|
||||
| [Trigger 1] | [Action 1] |
|
||||
| [Trigger 2] | [Action 2] |
|
||||
|
||||
## Background
|
||||
|
||||
Why this knowledge matters. What problems it prevents. Context from the original learning.
|
||||
|
||||
## Solution
|
||||
|
||||
### Step-by-Step
|
||||
|
||||
1. First step with code or command
|
||||
2. Second step
|
||||
3. Verification step
|
||||
|
||||
### Code Example
|
||||
|
||||
\`\`\`language
|
||||
// Example code demonstrating the solution
|
||||
\`\`\`
|
||||
|
||||
## Common Variations
|
||||
|
||||
- **Variation A**: Description and how to handle
|
||||
- **Variation B**: Description and how to handle
|
||||
|
||||
## Gotchas
|
||||
|
||||
- Warning or common mistake #1
|
||||
- Warning or common mistake #2
|
||||
|
||||
## Related
|
||||
|
||||
- Link to related documentation
|
||||
- Link to related skill
|
||||
|
||||
## Source
|
||||
|
||||
Extracted from learning entry.
|
||||
- **Learning ID**: LRN-YYYYMMDD-XXX
|
||||
- **Original Category**: correction | insight | knowledge_gap | best_practice
|
||||
- **Extraction Date**: YYYY-MM-DD
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Minimal Template
|
||||
|
||||
For simple skills that don't need all sections:
|
||||
|
||||
```markdown
|
||||
---
|
||||
name: skill-name-here
|
||||
description: "What this skill does and when to use it."
|
||||
---
|
||||
|
||||
# Skill Name
|
||||
|
||||
[Problem statement in one sentence]
|
||||
|
||||
## Solution
|
||||
|
||||
[Direct solution with code/commands]
|
||||
|
||||
## Source
|
||||
|
||||
- Learning ID: LRN-YYYYMMDD-XXX
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Template with Scripts
|
||||
|
||||
For skills that include executable helpers:
|
||||
|
||||
```markdown
|
||||
---
|
||||
name: skill-name-here
|
||||
description: "What this skill does and when to use it."
|
||||
---
|
||||
|
||||
# Skill Name
|
||||
|
||||
[Introduction]
|
||||
|
||||
## Quick Reference
|
||||
|
||||
| Command | Purpose |
|
||||
|---------|---------|
|
||||
| `./scripts/helper.sh` | [What it does] |
|
||||
| `./scripts/validate.sh` | [What it does] |
|
||||
|
||||
## Usage
|
||||
|
||||
### Automated (Recommended)
|
||||
|
||||
\`\`\`bash
|
||||
./skills/skill-name/scripts/helper.sh [args]
|
||||
\`\`\`
|
||||
|
||||
### Manual Steps
|
||||
|
||||
1. Step one
|
||||
2. Step two
|
||||
|
||||
## Scripts
|
||||
|
||||
| Script | Description |
|
||||
|--------|-------------|
|
||||
| `scripts/helper.sh` | Main utility |
|
||||
| `scripts/validate.sh` | Validation checker |
|
||||
|
||||
## Source
|
||||
|
||||
- Learning ID: LRN-YYYYMMDD-XXX
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Naming Conventions
|
||||
|
||||
- **Skill name**: lowercase, hyphens for spaces
|
||||
- Good: `docker-m1-fixes`, `api-timeout-patterns`
|
||||
- Bad: `Docker_M1_Fixes`, `APITimeoutPatterns`
|
||||
|
||||
- **Description**: Start with action verb, mention trigger
|
||||
- Good: "Handles Docker build failures on Apple Silicon. Use when builds fail with platform mismatch."
|
||||
- Bad: "Docker stuff"
|
||||
|
||||
- **Files**:
|
||||
- `SKILL.md` - Required, main documentation
|
||||
- `scripts/` - Optional, executable code
|
||||
- `references/` - Optional, detailed docs
|
||||
- `assets/` - Optional, templates
|
||||
|
||||
---
|
||||
|
||||
## Extraction Checklist
|
||||
|
||||
Before creating a skill from a learning:
|
||||
|
||||
- [ ] Learning is verified (status: resolved)
|
||||
- [ ] Solution is broadly applicable (not one-off)
|
||||
- [ ] Content is complete (has all needed context)
|
||||
- [ ] Name follows conventions
|
||||
- [ ] Description is concise but informative
|
||||
- [ ] Quick Reference table is actionable
|
||||
- [ ] Code examples are tested
|
||||
- [ ] Source learning ID is recorded
|
||||
|
||||
After creating:
|
||||
|
||||
- [ ] Update original learning with `promoted_to_skill` status
|
||||
- [ ] Add `Skill-Path: skills/skill-name` to learning metadata
|
||||
- [ ] Test skill by reading it in a fresh session
|
||||
@@ -0,0 +1,23 @@
|
||||
---
|
||||
name: self-improvement
|
||||
description: "Injects self-improvement reminder during agent bootstrap"
|
||||
metadata: {"openclaw":{"emoji":"🧠","events":["agent:bootstrap"]}}
|
||||
---
|
||||
|
||||
# Self-Improvement Hook
|
||||
|
||||
Injects a reminder to evaluate learnings during agent bootstrap.
|
||||
|
||||
## What It Does
|
||||
|
||||
- Fires on `agent:bootstrap` (before workspace files are injected)
|
||||
- Adds a reminder block to check `.learnings/` for relevant entries
|
||||
- Prompts the agent to log corrections, errors, and discoveries
|
||||
|
||||
## Configuration
|
||||
|
||||
No configuration needed. Enable with:
|
||||
|
||||
```bash
|
||||
openclaw hooks enable self-improvement
|
||||
```
|
||||
@@ -0,0 +1,56 @@
|
||||
/**
|
||||
* Self-Improvement Hook for OpenClaw
|
||||
*
|
||||
* Injects a reminder to evaluate learnings during agent bootstrap.
|
||||
* Fires on agent:bootstrap event before workspace files are injected.
|
||||
*/
|
||||
|
||||
const REMINDER_CONTENT = `
|
||||
## Self-Improvement Reminder
|
||||
|
||||
After completing tasks, evaluate if any learnings should be captured:
|
||||
|
||||
**Log when:**
|
||||
- User corrects you → \`.learnings/LEARNINGS.md\`
|
||||
- Command/operation fails → \`.learnings/ERRORS.md\`
|
||||
- User wants missing capability → \`.learnings/FEATURE_REQUESTS.md\`
|
||||
- You discover your knowledge was wrong → \`.learnings/LEARNINGS.md\`
|
||||
- You find a better approach → \`.learnings/LEARNINGS.md\`
|
||||
|
||||
**Promote when pattern is proven:**
|
||||
- Behavioral patterns → \`SOUL.md\`
|
||||
- Workflow improvements → \`AGENTS.md\`
|
||||
- Tool gotchas → \`TOOLS.md\`
|
||||
|
||||
Keep entries simple: date, title, what happened, what to do differently.
|
||||
`.trim();
|
||||
|
||||
const handler = async (event) => {
|
||||
// Safety checks for event structure
|
||||
if (!event || typeof event !== 'object') {
|
||||
return;
|
||||
}
|
||||
|
||||
// Only handle agent:bootstrap events
|
||||
if (event.type !== 'agent' || event.action !== 'bootstrap') {
|
||||
return;
|
||||
}
|
||||
|
||||
// Safety check for context
|
||||
if (!event.context || typeof event.context !== 'object') {
|
||||
return;
|
||||
}
|
||||
|
||||
// Inject the reminder as a virtual bootstrap file
|
||||
// Check that bootstrapFiles is an array before pushing
|
||||
if (Array.isArray(event.context.bootstrapFiles)) {
|
||||
event.context.bootstrapFiles.push({
|
||||
path: 'SELF_IMPROVEMENT_REMINDER.md',
|
||||
content: REMINDER_CONTENT,
|
||||
virtual: true,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = handler;
|
||||
module.exports.default = handler;
|
||||
@@ -0,0 +1,62 @@
|
||||
/**
|
||||
* Self-Improvement Hook for OpenClaw
|
||||
*
|
||||
* Injects a reminder to evaluate learnings during agent bootstrap.
|
||||
* Fires on agent:bootstrap event before workspace files are injected.
|
||||
*/
|
||||
|
||||
import type { HookHandler } from 'openclaw/hooks';
|
||||
|
||||
const REMINDER_CONTENT = `## Self-Improvement Reminder
|
||||
|
||||
After completing tasks, evaluate if any learnings should be captured:
|
||||
|
||||
**Log when:**
|
||||
- User corrects you → \`.learnings/LEARNINGS.md\`
|
||||
- Command/operation fails → \`.learnings/ERRORS.md\`
|
||||
- User wants missing capability → \`.learnings/FEATURE_REQUESTS.md\`
|
||||
- You discover your knowledge was wrong → \`.learnings/LEARNINGS.md\`
|
||||
- You find a better approach → \`.learnings/LEARNINGS.md\`
|
||||
|
||||
**Promote when pattern is proven:**
|
||||
- Behavioral patterns → \`SOUL.md\`
|
||||
- Workflow improvements → \`AGENTS.md\`
|
||||
- Tool gotchas → \`TOOLS.md\`
|
||||
|
||||
Keep entries simple: date, title, what happened, what to do differently.`;
|
||||
|
||||
const handler: HookHandler = async (event) => {
|
||||
// Safety checks for event structure
|
||||
if (!event || typeof event !== 'object') {
|
||||
return;
|
||||
}
|
||||
|
||||
// Only handle agent:bootstrap events
|
||||
if (event.type !== 'agent' || event.action !== 'bootstrap') {
|
||||
return;
|
||||
}
|
||||
|
||||
// Safety check for context
|
||||
if (!event.context || typeof event.context !== 'object') {
|
||||
return;
|
||||
}
|
||||
|
||||
// Skip sub-agent sessions to avoid bootstrap issues
|
||||
// Sub-agents have sessionKey patterns like "agent:main:subagent:..."
|
||||
const sessionKey = event.sessionKey || '';
|
||||
if (sessionKey.includes(':subagent:')) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Inject the reminder as a virtual bootstrap file
|
||||
// Check that bootstrapFiles is an array before pushing
|
||||
if (Array.isArray(event.context.bootstrapFiles)) {
|
||||
event.context.bootstrapFiles.push({
|
||||
path: 'SELF_IMPROVEMENT_REMINDER.md',
|
||||
content: REMINDER_CONTENT,
|
||||
virtual: true,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export default handler;
|
||||
@@ -0,0 +1,374 @@
|
||||
# Entry Examples
|
||||
|
||||
Concrete examples of well-formatted entries with all fields.
|
||||
|
||||
## Learning: Correction
|
||||
|
||||
```markdown
|
||||
## [LRN-20250115-001] correction
|
||||
|
||||
**Logged**: 2025-01-15T10:30:00Z
|
||||
**Priority**: high
|
||||
**Status**: pending
|
||||
**Area**: tests
|
||||
|
||||
### Summary
|
||||
Incorrectly assumed pytest fixtures are scoped to function by default
|
||||
|
||||
### Details
|
||||
When writing test fixtures, I assumed all fixtures were function-scoped.
|
||||
User corrected that while function scope is the default, the codebase
|
||||
convention uses module-scoped fixtures for database connections to
|
||||
improve test performance.
|
||||
|
||||
### Suggested Action
|
||||
When creating fixtures that involve expensive setup (DB, network),
|
||||
check existing fixtures for scope patterns before defaulting to function scope.
|
||||
|
||||
### Metadata
|
||||
- Source: user_feedback
|
||||
- Related Files: tests/conftest.py
|
||||
- Tags: pytest, testing, fixtures
|
||||
|
||||
---
|
||||
```
|
||||
|
||||
## Learning: Knowledge Gap (Resolved)
|
||||
|
||||
```markdown
|
||||
## [LRN-20250115-002] knowledge_gap
|
||||
|
||||
**Logged**: 2025-01-15T14:22:00Z
|
||||
**Priority**: medium
|
||||
**Status**: resolved
|
||||
**Area**: config
|
||||
|
||||
### Summary
|
||||
Project uses pnpm not npm for package management
|
||||
|
||||
### Details
|
||||
Attempted to run `npm install` but project uses pnpm workspaces.
|
||||
Lock file is `pnpm-lock.yaml`, not `package-lock.json`.
|
||||
|
||||
### Suggested Action
|
||||
Check for `pnpm-lock.yaml` or `pnpm-workspace.yaml` before assuming npm.
|
||||
Use `pnpm install` for this project.
|
||||
|
||||
### Metadata
|
||||
- Source: error
|
||||
- Related Files: pnpm-lock.yaml, pnpm-workspace.yaml
|
||||
- Tags: package-manager, pnpm, setup
|
||||
|
||||
### Resolution
|
||||
- **Resolved**: 2025-01-15T14:30:00Z
|
||||
- **Commit/PR**: N/A - knowledge update
|
||||
- **Notes**: Added to CLAUDE.md for future reference
|
||||
|
||||
---
|
||||
```
|
||||
|
||||
## Learning: Promoted to CLAUDE.md
|
||||
|
||||
```markdown
|
||||
## [LRN-20250115-003] best_practice
|
||||
|
||||
**Logged**: 2025-01-15T16:00:00Z
|
||||
**Priority**: high
|
||||
**Status**: promoted
|
||||
**Promoted**: CLAUDE.md
|
||||
**Area**: backend
|
||||
|
||||
### Summary
|
||||
API responses must include correlation ID from request headers
|
||||
|
||||
### Details
|
||||
All API responses should echo back the X-Correlation-ID header from
|
||||
the request. This is required for distributed tracing. Responses
|
||||
without this header break the observability pipeline.
|
||||
|
||||
### Suggested Action
|
||||
Always include correlation ID passthrough in API handlers.
|
||||
|
||||
### Metadata
|
||||
- Source: user_feedback
|
||||
- Related Files: src/middleware/correlation.ts
|
||||
- Tags: api, observability, tracing
|
||||
|
||||
---
|
||||
```
|
||||
|
||||
## Learning: Promoted to AGENTS.md
|
||||
|
||||
```markdown
|
||||
## [LRN-20250116-001] best_practice
|
||||
|
||||
**Logged**: 2025-01-16T09:00:00Z
|
||||
**Priority**: high
|
||||
**Status**: promoted
|
||||
**Promoted**: AGENTS.md
|
||||
**Area**: backend
|
||||
|
||||
### Summary
|
||||
Must regenerate API client after OpenAPI spec changes
|
||||
|
||||
### Details
|
||||
When modifying API endpoints, the TypeScript client must be regenerated.
|
||||
Forgetting this causes type mismatches that only appear at runtime.
|
||||
The generate script also runs validation.
|
||||
|
||||
### Suggested Action
|
||||
Add to agent workflow: after any API changes, run `pnpm run generate:api`.
|
||||
|
||||
### Metadata
|
||||
- Source: error
|
||||
- Related Files: openapi.yaml, src/client/api.ts
|
||||
- Tags: api, codegen, typescript
|
||||
|
||||
---
|
||||
```
|
||||
|
||||
## Error Entry
|
||||
|
||||
```markdown
|
||||
## [ERR-20250115-A3F] docker_build
|
||||
|
||||
**Logged**: 2025-01-15T09:15:00Z
|
||||
**Priority**: high
|
||||
**Status**: pending
|
||||
**Area**: infra
|
||||
|
||||
### Summary
|
||||
Docker build fails on M1 Mac due to platform mismatch
|
||||
|
||||
### Error
|
||||
```
|
||||
error: failed to solve: python:3.11-slim: no match for platform linux/arm64
|
||||
```
|
||||
|
||||
### Context
|
||||
- Command: `docker build -t myapp .`
|
||||
- Dockerfile uses `FROM python:3.11-slim`
|
||||
- Running on Apple Silicon (M1/M2)
|
||||
|
||||
### Suggested Fix
|
||||
Add platform flag: `docker build --platform linux/amd64 -t myapp .`
|
||||
Or update Dockerfile: `FROM --platform=linux/amd64 python:3.11-slim`
|
||||
|
||||
### Metadata
|
||||
- Reproducible: yes
|
||||
- Related Files: Dockerfile
|
||||
|
||||
---
|
||||
```
|
||||
|
||||
## Error Entry: Recurring Issue
|
||||
|
||||
```markdown
|
||||
## [ERR-20250120-B2C] api_timeout
|
||||
|
||||
**Logged**: 2025-01-20T11:30:00Z
|
||||
**Priority**: critical
|
||||
**Status**: pending
|
||||
**Area**: backend
|
||||
|
||||
### Summary
|
||||
Third-party payment API timeout during checkout
|
||||
|
||||
### Error
|
||||
```
|
||||
TimeoutError: Request to payments.example.com timed out after 30000ms
|
||||
```
|
||||
|
||||
### Context
|
||||
- Command: POST /api/checkout
|
||||
- Timeout set to 30s
|
||||
- Occurs during peak hours (lunch, evening)
|
||||
|
||||
### Suggested Fix
|
||||
Implement retry with exponential backoff. Consider circuit breaker pattern.
|
||||
|
||||
### Metadata
|
||||
- Reproducible: yes (during peak hours)
|
||||
- Related Files: src/services/payment.ts
|
||||
- See Also: ERR-20250115-X1Y, ERR-20250118-Z3W
|
||||
|
||||
---
|
||||
```
|
||||
|
||||
## Feature Request
|
||||
|
||||
```markdown
|
||||
## [FEAT-20250115-001] export_to_csv
|
||||
|
||||
**Logged**: 2025-01-15T16:45:00Z
|
||||
**Priority**: medium
|
||||
**Status**: pending
|
||||
**Area**: backend
|
||||
|
||||
### Requested Capability
|
||||
Export analysis results to CSV format
|
||||
|
||||
### User Context
|
||||
User runs weekly reports and needs to share results with non-technical
|
||||
stakeholders in Excel. Currently copies output manually.
|
||||
|
||||
### Complexity Estimate
|
||||
simple
|
||||
|
||||
### Suggested Implementation
|
||||
Add `--output csv` flag to the analyze command. Use standard csv module.
|
||||
Could extend existing `--output json` pattern.
|
||||
|
||||
### Metadata
|
||||
- Frequency: recurring
|
||||
- Related Features: analyze command, json output
|
||||
|
||||
---
|
||||
```
|
||||
|
||||
## Feature Request: Resolved
|
||||
|
||||
```markdown
|
||||
## [FEAT-20250110-002] dark_mode
|
||||
|
||||
**Logged**: 2025-01-10T14:00:00Z
|
||||
**Priority**: low
|
||||
**Status**: resolved
|
||||
**Area**: frontend
|
||||
|
||||
### Requested Capability
|
||||
Dark mode support for the dashboard
|
||||
|
||||
### User Context
|
||||
User works late hours and finds the bright interface straining.
|
||||
Several other users have mentioned this informally.
|
||||
|
||||
### Complexity Estimate
|
||||
medium
|
||||
|
||||
### Suggested Implementation
|
||||
Use CSS variables for colors. Add toggle in user settings.
|
||||
Consider system preference detection.
|
||||
|
||||
### Metadata
|
||||
- Frequency: recurring
|
||||
- Related Features: user settings, theme system
|
||||
|
||||
### Resolution
|
||||
- **Resolved**: 2025-01-18T16:00:00Z
|
||||
- **Commit/PR**: #142
|
||||
- **Notes**: Implemented with system preference detection and manual toggle
|
||||
|
||||
---
|
||||
```
|
||||
|
||||
## Learning: Promoted to Skill
|
||||
|
||||
```markdown
|
||||
## [LRN-20250118-001] best_practice
|
||||
|
||||
**Logged**: 2025-01-18T11:00:00Z
|
||||
**Priority**: high
|
||||
**Status**: promoted_to_skill
|
||||
**Skill-Path**: skills/docker-m1-fixes
|
||||
**Area**: infra
|
||||
|
||||
### Summary
|
||||
Docker build fails on Apple Silicon due to platform mismatch
|
||||
|
||||
### Details
|
||||
When building Docker images on M1/M2 Macs, the build fails because
|
||||
the base image doesn't have an ARM64 variant. This is a common issue
|
||||
that affects many developers.
|
||||
|
||||
### Suggested Action
|
||||
Add `--platform linux/amd64` to docker build command, or use
|
||||
`FROM --platform=linux/amd64` in Dockerfile.
|
||||
|
||||
### Metadata
|
||||
- Source: error
|
||||
- Related Files: Dockerfile
|
||||
- Tags: docker, arm64, m1, apple-silicon
|
||||
- See Also: ERR-20250115-A3F, ERR-20250117-B2D
|
||||
|
||||
---
|
||||
```
|
||||
|
||||
## Extracted Skill Example
|
||||
|
||||
When the above learning is extracted as a skill, it becomes:
|
||||
|
||||
**File**: `skills/docker-m1-fixes/SKILL.md`
|
||||
|
||||
```markdown
|
||||
---
|
||||
name: docker-m1-fixes
|
||||
description: "Fixes Docker build failures on Apple Silicon (M1/M2). Use when docker build fails with platform mismatch errors."
|
||||
---
|
||||
|
||||
# Docker M1 Fixes
|
||||
|
||||
Solutions for Docker build issues on Apple Silicon Macs.
|
||||
|
||||
## Quick Reference
|
||||
|
||||
| Error | Fix |
|
||||
|-------|-----|
|
||||
| `no match for platform linux/arm64` | Add `--platform linux/amd64` to build |
|
||||
| Image runs but crashes | Use emulation or find ARM-compatible base |
|
||||
|
||||
## The Problem
|
||||
|
||||
Many Docker base images don't have ARM64 variants. When building on
|
||||
Apple Silicon (M1/M2/M3), Docker attempts to pull ARM64 images by
|
||||
default, causing platform mismatch errors.
|
||||
|
||||
## Solutions
|
||||
|
||||
### Option 1: Build Flag (Recommended)
|
||||
|
||||
Add platform flag to your build command:
|
||||
|
||||
\`\`\`bash
|
||||
docker build --platform linux/amd64 -t myapp .
|
||||
\`\`\`
|
||||
|
||||
### Option 2: Dockerfile Modification
|
||||
|
||||
Specify platform in the FROM instruction:
|
||||
|
||||
\`\`\`dockerfile
|
||||
FROM --platform=linux/amd64 python:3.11-slim
|
||||
\`\`\`
|
||||
|
||||
### Option 3: Docker Compose
|
||||
|
||||
Add platform to your service:
|
||||
|
||||
\`\`\`yaml
|
||||
services:
|
||||
app:
|
||||
platform: linux/amd64
|
||||
build: .
|
||||
\`\`\`
|
||||
|
||||
## Trade-offs
|
||||
|
||||
| Approach | Pros | Cons |
|
||||
|----------|------|------|
|
||||
| Build flag | No file changes | Must remember flag |
|
||||
| Dockerfile | Explicit, versioned | Affects all builds |
|
||||
| Compose | Convenient for dev | Requires compose |
|
||||
|
||||
## Performance Note
|
||||
|
||||
Running AMD64 images on ARM64 uses Rosetta 2 emulation. This works
|
||||
for development but may be slower. For production, find ARM-native
|
||||
alternatives when possible.
|
||||
|
||||
## Source
|
||||
|
||||
- Learning ID: LRN-20250118-001
|
||||
- Category: best_practice
|
||||
- Extraction Date: 2025-01-18
|
||||
```
|
||||
@@ -0,0 +1,223 @@
|
||||
# Hook Setup Guide
|
||||
|
||||
Configure automatic self-improvement triggers for AI coding agents.
|
||||
|
||||
## Overview
|
||||
|
||||
Hooks enable proactive learning capture by injecting reminders at key moments:
|
||||
- **UserPromptSubmit**: Reminder after each prompt to evaluate learnings
|
||||
- **PostToolUse (Bash)**: Error detection when commands fail
|
||||
|
||||
## Claude Code Setup
|
||||
|
||||
### Option 1: Project-Level Configuration
|
||||
|
||||
Create `.claude/settings.json` in your project root:
|
||||
|
||||
```json
|
||||
{
|
||||
"hooks": {
|
||||
"UserPromptSubmit": [
|
||||
{
|
||||
"matcher": "",
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "./skills/self-improvement/scripts/activator.sh"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"PostToolUse": [
|
||||
{
|
||||
"matcher": "Bash",
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "./skills/self-improvement/scripts/error-detector.sh"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Option 2: User-Level Configuration
|
||||
|
||||
Add to `~/.claude/settings.json` for global activation:
|
||||
|
||||
```json
|
||||
{
|
||||
"hooks": {
|
||||
"UserPromptSubmit": [
|
||||
{
|
||||
"matcher": "",
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "~/.claude/skills/self-improvement/scripts/activator.sh"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Minimal Setup (Activator Only)
|
||||
|
||||
For lower overhead, use only the UserPromptSubmit hook:
|
||||
|
||||
```json
|
||||
{
|
||||
"hooks": {
|
||||
"UserPromptSubmit": [
|
||||
{
|
||||
"matcher": "",
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "./skills/self-improvement/scripts/activator.sh"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Codex CLI Setup
|
||||
|
||||
Codex uses the same hook system as Claude Code. Create `.codex/settings.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"hooks": {
|
||||
"UserPromptSubmit": [
|
||||
{
|
||||
"matcher": "",
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "./skills/self-improvement/scripts/activator.sh"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## GitHub Copilot Setup
|
||||
|
||||
Copilot doesn't support hooks directly. Instead, add guidance to `.github/copilot-instructions.md`:
|
||||
|
||||
```markdown
|
||||
## Self-Improvement
|
||||
|
||||
After completing tasks that involved:
|
||||
- Debugging non-obvious issues
|
||||
- Discovering workarounds
|
||||
- Learning project-specific patterns
|
||||
- Resolving unexpected errors
|
||||
|
||||
Consider logging the learning to `.learnings/` using the format from the self-improvement skill.
|
||||
|
||||
For high-value learnings that would benefit other sessions, consider skill extraction.
|
||||
```
|
||||
|
||||
## Verification
|
||||
|
||||
### Test Activator Hook
|
||||
|
||||
1. Enable the hook configuration
|
||||
2. Start a new Claude Code session
|
||||
3. Send any prompt
|
||||
4. Verify you see `<self-improvement-reminder>` in the context
|
||||
|
||||
### Test Error Detector Hook
|
||||
|
||||
1. Enable PostToolUse hook for Bash
|
||||
2. Run a command that fails: `ls /nonexistent/path`
|
||||
3. Verify you see `<error-detected>` reminder
|
||||
|
||||
### Dry Run Extract Script
|
||||
|
||||
```bash
|
||||
./skills/self-improvement/scripts/extract-skill.sh test-skill --dry-run
|
||||
```
|
||||
|
||||
Expected output shows the skill scaffold that would be created.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Hook Not Triggering
|
||||
|
||||
1. **Check script permissions**: `chmod +x scripts/*.sh`
|
||||
2. **Verify path**: Use absolute paths or paths relative to project root
|
||||
3. **Check settings location**: Project vs user-level settings
|
||||
4. **Restart session**: Hooks are loaded at session start
|
||||
|
||||
### Permission Denied
|
||||
|
||||
```bash
|
||||
chmod +x ./skills/self-improvement/scripts/activator.sh
|
||||
chmod +x ./skills/self-improvement/scripts/error-detector.sh
|
||||
chmod +x ./skills/self-improvement/scripts/extract-skill.sh
|
||||
```
|
||||
|
||||
### Script Not Found
|
||||
|
||||
If using relative paths, ensure you're in the correct directory or use absolute paths:
|
||||
|
||||
```json
|
||||
{
|
||||
"command": "/absolute/path/to/skills/self-improvement/scripts/activator.sh"
|
||||
}
|
||||
```
|
||||
|
||||
### Too Much Overhead
|
||||
|
||||
If the activator feels intrusive:
|
||||
|
||||
1. **Use minimal setup**: Only UserPromptSubmit, skip PostToolUse
|
||||
2. **Add matcher filter**: Only trigger for certain prompts:
|
||||
|
||||
```json
|
||||
{
|
||||
"matcher": "fix|debug|error|issue",
|
||||
"hooks": [...]
|
||||
}
|
||||
```
|
||||
|
||||
## Hook Output Budget
|
||||
|
||||
The activator is designed to be lightweight:
|
||||
- **Target**: ~50-100 tokens per activation
|
||||
- **Content**: Structured reminder, not verbose instructions
|
||||
- **Format**: XML tags for easy parsing
|
||||
|
||||
If you need to reduce overhead further, you can edit `activator.sh` to output less text.
|
||||
|
||||
## Security Considerations
|
||||
|
||||
- Hook scripts run with the same permissions as Claude Code
|
||||
- Scripts only output text; they don't modify files or run commands
|
||||
- Error detector reads `CLAUDE_TOOL_OUTPUT` environment variable
|
||||
- All scripts are opt-in (you must configure them explicitly)
|
||||
|
||||
## Disabling Hooks
|
||||
|
||||
To temporarily disable without removing configuration:
|
||||
|
||||
1. **Comment out in settings**:
|
||||
```json
|
||||
{
|
||||
"hooks": {
|
||||
// "UserPromptSubmit": [...]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
2. **Or delete the settings file**: Hooks won't run without configuration
|
||||
@@ -0,0 +1,248 @@
|
||||
# OpenClaw Integration
|
||||
|
||||
Complete setup and usage guide for integrating the self-improvement skill with OpenClaw.
|
||||
|
||||
## Overview
|
||||
|
||||
OpenClaw uses workspace-based prompt injection combined with event-driven hooks. Context is injected from workspace files at session start, and hooks can trigger on lifecycle events.
|
||||
|
||||
## Workspace Structure
|
||||
|
||||
```
|
||||
~/.openclaw/
|
||||
├── workspace/ # Working directory
|
||||
│ ├── AGENTS.md # Multi-agent coordination patterns
|
||||
│ ├── SOUL.md # Behavioral guidelines and personality
|
||||
│ ├── TOOLS.md # Tool capabilities and gotchas
|
||||
│ ├── MEMORY.md # Long-term memory (main session only)
|
||||
│ └── memory/ # Daily memory files
|
||||
│ └── YYYY-MM-DD.md
|
||||
├── skills/ # Installed skills
|
||||
│ └── <skill-name>/
|
||||
│ └── SKILL.md
|
||||
└── hooks/ # Custom hooks
|
||||
└── <hook-name>/
|
||||
├── HOOK.md
|
||||
└── handler.ts
|
||||
```
|
||||
|
||||
## Quick Setup
|
||||
|
||||
### 1. Install the Skill
|
||||
|
||||
```bash
|
||||
clawdhub install self-improving-agent
|
||||
```
|
||||
|
||||
Or copy manually:
|
||||
|
||||
```bash
|
||||
cp -r self-improving-agent ~/.openclaw/skills/
|
||||
```
|
||||
|
||||
### 2. Install the Hook (Optional)
|
||||
|
||||
Copy the hook to OpenClaw's hooks directory:
|
||||
|
||||
```bash
|
||||
cp -r hooks/openclaw ~/.openclaw/hooks/self-improvement
|
||||
```
|
||||
|
||||
Enable the hook:
|
||||
|
||||
```bash
|
||||
openclaw hooks enable self-improvement
|
||||
```
|
||||
|
||||
### 3. Create Learning Files
|
||||
|
||||
Create the `.learnings/` directory in your workspace:
|
||||
|
||||
```bash
|
||||
mkdir -p ~/.openclaw/workspace/.learnings
|
||||
```
|
||||
|
||||
Or in the skill directory:
|
||||
|
||||
```bash
|
||||
mkdir -p ~/.openclaw/skills/self-improving-agent/.learnings
|
||||
```
|
||||
|
||||
## Injected Prompt Files
|
||||
|
||||
### AGENTS.md
|
||||
|
||||
Purpose: Multi-agent workflows and delegation patterns.
|
||||
|
||||
```markdown
|
||||
# Agent Coordination
|
||||
|
||||
## Delegation Rules
|
||||
- Use explore agent for open-ended codebase questions
|
||||
- Spawn sub-agents for long-running tasks
|
||||
- Use sessions_send for cross-session communication
|
||||
|
||||
## Session Handoff
|
||||
When delegating to another session:
|
||||
1. Provide full context in the handoff message
|
||||
2. Include relevant file paths
|
||||
3. Specify expected output format
|
||||
```
|
||||
|
||||
### SOUL.md
|
||||
|
||||
Purpose: Behavioral guidelines and communication style.
|
||||
|
||||
```markdown
|
||||
# Behavioral Guidelines
|
||||
|
||||
## Communication Style
|
||||
- Be direct and concise
|
||||
- Avoid unnecessary caveats and disclaimers
|
||||
- Use technical language appropriate to context
|
||||
|
||||
## Error Handling
|
||||
- Admit mistakes promptly
|
||||
- Provide corrected information immediately
|
||||
- Log significant errors to learnings
|
||||
```
|
||||
|
||||
### TOOLS.md
|
||||
|
||||
Purpose: Tool capabilities, integration gotchas, local configuration.
|
||||
|
||||
```markdown
|
||||
# Tool Knowledge
|
||||
|
||||
## Self-Improvement Skill
|
||||
Log learnings to `.learnings/` for continuous improvement.
|
||||
|
||||
## Local Tools
|
||||
- Document tool-specific gotchas here
|
||||
- Note authentication requirements
|
||||
- Track integration quirks
|
||||
```
|
||||
|
||||
## Learning Workflow
|
||||
|
||||
### Capturing Learnings
|
||||
|
||||
1. **In-session**: Log to `.learnings/` as usual
|
||||
2. **Cross-session**: Promote to workspace files
|
||||
|
||||
### Promotion Decision Tree
|
||||
|
||||
```
|
||||
Is the learning project-specific?
|
||||
├── Yes → Keep in .learnings/
|
||||
└── No → Is it behavioral/style-related?
|
||||
├── Yes → Promote to SOUL.md
|
||||
└── No → Is it tool-related?
|
||||
├── Yes → Promote to TOOLS.md
|
||||
└── No → Promote to AGENTS.md (workflow)
|
||||
```
|
||||
|
||||
### Promotion Format Examples
|
||||
|
||||
**From learning:**
|
||||
> Git push to GitHub fails without auth configured - triggers desktop prompt
|
||||
|
||||
**To TOOLS.md:**
|
||||
```markdown
|
||||
## Git
|
||||
- Don't push without confirming auth is configured
|
||||
- Use `gh auth status` to check GitHub CLI auth
|
||||
```
|
||||
|
||||
## Inter-Agent Communication
|
||||
|
||||
OpenClaw provides tools for cross-session communication:
|
||||
|
||||
### sessions_list
|
||||
|
||||
View active and recent sessions:
|
||||
```
|
||||
sessions_list(activeMinutes=30, messageLimit=3)
|
||||
```
|
||||
|
||||
### sessions_history
|
||||
|
||||
Read transcript from another session:
|
||||
```
|
||||
sessions_history(sessionKey="session-id", limit=50)
|
||||
```
|
||||
|
||||
### sessions_send
|
||||
|
||||
Send message to another session:
|
||||
```
|
||||
sessions_send(sessionKey="session-id", message="Learning: API requires X-Custom-Header")
|
||||
```
|
||||
|
||||
### sessions_spawn
|
||||
|
||||
Spawn a background sub-agent:
|
||||
```
|
||||
sessions_spawn(task="Research X and report back", label="research")
|
||||
```
|
||||
|
||||
## Available Hook Events
|
||||
|
||||
| Event | When It Fires |
|
||||
|-------|---------------|
|
||||
| `agent:bootstrap` | Before workspace files inject |
|
||||
| `command:new` | When `/new` command issued |
|
||||
| `command:reset` | When `/reset` command issued |
|
||||
| `command:stop` | When `/stop` command issued |
|
||||
| `gateway:startup` | When gateway starts |
|
||||
|
||||
## Detection Triggers
|
||||
|
||||
### Standard Triggers
|
||||
- User corrections ("No, that's wrong...")
|
||||
- Command failures (non-zero exit codes)
|
||||
- API errors
|
||||
- Knowledge gaps
|
||||
|
||||
### OpenClaw-Specific Triggers
|
||||
|
||||
| Trigger | Action |
|
||||
|---------|--------|
|
||||
| Tool call error | Log to TOOLS.md with tool name |
|
||||
| Session handoff confusion | Log to AGENTS.md with delegation pattern |
|
||||
| Model behavior surprise | Log to SOUL.md with expected vs actual |
|
||||
| Skill issue | Log to .learnings/ or report upstream |
|
||||
|
||||
## Verification
|
||||
|
||||
Check hook is registered:
|
||||
|
||||
```bash
|
||||
openclaw hooks list
|
||||
```
|
||||
|
||||
Check skill is loaded:
|
||||
|
||||
```bash
|
||||
openclaw status
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Hook not firing
|
||||
|
||||
1. Ensure hooks enabled in config
|
||||
2. Restart gateway after config changes
|
||||
3. Check gateway logs for errors
|
||||
|
||||
### Learnings not persisting
|
||||
|
||||
1. Verify `.learnings/` directory exists
|
||||
2. Check file permissions
|
||||
3. Ensure workspace path is configured correctly
|
||||
|
||||
### Skill not loading
|
||||
|
||||
1. Check skill is in skills directory
|
||||
2. Verify SKILL.md has correct frontmatter
|
||||
3. Run `openclaw status` to see loaded skills
|
||||
@@ -0,0 +1,20 @@
|
||||
#!/bin/bash
|
||||
# Self-Improvement Activator Hook
|
||||
# Triggers on UserPromptSubmit to remind Claude about learning capture
|
||||
# Keep output minimal (~50-100 tokens) to minimize overhead
|
||||
|
||||
set -e
|
||||
|
||||
# Output reminder as system context
|
||||
cat << 'EOF'
|
||||
<self-improvement-reminder>
|
||||
After completing this task, evaluate if extractable knowledge emerged:
|
||||
- Non-obvious solution discovered through investigation?
|
||||
- Workaround for unexpected behavior?
|
||||
- Project-specific pattern learned?
|
||||
- Error required debugging to resolve?
|
||||
|
||||
If yes: Log to .learnings/ using the self-improvement skill format.
|
||||
If high-value (recurring, broadly applicable): Consider skill extraction.
|
||||
</self-improvement-reminder>
|
||||
EOF
|
||||
@@ -0,0 +1,55 @@
|
||||
#!/bin/bash
|
||||
# Self-Improvement Error Detector Hook
|
||||
# Triggers on PostToolUse for Bash to detect command failures
|
||||
# Reads CLAUDE_TOOL_OUTPUT environment variable
|
||||
|
||||
set -e
|
||||
|
||||
# Check if tool output indicates an error
|
||||
# CLAUDE_TOOL_OUTPUT contains the result of the tool execution
|
||||
OUTPUT="${CLAUDE_TOOL_OUTPUT:-}"
|
||||
|
||||
# Patterns indicating errors (case-insensitive matching)
|
||||
ERROR_PATTERNS=(
|
||||
"error:"
|
||||
"Error:"
|
||||
"ERROR:"
|
||||
"failed"
|
||||
"FAILED"
|
||||
"command not found"
|
||||
"No such file"
|
||||
"Permission denied"
|
||||
"fatal:"
|
||||
"Exception"
|
||||
"Traceback"
|
||||
"npm ERR!"
|
||||
"ModuleNotFoundError"
|
||||
"SyntaxError"
|
||||
"TypeError"
|
||||
"exit code"
|
||||
"non-zero"
|
||||
)
|
||||
|
||||
# Check if output contains any error pattern
|
||||
contains_error=false
|
||||
for pattern in "${ERROR_PATTERNS[@]}"; do
|
||||
if [[ "$OUTPUT" == *"$pattern"* ]]; then
|
||||
contains_error=true
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
# Only output reminder if error detected
|
||||
if [ "$contains_error" = true ]; then
|
||||
cat << 'EOF'
|
||||
<error-detected>
|
||||
A command error was detected. Consider logging this to .learnings/ERRORS.md if:
|
||||
- The error was unexpected or non-obvious
|
||||
- It required investigation to resolve
|
||||
- It might recur in similar contexts
|
||||
- The solution could benefit future sessions
|
||||
|
||||
Use the self-improvement skill format: [ERR-YYYYMMDD-XXX]
|
||||
</error-detected>
|
||||
EOF
|
||||
fi
|
||||
@@ -0,0 +1,221 @@
|
||||
#!/bin/bash
|
||||
# Skill Extraction Helper
|
||||
# Creates a new skill from a learning entry
|
||||
# Usage: ./extract-skill.sh <skill-name> [--dry-run]
|
||||
|
||||
set -e
|
||||
|
||||
# Configuration
|
||||
SKILLS_DIR="./skills"
|
||||
|
||||
# Colors for output
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
usage() {
|
||||
cat << EOF
|
||||
Usage: $(basename "$0") <skill-name> [options]
|
||||
|
||||
Create a new skill from a learning entry.
|
||||
|
||||
Arguments:
|
||||
skill-name Name of the skill (lowercase, hyphens for spaces)
|
||||
|
||||
Options:
|
||||
--dry-run Show what would be created without creating files
|
||||
--output-dir Relative output directory under current path (default: ./skills)
|
||||
-h, --help Show this help message
|
||||
|
||||
Examples:
|
||||
$(basename "$0") docker-m1-fixes
|
||||
$(basename "$0") api-timeout-patterns --dry-run
|
||||
$(basename "$0") pnpm-setup --output-dir ./skills/custom
|
||||
|
||||
The skill will be created in: \$SKILLS_DIR/<skill-name>/
|
||||
EOF
|
||||
}
|
||||
|
||||
log_info() {
|
||||
echo -e "${GREEN}[INFO]${NC} $1"
|
||||
}
|
||||
|
||||
log_warn() {
|
||||
echo -e "${YELLOW}[WARN]${NC} $1"
|
||||
}
|
||||
|
||||
log_error() {
|
||||
echo -e "${RED}[ERROR]${NC} $1" >&2
|
||||
}
|
||||
|
||||
# Parse arguments
|
||||
SKILL_NAME=""
|
||||
DRY_RUN=false
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case $1 in
|
||||
--dry-run)
|
||||
DRY_RUN=true
|
||||
shift
|
||||
;;
|
||||
--output-dir)
|
||||
if [ -z "${2:-}" ] || [[ "${2:-}" == -* ]]; then
|
||||
log_error "--output-dir requires a relative path argument"
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
SKILLS_DIR="$2"
|
||||
shift 2
|
||||
;;
|
||||
-h|--help)
|
||||
usage
|
||||
exit 0
|
||||
;;
|
||||
-*)
|
||||
log_error "Unknown option: $1"
|
||||
usage
|
||||
exit 1
|
||||
;;
|
||||
*)
|
||||
if [ -z "$SKILL_NAME" ]; then
|
||||
SKILL_NAME="$1"
|
||||
else
|
||||
log_error "Unexpected argument: $1"
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
shift
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Validate skill name
|
||||
if [ -z "$SKILL_NAME" ]; then
|
||||
log_error "Skill name is required"
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Validate skill name format (lowercase, hyphens, no spaces)
|
||||
if ! [[ "$SKILL_NAME" =~ ^[a-z0-9]+(-[a-z0-9]+)*$ ]]; then
|
||||
log_error "Invalid skill name format. Use lowercase letters, numbers, and hyphens only."
|
||||
log_error "Examples: 'docker-fixes', 'api-patterns', 'pnpm-setup'"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Validate output path to avoid writes outside current workspace.
|
||||
if [[ "$SKILLS_DIR" = /* ]]; then
|
||||
log_error "Output directory must be a relative path under the current directory."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ "$SKILLS_DIR" =~ (^|/)\.\.(/|$) ]]; then
|
||||
log_error "Output directory cannot include '..' path segments."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
SKILLS_DIR="${SKILLS_DIR#./}"
|
||||
SKILLS_DIR="./$SKILLS_DIR"
|
||||
|
||||
SKILL_PATH="$SKILLS_DIR/$SKILL_NAME"
|
||||
|
||||
# Check if skill already exists
|
||||
if [ -d "$SKILL_PATH" ] && [ "$DRY_RUN" = false ]; then
|
||||
log_error "Skill already exists: $SKILL_PATH"
|
||||
log_error "Use a different name or remove the existing skill first."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Dry run output
|
||||
if [ "$DRY_RUN" = true ]; then
|
||||
log_info "Dry run - would create:"
|
||||
echo " $SKILL_PATH/"
|
||||
echo " $SKILL_PATH/SKILL.md"
|
||||
echo ""
|
||||
echo "Template content would be:"
|
||||
echo "---"
|
||||
cat << TEMPLATE
|
||||
name: $SKILL_NAME
|
||||
description: "[TODO: Add a concise description of what this skill does and when to use it]"
|
||||
---
|
||||
|
||||
# $(echo "$SKILL_NAME" | sed 's/-/ /g' | awk '{for(i=1;i<=NF;i++) $i=toupper(substr($i,1,1)) tolower(substr($i,2))}1')
|
||||
|
||||
[TODO: Brief introduction explaining the skill's purpose]
|
||||
|
||||
## Quick Reference
|
||||
|
||||
| Situation | Action |
|
||||
|-----------|--------|
|
||||
| [Trigger condition] | [What to do] |
|
||||
|
||||
## Usage
|
||||
|
||||
[TODO: Detailed usage instructions]
|
||||
|
||||
## Examples
|
||||
|
||||
[TODO: Add concrete examples]
|
||||
|
||||
## Source Learning
|
||||
|
||||
This skill was extracted from a learning entry.
|
||||
- Learning ID: [TODO: Add original learning ID]
|
||||
- Original File: .learnings/LEARNINGS.md
|
||||
TEMPLATE
|
||||
echo "---"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Create skill directory structure
|
||||
log_info "Creating skill: $SKILL_NAME"
|
||||
|
||||
mkdir -p "$SKILL_PATH"
|
||||
|
||||
# Create SKILL.md from template
|
||||
cat > "$SKILL_PATH/SKILL.md" << TEMPLATE
|
||||
---
|
||||
name: $SKILL_NAME
|
||||
description: "[TODO: Add a concise description of what this skill does and when to use it]"
|
||||
---
|
||||
|
||||
# $(echo "$SKILL_NAME" | sed 's/-/ /g' | awk '{for(i=1;i<=NF;i++) $i=toupper(substr($i,1,1)) tolower(substr($i,2))}1')
|
||||
|
||||
[TODO: Brief introduction explaining the skill's purpose]
|
||||
|
||||
## Quick Reference
|
||||
|
||||
| Situation | Action |
|
||||
|-----------|--------|
|
||||
| [Trigger condition] | [What to do] |
|
||||
|
||||
## Usage
|
||||
|
||||
[TODO: Detailed usage instructions]
|
||||
|
||||
## Examples
|
||||
|
||||
[TODO: Add concrete examples]
|
||||
|
||||
## Source Learning
|
||||
|
||||
This skill was extracted from a learning entry.
|
||||
- Learning ID: [TODO: Add original learning ID]
|
||||
- Original File: .learnings/LEARNINGS.md
|
||||
TEMPLATE
|
||||
|
||||
log_info "Created: $SKILL_PATH/SKILL.md"
|
||||
|
||||
# Suggest next steps
|
||||
echo ""
|
||||
log_info "Skill scaffold created successfully!"
|
||||
echo ""
|
||||
echo "Next steps:"
|
||||
echo " 1. Edit $SKILL_PATH/SKILL.md"
|
||||
echo " 2. Fill in the TODO sections with content from your learning"
|
||||
echo " 3. Add references/ folder if you have detailed documentation"
|
||||
echo " 4. Add scripts/ folder if you have executable code"
|
||||
echo " 5. Update the original learning entry with:"
|
||||
echo " **Status**: promoted_to_skill"
|
||||
echo " **Skill-Path**: skills/$SKILL_NAME"
|
||||
@@ -0,0 +1,89 @@
|
||||
# Agent Composition Handbook
|
||||
|
||||
This document defines a set of preset Agents used to automate complex on-chain workflows composed of the `1m-trade-news`, and `1m-trade-dex` skills. You can invoke these Agents directly to achieve specific goals.
|
||||
|
||||
## Agent list
|
||||
|
||||
### 1) Agent: Market Scout
|
||||
- **Invocation name**: `market-scout`
|
||||
- **Description**: Runs a daily market health check. If the user provides no specific instructions, this agent can produce a comprehensive market snapshot.
|
||||
- **Workflow**:
|
||||
1. **Trigger**: user asks "How is the market today?" or a scheduled run.
|
||||
2. **Execution**:
|
||||
a. Call `1m-trade-news` → Scenario 1: Market snapshot.
|
||||
b. Fetch sentiment indicator, important newsflashes, BTC ETF net flow, and daily on-chain tx volume in parallel.
|
||||
3. **Output**: a formatted report with a data summary and brief interpretation (e.g. if sentiment < 20, highlight a potential opportunity zone).
|
||||
- **Use cases**: pre-open review, quick market sentiment check, decision support.
|
||||
|
||||
### 2) Agent: Wallet Setup
|
||||
- **Invocation name**: `wallet-setup`
|
||||
- **Description**: Directs users to **[1M-Trade](https://www.1m-trade.com)** for **wallet creation and management** in the browser; then guides **`hl1m init-wallet`** with wallet **public address** + **proxy (API) private key**. Does not bridge assets.
|
||||
- **Workflow**:
|
||||
1. **Trigger**: user wants to connect or configure trading (e.g. "init wallet", "set up Hyperliquid", "configure my API/proxy key", or non-English phrases with the same meaning plus labeled wallet address and proxy private key).
|
||||
2. **Execution**:
|
||||
a. For **creating/managing** the wallet in the UI, send the user to **[1M-Trade](https://www.1m-trade.com)**.
|
||||
b. Call `1m-trade-dex` → **Wallet initialization** and **Natural-language binding** (`skills/1m-trade-dex/SKILL.md`).
|
||||
c. If the user sends **both** address and proxy key in one message (labeled, e.g. `wallet address` / `proxy private key` or equivalent in other languages), parse and **invoke** `hl1m init-wallet --address … --pri_key …` in a trusted shell; do not echo full keys in chat.
|
||||
d. Otherwise, show placeholders only and ask the user to run locally:
|
||||
`hl1m init-wallet --address 0xYourWalletAddress --pri_key 0xYourProxyPrivateKey`
|
||||
e. **Critical**: **Never** use the wallet **main / master private key** for `init-wallet` — only the **proxy** key intended for automation/API use.
|
||||
3. **Output**: step-by-step checklist; confirm success with `hl1m query-user-state` after init. Do not repeat full private keys in assistant-visible text.
|
||||
- **Security note**: Prefer local init without pasting keys. If the user voluntarily pastes address + proxy key for binding, pass values only to the `hl1m` CLI invocation; do not store or quote them in chat.
|
||||
|
||||
### 3) Agent: Trend Trader
|
||||
- **Invocation name**: `trend-trader`
|
||||
- **Description**: Combines macro fund flows and micro price action to produce conditional trade ideas or simulated trades.
|
||||
- **Workflow**:
|
||||
1. **Trigger**: user asks "Can I buy BTC now?" or "Where is money flowing?"
|
||||
2. **Execution**:
|
||||
a. Call `1m-trade-news` → Scenario 2: Fund flow analysis.
|
||||
b. Call `1m-trade-news` → Scenario 3: Macro environment.
|
||||
c. If conditions are met (e.g. stablecoin expansion + top net inflow on a chain + macro not bearish):
|
||||
i. Call `1m-trade-dex` to query live market data.
|
||||
ii. Generate a trade idea report including target, macro rationale, on-chain rationale, and current price.
|
||||
3. **Output**: a report with bullish/bearish rationale and recommended targets. **Do not execute trades automatically**; require final user confirmation.
|
||||
- **Use cases**: data-driven decision support for manual traders.
|
||||
|
||||
### 4) Agent: News-driven Trade Alert
|
||||
- **Invocation name**: `news-alert-trader`
|
||||
- **Description**: Monitors configured news keywords and, when triggered, checks related asset market data to provide fast reaction context.
|
||||
- **Workflow**:
|
||||
1. **Configure**: user pre-defines keywords (e.g. "ETF approval", "hack", "mainnet launch").
|
||||
2. **Trigger**: periodically call `1m-trade-news` → Scenario 5: Keyword search (e.g. every 5 minutes).
|
||||
3. **Execution**: when new items contain keywords:
|
||||
a. Extract related assets from the news text (e.g. "Ethereum" → ETH).
|
||||
b. Call `1m-trade-dex` to query latest price/order book.
|
||||
c. Call `1m-trade-dex` to get recent kline.
|
||||
4. **Output**: alert including title, summary, related assets, price before/after, order book pressure change, and short-term kline trend.
|
||||
- **Use cases**: capture sudden news-driven moves for short-term traders.
|
||||
|
||||
### 5) Agent: HIP-3 TradFi Arb Monitor
|
||||
- **Invocation name**: `hip3-arb-monitor`
|
||||
- **Description**: Monitors HIP-3 markets (e.g. stocks/commodities) around TradFi open to find spread/arb opportunities.
|
||||
- **Workflow**:
|
||||
1. **Trigger**: run around US equity open (ET 9:30 AM).
|
||||
2. **Execution**:
|
||||
a. Call `1m-trade-dex` to list HIP-3 markets and filter targets (e.g. `xyz:AAPL`, `xyz:GOLD`).
|
||||
b. For each target in parallel:
|
||||
i. Get Hyperliquid price.
|
||||
ii. (Simulated) fetch TradFi open/spot price from an external API (not provided; mark as TODO).
|
||||
iii. Compute spread percentage.
|
||||
3. **Output**: spread report highlighting assets above a threshold (e.g. 2%) and optionally search related news via `1m-trade-news`.
|
||||
- **Use cases**: cross-market arbitrage and tokenized TradFi monitoring.
|
||||
|
||||
## How to use these agents
|
||||
You can invoke agents via natural language or structured commands.
|
||||
|
||||
Examples:
|
||||
- Natural language: "Start `market-scout` and give me a morning report."
|
||||
- Structured: `/agent run market-scout`
|
||||
- Combined: "Run `market-scout` first; if sentiment is bullish, then run `wallet-setup` so I can configure `hl1m init-wallet` before trading."
|
||||
|
||||
## Configuration & extension
|
||||
Each agent definition is a "script". You can modify this file to:
|
||||
1. **Adjust flows**: change internal skill call order or condition logic.
|
||||
2. **Create new agents**: combine skills with new logic using the same format.
|
||||
3. **Parameterize**: extract fixed parameters (keywords, thresholds) into configurable variables.
|
||||
|
||||
---
|
||||
*`AGENTS.md` together with the root `SKILL.md` forms the "strategy layer" and "tactics layer" of this skill library: automation workflows and interactive service definitions.*
|
||||
@@ -0,0 +1,341 @@
|
||||
---
|
||||
name: 1m-trade
|
||||
description: |
|
||||
Integrated on-chain operations hub: integrates BlockBeats market intelligence, Hyperliquid DEX trading via `hl1m`, wallet creation and management at https://www.1m-trade.com, and supports local initialization using `hl1m init-wallet` (wallet address + proxy private key, never use the main wallet private key). Supports fully autonomous AI trading.
|
||||
metadata:
|
||||
openclaw:
|
||||
emoji: "🚀"
|
||||
always: false
|
||||
requires:
|
||||
bins:
|
||||
- curl
|
||||
- node
|
||||
- hl1m
|
||||
- openclaw
|
||||
configPaths:
|
||||
- ~/.openclaw/.1m-trade/.env
|
||||
- $OPENCLAW_STATE_DIR/.1m-trade/.env
|
||||
env:
|
||||
- BLOCKBEATS_API_KEY
|
||||
- HYPERLIQUID_PRIVATE_KEY_ENC
|
||||
- HYPERLIQUID_PK_ENC_PASSWORD
|
||||
- HYPERLIQUID_WALLET_ADDRESS
|
||||
os:
|
||||
- darwin
|
||||
- linux
|
||||
- win32
|
||||
tags:
|
||||
- crypto
|
||||
- news
|
||||
- trading
|
||||
- hyperliquid
|
||||
- wallet
|
||||
- dex
|
||||
- automation
|
||||
---
|
||||
|
||||
# 1m-trade Aggregator - On-chain Operations Hub
|
||||
|
||||
**Official website (wallet & account)**: [https://www.1m-trade.com](https://www.1m-trade.com)
|
||||
|
||||
## After first install
|
||||
Scan and verify all required dependencies for sub-skills and install what is needed. From this skill bundle root, run `node auto_check.js` to verify required binaries and `.env` entries (it does not print secrets).
|
||||
|
||||
### `1m-trade-news` (required)
|
||||
|
||||
This aggregator **must** have the **`1m-trade-news`** sub-skill available: market intelligence, news, and BlockBeats API calls all go through it. Do **not** skip this step when installing the bundle.
|
||||
|
||||
1. **Skill files**: Ensure the bundle includes **`skills/1m-trade-news/`** (`SKILL.md`, etc.) and that your OpenClaw / host loads that folder as the **`1m-trade-news`** skill.
|
||||
2. **`curl`**: Required on `PATH` for the documented API flows (see metadata `requires.bins`).
|
||||
3. **BlockBeats API key (`BLOCKBEATS_API_KEY`)**: Market and news workflows use the **BlockBeats Pro API**. Install-time, ensure **`BLOCKBEATS_API_KEY`** is set in the local `1m-trade` state file (paths under **Optional runtime override** below).
|
||||
|
||||
**Apply for / obtain a key (free tier)**:
|
||||
|
||||
1. Request a free API key:
|
||||
```bash
|
||||
curl --request GET --url "https://api-pro.theblockbeats.info/v1/api-key/free"
|
||||
```
|
||||
2. From the JSON body, read `data.api_key` and use it as `BLOCKBEATS_API_KEY`.
|
||||
3. Write it to `~/.openclaw/.1m-trade/.env` (or `$OPENCLAW_STATE_DIR/.1m-trade/.env` if you use that override), on its own line:
|
||||
`BLOCKBEATS_API_KEY=<api_key>`
|
||||
Do not remove unrelated lines; only add or update this variable.
|
||||
|
||||
**Reference**: `skills/1m-trade-news/SKILL.md` → **Get an API key** (includes agent-safe steps to populate `.env` without printing the key).
|
||||
|
||||
**Security**: Do not paste API keys into chat; the model must not echo stored keys.
|
||||
|
||||
### `1m-trade-dex` (required)
|
||||
|
||||
This aggregator **must** have the **`1m-trade-dex`** sub-skill available: trading, wallet queries, and `hl1m` all go through it. Do **not** skip this step when installing the bundle.
|
||||
|
||||
1. **Skill files**: Ensure the bundle includes **`skills/1m-trade-dex/`** (`SKILL.md`, `reference.md`, etc.) and that your OpenClaw / host loads that folder as the **`1m-trade-dex`** skill.
|
||||
2. **CLI (`hl1m`)**: Install the `1m-trade` package so `hl1m` is on `PATH` (Python 3.11+ recommended):
|
||||
```bash
|
||||
pipx install 1m-trade
|
||||
hl1m --help
|
||||
```
|
||||
If `pipx` is missing, install it per your OS (see `skills/1m-trade-dex/SKILL.md` → **Setup**).
|
||||
3. **Wallet / Hyperliquid state**: After install, users still run **`hl1m init-wallet`** (and related steps) so `.env` contains the Hyperliquid fields `auto_check.js` expects — see **`skills/1m-trade-dex/SKILL.md`** → **Wallet initialization**.
|
||||
|
||||
Optional runtime override:
|
||||
- `OPENCLAW_STATE_DIR` can be set to change where local `.1m-trade` state files are read/written.
|
||||
- If not set, tools default to `~/.openclaw/.1m-trade/`.
|
||||
|
||||
Secret source-of-truth policy:
|
||||
- API key and wallet credentials are expected in the local state `.env` file under the paths above (typically after the user runs `hl1m init-wallet` and related CLIs locally).
|
||||
- Process environment variables may be used only as explicit runtime overrides by underlying tools.
|
||||
- **LLM boundary**: The model must **not** read `.env` into context or quote stored secrets. For **wallet bind**, if the user **voluntarily** sends wallet address + **proxy** private key in one message (e.g. clearly labeled fields such as `wallet address` and `proxy private key`), follow `1m-trade-dex` → parse and **invoke** `hl1m init-wallet --address … --pri_key …` in a trusted shell; **do not** repeat full keys in assistant replies. Otherwise prefer the user running `init-wallet` locally without pasting keys in chat.
|
||||
- Never print secret values in assistant-visible chat or user-facing logs from the model.
|
||||
|
||||
## Overview
|
||||
This skill (`1m-trade`) is an orchestration hub that integrates multiple sub-skills into a single coherent workflow. You describe your goal (e.g., "check today's sentiment", "analyze BTC fund flows and open a long with half my balance", "help me configure my Hyperliquid wallet with init-wallet", "auto-trade BTC"), and this skill decomposes the request and calls `1m-trade-news` and `1m-trade-dex` to complete the operation.
|
||||
|
||||
## Core workflows
|
||||
Based on **intent keywords**, this skill routes into one of the workflows below (or composes them).
|
||||
|
||||
### Workflow 1: Market intelligence (Data & News)
|
||||
**Triggers**: `market`, `price`, `news`, `macro`, `fund flows`, `perps`, `search [keyword]`
|
||||
|
||||
**Skill**: `1m-trade-news`
|
||||
|
||||
**Logic**:
|
||||
1. Parse the user query and map it to a scenario / intent mapping.
|
||||
2. Call the relevant BlockBeats API endpoints in parallel.
|
||||
3. Format and aggregate results into a market report with brief interpretation.
|
||||
|
||||
**Example output**:
|
||||
|
||||
```
|
||||
📰 Market Report · 202X-XX-XX
|
||||
===
|
||||
1. 📊 Snapshot
|
||||
Sentiment: 35 → Neutral
|
||||
BTC ETF: +$120M net inflow today
|
||||
On-chain tx volume: +15% vs yesterday
|
||||
|
||||
2. 💰 Hot flows (Solana)
|
||||
1. JTO net inflow $4.2M
|
||||
2. ...
|
||||
|
||||
3. 🌐 Macro
|
||||
Global M2: +4.5% YoY → Liquidity easing
|
||||
DXY: 104.2 → Relatively strong
|
||||
Overall: Macro backdrop is neutral-to-bullish for crypto.
|
||||
```
|
||||
|
||||
### Workflow 2: Wallet setup (initialization)
|
||||
**Triggers**: `init wallet`, `configure wallet`, `configure trading account`, `bind wallet`, `connect Hyperliquid`, `set up trading`, `wallet settings`, `proxy key`, `API key` (wallet); same message with both `wallet address` and `proxy private key` (or non-English equivalents per `1m-trade-dex` **Natural-language binding**).
|
||||
|
||||
**Skill**: `1m-trade-dex` (see `skills/1m-trade-dex/SKILL.md` → **Natural-language binding** and `skills/1m-trade-dex/reference.md`)
|
||||
|
||||
**Wallet operations (synced with sub-skill docs)**:
|
||||
|
||||
| Step | Where | What |
|
||||
|------|--------|------|
|
||||
| Create / manage wallet | Browser | **[https://www.1m-trade.com](https://www.1m-trade.com)** — official UI for account and wallet; do not recreate this flow in chat. |
|
||||
| Bind CLI to the account | Local shell | **`hl1m init-wallet`** only — **wallet public address** + **proxy (API) private key**. **Never** use the **main / master** wallet private key. |
|
||||
| Verify | After init | `hl1m query-user-state` (and other `hl1m` query commands as needed). |
|
||||
|
||||
**Logic**:
|
||||
1. Send users to **[https://www.1m-trade.com](https://www.1m-trade.com)** for **wallet creation and ongoing management** in the browser. Do not simulate full wallet creation inside the assistant.
|
||||
2. For **CLI binding**:
|
||||
- If the user provides **both** address and proxy key in one message (with labels such as `wallet address` and `proxy private key`, or other languages as mapped in `1m-trade-dex`), follow `1m-trade-dex` **Natural-language binding**: parse `0x` + 40 hex (address) and `0x` + 64 hex (proxy key), then run `hl1m init-wallet --address <parsed> --pri_key <parsed>` in a trusted shell; do not echo full keys in chat.
|
||||
- Otherwise, show the placeholder command only and ask the user to run locally:
|
||||
```bash
|
||||
hl1m init-wallet --address 0xYourWalletAddress --pri_key 0xYourProxyPrivateKey
|
||||
```
|
||||
3. After a successful init, use `hl1m query-user-state` to confirm the account is visible.
|
||||
|
||||
### Workflow 3: Trading execution & management (Trading & Management)
|
||||
**Triggers**: `trade`, `order`, `open`, `close`, `positions`, `price`, `kline`, `HIP3`, `AAPL`, `GOLD`
|
||||
|
||||
**Skill**: `1m-trade-dex`
|
||||
|
||||
**Logic**:
|
||||
1. **Market data**: query kline/mids/meta as requested and format results.
|
||||
2. **Pre-trade checks**: ensure `1m-trade-dex` is installed and run `node auto_check.js` to verify prerequisites. If it fails, do not execute any trades.
|
||||
3. **Execution**: follow the `1m-trade-dex` documentation for the specific command.
|
||||
|
||||
### Workflow 4: Hybrid orchestration (Hybrid Workflow)
|
||||
**Trigger examples**: "check the market then decide whether to buy BTC", "after I init my wallet, show ETH kline"
|
||||
|
||||
**Logic**:
|
||||
1. Call Workflow 1 to fetch the market report.
|
||||
2. Present the report and ask whether to continue (e.g., "proceed to wallet setup or trading?").
|
||||
3. After confirmation, call Workflow 2 (wallet init guidance) or Workflow 3.
|
||||
|
||||
## Examples
|
||||
**User**: "How is the crypto market today? I also need to connect my Hyperliquid wallet."
|
||||
**`1m-trade`**:
|
||||
1. Generate a market snapshot report (Workflow 1).
|
||||
2. Point to **[1M-Trade](https://www.1m-trade.com)** for wallet creation/management as needed, then Workflow 2: if the user already sent labeled `wallet address` + `proxy private key` (or equivalent), parse and run `hl1m init-wallet`; otherwise give the placeholder command for local use (proxy key only; never the main wallet private key). Do not guide `send-private-key`.
|
||||
|
||||
**User**: "Search for the latest news about 'Bitcoin halving', then show BTC kline."
|
||||
**`1m-trade`**:
|
||||
1. Call search (Workflow 1, Scenario 5) and return relevant items.
|
||||
2. Call kline query (Workflow 3) and return recent candles.
|
||||
|
||||
### Workflow 5: Fully autonomous mode (AI Auto-Trader)
|
||||
**Triggers**: `enable auto trading`, `autonomous trading`, `managed`, `AI trade for me`, `run every N minutes`, `auto trade BTC`
|
||||
|
||||
**Logic**:
|
||||
1. Run the checker once before enabling cron:
|
||||
- Repo root: `node auto_check.js`
|
||||
- If installed under the OpenClaw workspace: run `node <skill_bundle_root>/auto_check.js`
|
||||
If it fails, do not enable auto trading.
|
||||
2. Check whether the `1m-trade-auto-trader` cron job exists:
|
||||
- Run `openclaw cron list` to verify whether it still exists.
|
||||
- If it exists, ask the user to stop/remove it before creating a new one.
|
||||
- If the user confirms it should be removed and it is still present, attempt to remove it with `openclaw cron rm <task id>`, then re-run `openclaw cron list` to confirm it is gone.
|
||||
|
||||
3. Create a periodic workflow using the command below. `--session isolated` is fixed and must not be changed. The default interval is every 20 minutes (`*/20`); replace with `*/N` if needed. Send the trading report to the user.
|
||||
Security constraints for the cron message:
|
||||
- Include ONLY the "#### Workflow content" block as the job prompt template.
|
||||
- Never include any secrets (API keys, private keys, passwords, `.env` contents, tokens).
|
||||
- Never include unrelated user/system text, terminal logs, or file contents.
|
||||
- Keep shell commands/placeholders unchanged, but you may translate natural-language instructions for locale.
|
||||
4. Run:
|
||||
```bash
|
||||
openclaw cron add \
|
||||
--name "1m-trade-auto-trader" \
|
||||
--cron "*/20 * * * *" \
|
||||
--session isolated \
|
||||
--message "<Paste the FULL prompt from #### Workflow content through the end of the report template below; translate EVERY narrative line into the user's language (e.g. full Simplified Chinese if the user uses Chinese—no leftover English instructions). Keep skill names, hl1m subcommands, symbols, and <<...>> structure unchanged. No secrets. Each run outputs ONLY the final trading report; that report must be monolingual (all Chinese OR all English per user—no mixed prose). Replace this placeholder with that translated block.>" \
|
||||
--timeoutSeconds 600 \
|
||||
--announce \
|
||||
--channel <channel e.g. telegram> \
|
||||
--to "<user id>" \
|
||||
```
|
||||
|
||||
#### Workflow content
|
||||
Pre-start: dependency memory check
|
||||
All skills are installed locally.
|
||||
1. Try reading: `$OPENCLAW_STATE_DIR/.1m-trade/dependencies-status.md`
|
||||
- If missing → first run, treat as "not confirmed installed"
|
||||
- If present, look for any marker:
|
||||
- Installed: true
|
||||
- DependencyStatus: Installed
|
||||
- SkillsReady: true
|
||||
- Record status as "installed" or "not installed/unknown"
|
||||
|
||||
2. Decide based on the status:
|
||||
- If clearly "installed" → skip checks/install and go to step 4
|
||||
- Otherwise → run step 3
|
||||
|
||||
3. Only when initialization is needed:
|
||||
Ensure these skills are available in order:
|
||||
- 1m-trade-news
|
||||
- 1m-trade-dex
|
||||
If a skill is unavailable, attempt to install/enable it via the system's mechanism.
|
||||
Then record success in the memory file.
|
||||
|
||||
4. Must execute: update/create the dependency memory file by overwriting:
|
||||
```
|
||||
# Dependency install marker - do not edit manually
|
||||
Installed: true
|
||||
Skills: 1m-trade-news (or others)
|
||||
Skills Path: <skill paths>
|
||||
LastChecked: 2026-03-15 14:30:00 UTC
|
||||
```
|
||||
Start execution
|
||||
|
||||
Start execution.
|
||||
|
||||
### Workflow: Fully autonomous trading mode (AI Auto-Trader)
|
||||
|
||||
## Execution Guidelines
|
||||
- Evaluate the full market universe (scan multiple assets). Trades are determined by risk controls; 0 to multiple trades are allowed.
|
||||
- Output must be a trading report only (no executable code). Markdown tables/quotes are allowed.
|
||||
- Do not create or modify any files.
|
||||
- Only call existing skills.
|
||||
- Use real trading (not simulation).
|
||||
|
||||
## Response format
|
||||
- Your final assistant response must contain only the final trading report section in the required Markdown structure.
|
||||
- **Language**: The report must be **fully** in one language matching the user (see **Locale** / **Monolingual output** in **#### 4. Trading brief**) — no mixed Chinese/English prose.
|
||||
---
|
||||
|
||||
# Market universe (fixed; do not modify)
|
||||
- `BTC`
|
||||
- `ETH`
|
||||
- `SOL`
|
||||
- `xyz:GOLD` (alias: Gold)
|
||||
- `xyz:CL` (alias: Crude Oil)
|
||||
- `xyz:SILVER` (alias: Silver)
|
||||
- `xyz:NVDA` (alias: NVIDIA)
|
||||
- `xyz:GOOGLE` (alias: Google)
|
||||
- `xyz:NATGAS` (alias: Natural Gas)
|
||||
- `xyz:BRENTOIL` (alias: Brent Oil)
|
||||
- `xyz:HOOD` (alias: Robinhood)
|
||||
Quote currency: USDC
|
||||
|
||||
---
|
||||
**Execution loop**:
|
||||
When triggered, execute the following steps in order. Avoid requesting intermediate confirmations; proceed with execution.
|
||||
#### 1. Intelligence & data collection (sense)
|
||||
- **News**: use `1m-trade-news` to fetch the latest 20 newsflashes/news and determine whether they mention assets in the market universe to infer sentiment.
|
||||
- **Kline**: call `1m-trade-dex` → `query-kline` (default 1h).
|
||||
- **Wallet**: call `1m-trade-dex` → `query-user-state`.
|
||||
- **Prices**: call `1m-trade-dex` → `query-mids`.
|
||||
|
||||
#### 2. Decision
|
||||
Decide based on news sentiment and kline trend:
|
||||
|
||||
- Long
|
||||
- Short
|
||||
- Close
|
||||
- Hold
|
||||
|
||||
**Mandatory risk controls & calculations**:
|
||||
1. Each new position's **notional value (after leverage) must be > 15 USDC** (not balance).
|
||||
2. Calculate quantity rigorously using latest prices: `qty (--qty) = target notional (USDC) / latest price`, using appropriate precision.
|
||||
|
||||
#### 3. Execution (act)
|
||||
Based on the decision, use `1m-trade-dex` commands to trade.
|
||||
- Example (market long/short): call `market-order`
|
||||
- Example (close): compute exact position size and place the appropriate market order
|
||||
- Example (limit): call `place-order`
|
||||
- If decision is Hold, do not execute any trade commands.
|
||||
|
||||
#### 4. Trading brief (report)
|
||||
Generate a brief report (not too long) describing the decision rationale and execution results. Follow this Markdown format strictly.
|
||||
|
||||
**Locale**: Infer the user’s **primary language** from the session (e.g. Chinese vs English). The report must be **monolingual** — **no zh/en mix** in narrative text.
|
||||
|
||||
Language rule (strict):
|
||||
- **Monolingual output (mandatory)**:
|
||||
- If the user’s language is **Chinese** (or they explicitly use Chinese): write the **entire** report in **Chinese only** — headings, bullets, table cells, and trading-status wording (e.g. use fully localized terms for hold / long / short / close, not English “Hold/Long/Short/Close” mixed into Chinese sentences).
|
||||
- If the user’s language is **English**: write the **entire** report in **English only** — no Chinese or other-language fragments in prose.
|
||||
- **Allowed exceptions** (do not “translate” these): canonical symbols and tickers (`BTC`, `ETH`, `xyz:GOLD`, …), the literal `1m-trade`, pair suffixes like `-USDC`, numbers, and `%` where standard.
|
||||
- **`<<...>>` are schema hints in this template only — strip them in the final answer.** Do **not** print literal `<<` or `>>` in the user-visible report. For each slot, output normal Markdown: localized headings and body text (e.g. `- **Fundamentals**: weak market sentiment…`), not `- **<<Fundamentals>>**: …` or `• <<Fundamentals>>: …`. The reader must see finished prose, not bracket markers.
|
||||
- Translate/replace the **meaning** of each former `<<...>>` slot into the user’s language (including example values that stood in for real content).
|
||||
- Do NOT translate placeholders inside <...>.
|
||||
- Do NOT translate crypto symbols, tickers, or trading pairs (e.g. BTC, ETH, SOL, xyz:GOLD). Keep them exactly as-is.
|
||||
- Do NOT translate the literal string `1m-trade` anywhere.
|
||||
- Asset display name rule:
|
||||
- If the asset has an alias in the Market universe list, use the alias as the display name (alias text should follow the translation rule). Do NOT display the canonical symbol.
|
||||
- If the asset has no alias, use the canonical symbol as-is.
|
||||
|
||||
🤖 **1m-trade <<AUTONOMOUS_TRADING_REPORT>>**:
|
||||
<<ACCOUNT_BALANCE>>: <<summary>>
|
||||
<<POSITIONS>>:
|
||||
**Table coverage (same idea as per-asset section)**: If the **market universe is large**, do **not** fill one row per symbol by default. Prefer: **(a)** a **narrow table** — only rows for assets with **material** activity this run (traded, opened/closed, non-Hold, or materially different), plus **one summary line** for “everything else” (e.g. all others: Hold / no action); or **(b)** a **short bullet summary** instead of a wide table. When the set is **small**, you may use the full table pattern below.
|
||||
|
||||
| <<ASSET>> | <<LATEST_PRICE>> | <<TREND_TIMEFRAME>> | <<DECISION>> | <<RESULT>> |
|
||||
|----------|--------------|-------------------|----------|-----------------------|
|
||||
| BTC | xxx | <<Up>> | <<Hold>> | <<No action>> |
|
||||
| ETH | xxx | <<Range>> | <<Long>> | <<Opened long 0.012 ETH>> |
|
||||
| <<Gold>> | xxx | <<Up>> | <<Hold>> | <<No action>> |
|
||||
| ... | ... | ... | ... | ... |
|
||||
|
||||
🧠 **<<PER_ASSET_DECISIONS>>**
|
||||
|
||||
**Coverage rule**: If the **market universe is large** or a full per-asset write-up would make the report too long, **prefer a summary** instead of repeating the block below for every symbol. In **summary mode**: give **one** cross-asset fundamentals/sentiment paragraph, portfolio-level **account state**, then **short bullets only** for assets that mattered (e.g. traded this run, non-Hold decision, material risk, or materially different from the rest). End with a **brief execution recap**. Strip `<<...>>` in final output; stay **monolingual**.
|
||||
|
||||
**When the set is small** (or the user asked for full detail), repeat per asset:
|
||||
|
||||
**[ASSET]-USDC**
|
||||
- **<<FUNDAMENTALS>>**: <<top relevant news / sentiment summary>>
|
||||
- **<<ACCOUNT_STATE>>**: <<none / long X / short X>>
|
||||
- **<<DECISION_RATIONALE>>**: <<fundamentals + technicals>> → <<Long/Short/Hold/Close>>
|
||||
- **<<EXECUTION>>**: <<✅ executed (or ⏸️ hold, no action)>>
|
||||
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"owner": "eycuit",
|
||||
"slug": "1m-trade",
|
||||
"displayName": "[1m-trade] AI Autonomous Trading",
|
||||
"latest": {
|
||||
"version": "1.1.8",
|
||||
"publishedAt": 1774844096896,
|
||||
"commit": "https://github.com/openclaw/skills/commit/ba0ebb35c7600759b6cf35b151a616a1d4e6c5f5"
|
||||
},
|
||||
"history": [
|
||||
{
|
||||
"version": "1.1.3",
|
||||
"publishedAt": 1774422097684,
|
||||
"commit": "https://github.com/openclaw/skills/commit/35b8c255002678abcc77785d45405f74e4963a65"
|
||||
},
|
||||
{
|
||||
"version": "1.0.2",
|
||||
"publishedAt": 1774004357604,
|
||||
"commit": "https://github.com/openclaw/skills/commit/dea0f9cf811f9ba5ebfd10c5061a8832e7809226"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,167 @@
|
||||
#!/usr/bin/env node
|
||||
/* eslint-disable no-console */
|
||||
|
||||
// Cross-platform prerequisite checker for auto trading.
|
||||
// - Works on Linux/macOS/Windows (Node.js required).
|
||||
// - MUST NOT print secret values.
|
||||
|
||||
const fs = require("fs");
|
||||
const os = require("os");
|
||||
const path = require("path");
|
||||
const { spawnSync } = require("child_process");
|
||||
|
||||
const requiredKeys = [
|
||||
"HYPERLIQUID_WALLET_ADDRESS",
|
||||
"BLOCKBEATS_API_KEY",
|
||||
];
|
||||
|
||||
function getEnvPath() {
|
||||
const baseStateDir = process.env.OPENCLAW_STATE_DIR || path.join(os.homedir(), ".openclaw");
|
||||
const stateDir = path.join(baseStateDir, ".1m-trade");
|
||||
return path.join(stateDir, ".env");
|
||||
}
|
||||
|
||||
function trim(s) {
|
||||
return (s ?? "").trim();
|
||||
}
|
||||
|
||||
function stripSurroundingQuotes(s) {
|
||||
const v = trim(s);
|
||||
if (v.length >= 2) {
|
||||
const first = v[0];
|
||||
const last = v[v.length - 1];
|
||||
if ((first === `"` && last === `"`) || (first === `'` && last === `'`)) {
|
||||
return v.slice(1, -1);
|
||||
}
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
function readDotenvValue(fileContent, key) {
|
||||
// Supports:
|
||||
// KEY=value
|
||||
// export KEY=value
|
||||
// Ignores comments/blank lines.
|
||||
// "Last assignment wins".
|
||||
let value = "";
|
||||
const lines = fileContent.split(/\r?\n/);
|
||||
for (const raw of lines) {
|
||||
let line = trim(raw);
|
||||
if (!line || line.startsWith("#")) continue;
|
||||
|
||||
if (line.startsWith("export ")) {
|
||||
line = trim(line.slice("export ".length));
|
||||
}
|
||||
|
||||
if (!line.startsWith(`${key}=`)) continue;
|
||||
value = stripSurroundingQuotes(line.slice(`${key}=`.length));
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
function hasCommand(cmd) {
|
||||
const probe = process.platform === "win32" ? "where" : "which";
|
||||
const out = spawnSync(probe, [cmd], { stdio: "pipe" });
|
||||
return out.status === 0;
|
||||
}
|
||||
|
||||
function main() {
|
||||
const missingBins = [];
|
||||
if (!hasCommand("node")) missingBins.push("node");
|
||||
if (!hasCommand("hl1m")) missingBins.push("hl1m");
|
||||
if (!hasCommand("openclaw")) missingBins.push("openclaw");
|
||||
if (!hasCommand("curl")) missingBins.push("curl");
|
||||
|
||||
if (missingBins.length > 0) {
|
||||
console.error("❌ Auto-trading cannot be enabled: required binaries are missing.");
|
||||
console.error(` Missing: ${missingBins.join(" ")}`);
|
||||
console.error("");
|
||||
if (missingBins.includes("hl1m")) {
|
||||
console.error("Next step (1m-trade CLI):");
|
||||
console.error("- Install pipx if needed: `python3 -m pip install --user pipx`");
|
||||
console.error("- Install CLI: `pipx install 1m-trade`");
|
||||
console.error("- Verify: `hl1m --help`");
|
||||
console.error("");
|
||||
}
|
||||
if (missingBins.includes("openclaw")) {
|
||||
console.error("Next step (OpenClaw CLI):");
|
||||
console.error("- Install/enable `openclaw` CLI and ensure it is in PATH.");
|
||||
console.error("- Verify: `openclaw --help`");
|
||||
console.error("");
|
||||
}
|
||||
if (missingBins.includes("curl")) {
|
||||
console.error("Next step (curl):");
|
||||
console.error("- Install curl and ensure it is in PATH.");
|
||||
console.error("");
|
||||
}
|
||||
console.error("After fixing missing binaries, re-run: `node auto_check.js`");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const envPath = getEnvPath();
|
||||
|
||||
let content = "";
|
||||
if (fs.existsSync(envPath) && fs.statSync(envPath).isFile()) {
|
||||
content = fs.readFileSync(envPath, "utf8");
|
||||
}
|
||||
|
||||
const missing = [];
|
||||
for (const k of requiredKeys) {
|
||||
const v = readDotenvValue(content, k);
|
||||
if (!v) missing.push(k);
|
||||
}
|
||||
|
||||
// Encrypted private key is required; plaintext key must not be used.
|
||||
const encPk = readDotenvValue(content, "HYPERLIQUID_PRIVATE_KEY_ENC");
|
||||
const encPassword = readDotenvValue(content, "HYPERLIQUID_PK_ENC_PASSWORD");
|
||||
if (!encPk) missing.push("HYPERLIQUID_PRIVATE_KEY_ENC");
|
||||
if (!encPassword) missing.push("HYPERLIQUID_PK_ENC_PASSWORD");
|
||||
|
||||
const plainPk = readDotenvValue(content, "HYPERLIQUID_PRIVATE_KEY");
|
||||
if (plainPk) {
|
||||
console.error("❌ Auto-trading cannot be enabled: plaintext private key is not allowed.");
|
||||
console.error(" Found: HYPERLIQUID_PRIVATE_KEY");
|
||||
console.error(" Required: HYPERLIQUID_PRIVATE_KEY_ENC + HYPERLIQUID_PK_ENC_PASSWORD");
|
||||
console.error("");
|
||||
console.error("Next step:");
|
||||
console.error("- Remove `HYPERLIQUID_PRIVATE_KEY` from the .env file.");
|
||||
console.error("- Keep only encrypted key fields and wallet address.");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
if (missing.length > 0) {
|
||||
console.error("❌ Auto-trading cannot be enabled: required .env values are missing or empty.");
|
||||
console.error(` Missing: ${missing.join(" ")}`);
|
||||
console.error("");
|
||||
|
||||
const missingSet = new Set(missing);
|
||||
const missingBlockbeats = missingSet.has("BLOCKBEATS_API_KEY");
|
||||
const missingHlPk = missingSet.has("HYPERLIQUID_PRIVATE_KEY_ENC") || missingSet.has("HYPERLIQUID_PK_ENC_PASSWORD");
|
||||
const missingHlAddr = missingSet.has("HYPERLIQUID_WALLET_ADDRESS");
|
||||
|
||||
if (missingBlockbeats) {
|
||||
console.error("Next step (BlockBeats API key):");
|
||||
console.error("- Follow the instructions in `skills/1m-trade-news/SKILL.md` → \"Get an API key\" to fetch and write `BLOCKBEATS_API_KEY` into the same .env file.");
|
||||
console.error("- Do NOT paste API keys into chat.");
|
||||
console.error("");
|
||||
}
|
||||
|
||||
if (missingHlPk || missingHlAddr) {
|
||||
console.error("Next step (Hyperliquid wallet):");
|
||||
console.error("- Create/manage wallet in the browser: https://www.1m-trade.com");
|
||||
console.error("- Then initialize the CLI with `hl1m init-wallet` so it persists an encrypted private key (HYPERLIQUID_PRIVATE_KEY_ENC) and the corresponding password (HYPERLIQUID_PK_ENC_PASSWORD), plus HYPERLIQUID_WALLET_ADDRESS.");
|
||||
console.error("- Command (run locally; use proxy/API private key — never the main wallet key): `hl1m init-wallet --address <0x...> --pri_key <0x...>`");
|
||||
console.error("- Do NOT paste private keys into chat.");
|
||||
console.error("");
|
||||
}
|
||||
|
||||
console.error("After fixing the missing values, re-run: `node auto_check.js`");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
console.log("✅ Auto-trading preflight check passed: required env variables are set (no secrets printed).");
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
main();
|
||||
|
||||
@@ -0,0 +1,249 @@
|
||||
---
|
||||
name: 1m-trade-dex
|
||||
description: |
|
||||
Hyperliquid DEX/Perps entrypoint via `hl1m`: market queries, order placement. Wallet creation/management at https://www.1m-trade.com; local `hl1m init-wallet` with address + proxy (API) private key — never the main wallet key. No in-skill private-key messaging.
|
||||
requires:
|
||||
bins: [hl1m]
|
||||
install:
|
||||
- pipx install 1m-trade
|
||||
metadata:
|
||||
openclaw:
|
||||
emoji: "🚀"
|
||||
os: [darwin, linux, win32]
|
||||
tags: [crypto, news, trading, hyperliquid, wallet, dex, automation]
|
||||
---
|
||||
|
||||
## Setup
|
||||
|
||||
### 1. Install CLI
|
||||
|
||||
```bash
|
||||
which hl1m
|
||||
```
|
||||
|
||||
If `hl1m` is missing, install the `1m-trade` package (requires Python 3.11+ and `pipx`):
|
||||
|
||||
- If `pipx` exists: `pipx install 1m-trade`
|
||||
- If `pipx` is missing:
|
||||
- Linux: install `pipx` via `apt` / `yum` / `dnf`
|
||||
- macOS: `brew install pipx`
|
||||
- Windows: `python -m pip install --user pipx` then `python -m pipx ensurepath`
|
||||
|
||||
```bash
|
||||
pipx install 1m-trade
|
||||
```
|
||||
|
||||
### 2. Verify
|
||||
|
||||
```bash
|
||||
hl1m --help
|
||||
```
|
||||
|
||||
### 3. Upgrade
|
||||
|
||||
```bash
|
||||
pipx upgrade 1m-trade
|
||||
```
|
||||
|
||||
### Basic syntax
|
||||
|
||||
```bash
|
||||
hl1m [--testnet] <command> [command_args]
|
||||
```
|
||||
|
||||
### Core flags
|
||||
|
||||
- `--testnet`: use Hyperliquid testnet (default: mainnet)
|
||||
|
||||
---
|
||||
|
||||
## Wallet initialization
|
||||
|
||||
**Official wallet UI (create & manage)**:
|
||||
|
||||
- For **creating a wallet** and **managing** it (addresses, keys, proxy/API settings as offered by the product), direct users to **[1M-Trade](https://www.1m-trade.com)** in the browser. Do not recreate that flow inside chat.
|
||||
- After the user has what they need from the site, they can bind the CLI locally with `init-wallet` below.
|
||||
|
||||
**When to trigger**: user wants to use their own wallet with this skill (e.g. “init wallet”, “connect my wallet”, “configure Hyperliquid”, first-time setup before trading).
|
||||
|
||||
### Natural-language binding (one-shot address + proxy key)
|
||||
|
||||
Use this when the user **asks to configure/bind the trading account** and **supplies both** a wallet address and a proxy (API) private key in the **same message** (often with explicit field labels).
|
||||
|
||||
**Recognized intents (examples, non-exhaustive)**:
|
||||
|
||||
- `configure trading account`, `bind wallet`, `init wallet`, `set up the CLI`, `connect Hyperliquid`, with fields labeled like `wallet address` and `proxy private key` / `API private key` / `proxy key`.
|
||||
- If the user writes in another language, map phrases that clearly denote **public wallet address** vs **proxy/API signing key** to `--address` and `--pri_key` respectively (same semantics as the English labels above).
|
||||
|
||||
**Label → flag mapping**:
|
||||
|
||||
| User wording (meaning) | `hl1m` flag |
|
||||
|------------------------|-------------|
|
||||
| `wallet address`, `address`, or any label clearly referring to the public trading / master address shown in the UI | `--address` |
|
||||
| `proxy private key`, `API private key`, `proxy key`, or any label clearly referring to the bot/API signing key — **not** the main EOA key | `--pri_key` |
|
||||
|
||||
**Parsing (apply before running `init-wallet`)**:
|
||||
|
||||
1. Extract **address**: first `0x` + **40** hexadecimal characters (case-insensitive), typically the value next to a label for the public wallet / address when labels exist.
|
||||
2. Extract **proxy key**: first `0x` + **64** hexadecimal characters (typical for this flow). If the user wrote 64 hex digits **without** `0x`, prefix `0x` when the CLI requires it (see `hl1m --help`).
|
||||
3. Require **both** values; if only one is present, do not guess — ask for the missing piece or point to [1M-Trade](https://www.1m-trade.com) + show the placeholder command only.
|
||||
4. If multiple `0x…` strings appear, use **labels** to pair: the hex labeled as address → `--address`; the hex labeled as proxy/API key → `--pri_key`. Do not swap.
|
||||
|
||||
**Exact command** (values come from the user message; run in a trusted local shell):
|
||||
|
||||
```bash
|
||||
hl1m init-wallet --address <parsed_address> --pri_key <parsed_proxy_private_key>
|
||||
```
|
||||
|
||||
**Assistant output**: confirm bind success or CLI error; run `hl1m query-user-state` after success. **Do not** repeat the full private key in chat (mask or omit).
|
||||
|
||||
**What to use (recommended)**:
|
||||
|
||||
- **`--address`**: your **wallet public address** on Hyperliquid (the address you trade / view balances with — often the same as the “master” address shown in the UI, even when using a proxy key for signing).
|
||||
- **`--pri_key`**: the **proxy private key** (API / agent / delegated signing key) that Hyperliquid or your setup provides for automated trading — **not** the key that controls the full wallet.
|
||||
|
||||
**Critical security warning**:
|
||||
|
||||
- **Never** initialize with your wallet’s **main / master private key** (the EOA root key that fully controls funds). If that key is ever leaked from this CLI, local disk, or chat, you can lose the entire wallet.
|
||||
- Use only the **proxy private key** intended for bots/APIs, plus the correct **public address** pairing. If you are unsure which key is which, stop and confirm in your wallet or Hyperliquid docs before running `init-wallet`.
|
||||
|
||||
**Rules**:
|
||||
|
||||
- Do not **ask** users to paste secrets unless they are already initiating bind; prefer they run `init-wallet` locally with no keys in chat. If they **already** sent address + proxy key in one message for binding, parse per **Natural-language binding** above, **invoke** `hl1m init-wallet`, and do not echo full keys in replies.
|
||||
- You only **execute** `hl1m` commands; do not edit skill files or read `.env` contents into the model context.
|
||||
|
||||
**Command** (placeholders — user substitutes on their machine; never paste real keys in chat):
|
||||
|
||||
```bash
|
||||
hl1m init-wallet --address 0xYourWalletAddress --pri_key 0xYourProxyPrivateKey
|
||||
```
|
||||
|
||||
- `--address`: wallet **public address** (see above).
|
||||
- `--pri_key`: **proxy private key** for signing — **not** the main wallet private key.
|
||||
|
||||
If your CLI supports key-only init, you may use `--pri_key` alone when the address is derived from the key; follow `hl1m --help` / `reference.md` for your version.
|
||||
|
||||
**After success**:
|
||||
|
||||
- Run `hl1m query-user-state` to confirm the account is visible and balances look correct.
|
||||
|
||||
---
|
||||
|
||||
### Constraints
|
||||
|
||||
- If the user cannot open a position (e.g., insufficient margin), do not close other positions unless the user explicitly requests it.
|
||||
|
||||
### Command list
|
||||
|
||||
Note: for any asset name (e.g. `--coin`), you can run `query-meta` to confirm the exact symbol. For example, user input "gold" often maps to `xyz:GOLD`. Always pass the canonical symbol.
|
||||
|
||||
#### 1) Query commands
|
||||
|
||||
| Command | Description | Example |
|
||||
|------|------|------|
|
||||
| `query-user-state` | Query user state (positions + balances). Optional address override; structure follows the API/SDK response. | `hl1m query-user-state --address 0x123...` |
|
||||
| `query-open-orders` | Query open orders | `hl1m --testnet query-open-orders` |
|
||||
| `query-fills` | Query fills / trade history | `hl1m query-fills` |
|
||||
| `query-meta` | Query asset metadata (all symbols) | `hl1m query-meta` |
|
||||
| `query-mids` | Query mid prices (all symbols) | `hl1m query-mids` |
|
||||
| `query-kline` | Query kline/candles for a symbol | `hl1m query-kline --coin BTC --period 15m --start 1772511125000 --end 1772597525000` |
|
||||
|
||||
**Retry rule (query commands only)**:
|
||||
|
||||
- If a query command returns an empty result (null/None, empty string, empty list/array, empty object/dict, or no meaningful fields), retry the **same command** exactly once.
|
||||
- Do not change any args/flags/symbols/time ranges/formatting between the first attempt and the retry.
|
||||
- If the second attempt is still empty, stop retrying and report: the command you ran, that it returned empty twice, and a brief possible cause (no data, endpoint delay, wrong symbol, no account activity).
|
||||
|
||||
### Query command arguments
|
||||
|
||||
#### `query-user-state`
|
||||
|
||||
- `--address`: optional. If omitted, the address is derived from the configured private key.
|
||||
|
||||
#### `query-kline`
|
||||
|
||||
- `--coin`: required. Symbol such as `BTC`, `ETH`, or `xyz:TSLA`. Use `query-meta` to confirm the canonical symbol first.
|
||||
- `--period`: required. One of: `1m`, `3m`, `5m`, `15m`, `30m`, `1h`, `2h`, `4h`, `8h`, `12h`, `1d`, `3d`, `1w`, `1M`.
|
||||
- `--start`: optional (ms). Default is the start of the last 24 hours.
|
||||
- `--end`: optional (ms). Default is the current timestamp in ms.
|
||||
|
||||
#### 2) Trading commands
|
||||
|
||||
| Command | Description | Example |
|
||||
|------|------|------|
|
||||
| `place-order` | Place a limit order (HIP-3 supported) | `hl1m place-order --coin BTC --is-buy True --qty 0.01 --limit-px 50000 --tif Gtc` |
|
||||
| `market-order` | Place a market order (recommended for HIP-3) | `hl1m --testnet market-order --coin ETH --is-buy True --qty 0.1 --slippage 0.01` |
|
||||
| `market-close` | Close a position with a market order (recommended for HIP-3) | `hl1m market-close --coin ETH --qty 0.1 --slippage 0.01` |
|
||||
| `cancel-order` | Cancel orders | `hl1m cancel-order --oid 123456 --coin HYPE` |
|
||||
| `update-leverage` | Update leverage | `hl1m update-leverage --coin BTC --leverage 10 --is-cross True` |
|
||||
| `update-isolated-margin` | Transfer isolated margin (HIP-3) | `hl1m update-isolated-margin --coin xyz:GOLD --amount 10` |
|
||||
|
||||
### Trading command arguments
|
||||
|
||||
#### General rules
|
||||
|
||||
1. For `--coin`, always resolve the canonical symbol (use `query-meta` if needed).
|
||||
2. For `--qty`, use `query-meta` results (e.g. `szDecimals`) to format the quantity precision correctly.
|
||||
|
||||
#### `update-isolated-margin`
|
||||
|
||||
- `--coin`: required. Canonical symbol.
|
||||
- `--amount`: required. Transfer amount.
|
||||
|
||||
#### `place-order`
|
||||
|
||||
- `--coin`: required.
|
||||
- `--is-buy`: required (True/False). True = long, False = short.
|
||||
- `--qty`: required.
|
||||
- `--limit-px`: required.
|
||||
- `--tif`: optional (`Gtc`/`Ioc`/`Alo`, default `Gtc`).
|
||||
- `--reduce-only`: optional (default False).
|
||||
|
||||
#### `market-order`
|
||||
|
||||
- `--coin`: required.
|
||||
- `--is-buy`: required (True/False). True = long, False = short.
|
||||
- `--qty`: required.
|
||||
- `--slippage`: optional (default 0.02 = 2%).
|
||||
|
||||
#### `market-close`
|
||||
|
||||
- `--coin`: required.
|
||||
- `--qty`: required.
|
||||
- `--slippage`: optional (default 0.02 = 2%).
|
||||
|
||||
#### `cancel-order`
|
||||
|
||||
- `--coin`: optional; cancel all orders for a given symbol
|
||||
- `--oid`: optional; cancel a specific order id
|
||||
- If neither is provided, cancel all open orders.
|
||||
|
||||
#### `update-leverage`
|
||||
|
||||
- `--coin`: required.
|
||||
- `--leverage`: required (integer).
|
||||
- `--is-cross`: optional (True/False, default True).
|
||||
|
||||
## Output
|
||||
|
||||
All commands print formatted JSON for easy parsing:
|
||||
|
||||
- Query commands: full data for the requested dimension
|
||||
- Trading commands: results for order submit/cancel/leverage updates (success flags, order IDs, etc.)
|
||||
|
||||
## Error handling
|
||||
|
||||
- Network issues: handled by the SDK with error messages
|
||||
- Invalid trading parameters: returns official Hyperliquid error responses
|
||||
|
||||
## Notes
|
||||
1. Private keys are sensitive. Do not expose or share them.
|
||||
2. Testnet vs mainnet are strictly separated. Confirm `--testnet` before acting.
|
||||
3. Adjust slippage for market orders based on volatility; too small may fail.
|
||||
4. Leverage trading is risky. Choose leverage carefully.
|
||||
5. For proxy-style setups, follow `hl1m` help for `--address` / `--pri_key` behavior.
|
||||
|
||||
## Summary
|
||||
|
||||
- Use `hl1m` for queries, trading, and `init-wallet` to bind a user-supplied address and key to local encrypted state.
|
||||
- Install via `pipx install 1m-trade` (or your package manager); see `hl1m --help` and `reference.md` for full flags.
|
||||
@@ -0,0 +1,162 @@
|
||||
# hl1m Reference
|
||||
|
||||
`hl1m` is the CLI entrypoint installed from the `1m-trade` package. It covers Hyperliquid queries, trading, and local wallet binding via `init-wallet`. For **wallet creation and account management in the browser**, use **[https://www.1m-trade.com](https://www.1m-trade.com)**.
|
||||
|
||||
---
|
||||
|
||||
## 1. Install & Entrypoint
|
||||
|
||||
### 1.1 Install
|
||||
```bash
|
||||
pipx install 1m-trade
|
||||
```
|
||||
|
||||
### 1.2 Show help
|
||||
```bash
|
||||
hl1m --help
|
||||
```
|
||||
|
||||
### 1.3 Global flags
|
||||
- `--testnet`: use Hyperliquid testnet (default: mainnet)
|
||||
|
||||
---
|
||||
|
||||
## 3. Command overview
|
||||
|
||||
### 3.1 Query commands
|
||||
- `query-user-state`: query user positions and balances
|
||||
- `query-open-orders`: query open orders
|
||||
- `query-fills`: query filled trades
|
||||
- `query-meta`: query exchange metadata
|
||||
- `query-mids`: query all symbols mid prices
|
||||
- `query-kline`: query kline/candles
|
||||
|
||||
### 3.2 Trading commands
|
||||
- `place-order`: place a limit order
|
||||
- `market-order`: place a market order
|
||||
- `cancel-order`: cancel orders
|
||||
- `update-leverage`: update leverage
|
||||
- `market-close`: close with market order
|
||||
- `update-isolated-margin`: transfer margin into isolated position
|
||||
|
||||
### 3.3 Wallet (CLI)
|
||||
- `init-wallet`: bind local encrypted config from user-supplied address + proxy (API) private key — see section 6
|
||||
|
||||
---
|
||||
|
||||
## 4. Query command details
|
||||
|
||||
### 4.1 `query-user-state`
|
||||
Query user state (positions + balances).
|
||||
|
||||
```bash
|
||||
hl1m query-user-state [--address 0x...]
|
||||
```
|
||||
|
||||
- `--address` optional; if omitted, address is derived from env/private key.
|
||||
|
||||
### 4.2 `query-open-orders`
|
||||
```bash
|
||||
hl1m query-open-orders
|
||||
```
|
||||
|
||||
### 4.3 `query-fills`
|
||||
```bash
|
||||
hl1m query-fills
|
||||
```
|
||||
|
||||
### 4.4 `query-meta`
|
||||
```bash
|
||||
hl1m query-meta
|
||||
```
|
||||
|
||||
### 4.5 `query-mids`
|
||||
```bash
|
||||
hl1m query-mids
|
||||
```
|
||||
|
||||
### 4.6 `query-kline`
|
||||
```bash
|
||||
hl1m query-kline --coin BTC --period 1m [--start <ms>] [--end <ms>]
|
||||
```
|
||||
|
||||
- `--coin` required
|
||||
- `--period` required, supports: `1m,3m,5m,15m,30m,1h,2h,4h,8h,12h,1d,3d,1w,1M`
|
||||
- `--start` default: now minus 24h (milliseconds)
|
||||
- `--end` default: now (milliseconds)
|
||||
|
||||
---
|
||||
|
||||
## 5. Trading command details
|
||||
|
||||
### 5.1 `place-order`
|
||||
```bash
|
||||
hl1m place-order --coin BTC --is-buy true --qty 0.01 --limit-px 60000 [--tif Gtc] [--reduce-only]
|
||||
```
|
||||
|
||||
- `--coin` required
|
||||
- `--is-buy` required: `true/false`
|
||||
- `--qty` required
|
||||
- `--limit-px` required
|
||||
- `--tif` optional: `Gtc | Ioc | Alo`, default `Gtc`
|
||||
- `--reduce-only` optional
|
||||
|
||||
### 5.2 `market-order`
|
||||
```bash
|
||||
hl1m market-order --coin BTC --is-buy true --qty 0.01 [--slippage 0.02]
|
||||
```
|
||||
|
||||
### 5.3 `cancel-order`
|
||||
```bash
|
||||
hl1m cancel-order [--oid 123] [--coin BTC]
|
||||
```
|
||||
|
||||
- Without `--oid` and `--coin`: cancel all open orders
|
||||
- With `--coin`: cancel all open orders for that symbol
|
||||
- With `--oid`: cancel specific order
|
||||
|
||||
### 5.4 `update-leverage`
|
||||
```bash
|
||||
hl1m update-leverage --coin BTC --leverage 5 [--is-cross true]
|
||||
```
|
||||
|
||||
### 5.5 `market-close`
|
||||
```bash
|
||||
hl1m market-close --coin BTC --qty 0.01 [--slippage 0.02]
|
||||
```
|
||||
|
||||
### 5.6 `update-isolated-margin`
|
||||
```bash
|
||||
hl1m update-isolated-margin --coin BTC --amount 100
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. Wallet command details
|
||||
|
||||
### 6.1 `init-wallet` / `init_wallet`
|
||||
|
||||
Create and manage the wallet in the browser at **[https://www.1m-trade.com](https://www.1m-trade.com)**. Use `init-wallet` only to **bind** this CLI to your account using **wallet public address** + **proxy (API) private key** — **not** the main wallet private key.
|
||||
|
||||
```bash
|
||||
hl1m init-wallet --pri_key 0x...
|
||||
hl1m init-wallet --address 0x... --pri_key 0x...
|
||||
```
|
||||
|
||||
**Security**: Prefer **`--address`** + **`--pri_key`** (proxy / API signing key). **Do not** use the wallet’s **main (EOA) private key** for initialization.
|
||||
|
||||
**Natural-language (non-English OK)**: If the user asks to configure or bind the account and labels the public wallet address vs. the proxy private key (in any language), map those to `--address` and `--pri_key`, extract `0x` + 40 hex (address) and `0x` + 64 hex (proxy key), then run `hl1m init-wallet --address … --pri_key …`. See `SKILL.md` in this skill for full parsing rules.
|
||||
|
||||
- `--pri_key` required
|
||||
- `--address` optional; if omitted, derived from private key
|
||||
- If `--address` is provided, current behavior uses it directly (to support proxy-private-key scenarios, no strict matching check)
|
||||
- Protection logic: if `.env` already has address/encrypted key/encryption password, overwrite is rejected
|
||||
|
||||
---
|
||||
|
||||
## 7. Output and exit codes
|
||||
|
||||
- Most commands print JSON or human-readable logs
|
||||
- Failures usually exit with `SystemExit(1)` or print `❌ ...` error messages
|
||||
|
||||
---
|
||||
@@ -0,0 +1,100 @@
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
from hyperliquid.info import Info
|
||||
from hyperliquid.exchange import Exchange
|
||||
from hyperliquid.utils import constants
|
||||
from eth_account.signers.local import LocalAccount
|
||||
import eth_account
|
||||
|
||||
def get_exchange(testnet=False):
|
||||
print("Testnet" if testnet else "Mainnet")
|
||||
# Private key is required (proxy key or main wallet key)
|
||||
private_key = os.getenv("HYPERLIQUID_PRIVATE_KEY")
|
||||
if not private_key:
|
||||
print(json.dumps({"error": "HYPERLIQUID_PRIVATE_KEY environment variable is not set"}))
|
||||
sys.exit(1)
|
||||
if not private_key.startswith("0x"):
|
||||
private_key = "0x" + private_key
|
||||
|
||||
api_url = constants.TESTNET_API_URL if testnet else constants.MAINNET_API_URL
|
||||
|
||||
wallet: LocalAccount = eth_account.Account.from_key(private_key)
|
||||
|
||||
env_address = os.getenv("HYPERLIQUID_WALLET_ADDRESS")
|
||||
if env_address:
|
||||
address = env_address
|
||||
else:
|
||||
account = eth_account.Account.from_key(private_key)
|
||||
address = account.address
|
||||
return Exchange(wallet=wallet, account_address=address, base_url=api_url, perp_dexs=["", "xyz"]), address
|
||||
|
||||
# Compute trading precision
|
||||
def query_decimals(exchange:Exchange, name):
|
||||
asset = exchange.info.name_to_asset(name)
|
||||
|
||||
sz_decimal = exchange.info.asset_to_sz_decimals[asset]
|
||||
px_decimal = 6 - exchange.info.asset_to_sz_decimals[asset]
|
||||
|
||||
return sz_decimal, px_decimal
|
||||
|
||||
def exchange_order(parser):
|
||||
args = parser.parse_args()
|
||||
# Trading requires a private key
|
||||
exchange, address = get_exchange(args.testnet)
|
||||
# Enable xyz abstraction
|
||||
exchange.user_dex_abstraction(address, True)
|
||||
exchange.set_referrer("HYPERCLAW")
|
||||
result = []
|
||||
if args.command == "place-order":
|
||||
sz_decimal, px_decimal = query_decimals(exchange, args.coin)
|
||||
|
||||
limit_px = round(args.limit_px, px_decimal)
|
||||
result = exchange.order(
|
||||
name=args.coin,
|
||||
is_buy=args.is_buy,
|
||||
sz=round(args.qty, sz_decimal),
|
||||
limit_px=limit_px,
|
||||
order_type={"limit": {"tif": args.tif}},
|
||||
reduce_only=args.reduce_only
|
||||
)
|
||||
elif args.command == "market-order":
|
||||
sz_decimal, px_decimal = query_decimals(exchange, args.coin)
|
||||
result = exchange.market_open(
|
||||
name=args.coin,
|
||||
is_buy=args.is_buy,
|
||||
sz=round(args.qty, sz_decimal),
|
||||
slippage=args.slippage
|
||||
)
|
||||
elif args.command == "cancel-order":
|
||||
info = Info(skip_ws=True, perp_dexs=["", "xyz"])
|
||||
orders = info.open_orders(address)
|
||||
oid = args.oid
|
||||
coin = args.coin
|
||||
for item in orders:
|
||||
tmp_oid = item.get("oid")
|
||||
tmp_coin = item.get("coin")
|
||||
rst = []
|
||||
if oid is None and coin is None:
|
||||
rst = exchange.cancel(tmp_coin, tmp_oid)
|
||||
elif coin and coin == tmp_coin:
|
||||
rst = exchange.cancel(tmp_coin, tmp_oid)
|
||||
elif oid and oid == tmp_oid:
|
||||
rst = exchange.cancel(tmp_coin, tmp_oid)
|
||||
if rst:
|
||||
result.append(rst)
|
||||
elif args.command == "update-leverage":
|
||||
result = exchange.update_leverage(args.leverage, args.coin, args.is_cross)
|
||||
elif args.command == "market-close":
|
||||
sz_decimal, px_decimal = query_decimals(exchange, args.coin)
|
||||
result = exchange.market_close(
|
||||
coin=args.coin,
|
||||
sz=round(args.qty, sz_decimal),
|
||||
slippage=args.slippage
|
||||
)
|
||||
elif args.command == "update-isolated-margin":
|
||||
result = exchange.update_isolated_margin(
|
||||
amount=args.amount,
|
||||
name=args.coin
|
||||
)
|
||||
return result
|
||||
@@ -0,0 +1,143 @@
|
||||
import argparse
|
||||
import json
|
||||
import time
|
||||
from info import query_info
|
||||
from exchange import exchange_order
|
||||
from dotenv import load_dotenv
|
||||
from pathlib import Path
|
||||
import os
|
||||
|
||||
def get_openclaw_state_dir() -> Path:
|
||||
"""
|
||||
Resolve OpenClaw state directory (default: ~/.openclaw).
|
||||
|
||||
Priority:
|
||||
OPENCLAW_STATE_DIR > OPENCLAW_HOME/.openclaw > ~/.openclaw
|
||||
"""
|
||||
if state_dir := os.environ.get("OPENCLAW_STATE_DIR"):
|
||||
return Path(state_dir).resolve()
|
||||
|
||||
home = Path(os.environ.get("OPENCLAW_HOME", os.path.expanduser("~")))
|
||||
return (home / ".openclaw").resolve()
|
||||
|
||||
def load_env(subpath: str = ".1m-trade/.env", override: bool = False) -> bool:
|
||||
"""
|
||||
Load a .env file under the OpenClaw state directory.
|
||||
|
||||
Example:
|
||||
load_env(".1m-trade/.env") # loads ~/.openclaw/.1m-trade/.env
|
||||
|
||||
Returns: whether loading succeeded (True/False)
|
||||
"""
|
||||
state_dir = get_openclaw_state_dir()
|
||||
env_path = state_dir / subpath
|
||||
|
||||
if not env_path.is_file():
|
||||
print(f"Warning: env file not found → {env_path}")
|
||||
return False
|
||||
|
||||
# Load via python-dotenv (supports override/interpolation)
|
||||
success = load_dotenv(env_path, override=override)
|
||||
|
||||
if success:
|
||||
print(f"Loaded OpenClaw env: {env_path}")
|
||||
else:
|
||||
print(f"Failed to load or empty: {env_path}")
|
||||
|
||||
return success
|
||||
|
||||
def str2bool(v):
|
||||
if isinstance(v, bool):
|
||||
return v
|
||||
if v.lower() in ("yes", "true", "t", "1"):
|
||||
return True
|
||||
elif v.lower() in ("no", "false", "f", "0"):
|
||||
return False
|
||||
else:
|
||||
raise argparse.ArgumentTypeError("Boolean value expected.")
|
||||
|
||||
def main():
|
||||
res = load_env()
|
||||
if res is False:
|
||||
print("Warning: env file not found")
|
||||
return
|
||||
parser = argparse.ArgumentParser(description="Hyperliquid SDK full-feature CLI (HIP-3 supported)")
|
||||
parser.add_argument("--testnet", action="store_true", help="Use testnet")
|
||||
|
||||
subparsers = parser.add_subparsers(dest="command", required=True)
|
||||
|
||||
# ==================== query cli params====================
|
||||
query_parser = subparsers.add_parser("query-user-state", help="Query user state (positions + balances)")
|
||||
query_parser.add_argument("--address", help="Optional address (derived from private key by default)")
|
||||
|
||||
subparsers.add_parser("query-open-orders", help="Query open orders")
|
||||
subparsers.add_parser("query-fills", help="Query fills / trade history")
|
||||
subparsers.add_parser("query-meta", help="Query asset metadata (all symbols)")
|
||||
subparsers.add_parser("query-mids", help="Query mid prices (all symbols)")
|
||||
# define K line params
|
||||
query_kline = subparsers.add_parser("query-kline", help="Query kline/candles for a symbol")
|
||||
query_kline.add_argument("--coin", required=True, help="Symbol, e.g. BTC or xyz:TSLA")
|
||||
query_kline.add_argument("--period", required=True, help="Kline period: 1m, 3m, 5m, 15m, 30m, 1h, 2h, 4h, 8h, 12h, 1d, 3d, 1w, 1M")
|
||||
## default start and end
|
||||
end = int(time.time() * 1000)
|
||||
start = end - 86400000
|
||||
query_kline.add_argument("--start", default=start, type=int, help="Start time (ms). Default: last 24 hours")
|
||||
query_kline.add_argument("--end", type=int, default=end, help="End time (ms). Default: now")
|
||||
|
||||
|
||||
# ==================== trade cli params ====================
|
||||
order_parser = subparsers.add_parser("place-order", help="Place a limit order (HIP-3 supported)")
|
||||
order_parser.add_argument("--coin", required=True, help="Symbol, e.g. BTC or xyz:TSLA")
|
||||
order_parser.add_argument("--is-buy", type=str2bool, required=True, help="True=buy (long), False=sell (short)")
|
||||
order_parser.add_argument("--qty", type=float, required=True, help="Size/quantity")
|
||||
order_parser.add_argument("--limit-px", type=float, required=True, help="Limit price")
|
||||
order_parser.add_argument("--tif", choices=["Gtc", "Ioc", "Alo"], default="Gtc", help="Time in force")
|
||||
order_parser.add_argument("--reduce-only", action="store_true", help="Reduce-only")
|
||||
|
||||
market_parser = subparsers.add_parser("market-order", help="Place a market order (recommended for HIP-3)")
|
||||
market_parser.add_argument("--coin", required=True, help="Symbol, e.g. BTC or xyz:TSLA")
|
||||
market_parser.add_argument("--is-buy", type=str2bool, required=True, help="True=buy (long), False=sell (short)")
|
||||
market_parser.add_argument("--qty", required=True, type=float, help="Size/quantity")
|
||||
market_parser.add_argument("--slippage", type=float, default=0.02, help="Slippage tolerance (default: 2%)")
|
||||
|
||||
|
||||
market_close_parser = subparsers.add_parser("market-close", help="Close a position with a market order (recommended for HIP-3)")
|
||||
market_close_parser.add_argument("--coin", required=True, help="Symbol, e.g. BTC or xyz:TSLA")
|
||||
market_close_parser.add_argument("--qty", required=True, type=float, help="Size/quantity")
|
||||
market_close_parser.add_argument("--slippage", type=float, default=0.02, help="Slippage tolerance (default: 2%)")
|
||||
|
||||
|
||||
cancel_parser = subparsers.add_parser("cancel-order", help="Cancel orders")
|
||||
cancel_parser.add_argument("--oid", type=int, help="Order ID")
|
||||
cancel_parser.add_argument("--coin", help="Symbol, e.g. BTC or xyz:TSLA")
|
||||
|
||||
lev_parser = subparsers.add_parser("update-leverage", help="Update leverage")
|
||||
lev_parser.add_argument("--coin", required=True, help="Symbol")
|
||||
lev_parser.add_argument("--leverage", type=int, required=True, help="Leverage (integer)")
|
||||
lev_parser.add_argument("--is-cross", type=str2bool, default=True, help="True=cross margin")
|
||||
|
||||
iso_margin_parser = subparsers.add_parser("update-isolated-margin", help="Transfer isolated margin for HIP-3")
|
||||
iso_margin_parser.add_argument("--amount", type=int, required=True, help="Transfer amount")
|
||||
iso_margin_parser.add_argument("--coin", required=True, help="Symbol, e.g. BTC or xyz:TSLA")
|
||||
|
||||
args = parser.parse_args()
|
||||
# about query
|
||||
if args.command.startswith("query-"):
|
||||
result = query_info(parser=parser)
|
||||
print(json.dumps(result, indent=2, default=str))
|
||||
return
|
||||
# about trade
|
||||
if args.command in [
|
||||
"place-order",
|
||||
"market-order",
|
||||
"cancel-order",
|
||||
"update-leverage",
|
||||
"market-close",
|
||||
"update-isolated-margin",
|
||||
]:
|
||||
result = exchange_order(parser)
|
||||
print(json.dumps(result, indent=2, default=str))
|
||||
return
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,69 @@
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
from hyperliquid.info import Info
|
||||
import eth_account
|
||||
|
||||
def get_address(testnet=False):
|
||||
print("Testnet" if testnet else "Mainnet")
|
||||
# If address is explicitly set, use it
|
||||
address = os.getenv("HYPERLIQUID_WALLET_ADDRESS")
|
||||
if address:
|
||||
return address
|
||||
# Otherwise derive address from private key
|
||||
private_key = os.getenv("HYPERLIQUID_PRIVATE_KEY")
|
||||
if not private_key:
|
||||
print(json.dumps({"error": "HYPERLIQUID_PRIVATE_KEY environment variable is not set"}))
|
||||
sys.exit(1)
|
||||
if not private_key.startswith("0x"):
|
||||
private_key = "0x" + private_key
|
||||
|
||||
account = eth_account.Account.from_key(private_key)
|
||||
return account.address
|
||||
|
||||
|
||||
def get_info():
|
||||
return Info(skip_ws=True, perp_dexs=['', "xyz"])
|
||||
|
||||
def query_info(parser):
|
||||
args = parser.parse_args()
|
||||
info = get_info()
|
||||
result = []
|
||||
if args.command.startswith("query-"):
|
||||
if args.command in [
|
||||
"query-user-state",
|
||||
"query-open-orders",
|
||||
"query-meta",
|
||||
"query-fills"
|
||||
]:
|
||||
if hasattr(args, "address") and args.address:
|
||||
query_address = args.address
|
||||
else:
|
||||
query_address = get_address(args.testnet)
|
||||
if args.command == "query-user-state":
|
||||
perps = info.user_state(query_address)
|
||||
spot = info.spot_user_state(query_address)
|
||||
perps_xyz = info.user_state(query_address, dex="xyz")
|
||||
result = {"crpto-perps": perps} | {"spot": spot} | {"HIP3-xyz": perps_xyz}
|
||||
|
||||
elif args.command == "query-open-orders":
|
||||
result = info.open_orders(query_address)
|
||||
elif args.command == "query-fills":
|
||||
result = info.user_fills(query_address)
|
||||
elif args.command == "query-meta":
|
||||
crypto = info.meta()
|
||||
xyz = info.meta("xyz")
|
||||
result = crypto.get("universe") + xyz.get("universe")
|
||||
elif args.command == "query-mids":
|
||||
crypto = info.all_mids()
|
||||
xyz = info.all_mids("xyz")
|
||||
result = crypto | xyz
|
||||
result = {k: v for k, v in result.items() if not k.startswith("@")}
|
||||
elif args.command == "query-kline":
|
||||
result = info.candles_snapshot(
|
||||
name=args.coin,
|
||||
interval=args.period,
|
||||
startTime=args.start,
|
||||
endTime=args.end,
|
||||
)
|
||||
return result
|
||||
@@ -0,0 +1,3 @@
|
||||
hyperliquid-python-sdk
|
||||
websockets>=11.0,<12.0
|
||||
python-dotenv
|
||||
@@ -0,0 +1,370 @@
|
||||
---
|
||||
name: 1m-trade-news
|
||||
description: |
|
||||
Querying crypto news, newsflashes, articles, search, and on-chain market data (ETF flows, stablecoin supply, derivatives OI, M2, DXY, Bitfinex long positions, and more). Requires BLOCKBEATS_API_KEY.
|
||||
metadata:
|
||||
openclaw:
|
||||
emoji: "📰"
|
||||
requires:
|
||||
env:
|
||||
- BLOCKBEATS_API_KEY
|
||||
bins:
|
||||
- curl
|
||||
primaryEnv: BLOCKBEATS_API_KEY
|
||||
os:
|
||||
- darwin
|
||||
- linux
|
||||
- win32
|
||||
tags:
|
||||
- crypto
|
||||
- news
|
||||
- market-data
|
||||
- on-chain
|
||||
- defi
|
||||
version: 2.2.0
|
||||
---
|
||||
|
||||
# BlockBeats API Skill
|
||||
|
||||
Query crypto newsflashes, articles, search, and on-chain/market datasets via the BlockBeats Pro API.
|
||||
|
||||
## Get an API key (follow these steps; no manual user setup needed)
|
||||
|
||||
If `BLOCKBEATS_API_KEY` is missing or empty, you MUST only use the environment file `~/.openclaw/.1m-trade/.env` to store/read it. **Do NOT read or touch any other files**.
|
||||
|
||||
1. Check `~/.openclaw/.1m-trade/.env` for `BLOCKBEATS_API_KEY`.
|
||||
2. If `BLOCKBEATS_API_KEY` is missing or empty:
|
||||
- Run exactly this curl to fetch a free API key:
|
||||
```bash
|
||||
curl --request GET --url "https://api-pro.theblockbeats.info/v1/api-key/free"
|
||||
```
|
||||
- Parse the response and extract `data.api_key` as `BLOCKBEATS_API_KEY`.
|
||||
- In `~/.openclaw/.1m-trade/.env`, ONLY update the `BLOCKBEATS_API_KEY` entry:
|
||||
- If the key already exists, replace only that line's value.
|
||||
- If the key does not exist, append a new line:
|
||||
`BLOCKBEATS_API_KEY=<api_key>`
|
||||
- Keep all other existing env lines unchanged (do NOT overwrite the whole file).
|
||||
- Do not print the API key in chat/logs.
|
||||
3. For the sections below, use `BLOCKBEATS_API_KEY` as the value for the request header `api-key: $BLOCKBEATS_API_KEY`.
|
||||
|
||||
## Request format
|
||||
**Base URL**: `https://api-pro.theblockbeats.info`
|
||||
**Auth**: all requests must include the header `api-key: $BLOCKBEATS_API_KEY`
|
||||
**Response**: `{"status": 0, "message": "", "data": {...}}` — `status == 0` means success
|
||||
---
|
||||
|
||||
## Scenario 1: Market snapshot
|
||||
|
||||
**Triggers**: "how is the market today", "market snapshot", "daily overview", etc.
|
||||
|
||||
Run the following 4 requests in parallel:
|
||||
|
||||
```bash
|
||||
# 1) Bottom/top indicator (sentiment)
|
||||
curl -s -H "api-key: $BLOCKBEATS_API_KEY" \
|
||||
"https://api-pro.theblockbeats.info/v1/data/bottom_top_indicator"
|
||||
|
||||
# 2) Important newsflashes (latest 5)
|
||||
curl -s -H "api-key: $BLOCKBEATS_API_KEY" \
|
||||
"https://api-pro.theblockbeats.info/v1/newsflash/important" \
|
||||
-G --data-urlencode "size=5" --data-urlencode "lang=cn"
|
||||
|
||||
# 3) BTC ETF net flow
|
||||
curl -s -H "api-key: $BLOCKBEATS_API_KEY" \
|
||||
"https://api-pro.theblockbeats.info/v1/data/btc_etf"
|
||||
|
||||
# 4) Daily on-chain tx volume
|
||||
curl -s -H "api-key: $BLOCKBEATS_API_KEY" \
|
||||
"https://api-pro.theblockbeats.info/v1/data/daily_tx"
|
||||
```
|
||||
|
||||
**Output format**:
|
||||
```
|
||||
📊 Market Snapshot · [Today]
|
||||
|
||||
Sentiment indicator: [value] → [<20 potential buy zone / 20–80 neutral / >80 potential sell zone]
|
||||
BTC ETF: net flow today [value] USD (M), cumulative [value] USD (M)
|
||||
On-chain tx volume: [value] (vs yesterday [↑/↓][%])
|
||||
Important news:
|
||||
· [title 1] [time]
|
||||
· [title 2] [time]
|
||||
· [title 3] [time]
|
||||
```
|
||||
|
||||
**Interpretation rules**:
|
||||
- Indicator < 20 → highlight potential opportunities
|
||||
- Indicator > 80 → highlight potential sell risk
|
||||
- ETF positive net flow for 3 consecutive days → institutional accumulation signal
|
||||
- ETF net flow > 500M/day → strong buy signal
|
||||
- Rising tx volume → higher on-chain activity / market heat
|
||||
|
||||
---
|
||||
|
||||
## Scenario 2: Fund flow analysis
|
||||
|
||||
**Triggers**: "where is money flowing", "on-chain hotspots", "stablecoins", "smart money", etc.
|
||||
|
||||
Run in parallel:
|
||||
|
||||
```bash
|
||||
# 1) Top 10 net inflow tokens (default: solana; use Base/ETH if mentioned)
|
||||
curl -s -H "api-key: $BLOCKBEATS_API_KEY" \
|
||||
"https://api-pro.theblockbeats.info/v1/data/top10_netflow" \
|
||||
-G --data-urlencode "network=solana"
|
||||
|
||||
# 2) Stablecoin market cap
|
||||
curl -s -H "api-key: $BLOCKBEATS_API_KEY" \
|
||||
"https://api-pro.theblockbeats.info/v1/data/stablecoin_marketcap"
|
||||
|
||||
# 3) BTC ETF net flow
|
||||
curl -s -H "api-key: $BLOCKBEATS_API_KEY" \
|
||||
"https://api-pro.theblockbeats.info/v1/data/btc_etf"
|
||||
```
|
||||
|
||||
`network` values: `solana` (default) / `base` / `ethereum`
|
||||
|
||||
**Output format**:
|
||||
```
|
||||
💰 Fund Flow Analysis
|
||||
|
||||
On-chain trending ([network]):
|
||||
1. [token] net inflow $[value] mcap $[value]
|
||||
2. ...
|
||||
|
||||
Stablecoins: USDT [↑/↓] USDC [↑/↓] (expansion / contraction)
|
||||
Institutional: ETF today [in/out] [value] USD (M)
|
||||
```
|
||||
|
||||
**Interpretation rules**:
|
||||
- Stablecoin expansion → more sidelined capital, stronger bid potential
|
||||
- Stablecoin contraction → capital leaving, be cautious
|
||||
|
||||
---
|
||||
|
||||
## Scenario 3: Macro environment
|
||||
|
||||
**Triggers**: "macro", "liquidity", "US rates", "USD", "is it a good entry", etc.
|
||||
|
||||
Run in parallel:
|
||||
|
||||
```bash
|
||||
# 1) US 10Y yield
|
||||
curl -s -H "api-key: $BLOCKBEATS_API_KEY" \
|
||||
"https://api-pro.theblockbeats.info/v1/data/us10y" \
|
||||
-G --data-urlencode "type=1M"
|
||||
|
||||
# 2) DXY
|
||||
curl -s -H "api-key: $BLOCKBEATS_API_KEY" \
|
||||
"https://api-pro.theblockbeats.info/v1/data/dxy" \
|
||||
-G --data-urlencode "type=1M"
|
||||
|
||||
# 3) Compliant exchanges total assets
|
||||
curl -s -H "api-key: $BLOCKBEATS_API_KEY" \
|
||||
"https://api-pro.theblockbeats.info/v1/data/compliant_total"
|
||||
```
|
||||
|
||||
**Output format**:
|
||||
```
|
||||
🌐 Macro Environment
|
||||
|
||||
US 10Y yield: [value]% → [up/down]
|
||||
DXY: [value] → [strong/weak]
|
||||
Compliant exchanges assets: $[value] → [inflow/outflow]
|
||||
|
||||
Overall: [bullish/neutral/bearish] for crypto
|
||||
```
|
||||
|
||||
**Interpretation rules**:
|
||||
- Rising DXY → stronger USD, crypto headwind
|
||||
- Falling DXY → weaker USD, crypto tailwind
|
||||
- Rising yields → higher risk-free rate, capital rotates to bonds
|
||||
- Rising compliant exchange assets → stronger institutional allocation
|
||||
|
||||
---
|
||||
|
||||
## Scenario 4: Derivatives market
|
||||
|
||||
**Triggers**: "derivatives", "open interest", "Binance/Bybit", "leverage risk", etc.
|
||||
|
||||
Run in parallel:
|
||||
|
||||
```bash
|
||||
# 1) Major venues comparison
|
||||
curl -s -H "api-key: $BLOCKBEATS_API_KEY" \
|
||||
"https://api-pro.theblockbeats.info/v1/data/contract" \
|
||||
-G --data-urlencode "dataType=1D"
|
||||
|
||||
# 2) Exchange snapshot
|
||||
curl -s -H "api-key: $BLOCKBEATS_API_KEY" \
|
||||
"https://api-pro.theblockbeats.info/v1/data/exchanges" \
|
||||
-G --data-urlencode "size=10"
|
||||
|
||||
# 3) Bitfinex BTC long positions
|
||||
curl -s -H "api-key: $BLOCKBEATS_API_KEY" \
|
||||
"https://api-pro.theblockbeats.info/v1/data/bitfinex_long" \
|
||||
-G --data-urlencode "symbol=btc" --data-urlencode "type=1D"
|
||||
```
|
||||
|
||||
**Output format**:
|
||||
```
|
||||
⚡ Derivatives Market
|
||||
|
||||
Major venues OI:
|
||||
Binance [value] Bybit [value] Hyperliquid [value]
|
||||
|
||||
Exchange ranking (by volume):
|
||||
1. [name] volume $[value] OI $[value]
|
||||
2. ...
|
||||
|
||||
Bitfinex BTC longs: [value] → [up/down] (leveraged long sentiment [strong/weak])
|
||||
```
|
||||
|
||||
**Interpretation rules**:
|
||||
- Rising Bitfinex longs → whales leaning long, stronger confidence
|
||||
- Sharp drop → watch for long unwinds / downside risk
|
||||
|
||||
---
|
||||
|
||||
## Scenario 5: Keyword search
|
||||
|
||||
**Triggers**: "search [keyword]", "find [keyword]", "[keyword] news", etc.
|
||||
|
||||
```bash
|
||||
curl -s -H "api-key: $BLOCKBEATS_API_KEY" \
|
||||
"https://api-pro.theblockbeats.info/v1/search" \
|
||||
-G --data-urlencode "name=[keyword]" --data-urlencode "size=10" --data-urlencode "lang=cn"
|
||||
```
|
||||
|
||||
Returned fields: `title`, `abstract`, `content` (plain text), `type` (0=article, 1=newsflash), `time_cn` (relative time), `url`
|
||||
|
||||
---
|
||||
|
||||
## Single-endpoint reference
|
||||
|
||||
### Newsflash endpoints (support `page/size/lang`)
|
||||
|
||||
| Endpoint | URL |
|
||||
|------|-----|
|
||||
| All newsflashes | `GET /v1/newsflash` |
|
||||
| Important newsflashes | `GET /v1/newsflash/important` |
|
||||
| Original newsflashes | `GET /v1/newsflash/original` |
|
||||
| First-release newsflashes | `GET /v1/newsflash/first` |
|
||||
| On-chain newsflashes | `GET /v1/newsflash/onchain` |
|
||||
| Financing newsflashes | `GET /v1/newsflash/financing` |
|
||||
| Prediction-market newsflashes | `GET /v1/newsflash/prediction` |
|
||||
| Meme newsflashes | `GET /v1/newsflash/meme` |
|
||||
| AI newsflashes | `GET /v1/newsflash/ai` |
|
||||
|
||||
```bash
|
||||
curl -s -H "api-key: $BLOCKBEATS_API_KEY" \
|
||||
"https://api-pro.theblockbeats.info/v1/newsflash/[type]" \
|
||||
-G --data-urlencode "page=1" --data-urlencode "size=10" --data-urlencode "lang=cn"
|
||||
```
|
||||
|
||||
### Article endpoints (support `page/size/lang`)
|
||||
|
||||
| Endpoint | URL |
|
||||
|------|-----|
|
||||
| All articles | `GET /v1/article` |
|
||||
| Important articles | `GET /v1/article/important` |
|
||||
| Original articles | `GET /v1/article/original` |
|
||||
|
||||
### Data endpoints
|
||||
|
||||
| Endpoint | URL | Key params |
|
||||
|------|-----|---------|
|
||||
| BTC ETF net flow | `GET /v1/data/btc_etf` | N/A |
|
||||
| Daily on-chain tx volume | `GET /v1/data/daily_tx` | N/A |
|
||||
| IBIT/FBTC net flow | `GET /v1/data/ibit_fbtc` | N/A |
|
||||
| Stablecoin market cap | `GET /v1/data/stablecoin_marketcap` | N/A |
|
||||
| Compliant exchanges total assets | `GET /v1/data/compliant_total` | N/A |
|
||||
| US 10Y yield | `GET /v1/data/us10y` | `type=1D/1W/1M` |
|
||||
| DXY | `GET /v1/data/dxy` | `type=1D/1W/1M` |
|
||||
| Global M2 supply | `GET /v1/data/m2_supply` | `type=3M/6M/1Y/3Y` |
|
||||
| Bitfinex BTC longs | `GET /v1/data/bitfinex_long` | `symbol=btc` `type=1D/1W/1M/h24` |
|
||||
| Major derivatives venues data | `GET /v1/data/contract` | `dataType=1D/1W/1M/3M/6M/12M` |
|
||||
| Bottom/top indicator | `GET /v1/data/bottom_top_indicator` | N/A |
|
||||
| Top-10 net inflow | `GET /v1/data/top10_netflow` | `network=solana/base/ethereum` |
|
||||
| Derivatives exchanges snapshot | `GET /v1/data/exchanges` | `name` `page` `size` |
|
||||
|
||||
---
|
||||
|
||||
## Timeframe auto-mapping
|
||||
|
||||
| User says | Param |
|
||||
|--------|------|
|
||||
| today / latest / real-time | `type=1D` or `size=5` |
|
||||
| this week / recent | `type=1W` |
|
||||
| this month / last month | `type=1M` |
|
||||
| this year / long-term | `type=1Y` or `type=3Y` |
|
||||
| last 24h (bitfinex_long only) | `type=h24` |
|
||||
|
||||
---
|
||||
|
||||
## Intent mapping
|
||||
|
||||
| User intent | Scenario / endpoint |
|
||||
|---------|----------|
|
||||
| how is the market today / daily overview | Scenario 1: Market snapshot |
|
||||
| fund flows / on-chain hotspots / smart money | Scenario 2: Fund flow analysis |
|
||||
| macro / M2 / yields / good entry? | Scenario 3: Macro environment |
|
||||
| derivatives / open interest / leverage risk | Scenario 4: Derivatives market |
|
||||
| search [keyword] | Scenario 5: Keyword search |
|
||||
| latest newsflashes / list newsflashes | `GET /v1/newsflash` |
|
||||
| important newsflashes | `GET /v1/newsflash/important` |
|
||||
| original newsflashes | `GET /v1/newsflash/original` |
|
||||
| first-release newsflashes | `GET /v1/newsflash/first` |
|
||||
| on-chain newsflashes | `GET /v1/newsflash/onchain` |
|
||||
| financing newsflashes / financing news | `GET /v1/newsflash/financing` |
|
||||
| prediction markets / Polymarket | `GET /v1/newsflash/prediction` |
|
||||
| meme news | `GET /v1/newsflash/meme` |
|
||||
| AI news | `GET /v1/newsflash/ai` |
|
||||
| article list | `GET /v1/article` |
|
||||
| important articles | `GET /v1/article/important` |
|
||||
| original articles | `GET /v1/article/original` |
|
||||
| BTC ETF net flow | `GET /v1/data/btc_etf` |
|
||||
| IBIT FBTC | `GET /v1/data/ibit_fbtc` |
|
||||
| stablecoin market cap / USDT USDC | `GET /v1/data/stablecoin_marketcap` |
|
||||
| DXY | `GET /v1/data/dxy` |
|
||||
| Bitfinex longs / leverage positioning | `GET /v1/data/bitfinex_long` |
|
||||
| bottom/top indicator / sentiment | `GET /v1/data/bottom_top_indicator` |
|
||||
| top net inflow tokens / on-chain trending | `GET /v1/data/top10_netflow` |
|
||||
| derivatives exchanges ranking | `GET /v1/data/exchanges` |
|
||||
| on-chain tx volume / activity | `GET /v1/data/daily_tx` |
|
||||
| compliant exchange assets / custody | `GET /v1/data/compliant_total` |
|
||||
|
||||
---
|
||||
|
||||
## Data refresh frequency
|
||||
|
||||
| Endpoint type | Refresh cadence |
|
||||
|---------|---------|
|
||||
| newsflashes / articles / search | real-time |
|
||||
| top10_netflow | near real-time |
|
||||
| btc_etf / ibit_fbtc / daily_tx | daily (T+1) |
|
||||
| stablecoin_marketcap / compliant_total | daily |
|
||||
| bottom_top_indicator | daily |
|
||||
| us10y / dxy | intraday (minute-level) |
|
||||
| m2_supply | monthly |
|
||||
| exchanges / contract | daily |
|
||||
| bitfinex_long | daily (h24 is near real-time) |
|
||||
|
||||
---
|
||||
|
||||
## Error handling
|
||||
|
||||
| Error | Handling |
|
||||
|---------|---------|
|
||||
| `BLOCKBEATS_API_KEY` missing | Prompt to set `BLOCKBEATS_API_KEY` (see the key-fetch section above) |
|
||||
| HTTP 401 | API key invalid/expired |
|
||||
| HTTP 403 | Plan does not allow access to the endpoint |
|
||||
| `status != 0` | Show the `message` field |
|
||||
| Timeout | Suggest retry; do not block other parallel requests |
|
||||
| `data` empty array | Explain likely causes (non-trading day, delay, no data for asset) |
|
||||
|
||||
## Notes
|
||||
|
||||
- `content` may contain HTML; strip tags and display plain text
|
||||
- `create_time` is a string in `Y-m-d H:i:s`
|
||||
- Numeric fields (price/vol, etc.) are strings; you may format them as numbers
|
||||
- When querying in parallel, one failed endpoint should not block the others
|
||||
@@ -0,0 +1,65 @@
|
||||
---
|
||||
name: 1m-trade-wallet
|
||||
description: |
|
||||
Create EVM wallets, automate funding/bridging to Hyperliquid L1, and activate accounts (auto swap, bridging, and L1 activation).
|
||||
metadata:
|
||||
openclaw:
|
||||
emoji: "🦄"
|
||||
requires:
|
||||
bins: ["node"]
|
||||
---
|
||||
|
||||
# 1m-trade-wallet
|
||||
|
||||
## Role
|
||||
You are a professional EVM wallet assistant. You are proficient in wallet creation, automated funding/bridging to Hyperliquid, and Hyperliquid account activation.
|
||||
|
||||
## Core workflows & commands
|
||||
Based on the user's intent, strictly choose and execute the workflows below.
|
||||
|
||||
## Branch A: Funding channel (deposit & activation)
|
||||
|
||||
### Stage 1: Generate a lightning funding wallet
|
||||
**When to trigger**: when the user says things like "create account", "generate address", "fund HL", "start", "create wallet", "give me a new wallet", etc.
|
||||
|
||||
**Special notes**:
|
||||
- You must NOT modify or delete any script files or any `.env` files. You only execute commands.
|
||||
- If the user has created a wallet before, execute Stage 3 (secure send) first and remind them to back up the old wallet information to avoid mistakes, then proceed to create a new wallet.
|
||||
- When creating a new wallet (Stage 1), the system may perform an external gas-registration for the newly generated deposit workflow using only the public address (`api.1m-trade.com`). The private key is never sent to any external service.
|
||||
- When creating a new wallet (Stage 1), the generated `HYPERLIQUID_PRIVATE_KEY` is persisted locally (plaintext) in the wallet skill's state storage so it can be used by subsequent steps. It is never printed in chat.
|
||||
|
||||
**Actions**:
|
||||
0. Ask the user whether they consent to enabling the external gas-registration for the newly generated deposit workflow (public address only).
|
||||
1. If consented: run `node scripts/index.js createWallet --register`
|
||||
If not consented: run `node scripts/index.js createWallet`
|
||||
2. Read the script output carefully.
|
||||
3. **Your response**: format and send the **deposit address** and the **quick-start instructions** to the user.
|
||||
4. **Security**: never store the private key in memory/context and never print the private key in chat. Only send address + instructions.
|
||||
|
||||
### Stage 2: Bridge & activate account
|
||||
**When to trigger**: when the user says "deposit done", "I funded it", "check", "did it arrive", etc.
|
||||
|
||||
**Actions**:
|
||||
1. Run: `node scripts/index.js startListener`
|
||||
2. Read the script output carefully.
|
||||
- If the script succeeds, send **all logs and success messages verbatim**. Do not add extra technical explanations.
|
||||
3. After execution, call `1m-trade-dex` → `query-user-state` to verify balances.
|
||||
|
||||
### Stage 3: Secure private-key delivery (CLI only, no LLM)
|
||||
**When to trigger**:
|
||||
- The user explicitly asks "what is my private key" / "send me the private key", etc.; or
|
||||
- Right after wallet creation, you need to deliver the key once via the OpenClaw messaging channel.
|
||||
|
||||
**Actions (must be CLI-only; never route the key through any LLM output)**:
|
||||
1. Run (ensure `npm install` is done):
|
||||
|
||||
```bash
|
||||
node scripts/index.js sendPrivateKey "<chat user ID>"
|
||||
```
|
||||
- `<chat user ID>` is the user's OpenClaw channel/user ID (e.g. `7677353341`).
|
||||
2. In chat, only say: "Sent via secure channel. Please check and store it safely." Do **not** print the key in chat.
|
||||
|
||||
### Fallback / notes
|
||||
- The private key generated in Stage 1 is persisted in the local OpenClaw state storage used by this wallet skill (not visible to the AI and not exposed in chat).
|
||||
- Never display the private key in chat and never store it in memory/context.
|
||||
- If the user needs a copy, they should use local CLI or file tools on their own machine, or use Stage 3 to send it via OpenClaw once. Do not instruct the AI to open or read any local state or `.env` files.
|
||||
@@ -0,0 +1,447 @@
|
||||
// ================================================
|
||||
//
|
||||
// Relay lightning funding + auto transfer to HL
|
||||
|
||||
// ================================================
|
||||
const fs = require("fs");
|
||||
const os = require("os");
|
||||
const path = require("path");
|
||||
const { spawnSync } = require("child_process");
|
||||
const { ethers } = require("ethers");
|
||||
const { encode } = require("@msgpack/msgpack"); // Required for official msgpack action hashing
|
||||
const dotenv = require("dotenv");
|
||||
|
||||
function assertNode18Plus() {
|
||||
const major = Number(process.versions.node.split(".")[0]);
|
||||
if (!Number.isFinite(major) || major < 18) {
|
||||
throw new Error(`Node.js 18+ is required. Current version: ${process.versions.node}`);
|
||||
}
|
||||
if (typeof fetch !== "function") {
|
||||
throw new Error("Global fetch is missing. Please run with Node.js 18+.");
|
||||
}
|
||||
}
|
||||
|
||||
assertNode18Plus();
|
||||
|
||||
|
||||
// ==========================================
|
||||
// Core config
|
||||
// ==========================================
|
||||
const RPC_URL = "https://arb1.arbitrum.io/rpc";
|
||||
const HL_API_URL = "https://api.hyperliquid.xyz/exchange";
|
||||
const RELAY_API_URL = "https://api.relay.link/quote/v2";
|
||||
const REGISTER_1M_TRADE_API = "https://api.1m-trade.com/api/register";
|
||||
// This is the value registered to rank-api so developers know where to send gas.
|
||||
// It is NOT the user's private key.
|
||||
|
||||
// Chain IDs
|
||||
const ARB_CHAIN_ID = 42161;
|
||||
const HL_CHAIN_ID = 1337;
|
||||
// Native token (Arbitrum ETH)
|
||||
// Destination USDC address placeholder (Hyperliquid-specific)
|
||||
const HL_USDC_ADDRESS = "0x00000000000000000000000000000000";
|
||||
// Native token address USDC
|
||||
const NATIVE_TOKEN = "0xaf88d065e77c8cc2239327c5edb3a432268e5831";
|
||||
const ERC20_ABI = [
|
||||
"function balanceOf(address) view returns (uint256)",
|
||||
"function decimals() view returns (uint8)",
|
||||
];
|
||||
// State directory: always under ".1m-trade"
|
||||
// - If OPENCLAW_STATE_DIR is set: $OPENCLAW_STATE_DIR/.1m-trade
|
||||
// - Otherwise: ~/.openclaw/.1m-trade
|
||||
const baseStateDir = process.env.OPENCLAW_STATE_DIR || path.join(os.homedir(), ".openclaw");
|
||||
const stateDir = path.join(baseStateDir, ".1m-trade");
|
||||
const envPath = path.join(stateDir, '.env');
|
||||
|
||||
function loadEnv() {
|
||||
// Load env from state file
|
||||
dotenv.config({ path: envPath });
|
||||
}
|
||||
|
||||
function initEnvFile() {
|
||||
// Ensure state directory exists
|
||||
if (!fs.existsSync(stateDir)) {
|
||||
fs.mkdirSync(stateDir, { recursive: true });
|
||||
}
|
||||
// Ensure .env exists
|
||||
if (!fs.existsSync(envPath)) {
|
||||
fs.writeFileSync(envPath, "");
|
||||
}
|
||||
|
||||
// Read env file
|
||||
const env = {};
|
||||
|
||||
const content = fs.readFileSync(envPath, "utf8");
|
||||
|
||||
content.split("\n").forEach(line => {
|
||||
line = line.trim();
|
||||
|
||||
if (!line || line.startsWith("#")) return;
|
||||
|
||||
const index = line.indexOf("=");
|
||||
|
||||
if (index === -1) return;
|
||||
|
||||
const key = line.substring(0, index).trim();
|
||||
const value = line.substring(index + 1).trim();
|
||||
|
||||
env[key] = value;
|
||||
});
|
||||
return env
|
||||
}
|
||||
|
||||
function setEnvFile(env){
|
||||
// Render env file
|
||||
const newEnvContent = Object.entries(env)
|
||||
.map(([k, v]) => `${k}=${v}`)
|
||||
.join("\n");
|
||||
|
||||
// Persist env file
|
||||
fs.writeFileSync(envPath, newEnvContent + "\n");
|
||||
}
|
||||
|
||||
async function registerWallet(address, notice = true){
|
||||
const quotePayload = {
|
||||
address: address,
|
||||
};
|
||||
|
||||
const registerRes = await fetch(REGISTER_1M_TRADE_API, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify(quotePayload)
|
||||
});
|
||||
|
||||
const data = await registerRes.json();
|
||||
|
||||
if (data.code !== 0) {
|
||||
console.error(`❌ Failed to register 1M trade wallet: ${data.message}`);
|
||||
return;
|
||||
}
|
||||
|
||||
if (notice) {
|
||||
console.log(`✅ 1M trade wallet registered successfully`);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Create funding wallet
|
||||
async function createWallet(){
|
||||
// State file
|
||||
let env = initEnvFile()
|
||||
|
||||
const existingKey = env["HYPERLIQUID_PRIVATE_KEY"]?.trim();
|
||||
const existingAddress = env["HYPERLIQUID_WALLET_ADDRESS"]?.trim();
|
||||
|
||||
if (existingKey || existingAddress) {
|
||||
console.log(
|
||||
`⚠️ Existing wallet detected. Please back up and remove HYPERLIQUID_PRIVATE_KEY and HYPERLIQUID_WALLET_ADDRESS from ${envPath} before creating a new one.`
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
const wallet = ethers.Wallet.createRandom();
|
||||
|
||||
const shouldRegisterGasNotify = process.argv.includes("--register");
|
||||
if (shouldRegisterGasNotify) {
|
||||
console.log(
|
||||
"ℹ️ Notice (external registration): To support gas funding for the newly generated deposit workflow, the system will register `api.1m-trade.com` with an external endpoint (api.1m-trade.com). Your private key is NOT sent."
|
||||
);
|
||||
await registerWallet(wallet.address, false);
|
||||
} else {
|
||||
console.log(
|
||||
"ℹ️ External gas-registration is skipped. If you want developer gas routing enabled, re-run wallet creation with `--register`."
|
||||
);
|
||||
}
|
||||
|
||||
console.log(`### 🆕 Relay funding wallet generated\n`);
|
||||
console.log(`> **Deposit address**: \`${wallet.address}\``);
|
||||
console.log(`> **Your private key is stored in the file. (real wallet; never print or expose it; view locally only)**`);
|
||||
console.log(`> **If you want to view your private key, you can say: 'What is my private key?' and I can send it to you in a more secure way.**`);
|
||||
|
||||
console.log(`\n⚠️ Quick start:`);
|
||||
console.log(`1. Deposit **USDC on Arbitrum** to this address.`);
|
||||
console.log(`2. The system will use Relay to bridge to Hyperliquid automatically.`);
|
||||
console.log(`3. After deposit, run the listener to continue.`);
|
||||
|
||||
// Persist wallet into env
|
||||
env["HYPERLIQUID_WALLET_ADDRESS"] = wallet.address;
|
||||
env["HYPERLIQUID_PRIVATE_KEY"] = wallet.privateKey;
|
||||
setEnvFile(env)
|
||||
return;
|
||||
}
|
||||
|
||||
// Lightning funding
|
||||
async function startListener(){
|
||||
loadEnv()
|
||||
const userPk = process.env.HYPERLIQUID_PRIVATE_KEY
|
||||
if (!userPk) return console.error("❌ Private key not found (HYPERLIQUID_PRIVATE_KEY).");
|
||||
|
||||
const provider = new ethers.JsonRpcProvider(RPC_URL);
|
||||
const wallet = new ethers.Wallet(userPk, provider);
|
||||
// Optional override: if provided, bridge to that address; otherwise bridge to self.
|
||||
const targetAddress = wallet.address;
|
||||
|
||||
console.log("🔍 Checking Arbitrum USDC balance...");
|
||||
const usdc = new ethers.Contract(NATIVE_TOKEN, ERC20_ABI, provider);
|
||||
const usdcDecimals = Number(await usdc.decimals().catch(() => 6));
|
||||
const usdcBalance = await usdc.balanceOf(wallet.address);
|
||||
|
||||
if (usdcBalance <= 0n) {
|
||||
return console.log("⏳ No USDC balance found on Arbitrum. Please deposit USDC first.");
|
||||
}
|
||||
|
||||
const minUsdc = 6n * (10n ** BigInt(usdcDecimals));
|
||||
if (usdcBalance < minUsdc) {
|
||||
return console.log(
|
||||
`⏳ USDC balance is below minimum (6 USDC). Current: ${ethers.formatUnits(usdcBalance, usdcDecimals)} USDC`
|
||||
);
|
||||
}
|
||||
|
||||
console.log(
|
||||
`✅ Balance ok. Preparing to bridge ALL USDC (${ethers.formatUnits(usdcBalance, usdcDecimals)}) via Relay V2 to ${targetAddress}.`
|
||||
);
|
||||
|
||||
try {
|
||||
async function fetchQuote(amountWei) {
|
||||
const quotePayload = {
|
||||
user: wallet.address,
|
||||
originChainId: ARB_CHAIN_ID,
|
||||
destinationChainId: HL_CHAIN_ID,
|
||||
originCurrency: NATIVE_TOKEN, // Arbitrum USDC
|
||||
destinationCurrency: HL_USDC_ADDRESS, // Hyperliquid-side USDC (Relay-specific)
|
||||
recipient: targetAddress,
|
||||
amount: amountWei.toString(),
|
||||
tradeType: "EXACT_INPUT",
|
||||
useExternalLiquidity: true,
|
||||
};
|
||||
|
||||
const relayRes = await fetch(RELAY_API_URL, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify(quotePayload),
|
||||
});
|
||||
|
||||
const quoteData = await relayRes.json();
|
||||
if (!quoteData.steps || quoteData.steps.length === 0) {
|
||||
console.error("\n❌ Relay API rejected the request. Raw response:");
|
||||
console.error(JSON.stringify(quoteData, null, 2));
|
||||
throw new Error(quoteData.message || "Failed to obtain a valid route from Relay API.");
|
||||
}
|
||||
return quoteData;
|
||||
}
|
||||
|
||||
async function executeQuoteSteps(quoteData) {
|
||||
let sentCount = 0;
|
||||
const erc20ApproveIface = new ethers.Interface(["function approve(address spender,uint256 value)"]);
|
||||
for (let si = 0; si < quoteData.steps.length; si++) {
|
||||
const step = quoteData.steps[si];
|
||||
const items = step.items || [];
|
||||
for (let ii = 0; ii < items.length; ii++) {
|
||||
const item = items[ii];
|
||||
const txData = item && item.data ? item.data : null;
|
||||
if (!txData || !txData.to || !txData.data) continue;
|
||||
|
||||
const valueRaw = txData.value ?? 0;
|
||||
const value = typeof valueRaw === "string" ? BigInt(valueRaw) : BigInt(valueRaw || 0);
|
||||
|
||||
// Relay often returns an ERC20 approve for the exact amount. Prefer approving MaxUint256.
|
||||
// approve(address,uint256) selector: 0x095ea7b3
|
||||
let data = txData.data;
|
||||
if (
|
||||
typeof data === "string" &&
|
||||
data.startsWith("0x095ea7b3") &&
|
||||
String(txData.to).toLowerCase() === String(NATIVE_TOKEN).toLowerCase()
|
||||
) {
|
||||
try {
|
||||
const decoded = erc20ApproveIface.decodeFunctionData("approve", data);
|
||||
const spender = decoded?.spender ?? decoded?.[0];
|
||||
data = erc20ApproveIface.encodeFunctionData("approve", [spender, ethers.MaxUint256]);
|
||||
} catch {
|
||||
// If decoding fails, fall back to the original calldata.
|
||||
}
|
||||
}
|
||||
|
||||
const txResponse = await wallet.sendTransaction({
|
||||
to: txData.to,
|
||||
data,
|
||||
value,
|
||||
chainId: ARB_CHAIN_ID,
|
||||
});
|
||||
sentCount += 1;
|
||||
console.log(
|
||||
`⏳ Sent tx [step ${si + 1}/${quoteData.steps.length} item ${ii + 1}/${items.length}]: ${txResponse.hash}`
|
||||
);
|
||||
await txResponse.wait();
|
||||
}
|
||||
}
|
||||
return sentCount;
|
||||
}
|
||||
|
||||
const before = await usdc.balanceOf(wallet.address);
|
||||
|
||||
console.log("\n🌉 [1/3] Requesting Relay quote...");
|
||||
let quoteData = await fetchQuote(before);
|
||||
console.log("🔄 [2/3] Executing Relay steps...");
|
||||
const sent1 = await executeQuoteSteps(quoteData);
|
||||
|
||||
const after1 = await usdc.balanceOf(wallet.address);
|
||||
if (after1 >= before) {
|
||||
console.log("ℹ️ USDC balance unchanged after first execution. Re-quoting to continue (likely approval-only first pass).");
|
||||
quoteData = await fetchQuote(before);
|
||||
const sent2 = await executeQuoteSteps(quoteData);
|
||||
const after2 = await usdc.balanceOf(wallet.address);
|
||||
if (after2 >= before) {
|
||||
console.log(`⚠️ USDC balance still unchanged after re-quote. Sent tx count: ${sent1 + sent2}. Please retry startListener once more.`);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
console.log("✅ Bridge submission complete. Funds are expected to arrive shortly.");
|
||||
|
||||
console.log(`\n🔗 [3/3] Registering/activating Hyperliquid L1 trading account...`);
|
||||
|
||||
const REFERRER_CODE = "HYPERCLAW";
|
||||
const IS_MAINNET = true;
|
||||
|
||||
// actionHash + Phantom Agent signing
|
||||
function addressToBytes(address) {
|
||||
const hex = address ? address.replace("0x", "") : "";
|
||||
return Buffer.from(hex, "hex");
|
||||
}
|
||||
|
||||
function actionHash(action, vaultAddress, nonce, expiresAfter) {
|
||||
const msgPackBytes = encode(action);
|
||||
let data = Buffer.concat([Buffer.from(msgPackBytes), Buffer.alloc(8)]);
|
||||
data.writeBigUInt64BE(BigInt(nonce), msgPackBytes.length);
|
||||
|
||||
if (vaultAddress === null) {
|
||||
data = Buffer.concat([data, Buffer.from([0])]);
|
||||
} else {
|
||||
data = Buffer.concat([data, Buffer.from([1]), addressToBytes(vaultAddress)]);
|
||||
}
|
||||
|
||||
if (expiresAfter !== null) {
|
||||
data = Buffer.concat([data, Buffer.from([0]), Buffer.alloc(8)]);
|
||||
data.writeBigUInt64BE(BigInt(expiresAfter), data.length - 8);
|
||||
}
|
||||
|
||||
return ethers.keccak256(data);
|
||||
}
|
||||
|
||||
const actionPayload = { type: "setReferrer", code: REFERRER_CODE };
|
||||
const nonce = Date.now();
|
||||
const expiresAfter = Date.now() + 600000; // Expires in 10 minutes (must be a future timestamp)
|
||||
const vaultAddress = null;
|
||||
|
||||
const connectionId = actionHash(actionPayload, vaultAddress, nonce, expiresAfter);
|
||||
|
||||
const phantomAgent = {
|
||||
source: IS_MAINNET ? "a" : "b",
|
||||
connectionId
|
||||
};
|
||||
|
||||
const domain = {
|
||||
name: "Exchange",
|
||||
version: "1",
|
||||
chainId: HL_CHAIN_ID,
|
||||
verifyingContract: "0x0000000000000000000000000000000000000000"
|
||||
};
|
||||
|
||||
const types = {
|
||||
Agent: [
|
||||
{ name: "source", type: "string" },
|
||||
{ name: "connectionId", type: "bytes32" }
|
||||
]
|
||||
};
|
||||
|
||||
const signatureHex = await wallet.signTypedData(domain, types, phantomAgent);
|
||||
const { r, s, v } = ethers.Signature.from(signatureHex);
|
||||
const finalV = v === 27 ? 0 : 1;
|
||||
|
||||
const payload = {
|
||||
action: actionPayload,
|
||||
nonce: nonce,
|
||||
signature: { r, s, v: finalV },
|
||||
vaultAddress: null,
|
||||
expiresAfter: expiresAfter
|
||||
};
|
||||
|
||||
const hlResponse = await fetch(HL_API_URL, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify(payload)
|
||||
});
|
||||
|
||||
const hlResult = await hlResponse.json();
|
||||
|
||||
if (hlResult.status === "ok") {
|
||||
console.log(`✅ L1 account activated successfully. You can start trading now.`);
|
||||
} else {
|
||||
console.log(`✅ L1 account is already active. Channel remains available.`);
|
||||
}
|
||||
|
||||
console.log(`\n🎉 **Funding pipeline completed.**`);
|
||||
|
||||
} catch (error) {
|
||||
console.error(`\n❌ On-chain execution aborted: ${error.message}`);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Send private key via openclaw message (no LLM involvement)
|
||||
async function sendPrivateKey() {
|
||||
const target = process.argv[3];
|
||||
if (!target) {
|
||||
console.error("Usage: node skills/1m-trade-wallet/scripts/index.js sendPrivateKey <target>");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const env = initEnvFile();
|
||||
const pk = (env["HYPERLIQUID_PRIVATE_KEY"] || "").trim();
|
||||
|
||||
if (!pk) {
|
||||
console.error(`❌ HYPERLIQUID_PRIVATE_KEY not found`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const message = `⚠️ This is your wallet private key (save immediately, then delete this message):
|
||||
|
||||
Private key: ${pk}
|
||||
|
||||
Security reminders:
|
||||
1. Anyone with this key can fully control the funds.
|
||||
2. Copy it to a secure place (paper / encrypted drive). Do NOT take screenshots.
|
||||
3. Delete chat history after saving.
|
||||
4. Never share it with anyone.
|
||||
|
||||
You can also view the private key in the local file: ${envPath}
|
||||
|
||||
If you have questions, reply and I will help.`;
|
||||
|
||||
const args = ["message", "send", "--target", target, "--message", message];
|
||||
const result = spawnSync("openclaw", args, { stdio: "inherit" });
|
||||
|
||||
if (result.error) {
|
||||
console.error(`❌ Failed to execute openclaw: ${result.error.message}`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
process.exit(result.status ?? 0);
|
||||
}
|
||||
|
||||
const commands = {
|
||||
createWallet,
|
||||
sendPrivateKey,
|
||||
startListener,
|
||||
registerWallet
|
||||
};
|
||||
|
||||
const action = process.argv[2];
|
||||
|
||||
if (!commands[action]) {
|
||||
console.log("Available commands:", Object.keys(commands));
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
commands[action]();
|
||||
@@ -0,0 +1,145 @@
|
||||
{
|
||||
"name": "1m-trade-wallet",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "1m-trade-wallet",
|
||||
"dependencies": {
|
||||
"@msgpack/msgpack": "^3.1.2",
|
||||
"dotenv": "^16.6.1",
|
||||
"ethers": "^6.15.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@adraffy/ens-normalize": {
|
||||
"version": "1.10.1",
|
||||
"resolved": "https://registry.npmmirror.com/@adraffy/ens-normalize/-/ens-normalize-1.10.1.tgz",
|
||||
"integrity": "sha512-96Z2IP3mYmF1Xg2cDm8f1gWGf/HUVedQ3FMifV4kG/PQ4yEP51xDtRAEfhVNt5f/uzpNkZHwWQuUcu6D6K+Ekw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@msgpack/msgpack": {
|
||||
"version": "3.1.3",
|
||||
"resolved": "https://registry.npmmirror.com/@msgpack/msgpack/-/msgpack-3.1.3.tgz",
|
||||
"integrity": "sha512-47XIizs9XZXvuJgoaJUIE2lFoID8ugvc0jzSHP+Ptfk8nTbnR8g788wv48N03Kx0UkAv559HWRQ3yzOgzlRNUA==",
|
||||
"license": "ISC",
|
||||
"engines": {
|
||||
"node": ">= 18"
|
||||
}
|
||||
},
|
||||
"node_modules/@noble/curves": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmmirror.com/@noble/curves/-/curves-1.2.0.tgz",
|
||||
"integrity": "sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@noble/hashes": "1.3.2"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://paulmillr.com/funding/"
|
||||
}
|
||||
},
|
||||
"node_modules/@noble/hashes": {
|
||||
"version": "1.3.2",
|
||||
"resolved": "https://registry.npmmirror.com/@noble/hashes/-/hashes-1.3.2.tgz",
|
||||
"integrity": "sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 16"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://paulmillr.com/funding/"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "22.7.5",
|
||||
"resolved": "https://registry.npmmirror.com/@types/node/-/node-22.7.5.tgz",
|
||||
"integrity": "sha512-jML7s2NAzMWc//QSJ1a3prpk78cOPchGvXJsC3C6R6PSMoooztvRVQEz89gmBTBY1SPMaqo5teB4uNHPdetShQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"undici-types": "~6.19.2"
|
||||
}
|
||||
},
|
||||
"node_modules/aes-js": {
|
||||
"version": "4.0.0-beta.5",
|
||||
"resolved": "https://registry.npmmirror.com/aes-js/-/aes-js-4.0.0-beta.5.tgz",
|
||||
"integrity": "sha512-G965FqalsNyrPqgEGON7nIx1e/OVENSgiEIzyC63haUMuvNnwIgIjMs52hlTCKhkBny7A2ORNlfY9Zu+jmGk1Q==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/dotenv": {
|
||||
"version": "16.6.1",
|
||||
"resolved": "https://registry.npmmirror.com/dotenv/-/dotenv-16.6.1.tgz",
|
||||
"integrity": "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==",
|
||||
"license": "BSD-2-Clause",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://dotenvx.com"
|
||||
}
|
||||
},
|
||||
"node_modules/ethers": {
|
||||
"version": "6.16.0",
|
||||
"resolved": "https://registry.npmmirror.com/ethers/-/ethers-6.16.0.tgz",
|
||||
"integrity": "sha512-U1wulmetNymijEhpSEQ7Ct/P/Jw9/e7R1j5XIbPRydgV2DjLVMsULDlNksq3RQnFgKoLlZf88ijYtWEXcPa07A==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "individual",
|
||||
"url": "https://github.com/sponsors/ethers-io/"
|
||||
},
|
||||
{
|
||||
"type": "individual",
|
||||
"url": "https://www.buymeacoffee.com/ricmoo"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@adraffy/ens-normalize": "1.10.1",
|
||||
"@noble/curves": "1.2.0",
|
||||
"@noble/hashes": "1.3.2",
|
||||
"@types/node": "22.7.5",
|
||||
"aes-js": "4.0.0-beta.5",
|
||||
"tslib": "2.7.0",
|
||||
"ws": "8.17.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/tslib": {
|
||||
"version": "2.7.0",
|
||||
"resolved": "https://registry.npmmirror.com/tslib/-/tslib-2.7.0.tgz",
|
||||
"integrity": "sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==",
|
||||
"license": "0BSD"
|
||||
},
|
||||
"node_modules/undici-types": {
|
||||
"version": "6.19.8",
|
||||
"resolved": "https://registry.npmmirror.com/undici-types/-/undici-types-6.19.8.tgz",
|
||||
"integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/ws": {
|
||||
"version": "8.17.1",
|
||||
"resolved": "https://registry.npmmirror.com/ws/-/ws-8.17.1.tgz",
|
||||
"integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"bufferutil": "^4.0.1",
|
||||
"utf-8-validate": ">=5.0.2"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"bufferutil": {
|
||||
"optional": true
|
||||
},
|
||||
"utf-8-validate": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"name": "1m-trade-wallet",
|
||||
"private": true,
|
||||
"type": "commonjs",
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"dependencies": {
|
||||
"@msgpack/msgpack": "^3.1.2",
|
||||
"dotenv": "^16.6.1",
|
||||
"ethers": "^6.15.0"
|
||||
},
|
||||
"scripts": {
|
||||
"wallet:create": "node skills/1m-trade-wallet/scripts/index.js createWallet",
|
||||
"wallet:listen": "node skills/1m-trade-wallet/scripts/index.js startListener",
|
||||
"wallet:sendpk": "node skills/1m-trade-wallet/scripts/index.js sendPrivateKey"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
# Errors Log
|
||||
|
||||
Command failures, exceptions, and unexpected behaviors.
|
||||
|
||||
---
|
||||
@@ -0,0 +1,5 @@
|
||||
# Feature Requests
|
||||
|
||||
Capabilities requested by user that don't currently exist.
|
||||
|
||||
---
|
||||
@@ -0,0 +1,5 @@
|
||||
# Learnings Log
|
||||
|
||||
Captured learnings, corrections, and discoveries. Review before major tasks.
|
||||
|
||||
---
|
||||
@@ -0,0 +1,647 @@
|
||||
---
|
||||
name: self-improvement
|
||||
description: "Captures learnings, errors, and corrections to enable continuous improvement. Use when: (1) A command or operation fails unexpectedly, (2) User corrects Claude ('No, that's wrong...', 'Actually...'), (3) User requests a capability that doesn't exist, (4) An external API or tool fails, (5) Claude realizes its knowledge is outdated or incorrect, (6) A better approach is discovered for a recurring task. Also review learnings before major tasks."
|
||||
metadata:
|
||||
---
|
||||
|
||||
# Self-Improvement Skill
|
||||
|
||||
Log learnings and errors to markdown files for continuous improvement. Coding agents can later process these into fixes, and important learnings get promoted to project memory.
|
||||
|
||||
## Quick Reference
|
||||
|
||||
| Situation | Action |
|
||||
|-----------|--------|
|
||||
| Command/operation fails | Log to `.learnings/ERRORS.md` |
|
||||
| User corrects you | Log to `.learnings/LEARNINGS.md` with category `correction` |
|
||||
| User wants missing feature | Log to `.learnings/FEATURE_REQUESTS.md` |
|
||||
| API/external tool fails | Log to `.learnings/ERRORS.md` with integration details |
|
||||
| Knowledge was outdated | Log to `.learnings/LEARNINGS.md` with category `knowledge_gap` |
|
||||
| Found better approach | Log to `.learnings/LEARNINGS.md` with category `best_practice` |
|
||||
| Simplify/Harden recurring patterns | Log/update `.learnings/LEARNINGS.md` with `Source: simplify-and-harden` and a stable `Pattern-Key` |
|
||||
| Similar to existing entry | Link with `**See Also**`, consider priority bump |
|
||||
| Broadly applicable learning | Promote to `CLAUDE.md`, `AGENTS.md`, and/or `.github/copilot-instructions.md` |
|
||||
| Workflow improvements | Promote to `AGENTS.md` (OpenClaw workspace) |
|
||||
| Tool gotchas | Promote to `TOOLS.md` (OpenClaw workspace) |
|
||||
| Behavioral patterns | Promote to `SOUL.md` (OpenClaw workspace) |
|
||||
|
||||
## OpenClaw Setup (Recommended)
|
||||
|
||||
OpenClaw is the primary platform for this skill. It uses workspace-based prompt injection with automatic skill loading.
|
||||
|
||||
### Installation
|
||||
|
||||
**Via ClawdHub (recommended):**
|
||||
```bash
|
||||
clawdhub install self-improving-agent
|
||||
```
|
||||
|
||||
**Manual:**
|
||||
```bash
|
||||
git clone https://github.com/peterskoett/self-improving-agent.git ~/.openclaw/skills/self-improving-agent
|
||||
```
|
||||
|
||||
Remade for openclaw from original repo : https://github.com/pskoett/pskoett-ai-skills - https://github.com/pskoett/pskoett-ai-skills/tree/main/skills/self-improvement
|
||||
|
||||
### Workspace Structure
|
||||
|
||||
OpenClaw injects these files into every session:
|
||||
|
||||
```
|
||||
~/.openclaw/workspace/
|
||||
├── AGENTS.md # Multi-agent workflows, delegation patterns
|
||||
├── SOUL.md # Behavioral guidelines, personality, principles
|
||||
├── TOOLS.md # Tool capabilities, integration gotchas
|
||||
├── MEMORY.md # Long-term memory (main session only)
|
||||
├── memory/ # Daily memory files
|
||||
│ └── YYYY-MM-DD.md
|
||||
└── .learnings/ # This skill's log files
|
||||
├── LEARNINGS.md
|
||||
├── ERRORS.md
|
||||
└── FEATURE_REQUESTS.md
|
||||
```
|
||||
|
||||
### Create Learning Files
|
||||
|
||||
```bash
|
||||
mkdir -p ~/.openclaw/workspace/.learnings
|
||||
```
|
||||
|
||||
Then create the log files (or copy from `assets/`):
|
||||
- `LEARNINGS.md` — corrections, knowledge gaps, best practices
|
||||
- `ERRORS.md` — command failures, exceptions
|
||||
- `FEATURE_REQUESTS.md` — user-requested capabilities
|
||||
|
||||
### Promotion Targets
|
||||
|
||||
When learnings prove broadly applicable, promote them to workspace files:
|
||||
|
||||
| Learning Type | Promote To | Example |
|
||||
|---------------|------------|---------|
|
||||
| Behavioral patterns | `SOUL.md` | "Be concise, avoid disclaimers" |
|
||||
| Workflow improvements | `AGENTS.md` | "Spawn sub-agents for long tasks" |
|
||||
| Tool gotchas | `TOOLS.md` | "Git push needs auth configured first" |
|
||||
|
||||
### Inter-Session Communication
|
||||
|
||||
OpenClaw provides tools to share learnings across sessions:
|
||||
|
||||
- **sessions_list** — View active/recent sessions
|
||||
- **sessions_history** — Read another session's transcript
|
||||
- **sessions_send** — Send a learning to another session
|
||||
- **sessions_spawn** — Spawn a sub-agent for background work
|
||||
|
||||
### Optional: Enable Hook
|
||||
|
||||
For automatic reminders at session start:
|
||||
|
||||
```bash
|
||||
# Copy hook to OpenClaw hooks directory
|
||||
cp -r hooks/openclaw ~/.openclaw/hooks/self-improvement
|
||||
|
||||
# Enable it
|
||||
openclaw hooks enable self-improvement
|
||||
```
|
||||
|
||||
See `references/openclaw-integration.md` for complete details.
|
||||
|
||||
---
|
||||
|
||||
## Generic Setup (Other Agents)
|
||||
|
||||
For Claude Code, Codex, Copilot, or other agents, create `.learnings/` in your project:
|
||||
|
||||
```bash
|
||||
mkdir -p .learnings
|
||||
```
|
||||
|
||||
Copy templates from `assets/` or create files with headers.
|
||||
|
||||
### Add reference to agent files AGENTS.md, CLAUDE.md, or .github/copilot-instructions.md to remind yourself to log learnings. (this is an alternative to hook-based reminders)
|
||||
|
||||
#### Self-Improvement Workflow
|
||||
|
||||
When errors or corrections occur:
|
||||
1. Log to `.learnings/ERRORS.md`, `LEARNINGS.md`, or `FEATURE_REQUESTS.md`
|
||||
2. Review and promote broadly applicable learnings to:
|
||||
- `CLAUDE.md` - project facts and conventions
|
||||
- `AGENTS.md` - workflows and automation
|
||||
- `.github/copilot-instructions.md` - Copilot context
|
||||
|
||||
## Logging Format
|
||||
|
||||
### Learning Entry
|
||||
|
||||
Append to `.learnings/LEARNINGS.md`:
|
||||
|
||||
```markdown
|
||||
## [LRN-YYYYMMDD-XXX] category
|
||||
|
||||
**Logged**: ISO-8601 timestamp
|
||||
**Priority**: low | medium | high | critical
|
||||
**Status**: pending
|
||||
**Area**: frontend | backend | infra | tests | docs | config
|
||||
|
||||
### Summary
|
||||
One-line description of what was learned
|
||||
|
||||
### Details
|
||||
Full context: what happened, what was wrong, what's correct
|
||||
|
||||
### Suggested Action
|
||||
Specific fix or improvement to make
|
||||
|
||||
### Metadata
|
||||
- Source: conversation | error | user_feedback
|
||||
- Related Files: path/to/file.ext
|
||||
- Tags: tag1, tag2
|
||||
- See Also: LRN-20250110-001 (if related to existing entry)
|
||||
- Pattern-Key: simplify.dead_code | harden.input_validation (optional, for recurring-pattern tracking)
|
||||
- Recurrence-Count: 1 (optional)
|
||||
- First-Seen: 2025-01-15 (optional)
|
||||
- Last-Seen: 2025-01-15 (optional)
|
||||
|
||||
---
|
||||
```
|
||||
|
||||
### Error Entry
|
||||
|
||||
Append to `.learnings/ERRORS.md`:
|
||||
|
||||
```markdown
|
||||
## [ERR-YYYYMMDD-XXX] skill_or_command_name
|
||||
|
||||
**Logged**: ISO-8601 timestamp
|
||||
**Priority**: high
|
||||
**Status**: pending
|
||||
**Area**: frontend | backend | infra | tests | docs | config
|
||||
|
||||
### Summary
|
||||
Brief description of what failed
|
||||
|
||||
### Error
|
||||
```
|
||||
Actual error message or output
|
||||
```
|
||||
|
||||
### Context
|
||||
- Command/operation attempted
|
||||
- Input or parameters used
|
||||
- Environment details if relevant
|
||||
|
||||
### Suggested Fix
|
||||
If identifiable, what might resolve this
|
||||
|
||||
### Metadata
|
||||
- Reproducible: yes | no | unknown
|
||||
- Related Files: path/to/file.ext
|
||||
- See Also: ERR-20250110-001 (if recurring)
|
||||
|
||||
---
|
||||
```
|
||||
|
||||
### Feature Request Entry
|
||||
|
||||
Append to `.learnings/FEATURE_REQUESTS.md`:
|
||||
|
||||
```markdown
|
||||
## [FEAT-YYYYMMDD-XXX] capability_name
|
||||
|
||||
**Logged**: ISO-8601 timestamp
|
||||
**Priority**: medium
|
||||
**Status**: pending
|
||||
**Area**: frontend | backend | infra | tests | docs | config
|
||||
|
||||
### Requested Capability
|
||||
What the user wanted to do
|
||||
|
||||
### User Context
|
||||
Why they needed it, what problem they're solving
|
||||
|
||||
### Complexity Estimate
|
||||
simple | medium | complex
|
||||
|
||||
### Suggested Implementation
|
||||
How this could be built, what it might extend
|
||||
|
||||
### Metadata
|
||||
- Frequency: first_time | recurring
|
||||
- Related Features: existing_feature_name
|
||||
|
||||
---
|
||||
```
|
||||
|
||||
## ID Generation
|
||||
|
||||
Format: `TYPE-YYYYMMDD-XXX`
|
||||
- TYPE: `LRN` (learning), `ERR` (error), `FEAT` (feature)
|
||||
- YYYYMMDD: Current date
|
||||
- XXX: Sequential number or random 3 chars (e.g., `001`, `A7B`)
|
||||
|
||||
Examples: `LRN-20250115-001`, `ERR-20250115-A3F`, `FEAT-20250115-002`
|
||||
|
||||
## Resolving Entries
|
||||
|
||||
When an issue is fixed, update the entry:
|
||||
|
||||
1. Change `**Status**: pending` → `**Status**: resolved`
|
||||
2. Add resolution block after Metadata:
|
||||
|
||||
```markdown
|
||||
### Resolution
|
||||
- **Resolved**: 2025-01-16T09:00:00Z
|
||||
- **Commit/PR**: abc123 or #42
|
||||
- **Notes**: Brief description of what was done
|
||||
```
|
||||
|
||||
Other status values:
|
||||
- `in_progress` - Actively being worked on
|
||||
- `wont_fix` - Decided not to address (add reason in Resolution notes)
|
||||
- `promoted` - Elevated to CLAUDE.md, AGENTS.md, or .github/copilot-instructions.md
|
||||
|
||||
## Promoting to Project Memory
|
||||
|
||||
When a learning is broadly applicable (not a one-off fix), promote it to permanent project memory.
|
||||
|
||||
### When to Promote
|
||||
|
||||
- Learning applies across multiple files/features
|
||||
- Knowledge any contributor (human or AI) should know
|
||||
- Prevents recurring mistakes
|
||||
- Documents project-specific conventions
|
||||
|
||||
### Promotion Targets
|
||||
|
||||
| Target | What Belongs There |
|
||||
|--------|-------------------|
|
||||
| `CLAUDE.md` | Project facts, conventions, gotchas for all Claude interactions |
|
||||
| `AGENTS.md` | Agent-specific workflows, tool usage patterns, automation rules |
|
||||
| `.github/copilot-instructions.md` | Project context and conventions for GitHub Copilot |
|
||||
| `SOUL.md` | Behavioral guidelines, communication style, principles (OpenClaw workspace) |
|
||||
| `TOOLS.md` | Tool capabilities, usage patterns, integration gotchas (OpenClaw workspace) |
|
||||
|
||||
### How to Promote
|
||||
|
||||
1. **Distill** the learning into a concise rule or fact
|
||||
2. **Add** to appropriate section in target file (create file if needed)
|
||||
3. **Update** original entry:
|
||||
- Change `**Status**: pending` → `**Status**: promoted`
|
||||
- Add `**Promoted**: CLAUDE.md`, `AGENTS.md`, or `.github/copilot-instructions.md`
|
||||
|
||||
### Promotion Examples
|
||||
|
||||
**Learning** (verbose):
|
||||
> Project uses pnpm workspaces. Attempted `npm install` but failed.
|
||||
> Lock file is `pnpm-lock.yaml`. Must use `pnpm install`.
|
||||
|
||||
**In CLAUDE.md** (concise):
|
||||
```markdown
|
||||
## Build & Dependencies
|
||||
- Package manager: pnpm (not npm) - use `pnpm install`
|
||||
```
|
||||
|
||||
**Learning** (verbose):
|
||||
> When modifying API endpoints, must regenerate TypeScript client.
|
||||
> Forgetting this causes type mismatches at runtime.
|
||||
|
||||
**In AGENTS.md** (actionable):
|
||||
```markdown
|
||||
## After API Changes
|
||||
1. Regenerate client: `pnpm run generate:api`
|
||||
2. Check for type errors: `pnpm tsc --noEmit`
|
||||
```
|
||||
|
||||
## Recurring Pattern Detection
|
||||
|
||||
If logging something similar to an existing entry:
|
||||
|
||||
1. **Search first**: `grep -r "keyword" .learnings/`
|
||||
2. **Link entries**: Add `**See Also**: ERR-20250110-001` in Metadata
|
||||
3. **Bump priority** if issue keeps recurring
|
||||
4. **Consider systemic fix**: Recurring issues often indicate:
|
||||
- Missing documentation (→ promote to CLAUDE.md or .github/copilot-instructions.md)
|
||||
- Missing automation (→ add to AGENTS.md)
|
||||
- Architectural problem (→ create tech debt ticket)
|
||||
|
||||
## Simplify & Harden Feed
|
||||
|
||||
Use this workflow to ingest recurring patterns from the `simplify-and-harden`
|
||||
skill and turn them into durable prompt guidance.
|
||||
|
||||
### Ingestion Workflow
|
||||
|
||||
1. Read `simplify_and_harden.learning_loop.candidates` from the task summary.
|
||||
2. For each candidate, use `pattern_key` as the stable dedupe key.
|
||||
3. Search `.learnings/LEARNINGS.md` for an existing entry with that key:
|
||||
- `grep -n "Pattern-Key: <pattern_key>" .learnings/LEARNINGS.md`
|
||||
4. If found:
|
||||
- Increment `Recurrence-Count`
|
||||
- Update `Last-Seen`
|
||||
- Add `See Also` links to related entries/tasks
|
||||
5. If not found:
|
||||
- Create a new `LRN-...` entry
|
||||
- Set `Source: simplify-and-harden`
|
||||
- Set `Pattern-Key`, `Recurrence-Count: 1`, and `First-Seen`/`Last-Seen`
|
||||
|
||||
### Promotion Rule (System Prompt Feedback)
|
||||
|
||||
Promote recurring patterns into agent context/system prompt files when all are true:
|
||||
|
||||
- `Recurrence-Count >= 3`
|
||||
- Seen across at least 2 distinct tasks
|
||||
- Occurred within a 30-day window
|
||||
|
||||
Promotion targets:
|
||||
- `CLAUDE.md`
|
||||
- `AGENTS.md`
|
||||
- `.github/copilot-instructions.md`
|
||||
- `SOUL.md` / `TOOLS.md` for OpenClaw workspace-level guidance when applicable
|
||||
|
||||
Write promoted rules as short prevention rules (what to do before/while coding),
|
||||
not long incident write-ups.
|
||||
|
||||
## Periodic Review
|
||||
|
||||
Review `.learnings/` at natural breakpoints:
|
||||
|
||||
### When to Review
|
||||
- Before starting a new major task
|
||||
- After completing a feature
|
||||
- When working in an area with past learnings
|
||||
- Weekly during active development
|
||||
|
||||
### Quick Status Check
|
||||
```bash
|
||||
# Count pending items
|
||||
grep -h "Status\*\*: pending" .learnings/*.md | wc -l
|
||||
|
||||
# List pending high-priority items
|
||||
grep -B5 "Priority\*\*: high" .learnings/*.md | grep "^## \["
|
||||
|
||||
# Find learnings for a specific area
|
||||
grep -l "Area\*\*: backend" .learnings/*.md
|
||||
```
|
||||
|
||||
### Review Actions
|
||||
- Resolve fixed items
|
||||
- Promote applicable learnings
|
||||
- Link related entries
|
||||
- Escalate recurring issues
|
||||
|
||||
## Detection Triggers
|
||||
|
||||
Automatically log when you notice:
|
||||
|
||||
**Corrections** (→ learning with `correction` category):
|
||||
- "No, that's not right..."
|
||||
- "Actually, it should be..."
|
||||
- "You're wrong about..."
|
||||
- "That's outdated..."
|
||||
|
||||
**Feature Requests** (→ feature request):
|
||||
- "Can you also..."
|
||||
- "I wish you could..."
|
||||
- "Is there a way to..."
|
||||
- "Why can't you..."
|
||||
|
||||
**Knowledge Gaps** (→ learning with `knowledge_gap` category):
|
||||
- User provides information you didn't know
|
||||
- Documentation you referenced is outdated
|
||||
- API behavior differs from your understanding
|
||||
|
||||
**Errors** (→ error entry):
|
||||
- Command returns non-zero exit code
|
||||
- Exception or stack trace
|
||||
- Unexpected output or behavior
|
||||
- Timeout or connection failure
|
||||
|
||||
## Priority Guidelines
|
||||
|
||||
| Priority | When to Use |
|
||||
|----------|-------------|
|
||||
| `critical` | Blocks core functionality, data loss risk, security issue |
|
||||
| `high` | Significant impact, affects common workflows, recurring issue |
|
||||
| `medium` | Moderate impact, workaround exists |
|
||||
| `low` | Minor inconvenience, edge case, nice-to-have |
|
||||
|
||||
## Area Tags
|
||||
|
||||
Use to filter learnings by codebase region:
|
||||
|
||||
| Area | Scope |
|
||||
|------|-------|
|
||||
| `frontend` | UI, components, client-side code |
|
||||
| `backend` | API, services, server-side code |
|
||||
| `infra` | CI/CD, deployment, Docker, cloud |
|
||||
| `tests` | Test files, testing utilities, coverage |
|
||||
| `docs` | Documentation, comments, READMEs |
|
||||
| `config` | Configuration files, environment, settings |
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Log immediately** - context is freshest right after the issue
|
||||
2. **Be specific** - future agents need to understand quickly
|
||||
3. **Include reproduction steps** - especially for errors
|
||||
4. **Link related files** - makes fixes easier
|
||||
5. **Suggest concrete fixes** - not just "investigate"
|
||||
6. **Use consistent categories** - enables filtering
|
||||
7. **Promote aggressively** - if in doubt, add to CLAUDE.md or .github/copilot-instructions.md
|
||||
8. **Review regularly** - stale learnings lose value
|
||||
|
||||
## Gitignore Options
|
||||
|
||||
**Keep learnings local** (per-developer):
|
||||
```gitignore
|
||||
.learnings/
|
||||
```
|
||||
|
||||
**Track learnings in repo** (team-wide):
|
||||
Don't add to .gitignore - learnings become shared knowledge.
|
||||
|
||||
**Hybrid** (track templates, ignore entries):
|
||||
```gitignore
|
||||
.learnings/*.md
|
||||
!.learnings/.gitkeep
|
||||
```
|
||||
|
||||
## Hook Integration
|
||||
|
||||
Enable automatic reminders through agent hooks. This is **opt-in** - you must explicitly configure hooks.
|
||||
|
||||
### Quick Setup (Claude Code / Codex)
|
||||
|
||||
Create `.claude/settings.json` in your project:
|
||||
|
||||
```json
|
||||
{
|
||||
"hooks": {
|
||||
"UserPromptSubmit": [{
|
||||
"matcher": "",
|
||||
"hooks": [{
|
||||
"type": "command",
|
||||
"command": "./skills/self-improvement/scripts/activator.sh"
|
||||
}]
|
||||
}]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
This injects a learning evaluation reminder after each prompt (~50-100 tokens overhead).
|
||||
|
||||
### Full Setup (With Error Detection)
|
||||
|
||||
```json
|
||||
{
|
||||
"hooks": {
|
||||
"UserPromptSubmit": [{
|
||||
"matcher": "",
|
||||
"hooks": [{
|
||||
"type": "command",
|
||||
"command": "./skills/self-improvement/scripts/activator.sh"
|
||||
}]
|
||||
}],
|
||||
"PostToolUse": [{
|
||||
"matcher": "Bash",
|
||||
"hooks": [{
|
||||
"type": "command",
|
||||
"command": "./skills/self-improvement/scripts/error-detector.sh"
|
||||
}]
|
||||
}]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Available Hook Scripts
|
||||
|
||||
| Script | Hook Type | Purpose |
|
||||
|--------|-----------|---------|
|
||||
| `scripts/activator.sh` | UserPromptSubmit | Reminds to evaluate learnings after tasks |
|
||||
| `scripts/error-detector.sh` | PostToolUse (Bash) | Triggers on command errors |
|
||||
|
||||
See `references/hooks-setup.md` for detailed configuration and troubleshooting.
|
||||
|
||||
## Automatic Skill Extraction
|
||||
|
||||
When a learning is valuable enough to become a reusable skill, extract it using the provided helper.
|
||||
|
||||
### Skill Extraction Criteria
|
||||
|
||||
A learning qualifies for skill extraction when ANY of these apply:
|
||||
|
||||
| Criterion | Description |
|
||||
|-----------|-------------|
|
||||
| **Recurring** | Has `See Also` links to 2+ similar issues |
|
||||
| **Verified** | Status is `resolved` with working fix |
|
||||
| **Non-obvious** | Required actual debugging/investigation to discover |
|
||||
| **Broadly applicable** | Not project-specific; useful across codebases |
|
||||
| **User-flagged** | User says "save this as a skill" or similar |
|
||||
|
||||
### Extraction Workflow
|
||||
|
||||
1. **Identify candidate**: Learning meets extraction criteria
|
||||
2. **Run helper** (or create manually):
|
||||
```bash
|
||||
./skills/self-improvement/scripts/extract-skill.sh skill-name --dry-run
|
||||
./skills/self-improvement/scripts/extract-skill.sh skill-name
|
||||
```
|
||||
3. **Customize SKILL.md**: Fill in template with learning content
|
||||
4. **Update learning**: Set status to `promoted_to_skill`, add `Skill-Path`
|
||||
5. **Verify**: Read skill in fresh session to ensure it's self-contained
|
||||
|
||||
### Manual Extraction
|
||||
|
||||
If you prefer manual creation:
|
||||
|
||||
1. Create `skills/<skill-name>/SKILL.md`
|
||||
2. Use template from `assets/SKILL-TEMPLATE.md`
|
||||
3. Follow [Agent Skills spec](https://agentskills.io/specification):
|
||||
- YAML frontmatter with `name` and `description`
|
||||
- Name must match folder name
|
||||
- No README.md inside skill folder
|
||||
|
||||
### Extraction Detection Triggers
|
||||
|
||||
Watch for these signals that a learning should become a skill:
|
||||
|
||||
**In conversation:**
|
||||
- "Save this as a skill"
|
||||
- "I keep running into this"
|
||||
- "This would be useful for other projects"
|
||||
- "Remember this pattern"
|
||||
|
||||
**In learning entries:**
|
||||
- Multiple `See Also` links (recurring issue)
|
||||
- High priority + resolved status
|
||||
- Category: `best_practice` with broad applicability
|
||||
- User feedback praising the solution
|
||||
|
||||
### Skill Quality Gates
|
||||
|
||||
Before extraction, verify:
|
||||
|
||||
- [ ] Solution is tested and working
|
||||
- [ ] Description is clear without original context
|
||||
- [ ] Code examples are self-contained
|
||||
- [ ] No project-specific hardcoded values
|
||||
- [ ] Follows skill naming conventions (lowercase, hyphens)
|
||||
|
||||
## Multi-Agent Support
|
||||
|
||||
This skill works across different AI coding agents with agent-specific activation.
|
||||
|
||||
### Claude Code
|
||||
|
||||
**Activation**: Hooks (UserPromptSubmit, PostToolUse)
|
||||
**Setup**: `.claude/settings.json` with hook configuration
|
||||
**Detection**: Automatic via hook scripts
|
||||
|
||||
### Codex CLI
|
||||
|
||||
**Activation**: Hooks (same pattern as Claude Code)
|
||||
**Setup**: `.codex/settings.json` with hook configuration
|
||||
**Detection**: Automatic via hook scripts
|
||||
|
||||
### GitHub Copilot
|
||||
|
||||
**Activation**: Manual (no hook support)
|
||||
**Setup**: Add to `.github/copilot-instructions.md`:
|
||||
|
||||
```markdown
|
||||
## Self-Improvement
|
||||
|
||||
After solving non-obvious issues, consider logging to `.learnings/`:
|
||||
1. Use format from self-improvement skill
|
||||
2. Link related entries with See Also
|
||||
3. Promote high-value learnings to skills
|
||||
|
||||
Ask in chat: "Should I log this as a learning?"
|
||||
```
|
||||
|
||||
**Detection**: Manual review at session end
|
||||
|
||||
### OpenClaw
|
||||
|
||||
**Activation**: Workspace injection + inter-agent messaging
|
||||
**Setup**: See "OpenClaw Setup" section above
|
||||
**Detection**: Via session tools and workspace files
|
||||
|
||||
### Agent-Agnostic Guidance
|
||||
|
||||
Regardless of agent, apply self-improvement when you:
|
||||
|
||||
1. **Discover something non-obvious** - solution wasn't immediate
|
||||
2. **Correct yourself** - initial approach was wrong
|
||||
3. **Learn project conventions** - discovered undocumented patterns
|
||||
4. **Hit unexpected errors** - especially if diagnosis was difficult
|
||||
5. **Find better approaches** - improved on your original solution
|
||||
|
||||
### Copilot Chat Integration
|
||||
|
||||
For Copilot users, add this to your prompts when relevant:
|
||||
|
||||
> After completing this task, evaluate if any learnings should be logged to `.learnings/` using the self-improvement skill format.
|
||||
|
||||
Or use quick prompts:
|
||||
- "Log this to learnings"
|
||||
- "Create a skill from this solution"
|
||||
- "Check .learnings/ for related issues"
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"owner": "gakkiismywife",
|
||||
"slug": "aaaa",
|
||||
"displayName": "aaaa",
|
||||
"latest": {
|
||||
"version": "1.0.0",
|
||||
"publishedAt": 1773418514559,
|
||||
"commit": "https://github.com/openclaw/skills/commit/3e6c5a110d471e367ba93bdf23a7c8fcc5b0b193"
|
||||
},
|
||||
"history": []
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
# Learnings
|
||||
|
||||
Corrections, insights, and knowledge gaps captured during development.
|
||||
|
||||
**Categories**: correction | insight | knowledge_gap | best_practice
|
||||
**Areas**: frontend | backend | infra | tests | docs | config
|
||||
**Statuses**: pending | in_progress | resolved | wont_fix | promoted | promoted_to_skill
|
||||
|
||||
## Status Definitions
|
||||
|
||||
| Status | Meaning |
|
||||
|--------|---------|
|
||||
| `pending` | Not yet addressed |
|
||||
| `in_progress` | Actively being worked on |
|
||||
| `resolved` | Issue fixed or knowledge integrated |
|
||||
| `wont_fix` | Decided not to address (reason in Resolution) |
|
||||
| `promoted` | Elevated to CLAUDE.md, AGENTS.md, or copilot-instructions.md |
|
||||
| `promoted_to_skill` | Extracted as a reusable skill |
|
||||
|
||||
## Skill Extraction Fields
|
||||
|
||||
When a learning is promoted to a skill, add these fields:
|
||||
|
||||
```markdown
|
||||
**Status**: promoted_to_skill
|
||||
**Skill-Path**: skills/skill-name
|
||||
```
|
||||
|
||||
Example:
|
||||
```markdown
|
||||
## [LRN-20250115-001] best_practice
|
||||
|
||||
**Logged**: 2025-01-15T10:00:00Z
|
||||
**Priority**: high
|
||||
**Status**: promoted_to_skill
|
||||
**Skill-Path**: skills/docker-m1-fixes
|
||||
**Area**: infra
|
||||
|
||||
### Summary
|
||||
Docker build fails on Apple Silicon due to platform mismatch
|
||||
...
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -0,0 +1,177 @@
|
||||
# Skill Template
|
||||
|
||||
Template for creating skills extracted from learnings. Copy and customize.
|
||||
|
||||
---
|
||||
|
||||
## SKILL.md Template
|
||||
|
||||
```markdown
|
||||
---
|
||||
name: skill-name-here
|
||||
description: "Concise description of when and why to use this skill. Include trigger conditions."
|
||||
---
|
||||
|
||||
# Skill Name
|
||||
|
||||
Brief introduction explaining the problem this skill solves and its origin.
|
||||
|
||||
## Quick Reference
|
||||
|
||||
| Situation | Action |
|
||||
|-----------|--------|
|
||||
| [Trigger 1] | [Action 1] |
|
||||
| [Trigger 2] | [Action 2] |
|
||||
|
||||
## Background
|
||||
|
||||
Why this knowledge matters. What problems it prevents. Context from the original learning.
|
||||
|
||||
## Solution
|
||||
|
||||
### Step-by-Step
|
||||
|
||||
1. First step with code or command
|
||||
2. Second step
|
||||
3. Verification step
|
||||
|
||||
### Code Example
|
||||
|
||||
\`\`\`language
|
||||
// Example code demonstrating the solution
|
||||
\`\`\`
|
||||
|
||||
## Common Variations
|
||||
|
||||
- **Variation A**: Description and how to handle
|
||||
- **Variation B**: Description and how to handle
|
||||
|
||||
## Gotchas
|
||||
|
||||
- Warning or common mistake #1
|
||||
- Warning or common mistake #2
|
||||
|
||||
## Related
|
||||
|
||||
- Link to related documentation
|
||||
- Link to related skill
|
||||
|
||||
## Source
|
||||
|
||||
Extracted from learning entry.
|
||||
- **Learning ID**: LRN-YYYYMMDD-XXX
|
||||
- **Original Category**: correction | insight | knowledge_gap | best_practice
|
||||
- **Extraction Date**: YYYY-MM-DD
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Minimal Template
|
||||
|
||||
For simple skills that don't need all sections:
|
||||
|
||||
```markdown
|
||||
---
|
||||
name: skill-name-here
|
||||
description: "What this skill does and when to use it."
|
||||
---
|
||||
|
||||
# Skill Name
|
||||
|
||||
[Problem statement in one sentence]
|
||||
|
||||
## Solution
|
||||
|
||||
[Direct solution with code/commands]
|
||||
|
||||
## Source
|
||||
|
||||
- Learning ID: LRN-YYYYMMDD-XXX
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Template with Scripts
|
||||
|
||||
For skills that include executable helpers:
|
||||
|
||||
```markdown
|
||||
---
|
||||
name: skill-name-here
|
||||
description: "What this skill does and when to use it."
|
||||
---
|
||||
|
||||
# Skill Name
|
||||
|
||||
[Introduction]
|
||||
|
||||
## Quick Reference
|
||||
|
||||
| Command | Purpose |
|
||||
|---------|---------|
|
||||
| `./scripts/helper.sh` | [What it does] |
|
||||
| `./scripts/validate.sh` | [What it does] |
|
||||
|
||||
## Usage
|
||||
|
||||
### Automated (Recommended)
|
||||
|
||||
\`\`\`bash
|
||||
./skills/skill-name/scripts/helper.sh [args]
|
||||
\`\`\`
|
||||
|
||||
### Manual Steps
|
||||
|
||||
1. Step one
|
||||
2. Step two
|
||||
|
||||
## Scripts
|
||||
|
||||
| Script | Description |
|
||||
|--------|-------------|
|
||||
| `scripts/helper.sh` | Main utility |
|
||||
| `scripts/validate.sh` | Validation checker |
|
||||
|
||||
## Source
|
||||
|
||||
- Learning ID: LRN-YYYYMMDD-XXX
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Naming Conventions
|
||||
|
||||
- **Skill name**: lowercase, hyphens for spaces
|
||||
- Good: `docker-m1-fixes`, `api-timeout-patterns`
|
||||
- Bad: `Docker_M1_Fixes`, `APITimeoutPatterns`
|
||||
|
||||
- **Description**: Start with action verb, mention trigger
|
||||
- Good: "Handles Docker build failures on Apple Silicon. Use when builds fail with platform mismatch."
|
||||
- Bad: "Docker stuff"
|
||||
|
||||
- **Files**:
|
||||
- `SKILL.md` - Required, main documentation
|
||||
- `scripts/` - Optional, executable code
|
||||
- `references/` - Optional, detailed docs
|
||||
- `assets/` - Optional, templates
|
||||
|
||||
---
|
||||
|
||||
## Extraction Checklist
|
||||
|
||||
Before creating a skill from a learning:
|
||||
|
||||
- [ ] Learning is verified (status: resolved)
|
||||
- [ ] Solution is broadly applicable (not one-off)
|
||||
- [ ] Content is complete (has all needed context)
|
||||
- [ ] Name follows conventions
|
||||
- [ ] Description is concise but informative
|
||||
- [ ] Quick Reference table is actionable
|
||||
- [ ] Code examples are tested
|
||||
- [ ] Source learning ID is recorded
|
||||
|
||||
After creating:
|
||||
|
||||
- [ ] Update original learning with `promoted_to_skill` status
|
||||
- [ ] Add `Skill-Path: skills/skill-name` to learning metadata
|
||||
- [ ] Test skill by reading it in a fresh session
|
||||
@@ -0,0 +1,23 @@
|
||||
---
|
||||
name: self-improvement
|
||||
description: "Injects self-improvement reminder during agent bootstrap"
|
||||
metadata: {"openclaw":{"emoji":"🧠","events":["agent:bootstrap"]}}
|
||||
---
|
||||
|
||||
# Self-Improvement Hook
|
||||
|
||||
Injects a reminder to evaluate learnings during agent bootstrap.
|
||||
|
||||
## What It Does
|
||||
|
||||
- Fires on `agent:bootstrap` (before workspace files are injected)
|
||||
- Adds a reminder block to check `.learnings/` for relevant entries
|
||||
- Prompts the agent to log corrections, errors, and discoveries
|
||||
|
||||
## Configuration
|
||||
|
||||
No configuration needed. Enable with:
|
||||
|
||||
```bash
|
||||
openclaw hooks enable self-improvement
|
||||
```
|
||||
@@ -0,0 +1,56 @@
|
||||
/**
|
||||
* Self-Improvement Hook for OpenClaw
|
||||
*
|
||||
* Injects a reminder to evaluate learnings during agent bootstrap.
|
||||
* Fires on agent:bootstrap event before workspace files are injected.
|
||||
*/
|
||||
|
||||
const REMINDER_CONTENT = `
|
||||
## Self-Improvement Reminder
|
||||
|
||||
After completing tasks, evaluate if any learnings should be captured:
|
||||
|
||||
**Log when:**
|
||||
- User corrects you → \`.learnings/LEARNINGS.md\`
|
||||
- Command/operation fails → \`.learnings/ERRORS.md\`
|
||||
- User wants missing capability → \`.learnings/FEATURE_REQUESTS.md\`
|
||||
- You discover your knowledge was wrong → \`.learnings/LEARNINGS.md\`
|
||||
- You find a better approach → \`.learnings/LEARNINGS.md\`
|
||||
|
||||
**Promote when pattern is proven:**
|
||||
- Behavioral patterns → \`SOUL.md\`
|
||||
- Workflow improvements → \`AGENTS.md\`
|
||||
- Tool gotchas → \`TOOLS.md\`
|
||||
|
||||
Keep entries simple: date, title, what happened, what to do differently.
|
||||
`.trim();
|
||||
|
||||
const handler = async (event) => {
|
||||
// Safety checks for event structure
|
||||
if (!event || typeof event !== 'object') {
|
||||
return;
|
||||
}
|
||||
|
||||
// Only handle agent:bootstrap events
|
||||
if (event.type !== 'agent' || event.action !== 'bootstrap') {
|
||||
return;
|
||||
}
|
||||
|
||||
// Safety check for context
|
||||
if (!event.context || typeof event.context !== 'object') {
|
||||
return;
|
||||
}
|
||||
|
||||
// Inject the reminder as a virtual bootstrap file
|
||||
// Check that bootstrapFiles is an array before pushing
|
||||
if (Array.isArray(event.context.bootstrapFiles)) {
|
||||
event.context.bootstrapFiles.push({
|
||||
path: 'SELF_IMPROVEMENT_REMINDER.md',
|
||||
content: REMINDER_CONTENT,
|
||||
virtual: true,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = handler;
|
||||
module.exports.default = handler;
|
||||
@@ -0,0 +1,62 @@
|
||||
/**
|
||||
* Self-Improvement Hook for OpenClaw
|
||||
*
|
||||
* Injects a reminder to evaluate learnings during agent bootstrap.
|
||||
* Fires on agent:bootstrap event before workspace files are injected.
|
||||
*/
|
||||
|
||||
import type { HookHandler } from 'openclaw/hooks';
|
||||
|
||||
const REMINDER_CONTENT = `## Self-Improvement Reminder
|
||||
|
||||
After completing tasks, evaluate if any learnings should be captured:
|
||||
|
||||
**Log when:**
|
||||
- User corrects you → \`.learnings/LEARNINGS.md\`
|
||||
- Command/operation fails → \`.learnings/ERRORS.md\`
|
||||
- User wants missing capability → \`.learnings/FEATURE_REQUESTS.md\`
|
||||
- You discover your knowledge was wrong → \`.learnings/LEARNINGS.md\`
|
||||
- You find a better approach → \`.learnings/LEARNINGS.md\`
|
||||
|
||||
**Promote when pattern is proven:**
|
||||
- Behavioral patterns → \`SOUL.md\`
|
||||
- Workflow improvements → \`AGENTS.md\`
|
||||
- Tool gotchas → \`TOOLS.md\`
|
||||
|
||||
Keep entries simple: date, title, what happened, what to do differently.`;
|
||||
|
||||
const handler: HookHandler = async (event) => {
|
||||
// Safety checks for event structure
|
||||
if (!event || typeof event !== 'object') {
|
||||
return;
|
||||
}
|
||||
|
||||
// Only handle agent:bootstrap events
|
||||
if (event.type !== 'agent' || event.action !== 'bootstrap') {
|
||||
return;
|
||||
}
|
||||
|
||||
// Safety check for context
|
||||
if (!event.context || typeof event.context !== 'object') {
|
||||
return;
|
||||
}
|
||||
|
||||
// Skip sub-agent sessions to avoid bootstrap issues
|
||||
// Sub-agents have sessionKey patterns like "agent:main:subagent:..."
|
||||
const sessionKey = event.sessionKey || '';
|
||||
if (sessionKey.includes(':subagent:')) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Inject the reminder as a virtual bootstrap file
|
||||
// Check that bootstrapFiles is an array before pushing
|
||||
if (Array.isArray(event.context.bootstrapFiles)) {
|
||||
event.context.bootstrapFiles.push({
|
||||
path: 'SELF_IMPROVEMENT_REMINDER.md',
|
||||
content: REMINDER_CONTENT,
|
||||
virtual: true,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export default handler;
|
||||
@@ -0,0 +1,374 @@
|
||||
# Entry Examples
|
||||
|
||||
Concrete examples of well-formatted entries with all fields.
|
||||
|
||||
## Learning: Correction
|
||||
|
||||
```markdown
|
||||
## [LRN-20250115-001] correction
|
||||
|
||||
**Logged**: 2025-01-15T10:30:00Z
|
||||
**Priority**: high
|
||||
**Status**: pending
|
||||
**Area**: tests
|
||||
|
||||
### Summary
|
||||
Incorrectly assumed pytest fixtures are scoped to function by default
|
||||
|
||||
### Details
|
||||
When writing test fixtures, I assumed all fixtures were function-scoped.
|
||||
User corrected that while function scope is the default, the codebase
|
||||
convention uses module-scoped fixtures for database connections to
|
||||
improve test performance.
|
||||
|
||||
### Suggested Action
|
||||
When creating fixtures that involve expensive setup (DB, network),
|
||||
check existing fixtures for scope patterns before defaulting to function scope.
|
||||
|
||||
### Metadata
|
||||
- Source: user_feedback
|
||||
- Related Files: tests/conftest.py
|
||||
- Tags: pytest, testing, fixtures
|
||||
|
||||
---
|
||||
```
|
||||
|
||||
## Learning: Knowledge Gap (Resolved)
|
||||
|
||||
```markdown
|
||||
## [LRN-20250115-002] knowledge_gap
|
||||
|
||||
**Logged**: 2025-01-15T14:22:00Z
|
||||
**Priority**: medium
|
||||
**Status**: resolved
|
||||
**Area**: config
|
||||
|
||||
### Summary
|
||||
Project uses pnpm not npm for package management
|
||||
|
||||
### Details
|
||||
Attempted to run `npm install` but project uses pnpm workspaces.
|
||||
Lock file is `pnpm-lock.yaml`, not `package-lock.json`.
|
||||
|
||||
### Suggested Action
|
||||
Check for `pnpm-lock.yaml` or `pnpm-workspace.yaml` before assuming npm.
|
||||
Use `pnpm install` for this project.
|
||||
|
||||
### Metadata
|
||||
- Source: error
|
||||
- Related Files: pnpm-lock.yaml, pnpm-workspace.yaml
|
||||
- Tags: package-manager, pnpm, setup
|
||||
|
||||
### Resolution
|
||||
- **Resolved**: 2025-01-15T14:30:00Z
|
||||
- **Commit/PR**: N/A - knowledge update
|
||||
- **Notes**: Added to CLAUDE.md for future reference
|
||||
|
||||
---
|
||||
```
|
||||
|
||||
## Learning: Promoted to CLAUDE.md
|
||||
|
||||
```markdown
|
||||
## [LRN-20250115-003] best_practice
|
||||
|
||||
**Logged**: 2025-01-15T16:00:00Z
|
||||
**Priority**: high
|
||||
**Status**: promoted
|
||||
**Promoted**: CLAUDE.md
|
||||
**Area**: backend
|
||||
|
||||
### Summary
|
||||
API responses must include correlation ID from request headers
|
||||
|
||||
### Details
|
||||
All API responses should echo back the X-Correlation-ID header from
|
||||
the request. This is required for distributed tracing. Responses
|
||||
without this header break the observability pipeline.
|
||||
|
||||
### Suggested Action
|
||||
Always include correlation ID passthrough in API handlers.
|
||||
|
||||
### Metadata
|
||||
- Source: user_feedback
|
||||
- Related Files: src/middleware/correlation.ts
|
||||
- Tags: api, observability, tracing
|
||||
|
||||
---
|
||||
```
|
||||
|
||||
## Learning: Promoted to AGENTS.md
|
||||
|
||||
```markdown
|
||||
## [LRN-20250116-001] best_practice
|
||||
|
||||
**Logged**: 2025-01-16T09:00:00Z
|
||||
**Priority**: high
|
||||
**Status**: promoted
|
||||
**Promoted**: AGENTS.md
|
||||
**Area**: backend
|
||||
|
||||
### Summary
|
||||
Must regenerate API client after OpenAPI spec changes
|
||||
|
||||
### Details
|
||||
When modifying API endpoints, the TypeScript client must be regenerated.
|
||||
Forgetting this causes type mismatches that only appear at runtime.
|
||||
The generate script also runs validation.
|
||||
|
||||
### Suggested Action
|
||||
Add to agent workflow: after any API changes, run `pnpm run generate:api`.
|
||||
|
||||
### Metadata
|
||||
- Source: error
|
||||
- Related Files: openapi.yaml, src/client/api.ts
|
||||
- Tags: api, codegen, typescript
|
||||
|
||||
---
|
||||
```
|
||||
|
||||
## Error Entry
|
||||
|
||||
```markdown
|
||||
## [ERR-20250115-A3F] docker_build
|
||||
|
||||
**Logged**: 2025-01-15T09:15:00Z
|
||||
**Priority**: high
|
||||
**Status**: pending
|
||||
**Area**: infra
|
||||
|
||||
### Summary
|
||||
Docker build fails on M1 Mac due to platform mismatch
|
||||
|
||||
### Error
|
||||
```
|
||||
error: failed to solve: python:3.11-slim: no match for platform linux/arm64
|
||||
```
|
||||
|
||||
### Context
|
||||
- Command: `docker build -t myapp .`
|
||||
- Dockerfile uses `FROM python:3.11-slim`
|
||||
- Running on Apple Silicon (M1/M2)
|
||||
|
||||
### Suggested Fix
|
||||
Add platform flag: `docker build --platform linux/amd64 -t myapp .`
|
||||
Or update Dockerfile: `FROM --platform=linux/amd64 python:3.11-slim`
|
||||
|
||||
### Metadata
|
||||
- Reproducible: yes
|
||||
- Related Files: Dockerfile
|
||||
|
||||
---
|
||||
```
|
||||
|
||||
## Error Entry: Recurring Issue
|
||||
|
||||
```markdown
|
||||
## [ERR-20250120-B2C] api_timeout
|
||||
|
||||
**Logged**: 2025-01-20T11:30:00Z
|
||||
**Priority**: critical
|
||||
**Status**: pending
|
||||
**Area**: backend
|
||||
|
||||
### Summary
|
||||
Third-party payment API timeout during checkout
|
||||
|
||||
### Error
|
||||
```
|
||||
TimeoutError: Request to payments.example.com timed out after 30000ms
|
||||
```
|
||||
|
||||
### Context
|
||||
- Command: POST /api/checkout
|
||||
- Timeout set to 30s
|
||||
- Occurs during peak hours (lunch, evening)
|
||||
|
||||
### Suggested Fix
|
||||
Implement retry with exponential backoff. Consider circuit breaker pattern.
|
||||
|
||||
### Metadata
|
||||
- Reproducible: yes (during peak hours)
|
||||
- Related Files: src/services/payment.ts
|
||||
- See Also: ERR-20250115-X1Y, ERR-20250118-Z3W
|
||||
|
||||
---
|
||||
```
|
||||
|
||||
## Feature Request
|
||||
|
||||
```markdown
|
||||
## [FEAT-20250115-001] export_to_csv
|
||||
|
||||
**Logged**: 2025-01-15T16:45:00Z
|
||||
**Priority**: medium
|
||||
**Status**: pending
|
||||
**Area**: backend
|
||||
|
||||
### Requested Capability
|
||||
Export analysis results to CSV format
|
||||
|
||||
### User Context
|
||||
User runs weekly reports and needs to share results with non-technical
|
||||
stakeholders in Excel. Currently copies output manually.
|
||||
|
||||
### Complexity Estimate
|
||||
simple
|
||||
|
||||
### Suggested Implementation
|
||||
Add `--output csv` flag to the analyze command. Use standard csv module.
|
||||
Could extend existing `--output json` pattern.
|
||||
|
||||
### Metadata
|
||||
- Frequency: recurring
|
||||
- Related Features: analyze command, json output
|
||||
|
||||
---
|
||||
```
|
||||
|
||||
## Feature Request: Resolved
|
||||
|
||||
```markdown
|
||||
## [FEAT-20250110-002] dark_mode
|
||||
|
||||
**Logged**: 2025-01-10T14:00:00Z
|
||||
**Priority**: low
|
||||
**Status**: resolved
|
||||
**Area**: frontend
|
||||
|
||||
### Requested Capability
|
||||
Dark mode support for the dashboard
|
||||
|
||||
### User Context
|
||||
User works late hours and finds the bright interface straining.
|
||||
Several other users have mentioned this informally.
|
||||
|
||||
### Complexity Estimate
|
||||
medium
|
||||
|
||||
### Suggested Implementation
|
||||
Use CSS variables for colors. Add toggle in user settings.
|
||||
Consider system preference detection.
|
||||
|
||||
### Metadata
|
||||
- Frequency: recurring
|
||||
- Related Features: user settings, theme system
|
||||
|
||||
### Resolution
|
||||
- **Resolved**: 2025-01-18T16:00:00Z
|
||||
- **Commit/PR**: #142
|
||||
- **Notes**: Implemented with system preference detection and manual toggle
|
||||
|
||||
---
|
||||
```
|
||||
|
||||
## Learning: Promoted to Skill
|
||||
|
||||
```markdown
|
||||
## [LRN-20250118-001] best_practice
|
||||
|
||||
**Logged**: 2025-01-18T11:00:00Z
|
||||
**Priority**: high
|
||||
**Status**: promoted_to_skill
|
||||
**Skill-Path**: skills/docker-m1-fixes
|
||||
**Area**: infra
|
||||
|
||||
### Summary
|
||||
Docker build fails on Apple Silicon due to platform mismatch
|
||||
|
||||
### Details
|
||||
When building Docker images on M1/M2 Macs, the build fails because
|
||||
the base image doesn't have an ARM64 variant. This is a common issue
|
||||
that affects many developers.
|
||||
|
||||
### Suggested Action
|
||||
Add `--platform linux/amd64` to docker build command, or use
|
||||
`FROM --platform=linux/amd64` in Dockerfile.
|
||||
|
||||
### Metadata
|
||||
- Source: error
|
||||
- Related Files: Dockerfile
|
||||
- Tags: docker, arm64, m1, apple-silicon
|
||||
- See Also: ERR-20250115-A3F, ERR-20250117-B2D
|
||||
|
||||
---
|
||||
```
|
||||
|
||||
## Extracted Skill Example
|
||||
|
||||
When the above learning is extracted as a skill, it becomes:
|
||||
|
||||
**File**: `skills/docker-m1-fixes/SKILL.md`
|
||||
|
||||
```markdown
|
||||
---
|
||||
name: docker-m1-fixes
|
||||
description: "Fixes Docker build failures on Apple Silicon (M1/M2). Use when docker build fails with platform mismatch errors."
|
||||
---
|
||||
|
||||
# Docker M1 Fixes
|
||||
|
||||
Solutions for Docker build issues on Apple Silicon Macs.
|
||||
|
||||
## Quick Reference
|
||||
|
||||
| Error | Fix |
|
||||
|-------|-----|
|
||||
| `no match for platform linux/arm64` | Add `--platform linux/amd64` to build |
|
||||
| Image runs but crashes | Use emulation or find ARM-compatible base |
|
||||
|
||||
## The Problem
|
||||
|
||||
Many Docker base images don't have ARM64 variants. When building on
|
||||
Apple Silicon (M1/M2/M3), Docker attempts to pull ARM64 images by
|
||||
default, causing platform mismatch errors.
|
||||
|
||||
## Solutions
|
||||
|
||||
### Option 1: Build Flag (Recommended)
|
||||
|
||||
Add platform flag to your build command:
|
||||
|
||||
\`\`\`bash
|
||||
docker build --platform linux/amd64 -t myapp .
|
||||
\`\`\`
|
||||
|
||||
### Option 2: Dockerfile Modification
|
||||
|
||||
Specify platform in the FROM instruction:
|
||||
|
||||
\`\`\`dockerfile
|
||||
FROM --platform=linux/amd64 python:3.11-slim
|
||||
\`\`\`
|
||||
|
||||
### Option 3: Docker Compose
|
||||
|
||||
Add platform to your service:
|
||||
|
||||
\`\`\`yaml
|
||||
services:
|
||||
app:
|
||||
platform: linux/amd64
|
||||
build: .
|
||||
\`\`\`
|
||||
|
||||
## Trade-offs
|
||||
|
||||
| Approach | Pros | Cons |
|
||||
|----------|------|------|
|
||||
| Build flag | No file changes | Must remember flag |
|
||||
| Dockerfile | Explicit, versioned | Affects all builds |
|
||||
| Compose | Convenient for dev | Requires compose |
|
||||
|
||||
## Performance Note
|
||||
|
||||
Running AMD64 images on ARM64 uses Rosetta 2 emulation. This works
|
||||
for development but may be slower. For production, find ARM-native
|
||||
alternatives when possible.
|
||||
|
||||
## Source
|
||||
|
||||
- Learning ID: LRN-20250118-001
|
||||
- Category: best_practice
|
||||
- Extraction Date: 2025-01-18
|
||||
```
|
||||
@@ -0,0 +1,223 @@
|
||||
# Hook Setup Guide
|
||||
|
||||
Configure automatic self-improvement triggers for AI coding agents.
|
||||
|
||||
## Overview
|
||||
|
||||
Hooks enable proactive learning capture by injecting reminders at key moments:
|
||||
- **UserPromptSubmit**: Reminder after each prompt to evaluate learnings
|
||||
- **PostToolUse (Bash)**: Error detection when commands fail
|
||||
|
||||
## Claude Code Setup
|
||||
|
||||
### Option 1: Project-Level Configuration
|
||||
|
||||
Create `.claude/settings.json` in your project root:
|
||||
|
||||
```json
|
||||
{
|
||||
"hooks": {
|
||||
"UserPromptSubmit": [
|
||||
{
|
||||
"matcher": "",
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "./skills/self-improvement/scripts/activator.sh"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"PostToolUse": [
|
||||
{
|
||||
"matcher": "Bash",
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "./skills/self-improvement/scripts/error-detector.sh"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Option 2: User-Level Configuration
|
||||
|
||||
Add to `~/.claude/settings.json` for global activation:
|
||||
|
||||
```json
|
||||
{
|
||||
"hooks": {
|
||||
"UserPromptSubmit": [
|
||||
{
|
||||
"matcher": "",
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "~/.claude/skills/self-improvement/scripts/activator.sh"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Minimal Setup (Activator Only)
|
||||
|
||||
For lower overhead, use only the UserPromptSubmit hook:
|
||||
|
||||
```json
|
||||
{
|
||||
"hooks": {
|
||||
"UserPromptSubmit": [
|
||||
{
|
||||
"matcher": "",
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "./skills/self-improvement/scripts/activator.sh"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Codex CLI Setup
|
||||
|
||||
Codex uses the same hook system as Claude Code. Create `.codex/settings.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"hooks": {
|
||||
"UserPromptSubmit": [
|
||||
{
|
||||
"matcher": "",
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "./skills/self-improvement/scripts/activator.sh"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## GitHub Copilot Setup
|
||||
|
||||
Copilot doesn't support hooks directly. Instead, add guidance to `.github/copilot-instructions.md`:
|
||||
|
||||
```markdown
|
||||
## Self-Improvement
|
||||
|
||||
After completing tasks that involved:
|
||||
- Debugging non-obvious issues
|
||||
- Discovering workarounds
|
||||
- Learning project-specific patterns
|
||||
- Resolving unexpected errors
|
||||
|
||||
Consider logging the learning to `.learnings/` using the format from the self-improvement skill.
|
||||
|
||||
For high-value learnings that would benefit other sessions, consider skill extraction.
|
||||
```
|
||||
|
||||
## Verification
|
||||
|
||||
### Test Activator Hook
|
||||
|
||||
1. Enable the hook configuration
|
||||
2. Start a new Claude Code session
|
||||
3. Send any prompt
|
||||
4. Verify you see `<self-improvement-reminder>` in the context
|
||||
|
||||
### Test Error Detector Hook
|
||||
|
||||
1. Enable PostToolUse hook for Bash
|
||||
2. Run a command that fails: `ls /nonexistent/path`
|
||||
3. Verify you see `<error-detected>` reminder
|
||||
|
||||
### Dry Run Extract Script
|
||||
|
||||
```bash
|
||||
./skills/self-improvement/scripts/extract-skill.sh test-skill --dry-run
|
||||
```
|
||||
|
||||
Expected output shows the skill scaffold that would be created.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Hook Not Triggering
|
||||
|
||||
1. **Check script permissions**: `chmod +x scripts/*.sh`
|
||||
2. **Verify path**: Use absolute paths or paths relative to project root
|
||||
3. **Check settings location**: Project vs user-level settings
|
||||
4. **Restart session**: Hooks are loaded at session start
|
||||
|
||||
### Permission Denied
|
||||
|
||||
```bash
|
||||
chmod +x ./skills/self-improvement/scripts/activator.sh
|
||||
chmod +x ./skills/self-improvement/scripts/error-detector.sh
|
||||
chmod +x ./skills/self-improvement/scripts/extract-skill.sh
|
||||
```
|
||||
|
||||
### Script Not Found
|
||||
|
||||
If using relative paths, ensure you're in the correct directory or use absolute paths:
|
||||
|
||||
```json
|
||||
{
|
||||
"command": "/absolute/path/to/skills/self-improvement/scripts/activator.sh"
|
||||
}
|
||||
```
|
||||
|
||||
### Too Much Overhead
|
||||
|
||||
If the activator feels intrusive:
|
||||
|
||||
1. **Use minimal setup**: Only UserPromptSubmit, skip PostToolUse
|
||||
2. **Add matcher filter**: Only trigger for certain prompts:
|
||||
|
||||
```json
|
||||
{
|
||||
"matcher": "fix|debug|error|issue",
|
||||
"hooks": [...]
|
||||
}
|
||||
```
|
||||
|
||||
## Hook Output Budget
|
||||
|
||||
The activator is designed to be lightweight:
|
||||
- **Target**: ~50-100 tokens per activation
|
||||
- **Content**: Structured reminder, not verbose instructions
|
||||
- **Format**: XML tags for easy parsing
|
||||
|
||||
If you need to reduce overhead further, you can edit `activator.sh` to output less text.
|
||||
|
||||
## Security Considerations
|
||||
|
||||
- Hook scripts run with the same permissions as Claude Code
|
||||
- Scripts only output text; they don't modify files or run commands
|
||||
- Error detector reads `CLAUDE_TOOL_OUTPUT` environment variable
|
||||
- All scripts are opt-in (you must configure them explicitly)
|
||||
|
||||
## Disabling Hooks
|
||||
|
||||
To temporarily disable without removing configuration:
|
||||
|
||||
1. **Comment out in settings**:
|
||||
```json
|
||||
{
|
||||
"hooks": {
|
||||
// "UserPromptSubmit": [...]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
2. **Or delete the settings file**: Hooks won't run without configuration
|
||||
@@ -0,0 +1,248 @@
|
||||
# OpenClaw Integration
|
||||
|
||||
Complete setup and usage guide for integrating the self-improvement skill with OpenClaw.
|
||||
|
||||
## Overview
|
||||
|
||||
OpenClaw uses workspace-based prompt injection combined with event-driven hooks. Context is injected from workspace files at session start, and hooks can trigger on lifecycle events.
|
||||
|
||||
## Workspace Structure
|
||||
|
||||
```
|
||||
~/.openclaw/
|
||||
├── workspace/ # Working directory
|
||||
│ ├── AGENTS.md # Multi-agent coordination patterns
|
||||
│ ├── SOUL.md # Behavioral guidelines and personality
|
||||
│ ├── TOOLS.md # Tool capabilities and gotchas
|
||||
│ ├── MEMORY.md # Long-term memory (main session only)
|
||||
│ └── memory/ # Daily memory files
|
||||
│ └── YYYY-MM-DD.md
|
||||
├── skills/ # Installed skills
|
||||
│ └── <skill-name>/
|
||||
│ └── SKILL.md
|
||||
└── hooks/ # Custom hooks
|
||||
└── <hook-name>/
|
||||
├── HOOK.md
|
||||
└── handler.ts
|
||||
```
|
||||
|
||||
## Quick Setup
|
||||
|
||||
### 1. Install the Skill
|
||||
|
||||
```bash
|
||||
clawdhub install self-improving-agent
|
||||
```
|
||||
|
||||
Or copy manually:
|
||||
|
||||
```bash
|
||||
cp -r self-improving-agent ~/.openclaw/skills/
|
||||
```
|
||||
|
||||
### 2. Install the Hook (Optional)
|
||||
|
||||
Copy the hook to OpenClaw's hooks directory:
|
||||
|
||||
```bash
|
||||
cp -r hooks/openclaw ~/.openclaw/hooks/self-improvement
|
||||
```
|
||||
|
||||
Enable the hook:
|
||||
|
||||
```bash
|
||||
openclaw hooks enable self-improvement
|
||||
```
|
||||
|
||||
### 3. Create Learning Files
|
||||
|
||||
Create the `.learnings/` directory in your workspace:
|
||||
|
||||
```bash
|
||||
mkdir -p ~/.openclaw/workspace/.learnings
|
||||
```
|
||||
|
||||
Or in the skill directory:
|
||||
|
||||
```bash
|
||||
mkdir -p ~/.openclaw/skills/self-improving-agent/.learnings
|
||||
```
|
||||
|
||||
## Injected Prompt Files
|
||||
|
||||
### AGENTS.md
|
||||
|
||||
Purpose: Multi-agent workflows and delegation patterns.
|
||||
|
||||
```markdown
|
||||
# Agent Coordination
|
||||
|
||||
## Delegation Rules
|
||||
- Use explore agent for open-ended codebase questions
|
||||
- Spawn sub-agents for long-running tasks
|
||||
- Use sessions_send for cross-session communication
|
||||
|
||||
## Session Handoff
|
||||
When delegating to another session:
|
||||
1. Provide full context in the handoff message
|
||||
2. Include relevant file paths
|
||||
3. Specify expected output format
|
||||
```
|
||||
|
||||
### SOUL.md
|
||||
|
||||
Purpose: Behavioral guidelines and communication style.
|
||||
|
||||
```markdown
|
||||
# Behavioral Guidelines
|
||||
|
||||
## Communication Style
|
||||
- Be direct and concise
|
||||
- Avoid unnecessary caveats and disclaimers
|
||||
- Use technical language appropriate to context
|
||||
|
||||
## Error Handling
|
||||
- Admit mistakes promptly
|
||||
- Provide corrected information immediately
|
||||
- Log significant errors to learnings
|
||||
```
|
||||
|
||||
### TOOLS.md
|
||||
|
||||
Purpose: Tool capabilities, integration gotchas, local configuration.
|
||||
|
||||
```markdown
|
||||
# Tool Knowledge
|
||||
|
||||
## Self-Improvement Skill
|
||||
Log learnings to `.learnings/` for continuous improvement.
|
||||
|
||||
## Local Tools
|
||||
- Document tool-specific gotchas here
|
||||
- Note authentication requirements
|
||||
- Track integration quirks
|
||||
```
|
||||
|
||||
## Learning Workflow
|
||||
|
||||
### Capturing Learnings
|
||||
|
||||
1. **In-session**: Log to `.learnings/` as usual
|
||||
2. **Cross-session**: Promote to workspace files
|
||||
|
||||
### Promotion Decision Tree
|
||||
|
||||
```
|
||||
Is the learning project-specific?
|
||||
├── Yes → Keep in .learnings/
|
||||
└── No → Is it behavioral/style-related?
|
||||
├── Yes → Promote to SOUL.md
|
||||
└── No → Is it tool-related?
|
||||
├── Yes → Promote to TOOLS.md
|
||||
└── No → Promote to AGENTS.md (workflow)
|
||||
```
|
||||
|
||||
### Promotion Format Examples
|
||||
|
||||
**From learning:**
|
||||
> Git push to GitHub fails without auth configured - triggers desktop prompt
|
||||
|
||||
**To TOOLS.md:**
|
||||
```markdown
|
||||
## Git
|
||||
- Don't push without confirming auth is configured
|
||||
- Use `gh auth status` to check GitHub CLI auth
|
||||
```
|
||||
|
||||
## Inter-Agent Communication
|
||||
|
||||
OpenClaw provides tools for cross-session communication:
|
||||
|
||||
### sessions_list
|
||||
|
||||
View active and recent sessions:
|
||||
```
|
||||
sessions_list(activeMinutes=30, messageLimit=3)
|
||||
```
|
||||
|
||||
### sessions_history
|
||||
|
||||
Read transcript from another session:
|
||||
```
|
||||
sessions_history(sessionKey="session-id", limit=50)
|
||||
```
|
||||
|
||||
### sessions_send
|
||||
|
||||
Send message to another session:
|
||||
```
|
||||
sessions_send(sessionKey="session-id", message="Learning: API requires X-Custom-Header")
|
||||
```
|
||||
|
||||
### sessions_spawn
|
||||
|
||||
Spawn a background sub-agent:
|
||||
```
|
||||
sessions_spawn(task="Research X and report back", label="research")
|
||||
```
|
||||
|
||||
## Available Hook Events
|
||||
|
||||
| Event | When It Fires |
|
||||
|-------|---------------|
|
||||
| `agent:bootstrap` | Before workspace files inject |
|
||||
| `command:new` | When `/new` command issued |
|
||||
| `command:reset` | When `/reset` command issued |
|
||||
| `command:stop` | When `/stop` command issued |
|
||||
| `gateway:startup` | When gateway starts |
|
||||
|
||||
## Detection Triggers
|
||||
|
||||
### Standard Triggers
|
||||
- User corrections ("No, that's wrong...")
|
||||
- Command failures (non-zero exit codes)
|
||||
- API errors
|
||||
- Knowledge gaps
|
||||
|
||||
### OpenClaw-Specific Triggers
|
||||
|
||||
| Trigger | Action |
|
||||
|---------|--------|
|
||||
| Tool call error | Log to TOOLS.md with tool name |
|
||||
| Session handoff confusion | Log to AGENTS.md with delegation pattern |
|
||||
| Model behavior surprise | Log to SOUL.md with expected vs actual |
|
||||
| Skill issue | Log to .learnings/ or report upstream |
|
||||
|
||||
## Verification
|
||||
|
||||
Check hook is registered:
|
||||
|
||||
```bash
|
||||
openclaw hooks list
|
||||
```
|
||||
|
||||
Check skill is loaded:
|
||||
|
||||
```bash
|
||||
openclaw status
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Hook not firing
|
||||
|
||||
1. Ensure hooks enabled in config
|
||||
2. Restart gateway after config changes
|
||||
3. Check gateway logs for errors
|
||||
|
||||
### Learnings not persisting
|
||||
|
||||
1. Verify `.learnings/` directory exists
|
||||
2. Check file permissions
|
||||
3. Ensure workspace path is configured correctly
|
||||
|
||||
### Skill not loading
|
||||
|
||||
1. Check skill is in skills directory
|
||||
2. Verify SKILL.md has correct frontmatter
|
||||
3. Run `openclaw status` to see loaded skills
|
||||
@@ -0,0 +1,20 @@
|
||||
#!/bin/bash
|
||||
# Self-Improvement Activator Hook
|
||||
# Triggers on UserPromptSubmit to remind Claude about learning capture
|
||||
# Keep output minimal (~50-100 tokens) to minimize overhead
|
||||
|
||||
set -e
|
||||
|
||||
# Output reminder as system context
|
||||
cat << 'EOF'
|
||||
<self-improvement-reminder>
|
||||
After completing this task, evaluate if extractable knowledge emerged:
|
||||
- Non-obvious solution discovered through investigation?
|
||||
- Workaround for unexpected behavior?
|
||||
- Project-specific pattern learned?
|
||||
- Error required debugging to resolve?
|
||||
|
||||
If yes: Log to .learnings/ using the self-improvement skill format.
|
||||
If high-value (recurring, broadly applicable): Consider skill extraction.
|
||||
</self-improvement-reminder>
|
||||
EOF
|
||||
@@ -0,0 +1,55 @@
|
||||
#!/bin/bash
|
||||
# Self-Improvement Error Detector Hook
|
||||
# Triggers on PostToolUse for Bash to detect command failures
|
||||
# Reads CLAUDE_TOOL_OUTPUT environment variable
|
||||
|
||||
set -e
|
||||
|
||||
# Check if tool output indicates an error
|
||||
# CLAUDE_TOOL_OUTPUT contains the result of the tool execution
|
||||
OUTPUT="${CLAUDE_TOOL_OUTPUT:-}"
|
||||
|
||||
# Patterns indicating errors (case-insensitive matching)
|
||||
ERROR_PATTERNS=(
|
||||
"error:"
|
||||
"Error:"
|
||||
"ERROR:"
|
||||
"failed"
|
||||
"FAILED"
|
||||
"command not found"
|
||||
"No such file"
|
||||
"Permission denied"
|
||||
"fatal:"
|
||||
"Exception"
|
||||
"Traceback"
|
||||
"npm ERR!"
|
||||
"ModuleNotFoundError"
|
||||
"SyntaxError"
|
||||
"TypeError"
|
||||
"exit code"
|
||||
"non-zero"
|
||||
)
|
||||
|
||||
# Check if output contains any error pattern
|
||||
contains_error=false
|
||||
for pattern in "${ERROR_PATTERNS[@]}"; do
|
||||
if [[ "$OUTPUT" == *"$pattern"* ]]; then
|
||||
contains_error=true
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
# Only output reminder if error detected
|
||||
if [ "$contains_error" = true ]; then
|
||||
cat << 'EOF'
|
||||
<error-detected>
|
||||
A command error was detected. Consider logging this to .learnings/ERRORS.md if:
|
||||
- The error was unexpected or non-obvious
|
||||
- It required investigation to resolve
|
||||
- It might recur in similar contexts
|
||||
- The solution could benefit future sessions
|
||||
|
||||
Use the self-improvement skill format: [ERR-YYYYMMDD-XXX]
|
||||
</error-detected>
|
||||
EOF
|
||||
fi
|
||||
@@ -0,0 +1,221 @@
|
||||
#!/bin/bash
|
||||
# Skill Extraction Helper
|
||||
# Creates a new skill from a learning entry
|
||||
# Usage: ./extract-skill.sh <skill-name> [--dry-run]
|
||||
|
||||
set -e
|
||||
|
||||
# Configuration
|
||||
SKILLS_DIR="./skills"
|
||||
|
||||
# Colors for output
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
usage() {
|
||||
cat << EOF
|
||||
Usage: $(basename "$0") <skill-name> [options]
|
||||
|
||||
Create a new skill from a learning entry.
|
||||
|
||||
Arguments:
|
||||
skill-name Name of the skill (lowercase, hyphens for spaces)
|
||||
|
||||
Options:
|
||||
--dry-run Show what would be created without creating files
|
||||
--output-dir Relative output directory under current path (default: ./skills)
|
||||
-h, --help Show this help message
|
||||
|
||||
Examples:
|
||||
$(basename "$0") docker-m1-fixes
|
||||
$(basename "$0") api-timeout-patterns --dry-run
|
||||
$(basename "$0") pnpm-setup --output-dir ./skills/custom
|
||||
|
||||
The skill will be created in: \$SKILLS_DIR/<skill-name>/
|
||||
EOF
|
||||
}
|
||||
|
||||
log_info() {
|
||||
echo -e "${GREEN}[INFO]${NC} $1"
|
||||
}
|
||||
|
||||
log_warn() {
|
||||
echo -e "${YELLOW}[WARN]${NC} $1"
|
||||
}
|
||||
|
||||
log_error() {
|
||||
echo -e "${RED}[ERROR]${NC} $1" >&2
|
||||
}
|
||||
|
||||
# Parse arguments
|
||||
SKILL_NAME=""
|
||||
DRY_RUN=false
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case $1 in
|
||||
--dry-run)
|
||||
DRY_RUN=true
|
||||
shift
|
||||
;;
|
||||
--output-dir)
|
||||
if [ -z "${2:-}" ] || [[ "${2:-}" == -* ]]; then
|
||||
log_error "--output-dir requires a relative path argument"
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
SKILLS_DIR="$2"
|
||||
shift 2
|
||||
;;
|
||||
-h|--help)
|
||||
usage
|
||||
exit 0
|
||||
;;
|
||||
-*)
|
||||
log_error "Unknown option: $1"
|
||||
usage
|
||||
exit 1
|
||||
;;
|
||||
*)
|
||||
if [ -z "$SKILL_NAME" ]; then
|
||||
SKILL_NAME="$1"
|
||||
else
|
||||
log_error "Unexpected argument: $1"
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
shift
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Validate skill name
|
||||
if [ -z "$SKILL_NAME" ]; then
|
||||
log_error "Skill name is required"
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Validate skill name format (lowercase, hyphens, no spaces)
|
||||
if ! [[ "$SKILL_NAME" =~ ^[a-z0-9]+(-[a-z0-9]+)*$ ]]; then
|
||||
log_error "Invalid skill name format. Use lowercase letters, numbers, and hyphens only."
|
||||
log_error "Examples: 'docker-fixes', 'api-patterns', 'pnpm-setup'"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Validate output path to avoid writes outside current workspace.
|
||||
if [[ "$SKILLS_DIR" = /* ]]; then
|
||||
log_error "Output directory must be a relative path under the current directory."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ "$SKILLS_DIR" =~ (^|/)\.\.(/|$) ]]; then
|
||||
log_error "Output directory cannot include '..' path segments."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
SKILLS_DIR="${SKILLS_DIR#./}"
|
||||
SKILLS_DIR="./$SKILLS_DIR"
|
||||
|
||||
SKILL_PATH="$SKILLS_DIR/$SKILL_NAME"
|
||||
|
||||
# Check if skill already exists
|
||||
if [ -d "$SKILL_PATH" ] && [ "$DRY_RUN" = false ]; then
|
||||
log_error "Skill already exists: $SKILL_PATH"
|
||||
log_error "Use a different name or remove the existing skill first."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Dry run output
|
||||
if [ "$DRY_RUN" = true ]; then
|
||||
log_info "Dry run - would create:"
|
||||
echo " $SKILL_PATH/"
|
||||
echo " $SKILL_PATH/SKILL.md"
|
||||
echo ""
|
||||
echo "Template content would be:"
|
||||
echo "---"
|
||||
cat << TEMPLATE
|
||||
name: $SKILL_NAME
|
||||
description: "[TODO: Add a concise description of what this skill does and when to use it]"
|
||||
---
|
||||
|
||||
# $(echo "$SKILL_NAME" | sed 's/-/ /g' | awk '{for(i=1;i<=NF;i++) $i=toupper(substr($i,1,1)) tolower(substr($i,2))}1')
|
||||
|
||||
[TODO: Brief introduction explaining the skill's purpose]
|
||||
|
||||
## Quick Reference
|
||||
|
||||
| Situation | Action |
|
||||
|-----------|--------|
|
||||
| [Trigger condition] | [What to do] |
|
||||
|
||||
## Usage
|
||||
|
||||
[TODO: Detailed usage instructions]
|
||||
|
||||
## Examples
|
||||
|
||||
[TODO: Add concrete examples]
|
||||
|
||||
## Source Learning
|
||||
|
||||
This skill was extracted from a learning entry.
|
||||
- Learning ID: [TODO: Add original learning ID]
|
||||
- Original File: .learnings/LEARNINGS.md
|
||||
TEMPLATE
|
||||
echo "---"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Create skill directory structure
|
||||
log_info "Creating skill: $SKILL_NAME"
|
||||
|
||||
mkdir -p "$SKILL_PATH"
|
||||
|
||||
# Create SKILL.md from template
|
||||
cat > "$SKILL_PATH/SKILL.md" << TEMPLATE
|
||||
---
|
||||
name: $SKILL_NAME
|
||||
description: "[TODO: Add a concise description of what this skill does and when to use it]"
|
||||
---
|
||||
|
||||
# $(echo "$SKILL_NAME" | sed 's/-/ /g' | awk '{for(i=1;i<=NF;i++) $i=toupper(substr($i,1,1)) tolower(substr($i,2))}1')
|
||||
|
||||
[TODO: Brief introduction explaining the skill's purpose]
|
||||
|
||||
## Quick Reference
|
||||
|
||||
| Situation | Action |
|
||||
|-----------|--------|
|
||||
| [Trigger condition] | [What to do] |
|
||||
|
||||
## Usage
|
||||
|
||||
[TODO: Detailed usage instructions]
|
||||
|
||||
## Examples
|
||||
|
||||
[TODO: Add concrete examples]
|
||||
|
||||
## Source Learning
|
||||
|
||||
This skill was extracted from a learning entry.
|
||||
- Learning ID: [TODO: Add original learning ID]
|
||||
- Original File: .learnings/LEARNINGS.md
|
||||
TEMPLATE
|
||||
|
||||
log_info "Created: $SKILL_PATH/SKILL.md"
|
||||
|
||||
# Suggest next steps
|
||||
echo ""
|
||||
log_info "Skill scaffold created successfully!"
|
||||
echo ""
|
||||
echo "Next steps:"
|
||||
echo " 1. Edit $SKILL_PATH/SKILL.md"
|
||||
echo " 2. Fill in the TODO sections with content from your learning"
|
||||
echo " 3. Add references/ folder if you have detailed documentation"
|
||||
echo " 4. Add scripts/ folder if you have executable code"
|
||||
echo " 5. Update the original learning entry with:"
|
||||
echo " **Status**: promoted_to_skill"
|
||||
echo " **Skill-Path**: skills/$SKILL_NAME"
|
||||
@@ -0,0 +1,106 @@
|
||||
[
|
||||
{
|
||||
"id": 0,
|
||||
"prompt": "Monitor AADE websites for deadline changes in the last 24 hours and generate immediate alerts for any critical changes affecting VAT submissions or individual tax deadlines. Process downloaded government documents and classify by urgency.",
|
||||
"expectations": [
|
||||
"Downloads and processes AADE announcements from government websites",
|
||||
"Uses OpenClaw deepread skill for Greek document text extraction",
|
||||
"Detects deadline changes by comparing with cached previous versions",
|
||||
"Classifies changes as critical, important, or routine based on business impact",
|
||||
"Generates immediate alerts for critical VAT deadline changes",
|
||||
"Creates professional Greek language notifications for accounting firms",
|
||||
"Integrates with cli-deadline-monitor to update compliance calendars",
|
||||
"Maintains complete audit trail of detected changes"
|
||||
],
|
||||
"files": [
|
||||
{
|
||||
"name": "aade_deadline_change.pdf",
|
||||
"content": "simulated_pdf_binary_data"
|
||||
},
|
||||
{
|
||||
"name": "monitoring_config.yaml",
|
||||
"content": "monitoring:\n sources:\n - url: \"https://www.aade.gr/epiheiriseis/forologikes-ypohreosieis\"\n type: \"deadlines\"\n frequency: \"2_hours\"\n - url: \"https://www.aade.gr/deltia-typou\"\n type: \"announcements\"\n frequency: \"4_hours\"\n \ndetection:\n deadline_keywords:\n - \"πÏοθεσμία\"\n - \"λήξη\" \n - \"υποβολή\"\n - \"deadline\"\n \n critical_taxes:\n - \"ΦΠΑ\"\n - \"VAT\"\n - \"εισοδήματος\"\n - \"income tax\"\n - \"ΕÎΦΘΑ\"\n - \"ENFIA\"\n \nalerts:\n critical_delivery:\n - \"immediate_email\"\n - \"sms_notification\"\n - \"slack_alert\"\n \n templates:\n language: \"greek\"\n tone: \"professional\""
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 1,
|
||||
"prompt": "Set up automated AADE system status monitoring to track TAXIS, myDATA, and EFKA system availability. Generate uptime reports and alert accounting teams when critical systems are down for more than 30 minutes.",
|
||||
"expectations": [
|
||||
"Configures automated monitoring of Greek government tax systems",
|
||||
"Tracks system response times and availability metrics",
|
||||
"Detects system outages and maintenance windows automatically",
|
||||
"Generates business impact assessments for system outages",
|
||||
"Creates alerts when critical systems unavailable >30 minutes",
|
||||
"Provides workaround suggestions for system outages",
|
||||
"Integrates with accounting workflows to delay automated submissions",
|
||||
"Maintains historical uptime data for reliability analysis"
|
||||
],
|
||||
"files": [
|
||||
{
|
||||
"name": "system_status_data.json",
|
||||
"content": "{\n \"monitoring_timestamp\": \"2026-02-18T10:30:00Z\",\n \"systems\": {\n \"taxis\": {\n \"url\": \"https://www1.aade.gr/taxisnet\",\n \"status\": \"online\",\n \"response_time_ms\": 245,\n \"last_check\": \"2026-02-18T10:29:45Z\",\n \"uptime_24h\": 98.2,\n \"critical_services\": [\"vat_submissions\", \"income_tax\", \"digital_signatures\"]\n },\n \"mydata\": {\n \"url\": \"https://mydatapi.aade.gr\",\n \"status\": \"online\", \n \"response_time_ms\": 180,\n \"last_check\": \"2026-02-18T10:29:50Z\",\n \"uptime_24h\": 99.1,\n \"critical_services\": [\"invoice_submissions\", \"real_time_data\", \"api_access\"]\n },\n \"efka_portal\": {\n \"url\": \"https://www.efka.gov.gr\",\n \"status\": \"maintenance\",\n \"response_time_ms\": null,\n \"last_check\": \"2026-02-18T10:25:00Z\",\n \"uptime_24h\": 97.5,\n \"maintenance_window\": {\n \"start\": \"2026-02-18T10:00:00Z\",\n \"estimated_end\": \"2026-02-18T12:00:00Z\",\n \"announced\": true\n },\n \"critical_services\": [\"social_security_submissions\", \"employee_records\", \"contributions\"]\n }\n },\n \"alerts_generated\": [\n {\n \"system\": \"efka_portal\",\n \"type\": \"scheduled_maintenance\",\n \"severity\": \"medium\",\n \"message\": \"EFKA portal scheduled maintenance 10:00-12:00 EET\",\n \"business_impact\": \"Social security submissions delayed\"\n }\n ]\n}"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"prompt": "Process a batch of AADE circulars and announcements to detect VAT rate changes, new tax regulations, and implementation dates. Generate professional Greek language summaries for accounting firm clients.",
|
||||
"expectations": [
|
||||
"Processes multiple Greek government documents simultaneously",
|
||||
"Extracts VAT rate information and effective dates accurately",
|
||||
"Identifies new tax regulations and compliance requirements",
|
||||
"Calculates business impact of rate changes on different client types",
|
||||
"Generates professional Greek language client communications",
|
||||
"Creates implementation timeline for new regulations",
|
||||
"Integrates with greek-compliance-aade skill for rate updates",
|
||||
"Provides specific guidance for different business sectors"
|
||||
],
|
||||
"files": [
|
||||
{
|
||||
"name": "aade_circulars_batch.json",
|
||||
"content": "{\n \"processing_batch\": \"2026-02-18_circulars\",\n \"documents\": [\n {\n \"document_id\": \"POL.1157/2026\",\n \"title\": \"ΔιευκÏινήσεις επί του ΦΠΑ για ψηφιακές υπηÏεσίες\",\n \"date_published\": \"2026-02-15\",\n \"effective_date\": \"2026-03-01\",\n \"document_type\": \"circular\",\n \"content_summary\": \"Clarifications on VAT treatment of digital services\",\n \"key_changes\": [\n \"Digital services to EU customers now subject to 24% VAT\",\n \"New reporting requirements for digital platform operators\",\n \"Exemption threshold raised to €10,000 annually\"\n ],\n \"affected_businesses\": [\"software_companies\", \"digital_platforms\", \"online_services\"]\n },\n {\n \"document_id\": \"POL.1158/2026\", \n \"title\": \"Αλλαγή πÏοθεσμίας υποβολής μηνιαίας δήλωσης ΦΠΑ\",\n \"date_published\": \"2026-02-18\",\n \"effective_date\": \"2026-04-20\", \n \"document_type\": \"deadline_change\",\n \"content_summary\": \"Monthly VAT deadline moved earlier\",\n \"key_changes\": [\n \"March 2026 VAT returns due April 20 instead of April 25\",\n \"Change applies to all monthly VAT filers\",\n \"No extension available for this deadline\"\n ],\n \"affected_businesses\": [\"all_vat_registered\"],\n \"urgency\": \"critical\"\n },\n {\n \"document_id\": \"POL.1159/2026\",\n \"title\": \"Îέες φοÏολογικές ελαφÏÏνσεις για ΜμΕ\",\n \"date_published\": \"2026-02-16\",\n \"effective_date\": \"2026-01-01\",\n \"document_type\": \"tax_relief\",\n \"content_summary\": \"New tax benefits for small and medium enterprises\",\n \"key_changes\": [\n \"Reduced corporate tax rate 20% for SMEs (turnover <€1M)\",\n \"Enhanced depreciation rates for equipment purchases\", \n \"Simplified tax return procedures for qualifying businesses\"\n ],\n \"affected_businesses\": [\"small_medium_enterprises\"]\n }\n ]\n}"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"prompt": "Handle emergency AADE system outage affecting TAXIS submissions. Activate offline mode, notify affected clients in Greek, provide alternative submission procedures, and track system restoration.",
|
||||
"expectations": [
|
||||
"Detects major system outage affecting critical tax submissions",
|
||||
"Immediately activates offline/emergency mode with cached data",
|
||||
"Generates urgent professional Greek language client notifications",
|
||||
"Provides step-by-step alternative submission procedures",
|
||||
"Coordinates with meta-skill to delay automated submissions",
|
||||
"Tracks system restoration and resumption of normal operations",
|
||||
"Creates post-incident report with timeline and impact analysis",
|
||||
"Updates contingency procedures based on lessons learned"
|
||||
],
|
||||
"files": [
|
||||
{
|
||||
"name": "system_outage_event.json",
|
||||
"content": "{\n \"incident\": {\n \"incident_id\": \"TAXIS-OUT-20260218-001\",\n \"system_affected\": \"TAXIS\",\n \"outage_start\": \"2026-02-18T11:45:00Z\",\n \"detection_time\": \"2026-02-18T11:47:30Z\",\n \"severity\": \"critical\",\n \"status\": \"active_outage\"\n },\n \"impact_assessment\": {\n \"affected_services\": [\n \"VAT return submissions\",\n \"Income tax filings\",\n \"Digital signature services\",\n \"ENFIA payments\",\n \"Professional tax submissions\"\n ],\n \"estimated_affected_users\": 150000,\n \"business_impact\": \"All tax submissions halted nationwide\",\n \"deadline_risks\": [\n {\n \"deadline_type\": \"Monthly VAT returns\", \n \"due_date\": \"2026-02-20\",\n \"risk_level\": \"high\",\n \"affected_clients\": 47\n },\n {\n \"deadline_type\": \"Quarterly social security\",\n \"due_date\": \"2026-02-28\", \n \"risk_level\": \"medium\",\n \"affected_clients\": 12\n }\n ]\n },\n \"response_actions\": {\n \"immediate_actions\": [\n \"Activate emergency mode\",\n \"Switch to cached deadline data\",\n \"Generate client emergency notifications\",\n \"Prepare manual submission procedures\"\n ],\n \"client_communication\": {\n \"urgency\": \"immediate\",\n \"channels\": [\"email\", \"sms\", \"phone_calls\"],\n \"language\": \"greek\",\n \"tone\": \"professional_urgent\"\n },\n \"alternative_procedures\": [\n \"Paper submission at tax offices\",\n \"Authorized agent submission\",\n \"Email submission with follow-up\",\n \"Extension request procedures\"\n ]\n }\n}"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"prompt": "Generate weekly AADE monitoring summary report for accounting firm management including system uptime statistics, detected changes, client impact analysis, and upcoming compliance requirements.",
|
||||
"expectations": [
|
||||
"Compiles comprehensive weekly monitoring statistics and trends",
|
||||
"Analyzes system reliability data and identifies patterns",
|
||||
"Summarizes all detected regulatory and deadline changes",
|
||||
"Provides client impact analysis with specific recommendations",
|
||||
"Creates professional management report in Greek",
|
||||
"Includes actionable insights and strategic recommendations",
|
||||
"Integrates data from all monitoring activities and skill interactions",
|
||||
"Formats report suitable for accounting firm management review"
|
||||
],
|
||||
"files": [
|
||||
{
|
||||
"name": "weekly_monitoring_data.json",
|
||||
"content": "{\n \"report_period\": {\n \"start_date\": \"2026-02-10\", \n \"end_date\": \"2026-02-16\",\n \"total_monitoring_hours\": 168\n },\n \"system_reliability\": {\n \"taxis\": {\n \"uptime_percentage\": 98.8,\n \"total_outages\": 2,\n \"longest_outage_minutes\": 45,\n \"average_response_time_ms\": 267,\n \"performance_trend\": \"stable\"\n },\n \"mydata\": {\n \"uptime_percentage\": 99.2,\n \"total_outages\": 1,\n \"longest_outage_minutes\": 15,\n \"average_response_time_ms\": 198,\n \"performance_trend\": \"improving\"\n },\n \"efka_portal\": {\n \"uptime_percentage\": 97.1,\n \"total_outages\": 3,\n \"longest_outage_minutes\": 120,\n \"average_response_time_ms\": 445,\n \"performance_trend\": \"declining\",\n \"scheduled_maintenance\": 1\n }\n },\n \"detected_changes\": {\n \"total_documents_processed\": 23,\n \"critical_changes\": 1,\n \"important_changes\": 3,\n \"routine_updates\": 19,\n \"changes_summary\": [\n {\n \"type\": \"deadline_change\",\n \"severity\": \"critical\",\n \"description\": \"VAT submission deadline moved forward 5 days\",\n \"clients_affected\": 47,\n \"action_taken\": \"Immediate client notifications sent\"\n },\n {\n \"type\": \"rate_change\",\n \"severity\": \"important\", \n \"description\": \"New VAT exemption for digital services\",\n \"clients_affected\": 8,\n \"action_taken\": \"Client consultation scheduled\"\n }\n ]\n },\n \"client_impact_analysis\": {\n \"high_impact_clients\": 12,\n \"medium_impact_clients\": 35, \n \"low_impact_clients\": 89,\n \"immediate_action_required\": 5,\n \"consultation_recommended\": 15,\n \"monitoring_only\": 117\n },\n \"upcoming_compliance\": {\n \"next_7_days\": [\n {\"type\": \"Monthly VAT\", \"count\": 47, \"deadline\": \"2026-02-20\"},\n {\"type\": \"Employee declarations\", \"count\": 12, \"deadline\": \"2026-02-22\"}\n ],\n \"next_30_days\": [\n {\"type\": \"Quarterly social security\", \"count\": 67, \"deadline\": \"2026-02-28\"},\n {\"type\": \"ENFIA payments\", \"count\": 23, \"deadline\": \"2026-03-15\"}\n ]\n },\n \"recommendations\": [\n \"Increase EFKA monitoring frequency due to recent instability\",\n \"Prepare contingency plans for March VAT submissions\",\n \"Schedule client consultations for digital services VAT changes\",\n \"Consider automated backup submission procedures for critical deadlines\"\n ]\n}"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,518 @@
|
||||
---
|
||||
name: aade-api-monitor
|
||||
description: Real-time monitoring of Greek AADE tax authority systems — tracks deadlines, rate changes, and compliance updates. File-based, OpenClaw-native.
|
||||
version: 1.0.0
|
||||
author: openclaw-greek-accounting
|
||||
homepage: https://github.com/satoshistackalotto/openclaw-greek-accounting
|
||||
tags: ["greek", "accounting", "aade", "government-monitoring", "api"]
|
||||
metadata: {"openclaw": {"requires": {"bins": ["jq", "curl"], "env": ["OPENCLAW_DATA_DIR", "AADE_USERNAME", "AADE_PASSWORD"]}, "optional_env": {"SLACK_WEBHOOK_URL": "Webhook URL for urgent AADE change alerts", "SMS_GATEWAY_URL": "SMS gateway for critical compliance alerts", "GOOGLE_CALENDAR_ID": "Google Calendar ID for compliance deadline sync (optional)", "OUTLOOK_CALENDAR_ID": "Outlook Calendar ID for compliance deadline sync (optional)"}, "notes": "AADE credentials required for monitoring government portal. Slack and SMS alert channels are optional — if not configured, alerts are written to local files only."}}
|
||||
---
|
||||
|
||||
# AADE API Monitor
|
||||
|
||||
This skill provides comprehensive monitoring of AADE systems and announcements through OpenClaw's file processing capabilities, delivering real-time alerts for Greek tax compliance changes.
|
||||
|
||||
|
||||
## Setup
|
||||
|
||||
```bash
|
||||
export OPENCLAW_DATA_DIR="/data"
|
||||
export AADE_USERNAME="your-aade-username"
|
||||
export AADE_PASSWORD="your-aade-password"
|
||||
which jq curl || sudo apt install jq curl
|
||||
```
|
||||
|
||||
AADE credentials are used for authenticated read-only checks of announcements, rate changes, and system status. This skill never submits filings.
|
||||
|
||||
|
||||
## Core Philosophy
|
||||
|
||||
- **File-First Processing**: Monitor and process government documents, not complex APIs
|
||||
- **Reliable Operation**: Work offline with cached data when government sites unavailable
|
||||
- **OpenClaw Native**: Built specifically for OpenClaw's strengths and limitations
|
||||
- **Production Ready**: Error handling, logging, and recovery built-in from start
|
||||
- **Greek Business Focus**: Professional alerts and reporting in Greek
|
||||
|
||||
## OpenClaw Commands
|
||||
|
||||
### Core AADE Monitoring Commands
|
||||
```bash
|
||||
# Primary monitoring operations
|
||||
openclaw aade monitor --enable --government-sites --cache-updates
|
||||
openclaw aade check-updates --since "24 hours" --urgent-only
|
||||
openclaw aade download-announcements --date today --all-categories
|
||||
openclaw aade scan-deadlines --compare-previous --alert-changes
|
||||
|
||||
# System status monitoring
|
||||
openclaw aade status-check --taxis --mydata --efka --report-outages
|
||||
openclaw aade system-health --uptime-tracking --performance-metrics
|
||||
openclaw aade maintenance-schedule --upcoming --impact-assessment
|
||||
|
||||
# Document processing
|
||||
openclaw aade process-documents --input /data/incoming/government/ --extract-deadlines
|
||||
openclaw aade classify-updates --tax-changes --deadline-changes --system-updates
|
||||
openclaw aade generate-alerts --priority high --recipients accounting-team
|
||||
```
|
||||
|
||||
### Deadline & Rate Change Monitoring
|
||||
```bash
|
||||
# Deadline monitoring
|
||||
openclaw aade monitor-deadlines --vat --income-tax --enfia --social-security
|
||||
openclaw aade deadline-changes --since yesterday --client-impact-analysis
|
||||
openclaw aade calendar-update --sync-changes --notify-affected-clients
|
||||
|
||||
# Rate and regulation changes
|
||||
openclaw aade monitor-rates --vat-rates --tax-brackets --social-security
|
||||
openclaw aade regulation-tracker --new-circulars --law-changes --implementation-dates
|
||||
openclaw aade impact-analysis --rate-changes --client-calculations --cost-impact
|
||||
```
|
||||
|
||||
### Integration & Reporting Commands
|
||||
```bash
|
||||
# Integration with other skills
|
||||
openclaw aade integrate --cli-deadline-monitor --email-processor --meta-skill
|
||||
openclaw aade export-data --format json --destination /data/dashboard/state/
|
||||
openclaw aade sync-calendar --include-holidays
|
||||
|
||||
# Professional reporting
|
||||
openclaw aade report-generate --daily --weekly --monthly --client-ready-greek
|
||||
openclaw aade client-notifications --deadline-changes --rate-updates --professional-tone
|
||||
openclaw aade compliance-dashboard --current-status --upcoming-deadlines --action-items
|
||||
```
|
||||
|
||||
## OpenClaw File Processing Architecture
|
||||
|
||||
### File System Organization
|
||||
```yaml
|
||||
AADE_File_Structure:
|
||||
input_monitoring: # Raw government documents arrive here
|
||||
- /data/incoming/government/ # All AADE/government downloads
|
||||
|
||||
processing_workspace: # Ephemeral — cleared after pipeline
|
||||
- /data/processing/compliance/ # Classification and extraction workspace
|
||||
|
||||
output_delivery:
|
||||
- /data/dashboard/state/current-alerts.json # Active alerts for dashboard
|
||||
- /data/dashboard/state/deadline-tracker.json # Updated deadline tracker
|
||||
- /data/reports/compliance/ # Professional compliance reports
|
||||
- /data/exports/compliance-deadlines.json # Calendar integration export
|
||||
```
|
||||
|
||||
### Document Processing Pipeline
|
||||
```yaml
|
||||
Processing_Workflow:
|
||||
step_1_download:
|
||||
command: "openclaw aade download-batch --sources all --format pdf,html,xml"
|
||||
input: "Government website monitoring"
|
||||
output: "/data/incoming/government/{YYYYMMDD}/"
|
||||
|
||||
step_2_extract:
|
||||
command: "openclaw aade extract-content --use-deepread --greek-language"
|
||||
input: "/data/incoming/government/"
|
||||
output: "/data/processing/compliance/"
|
||||
|
||||
step_3_classify:
|
||||
command: "openclaw aade classify-importance --deadline-changes high --rate-changes high"
|
||||
input: "/data/processing/compliance/"
|
||||
output: "/data/processing/compliance/"
|
||||
|
||||
step_4_compare:
|
||||
command: "openclaw aade detect-changes --compare-with-cache --highlight-differences"
|
||||
input: "/data/processing/compliance/"
|
||||
output: "/data/processing/compliance/"
|
||||
|
||||
step_5_validate:
|
||||
command: "openclaw aade validate-data --cross-reference --accuracy-check"
|
||||
input: "/data/processing/compliance/"
|
||||
output: "/data/processing/compliance/"
|
||||
|
||||
step_6_generate:
|
||||
command: "openclaw aade generate-outputs --alerts --reports --notifications"
|
||||
input: "/data/processing/compliance/"
|
||||
output: "/data/dashboard/state/ and /data/reports/compliance/"
|
||||
```
|
||||
|
||||
## Intelligent Document Monitoring
|
||||
|
||||
### AADE Website Monitoring Strategy
|
||||
```yaml
|
||||
Government_Site_Monitoring:
|
||||
primary_sources:
|
||||
aade_main:
|
||||
url: "https://www.aade.gr"
|
||||
sections: ["announcements", "circulars", "deadlines", "rates"]
|
||||
frequency: "every_2_hours"
|
||||
|
||||
taxis_updates:
|
||||
url: "https://www1.aade.gr/taxisnet"
|
||||
sections: ["system-announcements", "maintenance-schedules"]
|
||||
frequency: "every_4_hours"
|
||||
|
||||
mydata_status:
|
||||
url: "https://mydatapi.aade.gr"
|
||||
sections: ["api-status", "system-updates", "technical-announcements"]
|
||||
frequency: "hourly"
|
||||
|
||||
backup_sources:
|
||||
press_releases:
|
||||
url: "https://www.aade.gr/deltia-typou"
|
||||
fallback: true
|
||||
|
||||
legal_database:
|
||||
url: "https://www.aade.gr/nomothesia"
|
||||
frequency: "daily"
|
||||
```
|
||||
|
||||
### Intelligent Change Detection
|
||||
```yaml
|
||||
Change_Detection_Logic:
|
||||
deadline_changes:
|
||||
triggers:
|
||||
- "Date changes in deadline tables"
|
||||
- "New deadline announcements"
|
||||
- "Extension or acceleration notices"
|
||||
confidence_threshold: 0.95
|
||||
validation: "Cross-reference multiple sources"
|
||||
|
||||
rate_changes:
|
||||
triggers:
|
||||
- "VAT rate modifications"
|
||||
- "Tax bracket adjustments"
|
||||
- "Social security rate updates"
|
||||
effective_date_tracking: "Extract implementation dates"
|
||||
impact_calculation: "Estimate client effects"
|
||||
|
||||
system_updates:
|
||||
triggers:
|
||||
- "Maintenance announcements"
|
||||
- "New feature releases"
|
||||
- "System outage notifications"
|
||||
criticality_assessment: "Business impact analysis"
|
||||
workaround_suggestions: "Alternative procedures"
|
||||
```
|
||||
|
||||
## OpenClaw-Native Processing Features
|
||||
|
||||
### Robust Error Handling
|
||||
```bash
|
||||
# Error recovery commands
|
||||
openclaw aade retry-failed --batch-id {id} --fix-network-issues
|
||||
openclaw aade fallback-mode --use-cached-data --offline-operation
|
||||
openclaw aade manual-review --flagged-updates --require-human-verification
|
||||
|
||||
# Monitoring and diagnostics
|
||||
openclaw aade health-check --test-all-sources --report-failures
|
||||
openclaw aade diagnostics --connection-test --parsing-test --alert-test
|
||||
openclaw aade logs --filter errors --last 48h --include-context
|
||||
```
|
||||
|
||||
### Caching & Offline Operation
|
||||
```yaml
|
||||
Caching_Strategy:
|
||||
announcement_cache:
|
||||
retention: "90 days"
|
||||
update_frequency: "every_2_hours"
|
||||
fallback_behavior: "Use cached data if source unavailable"
|
||||
|
||||
deadline_cache:
|
||||
retention: "1 year"
|
||||
critical_updates: "Force immediate refresh"
|
||||
validation: "Compare multiple sources for accuracy"
|
||||
|
||||
system_status_cache:
|
||||
retention: "7 days"
|
||||
real_time_updates: "When possible"
|
||||
offline_mode: "Report last known status with timestamp"
|
||||
```
|
||||
|
||||
### Greek Language Processing
|
||||
```yaml
|
||||
Greek_Document_Processing:
|
||||
text_extraction:
|
||||
encoding: "UTF-8, Windows-1253, ISO-8859-7"
|
||||
ocr_support: "Greek character recognition via deepread"
|
||||
|
||||
keyword_detection:
|
||||
deadline_terms: ["προθεσμία", "λήξη", "υποβολή", "deadline"]
|
||||
rate_terms: ["συνπžελεσπžήπš", "ποσοσπžς", "π ςροπš", "rate", "tax"]
|
||||
system_terms: ["συνπžήρηση", "διακοπή", "maintenance", "outage"]
|
||||
|
||||
date_recognition:
|
||||
greek_formats: ["dd/MM/yyyy", "dd-MM-yyyy", "dd Μμμ yyyy"]
|
||||
month_names: ["Ιανουάριοπš", "Φεβρουάριοπš", ..., "Δεκέμβριοπš"]
|
||||
business_day_calculation: "Exclude Greek holidays and weekends"
|
||||
```
|
||||
|
||||
## Professional Alert System
|
||||
|
||||
### Alert Generation & Classification
|
||||
```yaml
|
||||
Alert_System:
|
||||
critical_alerts:
|
||||
deadline_changes:
|
||||
trigger: "Any tax deadline moved forward"
|
||||
delivery: "Immediate notification to assigned accountant"
|
||||
template: "ΡΡΙΣΙΜθ: Προθεσμία {tax_type} μεπžακινήθηκε σπžιπš {new_date}"
|
||||
|
||||
system_outages:
|
||||
trigger: "TAXIS or myDATA unavailable >30 minutes"
|
||||
delivery: "Immediate notification to accounting teams"
|
||||
template: "ΔΙΑΡθΠΗ: Σύσπžημα {system_name} μη διαθέσιμο απς {outage_start}"
|
||||
|
||||
important_alerts:
|
||||
rate_changes:
|
||||
trigger: "VAT or tax rate modifications"
|
||||
delivery: "Email + dashboard update"
|
||||
template: "Αλλαγή συνπžελεσπžή: {rate_type} απς {old_rate} σε {new_rate}"
|
||||
|
||||
new_regulations:
|
||||
trigger: "New tax circulars or law changes"
|
||||
delivery: "Daily digest email"
|
||||
template: "Νέα εγκύκλιοπš: {circular_number} - {summary}"
|
||||
|
||||
routine_alerts:
|
||||
system_maintenance:
|
||||
trigger: "Scheduled maintenance announcements"
|
||||
delivery: "Weekly summary"
|
||||
template: "Προγραμμαπžισμένη συνπžήρηση: {system} πžην {date} {time}"
|
||||
```
|
||||
|
||||
### Greek Professional Communication
|
||||
```yaml
|
||||
Professional_Templates:
|
||||
client_deadline_alert:
|
||||
subject: "Σημανπžική ενημέρπ°ση: Αλλαγή προθεσμίαπš {tax_type}"
|
||||
body: |
|
||||
Αξιςπžιμοι πελάπžεπš,
|
||||
|
||||
Σαπš ενημερϽνουμε ςπžι η ΑΑΔΕ ανακοίνπ°σε αλλαγή σπžην προθεσμία
|
||||
υποβολήπš {tax_description}.
|
||||
|
||||
Νέα προθεσμία: {new_deadline}
|
||||
Προηγούμενη προθεσμία: {old_deadline}
|
||||
|
||||
Παρακαλούμε επικοινπ°νήσπžε μαζί μαπš για οποιαδήποπžε διευκρίνιση.
|
||||
|
||||
Με εκπžίμηση,
|
||||
{accounting_firm_name}
|
||||
|
||||
rate_change_notification:
|
||||
subject: "Ενημέρπ°ση: Αλλαγή π ορολογικού συνπžελεσπžή"
|
||||
body: |
|
||||
Αγαπηπžοί συνεργάπžεπš,
|
||||
|
||||
Απς {effective_date} ισπ¡ύει νέοπš συνπžελεσπžήπš {tax_type}:
|
||||
- Νέοπš συνπžελεσπžήπš: {new_rate}%
|
||||
- Προηγούμενοπš: {old_rate}%
|
||||
|
||||
Η αλλαγή επηρεάζει: {affected_transactions}
|
||||
|
||||
Το λογισπžικς μαπš γραπ είο θα ενημερϽσει ςλουπš πžουπš υπολογισμούπš.
|
||||
|
||||
{firm_contact_info}
|
||||
```
|
||||
|
||||
## Integration Workflows
|
||||
|
||||
### Meta-Skill Integration
|
||||
```bash
|
||||
# Integration with OpenClaw Greek Accounting Meta-Skill
|
||||
openclaw aade register-with-meta --enable-orchestration
|
||||
openclaw aade meta-commands --list-available --business-focused
|
||||
|
||||
# Meta-skill can now call:
|
||||
# openclaw greek government-check (calls aade-api-monitor internally)
|
||||
# openclaw greek emergency-compliance (uses aade alerts)
|
||||
# openclaw greek status-dashboard (includes aade system status)
|
||||
```
|
||||
|
||||
### Other Skill Integration
|
||||
```yaml
|
||||
Skill_Integration_Points:
|
||||
cli_deadline_monitor:
|
||||
data_exchange: "Share deadline change data"
|
||||
coordination: "Avoid duplicate monitoring"
|
||||
backup_relationship: "CLI monitor provides fallback data"
|
||||
|
||||
greek_email_processor:
|
||||
alert_delivery: "Use email processor for client notifications"
|
||||
template_sharing: "Share Greek language templates"
|
||||
document_processing: "Process AADE emails received by clients"
|
||||
|
||||
greek_compliance_aade:
|
||||
rate_updates: "Notify compliance skill of rate changes"
|
||||
calculation_updates: "Trigger recalculation when rates change"
|
||||
submission_timing: "Coordinate deadline changes with submissions"
|
||||
```
|
||||
|
||||
## Production Monitoring & Maintenance
|
||||
|
||||
### Automated Health Monitoring
|
||||
```bash
|
||||
# Health check commands for production deployment
|
||||
openclaw aade health-check --comprehensive --test-all-endpoints
|
||||
openclaw aade performance-monitor --response-times --error-rates --uptime
|
||||
openclaw aade data-validation --accuracy-check --cross-reference --anomaly-detection
|
||||
|
||||
# Maintenance and optimization
|
||||
openclaw aade cache-optimize --cleanup-old --defragment --performance-tune
|
||||
openclaw aade update-patterns --learn-new-formats --improve-accuracy
|
||||
openclaw aade backup-data --critical-cache --configuration --logs
|
||||
```
|
||||
|
||||
### Logging & Audit Trail
|
||||
```yaml
|
||||
Production_Logging:
|
||||
access_logs:
|
||||
file: "/logs/aade-monitor/access.log"
|
||||
retention: "6 months"
|
||||
includes: ["URLs accessed", "Response codes", "Response times"]
|
||||
|
||||
change_detection_logs:
|
||||
file: "/logs/aade-monitor/changes.log"
|
||||
retention: "2 years"
|
||||
includes: ["Detected changes", "Confidence scores", "Validation results"]
|
||||
|
||||
alert_logs:
|
||||
file: "/logs/aade-monitor/alerts.log"
|
||||
retention: "1 year"
|
||||
includes: ["Alert generation", "Delivery methods", "User responses"]
|
||||
|
||||
error_logs:
|
||||
file: "/logs/aade-monitor/errors.log"
|
||||
retention: "1 year"
|
||||
includes: ["Processing errors", "Network failures", "Recovery actions"]
|
||||
```
|
||||
|
||||
## Advanced Features
|
||||
|
||||
### Machine Learning Enhancement
|
||||
```yaml
|
||||
ML_Capabilities:
|
||||
document_classification:
|
||||
training_data: "Historical AADE announcements with manual classifications"
|
||||
accuracy_target: ">95% for critical document identification"
|
||||
continuous_learning: "Update model based on manual corrections"
|
||||
|
||||
change_impact_prediction:
|
||||
analysis: "Predict client impact based on historical patterns"
|
||||
risk_assessment: "Identify high-risk clients for proactive communication"
|
||||
resource_planning: "Estimate workload from detected changes"
|
||||
|
||||
anomaly_detection:
|
||||
baseline_patterns: "Learn normal AADE announcement patterns"
|
||||
unusual_activity: "Flag potential system issues or major changes"
|
||||
false_positive_reduction: "Reduce unnecessary alerts through pattern learning"
|
||||
```
|
||||
|
||||
### Compliance Dashboard Integration
|
||||
```yaml
|
||||
Dashboard_Features:
|
||||
real_time_status:
|
||||
aade_systems: "Live status of TAXIS, myDATA, EFKA systems"
|
||||
recent_changes: "Timeline of recent deadline and rate changes"
|
||||
alert_summary: "Critical, important, and routine alerts overview"
|
||||
|
||||
client_impact_view:
|
||||
affected_clients: "Which clients affected by recent changes"
|
||||
action_required: "Immediate actions needed per client"
|
||||
communication_status: "Which clients have been notified"
|
||||
|
||||
performance_metrics:
|
||||
monitoring_uptime: "AADE monitor system availability"
|
||||
detection_accuracy: "Change detection success rate"
|
||||
alert_effectiveness: "User response to generated alerts"
|
||||
```
|
||||
|
||||
## Usage Examples
|
||||
|
||||
### Daily Operations
|
||||
```bash
|
||||
# Morning AADE check (part of daily routine)
|
||||
$ openclaw aade morning-check --since yesterday
|
||||
|
||||
📊 AADE Morning Summary - February 18, 2026:
|
||||
|
||||
ðŸÂ€ºï¸ System Status:
|
||||
✅ TAXIS Online (98.2% uptime last 24h)
|
||||
✅ myDATA Online (99.1% uptime last 24h)
|
||||
✅ EFKA Portal Online (97.5% uptime last 24h)
|
||||
|
||||
📢 New Announcements (2):
|
||||
📀¹ Circular POL.1157/2026 - VAT exemption clarification
|
||||
⚠ï¸ System maintenance scheduled: February 20, 02:00-06:00 EET
|
||||
|
||||
🔀ž Changes Detected: None
|
||||
📅 Upcoming Deadlines: 3 VAT returns due in 7 days
|
||||
|
||||
Next check in 2 hours. Manual refresh: openclaw aade check-updates
|
||||
```
|
||||
|
||||
### Change Detection Example
|
||||
```bash
|
||||
$ openclaw aade detect-changes --urgent --notify-immediately
|
||||
|
||||
🚨 CRITICAL CHANGE DETECTED:
|
||||
|
||||
📅 Deadline Change Alert:
|
||||
Tax Type: Monthly VAT Return (March 2026)
|
||||
Old Deadline: April 25, 2026
|
||||
New Deadline: April 20, 2026
|
||||
Change: 5 days earlier
|
||||
Impact: 47 clients affected
|
||||
|
||||
📀¹ Source Document:
|
||||
AADE Announcement: Πθº.1158/2026
|
||||
Published: 2026-02-18 14:30 EET
|
||||
Confidence: 98.5%
|
||||
|
||||
✅ Actions Taken:
|
||||
- Updated compliance deadline tracker
|
||||
- Generated client notifications (47 emails prepared)
|
||||
- Integrated with meta-skill workflow
|
||||
- Logged change in audit trail
|
||||
|
||||
📧 Client notifications ready for review:
|
||||
openclaw aade review-notifications --batch-id 2026021801
|
||||
```
|
||||
|
||||
### Professional Client Communication
|
||||
```bash
|
||||
$ openclaw aade generate-client-alert --deadline-change --professional-tone
|
||||
|
||||
📧 Generated Greek Client Communication:
|
||||
|
||||
Subject: ΕΠΕΙΓθΝ: Αλλαγή προθεσμίαπš δήλπ°σηπš ΦΠΑ Μαρπžίου 2026
|
||||
|
||||
Αξιςπžιμοι πελάπžεπš,
|
||||
|
||||
Σαπš ενημερϽνουμε με απ ορμή πžην ανακοίνπ°ση πžηπš ΑΑΔΕ (Πθº.1158/2026)
|
||||
ςπžι η προθεσμία υποβολήπš πžηπš μηνιαίαπš δήλπ°σηπš ΦΠΑ για πžον Μάρπžιο 2026
|
||||
μεπžακινείπžαι απς πžιπš 25 Απριλίου σπžιπš 20 Απριλίου 2026.
|
||||
|
||||
Η αλλαγή επηρεάζει ςλεπš πžιπš επιπ¡ειρήσειπš με υποπ¡ρέπ°ση υποβολήπš
|
||||
μηνιαίαπš δήλπ°σηπš ΦΠΑ.
|
||||
|
||||
Το λογισπžικς μαπš γραπ είο έπ¡ει ήδη ενημερϽσει πžο σύσπžημα παρακολούθησηπš
|
||||
προθεσμιϽν και θα π ρονπžίσουμε για πžην έγκαιρη προεπžοιμασία και υποβολή.
|
||||
|
||||
Για οποιαδήποπžε διευκρίνιση, παρακαλούμε επικοινπ°νήσπžε μαζί μαπš.
|
||||
|
||||
Με εκπžίμηση,
|
||||
[Accounting Firm Name]
|
||||
📧 Ready for sending to 47 affected clients
|
||||
```
|
||||
|
||||
## Success Metrics
|
||||
|
||||
A successful AADE API Monitor should achieve:
|
||||
- ✅ 99%+ uptime monitoring of critical AADE systems
|
||||
- ✅ <5 minute detection time for critical deadline changes
|
||||
- ✅ 95%+ accuracy in document classification and change detection
|
||||
- ✅ Zero false positives for critical alerts
|
||||
- ✅ Complete integration with meta-skill orchestration
|
||||
- ✅ Professional Greek communication standards
|
||||
- ✅ Comprehensive audit trail for compliance purposes
|
||||
- ✅ Robust offline operation with cached data fallback
|
||||
|
||||
Remember: This skill is built OpenClaw-first, using file processing and practical automation rather than complex API integrations, making it reliable and maintainable for production Greek accounting environments.
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"owner": "satoshistackalotto",
|
||||
"slug": "aade-api-monitor",
|
||||
"displayName": "Aade Api Monitor",
|
||||
"latest": {
|
||||
"version": "0.1.0",
|
||||
"publishedAt": 1771661208973,
|
||||
"commit": "https://github.com/openclaw/skills/commit/32b6456777ce8e240787b61c878ab64904b7a2ea"
|
||||
},
|
||||
"history": []
|
||||
}
|
||||
@@ -0,0 +1,339 @@
|
||||
---
|
||||
name: product-marketing-context
|
||||
description: "When the user wants to create or update their product marketing context document. Also use when the user mentions 'product context,' 'service context,' 'marketing context,' 'set up context,' 'positioning,' 'who is my target audience,' 'describe my product,' 'describe my service,' 'ICP,' 'ideal customer profile,' or wants to avoid repeating foundational information across marketing tasks. Works for products, services, or hybrid offerings — B2B and B2C. Use this at the start of any new project before using other marketing skills — it creates `.agents/product-marketing-context.md` that all other skills reference for offering, audience, and positioning context."
|
||||
metadata:
|
||||
version: 2.0.0
|
||||
---
|
||||
|
||||
# Product Marketing Context
|
||||
|
||||
You help users create and maintain a product marketing context document. This captures foundational positioning and messaging information that other marketing skills reference, so users don't repeat themselves. Works for products, services, or hybrid offerings — B2B and B2C alike.
|
||||
|
||||
The document is stored at `.agents/product-marketing-context.md`.
|
||||
|
||||
## Workflow
|
||||
|
||||
### Step 1: Check for Existing Context
|
||||
|
||||
First, check if `.agents/product-marketing-context.md` already exists. Also check `.claude/product-marketing-context.md` for older setups — if found there but not in `.agents/`, offer to move it.
|
||||
|
||||
**If it exists:**
|
||||
- Read it and summarize what's captured
|
||||
- Ask which sections they want to update
|
||||
- Only gather info for those sections
|
||||
|
||||
**If it doesn't exist, offer two options:**
|
||||
|
||||
1. **Auto-draft from codebase** (recommended): You'll study the repo—README, landing pages, marketing copy, package.json, etc.—and draft a V1 of the context document. The user then reviews, corrects, and fills gaps. This is faster than starting from scratch.
|
||||
|
||||
2. **Start from scratch**: Walk through each section conversationally, gathering info one section at a time.
|
||||
|
||||
Most users prefer option 1. After presenting the draft, ask: "What needs correcting? What's missing?"
|
||||
|
||||
### Step 2: Gather Information
|
||||
|
||||
**If auto-drafting:**
|
||||
1. Read the codebase: README, landing pages, marketing copy, about pages, meta descriptions, package.json, any existing docs
|
||||
2. Draft all sections based on what you find
|
||||
3. Present the draft and ask what needs correcting or is missing
|
||||
4. Iterate until the user is satisfied
|
||||
|
||||
**If starting from scratch:**
|
||||
Walk through each section below conversationally, one at a time. Don't dump all questions at once.
|
||||
|
||||
For each section:
|
||||
1. Briefly explain what you're capturing
|
||||
2. Ask relevant questions using the right question format (see below)
|
||||
3. Confirm accuracy
|
||||
4. Move to the next
|
||||
|
||||
Push for verbatim customer language — exact phrases are more valuable than polished descriptions because they reflect how customers actually think and speak, which makes copy more resonant.
|
||||
|
||||
**Question design — reduce friction, get better answers:**
|
||||
- **Select one**: When a field has known options (stage, offering type, business model), present them as a lettered list: "(a) ... (b) ... (c) ...". Faster than open-ended, and the user can still say something different.
|
||||
- **Select all that apply**: When multiple values are valid (discovery channels, pain cost types), present common options as a numbered or bulleted list and ask the user to pick all that apply, plus "other." In the sections below, ☐ marks indicate the options to present — format them as a clean list for the user, not inline.
|
||||
- **Finish this sentence**: When users freeze on open-ended questions, offer a fill-in-the-blank: "We help ___ do ___ so they can ___." This scaffolds without constraining.
|
||||
- **Constraining prompts**: When answers tend to sprawl, add a length constraint: "In one sentence..." or "Pick your top 3."
|
||||
- **Spectrum selection**: When capturing degree/preference, offer a scale: "Where do you fall? More formal ← → more casual."
|
||||
- **Examples as anchors**: Show one concrete example of a good answer before asking, especially for open-ended fields. This sets the bar and unblocks the user.
|
||||
- **Confirm by summarizing**: After each section, summarize what you captured in 2-3 sentences and ask: "Does this capture it? Anything to adjust?" Don't just say "confirm."
|
||||
- **Stay conversational**: These patterns are tools to reach for, not a rigid form. If the user gives a rich, detailed answer unprompted, don't force them through a select-all list — capture what they said and move on. Use structured prompts when the user seems stuck, gives a vague answer, or needs help articulating what they mean.
|
||||
- Don't use all patterns in every section — match the pattern to the question type. Sections below use `→ *pattern*:` annotations to indicate which pattern to use — these are instructions for you, not text to show the user.
|
||||
|
||||
**Important: Adapt to offering type.** Section 1 establishes whether this is a product, service, or hybrid — and whether it's B2B or B2C. Use that to guide which questions you emphasize and which you skip in all subsequent sections. Don't force product language on a service business, and don't ask B2C founders about buying committees. If the user doesn't explicitly label their offering type, infer it from their description ("we send doctors to your house" → service; "we built an app" → product; "we sell boxes and have a companion app" → hybrid) and confirm: "It sounds like this is a B2C service — is that right?"
|
||||
|
||||
**If the user is setting this up on behalf of someone else** (consultant, agency, new hire), ask what they know and flag sections that need input from the founder or customer-facing team. Mark those sections as "[needs founder input]" in the output.
|
||||
|
||||
---
|
||||
|
||||
## Sections to Capture
|
||||
|
||||
**Priority guide:** Sections 1-6 are essential — they form the core that downstream skills depend on. Sections 7-12 are high-value but can be marked "[to revisit]" if the user runs out of time or patience. Always capture 1-6 before moving to 7-12.
|
||||
|
||||
### 1. Offering Overview
|
||||
- Company or brand name
|
||||
- One-line description → *finish this sentence*: "We help ___ do ___ so they can ___."
|
||||
- What it does (2-3 sentences) → *constraining prompt*: "Explain what you do as if you had 30 seconds with a stranger."
|
||||
- Why it exists — the founding insight or personal experience that sparked this, and what makes the team uniquely qualified (this often becomes your most powerful marketing story)
|
||||
- Category → *finish this sentence*: "When someone searches for what we do, they'd type ___." (This is the "shelf" you sit on.)
|
||||
- Offering type → *select one*: (a) Product (b) Service (c) Hybrid — then give an example: "e.g., SaaS, home tutoring service, subscription box + companion app"
|
||||
- Business model → *select one + details*: (a) Subscription/SaaS (b) One-time purchase (c) Freemium (d) Marketplace/commission (e) Retainer/hourly (f) Pay-per-use (g) Other — then ask for price points or tiers
|
||||
- Stage → *select one*: (a) Pre-launch (b) Early traction (c) Growth (d) Established — this shapes what proof points and strategies are credible
|
||||
- For services: delivery model → *select one*: (a) On-demand (b) Scheduled (c) Subscription (d) Retainer — and coverage area if relevant
|
||||
|
||||
### 2. Target Audience
|
||||
|
||||
Adapt these fields based on offering type:
|
||||
|
||||
**For B2B:**
|
||||
- Target company type (industry, size, stage)
|
||||
- Target decision-makers (roles, departments)
|
||||
|
||||
**For B2C:**
|
||||
- Target customer segments (demographics, life stage, situation)
|
||||
- Who makes the decision — often the user themselves, but not always (e.g., a family member choosing home care for a parent, a parent choosing a tutor for a child)
|
||||
|
||||
**For all:**
|
||||
- Primary use case → *finish this sentence*: "Most customers come to us because they need to ___."
|
||||
- Jobs to be done → *constraining prompt*: "Name 2-3 things customers 'hire' you to do for them."
|
||||
- Specific use cases or scenarios
|
||||
- How they find you → *select all that apply*:
|
||||
☐ Google search ☐ Word-of-mouth ☐ Professional referral
|
||||
☐ Social media ☐ Communities/forums ☐ Content/blog
|
||||
☐ Paid ads ☐ Events/trade shows ☐ App store ☐ Other: ___
|
||||
- Where they spend time → *select all + add your own* (online and offline):
|
||||
☐ LinkedIn ☐ Facebook groups ☐ Reddit ☐ Twitter/X
|
||||
☐ YouTube ☐ TikTok ☐ Industry forums
|
||||
☐ Conferences/trade shows ☐ Professional associations
|
||||
☐ Specific communities: ___ ☐ Offline locations: ___
|
||||
- How they buy → *ask for a step-by-step journey*: "Walk me through how a customer goes from 'I have this problem' to choosing you. What are the steps?" Show an example: "e.g., Google search → read reviews → book a demo → free trial → purchase." Then ask: Is this typically a quick decision (minutes/hours) or a long consideration (days/weeks/months)?
|
||||
|
||||
### 3. Personas
|
||||
Capture 2-4 distinct personas — the people who interact with your offering. Think about who uses it, who pays for it, and who influences the choice — these may be different people.
|
||||
|
||||
**For B2B** — organizational buying roles:
|
||||
- User, Champion, Decision Maker, Financial Buyer, Technical Influencer
|
||||
|
||||
**For B2C** — user segments and decision stakeholders:
|
||||
- e.g., Primary user, Family decision-maker, Referring professional, Gift buyer
|
||||
- For services especially, the person receiving the service and the person choosing/paying may differ
|
||||
|
||||
For each persona, capture: what they care about, their challenge, and the value you promise them.
|
||||
|
||||
*Example*: "The Family Decision-Maker — cares about safety and trust, challenged by navigating confusing care options, we promise peace of mind and vetted professionals."
|
||||
|
||||
### 4. Problems & Pain Points
|
||||
- Core challenge → *finish this sentence*: "Before finding us, customers were stuck because ___."
|
||||
- Why current solutions or alternatives fall short
|
||||
- What it costs them → *select all that apply, then ask "which is the biggest?"*:
|
||||
☐ Time ☐ Money ☐ Health/wellbeing ☐ Peace of mind
|
||||
☐ Missed opportunities ☐ Reputation ☐ Relationships ☐ Other: ___
|
||||
- Emotional tension → *select all that apply*:
|
||||
☐ Frustration ☐ Anxiety/worry ☐ Overwhelm ☐ Distrust
|
||||
☐ Guilt ☐ Embarrassment ☐ Fear ☐ Helplessness ☐ Other: ___
|
||||
- For services: what's broken about the current experience → *select all that apply*:
|
||||
☐ Hard to access ☐ Long wait times ☐ Can't trust quality
|
||||
☐ Inconvenient ☐ Impersonal ☐ Too expensive ☐ Poor communication ☐ Other: ___
|
||||
|
||||
### 5. Competitive Landscape
|
||||
|
||||
Help the user think in three tiers — show examples for each to unblock them:
|
||||
|
||||
- **Direct competitors**: Same solution, same problem (e.g., Calendly vs SavvyCal, or one dog-walking service vs another)
|
||||
- **Secondary competitors**: Different solution, same problem (e.g., dog-walking service vs doggy daycare)
|
||||
- **Indirect competitors**: Conflicting approach or inaction (e.g., dog-walking service vs "just let the dog out in the yard")
|
||||
- For each: "How does this option fall short for your customers?"
|
||||
|
||||
*Prompt*: "Name 1-2 for each tier. If you're not sure, think about what your customers were doing before they found you — that's your indirect competitor."
|
||||
|
||||
### 6. Differentiation
|
||||
- Key differentiators (capabilities or qualities alternatives lack) → *constraining prompt*: "Name your top 3 differentiators — things competitors can't or don't offer."
|
||||
- How you solve it differently
|
||||
- Why that's better (benefits)
|
||||
- Why customers choose you over alternatives → *finish this sentence*: "Customers pick us over alternatives because ___."
|
||||
- For services: what makes the experience different → *select all that apply*:
|
||||
☐ More convenient ☐ More trustworthy ☐ Better credentials
|
||||
☐ Higher quality ☐ Faster ☐ Easier access
|
||||
☐ More personalized ☐ Better communication ☐ Other: ___
|
||||
|
||||
### 7. Objections & Anti-Personas
|
||||
- Top 3 objections → *show common categories to jog memory*: "What pushback do you hear? Common ones include: price ('too expensive'), trust ('how do I know it works?'), switching cost ('too hard to change'), timing ('not now'), complexity ('seems complicated'), risk ('what if it doesn't work?'). What are your top 3?"
|
||||
- For each objection, ask: "How do you respond to that?"
|
||||
- Who is NOT a good fit (anti-persona) → *ask directly*: "Describe a customer you'd turn away. Who wastes your time or churns fast?"
|
||||
|
||||
### 8. Switching Dynamics
|
||||
Compile the JTBD Four Forces from what you've already captured — do NOT re-ask questions the user already answered:
|
||||
- **Push** ← pull from Section 4 (pain points, emotional tension, what it costs them)
|
||||
- **Pull** ← pull from Section 6 (differentiators, why customers choose you)
|
||||
- **Habit** ← what keeps them stuck (often not yet captured — ask if missing)
|
||||
- **Anxiety** ← what worries them about switching (often not yet captured — ask if missing)
|
||||
|
||||
Present your compiled draft of all four forces and ask: "Does this capture the dynamics? What's missing?" Only probe for Habit and Anxiety directly — Push and Pull should already be covered.
|
||||
|
||||
### 9. Customer Language
|
||||
- How customers describe the problem → *finish this sentence*: "A customer would tell a friend: 'I was struggling with ___ and then I found ___.'"
|
||||
- How they describe your solution (verbatim) → ask: "When customers recommend you, what do they actually say? Not your marketing — their words."
|
||||
- Words/phrases to use → ask: "What words does your audience use? What resonates?"
|
||||
- Words/phrases to avoid → ask: "Any words that would make your audience cringe or tune out?"
|
||||
- Glossary of key terms specific to your offering
|
||||
|
||||
For early-stage companies with few customers: "How would your ideal customer describe this problem to a friend? Just make it up — what would they say?"
|
||||
|
||||
### 10. Brand Voice
|
||||
- Brand personality: "If your brand were a person, how would you describe them?" (3-5 adjectives, but push for a one-sentence character sketch too)
|
||||
- Voice attributes (pick 2-3 core attributes — `/brand-voice` expands to 3-5 with full examples): for each, capture what it means and what it does NOT mean. E.g., "Approachable — friendly and jargon-free, but not dumbed-down or overly casual"
|
||||
- Tone direction → *spectrum selection*: "Where do you fall on each? (a) Formal ← → Casual (b) Technical ← → Accessible (c) Bold ← → Measured (d) Warm ← → Direct"
|
||||
- Voice do's and don'ts (1-2 each): e.g., "We explain, we don't lecture" or "We're confident, never arrogant"
|
||||
- Sample sentence: ask for one sentence that sounds like the brand at its best — this is the most useful reference for downstream skills
|
||||
- Tone shifts: does the voice change for different audiences or channels? (e.g., warmer with patients, more clinical with referring doctors; casual on social, professional in email)
|
||||
|
||||
**When is this section enough?** For most teams, these essentials are sufficient — downstream skills can produce consistent content from this. Run `/brand-voice` when you need grammar/style rules, detailed terminology governance, channel-by-channel tone tables, or have multiple writers who need a shared reference document.
|
||||
|
||||
### 11. Proof Points
|
||||
- What proof do you have? → *select all that apply*:
|
||||
☐ Metrics/results (revenue, users, growth) ☐ Customer logos ☐ Case studies
|
||||
☐ Testimonials/quotes ☐ Ratings/reviews ☐ Certifications/credentials
|
||||
☐ Awards ☐ Press/media mentions ☐ Research/data
|
||||
☐ Founder expertise ☐ Pilot/beta results ☐ Waitlist size ☐ Other: ___
|
||||
- For each type selected, ask for specifics
|
||||
- Main value themes and supporting evidence
|
||||
|
||||
For early-stage: "What proof do you have so far, even if small? Anything counts — beta user feedback, waitlist numbers, founder credentials, a pilot result."
|
||||
|
||||
### 12. Goals
|
||||
- Primary business goal → *select one or two*: (a) Grow revenue (b) Acquire customers/users (c) Increase retention (d) Build awareness/brand (e) Enter new market (f) Launch new offering (g) Raise funding (h) Other: ___
|
||||
- Key conversion action → *select one*: What's the #1 thing you want someone to do? (a) Sign up / create account (b) Start free trial (c) Book a demo/call (d) Make a purchase (e) Request a quote (f) Download something (g) Join waitlist (h) Subscribe (i) Other: ___
|
||||
- Current metrics (if known) — ask: "Any numbers you're tracking? Revenue, users, conversion rate, traffic — whatever you have."
|
||||
|
||||
---
|
||||
|
||||
## Step 3: Create the Document
|
||||
|
||||
After gathering information, create `.agents/product-marketing-context.md` with this structure:
|
||||
|
||||
```markdown
|
||||
# Product Marketing Context
|
||||
|
||||
*Last updated: [date]*
|
||||
|
||||
## Offering Overview
|
||||
**Company/brand:**
|
||||
**One-liner:**
|
||||
**What it does:**
|
||||
**Why it exists:**
|
||||
**Category:**
|
||||
**Offering type:**
|
||||
**Stage:**
|
||||
**Business model & pricing:**
|
||||
**Delivery model:** *(if service/hybrid)*
|
||||
**Coverage area:** *(if service/hybrid)*
|
||||
|
||||
## Target Audience
|
||||
**Target customers:**
|
||||
**Who decides:**
|
||||
**How they find us:**
|
||||
**Where they spend time:**
|
||||
**How they buy:**
|
||||
**Primary use case:**
|
||||
**Jobs to be done:**
|
||||
-
|
||||
**Use cases:**
|
||||
-
|
||||
|
||||
## Personas
|
||||
| Persona | Cares about | Challenge | Value we promise |
|
||||
|---------|-------------|-----------|------------------|
|
||||
| | | | |
|
||||
|
||||
## Problems & Pain Points
|
||||
**Core problem:**
|
||||
**Why alternatives fall short:**
|
||||
-
|
||||
**What it costs them:**
|
||||
**Emotional tension:**
|
||||
|
||||
## Competitive Landscape
|
||||
**Direct:** [Competitor] — falls short because...
|
||||
**Secondary:** [Approach] — falls short because...
|
||||
**Indirect:** [Alternative] — falls short because...
|
||||
|
||||
## Differentiation
|
||||
**Key differentiators:**
|
||||
-
|
||||
**How we do it differently:**
|
||||
**Why that's better:**
|
||||
**Why customers choose us:**
|
||||
|
||||
## Objections
|
||||
| Objection | Response |
|
||||
|-----------|----------|
|
||||
| | |
|
||||
|
||||
**Anti-persona:**
|
||||
|
||||
## Switching Dynamics
|
||||
**Push:**
|
||||
**Pull:**
|
||||
**Habit:**
|
||||
**Anxiety:**
|
||||
|
||||
## Customer Language
|
||||
**How they describe the problem:**
|
||||
- "[verbatim]"
|
||||
**How they describe us:**
|
||||
- "[verbatim]"
|
||||
**Words to use:**
|
||||
**Words to avoid:**
|
||||
**Glossary:**
|
||||
| Term | Meaning |
|
||||
|------|---------|
|
||||
| | |
|
||||
|
||||
## Brand Voice
|
||||
**Personality:** [3-5 adjectives + one-sentence character sketch]
|
||||
**Voice attributes:**
|
||||
| Attribute | We are | We are not |
|
||||
|-----------|--------|------------|
|
||||
| | | |
|
||||
**Tone direction:**
|
||||
**Voice do's:**
|
||||
**Voice don'ts:**
|
||||
**Sample sentence:**
|
||||
**Tone shifts:** [how voice adapts by audience or channel]
|
||||
|
||||
## Proof Points
|
||||
**Metrics:**
|
||||
**Customers/Credentials:**
|
||||
**Testimonials:**
|
||||
> "[quote]" — [who]
|
||||
**Value themes:**
|
||||
| Theme | Proof |
|
||||
|-------|-------|
|
||||
| | |
|
||||
|
||||
## Goals
|
||||
**Business goal:**
|
||||
**Conversion action:**
|
||||
**Current metrics:**
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Step 4: Confirm and Save
|
||||
|
||||
- Show the completed document
|
||||
- Ask if anything needs adjustment
|
||||
- Save to `.agents/product-marketing-context.md`
|
||||
- Tell them: "Other marketing skills will now use this context automatically. Run `/product-marketing-context` anytime to update it."
|
||||
|
||||
---
|
||||
|
||||
## Tips
|
||||
|
||||
- **Be specific**: Ask "What's the #1 frustration that brings them to you?" not "What problem do they solve?"
|
||||
- **Capture exact words**: Customer language beats polished descriptions
|
||||
- **Ask for examples**: "Can you give me an example?" unlocks better answers
|
||||
- **Validate as you go**: Summarize each section and confirm before moving on
|
||||
- **Skip what doesn't apply**: Not every offering needs all sections — adapt to the offering type
|
||||
- **Adapt to the offering**: For services, lean into trust, access, experience, and relationship. For products, lean into features, capabilities, and integrations. Hybrid offerings need both. Let offering type (from Section 1) guide your emphasis throughout.
|
||||
- **Match depth to stage**: Pre-launch companies will have sparse Proof Points and Customer Language — that's fine. Capture what exists and mark gaps to revisit later.
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"owner": "mariokarras",
|
||||
"slug": "abm-product-marketing-context",
|
||||
"displayName": "Product Marketing Context",
|
||||
"latest": {
|
||||
"version": "1.0.0",
|
||||
"publishedAt": 1773903619619,
|
||||
"commit": "https://github.com/openclaw/skills/commit/52e71784e6eecbba8c21b76966470b7c67251b07"
|
||||
},
|
||||
"history": []
|
||||
}
|
||||
@@ -0,0 +1,157 @@
|
||||
{
|
||||
"skill_name": "product-marketing-context",
|
||||
"evals": [
|
||||
{
|
||||
"id": 1,
|
||||
"prompt": "I want to set up my product marketing context. We're a B2B SaaS company that sells a customer feedback platform to product teams.",
|
||||
"expected_output": "Should check if .agents/product-marketing-context.md already exists. If not, should offer two options: (1) Auto-draft from codebase (recommended) or (2) Start from scratch. Should ask for the company/brand name early. If user chooses start from scratch, should walk through sections conversationally one at a time. Should cover all applicable sections: Offering Overview, Target Audience, Personas (B2B buying committee), Problems & Pain Points, Competitive Landscape, Differentiation, Objections, Switching Dynamics (compiled from earlier sections, not re-asked), Customer Language, Brand Voice, Proof Points, and Goals. Should create the file at .agents/product-marketing-context.md when complete.",
|
||||
"assertions": [
|
||||
"Checks for existing product-marketing-context.md",
|
||||
"Offers two options: auto-draft or start from scratch",
|
||||
"Asks for company/brand name",
|
||||
"Covers applicable sections",
|
||||
"Walks through sections conversationally one at a time",
|
||||
"Uses B2B persona roles (User, Champion, Decision Maker, etc.)",
|
||||
"Compiles Switching Dynamics from earlier sections rather than re-asking",
|
||||
"Uses structured prompts where indicated (select-one for stage/offering type/business model, finish-this-sentence for one-liner, select-all-that-apply for discovery channels)",
|
||||
"Creates file at .agents/product-marketing-context.md"
|
||||
],
|
||||
"files": []
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"prompt": "Update our product marketing context. We just added a new enterprise tier and our target audience has expanded to include VP of Engineering, not just Product Managers.",
|
||||
"expected_output": "Should check for existing .agents/product-marketing-context.md and read it. Should identify which sections need updating based on the changes: Target Audience (add VP of Engineering), Personas (add new persona), Offering Overview (new enterprise tier, including pricing updates within that section), Objections (enterprise-specific), and Competitive Landscape (enterprise competitors). Should update only the relevant sections, preserving existing content that hasn't changed.",
|
||||
"assertions": [
|
||||
"Reads existing product-marketing-context.md",
|
||||
"Identifies sections that need updating",
|
||||
"Updates Target Audience with VP of Engineering",
|
||||
"Adds new persona for the expanded audience",
|
||||
"Updates Offering Overview for enterprise tier",
|
||||
"Preserves unchanged sections"
|
||||
],
|
||||
"files": []
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"prompt": "create a product context doc for my app. it's a mobile app that helps people find hiking trails. we're just getting started.",
|
||||
"expected_output": "Should trigger on casual phrasing. Should check for existing context doc. Should offer auto-draft or start-from-scratch options. Should adapt questions for an early-stage B2C mobile app (outdoor/fitness niche). Should note that some sections may be sparse for an early-stage product and that's okay — they can be filled in as the business matures. Should adapt Personas for B2C user segments (e.g., casual hiker, serious hiker) rather than B2B buying committee. Should accept lighter answers for sections like Proof Points or Customer Language, offering the 'how would your ideal customer describe this to a friend?' prompt if verbatim quotes aren't available.",
|
||||
"assertions": [
|
||||
"Triggers on casual phrasing",
|
||||
"Checks for existing context doc",
|
||||
"Offers auto-draft or start-from-scratch options",
|
||||
"Adapts questions for early-stage B2C mobile app",
|
||||
"Notes some sections may be sparse early on",
|
||||
"Adapts Personas for B2C user segments",
|
||||
"Uses early-stage fallback prompts for Customer Language and Proof Points",
|
||||
"Creates file at .agents/product-marketing-context.md"
|
||||
],
|
||||
"files": []
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"prompt": "Can you auto-draft our product marketing context from our existing codebase and marketing materials?",
|
||||
"expected_output": "Should activate the auto-draft workflow mode. Should scan the codebase for existing marketing context: README, landing page copy, pricing page, about page, meta descriptions, any existing documentation. Should draft the product-marketing-context.md from what it finds, filling in sections where information is available and flagging sections that need manual input. Should present the draft for review before saving.",
|
||||
"assertions": [
|
||||
"Activates auto-draft workflow mode",
|
||||
"Scans codebase for existing marketing materials",
|
||||
"Drafts context from found information",
|
||||
"Flags sections needing manual input",
|
||||
"Presents draft for review before saving"
|
||||
],
|
||||
"files": []
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"prompt": "Do we have a product marketing context set up? I want to make sure the other marketing skills have context about our product.",
|
||||
"expected_output": "Should check for .agents/product-marketing-context.md (and the older .claude/product-marketing-context.md location). Should report whether it exists and summarize its contents if found. If it doesn't exist, should offer to create one and explain why it's valuable (other skills like copywriting, page-cro, seo-audit check for it first). Should explain how other skills use this context document.",
|
||||
"assertions": [
|
||||
"Checks both file locations",
|
||||
"Reports whether context doc exists",
|
||||
"Summarizes contents if found",
|
||||
"Offers to create if missing",
|
||||
"Explains how other skills use it"
|
||||
],
|
||||
"files": []
|
||||
},
|
||||
{
|
||||
"id": 6,
|
||||
"prompt": "set up our marketing context. we're launching a home healthcare service — doctors come to your house. it's B2C but families often make the decision for elderly parents. it's a service, not a product.",
|
||||
"expected_output": "Should recognize this as a B2C service offering. Should ask for company/brand name. Should capture offering type as 'service' and ask about delivery model (on-demand, scheduled) and coverage area. Should ask about the founding insight — why does this service exist, what personal or professional experience sparked it, and what makes the team qualified. Should capture stage (launching = early/pre-launch). Should adapt Target Audience for consumer segments (patients, elderly, families) rather than companies/departments. Should ask about the buying journey (how does a family go from 'mom needs help' to booking the first visit). Should capture 2-4 personas even though it's B2C — the patient, the family decision-maker (e.g., adult child arranging care for parent), and possibly referring physicians. Should compile Switching Dynamics from earlier sections (trust/relationship framing from Problems and Objections), only asking follow-up about Habit and Anxiety if not already covered. Should ask about discovery channels relevant to healthcare (doctor referrals, insurance, word-of-mouth). Objections should reflect consumer concerns (trust, insurance coverage, quality, safety) not B2B sales objections. Proof Points should lean toward credentials, certifications, reviews, and patient outcomes rather than logos.",
|
||||
"assertions": [
|
||||
"Recognizes B2C service offering type",
|
||||
"Asks for company/brand name",
|
||||
"Captures delivery model and coverage area for the service",
|
||||
"Asks about founding insight and team qualification",
|
||||
"Captures company stage",
|
||||
"Adapts Target Audience for consumer segments, not companies",
|
||||
"Asks about the customer buying journey",
|
||||
"Captures 2-4 personas (patient, family decision-maker, referring professional)",
|
||||
"Compiles Switching Dynamics from earlier sections rather than re-asking everything",
|
||||
"Asks about service-relevant discovery channels using select-all-that-apply",
|
||||
"Objections reflect consumer concerns not B2B sales objections",
|
||||
"Proof Points emphasize credentials and reviews over logos",
|
||||
"Uses structured prompts (select-one for delivery model, select-all for broken experience, finish-this-sentence for core challenge)",
|
||||
"Does not force product-only language"
|
||||
],
|
||||
"files": []
|
||||
},
|
||||
{
|
||||
"id": 7,
|
||||
"prompt": "help me set up context for our business. we sell curated subscription boxes of artisan coffee plus an app that tracks your taste profile and recommends roasts. it's both a product and a service.",
|
||||
"expected_output": "Should recognize this as a hybrid offering (physical product + digital service). Should capture both the product dimension (subscription box, pricing, what's in it) and the service dimension (app, personalization, taste profiling). Should ask about both product-style differentiation (quality, sourcing, variety) and service-style differentiation (personalization, convenience, discovery experience). Personas might include the coffee enthusiast, the gift buyer, and the casual explorer. Should handle this as a unified context document, not force a choice between product or service.",
|
||||
"assertions": [
|
||||
"Recognizes hybrid offering type",
|
||||
"Captures both product and service dimensions",
|
||||
"Asks about product-style and service-style differentiation",
|
||||
"Does not force a binary product-or-service choice",
|
||||
"Creates unified context document",
|
||||
"Creates file at .agents/product-marketing-context.md"
|
||||
],
|
||||
"files": []
|
||||
},
|
||||
{
|
||||
"id": 8,
|
||||
"prompt": "Write homepage copy for our SaaS product.",
|
||||
"expected_output": "Should recognize this is a copywriting task, not a product marketing context task. Should check for product-marketing-context.md (as other skills do), and if it doesn't exist, may suggest creating one first. But should defer to the copywriting skill for actually writing the homepage copy.",
|
||||
"assertions": [
|
||||
"Recognizes this as a copywriting task",
|
||||
"May check for or suggest creating product-marketing-context.md",
|
||||
"References or defers to copywriting skill for the actual copy",
|
||||
"Does not attempt to write homepage copy using context creation patterns"
|
||||
],
|
||||
"files": []
|
||||
},
|
||||
{
|
||||
"id": 9,
|
||||
"prompt": "I'm a marketing consultant. My client runs a fitness coaching business but I don't know all the details about their customers. Can you help me set up the context doc?",
|
||||
"expected_output": "Should recognize the user is a proxy, not the founder. Should capture what the consultant knows and flag sections that need founder or customer-facing team input. Should mark incomplete sections as '[needs founder input]' in the output rather than forcing the consultant to guess. Should still walk through all sections but accept 'I'd need to ask them' as a valid answer.",
|
||||
"assertions": [
|
||||
"Recognizes proxy scenario (consultant setting up for client)",
|
||||
"Captures what the proxy knows",
|
||||
"Flags sections needing founder input rather than forcing guesses",
|
||||
"Marks gaps as '[needs founder input]' in output",
|
||||
"Completes the document with available information"
|
||||
],
|
||||
"files": []
|
||||
},
|
||||
{
|
||||
"id": 10,
|
||||
"prompt": "set up our marketing context. we're a B2B consulting firm that helps mid-market companies with digital transformation. we sell strategy engagements and implementation services.",
|
||||
"expected_output": "Should recognize this as a B2B service offering (not product). Should ask for company/brand name. Should capture offering type as 'service' and ask about delivery model (retainer, project-based) and any geographic or industry focus. Should use B2B persona roles (Champion, Decision Maker, etc.) but adapt questions for a service business — e.g., 'what does the engagement look like?' rather than 'what features do you have?'. Should ask about the B2B buying journey for services (RFP, referral, thought leadership → consultation → proposal → engagement). Discovery channels should reflect B2B services (referrals, thought leadership, conferences, LinkedIn, industry events). Differentiation should focus on expertise, methodology, team credentials, and client outcomes rather than product features. Proof Points should emphasize case studies, client logos, and measurable business outcomes.",
|
||||
"assertions": [
|
||||
"Recognizes B2B service offering type",
|
||||
"Asks for company/brand name",
|
||||
"Captures delivery model for services (retainer, project-based)",
|
||||
"Uses B2B persona roles but adapts for service context",
|
||||
"Asks about B2B service buying journey",
|
||||
"Discovery channels reflect B2B services (referrals, thought leadership, conferences)",
|
||||
"Differentiation focuses on expertise and methodology, not product features",
|
||||
"Proof Points emphasize case studies and business outcomes",
|
||||
"Does not force product-only language on a service business",
|
||||
"Creates file at .agents/product-marketing-context.md"
|
||||
],
|
||||
"files": []
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
# Errors Log
|
||||
|
||||
Command failures, exceptions, and unexpected behaviors.
|
||||
|
||||
---
|
||||
@@ -0,0 +1,5 @@
|
||||
# Feature Requests
|
||||
|
||||
Capabilities requested by user that don't currently exist.
|
||||
|
||||
---
|
||||
@@ -0,0 +1,5 @@
|
||||
# Learnings Log
|
||||
|
||||
Captured learnings, corrections, and discoveries. Review before major tasks.
|
||||
|
||||
---
|
||||
@@ -0,0 +1,647 @@
|
||||
---
|
||||
name: self-improvement
|
||||
description: "Captures learnings, errors, and corrections to enable continuous improvement. Use when: (1) A command or operation fails unexpectedly, (2) User corrects Claude ('No, that's wrong...', 'Actually...'), (3) User requests a capability that doesn't exist, (4) An external API or tool fails, (5) Claude realizes its knowledge is outdated or incorrect, (6) A better approach is discovered for a recurring task. Also review learnings before major tasks."
|
||||
metadata:
|
||||
---
|
||||
|
||||
# Self-Improvement Skill
|
||||
|
||||
Log learnings and errors to markdown files for continuous improvement. Coding agents can later process these into fixes, and important learnings get promoted to project memory.
|
||||
|
||||
## Quick Reference
|
||||
|
||||
| Situation | Action |
|
||||
|-----------|--------|
|
||||
| Command/operation fails | Log to `.learnings/ERRORS.md` |
|
||||
| User corrects you | Log to `.learnings/LEARNINGS.md` with category `correction` |
|
||||
| User wants missing feature | Log to `.learnings/FEATURE_REQUESTS.md` |
|
||||
| API/external tool fails | Log to `.learnings/ERRORS.md` with integration details |
|
||||
| Knowledge was outdated | Log to `.learnings/LEARNINGS.md` with category `knowledge_gap` |
|
||||
| Found better approach | Log to `.learnings/LEARNINGS.md` with category `best_practice` |
|
||||
| Simplify/Harden recurring patterns | Log/update `.learnings/LEARNINGS.md` with `Source: simplify-and-harden` and a stable `Pattern-Key` |
|
||||
| Similar to existing entry | Link with `**See Also**`, consider priority bump |
|
||||
| Broadly applicable learning | Promote to `CLAUDE.md`, `AGENTS.md`, and/or `.github/copilot-instructions.md` |
|
||||
| Workflow improvements | Promote to `AGENTS.md` (OpenClaw workspace) |
|
||||
| Tool gotchas | Promote to `TOOLS.md` (OpenClaw workspace) |
|
||||
| Behavioral patterns | Promote to `SOUL.md` (OpenClaw workspace) |
|
||||
|
||||
## OpenClaw Setup (Recommended)
|
||||
|
||||
OpenClaw is the primary platform for this skill. It uses workspace-based prompt injection with automatic skill loading.
|
||||
|
||||
### Installation
|
||||
|
||||
**Via ClawdHub (recommended):**
|
||||
```bash
|
||||
clawdhub install self-improving-agent
|
||||
```
|
||||
|
||||
**Manual:**
|
||||
```bash
|
||||
git clone https://github.com/peterskoett/self-improving-agent.git ~/.openclaw/skills/self-improving-agent
|
||||
```
|
||||
|
||||
Remade for openclaw from original repo : https://github.com/pskoett/pskoett-ai-skills - https://github.com/pskoett/pskoett-ai-skills/tree/main/skills/self-improvement
|
||||
|
||||
### Workspace Structure
|
||||
|
||||
OpenClaw injects these files into every session:
|
||||
|
||||
```
|
||||
~/.openclaw/workspace/
|
||||
├── AGENTS.md # Multi-agent workflows, delegation patterns
|
||||
├── SOUL.md # Behavioral guidelines, personality, principles
|
||||
├── TOOLS.md # Tool capabilities, integration gotchas
|
||||
├── MEMORY.md # Long-term memory (main session only)
|
||||
├── memory/ # Daily memory files
|
||||
│ └── YYYY-MM-DD.md
|
||||
└── .learnings/ # This skill's log files
|
||||
├── LEARNINGS.md
|
||||
├── ERRORS.md
|
||||
└── FEATURE_REQUESTS.md
|
||||
```
|
||||
|
||||
### Create Learning Files
|
||||
|
||||
```bash
|
||||
mkdir -p ~/.openclaw/workspace/.learnings
|
||||
```
|
||||
|
||||
Then create the log files (or copy from `assets/`):
|
||||
- `LEARNINGS.md` — corrections, knowledge gaps, best practices
|
||||
- `ERRORS.md` — command failures, exceptions
|
||||
- `FEATURE_REQUESTS.md` — user-requested capabilities
|
||||
|
||||
### Promotion Targets
|
||||
|
||||
When learnings prove broadly applicable, promote them to workspace files:
|
||||
|
||||
| Learning Type | Promote To | Example |
|
||||
|---------------|------------|---------|
|
||||
| Behavioral patterns | `SOUL.md` | "Be concise, avoid disclaimers" |
|
||||
| Workflow improvements | `AGENTS.md` | "Spawn sub-agents for long tasks" |
|
||||
| Tool gotchas | `TOOLS.md` | "Git push needs auth configured first" |
|
||||
|
||||
### Inter-Session Communication
|
||||
|
||||
OpenClaw provides tools to share learnings across sessions:
|
||||
|
||||
- **sessions_list** — View active/recent sessions
|
||||
- **sessions_history** — Read another session's transcript
|
||||
- **sessions_send** — Send a learning to another session
|
||||
- **sessions_spawn** — Spawn a sub-agent for background work
|
||||
|
||||
### Optional: Enable Hook
|
||||
|
||||
For automatic reminders at session start:
|
||||
|
||||
```bash
|
||||
# Copy hook to OpenClaw hooks directory
|
||||
cp -r hooks/openclaw ~/.openclaw/hooks/self-improvement
|
||||
|
||||
# Enable it
|
||||
openclaw hooks enable self-improvement
|
||||
```
|
||||
|
||||
See `references/openclaw-integration.md` for complete details.
|
||||
|
||||
---
|
||||
|
||||
## Generic Setup (Other Agents)
|
||||
|
||||
For Claude Code, Codex, Copilot, or other agents, create `.learnings/` in your project:
|
||||
|
||||
```bash
|
||||
mkdir -p .learnings
|
||||
```
|
||||
|
||||
Copy templates from `assets/` or create files with headers.
|
||||
|
||||
### Add reference to agent files AGENTS.md, CLAUDE.md, or .github/copilot-instructions.md to remind yourself to log learnings. (this is an alternative to hook-based reminders)
|
||||
|
||||
#### Self-Improvement Workflow
|
||||
|
||||
When errors or corrections occur:
|
||||
1. Log to `.learnings/ERRORS.md`, `LEARNINGS.md`, or `FEATURE_REQUESTS.md`
|
||||
2. Review and promote broadly applicable learnings to:
|
||||
- `CLAUDE.md` - project facts and conventions
|
||||
- `AGENTS.md` - workflows and automation
|
||||
- `.github/copilot-instructions.md` - Copilot context
|
||||
|
||||
## Logging Format
|
||||
|
||||
### Learning Entry
|
||||
|
||||
Append to `.learnings/LEARNINGS.md`:
|
||||
|
||||
```markdown
|
||||
## [LRN-YYYYMMDD-XXX] category
|
||||
|
||||
**Logged**: ISO-8601 timestamp
|
||||
**Priority**: low | medium | high | critical
|
||||
**Status**: pending
|
||||
**Area**: frontend | backend | infra | tests | docs | config
|
||||
|
||||
### Summary
|
||||
One-line description of what was learned
|
||||
|
||||
### Details
|
||||
Full context: what happened, what was wrong, what's correct
|
||||
|
||||
### Suggested Action
|
||||
Specific fix or improvement to make
|
||||
|
||||
### Metadata
|
||||
- Source: conversation | error | user_feedback
|
||||
- Related Files: path/to/file.ext
|
||||
- Tags: tag1, tag2
|
||||
- See Also: LRN-20250110-001 (if related to existing entry)
|
||||
- Pattern-Key: simplify.dead_code | harden.input_validation (optional, for recurring-pattern tracking)
|
||||
- Recurrence-Count: 1 (optional)
|
||||
- First-Seen: 2025-01-15 (optional)
|
||||
- Last-Seen: 2025-01-15 (optional)
|
||||
|
||||
---
|
||||
```
|
||||
|
||||
### Error Entry
|
||||
|
||||
Append to `.learnings/ERRORS.md`:
|
||||
|
||||
```markdown
|
||||
## [ERR-YYYYMMDD-XXX] skill_or_command_name
|
||||
|
||||
**Logged**: ISO-8601 timestamp
|
||||
**Priority**: high
|
||||
**Status**: pending
|
||||
**Area**: frontend | backend | infra | tests | docs | config
|
||||
|
||||
### Summary
|
||||
Brief description of what failed
|
||||
|
||||
### Error
|
||||
```
|
||||
Actual error message or output
|
||||
```
|
||||
|
||||
### Context
|
||||
- Command/operation attempted
|
||||
- Input or parameters used
|
||||
- Environment details if relevant
|
||||
|
||||
### Suggested Fix
|
||||
If identifiable, what might resolve this
|
||||
|
||||
### Metadata
|
||||
- Reproducible: yes | no | unknown
|
||||
- Related Files: path/to/file.ext
|
||||
- See Also: ERR-20250110-001 (if recurring)
|
||||
|
||||
---
|
||||
```
|
||||
|
||||
### Feature Request Entry
|
||||
|
||||
Append to `.learnings/FEATURE_REQUESTS.md`:
|
||||
|
||||
```markdown
|
||||
## [FEAT-YYYYMMDD-XXX] capability_name
|
||||
|
||||
**Logged**: ISO-8601 timestamp
|
||||
**Priority**: medium
|
||||
**Status**: pending
|
||||
**Area**: frontend | backend | infra | tests | docs | config
|
||||
|
||||
### Requested Capability
|
||||
What the user wanted to do
|
||||
|
||||
### User Context
|
||||
Why they needed it, what problem they're solving
|
||||
|
||||
### Complexity Estimate
|
||||
simple | medium | complex
|
||||
|
||||
### Suggested Implementation
|
||||
How this could be built, what it might extend
|
||||
|
||||
### Metadata
|
||||
- Frequency: first_time | recurring
|
||||
- Related Features: existing_feature_name
|
||||
|
||||
---
|
||||
```
|
||||
|
||||
## ID Generation
|
||||
|
||||
Format: `TYPE-YYYYMMDD-XXX`
|
||||
- TYPE: `LRN` (learning), `ERR` (error), `FEAT` (feature)
|
||||
- YYYYMMDD: Current date
|
||||
- XXX: Sequential number or random 3 chars (e.g., `001`, `A7B`)
|
||||
|
||||
Examples: `LRN-20250115-001`, `ERR-20250115-A3F`, `FEAT-20250115-002`
|
||||
|
||||
## Resolving Entries
|
||||
|
||||
When an issue is fixed, update the entry:
|
||||
|
||||
1. Change `**Status**: pending` → `**Status**: resolved`
|
||||
2. Add resolution block after Metadata:
|
||||
|
||||
```markdown
|
||||
### Resolution
|
||||
- **Resolved**: 2025-01-16T09:00:00Z
|
||||
- **Commit/PR**: abc123 or #42
|
||||
- **Notes**: Brief description of what was done
|
||||
```
|
||||
|
||||
Other status values:
|
||||
- `in_progress` - Actively being worked on
|
||||
- `wont_fix` - Decided not to address (add reason in Resolution notes)
|
||||
- `promoted` - Elevated to CLAUDE.md, AGENTS.md, or .github/copilot-instructions.md
|
||||
|
||||
## Promoting to Project Memory
|
||||
|
||||
When a learning is broadly applicable (not a one-off fix), promote it to permanent project memory.
|
||||
|
||||
### When to Promote
|
||||
|
||||
- Learning applies across multiple files/features
|
||||
- Knowledge any contributor (human or AI) should know
|
||||
- Prevents recurring mistakes
|
||||
- Documents project-specific conventions
|
||||
|
||||
### Promotion Targets
|
||||
|
||||
| Target | What Belongs There |
|
||||
|--------|-------------------|
|
||||
| `CLAUDE.md` | Project facts, conventions, gotchas for all Claude interactions |
|
||||
| `AGENTS.md` | Agent-specific workflows, tool usage patterns, automation rules |
|
||||
| `.github/copilot-instructions.md` | Project context and conventions for GitHub Copilot |
|
||||
| `SOUL.md` | Behavioral guidelines, communication style, principles (OpenClaw workspace) |
|
||||
| `TOOLS.md` | Tool capabilities, usage patterns, integration gotchas (OpenClaw workspace) |
|
||||
|
||||
### How to Promote
|
||||
|
||||
1. **Distill** the learning into a concise rule or fact
|
||||
2. **Add** to appropriate section in target file (create file if needed)
|
||||
3. **Update** original entry:
|
||||
- Change `**Status**: pending` → `**Status**: promoted`
|
||||
- Add `**Promoted**: CLAUDE.md`, `AGENTS.md`, or `.github/copilot-instructions.md`
|
||||
|
||||
### Promotion Examples
|
||||
|
||||
**Learning** (verbose):
|
||||
> Project uses pnpm workspaces. Attempted `npm install` but failed.
|
||||
> Lock file is `pnpm-lock.yaml`. Must use `pnpm install`.
|
||||
|
||||
**In CLAUDE.md** (concise):
|
||||
```markdown
|
||||
## Build & Dependencies
|
||||
- Package manager: pnpm (not npm) - use `pnpm install`
|
||||
```
|
||||
|
||||
**Learning** (verbose):
|
||||
> When modifying API endpoints, must regenerate TypeScript client.
|
||||
> Forgetting this causes type mismatches at runtime.
|
||||
|
||||
**In AGENTS.md** (actionable):
|
||||
```markdown
|
||||
## After API Changes
|
||||
1. Regenerate client: `pnpm run generate:api`
|
||||
2. Check for type errors: `pnpm tsc --noEmit`
|
||||
```
|
||||
|
||||
## Recurring Pattern Detection
|
||||
|
||||
If logging something similar to an existing entry:
|
||||
|
||||
1. **Search first**: `grep -r "keyword" .learnings/`
|
||||
2. **Link entries**: Add `**See Also**: ERR-20250110-001` in Metadata
|
||||
3. **Bump priority** if issue keeps recurring
|
||||
4. **Consider systemic fix**: Recurring issues often indicate:
|
||||
- Missing documentation (→ promote to CLAUDE.md or .github/copilot-instructions.md)
|
||||
- Missing automation (→ add to AGENTS.md)
|
||||
- Architectural problem (→ create tech debt ticket)
|
||||
|
||||
## Simplify & Harden Feed
|
||||
|
||||
Use this workflow to ingest recurring patterns from the `simplify-and-harden`
|
||||
skill and turn them into durable prompt guidance.
|
||||
|
||||
### Ingestion Workflow
|
||||
|
||||
1. Read `simplify_and_harden.learning_loop.candidates` from the task summary.
|
||||
2. For each candidate, use `pattern_key` as the stable dedupe key.
|
||||
3. Search `.learnings/LEARNINGS.md` for an existing entry with that key:
|
||||
- `grep -n "Pattern-Key: <pattern_key>" .learnings/LEARNINGS.md`
|
||||
4. If found:
|
||||
- Increment `Recurrence-Count`
|
||||
- Update `Last-Seen`
|
||||
- Add `See Also` links to related entries/tasks
|
||||
5. If not found:
|
||||
- Create a new `LRN-...` entry
|
||||
- Set `Source: simplify-and-harden`
|
||||
- Set `Pattern-Key`, `Recurrence-Count: 1`, and `First-Seen`/`Last-Seen`
|
||||
|
||||
### Promotion Rule (System Prompt Feedback)
|
||||
|
||||
Promote recurring patterns into agent context/system prompt files when all are true:
|
||||
|
||||
- `Recurrence-Count >= 3`
|
||||
- Seen across at least 2 distinct tasks
|
||||
- Occurred within a 30-day window
|
||||
|
||||
Promotion targets:
|
||||
- `CLAUDE.md`
|
||||
- `AGENTS.md`
|
||||
- `.github/copilot-instructions.md`
|
||||
- `SOUL.md` / `TOOLS.md` for OpenClaw workspace-level guidance when applicable
|
||||
|
||||
Write promoted rules as short prevention rules (what to do before/while coding),
|
||||
not long incident write-ups.
|
||||
|
||||
## Periodic Review
|
||||
|
||||
Review `.learnings/` at natural breakpoints:
|
||||
|
||||
### When to Review
|
||||
- Before starting a new major task
|
||||
- After completing a feature
|
||||
- When working in an area with past learnings
|
||||
- Weekly during active development
|
||||
|
||||
### Quick Status Check
|
||||
```bash
|
||||
# Count pending items
|
||||
grep -h "Status\*\*: pending" .learnings/*.md | wc -l
|
||||
|
||||
# List pending high-priority items
|
||||
grep -B5 "Priority\*\*: high" .learnings/*.md | grep "^## \["
|
||||
|
||||
# Find learnings for a specific area
|
||||
grep -l "Area\*\*: backend" .learnings/*.md
|
||||
```
|
||||
|
||||
### Review Actions
|
||||
- Resolve fixed items
|
||||
- Promote applicable learnings
|
||||
- Link related entries
|
||||
- Escalate recurring issues
|
||||
|
||||
## Detection Triggers
|
||||
|
||||
Automatically log when you notice:
|
||||
|
||||
**Corrections** (→ learning with `correction` category):
|
||||
- "No, that's not right..."
|
||||
- "Actually, it should be..."
|
||||
- "You're wrong about..."
|
||||
- "That's outdated..."
|
||||
|
||||
**Feature Requests** (→ feature request):
|
||||
- "Can you also..."
|
||||
- "I wish you could..."
|
||||
- "Is there a way to..."
|
||||
- "Why can't you..."
|
||||
|
||||
**Knowledge Gaps** (→ learning with `knowledge_gap` category):
|
||||
- User provides information you didn't know
|
||||
- Documentation you referenced is outdated
|
||||
- API behavior differs from your understanding
|
||||
|
||||
**Errors** (→ error entry):
|
||||
- Command returns non-zero exit code
|
||||
- Exception or stack trace
|
||||
- Unexpected output or behavior
|
||||
- Timeout or connection failure
|
||||
|
||||
## Priority Guidelines
|
||||
|
||||
| Priority | When to Use |
|
||||
|----------|-------------|
|
||||
| `critical` | Blocks core functionality, data loss risk, security issue |
|
||||
| `high` | Significant impact, affects common workflows, recurring issue |
|
||||
| `medium` | Moderate impact, workaround exists |
|
||||
| `low` | Minor inconvenience, edge case, nice-to-have |
|
||||
|
||||
## Area Tags
|
||||
|
||||
Use to filter learnings by codebase region:
|
||||
|
||||
| Area | Scope |
|
||||
|------|-------|
|
||||
| `frontend` | UI, components, client-side code |
|
||||
| `backend` | API, services, server-side code |
|
||||
| `infra` | CI/CD, deployment, Docker, cloud |
|
||||
| `tests` | Test files, testing utilities, coverage |
|
||||
| `docs` | Documentation, comments, READMEs |
|
||||
| `config` | Configuration files, environment, settings |
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Log immediately** - context is freshest right after the issue
|
||||
2. **Be specific** - future agents need to understand quickly
|
||||
3. **Include reproduction steps** - especially for errors
|
||||
4. **Link related files** - makes fixes easier
|
||||
5. **Suggest concrete fixes** - not just "investigate"
|
||||
6. **Use consistent categories** - enables filtering
|
||||
7. **Promote aggressively** - if in doubt, add to CLAUDE.md or .github/copilot-instructions.md
|
||||
8. **Review regularly** - stale learnings lose value
|
||||
|
||||
## Gitignore Options
|
||||
|
||||
**Keep learnings local** (per-developer):
|
||||
```gitignore
|
||||
.learnings/
|
||||
```
|
||||
|
||||
**Track learnings in repo** (team-wide):
|
||||
Don't add to .gitignore - learnings become shared knowledge.
|
||||
|
||||
**Hybrid** (track templates, ignore entries):
|
||||
```gitignore
|
||||
.learnings/*.md
|
||||
!.learnings/.gitkeep
|
||||
```
|
||||
|
||||
## Hook Integration
|
||||
|
||||
Enable automatic reminders through agent hooks. This is **opt-in** - you must explicitly configure hooks.
|
||||
|
||||
### Quick Setup (Claude Code / Codex)
|
||||
|
||||
Create `.claude/settings.json` in your project:
|
||||
|
||||
```json
|
||||
{
|
||||
"hooks": {
|
||||
"UserPromptSubmit": [{
|
||||
"matcher": "",
|
||||
"hooks": [{
|
||||
"type": "command",
|
||||
"command": "./skills/self-improvement/scripts/activator.sh"
|
||||
}]
|
||||
}]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
This injects a learning evaluation reminder after each prompt (~50-100 tokens overhead).
|
||||
|
||||
### Full Setup (With Error Detection)
|
||||
|
||||
```json
|
||||
{
|
||||
"hooks": {
|
||||
"UserPromptSubmit": [{
|
||||
"matcher": "",
|
||||
"hooks": [{
|
||||
"type": "command",
|
||||
"command": "./skills/self-improvement/scripts/activator.sh"
|
||||
}]
|
||||
}],
|
||||
"PostToolUse": [{
|
||||
"matcher": "Bash",
|
||||
"hooks": [{
|
||||
"type": "command",
|
||||
"command": "./skills/self-improvement/scripts/error-detector.sh"
|
||||
}]
|
||||
}]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Available Hook Scripts
|
||||
|
||||
| Script | Hook Type | Purpose |
|
||||
|--------|-----------|---------|
|
||||
| `scripts/activator.sh` | UserPromptSubmit | Reminds to evaluate learnings after tasks |
|
||||
| `scripts/error-detector.sh` | PostToolUse (Bash) | Triggers on command errors |
|
||||
|
||||
See `references/hooks-setup.md` for detailed configuration and troubleshooting.
|
||||
|
||||
## Automatic Skill Extraction
|
||||
|
||||
When a learning is valuable enough to become a reusable skill, extract it using the provided helper.
|
||||
|
||||
### Skill Extraction Criteria
|
||||
|
||||
A learning qualifies for skill extraction when ANY of these apply:
|
||||
|
||||
| Criterion | Description |
|
||||
|-----------|-------------|
|
||||
| **Recurring** | Has `See Also` links to 2+ similar issues |
|
||||
| **Verified** | Status is `resolved` with working fix |
|
||||
| **Non-obvious** | Required actual debugging/investigation to discover |
|
||||
| **Broadly applicable** | Not project-specific; useful across codebases |
|
||||
| **User-flagged** | User says "save this as a skill" or similar |
|
||||
|
||||
### Extraction Workflow
|
||||
|
||||
1. **Identify candidate**: Learning meets extraction criteria
|
||||
2. **Run helper** (or create manually):
|
||||
```bash
|
||||
./skills/self-improvement/scripts/extract-skill.sh skill-name --dry-run
|
||||
./skills/self-improvement/scripts/extract-skill.sh skill-name
|
||||
```
|
||||
3. **Customize SKILL.md**: Fill in template with learning content
|
||||
4. **Update learning**: Set status to `promoted_to_skill`, add `Skill-Path`
|
||||
5. **Verify**: Read skill in fresh session to ensure it's self-contained
|
||||
|
||||
### Manual Extraction
|
||||
|
||||
If you prefer manual creation:
|
||||
|
||||
1. Create `skills/<skill-name>/SKILL.md`
|
||||
2. Use template from `assets/SKILL-TEMPLATE.md`
|
||||
3. Follow [Agent Skills spec](https://agentskills.io/specification):
|
||||
- YAML frontmatter with `name` and `description`
|
||||
- Name must match folder name
|
||||
- No README.md inside skill folder
|
||||
|
||||
### Extraction Detection Triggers
|
||||
|
||||
Watch for these signals that a learning should become a skill:
|
||||
|
||||
**In conversation:**
|
||||
- "Save this as a skill"
|
||||
- "I keep running into this"
|
||||
- "This would be useful for other projects"
|
||||
- "Remember this pattern"
|
||||
|
||||
**In learning entries:**
|
||||
- Multiple `See Also` links (recurring issue)
|
||||
- High priority + resolved status
|
||||
- Category: `best_practice` with broad applicability
|
||||
- User feedback praising the solution
|
||||
|
||||
### Skill Quality Gates
|
||||
|
||||
Before extraction, verify:
|
||||
|
||||
- [ ] Solution is tested and working
|
||||
- [ ] Description is clear without original context
|
||||
- [ ] Code examples are self-contained
|
||||
- [ ] No project-specific hardcoded values
|
||||
- [ ] Follows skill naming conventions (lowercase, hyphens)
|
||||
|
||||
## Multi-Agent Support
|
||||
|
||||
This skill works across different AI coding agents with agent-specific activation.
|
||||
|
||||
### Claude Code
|
||||
|
||||
**Activation**: Hooks (UserPromptSubmit, PostToolUse)
|
||||
**Setup**: `.claude/settings.json` with hook configuration
|
||||
**Detection**: Automatic via hook scripts
|
||||
|
||||
### Codex CLI
|
||||
|
||||
**Activation**: Hooks (same pattern as Claude Code)
|
||||
**Setup**: `.codex/settings.json` with hook configuration
|
||||
**Detection**: Automatic via hook scripts
|
||||
|
||||
### GitHub Copilot
|
||||
|
||||
**Activation**: Manual (no hook support)
|
||||
**Setup**: Add to `.github/copilot-instructions.md`:
|
||||
|
||||
```markdown
|
||||
## Self-Improvement
|
||||
|
||||
After solving non-obvious issues, consider logging to `.learnings/`:
|
||||
1. Use format from self-improvement skill
|
||||
2. Link related entries with See Also
|
||||
3. Promote high-value learnings to skills
|
||||
|
||||
Ask in chat: "Should I log this as a learning?"
|
||||
```
|
||||
|
||||
**Detection**: Manual review at session end
|
||||
|
||||
### OpenClaw
|
||||
|
||||
**Activation**: Workspace injection + inter-agent messaging
|
||||
**Setup**: See "OpenClaw Setup" section above
|
||||
**Detection**: Via session tools and workspace files
|
||||
|
||||
### Agent-Agnostic Guidance
|
||||
|
||||
Regardless of agent, apply self-improvement when you:
|
||||
|
||||
1. **Discover something non-obvious** - solution wasn't immediate
|
||||
2. **Correct yourself** - initial approach was wrong
|
||||
3. **Learn project conventions** - discovered undocumented patterns
|
||||
4. **Hit unexpected errors** - especially if diagnosis was difficult
|
||||
5. **Find better approaches** - improved on your original solution
|
||||
|
||||
### Copilot Chat Integration
|
||||
|
||||
For Copilot users, add this to your prompts when relevant:
|
||||
|
||||
> After completing this task, evaluate if any learnings should be logged to `.learnings/` using the self-improvement skill format.
|
||||
|
||||
Or use quick prompts:
|
||||
- "Log this to learnings"
|
||||
- "Create a skill from this solution"
|
||||
- "Check .learnings/ for related issues"
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"owner": "adityasagar2",
|
||||
"slug": "aditya",
|
||||
"displayName": "Adityasagar",
|
||||
"latest": {
|
||||
"version": "1.0.0",
|
||||
"publishedAt": 1772589278940,
|
||||
"commit": "https://github.com/openclaw/skills/commit/0e75a81e4d4e53f92ad13ce7ff3566ba45d2ded9"
|
||||
},
|
||||
"history": []
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
# Learnings
|
||||
|
||||
Corrections, insights, and knowledge gaps captured during development.
|
||||
|
||||
**Categories**: correction | insight | knowledge_gap | best_practice
|
||||
**Areas**: frontend | backend | infra | tests | docs | config
|
||||
**Statuses**: pending | in_progress | resolved | wont_fix | promoted | promoted_to_skill
|
||||
|
||||
## Status Definitions
|
||||
|
||||
| Status | Meaning |
|
||||
|--------|---------|
|
||||
| `pending` | Not yet addressed |
|
||||
| `in_progress` | Actively being worked on |
|
||||
| `resolved` | Issue fixed or knowledge integrated |
|
||||
| `wont_fix` | Decided not to address (reason in Resolution) |
|
||||
| `promoted` | Elevated to CLAUDE.md, AGENTS.md, or copilot-instructions.md |
|
||||
| `promoted_to_skill` | Extracted as a reusable skill |
|
||||
|
||||
## Skill Extraction Fields
|
||||
|
||||
When a learning is promoted to a skill, add these fields:
|
||||
|
||||
```markdown
|
||||
**Status**: promoted_to_skill
|
||||
**Skill-Path**: skills/skill-name
|
||||
```
|
||||
|
||||
Example:
|
||||
```markdown
|
||||
## [LRN-20250115-001] best_practice
|
||||
|
||||
**Logged**: 2025-01-15T10:00:00Z
|
||||
**Priority**: high
|
||||
**Status**: promoted_to_skill
|
||||
**Skill-Path**: skills/docker-m1-fixes
|
||||
**Area**: infra
|
||||
|
||||
### Summary
|
||||
Docker build fails on Apple Silicon due to platform mismatch
|
||||
...
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -0,0 +1,177 @@
|
||||
# Skill Template
|
||||
|
||||
Template for creating skills extracted from learnings. Copy and customize.
|
||||
|
||||
---
|
||||
|
||||
## SKILL.md Template
|
||||
|
||||
```markdown
|
||||
---
|
||||
name: skill-name-here
|
||||
description: "Concise description of when and why to use this skill. Include trigger conditions."
|
||||
---
|
||||
|
||||
# Skill Name
|
||||
|
||||
Brief introduction explaining the problem this skill solves and its origin.
|
||||
|
||||
## Quick Reference
|
||||
|
||||
| Situation | Action |
|
||||
|-----------|--------|
|
||||
| [Trigger 1] | [Action 1] |
|
||||
| [Trigger 2] | [Action 2] |
|
||||
|
||||
## Background
|
||||
|
||||
Why this knowledge matters. What problems it prevents. Context from the original learning.
|
||||
|
||||
## Solution
|
||||
|
||||
### Step-by-Step
|
||||
|
||||
1. First step with code or command
|
||||
2. Second step
|
||||
3. Verification step
|
||||
|
||||
### Code Example
|
||||
|
||||
\`\`\`language
|
||||
// Example code demonstrating the solution
|
||||
\`\`\`
|
||||
|
||||
## Common Variations
|
||||
|
||||
- **Variation A**: Description and how to handle
|
||||
- **Variation B**: Description and how to handle
|
||||
|
||||
## Gotchas
|
||||
|
||||
- Warning or common mistake #1
|
||||
- Warning or common mistake #2
|
||||
|
||||
## Related
|
||||
|
||||
- Link to related documentation
|
||||
- Link to related skill
|
||||
|
||||
## Source
|
||||
|
||||
Extracted from learning entry.
|
||||
- **Learning ID**: LRN-YYYYMMDD-XXX
|
||||
- **Original Category**: correction | insight | knowledge_gap | best_practice
|
||||
- **Extraction Date**: YYYY-MM-DD
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Minimal Template
|
||||
|
||||
For simple skills that don't need all sections:
|
||||
|
||||
```markdown
|
||||
---
|
||||
name: skill-name-here
|
||||
description: "What this skill does and when to use it."
|
||||
---
|
||||
|
||||
# Skill Name
|
||||
|
||||
[Problem statement in one sentence]
|
||||
|
||||
## Solution
|
||||
|
||||
[Direct solution with code/commands]
|
||||
|
||||
## Source
|
||||
|
||||
- Learning ID: LRN-YYYYMMDD-XXX
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Template with Scripts
|
||||
|
||||
For skills that include executable helpers:
|
||||
|
||||
```markdown
|
||||
---
|
||||
name: skill-name-here
|
||||
description: "What this skill does and when to use it."
|
||||
---
|
||||
|
||||
# Skill Name
|
||||
|
||||
[Introduction]
|
||||
|
||||
## Quick Reference
|
||||
|
||||
| Command | Purpose |
|
||||
|---------|---------|
|
||||
| `./scripts/helper.sh` | [What it does] |
|
||||
| `./scripts/validate.sh` | [What it does] |
|
||||
|
||||
## Usage
|
||||
|
||||
### Automated (Recommended)
|
||||
|
||||
\`\`\`bash
|
||||
./skills/skill-name/scripts/helper.sh [args]
|
||||
\`\`\`
|
||||
|
||||
### Manual Steps
|
||||
|
||||
1. Step one
|
||||
2. Step two
|
||||
|
||||
## Scripts
|
||||
|
||||
| Script | Description |
|
||||
|--------|-------------|
|
||||
| `scripts/helper.sh` | Main utility |
|
||||
| `scripts/validate.sh` | Validation checker |
|
||||
|
||||
## Source
|
||||
|
||||
- Learning ID: LRN-YYYYMMDD-XXX
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Naming Conventions
|
||||
|
||||
- **Skill name**: lowercase, hyphens for spaces
|
||||
- Good: `docker-m1-fixes`, `api-timeout-patterns`
|
||||
- Bad: `Docker_M1_Fixes`, `APITimeoutPatterns`
|
||||
|
||||
- **Description**: Start with action verb, mention trigger
|
||||
- Good: "Handles Docker build failures on Apple Silicon. Use when builds fail with platform mismatch."
|
||||
- Bad: "Docker stuff"
|
||||
|
||||
- **Files**:
|
||||
- `SKILL.md` - Required, main documentation
|
||||
- `scripts/` - Optional, executable code
|
||||
- `references/` - Optional, detailed docs
|
||||
- `assets/` - Optional, templates
|
||||
|
||||
---
|
||||
|
||||
## Extraction Checklist
|
||||
|
||||
Before creating a skill from a learning:
|
||||
|
||||
- [ ] Learning is verified (status: resolved)
|
||||
- [ ] Solution is broadly applicable (not one-off)
|
||||
- [ ] Content is complete (has all needed context)
|
||||
- [ ] Name follows conventions
|
||||
- [ ] Description is concise but informative
|
||||
- [ ] Quick Reference table is actionable
|
||||
- [ ] Code examples are tested
|
||||
- [ ] Source learning ID is recorded
|
||||
|
||||
After creating:
|
||||
|
||||
- [ ] Update original learning with `promoted_to_skill` status
|
||||
- [ ] Add `Skill-Path: skills/skill-name` to learning metadata
|
||||
- [ ] Test skill by reading it in a fresh session
|
||||
@@ -0,0 +1,23 @@
|
||||
---
|
||||
name: self-improvement
|
||||
description: "Injects self-improvement reminder during agent bootstrap"
|
||||
metadata: {"openclaw":{"emoji":"🧠","events":["agent:bootstrap"]}}
|
||||
---
|
||||
|
||||
# Self-Improvement Hook
|
||||
|
||||
Injects a reminder to evaluate learnings during agent bootstrap.
|
||||
|
||||
## What It Does
|
||||
|
||||
- Fires on `agent:bootstrap` (before workspace files are injected)
|
||||
- Adds a reminder block to check `.learnings/` for relevant entries
|
||||
- Prompts the agent to log corrections, errors, and discoveries
|
||||
|
||||
## Configuration
|
||||
|
||||
No configuration needed. Enable with:
|
||||
|
||||
```bash
|
||||
openclaw hooks enable self-improvement
|
||||
```
|
||||
@@ -0,0 +1,56 @@
|
||||
/**
|
||||
* Self-Improvement Hook for OpenClaw
|
||||
*
|
||||
* Injects a reminder to evaluate learnings during agent bootstrap.
|
||||
* Fires on agent:bootstrap event before workspace files are injected.
|
||||
*/
|
||||
|
||||
const REMINDER_CONTENT = `
|
||||
## Self-Improvement Reminder
|
||||
|
||||
After completing tasks, evaluate if any learnings should be captured:
|
||||
|
||||
**Log when:**
|
||||
- User corrects you → \`.learnings/LEARNINGS.md\`
|
||||
- Command/operation fails → \`.learnings/ERRORS.md\`
|
||||
- User wants missing capability → \`.learnings/FEATURE_REQUESTS.md\`
|
||||
- You discover your knowledge was wrong → \`.learnings/LEARNINGS.md\`
|
||||
- You find a better approach → \`.learnings/LEARNINGS.md\`
|
||||
|
||||
**Promote when pattern is proven:**
|
||||
- Behavioral patterns → \`SOUL.md\`
|
||||
- Workflow improvements → \`AGENTS.md\`
|
||||
- Tool gotchas → \`TOOLS.md\`
|
||||
|
||||
Keep entries simple: date, title, what happened, what to do differently.
|
||||
`.trim();
|
||||
|
||||
const handler = async (event) => {
|
||||
// Safety checks for event structure
|
||||
if (!event || typeof event !== 'object') {
|
||||
return;
|
||||
}
|
||||
|
||||
// Only handle agent:bootstrap events
|
||||
if (event.type !== 'agent' || event.action !== 'bootstrap') {
|
||||
return;
|
||||
}
|
||||
|
||||
// Safety check for context
|
||||
if (!event.context || typeof event.context !== 'object') {
|
||||
return;
|
||||
}
|
||||
|
||||
// Inject the reminder as a virtual bootstrap file
|
||||
// Check that bootstrapFiles is an array before pushing
|
||||
if (Array.isArray(event.context.bootstrapFiles)) {
|
||||
event.context.bootstrapFiles.push({
|
||||
path: 'SELF_IMPROVEMENT_REMINDER.md',
|
||||
content: REMINDER_CONTENT,
|
||||
virtual: true,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = handler;
|
||||
module.exports.default = handler;
|
||||
@@ -0,0 +1,62 @@
|
||||
/**
|
||||
* Self-Improvement Hook for OpenClaw
|
||||
*
|
||||
* Injects a reminder to evaluate learnings during agent bootstrap.
|
||||
* Fires on agent:bootstrap event before workspace files are injected.
|
||||
*/
|
||||
|
||||
import type { HookHandler } from 'openclaw/hooks';
|
||||
|
||||
const REMINDER_CONTENT = `## Self-Improvement Reminder
|
||||
|
||||
After completing tasks, evaluate if any learnings should be captured:
|
||||
|
||||
**Log when:**
|
||||
- User corrects you → \`.learnings/LEARNINGS.md\`
|
||||
- Command/operation fails → \`.learnings/ERRORS.md\`
|
||||
- User wants missing capability → \`.learnings/FEATURE_REQUESTS.md\`
|
||||
- You discover your knowledge was wrong → \`.learnings/LEARNINGS.md\`
|
||||
- You find a better approach → \`.learnings/LEARNINGS.md\`
|
||||
|
||||
**Promote when pattern is proven:**
|
||||
- Behavioral patterns → \`SOUL.md\`
|
||||
- Workflow improvements → \`AGENTS.md\`
|
||||
- Tool gotchas → \`TOOLS.md\`
|
||||
|
||||
Keep entries simple: date, title, what happened, what to do differently.`;
|
||||
|
||||
const handler: HookHandler = async (event) => {
|
||||
// Safety checks for event structure
|
||||
if (!event || typeof event !== 'object') {
|
||||
return;
|
||||
}
|
||||
|
||||
// Only handle agent:bootstrap events
|
||||
if (event.type !== 'agent' || event.action !== 'bootstrap') {
|
||||
return;
|
||||
}
|
||||
|
||||
// Safety check for context
|
||||
if (!event.context || typeof event.context !== 'object') {
|
||||
return;
|
||||
}
|
||||
|
||||
// Skip sub-agent sessions to avoid bootstrap issues
|
||||
// Sub-agents have sessionKey patterns like "agent:main:subagent:..."
|
||||
const sessionKey = event.sessionKey || '';
|
||||
if (sessionKey.includes(':subagent:')) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Inject the reminder as a virtual bootstrap file
|
||||
// Check that bootstrapFiles is an array before pushing
|
||||
if (Array.isArray(event.context.bootstrapFiles)) {
|
||||
event.context.bootstrapFiles.push({
|
||||
path: 'SELF_IMPROVEMENT_REMINDER.md',
|
||||
content: REMINDER_CONTENT,
|
||||
virtual: true,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export default handler;
|
||||
@@ -0,0 +1,374 @@
|
||||
# Entry Examples
|
||||
|
||||
Concrete examples of well-formatted entries with all fields.
|
||||
|
||||
## Learning: Correction
|
||||
|
||||
```markdown
|
||||
## [LRN-20250115-001] correction
|
||||
|
||||
**Logged**: 2025-01-15T10:30:00Z
|
||||
**Priority**: high
|
||||
**Status**: pending
|
||||
**Area**: tests
|
||||
|
||||
### Summary
|
||||
Incorrectly assumed pytest fixtures are scoped to function by default
|
||||
|
||||
### Details
|
||||
When writing test fixtures, I assumed all fixtures were function-scoped.
|
||||
User corrected that while function scope is the default, the codebase
|
||||
convention uses module-scoped fixtures for database connections to
|
||||
improve test performance.
|
||||
|
||||
### Suggested Action
|
||||
When creating fixtures that involve expensive setup (DB, network),
|
||||
check existing fixtures for scope patterns before defaulting to function scope.
|
||||
|
||||
### Metadata
|
||||
- Source: user_feedback
|
||||
- Related Files: tests/conftest.py
|
||||
- Tags: pytest, testing, fixtures
|
||||
|
||||
---
|
||||
```
|
||||
|
||||
## Learning: Knowledge Gap (Resolved)
|
||||
|
||||
```markdown
|
||||
## [LRN-20250115-002] knowledge_gap
|
||||
|
||||
**Logged**: 2025-01-15T14:22:00Z
|
||||
**Priority**: medium
|
||||
**Status**: resolved
|
||||
**Area**: config
|
||||
|
||||
### Summary
|
||||
Project uses pnpm not npm for package management
|
||||
|
||||
### Details
|
||||
Attempted to run `npm install` but project uses pnpm workspaces.
|
||||
Lock file is `pnpm-lock.yaml`, not `package-lock.json`.
|
||||
|
||||
### Suggested Action
|
||||
Check for `pnpm-lock.yaml` or `pnpm-workspace.yaml` before assuming npm.
|
||||
Use `pnpm install` for this project.
|
||||
|
||||
### Metadata
|
||||
- Source: error
|
||||
- Related Files: pnpm-lock.yaml, pnpm-workspace.yaml
|
||||
- Tags: package-manager, pnpm, setup
|
||||
|
||||
### Resolution
|
||||
- **Resolved**: 2025-01-15T14:30:00Z
|
||||
- **Commit/PR**: N/A - knowledge update
|
||||
- **Notes**: Added to CLAUDE.md for future reference
|
||||
|
||||
---
|
||||
```
|
||||
|
||||
## Learning: Promoted to CLAUDE.md
|
||||
|
||||
```markdown
|
||||
## [LRN-20250115-003] best_practice
|
||||
|
||||
**Logged**: 2025-01-15T16:00:00Z
|
||||
**Priority**: high
|
||||
**Status**: promoted
|
||||
**Promoted**: CLAUDE.md
|
||||
**Area**: backend
|
||||
|
||||
### Summary
|
||||
API responses must include correlation ID from request headers
|
||||
|
||||
### Details
|
||||
All API responses should echo back the X-Correlation-ID header from
|
||||
the request. This is required for distributed tracing. Responses
|
||||
without this header break the observability pipeline.
|
||||
|
||||
### Suggested Action
|
||||
Always include correlation ID passthrough in API handlers.
|
||||
|
||||
### Metadata
|
||||
- Source: user_feedback
|
||||
- Related Files: src/middleware/correlation.ts
|
||||
- Tags: api, observability, tracing
|
||||
|
||||
---
|
||||
```
|
||||
|
||||
## Learning: Promoted to AGENTS.md
|
||||
|
||||
```markdown
|
||||
## [LRN-20250116-001] best_practice
|
||||
|
||||
**Logged**: 2025-01-16T09:00:00Z
|
||||
**Priority**: high
|
||||
**Status**: promoted
|
||||
**Promoted**: AGENTS.md
|
||||
**Area**: backend
|
||||
|
||||
### Summary
|
||||
Must regenerate API client after OpenAPI spec changes
|
||||
|
||||
### Details
|
||||
When modifying API endpoints, the TypeScript client must be regenerated.
|
||||
Forgetting this causes type mismatches that only appear at runtime.
|
||||
The generate script also runs validation.
|
||||
|
||||
### Suggested Action
|
||||
Add to agent workflow: after any API changes, run `pnpm run generate:api`.
|
||||
|
||||
### Metadata
|
||||
- Source: error
|
||||
- Related Files: openapi.yaml, src/client/api.ts
|
||||
- Tags: api, codegen, typescript
|
||||
|
||||
---
|
||||
```
|
||||
|
||||
## Error Entry
|
||||
|
||||
```markdown
|
||||
## [ERR-20250115-A3F] docker_build
|
||||
|
||||
**Logged**: 2025-01-15T09:15:00Z
|
||||
**Priority**: high
|
||||
**Status**: pending
|
||||
**Area**: infra
|
||||
|
||||
### Summary
|
||||
Docker build fails on M1 Mac due to platform mismatch
|
||||
|
||||
### Error
|
||||
```
|
||||
error: failed to solve: python:3.11-slim: no match for platform linux/arm64
|
||||
```
|
||||
|
||||
### Context
|
||||
- Command: `docker build -t myapp .`
|
||||
- Dockerfile uses `FROM python:3.11-slim`
|
||||
- Running on Apple Silicon (M1/M2)
|
||||
|
||||
### Suggested Fix
|
||||
Add platform flag: `docker build --platform linux/amd64 -t myapp .`
|
||||
Or update Dockerfile: `FROM --platform=linux/amd64 python:3.11-slim`
|
||||
|
||||
### Metadata
|
||||
- Reproducible: yes
|
||||
- Related Files: Dockerfile
|
||||
|
||||
---
|
||||
```
|
||||
|
||||
## Error Entry: Recurring Issue
|
||||
|
||||
```markdown
|
||||
## [ERR-20250120-B2C] api_timeout
|
||||
|
||||
**Logged**: 2025-01-20T11:30:00Z
|
||||
**Priority**: critical
|
||||
**Status**: pending
|
||||
**Area**: backend
|
||||
|
||||
### Summary
|
||||
Third-party payment API timeout during checkout
|
||||
|
||||
### Error
|
||||
```
|
||||
TimeoutError: Request to payments.example.com timed out after 30000ms
|
||||
```
|
||||
|
||||
### Context
|
||||
- Command: POST /api/checkout
|
||||
- Timeout set to 30s
|
||||
- Occurs during peak hours (lunch, evening)
|
||||
|
||||
### Suggested Fix
|
||||
Implement retry with exponential backoff. Consider circuit breaker pattern.
|
||||
|
||||
### Metadata
|
||||
- Reproducible: yes (during peak hours)
|
||||
- Related Files: src/services/payment.ts
|
||||
- See Also: ERR-20250115-X1Y, ERR-20250118-Z3W
|
||||
|
||||
---
|
||||
```
|
||||
|
||||
## Feature Request
|
||||
|
||||
```markdown
|
||||
## [FEAT-20250115-001] export_to_csv
|
||||
|
||||
**Logged**: 2025-01-15T16:45:00Z
|
||||
**Priority**: medium
|
||||
**Status**: pending
|
||||
**Area**: backend
|
||||
|
||||
### Requested Capability
|
||||
Export analysis results to CSV format
|
||||
|
||||
### User Context
|
||||
User runs weekly reports and needs to share results with non-technical
|
||||
stakeholders in Excel. Currently copies output manually.
|
||||
|
||||
### Complexity Estimate
|
||||
simple
|
||||
|
||||
### Suggested Implementation
|
||||
Add `--output csv` flag to the analyze command. Use standard csv module.
|
||||
Could extend existing `--output json` pattern.
|
||||
|
||||
### Metadata
|
||||
- Frequency: recurring
|
||||
- Related Features: analyze command, json output
|
||||
|
||||
---
|
||||
```
|
||||
|
||||
## Feature Request: Resolved
|
||||
|
||||
```markdown
|
||||
## [FEAT-20250110-002] dark_mode
|
||||
|
||||
**Logged**: 2025-01-10T14:00:00Z
|
||||
**Priority**: low
|
||||
**Status**: resolved
|
||||
**Area**: frontend
|
||||
|
||||
### Requested Capability
|
||||
Dark mode support for the dashboard
|
||||
|
||||
### User Context
|
||||
User works late hours and finds the bright interface straining.
|
||||
Several other users have mentioned this informally.
|
||||
|
||||
### Complexity Estimate
|
||||
medium
|
||||
|
||||
### Suggested Implementation
|
||||
Use CSS variables for colors. Add toggle in user settings.
|
||||
Consider system preference detection.
|
||||
|
||||
### Metadata
|
||||
- Frequency: recurring
|
||||
- Related Features: user settings, theme system
|
||||
|
||||
### Resolution
|
||||
- **Resolved**: 2025-01-18T16:00:00Z
|
||||
- **Commit/PR**: #142
|
||||
- **Notes**: Implemented with system preference detection and manual toggle
|
||||
|
||||
---
|
||||
```
|
||||
|
||||
## Learning: Promoted to Skill
|
||||
|
||||
```markdown
|
||||
## [LRN-20250118-001] best_practice
|
||||
|
||||
**Logged**: 2025-01-18T11:00:00Z
|
||||
**Priority**: high
|
||||
**Status**: promoted_to_skill
|
||||
**Skill-Path**: skills/docker-m1-fixes
|
||||
**Area**: infra
|
||||
|
||||
### Summary
|
||||
Docker build fails on Apple Silicon due to platform mismatch
|
||||
|
||||
### Details
|
||||
When building Docker images on M1/M2 Macs, the build fails because
|
||||
the base image doesn't have an ARM64 variant. This is a common issue
|
||||
that affects many developers.
|
||||
|
||||
### Suggested Action
|
||||
Add `--platform linux/amd64` to docker build command, or use
|
||||
`FROM --platform=linux/amd64` in Dockerfile.
|
||||
|
||||
### Metadata
|
||||
- Source: error
|
||||
- Related Files: Dockerfile
|
||||
- Tags: docker, arm64, m1, apple-silicon
|
||||
- See Also: ERR-20250115-A3F, ERR-20250117-B2D
|
||||
|
||||
---
|
||||
```
|
||||
|
||||
## Extracted Skill Example
|
||||
|
||||
When the above learning is extracted as a skill, it becomes:
|
||||
|
||||
**File**: `skills/docker-m1-fixes/SKILL.md`
|
||||
|
||||
```markdown
|
||||
---
|
||||
name: docker-m1-fixes
|
||||
description: "Fixes Docker build failures on Apple Silicon (M1/M2). Use when docker build fails with platform mismatch errors."
|
||||
---
|
||||
|
||||
# Docker M1 Fixes
|
||||
|
||||
Solutions for Docker build issues on Apple Silicon Macs.
|
||||
|
||||
## Quick Reference
|
||||
|
||||
| Error | Fix |
|
||||
|-------|-----|
|
||||
| `no match for platform linux/arm64` | Add `--platform linux/amd64` to build |
|
||||
| Image runs but crashes | Use emulation or find ARM-compatible base |
|
||||
|
||||
## The Problem
|
||||
|
||||
Many Docker base images don't have ARM64 variants. When building on
|
||||
Apple Silicon (M1/M2/M3), Docker attempts to pull ARM64 images by
|
||||
default, causing platform mismatch errors.
|
||||
|
||||
## Solutions
|
||||
|
||||
### Option 1: Build Flag (Recommended)
|
||||
|
||||
Add platform flag to your build command:
|
||||
|
||||
\`\`\`bash
|
||||
docker build --platform linux/amd64 -t myapp .
|
||||
\`\`\`
|
||||
|
||||
### Option 2: Dockerfile Modification
|
||||
|
||||
Specify platform in the FROM instruction:
|
||||
|
||||
\`\`\`dockerfile
|
||||
FROM --platform=linux/amd64 python:3.11-slim
|
||||
\`\`\`
|
||||
|
||||
### Option 3: Docker Compose
|
||||
|
||||
Add platform to your service:
|
||||
|
||||
\`\`\`yaml
|
||||
services:
|
||||
app:
|
||||
platform: linux/amd64
|
||||
build: .
|
||||
\`\`\`
|
||||
|
||||
## Trade-offs
|
||||
|
||||
| Approach | Pros | Cons |
|
||||
|----------|------|------|
|
||||
| Build flag | No file changes | Must remember flag |
|
||||
| Dockerfile | Explicit, versioned | Affects all builds |
|
||||
| Compose | Convenient for dev | Requires compose |
|
||||
|
||||
## Performance Note
|
||||
|
||||
Running AMD64 images on ARM64 uses Rosetta 2 emulation. This works
|
||||
for development but may be slower. For production, find ARM-native
|
||||
alternatives when possible.
|
||||
|
||||
## Source
|
||||
|
||||
- Learning ID: LRN-20250118-001
|
||||
- Category: best_practice
|
||||
- Extraction Date: 2025-01-18
|
||||
```
|
||||
@@ -0,0 +1,223 @@
|
||||
# Hook Setup Guide
|
||||
|
||||
Configure automatic self-improvement triggers for AI coding agents.
|
||||
|
||||
## Overview
|
||||
|
||||
Hooks enable proactive learning capture by injecting reminders at key moments:
|
||||
- **UserPromptSubmit**: Reminder after each prompt to evaluate learnings
|
||||
- **PostToolUse (Bash)**: Error detection when commands fail
|
||||
|
||||
## Claude Code Setup
|
||||
|
||||
### Option 1: Project-Level Configuration
|
||||
|
||||
Create `.claude/settings.json` in your project root:
|
||||
|
||||
```json
|
||||
{
|
||||
"hooks": {
|
||||
"UserPromptSubmit": [
|
||||
{
|
||||
"matcher": "",
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "./skills/self-improvement/scripts/activator.sh"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"PostToolUse": [
|
||||
{
|
||||
"matcher": "Bash",
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "./skills/self-improvement/scripts/error-detector.sh"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Option 2: User-Level Configuration
|
||||
|
||||
Add to `~/.claude/settings.json` for global activation:
|
||||
|
||||
```json
|
||||
{
|
||||
"hooks": {
|
||||
"UserPromptSubmit": [
|
||||
{
|
||||
"matcher": "",
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "~/.claude/skills/self-improvement/scripts/activator.sh"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Minimal Setup (Activator Only)
|
||||
|
||||
For lower overhead, use only the UserPromptSubmit hook:
|
||||
|
||||
```json
|
||||
{
|
||||
"hooks": {
|
||||
"UserPromptSubmit": [
|
||||
{
|
||||
"matcher": "",
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "./skills/self-improvement/scripts/activator.sh"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Codex CLI Setup
|
||||
|
||||
Codex uses the same hook system as Claude Code. Create `.codex/settings.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"hooks": {
|
||||
"UserPromptSubmit": [
|
||||
{
|
||||
"matcher": "",
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "./skills/self-improvement/scripts/activator.sh"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## GitHub Copilot Setup
|
||||
|
||||
Copilot doesn't support hooks directly. Instead, add guidance to `.github/copilot-instructions.md`:
|
||||
|
||||
```markdown
|
||||
## Self-Improvement
|
||||
|
||||
After completing tasks that involved:
|
||||
- Debugging non-obvious issues
|
||||
- Discovering workarounds
|
||||
- Learning project-specific patterns
|
||||
- Resolving unexpected errors
|
||||
|
||||
Consider logging the learning to `.learnings/` using the format from the self-improvement skill.
|
||||
|
||||
For high-value learnings that would benefit other sessions, consider skill extraction.
|
||||
```
|
||||
|
||||
## Verification
|
||||
|
||||
### Test Activator Hook
|
||||
|
||||
1. Enable the hook configuration
|
||||
2. Start a new Claude Code session
|
||||
3. Send any prompt
|
||||
4. Verify you see `<self-improvement-reminder>` in the context
|
||||
|
||||
### Test Error Detector Hook
|
||||
|
||||
1. Enable PostToolUse hook for Bash
|
||||
2. Run a command that fails: `ls /nonexistent/path`
|
||||
3. Verify you see `<error-detected>` reminder
|
||||
|
||||
### Dry Run Extract Script
|
||||
|
||||
```bash
|
||||
./skills/self-improvement/scripts/extract-skill.sh test-skill --dry-run
|
||||
```
|
||||
|
||||
Expected output shows the skill scaffold that would be created.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Hook Not Triggering
|
||||
|
||||
1. **Check script permissions**: `chmod +x scripts/*.sh`
|
||||
2. **Verify path**: Use absolute paths or paths relative to project root
|
||||
3. **Check settings location**: Project vs user-level settings
|
||||
4. **Restart session**: Hooks are loaded at session start
|
||||
|
||||
### Permission Denied
|
||||
|
||||
```bash
|
||||
chmod +x ./skills/self-improvement/scripts/activator.sh
|
||||
chmod +x ./skills/self-improvement/scripts/error-detector.sh
|
||||
chmod +x ./skills/self-improvement/scripts/extract-skill.sh
|
||||
```
|
||||
|
||||
### Script Not Found
|
||||
|
||||
If using relative paths, ensure you're in the correct directory or use absolute paths:
|
||||
|
||||
```json
|
||||
{
|
||||
"command": "/absolute/path/to/skills/self-improvement/scripts/activator.sh"
|
||||
}
|
||||
```
|
||||
|
||||
### Too Much Overhead
|
||||
|
||||
If the activator feels intrusive:
|
||||
|
||||
1. **Use minimal setup**: Only UserPromptSubmit, skip PostToolUse
|
||||
2. **Add matcher filter**: Only trigger for certain prompts:
|
||||
|
||||
```json
|
||||
{
|
||||
"matcher": "fix|debug|error|issue",
|
||||
"hooks": [...]
|
||||
}
|
||||
```
|
||||
|
||||
## Hook Output Budget
|
||||
|
||||
The activator is designed to be lightweight:
|
||||
- **Target**: ~50-100 tokens per activation
|
||||
- **Content**: Structured reminder, not verbose instructions
|
||||
- **Format**: XML tags for easy parsing
|
||||
|
||||
If you need to reduce overhead further, you can edit `activator.sh` to output less text.
|
||||
|
||||
## Security Considerations
|
||||
|
||||
- Hook scripts run with the same permissions as Claude Code
|
||||
- Scripts only output text; they don't modify files or run commands
|
||||
- Error detector reads `CLAUDE_TOOL_OUTPUT` environment variable
|
||||
- All scripts are opt-in (you must configure them explicitly)
|
||||
|
||||
## Disabling Hooks
|
||||
|
||||
To temporarily disable without removing configuration:
|
||||
|
||||
1. **Comment out in settings**:
|
||||
```json
|
||||
{
|
||||
"hooks": {
|
||||
// "UserPromptSubmit": [...]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
2. **Or delete the settings file**: Hooks won't run without configuration
|
||||
@@ -0,0 +1,248 @@
|
||||
# OpenClaw Integration
|
||||
|
||||
Complete setup and usage guide for integrating the self-improvement skill with OpenClaw.
|
||||
|
||||
## Overview
|
||||
|
||||
OpenClaw uses workspace-based prompt injection combined with event-driven hooks. Context is injected from workspace files at session start, and hooks can trigger on lifecycle events.
|
||||
|
||||
## Workspace Structure
|
||||
|
||||
```
|
||||
~/.openclaw/
|
||||
├── workspace/ # Working directory
|
||||
│ ├── AGENTS.md # Multi-agent coordination patterns
|
||||
│ ├── SOUL.md # Behavioral guidelines and personality
|
||||
│ ├── TOOLS.md # Tool capabilities and gotchas
|
||||
│ ├── MEMORY.md # Long-term memory (main session only)
|
||||
│ └── memory/ # Daily memory files
|
||||
│ └── YYYY-MM-DD.md
|
||||
├── skills/ # Installed skills
|
||||
│ └── <skill-name>/
|
||||
│ └── SKILL.md
|
||||
└── hooks/ # Custom hooks
|
||||
└── <hook-name>/
|
||||
├── HOOK.md
|
||||
└── handler.ts
|
||||
```
|
||||
|
||||
## Quick Setup
|
||||
|
||||
### 1. Install the Skill
|
||||
|
||||
```bash
|
||||
clawdhub install self-improving-agent
|
||||
```
|
||||
|
||||
Or copy manually:
|
||||
|
||||
```bash
|
||||
cp -r self-improving-agent ~/.openclaw/skills/
|
||||
```
|
||||
|
||||
### 2. Install the Hook (Optional)
|
||||
|
||||
Copy the hook to OpenClaw's hooks directory:
|
||||
|
||||
```bash
|
||||
cp -r hooks/openclaw ~/.openclaw/hooks/self-improvement
|
||||
```
|
||||
|
||||
Enable the hook:
|
||||
|
||||
```bash
|
||||
openclaw hooks enable self-improvement
|
||||
```
|
||||
|
||||
### 3. Create Learning Files
|
||||
|
||||
Create the `.learnings/` directory in your workspace:
|
||||
|
||||
```bash
|
||||
mkdir -p ~/.openclaw/workspace/.learnings
|
||||
```
|
||||
|
||||
Or in the skill directory:
|
||||
|
||||
```bash
|
||||
mkdir -p ~/.openclaw/skills/self-improving-agent/.learnings
|
||||
```
|
||||
|
||||
## Injected Prompt Files
|
||||
|
||||
### AGENTS.md
|
||||
|
||||
Purpose: Multi-agent workflows and delegation patterns.
|
||||
|
||||
```markdown
|
||||
# Agent Coordination
|
||||
|
||||
## Delegation Rules
|
||||
- Use explore agent for open-ended codebase questions
|
||||
- Spawn sub-agents for long-running tasks
|
||||
- Use sessions_send for cross-session communication
|
||||
|
||||
## Session Handoff
|
||||
When delegating to another session:
|
||||
1. Provide full context in the handoff message
|
||||
2. Include relevant file paths
|
||||
3. Specify expected output format
|
||||
```
|
||||
|
||||
### SOUL.md
|
||||
|
||||
Purpose: Behavioral guidelines and communication style.
|
||||
|
||||
```markdown
|
||||
# Behavioral Guidelines
|
||||
|
||||
## Communication Style
|
||||
- Be direct and concise
|
||||
- Avoid unnecessary caveats and disclaimers
|
||||
- Use technical language appropriate to context
|
||||
|
||||
## Error Handling
|
||||
- Admit mistakes promptly
|
||||
- Provide corrected information immediately
|
||||
- Log significant errors to learnings
|
||||
```
|
||||
|
||||
### TOOLS.md
|
||||
|
||||
Purpose: Tool capabilities, integration gotchas, local configuration.
|
||||
|
||||
```markdown
|
||||
# Tool Knowledge
|
||||
|
||||
## Self-Improvement Skill
|
||||
Log learnings to `.learnings/` for continuous improvement.
|
||||
|
||||
## Local Tools
|
||||
- Document tool-specific gotchas here
|
||||
- Note authentication requirements
|
||||
- Track integration quirks
|
||||
```
|
||||
|
||||
## Learning Workflow
|
||||
|
||||
### Capturing Learnings
|
||||
|
||||
1. **In-session**: Log to `.learnings/` as usual
|
||||
2. **Cross-session**: Promote to workspace files
|
||||
|
||||
### Promotion Decision Tree
|
||||
|
||||
```
|
||||
Is the learning project-specific?
|
||||
├── Yes → Keep in .learnings/
|
||||
└── No → Is it behavioral/style-related?
|
||||
├── Yes → Promote to SOUL.md
|
||||
└── No → Is it tool-related?
|
||||
├── Yes → Promote to TOOLS.md
|
||||
└── No → Promote to AGENTS.md (workflow)
|
||||
```
|
||||
|
||||
### Promotion Format Examples
|
||||
|
||||
**From learning:**
|
||||
> Git push to GitHub fails without auth configured - triggers desktop prompt
|
||||
|
||||
**To TOOLS.md:**
|
||||
```markdown
|
||||
## Git
|
||||
- Don't push without confirming auth is configured
|
||||
- Use `gh auth status` to check GitHub CLI auth
|
||||
```
|
||||
|
||||
## Inter-Agent Communication
|
||||
|
||||
OpenClaw provides tools for cross-session communication:
|
||||
|
||||
### sessions_list
|
||||
|
||||
View active and recent sessions:
|
||||
```
|
||||
sessions_list(activeMinutes=30, messageLimit=3)
|
||||
```
|
||||
|
||||
### sessions_history
|
||||
|
||||
Read transcript from another session:
|
||||
```
|
||||
sessions_history(sessionKey="session-id", limit=50)
|
||||
```
|
||||
|
||||
### sessions_send
|
||||
|
||||
Send message to another session:
|
||||
```
|
||||
sessions_send(sessionKey="session-id", message="Learning: API requires X-Custom-Header")
|
||||
```
|
||||
|
||||
### sessions_spawn
|
||||
|
||||
Spawn a background sub-agent:
|
||||
```
|
||||
sessions_spawn(task="Research X and report back", label="research")
|
||||
```
|
||||
|
||||
## Available Hook Events
|
||||
|
||||
| Event | When It Fires |
|
||||
|-------|---------------|
|
||||
| `agent:bootstrap` | Before workspace files inject |
|
||||
| `command:new` | When `/new` command issued |
|
||||
| `command:reset` | When `/reset` command issued |
|
||||
| `command:stop` | When `/stop` command issued |
|
||||
| `gateway:startup` | When gateway starts |
|
||||
|
||||
## Detection Triggers
|
||||
|
||||
### Standard Triggers
|
||||
- User corrections ("No, that's wrong...")
|
||||
- Command failures (non-zero exit codes)
|
||||
- API errors
|
||||
- Knowledge gaps
|
||||
|
||||
### OpenClaw-Specific Triggers
|
||||
|
||||
| Trigger | Action |
|
||||
|---------|--------|
|
||||
| Tool call error | Log to TOOLS.md with tool name |
|
||||
| Session handoff confusion | Log to AGENTS.md with delegation pattern |
|
||||
| Model behavior surprise | Log to SOUL.md with expected vs actual |
|
||||
| Skill issue | Log to .learnings/ or report upstream |
|
||||
|
||||
## Verification
|
||||
|
||||
Check hook is registered:
|
||||
|
||||
```bash
|
||||
openclaw hooks list
|
||||
```
|
||||
|
||||
Check skill is loaded:
|
||||
|
||||
```bash
|
||||
openclaw status
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Hook not firing
|
||||
|
||||
1. Ensure hooks enabled in config
|
||||
2. Restart gateway after config changes
|
||||
3. Check gateway logs for errors
|
||||
|
||||
### Learnings not persisting
|
||||
|
||||
1. Verify `.learnings/` directory exists
|
||||
2. Check file permissions
|
||||
3. Ensure workspace path is configured correctly
|
||||
|
||||
### Skill not loading
|
||||
|
||||
1. Check skill is in skills directory
|
||||
2. Verify SKILL.md has correct frontmatter
|
||||
3. Run `openclaw status` to see loaded skills
|
||||
@@ -0,0 +1,20 @@
|
||||
#!/bin/bash
|
||||
# Self-Improvement Activator Hook
|
||||
# Triggers on UserPromptSubmit to remind Claude about learning capture
|
||||
# Keep output minimal (~50-100 tokens) to minimize overhead
|
||||
|
||||
set -e
|
||||
|
||||
# Output reminder as system context
|
||||
cat << 'EOF'
|
||||
<self-improvement-reminder>
|
||||
After completing this task, evaluate if extractable knowledge emerged:
|
||||
- Non-obvious solution discovered through investigation?
|
||||
- Workaround for unexpected behavior?
|
||||
- Project-specific pattern learned?
|
||||
- Error required debugging to resolve?
|
||||
|
||||
If yes: Log to .learnings/ using the self-improvement skill format.
|
||||
If high-value (recurring, broadly applicable): Consider skill extraction.
|
||||
</self-improvement-reminder>
|
||||
EOF
|
||||
@@ -0,0 +1,55 @@
|
||||
#!/bin/bash
|
||||
# Self-Improvement Error Detector Hook
|
||||
# Triggers on PostToolUse for Bash to detect command failures
|
||||
# Reads CLAUDE_TOOL_OUTPUT environment variable
|
||||
|
||||
set -e
|
||||
|
||||
# Check if tool output indicates an error
|
||||
# CLAUDE_TOOL_OUTPUT contains the result of the tool execution
|
||||
OUTPUT="${CLAUDE_TOOL_OUTPUT:-}"
|
||||
|
||||
# Patterns indicating errors (case-insensitive matching)
|
||||
ERROR_PATTERNS=(
|
||||
"error:"
|
||||
"Error:"
|
||||
"ERROR:"
|
||||
"failed"
|
||||
"FAILED"
|
||||
"command not found"
|
||||
"No such file"
|
||||
"Permission denied"
|
||||
"fatal:"
|
||||
"Exception"
|
||||
"Traceback"
|
||||
"npm ERR!"
|
||||
"ModuleNotFoundError"
|
||||
"SyntaxError"
|
||||
"TypeError"
|
||||
"exit code"
|
||||
"non-zero"
|
||||
)
|
||||
|
||||
# Check if output contains any error pattern
|
||||
contains_error=false
|
||||
for pattern in "${ERROR_PATTERNS[@]}"; do
|
||||
if [[ "$OUTPUT" == *"$pattern"* ]]; then
|
||||
contains_error=true
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
# Only output reminder if error detected
|
||||
if [ "$contains_error" = true ]; then
|
||||
cat << 'EOF'
|
||||
<error-detected>
|
||||
A command error was detected. Consider logging this to .learnings/ERRORS.md if:
|
||||
- The error was unexpected or non-obvious
|
||||
- It required investigation to resolve
|
||||
- It might recur in similar contexts
|
||||
- The solution could benefit future sessions
|
||||
|
||||
Use the self-improvement skill format: [ERR-YYYYMMDD-XXX]
|
||||
</error-detected>
|
||||
EOF
|
||||
fi
|
||||
@@ -0,0 +1,221 @@
|
||||
#!/bin/bash
|
||||
# Skill Extraction Helper
|
||||
# Creates a new skill from a learning entry
|
||||
# Usage: ./extract-skill.sh <skill-name> [--dry-run]
|
||||
|
||||
set -e
|
||||
|
||||
# Configuration
|
||||
SKILLS_DIR="./skills"
|
||||
|
||||
# Colors for output
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
usage() {
|
||||
cat << EOF
|
||||
Usage: $(basename "$0") <skill-name> [options]
|
||||
|
||||
Create a new skill from a learning entry.
|
||||
|
||||
Arguments:
|
||||
skill-name Name of the skill (lowercase, hyphens for spaces)
|
||||
|
||||
Options:
|
||||
--dry-run Show what would be created without creating files
|
||||
--output-dir Relative output directory under current path (default: ./skills)
|
||||
-h, --help Show this help message
|
||||
|
||||
Examples:
|
||||
$(basename "$0") docker-m1-fixes
|
||||
$(basename "$0") api-timeout-patterns --dry-run
|
||||
$(basename "$0") pnpm-setup --output-dir ./skills/custom
|
||||
|
||||
The skill will be created in: \$SKILLS_DIR/<skill-name>/
|
||||
EOF
|
||||
}
|
||||
|
||||
log_info() {
|
||||
echo -e "${GREEN}[INFO]${NC} $1"
|
||||
}
|
||||
|
||||
log_warn() {
|
||||
echo -e "${YELLOW}[WARN]${NC} $1"
|
||||
}
|
||||
|
||||
log_error() {
|
||||
echo -e "${RED}[ERROR]${NC} $1" >&2
|
||||
}
|
||||
|
||||
# Parse arguments
|
||||
SKILL_NAME=""
|
||||
DRY_RUN=false
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case $1 in
|
||||
--dry-run)
|
||||
DRY_RUN=true
|
||||
shift
|
||||
;;
|
||||
--output-dir)
|
||||
if [ -z "${2:-}" ] || [[ "${2:-}" == -* ]]; then
|
||||
log_error "--output-dir requires a relative path argument"
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
SKILLS_DIR="$2"
|
||||
shift 2
|
||||
;;
|
||||
-h|--help)
|
||||
usage
|
||||
exit 0
|
||||
;;
|
||||
-*)
|
||||
log_error "Unknown option: $1"
|
||||
usage
|
||||
exit 1
|
||||
;;
|
||||
*)
|
||||
if [ -z "$SKILL_NAME" ]; then
|
||||
SKILL_NAME="$1"
|
||||
else
|
||||
log_error "Unexpected argument: $1"
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
shift
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Validate skill name
|
||||
if [ -z "$SKILL_NAME" ]; then
|
||||
log_error "Skill name is required"
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Validate skill name format (lowercase, hyphens, no spaces)
|
||||
if ! [[ "$SKILL_NAME" =~ ^[a-z0-9]+(-[a-z0-9]+)*$ ]]; then
|
||||
log_error "Invalid skill name format. Use lowercase letters, numbers, and hyphens only."
|
||||
log_error "Examples: 'docker-fixes', 'api-patterns', 'pnpm-setup'"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Validate output path to avoid writes outside current workspace.
|
||||
if [[ "$SKILLS_DIR" = /* ]]; then
|
||||
log_error "Output directory must be a relative path under the current directory."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ "$SKILLS_DIR" =~ (^|/)\.\.(/|$) ]]; then
|
||||
log_error "Output directory cannot include '..' path segments."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
SKILLS_DIR="${SKILLS_DIR#./}"
|
||||
SKILLS_DIR="./$SKILLS_DIR"
|
||||
|
||||
SKILL_PATH="$SKILLS_DIR/$SKILL_NAME"
|
||||
|
||||
# Check if skill already exists
|
||||
if [ -d "$SKILL_PATH" ] && [ "$DRY_RUN" = false ]; then
|
||||
log_error "Skill already exists: $SKILL_PATH"
|
||||
log_error "Use a different name or remove the existing skill first."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Dry run output
|
||||
if [ "$DRY_RUN" = true ]; then
|
||||
log_info "Dry run - would create:"
|
||||
echo " $SKILL_PATH/"
|
||||
echo " $SKILL_PATH/SKILL.md"
|
||||
echo ""
|
||||
echo "Template content would be:"
|
||||
echo "---"
|
||||
cat << TEMPLATE
|
||||
name: $SKILL_NAME
|
||||
description: "[TODO: Add a concise description of what this skill does and when to use it]"
|
||||
---
|
||||
|
||||
# $(echo "$SKILL_NAME" | sed 's/-/ /g' | awk '{for(i=1;i<=NF;i++) $i=toupper(substr($i,1,1)) tolower(substr($i,2))}1')
|
||||
|
||||
[TODO: Brief introduction explaining the skill's purpose]
|
||||
|
||||
## Quick Reference
|
||||
|
||||
| Situation | Action |
|
||||
|-----------|--------|
|
||||
| [Trigger condition] | [What to do] |
|
||||
|
||||
## Usage
|
||||
|
||||
[TODO: Detailed usage instructions]
|
||||
|
||||
## Examples
|
||||
|
||||
[TODO: Add concrete examples]
|
||||
|
||||
## Source Learning
|
||||
|
||||
This skill was extracted from a learning entry.
|
||||
- Learning ID: [TODO: Add original learning ID]
|
||||
- Original File: .learnings/LEARNINGS.md
|
||||
TEMPLATE
|
||||
echo "---"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Create skill directory structure
|
||||
log_info "Creating skill: $SKILL_NAME"
|
||||
|
||||
mkdir -p "$SKILL_PATH"
|
||||
|
||||
# Create SKILL.md from template
|
||||
cat > "$SKILL_PATH/SKILL.md" << TEMPLATE
|
||||
---
|
||||
name: $SKILL_NAME
|
||||
description: "[TODO: Add a concise description of what this skill does and when to use it]"
|
||||
---
|
||||
|
||||
# $(echo "$SKILL_NAME" | sed 's/-/ /g' | awk '{for(i=1;i<=NF;i++) $i=toupper(substr($i,1,1)) tolower(substr($i,2))}1')
|
||||
|
||||
[TODO: Brief introduction explaining the skill's purpose]
|
||||
|
||||
## Quick Reference
|
||||
|
||||
| Situation | Action |
|
||||
|-----------|--------|
|
||||
| [Trigger condition] | [What to do] |
|
||||
|
||||
## Usage
|
||||
|
||||
[TODO: Detailed usage instructions]
|
||||
|
||||
## Examples
|
||||
|
||||
[TODO: Add concrete examples]
|
||||
|
||||
## Source Learning
|
||||
|
||||
This skill was extracted from a learning entry.
|
||||
- Learning ID: [TODO: Add original learning ID]
|
||||
- Original File: .learnings/LEARNINGS.md
|
||||
TEMPLATE
|
||||
|
||||
log_info "Created: $SKILL_PATH/SKILL.md"
|
||||
|
||||
# Suggest next steps
|
||||
echo ""
|
||||
log_info "Skill scaffold created successfully!"
|
||||
echo ""
|
||||
echo "Next steps:"
|
||||
echo " 1. Edit $SKILL_PATH/SKILL.md"
|
||||
echo " 2. Fill in the TODO sections with content from your learning"
|
||||
echo " 3. Add references/ folder if you have detailed documentation"
|
||||
echo " 4. Add scripts/ folder if you have executable code"
|
||||
echo " 5. Update the original learning entry with:"
|
||||
echo " **Status**: promoted_to_skill"
|
||||
echo " **Skill-Path**: skills/$SKILL_NAME"
|
||||
@@ -0,0 +1,517 @@
|
||||
---
|
||||
name: agent-browser
|
||||
description: Browser automation CLI for AI agents. Use when the user needs to interact with websites, including navigating pages, filling forms, clicking buttons, taking screenshots, extracting data, testing web apps, or automating any browser task. Triggers include requests to "open a website", "fill out a form", "click a button", "take a screenshot", "scrape data from a page", "test this web app", "login to a site", "automate browser actions", or any task requiring programmatic web interaction.
|
||||
allowed-tools: Bash(npx agent-browser:*), Bash(agent-browser:*)
|
||||
---
|
||||
|
||||
# Browser Automation with agent-browser
|
||||
|
||||
## Core Workflow
|
||||
|
||||
Every browser automation follows this pattern:
|
||||
|
||||
1. **Navigate**: `agent-browser open <url>`
|
||||
2. **Snapshot**: `agent-browser snapshot -i` (get element refs like `@e1`, `@e2`)
|
||||
3. **Interact**: Use refs to click, fill, select
|
||||
4. **Re-snapshot**: After navigation or DOM changes, get fresh refs
|
||||
|
||||
```bash
|
||||
agent-browser open https://example.com/form
|
||||
agent-browser snapshot -i
|
||||
# Output: @e1 [input type="email"], @e2 [input type="password"], @e3 [button] "Submit"
|
||||
|
||||
agent-browser fill @e1 "user@example.com"
|
||||
agent-browser fill @e2 "password123"
|
||||
agent-browser click @e3
|
||||
agent-browser wait --load networkidle
|
||||
agent-browser snapshot -i # Check result
|
||||
```
|
||||
|
||||
## Command Chaining
|
||||
|
||||
Commands can be chained with `&&` in a single shell invocation. The browser persists between commands via a background daemon, so chaining is safe and more efficient than separate calls.
|
||||
|
||||
```bash
|
||||
# Chain open + wait + snapshot in one call
|
||||
agent-browser open https://example.com && agent-browser wait --load networkidle && agent-browser snapshot -i
|
||||
|
||||
# Chain multiple interactions
|
||||
agent-browser fill @e1 "user@example.com" && agent-browser fill @e2 "password123" && agent-browser click @e3
|
||||
|
||||
# Navigate and capture
|
||||
agent-browser open https://example.com && agent-browser wait --load networkidle && agent-browser screenshot page.png
|
||||
```
|
||||
|
||||
**When to chain:** Use `&&` when you don't need to read the output of an intermediate command before proceeding (e.g., open + wait + screenshot). Run commands separately when you need to parse the output first (e.g., snapshot to discover refs, then interact using those refs).
|
||||
|
||||
## Essential Commands
|
||||
|
||||
```bash
|
||||
# Navigation
|
||||
agent-browser open <url> # Navigate (aliases: goto, navigate)
|
||||
agent-browser close # Close browser
|
||||
|
||||
# Snapshot
|
||||
agent-browser snapshot -i # Interactive elements with refs (recommended)
|
||||
agent-browser snapshot -i -C # Include cursor-interactive elements (divs with onclick, cursor:pointer)
|
||||
agent-browser snapshot -s "#selector" # Scope to CSS selector
|
||||
|
||||
# Interaction (use @refs from snapshot)
|
||||
agent-browser click @e1 # Click element
|
||||
agent-browser click @e1 --new-tab # Click and open in new tab
|
||||
agent-browser fill @e2 "text" # Clear and type text
|
||||
agent-browser type @e2 "text" # Type without clearing
|
||||
agent-browser select @e1 "option" # Select dropdown option
|
||||
agent-browser check @e1 # Check checkbox
|
||||
agent-browser press Enter # Press key
|
||||
agent-browser keyboard type "text" # Type at current focus (no selector)
|
||||
agent-browser keyboard inserttext "text" # Insert without key events
|
||||
agent-browser scroll down 500 # Scroll page
|
||||
agent-browser scroll down 500 --selector "div.content" # Scroll within a specific container
|
||||
|
||||
# Get information
|
||||
agent-browser get text @e1 # Get element text
|
||||
agent-browser get url # Get current URL
|
||||
agent-browser get title # Get page title
|
||||
|
||||
# Wait
|
||||
agent-browser wait @e1 # Wait for element
|
||||
agent-browser wait --load networkidle # Wait for network idle
|
||||
agent-browser wait --url "**/page" # Wait for URL pattern
|
||||
agent-browser wait 2000 # Wait milliseconds
|
||||
|
||||
# Downloads
|
||||
agent-browser download @e1 ./file.pdf # Click element to trigger download
|
||||
agent-browser wait --download ./output.zip # Wait for any download to complete
|
||||
agent-browser --download-path ./downloads open <url> # Set default download directory
|
||||
|
||||
# Capture
|
||||
agent-browser screenshot # Screenshot to temp dir
|
||||
agent-browser screenshot --full # Full page screenshot
|
||||
agent-browser screenshot --annotate # Annotated screenshot with numbered element labels
|
||||
agent-browser pdf output.pdf # Save as PDF
|
||||
|
||||
# Diff (compare page states)
|
||||
agent-browser diff snapshot # Compare current vs last snapshot
|
||||
agent-browser diff snapshot --baseline before.txt # Compare current vs saved file
|
||||
agent-browser diff screenshot --baseline before.png # Visual pixel diff
|
||||
agent-browser diff url <url1> <url2> # Compare two pages
|
||||
agent-browser diff url <url1> <url2> --wait-until networkidle # Custom wait strategy
|
||||
agent-browser diff url <url1> <url2> --selector "#main" # Scope to element
|
||||
```
|
||||
|
||||
## Common Patterns
|
||||
|
||||
### Form Submission
|
||||
|
||||
```bash
|
||||
agent-browser open https://example.com/signup
|
||||
agent-browser snapshot -i
|
||||
agent-browser fill @e1 "Jane Doe"
|
||||
agent-browser fill @e2 "jane@example.com"
|
||||
agent-browser select @e3 "California"
|
||||
agent-browser check @e4
|
||||
agent-browser click @e5
|
||||
agent-browser wait --load networkidle
|
||||
```
|
||||
|
||||
### Authentication with Auth Vault (Recommended)
|
||||
|
||||
```bash
|
||||
# Save credentials once (encrypted with AGENT_BROWSER_ENCRYPTION_KEY)
|
||||
# Recommended: pipe password via stdin to avoid shell history exposure
|
||||
echo "pass" | agent-browser auth save github --url https://github.com/login --username user --password-stdin
|
||||
|
||||
# Login using saved profile (LLM never sees password)
|
||||
agent-browser auth login github
|
||||
|
||||
# List/show/delete profiles
|
||||
agent-browser auth list
|
||||
agent-browser auth show github
|
||||
agent-browser auth delete github
|
||||
```
|
||||
|
||||
### Authentication with State Persistence
|
||||
|
||||
```bash
|
||||
# Login once and save state
|
||||
agent-browser open https://app.example.com/login
|
||||
agent-browser snapshot -i
|
||||
agent-browser fill @e1 "$USERNAME"
|
||||
agent-browser fill @e2 "$PASSWORD"
|
||||
agent-browser click @e3
|
||||
agent-browser wait --url "**/dashboard"
|
||||
agent-browser state save auth.json
|
||||
|
||||
# Reuse in future sessions
|
||||
agent-browser state load auth.json
|
||||
agent-browser open https://app.example.com/dashboard
|
||||
```
|
||||
|
||||
### Session Persistence
|
||||
|
||||
```bash
|
||||
# Auto-save/restore cookies and localStorage across browser restarts
|
||||
agent-browser --session-name myapp open https://app.example.com/login
|
||||
# ... login flow ...
|
||||
agent-browser close # State auto-saved to ~/.agent-browser/sessions/
|
||||
|
||||
# Next time, state is auto-loaded
|
||||
agent-browser --session-name myapp open https://app.example.com/dashboard
|
||||
|
||||
# Encrypt state at rest
|
||||
export AGENT_BROWSER_ENCRYPTION_KEY=$(openssl rand -hex 32)
|
||||
agent-browser --session-name secure open https://app.example.com
|
||||
|
||||
# Manage saved states
|
||||
agent-browser state list
|
||||
agent-browser state show myapp-default.json
|
||||
agent-browser state clear myapp
|
||||
agent-browser state clean --older-than 7
|
||||
```
|
||||
|
||||
### Data Extraction
|
||||
|
||||
```bash
|
||||
agent-browser open https://example.com/products
|
||||
agent-browser snapshot -i
|
||||
agent-browser get text @e5 # Get specific element text
|
||||
agent-browser get text body > page.txt # Get all page text
|
||||
|
||||
# JSON output for parsing
|
||||
agent-browser snapshot -i --json
|
||||
agent-browser get text @e1 --json
|
||||
```
|
||||
|
||||
### Parallel Sessions
|
||||
|
||||
```bash
|
||||
agent-browser --session site1 open https://site-a.com
|
||||
agent-browser --session site2 open https://site-b.com
|
||||
|
||||
agent-browser --session site1 snapshot -i
|
||||
agent-browser --session site2 snapshot -i
|
||||
|
||||
agent-browser session list
|
||||
```
|
||||
|
||||
### Connect to Existing Chrome
|
||||
|
||||
```bash
|
||||
# Auto-discover running Chrome with remote debugging enabled
|
||||
agent-browser --auto-connect open https://example.com
|
||||
agent-browser --auto-connect snapshot
|
||||
|
||||
# Or with explicit CDP port
|
||||
agent-browser --cdp 9222 snapshot
|
||||
```
|
||||
|
||||
### Color Scheme (Dark Mode)
|
||||
|
||||
```bash
|
||||
# Persistent dark mode via flag (applies to all pages and new tabs)
|
||||
agent-browser --color-scheme dark open https://example.com
|
||||
|
||||
# Or via environment variable
|
||||
AGENT_BROWSER_COLOR_SCHEME=dark agent-browser open https://example.com
|
||||
|
||||
# Or set during session (persists for subsequent commands)
|
||||
agent-browser set media dark
|
||||
```
|
||||
|
||||
### Visual Browser (Debugging)
|
||||
|
||||
```bash
|
||||
agent-browser --headed open https://example.com
|
||||
agent-browser highlight @e1 # Highlight element
|
||||
agent-browser record start demo.webm # Record session
|
||||
agent-browser profiler start # Start Chrome DevTools profiling
|
||||
agent-browser profiler stop trace.json # Stop and save profile (path optional)
|
||||
```
|
||||
|
||||
Use `AGENT_BROWSER_HEADED=1` to enable headed mode via environment variable. Browser extensions work in both headed and headless mode.
|
||||
|
||||
### Local Files (PDFs, HTML)
|
||||
|
||||
```bash
|
||||
# Open local files with file:// URLs
|
||||
agent-browser --allow-file-access open file:///path/to/document.pdf
|
||||
agent-browser --allow-file-access open file:///path/to/page.html
|
||||
agent-browser screenshot output.png
|
||||
```
|
||||
|
||||
### iOS Simulator (Mobile Safari)
|
||||
|
||||
```bash
|
||||
# List available iOS simulators
|
||||
agent-browser device list
|
||||
|
||||
# Launch Safari on a specific device
|
||||
agent-browser -p ios --device "iPhone 16 Pro" open https://example.com
|
||||
|
||||
# Same workflow as desktop - snapshot, interact, re-snapshot
|
||||
agent-browser -p ios snapshot -i
|
||||
agent-browser -p ios tap @e1 # Tap (alias for click)
|
||||
agent-browser -p ios fill @e2 "text"
|
||||
agent-browser -p ios swipe up # Mobile-specific gesture
|
||||
|
||||
# Take screenshot
|
||||
agent-browser -p ios screenshot mobile.png
|
||||
|
||||
# Close session (shuts down simulator)
|
||||
agent-browser -p ios close
|
||||
```
|
||||
|
||||
**Requirements:** macOS with Xcode, Appium (`npm install -g appium && appium driver install xcuitest`)
|
||||
|
||||
**Real devices:** Works with physical iOS devices if pre-configured. Use `--device "<UDID>"` where UDID is from `xcrun xctrace list devices`.
|
||||
|
||||
## Security
|
||||
|
||||
All security features are opt-in. By default, agent-browser imposes no restrictions on navigation, actions, or output.
|
||||
|
||||
### Content Boundaries (Recommended for AI Agents)
|
||||
|
||||
Enable `--content-boundaries` to wrap page-sourced output in markers that help LLMs distinguish tool output from untrusted page content:
|
||||
|
||||
```bash
|
||||
export AGENT_BROWSER_CONTENT_BOUNDARIES=1
|
||||
agent-browser snapshot
|
||||
# Output:
|
||||
# --- AGENT_BROWSER_PAGE_CONTENT nonce=<hex> origin=https://example.com ---
|
||||
# [accessibility tree]
|
||||
# --- END_AGENT_BROWSER_PAGE_CONTENT nonce=<hex> ---
|
||||
```
|
||||
|
||||
### Domain Allowlist
|
||||
|
||||
Restrict navigation to trusted domains. Wildcards like `*.example.com` also match the bare domain `example.com`. Sub-resource requests, WebSocket, and EventSource connections to non-allowed domains are also blocked. Include CDN domains your target pages depend on:
|
||||
|
||||
```bash
|
||||
export AGENT_BROWSER_ALLOWED_DOMAINS="example.com,*.example.com"
|
||||
agent-browser open https://example.com # OK
|
||||
agent-browser open https://malicious.com # Blocked
|
||||
```
|
||||
|
||||
### Action Policy
|
||||
|
||||
Use a policy file to gate destructive actions:
|
||||
|
||||
```bash
|
||||
export AGENT_BROWSER_ACTION_POLICY=./policy.json
|
||||
```
|
||||
|
||||
Example `policy.json`:
|
||||
```json
|
||||
{"default": "deny", "allow": ["navigate", "snapshot", "click", "scroll", "wait", "get"]}
|
||||
```
|
||||
|
||||
Auth vault operations (`auth login`, etc.) bypass action policy but domain allowlist still applies.
|
||||
|
||||
### Output Limits
|
||||
|
||||
Prevent context flooding from large pages:
|
||||
|
||||
```bash
|
||||
export AGENT_BROWSER_MAX_OUTPUT=50000
|
||||
```
|
||||
|
||||
## Diffing (Verifying Changes)
|
||||
|
||||
Use `diff snapshot` after performing an action to verify it had the intended effect. This compares the current accessibility tree against the last snapshot taken in the session.
|
||||
|
||||
```bash
|
||||
# Typical workflow: snapshot -> action -> diff
|
||||
agent-browser snapshot -i # Take baseline snapshot
|
||||
agent-browser click @e2 # Perform action
|
||||
agent-browser diff snapshot # See what changed (auto-compares to last snapshot)
|
||||
```
|
||||
|
||||
For visual regression testing or monitoring:
|
||||
|
||||
```bash
|
||||
# Save a baseline screenshot, then compare later
|
||||
agent-browser screenshot baseline.png
|
||||
# ... time passes or changes are made ...
|
||||
agent-browser diff screenshot --baseline baseline.png
|
||||
|
||||
# Compare staging vs production
|
||||
agent-browser diff url https://staging.example.com https://prod.example.com --screenshot
|
||||
```
|
||||
|
||||
`diff snapshot` output uses `+` for additions and `-` for removals, similar to git diff. `diff screenshot` produces a diff image with changed pixels highlighted in red, plus a mismatch percentage.
|
||||
|
||||
## Timeouts and Slow Pages
|
||||
|
||||
The default Playwright timeout is 25 seconds for local browsers. This can be overridden with the `AGENT_BROWSER_DEFAULT_TIMEOUT` environment variable (value in milliseconds). For slow websites or large pages, use explicit waits instead of relying on the default timeout:
|
||||
|
||||
```bash
|
||||
# Wait for network activity to settle (best for slow pages)
|
||||
agent-browser wait --load networkidle
|
||||
|
||||
# Wait for a specific element to appear
|
||||
agent-browser wait "#content"
|
||||
agent-browser wait @e1
|
||||
|
||||
# Wait for a specific URL pattern (useful after redirects)
|
||||
agent-browser wait --url "**/dashboard"
|
||||
|
||||
# Wait for a JavaScript condition
|
||||
agent-browser wait --fn "document.readyState === 'complete'"
|
||||
|
||||
# Wait a fixed duration (milliseconds) as a last resort
|
||||
agent-browser wait 5000
|
||||
```
|
||||
|
||||
When dealing with consistently slow websites, use `wait --load networkidle` after `open` to ensure the page is fully loaded before taking a snapshot. If a specific element is slow to render, wait for it directly with `wait <selector>` or `wait @ref`.
|
||||
|
||||
## Session Management and Cleanup
|
||||
|
||||
When running multiple agents or automations concurrently, always use named sessions to avoid conflicts:
|
||||
|
||||
```bash
|
||||
# Each agent gets its own isolated session
|
||||
agent-browser --session agent1 open site-a.com
|
||||
agent-browser --session agent2 open site-b.com
|
||||
|
||||
# Check active sessions
|
||||
agent-browser session list
|
||||
```
|
||||
|
||||
Always close your browser session when done to avoid leaked processes:
|
||||
|
||||
```bash
|
||||
agent-browser close # Close default session
|
||||
agent-browser --session agent1 close # Close specific session
|
||||
```
|
||||
|
||||
If a previous session was not closed properly, the daemon may still be running. Use `agent-browser close` to clean it up before starting new work.
|
||||
|
||||
## Ref Lifecycle (Important)
|
||||
|
||||
Refs (`@e1`, `@e2`, etc.) are invalidated when the page changes. Always re-snapshot after:
|
||||
|
||||
- Clicking links or buttons that navigate
|
||||
- Form submissions
|
||||
- Dynamic content loading (dropdowns, modals)
|
||||
|
||||
```bash
|
||||
agent-browser click @e5 # Navigates to new page
|
||||
agent-browser snapshot -i # MUST re-snapshot
|
||||
agent-browser click @e1 # Use new refs
|
||||
```
|
||||
|
||||
## Annotated Screenshots (Vision Mode)
|
||||
|
||||
Use `--annotate` to take a screenshot with numbered labels overlaid on interactive elements. Each label `[N]` maps to ref `@eN`. This also caches refs, so you can interact with elements immediately without a separate snapshot.
|
||||
|
||||
```bash
|
||||
agent-browser screenshot --annotate
|
||||
# Output includes the image path and a legend:
|
||||
# [1] @e1 button "Submit"
|
||||
# [2] @e2 link "Home"
|
||||
# [3] @e3 textbox "Email"
|
||||
agent-browser click @e2 # Click using ref from annotated screenshot
|
||||
```
|
||||
|
||||
Use annotated screenshots when:
|
||||
- The page has unlabeled icon buttons or visual-only elements
|
||||
- You need to verify visual layout or styling
|
||||
- Canvas or chart elements are present (invisible to text snapshots)
|
||||
- You need spatial reasoning about element positions
|
||||
|
||||
## Semantic Locators (Alternative to Refs)
|
||||
|
||||
When refs are unavailable or unreliable, use semantic locators:
|
||||
|
||||
```bash
|
||||
agent-browser find text "Sign In" click
|
||||
agent-browser find label "Email" fill "user@test.com"
|
||||
agent-browser find role button click --name "Submit"
|
||||
agent-browser find placeholder "Search" type "query"
|
||||
agent-browser find testid "submit-btn" click
|
||||
```
|
||||
|
||||
## JavaScript Evaluation (eval)
|
||||
|
||||
Use `eval` to run JavaScript in the browser context. **Shell quoting can corrupt complex expressions** -- use `--stdin` or `-b` to avoid issues.
|
||||
|
||||
```bash
|
||||
# Simple expressions work with regular quoting
|
||||
agent-browser eval 'document.title'
|
||||
agent-browser eval 'document.querySelectorAll("img").length'
|
||||
|
||||
# Complex JS: use --stdin with heredoc (RECOMMENDED)
|
||||
agent-browser eval --stdin <<'EVALEOF'
|
||||
JSON.stringify(
|
||||
Array.from(document.querySelectorAll("img"))
|
||||
.filter(i => !i.alt)
|
||||
.map(i => ({ src: i.src.split("/").pop(), width: i.width }))
|
||||
)
|
||||
EVALEOF
|
||||
|
||||
# Alternative: base64 encoding (avoids all shell escaping issues)
|
||||
agent-browser eval -b "$(echo -n 'Array.from(document.querySelectorAll("a")).map(a => a.href)' | base64)"
|
||||
```
|
||||
|
||||
**Why this matters:** When the shell processes your command, inner double quotes, `!` characters (history expansion), backticks, and `$()` can all corrupt the JavaScript before it reaches agent-browser. The `--stdin` and `-b` flags bypass shell interpretation entirely.
|
||||
|
||||
**Rules of thumb:**
|
||||
- Single-line, no nested quotes -> regular `eval 'expression'` with single quotes is fine
|
||||
- Nested quotes, arrow functions, template literals, or multiline -> use `eval --stdin <<'EVALEOF'`
|
||||
- Programmatic/generated scripts -> use `eval -b` with base64
|
||||
|
||||
## Configuration File
|
||||
|
||||
Create `agent-browser.json` in the project root for persistent settings:
|
||||
|
||||
```json
|
||||
{
|
||||
"headed": true,
|
||||
"proxy": "http://localhost:8080",
|
||||
"profile": "./browser-data"
|
||||
}
|
||||
```
|
||||
|
||||
Priority (lowest to highest): `~/.agent-browser/config.json` < `./agent-browser.json` < env vars < CLI flags. Use `--config <path>` or `AGENT_BROWSER_CONFIG` env var for a custom config file (exits with error if missing/invalid). All CLI options map to camelCase keys (e.g., `--executable-path` -> `"executablePath"`). Boolean flags accept `true`/`false` values (e.g., `--headed false` overrides config). Extensions from user and project configs are merged, not replaced.
|
||||
|
||||
## Deep-Dive Documentation
|
||||
|
||||
| Reference | When to Use |
|
||||
|-----------|-------------|
|
||||
| [references/commands.md](references/commands.md) | Full command reference with all options |
|
||||
| [references/snapshot-refs.md](references/snapshot-refs.md) | Ref lifecycle, invalidation rules, troubleshooting |
|
||||
| [references/session-management.md](references/session-management.md) | Parallel sessions, state persistence, concurrent scraping |
|
||||
| [references/authentication.md](references/authentication.md) | Login flows, OAuth, 2FA handling, state reuse |
|
||||
| [references/video-recording.md](references/video-recording.md) | Recording workflows for debugging and documentation |
|
||||
| [references/profiling.md](references/profiling.md) | Chrome DevTools profiling for performance analysis |
|
||||
| [references/proxy-support.md](references/proxy-support.md) | Proxy configuration, geo-testing, rotating proxies |
|
||||
|
||||
## Experimental: Native Mode
|
||||
|
||||
agent-browser has an experimental native Rust daemon that communicates with Chrome directly via CDP, bypassing Node.js and Playwright entirely. It is opt-in and not recommended for production use yet.
|
||||
|
||||
```bash
|
||||
# Enable via flag
|
||||
agent-browser --native open example.com
|
||||
|
||||
# Enable via environment variable (avoids passing --native every time)
|
||||
export AGENT_BROWSER_NATIVE=1
|
||||
agent-browser open example.com
|
||||
```
|
||||
|
||||
The native daemon supports Chromium and Safari (via WebDriver). Firefox and WebKit are not yet supported. All core commands (navigate, snapshot, click, fill, screenshot, cookies, storage, tabs, eval, etc.) work identically in native mode. Use `agent-browser close` before switching between native and default mode within the same session.
|
||||
|
||||
## Ready-to-Use Templates
|
||||
|
||||
| Template | Description |
|
||||
|----------|-------------|
|
||||
| [templates/form-automation.sh](templates/form-automation.sh) | Form filling with validation |
|
||||
| [templates/authenticated-session.sh](templates/authenticated-session.sh) | Login once, reuse state |
|
||||
| [templates/capture-workflow.sh](templates/capture-workflow.sh) | Content extraction with screenshots |
|
||||
|
||||
```bash
|
||||
./templates/form-automation.sh https://example.com/form
|
||||
./templates/authenticated-session.sh https://app.example.com/login
|
||||
./templates/capture-workflow.sh https://example.com ./output
|
||||
```
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"owner": "winchester-yi",
|
||||
"slug": "agent-browser-vercel",
|
||||
"displayName": "Agent Browser",
|
||||
"latest": {
|
||||
"version": "0.1.0",
|
||||
"publishedAt": 1772758164707,
|
||||
"commit": "https://github.com/openclaw/skills/commit/6255ba120beea941994acab2832644d0a1755320"
|
||||
},
|
||||
"history": []
|
||||
}
|
||||
@@ -0,0 +1,202 @@
|
||||
# Authentication Patterns
|
||||
|
||||
Login flows, session persistence, OAuth, 2FA, and authenticated browsing.
|
||||
|
||||
**Related**: [session-management.md](session-management.md) for state persistence details, [SKILL.md](../SKILL.md) for quick start.
|
||||
|
||||
## Contents
|
||||
|
||||
- [Basic Login Flow](#basic-login-flow)
|
||||
- [Saving Authentication State](#saving-authentication-state)
|
||||
- [Restoring Authentication](#restoring-authentication)
|
||||
- [OAuth / SSO Flows](#oauth--sso-flows)
|
||||
- [Two-Factor Authentication](#two-factor-authentication)
|
||||
- [HTTP Basic Auth](#http-basic-auth)
|
||||
- [Cookie-Based Auth](#cookie-based-auth)
|
||||
- [Token Refresh Handling](#token-refresh-handling)
|
||||
- [Security Best Practices](#security-best-practices)
|
||||
|
||||
## Basic Login Flow
|
||||
|
||||
```bash
|
||||
# Navigate to login page
|
||||
agent-browser open https://app.example.com/login
|
||||
agent-browser wait --load networkidle
|
||||
|
||||
# Get form elements
|
||||
agent-browser snapshot -i
|
||||
# Output: @e1 [input type="email"], @e2 [input type="password"], @e3 [button] "Sign In"
|
||||
|
||||
# Fill credentials
|
||||
agent-browser fill @e1 "user@example.com"
|
||||
agent-browser fill @e2 "password123"
|
||||
|
||||
# Submit
|
||||
agent-browser click @e3
|
||||
agent-browser wait --load networkidle
|
||||
|
||||
# Verify login succeeded
|
||||
agent-browser get url # Should be dashboard, not login
|
||||
```
|
||||
|
||||
## Saving Authentication State
|
||||
|
||||
After logging in, save state for reuse:
|
||||
|
||||
```bash
|
||||
# Login first (see above)
|
||||
agent-browser open https://app.example.com/login
|
||||
agent-browser snapshot -i
|
||||
agent-browser fill @e1 "user@example.com"
|
||||
agent-browser fill @e2 "password123"
|
||||
agent-browser click @e3
|
||||
agent-browser wait --url "**/dashboard"
|
||||
|
||||
# Save authenticated state
|
||||
agent-browser state save ./auth-state.json
|
||||
```
|
||||
|
||||
## Restoring Authentication
|
||||
|
||||
Skip login by loading saved state:
|
||||
|
||||
```bash
|
||||
# Load saved auth state
|
||||
agent-browser state load ./auth-state.json
|
||||
|
||||
# Navigate directly to protected page
|
||||
agent-browser open https://app.example.com/dashboard
|
||||
|
||||
# Verify authenticated
|
||||
agent-browser snapshot -i
|
||||
```
|
||||
|
||||
## OAuth / SSO Flows
|
||||
|
||||
For OAuth redirects:
|
||||
|
||||
```bash
|
||||
# Start OAuth flow
|
||||
agent-browser open https://app.example.com/auth/google
|
||||
|
||||
# Handle redirects automatically
|
||||
agent-browser wait --url "**/accounts.google.com**"
|
||||
agent-browser snapshot -i
|
||||
|
||||
# Fill Google credentials
|
||||
agent-browser fill @e1 "user@gmail.com"
|
||||
agent-browser click @e2 # Next button
|
||||
agent-browser wait 2000
|
||||
agent-browser snapshot -i
|
||||
agent-browser fill @e3 "password"
|
||||
agent-browser click @e4 # Sign in
|
||||
|
||||
# Wait for redirect back
|
||||
agent-browser wait --url "**/app.example.com**"
|
||||
agent-browser state save ./oauth-state.json
|
||||
```
|
||||
|
||||
## Two-Factor Authentication
|
||||
|
||||
Handle 2FA with manual intervention:
|
||||
|
||||
```bash
|
||||
# Login with credentials
|
||||
agent-browser open https://app.example.com/login --headed # Show browser
|
||||
agent-browser snapshot -i
|
||||
agent-browser fill @e1 "user@example.com"
|
||||
agent-browser fill @e2 "password123"
|
||||
agent-browser click @e3
|
||||
|
||||
# Wait for user to complete 2FA manually
|
||||
echo "Complete 2FA in the browser window..."
|
||||
agent-browser wait --url "**/dashboard" --timeout 120000
|
||||
|
||||
# Save state after 2FA
|
||||
agent-browser state save ./2fa-state.json
|
||||
```
|
||||
|
||||
## HTTP Basic Auth
|
||||
|
||||
For sites using HTTP Basic Authentication:
|
||||
|
||||
```bash
|
||||
# Set credentials before navigation
|
||||
agent-browser set credentials username password
|
||||
|
||||
# Navigate to protected resource
|
||||
agent-browser open https://protected.example.com/api
|
||||
```
|
||||
|
||||
## Cookie-Based Auth
|
||||
|
||||
Manually set authentication cookies:
|
||||
|
||||
```bash
|
||||
# Set auth cookie
|
||||
agent-browser cookies set session_token "abc123xyz"
|
||||
|
||||
# Navigate to protected page
|
||||
agent-browser open https://app.example.com/dashboard
|
||||
```
|
||||
|
||||
## Token Refresh Handling
|
||||
|
||||
For sessions with expiring tokens:
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# Wrapper that handles token refresh
|
||||
|
||||
STATE_FILE="./auth-state.json"
|
||||
|
||||
# Try loading existing state
|
||||
if [[ -f "$STATE_FILE" ]]; then
|
||||
agent-browser state load "$STATE_FILE"
|
||||
agent-browser open https://app.example.com/dashboard
|
||||
|
||||
# Check if session is still valid
|
||||
URL=$(agent-browser get url)
|
||||
if [[ "$URL" == *"/login"* ]]; then
|
||||
echo "Session expired, re-authenticating..."
|
||||
# Perform fresh login
|
||||
agent-browser snapshot -i
|
||||
agent-browser fill @e1 "$USERNAME"
|
||||
agent-browser fill @e2 "$PASSWORD"
|
||||
agent-browser click @e3
|
||||
agent-browser wait --url "**/dashboard"
|
||||
agent-browser state save "$STATE_FILE"
|
||||
fi
|
||||
else
|
||||
# First-time login
|
||||
agent-browser open https://app.example.com/login
|
||||
# ... login flow ...
|
||||
fi
|
||||
```
|
||||
|
||||
## Security Best Practices
|
||||
|
||||
1. **Never commit state files** - They contain session tokens
|
||||
```bash
|
||||
echo "*.auth-state.json" >> .gitignore
|
||||
```
|
||||
|
||||
2. **Use environment variables for credentials**
|
||||
```bash
|
||||
agent-browser fill @e1 "$APP_USERNAME"
|
||||
agent-browser fill @e2 "$APP_PASSWORD"
|
||||
```
|
||||
|
||||
3. **Clean up after automation**
|
||||
```bash
|
||||
agent-browser cookies clear
|
||||
rm -f ./auth-state.json
|
||||
```
|
||||
|
||||
4. **Use short-lived sessions for CI/CD**
|
||||
```bash
|
||||
# Don't persist state in CI
|
||||
agent-browser open https://app.example.com/login
|
||||
# ... login and perform actions ...
|
||||
agent-browser close # Session ends, nothing persisted
|
||||
```
|
||||
@@ -0,0 +1,263 @@
|
||||
# Command Reference
|
||||
|
||||
Complete reference for all agent-browser commands. For quick start and common patterns, see SKILL.md.
|
||||
|
||||
## Navigation
|
||||
|
||||
```bash
|
||||
agent-browser open <url> # Navigate to URL (aliases: goto, navigate)
|
||||
# Supports: https://, http://, file://, about:, data://
|
||||
# Auto-prepends https:// if no protocol given
|
||||
agent-browser back # Go back
|
||||
agent-browser forward # Go forward
|
||||
agent-browser reload # Reload page
|
||||
agent-browser close # Close browser (aliases: quit, exit)
|
||||
agent-browser connect 9222 # Connect to browser via CDP port
|
||||
```
|
||||
|
||||
## Snapshot (page analysis)
|
||||
|
||||
```bash
|
||||
agent-browser snapshot # Full accessibility tree
|
||||
agent-browser snapshot -i # Interactive elements only (recommended)
|
||||
agent-browser snapshot -c # Compact output
|
||||
agent-browser snapshot -d 3 # Limit depth to 3
|
||||
agent-browser snapshot -s "#main" # Scope to CSS selector
|
||||
```
|
||||
|
||||
## Interactions (use @refs from snapshot)
|
||||
|
||||
```bash
|
||||
agent-browser click @e1 # Click
|
||||
agent-browser click @e1 --new-tab # Click and open in new tab
|
||||
agent-browser dblclick @e1 # Double-click
|
||||
agent-browser focus @e1 # Focus element
|
||||
agent-browser fill @e2 "text" # Clear and type
|
||||
agent-browser type @e2 "text" # Type without clearing
|
||||
agent-browser press Enter # Press key (alias: key)
|
||||
agent-browser press Control+a # Key combination
|
||||
agent-browser keydown Shift # Hold key down
|
||||
agent-browser keyup Shift # Release key
|
||||
agent-browser hover @e1 # Hover
|
||||
agent-browser check @e1 # Check checkbox
|
||||
agent-browser uncheck @e1 # Uncheck checkbox
|
||||
agent-browser select @e1 "value" # Select dropdown option
|
||||
agent-browser select @e1 "a" "b" # Select multiple options
|
||||
agent-browser scroll down 500 # Scroll page (default: down 300px)
|
||||
agent-browser scrollintoview @e1 # Scroll element into view (alias: scrollinto)
|
||||
agent-browser drag @e1 @e2 # Drag and drop
|
||||
agent-browser upload @e1 file.pdf # Upload files
|
||||
```
|
||||
|
||||
## Get Information
|
||||
|
||||
```bash
|
||||
agent-browser get text @e1 # Get element text
|
||||
agent-browser get html @e1 # Get innerHTML
|
||||
agent-browser get value @e1 # Get input value
|
||||
agent-browser get attr @e1 href # Get attribute
|
||||
agent-browser get title # Get page title
|
||||
agent-browser get url # Get current URL
|
||||
agent-browser get count ".item" # Count matching elements
|
||||
agent-browser get box @e1 # Get bounding box
|
||||
agent-browser get styles @e1 # Get computed styles (font, color, bg, etc.)
|
||||
```
|
||||
|
||||
## Check State
|
||||
|
||||
```bash
|
||||
agent-browser is visible @e1 # Check if visible
|
||||
agent-browser is enabled @e1 # Check if enabled
|
||||
agent-browser is checked @e1 # Check if checked
|
||||
```
|
||||
|
||||
## Screenshots and PDF
|
||||
|
||||
```bash
|
||||
agent-browser screenshot # Save to temporary directory
|
||||
agent-browser screenshot path.png # Save to specific path
|
||||
agent-browser screenshot --full # Full page
|
||||
agent-browser pdf output.pdf # Save as PDF
|
||||
```
|
||||
|
||||
## Video Recording
|
||||
|
||||
```bash
|
||||
agent-browser record start ./demo.webm # Start recording
|
||||
agent-browser click @e1 # Perform actions
|
||||
agent-browser record stop # Stop and save video
|
||||
agent-browser record restart ./take2.webm # Stop current + start new
|
||||
```
|
||||
|
||||
## Wait
|
||||
|
||||
```bash
|
||||
agent-browser wait @e1 # Wait for element
|
||||
agent-browser wait 2000 # Wait milliseconds
|
||||
agent-browser wait --text "Success" # Wait for text (or -t)
|
||||
agent-browser wait --url "**/dashboard" # Wait for URL pattern (or -u)
|
||||
agent-browser wait --load networkidle # Wait for network idle (or -l)
|
||||
agent-browser wait --fn "window.ready" # Wait for JS condition (or -f)
|
||||
```
|
||||
|
||||
## Mouse Control
|
||||
|
||||
```bash
|
||||
agent-browser mouse move 100 200 # Move mouse
|
||||
agent-browser mouse down left # Press button
|
||||
agent-browser mouse up left # Release button
|
||||
agent-browser mouse wheel 100 # Scroll wheel
|
||||
```
|
||||
|
||||
## Semantic Locators (alternative to refs)
|
||||
|
||||
```bash
|
||||
agent-browser find role button click --name "Submit"
|
||||
agent-browser find text "Sign In" click
|
||||
agent-browser find text "Sign In" click --exact # Exact match only
|
||||
agent-browser find label "Email" fill "user@test.com"
|
||||
agent-browser find placeholder "Search" type "query"
|
||||
agent-browser find alt "Logo" click
|
||||
agent-browser find title "Close" click
|
||||
agent-browser find testid "submit-btn" click
|
||||
agent-browser find first ".item" click
|
||||
agent-browser find last ".item" click
|
||||
agent-browser find nth 2 "a" hover
|
||||
```
|
||||
|
||||
## Browser Settings
|
||||
|
||||
```bash
|
||||
agent-browser set viewport 1920 1080 # Set viewport size
|
||||
agent-browser set device "iPhone 14" # Emulate device
|
||||
agent-browser set geo 37.7749 -122.4194 # Set geolocation (alias: geolocation)
|
||||
agent-browser set offline on # Toggle offline mode
|
||||
agent-browser set headers '{"X-Key":"v"}' # Extra HTTP headers
|
||||
agent-browser set credentials user pass # HTTP basic auth (alias: auth)
|
||||
agent-browser set media dark # Emulate color scheme
|
||||
agent-browser set media light reduced-motion # Light mode + reduced motion
|
||||
```
|
||||
|
||||
## Cookies and Storage
|
||||
|
||||
```bash
|
||||
agent-browser cookies # Get all cookies
|
||||
agent-browser cookies set name value # Set cookie
|
||||
agent-browser cookies clear # Clear cookies
|
||||
agent-browser storage local # Get all localStorage
|
||||
agent-browser storage local key # Get specific key
|
||||
agent-browser storage local set k v # Set value
|
||||
agent-browser storage local clear # Clear all
|
||||
```
|
||||
|
||||
## Network
|
||||
|
||||
```bash
|
||||
agent-browser network route <url> # Intercept requests
|
||||
agent-browser network route <url> --abort # Block requests
|
||||
agent-browser network route <url> --body '{}' # Mock response
|
||||
agent-browser network unroute [url] # Remove routes
|
||||
agent-browser network requests # View tracked requests
|
||||
agent-browser network requests --filter api # Filter requests
|
||||
```
|
||||
|
||||
## Tabs and Windows
|
||||
|
||||
```bash
|
||||
agent-browser tab # List tabs
|
||||
agent-browser tab new [url] # New tab
|
||||
agent-browser tab 2 # Switch to tab by index
|
||||
agent-browser tab close # Close current tab
|
||||
agent-browser tab close 2 # Close tab by index
|
||||
agent-browser window new # New window
|
||||
```
|
||||
|
||||
## Frames
|
||||
|
||||
```bash
|
||||
agent-browser frame "#iframe" # Switch to iframe
|
||||
agent-browser frame main # Back to main frame
|
||||
```
|
||||
|
||||
## Dialogs
|
||||
|
||||
```bash
|
||||
agent-browser dialog accept [text] # Accept dialog
|
||||
agent-browser dialog dismiss # Dismiss dialog
|
||||
```
|
||||
|
||||
## JavaScript
|
||||
|
||||
```bash
|
||||
agent-browser eval "document.title" # Simple expressions only
|
||||
agent-browser eval -b "<base64>" # Any JavaScript (base64 encoded)
|
||||
agent-browser eval --stdin # Read script from stdin
|
||||
```
|
||||
|
||||
Use `-b`/`--base64` or `--stdin` for reliable execution. Shell escaping with nested quotes and special characters is error-prone.
|
||||
|
||||
```bash
|
||||
# Base64 encode your script, then:
|
||||
agent-browser eval -b "ZG9jdW1lbnQucXVlcnlTZWxlY3RvcignW3NyYyo9Il9uZXh0Il0nKQ=="
|
||||
|
||||
# Or use stdin with heredoc for multiline scripts:
|
||||
cat <<'EOF' | agent-browser eval --stdin
|
||||
const links = document.querySelectorAll('a');
|
||||
Array.from(links).map(a => a.href);
|
||||
EOF
|
||||
```
|
||||
|
||||
## State Management
|
||||
|
||||
```bash
|
||||
agent-browser state save auth.json # Save cookies, storage, auth state
|
||||
agent-browser state load auth.json # Restore saved state
|
||||
```
|
||||
|
||||
## Global Options
|
||||
|
||||
```bash
|
||||
agent-browser --session <name> ... # Isolated browser session
|
||||
agent-browser --json ... # JSON output for parsing
|
||||
agent-browser --headed ... # Show browser window (not headless)
|
||||
agent-browser --full ... # Full page screenshot (-f)
|
||||
agent-browser --cdp <port> ... # Connect via Chrome DevTools Protocol
|
||||
agent-browser -p <provider> ... # Cloud browser provider (--provider)
|
||||
agent-browser --proxy <url> ... # Use proxy server
|
||||
agent-browser --proxy-bypass <hosts> # Hosts to bypass proxy
|
||||
agent-browser --headers <json> ... # HTTP headers scoped to URL's origin
|
||||
agent-browser --executable-path <p> # Custom browser executable
|
||||
agent-browser --extension <path> ... # Load browser extension (repeatable)
|
||||
agent-browser --ignore-https-errors # Ignore SSL certificate errors
|
||||
agent-browser --help # Show help (-h)
|
||||
agent-browser --version # Show version (-V)
|
||||
agent-browser <command> --help # Show detailed help for a command
|
||||
```
|
||||
|
||||
## Debugging
|
||||
|
||||
```bash
|
||||
agent-browser --headed open example.com # Show browser window
|
||||
agent-browser --cdp 9222 snapshot # Connect via CDP port
|
||||
agent-browser connect 9222 # Alternative: connect command
|
||||
agent-browser console # View console messages
|
||||
agent-browser console --clear # Clear console
|
||||
agent-browser errors # View page errors
|
||||
agent-browser errors --clear # Clear errors
|
||||
agent-browser highlight @e1 # Highlight element
|
||||
agent-browser trace start # Start recording trace
|
||||
agent-browser trace stop trace.zip # Stop and save trace
|
||||
agent-browser profiler start # Start Chrome DevTools profiling
|
||||
agent-browser profiler stop trace.json # Stop and save profile
|
||||
```
|
||||
|
||||
## Environment Variables
|
||||
|
||||
```bash
|
||||
AGENT_BROWSER_SESSION="mysession" # Default session name
|
||||
AGENT_BROWSER_EXECUTABLE_PATH="/path/chrome" # Custom browser path
|
||||
AGENT_BROWSER_EXTENSIONS="/ext1,/ext2" # Comma-separated extension paths
|
||||
AGENT_BROWSER_PROVIDER="browserbase" # Cloud browser provider
|
||||
AGENT_BROWSER_STREAM_PORT="9223" # WebSocket streaming port
|
||||
AGENT_BROWSER_HOME="/path/to/agent-browser" # Custom install location
|
||||
```
|
||||
@@ -0,0 +1,120 @@
|
||||
# Profiling
|
||||
|
||||
Capture Chrome DevTools performance profiles during browser automation for performance analysis.
|
||||
|
||||
**Related**: [commands.md](commands.md) for full command reference, [SKILL.md](../SKILL.md) for quick start.
|
||||
|
||||
## Contents
|
||||
|
||||
- [Basic Profiling](#basic-profiling)
|
||||
- [Profiler Commands](#profiler-commands)
|
||||
- [Categories](#categories)
|
||||
- [Use Cases](#use-cases)
|
||||
- [Output Format](#output-format)
|
||||
- [Viewing Profiles](#viewing-profiles)
|
||||
- [Limitations](#limitations)
|
||||
|
||||
## Basic Profiling
|
||||
|
||||
```bash
|
||||
# Start profiling
|
||||
agent-browser profiler start
|
||||
|
||||
# Perform actions
|
||||
agent-browser navigate https://example.com
|
||||
agent-browser click "#button"
|
||||
agent-browser wait 1000
|
||||
|
||||
# Stop and save
|
||||
agent-browser profiler stop ./trace.json
|
||||
```
|
||||
|
||||
## Profiler Commands
|
||||
|
||||
```bash
|
||||
# Start profiling with default categories
|
||||
agent-browser profiler start
|
||||
|
||||
# Start with custom trace categories
|
||||
agent-browser profiler start --categories "devtools.timeline,v8.execute,blink.user_timing"
|
||||
|
||||
# Stop profiling and save to file
|
||||
agent-browser profiler stop ./trace.json
|
||||
```
|
||||
|
||||
## Categories
|
||||
|
||||
The `--categories` flag accepts a comma-separated list of Chrome trace categories. Default categories include:
|
||||
|
||||
- `devtools.timeline` -- standard DevTools performance traces
|
||||
- `v8.execute` -- time spent running JavaScript
|
||||
- `blink` -- renderer events
|
||||
- `blink.user_timing` -- `performance.mark()` / `performance.measure()` calls
|
||||
- `latencyInfo` -- input-to-latency tracking
|
||||
- `renderer.scheduler` -- task scheduling and execution
|
||||
- `toplevel` -- broad-spectrum basic events
|
||||
|
||||
Several `disabled-by-default-*` categories are also included for detailed timeline, call stack, and V8 CPU profiling data.
|
||||
|
||||
## Use Cases
|
||||
|
||||
### Diagnosing Slow Page Loads
|
||||
|
||||
```bash
|
||||
agent-browser profiler start
|
||||
agent-browser navigate https://app.example.com
|
||||
agent-browser wait --load networkidle
|
||||
agent-browser profiler stop ./page-load-profile.json
|
||||
```
|
||||
|
||||
### Profiling User Interactions
|
||||
|
||||
```bash
|
||||
agent-browser navigate https://app.example.com
|
||||
agent-browser profiler start
|
||||
agent-browser click "#submit"
|
||||
agent-browser wait 2000
|
||||
agent-browser profiler stop ./interaction-profile.json
|
||||
```
|
||||
|
||||
### CI Performance Regression Checks
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
agent-browser profiler start
|
||||
agent-browser navigate https://app.example.com
|
||||
agent-browser wait --load networkidle
|
||||
agent-browser profiler stop "./profiles/build-${BUILD_ID}.json"
|
||||
```
|
||||
|
||||
## Output Format
|
||||
|
||||
The output is a JSON file in Chrome Trace Event format:
|
||||
|
||||
```json
|
||||
{
|
||||
"traceEvents": [
|
||||
{ "cat": "devtools.timeline", "name": "RunTask", "ph": "X", "ts": 12345, "dur": 100, ... },
|
||||
...
|
||||
],
|
||||
"metadata": {
|
||||
"clock-domain": "LINUX_CLOCK_MONOTONIC"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The `metadata.clock-domain` field is set based on the host platform (Linux or macOS). On Windows it is omitted.
|
||||
|
||||
## Viewing Profiles
|
||||
|
||||
Load the output JSON file in any of these tools:
|
||||
|
||||
- **Chrome DevTools**: Performance panel > Load profile (Ctrl+Shift+I > Performance)
|
||||
- **Perfetto UI**: https://ui.perfetto.dev/ -- drag and drop the JSON file
|
||||
- **Trace Viewer**: `chrome://tracing` in any Chromium browser
|
||||
|
||||
## Limitations
|
||||
|
||||
- Only works with Chromium-based browsers (Chrome, Edge). Not supported on Firefox or WebKit.
|
||||
- Trace data accumulates in memory while profiling is active (capped at 5 million events). Stop profiling promptly after the area of interest.
|
||||
- Data collection on stop has a 30-second timeout. If the browser is unresponsive, the stop command may fail.
|
||||
@@ -0,0 +1,194 @@
|
||||
# Proxy Support
|
||||
|
||||
Proxy configuration for geo-testing, rate limiting avoidance, and corporate environments.
|
||||
|
||||
**Related**: [commands.md](commands.md) for global options, [SKILL.md](../SKILL.md) for quick start.
|
||||
|
||||
## Contents
|
||||
|
||||
- [Basic Proxy Configuration](#basic-proxy-configuration)
|
||||
- [Authenticated Proxy](#authenticated-proxy)
|
||||
- [SOCKS Proxy](#socks-proxy)
|
||||
- [Proxy Bypass](#proxy-bypass)
|
||||
- [Common Use Cases](#common-use-cases)
|
||||
- [Verifying Proxy Connection](#verifying-proxy-connection)
|
||||
- [Troubleshooting](#troubleshooting)
|
||||
- [Best Practices](#best-practices)
|
||||
|
||||
## Basic Proxy Configuration
|
||||
|
||||
Use the `--proxy` flag or set proxy via environment variable:
|
||||
|
||||
```bash
|
||||
# Via CLI flag
|
||||
agent-browser --proxy "http://proxy.example.com:8080" open https://example.com
|
||||
|
||||
# Via environment variable
|
||||
export HTTP_PROXY="http://proxy.example.com:8080"
|
||||
agent-browser open https://example.com
|
||||
|
||||
# HTTPS proxy
|
||||
export HTTPS_PROXY="https://proxy.example.com:8080"
|
||||
agent-browser open https://example.com
|
||||
|
||||
# Both
|
||||
export HTTP_PROXY="http://proxy.example.com:8080"
|
||||
export HTTPS_PROXY="http://proxy.example.com:8080"
|
||||
agent-browser open https://example.com
|
||||
```
|
||||
|
||||
## Authenticated Proxy
|
||||
|
||||
For proxies requiring authentication:
|
||||
|
||||
```bash
|
||||
# Include credentials in URL
|
||||
export HTTP_PROXY="http://username:password@proxy.example.com:8080"
|
||||
agent-browser open https://example.com
|
||||
```
|
||||
|
||||
## SOCKS Proxy
|
||||
|
||||
```bash
|
||||
# SOCKS5 proxy
|
||||
export ALL_PROXY="socks5://proxy.example.com:1080"
|
||||
agent-browser open https://example.com
|
||||
|
||||
# SOCKS5 with auth
|
||||
export ALL_PROXY="socks5://user:pass@proxy.example.com:1080"
|
||||
agent-browser open https://example.com
|
||||
```
|
||||
|
||||
## Proxy Bypass
|
||||
|
||||
Skip proxy for specific domains using `--proxy-bypass` or `NO_PROXY`:
|
||||
|
||||
```bash
|
||||
# Via CLI flag
|
||||
agent-browser --proxy "http://proxy.example.com:8080" --proxy-bypass "localhost,*.internal.com" open https://example.com
|
||||
|
||||
# Via environment variable
|
||||
export NO_PROXY="localhost,127.0.0.1,.internal.company.com"
|
||||
agent-browser open https://internal.company.com # Direct connection
|
||||
agent-browser open https://external.com # Via proxy
|
||||
```
|
||||
|
||||
## Common Use Cases
|
||||
|
||||
### Geo-Location Testing
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# Test site from different regions using geo-located proxies
|
||||
|
||||
PROXIES=(
|
||||
"http://us-proxy.example.com:8080"
|
||||
"http://eu-proxy.example.com:8080"
|
||||
"http://asia-proxy.example.com:8080"
|
||||
)
|
||||
|
||||
for proxy in "${PROXIES[@]}"; do
|
||||
export HTTP_PROXY="$proxy"
|
||||
export HTTPS_PROXY="$proxy"
|
||||
|
||||
region=$(echo "$proxy" | grep -oP '^\w+-\w+')
|
||||
echo "Testing from: $region"
|
||||
|
||||
agent-browser --session "$region" open https://example.com
|
||||
agent-browser --session "$region" screenshot "./screenshots/$region.png"
|
||||
agent-browser --session "$region" close
|
||||
done
|
||||
```
|
||||
|
||||
### Rotating Proxies for Scraping
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# Rotate through proxy list to avoid rate limiting
|
||||
|
||||
PROXY_LIST=(
|
||||
"http://proxy1.example.com:8080"
|
||||
"http://proxy2.example.com:8080"
|
||||
"http://proxy3.example.com:8080"
|
||||
)
|
||||
|
||||
URLS=(
|
||||
"https://site.com/page1"
|
||||
"https://site.com/page2"
|
||||
"https://site.com/page3"
|
||||
)
|
||||
|
||||
for i in "${!URLS[@]}"; do
|
||||
proxy_index=$((i % ${#PROXY_LIST[@]}))
|
||||
export HTTP_PROXY="${PROXY_LIST[$proxy_index]}"
|
||||
export HTTPS_PROXY="${PROXY_LIST[$proxy_index]}"
|
||||
|
||||
agent-browser open "${URLS[$i]}"
|
||||
agent-browser get text body > "output-$i.txt"
|
||||
agent-browser close
|
||||
|
||||
sleep 1 # Polite delay
|
||||
done
|
||||
```
|
||||
|
||||
### Corporate Network Access
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# Access internal sites via corporate proxy
|
||||
|
||||
export HTTP_PROXY="http://corpproxy.company.com:8080"
|
||||
export HTTPS_PROXY="http://corpproxy.company.com:8080"
|
||||
export NO_PROXY="localhost,127.0.0.1,.company.com"
|
||||
|
||||
# External sites go through proxy
|
||||
agent-browser open https://external-vendor.com
|
||||
|
||||
# Internal sites bypass proxy
|
||||
agent-browser open https://intranet.company.com
|
||||
```
|
||||
|
||||
## Verifying Proxy Connection
|
||||
|
||||
```bash
|
||||
# Check your apparent IP
|
||||
agent-browser open https://httpbin.org/ip
|
||||
agent-browser get text body
|
||||
# Should show proxy's IP, not your real IP
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Proxy Connection Failed
|
||||
|
||||
```bash
|
||||
# Test proxy connectivity first
|
||||
curl -x http://proxy.example.com:8080 https://httpbin.org/ip
|
||||
|
||||
# Check if proxy requires auth
|
||||
export HTTP_PROXY="http://user:pass@proxy.example.com:8080"
|
||||
```
|
||||
|
||||
### SSL/TLS Errors Through Proxy
|
||||
|
||||
Some proxies perform SSL inspection. If you encounter certificate errors:
|
||||
|
||||
```bash
|
||||
# For testing only - not recommended for production
|
||||
agent-browser open https://example.com --ignore-https-errors
|
||||
```
|
||||
|
||||
### Slow Performance
|
||||
|
||||
```bash
|
||||
# Use proxy only when necessary
|
||||
export NO_PROXY="*.cdn.com,*.static.com" # Direct CDN access
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Use environment variables** - Don't hardcode proxy credentials
|
||||
2. **Set NO_PROXY appropriately** - Avoid routing local traffic through proxy
|
||||
3. **Test proxy before automation** - Verify connectivity with simple requests
|
||||
4. **Handle proxy failures gracefully** - Implement retry logic for unstable proxies
|
||||
5. **Rotate proxies for large scraping jobs** - Distribute load and avoid bans
|
||||
@@ -0,0 +1,193 @@
|
||||
# Session Management
|
||||
|
||||
Multiple isolated browser sessions with state persistence and concurrent browsing.
|
||||
|
||||
**Related**: [authentication.md](authentication.md) for login patterns, [SKILL.md](../SKILL.md) for quick start.
|
||||
|
||||
## Contents
|
||||
|
||||
- [Named Sessions](#named-sessions)
|
||||
- [Session Isolation Properties](#session-isolation-properties)
|
||||
- [Session State Persistence](#session-state-persistence)
|
||||
- [Common Patterns](#common-patterns)
|
||||
- [Default Session](#default-session)
|
||||
- [Session Cleanup](#session-cleanup)
|
||||
- [Best Practices](#best-practices)
|
||||
|
||||
## Named Sessions
|
||||
|
||||
Use `--session` flag to isolate browser contexts:
|
||||
|
||||
```bash
|
||||
# Session 1: Authentication flow
|
||||
agent-browser --session auth open https://app.example.com/login
|
||||
|
||||
# Session 2: Public browsing (separate cookies, storage)
|
||||
agent-browser --session public open https://example.com
|
||||
|
||||
# Commands are isolated by session
|
||||
agent-browser --session auth fill @e1 "user@example.com"
|
||||
agent-browser --session public get text body
|
||||
```
|
||||
|
||||
## Session Isolation Properties
|
||||
|
||||
Each session has independent:
|
||||
- Cookies
|
||||
- LocalStorage / SessionStorage
|
||||
- IndexedDB
|
||||
- Cache
|
||||
- Browsing history
|
||||
- Open tabs
|
||||
|
||||
## Session State Persistence
|
||||
|
||||
### Save Session State
|
||||
|
||||
```bash
|
||||
# Save cookies, storage, and auth state
|
||||
agent-browser state save /path/to/auth-state.json
|
||||
```
|
||||
|
||||
### Load Session State
|
||||
|
||||
```bash
|
||||
# Restore saved state
|
||||
agent-browser state load /path/to/auth-state.json
|
||||
|
||||
# Continue with authenticated session
|
||||
agent-browser open https://app.example.com/dashboard
|
||||
```
|
||||
|
||||
### State File Contents
|
||||
|
||||
```json
|
||||
{
|
||||
"cookies": [...],
|
||||
"localStorage": {...},
|
||||
"sessionStorage": {...},
|
||||
"origins": [...]
|
||||
}
|
||||
```
|
||||
|
||||
## Common Patterns
|
||||
|
||||
### Authenticated Session Reuse
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# Save login state once, reuse many times
|
||||
|
||||
STATE_FILE="/tmp/auth-state.json"
|
||||
|
||||
# Check if we have saved state
|
||||
if [[ -f "$STATE_FILE" ]]; then
|
||||
agent-browser state load "$STATE_FILE"
|
||||
agent-browser open https://app.example.com/dashboard
|
||||
else
|
||||
# Perform login
|
||||
agent-browser open https://app.example.com/login
|
||||
agent-browser snapshot -i
|
||||
agent-browser fill @e1 "$USERNAME"
|
||||
agent-browser fill @e2 "$PASSWORD"
|
||||
agent-browser click @e3
|
||||
agent-browser wait --load networkidle
|
||||
|
||||
# Save for future use
|
||||
agent-browser state save "$STATE_FILE"
|
||||
fi
|
||||
```
|
||||
|
||||
### Concurrent Scraping
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# Scrape multiple sites concurrently
|
||||
|
||||
# Start all sessions
|
||||
agent-browser --session site1 open https://site1.com &
|
||||
agent-browser --session site2 open https://site2.com &
|
||||
agent-browser --session site3 open https://site3.com &
|
||||
wait
|
||||
|
||||
# Extract from each
|
||||
agent-browser --session site1 get text body > site1.txt
|
||||
agent-browser --session site2 get text body > site2.txt
|
||||
agent-browser --session site3 get text body > site3.txt
|
||||
|
||||
# Cleanup
|
||||
agent-browser --session site1 close
|
||||
agent-browser --session site2 close
|
||||
agent-browser --session site3 close
|
||||
```
|
||||
|
||||
### A/B Testing Sessions
|
||||
|
||||
```bash
|
||||
# Test different user experiences
|
||||
agent-browser --session variant-a open "https://app.com?variant=a"
|
||||
agent-browser --session variant-b open "https://app.com?variant=b"
|
||||
|
||||
# Compare
|
||||
agent-browser --session variant-a screenshot /tmp/variant-a.png
|
||||
agent-browser --session variant-b screenshot /tmp/variant-b.png
|
||||
```
|
||||
|
||||
## Default Session
|
||||
|
||||
When `--session` is omitted, commands use the default session:
|
||||
|
||||
```bash
|
||||
# These use the same default session
|
||||
agent-browser open https://example.com
|
||||
agent-browser snapshot -i
|
||||
agent-browser close # Closes default session
|
||||
```
|
||||
|
||||
## Session Cleanup
|
||||
|
||||
```bash
|
||||
# Close specific session
|
||||
agent-browser --session auth close
|
||||
|
||||
# List active sessions
|
||||
agent-browser session list
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
### 1. Name Sessions Semantically
|
||||
|
||||
```bash
|
||||
# GOOD: Clear purpose
|
||||
agent-browser --session github-auth open https://github.com
|
||||
agent-browser --session docs-scrape open https://docs.example.com
|
||||
|
||||
# AVOID: Generic names
|
||||
agent-browser --session s1 open https://github.com
|
||||
```
|
||||
|
||||
### 2. Always Clean Up
|
||||
|
||||
```bash
|
||||
# Close sessions when done
|
||||
agent-browser --session auth close
|
||||
agent-browser --session scrape close
|
||||
```
|
||||
|
||||
### 3. Handle State Files Securely
|
||||
|
||||
```bash
|
||||
# Don't commit state files (contain auth tokens!)
|
||||
echo "*.auth-state.json" >> .gitignore
|
||||
|
||||
# Delete after use
|
||||
rm /tmp/auth-state.json
|
||||
```
|
||||
|
||||
### 4. Timeout Long Sessions
|
||||
|
||||
```bash
|
||||
# Set timeout for automated scripts
|
||||
timeout 60 agent-browser --session long-task get text body
|
||||
```
|
||||
@@ -0,0 +1,194 @@
|
||||
# Snapshot and Refs
|
||||
|
||||
Compact element references that reduce context usage dramatically for AI agents.
|
||||
|
||||
**Related**: [commands.md](commands.md) for full command reference, [SKILL.md](../SKILL.md) for quick start.
|
||||
|
||||
## Contents
|
||||
|
||||
- [How Refs Work](#how-refs-work)
|
||||
- [Snapshot Command](#the-snapshot-command)
|
||||
- [Using Refs](#using-refs)
|
||||
- [Ref Lifecycle](#ref-lifecycle)
|
||||
- [Best Practices](#best-practices)
|
||||
- [Ref Notation Details](#ref-notation-details)
|
||||
- [Troubleshooting](#troubleshooting)
|
||||
|
||||
## How Refs Work
|
||||
|
||||
Traditional approach:
|
||||
```
|
||||
Full DOM/HTML → AI parses → CSS selector → Action (~3000-5000 tokens)
|
||||
```
|
||||
|
||||
agent-browser approach:
|
||||
```
|
||||
Compact snapshot → @refs assigned → Direct interaction (~200-400 tokens)
|
||||
```
|
||||
|
||||
## The Snapshot Command
|
||||
|
||||
```bash
|
||||
# Basic snapshot (shows page structure)
|
||||
agent-browser snapshot
|
||||
|
||||
# Interactive snapshot (-i flag) - RECOMMENDED
|
||||
agent-browser snapshot -i
|
||||
```
|
||||
|
||||
### Snapshot Output Format
|
||||
|
||||
```
|
||||
Page: Example Site - Home
|
||||
URL: https://example.com
|
||||
|
||||
@e1 [header]
|
||||
@e2 [nav]
|
||||
@e3 [a] "Home"
|
||||
@e4 [a] "Products"
|
||||
@e5 [a] "About"
|
||||
@e6 [button] "Sign In"
|
||||
|
||||
@e7 [main]
|
||||
@e8 [h1] "Welcome"
|
||||
@e9 [form]
|
||||
@e10 [input type="email"] placeholder="Email"
|
||||
@e11 [input type="password"] placeholder="Password"
|
||||
@e12 [button type="submit"] "Log In"
|
||||
|
||||
@e13 [footer]
|
||||
@e14 [a] "Privacy Policy"
|
||||
```
|
||||
|
||||
## Using Refs
|
||||
|
||||
Once you have refs, interact directly:
|
||||
|
||||
```bash
|
||||
# Click the "Sign In" button
|
||||
agent-browser click @e6
|
||||
|
||||
# Fill email input
|
||||
agent-browser fill @e10 "user@example.com"
|
||||
|
||||
# Fill password
|
||||
agent-browser fill @e11 "password123"
|
||||
|
||||
# Submit the form
|
||||
agent-browser click @e12
|
||||
```
|
||||
|
||||
## Ref Lifecycle
|
||||
|
||||
**IMPORTANT**: Refs are invalidated when the page changes!
|
||||
|
||||
```bash
|
||||
# Get initial snapshot
|
||||
agent-browser snapshot -i
|
||||
# @e1 [button] "Next"
|
||||
|
||||
# Click triggers page change
|
||||
agent-browser click @e1
|
||||
|
||||
# MUST re-snapshot to get new refs!
|
||||
agent-browser snapshot -i
|
||||
# @e1 [h1] "Page 2" ← Different element now!
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
### 1. Always Snapshot Before Interacting
|
||||
|
||||
```bash
|
||||
# CORRECT
|
||||
agent-browser open https://example.com
|
||||
agent-browser snapshot -i # Get refs first
|
||||
agent-browser click @e1 # Use ref
|
||||
|
||||
# WRONG
|
||||
agent-browser open https://example.com
|
||||
agent-browser click @e1 # Ref doesn't exist yet!
|
||||
```
|
||||
|
||||
### 2. Re-Snapshot After Navigation
|
||||
|
||||
```bash
|
||||
agent-browser click @e5 # Navigates to new page
|
||||
agent-browser snapshot -i # Get new refs
|
||||
agent-browser click @e1 # Use new refs
|
||||
```
|
||||
|
||||
### 3. Re-Snapshot After Dynamic Changes
|
||||
|
||||
```bash
|
||||
agent-browser click @e1 # Opens dropdown
|
||||
agent-browser snapshot -i # See dropdown items
|
||||
agent-browser click @e7 # Select item
|
||||
```
|
||||
|
||||
### 4. Snapshot Specific Regions
|
||||
|
||||
For complex pages, snapshot specific areas:
|
||||
|
||||
```bash
|
||||
# Snapshot just the form
|
||||
agent-browser snapshot @e9
|
||||
```
|
||||
|
||||
## Ref Notation Details
|
||||
|
||||
```
|
||||
@e1 [tag type="value"] "text content" placeholder="hint"
|
||||
│ │ │ │ │
|
||||
│ │ │ │ └─ Additional attributes
|
||||
│ │ │ └─ Visible text
|
||||
│ │ └─ Key attributes shown
|
||||
│ └─ HTML tag name
|
||||
└─ Unique ref ID
|
||||
```
|
||||
|
||||
### Common Patterns
|
||||
|
||||
```
|
||||
@e1 [button] "Submit" # Button with text
|
||||
@e2 [input type="email"] # Email input
|
||||
@e3 [input type="password"] # Password input
|
||||
@e4 [a href="/page"] "Link Text" # Anchor link
|
||||
@e5 [select] # Dropdown
|
||||
@e6 [textarea] placeholder="Message" # Text area
|
||||
@e7 [div class="modal"] # Container (when relevant)
|
||||
@e8 [img alt="Logo"] # Image
|
||||
@e9 [checkbox] checked # Checked checkbox
|
||||
@e10 [radio] selected # Selected radio
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### "Ref not found" Error
|
||||
|
||||
```bash
|
||||
# Ref may have changed - re-snapshot
|
||||
agent-browser snapshot -i
|
||||
```
|
||||
|
||||
### Element Not Visible in Snapshot
|
||||
|
||||
```bash
|
||||
# Scroll down to reveal element
|
||||
agent-browser scroll down 1000
|
||||
agent-browser snapshot -i
|
||||
|
||||
# Or wait for dynamic content
|
||||
agent-browser wait 1000
|
||||
agent-browser snapshot -i
|
||||
```
|
||||
|
||||
### Too Many Elements
|
||||
|
||||
```bash
|
||||
# Snapshot specific container
|
||||
agent-browser snapshot @e5
|
||||
|
||||
# Or use get text for content-only extraction
|
||||
agent-browser get text @e5
|
||||
```
|
||||
@@ -0,0 +1,173 @@
|
||||
# Video Recording
|
||||
|
||||
Capture browser automation as video for debugging, documentation, or verification.
|
||||
|
||||
**Related**: [commands.md](commands.md) for full command reference, [SKILL.md](../SKILL.md) for quick start.
|
||||
|
||||
## Contents
|
||||
|
||||
- [Basic Recording](#basic-recording)
|
||||
- [Recording Commands](#recording-commands)
|
||||
- [Use Cases](#use-cases)
|
||||
- [Best Practices](#best-practices)
|
||||
- [Output Format](#output-format)
|
||||
- [Limitations](#limitations)
|
||||
|
||||
## Basic Recording
|
||||
|
||||
```bash
|
||||
# Start recording
|
||||
agent-browser record start ./demo.webm
|
||||
|
||||
# Perform actions
|
||||
agent-browser open https://example.com
|
||||
agent-browser snapshot -i
|
||||
agent-browser click @e1
|
||||
agent-browser fill @e2 "test input"
|
||||
|
||||
# Stop and save
|
||||
agent-browser record stop
|
||||
```
|
||||
|
||||
## Recording Commands
|
||||
|
||||
```bash
|
||||
# Start recording to file
|
||||
agent-browser record start ./output.webm
|
||||
|
||||
# Stop current recording
|
||||
agent-browser record stop
|
||||
|
||||
# Restart with new file (stops current + starts new)
|
||||
agent-browser record restart ./take2.webm
|
||||
```
|
||||
|
||||
## Use Cases
|
||||
|
||||
### Debugging Failed Automation
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# Record automation for debugging
|
||||
|
||||
agent-browser record start ./debug-$(date +%Y%m%d-%H%M%S).webm
|
||||
|
||||
# Run your automation
|
||||
agent-browser open https://app.example.com
|
||||
agent-browser snapshot -i
|
||||
agent-browser click @e1 || {
|
||||
echo "Click failed - check recording"
|
||||
agent-browser record stop
|
||||
exit 1
|
||||
}
|
||||
|
||||
agent-browser record stop
|
||||
```
|
||||
|
||||
### Documentation Generation
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# Record workflow for documentation
|
||||
|
||||
agent-browser record start ./docs/how-to-login.webm
|
||||
|
||||
agent-browser open https://app.example.com/login
|
||||
agent-browser wait 1000 # Pause for visibility
|
||||
|
||||
agent-browser snapshot -i
|
||||
agent-browser fill @e1 "demo@example.com"
|
||||
agent-browser wait 500
|
||||
|
||||
agent-browser fill @e2 "password"
|
||||
agent-browser wait 500
|
||||
|
||||
agent-browser click @e3
|
||||
agent-browser wait --load networkidle
|
||||
agent-browser wait 1000 # Show result
|
||||
|
||||
agent-browser record stop
|
||||
```
|
||||
|
||||
### CI/CD Test Evidence
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# Record E2E test runs for CI artifacts
|
||||
|
||||
TEST_NAME="${1:-e2e-test}"
|
||||
RECORDING_DIR="./test-recordings"
|
||||
mkdir -p "$RECORDING_DIR"
|
||||
|
||||
agent-browser record start "$RECORDING_DIR/$TEST_NAME-$(date +%s).webm"
|
||||
|
||||
# Run test
|
||||
if run_e2e_test; then
|
||||
echo "Test passed"
|
||||
else
|
||||
echo "Test failed - recording saved"
|
||||
fi
|
||||
|
||||
agent-browser record stop
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
### 1. Add Pauses for Clarity
|
||||
|
||||
```bash
|
||||
# Slow down for human viewing
|
||||
agent-browser click @e1
|
||||
agent-browser wait 500 # Let viewer see result
|
||||
```
|
||||
|
||||
### 2. Use Descriptive Filenames
|
||||
|
||||
```bash
|
||||
# Include context in filename
|
||||
agent-browser record start ./recordings/login-flow-2024-01-15.webm
|
||||
agent-browser record start ./recordings/checkout-test-run-42.webm
|
||||
```
|
||||
|
||||
### 3. Handle Recording in Error Cases
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
cleanup() {
|
||||
agent-browser record stop 2>/dev/null || true
|
||||
agent-browser close 2>/dev/null || true
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
agent-browser record start ./automation.webm
|
||||
# ... automation steps ...
|
||||
```
|
||||
|
||||
### 4. Combine with Screenshots
|
||||
|
||||
```bash
|
||||
# Record video AND capture key frames
|
||||
agent-browser record start ./flow.webm
|
||||
|
||||
agent-browser open https://example.com
|
||||
agent-browser screenshot ./screenshots/step1-homepage.png
|
||||
|
||||
agent-browser click @e1
|
||||
agent-browser screenshot ./screenshots/step2-after-click.png
|
||||
|
||||
agent-browser record stop
|
||||
```
|
||||
|
||||
## Output Format
|
||||
|
||||
- Default format: WebM (VP8/VP9 codec)
|
||||
- Compatible with all modern browsers and video players
|
||||
- Compressed but high quality
|
||||
|
||||
## Limitations
|
||||
|
||||
- Recording adds slight overhead to automation
|
||||
- Large recordings can consume significant disk space
|
||||
- Some headless environments may have codec limitations
|
||||
@@ -0,0 +1,105 @@
|
||||
#!/bin/bash
|
||||
# Template: Authenticated Session Workflow
|
||||
# Purpose: Login once, save state, reuse for subsequent runs
|
||||
# Usage: ./authenticated-session.sh <login-url> [state-file]
|
||||
#
|
||||
# RECOMMENDED: Use the auth vault instead of this template:
|
||||
# echo "<pass>" | agent-browser auth save myapp --url <login-url> --username <user> --password-stdin
|
||||
# agent-browser auth login myapp
|
||||
# The auth vault stores credentials securely and the LLM never sees passwords.
|
||||
#
|
||||
# Environment variables:
|
||||
# APP_USERNAME - Login username/email
|
||||
# APP_PASSWORD - Login password
|
||||
#
|
||||
# Two modes:
|
||||
# 1. Discovery mode (default): Shows form structure so you can identify refs
|
||||
# 2. Login mode: Performs actual login after you update the refs
|
||||
#
|
||||
# Setup steps:
|
||||
# 1. Run once to see form structure (discovery mode)
|
||||
# 2. Update refs in LOGIN FLOW section below
|
||||
# 3. Set APP_USERNAME and APP_PASSWORD
|
||||
# 4. Delete the DISCOVERY section
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
LOGIN_URL="${1:?Usage: $0 <login-url> [state-file]}"
|
||||
STATE_FILE="${2:-./auth-state.json}"
|
||||
|
||||
echo "Authentication workflow: $LOGIN_URL"
|
||||
|
||||
# ================================================================
|
||||
# SAVED STATE: Skip login if valid saved state exists
|
||||
# ================================================================
|
||||
if [[ -f "$STATE_FILE" ]]; then
|
||||
echo "Loading saved state from $STATE_FILE..."
|
||||
if agent-browser --state "$STATE_FILE" open "$LOGIN_URL" 2>/dev/null; then
|
||||
agent-browser wait --load networkidle
|
||||
|
||||
CURRENT_URL=$(agent-browser get url)
|
||||
if [[ "$CURRENT_URL" != *"login"* ]] && [[ "$CURRENT_URL" != *"signin"* ]]; then
|
||||
echo "Session restored successfully"
|
||||
agent-browser snapshot -i
|
||||
exit 0
|
||||
fi
|
||||
echo "Session expired, performing fresh login..."
|
||||
agent-browser close 2>/dev/null || true
|
||||
else
|
||||
echo "Failed to load state, re-authenticating..."
|
||||
fi
|
||||
rm -f "$STATE_FILE"
|
||||
fi
|
||||
|
||||
# ================================================================
|
||||
# DISCOVERY MODE: Shows form structure (delete after setup)
|
||||
# ================================================================
|
||||
echo "Opening login page..."
|
||||
agent-browser open "$LOGIN_URL"
|
||||
agent-browser wait --load networkidle
|
||||
|
||||
echo ""
|
||||
echo "Login form structure:"
|
||||
echo "---"
|
||||
agent-browser snapshot -i
|
||||
echo "---"
|
||||
echo ""
|
||||
echo "Next steps:"
|
||||
echo " 1. Note the refs: username=@e?, password=@e?, submit=@e?"
|
||||
echo " 2. Update the LOGIN FLOW section below with your refs"
|
||||
echo " 3. Set: export APP_USERNAME='...' APP_PASSWORD='...'"
|
||||
echo " 4. Delete this DISCOVERY MODE section"
|
||||
echo ""
|
||||
agent-browser close
|
||||
exit 0
|
||||
|
||||
# ================================================================
|
||||
# LOGIN FLOW: Uncomment and customize after discovery
|
||||
# ================================================================
|
||||
# : "${APP_USERNAME:?Set APP_USERNAME environment variable}"
|
||||
# : "${APP_PASSWORD:?Set APP_PASSWORD environment variable}"
|
||||
#
|
||||
# agent-browser open "$LOGIN_URL"
|
||||
# agent-browser wait --load networkidle
|
||||
# agent-browser snapshot -i
|
||||
#
|
||||
# # Fill credentials (update refs to match your form)
|
||||
# agent-browser fill @e1 "$APP_USERNAME"
|
||||
# agent-browser fill @e2 "$APP_PASSWORD"
|
||||
# agent-browser click @e3
|
||||
# agent-browser wait --load networkidle
|
||||
#
|
||||
# # Verify login succeeded
|
||||
# FINAL_URL=$(agent-browser get url)
|
||||
# if [[ "$FINAL_URL" == *"login"* ]] || [[ "$FINAL_URL" == *"signin"* ]]; then
|
||||
# echo "Login failed - still on login page"
|
||||
# agent-browser screenshot /tmp/login-failed.png
|
||||
# agent-browser close
|
||||
# exit 1
|
||||
# fi
|
||||
#
|
||||
# # Save state for future runs
|
||||
# echo "Saving state to $STATE_FILE"
|
||||
# agent-browser state save "$STATE_FILE"
|
||||
# echo "Login successful"
|
||||
# agent-browser snapshot -i
|
||||
@@ -0,0 +1,69 @@
|
||||
#!/bin/bash
|
||||
# Template: Content Capture Workflow
|
||||
# Purpose: Extract content from web pages (text, screenshots, PDF)
|
||||
# Usage: ./capture-workflow.sh <url> [output-dir]
|
||||
#
|
||||
# Outputs:
|
||||
# - page-full.png: Full page screenshot
|
||||
# - page-structure.txt: Page element structure with refs
|
||||
# - page-text.txt: All text content
|
||||
# - page.pdf: PDF version
|
||||
#
|
||||
# Optional: Load auth state for protected pages
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
TARGET_URL="${1:?Usage: $0 <url> [output-dir]}"
|
||||
OUTPUT_DIR="${2:-.}"
|
||||
|
||||
echo "Capturing: $TARGET_URL"
|
||||
mkdir -p "$OUTPUT_DIR"
|
||||
|
||||
# Optional: Load authentication state
|
||||
# if [[ -f "./auth-state.json" ]]; then
|
||||
# echo "Loading authentication state..."
|
||||
# agent-browser state load "./auth-state.json"
|
||||
# fi
|
||||
|
||||
# Navigate to target
|
||||
agent-browser open "$TARGET_URL"
|
||||
agent-browser wait --load networkidle
|
||||
|
||||
# Get metadata
|
||||
TITLE=$(agent-browser get title)
|
||||
URL=$(agent-browser get url)
|
||||
echo "Title: $TITLE"
|
||||
echo "URL: $URL"
|
||||
|
||||
# Capture full page screenshot
|
||||
agent-browser screenshot --full "$OUTPUT_DIR/page-full.png"
|
||||
echo "Saved: $OUTPUT_DIR/page-full.png"
|
||||
|
||||
# Get page structure with refs
|
||||
agent-browser snapshot -i > "$OUTPUT_DIR/page-structure.txt"
|
||||
echo "Saved: $OUTPUT_DIR/page-structure.txt"
|
||||
|
||||
# Extract all text content
|
||||
agent-browser get text body > "$OUTPUT_DIR/page-text.txt"
|
||||
echo "Saved: $OUTPUT_DIR/page-text.txt"
|
||||
|
||||
# Save as PDF
|
||||
agent-browser pdf "$OUTPUT_DIR/page.pdf"
|
||||
echo "Saved: $OUTPUT_DIR/page.pdf"
|
||||
|
||||
# Optional: Extract specific elements using refs from structure
|
||||
# agent-browser get text @e5 > "$OUTPUT_DIR/main-content.txt"
|
||||
|
||||
# Optional: Handle infinite scroll pages
|
||||
# for i in {1..5}; do
|
||||
# agent-browser scroll down 1000
|
||||
# agent-browser wait 1000
|
||||
# done
|
||||
# agent-browser screenshot --full "$OUTPUT_DIR/page-scrolled.png"
|
||||
|
||||
# Cleanup
|
||||
agent-browser close
|
||||
|
||||
echo ""
|
||||
echo "Capture complete:"
|
||||
ls -la "$OUTPUT_DIR"
|
||||
@@ -0,0 +1,62 @@
|
||||
#!/bin/bash
|
||||
# Template: Form Automation Workflow
|
||||
# Purpose: Fill and submit web forms with validation
|
||||
# Usage: ./form-automation.sh <form-url>
|
||||
#
|
||||
# This template demonstrates the snapshot-interact-verify pattern:
|
||||
# 1. Navigate to form
|
||||
# 2. Snapshot to get element refs
|
||||
# 3. Fill fields using refs
|
||||
# 4. Submit and verify result
|
||||
#
|
||||
# Customize: Update the refs (@e1, @e2, etc.) based on your form's snapshot output
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
FORM_URL="${1:?Usage: $0 <form-url>}"
|
||||
|
||||
echo "Form automation: $FORM_URL"
|
||||
|
||||
# Step 1: Navigate to form
|
||||
agent-browser open "$FORM_URL"
|
||||
agent-browser wait --load networkidle
|
||||
|
||||
# Step 2: Snapshot to discover form elements
|
||||
echo ""
|
||||
echo "Form structure:"
|
||||
agent-browser snapshot -i
|
||||
|
||||
# Step 3: Fill form fields (customize these refs based on snapshot output)
|
||||
#
|
||||
# Common field types:
|
||||
# agent-browser fill @e1 "John Doe" # Text input
|
||||
# agent-browser fill @e2 "user@example.com" # Email input
|
||||
# agent-browser fill @e3 "SecureP@ss123" # Password input
|
||||
# agent-browser select @e4 "Option Value" # Dropdown
|
||||
# agent-browser check @e5 # Checkbox
|
||||
# agent-browser click @e6 # Radio button
|
||||
# agent-browser fill @e7 "Multi-line text" # Textarea
|
||||
# agent-browser upload @e8 /path/to/file.pdf # File upload
|
||||
#
|
||||
# Uncomment and modify:
|
||||
# agent-browser fill @e1 "Test User"
|
||||
# agent-browser fill @e2 "test@example.com"
|
||||
# agent-browser click @e3 # Submit button
|
||||
|
||||
# Step 4: Wait for submission
|
||||
# agent-browser wait --load networkidle
|
||||
# agent-browser wait --url "**/success" # Or wait for redirect
|
||||
|
||||
# Step 5: Verify result
|
||||
echo ""
|
||||
echo "Result:"
|
||||
agent-browser get url
|
||||
agent-browser snapshot -i
|
||||
|
||||
# Optional: Capture evidence
|
||||
agent-browser screenshot /tmp/form-result.png
|
||||
echo "Screenshot saved: /tmp/form-result.png"
|
||||
|
||||
# Cleanup
|
||||
agent-browser close
|
||||
echo "Done"
|
||||
@@ -0,0 +1,557 @@
|
||||
---
|
||||
name: AI Rankings Leaderboard
|
||||
display_name: AI Rankings Leaderboard / AI 排行榜
|
||||
description: Comprehensive AI leaderboard for LLM models and AI applications. Query model rankings, model IDs, and pricing from OpenRouter, Artificial Analysis, and Pinchbench. Trigger words include "AI rankings", "LLM leaderboard", "model comparison", "AI apps ranking", "best AI models", "model benchmark", "free models", "免费模型", "OpenRouter model ID", "OpenRouter 模型", "Artificial Analysis", "artificial analysis", "AI 智力指数", "intelligence index", "coding index", "coding排行榜", "agentic index", "agentic排行榜", "模型速度排行", "模型价格对比", "model ID for", "OpenRouter model parameter".
|
||||
version: 1.20.1
|
||||
cli_dependencies:
|
||||
- agent-browser
|
||||
---
|
||||
|
||||
# AI Rankings Leaderboard Skill
|
||||
|
||||
## Description
|
||||
|
||||
A comprehensive skill for querying AI model and application rankings from multiple authoritative sources. Get the latest insights on LLM performance, popularity, pricing, and value metrics.
|
||||
|
||||
## Data Sources
|
||||
|
||||
| Source | URL | Focus |
|
||||
|--------|-----|-------|
|
||||
| **Artificial Analysis** | https://artificialanalysis.ai/ | Intelligence Index, Speed, Price benchmarks |
|
||||
| LLM Leaderboard | https://artificialanalysis.ai/leaderboards/models | Model comparison (100+ models) |
|
||||
| LLM API Providers | https://artificialanalysis.ai/leaderboards/providers | API Provider comparison (500+ endpoints) |
|
||||
| Image & Video Leaderboards | https://artificialanalysis.ai/ (Image & Video section) | Image/Video model ELO rankings |
|
||||
| OpenRouter Rankings | https://openrouter.ai/rankings | Model usage & popularity |
|
||||
| OpenRouter Apps | https://openrouter.ai/apps | AI applications ranking |
|
||||
| OpenRouter Models | https://openrouter.ai/models | All available models with pricing |
|
||||
| OpenRouter Free Models | https://openrouter.ai/models?q=free | Free models only |
|
||||
| Pinchbench | https://pinchbench.com/ | Model benchmark (Success Rate, Speed, Cost, Value) |
|
||||
|
||||
## Features
|
||||
|
||||
### 1. Artificial Analysis LLM Leaderboard
|
||||
|
||||
**Intelligence Index (智力指数)**
|
||||
- **Artificial Analysis Intelligence Index v4.0**: Comprehensive model intelligence score
|
||||
- **10 evaluation dimensions**: Multiple independent assessment criteria
|
||||
- **Frontier Models**: Top intelligence models (Gemini 3.1 Pro, GPT-5.4, Claude Opus 4.6, etc.)
|
||||
- **Reasoning Models**: Identifies models with reasoning capabilities
|
||||
|
||||
**Artificial Analysis Coding Index** (编程能力指数)
|
||||
- URL: https://artificialanalysis.ai/?intelligence=coding-index
|
||||
- 评估模型在编程任务上的表现
|
||||
- 综合多个代码评测基准
|
||||
|
||||
**Artificial Analysis Agentic Index** (智能体能力指数)
|
||||
- URL: https://artificialanalysis.ai/?intelligence=agentic-index
|
||||
- 评估模型的自主智能体能力
|
||||
- 包括工具使用、多步骤推理、任务完成等
|
||||
|
||||
**Performance Metrics**
|
||||
| Metric | Description |
|
||||
|--------|-------------|
|
||||
| Intelligence Index | Overall model intelligence score (higher is better) |
|
||||
| Speed | Output tokens per second (tokens/s) |
|
||||
| Blended Price | Combined USD per million tokens (3:1 input/output ratio) |
|
||||
| Input Price | Price per million input tokens (USD) |
|
||||
| Output Price | Price per million output tokens (USD) |
|
||||
| Latency (TTFT) | Time to First Token in seconds |
|
||||
| Context Window | Maximum context length supported |
|
||||
|
||||
**Model Comparison Table Columns**
|
||||
| Column | Description |
|
||||
|--------|-------------|
|
||||
| Features | Model features (reasoning badge, etc.) |
|
||||
| Model | Model name with logo |
|
||||
| Context Window | Max context length |
|
||||
| Creator | Provider/Company |
|
||||
| Intelligence Index | AI intelligence score |
|
||||
| Blended USD/1M Tokens | Combined input/output price |
|
||||
| Median Tokens/s | Median output speed |
|
||||
| Latency First Chunk (s) | Time to first token |
|
||||
| Further Analysis | Link to detailed analysis |
|
||||
|
||||
**Filters Available**
|
||||
| Filter | Options |
|
||||
|--------|---------|
|
||||
| Frontier Models | On/Off |
|
||||
| Open Weights | On/Off (开源权重模型) |
|
||||
| Size Class | Small, Medium, Large, etc. |
|
||||
| Reasoning | On/Off (推理模型筛选) |
|
||||
| Model Status | Current, Preview, Discontinued |
|
||||
|
||||
### 2. Artificial Analysis LLM API Providers Leaderboard
|
||||
|
||||
**Comparison of 500+ AI Model Endpoints**
|
||||
|
||||
| Column | Description |
|
||||
|--------|-------------|
|
||||
| API Provider | Provider name (Cerebras, Groq, Fireworks, etc.) |
|
||||
| Model | Model name |
|
||||
| Context Window | Max context length |
|
||||
| License | Model license |
|
||||
| Intelligence Index | Model intelligence score |
|
||||
| Blended USD/1M Tokens | Combined price |
|
||||
| Median Tokens/s | Output speed |
|
||||
| Median First Chunk (s) | Latency (TTFT) |
|
||||
| Total Response (s) | End-to-end response time |
|
||||
| Reasoning Time (s) | Reasoning model computation time |
|
||||
| End-to-End Response Time | Full request-response cycle |
|
||||
|
||||
**Key Providers**
|
||||
- Cerebras
|
||||
- Eigen AI
|
||||
- Fireworks
|
||||
- SambaNova
|
||||
- Together.ai
|
||||
- Hyperbolic
|
||||
- Nebius Fast
|
||||
- Google Vertex
|
||||
- Groq
|
||||
- Azure OpenAI
|
||||
- AWS Bedrock
|
||||
- OpenAI Direct
|
||||
- Anthropic Direct
|
||||
- And 10+ more...
|
||||
|
||||
### 3. Artificial Analysis Image & Video Leaderboards
|
||||
|
||||
**Text-to-Image Leaderboard**
|
||||
- ELO scores from blind preference votes
|
||||
- 95% confidence intervals displayed
|
||||
- Top models: GPT Image 1.5, Imagen 4 Ultra, Gemini Image models, etc.
|
||||
|
||||
**Video Leaderboards**
|
||||
| Category | Description |
|
||||
|----------|-------------|
|
||||
| Text to Video (with Audio) | Text generates video with sound |
|
||||
| Text to Video (without Audio) | Text generates silent video |
|
||||
| Image to Video (with Audio) | Image + text generates video with sound |
|
||||
| Image to Video (without Audio) | Image + text generates silent video |
|
||||
| Image Editing | Edit existing images with AI |
|
||||
|
||||
**Evaluation Method**
|
||||
- ELO scoring system (blind preference voting)
|
||||
- 95% confidence intervals
|
||||
- Real user preference data
|
||||
|
||||
### 4. OpenRouter Model Rankings
|
||||
- **LLM Leaderboard**: Overall model usage rankings
|
||||
- **Market Share**: Market share by model provider
|
||||
- **Categories**: Rankings by use case
|
||||
- **Languages**: Natural language support rankings
|
||||
- **Programming**: Programming language support
|
||||
- **Context Length**: Long context handling
|
||||
- **Tool Calls**: Tool calling capabilities
|
||||
- **Images**: Image processing volume
|
||||
|
||||
### 5. OpenRouter App Rankings
|
||||
- **Most Popular**: Top apps by token usage
|
||||
- **Trending**: Fastest growing apps this week
|
||||
- **Categories**: Coding Agents, Productivity, Creative, Entertainment
|
||||
|
||||
### 6. OpenRouter Model Catalog
|
||||
- **All Models**: Complete list of available models on OpenRouter
|
||||
- **Free Models**: Models with $0 pricing (free to use)
|
||||
- **Model ID**: The exact `model` parameter to use when calling OpenRouter API
|
||||
- **Pricing Info**: Input/output token pricing
|
||||
|
||||
### 7. Pinchbench Benchmarks
|
||||
- **Success Rate**: Task completion success percentage
|
||||
- **Speed**: Response time performance
|
||||
- **Cost**: Cost per run analysis
|
||||
- **Value**: Price-performance ratio
|
||||
|
||||
## Trigger Keywords
|
||||
|
||||
### General AI Rankings
|
||||
- "AI rankings" / "AI 排行榜"
|
||||
- "LLM leaderboard" / "LLM 排行"
|
||||
- "model comparison" / "模型对比"
|
||||
- "best AI models" / "最好的 AI 模型"
|
||||
- "AI apps ranking" / "AI 应用排行"
|
||||
- "model benchmark" / "模型评测"
|
||||
|
||||
### Artificial Analysis Specific
|
||||
- "Artificial Analysis" / "artificialanalysis"
|
||||
- "AI intelligence index" / "AI 智力指数"
|
||||
- "intelligence index" / "智力指数"
|
||||
- "模型速度排行" / "speed ranking"
|
||||
- "模型价格对比" / "price comparison"
|
||||
- "fastest models" / "最快模型"
|
||||
- "cheapest models" / "最便宜模型"
|
||||
- "tokens per second" / "t/s" / "tokens/s"
|
||||
- "latency" / "TTFT" / "首 token 延迟"
|
||||
- "Artificial Analysis Intelligence Index"
|
||||
- "AAII" / "AA Intelligence"
|
||||
- "API providers" / "API 提供商"
|
||||
- "LLM providers" / "LLM 提供商"
|
||||
- "Cerebras" / "Groq" / "Fireworks"
|
||||
- "open weights" / "开源权重"
|
||||
- "reasoning models" / "推理模型"
|
||||
- "elo score" / "ELO 评分"
|
||||
- "image arena" / "图生图"
|
||||
- "text to image" / "文生图"
|
||||
- "text to video" / "文生视频"
|
||||
- "image to video" / "图生视频"
|
||||
|
||||
### OpenRouter Specific
|
||||
- "free models" / "免费模型" / "free AI models"
|
||||
- "OpenRouter models" / "OpenRouter 免费模型"
|
||||
- "OpenRouter rankings" / "OpenRouter 排行"
|
||||
- "Pinchbench"
|
||||
- "OpenRouter model ID" / "OpenRouter 模型 ID"
|
||||
- "查找 OpenRouter" / "OpenRouter 上的模型"
|
||||
- "model ID for [模型名]" / "[模型名] model ID"
|
||||
- "OpenRouter 上 [模型名]" / "OpenRouter [模型名] 模型"
|
||||
- "OpenRouter model parameter"
|
||||
- "调用量排行" / "使用量排行" / "top models" / "top 模型"
|
||||
- "OpenRouter 调用量" / "OpenRouter 使用量"
|
||||
|
||||
## Runtime Tools
|
||||
|
||||
This skill requires:
|
||||
- `execute_command`: Execute shell commands and scripts
|
||||
- `use_skill`: Load browser-automation skill for JavaScript-rendered pages
|
||||
- `web_fetch`: Fallback for simple HTTP requests
|
||||
|
||||
## Installation
|
||||
|
||||
**Required CLI Dependency**: `agent-browser`
|
||||
|
||||
The `agent-browser` CLI must be installed before using this skill. Install via:
|
||||
|
||||
```bash
|
||||
npm install -g agent-browser
|
||||
# or
|
||||
npx agent-browser --version
|
||||
```
|
||||
|
||||
This skill calls `agent-browser` via subprocess with hardcoded argument arrays (no shell injection risk).
|
||||
|
||||
**Note on browser eval**: The `agent-browser eval` command executes `document.body.innerText` or similar DOM queries on the remote page to extract rendered content. This is standard web scraping behavior for JavaScript-rendered pages and is limited to reading page content only.
|
||||
|
||||
## Browser Automation Support
|
||||
|
||||
For JavaScript-rendered pages (OpenRouter Rankings, Artificial Analysis), this skill uses browser automation:
|
||||
|
||||
1. **Load browser-automation skill first**:
|
||||
```
|
||||
use_skill("browser-automation")
|
||||
```
|
||||
|
||||
2. **Navigate to rankings page**:
|
||||
```bash
|
||||
agent-browser open "https://artificialanalysis.ai/leaderboards/models"
|
||||
agent-browser wait --load networkidle
|
||||
agent-browser eval "document.body.innerText"
|
||||
```
|
||||
|
||||
3. **Key pages requiring browser**:
|
||||
- `https://artificialanalysis.ai/leaderboards/models` - LLM comparison (100+ models)
|
||||
- `https://artificialanalysis.ai/leaderboards/providers` - API providers (500+ endpoints)
|
||||
- `https://artificialanalysis.ai/` - Image & Video leaderboards
|
||||
- `https://openrouter.ai/rankings` - Model usage rankings (JS rendered)
|
||||
- `https://openrouter.ai/apps` - App rankings (JS rendered)
|
||||
|
||||
### Artificial Analysis Page Structure
|
||||
|
||||
**LLM Leaderboard Page** (`/leaderboards/models`):
|
||||
```
|
||||
LLM Leaderboard - Comparison of over 100 AI models
|
||||
├── HIGHLIGHTS section
|
||||
│ ├── Intelligence: Gemini 3.1 Pro Preview, GPT-5.4 (xhigh)
|
||||
│ ├── Speed: Mercury 2 (943 t/s), NVIDIA Nemotron 3 Super (462 t/s)
|
||||
│ └── Price: Gemma 3n E4B (cheapest)
|
||||
├── Filters:
|
||||
│ ├── Frontier Models | Open Weights | Size Class | Reasoning | Model Status
|
||||
├── Comparison table columns:
|
||||
│ ├── Features | Model | Context Window | Creator
|
||||
│ ├── Intelligence Index | Blended USD/1M | Median Tokens/s | Latency
|
||||
│ └── Further Analysis
|
||||
└── Key definitions (expandable)
|
||||
├── Context window
|
||||
├── Output Speed (tokens/s)
|
||||
├── Latency (Time to First Token)
|
||||
├── Price (3:1 blended)
|
||||
├── Output Price
|
||||
└── Input Price
|
||||
```
|
||||
|
||||
**LLM API Providers Page** (`/leaderboards/providers`):
|
||||
```
|
||||
LLM API Providers Leaderboard - 500+ endpoints
|
||||
├── Filters (same as LLM Leaderboard)
|
||||
├── Comparison table columns:
|
||||
│ ├── API Provider | Model | Context Window | License
|
||||
│ ├── Intelligence Index | Blended USD/1M | Median Tokens/s
|
||||
│ ├── Median First Chunk (s) | Total Response (s) | Reasoning Time (s)
|
||||
│ └── Further Analysis
|
||||
└── 24+ Providers: Cerebras, Groq, Fireworks, SambaNova, etc.
|
||||
```
|
||||
|
||||
**Image & Video Leaderboards** (on homepage):
|
||||
```
|
||||
Image & Video Leaderboards
|
||||
├── Tabs:
|
||||
│ ├── Text to Image (ELO scores, 95% CI)
|
||||
│ ├── Image Editing
|
||||
│ ├── Text to Video (with Audio)
|
||||
│ ├── Text to Video (without Audio)
|
||||
│ ├── Image to Video (with Audio)
|
||||
│ └── Image to Video (without Audio)
|
||||
└── Top models with ELO rankings
|
||||
```
|
||||
|
||||
### OpenRouter Page Structure (Reminder)
|
||||
|
||||
**OpenRouter Rankings Page** (`/rankings`):
|
||||
```
|
||||
https://openrouter.ai/rankings
|
||||
├── Top Models (chart header)
|
||||
├── LLM Leaderboard ← THIS is the usage ranking (parse this!)
|
||||
│ ├── 1. MiniMax M2.5 (1.75T tokens)
|
||||
│ ├── 2. Step 3.5 Flash (1.34T tokens)
|
||||
│ └── [Show more] button
|
||||
├── Market Share (different metric - don't mix!)
|
||||
└── ...
|
||||
```
|
||||
|
||||
## Usage Examples
|
||||
|
||||
### Query Artificial Analysis Intelligence Index
|
||||
```
|
||||
User: "What are the top models on Artificial Analysis Intelligence Index?"
|
||||
-> Fetches Artificial Analysis LLM Leaderboard and displays top models by intelligence
|
||||
```
|
||||
|
||||
### Query Model Speed Rankings
|
||||
```
|
||||
User: "Which AI models are the fastest in terms of output speed?"
|
||||
-> Fetches Artificial Analysis data and lists models by tokens/second
|
||||
```
|
||||
|
||||
### Query API Providers
|
||||
```
|
||||
User: "Compare LLM API providers like Cerebras and Groq"
|
||||
-> Fetches Artificial Analysis Providers Leaderboard and compares speed/price
|
||||
```
|
||||
|
||||
### Query Image/Video Models
|
||||
```
|
||||
User: "What are the best text-to-image models?"
|
||||
-> Fetches Artificial Analysis Image Arena leaderboard with ELO scores
|
||||
```
|
||||
|
||||
### Query Model Rankings (OpenRouter)
|
||||
```
|
||||
User: "What are the top 10 AI models right now?"
|
||||
-> Fetches OpenRouter rankings and displays top models with usage stats
|
||||
```
|
||||
|
||||
### Query Free Models
|
||||
```
|
||||
User: "What free models are available on OpenRouter?"
|
||||
-> Fetches https://openrouter.ai/models?q=free and lists all free models with their model IDs
|
||||
```
|
||||
|
||||
### Get Model ID for API Calls
|
||||
```
|
||||
User: "What's the model ID for GPT-4o on OpenRouter?"
|
||||
-> Fetches https://openrouter.ai/models and returns the exact model parameter to use
|
||||
```
|
||||
|
||||
### Compare Model Performance
|
||||
```
|
||||
User: "Compare GPT-4 and Claude on Pinchbench"
|
||||
-> Fetches Pinchbench data and compares success rate, speed, cost
|
||||
```
|
||||
|
||||
## Output Format
|
||||
|
||||
### Artificial Analysis Intelligence Index
|
||||
```
|
||||
==================================================
|
||||
Artificial Analysis Intelligence Index
|
||||
==================================================
|
||||
|
||||
Top 10 Models by Intelligence:
|
||||
|
||||
| Rank | Model | Intelligence | Speed (t/s) | Price ($/M) |
|
||||
|------|-------|--------------|-------------|-------------|
|
||||
| 1 | Gemini 3.1 Pro Preview | 57 | ~50 | $1.25 |
|
||||
| 2 | GPT-5.4 (xhigh) | 57 | ~60 | $15.00 |
|
||||
| 3 | Claude Opus 4.6 (max) | 53 | ~80 | $18.00 |
|
||||
| 4 | Claude Sonnet 4.6 (max) | 52 | ~85 | $4.50 |
|
||||
| 5 | GLM-5 | 50 | ~45 | $0.50 |
|
||||
...
|
||||
|
||||
Fastest Models: Mercury 2 (943 t/s), NVIDIA Nemotron 3 Super (462 t/s)
|
||||
Best Price: Gemma 3n E4B, Granite 4.0 H Small
|
||||
|
||||
Data Source: Artificial Analysis (artificialanalysis.ai)
|
||||
==================================================
|
||||
```
|
||||
|
||||
### API Providers Comparison
|
||||
```
|
||||
==================================================
|
||||
LLM API Providers Leaderboard
|
||||
==================================================
|
||||
|
||||
| Provider | Model | Speed (t/s) | Price ($/M) | Latency (s) |
|
||||
|----------|-------|-------------|-------------|-------------|
|
||||
| Cerebras | Llama 3.1 70B | 2143 | $0.12 | 0.08 |
|
||||
| Groq | Llama 3.1 70B | 943 | $0.59 | 0.15 |
|
||||
| Fireworks | Llama 3.1 70B | 562 | $0.90 | 0.22 |
|
||||
...
|
||||
|
||||
Data Source: Artificial Analysis Providers
|
||||
==================================================
|
||||
```
|
||||
|
||||
### Image Arena (ELO Rankings)
|
||||
```
|
||||
==================================================
|
||||
Text-to-Image Leaderboard (ELO)
|
||||
==================================================
|
||||
|
||||
| Rank | Model | ELO Score | 95% CI |
|
||||
|------|-------|-----------|--------|
|
||||
| 1 | GPT Image 1.5 (high) | 1342 | ±12 |
|
||||
| 2 | Imagen 4 Ultra | 1289 | ±15 |
|
||||
| 3 | Gemini 3.1 Flash Image | 1245 | ±18 |
|
||||
...
|
||||
|
||||
Data Source: Artificial Analysis Image Arena
|
||||
==================================================
|
||||
```
|
||||
|
||||
### OpenRouter Model Rankings
|
||||
```
|
||||
==================================================
|
||||
AI Model Rankings (OpenRouter)
|
||||
==================================================
|
||||
|
||||
Top 10 Models by Usage:
|
||||
|
||||
| Rank | Model | Provider | Tokens | Growth |
|
||||
|------|-------|----------|--------|--------|
|
||||
| 1 | MiniMax M2.5 | minimax | 1.75T | +15% |
|
||||
| 2 | Step 3.5 Flash | step | 1.34T | +22% |
|
||||
...
|
||||
|
||||
Data Source: OpenRouter (Weekly Rankings)
|
||||
==================================================
|
||||
```
|
||||
|
||||
### Free Models List
|
||||
```
|
||||
==================================================
|
||||
Free Models on OpenRouter
|
||||
==================================================
|
||||
|
||||
| Model Name | Model ID (for API) | Context |
|
||||
|------------|-------------------|---------|
|
||||
| GPT-4o Mini | openai/gpt-4o-mini | 128K |
|
||||
| Llama 3.3 70B | meta-llama/llama-3.3-70b-instruct | 128K |
|
||||
| DeepSeek V3 | deepseek/deepseek-chat | 64K |
|
||||
...
|
||||
|
||||
💡 Usage: Set model parameter to the Model ID value
|
||||
Example: model="openai/gpt-4o-mini"
|
||||
|
||||
Data Source: OpenRouter Models
|
||||
==================================================
|
||||
```
|
||||
|
||||
## Execution Instructions
|
||||
|
||||
### Method 1: Browser Automation for Rankings (Recommended)
|
||||
|
||||
Artificial Analysis and OpenRouter rankings pages require JavaScript rendering:
|
||||
|
||||
```bash
|
||||
# Step 1: Load browser-automation skill (REQUIRED)
|
||||
use_skill("browser-automation")
|
||||
|
||||
# Step 2: Navigate to Artificial Analysis LLM Leaderboard
|
||||
agent-browser open "https://artificialanalysis.ai/leaderboards/models"
|
||||
agent-browser wait --load networkidle
|
||||
|
||||
# Step 3: Wait for content to load, then extract
|
||||
agent-browser wait 3000
|
||||
agent-browser eval "document.body.innerText"
|
||||
|
||||
# Step 4: Close browser when done
|
||||
agent-browser close
|
||||
```
|
||||
|
||||
### Method 2: Python Script for OpenRouter Model Catalog
|
||||
|
||||
Use the `query_leaderboard.py` script to fetch model data via OpenRouter API (no JavaScript needed):
|
||||
|
||||
```bash
|
||||
# List free models
|
||||
python3 "${SKILL_DIR}/query_leaderboard.py --free"
|
||||
|
||||
# Search models by name
|
||||
python3 "${SKILL_DIR}/query_leaderboard.py -s glm"
|
||||
python3 "${SKILL_DIR}/query_leaderboard.py -s gpt"
|
||||
|
||||
# Get specific model info
|
||||
python3 "${SKILL_DIR}/query_leaderboard.py --id openai/gpt-4o"
|
||||
|
||||
# List all models with limit
|
||||
python3 "${SKILL_DIR}/query_leaderboard.py --all --limit 50"
|
||||
```
|
||||
|
||||
### Method 3: Web Fetch (Fallback)
|
||||
|
||||
When browser/Python is not available, use `web_fetch`:
|
||||
|
||||
1. **For Artificial Analysis**: Fetch `https://artificialanalysis.ai/leaderboards/models`
|
||||
2. **For OpenRouter model catalog**: Use OpenRouter API `https://openrouter.ai/api/v1/models`
|
||||
3. **For benchmarks**: Fetch `https://pinchbench.com/`
|
||||
|
||||
**Note**: Rankings pages require JavaScript rendering - use browser automation (Method 1).
|
||||
|
||||
## Notes
|
||||
|
||||
- Data is updated regularly (Artificial Analysis, OpenRouter weekly, Pinchbench near real-time)
|
||||
- Artificial Analysis Intelligence Index is based on 10 independent evaluations
|
||||
- ELO scores are from blind preference voting with 95% confidence intervals
|
||||
- Pinchbench disclaimer: "For entertainment purposes only, should not be relied upon for critical decisions"
|
||||
- Rankings reflect actual usage data from millions of users
|
||||
- Free models have $0.00 pricing on OpenRouter
|
||||
- **Model ID format**: Use the exact string (e.g., `openai/gpt-4o-mini`) as the `model` parameter in API calls
|
||||
|
||||
## Artificial Analysis API Patterns
|
||||
|
||||
Based on observed page structure, Artificial Analysis provides:
|
||||
- **Model comparison data**: https://artificialanalysis.ai/leaderboards/models
|
||||
- **Provider comparison**: https://artificialanalysis.ai/leaderboards/providers
|
||||
- **Image/Video arenas**: Embedded on homepage with tab navigation
|
||||
- **Model-specific provider data**: `/models/{model-id}/providers` endpoint pattern
|
||||
|
||||
**Example model providers API**:
|
||||
```
|
||||
/models/gpt-oss-120b/providers
|
||||
/models/gemini-3-1-pro-preview/providers
|
||||
/models/claude-opus-4-6-adaptive/providers
|
||||
```
|
||||
|
||||
## OpenRouter API Usage
|
||||
|
||||
When calling OpenRouter API (for chat completions), use the Model ID. Note: This skill's scripts (fetch_rankings.py, query_leaderboard.py) only read public leaderboard data and do NOT require API authentication.
|
||||
|
||||
```bash
|
||||
curl https://openrouter.ai/api/v1/chat/completions \
|
||||
-H "Authorization: Bearer $OPENROUTER_API_KEY" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"model": "openai/gpt-4o-mini", # <- Model ID from this skill
|
||||
"messages": [{"role": "user", "content": "Hello"}]
|
||||
}'
|
||||
```
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"owner": "luduoxin",
|
||||
"slug": "ai-leaderboard",
|
||||
"displayName": "AI Leaderboard",
|
||||
"latest": {
|
||||
"version": "1.20.1",
|
||||
"publishedAt": 1773899776856,
|
||||
"commit": "https://github.com/openclaw/skills/commit/e90ea1091419a452a42a914ca55873998276949d"
|
||||
},
|
||||
"history": [
|
||||
{
|
||||
"version": "1.7.0",
|
||||
"publishedAt": 1773658665884,
|
||||
"commit": "https://github.com/openclaw/skills/commit/9625262ee2b8746d2a7f54c9587a3ac0a25a9452"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,644 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Fetch AI Rankings via Browser Automation
|
||||
|
||||
This script uses agent-browser CLI to fetch JavaScript-rendered content
|
||||
from AI rankings pages including Artificial Analysis and OpenRouter.
|
||||
|
||||
Requirements:
|
||||
- agent-browser CLI installed
|
||||
- Run after loading browser-automation skill
|
||||
|
||||
Usage:
|
||||
python3 fetch_rankings.py # Get Artificial Analysis LLM Leaderboard
|
||||
python3 fetch_rankings.py --aa-intelligence # Get Intelligence Index rankings
|
||||
python3 fetch_rankings.py --aa-coding # Get Coding Index rankings
|
||||
python3 fetch_rankings.py --aa-agentic # Get Agentic Index rankings
|
||||
python3 fetch_rankings.py --aa-providers # Get API Providers rankings
|
||||
python3 fetch_rankings.py --openrouter # Get OpenRouter rankings
|
||||
python3 fetch_rankings.py --apps # Get OpenRouter apps ranking
|
||||
|
||||
Security Note:
|
||||
- Uses subprocess.run() with shell=False for security
|
||||
- All commands are hardcoded, no user input passed to shell
|
||||
"""
|
||||
|
||||
import subprocess
|
||||
import json
|
||||
import re
|
||||
import sys
|
||||
import time
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
def run_browser_command(args: list) -> str:
|
||||
"""
|
||||
Run agent-browser command and return output.
|
||||
|
||||
Security: Uses shell=False (default) to prevent command injection.
|
||||
All arguments are passed as a list, not as a shell command string.
|
||||
"""
|
||||
cmd = ['agent-browser'] + args
|
||||
result = subprocess.run(cmd, capture_output=True, text=True)
|
||||
if result.returncode != 0:
|
||||
print(f"Error: {result.stderr}", file=sys.stderr)
|
||||
return ""
|
||||
return result.stdout
|
||||
|
||||
|
||||
def fetch_artificial_analysis_leaderboard():
|
||||
"""Fetch Artificial Analysis LLM Leaderboard via browser"""
|
||||
print("Fetching Artificial Analysis LLM Leaderboard via browser...")
|
||||
|
||||
run_browser_command(['open', 'https://artificialanalysis.ai/leaderboards/models'])
|
||||
run_browser_command(['wait', '--load', 'networkidle'])
|
||||
run_browser_command(['wait', '5000']) # Wait for JS rendering
|
||||
output = run_browser_command(['eval', 'document.body.innerText'])
|
||||
|
||||
return output
|
||||
|
||||
|
||||
def fetch_artificial_analysis_providers():
|
||||
"""Fetch Artificial Analysis API Providers Leaderboard via JavaScript table extraction"""
|
||||
print("Fetching Artificial Analysis API Providers Leaderboard...")
|
||||
|
||||
run_browser_command(['open', 'https://artificialanalysis.ai/leaderboards/providers'])
|
||||
run_browser_command(['wait', '--load', 'networkidle'])
|
||||
run_browser_command(['wait', '5000']) # Wait for JS rendering
|
||||
|
||||
# Use JavaScript to extract table data - use simpler approach
|
||||
js_code = 'document.querySelector("table") ? Array.from(document.querySelectorAll("tr")).slice(0,25).map(tr => Array.from(tr.querySelectorAll("td")).map(td => td.innerText.replace(/\\n/g," ").trim()).join("||")).join("\\n") : "NO TABLE"'
|
||||
output = run_browser_command(['eval', js_code])
|
||||
|
||||
return output if output else ""
|
||||
|
||||
|
||||
def fetch_artificial_analysis_coding():
|
||||
"""Fetch Artificial Analysis Coding Index Leaderboard via snapshot"""
|
||||
print("Fetching Artificial Analysis Coding Index Leaderboard...")
|
||||
|
||||
run_browser_command(['open', 'https://artificialanalysis.ai/?intelligence=coding-index'])
|
||||
run_browser_command(['wait', '--load', 'networkidle'])
|
||||
run_browser_command(['wait', '6000'])
|
||||
|
||||
# Use snapshot to get the raw output, then parse
|
||||
result = subprocess.run(
|
||||
['agent-browser', 'snapshot'],
|
||||
capture_output=True, text=True
|
||||
)
|
||||
|
||||
if result.returncode != 0:
|
||||
return ""
|
||||
|
||||
snapshot = result.stdout
|
||||
|
||||
lines = snapshot.split('\n')
|
||||
|
||||
in_coding_section = False
|
||||
section_lines = []
|
||||
|
||||
for i, line in enumerate(lines):
|
||||
if 'tabpanel "Coding Index"' in line:
|
||||
in_coding_section = True
|
||||
continue
|
||||
|
||||
if in_coding_section:
|
||||
if line.strip().startswith('- tabpanel "'):
|
||||
break
|
||||
section_lines.append(line)
|
||||
|
||||
section_text = '\n'.join(section_lines)
|
||||
|
||||
# Extract model names from "group" elements - only those in THIS tabpanel
|
||||
models = []
|
||||
seen = set()
|
||||
for line in section_lines[:300]: # First ~300 lines have the models
|
||||
match = re.search(r'group "([^"]+)"', line)
|
||||
if match:
|
||||
model_name = match.group(1).strip()
|
||||
if model_name and model_name != 'Reasoning model' and len(model_name) > 2 and len(model_name) < 50:
|
||||
if model_name not in seen:
|
||||
seen.add(model_name)
|
||||
models.append(model_name)
|
||||
|
||||
# Extract ALL valid scores (they start around line 231 and go to end)
|
||||
all_scores = re.findall(r'StaticText "(\d{2})"', section_text)
|
||||
valid_scores = [s for s in all_scores if 10 <= int(s) <= 60]
|
||||
|
||||
# Combine models with scores (first N models match first N scores)
|
||||
result_lines = []
|
||||
count = min(len(models), len(valid_scores))
|
||||
for i in range(count):
|
||||
result_lines.append(f"{models[i]}|{valid_scores[i]}")
|
||||
|
||||
if result_lines:
|
||||
return "CODING INDEX\n" + "\n".join(result_lines)
|
||||
return ""
|
||||
|
||||
|
||||
def fetch_artificial_analysis_agentic():
|
||||
"""Fetch Artificial Analysis Agentic Index Leaderboard via snapshot"""
|
||||
print("Fetching Artificial Analysis Agentic Index Leaderboard...")
|
||||
|
||||
run_browser_command(['open', 'https://artificialanalysis.ai/?intelligence=agentic-index'])
|
||||
run_browser_command(['wait', '--load', 'networkidle'])
|
||||
run_browser_command(['wait', '6000'])
|
||||
|
||||
# Use snapshot to get the raw output, then parse
|
||||
result = subprocess.run(
|
||||
['agent-browser', 'snapshot'],
|
||||
capture_output=True, text=True
|
||||
)
|
||||
|
||||
if result.returncode != 0:
|
||||
return ""
|
||||
|
||||
snapshot = result.stdout
|
||||
|
||||
lines = snapshot.split('\n')
|
||||
|
||||
in_agentic_section = False
|
||||
section_lines = []
|
||||
|
||||
for i, line in enumerate(lines):
|
||||
if 'tabpanel "Agentic Index"' in line:
|
||||
in_agentic_section = True
|
||||
continue
|
||||
|
||||
if in_agentic_section:
|
||||
if line.strip().startswith('- tabpanel "'):
|
||||
break
|
||||
section_lines.append(line)
|
||||
|
||||
section_text = '\n'.join(section_lines)
|
||||
|
||||
# Extract model names - only from early part
|
||||
models = []
|
||||
seen = set()
|
||||
for line in section_lines[:300]:
|
||||
match = re.search(r'group "([^"]+)"', line)
|
||||
if match:
|
||||
model_name = match.group(1).strip()
|
||||
if model_name and model_name != 'Reasoning model' and len(model_name) > 2 and len(model_name) < 50:
|
||||
if model_name not in seen:
|
||||
seen.add(model_name)
|
||||
models.append(model_name)
|
||||
|
||||
# Extract ALL valid scores
|
||||
all_scores = re.findall(r'StaticText "(\d{2})"', section_text)
|
||||
valid_scores = [s for s in all_scores if 10 <= int(s) <= 60]
|
||||
|
||||
# Combine
|
||||
result_lines = []
|
||||
count = min(len(models), len(valid_scores))
|
||||
for i in range(count):
|
||||
result_lines.append(f"{models[i]}|{valid_scores[i]}")
|
||||
|
||||
if result_lines:
|
||||
return "AGENTIC INDEX\n" + "\n".join(result_lines)
|
||||
return ""
|
||||
|
||||
|
||||
def fetch_artificial_analysis_image_models():
|
||||
"""Fetch Artificial Analysis Image/Video Models Leaderboard"""
|
||||
print("Fetching Artificial Analysis Image/Video Models Leaderboard...")
|
||||
|
||||
run_browser_command(['open', 'https://artificialanalysis.ai/'])
|
||||
run_browser_command(['wait', '--load', 'networkidle'])
|
||||
run_browser_command(['wait', '3000'])
|
||||
|
||||
output = run_browser_command(['eval', 'document.body.innerText.substring(0, 5000)'])
|
||||
|
||||
return output if output else "Image models section not found"
|
||||
|
||||
|
||||
def fetch_openrouter_rankings():
|
||||
"""Fetch OpenRouter rankings page via browser"""
|
||||
print("Fetching OpenRouter rankings via browser...")
|
||||
|
||||
run_browser_command(['open', 'https://openrouter.ai/rankings'])
|
||||
run_browser_command(['wait', '--load', 'networkidle'])
|
||||
|
||||
# Click "Show more" to expand from Top 10 to Top 20+
|
||||
run_browser_command(['eval', "const buttons = document.querySelectorAll('button'); for(let b of buttons) { if(b.innerText === 'Show more') { b.click(); break; } }"])
|
||||
run_browser_command(['wait', '3000'])
|
||||
|
||||
output = run_browser_command(['eval', 'document.body.innerText'])
|
||||
|
||||
return output
|
||||
|
||||
|
||||
def fetch_openrouter_apps():
|
||||
"""Fetch OpenRouter apps ranking"""
|
||||
print("Fetching OpenRouter apps ranking...")
|
||||
|
||||
run_browser_command(['open', 'https://openrouter.ai/apps'])
|
||||
run_browser_command(['wait', '--load', 'networkidle'])
|
||||
run_browser_command(['wait', '3000'])
|
||||
output = run_browser_command(['eval', 'document.body.innerText'])
|
||||
|
||||
return output
|
||||
|
||||
|
||||
def parse_aa_highlights(text: str) -> str:
|
||||
"""Parse Artificial Analysis highlights section"""
|
||||
lines = []
|
||||
|
||||
if 'Intelligence' in text:
|
||||
int_match = re.search(r'Intelligence.*?:\s*([^\n]+)', text)
|
||||
if int_match:
|
||||
lines.append(f"Intelligence: {int_match.group(1)}")
|
||||
|
||||
if 'Output Speed' in text or 'tokens/s' in text:
|
||||
speed_match = re.search(r'Output Speed.*?:\s*([^\n]+)', text)
|
||||
if speed_match:
|
||||
lines.append(f"Speed: {speed_match.group(1)}")
|
||||
|
||||
if 'Price' in text:
|
||||
price_match = re.search(r'Price.*?:\s*([^\n]+)', text)
|
||||
if price_match:
|
||||
lines.append(f"Price: {price_match.group(1)}")
|
||||
|
||||
return '\n'.join(lines) if lines else "Highlights not found in page"
|
||||
|
||||
|
||||
def parse_aa_providers(text: str) -> list:
|
||||
"""Parse API Providers data from double-pipe-separated table rows"""
|
||||
providers = []
|
||||
|
||||
# Clean up text - remove JSON string wrapper if present
|
||||
text = text.strip()
|
||||
if text.startswith('"') and text.endswith('"'):
|
||||
# It's a JSON-encoded string, decode it
|
||||
import json
|
||||
try:
|
||||
text = json.loads(text)
|
||||
text = text.strip()
|
||||
except:
|
||||
pass
|
||||
|
||||
# Remove leading/trailing whitespace and quotes
|
||||
text = text.strip('"\n ')
|
||||
|
||||
lines = text.split('\n')
|
||||
for line in lines:
|
||||
line = line.strip()
|
||||
if not line:
|
||||
continue
|
||||
|
||||
# Split by || (double pipe)
|
||||
parts = [p.strip() for p in line.split('||')]
|
||||
|
||||
if len(parts) < 7:
|
||||
continue
|
||||
|
||||
# Skip header row
|
||||
if parts[0].strip() in ['Features', 'API Provider', '']:
|
||||
continue
|
||||
if not parts[0] or not parts[1]:
|
||||
continue
|
||||
|
||||
# Extract fields: Provider, Model, Context, License, II, Price, Speed, Latency, etc.
|
||||
provider = parts[0].strip()
|
||||
model = parts[1].strip()
|
||||
context = parts[2].strip() if len(parts) > 2 else ''
|
||||
license = parts[3].strip() if len(parts) > 3 else ''
|
||||
ii = parts[4].strip() if len(parts) > 4 else ''
|
||||
price = parts[5].strip() if len(parts) > 5 else ''
|
||||
speed = parts[6].strip() if len(parts) > 6 else ''
|
||||
latency = parts[7].strip() if len(parts) > 7 else ''
|
||||
|
||||
# Clean up price (already has $)
|
||||
if price.startswith('$') and price.count('$') > 1:
|
||||
price = price.replace('$', '', 1)
|
||||
|
||||
if model and ii and provider not in ['Features', 'Model', 'API Provider']:
|
||||
# Validate II is a number
|
||||
try:
|
||||
ii_num = int(ii)
|
||||
providers.append({
|
||||
'provider': provider[:22],
|
||||
'model': model[:38],
|
||||
'context': context,
|
||||
'license': license[:4],
|
||||
'ii': str(ii_num),
|
||||
'price': price if price else '-',
|
||||
'speed': speed if speed else '-',
|
||||
'latency': latency if latency else '-'
|
||||
})
|
||||
except ValueError:
|
||||
continue
|
||||
|
||||
# Sort by Intelligence Index
|
||||
providers.sort(key=lambda x: int(x['ii']) if x['ii'].isdigit() else 0, reverse=True)
|
||||
|
||||
return providers[:25]
|
||||
|
||||
|
||||
def format_aa_leaderboard(text: str, source: str = "LLM Leaderboard") -> str:
|
||||
"""Format Artificial Analysis leaderboard as markdown"""
|
||||
lines = [
|
||||
"=" * 70,
|
||||
f" Artificial Analysis {source}",
|
||||
" (Intelligence Index, Speed, Price Comparison)",
|
||||
"=" * 70,
|
||||
"",
|
||||
"HIGHLIGHTS:",
|
||||
parse_aa_highlights(text),
|
||||
"",
|
||||
"-" * 70,
|
||||
"For detailed comparison, please visit:",
|
||||
"https://artificialanalysis.ai/leaderboards/models" if "providers" not in source.lower() else "https://artificialanalysis.ai/leaderboards/providers",
|
||||
"-" * 70,
|
||||
f"Query time: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}",
|
||||
"=" * 70
|
||||
]
|
||||
|
||||
return "\n".join(lines)
|
||||
|
||||
|
||||
def format_aa_providers(text: str) -> str:
|
||||
"""Format Artificial Analysis API Providers as markdown"""
|
||||
providers = parse_aa_providers(text)
|
||||
|
||||
lines = [
|
||||
"=" * 70,
|
||||
" Artificial Analysis LLM API Providers Leaderboard",
|
||||
" (Comparison of 500+ AI Model Endpoints)",
|
||||
"=" * 70,
|
||||
"",
|
||||
"TOP PROVIDERS BY INTELLIGENCE INDEX:",
|
||||
"-" * 70,
|
||||
f"{'#':<3} {'Provider':<22} {'Model':<35} {'II':<3} {'Price':<7} {'Speed':<6} {'Latency':<8}",
|
||||
"-" * 70
|
||||
]
|
||||
|
||||
if providers:
|
||||
for i, p in enumerate(providers[:20], 1):
|
||||
lines.append(
|
||||
f"{i:<3} {p['provider']:<22} {p['model']:<35} "
|
||||
f"{p['ii']:<3} {p['price']:<7} {p['speed']:<6} {p['latency']:<8}"
|
||||
)
|
||||
else:
|
||||
lines.append("Failed to parse providers data. Please visit the website directly.")
|
||||
|
||||
lines.extend([
|
||||
"",
|
||||
"-" * 70,
|
||||
"KEY PROVIDERS:",
|
||||
"Cerebras, Groq, Fireworks, SambaNova, Together.ai, Hyperbolic, Nebius",
|
||||
"Google Vertex, Azure OpenAI, AWS Bedrock, DeepInfra, HuggingFace",
|
||||
"",
|
||||
"For complete rankings (500+ endpoints), please visit:",
|
||||
"https://artificialanalysis.ai/leaderboards/providers",
|
||||
"-" * 70,
|
||||
f"Query time: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}",
|
||||
"=" * 70
|
||||
])
|
||||
|
||||
return "\n".join(lines)
|
||||
|
||||
|
||||
def format_index_ranking(text: str, index_type: str) -> str:
|
||||
"""Format Coding or Agentic Index as markdown table"""
|
||||
lines = [
|
||||
"=" * 70,
|
||||
f" Artificial Analysis {index_type}",
|
||||
f" (Intelligence Index for {index_type})",
|
||||
"=" * 70,
|
||||
"",
|
||||
f"{'Rank':<6} {'Model':<40} {'Score':<6}",
|
||||
"-" * 70
|
||||
]
|
||||
|
||||
# Parse model|score pairs
|
||||
entries = []
|
||||
for line in text.strip().split('\n'):
|
||||
if '|' in line:
|
||||
parts = line.split('|')
|
||||
if len(parts) >= 2:
|
||||
model = parts[0].strip()
|
||||
score = parts[1].strip()
|
||||
if model and score.isdigit():
|
||||
entries.append((model, int(score)))
|
||||
|
||||
# Sort by score descending
|
||||
entries.sort(key=lambda x: x[1], reverse=True)
|
||||
|
||||
for i, (model, score) in enumerate(entries[:20], 1):
|
||||
lines.append(f"{i:<6} {model:<40} {score:<6}")
|
||||
|
||||
lines.extend([
|
||||
"",
|
||||
"-" * 70,
|
||||
f"Full rankings (417 models): https://artificialanalysis.ai/?intelligence={index_type.lower().replace(' ', '-')}",
|
||||
f"Query time: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}",
|
||||
"=" * 70
|
||||
])
|
||||
|
||||
return "\n".join(lines)
|
||||
|
||||
|
||||
def parse_openrouter_models(text: str) -> list:
|
||||
"""Parse top models from OpenRouter page text"""
|
||||
models = []
|
||||
|
||||
# Find LLM Leaderboard section
|
||||
llm_section = text
|
||||
if 'LLM Leaderboard' in text:
|
||||
parts = text.split('LLM Leaderboard')
|
||||
if len(parts) > 1:
|
||||
section_content = parts[1]
|
||||
if 'Market Share' in section_content:
|
||||
llm_section = section_content.split('Market Share')[0]
|
||||
else:
|
||||
llm_section = section_content
|
||||
|
||||
# Pattern: "1.\nMiniMax M2.5\nby\nminimax\n1.75T tokens\n6%"
|
||||
pattern = r'(\d+)\.\n([^\n]+)\nby\n([^\n]+)\n([\d.]+[TB]) tokens\n([+-]?\d+%)?(new)?'
|
||||
|
||||
matches = re.findall(pattern, llm_section)
|
||||
for match in matches:
|
||||
rank, model, provider, tokens, change, is_new = match
|
||||
models.append({
|
||||
"rank": int(rank),
|
||||
"model": model.strip(),
|
||||
"provider": provider.strip(),
|
||||
"tokens": tokens,
|
||||
"change": change if change else ("new" if is_new else "N/A")
|
||||
})
|
||||
|
||||
return models
|
||||
|
||||
|
||||
def parse_openrouter_apps(text: str) -> list:
|
||||
"""Parse top apps from OpenRouter page text"""
|
||||
apps = []
|
||||
|
||||
# Find the Top Apps section
|
||||
apps_section = text.split("Top Apps")[-1] if "Top Apps" in text else text
|
||||
|
||||
# Pattern for apps: "1.\nOpenClaw \nThe AI that actually does things\n552Btokens"
|
||||
pattern = r'(\d+)\.\n([^\n]+)\n([^\n]+)\n([\d.]+[TB])tokens'
|
||||
|
||||
matches = re.findall(pattern, apps_section)
|
||||
for match in matches:
|
||||
rank, name, description, tokens = match
|
||||
apps.append({
|
||||
"rank": int(rank),
|
||||
"name": name.strip(),
|
||||
"description": description.strip(),
|
||||
"tokens": tokens
|
||||
})
|
||||
|
||||
return apps
|
||||
|
||||
|
||||
def format_models_table(models: list, source: str = "OpenRouter") -> str:
|
||||
"""Format models as markdown table"""
|
||||
lines = [
|
||||
"=" * 70,
|
||||
f" {source} Top Models (Weekly Usage)",
|
||||
"=" * 70,
|
||||
"",
|
||||
f"{'Rank':<6} {'Model':<30} {'Provider':<15} {'Tokens':<12} {'Change'}",
|
||||
"-" * 70
|
||||
]
|
||||
|
||||
for m in models:
|
||||
lines.append(f"{m['rank']:<6} {m['model']:<30} {m['provider']:<15} {m['tokens']:<12} {m['change']}")
|
||||
|
||||
lines.extend([
|
||||
"-" * 70,
|
||||
f"Total: {len(models)} models",
|
||||
f"Query time: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}",
|
||||
"=" * 70
|
||||
])
|
||||
|
||||
return "\n".join(lines)
|
||||
|
||||
|
||||
def format_apps_table(apps: list) -> str:
|
||||
"""Format apps as markdown table"""
|
||||
lines = [
|
||||
"=" * 70,
|
||||
" OpenRouter Top Apps (Daily Usage)",
|
||||
"=" * 70,
|
||||
"",
|
||||
f"{'Rank':<6} {'App Name':<25} {'Tokens':<12}",
|
||||
"-" * 70
|
||||
]
|
||||
|
||||
for a in apps:
|
||||
lines.append(f"{a['rank']:<6} {a['name']:<25} {a['tokens']:<12}")
|
||||
|
||||
lines.extend([
|
||||
"-" * 70,
|
||||
f"Total: {len(apps)} apps",
|
||||
f"Query time: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}",
|
||||
"=" * 70
|
||||
])
|
||||
|
||||
return "\n".join(lines)
|
||||
|
||||
|
||||
def main():
|
||||
"""Main function"""
|
||||
mode = "aa-leaderboard" # Default to Artificial Analysis
|
||||
|
||||
if len(sys.argv) > 1:
|
||||
arg = sys.argv[1]
|
||||
if arg == "--aa-intelligence" or arg == "--aa-speed" or arg == "--aa-price":
|
||||
mode = "aa-leaderboard"
|
||||
elif arg == "--aa-providers":
|
||||
mode = "aa-providers"
|
||||
elif arg == "--aa-coding":
|
||||
mode = "aa-coding"
|
||||
elif arg == "--aa-agentic":
|
||||
mode = "aa-agentic"
|
||||
elif arg == "--aa-image":
|
||||
mode = "aa-image"
|
||||
elif arg == "--openrouter":
|
||||
mode = "openrouter"
|
||||
elif arg == "--apps":
|
||||
mode = "apps"
|
||||
elif arg in ["-h", "--help"]:
|
||||
print(__doc__)
|
||||
return
|
||||
|
||||
# Fetch page content based on mode
|
||||
if mode == "aa-leaderboard":
|
||||
text = fetch_artificial_analysis_leaderboard()
|
||||
if text:
|
||||
print(format_aa_leaderboard(text, "LLM Leaderboard"))
|
||||
else:
|
||||
print("Failed to fetch Artificial Analysis leaderboard", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
elif mode == "aa-providers":
|
||||
text = fetch_artificial_analysis_providers()
|
||||
if text:
|
||||
print(format_aa_providers(text))
|
||||
else:
|
||||
print("Failed to fetch Artificial Analysis providers", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
elif mode == "aa-coding":
|
||||
text = fetch_artificial_analysis_coding()
|
||||
if text:
|
||||
print(format_index_ranking(text, "Coding Index"))
|
||||
else:
|
||||
print("Failed to fetch Artificial Analysis coding index", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
elif mode == "aa-agentic":
|
||||
text = fetch_artificial_analysis_agentic()
|
||||
if text:
|
||||
print(format_index_ranking(text, "Agentic Index"))
|
||||
else:
|
||||
print("Failed to fetch Artificial Analysis agentic index", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
elif mode == "aa-image":
|
||||
text = fetch_artificial_analysis_image_models()
|
||||
if text:
|
||||
print(format_aa_leaderboard(text, "Image/Video Models"))
|
||||
else:
|
||||
print("Failed to fetch Artificial Analysis image models", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
elif mode == "openrouter":
|
||||
text = fetch_openrouter_rankings()
|
||||
if text:
|
||||
if text.startswith('"') and text.endswith('"'):
|
||||
text = json.loads(text)
|
||||
|
||||
models = parse_openrouter_models(text)
|
||||
if models:
|
||||
print(format_models_table(models, "OpenRouter"))
|
||||
else:
|
||||
print("No models found in page content")
|
||||
print("\n--- Raw Content (first 2000 chars) ---")
|
||||
print(text[:2000])
|
||||
else:
|
||||
print("Failed to fetch OpenRouter rankings", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
elif mode == "apps":
|
||||
text = fetch_openrouter_apps()
|
||||
if text:
|
||||
apps = parse_openrouter_apps(text)
|
||||
if apps:
|
||||
print(format_apps_table(apps))
|
||||
else:
|
||||
print("No apps found in page content")
|
||||
else:
|
||||
print("Failed to fetch OpenRouter apps", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
# Close browser
|
||||
run_browser_command(['close'])
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,222 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
AI Rankings Leaderboard Query Tool
|
||||
Fetches model rankings, model IDs, and pricing from OpenRouter and Pinchbench
|
||||
"""
|
||||
|
||||
import sys
|
||||
import json
|
||||
import argparse
|
||||
from urllib.request import urlopen, Request
|
||||
from datetime import datetime
|
||||
|
||||
# OpenRouter API endpoints (no auth needed for public data)
|
||||
OPENROUTER_MODELS_API = "https://openrouter.ai/api/v1/models"
|
||||
OPENROUTER_RANKINGS_URL = "https://openrouter.ai/rankings"
|
||||
PINCHBENCH_URL = "https://pinchbench.com/"
|
||||
|
||||
HEADERS = {
|
||||
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
|
||||
'Accept': 'application/json'
|
||||
}
|
||||
|
||||
|
||||
def fetch_json(url):
|
||||
"""Fetch JSON data from API"""
|
||||
try:
|
||||
req = Request(url, headers=HEADERS)
|
||||
with urlopen(req, timeout=30) as response:
|
||||
return json.loads(response.read().decode('utf-8'))
|
||||
except Exception as e:
|
||||
print(f"Error fetching {url}: {e}")
|
||||
return None
|
||||
|
||||
|
||||
def get_all_models():
|
||||
"""Get all models from OpenRouter API"""
|
||||
print("Fetching models from OpenRouter API...")
|
||||
data = fetch_json(OPENROUTER_MODELS_API)
|
||||
|
||||
if not data or 'data' not in data:
|
||||
print("Failed to fetch models from API")
|
||||
return []
|
||||
|
||||
models = []
|
||||
for model in data['data']:
|
||||
models.append({
|
||||
'id': model.get('id', ''),
|
||||
'name': model.get('name', model.get('id', '')),
|
||||
'provider': model.get('id', '').split('/')[0] if '/' in model.get('id', '') else 'unknown',
|
||||
'context_length': model.get('context_length', 0),
|
||||
'pricing': {
|
||||
'input': model.get('pricing', {}).get('prompt', '0'),
|
||||
'output': model.get('pricing', {}).get('completion', '0')
|
||||
},
|
||||
'top_provider': model.get('top_provider', {}),
|
||||
'per_request_limits': model.get('per_request_limits', {}),
|
||||
'architecture': model.get('architecture', {})
|
||||
})
|
||||
|
||||
return models
|
||||
|
||||
|
||||
def get_free_models():
|
||||
"""Get free models from OpenRouter"""
|
||||
models = get_all_models()
|
||||
free_models = []
|
||||
|
||||
for m in models:
|
||||
input_price = float(m['pricing']['input'] or 0)
|
||||
output_price = float(m['pricing']['output'] or 0)
|
||||
|
||||
if input_price == 0 and output_price == 0:
|
||||
free_models.append(m)
|
||||
|
||||
return free_models
|
||||
|
||||
|
||||
def search_models(query):
|
||||
"""Search models by name or ID"""
|
||||
models = get_all_models()
|
||||
query_lower = query.lower()
|
||||
|
||||
results = []
|
||||
for m in models:
|
||||
if query_lower in m['id'].lower() or query_lower in m['name'].lower():
|
||||
results.append(m)
|
||||
|
||||
return results
|
||||
|
||||
|
||||
def format_pricing(price_str):
|
||||
"""Format pricing string"""
|
||||
if not price_str:
|
||||
return "$0"
|
||||
try:
|
||||
price = float(price_str)
|
||||
if price == 0:
|
||||
return "FREE"
|
||||
return f"${price * 1000000:.2f}/M"
|
||||
except:
|
||||
return price_str
|
||||
|
||||
|
||||
def print_models_table(models, title="Models"):
|
||||
"""Print models in table format"""
|
||||
if not models:
|
||||
print(f"No {title.lower()} found")
|
||||
return
|
||||
|
||||
print("=" * 80)
|
||||
print(f" {title}")
|
||||
print("=" * 80)
|
||||
print()
|
||||
|
||||
for i, m in enumerate(models[:20], 1): # Limit to 20 for readability
|
||||
print(f"{i}. {m['name']}")
|
||||
print(f" Model ID: {m['id']}")
|
||||
print(f" Context: {m['context_length']:,} tokens" if m['context_length'] else " Context: N/A")
|
||||
|
||||
input_price = format_pricing(m['pricing']['input'])
|
||||
output_price = format_pricing(m['pricing']['output'])
|
||||
print(f" Pricing: Input {input_price} | Output {output_price}")
|
||||
print()
|
||||
|
||||
if len(models) > 20:
|
||||
print(f"... and {len(models) - 20} more models")
|
||||
|
||||
print("=" * 80)
|
||||
print(f"Total: {len(models)} models")
|
||||
print(f"Query time: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
|
||||
print("=" * 80)
|
||||
|
||||
|
||||
def print_model_detail(model):
|
||||
"""Print detailed model info"""
|
||||
print("=" * 60)
|
||||
print(f" {model['name']}")
|
||||
print("=" * 60)
|
||||
print()
|
||||
print(f"Model ID: {model['id']}")
|
||||
print(f"Provider: {model['provider']}")
|
||||
print(f"Context Length: {model['context_length']:,} tokens" if model['context_length'] else "Context Length: N/A")
|
||||
print()
|
||||
|
||||
input_price = format_pricing(model['pricing']['input'])
|
||||
output_price = format_pricing(model['pricing']['output'])
|
||||
print(f"Pricing:")
|
||||
print(f" Input: {input_price}")
|
||||
print(f" Output: {output_price}")
|
||||
print()
|
||||
|
||||
# Architecture info
|
||||
arch = model.get('architecture', {})
|
||||
if arch:
|
||||
print("Architecture:")
|
||||
if arch.get('modality'):
|
||||
print(f" Modality: {arch.get('modality')}")
|
||||
if arch.get('tokenizer'):
|
||||
print(f" Tokenizer: {arch.get('tokenizer')}")
|
||||
|
||||
print()
|
||||
print("=" * 60)
|
||||
print("API Usage Example (for reference only, this script does not require API key):")
|
||||
print("=" * 60)
|
||||
print(f'''
|
||||
curl https://openrouter.ai/api/v1/chat/completions \\
|
||||
-H "Authorization: Bearer $OPENROUTER_API_KEY" \\
|
||||
-H "Content-Type: application/json" \\
|
||||
-d '{{
|
||||
"model": "{model['id']}",
|
||||
"messages": [{{"role": "user", "content": "Hello"}}]
|
||||
}}'
|
||||
''')
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description='AI Rankings Leaderboard Query Tool')
|
||||
parser.add_argument('--free', action='store_true', help='List free models only')
|
||||
parser.add_argument('--search', '-s', type=str, help='Search models by name or ID')
|
||||
parser.add_argument('--id', type=str, help='Get model by exact ID')
|
||||
parser.add_argument('--all', action='store_true', help='List all models')
|
||||
parser.add_argument('--limit', '-l', type=int, default=20, help='Limit number of results')
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.id:
|
||||
# Get specific model by ID
|
||||
models = get_all_models()
|
||||
model = next((m for m in models if m['id'] == args.id), None)
|
||||
if model:
|
||||
print_model_detail(model)
|
||||
else:
|
||||
print(f"Model not found: {args.id}")
|
||||
print("Try --search to find similar models")
|
||||
|
||||
elif args.search:
|
||||
# Search models
|
||||
results = search_models(args.search)
|
||||
print_models_table(results, f"Search Results for '{args.search}'")
|
||||
|
||||
elif args.free:
|
||||
# List free models
|
||||
free = get_free_models()
|
||||
print_models_table(free, "Free Models on OpenRouter")
|
||||
|
||||
elif args.all:
|
||||
# List all models
|
||||
models = get_all_models()
|
||||
print_models_table(models[:args.limit], "All Models on OpenRouter")
|
||||
|
||||
else:
|
||||
# Default: show help
|
||||
parser.print_help()
|
||||
print()
|
||||
print("Examples:")
|
||||
print(" python3 query_leaderboard.py --free # List free models")
|
||||
print(" python3 query_leaderboard.py -s gpt # Search for GPT models")
|
||||
print(" python3 query_leaderboard.py -s glm # Search for GLM models")
|
||||
print(" python3 query_leaderboard.py --id openai/gpt-4o # Get specific model info")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user