> For the complete documentation index, see [llms.txt](https://canopy-network.gitbook.io/docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://canopy-network.gitbook.io/docs/app-builder/plugin-api-reference.md).

# Plugin API Reference

## Interface

The interface is defined in `plugin/go/contract/plugin.go` and `plugin/go/proto/plugin.proto`. All type definitions below are derived from those files. The Go template is used throughout; the interface contract is identical in the TypeScript, Python, Kotlin, and C# templates.

***

### **Overview**

Your plugin implements five lifecycle methods that Canopy calls during block processing, and uses two state helpers to read and write persistent data. You configure the plugin with a `PluginConfig` struct that tells Canopy which transaction types you handle.

```
PluginConfig          — declares your plugin's identity and transaction types
─────────────────────────────────────────────────────────
Genesis()             — initialize or export state at height 0
BeginBlock()          — called at the start of every block
CheckTx()             — stateless transaction validation (mempool gate)
DeliverTx()           — stateful transaction execution (block application)
EndBlock()            — called at the end of every block
─────────────────────────────────────────────────────────
StateRead()           — read one or more keys from the key-value store
StateWrite()          — write or delete one or more keys in the key-value store
```

***

### **PluginConfig**

Declared as a package-level variable in `contract/contract.go`. Sent to the FSM during the startup handshake. The FSM uses it to route transactions to your plugin and to register your protobuf type descriptors.

```go
var ContractConfig = &PluginConfig{
    Name:                  "go_plugin_contract",  // human-readable identifier
    Id:                    1,                      // unique chain/plugin ID
    Version:               1,                      // plugin version
    SupportedTransactions: []string{"send"},       // transaction names
    TransactionTypeUrls: []string{
        "type.googleapis.com/types.MessageSend",   // matching protobuf type URLs
    },
    EventTypeUrls:         nil,                    // optional: custom event types
    // FileDescriptorProtos is populated automatically in init()
}
```

**Fields**

| Field                   | Type       | Description                                                                                                                      |
| ----------------------- | ---------- | -------------------------------------------------------------------------------------------------------------------------------- |
| `Name`                  | `string`   | Human-readable name for this plugin. Appears in logs.                                                                            |
| `Id`                    | `uint64`   | The chain ID this plugin handles. Must match `chainId` in `config.json`.                                                         |
| `Version`               | `uint64`   | Plugin version. Increment when making breaking changes to your interface.                                                        |
| `SupportedTransactions` | `[]string` | Short names for each transaction type you handle (e.g. `"send"`, `"post_message"`).                                              |
| `TransactionTypeUrls`   | `[]string` | Fully-qualified protobuf type URLs for each transaction message. Must be in the **same order** as `SupportedTransactions`.       |
| `EventTypeUrls`         | `[]string` | Fully-qualified protobuf type URLs for any custom event types you emit. Can be `nil` if you use no custom events.                |
| `FileDescriptorProtos`  | `[][]byte` | Serialized protobuf file descriptors for all your `.proto` files. **Populated automatically in `init()` — do not set manually.** |

**Critical constraint:** `SupportedTransactions[i]` must correspond to `TransactionTypeUrls[i]`. A mismatch causes transactions to route to the wrong handler silently.

***

### **Lifecycle Methods**

#### **Genesis**

```go
func (c *Contract) Genesis(request *PluginGenesisRequest) *PluginGenesisResponse
```

Called once at chain launch (height 0) to initialize state from a genesis JSON document, and optionally at any height to export a state snapshot.

**Input: `PluginGenesisRequest`**

| Field         | Type     | Description                                                               |
| ------------- | -------- | ------------------------------------------------------------------------- |
| `GenesisJson` | `[]byte` | Raw JSON bytes of the genesis document. Parse this to seed initial state. |

**Output: `PluginGenesisResponse`**

| Field   | Type           | Description                                                 |
| ------- | -------------- | ----------------------------------------------------------- |
| `Error` | `*PluginError` | Return `nil` for success. Return an error to abort genesis. |

**What to do here:** Parse `GenesisJson`, unmarshal any initial state objects your app needs (accounts, parameters, counters), and write them to state via `StateWrite`. The default template returns an empty response; implement this when you need a non-empty initial state.

**Can read/write state:** Yes.

***

#### **BeginBlock**

```go
func (c *Contract) BeginBlock(request *PluginBeginRequest) *PluginBeginResponse
```

Called at the start of every block, before any transactions are processed.

**Input: `PluginBeginRequest`**

| Field    | Type     | Description                                  |
| -------- | -------- | -------------------------------------------- |
| `Height` | `uint64` | The height of the block about to be applied. |

**Output: `PluginBeginResponse`**

| Field    | Type           | Description                                         |
| -------- | -------------- | --------------------------------------------------- |
| `Events` | `[]*Event`     | Optional events to emit at the start of this block. |
| `Error`  | `*PluginError` | Return `nil` for success.                           |

**What to do here:** Per-block setup logic. Common uses: storing the current block height on the `Contract` struct so `DeliverTx` can reference it, resetting per-block counters, or checking time-based conditions.

**Storing height for use in DeliverTx:** `PluginDeliverRequest` does not carry a block height field. If your `DeliverTx` needs the current height (e.g. to timestamp a record), capture it here and store it on the `Contract` struct:

```go
func (c *Contract) BeginBlock(req *PluginBeginRequest) *PluginBeginResponse {
    c.currentHeight = req.Height
    return &PluginBeginResponse{}
}
```

**Can read/write state:** Yes.

***

#### **CheckTx**

```go
func (c *Contract) CheckTx(request *PluginCheckRequest) *PluginCheckResponse
```

Called when a transaction arrives at the node's mempool. Runs on every node that receives the transaction. Stateless validation only — cannot write state, and state reads should be used sparingly.

**Input: `PluginCheckRequest`**

| Field | Type           | Description                                                                         |
| ----- | -------------- | ----------------------------------------------------------------------------------- |
| `Tx`  | `*Transaction` | The transaction to validate. Deserialize `Tx.Msg` to get the concrete message type. |

**Output: `PluginCheckResponse`**

| Field               | Type           | Description                                                                                                     |
| ------------------- | -------------- | --------------------------------------------------------------------------------------------------------------- |
| `AuthorizedSigners` | `[][]byte`     | The addresses whose signatures are required on this transaction. The FSM verifies signatures against this list. |
| `Recipient`         | `[]byte`       | Optional. The intended recipient address, if applicable. Used for indexing.                                     |
| `Error`             | `*PluginError` | Return `nil` to accept the transaction into the mempool. Return an error to reject it.                          |

**What to do here:** Validate that the transaction is well-formed — correct address lengths, non-zero amounts, valid field values. Return the `AuthorizedSigners` whose signatures must be present. The FSM performs the actual cryptographic signature verification against this list; you declare who must sign, not whether the signature is valid.

**What not to do here:** Do not write state. Do not make decisions that depend on current balances or other mutable state — those checks belong in `DeliverTx`. `CheckTx` is a fast filter, not the authoritative validation step.

**Can write state:** No. **Can read state:** Technically yes (the default template reads fee params here), but keep reads minimal since `CheckTx` runs on every mempool submission across every node.

**Deserialization pattern:**

```go
msg, err := FromAny(request.Tx.Msg)
if err != nil {
    return &PluginCheckResponse{Error: err}
}
switch x := msg.(type) {
case *MessageSend:
    return c.CheckMessageSend(x)
case *MessagePost:
    return c.CheckMessagePost(x)
default:
    return &PluginCheckResponse{Error: ErrInvalidMessageCast()}
}
```

***

#### **DeliverTx**

```go
func (c *Contract) DeliverTx(request *PluginDeliverRequest) *PluginDeliverResponse
```

Called when a block is applied and a transaction in that block is executed. This is where state changes happen. Runs exactly once per transaction, in order, as part of block application.

**Input: `PluginDeliverRequest`**

| Field | Type           | Description                                                                                                     |
| ----- | -------------- | --------------------------------------------------------------------------------------------------------------- |
| `Tx`  | `*Transaction` | The transaction to execute. Deserialize `Tx.Msg` to get the concrete message type. Use `Tx.Fee` to deduct fees. |

**Output: `PluginDeliverResponse`**

| Field    | Type           | Description                                                                                                                                            |
| -------- | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `Events` | `[]*Event`     | Optional events to emit for this transaction. Indexable and subscribable via WebSocket.                                                                |
| `Error`  | `*PluginError` | Return `nil` for success. Returning an error marks the transaction as failed — but it is still included in the block and **the fee is still charged**. |

**What to do here:** Read the state you need, apply the transaction's effect, write the new state back. The canonical pattern: batch-read all relevant keys in one `StateRead` call, apply logic, batch-write all changes in one `StateWrite` call.

**Can read/write state:** Yes.

**Important: failed DeliverTx still charges fees.** If `DeliverTx` returns an error, the transaction is recorded in the block as failed and the sender's fee is deducted. Design `CheckTx` to catch everything that would cause `DeliverTx` to fail, so bad transactions are rejected before they enter a block.

**Deserialization pattern** (mirrors `CheckTx`):

```go
msg, err := FromAny(request.Tx.Msg)
if err != nil {
    return &PluginDeliverResponse{Error: err}
}
switch x := msg.(type) {
case *MessageSend:
    return c.DeliverMessageSend(x, request.Tx.Fee)
case *MessagePost:
    return c.DeliverMessagePost(x, request.Tx.Fee)
default:
    return &PluginDeliverResponse{Error: ErrInvalidMessageCast()}
}
```

***

#### **EndBlock**

```go
func (c *Contract) EndBlock(request *PluginEndRequest) *PluginEndResponse
```

Called at the end of every block, after all transactions have been applied.

**Input: `PluginEndRequest`**

| Field             | Type     | Description                                            |
| ----------------- | -------- | ------------------------------------------------------ |
| `Height`          | `uint64` | The height of the block that just finished.            |
| `ProposerAddress` | `[]byte` | The address of the validator that proposed this block. |

**Output: `PluginEndResponse`**

| Field    | Type           | Description                                                                                                    |
| -------- | -------------- | -------------------------------------------------------------------------------------------------------------- |
| `Events` | `[]*Event`     | Optional events to emit at the end of this block. A common use is broadcasting state snapshots over WebSocket. |
| `Error`  | `*PluginError` | Return `nil` for success.                                                                                      |

**What to do here:** Per-block finalization logic. Common uses: computing aggregate statistics, emitting a WebSocket broadcast of recent records, rewarding the block proposer, expiring time-limited state. The default template returns an empty response.

**Can read/write state:** Yes.

***

### **State Operations**

The plugin never talks to a database directly. All persistent state goes through two functions that communicate with the FSM over the socket connection.

***

#### **StateRead**

```go
func StateRead(c *Contract, request *PluginStateReadRequest) (*PluginStateReadResponse, *PluginError)
```

Reads one or more keys or key ranges from the FSM's key-value store in a single batched call.

**Input: `PluginStateReadRequest`**

| Field    | Type                 | Description                                              |
| -------- | -------------------- | -------------------------------------------------------- |
| `Keys`   | `[]*PluginKeyRead`   | Point lookups — fetch a specific key by its exact bytes. |
| `Ranges` | `[]*PluginRangeRead` | Range scans — fetch all keys matching a prefix.          |

**`PluginKeyRead`**

| Field     | Type     | Description                                                                                               |
| --------- | -------- | --------------------------------------------------------------------------------------------------------- |
| `QueryId` | `uint64` | A caller-assigned ID used to match results back to requests. Use `rand.Uint64()` or a sequential counter. |
| `Key`     | `[]byte` | The exact state key to look up.                                                                           |

**`PluginRangeRead`**

| Field     | Type     | Description                                                                |
| --------- | -------- | -------------------------------------------------------------------------- |
| `QueryId` | `uint64` | Caller-assigned ID for matching results.                                   |
| `Prefix`  | `[]byte` | Key prefix to scan. Returns all entries whose key starts with this prefix. |
| `Limit`   | `uint64` | Maximum number of entries to return. Use `0` for no limit.                 |
| `Reverse` | `bool`   | If `true`, entries are returned in descending key order.                   |

**Output: `PluginStateReadResponse`**

| Field     | Type                  | Description                                       |
| --------- | --------------------- | ------------------------------------------------- |
| `Results` | `[]*PluginReadResult` | One result entry per query, matched by `QueryId`. |
| `Error`   | `*PluginError`        | Non-nil if the FSM encountered an error.          |

**`PluginReadResult`**

| Field     | Type                  | Description                                                          |
| --------- | --------------------- | -------------------------------------------------------------------- |
| `QueryId` | `uint64`              | Matches the `QueryId` from the request.                              |
| `Entries` | `[]*PluginStateEntry` | The matching key-value pairs. Empty slice if the key does not exist. |

**`PluginStateEntry`**

| Field   | Type     | Description                                                         |
| ------- | -------- | ------------------------------------------------------------------- |
| `Key`   | `[]byte` | The state key.                                                      |
| `Value` | `[]byte` | The raw bytes stored at that key. Unmarshal with `proto.Unmarshal`. |

**Example — batch point lookup:**

```go
fromQId, toQId, feeQId := rand.Uint64(), rand.Uint64(), rand.Uint64()

resp, err := StateRead(c, &PluginStateReadRequest{
    Keys: []*PluginKeyRead{
        {QueryId: fromQId, Key: KeyForAccount(msg.FromAddress)},
        {QueryId: toQId,   Key: KeyForAccount(msg.ToAddress)},
        {QueryId: feeQId,  Key: KeyForFeePool(c.Config.ChainId)},
    },
})

// Match results back by QueryId
for _, result := range resp.Results {
    switch result.QueryId {
    case fromQId:
        proto.Unmarshal(result.Entries[0].Value, fromAccount)
    case toQId:
        proto.Unmarshal(result.Entries[0].Value, toAccount)
    case feeQId:
        proto.Unmarshal(result.Entries[0].Value, feePool)
    }
}
```

**Example — range scan:**

```go
resp, err := StateRead(c, &PluginStateReadRequest{
    Ranges: []*PluginRangeRead{
        {
            QueryId: rand.Uint64(),
            Prefix:  []byte{0x03},  // prefix for Post records
            Limit:   50,
            Reverse: true,          // newest first
        },
    },
})

for _, entry := range resp.Results[0].Entries {
    post := &Post{}
    proto.Unmarshal(entry.Value, post)
    // ...
}
```

***

#### **StateWrite**

```go
func StateWrite(c *Contract, request *PluginStateWriteRequest) (*PluginStateWriteResponse, *PluginError)
```

Writes and/or deletes one or more keys in the FSM's key-value store in a single batched call. All operations in one `StateWrite` call are applied atomically.

**Input: `PluginStateWriteRequest`**

| Field     | Type                | Description                            |
| --------- | ------------------- | -------------------------------------- |
| `Sets`    | `[]*PluginSetOp`    | Key-value pairs to write or overwrite. |
| `Deletes` | `[]*PluginDeleteOp` | Keys to delete.                        |

**`PluginSetOp`**

| Field   | Type     | Description                                                               |
| ------- | -------- | ------------------------------------------------------------------------- |
| `Key`   | `[]byte` | The state key to write.                                                   |
| `Value` | `[]byte` | The serialized value to store. Use `proto.Marshal` to encode your struct. |

**`PluginDeleteOp`**

| Field | Type     | Description              |
| ----- | -------- | ------------------------ |
| `Key` | `[]byte` | The state key to delete. |

**Output: `PluginStateWriteResponse`**

| Field   | Type           | Description                                               |
| ------- | -------------- | --------------------------------------------------------- |
| `Error` | `*PluginError` | Non-nil if the FSM encountered an error during the write. |

**Example — mixed set and delete:**

```go
fromBytes, _ := proto.Marshal(fromAccount)
toBytes, _   := proto.Marshal(toAccount)
feeBytes, _  := proto.Marshal(feePool)

// Delete the sender's account if their balance reaches zero;
// otherwise update all three records.
if fromAccount.Amount == 0 {
    StateWrite(c, &PluginStateWriteRequest{
        Sets:    []*PluginSetOp{
            {Key: KeyForAccount(msg.ToAddress),      Value: toBytes},
            {Key: KeyForFeePool(c.Config.ChainId),   Value: feeBytes},
        },
        Deletes: []*PluginDeleteOp{
            {Key: KeyForAccount(msg.FromAddress)},
        },
    })
} else {
    StateWrite(c, &PluginStateWriteRequest{
        Sets: []*PluginSetOp{
            {Key: KeyForAccount(msg.FromAddress),    Value: fromBytes},
            {Key: KeyForAccount(msg.ToAddress),      Value: toBytes},
            {Key: KeyForFeePool(c.Config.ChainId),   Value: feeBytes},
        },
    })
}
```

***

### **Built-in Types**

These types are defined in the plugin's proto files and available in all templates.

#### **Transaction**

Defined in `proto/tx.proto`. The outer envelope for every submission to the chain.

| Field           | Type         | JSON tag        | Description                                                                 |
| --------------- | ------------ | --------------- | --------------------------------------------------------------------------- |
| `MessageType`   | `string`     | `messageType`   | The transaction type name, e.g. `"send"`. Matches `SupportedTransactions`.  |
| `Msg`           | `*anypb.Any` | —               | The inner message payload. Call `FromAny(tx.Msg)` to get the concrete type. |
| `Signature`     | `*Signature` | —               | BLS12-381 signature. Set to `nil` when computing sign bytes.                |
| `CreatedHeight` | `uint64`     | `createdHeight` | Block height at which the transaction was created. Used for safe pruning.   |
| `Time`          | `uint64`     | `time`          | Unix nanosecond timestamp. Used as entropy to prevent hash collisions.      |
| `Fee`           | `uint64`     | `fee`           | Fee in micro-denomination (uCNPY or your chain's token).                    |
| `Memo`          | `string`     | `memo`          | Optional human-readable note.                                               |
| `NetworkId`     | `uint64`     | `networkID`     | Network identifier. Must match the node's configured network.               |
| `ChainId`       | `uint64`     | `chainID`       | Committee/chain identifier. Must match the node's configured chain.         |

#### **Signature**

| Field       | Type     | JSON tag    | Description                                      |
| ----------- | -------- | ----------- | ------------------------------------------------ |
| `PublicKey` | `[]byte` | `publicKey` | 48-byte BLS12-381 public key.                    |
| `Signature` | `[]byte` | `signature` | 96-byte BLS12-381 signature over the sign bytes. |

#### **Account**

Defined in `proto/account.proto`. The basic unit of token ownership.

| Field     | Type     | Description                                                     |
| --------- | -------- | --------------------------------------------------------------- |
| `Address` | `[]byte` | 20-byte address derived from the SHA256 hash of the public key. |
| `Amount`  | `uint64` | Token balance in micro-denomination.                            |

Accounts with a zero balance are conventionally deleted from state (rather than stored with `Amount: 0`) to keep the state size minimal.

#### **Pool**

Defined in `proto/account.proto`. A protocol-controlled fund with no owner key — governed by chain rules rather than a private key.

| Field    | Type     | Description                                                |
| -------- | -------- | ---------------------------------------------------------- |
| `Id`     | `uint64` | Pool identifier (typically the chain ID for the fee pool). |
| `Amount` | `uint64` | Token balance in micro-denomination.                       |

#### **Event**

Defined in `proto/event.proto`. Emitted from `BeginBlock`, `DeliverTx`, or `EndBlock` to signal state changes to subscribers.

| Field       | Type                | Description                                                               |
| ----------- | ------------------- | ------------------------------------------------------------------------- |
| `EventType` | `string`            | A short label categorizing the event, e.g. `"post_created"`.              |
| `Msg`       | `oneof EventCustom` | Custom event payload, wrapped in `google.protobuf.Any` for extensibility. |
| `Height`    | `uint64`            | Block height at which the event was emitted.                              |
| `Reference` | `string`            | Source identifier: `"begin_block"`, a transaction hash, or `"end_block"`. |
| `ChainId`   | `uint64`            | Chain identifier.                                                         |
| `Address`   | `[]byte`            | The address most relevant to this event (e.g. the affected account).      |

#### **PluginError**

Returned in the `Error` field of all response types.

| Field    | Type     | Description                           |
| -------- | -------- | ------------------------------------- |
| `Code`   | `uint64` | Numeric error code (see table below). |
| `Module` | `string` | Origin module, e.g. `"plugin"`.       |
| `Msg`    | `string` | Human-readable error description.     |

**Built-in error codes**

| Code | Constructor                 | Meaning                                            |
| ---- | --------------------------- | -------------------------------------------------- |
| 1    | `ErrPluginTimeout()`        | Plugin did not respond within `pluginTimeoutMS`.   |
| 2    | `ErrMarshal()`              | Failed to serialize a protobuf message.            |
| 3    | `ErrUnmarshal()`            | Failed to deserialize a protobuf message.          |
| 4    | `ErrPluginRead()`           | State read operation failed.                       |
| 5    | `ErrPluginWrite()`          | State write operation failed.                      |
| 6    | `ErrInvalidResponseId()`    | Response ID did not match any pending request.     |
| 7    | `ErrUnexpectedType()`       | FSM sent an unexpected message type.               |
| 8    | `ErrInvalidMessage()`       | FSM message could not be parsed.                   |
| 9    | `ErrInsufficientFunds()`    | Sender's balance is below the required amount.     |
| 10   | `ErrFromAny()`              | Failed to unpack a `google.protobuf.Any` value.    |
| 11   | `ErrInvalidMessageCast()`   | Message type did not match any registered type.    |
| 12   | `ErrInvalidAddress()`       | Address is not exactly 20 bytes.                   |
| 13   | `ErrInvalidAmount()`        | Amount is zero or otherwise invalid.               |
| 14   | `ErrTxFeeBelowStateLimit()` | Transaction fee is below the minimum set in state. |

Define additional error codes starting above 14 to avoid conflicts with built-in codes.

***

### **State Key Conventions**

The key-value store is a flat byte namespace shared by all state types in your plugin. Use byte-prefixed keys to namespace each type and prevent collisions.

Built-in prefixes used by the default template:

| Prefix | Type              | Key function                    |
| ------ | ----------------- | ------------------------------- |
| `0x01` | `Account`         | `KeyForAccount(addr []byte)`    |
| `0x02` | `Pool` (fee pool) | `KeyForFeePool(chainId uint64)` |
| `0x07` | `FeeParams`       | `KeyForFeeParams()`             |

When defining keys for your own types, choose byte prefixes that don't conflict with these. Any unused byte value works. Keys are constructed with `JoinLenPrefix`:

```go
var postPrefix = []byte{0x03}

func KeyForPost(id uint64) []byte {
    idBytes := make([]byte, 8)
    binary.BigEndian.PutUint64(idBytes, id)
    return JoinLenPrefix(postPrefix, idBytes)
}
```

`JoinLenPrefix(a, b)` produces a key by length-prefixing each segment and concatenating them, which ensures keys of different lengths within the same prefix namespace don't collide.

***

### **FeeParams**

Defined in `proto/tx.proto`. Stored in state at `KeyForFeeParams()` and governable via on-chain parameter change proposals.

| Field     | Type     | JSON tag  | Description                                           |
| --------- | -------- | --------- | ----------------------------------------------------- |
| `SendFee` | `uint64` | `sendFee` | Minimum fee required for a `MessageSend` transaction. |

Add fields here (starting at field number 14 or higher to avoid conflicts) for any custom transaction types that need governance-controlled minimum fees.

***

### **Lifecycle Execution Order**

For reference, here is the order in which the FSM calls into your plugin for a block containing two transactions:

```
BeginBlock(height=N)
  CheckTx is NOT called here — it ran earlier at mempool ingress
  DeliverTx(tx[0])
  DeliverTx(tx[1])
EndBlock(height=N)
```

`CheckTx` runs independently, on each node that receives the transaction, as soon as it arrives — not as part of block application. By the time `DeliverTx` runs, the transaction has already passed `CheckTx` on the proposing node.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://canopy-network.gitbook.io/docs/app-builder/plugin-api-reference.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
