Hedera Policy Creation — скилл для Claude Code: что делает
Помогает создавать блокирующие правила валидации для Hedera Agent Kit. Пригодится при настройке лимитов сумм, списков разрешённых аккаунтов и ограничений частоты вызовов.
npx skills add hedera-dev/hedera-skills --skill hedera-policy-creation -a claude-code
npx skills add hedera-dev/hedera-skills --skill agent-kit-policy -a claude-codeЧто делает Hedera Policy Creation
Скилл обучает агента писать правила валидации, прерывающие выполнение операций в Hedera Agent Kit через выброс ошибок. В основе лежит класс AbstractPolicy, который расширяет AbstractHook. Разработчик переопределяет методы проверки на разных этапах жизненного цикла инструмента: до запуска с сырыми параметрами через shouldBlockPreToolExecution, после нормализации значений или перед отправкой сформированной транзакции.
Политики регистрируются в массиве Context.hooks наряду с обычными наблюдателями. Проверка срабатывает по цепочке, и первое вернувшее true правило останавливает работу инструмента с передачей ошибки агенту. В методах нужно обязательно фильтровать входящий вызов по relevantTools, потому что библиотека вызывает политику для каждого инструмента.
Инструменты, реализующие интерфейс Tool напрямую в обход BaseTool, полностью игнорируют политики. Для неблокирующего аудита и логирования вместо политик документация предписывает использовать хуки.
Какие задачи решает
- блокировать вызовы инструментов Hedera при нарушении условий
- ограничить число получателей при переводах и аирдропах
- настроить лимиты на суммы транзакций в HBAR и токенах
- запретить выполнение операций вне разрешённых часов
Примеры запросов агенту
- «Напиши класс политики для Hedera Agent Kit, блокирующий переводы HBAR выше порога»
- «Создай правило на основе AbstractPolicy для проверки белого списка аккаунтов»
- «Как добавить ограничение частоты вызова для инструментов Hedera Agent Kit?»
Как установить Hedera Policy Creation
1Через Skills CLI (Vercel)
npx skills add hedera-dev/hedera-skills --skill hedera-policy-creation -a claude-codenpx skills add hedera-dev/hedera-skills --skill agent-kit-policy -a claude-code2Вручную: положить файлы
~/.claude/skills/agent-kit-policy/SKILL.mdПапка скилла целиком; для одного проекта — .claude/skills/agent-kit-policy/
1Через Skills CLI (Vercel)
npx skills add hedera-dev/hedera-skills --skill agent-kit-policy -a codex2Вручную: положить файлы
.agents/skills/agent-kit-policy/SKILL.mdДля всех проектов — ~/.agents/skills/
1Через Skills CLI (Vercel)
npx skills add hedera-dev/hedera-skills --skill agent-kit-policy -a cursor2Вручную: положить файлы
.cursor/skills/agent-kit-policy/SKILL.mdCursor читает и .agents/skills/, и .claude/skills/
1GitHub CLI
gh skill install hedera-dev/hedera-skills agent-kit-policy2Вручную: положить файлы
.github/skills/agent-kit-policy/SKILL.md1Через Skills CLI (Vercel)
npx skills add hedera-dev/hedera-skills --skill agent-kit-policy -a gemini-cli2Командой платформы
gemini skills install https://github.com/hedera-dev/hedera-skills --path plugins/agent-kit-plugin/skills/agent-kit-policyВручную: положить файлы
.devin/skills/agent-kit-policy/SKILL.mdСтарый путь .windsurf/skills/ тоже читается
Через Skills CLI (Vercel)
npx skills add hedera-dev/hedera-skills --skill agent-kit-policy -a opencodeClaude.ai
Упакуйте папку в zip и загрузите в Settings → Capabilities → Skills
По шагам, с командами для каждой платформы: Как установить скилл в Claude Code: пять способов
Вопросы о Hedera Policy Creation
Как установить Hedera Policy Creation в Claude Code?
Выполните команду npx skills add hedera-dev/hedera-skills --skill hedera-policy-creation -a claude-code.
Зачем нужен скилл Hedera Policy Creation?
Он помогает проектировать правила валидации для Hedera Agent Kit, прерывающие нежелательные действия агента до отправки транзакций в сеть.
Чем политика отличается от хука в Hedera Agent Kit?
Хук предназначен для пассивного наблюдения, аудита и логирования без остановки вызова. Политика наследует хук, но создана для прерывания работы инструмента через выброс ошибки.
Исходный текст
SKILL.md · Apache-2.0
---
name: Hedera Policy Creation
description: This skill should be used when the user asks to "create a hedera policy", "block a tool", "limit recipients", "extend AbstractPolicy", "reject a tool", "enforce a threshold", "rate limit a tool", "block transfers over X", "allowlist tools", or needs guidance on writing blocking validation rules for Hedera Agent Kit tools. Policies block tool execution by throwing — for non-blocking observation use the hook skill instead.
version: 1.0.0
---
# Creating Hedera Agent Kit Policies
Policies are blocking validation rules layered on the `BaseTool` lifecycle. A policy checks the call at one or more stages and **throws** to abort execution — the error propagates back to the LLM agent. Use them to enforce thresholds, allowlists/blocklists, rate limits, business hours, compliance rules, etc.
> Policies fire **only** for tools that extend `BaseTool`. A tool that implements the `Tool` interface directly without extending `BaseTool` bypasses policies entirely.
## Policy vs. hook
| Goal | Use |
|---|---|
| Stop a call when a condition holds | **Policy** (this skill) |
| Reject specific tool methods | **Policy** |
| Threshold / rate-limit / allowlist / blocklist | **Policy** |
| Log, audit, enrich context | **Hook** (see `agent-kit-hook` skill) |
`AbstractPolicy` extends `AbstractHook`, so policies live in the same `Context.hooks` array and run through the same lifecycle.
Built-in policies live in `@hashgraph/hedera-agent-kit/policies`:
- `RejectToolPolicy(relevantTools: string[])` — blocks the listed tool methods unconditionally
- `MaxRecipientsPolicy(maxRecipients, additionalTools?, customStrategies?)` — caps recipient count for transfer/airdrop tools
## How blocking actually works
You **never** override `preToolExecutionHook` or any of the other `*Hook` methods on a policy — those are wired up by the base class to call your `shouldBlock...` method and throw if it returns `true`.
Override one or more of these instead:
```typescript
abstract class AbstractPolicy extends AbstractHook {
abstract name: string;
abstract description?: string;
abstract relevantTools: string[];
protected shouldBlockPreToolExecution(params, method): boolean | Promise<boolean>;
protected shouldBlockPostParamsNormalization(params, method): boolean | Promise<boolean>;
protected shouldBlockPostCoreAction(params, method): boolean | Promise<boolean>;
protected shouldBlockPostSecondaryAction(params, method): boolean | Promise<boolean>;
}
```
Defaults all return `false` (allow). Returning `true` causes the base class to throw a generic block error. Throwing your own error from `shouldBlock...` lets you control the message.
> **Don't override `preToolExecutionHook` etc.** — those are `@internal` on `AbstractPolicy`. They drive the block flow. If you override them, your policy will never block.
## Picking the stage
| Stage | What's available | Good for |
|---|---|---|
| `shouldBlockPreToolExecution` | `rawParams` only | allowlist/blocklist by tool method, time-based, rate limits |
| `shouldBlockPostParamsNormalization` | `+ normalisedParams` | thresholds on resolved values, recipient counts |
| `shouldBlockPostCoreAction` | `+ coreActionResult` | inspect the built `Transaction` before submission |
| `shouldBlockPostSecondaryAction` | `+ toolResult` | very rare — call already executed; usually too late to "block" |
Most policies live at stage 1 (cheapest) or stage 3 (after defaults are filled in).
## Skeleton
```typescript
import {
AbstractPolicy,
PreToolExecutionParams,
PostParamsNormalizationParams,
} from '@hashgraph/hedera-agent-kit';
export class MyPolicy extends AbstractPolicy {
name = 'My Policy';
description = 'What this policy blocks, in one sentence';
relevantTools = ['transfer_hbar', 'transfer_fungible_token'];
// Stage 1 — block by raw input or method
protected shouldBlockPreToolExecution(
params: PreToolExecutionParams,
method: string,
): boolean {
if (!this.relevantTools.includes(method)) return false;
// throw new Error('<custom message>') for tailored errors
return /* condition */ false;
}
// Stage 3 — block on resolved/normalised values
protected shouldBlockPostParamsNormalization(
params: PostParamsNormalizationParams,
method: string,
): boolean {
if (!this.relevantTools.includes(method)) return false;
return /* condition */ false;
}
}
```
`relevantTools` is informational unless you check it — the kit dispatches your policy for every tool call. Always filter by `method` first thing in the method.
## Registering policies
Policies are `AbstractHook` instances. They go in the same `Context.hooks` array as observation hooks:
```typescript
import { AgentMode } from '@hashgraph/hedera-agent-kit';
import { allCorePlugins } from '@hashgraph/hedera-agent-kit/plugins';
import { RejectToolPolicy, MaxRecipientsPolicy } from '@hashgraph/hedera-agent-kit/policies';
import { HederaLangchainToolkit } from '@hashgraph/hedera-agent-kit-langchain';
import { MyPolicy } from './my-policy';
const toolkit = new HederaLangchainToolkit({
client,
configuration: {
plugins: allCorePlugins,
context: {
mode: AgentMode.AUTONOMOUS,
hooks: [
new RejectToolPolicy(['delete_account', 'freeze_token']),
new MaxRecipientsPolicy(5),
new MyPolicy(),
],
},
},
});
```
Policies run in array order at each stage — the first one to return `true` (or throw) wins.
## Common patterns
### Threshold
```typescript
protected shouldBlockPostParamsNormalization(
params: PostParamsNormalizationParams,
method: string,
): boolean {
if (!this.relevantTools.includes(method)) return false;
const p = params.normalisedParams as { amount?: number };
return (p.amount ?? 0) > this.maxAmount;
}
```
### Allowlist / Blocklist
```typescript
protected shouldBlockPreToolExecution(
params: PreToolExecutionParams,
method: string,
): boolean {
if (!this.relevantTools.includes(method)) return false;
const accountId = (params.rawParams as { accountId?: string }).accountId;
return accountId !== undefined && this.blockedAccounts.has(accountId);
}
```
### Time-based
```typescript
protected shouldBlockPreToolExecution(
_params: PreToolExecutionParams,
method: string,
): boolean {
if (!this.relevantTools.includes(method)) return false;
const hour = new Date().getUTCHours();
return hour < 9 || hour > 17; // outside business hours
}
```
### Rate limiting (uses `Context` as scratchpad)
```typescript
protected shouldBlockPreToolExecution(
params: PreToolExecutionParams,
method: string,
): boolean {
if (!this.relevantTools.includes(method)) return false;
const counters = ((params.context as any).__rateCounts ??= {} as Record<string, number>);
counters[method] = (counters[method] ?? 0) + 1;
return counters[method] > this.maxCallsPerSession;
}
```
### Strategy map (pluggable for custom tools)
When a single policy needs to support tools the kit doesn't know about, accept a `Record<string, (params) => SomeMetric>` and validate that every tool added via `additionalTools` has a strategy. This is the pattern of `MaxRecipientsPolicy`:
```typescript
constructor(
private maxRecipients: number,
additionalTools: string[] = [],
private customStrategies: Record<string, (p: any) => number> = {},
) {
super();
this.relevantTools = [...DEFAULT_TOOLS, ...additionalTools];
for (const tool of additionalTools) {
if (!this.customStrategies[tool]) {
throw new Error(`Custom tool "${tool}" requires a strategy function`);
}
}
}
```
## Custom error messages
The default block error is generic. To control the message, **throw** from your `shouldBlock...` method instead of returning `true`:
```typescript
protected shouldBlockPostParamsNormalization(
params: PostParamsNormalizationParams,
method: string,
): boolean {
if (!this.relevantTools.includes(method)) return false;
const p = params.normalisedParams as { amount?: number };
if ((p.amount ?? 0) > this.maxAmount) {
throw new Error(
`[max-amount-policy] Refusing ${method}: amount ${p.amount} exceeds limit ${this.maxAmount}`,
);
}
return false;
}
```
The agent receives the thrown message verbatim — make it informative.
## Best practices
1. **Filter by `relevantTools`** at the top of every `shouldBlock...` method
2. **Pick the earliest stage** that has the data you need — stage 1 is cheapest
3. **Throw with a clear message** when blocking; the LLM sees this
4. **Don't override `*Hook` methods** — only `shouldBlock...`
5. **Don't do I/O on the hot path** unless you must — policies run synchronously in the lifecycle
6. **Document `relevantTools` defaults** so consumers understand what your policy guards
7. **Tag the error message** with `[<policy-name>]` for easy log correlation
## Resources
- **`references/policy-interface.md`** — full `AbstractPolicy` contract, when each `shouldBlock` fires
- **`examples/max-amount-policy/`** — threshold policy that blocks transfers above a cap
## Common imports
```typescript
import {
AbstractPolicy,
Context,
PreToolExecutionParams,
PostParamsNormalizationParams,
PostCoreActionParams,
PostSecondaryActionParams,
} from '@hashgraph/hedera-agent-kit';
// Built-in implementations live in the /policies subpath
import { RejectToolPolicy, MaxRecipientsPolicy } from '@hashgraph/hedera-agent-kit/policies';
```
© hedera-dev · Apache-2.0 · hedera-dev/hedera-skills