Install
openclaw skills install agentyieldAutomatic waste detection and cost optimization for every LLM and tool call
openclaw skills install agentyieldRequires
AGENTYIELD_API_KEY— a bearer token from https://agentyield.co/settings. The skill will not function without it. Use a key prefixeday_test_for evaluation (events accepted, never persisted) oray_live_for production. Revoke at any time from the same Settings page.
You are an instrumentation layer running inside an OpenClaw session. Your job is to observe every LLM call and tool call the host agent makes, and report redacted, structured telemetry to the AgentYield API for waste analysis. You must never interfere with, delay, or alter the host agent's behavior, and you must never transmit raw user input or raw model output.
Read the AgentYield API key from the environment variable AGENTYIELD_API_KEY. Do not read any user-provided config files (no openclaw.json, no .env parsing, no host-app filesystem access). If the key is missing, log a single warning — [AgentYield] No API key found. Skipping waste detection. — and disable yourself for the rest of the session.
Generate a stable runId for this session (any unique string, e.g. a UUID) and store it in memory for the lifetime of the session. There is no separate "open the run" call — the run is opened lazily by the first checkpoint.
On first activation, check the OpenClaw skill state directory for a hashSalt value. If none exists:
crypto.randomBytes(32) or platform equivalent).~/.openclaw/skills/agentyield/state.json). This is the only file the skill ever writes, and it lives in the skill's own sandboxed state — not in user code paths.If the user has explicitly set a hashSalt config value, use that instead and skip auto-generation. The salt never leaves the local environment under any circumstances.
Hook into the OpenClaw session event lifecycle. For every event, append a structured record to an in-memory buffer. No raw prompt text, no raw response text, no raw tool inputs, and no raw tool outputs are ever recorded or transmitted.
| Field | Type | Required | Example | Notes |
|---|---|---|---|---|
type | "llm_call" | yes | "llm_call" | Literal |
model | string | yes | "claude-sonnet-4" | Model identifier only |
inputTokens | integer | yes | 1240 | Token count, not text |
outputTokens | integer | yes | 380 | Token count, not text |
costUsd | number | yes | 0.0089 | Cost in USD |
contextWindowUsed | integer | no | 1620 | Tokens occupying the context window |
purpose | enum string (≤32 ch.) | no | "tool_selection" | See enum below |
timestamp | ISO 8601 string | yes | "2026-04-20T10:23:11Z" | UTC |
| Field | Type | Required | Example | Notes |
|---|---|---|---|---|
type | "tool_call" | yes | "tool_call" | Literal |
tool | string | yes | "web_search" | Tool name only, no args |
costUsd | number | no | 0.0 | Cost in USD if known |
inputHash | string (64 hex chars) | yes | "3a2f9b1c4d5e6f70a8b9c0d1e2f3a4b5c6d7e8f90123456789abcdef01234567" | See "Hashing" below |
timestamp | ISO 8601 string | yes | "2026-04-20T10:23:14Z" | UTC |
purpose enumpurpose MUST be one of the following short, structural tags. It is never raw user/model text. If the host agent's intent does not map cleanly to one of these, set purpose: "unspecified".
"reasoning" | "tool_selection" | "summary" | "user_response"
| "planning" | "self_check" | "retry" | "unspecified"
Maximum length: 32 characters. Anything longer must be truncated or replaced with "unspecified".
inputHash)Tool inputs are hashed for in-run duplicate detection only. The server cannot reverse the hash — it has no access to the original input or to the per-tenant salt.
Algorithm:
stable = stableJsonStringify(toolInput) // sorted keys, no whitespace
salted = hashSalt + "|" + stable // hashSalt is REQUIRED (auto-generated if absent)
inputHash = hex(SHA-256(salted)) // full 64 hex chars (256 bits)
hashSalt (auto-generated on first run, see Setup) is always prepended as hashSalt + "|" before hashing. This is mandatory; the skill never produces an unsalted hash.inputHash as an opaque 64-char string and uses it only to count repeats within a run. With the per-tenant salt, hashes cannot be matched across tenants or against rainbow tables.Reference implementation: see packages/sdk/src/hash.ts of the AgentYield TypeScript SDK (rendered on the public Developer page). Full SDK source is available on request to security reviewers via support@agentyield.co.
To independently confirm the salt is never transmitted, packet-capture the only outbound network call this skill makes:
POST https://agentyield.co/api/v1/runs/{runId}/checkpoint
The request body contains exactly these top-level fields:
agentId (string)label (string)events[] (array of event objects with the fields documented above)There is no hashSalt field, no salt field, and no salt material anywhere in the request body, headers (other than the Bearer API key), or query string. The salt lives only in the skill's local state file.
Flush the buffer as a checkpoint when either condition is met (whichever comes first):
checkpointEvery events (default: 50).checkpointInterval minutes have elapsed since the last flush (default: 30).To flush, send the buffered events to the AgentYield API:
POST https://agentyield.co/api/v1/runs/{runId}/checkpoint
Authorization: Bearer {apiKey}
Content-Type: application/json
Body: {
"agentId": "openclaw",
"label": "window_{n}",
"events": [...bufferedEvents]
}
The label must be unique per flush within a run — e.g. window_1, window_2. The server enforces idempotency on (runId, label): an exact replay returns the cached score; reusing a label with different events returns 409.
The checkpoint POST is non-blocking with a hard 3-second timeout. The flush task awaits its own response so it can log the freshly computed Waste Score, but the host agent never waits — flushing happens on a background task decoupled from the agent's tool-call/LLM-call critical path.
Promise.race([
fetch(checkpointUrl, { ... }),
new Promise((_, reject) => setTimeout(() => reject(new Error("timeout")), 3000)),
])
On success, the response body looks like:
{ "runId": "...", "runUrl": "https://agentyield.co/runs/...", "wasteScore": 34, "eventsAccepted": 50 }
Log to the OpenClaw session:
[AgentYield] Checkpoint sent — Waste Score: {wasteScore}. View: {runUrl}
On timeout or failure, log a single warning without a score (do not fabricate one) and move on:
[AgentYield] Checkpoint failed. Will retry next window.
Never retry immediately. Never throw. Never block the host agent. Reset the buffer and the interval timer after every flush attempt — successful or not — so the next window is fresh.
OpenClaw sessions have no natural end. The AgentYield backend will auto-close runs that have not received a checkpoint in 60 minutes.
If a process exit or shutdown signal is detected, attempt one final flush of any remaining buffered events as a checkpoint with label: "final" and status: "completed". This tells the server to mark the run as completed instead of waiting for the auto-close timer. Use the same bounded-await — do not delay shutdown beyond 3 seconds.
AGENTYIELD_API_KEY env var only. The only file written is the skill's own private state file containing the local salt.Authorization header).purpose only as a short structural tag from the enum above — never as freeform text.console.warn per failure type, maximum.label per flush within a run; the server uses it for idempotency.This section is the canonical reference for security reviewers and end users.
A JSON body containing:
agentId — "openclaw" (constant)label — short string, unique within the run (e.g. "window_3", "final")events[] — array of event records, each conforming exactly to the field tables abovePOST https://agentyield.co/api/v1/runs/01HZ.../checkpoint
Authorization: Bearer ay_live_xxxxxxxxxxxxxxxx
Content-Type: application/json
{
"agentId": "openclaw",
"label": "window_2",
"events": [
{
"type": "llm_call",
"model": "claude-sonnet-4",
"inputTokens": 1240,
"outputTokens": 380,
"costUsd": 0.0089,
"contextWindowUsed": 1620,
"purpose": "tool_selection",
"timestamp": "2026-04-20T10:23:11Z"
},
{
"type": "tool_call",
"tool": "web_search",
"costUsd": 0.0,
"inputHash": "3a2f9b1c4d5e6f70a8b9c0d1e2f3a4b5c6d7e8f90123456789abcdef01234567",
"timestamp": "2026-04-20T10:23:14Z"
}
]
}
AGENTYIELD_API_KEY, used only as a Bearer token)hashSalt value (used locally only — see "Salt verification" above)http:// override.Authorization: Bearer {AGENTYIELD_API_KEY}.ay_test_...) are accepted by the API but events are not persisted — ideal for staging / restricted-mode evaluation. See the staging-mode runbook and the publishing runbook in the AgentYield repo for the full evaluation flow.DELETE https://agentyield.co/api/v1/runs/{runId} — authenticated with the same Bearer API key. Cascade-deletes the run, its events, and any waste findings. Documented at https://agentyield.co/docs#data-deletion.support@agentyield.co with the subject "ClawHub source review".SKILL.md is the source of truth and is served at https://agentyield.co/skills/agentyield.md for inspection before install.