hedera-consensus-service — скилл для Claude Code: топики и сообщения
Скилл учит агента работать с Hedera Consensus Service на JavaScript: создавать топики, отправлять сообщения и слушать поток через mirror node.
npx skills add hedera-dev/hedera-skills --skill hedera-consensus-service -a claude-codeЧто делает hedera-consensus-service
Скилл описывает HCS как упорядоченный лог сообщений с консенсусными метками времени. Внутри — готовые шаблоны на @hiero-ledger/sdk: создание топика, отправка сообщения, подписка на поток, кастомные сборы за сообщение и разбивка крупных сообщений на чанки.
Агенту объясняют две схемы подключения: через Client.forName с setOperator и через Wallet с LocalProvider. Для signer-варианта используются freezeWithSigner, signWithSigner, executeWithSigner и getReceiptWithSigner. Есть разбор поведения ключей: без adminKey топик не обновить и не удалить, без submitKey писать может кто угодно.
Одна деталь, на которой легко споткнуться: после создания топика подписку нужно отложить на несколько секунд, иначе mirror node ещё не успеет синхронизировать новый топик. Сообщения длиннее 1024 байт SDK режет на чанки сам, а при подписке собирает обратно. Для работы понадобятся OPERATOR_ID и OPERATOR_KEY в окружении.
Какие задачи решает
- создать топик HCS с ключами администратора и отправки
- отправить сообщение в топик и получить номер последовательности
- подписаться на поток сообщений через mirror node
- настроить фиксированный сбор за сообщение и лимит оплаты
- отправить сообщение больше 1024 байт чанками
Примеры запросов агенту
- создай топик Hedera с memo «журнал событий» и adminKey из OPERATOR_KEY
- отправь в топик строку «Hello, Hedera!» и покажи topicSequenceNumber
- подпишись на топик с setStartTime(0) и выведи consensusTimestamp каждого сообщения
Как установить hedera-consensus-service
1Через Skills CLI (Vercel)
npx skills add hedera-dev/hedera-skills --skill hedera-consensus-service -a claude-code2Вручную: положить файлы
~/.claude/skills/hedera-consensus-service/SKILL.mdПапка скилла целиком; для одного проекта — .claude/skills/hedera-consensus-service/
1Через Skills CLI (Vercel)
npx skills add hedera-dev/hedera-skills --skill hedera-consensus-service -a codex2Вручную: положить файлы
.agents/skills/hedera-consensus-service/SKILL.mdДля всех проектов — ~/.agents/skills/
1Через Skills CLI (Vercel)
npx skills add hedera-dev/hedera-skills --skill hedera-consensus-service -a cursor2Вручную: положить файлы
.cursor/skills/hedera-consensus-service/SKILL.mdCursor читает и .agents/skills/, и .claude/skills/
1GitHub CLI
gh skill install hedera-dev/hedera-skills hedera-consensus-service2Вручную: положить файлы
.github/skills/hedera-consensus-service/SKILL.md1Через Skills CLI (Vercel)
npx skills add hedera-dev/hedera-skills --skill hedera-consensus-service -a gemini-cli2Командой платформы
gemini skills install https://github.com/hedera-dev/hedera-skills --path plugins/native-services-js/skills/hedera-consensus-serviceВручную: положить файлы
.devin/skills/hedera-consensus-service/SKILL.mdСтарый путь .windsurf/skills/ тоже читается
Через Skills CLI (Vercel)
npx skills add hedera-dev/hedera-skills --skill hedera-consensus-service -a opencodeClaude.ai
Упакуйте папку в zip и загрузите в Settings → Capabilities → Skills
По шагам, с командами для каждой платформы: Как установить скилл в Claude Code: пять способов
Вопросы о hedera-consensus-service
Как установить hedera-consensus-service в Claude?
Выполните npx skills add hedera-dev/hedera-skills --skill hedera-consensus-service -a claude-code. Скилл появится в ~/.claude/skills/hedera-consensus-service/SKILL.md.
Что делает hedera-consensus-service?
Даёт агенту шаблоны для Hedera Consensus Service: создание топиков, отправку сообщений, подписку на поток, кастомные сборы и чанки для крупных сообщений.
Что нужно для работы скилла?
Переменные окружения OPERATOR_ID и OPERATOR_KEY, а также пакет @hiero-ledger/sdk — все примеры в скилле на JavaScript и TypeScript.
Исходный текст
SKILL.md · Apache-2.0
---
name: hedera-consensus-service
description: "How to create topics, submit messages, and subscribe to real-time message streams on Hedera using the Hiero JavaScript SDK (@hiero-ledger/sdk). Use this skill whenever the user wants to work with Hedera Consensus Service (HCS), including topic creation, message submission, pub/sub messaging, mirror node subscriptions, chunked large messages, topic fees, or any consensus-related operation in JavaScript or TypeScript. Also trigger when users mention @hashgraph/sdk topic operations, event logging on Hedera, decentralized messaging, audit trails, or ordered message streams."
---
# Hedera Consensus Service (HCS) — JavaScript SDK
HCS provides a decentralized, ordered message log with consensus timestamps. It works like a pub/sub system: you create **topics**, **submit messages** to them, and **subscribe** to receive messages in real time via mirror nodes. Messages are immutable, ordered, and timestamped by network consensus — useful for audit trails, event logs, supply chain tracking, and decentralized communication.
## Setup
All imports come from `@hiero-ledger/sdk`. Two setup patterns:
### Client + setOperator (direct)
```js
import { Client, AccountId, PrivateKey } from "@hiero-ledger/sdk";
const client = Client.forName(process.env.HEDERA_NETWORK)
.setOperator(
AccountId.fromString(process.env.OPERATOR_ID),
PrivateKey.fromStringECDSA(process.env.OPERATOR_KEY),
);
```
### Wallet + LocalProvider (signer-based)
```js
import { Wallet, LocalProvider } from "@hiero-ledger/sdk";
const provider = new LocalProvider();
const wallet = new Wallet(process.env.OPERATOR_ID, process.env.OPERATOR_KEY, provider);
```
With the signer pattern, use `freezeWithSigner(wallet)`, `signWithSigner(wallet)`, `executeWithSigner(wallet)`, and `getReceiptWithSigner(wallet)`.
## Creating a Topic
```js
import { TopicCreateTransaction } from "@hiero-ledger/sdk";
const { topicId } = await (
await new TopicCreateTransaction()
.setTopicMemo("My event log")
.setAdminKey(operatorKey) // allows update/delete
.setSubmitKey(operatorKey) // restricts who can post
.execute(client)
).getReceipt(client);
console.log(`Topic created: ${topicId.toString()}`);
```
**Key behaviors**:
- Without an `adminKey`, the topic cannot be updated or deleted (only expiration can be extended).
- Without a `submitKey`, anyone can submit messages.
- Default auto-renew period is 90 days.
### Topic with Custom Fees
Topics can charge per-message fees (Hbar or token-denominated):
```js
import { TopicCreateTransaction, CustomFixedFee, Hbar } from "@hiero-ledger/sdk";
const fee = new CustomFixedFee()
.setAmount(new Hbar(1).toTinybars())
.setFeeCollectorAccountId(collectorId);
const { topicId } = await (
await new TopicCreateTransaction()
.setAdminKey(operatorKey)
.setSubmitKey(operatorKey)
.setFeeScheduleKey(operatorKey)
.setCustomFees([fee])
.addFeeExemptKey(trustedKey) // this key skips fees
.execute(client)
).getReceipt(client);
```
When paying custom fees, submitters can set a maximum they're willing to pay:
```js
import { CustomFeeLimit, CustomFixedFee, Hbar, HbarUnit } from "@hiero-ledger/sdk";
const limit = new CustomFeeLimit()
.setAccountId(payerId)
.setFees([
new CustomFixedFee().setAmount(Hbar.from(2, HbarUnit.Hbar).toTinybars())
]);
await new TopicMessageSubmitTransaction()
.setTopicId(topicId)
.setMessage("Hello")
.setCustomFeeLimits([limit])
.execute(client);
```
## Submitting Messages
```js
import { TopicMessageSubmitTransaction } from "@hiero-ledger/sdk";
const response = await new TopicMessageSubmitTransaction()
.setTopicId(topicId)
.setMessage("Hello, Hedera!")
.execute(client);
const receipt = await response.getReceipt(client);
console.log(`Sequence: ${receipt.topicSequenceNumber}`);
```
Messages can be `string` or `Uint8Array`. The receipt contains `topicSequenceNumber` (incremented per message) and `topicRunningHash`.
### When a submit key exists
If the topic has a submit key, messages must be signed by it:
```js
await (
await new TopicMessageSubmitTransaction()
.setTopicId(topicId)
.setMessage("Authorized message")
.freezeWith(client)
.sign(submitKey)
).execute(client);
```
## Subscribing to Messages
The `TopicMessageQuery` creates a real-time subscription via the mirror node. Messages arrive as they reach consensus.
```js
import { TopicMessageQuery } from "@hiero-ledger/sdk";
const handle = new TopicMessageQuery()
.setTopicId(topicId)
.setStartTime(0) // from the beginning
.subscribe(
client,
(message, error) => console.error("Error:", error),
(message) => {
console.log(
`[${message.consensusTimestamp}] #${message.sequenceNumber}: ` +
Buffer.from(message.contents).toString("utf8")
);
},
);
// Later, to stop receiving:
handle.unsubscribe();
```
**Important**: After creating a topic, wait a few seconds before subscribing — the mirror node needs time to sync the new topic.
### Subscription Options
```js
new TopicMessageQuery()
.setTopicId(topicId)
.setStartTime(startTimestamp) // receive from this time forward
.setEndTime(endTimestamp) // stop after this time
.setLimit(100) // max messages to receive
.setMaxAttempts(20) // retry attempts (default: 20)
.setMaxBackoff(8000) // max retry delay ms (default: 8000)
.setErrorHandler((msg, err) => {}) // error callback
.setCompletionHandler(() => {}) // fires when limit/endTime reached
.subscribe(client, errorHandler, messageHandler);
```
### TopicMessage Properties
Each received `TopicMessage` has:
- `consensusTimestamp` — when the message reached consensus
- `contents` — `Uint8Array` message body (automatically reassembled from chunks)
- `sequenceNumber` — position in the topic (starts at 1)
- `runningHash` — SHA-384 running hash of the topic at this message
- `chunks` — individual `TopicMessageChunk[]` if the message was chunked
- `initialTransactionId` — original transaction ID (for chunked messages)
## Chunked Messages
Messages larger than 1024 bytes are automatically split into chunks. Each chunk is a separate transaction on the network. The SDK handles splitting on submit and reassembly on subscribe.
```js
const largeMessage = "x".repeat(5000); // 5KB message
// Option 1: execute() returns first chunk's response
const response = await new TopicMessageSubmitTransaction()
.setTopicId(topicId)
.setMessage(largeMessage)
.execute(client);
// Option 2: executeAll() returns all chunk responses
const responses = await new TopicMessageSubmitTransaction()
.setTopicId(topicId)
.setMessage(largeMessage)
.setMaxChunks(30) // default: 20 (max ~20KB at 1024/chunk)
.setChunkSize(2048) // override chunk size (default: 1024)
.executeAll(client);
for (const resp of responses) {
const receipt = await resp.getReceipt(client);
console.log(`Chunk seq: ${receipt.topicSequenceNumber}`);
}
```
**Limits**:
- Default chunk size: 1024 bytes
- Default max chunks: 20 (so ~20KB max message by default)
- Configurable via `setChunkSize()` and `setMaxChunks()`
- Subscribers automatically reassemble chunks into a single `TopicMessage`
## Updating a Topic
```js
import { TopicUpdateTransaction } from "@hiero-ledger/sdk";
await new TopicUpdateTransaction()
.setTopicId(topicId)
.setTopicMemo("Updated memo")
.setSubmitKey(newSubmitKey)
.execute(client);
```
All update operations require the admin key. Key-specific updates:
- Changing the admin key requires both old and new admin keys to sign
- Setting a new auto-renew account requires that account to sign
- You can clear keys with `clearAdminKey()`, `clearSubmitKey()`, etc.
### Updating Topic Fees
```js
await new TopicUpdateTransaction()
.setTopicId(topicId)
.setCustomFees([newFee])
.addFeeExemptKey(anotherKey)
.execute(client);
```
## Deleting a Topic
```js
import { TopicDeleteTransaction } from "@hiero-ledger/sdk";
await new TopicDeleteTransaction()
.setTopicId(topicId)
.execute(client);
```
Requires the admin key. After deletion, no operations on the topic will succeed.
## Querying Topic Info
```js
import { TopicInfoQuery } from "@hiero-ledger/sdk";
const info = await new TopicInfoQuery()
.setTopicId(topicId)
.execute(client);
console.log(`Memo: ${info.topicMemo}`);
console.log(`Sequence: ${info.sequenceNumber}`);
console.log(`Admin key: ${info.adminKey}`);
console.log(`Submit key: ${info.submitKey}`);
```
See `references/api-reference.md` for the full `TopicInfo` property list.
## Key Roles
| Key | Purpose |
|-----|---------|
| `adminKey` | Update/delete the topic; rotate other keys |
| `submitKey` | Authorize message submission (if absent, open to all) |
| `feeScheduleKey` | Update custom fee schedule |
## Common Patterns
### Event Log / Audit Trail
Create a topic per entity or event type. Submit structured JSON messages. Subscribe from a service to build a read model.
```js
const event = JSON.stringify({
type: "ORDER_PLACED",
orderId: "12345",
timestamp: Date.now(),
data: { items: 3, total: 99.99 },
});
await new TopicMessageSubmitTransaction()
.setTopicId(ordersTopic)
.setMessage(event)
.execute(client);
```
### Pub/Sub with Multiple Subscribers
Multiple services can subscribe to the same topic independently. Each maintains its own cursor via `setStartTime`.
```js
// Service A: process all messages from the beginning
new TopicMessageQuery()
.setTopicId(topicId)
.setStartTime(0)
.subscribe(client, null, processMessage);
// Service B: only new messages from now
new TopicMessageQuery()
.setTopicId(topicId)
.subscribe(client, null, processMessage);
```
## Common Gotchas
1. **Mirror node sync delay**: After creating a topic, wait 3-5 seconds before subscribing. The mirror node needs time to index the new topic.
2. **Chunk reassembly is automatic**: When subscribing, you receive complete messages even if they were submitted as multiple chunks. The SDK handles reassembly.
3. **No `execute()` for subscriptions**: `TopicMessageQuery` uses `.subscribe()`, not `.execute()`. It returns a `SubscriptionHandle`, not a `TransactionResponse`.
4. **Messages are immutable**: Once submitted, messages cannot be edited or deleted. Design your message schema with this in mind.
5. **Sequence numbers start at 1**: The first message on a topic gets sequence number 1, not 0.
6. **Submit key means access control**: If you set a submit key, only holders of that key can post. Omit it for open topics.
7. **String vs Uint8Array**: `setMessage()` accepts both. Use `Buffer.from(message.contents).toString("utf8")` to decode on the subscriber side.
8. **Cleanup**: Always call `handle.unsubscribe()` when done, and `client.close()` when shutting down.
## Reference Files
- `references/api-reference.md` — Complete list of all HCS classes with their methods and properties
© hedera-dev · Apache-2.0 · hedera-dev/hedera-skills