@synchronic1/harness-ranger
v0.5.0
Published
Tool-execution timing, resilient fetch fallback, and fetch_with_fallback skill for OpenClaw agents
Maintainers
Readme
@synchronic1/harness-ranger
OpenClaw plugin that ports several operational patterns from the Claude Code harness into OpenClaw — patterns that exist in Claude Code's tool execution layer but have no equivalent in the base OpenClaw runtime.
Background: the gap between Claude Code and OpenClaw
Claude Code (Anthropic's CLI) and OpenClaw are both agentic runtimes built on Claude, but they evolved separately. Claude Code's internal harness — the layer that sits between the model and tool execution — includes a number of production-grade patterns that OpenClaw does not ship with out of the box:
| Capability | Claude Code harness | OpenClaw (native) | harness-ranger |
|---|---|---|---|
| Tool execution timing with threshold warnings | Yes — every tool bracketed, slow tools surfaced in logs | No timing visibility | Adds per-tool timing hooks, configurable thresholds |
| Resilient web fetch with fallback chain | Yes — multiple strategies, degrades gracefully | browser only (headless Chromium; fails on CPU-only hosts) | Adds fetch_with_fallback: native fetch → curl → Reddit JSON API |
| Agent-level tool guidance (skill injection) | Yes — skill documents loaded into system prompt | No equivalent | Adds SKILL.md wired via plugin manifest |
| Semantic tool discovery | Yes — tools found by intent, not just name | Name lookup only | Adds findTools(query) with scored similarity matching |
| Permission-aware execution gating | Yes — role/resource checks before any tool runs | No permission layer | Adds canExecute() check in before_tool_execution |
| Token-aware session compaction | Yes — automatic context compression at budget | No automatic compaction | Adds SessionManager with configurable budgets |
| Structured streaming event pipeline | Yes — typed events through response lifecycle | Basic streaming | Adds message_start / tool_match / message_delta / message_stop |
The practical gaps that affect day-to-day operation are the first three: you cannot see which tools are slow, web fetches fail silently on any host without a working browser, and the agent has no built-in guidance to prefer faster alternatives. harness-ranger addresses all three and layers in the rest of the Claude Code harness pattern for completeness.
What harness-ranger adds in detail
Tool-execution timing with threshold warnings
Every tool call is bracketed by before_tool_execution / after_tool_execution hooks. Elapsed time is computed in milliseconds and logged. When a tool exceeds its threshold the plugin emits a structured SLOW TOOL warning with tool name, actual elapsed time, and configured threshold — surfaced in OpenClaw logs without any changes to the tool itself.
Default thresholds:
| Tool | Warning threshold |
|---|---|
| browser | 30 s |
| web_fetch | 15 s |
| ollama_web_fetch | 15 s |
| exec_local | 60 s |
| exec_remote | 60 s |
Any tool not listed is timed silently (debug log only). All thresholds are configurable per-tool.
fetch_with_fallback — resilient URL fetch
Registered as a first-class OpenClaw tool. Three strategies run in sequence; the first non-empty success is returned:
- Native fetch — Node built-in,
curl/8.7.1User-Agent, configurable timeout - curl subprocess — browser User-Agent, follows up to 5 redirects, 4 MB buffer
- Reddit JSON API — appends
.jsonto the URL path forreddit.comURLs, bypasses Cloudflare
Claude Code's equivalent never relies solely on a headless browser for content retrieval. OpenClaw's base browser tool runs headless Chromium, which on CPU-only hosts hits the 2-minute typing TTL before the page renders, producing empty results. fetch_with_fallback returns the same content in under a second for most pages because it never touches the browser unless the other strategies have already failed.
If all three strategies fail, the tool returns a structured error listing per-strategy failure reasons so the agent can diagnose rather than retry blindly.
SKILL.md — agent-level guidance via plugin manifest
Claude Code uses skill documents to inject tool-selection guidance directly into the agent's system prompt without requiring prompt engineering by the operator. OpenClaw supports the same mechanism via the "skills" array in openclaw.plugin.json.
harness-ranger ships a SKILL.md that is automatically loaded into the system prompt. It instructs the agent to:
- Reach for
fetch_with_fallbackby default for any URL - Only fall back to
browserafterfetch_with_fallbackhas returned empty or blocked content and JavaScript rendering is confirmed necessary - Always use
fetch_with_fallbackfor anyreddit.comURL (Reddit JSON API endpoint, no Cloudflare)
This changes agent behavior at the guidance layer — no system prompt modifications required.
Semantic tool discovery
api.registerService exposes harness-ranger.findTools(query, context) to other extensions. Tools are matched by keyword and tag similarity against a configurable threshold (default 0.6). Returns candidates sorted by relevance score. OpenClaw's native tool lookup is name-exact only.
Permission-aware execution gating
Wraps before_tool_execution with a canExecute(toolName, user, resource) check before timing starts. Tools can be denied globally or restricted to specific resource paths. Blocked calls emit a structured warning; the tool never executes and the reason is returned to the caller.
Token-aware session management
Tracks tool calls and results per session. When a session exceeds maxBudgetTokens or compactAfterTurns the session manager compacts it — keeping the most recent maxContextTurns turns and summarizing the rest. Exposed via the service registry as harness-ranger.getSession(sessionId).
Structured streaming response handler
harness-ranger.streamResponse(generator, context) wraps an async generator and emits typed events for downstream consumers: message_start, command_match, tool_match, message_delta, message_stop. Mirrors the event structure used in Claude Code's streaming pipeline.
Installation
Step 1 — Install via the OpenClaw plugin CLI
openclaw plugins install @synchronic1/harness-rangerThis installs the package to ~/.openclaw/node_modules/ — the path OpenClaw's discovery scans for npm-installed plugins — and records the install in your config. Do not use plain npm install: it puts the package in whatever directory you're in, which OpenClaw's discovery does not scan.
Step 2 — Enable the plugin
Installing does not auto-enable. Run:
openclaw plugins enable harness-rangerOr add it manually to ~/.openclaw/config.json:
{
"plugins": {
"entries": {
"harness-ranger": {
"enabled": true,
"config": {}
}
}
}
}Step 3 — Restart the gateway
The plugin registry is built once at startup. Restart however your OpenClaw gateway is running:
pnpm gateway:dev
# or restart your systemd / pm2 / docker serviceVerify
openclaw plugins list --verboseThe plugin appears as enabled with version and loaded tools. If it fails to load:
openclaw plugins doctorConfiguration reference
All config goes under plugins.entries.harness-ranger.config in ~/.openclaw/config.json.
| Key | Type | Default | Description |
|---|---|---|---|
| maxContextTurns | number | 12 | Turns to retain after compaction |
| maxBudgetTokens | number | 4000 | Token budget before compaction triggers |
| compactAfterTurns | number | 16 | Force compact after N turns regardless of token count |
| semanticMatchingThreshold | number | 0.6 | Minimum similarity score for tool discovery (0 = match everything, 1 = exact only) |
| toolTimeouts | object | {} | Per-tool warning thresholds in ms. Overrides built-in defaults. Keys are tool names |
| enableFallbackOrchestration | boolean | true | Register the fetch_with_fallback tool. Disable only if it conflicts with another extension |
Example with custom thresholds
"harness-ranger": {
"enabled": true,
"config": {
"enableFallbackOrchestration": true,
"semanticMatchingThreshold": 0.6,
"maxContextTurns": 12,
"maxBudgetTokens": 4000,
"compactAfterTurns": 16,
"toolTimeouts": {
"browser": 20000,
"my_slow_api_tool": 45000
}
}
}fetch_with_fallback tool reference
fetch_with_fallback(url, timeout_ms?)| Parameter | Type | Required | Default | Notes |
|---|---|---|---|---|
| url | string | yes | — | Must be http:// or https://. Other protocols are rejected |
| timeout_ms | number | no | 15000 | Per-strategy timeout. Clamped to 1000–120000 ms |
Returns { type: 'text', text: string } on success or { type: 'error', text: string } listing each strategy's failure reason.
Architecture
harness-ranger/
├── index.js # Plugin entry, lifecycle hooks, fetch_with_fallback tool
├── openclaw.plugin.json # Manifest: id, configSchema, skills array
├── skills/
│ └── fetch-fallback/
│ └── SKILL.md # Loaded into agent system prompt by OpenClaw
└── src/
├── tool-registry.js # Semantic tool discovery and scoring
├── permission-context.js # Permission gating (canExecute)
├── session-manager.js # Token-aware session persistence and compaction
└── streaming-responses.js # Structured event streaming pipelineChangelog
0.4.3 — Installation guide and Claude Code harness comparison
- README rewritten to document correct installation flow (
openclaw plugins install, notnpm i) - Added comparison table showing which Claude Code harness capabilities are missing from native OpenClaw and which harness-ranger provides
0.4.2 — README rewrite
- Replaced scaffolded README with accurate feature documentation
0.4.1 — Security and reliability patches
- Security: URL validated with
new URL()before all fetch strategies. Non-HTTP/S protocols (file://,ftp://, etc.) are rejected — prevents curl argument injection and local file SSRF - Security:
timeout_msclamped to 1 s–120 s. Previously accepted arbitrary values including 0 and negatives - Fix:
clearTimeoutcalled after body fully read, not before — prevented aborting mid-download - Fix: Stale timing map entries pruned with 5-minute TTL sweep — prevents unbounded memory growth in long-running sessions
- Fix: Reddit domain check uses
parsedUrl.hostname(reddit.com/*.reddit.com) instead ofurl.includes— closes false positive on URLs that reference reddit in the path - Fix: Reddit JSON URL built from
parsedUrlproperties, not string manipulation — correct with query strings present - Package:
"files"field added topackage.json— npm tarball is now explicit
0.4.0 — Timing hooks, fetch fallback, SKILL.md
- Added
before_tool_execution/after_tool_executiontiming hooks with per-tool configurable warning thresholds - Added
fetch_with_fallbacktool: native fetch → curl subprocess → Reddit JSON API - Added
SKILL.mdregistered viaopenclaw.plugin.json"skills"array — agent proactively prefersfetch_with_fallback - Added
api.registerServiceintegration exposingfindTools,getSession,registerTool,streamResponse,getStatus - Published to npm as
@synchronic1/harness-ranger
0.3.x and earlier
Initial scaffold: EnhancedToolRegistry, PermissionContext, SessionManager, StreamingResponseHandler modules. No timing hooks, no fetch_with_fallback, no SKILL.md.
License
MIT
