416 lines
14 KiB
Markdown
416 lines
14 KiB
Markdown
|
|
# TOOLS.md - Local Notes & Tool Syntax
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 🔧 `read` — Read File Contents
|
||
|
|
|
||
|
|
**Syntax:**
|
||
|
|
```javascript
|
||
|
|
read({ file_path: "/path/to/file"[, offset: N, limit: N] })
|
||
|
|
```
|
||
|
|
|
||
|
|
**When to use:** Read text files or view images (jpg, png, gif, webp).
|
||
|
|
|
||
|
|
**Required:** `file_path` — NEVER use `path`
|
||
|
|
|
||
|
|
**Correct:**
|
||
|
|
```javascript
|
||
|
|
await read({ file_path: "/path/to/file" })
|
||
|
|
await read({ file_path: "/path/to/file", offset: 1, limit: 50 })
|
||
|
|
```
|
||
|
|
|
||
|
|
**Wrong:**
|
||
|
|
```javascript
|
||
|
|
await read({ path: "/path/to/file" }) // ❌ 'path' is wrong, use 'file_path'
|
||
|
|
await read({}) // ❌ missing file_path entirely
|
||
|
|
```
|
||
|
|
|
||
|
|
**Notes:**
|
||
|
|
- Output truncated at 2000 lines or 50KB
|
||
|
|
- Use `offset` + `limit` for files >100 lines
|
||
|
|
- Images sent as attachments automatically
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 🔧 `edit` — Edit File Contents
|
||
|
|
|
||
|
|
**Syntax:**
|
||
|
|
```javascript
|
||
|
|
edit({ file_path: "/path", old_string: "exact text", new_string: "replacement" })
|
||
|
|
```
|
||
|
|
|
||
|
|
**When to use:** Precise text replacement. Old text must match exactly (including whitespace).
|
||
|
|
|
||
|
|
**Required:** BOTH `old_string` AND `new_string` (not `oldText`/`newText`)
|
||
|
|
|
||
|
|
**Correct:**
|
||
|
|
```javascript
|
||
|
|
await edit({
|
||
|
|
file_path: "/path/to/file",
|
||
|
|
old_string: "text to replace",
|
||
|
|
new_string: "replacement text"
|
||
|
|
})
|
||
|
|
```
|
||
|
|
|
||
|
|
**Wrong:**
|
||
|
|
```javascript
|
||
|
|
await edit({ file_path: "/path/file", old_string: "text" }) // ❌ missing new_string
|
||
|
|
await edit({ file_path: "/path/file", new_string: "text" }) // ❌ missing old_string
|
||
|
|
await edit({ file_path: "/path/file", oldText: "x", newText: "y" }) // ❌ wrong param names
|
||
|
|
```
|
||
|
|
|
||
|
|
**Recovery:** After 2 failed edit attempts → use `write` to rewrite the file completely.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 🔧 `write` — Write File Contents
|
||
|
|
|
||
|
|
**Syntax:**
|
||
|
|
```javascript
|
||
|
|
write({ file_path: "/path", content: "complete file content" })
|
||
|
|
```
|
||
|
|
|
||
|
|
**When to use:** Creating new files or rewriting entire files after failed edits.
|
||
|
|
|
||
|
|
**Required:** `file_path` AND complete `content` (overwrites everything)
|
||
|
|
|
||
|
|
**Correct:**
|
||
|
|
```javascript
|
||
|
|
await write({
|
||
|
|
file_path: "/path/to/file",
|
||
|
|
content: "complete file content here"
|
||
|
|
})
|
||
|
|
```
|
||
|
|
|
||
|
|
**Wrong:**
|
||
|
|
```javascript
|
||
|
|
await write({ content: "text" }) // ❌ missing file_path
|
||
|
|
await write({ path: "/file", content: "text" }) // ❌ use file_path not path
|
||
|
|
```
|
||
|
|
|
||
|
|
**⚠️ Caution:** Overwrites entire file — make sure you have the full content.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 🔧 `exec` — Execute Shell Commands
|
||
|
|
|
||
|
|
**Syntax:**
|
||
|
|
```javascript
|
||
|
|
exec({ command: "shell command"[, timeout: 30, workdir: "/path"] })
|
||
|
|
```
|
||
|
|
|
||
|
|
**When to use:** Run shell commands, background processes, or TTY-required CLIs.
|
||
|
|
|
||
|
|
**Required:** `command`
|
||
|
|
|
||
|
|
**Correct:**
|
||
|
|
```javascript
|
||
|
|
await exec({ command: "ls -la" })
|
||
|
|
await exec({ command: "python3 script.py", timeout: 60 })
|
||
|
|
await exec({ command: "./script.sh", workdir: "/path/to/dir" })
|
||
|
|
```
|
||
|
|
|
||
|
|
**Cron Scripts — CRITICAL:**
|
||
|
|
```python
|
||
|
|
# Always exit 0 for cron jobs
|
||
|
|
import sys
|
||
|
|
sys.exit(0)
|
||
|
|
```
|
||
|
|
|
||
|
|
**Why:** OpenClaw logs non-zero exits as failures. Use stdout presence for signaling:
|
||
|
|
```python
|
||
|
|
if significant_update:
|
||
|
|
print(notification) # Output triggers notification
|
||
|
|
# No output = silent success
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 🔧 `browser` — Browser Control
|
||
|
|
|
||
|
|
**Syntax:**
|
||
|
|
```javascript
|
||
|
|
browser({ action: "navigate|snapshot|click|...", targetUrl: "..." })
|
||
|
|
```
|
||
|
|
|
||
|
|
**When to use:** Navigate, screenshot, or interact with web pages.
|
||
|
|
|
||
|
|
**Required:** `action`
|
||
|
|
|
||
|
|
**Requirements:**
|
||
|
|
- Gateway must be running
|
||
|
|
- Chrome extension must be attached (click extension icon on tab)
|
||
|
|
|
||
|
|
**Correct:**
|
||
|
|
```javascript
|
||
|
|
await browser({ action: "navigate", targetUrl: "https://example.com" })
|
||
|
|
await browser({ action: "snapshot" })
|
||
|
|
await browser({ action: "click", ref: "button-name" })
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Quick Reference Summary
|
||
|
|
|
||
|
|
| Tool | Required Parameters | Common Errors |
|
||
|
|
|------|---------------------|---------------|
|
||
|
|
| `read` | `file_path` | Using `path` |
|
||
|
|
| `edit` | `file_path`, `old_string`, `new_string` | Using `newText`/`oldText`, missing one param |
|
||
|
|
| `write` | `file_path`, `content` | Partial content, missing `file_path` |
|
||
|
|
| `exec` | `command` | Non-zero exit codes for cron |
|
||
|
|
| `browser` | `action` | Using without gateway check |
|
||
|
|
|
||
|
|
**Critical rules:** Use `file_path` not `path`. Use `old_string`/`new_string` not `oldText`/`newText`.
|
||
|
|
|
||
|
|
**Quality over speed. Verify before executing. Get it right.**
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Unified Search — Perplexity Primary, SearXNG Fallback
|
||
|
|
|
||
|
|
**Primary:** Perplexity API (cloud, AI-curated, paid)
|
||
|
|
**Fallback:** SearXNG (local, raw results, free)
|
||
|
|
|
||
|
|
### Usage
|
||
|
|
```bash
|
||
|
|
# Default: Perplexity primary, SearXNG fallback on error
|
||
|
|
search "your query"
|
||
|
|
|
||
|
|
# Perplexity only (p = perplexity)
|
||
|
|
search p "your query"
|
||
|
|
search perplexity "your query"
|
||
|
|
|
||
|
|
# SearXNG only (local = searxng)
|
||
|
|
search local "your query"
|
||
|
|
search searxng "your query"
|
||
|
|
|
||
|
|
# With citations (Perplexity)
|
||
|
|
search --citations "your query"
|
||
|
|
|
||
|
|
# Pro model for complex queries
|
||
|
|
search --model sonar-pro "your query"
|
||
|
|
search --model sonar-deep-research "comprehensive research"
|
||
|
|
```
|
||
|
|
|
||
|
|
### Models
|
||
|
|
| Model | Best For | Search Context |
|
||
|
|
|-------|----------|----------------|
|
||
|
|
| sonar | Quick answers, simple queries | Low/Medium/High |
|
||
|
|
| sonar-pro | Complex queries, coding | Medium/High |
|
||
|
|
| sonar-reasoning | Step-by-step reasoning | Medium/High |
|
||
|
|
| sonar-deep-research | Comprehensive research | High |
|
||
|
|
|
||
|
|
### When to Use Each
|
||
|
|
- **Perplexity**: Complex queries, research, current events, anything needing synthesis
|
||
|
|
- **SearXNG**: Privacy-sensitive searches, simple factual lookups, bulk operations, rate limit fallback
|
||
|
|
|
||
|
|
### Scripts
|
||
|
|
- **Unified**: `skills/perplexity/scripts/search.py`
|
||
|
|
- **Perplexity-only**: `skills/perplexity/scripts/query.py`
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Perplexity API
|
||
|
|
|
||
|
|
- **Location**: `/root/.openclaw/workspace/skills/perplexity/`
|
||
|
|
- **Key**: `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`
|
||
|
|
- **Endpoint**: `https://api.perplexity.ai/chat/completions`
|
||
|
|
- **Models**: sonar, sonar-pro, sonar-reasoning, sonar-deep-research
|
||
|
|
- **Format**: OpenAI-compatible
|
||
|
|
- **Cost**: ~$0.005 per query (shown in output)
|
||
|
|
- **Features**: AI-synthesized answers, citations, real-time search
|
||
|
|
- **Note**: Sends queries to Perplexity servers (cloud)
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### Voice/Text Reply Rules
|
||
|
|
- **Voice message received** → Reply with **voice** (using Kimi-XXX.ogg filename)
|
||
|
|
- Transcribe internally for understanding
|
||
|
|
- **DO NOT send transcript text to Telegram**
|
||
|
|
- **DO NOT include any text with voice messages** — voice-only, completely silent text
|
||
|
|
- Reply with voice-only, no text
|
||
|
|
- **Text message received** → Reply with **text**
|
||
|
|
- **Never** send both voice + text for the same reply
|
||
|
|
- **ENFORCED 2026-02-07:** Voice messages must be sent alone without accompanying text
|
||
|
|
|
||
|
|
### Voice Settings
|
||
|
|
- **TTS Provider**: Local Kokoro @ `http://10.0.0.228:8880`
|
||
|
|
- **Voice**: `af_bella` (American Female)
|
||
|
|
- **Filename format**: `Kimi-YYYYMMDD-HHMMSS.ogg`
|
||
|
|
- **Mode**: Voice-only (no text transcript when sending voice)
|
||
|
|
|
||
|
|
### Web Search
|
||
|
|
- **Primary**: Perplexity API (unified search, AI-curated)
|
||
|
|
- **Fallback**: SearXNG (local instance at `http://10.0.0.8:8888/`)
|
||
|
|
- **Manual fallback**: Use `search local "query"` for privacy-sensitive searches
|
||
|
|
- **Browser tool**: Only when gateway running and extension attached
|
||
|
|
|
||
|
|
### Core Values
|
||
|
|
- **Best accuracy** — No compromises on quality
|
||
|
|
- **Best performance** — Optimize for speed where possible
|
||
|
|
- **Privacy first** — Always prioritize privacy in all decisions
|
||
|
|
- **Always research before install** — Search web for details, docs, best practices
|
||
|
|
- **Local docs exception** — If docs are local (OpenClaw, ClawHub), use those first
|
||
|
|
|
||
|
|
### Search Preferences
|
||
|
|
- **Search first** — Try SearXNG before asking clarifying questions
|
||
|
|
- **Prioritize sites**: *(to be filled in)*
|
||
|
|
- GitHub / GitLab — For code, repos, technical docs
|
||
|
|
- Stack Overflow — For programming Q&A
|
||
|
|
- Wikipedia — For general knowledge
|
||
|
|
- Arch Wiki — For Linux/system admin topics
|
||
|
|
- Official docs — project.readthedocs.io, docs.project.org
|
||
|
|
- **Avoid/deprioritize**: *(to be filled in)*
|
||
|
|
- SEO spam sites
|
||
|
|
- Outdated forums (pre-2020 unless historical)
|
||
|
|
- **Search language**: English preferred, unless query is non-English
|
||
|
|
- **Time bias**: Prefer recent results for tech topics, timeless for facts
|
||
|
|
|
||
|
|
### Search-First Sites (Priority Order)
|
||
|
|
When searching, prefer results from:
|
||
|
|
1. **docs.openclaw.ai** / **OpenClaw docs** — OpenClaw documentation
|
||
|
|
2. **clawhub.com** / **ClawHub** — OpenClaw skills registry
|
||
|
|
3. **docs.*.org** / **readthedocs.io** — Official documentation
|
||
|
|
4. **github.com** / **gitlab.com** — Source code, issues, READMEs
|
||
|
|
5. **stackoverflow.com** — Programming solutions
|
||
|
|
6. **wikipedia.org** — General reference
|
||
|
|
7. **archlinux.org/wiki** — Linux/system administration
|
||
|
|
8. **reddit.com/r/* —** Community discussions (for opinions/experiences)
|
||
|
|
9. **news.ycombinator.com** — Tech news and discussions
|
||
|
|
10. **medium.com** / **dev.to** — Developer blogs (verify date)
|
||
|
|
|
||
|
|
## SSH Hosts
|
||
|
|
|
||
|
|
- **epyc-debian-SSH (deb)** — `n8n@10.0.0.38`
|
||
|
|
- Auth: SSH key (no password)
|
||
|
|
- Key: `~/.ssh/id_ed25519`
|
||
|
|
- Sudo password: `passw0rd`
|
||
|
|
- Usage: `ssh n8n@10.0.0.38`
|
||
|
|
- Status: OpenClaw removed 2026-02-07
|
||
|
|
|
||
|
|
- **epyc-debian2-SSH (deb2)** — `n8n@10.0.0.39`
|
||
|
|
- Auth: SSH key (same as deb)
|
||
|
|
- Key: `~/.ssh/id_ed25519`
|
||
|
|
- Sudo password: `passw0rd`
|
||
|
|
- Usage: `ssh n8n@10.0.0.39`
|
||
|
|
|
||
|
|
## Existing Software Stack
|
||
|
|
|
||
|
|
**⚠️ ALREADY INSTALLED — Do not recommend these:**
|
||
|
|
|
||
|
|
- **n8n** — Workflow automation
|
||
|
|
- **ollama** — Local LLM runner
|
||
|
|
- **openclaw** — AI agent platform (this system)
|
||
|
|
- **openwebui** — LLM chat interface
|
||
|
|
- **anythingllm** — RAG/chat with documents
|
||
|
|
- **searxng** — Privacy-focused search engine
|
||
|
|
- **flowise** — Low-code LLM workflow builder
|
||
|
|
- **plex** — Media server
|
||
|
|
- **radarr** — Movie management
|
||
|
|
- **sonarr** — TV show management
|
||
|
|
- **sabnzbd** — Usenet downloader
|
||
|
|
- **comfyui** — Stable Diffusion UI
|
||
|
|
|
||
|
|
**When recommending software, ALWAYS check this list first and omit any matches.**
|
||
|
|
|
||
|
|
## Skills
|
||
|
|
|
||
|
|
### Local Whisper STT
|
||
|
|
- **Location**: `/root/.openclaw/workspace/skills/local-whisper-stt/`
|
||
|
|
- **Purpose**: Transcribe inbound voice messages
|
||
|
|
- **Model**: `base` (CPU-only)
|
||
|
|
- **Usage**: Auto-transcribes when voice message received
|
||
|
|
- **Correct path**: `scripts/transcribe.py` (not root level)
|
||
|
|
|
||
|
|
### Kimi TTS Custom
|
||
|
|
- **Location**: `/root/.openclaw/workspace/skills/kimi-tts-custom/`
|
||
|
|
- **Purpose**: Generate voice with custom filenames and send voice-only replies
|
||
|
|
- **Scripts**:
|
||
|
|
- `scripts/generate_voice.py` — Generate voice file (returns path, does NOT send)
|
||
|
|
- `scripts/voice_reply.py` — Generate + send voice-only reply (USE THIS for voice replies)
|
||
|
|
- **Usage**: `python3 scripts/voice_reply.py <chat_id> "text"`
|
||
|
|
- **⚠️ CRITICAL**: Text reference to voice file does NOT send audio. Must use `voice_reply.py` or proper Telegram API delivery. Generation ≠ Delivery.
|
||
|
|
|
||
|
|
### Qdrant Memory
|
||
|
|
- **Location**: `/root/.openclaw/workspace/skills/qdrant-memory/`
|
||
|
|
- **Mode**: MANUAL ONLY — No automatic storage
|
||
|
|
- **Collections**:
|
||
|
|
- `kimi_memories` (personal) — Identity, rules, preferences, lessons
|
||
|
|
- `kimi_kb` (knowledge base) — Web data, documents, reference materials
|
||
|
|
- **Vector size**: 1024 (snowflake-arctic-embed2)
|
||
|
|
- **Distance**: Cosine
|
||
|
|
- **Qdrant URL**: `http://10.0.0.40:6333`
|
||
|
|
|
||
|
|
**Personal Memory Scripts (kimi_memories):**
|
||
|
|
- `scripts/store_memory.py` — Manual storage with metadata
|
||
|
|
- `scripts/search_memories.py` — Semantic search
|
||
|
|
- `scripts/hybrid_search.py` — Search files + vectors
|
||
|
|
|
||
|
|
**Knowledge Base Scripts (kimi_kb):**
|
||
|
|
- `scripts/kb_store.py` — Store web/docs to KB
|
||
|
|
- `scripts/kb_search.py` — Search knowledge base
|
||
|
|
|
||
|
|
**Usage:**
|
||
|
|
```bash
|
||
|
|
# Personal memories ("q remember", "q recall")
|
||
|
|
python3 store_memory.py "Memory" --importance high --tags "preference"
|
||
|
|
python3 search_memories.py "voice settings"
|
||
|
|
|
||
|
|
# Knowledge base (manual document/web storage)
|
||
|
|
python3 kb_store.py "Content" --title "X" --domain "Docker" --tags "container"
|
||
|
|
python3 kb_search.py "docker volumes" --domain "Docker"
|
||
|
|
```
|
||
|
|
|
||
|
|
**⚠️ CRITICAL**: Never auto-store. Only when user explicitly requests with "q" prefix.
|
||
|
|
|
||
|
|
## Infrastructure
|
||
|
|
|
||
|
|
### Container Limits
|
||
|
|
- **No GPUs attached** — All ML workloads run on CPU
|
||
|
|
- **Whisper**: Use `tiny` or `base` models for speed
|
||
|
|
|
||
|
|
### Local Services
|
||
|
|
- **Kokoro TTS**: `http://10.0.0.228:8880` (OpenAI-compatible)
|
||
|
|
- **Ollama**: `http://10.0.0.10:11434`
|
||
|
|
- **SearXNG**: `http://10.0.0.8:8888` (web search via curl)
|
||
|
|
- **Qdrant**: `http://10.0.0.40:6333` (vector database for memory + KB)
|
||
|
|
- **Collections**: `kimi_memories` (personal), `kimi_kb` (knowledge base)
|
||
|
|
- **Vector size**: 1024 (snowflake-arctic-embed2)
|
||
|
|
- **Distance**: Cosine similarity
|
||
|
|
- **Redis**: `10.0.0.36:6379` (task queue, available for future use)
|
||
|
|
|
||
|
|
## Cron Jobs
|
||
|
|
|
||
|
|
- **Default:** Always check `openclaw cron list` first when asked about cron jobs
|
||
|
|
- Rob's scheduled tasks live in OpenClaw's cron system, not system crontab
|
||
|
|
- Only check system crontab (`crontab -l`, `/etc/cron.d/`) if specifically asked about system-level jobs
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Lessons Learned & Workarounds
|
||
|
|
|
||
|
|
### Embedded Session Tool Errors
|
||
|
|
**Issue:** `read tool called without path` errors occur in embedded sessions even when parameter syntax is correct in workspace scripts.
|
||
|
|
|
||
|
|
**Workarounds:**
|
||
|
|
1. **Double-check parameters manually** — Don't trust the model to pass them correctly in embedded contexts
|
||
|
|
2. **Avoid embedded tool calls when possible** — Use workspace scripts instead
|
||
|
|
3. **Edit fails twice → Use write immediately** — Don't retry edit tool more than once
|
||
|
|
4. **Verify file exists before read** — Prevents ENOENT errors
|
||
|
|
5. **No redis-cli in container** — Use Python redis module instead
|
||
|
|
6. **Browser tool unreliable** — Use curl/SearXNG as primary web access
|
||
|
|
|
||
|
|
### Common Parameter Errors to Avoid
|
||
|
|
| Wrong | Right | Notes |
|
||
|
|
|-------|-------|-------|
|
||
|
|
| `path` | `file_path` | Most common error |
|
||
|
|
| `newText`/`oldText` | `new_string`/`new_string` | Edit tool only |
|
||
|
|
| Missing `new_string` | Include both params | Edit requires both |
|
||
|
|
| Using `write` for small edits | Use `edit` first | Edit is safer for small changes |
|
||
|
|
|
||
|
|
### Environment-Specific Gotchas
|
||
|
|
- **Qdrant Python module** — Must use scripts with proper sys.path setup
|
||
|
|
- **Playwright browsers** — Not installed, use curl/SearXNG for web scraping
|
||
|
|
- **Browser gateway** — Requires Chrome extension attached; rarely available
|
||
|
|
- **Redis CLI** — Not available; use `python3 -c "import redis..."` instead
|