A production-ready plugin implementing advanced harness patterns from Claude Code's porting workspace:
- Enhanced Tool Registry with semantic matching
- Permission-Aware Tool Execution
- Token-Aware Session Management with intelligent compaction
- Structured Streaming Responses with event pipeline
- Evidence-Gated Artifact Evolution with redacted telemetry, immutable candidates, host-specific evaluation, canary promotion, and rollback
The self-improvement subsystem is disabled by default and only evolves allowlisted text artifacts. See the feature guide for its safety model, setup, CLI, service API, and host adapters.
harness-ranger/
├── src/
│ ├── tool-registry.js # Semantic tool discovery & metadata management
│ ├── permission-context.js # Permission-aware execution gating
│ ├── session-manager.js # Token-aware session persistence
│ └── streaming-responses.js # Structured event streaming pipeline
├── self-improvement/ # Evidence-gated text-artifact evolution
├── index.js # Plugin entrypoint & lifecycle hooks
├── package.json
└── README.md
The npm package contains native bundles for OpenClaw, Claude Code, Codex, and Hermes. Run the explicit setup command after installation; npm installation itself never modifies harness configuration.
npx @synchronic1/harness-ranger setupWhen one harness is detected, --auto selects it. When several are detected, choose interactively or pass --target/--all:
npx @synchronic1/harness-ranger setup --auto
npx @synchronic1/harness-ranger setup --target claude --scope user
npx @synchronic1/harness-ranger setup --target codex --scope project --dry-run
npx @synchronic1/harness-ranger setup --allUse detect --json, status, and uninstall --target <host> for automation and lifecycle management. OpenClaw supports user scope only; project-scoped Hermes plugins require HERMES_ENABLE_PROJECT_PLUGINS=1. Setup never restarts a harness unless --restart is supplied.
The installable integration bundles are OpenClaw, Claude Code, Codex, and Hermes. These are the only hosts whose lifecycle adapters and generated installation bundles are currently implemented. The EvidenceProvider entries for those hosts are intentionally dashboard-visible planning scaffolds; they do not yet change host retrieval or request paths.
The public interactive demo is a static, illustrative operations dashboard. Its sample instances and metrics are not live connector data, and it must not be read as a claim that LangGraph or custom HTTP integrations are shipped. Use the local setup command and the validation commands below to test the implemented integrations.
The LLM judge is disabled by default and runs only as an explicit, offline evaluation worker. It never executes in a live hook and cannot promote a candidate by itself. After installing a compatible local llama.cpp worker and model outside this repository, inspect the profile and create a launch plan:
harness-evolve judge-profiles --workspace .
harness-judge plan --backend local-cpu --threads 8
harness-evolve judge-health --workspace . --backend local-cpuQueue bounded, redacted evaluation cases only after the health check succeeds. A CUDA worker may be selected explicitly where available; see the evidence-gated evolution guide for the 6 GB VRAM starting profile, model-worker setup, and case format.
HeurChain is disabled by default. The OpenClaw service exposes getHeurChainMemoryDashboard() for a dashboard to render the selected transport, configuration readiness, capture toggles, recall policy, limits, and non-sensitive counters; checkHeurChainMemoryHealth() is an explicit health probe for a dashboard refresh.
local-brokerconnects to the existing CT203 broker contract.cloud-apiconnects tohttps://api.heurchain.comonly aftercloud.apiKeyandcloud.tenantare supplied by the host. It is intentionally a separate adapter, not a URL substitution for the legacy broker.- Typed memory stores redacted, bounded
fact,procedure, andepisoderecords. Compaction and incident capture can be toggled independently. - Recall is explicit and returned as untrusted context. Automatic prompt recall is shown as unavailable because HarnessRanger has no verified host-owned prompt-injection point for it.
- The older unredacted
heurchain_storeandheurchain_searchlocal-broker compatibility tools are disabled by default (enableLegacyTools: false) and are never registered for Cloud API mode.
{
"heurchain": {
"enabled": true,
"transport": "cloud-api",
"agentName": "openclaw",
"cloud": {
"apiKey": "set-by-host",
"tenant": "set-by-host"
},
"memory": {
"enabled": true,
"captureCompaction": true,
"captureIncidents": true,
"recallMode": "explicit"
}
}
}-
Clone or copy to
~/.openclaw/plugins/harness-ranger -
Add to
openclaw.json:
{
"plugins": {
"allow": ["harness-ranger"],
"entries": {
"harness-ranger": {
"enabled": true,
"config": {
"maxContextTurns": 12,
"maxBudgetTokens": 4000,
"compactAfterTurns": 16,
"semanticMatchingThreshold": 0.6
}
}
}
}
}- Install dependencies:
cd ~/.openclaw/plugins/harness-ranger
npm installRegister tools with metadata:
plugin.registerTool('analyze-code', codeAnalyzer, {
description: 'Analyzes source code for patterns and issues',
category: 'analysis',
tags: ['code', 'patterns', 'linting'],
permission: 'user'
});Find tools using semantic matching:
const matches = plugin.findTools('analyze my python code', {
category: 'analysis',
recentToolNames: ['code-review']
});
// Returns tools sorted by relevance scoreThe plugin automatically checks permissions before tool execution:
const result = await plugin.beforeToolExecution('analyze-code', params, {
user: { id: 'user123', roles: ['developer'] },
resource: '/path/to/code',
sessionId: 'sess-456'
});
if (!result.allowed) {
console.log(`Denied: ${result.reason}`);
}Sessions automatically compact when token budgets are exceeded:
const session = await plugin.getSession('sess-456');
// Compaction happens automatically if needed
plugin.addTurn('sess-456', 'Analyze this code', 'Here\'s the analysis...', []);Stream responses with structured events:
for await (const event of plugin.streamResponse(generator, {
sessionId: 'sess-456'
})) {
switch (event.type) {
case 'message_start':
console.log('Starting response...');
break;
case 'message_delta':
console.log('Content:', event.content);
break;
case 'message_stop':
console.log(`Complete (${event.totalTokens} tokens)`);
break;
}
}{
// Session management
maxContextTurns: 12, // Keep last N turns in memory
maxBudgetTokens: 4000, // Max tokens before compaction
compactAfterTurns: 16, // Force compact after this many turns
// Tool discovery
semanticMatchingThreshold: 0.6, // Min score for tool matches (0-1)
// Storage
sessionDir: '.openclaw/sessions', // Where to persist sessions
// Security
deniedTools: ['exec', 'shell'], // Tools that are always denied
restrictedResources: {
'admin-panel': ['root-user'] // Tool -> allowed resources
}
}Central registry with discoverable capabilities, metadata-driven tool dispatch, and permission-aware filtering.
const registry = plugin.toolRegistry;
registry.registerTool(name, handler, metadata);
const matches = registry.findTools(query, context);Contextual permission checks before tool execution with support for user roles, resource restrictions, and rate limiting.
const permission = plugin.permissionContext.canExecute(
toolName, user, resource
);Token-aware session management with automatic compaction, usage tracking, and conversation replay.
The deterministic compaction fallback preserves bounded structured rows, code, and date-bearing lines rather than replacing structured values with a placeholder. The composed prompt also includes a context_preservation section so model-backed compaction retains answer-bearing tables, schedules, tool results, state changes, and temporal anchors.
const session = plugin.sessionManager.getSession(sessionId);
plugin.sessionManager.recordToolCall(sessionId, toolName, params);Structured event streaming with clear visibility into decision-making: message_start → command_match → tool_match → message_delta → message_stop
for await (const event of plugin.streamResponse(generator, context)) {
// Handle different event types
}npm run build:release # Generate and validate all harness bundles
npm run lint:release # Lint release-owned JavaScript
npm test # Run the full unit suite
npm run test:install # Verify the plugin export and parseability
npm pack --dry-run --json # Verify the published-package boundaryGitHub Actions workflows included:
- ci.yml - Lint, test, build, security audit
- code-review.yml - Automated PR code review with analysis
initialize(runtime)- Initialize with OpenClaw runtimefindTools(query, context)- Find tools by semantic matchgetSession(sessionId)- Get or create sessionregisterTool(name, handler, metadata)- Register custom toolstreamResponse(generator, context)- Stream with structured eventsgetStatus()- Get plugin metrics and status
getEvolutionStatus()- Inspect feature mode and lifecycle stategetActiveArtifactVersion(host, artifactId, sessionId?)- Resolve stable or session-sticky versionsgetEvolutionPointers(host, artifactId)- Inspect stable, canary, and rollback pointerslistEvolutionCandidates(filters)- List immutable candidate manifestsevaluateEvolutionCandidate(version, metrics)- Apply offline evidence gatestriageEvolutionResults(results)- Diagnose offline context, selection, answer, judge, and safety failure stagesplanEvolutionReplay(results, options?)- Produce an offline targeted-stage rerun plan without invoking a host or modelcacheEvolutionStage(stage, input, output)- Persist a redacted immutable offline stage resultgetCachedEvolutionStage(stage, input)- Retrieve a cached offline stage result without changing itbenchmarkHostAdapter(host, eventName, payloads, options?)- Measure deterministic adapter normalization; optional recorded baselines exclude fixture payloadsselectEvolutionEvidence(query, evidence, options?)- Select a bounded multi-evidence union and report uncovered needssearchTemporalEvolutionEvidence(query, evidence, options?)- Search date-tagged evidence only when temporal routing appliesgetEvidenceProviderDashboard()- Dashboard-safe readiness matrix for the four future host providersregisterEvidenceProvider(provider)- Register explicit future-stage handlers without enabling retrievalgetJudgeDashboard()- Dashboard-safe offline judge configuration, model profiles, and worker readinesscheckJudgeHealth()- Explicitly health-check the offline judge worker; never runs in a hookrunJudgeEvaluation(input)- Explicitly run and cache one bounded, redacted offline judge casestartEvolutionCanary(version, metrics)- Start a passing fresh-session canarypromoteEvolutionCanary(host, artifactId, metrics)- Promote after live evidence passesrollbackEvolution(host, artifactId, version?)- Restore a prior stable versiongetEvolvedToolDescriptions(sessionId)- Resolve versioned tool descriptions
Live metrics are process-local snapshots exposed by getMetricsCollector(): numeric tool-call status counts, permission decisions, observed tool lifecycle latency, tracked-session count, compaction count, and hook/tool errors. They are operational observations, not task-success evidence; use paired offline or canary outcomes for impact claims.
The runtime records the operational metrics above automatically through its normal hooks. It does not include an autonomous corpus-tuning cron or infer that latency, tool success, or judge output means the agent completed a user task. Calibrated outcome ingestion must be supplied explicitly by the host or evaluator as labeled task results.
Once a host supplies those labels, run offline evaluation and canary analysis as a separate, operator-scheduled job (for example, scheduled CI or a platform scheduler), never from a request-path hook. A scheduled job may collect bounded, redacted evidence and evaluate a candidate, but promotion must remain evidence-gated; without host-provided outcome labels, it must report insufficient evidence and make no tuning or promotion decision.
Full configuration and examples are in the evidence-gated evolution guide.
registerTool(name, handler, metadata)findTools(query, context)getTool(name)getToolMetadata(name)listTools(filter)updateToolMetadata(name, updates)removeTool(name)export()
canExecute(toolName, user, resource)denyTool(toolName)allowTool(toolName)restrictResource(toolName, resources)getDeniedTools()
getSession(sessionId)addTurn(sessionId, userMsg, assistantMsg, toolCalls)recordToolCall(sessionId, toolName, params)recordToolResult(sessionId, toolName, result)shouldCompact(sessionId)compactSession(sessionId)saveSession(sessionId)loadSession(sessionId)deleteSession(sessionId)listSessions()
- Create a branch for your feature
- Make changes and add tests
- Run
npm test && npm run lint - Push and create a PR
- CI/CD pipeline runs automatically with code review feedback
Coding agents must read the repository-level AGENTS.md. Changes under self-improvement/ must also follow the scoped self-improvement agent instructions, which define the telemetry, evidence, promotion, rollback, dependency, and validation invariants for this feature.
OpenAI GPT-5.6 through Codex provided significant engineering input during the July 20–21, 2026 up-revision and refactoring of HarnessRanger, including its evaluation-harness additions. See AI-Assisted Development Attribution for the credited areas, implemented features, and provenance notes.
MIT