From 106d54439365f646117b27d029df4e33b5a984e4 Mon Sep 17 00:00:00 2001 From: PiVortex Date: Fri, 13 Feb 2026 17:22:59 +0000 Subject: [PATCH 01/12] API docs updated, most of CLI updated --- docs/ai/shade-agents/reference/api.md | 577 ++++++-------------------- docs/ai/shade-agents/reference/cli.md | 357 ++++++++++++---- 2 files changed, 416 insertions(+), 518 deletions(-) diff --git a/docs/ai/shade-agents/reference/api.md b/docs/ai/shade-agents/reference/api.md index 270a9177891..965f908a79d 100644 --- a/docs/ai/shade-agents/reference/api.md +++ b/docs/ai/shade-agents/reference/api.md @@ -1,524 +1,207 @@ --- id: api -title: Shade Agent API -sidebar_label: Shade Agent API -description: "Learn how to use the Shade Agent API." ---- - -import Tabs from '@theme/Tabs'; -import TabItem from '@theme/TabItem'; -import {Github, Language} from "@site/src/components/UI/Codetabs" - -The Shade Agent API abstracts away the complexity of the TEE and interacting with the agent contract to help you build a Shade Agent quickly. - +title: Shade Agent API +sidebar_label: Shade Agent API +description: "Use the Shade Agent API (TypeScript/JavaScript) to connect your agent to the Shade Agent Framework" --- ## API Overview -The API is packaged as a Docker image and included in your agent when it's uploaded to Phala Cloud. The API is accessible internally by default on port 3140, but it's not accessible from outside the TEE. - -When the API image boots up, it will automatically derive the agent's NEAR account (a random [implicit account](https://near-docs-pr-2740.onrender.com/protocol/account-id#implicit-address)), fund it with 0.3 NEAR from the NEAR_ACCOUNT_ID specified in the environment variables, and registers the agent in the agent contract. - -The API can be used in any language, but API wrappers are maintained in TypeScript/JavaScript and Python. It's recommended you develop in TypeScript as it has great synergies with [chainsig.js](../../../chain-abstraction/chain-signatures/implementation.md) for building multichain transactions. +`shade-agent-js` is a `TypeScript/JavaScript` library that connects your agent to the Shade Agent Framework. It hides TEE complexity and simplifies calls to the agent contract. The same API works locally and inside a TEE; its behavior differs slightly by environment, but the interface stays the same. --- -## Setup - - - - - - ```bash - npm install @neardefi/shade-agent-js - ``` - - - - - - ```bash - pip install shade-agent-py - ``` - - - - +## Installation - You can use the Shade Agent API directly with any language that supports HTTP requests. The base API endpoints change depending on your deployment: - - **Local Development:** - ``` - http://localhost:3140/api/agent - ``` - - **Production (TEE):** - ``` - http://shade-agent-api:3140/api/agent - ``` - - All endpoints expect `POST` requests with JSON payloads and return JSON responses. - - If you're running your API on a port other than 3140, you should amend the base URL accordingly. - - - - +```bash +npm install @neardefi/shade-agent-js +``` --- -## Agent Account ID - -Fetches the NEAR account ID of the agent. - - - - - - ```ts - import { agentAccountId } from '@neardefi/shade-agent-js'; - - const res = await agentAccountId(); - const accountId = res.accountId - ``` - - - +## Initializing the client - +Sets up the client with the desired configuration. - ```py - from shade_agent import agent_account_id - - res = await agent_account_id() - account_id = res["account_id"] - ``` +```ts +import { ShadeClient } from "@neardefi/shade-agent-js"; - +const agent = await ShadeClient.create({ + networkId: "testnet", // or "mainnet" + agentContractId: process.env.AGENT_CONTRACT_ID, // example-agent-contract.testnet + sponsor: { + accountId: process.env.SPONSOR_ACCOUNT_ID, // example-sponsor.testnet + privateKey: process.env.SPONSOR_PRIVATE_KEY, // ed25519:4vKz... + }, + rpc: provider, + numKeys: 10, + derivationPath: process.env.SPONSOR_PRIVATE_KEY, // ed25519:4vKz... +}); +``` - +### **Arguments** - **POST /getAccountId** +All arguments are optional. Omitting some makes certain methods unavailable. - Request body - ```json - {} - ``` - - Response - ```json - { - "accountId": "14bc8ee18f2d1ef51e7d581bdd96797804c56247733defdae67ad41314686fd7" - } - ``` - - - - +| Argument | Description | +|----------|-------------| +| **networkId** | The NEAR network: `mainnet` or `testnet` (defaults to testnet). | +| **agentContractId** | The account ID of your agent contract that your agent will interact with. | +| **sponsor** | The account details of a sponsor account to fund the agent. | +| **rpc** | A [near-api-js provider](https://near.github.io/near-api-js/modules/providers.html) object used by the client (defaults to a basic RPC provider based on the network). | +| **numKeys** | The number of key pairs the agent has (1–100, defaults to 1). More keys increase transaction throughput; the client rotates through them when signing transactions. | +| **derivationPath** | A string used to derive deterministic agent account IDs when running locally. Lets you avoid re-whitelisting and re-funding the agent on each run. Use a unique secret (e.g. a private key). If two agents share the same derivation path, they get the same account ID and could control contracts they are not authorized for. | --- -## Agent Info - -Fetches the code hash and checksum for the agent. -- The `code hash` is the code hash of the app image running inside the agent. -- The `checksum` is produced by the TEEs attestation and represents that the agent is registered. - -This function will only return the details once the agent has successfully registered in the agent contract. When running the API locally, it will only return the code hash, and not the checksum. - - - - - - ```ts - import { agentInfo } from '@neardefi/shade-agent-js'; - - const res = await agentInfo(); - const codehash = res.codehash - const checksum = res.checksum - ``` - - - - - - - ```py - from shade_agent import agent_info - - res = await agent_info() - codehash = res["codehash"] - checksum = res["checksum"] - ``` - - +## Agent account ID - +Returns the ephemeral NEAR account ID of the agent. - **POST /view** +```ts +const accountId = agent.accountId(); +``` - Request body - ```json - { - "methodName": "get_agent", - "args": { - "account_id": "14bc8ee18f2d1ef51e7d581bdd96797804c56247733defdae67ad41314686fd7" - } - } - ``` +--- - Response - ```json - { - "codehash": "03bcd36d3ffb5346c9e1e0166a4c2734a9e7cceedee6f7d992499aeb7fa54ead", - "checksum": "0c32c5c598bc8a3bfec47f3d7d9a9d600c8a60e5b97d90a4c2856a7c829eb6d4" - } - ``` +## Agent balance - +Returns the NEAR balance of the agent's account in human-readable units (e.g. 1 = one NEAR). If the account does not exist, returns 0. - +```ts +const balance = await agent.balance(); +``` --- -## Agent Balance - -Fetches the NEAR balance of the agent's account in yoctoNEAR (1 NEAR = 10^24 yoctoNEAR). +## Fund agent - +Transfers NEAR from the configured sponsor account to the agent's account. - - - ```ts - import { agent } from '@neardefi/shade-agent-js'; +```ts +await agent.fund(0.3); // 0.3 NEAR +``` - const res = await agent("getBalance"); - const balance = res.balance - ``` - +Requires sponsor in config. - +--- - +## Check whitelist - ```py - from shade_agent import agent - - res = await agent("getBalance") - balance = res["balance"] - ``` +Checks whether the agent's account is whitelisted for local mode. - +```ts +const whitelisted = await agent.isWhitelisted(); +``` - +**TEE vs local:** +- TEE: Always returns `null`. +- Local: Returns `true` if the agent is whitelisted, `false` otherwise. - **POST /getBalance** +Requires agentContractId in config. - Request body - ```json - {} - ``` +--- - Response - ```json - { - "balance": "203436730084671139765003" - } - ``` +## Register agent - +Registers the agent's account in the agent contract. Returns `true` on success, throws on failure. - +```ts +await agent.register(); +``` ---- +**TEE vs local:** +- TEE: Registers with a real attestation. +- Local: Registers with a default fake attestation. -## Request Signature - -Requests a signature from the Shade Agent for a multichain account (by calling request_signature on the agent contract). It has three arguments: -- **path** - A string that decides which account the signature is for. The path can be set to anything, and by changing the path, you produce a signature for a different account. -- **payload** - The hash of the transaction to be signed, given as a hex string. -- **keyType** - The signature scheme being used to sign the payload `Ecdsa` (secp256k1) or `Eddsa` (ed25519). - -It returns the signature for the transaction. - - - - - - ```ts - import { requestSignature } from '@neardefi/shade-agent-js'; - - const res = await requestSignature({ - path: "ethereum-1", - payload: "cf80cd8a...", - keyType: "Ecdsa", // Or "Eddsa" - }); - ``` - -
- Response - - For `Ecdsa`, the function returns the components of the signature as hex strings. Note that to get `r`, remove the first two hex characters from `big_r`. - - ```typescript - { - scheme: 'Secp256k1', - big_r: { - affine_point: '03D537AFFD52BE9AF0DA6CF41B573F4BE065434AEE2D25A500BC730C06E7EB2AF1' - }, - s: { - scalar: '3470037EB46DC6D1921900B635785290184EC980CFEC7109EB103B5698D4F725' - }, - recovery_id: 0 - } - ``` - - For `Eddsa`, the function returns the whole signature as a 64-byte array. - - ```typescript - { - scheme: 'Ed25519', - signature: [ - 5, 105, 30, 208, 192, 39, 154, 105, 252, 20, 132, - 64, 247, 207, 223, 127, 197, 43, 30, 145, 164, 224, - 1, 45, 240, 28, 155, 218, 204, 5, 136, 111, 238, - 40, 120, 122, 249, 166, 193, 174, 120, 94, 177, 39, - 179, 193, 170, 117, 37, 36, 155, 38, 72, 24, 118, - 235, 187, 110, 129, 26, 186, 7, 0, 8 - ] - } - ``` - - If you're using the chainsig.js library, you don't need to worry about the format of these responses since the library handles it. - -
- -
- - - - ```py - from shade_agent import request_signature - - res = await request_signature( - path="ethereum-1", - payload="cf80cd8a...", - key_type="Ecdsa", # Or "Eddsa" - ) - ``` - -
- Response - - For `Ecdsa`, the function returns the components of the signature as hex strings. Note that to get `r`, remove the first two hex characters from `big_r`. - - ```python - { - 'scheme': 'Secp256k1', - 'big_r': { - 'affine_point': '03D537AFFD52BE9AF0DA6CF41B573F4BE065434AEE2D25A500BC730C06E7EB2AF1' - }, - 's': { - 'scalar': '3470037EB46DC6D1921900B635785290184EC980CFEC7109EB103B5698D4F725' - }, - 'recovery_id': 0 - } - ``` - - For `Eddsa`, the function returns the whole signature as a 64-byte array. - - ```python - { - 'scheme': 'Ed25519', - 'signature': [ - 5, 105, 30, 208, 192, 39, 154, 105, 252, 20, 132, - 64, 247, 207, 223, 127, 197, 43, 30, 145, 164, 224, - 1, 45, 240, 28, 155, 218, 204, 5, 136, 111, 238, - 40, 120, 122, 249, 166, 193, 174, 120, 94, 177, 39, - 179, 193, 170, 117, 37, 36, 155, 38, 72, 24, 118, - 235, 187, 110, 129, 26, 186, 7, 0, 8 - ] - } - ``` - -
- -
- - - - **POST /call** - - Request body - ```json - { - "methodName": "request_signature", - "args": { - "path": "ethereum-1", - "payload": "cf80cd8a...", - "key_type": "Ecdsa" - } - } - ``` - -
- Response - - For `Ecdsa`, the function returns the components of the signature as hex strings. Note that to get `r`, remove the first two hex characters from `big_r`. - - ```json - { - "scheme": "Secp256k1", - "big_r": { - "affine_point": "03D537AFFD52BE9AF0DA6CF41B573F4BE065434AEE2D25A500BC730C06E7EB2AF1" - }, - "s": { - "scalar": "3470037EB46DC6D1921900B635785290184EC980CFEC7109EB103B5698D4F725" - }, - "recovery_id": 0 - } - ``` - - For `Eddsa`, the function returns the whole signature as a 64-byte array. - - ```json - { - "scheme": "Ed25519", - "signature": [ - 5, 105, 30, 208, 192, 39, 154, 105, 252, 20, 132, - 64, 247, 207, 223, 127, 197, 43, 30, 145, 164, 224, - 1, 45, 240, 28, 155, 218, 204, 5, 136, 111, 238, - 40, 120, 122, 249, 166, 193, 174, 120, 94, 177, 39, - 179, 193, 170, 117, 37, 36, 155, 38, 72, 24, 118, - 235, 187, 110, 129, 26, 186, 7, 0, 8 - ] - } - ``` - -
- -
- -
+Requires agentContractId in config. --- -## Agent Call - -Makes a function call to the agent contract from the agent. This is used for custom contracts when you want to call a function other than request_signature. It returns the result of the function call. +## Call agent contract - +Calls a change function on the agent contract (uses gas, can change state). Returns the call result or throws. - - - ```ts - import { agentCall } from '@neardefi/shade-agent-js'; +```ts +const result = await agent.call({ + methodName: "example_call_function", + args: { arg1: "value1", arg2: "value2" }, + gas: BigInt("300000000000000"), // Optional + deposit: "0", // Optional +}); +``` - const res = await agentCall({ - methodName: "example_call_method", - args: { - arg1: "Value1", - arg2: "Value2", - }, - gas: "30000000000000", // Optional - }) - ``` +Requires agentContractId in config. - +--- - +## View agent contract - ```py - from shade_agent import agent_call +Calls a view function on the agent contract (no gas, read-only). Returns the call result or throws. - res = await agent_call({ - "methodName": "example_call_method", - "args": { - "arg1": "Value1", - "arg2": "Value2", - }, - "gas": "30000000000000", # Optional - }) - ``` +```ts +const result = await agent.view({ + methodName: "example_view_function", + args: { arg1: "value1", arg2: "value2" }, +}); +``` - +Requires agentContractId in config. - +--- - **POST /call** +## Get attestation - Request body - ```json - { - "methodName": "example_call_method", - "args": { - "arg1": "value1", - "arg2": "value2" - }, - "gas": "30000000000000" // Optional - } - ``` +Returns the attestation in the format the agent contract expects. - +```ts +const attestation = await agent.getAttestation(); +``` - - +**TEE vs local:** +- TEE: Returns a real attestation. +- Local: Returns a default fake attestation. --- -## Agent View - -Makes a function call to a view method (a method that does not require gas) on the agent contract. It returns the result of the function call. +## Get private keys - +Returns the agent's ephemeral private keys. Useful for use in other NEAR tooling (e.g. near-api-js) or for other operations like encrypting messages. - - - ```ts - import { agentView } from '@neardefi/shade-agent-js'; +:::danger +Never log, expose, or store these keys. Doing so allows registered keys to be used outside of verified code (the keys can execute any operation not authorized by the measurements). Do not hold funds or important state with these keys — they are ephemeral and lost if the TEE reboots. +::: - const res = await agentView({ - methodName: "example_view_method", - args: { - arg1: "value1", - arg2: "value2", - }, - }) - ``` +```ts +const keys = agent.getPrivateKeys({ acknowledgeRisk: true }); +``` - - - +--- - ```py - from shade_agent import agent_view +## Utilities - res = await agent_view({ - "methodName": "example_view_method", - "args": { - "arg1": "value1", - "arg2": "value2", - }, - }) - ``` +### Sanitize - +Aims to redact private keys from strings, objects, or Errors. Use before logging. - +```ts +import { sanitize } from "@neardefi/shade-agent-js"; +console.error(sanitize(someError)); +``` - **POST /view** +:::warning +Sanitize redacts common key patterns, but can't catch every case or other sensitive data. Add your own sanitization where needed so no sensitive data is emitted from the TEE. +::: - Request body - ```json - { - "methodName": "example_view_method", - "args": { - "arg1": "value1", - "arg2": "value2" - } - } - ``` +### toThrowable - +Returns an error with a sanitized message. Use when rethrowing. - \ No newline at end of file +```ts +import { toThrowable } from "@neardefi/shade-agent-js"; +try { + await client.register(); +} catch (e) { + throw toThrowable(e); +} +``` \ No newline at end of file diff --git a/docs/ai/shade-agents/reference/cli.md b/docs/ai/shade-agents/reference/cli.md index 19d3ca1cadb..2e8e0214529 100644 --- a/docs/ai/shade-agents/reference/cli.md +++ b/docs/ai/shade-agents/reference/cli.md @@ -2,129 +2,344 @@ id: cli title: Shade Agent CLI sidebar_label: Shade Agent CLI -description: "Learn about the Shade Agent CLI and how to use it to deploy Shade Agents." +description: "Use the Shade Agent CLI to deploy your Shade Agent." --- -The [Shade Agent CLI](https://github.com/NearDeFi/shade-agent-cli/tree/main) makes it simple to deploy a Shade Agent. +The Shade Agent CLI makes it easy to deploy a Shade Agent as a whole. Including building and deploying your agent contract, building and publishing your agent's docker image, and deploying to Phala Cloud. + +The CLI revolves around a `deployment.yaml` file that configures how your Shade Agent will be deployed. It allows easy switching between local and TEE deployment modes for rapid development. --- -## CLI Overview +## Installation -Under the hood, the CLI: -- Builds and publishes the Docker Image for your agent app, and modifies your environment variables and docker-compose.yaml to match your new image hash -- Creates the agent contract account, deploys the agent contract to it, and initializes it with the NEAR_ACCOUNT_ID as the owner -- Approves the image code hashes for your agent (app and API image) -- Deploys the agent to a TEE on Phala Cloud +```bash +npm install -g @neardefi/shade-agent-cli +``` --- -## Local vs Production +## Commands -The `NEXT_PUBLIC_contractId` in your environment variables prefix should be set to `ac-proxy.` for local development and `ac-sandbox.` for TEE deployment. +### Deploy -For local deployment, the CLI works a little differently: -- No Docker Image is built or published for your agent app -- An agent contract that doesn't require agent registration is deployed instead (since locally, you cannot produce a valid TEE attestation) -- The API image is hosted locally instead of deploying anything to a TEE +Deploys your Shade Agent with the configuration as defined by the deployment.yaml file. ---- +```bash +shade deploy +``` + +Must be executed in the same directory as your deployment.yaml file. + +### Plan -## Installation +Generates a preview of how your Shade Agent will be deployed as defined by the deployment.yaml file. ```bash -npm i -g @neardefi/shade-agent-cli +shade plan ``` ---- +Must be executed in the same directory as your deployment.yaml file. -## Usage +### Whitelist -The Shade Agent CLI is a single command that runs the CLI with standard configurations. Run the command within the root of your project. +Whitelists a specified agent's account ID in the agent contract as defined by the deployment.yaml file. This is only relevant for local mode. ```bash -shade-agent-cli +shade whitelist ``` -Your project root must contain your `.env.development.local`, `Dockerfile` and `docker-compose.yaml` files. +Must be executed in the same directory as your deployment.yaml file. + +### Auth + +Configure NEAR and Phala credentials required for deploying your Shade Agent. + +```bash +shade auth +``` --- -## Flags -The CLI includes various flags to configure deployment options and disable specific components. If you require further customizability when deploying your agent, you can disable the relevant components using flags and complete those steps manually with native tools: [Docker CLI](https://docs.docker.com/reference/cli/docker/), [NEAR CLI](https://docs.near.org/tools/near-cli), and [Phala CLI](https://docs.phala.network/phala-cloud/phala-cloud-cli/overview) +## deployment.yaml reference + +All keys are read from a single `deployment.yaml` file in the project root. The following sections describe what each top-level key and nested option configures. + +### Top-level keys + +| Key | Required | Description | +|-----|----------|-------------| +| **environment** | Yes |`local` or `TEE`. Controls whether the agent runs locally or in a Phala TEE. | +| **network** | Yes | `testnet` or `mainnet`. Controls whether the agent contract is on NEAR testnet or mainnet. | +| **docker_compose_path** | Yes if TEE | Path to the Docker Compose file (e.g. `./docker-compose.yaml`). used for building the docker image and deploying your application to a TEE. | +| **agent_contract** | Yes | Agent contract configuration. See [agent_contract](#agent_contract) for more details. | +| **approve_measurements** | No | If enabled, calls the agent contract to approve measurements. | +| **approve_ppids** | No | If enabled, calls the agent to approve PPIDs.| +| **build_docker_image** | No (TEE only) | If enabled and environment is TEE, builds a new Docker image for your agent, publishes it and updates the Docker Compose with the new image. | +| **deploy_to_phala** | No (TEE only) | If enabled and environment is TEE, deploys the Docker Compose to Phala Cloud. | +| **whitelist_agent_for_local** | No | Config for the `shade whitelist` command to whitelist an agent's account ID whilst in local mode (not used by the shade deploy command). | +| **os** | No | Override OS for tooling: `mac` or `linux`. If omitted, the CLI auto-detects from the current platform. | + +### agent_contract + +| Key | Required | Description | +|-----|----------|-------------| +| **contract_id** | Yes | NEAR account ID for the agent contract (e.g. `example-contract-123.testnet`). Must be unused if you are deploying a new contract. | +| **deploy_custom** | No | If present and enabled, the CLI creates the contract account with the same private key as the account set up via `shade auth`, and deploys a new contract. If the contract account already exists it will be deleted and recreated to remove the old contract. | + +#### deploy_custom -- **--wasm ``** +`agent_contract.deploy_custom` - Path to a custom agent contract WASM file (e.g. `contract/near/contract.wasm`) to deploy instead of the default contract. Use this when deploying [custom contracts](./custom-agent-contract.md). +| Key | Required | Description | +|-----|----------|-------------| +| **enabled** | No | If `false`, deploy_custom is skipped. | +| **funding_amount** | Yes | NEAR amount to fund the new contract account with, used to fund the deployment of the contract (number between 0 and 100). | +| **delete_key** | No | If `true`, the key for the contract account is deleted after deployment, locking the contract (defaults `false`). | +| **deploy_from_source** | One of three | Build the contract from source and deploy: set `enabled: true` and `source_path` to the contract directory. | +| **deploy_from_wasm** | One of three | Deploy a pre-built WASM file: set `enabled: true` and `wasm_path` to the `.wasm` file. | +| **use_global_by_hash** | One of three | Deploy using a global contract: set `enabled: true` and `global_hash` to the contract hash. | +| **init** | No | If present and enabled, initializes the contract via a function call. | -- **--funding ``** +#### init - Amount of NEAR tokens to fund the contract deployment with (e.g. `5` for 5 NEAR). Use this when deploying a custom contract. +`agent_contract.deploy_custom.init` -- **--image** +| Key | Required | Description | +|-----|----------|-------------| +| **enabled** | No | If `false`, init is skipped. | +| **method_name** | Yes | Contract method to call (e.g. `new`). | +| **args** | Yes | Arguments to call the method with. | +| **tgas** | No | Gas for the call (default 30). | - Build and push the Docker image only. Use this when you want customizability over the deployment of the agent contract. +Placeholders in args: -- **--contract** +- `` — Resolves to `true` or `false` depending on `environment`. +- `<7_DAYS>` — Resolves to 7 days in milliseconds (`604800000`). +- `` — Resolves to the NEAR account ID from `shade auth`. +- `` — Resolves to the default MPC contract for the selected `network` (testnet/mainnet). - Build and push the Docker image, and deploy the contract only. Use this when you want customizability over the contract initialization and approval of image code hashes. +### approve_measurements -- **--phala-only** +| Key | Required | Description | +|-----|----------|-------------| +| **enabled** | No | If `false`, measurements are not approved. | +| **method_name** | Yes | Contract method to call (e.g. `approve_measurements`). | +| **args** | Yes | Arguments to call the method with. | +| **tgas** | No | Gas for the call (default 30). | - Deploy the agent, specified by the current `docker-compose.yaml`, to Phala Cloud. Use this when you want to redeploy the same agent as you last deployed. +Placeholders in args: -- **--no-redeploy** +- `` — Resolves to default fake measurements for local and real calculated measurements for the application. - Skip redeploying the contract. Use when you want to deploy a new agent quicker and you don't need the agent contract redeploying. +### approve_ppids -- **--no-build** +| Key | Required | Description | +|-----|----------|-------------| +| **enabled** | No | If `false`, PPIDs are not approved. Default is effectively true when the block is present. | +| **method_name** | Yes if enabled | Contract method to call (e.g. `approve_ppids`). | +| **args** | Yes if enabled | Multiline string (YAML block) of JSON. Must be a multiline string. | +| **tgas** | No | Gas for the call (default 30). | - Skip building and pushing the Docker image. Use this when you want to redeploy the same agent or want more control over the image build process. +Placeholders in **approve_ppids.args**: -- **--no-phala** +- `` — Replaced by PPIDs (local: default/zeros; TEE: fetched from Phala). - Skip deploying the agent to Phala Cloud. Use this when you want more control over hosting the agent (e.g. deploying to a TEE with higher specs). +### build_docker_image (TEE only) -- **--no-cache** +| Key | Required | Description | +|-----|----------|-------------| +| **enabled** | No | If `false`, the Docker image is not built. Default is effectively true when the block is present. | +| **tag** | Yes if enabled | Docker image tag (e.g. `username/my-first-agent`) for building and pushing. | +| **cache** | Yes if enabled | Boolean; whether to use Docker build cache. | +| **dockerfile_path** | Yes if enabled | Path to the Dockerfile (e.g. `./Dockerfile`). | - Run Docker build with --no-cache. Use this when you need clean builds or want to update cached layers (e.g. cached layers may use older packages). +### deploy_to_phala (TEE only) -:::note -Some options are mutually exclusive. See error messages for details if you use conflicting flags. +| Key | Required | Description | +|-----|----------|-------------| +| **enabled** | No | If `false`, deployment to Phala Cloud is skipped. Default is effectively true when the block is present. | +| **app_name** | Yes if enabled | Phala Cloud app (CVM) name. | +| **env_file_path** | Yes if enabled | Path to the environment file (e.g. `./.env`) loaded when deploying to Phala. | + +### whitelist_agent_for_local (local only) + +Used by `shade whitelist`. No `enabled` flag; if the section is present, the command is available. + +| Key | Required | Description | +|-----|----------|-------------| +| **method_name** | Yes | Contract method to call (e.g. `whitelist_agent_for_local`). | +| **args** | Yes | Multiline string of JSON. Must be a multiline string. | +| **tgas** | No | Gas for the call (default 30). | + +Placeholders in **whitelist_agent_for_local.args**: + +- `` — Replaced with the agent account ID you provide when running `shade whitelist`. + +:::info +Currently the CLI supports measurement calculation and Phala Cloud deployment for fixed configurations on DStack. If you need to deploy with different configurations you can calculate the measurements and deploy to Phala by other means, you can ask for assistance with this in our [support group](https://t.me/+mrNSq_0tp4IyNzg8). + +
+ Fixed Dstack configurations + +- Dstack Version: dstack-0.5.5 +- Hardware: 1vCPU and 2GB RAM (tdx.small on Phala) +- Key Provider: Phala Key Provider + +**App compose configs** +- Pre Launch Script: v0.0.12 + +... + +- features: ["kms", "tproxy-net"], +- gateway_enabled: true, +- kms_enabled: true, +- local_key_provider_enabled: false, +- manifest_version: 2, +- name: "", +- no_instance_id: false, +- public_logs: true, +- public_sysinfo: true, +- public_tcbinfo: true, +- runner: "docker-compose", +- secure_time: false, +- storage_fs: "zfs", +- tproxy_enabled: true, + + + + +
::: --- -## Custom RPC -To use customs RPCs with the CLI and the API, create a file named `near-rpc.json` within your project's root and configure the RPCs you would like to use, for example: -```json -{ - "nearRpcProviders": [ +## Example deployment.yaml configurations + +This example will oiasdfjoidajsfiojdiofj + +Give a few common examples here of things I want to do. + +I already have a contract deployed but want to remove its state, for example . + +```yaml +# environment: local | TEE +environment: local + +# network: testnet | mainnet +network: testnet + +# Path to docker-compose file +docker_compose_path: ./docker-compose.yaml + +agent_contract: + # NEAR Account Id of the contract + # Fill this out with a unique contract id for your agent contract + # For example: example-contract-123.testnet + # This account should not already be in use + contract_id: example-contract-123.testnet + + # Optional, if not enabled the contract will not be deployed + # and it's assumed the agent contract is already deployed to the contract_id + # and is initialized + deploy_custom: + enabled: true + # Amount to fund the agent contract with in NEAR + funding_amount: 8 + # If true the key for contract account will be deleted after deployment locking it + delete_key: false + + # Choose ONE of the following: + # Option 1: Build contract from source and deploy + deploy_from_source: + enabled: true + source_path: ./agent-contract + # Option 2: Use pre-built WASM file + deploy_from_wasm: + enabled: false + wasm_path: ./agent-contract/target/near/shade-contract-template.wasm + # Option 3: Use a deployed global contract, specifying it by its hash + use_global_by_hash: + enabled: false + global_hash: 8eHvv9q4eovoUgDXYEduwv3dbcfXkCyPP9TSmhUSxkcm + + # Optional, if not enabled the contract will not be initialized + init: + enabled: true + method_name: new + # will be replaced wil true or false depending on the environment selected + # <7_DAYS> will be replaced with 7 days in milliseconds + # will be replaced with the master account set up in the auth of the CLI + # will be replaced with the MPC contract address depending on the network selected + args: | + { + "requires_tee": , + "attestation_expiration_time_ms": <7_DAYS>, + "owner_id": , + "mpc_contract_id": + } + # tgas: 30 + +# Approve allowed measurements for registration +# Optional, if not enabled the measurements will not be approved +approve_measurements: + enabled: true + method_name: approve_measurements + # will be replaced with calculated measurements + # for local it will be set to default measurements (all zeros) + # for TEE and docker disabled it will be set to the measurements based on the current docker-compose file + # for TEE and docker enabled it will be set to the measurements based on the docker-compose file once it has been updated + args: | { - "connectionInfo": { - "url": "https://neart.lava.build:443" - }, - "options": { - "retries": 3, - "backoff": 2, - "wait": 1000 - } - }, + "measurements": + } + # tgas: 30 + +# Approve allowed PPIDs for registration +# Optional, if not enabled the PPIDs will not be approved +approve_ppids: + enabled: true + method_name: approve_ppids + # will be replaced with the PPIDs + # for local it will be set to a default PPID (all zeros) + # for TEE it will approve PPIDs on Phala Cloud + args: | { - "connectionInfo": { - "url": "https://test.rpc.fastnear.com" - }, - "options": { - "retries": 3, - "backoff": 2, - "wait": 1000 - } + "ppids": } - ] -} -``` - -If required, you can specify headers under connectionInfo. + # tgas: 30 + +# Build a new docker image using the specified Dockerfile +# the docker-compose.yaml will be updated with the new docker image +# Optional, if not enabled the current docker-compose.yaml file will be used +# Only applicable if the environment is TEE +build_docker_image: + enabled: true + # Fill this out with the docker tag you want to use. For example: pivortex/my-first-agent + tag: username/my-first-agent + cache: true + dockerfile_path: ./Dockerfile + +# Deploy the docker compose file to Phala Cloud with the specified environment variables +# Optional, if not enabled the app will not be deployed to Phala Cloud +# Only applicable if the environment is TEE +deploy_to_phala: + enabled: true + app_name: my-first-agent + env_file_path: ./.env + +# Helper command to whitelist an agent for local mode +# Use the "shade whitelist" command +whitelist_agent_for_local: + method_name: whitelist_agent_for_local + # The will automatically be replaced with the agent account id + # specified when running the "shade whitelist" command + args: | + { + "account_id": + } + # tgas: 30 +``` \ No newline at end of file From c8b6ac5d46c278a63e3e4692a29fd411a18c13c1 Mon Sep 17 00:00:00 2001 From: PiVortex Date: Mon, 16 Feb 2026 12:50:40 +0000 Subject: [PATCH 02/12] finish cli --- .../concepts/framework-overview.md | 10 +- docs/ai/shade-agents/reference/api.md | 2 +- docs/ai/shade-agents/reference/cli.md | 178 +++--------------- .../reference/custom-agent-contract.md | 68 ------- .../reference/environment-variables.md | 92 --------- docs/ai/shade-agents/reference/plugins.md | 12 -- .../shade-agents/tutorials/ai-dao/overview.md | 1 - website/sidebars.js | 3 - 8 files changed, 31 insertions(+), 335 deletions(-) delete mode 100644 docs/ai/shade-agents/reference/custom-agent-contract.md delete mode 100644 docs/ai/shade-agents/reference/environment-variables.md delete mode 100644 docs/ai/shade-agents/reference/plugins.md diff --git a/docs/ai/shade-agents/concepts/framework-overview.md b/docs/ai/shade-agents/concepts/framework-overview.md index b5f78fdc6fe..f2d54f4c1c3 100644 --- a/docs/ai/shade-agents/concepts/framework-overview.md +++ b/docs/ai/shade-agents/concepts/framework-overview.md @@ -50,7 +50,7 @@ The Shade Agent CLI simplifies deploying a Shade Agent. To learn more about how ## Environment Variables -Environment variables are a crucial component of the Shade Agent Framework. They configure your Shade Agent and are passed encrypted into your agent when it goes live. To learn more about configuring environment variables in your project, please refer to the [Environment Variables page](../reference/environment-variables.md). +Environment variables are a crucial component of the Shade Agent Framework. They configure your Shade Agent and are passed encrypted into your agent when it goes live. To learn more about configuring environment variables in your project, please refer to the Environment Variables page. --- @@ -63,7 +63,7 @@ There are also cases when you should develop your own `custom agent contract`. T 2) You want to implement a custom agent registration or code hash upgradability mechanism 3) You want to build an agent that just interacts with the NEAR blockchain -Further documentation can be found in the [custom contract section](../reference/custom-agent-contract.md). +Further documentation can be found in the custom contract section. --- @@ -122,9 +122,9 @@ You can learn more about the Docker Compose file [here](https://docs.docker.com/ ## Next Steps Now that you have an overview of the framework, here are some great sections to explore next: -1. Framework components: [API](../reference/api.md), [CLI](../reference/cli.md), and [Environment Variables](../reference/environment-variables.md) -2. [Custom Contracts](../reference/custom-agent-contract.md) - build specialized agent contracts -3. [Plugins](../reference/plugins.md) - extend your agent's capabilities +1. Framework components: [API](../reference/api.md), [CLI](../reference/cli.md), and Environment Variables +2. Custom Contracts - build specialized agent contracts +3. Plugins - extend your agent's capabilities 4. [Tutorials and Templates](../tutorials/tutorials-overview.md) - get up and running with different Shade Agent architectures, and use cases as quickly as possible and learn how to build apps in full 4. [Security Considerations](../concepts/security.md) - check your agent abides by best practices diff --git a/docs/ai/shade-agents/reference/api.md b/docs/ai/shade-agents/reference/api.md index 965f908a79d..d3ca6ada95c 100644 --- a/docs/ai/shade-agents/reference/api.md +++ b/docs/ai/shade-agents/reference/api.md @@ -166,7 +166,7 @@ const attestation = await agent.getAttestation(); ## Get private keys -Returns the agent's ephemeral private keys. Useful for use in other NEAR tooling (e.g. near-api-js) or for other operations like encrypting messages. +Returns the agent's ephemeral private keys. Useful for when wanting to use other NEAR tooling (e.g. near-api-js) or for other operations like encrypting messages. :::danger Never log, expose, or store these keys. Doing so allows registered keys to be used outside of verified code (the keys can execute any operation not authorized by the measurements). Do not hold funds or important state with these keys — they are ephemeral and lost if the TEE reboots. diff --git a/docs/ai/shade-agents/reference/cli.md b/docs/ai/shade-agents/reference/cli.md index 2e8e0214529..7de43162c9b 100644 --- a/docs/ai/shade-agents/reference/cli.md +++ b/docs/ai/shade-agents/reference/cli.md @@ -5,9 +5,7 @@ sidebar_label: Shade Agent CLI description: "Use the Shade Agent CLI to deploy your Shade Agent." --- -The Shade Agent CLI makes it easy to deploy a Shade Agent as a whole. Including building and deploying your agent contract, building and publishing your agent's docker image, and deploying to Phala Cloud. - -The CLI revolves around a `deployment.yaml` file that configures how your Shade Agent will be deployed. It allows easy switching between local and TEE deployment modes for rapid development. +The Shade Agent CLI makes it easy to deploy a Shade Agent. Including building and deploying your agent contract, building and publishing your agent's Docker image, and deploying the agent to Phala Cloud. The CLI revolves around a `deployment.yaml` file that configures how your Shade Agent will be deployed. --- @@ -53,7 +51,7 @@ Must be executed in the same directory as your deployment.yaml file. ### Auth -Configure NEAR and Phala credentials required for deploying your Shade Agent. +Configure NEAR and Phala credentials required for deploying your Shade Agent. Must be run before using the `deploy` or `whitelist` commands. ```bash shade auth @@ -64,7 +62,7 @@ shade auth ## deployment.yaml reference -All keys are read from a single `deployment.yaml` file in the project root. The following sections describe what each top-level key and nested option configures. +CLI configurations are read from a single `deployment.yaml` file in the project root. The following sections describe what each key configures. ### Top-level keys @@ -72,10 +70,10 @@ All keys are read from a single `deployment.yaml` file in the project root. The |-----|----------|-------------| | **environment** | Yes |`local` or `TEE`. Controls whether the agent runs locally or in a Phala TEE. | | **network** | Yes | `testnet` or `mainnet`. Controls whether the agent contract is on NEAR testnet or mainnet. | -| **docker_compose_path** | Yes if TEE | Path to the Docker Compose file (e.g. `./docker-compose.yaml`). used for building the docker image and deploying your application to a TEE. | +| **docker_compose_path** | Yes if TEE | Path to the Docker Compose file (e.g. `./docker-compose.yaml`). Used for building the Docker image and deploying your application to a TEE. | | **agent_contract** | Yes | Agent contract configuration. See [agent_contract](#agent_contract) for more details. | -| **approve_measurements** | No | If enabled, calls the agent contract to approve measurements. | -| **approve_ppids** | No | If enabled, calls the agent to approve PPIDs.| +| **approve_measurements** | No | If enabled, sets allowed measurements in the agent contract. | +| **approve_ppids** | No | If enabled, sets allowed PPIDs in the agent contract.| | **build_docker_image** | No (TEE only) | If enabled and environment is TEE, builds a new Docker image for your agent, publishes it and updates the Docker Compose with the new image. | | **deploy_to_phala** | No (TEE only) | If enabled and environment is TEE, deploys the Docker Compose to Phala Cloud. | | **whitelist_agent_for_local** | No | Config for the `shade whitelist` command to whitelist an agent's account ID whilst in local mode (not used by the shade deploy command). | @@ -86,7 +84,7 @@ All keys are read from a single `deployment.yaml` file in the project root. The | Key | Required | Description | |-----|----------|-------------| | **contract_id** | Yes | NEAR account ID for the agent contract (e.g. `example-contract-123.testnet`). Must be unused if you are deploying a new contract. | -| **deploy_custom** | No | If present and enabled, the CLI creates the contract account with the same private key as the account set up via `shade auth`, and deploys a new contract. If the contract account already exists it will be deleted and recreated to remove the old contract. | +| **deploy_custom** | No | If enabled, the CLI creates the contract account with the same private key as the account set up via `shade auth`, and deploys a new contract. If the contract account already exists, it will be deleted and recreated to remove the old contract. | #### deploy_custom @@ -100,7 +98,7 @@ All keys are read from a single `deployment.yaml` file in the project root. The | **deploy_from_source** | One of three | Build the contract from source and deploy: set `enabled: true` and `source_path` to the contract directory. | | **deploy_from_wasm** | One of three | Deploy a pre-built WASM file: set `enabled: true` and `wasm_path` to the `.wasm` file. | | **use_global_by_hash** | One of three | Deploy using a global contract: set `enabled: true` and `global_hash` to the contract hash. | -| **init** | No | If present and enabled, initializes the contract via a function call. | +| **init** | No | If enabled, initializes the contract via a function call. | #### init @@ -131,37 +129,37 @@ Placeholders in args: Placeholders in args: -- `` — Resolves to default fake measurements for local and real calculated measurements for the application. +- `` — Resolves to real calculated measurements for the application for TEE and fake default measurements for local. ### approve_ppids | Key | Required | Description | |-----|----------|-------------| -| **enabled** | No | If `false`, PPIDs are not approved. Default is effectively true when the block is present. | -| **method_name** | Yes if enabled | Contract method to call (e.g. `approve_ppids`). | -| **args** | Yes if enabled | Multiline string (YAML block) of JSON. Must be a multiline string. | +| **enabled** | No | If `false`, PPIDs are not approved. | +| **method_name** | Yes | Contract method to call (e.g. `approve_ppids`). | +| **args** | Yes | Arguments to call the method with. | | **tgas** | No | Gas for the call (default 30). | -Placeholders in **approve_ppids.args**: +Placeholders in args: -- `` — Replaced by PPIDs (local: default/zeros; TEE: fetched from Phala). +- `` — Resolves to a list of all PPIDs of devices on Phala Cloud for TEE and a fake fault PPID for local. ### build_docker_image (TEE only) | Key | Required | Description | |-----|----------|-------------| -| **enabled** | No | If `false`, the Docker image is not built. Default is effectively true when the block is present. | -| **tag** | Yes if enabled | Docker image tag (e.g. `username/my-first-agent`) for building and pushing. | -| **cache** | Yes if enabled | Boolean; whether to use Docker build cache. | -| **dockerfile_path** | Yes if enabled | Path to the Dockerfile (e.g. `./Dockerfile`). | +| **enabled** | No | If `false`, the Docker image is not built. If disabled, the CLI will use the existing Docker Compose file. | +| **tag** | Yes | Docker image tag (e.g. `username/my-first-agent`) for building and pushing. | +| **cache** | Yes | Boolean; whether to use caching in the build process. | +| **dockerfile_path** | Yes | Path to the Dockerfile to use for the build process (e.g. `./Dockerfile`). | ### deploy_to_phala (TEE only) | Key | Required | Description | |-----|----------|-------------| -| **enabled** | No | If `false`, deployment to Phala Cloud is skipped. Default is effectively true when the block is present. | -| **app_name** | Yes if enabled | Phala Cloud app (CVM) name. | -| **env_file_path** | Yes if enabled | Path to the environment file (e.g. `./.env`) loaded when deploying to Phala. | +| **enabled** | No | If `false`, deployment to Phala Cloud is skipped. | +| **app_name** | Yes | Phala Cloud app (CVM) name. | +| **env_file_path** | Yes | Path to the environment variables file loaded when deploying to Phala (e.g. `./.env`). | ### whitelist_agent_for_local (local only) @@ -170,15 +168,15 @@ Used by `shade whitelist`. No `enabled` flag; if the section is present, the com | Key | Required | Description | |-----|----------|-------------| | **method_name** | Yes | Contract method to call (e.g. `whitelist_agent_for_local`). | -| **args** | Yes | Multiline string of JSON. Must be a multiline string. | +| **args** | Yes | Arguments to call the method with. | | **tgas** | No | Gas for the call (default 30). | -Placeholders in **whitelist_agent_for_local.args**: +Placeholders in args: - `` — Replaced with the agent account ID you provide when running `shade whitelist`. :::info -Currently the CLI supports measurement calculation and Phala Cloud deployment for fixed configurations on DStack. If you need to deploy with different configurations you can calculate the measurements and deploy to Phala by other means, you can ask for assistance with this in our [support group](https://t.me/+mrNSq_0tp4IyNzg8). +Currently, the CLI only supports measurement calculation and Phala Cloud deployment for fixed configurations on DStack. If you need to deploy with different configurations, you can calculate the measurements and deploy to Phala by other means; you can ask for assistance with this in our [support group](https://t.me/+mrNSq_0tp4IyNzg8).
Fixed Dstack configurations @@ -207,9 +205,6 @@ Currently the CLI supports measurement calculation and Phala Cloud deployment fo - storage_fs: "zfs", - tproxy_enabled: true, - - -
::: @@ -219,127 +214,4 @@ Currently the CLI supports measurement calculation and Phala Cloud deployment fo ## Example deployment.yaml configurations -This example will oiasdfjoidajsfiojdiofj - -Give a few common examples here of things I want to do. - -I already have a contract deployed but want to remove its state, for example . - -```yaml -# environment: local | TEE -environment: local - -# network: testnet | mainnet -network: testnet - -# Path to docker-compose file -docker_compose_path: ./docker-compose.yaml - -agent_contract: - # NEAR Account Id of the contract - # Fill this out with a unique contract id for your agent contract - # For example: example-contract-123.testnet - # This account should not already be in use - contract_id: example-contract-123.testnet - - # Optional, if not enabled the contract will not be deployed - # and it's assumed the agent contract is already deployed to the contract_id - # and is initialized - deploy_custom: - enabled: true - # Amount to fund the agent contract with in NEAR - funding_amount: 8 - # If true the key for contract account will be deleted after deployment locking it - delete_key: false - - # Choose ONE of the following: - # Option 1: Build contract from source and deploy - deploy_from_source: - enabled: true - source_path: ./agent-contract - # Option 2: Use pre-built WASM file - deploy_from_wasm: - enabled: false - wasm_path: ./agent-contract/target/near/shade-contract-template.wasm - # Option 3: Use a deployed global contract, specifying it by its hash - use_global_by_hash: - enabled: false - global_hash: 8eHvv9q4eovoUgDXYEduwv3dbcfXkCyPP9TSmhUSxkcm - - # Optional, if not enabled the contract will not be initialized - init: - enabled: true - method_name: new - # will be replaced wil true or false depending on the environment selected - # <7_DAYS> will be replaced with 7 days in milliseconds - # will be replaced with the master account set up in the auth of the CLI - # will be replaced with the MPC contract address depending on the network selected - args: | - { - "requires_tee": , - "attestation_expiration_time_ms": <7_DAYS>, - "owner_id": , - "mpc_contract_id": - } - # tgas: 30 - -# Approve allowed measurements for registration -# Optional, if not enabled the measurements will not be approved -approve_measurements: - enabled: true - method_name: approve_measurements - # will be replaced with calculated measurements - # for local it will be set to default measurements (all zeros) - # for TEE and docker disabled it will be set to the measurements based on the current docker-compose file - # for TEE and docker enabled it will be set to the measurements based on the docker-compose file once it has been updated - args: | - { - "measurements": - } - # tgas: 30 - -# Approve allowed PPIDs for registration -# Optional, if not enabled the PPIDs will not be approved -approve_ppids: - enabled: true - method_name: approve_ppids - # will be replaced with the PPIDs - # for local it will be set to a default PPID (all zeros) - # for TEE it will approve PPIDs on Phala Cloud - args: | - { - "ppids": - } - # tgas: 30 - -# Build a new docker image using the specified Dockerfile -# the docker-compose.yaml will be updated with the new docker image -# Optional, if not enabled the current docker-compose.yaml file will be used -# Only applicable if the environment is TEE -build_docker_image: - enabled: true - # Fill this out with the docker tag you want to use. For example: pivortex/my-first-agent - tag: username/my-first-agent - cache: true - dockerfile_path: ./Dockerfile - -# Deploy the docker compose file to Phala Cloud with the specified environment variables -# Optional, if not enabled the app will not be deployed to Phala Cloud -# Only applicable if the environment is TEE -deploy_to_phala: - enabled: true - app_name: my-first-agent - env_file_path: ./.env - -# Helper command to whitelist an agent for local mode -# Use the "shade whitelist" command -whitelist_agent_for_local: - method_name: whitelist_agent_for_local - # The will automatically be replaced with the agent account id - # specified when running the "shade whitelist" command - args: | - { - "account_id": - } - # tgas: 30 -``` \ No newline at end of file +You can view a list of [example deployment.yaml configurations here](https://github.com/NearDeFi/shade-agent-framework/tree/main/shade-agent-cli/example-deployment-files). \ No newline at end of file diff --git a/docs/ai/shade-agents/reference/custom-agent-contract.md b/docs/ai/shade-agents/reference/custom-agent-contract.md deleted file mode 100644 index a26ffb6fb57..00000000000 --- a/docs/ai/shade-agents/reference/custom-agent-contract.md +++ /dev/null @@ -1,68 +0,0 @@ ---- -id: custom-agent-contract -title: Custom Agent Contract -sidebar_label: Custom Agent Contract -description: "Learn how to build, deploy, and interact with custom Shade Agent contracts." ---- - -import Tabs from '@theme/Tabs'; -import TabItem from '@theme/TabItem'; - -In some cases, you may want to deploy a `custom agent contract`. This allows for more customizability inside the agent contract, allows you to restrict your agent to certain actions by implementing `guard rails`, and is used for building Shade Agents that interact with just NEAR. - ---- - -## Creating the Contract - -To create a custom agent contract, we recommend you fork the [sandbox contract](https://github.com/NearDeFi/shade-agent-js/tree/main/contracts/sandbox). This is the agent contract that's deployed under the hood when using the `shade-agent-cli`. For testing locally, you will need to maintain a separate similar contract that does not implement the agent registration flow; for this, you can follow the structure of the [proxy contract](https://github.com/NearDeFi/shade-agent-js/tree/main/contracts/proxy). - -Inside this contract, you will create your own functions. For building contracts on NEAR, see our [smart contract docs](../../../smart-contracts/quickstart.md). You can only develop agent contracts in Rust. - -With the quickstart template, an agent can sign any transaction. You may want to limit your agent to only be able to sign transactions for a limited set of functions or actions. For this, we recommend building your transactions inside your agent contract with the [omni-transaction-rs](https://github.com/near/omni-transaction-rs) library. In such case, you should make the `request_signature` function private. - -For developing Shade Agents that just interact with NEAR, you can remove the `request_signature` function. The agent will make function calls to the contract directly. Make sure that you restrict relevant functions to only be allowed to be called by the agent. If you want to interact with existing contracts on NEAR that do not implement agent registration, you can leverage [cross contract calls](../../../smart-contracts/anatomy/crosscontract.md). - -How you compile the contract depends on your operating system. - - - - - - For Linux, you can compile the contract directly with [cargo near](https://github.com/near/cargo-near/releases/latest). - - - ```bash - cargo near build non-reproducible-wasm - ``` - - - - - - Because of a required dependency used in the agent registration flow, agent contracts cannot easily be compiled on a Mac. We suggest you build the contract inside a Docker container. You can use this pre-configured image for compiling NEAR contracts: - - ```bash - docker run --rm -v "$(pwd)":/workspace pivortex/near-builder@sha256:cdffded38c6cff93a046171269268f99d517237fac800f58e5ad1bcd8d6e2418 cargo near build non-reproducible-wasm - ``` - - - - - ---- - -## Deploying the Custom Contract - -To deploy your agent with the custom contract, add the `--wasm` flag when using the Shade Agent CLI, specifying the path to your wasm file. Depending on the size of the wasm, you may require more NEAR to deploy the contract. This can be done using the `--funding` flag, followed by the amount of NEAR (100KB = 1 NEAR). - -Here is an example: - -```bash -shade-agent-cli --wasm contract/target/near/contract.wasm --funding 5 -``` - ---- - -## Interacting with Custom Contract - -To call a function on your custom agent contract, use the `agentCall` function provided by the Shade Agent API. Please refer to the [relevant docs](./api.md#agent-call) for calling the contract in your desired language. \ No newline at end of file diff --git a/docs/ai/shade-agents/reference/environment-variables.md b/docs/ai/shade-agents/reference/environment-variables.md deleted file mode 100644 index 9a20ab8243e..00000000000 --- a/docs/ai/shade-agents/reference/environment-variables.md +++ /dev/null @@ -1,92 +0,0 @@ ---- -id: environment-variables -title: Environment Variables -sidebar_label: Environment Variables -description: "Learn about the required and optional environment variables as part of the Shade Agent Framework." ---- - -Environment variables are a crucial component of the Shade Agent Framework. They configure your Shade Agent and are passed encrypted into your agent when it goes live. Note that the same agent code (same Docker Compose file) can use different environment variables in different deployments. - -The environment variables file must be named `.env.development.local`. - -## Required Variables - -- **NEAR_ACCOUNT_ID** - - :::info Example - NEAR_ACCOUNT_ID=example-account.testnet - ::: - - This is the NEAR account ID used to create the agent contract's account when running the Shade Agent CLI and is used to automatically fund the agent's account on boot. You should ensure this account remains funded as you continue to deploy additional agents. - - You can create a NEAR account by using the NEAR CLI. - - Install the NEAR CLI: - - ```bash - curl --proto '=https' --tlsv1.2 -LsSf https://github.com/near/near-cli-rs/releases/latest/download/near-cli-rs-installer.sh | sh - ``` - - Create an account: - - ```bash - export ACCOUNT_ID=example-name.testnet - near account create-account sponsor-by-faucet-service $ACCOUNT_ID autogenerate-new-keypair save-to-keychain network-config testnet create - ``` - - Replace `example-name.testnet` with a unique account ID. - -- **NEAR_SEED_PHRASE** - - :::info Example - NEAR_SEED_PHRASE="book chapter unknown knife strange inherit amazing artist mixture loan rotate lyrics" - ::: - - This is the seed phrase for the NEAR_ACCOUNT_ID. When creating an account with the above command, the seed phrase will be printed to the terminal. - -- **NEXT_PUBLIC_contractId** - - :::info Examples - NEXT_PUBLIC_contractId=ac-proxy.example-account.testnet - NEXT_PUBLIC_contractId=ac-sandbox.example-account.testnet - ::: - - This is the NEAR account ID where the agent contract will be deployed when running the Shade Agent CLI. The account is automatically created when you run the Shade Agent CLI. This account must be your NEAR_ACCOUNT_ID prefixed with either `ac-proxy.` or `ac-sandbox.`, which determines whether the deployment is local or to a TEE, respectively. - -- **API_CODEHASH** - - The API_CODEHASH defines the code hash of the Shade Agent API. You only need to update this when a new API version is released. The [Quickstart Template](https://github.com/NearDeFi/shade-agent-template/blob/main/.env.development.local.example#L9) always includes the most up-to-date API code hash. - -- **APP_CODEHASH** - - The APP_CODEHASH defines the code hash of your agent. You don't need to edit this as it will be automatically updated when running the Shade Agent CLI in production. - -- **DOCKER_TAG** - - :::info Example - DOCKER_TAG=username/my-app - ::: - - The DOCKER_TAG specifies the location of your app image on Docker Hub. Edit this tag to match your Docker username in the first part, and choose any name you'd like for the second part. The CLI will automatically update the Docker tag in your docker-compose.yaml file when it runs in production. - -- **PHALA_API_KEY** - - :::info Example - PHALA_API_KEY=phak_tIhrDY0mXJMgmLLMEMoM6yBxOsjfVM-sTmXmjOF4Fks - ::: - - The PHALA_API_KEY is used to upload your agent to Phala Cloud when running the Shade Agent CLI. You can get a key [here](https://cloud.phala.network/dashboard/tokens). - -## Optional Environment Variables - -- **API_PORT** - - :::info Example - API_PORT=4000 - ::: - - The API_PORT defines which port number the Shade Agent API is exposed on. The API by default is hosted on port 3140. - -## Your Own Variables - -You should also set any additional environment variables your agent may need in the `.env.development.local` file. Remember to update your [Docker Compose](https://github.com/NearDeFi/shade-agent-template/blob/main/docker-compose.yaml#L21) file to pass these additional variables to your agent. \ No newline at end of file diff --git a/docs/ai/shade-agents/reference/plugins.md b/docs/ai/shade-agents/reference/plugins.md deleted file mode 100644 index 3d06778e8ab..00000000000 --- a/docs/ai/shade-agents/reference/plugins.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -id: plugins -title: Shade Agent Plugins -sidebar_label: Plugins -description: "Learn how to use plugins to extend Shade Agent functionality." ---- - -Docs for integrating plugins into your Shade Agent will be coming soon. - -In the meantime, please feel free to check out these links: -- Docs on using [private and verifiable inference](https://docs.near.ai/cloud/get-started/) -- An example using a [Twitter API](https://github.com/NearDeFi/shade-agent-basednames) \ No newline at end of file diff --git a/docs/ai/shade-agents/tutorials/ai-dao/overview.md b/docs/ai/shade-agents/tutorials/ai-dao/overview.md index 8326a345c75..dd8c1b50fb7 100644 --- a/docs/ai/shade-agents/tutorials/ai-dao/overview.md +++ b/docs/ai/shade-agents/tutorials/ai-dao/overview.md @@ -32,7 +32,6 @@ This tutorial demonstrates how key components of the Shade Agent Framework work To understand this tutorial, you should have familiarity with these concepts: - [Shade Agents](../../getting-started/introduction.md) - [NEAR Smart Contracts](../../../../smart-contracts/what-is.md) -- [Custom Agent Contracts](../../reference/custom-agent-contract.md) --- diff --git a/website/sidebars.js b/website/sidebars.js index 5211eaea986..8f75f18bce9 100644 --- a/website/sidebars.js +++ b/website/sidebars.js @@ -230,9 +230,6 @@ const sidebar = { "Reference": [ "ai/shade-agents/reference/api", "ai/shade-agents/reference/cli", - "ai/shade-agents/reference/environment-variables", - "ai/shade-agents/reference/custom-agent-contract", - "ai/shade-agents/reference/plugins", ] }, ] From dea1854d494b4ff03940eb3ff3419ae406ed0ea5 Mon Sep 17 00:00:00 2001 From: PiVortex Date: Mon, 16 Feb 2026 17:27:04 +0000 Subject: [PATCH 03/12] progress on agent-contract reference doc --- .../shade-agents/reference/agent-contract.md | 206 ++++++++++++++++++ website/sidebars.js | 1 + 2 files changed, 207 insertions(+) create mode 100644 docs/ai/shade-agents/reference/agent-contract.md diff --git a/docs/ai/shade-agents/reference/agent-contract.md b/docs/ai/shade-agents/reference/agent-contract.md new file mode 100644 index 00000000000..1bae3076055 --- /dev/null +++ b/docs/ai/shade-agents/reference/agent-contract.md @@ -0,0 +1,206 @@ +--- +id: agent-contract +title: Agent Contract +sidebar_label: Agent Contract +description: "Review the agent contract template for the Shade Agent Framework." +--- + +import { Github } from "@site/src/components/UI/Codetabs"; + +The agent contract is the on-chain component of the Shade Agent Framework. It handles agent registration, measurements and PPID management and enforces that only valid agent can call specific methods. + +On this page you'll walk through the key components of the a reference agent contract then you'll see how to implement your own agent gated functions in the [your_functions](https://github.com/NearDeFi/shade-agent-template/blob/2.0/agent-contract/src/your_functions.rs) file. You may want to make changes to other parts of the contract depending on your use case. If you would like to dig deeper into the contract, the source code can be found in the [shade-agent-template](https://github.com/NearDeFi/shade-agent-template/tree/2.0/agent-contract). + + +flow + +contract deployed +initizalized by owner +measurements + PPID approved by owner +agent registers +agent can now call agent gated functions + + +--- + +## Initialization + +The template takes four arguments. The CLI will initialize the contract with default arguments. +- **requires_tee**: Sets the contract to local or TEE mode. Changes the behavior of the contract depending on the mode to switch easily between local and TEE deployments. +- **attestation_expiration_time_ms**: Sets how long an agent is valid for after registering. +- **owner_id**: Sets the account ID of the owner who is permitted to call owner gated methods. In general the owner shoudl be set to a multisig. +- **mpc_contract_id**: Sets the MPC contract that the agent contract will interact with. + +On init the rest of the state in the contract is set to empty. + + + +If your contract requires additional state you'll need to modify the init method. + +--- + +## Measurements, PPID, whitelist and agent management + +The `owner_id` of the contract can manage the approved measurements, PPIDs, whitelist and agents. + +### Measurements + +The approved measurements decide what code an agent is allowed to run. The CLI will approve a set of measurements for your agent when ran. You can learn more about measurements here TODO. + +An owner sets which measurements are approved in a contract and can add and remove them over time. To upgrade the code an agent runs a typical upgrade pattern is that a new set of measurements are approved to the contract, a transition period happens (of say a week) allowing operators time to start running the new codebase, and then the old measurements are removed. + + + +### PPID + +The approved PPIDs decide which physical TEE CPUs an agent is allowed to run on. The CLI will approve a list of default PPIDs when ran. You can learn more about PPID here TODO. + + + +### Agent + +The authorization of agents happens by an agent calling the `register_agent` method, but an owner can manually remove an agent. This can be useful for cleaning up no longer valid agents or removing agents in the case of a TEE exploit. + + + +Note that a removed agent can re-register if it again provides a valid attestation. + +### Whitelist + +The whitelist is only relevant for local mode. It sets which account IDs are permitted to call the agent gated methods, as in local mode the contract cannot verify an agent is running the correct code. The CLI will whitelist the specified account ID when running `shade whitelist`. You can learn more about whitelisting agents here TODO. + + + +--- + +## Register agent + +Agents register in the contract by calling the `register_agent` method. The method checks that the agent has a valid attestation via `verify_attestation`, and if so registers it in the contract recording its measurements, PPID and how long it's valid for (determined by the attestation_expiration_time). + +An agent must pay 0.005 NEAR to cover its own storage cost in the contract. + + + +By default an agent that provides a valid attestation can register. Meaning that anyone may be able to run an agent and register. Depending on your use case you may want to add additional restrictions to an agent (for example require the agent to contain a secret and perform signature verification) or only allow a single agent to register at a time. + +### Verify attestation + +`verify_attestation` checks if an agent is allowed to register. It's behavior changes depending on whether the contract is in TEE or local mode. + +#### TEE mode + +If the contract is in TEE mode `requires_tee = true` then the method will approve the agent if it provides a genuine attestation, this is checked via the `verify` function provided by the [shade-attestation crate](https://github.com/NearDeFi/shade-agent-framework/tree/main/shade-attestation). This function expects a list of approved measurement and PPIDs, the current timestamp in milliseconds and something called the `report data`. + + + +The verify function expects the attestation's report data to contain the NEAR account ID of the agent that called the register function. This proves that the attestation was produced in the same TEE that the agent's key was generated in, this stops attackers replaying genuine attestations. The report data is submitted as bytes. + + + +#### Local mode + +If the contract is in local mode `requires_tee = false` then the method will approve the agent if it is whitelisted and the the default fake measurements and PPID are approved in the contract. + + + +--- + +## Require valid agent + +Methods in the contract can be gated to only allow valid agents to call them. The contract has a helper function called `require_valid_agent` that completes the valid checks. Just because an agent once registered doesn't mean that its currently valid. + + + + + + + +To gate a function you must call the `require_valid_agent` function, check if it returns a promise, and if so execute the promise. You can see the logic here: + + + +If the function returns a promise it means that it is not a valid + +--- + + +## Your logic + +example request signature + + +Put your own functions here + +omni-transaction-rs + + +--- + +## Building the contract + + +--- + +for Calling other methods + +Use NEAR CLI \ No newline at end of file diff --git a/website/sidebars.js b/website/sidebars.js index 8f75f18bce9..b7a76bd7c28 100644 --- a/website/sidebars.js +++ b/website/sidebars.js @@ -230,6 +230,7 @@ const sidebar = { "Reference": [ "ai/shade-agents/reference/api", "ai/shade-agents/reference/cli", + "ai/shade-agents/reference/agent-contract", ] }, ] From 582334391730f348d7496265886580eebe8bda47 Mon Sep 17 00:00:00 2001 From: PiVortex Date: Tue, 17 Feb 2026 13:22:42 +0000 Subject: [PATCH 04/12] do agent-contract docs --- .../shade-agents/reference/agent-contract.md | 188 +++++++++++++----- docs/ai/shade-agents/reference/api.md | 4 +- docs/ai/shade-agents/reference/cli.md | 4 +- 3 files changed, 146 insertions(+), 50 deletions(-) diff --git a/docs/ai/shade-agents/reference/agent-contract.md b/docs/ai/shade-agents/reference/agent-contract.md index 1bae3076055..98ef84a8060 100644 --- a/docs/ai/shade-agents/reference/agent-contract.md +++ b/docs/ai/shade-agents/reference/agent-contract.md @@ -5,33 +5,36 @@ sidebar_label: Agent Contract description: "Review the agent contract template for the Shade Agent Framework." --- +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; import { Github } from "@site/src/components/UI/Codetabs"; -The agent contract is the on-chain component of the Shade Agent Framework. It handles agent registration, measurements and PPID management and enforces that only valid agent can call specific methods. +The agent contract is the on-chain component of the Shade Agent Framework. It handles agent registration, measurement and PPID approval, and enforces that only valid agents can call specific methods. -On this page you'll walk through the key components of the a reference agent contract then you'll see how to implement your own agent gated functions in the [your_functions](https://github.com/NearDeFi/shade-agent-template/blob/2.0/agent-contract/src/your_functions.rs) file. You may want to make changes to other parts of the contract depending on your use case. If you would like to dig deeper into the contract, the source code can be found in the [shade-agent-template](https://github.com/NearDeFi/shade-agent-template/tree/2.0/agent-contract). +**suggested:** On this page you'll walk through the key components of the reference agent contract and how to implement your own agent-gated functions. You may need to change other parts of the contract depending on your use case. The full source lives in the [shade-agent-template](https://github.com/NearDeFi/shade-agent-template/tree/2.0/agent-contract) repo. +--- -flow - -contract deployed -initizalized by owner -measurements + PPID approved by owner -agent registers -agent can now call agent gated functions +## Flow +High-level flow: +- Owner deploys and initializes the contract. +- Owner approves measurements and PPIDs. +- Each agent calls `register_agent` with a valid attestation. +- Valid agents can then call agent-gated methods. --- ## Initialization -The template takes four arguments. The CLI will initialize the contract with default arguments. -- **requires_tee**: Sets the contract to local or TEE mode. Changes the behavior of the contract depending on the mode to switch easily between local and TEE deployments. -- **attestation_expiration_time_ms**: Sets how long an agent is valid for after registering. -- **owner_id**: Sets the account ID of the owner who is permitted to call owner gated methods. In general the owner shoudl be set to a multisig. -- **mpc_contract_id**: Sets the MPC contract that the agent contract will interact with. -On init the rest of the state in the contract is set to empty. +The `new` method initializes the contract and takes four arguments (the CLI can initialize the contract with defaults): +- **requires_tee**: Whether the contract runs in local or TEE mode. This switches the behavior of the contract so you can move easily between local and TEE deployments. +- **attestation_expiration_time_ms**: How long a registration stays valid for after an agent registers. +- **owner_id**: The account ID allowed to call owner-only methods. The owner should usually be a multisig. +- **mpc_contract_id**: The Chain Signatures MPC contract that the agent contract will call for multichain signing. + +On initialization, the rest of the contract state is left empty. -If your contract requires additional state you'll need to modify the init method. +If your contract needs additional state, add it in the init method and extend the `Contract` struct accordingly. --- -## Measurements, PPID, whitelist and agent management +## Measurements, PPID, whitelist, and agent management -The `owner_id` of the contract can manage the approved measurements, PPIDs, whitelist and agents. +The `owner_id` of the contract can manage the approved measurements, PPIDs, whitelist, and agents. ### Measurements -The approved measurements decide what code an agent is allowed to run. The CLI will approve a set of measurements for your agent when ran. You can learn more about measurements here TODO. +The approved measurements decide what code an agent is allowed to run. The CLI will approve a set of measurements for your agent when run. You can learn more about measurements here TODO. -An owner sets which measurements are approved in a contract and can add and remove them over time. To upgrade the code an agent runs a typical upgrade pattern is that a new set of measurements are approved to the contract, a transition period happens (of say a week) allowing operators time to start running the new codebase, and then the old measurements are removed. +The owner controls which measurements are approved and can add or remove them over time. A typical agent code upgrade flow is: approve a new set of measurements, allow a transition period (e.g. a week) so operators can update agents to run the new code, then remove the old measurements. -Note that a removed agent can re-register if it again provides a valid attestation. +:::note +A removed agent can re-register by calling `register_agent` with a valid attestation. +::: ### Whitelist -The whitelist is only relevant for local mode. It sets which account IDs are permitted to call the agent gated methods, as in local mode the contract cannot verify an agent is running the correct code. The CLI will whitelist the specified account ID when running `shade whitelist`. You can learn more about whitelisting agents here TODO. +The whitelist applies only in local mode. It defines which account IDs may call agent-gated methods, since in local mode the contract cannot verify that an agent is running approved code. Use `shade whitelist` in the CLI to add an account. (Whitelisting documentation link: TODO.) -By default an agent that provides a valid attestation can register. Meaning that anyone may be able to run an agent and register. Depending on your use case you may want to add additional restrictions to an agent (for example require the agent to contain a secret and perform signature verification) or only allow a single agent to register at a time. +By default, an agent that provides a valid attestation can register. Meaning that anyone may be able to run an agent and register. Depending on your use case, you may want to add additional restrictions to an agent, for example, an allow-list of accounts, proof of a shared secret, or a limit of one agent per contract. ### Verify attestation -`verify_attestation` checks if an agent is allowed to register. It's behavior changes depending on whether the contract is in TEE or local mode. +`verify_attestation` decides if an agent is allowed to register. Its behavior depends on whether the contract is in TEE or local mode. #### TEE mode -If the contract is in TEE mode `requires_tee = true` then the method will approve the agent if it provides a genuine attestation, this is checked via the `verify` function provided by the [shade-attestation crate](https://github.com/NearDeFi/shade-agent-framework/tree/main/shade-attestation). This function expects a list of approved measurement and PPIDs, the current timestamp in milliseconds and something called the `report data`. +In TEE mode (`requires_tee = true`), the method accepts the agent only if it supplies a valid attestation this is checked using the the `verify` function provided by the [shade-attestation crate](https://github.com/NearDeFi/shade-agent-framework/tree/main/shade-attestation), which takes the list of approved measurements and PPIDs, the current timestamp (in seconds), and the expected `report data`. -The verify function expects the attestation's report data to contain the NEAR account ID of the agent that called the register function. This proves that the attestation was produced in the same TEE that the agent's key was generated in, this stops attackers replaying genuine attestations. The report data is submitted as bytes. +The attestation’s report data must contain the NEAR account ID of the agent. This binds the attestation to the same TEE where the agent’s key was created to prevent replay of valid attestations. Report data is passed as bytes. +:::caution Handle the promise +You must execute the promise returned by `require_valid_agent` when it is `Some(promise)`; otherwise, the invalid agent can still call the function. +::: +`require_valid_agent` first loads the agent from storage; if the caller is not registered, it panics. + + +It then checks whether the agent is still valid. It's valid if its registration has not expired (determined by `attestation_expiration_time_ms`), its measurements are still in the approved set, and its PPID is still approved. + + + + + + + + + + -To gate a function you must call the `require_valid_agent` function, check if it returns a promise, and if so execute the promise. You can see the logic here: + + +If the agent is valid, then the function will return `None`. If the agent is invalid, it will be removed from the map of agents, an event will be emitted detailing the reasons for removal, and a promise will be returned from the function that will call `fail_on_invalid_agent` in the next block. -If the function returns a promise it means that it is not a valid +The promise calls `fail_on_invalid_agent`, which panics in the next block. Panicking in the next block (rather than the current one) ensures the agent is removed from storage; panicking in the current block would revert that removal. + + --- - ## Your logic -example request signature - +The template includes an example `request_signature` function. It allows a valid agent to request a signature for a transaction payload from the MPC contract, so you can sign transactions for most chains. You can learn more about singing transactions for different chains in the [chain signatures documentation](../../../chain-abstraction/chain-signatures/implementation). -Put your own functions here + -omni-transaction-rs +You should implement your own agent-gated functions in this `your_functions.rs` file, following the same pattern: call `require_valid_agent`, then run your logic. +:::tip On chain guard rails +A key part of the Shade Agent Framework is the ability to implement on-chain guard rails. This gives protection against unauthorized actions - even if the TEE is compromised. It's strongly recommended that you build actions within the agent contract rather than in the agent itself, for example, using the [omni-transaction-rs](https://github.com/Omni-rs/omni-transaction-rs) library. +::: --- ## Building the contract +Usually, you build and deploy with the Shade Agent CLI: `shade deploy`. To build the contract manually, use the following command: + + + + + + For Linux, you can compile the contract directly with [cargo near](https://github.com/near/cargo-near/releases/latest). + + + ```bash + cargo near build non-reproducible-wasm --no-abi + ``` + + + + + + Because of a required dependency in the shade-attestation crate, agent contracts cannot be built on Mac machines. You can build the contract inside a Docker container using the following command: + + ```bash + docker run --rm -v "$(pwd)":/workspace pivortex/near-builder@sha256:cdffded38c6cff93a046171269268f99d517237fac800f58e5ad1bcd8d6e2418 cargo near build non-reproducible-wasm --no-abi + ``` + + If you would like to build the image yourself you can use [this Dockerfile](https://github.com/NearDeFi/shade-agent-framework/blob/main/contract-builder/Dockerfile). + + + + + +:::note +The `--no-abi` flag is used to build the contract without an ABI. This is required because the shade-attestation crate currently doesn't support ABI generation. +::: --- -for Calling other methods +## Calling methods -Use NEAR CLI \ No newline at end of file +The Shade Agent CLI calls the main contract methods when you run `shade deploy`, but it does not cover every method. For methods the CLI doesn’t support, use the [NEAR CLI](../../../tools/cli) or create scripts using the [NEAR API](../../../tools/near-api). \ No newline at end of file diff --git a/docs/ai/shade-agents/reference/api.md b/docs/ai/shade-agents/reference/api.md index d3ca6ada95c..433ce3e164b 100644 --- a/docs/ai/shade-agents/reference/api.md +++ b/docs/ai/shade-agents/reference/api.md @@ -112,7 +112,7 @@ await agent.register(); **TEE vs local:** - TEE: Registers with a real attestation. -- Local: Registers with a default fake attestation. +- Local: Registers with a mock attestation. Requires agentContractId in config. @@ -160,7 +160,7 @@ const attestation = await agent.getAttestation(); **TEE vs local:** - TEE: Returns a real attestation. -- Local: Returns a default fake attestation. +- Local: Returns a mock attestation. --- diff --git a/docs/ai/shade-agents/reference/cli.md b/docs/ai/shade-agents/reference/cli.md index 7de43162c9b..09051320592 100644 --- a/docs/ai/shade-agents/reference/cli.md +++ b/docs/ai/shade-agents/reference/cli.md @@ -129,7 +129,7 @@ Placeholders in args: Placeholders in args: -- `` — Resolves to real calculated measurements for the application for TEE and fake default measurements for local. +- `` — Resolves to real calculated measurements for the application for TEE and mock measurements for local. ### approve_ppids @@ -142,7 +142,7 @@ Placeholders in args: Placeholders in args: -- `` — Resolves to a list of all PPIDs of devices on Phala Cloud for TEE and a fake fault PPID for local. +- `` — Resolves to a list of all PPIDs of devices on Phala Cloud for TEE and a mock PPID for local. ### build_docker_image (TEE only) From 27994a148e953d3cb1af1dd1efc67a056a434283 Mon Sep 17 00:00:00 2001 From: PiVortex Date: Tue, 17 Feb 2026 18:01:38 +0000 Subject: [PATCH 05/12] working on terminology --- docs/ai/shade-agents/concepts/security.md | 2 +- docs/ai/shade-agents/concepts/terminology.md | 129 ++++++++++++++++++ .../shade-agents/reference/agent-contract.md | 4 +- website/sidebars.js | 1 + 4 files changed, 133 insertions(+), 3 deletions(-) create mode 100644 docs/ai/shade-agents/concepts/terminology.md diff --git a/docs/ai/shade-agents/concepts/security.md b/docs/ai/shade-agents/concepts/security.md index 3bfc93f31e9..a0a647e2dc3 100644 --- a/docs/ai/shade-agents/concepts/security.md +++ b/docs/ai/shade-agents/concepts/security.md @@ -23,7 +23,7 @@ Please review this list of security considerations before deploying a Shade Agen ## Restricting Actions -While TEEs are considered trusted and tamper-resistant, implementing tight restrictions or `guard rails` on agent actions within the agent contract is recommended so that even if the private key to a agent was extracted funds can't be withdrew. +While TEEs are considered trusted and tamper-resistant, implementing tight restrictions or `guardrails` on agent actions within the agent contract is recommended so that even if the private key to a agent was extracted funds can't be withdrew. Examples of restrictions could be: - The agent contract can only build transactions for a list of functions and smart contract addresses. diff --git a/docs/ai/shade-agents/concepts/terminology.md b/docs/ai/shade-agents/concepts/terminology.md new file mode 100644 index 00000000000..383d23977b4 --- /dev/null +++ b/docs/ai/shade-agents/concepts/terminology.md @@ -0,0 +1,129 @@ +--- +id: terminology +title: Terminology +sidebar_label: Terminology +description: "Learn the key terms and concepts used in the Shade Agent Framework." +--- + +Below are the main terms and concepts used in the Shade Agent Framework. + +--- + +## Shade Agent Framework + +The Shade Agent Framework is a suite of tools for creating Web3 agents and off-chain services that are trust-minimized, decentralized and verifiable. It includes the Shade Agent API, the Shade Agent CLI and an agent contract template. The framework aims to abstract most of the underlying TEE and blockchain interactions so you can focus on building your application. + +--- + +## Shade Agent + +A Shade Agent is an application built using the Shade Agent Framework. See the [what can you build section](../getting-started/introduction.md#what-can-you-build) for some examples. + +--- + +## Agent + +In the Shade Agent Framework an agent is a single instance of the off-chain code running inside a TEE (or locally in development) that uses the Shade Agent API. One agent contract can have many registered agents: they may run the same code for redundancy or different code for different tasks. + +--- + +## Agent's account + +The agent’s account is the NEAR account ID that represents that agent on-chain. It is an implicit account (64-character hex) derived from the agent's ephemeral private key, meaning the private key and account ID are unique to the agent, and change each time the agent reboots. In local mode you can set the agents account ID to be deterministic to avoid re-whitelisting or re-funding the agent on each run. + +--- + +## Agent contract + +The agent contract is the on-chain NEAR smart contract that authorizes agents, enforces guardrails and gives agents access to on-chain signing. Agents must provide a valid attestation, have valid measurements, a valid PPID and not be expired to have access to on-chain signing. + +--- + +## On-chain guardrails + +On-chain guardrails are restrictions that are enforced on the agent contract to prevent unauthorized actions even if the TEE is compromised. Examples include limiting transactions to specific functions, smart contracts, blockchains or amounts. Guardrails are usually implemented using the [omni-transaction-rs](https://github.com/Omni-rs/omni-transaction-rs) library. + +--- + +## On-chain signing + +The agent contract can sign transactions for most chains via NEAR's [chain signatures](../../../chain-abstraction/chain-signatures.md) service, it's accessed by making cross contract calls to the MPC contract. All assets and state of the Shade Agent should be tied to the agent contract not the agent's account since agent's keys are ephemeral. + +--- + +## TEE + +A trusted execution environment is a secure part of a CPU that runs code in an isolated and protected way. Execution and state stay private, including from the host. TEEs produce attestations that prove both that code is running inside a TEE and that it is the expected code. + +--- + +## Local + +Local mode means the agent runs on your machine (or any non-TEE environment) instead of inside a TEE. There is no real attestation; and the contract uses a whitelist of allowed account IDs instead. Use local mode for development and testing only, not for production. + +--- + +## Registering an agent + +An agent registers with an agent contract by calling the `register_agent` method which verifies it has a valid attestation, on success the agent will be stored in the contract's state with its measurements, PPID and validity period. + +--- + +## Whitelisted accounts + +The whitelist is a set of NEAR account IDs that are allowed to register when the agent contract is in local mode. Because the contract cannot verify code or hardware in local mode, it instead restricts access to specific account IDs. + +--- + +## Valid agent + +A valid agent is one that has is registered with the agent contract and still has measurements and a PPID that are approved and its registration has not expired. Valid agents can call agent-gated methods. + + +--- + +## Attestation + +An attestation is a cryptographic proof produced by a TEE that the application is running inside a genuine TEE. The agent submits its attestation when registering with the agent contract and the contract verifies that its a genuine attestation, and checks that the attestation contains a set of approved measurements and an approved PPID. + +--- + +## Approved measurements + +The measurements are hashes that uniquely identify the code running in the TEE, and the platform it's running on. The agent contract stores a list of approved measurements which can be updated by the owner of the contract. There are 6 measurements: +- **MRTD**: measures the initial setup of the trusted domain. This is constant. +- **RTMR0**: measures the virtual hardware. This is constant for a given number of vCPUs and memory allocation. +- **RTMR1**: measures the kernel. This is constant. +- **RTMR2**: measures the Dstack image version. This is constant for a given Dstack image version. +- **Key provider digest**: measures the key provider of the TEE. By default Shade Agents contain Phala's key providers but don't actually use it since it uses a local key provider. This is constant for Phala's key provider. +- **App compose hash**: measures the application. This is constant for a given Docker Compose file and app layer configurations. + +--- + +## PPID + +The PPID (Provisioning Platform ID) is a unique identifier of a physical TEE machine. Recent exploits to TEEs have been due to attackers having physical access to the machine, revealing that the physical location of the machine is important in TEE security. By setting approved PPIDs the agent contract can ensure that only agents running on specific machines can register. You should approve PPIDs for machines known to be located in secure data centers. By default the CLI approves all PPIDs for Phala Cloud. + +Note that on Phala Cloud two different deployments can have the same PPID if they are running on the same server since resources are virtualized. + +--- + +## Docker + +Docker is used in the Shade Agent Framework to deploy agents to TEEs. + +- The Dockerfile defines how to build a single image for your agent (dependencies, entrypoint, etc.). The CLI uses it when building the image. +- The Docker image is a single packaged application for your agent. +- The Docker Compose file defines the full application stack of the agent that runs in the TEE. It defines the images for the agent, the allowed environment variables, ports, volumes, etc. + +--- + +## Phala Cloud + +Phala Cloud is a cloud provider for hosting applications inside Trusted Execution Environments. The Shade Agent Framework uses it as its default hosting provider for agents. + +--- + +## DStack + +DStack is a framework for running and proving applications inside of Trusted Execution Environments that Phala Cloud uses. The Shade Agent Framework only supports Dstack environments either on Phala Cloud, your own hardware or other providers. \ No newline at end of file diff --git a/docs/ai/shade-agents/reference/agent-contract.md b/docs/ai/shade-agents/reference/agent-contract.md index 98ef84a8060..0b0f2c5f790 100644 --- a/docs/ai/shade-agents/reference/agent-contract.md +++ b/docs/ai/shade-agents/reference/agent-contract.md @@ -254,8 +254,8 @@ The template includes an example `request_signature` function. It allows a valid You should implement your own agent-gated functions in this `your_functions.rs` file, following the same pattern: call `require_valid_agent`, then run your logic. -:::tip On chain guard rails -A key part of the Shade Agent Framework is the ability to implement on-chain guard rails. This gives protection against unauthorized actions - even if the TEE is compromised. It's strongly recommended that you build actions within the agent contract rather than in the agent itself, for example, using the [omni-transaction-rs](https://github.com/Omni-rs/omni-transaction-rs) library. +:::tip On chain guardrails +A key part of the Shade Agent Framework is the ability to implement on-chain guardrails. This gives protection against unauthorized actions - even if the TEE is compromised. It's strongly recommended that you build actions within the agent contract rather than in the agent itself, for example, using the [omni-transaction-rs](https://github.com/Omni-rs/omni-transaction-rs) library. ::: --- diff --git a/website/sidebars.js b/website/sidebars.js index b7a76bd7c28..d1481e0af43 100644 --- a/website/sidebars.js +++ b/website/sidebars.js @@ -210,6 +210,7 @@ const sidebar = { "Concepts": [ "ai/shade-agents/concepts/framework-overview", "ai/shade-agents/concepts/what-can-you-build", + "ai/shade-agents/concepts/terminology", "ai/shade-agents/concepts/security", ] }, From b8d81f25284dbec21d5416a39c59aa2459274edf Mon Sep 17 00:00:00 2001 From: PiVortex Date: Wed, 18 Feb 2026 12:48:23 +0000 Subject: [PATCH 06/12] update shade intro roughly --- docs/ai/shade-agents/concepts/terminology.md | 24 ++++---- .../getting-started/introduction.md | 54 +++++++++--------- .../docs/ai/shade-agent-stack-diagram.png | Bin 139864 -> 124016 bytes 3 files changed, 41 insertions(+), 37 deletions(-) diff --git a/docs/ai/shade-agents/concepts/terminology.md b/docs/ai/shade-agents/concepts/terminology.md index 383d23977b4..0c02ed81ecf 100644 --- a/docs/ai/shade-agents/concepts/terminology.md +++ b/docs/ai/shade-agents/concepts/terminology.md @@ -11,7 +11,9 @@ Below are the main terms and concepts used in the Shade Agent Framework. ## Shade Agent Framework -The Shade Agent Framework is a suite of tools for creating Web3 agents and off-chain services that are trust-minimized, decentralized and verifiable. It includes the Shade Agent API, the Shade Agent CLI and an agent contract template. The framework aims to abstract most of the underlying TEE and blockchain interactions so you can focus on building your application. +The Shade Agent Framework is a suite of tools for creating Web3 agents and off-chain services that are trust-minimized, decentralized, and verifiable. It leverages on-chain signing to allow agents to to hold assets and sign transactions on most blockchains and implement strict guardrails to prevent unauthorized actions. + +It includes the Shade Agent API, the Shade Agent CLI, and an agent contract template. The framework aims to abstract most of the underlying TEE and blockchain interactions so you can focus on building your application. --- @@ -23,7 +25,7 @@ A Shade Agent is an application built using the Shade Agent Framework. See the [ ## Agent -In the Shade Agent Framework an agent is a single instance of the off-chain code running inside a TEE (or locally in development) that uses the Shade Agent API. One agent contract can have many registered agents: they may run the same code for redundancy or different code for different tasks. +In the Shade Agent Framework, an agent is a single instance of the off-chain code running inside a TEE (or locally in development) that uses the Shade Agent API. One agent contract can have many registered agents: they may run the same code for redundancy or different code for different tasks. --- @@ -53,19 +55,19 @@ The agent contract can sign transactions for most chains via NEAR's [chain signa ## TEE -A trusted execution environment is a secure part of a CPU that runs code in an isolated and protected way. Execution and state stay private, including from the host. TEEs produce attestations that prove both that code is running inside a TEE and that it is the expected code. +A trusted execution environment is a secure part of a CPU that runs code in an isolated and protected way. Execution and state stay private, including from the host. TEEs produce cryptographic attestations that prove it's running certain code inside a genuine TEE. --- ## Local -Local mode means the agent runs on your machine (or any non-TEE environment) instead of inside a TEE. There is no real attestation; and the contract uses a whitelist of allowed account IDs instead. Use local mode for development and testing only, not for production. +Local mode means the agent runs on your machine (or any non-TEE environment) instead of inside a TEE. There is no real attestation, and the contract uses a whitelist of allowed account IDs instead. Use local mode for development and testing only, not for production. --- ## Registering an agent -An agent registers with an agent contract by calling the `register_agent` method which verifies it has a valid attestation, on success the agent will be stored in the contract's state with its measurements, PPID and validity period. +An agent registers with an agent contract by calling the `register_agent` method, which verifies it has a valid attestation. On successful registration the agent will be stored in the contract's state with its measurements, PPID, and validity period. --- @@ -77,34 +79,34 @@ The whitelist is a set of NEAR account IDs that are allowed to register when the ## Valid agent -A valid agent is one that has is registered with the agent contract and still has measurements and a PPID that are approved and its registration has not expired. Valid agents can call agent-gated methods. +A valid agent is one that is registered with the agent contract and still has measurements and a PPID that are approved, and its registration has not expired. Valid agents can call agent-gated methods. --- ## Attestation -An attestation is a cryptographic proof produced by a TEE that the application is running inside a genuine TEE. The agent submits its attestation when registering with the agent contract and the contract verifies that its a genuine attestation, and checks that the attestation contains a set of approved measurements and an approved PPID. +An attestation is a cryptographic proof produced by a TEE that the application is running inside a genuine TEE. The agent submits its attestation when registering with the agent contract, and the contract verifies that it's a genuine attestation, and checks that the attestation contains a set of approved measurements and an approved PPID. --- ## Approved measurements -The measurements are hashes that uniquely identify the code running in the TEE, and the platform it's running on. The agent contract stores a list of approved measurements which can be updated by the owner of the contract. There are 6 measurements: +The measurements are hashes that uniquely identify the code running in the TEE, and the platform it's running on. The agent contract stores a list of approved measurements, which can be updated by the owner of the contract. There are 6 measurements: - **MRTD**: measures the initial setup of the trusted domain. This is constant. - **RTMR0**: measures the virtual hardware. This is constant for a given number of vCPUs and memory allocation. - **RTMR1**: measures the kernel. This is constant. - **RTMR2**: measures the Dstack image version. This is constant for a given Dstack image version. -- **Key provider digest**: measures the key provider of the TEE. By default Shade Agents contain Phala's key providers but don't actually use it since it uses a local key provider. This is constant for Phala's key provider. +- **Key provider digest**: measures the key provider of the TEE. By default, Shade Agents contain Phala's key providers but don't actually use it since it uses a chain signatures for decentralized key management instead. This is constant for Phala's key provider. - **App compose hash**: measures the application. This is constant for a given Docker Compose file and app layer configurations. --- ## PPID -The PPID (Provisioning Platform ID) is a unique identifier of a physical TEE machine. Recent exploits to TEEs have been due to attackers having physical access to the machine, revealing that the physical location of the machine is important in TEE security. By setting approved PPIDs the agent contract can ensure that only agents running on specific machines can register. You should approve PPIDs for machines known to be located in secure data centers. By default the CLI approves all PPIDs for Phala Cloud. +The PPID (Provisioning Platform ID) is a unique identifier of a physical TEE machine. Recent exploits of TEEs have been due to attackers having physical access to the machine, revealing that the physical location of the machine is important in TEE security. By setting approved PPIDs, the agent contract can ensure that only agents running on specific machines can register. You should approve PPIDs for machines known to be located in secure data centers. By default, the CLI approves all PPIDs for Phala Cloud. -Note that on Phala Cloud two different deployments can have the same PPID if they are running on the same server since resources are virtualized. +Note that on Phala Cloud, two different deployments can have the same PPID if they are running on the same server, since resources are virtualized. --- diff --git a/docs/ai/shade-agents/getting-started/introduction.md b/docs/ai/shade-agents/getting-started/introduction.md index 0f9ef265228..0c24038b0fc 100644 --- a/docs/ai/shade-agents/getting-started/introduction.md +++ b/docs/ai/shade-agents/getting-started/introduction.md @@ -5,6 +5,8 @@ sidebar_label: What are Shade Agents? description: "Learn about Shade Agents - decentralized and trustless AI agents that control accounts and assets across multiple blockchains using TEEs and NEAR's decentralized key management." --- +import { SigsSupport } from '@site/src/components/sigsSupport'; + :::warning The Shade Agent Framework is experimental and contains known critical vulnerabilities. @@ -15,17 +17,15 @@ No representations or warranties are made regarding security, correctness, or fi A production-ready version of the framework is currently in development. ::: -import { SigsSupport } from '@site/src/components/sigsSupport'; - -The Shade Agent Framework allows developers to build decentralized and trustless AI agents that control accounts and assets across multiple blockchains. +The Shade Agent Framework is a suite of tools for creating Web3 agents and off-chain services that are trust-minimized, decentralized, and verifiable. It leverages on-chain signing allowing agents to hold assets and sign transactions on most blockchains and implement strict guardrails to prevent unauthorized actions. Previous Web3 agents fall into one of two categories: 1. They are trustless and verifiable by using a trusted execution environment (TEE), but if the TEE goes down, the private keys and funds of the agent are lost. 2. The agent’s accounts are persistent, but the agents are centralized. -Shade Agents provide verifiability and non-custody by operating in TEEs, but also persistent control of accounts by using NEAR's decentralized key management. Any instance of an agent running the same code inside a TEE can access the same accounts meaning you don't need to worry about private keys being lost or exposed. +Shade Agents provide verifiability and non-custody by operating in TEEs, but also persistent control of accounts by using NEAR's decentralized key management. Any instance of an agent running the same code inside a TEE can access the same accounts, meaning you don't need to worry about private keys being lost or exposed. -Thanks to combining TEEs with the NEAR tech stack, Shade Agents can autonomously sign transactions across any chain, interact with AI models and external data sources, manage assets, and perform privacy-preserving, verifiable computations, offering the flexibility and performance of Web2 with the verifiability of Web3. +Thanks to combining TEEs with the NEAR tech stack, Shade Agents can autonomously sign transactions across most chains, interact with AI models and external data sources, manage assets, and perform privacy-preserving, verifiable computations, offering the flexibility and performance of Web2 with the verifiability of Web3. :::info Shade Agents power [Agentic Protocols](../concepts/what-can-you-build.md#agentic-protocols): a new type of decentralized application designed to be autonomous, proactive, and intelligent. @@ -39,56 +39,60 @@ Shade Agents consist of two main components: the `agent` and the `agent smart co ![Shade Agent Architecture](/assets/docs/ai/shade-agent-stack-diagram.png) -When an agent is booted up in a TEE, the `TEE's hardware-based entropy` generates a random private key and account. This private key is exclusively used to call the agent contract, not for storing funds. +When an agent is booted up in a TEE, it generates a random ephemeral private key and NEAR account. This private key is exclusively used to call the agent contract, not for storing funds.
What is a TEE? -A trusted execution environment is a secure area of a CPU that runs code in an isolated and protected way. This means one can verify that the expected code is running and its execution is not exposed outside of the enclave. TEEs produce attestations to prove that the code is running within a TEE and that it's running the specified code. +A trusted execution environment is a secure part of a CPU that runs code in an isolated and protected way. Execution and state stay private, including from the host. TEEs produce cryptographic attestations that prove it's running certain code inside a genuine TEE.
-The agent calls the `register_agent` function on the `agent smart contract`, providing two pieces of information generated inside the TEE: -- A `remote attestation quote` (which proves it is running inside a genuine TEE). -- The Docker image's SHA256 `code hash` (to prove that the expected code is running). +The agent calls the `register_agent` function on the `agent smart contract`, providing its `attestation`. The attestation contains: +- A proof that it's running inside a genuine TEE. +- The [measurements](../concepts/terminology.md#measurements) of the code running in the TEE (which uniquely identifies the code and platform it's running on). -If the attestation quote is valid and the code hash matches the expected code hash of the agent (defined during the agent contract's deployment), the agent's account is approved as a valid agent inside the agent contract. +If the attestation is valid, the measurements fit the approved measurements in the contract, and it's running on a certain machine (identified by a [PPID](../concepts/terminology.md#ppid)), then the agent's account is registered inside the agent contract. -Once registered, the `agent` can call the `request_signature` function on the agent contract, enabling it to sign transactions on behalf of the Shade Agent. `request_signature` leverages [chain signatures](../../../chain-abstraction/chain-signatures.md) for decentralized key management, allowing the Shade Agent to hold assets and sign transactions on nearly any chain. +Once registered, the `agent` can call the agent-gated functions on the agent contract. An example of this is the `request_signature` function, enabling it to sign transactions on behalf of the Shade Agent. `request_signature` leverages [chain signatures](../../../chain-abstraction/chain-signatures.md) for decentralized key management, allowing the Shade Agent to hold assets and sign transactions on nearly any chain. -`Anyone` can deploy the same Docker image of the `agent` to a different TEE. Since the Docker image will have the same code hash, it can then be registered as a new valid agent, and thus gain access to signing transactions using the Shade Agent's accounts. This means the accounts are persisted across different TEE instances. To facilitate this functionality, agents are designed to be stateless. +If `anyone` deploys the same code to a different TEE with the same measurements and PPID, it can also register in the contract, and thus gain access to signing transactions using the Shade Agent's accounts. This means the accounts are persisted across different TEE instances. To facilitate this functionality, agents are designed to be stateless. --- ## Agent Contract Functions -The Agent Contract has three main functions: +The Agent Contract has four main functions: -#### Approve Code Hash +#### Approve Measurements -After the contract is deployed, a `code hash` is set to ensure that only agents running the correct code (i.e. it has the same code hash) can be registered in the agent contract. +After the contract is deployed, a set of `measurements` is set to ensure that only agents running the correct code (i.e. it has the same measurements) can be registered in the agent contract. -Developers or protocols may need to modify the code running inside agents over time. Because of this, when the contract is initialized an `owner` account ID is set. Only the owner can approve a new `code hash`. +Developers or protocols may need to modify the code running inside agents over time. Because of this, when the contract is initialized, an `owner` account ID is set. Only the owner can approve a new set of `measurements`. -The `shade-agent-cli` handles the deployment of the agent contract and automatically approves the code hash of your agent. +The `shade-agent-cli` handles the deployment of the agent contract and automatically approves the measurements of your agent. :::tip -Upgradeability can be designed for the specific use case. Common upgrade methods include approving a new code hash through DAO voting or implementing a grace period or cool down, allowing users to withdraw funds if they're uncomfortable with the incoming code hash for the new agent. +Upgradeability can be designed for the specific use case. Common upgrade methods include approving a new set of measurements through DAO voting or implementing a grace period or cool down, allowing users to withdraw funds if they're uncomfortable with the incoming measurements for the new agent. ::: +#### Approve PPIDs + +Similar to how measurements are approved, the owner also approves a set of `PPIDs` to ensure that only agents running on specific machines can register. + #### Register Agent -The `register_agent` function verifies that the agent is running in a TEE and executing the expected code (as defined by the approved code hash). Upon successful verification, the agent's account ID becomes registered and gains access to transaction signing (request_signature). +The `register_agent` function verifies that the agent is running in a TEE, is executing the expected code (as defined by the approved measurements), and is running on a certain machine (as defined by the approved PPIDs). Upon successful verification, the agent's account ID becomes registered and gains access to agent-gated functions. -The `shade-agent-api` automatically registers the agent when booting up in the TEE. +The `shade-agent-api` makes it easy to register; just use the `register` method. #### Request Signature The `request_signature` function serves as the gateway to access the Shade Agent's multichain accounts and sign transactions. It employs `method access control` so that only registered agents can use this function. :::tip -Developers should not sign transactions from the agents themselves (except for functions on the agent contract) as these accounts will be lost if the agent goes down. The magic of Shade Agents is that the multichain accounts are tied to the agent contract, which are persistent and accessible by any instance of a valid agent. +Developers should not sign transactions from the agents themselves (except for functions on the agent contract), as these accounts will be lost if the agent goes down. The magic of Shade Agents is that the multichain accounts are tied to the agent contract, which are persistent and accessible by any instance of a valid agent. ::: The request signature function accepts three arguments: @@ -99,7 +103,7 @@ The request signature function accepts three arguments: The `shade-agent-api` exposes the `requestSignature` function to sign transactions on behalf of the Shade Agent within your agent. :::tip -Within agent gated functions, you can implement an additional layer of security to strictly limit the Shade Agent's actions. For example, it could be restricted to only create transactions for Solana, perform swaps but not transfers, or transfer a maximum of 1 ETH per day. +`request_signature` is only an example of an agent-gated function. You can implement any function you want on the agent contract. It's recommended to implement [on-chain guardrails](../concepts/terminology.md#on-chain-guardrails) to prevent unauthorized actions even in the case of a compromised TEE. ::: --- @@ -108,9 +112,7 @@ Within agent gated functions, you can implement an additional layer of security The agent is just a backend service that runs inside a TEE instead of a centralized server. You can run the agent on an internal cron job, respond to actions, or it can expose API routes that can be called. -Agents can be written in virtually any programming language and use any framework, as long as you can build a `Docker image` for your program. - -If you require a custom agent contract, which not all use cases do, then these are written in Rust. +Agents are written in TypeScript/JavaScript using the `shade-agent-api` and agent contracts are written in Rust. --- diff --git a/website/static/assets/docs/ai/shade-agent-stack-diagram.png b/website/static/assets/docs/ai/shade-agent-stack-diagram.png index 8a6dcbebea3fa57b302c5ac6bbda8bb9ef245e9e..2f564e21b4f2a1435cebe3a63a9aba624d0423f4 100644 GIT binary patch literal 124016 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

D=QjnaK&C0sXNZBBvbMMgnh!PkP) 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 C(ktZv literal 139864 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 Date: Sun, 22 Feb 2026 17:25:06 -0800 Subject: [PATCH 07/12] spell check stuff --- .../concepts/framework-overview.md | 113 +++--------------- docs/ai/shade-agents/concepts/security.md | 94 ++++++++------- docs/ai/shade-agents/concepts/terminology.md | 102 +++++++--------- docs/ai/shade-agents/concepts/using-ai.md | 22 ++++ .../concepts/what-can-you-build.md | 4 +- .../getting-started/introduction.md | 50 ++++---- .../getting-started/quickstart/components.md | 108 ++++++++++++----- .../getting-started/quickstart/deploying.md | 109 +++++++++-------- .../shade-agents/reference/agent-contract.md | 63 +++++----- docs/ai/shade-agents/reference/api.md | 52 ++++---- docs/ai/shade-agents/reference/cli.md | 30 ++--- .../tutorials/ai-dao/dao-agent-contract.md | 2 +- .../tutorials/ai-dao/deploying.md | 6 +- .../shade-agents/tutorials/ai-dao/overview.md | 15 ++- .../tutorials/tutorials-overview.md | 5 - website/sidebars.js | 1 + website/src/components/sigsSupport.js | 2 +- 17 files changed, 372 insertions(+), 406 deletions(-) create mode 100644 docs/ai/shade-agents/concepts/using-ai.md diff --git a/docs/ai/shade-agents/concepts/framework-overview.md b/docs/ai/shade-agents/concepts/framework-overview.md index f2d54f4c1c3..cf3426a0d75 100644 --- a/docs/ai/shade-agents/concepts/framework-overview.md +++ b/docs/ai/shade-agents/concepts/framework-overview.md @@ -7,126 +7,43 @@ description: "Learn about the core components of the Shade Agent Framework with import { SigsSupport } from '@site/src/components/sigsSupport'; -The Shade Agent Framework provides a suite of tools designed to simplify the development and deployment of Shade Agents. The framework abstracts away the complexities of the underlying infrastructure, allowing developers to focus on building their agent logic. In this section, you'll explore the tooling provided by the framework and examine the key components you need when building an agent. +The **Shade Agent Framework** is a platform for creating Web3 agents and off-chain services that are **verifiable**, **trust-minimized**, and **decentralized**. It leverages **on-chain signing** to allow agents to hold assets and sign transactions on most blockchains and implement strict **guardrails** to prevent unauthorized actions. ---- - -## Templates, Languages, and Architecture - -### Templates - -When starting to build with the Shade Agent Framework, it's recommended to start by forking the [Quickstart Shade Agent Template](https://github.com/NearDeFi/shade-agent-template). This template contains all the necessary files to build a Shade Agent and provides the fastest starting path. - -Additional templates can be found in our [Tutorials and Templates](../tutorials/tutorials-overview.md) section. +It includes the **Shade Agent API**, the **Shade Agent CLI**, and an **agent contract reference implementation**. The framework aims to abstract most of the underlying TEE and blockchain interactions so you can focus on building your application. -### Supported Languages - -**TypeScript/JavaScript (Recommended)** -Agents are primarily written in TypeScript/JavaScript using `shade-agent-js`, which integrates seamlessly with [chainsig.js](../../../chain-abstraction/chain-signatures/implementation.md) for building multichain transactions and deriving multichain accounts. - -**Python** -The framework also supports `shade-agent-py`, which allows you to develop agents in Python. Here is an [example](https://github.com/NearDeFi/shade-python-example/tree/main). However, note that tooling for building multichain transactions and deriving multichain accounts is not currently available in Python, so additional development work will be required for multichain use cases. +--- -**Other Languages** -Agents can be written in any language, provided you can create a Docker image for the agent. To build a Shade Agent in other languages, you can use the API directly. Learn more about this approach on the [API page](../reference/api.md). +## Architecture Overview -### Architecture Overview +A **Shade Agent** has two main parts: the **agent** (off-chain) and the **agent contract** (on-chain). The agent is a backend service that runs in a TEE (or locally in dev) and holds your business logic; it uses the Shade Agent API to register and interact with the agent contract. The agent contract is a NEAR smart contract that decides who can act as an agent (via attestations, approved measurements, and PPIDs), enforces guardrails, and gives valid agents access to on-chain signing via chain signatures (MPC signing). One agent contract can have many registered agents - for example, several instances running the same code for redundancy, or different agents for different tasks. -A Shade Agent is essentially a `backend service` that uses the Shade Agent API and runs inside a Trusted Execution Environment (TEE) instead of on a classic server. You can develop using any backend framework you prefer, expose API routes, run cron jobs, or index events and respond to them with actions. +By default, agents are deployed to Phala Cloud, but you can deploy them to other TEE providers that support Dstack. --- ## Shade Agent API -The Shade Agent API abstracts away the complexity of TEE operations and agent contract interactions. For detailed information on how the API works and how to use it across different languages, please refer to the [API page](../reference/api.md). +The Shade Agent API is a **TypeScript/JavaScript** library that connects your agent to the Shade Agent Framework. It abstracts TEE complexity and simplifies calls to the agent contract. You can learn more about the Shade Agent API on the [API page](../reference/api.md). --- ## Shade Agent CLI -The Shade Agent CLI simplifies deploying a Shade Agent. To learn more about how the CLI works and how to use it, please refer to the [CLI page](../reference/cli.md). - ---- - -## Environment Variables - -Environment variables are a crucial component of the Shade Agent Framework. They configure your Shade Agent and are passed encrypted into your agent when it goes live. To learn more about configuring environment variables in your project, please refer to the Environment Variables page. +The Shade Agent CLI makes it easy to deploy a Shade Agent. Including building and deploying your agent contract, building and publishing your agent's Docker image, and deploying the agent to Phala Cloud. You can learn more about the Shade Agent CLI on the [CLI page](../reference/cli.md). --- -## Agent Contract - -By default, the Shade Agent CLI will deploy a generic agent contract that implements the three core functions, `approve_codehash`, `register_agent`, and `request_signature`, discussed in the introduction. This generic agent contract works for many use cases since you can register any arbitrary agent and have it request signatures for any chain - it's very flexible. +## Agent Contract Reference Implementation -There are also cases when you should develop your own `custom agent contract`. These include, but are not limited to: -1) You want to implement strict `guard rails` that prevent malicious actions, even if the TEE is somehow compromised - Review our [security considerations](../concepts/security.md#restricting-actions) for more details -2) You want to implement a custom agent registration or code hash upgradability mechanism -3) You want to build an agent that just interacts with the NEAR blockchain - -Further documentation can be found in the custom contract section. +A walkthrough of the agent contract reference implementation is available on the [Agent Contract Reference Implementation page](../reference/agent-contract.md). It contains the fundamental agent contract logic which you can use as a starting point for your own agent contract. --- -## Phala Cloud - -Phala Cloud is a cloud solution that simplifies hosting applications and agents inside Trusted Execution Environments. The Shade Agent Framework uses Phala Cloud for agent deployment. You can deploy any standard Docker application to Phala. To learn more about Phala, visit their [documentation](https://docs.phala.network/phala-cloud/what-is/what-is-phala-cloud). - -Once your agent is deployed, you can manage the deployment from the [dashboard](https://cloud.phala.network/dashboard). - -To deploy an agent to production, you'll need a Phala Cloud account. You can create one [here](https://cloud.phala.network/register). - -After deploying to Phala Cloud, monitor your deployments and delete unused ones to avoid unnecessary costs. - ---- - -## Docker - -Docker is a platform that allows you to package an application into a self-contained environment. By creating a Docker image, you can run your agent in the TEE. An agent typically consists of two Docker images (the application and the Shade Agent API), but it can include more. When building Shade Agents, it's helpful to understand how Docker works. If you're interested in learning more about Docker, please visit the [documentation](https://docs.docker.com/get-started/docker-overview/). - -You'll need to set up Docker on your machine if you do not have it already, and create an account: -- Install Docker for [Mac](https://docs.docker.com/desktop/setup/install/mac-install/) or [Linux](https://docs.docker.com/desktop/setup/install/linux/) and create an account. -- Log in to Docker, using `docker login` for Mac or `sudo docker login` for Linux. - -There are two Docker-related files included in our project: the `Dockerfile` and the `Docker Compose` file. - -### Dockerfile - -The Dockerfile tells Docker how to build and run your image. The Shade Agent CLI automatically builds your Docker image using the Dockerfile and pushes it to Docker Hub, making it accessible over the internet. - -A standard Dockerfile will: -1. Start with a `base image`, which serves as the starting point for your application (e.g., Ubuntu, Alpine, Node.js, Python pre-installed) -2. Set the working directory -3. Install system dependencies -4. Add relevant files from the project to the image (in our examples, everything within the `source folder` is included, along with the `manifest file` that lists your dependencies like the package.json or pyproject.toml) -5. Install project dependencies -6. Build the project -7. Set the environment (production, development) -8. Tell Docker how to start the application - -In most cases, you can use the Dockerfile already supplied in the template without modification. - -Here are example Dockerfiles for a [Typescript](https://github.com/NearDeFi/shade-agent-template/blob/main/Dockerfile) and [Python](https://github.com/NearDeFi/shade-python-example/blob/main/Dockerfile) agent. - -You can learn more about the Dockerfile [here](https://docs.docker.com/reference/dockerfile/) - -### Docker Compose - -The Docker Compose file (docker-compose.yaml) defines which Docker images will be included within your agent. This file is what is actually uploaded to Phala Cloud to run your agent, which pulls the specified images on boot. The compose file also specifies which environment variables are passed to the images, whether images are exposed on ports, and other configuration details. - -The images used are automatically configured when you run the Shade Agent CLI. In most cases, you can use the Docker Compose file already supplied [in the template](https://github.com/NearDeFi/shade-agent-template/blob/main/docker-compose.yaml). However, if you want to include additional Docker images in your agent or use additional environment variables for your application, you'll need to edit the Docker Compose file. - -You can learn more about the Docker Compose file [here](https://docs.docker.com/reference/compose-file/) - ---- - -## Next Steps - Now that you have an overview of the framework, here are some great sections to explore next: -1. Framework components: [API](../reference/api.md), [CLI](../reference/cli.md), and Environment Variables -2. Custom Contracts - build specialized agent contracts -3. Plugins - extend your agent's capabilities -4. [Tutorials and Templates](../tutorials/tutorials-overview.md) - get up and running with different Shade Agent architectures, and use cases as quickly as possible and learn how to build apps in full -4. [Security Considerations](../concepts/security.md) - check your agent abides by best practices - +1. Framework components: [API](../reference/api.md), [CLI](../reference/cli.md), and [Agent Contract Reference Implementation](../reference/agent-contract.md). +2. [Tutorials and Templates](../tutorials/tutorials-overview.md) - get up and running with different Shade Agent architectures and use cases as quickly as possible, and learn how to build apps in full. +3. [What can you build?](../concepts/what-can-you-build.md) - learn about the different types of applications you can build with Shade Agents. +4. [Terminology](../concepts/terminology.md) - learn the key terms and concepts used in the Shade Agent Framework. +5. [Security Considerations](../concepts/security.md) - check your agent abides by best practices. \ No newline at end of file diff --git a/docs/ai/shade-agents/concepts/security.md b/docs/ai/shade-agents/concepts/security.md index a0a647e2dc3..12056a5d642 100644 --- a/docs/ai/shade-agents/concepts/security.md +++ b/docs/ai/shade-agents/concepts/security.md @@ -2,105 +2,111 @@ id: security title: Security Considerations sidebar_label: Security Considerations -description: "Learn key security practices when deploying Shade Agents, including duplicate actions, transaction restrictions, and RPC trust." +description: "Learn key security practices when deploying Shade Agents, including preventing duplicate actions, handling failed or unsent transactions, restricting API routes, removing agent contract keys, removing local deployment, approved measurements limits, public logs, storing agent keys, public PPIDs, fixed Docker images, trusting RPCs, and verifying the state." --- -:::warning -The Shade Agent Framework is experimental and contains known critical vulnerabilities. +import { SigsSupport } from '@site/src/components/sigsSupport'; -It must not be used in production or on mainnet and is intended solely for testing and non-critical use on testnet. +:::warning +The Shade Agent Framework has not yet undergone a formal audit. No representations or warranties are made regarding security, correctness, or fitness for any purpose. Use of this software is entirely at your own risk. - -A production-ready version of the framework is currently in development. ::: -import { SigsSupport } from '@site/src/components/sigsSupport'; - -Please review this list of security considerations before deploying a Shade Agent to Mainnet. - --- ## Restricting Actions -While TEEs are considered trusted and tamper-resistant, implementing tight restrictions or `guardrails` on agent actions within the agent contract is recommended so that even if the private key to a agent was extracted funds can't be withdrew. +While TEEs are considered trusted and tamper-resistant, implementing tight restrictions or **guardrails** on agent actions within the agent contract is recommended so that even in the event a TEE is compromised and the private key to an agent is extracted, funds can't be withdrawn. You can read more about guardrails [here](terminology.md#on-chain-guardrails). -Examples of restrictions could be: -- The agent contract can only build transactions for a list of functions and smart contract addresses. -- The agent contract can only build transactions for specific chains. -- The agent contract can only build transactions that swap or send up to 0.1 ETH per 24 hours. +--- + +## Preventing Duplicate Actions + +To ensure liveness, a Shade Agent should consist of multiple identical agents hosted by different providers/on different hardware. When multiple agents are running, all agents will respond to triggers (user inputs, cron jobs, API calls, etc.). You must ensure that the Shade Agent collectively performs the desired action only **once** in response to each update. -We recommend using the [omni-transactions-rs](https://github.com/near/omni-transaction-rs) library to build transactions within your agent contract rather than in the agent. +Consider a mindshare trading agent as an example. If Solana's mindshare increases relative to NEAR, the agent would swap SOL for NEAR. With two agents running, you must ensure this swap doesn't occur twice. -Another solution is for the Shade Agent's multichain accounts to not hold funds themselves, but the accounts to be a restricted admin on a contract on the target chain. +This logic is typically best implemented within the agent contract by only allowing one agent to perform the action at a time. --- -## Secure Data Centers +## Handling Failed or Unsent Transactions -With recent exploits of TEEs, such as TEE.fail, it’s important for TEEs to have physical security by running them in secure data centers. +A successful MPC signature on a transaction payload doesn't guarantee the transaction's success or transmission. Transactions may fail for various reasons, such as network congestion, incorrect nonce, or insufficient gas. + +It's suggested you build your agent in such a way that if the transaction fails, then a new signature can be requested without allowing for more signing for the same action when the transaction is successful. -In addition to verifying agent attestations in the smart contract, it’s recommended to only allow them to register as valid agents (via whitelisting account IDs) after verifying off-chain that they are running within secure data centers (like ones provided by Phala Cloud). Proof of Cloud https://proofofcloud.org/ is an initiative to verify TEEs are running in secure facilities. +For some use cases, it may be beneficial to emit signed transactions from your agent contract, allowing anyone or an indexer to relay them if your agent fails to retrieve the result. Signed transactions can be built using [omni-transactions-rs](https://github.com/near/omni-transaction-rs). Exercise caution with unsent signatures. --- -## Duplicate Actions +## Restricting API Routes -To ensure liveness, the Shade Agent should consist of multiple identical agents hosted by different providers/on different hardware. When multiple agents are running, all agents will respond to updates (user inputs, agent pings, API updates, etc.) or will create the same action whilst running on a cron. You must ensure that the Shade Agent collectively performs the desired action only `once` in response to each update. +In the quickstart, the agent can take an API request from anyone, allowing someone to drain the funds from the agent's account and the Ethereum Sepolia account through gas expenditure. If using API routes, you need to design your agent to only perform the action when the desired condition is met or implement authentication inside the route, for example, a user has signed an action with their wallet or they are logged in from their Google account. -Consider a Kaito Mindshare Trading Agent as an example. If Solana's mindshare increases relative to NEAR, the agent would swap SOL for NEAR. With two agents running, you must ensure this swap doesn't occur twice. +--- + +## Removing Agent Contract Keys + +Before deploying your agent contract to production, you should ensure that all **access keys** to the agent contract account have been removed. Otherwise, this would allow the access key owner to withdraw the funds held by the Shade Agent. This can be done using the CLI. -This logic is typically best implemented within the agent contract or a target smart contract being interacted with. +In the agent contract reference implementation, the contract code, approved measurements, and PPID can be updated by the owner. It's recommended that the owner be a **multisig**. --- -## Failed or Unsent Transactions +## Removing Local Deployment -A successful MPC signature on a transaction payload doesn't guarantee the transaction's success or transmission. Transactions may fail for various reasons, such as network congestion, incorrect nonce, or insufficient gas. +When deploying to production, it's recommended to remove the **local deployment flow** from the agent contract entirely. Strip out the code that supports local mode (whitelist checks, default measurements, and PPID for local, and any `requires_tee: false` branches) so the contract only accepts TEE attestations. That way, there is no way to misconfigure or re-enable local mode, and no code path that trusts a whitelist instead of attestation. -We suggest you build your agent in such a way that if the transaction fails, then a new signature can be requested without allowing for signing when the transaction is successful. +--- -For some use cases, it may be beneficial to emit signed transactions from your agent contract, allowing anyone or an indexer to relay them if your agent fails to retrieve the result. Signed transactions can be built using [omni-transactions-rs](https://github.com/near/omni-transaction-rs). Exercise caution with unsent signatures. +## Approved Measurements Limits + +The attestation verification process iterates over all approved measurements and verifies that the TEE's measurements match the approved measurements. If the approved measurements list grows too large, registration could fail due to the function call running into the **gas limit**. It's recommended to limit the number of approved measurements to a reasonable number. --- -## Parallel Transactions +## Public Logs + +By default, the Shade Agent CLI deploys the agent with **public logs** enabled. You should not emit any sensitive information in the logs when this is enabled. -Building on the above, the MPC signing a transaction payload doesn't change any nonce or state on the destination chain. So if you'd like to create an agent that can issue several parallel transactions, you will have to have an intimate knowledge of the destination chain and increment nonces for the derived accounts that you're generation signatures for. +--- -This can cause a lot of issues in the EVM world, for example: Transactions can get stuck in the mempool if the nonce used is not in sequential order. A transaction with a higher nonce will remain pending if a previous transaction (with a lower nonce) hasn't been processed. +## Storing Agent Keys -If your agent frequently tries to sign multiple transactions in parallel with the MPC, then you must keep track of which transactions are successful and handle failures appropriately so that all transactions eventually are included in blocks of the destination chain. +The agent's **ephemeral keys should not be stored** anywhere, including on the host machine. This could lead to code that is not approved in the contract accessing keys that are approved in the contract. --- -## Restricting Agent API Routes +## Public PPIDs -In the quickstart, our agent can take an API request from anyone. In a lot of cases, a Shade Agent will run on a loop responding to actions or data every set time period. If using API routes, you need to design your agent to only perform the action when the desired condition is met or do some sort of verification or authentication inside the route, for example, a user has signed an action with their wallet, or they are logged in from their Google account. +All PPIDs that are approved in the agent contract are made **public**. If you are using your own hardware, consider whether you are comfortable with its PPID being public since it could be used to track your hardware. --- -## Removing Agent Contract Keys +## Fixed Docker Images -Before deploying your agent contract to production, you should ensure that all access keys to the agent contract account have been removed. Otherwise, this would allow the access key owner to withdraw the funds held by the Shade Agent. It is best practice to implement an [upgrade mechanism](../../../tutorials/examples/update.md) that is controlled by a multisig or DAO. +Never reference Docker images by `latest` (e.g. pivortex/my-first-agent:latest) in your **Docker Compose** file; this can lead to different images being loaded in the TEE for the same measurements. Always reference versions of the image you want to use via **hash** (e.g. pivortex/my-first-agent@sha256:bf3faac9793f0fb46e89a4a4a299fad69a4bfd1e26a48846b9adf43b63cb263b). --- ## Trusting RPCs -Inside an agent, it is common to want to query the state of the blockchain and perform actions based on the state. Since RPCs can lie about the state of the blockchain and do not have crypto-economic security, we suggest you design your agent to defend against this. Below are some solutions, which solution you use will differ depending on your use case and the design of your agent: +Inside an agent, it's common to want to query the state of the blockchain and perform actions based on the state. Since **RPCs can lie** about the state of the blockchain and do not have crypto-economic security, it's suggested you design your agent to defend against this. Below are some solutions, which solution you use will differ depending on your use case and the design of your agent: -#### Verifying the State +### Verifying the State -In some cases, you will be able to submit the state back to the smart contract from which the state was queried and verify that it matches the actual state. For example, take a DAO on Ethereum that uses AI to vote on proposals. When a proposal goes live, the agent indexes the proposal, makes a decision on the proposal using an LLM, and then submits the yes/no decision back to the DAO. The agent should also submit a hash of the proposal back to the DAO, so the DAO can verify that the decision was made based on the true state of the blockchain. +In some cases, you will be able to submit the state back to the smart contract from which the state was queried and verify that it matches the actual state. For example, the verifiable DAO example submits a hash of the proposal back to the DAO, so the DAO can verify that the decision was made based on the true state of the blockchain. -#### Trustless Providers +### Trustless Providers -You can use RPC providers that leverage cryptographic proofs or run in TEEs themselves to know that the result is the true state of the blockchain. +You can use RPC providers that leverage cryptographic proofs or run in TEEs themselves to know that the result mirrors the true state of the blockchain. -#### Multiple Reputable Providers +### Multiple Reputable Providers -You can use multiple reputable RPC providers (like Infura and Alchemy) and check the result across each provider to make sure they match. - +You can use multiple reputable RPC providers and check the result across each provider to make sure they match. + + diff --git a/docs/ai/shade-agents/concepts/terminology.md b/docs/ai/shade-agents/concepts/terminology.md index 0c02ed81ecf..bc494474b1f 100644 --- a/docs/ai/shade-agents/concepts/terminology.md +++ b/docs/ai/shade-agents/concepts/terminology.md @@ -11,100 +11,80 @@ Below are the main terms and concepts used in the Shade Agent Framework. ## Shade Agent Framework -The Shade Agent Framework is a suite of tools for creating Web3 agents and off-chain services that are trust-minimized, decentralized, and verifiable. It leverages on-chain signing to allow agents to to hold assets and sign transactions on most blockchains and implement strict guardrails to prevent unauthorized actions. +The **Shade Agent Framework** is a platform for creating Web3 agents and off-chain services that are **verifiable**, **trust-minimized**, and **decentralized**. It leverages **on-chain signing** to allow agents to hold assets and sign transactions on most blockchains and implement strict **guardrails** to prevent unauthorized actions. -It includes the Shade Agent API, the Shade Agent CLI, and an agent contract template. The framework aims to abstract most of the underlying TEE and blockchain interactions so you can focus on building your application. +It includes the **Shade Agent API**, the **Shade Agent CLI**, and an **agent contract reference implementation**. The framework aims to abstract most of the underlying TEE and blockchain interactions so you can focus on building your application. ---- - -## Shade Agent - -A Shade Agent is an application built using the Shade Agent Framework. See the [what can you build section](../getting-started/introduction.md#what-can-you-build) for some examples. - ---- - -## Agent +### Shade Agent -In the Shade Agent Framework, an agent is a single instance of the off-chain code running inside a TEE (or locally in development) that uses the Shade Agent API. One agent contract can have many registered agents: they may run the same code for redundancy or different code for different tasks. +A **Shade Agent** is an application built using the Shade Agent Framework. See the [what can you build section](../getting-started/introduction.md#what-can-you-build) for some examples. ---- - -## Agent's account +### Agent -The agent’s account is the NEAR account ID that represents that agent on-chain. It is an implicit account (64-character hex) derived from the agent's ephemeral private key, meaning the private key and account ID are unique to the agent, and change each time the agent reboots. In local mode you can set the agents account ID to be deterministic to avoid re-whitelisting or re-funding the agent on each run. +In the Shade Agent Framework, an agent is a single instance of the off-chain code running inside a **TEE** (or locally in development) that uses the Shade Agent API. One agent contract can have many registered agents: they may run the same code for redundancy or different code for different tasks. ---- +### Agent's Account -## Agent contract +The agent’s account is the NEAR account ID that represents that agent on-chain. It is an **implicit account** (64-character hex) derived from the agent's **ephemeral private key**, meaning the private key and account ID are unique to the agent, and change each time the agent reboots. In local mode, you can set the agent's account ID to be **deterministic** to avoid re-whitelisting or re-funding the agent on each run. -The agent contract is the on-chain NEAR smart contract that authorizes agents, enforces guardrails and gives agents access to on-chain signing. Agents must provide a valid attestation, have valid measurements, a valid PPID and not be expired to have access to on-chain signing. +### Agent Contract ---- +The agent contract is the on-chain **NEAR smart contract** that authorizes agents via attestations and approved measurements and PPIDs, enforces guardrails, and gives valid agents access to on-chain signing. -## On-chain guardrails -On-chain guardrails are restrictions that are enforced on the agent contract to prevent unauthorized actions even if the TEE is compromised. Examples include limiting transactions to specific functions, smart contracts, blockchains or amounts. Guardrails are usually implemented using the [omni-transaction-rs](https://github.com/Omni-rs/omni-transaction-rs) library. +### On-Chain Guardrails ---- +On-chain guardrails are restrictions that are enforced on the agent contract to **prevent unauthorized actions** even if the TEE is compromised. Examples include limiting transactions to specific functions, smart contracts, blockchains, or amounts. Guardrails are usually implemented using the [omni-transaction-rs](https://github.com/Omni-rs/omni-transaction-rs) library. -## On-chain signing +### On-Chain Signing -The agent contract can sign transactions for most chains via NEAR's [chain signatures](../../../chain-abstraction/chain-signatures.md) service, it's accessed by making cross contract calls to the MPC contract. All assets and state of the Shade Agent should be tied to the agent contract not the agent's account since agent's keys are ephemeral. +The agent contract can sign transactions for **most chains** via NEAR's [Chain Signatures](../../../chain-abstraction/chain-signatures.md) service, which is accessed by making cross-contract calls to the **MPC contract**. All assets and state of the Shade Agent should be tied to the agent contract, not the agent's account, since agent keys are ephemeral. --- -## TEE +## Environment -A trusted execution environment is a secure part of a CPU that runs code in an isolated and protected way. Execution and state stay private, including from the host. TEEs produce cryptographic attestations that prove it's running certain code inside a genuine TEE. +### TEE ---- +A **Trusted Execution Environment** (TEE) is a secure part of a CPU that runs code in an isolated and protected way. Execution and state stay private, including from the host. TEEs produce cryptographic attestations that prove it's running certain code inside a genuine TEE. -## Local +### Local Local mode means the agent runs on your machine (or any non-TEE environment) instead of inside a TEE. There is no real attestation, and the contract uses a whitelist of allowed account IDs instead. Use local mode for development and testing only, not for production. --- -## Registering an agent +## Registration -An agent registers with an agent contract by calling the `register_agent` method, which verifies it has a valid attestation. On successful registration the agent will be stored in the contract's state with its measurements, PPID, and validity period. +### Registering an Agent ---- - -## Whitelisted accounts +An agent **registers** with an agent contract by calling the `register_agent` method, which verifies that it has a valid attestation. On successful registration, the agent will be stored in the contract's state with its **measurements**, **PPID**, and **validity period**. -The whitelist is a set of NEAR account IDs that are allowed to register when the agent contract is in local mode. Because the contract cannot verify code or hardware in local mode, it instead restricts access to specific account IDs. +### Whitelisted Accounts ---- +The whitelist is a set of **NEAR account IDs** that are allowed to register when the agent contract is in **local mode**. Because the contract cannot verify code or hardware in local mode, it instead restricts access to specific account IDs. -## Valid agent +### Valid Agent A valid agent is one that is registered with the agent contract and still has measurements and a PPID that are approved, and its registration has not expired. Valid agents can call agent-gated methods. +### Attestation ---- - -## Attestation - -An attestation is a cryptographic proof produced by a TEE that the application is running inside a genuine TEE. The agent submits its attestation when registering with the agent contract, and the contract verifies that it's a genuine attestation, and checks that the attestation contains a set of approved measurements and an approved PPID. +An attestation is a cryptographic proof produced by a TEE that the application is running inside a genuine TEE. The agent submits its attestation when registering with the agent contract, and the contract verifies that it's a genuine attestation and checks that the attestation contains a set of approved measurements and an approved PPID. ---- - -## Approved measurements +### Measurements The measurements are hashes that uniquely identify the code running in the TEE, and the platform it's running on. The agent contract stores a list of approved measurements, which can be updated by the owner of the contract. There are 6 measurements: -- **MRTD**: measures the initial setup of the trusted domain. This is constant. -- **RTMR0**: measures the virtual hardware. This is constant for a given number of vCPUs and memory allocation. -- **RTMR1**: measures the kernel. This is constant. -- **RTMR2**: measures the Dstack image version. This is constant for a given Dstack image version. -- **Key provider digest**: measures the key provider of the TEE. By default, Shade Agents contain Phala's key providers but don't actually use it since it uses a chain signatures for decentralized key management instead. This is constant for Phala's key provider. -- **App compose hash**: measures the application. This is constant for a given Docker Compose file and app layer configurations. - ---- +- **MRTD**: Measures the initial setup of the trusted domain. This is constant. +- **RTMR0**: Measures the virtual hardware. This is constant for a given number of vCPUs and memory allocation. +- **RTMR1**: Measures the kernel. This is constant. +- **RTMR2**: Measures the Dstack image version. This is constant for a given Dstack image version. +- **Key Provider Digest**: Measures the key provider of the TEE. By default, Shade Agents contain Phala's key providers but don't actually use it since it uses a Chain Signatures for decentralized key management instead. This is constant for Phala's key provider. +- **App Compose Hash**: Measures the application. This is constant for a given Docker Compose file and app layer configurations. -## PPID +### PPID -The PPID (Provisioning Platform ID) is a unique identifier of a physical TEE machine. Recent exploits of TEEs have been due to attackers having physical access to the machine, revealing that the physical location of the machine is important in TEE security. By setting approved PPIDs, the agent contract can ensure that only agents running on specific machines can register. You should approve PPIDs for machines known to be located in secure data centers. By default, the CLI approves all PPIDs for Phala Cloud. +The PPID (Provisioning Platform ID) is a unique identifier of a **physical TEE machine**. Recent exploits of TEEs have been due to attackers having physical access to the machine, revealing that the physical location of the machine is important in TEE security. By setting approved PPIDs, the agent contract can ensure that only agents running on specific machines can register. You should approve PPIDs for machines known to be located in secure data centers. By default, the CLI approves all PPIDs for Phala Cloud. Note that on Phala Cloud, two different deployments can have the same PPID if they are running on the same server, since resources are virtualized. @@ -114,9 +94,9 @@ Note that on Phala Cloud, two different deployments can have the same PPID if th Docker is used in the Shade Agent Framework to deploy agents to TEEs. -- The Dockerfile defines how to build a single image for your agent (dependencies, entrypoint, etc.). The CLI uses it when building the image. -- The Docker image is a single packaged application for your agent. -- The Docker Compose file defines the full application stack of the agent that runs in the TEE. It defines the images for the agent, the allowed environment variables, ports, volumes, etc. +- The **Dockerfile** defines how to build a single image for your agent (dependencies, entrypoint, etc.). The CLI uses it when building the image. +- The **Docker image** is a single packaged application for your agent. +- The **Docker Compose file** defines the full application stack of the agent that runs in the TEE. It defines the images for the agent, the allowed environment variables, ports, volumes, etc. --- @@ -124,8 +104,6 @@ Docker is used in the Shade Agent Framework to deploy agents to TEEs. Phala Cloud is a cloud provider for hosting applications inside Trusted Execution Environments. The Shade Agent Framework uses it as its default hosting provider for agents. ---- - -## DStack +### DStack -DStack is a framework for running and proving applications inside of Trusted Execution Environments that Phala Cloud uses. The Shade Agent Framework only supports Dstack environments either on Phala Cloud, your own hardware or other providers. \ No newline at end of file +DStack is a framework for running and proving applications inside of Trusted Execution Environments that Phala Cloud uses. The Shade Agent Framework only supports Dstack environments either on Phala Cloud, your own hardware, or other providers. \ No newline at end of file diff --git a/docs/ai/shade-agents/concepts/using-ai.md b/docs/ai/shade-agents/concepts/using-ai.md new file mode 100644 index 00000000000..7620f15bbda --- /dev/null +++ b/docs/ai/shade-agents/concepts/using-ai.md @@ -0,0 +1,22 @@ +--- +id: ai-inference +title: AI Inference +sidebar_label: AI Inference +description: "Learn how to use AI with Shade Agents." +--- + +Your agent can call AI inference in two main ways; they have different trust assumptions and privacy guarantees. + +--- + +### NEAR AI Cloud + +NEAR AI Cloud provides **verifiable private inference** using TEEs. You get cryptographic proof that inputs stayed private and that the output was produced by the intended model. If you use NEAR AI Cloud, you should verify the TEE attestations in your agent. + +You can learn more about NEAR AI Cloud [here](https://docs.near.ai/cloud/private-inference). + +--- + +### Other Inference Providers + +You can use other inference providers like OpenAI, Anthropic, etc. However, you need to place a certain level of trust in the provider that the inputs remain private and the output was produced by the intended model. diff --git a/docs/ai/shade-agents/concepts/what-can-you-build.md b/docs/ai/shade-agents/concepts/what-can-you-build.md index 0f72cfd1d97..720851bedbc 100644 --- a/docs/ai/shade-agents/concepts/what-can-you-build.md +++ b/docs/ai/shade-agents/concepts/what-can-you-build.md @@ -14,7 +14,7 @@ Shade Agents are: - **Verifiable** - Agent code is known and executes as expected; no one can tamper with the agent. -- **Multichain** - Can hold any crypto asset and sign transactions on any chain. +- **Multichain** - Can hold any crypto asset and sign transactions on most chains. - **AI Powered** - Can verifiably access LLMs. @@ -47,7 +47,7 @@ Since Shade Agents can access off-chain data and APIs, they make great cheap, fl --- -## Smart Contracts using LLMs +## Smart Contracts Using LLMs Shade Agents allow you to access LLMs from a smart contract that lives on any chain. The LLM and agent are both running in a TEE, so one can verify that the response from the agent is actually from an LLM and its response is a function of the provided inputs. diff --git a/docs/ai/shade-agents/getting-started/introduction.md b/docs/ai/shade-agents/getting-started/introduction.md index 0c24038b0fc..4aa42a45824 100644 --- a/docs/ai/shade-agents/getting-started/introduction.md +++ b/docs/ai/shade-agents/getting-started/introduction.md @@ -8,24 +8,20 @@ description: "Learn about Shade Agents - decentralized and trustless AI agents t import { SigsSupport } from '@site/src/components/sigsSupport'; :::warning -The Shade Agent Framework is experimental and contains known critical vulnerabilities. - -It must not be used in production or on mainnet and is intended solely for testing and non-critical use on testnet. +The Shade Agent Framework has not yet undergone a formal audit. No representations or warranties are made regarding security, correctness, or fitness for any purpose. Use of this software is entirely at your own risk. - -A production-ready version of the framework is currently in development. ::: -The Shade Agent Framework is a suite of tools for creating Web3 agents and off-chain services that are trust-minimized, decentralized, and verifiable. It leverages on-chain signing allowing agents to hold assets and sign transactions on most blockchains and implement strict guardrails to prevent unauthorized actions. +The **Shade Agent Framework** is a platform for creating Web3 agents and off-chain services that are **verifiable**, **trust-minimized**, and **decentralized**. It leverages **on-chain signing** to allow agents to hold assets and sign transactions on most blockchains and implement strict **guardrails** to prevent unauthorized actions. Previous Web3 agents fall into one of two categories: -1. They are trustless and verifiable by using a trusted execution environment (TEE), but if the TEE goes down, the private keys and funds of the agent are lost. +1. They are trustless and verifiable by using a **trusted execution environment (TEE)**, but if the TEE goes down, the private keys and funds of the agent are lost. 2. The agent’s accounts are persistent, but the agents are centralized. -Shade Agents provide verifiability and non-custody by operating in TEEs, but also persistent control of accounts by using NEAR's decentralized key management. Any instance of an agent running the same code inside a TEE can access the same accounts, meaning you don't need to worry about private keys being lost or exposed. +Shade Agents provide verifiability and non-custody by operating in **TEEs**, but also persistent control of accounts by using NEAR's **decentralized key management**. Any instance of an agent running the same code inside a TEE can access the same accounts, meaning you don't need to worry about private keys being lost or exposed. -Thanks to combining TEEs with the NEAR tech stack, Shade Agents can autonomously sign transactions across most chains, interact with AI models and external data sources, manage assets, and perform privacy-preserving, verifiable computations, offering the flexibility and performance of Web2 with the verifiability of Web3. +Thanks to combining TEEs with the NEAR tech stack, Shade Agents can sign transactions across most chains, interact with AI models and external data sources, manage assets, and perform privacy-preserving, verifiable computations, offering the flexibility and performance of Web2 with the verifiability of Web3. :::info Shade Agents power [Agentic Protocols](../concepts/what-can-you-build.md#agentic-protocols): a new type of decentralized application designed to be autonomous, proactive, and intelligent. @@ -33,13 +29,13 @@ Shade Agents power [Agentic Protocols](../concepts/what-can-you-build.md#agentic --- -## How do Shade Agents work? +## How Do Shade Agents Work? -Shade Agents consist of two main components: the `agent` and the `agent smart contract`. +Shade Agents consist of two main components: the **agent** and the **agent smart contract**. ![Shade Agent Architecture](/assets/docs/ai/shade-agent-stack-diagram.png) -When an agent is booted up in a TEE, it generates a random ephemeral private key and NEAR account. This private key is exclusively used to call the agent contract, not for storing funds. +When an agent is booted up in a TEE, it generates a random **ephemeral private key** and **NEAR account**. This private key is exclusively used to call the agent contract, not for storing funds.
@@ -49,15 +45,15 @@ A trusted execution environment is a secure part of a CPU that runs code in an i
-The agent calls the `register_agent` function on the `agent smart contract`, providing its `attestation`. The attestation contains: -- A proof that it's running inside a genuine TEE. +The agent calls the `register_agent` function on the **agent smart contract**, providing its **attestation**. The attestation contains: +- A proof that it's running inside a **genuine TEE**. - The [measurements](../concepts/terminology.md#measurements) of the code running in the TEE (which uniquely identifies the code and platform it's running on). If the attestation is valid, the measurements fit the approved measurements in the contract, and it's running on a certain machine (identified by a [PPID](../concepts/terminology.md#ppid)), then the agent's account is registered inside the agent contract. -Once registered, the `agent` can call the agent-gated functions on the agent contract. An example of this is the `request_signature` function, enabling it to sign transactions on behalf of the Shade Agent. `request_signature` leverages [chain signatures](../../../chain-abstraction/chain-signatures.md) for decentralized key management, allowing the Shade Agent to hold assets and sign transactions on nearly any chain. +Once registered, the **agent** can call the agent-gated functions on the agent contract. An example of this is the `request_signature` function, enabling it to sign transactions on behalf of the Shade Agent. `request_signature` leverages [chain signatures](../../../chain-abstraction/chain-signatures.md) for decentralized key management, allowing the Shade Agent to hold assets and sign transactions on nearly any chain. -If `anyone` deploys the same code to a different TEE with the same measurements and PPID, it can also register in the contract, and thus gain access to signing transactions using the Shade Agent's accounts. This means the accounts are persisted across different TEE instances. To facilitate this functionality, agents are designed to be stateless. +If **anyone** deploys the same code to a different TEE with the same measurements and PPID, it can also register in the contract, and thus gain access to signing transactions using the Shade Agent's accounts. This means the accounts are persisted across different TEE instances. To facilitate this functionality, agents are designed to be stateless. --- @@ -67,11 +63,11 @@ The Agent Contract has four main functions: #### Approve Measurements -After the contract is deployed, a set of `measurements` is set to ensure that only agents running the correct code (i.e. it has the same measurements) can be registered in the agent contract. +After the contract is deployed, a set of **measurements** is set to ensure that only agents running the correct code (i.e. it has the same measurements) can be registered in the agent contract. -Developers or protocols may need to modify the code running inside agents over time. Because of this, when the contract is initialized, an `owner` account ID is set. Only the owner can approve a new set of `measurements`. +Developers or protocols may need to modify the code running inside agents over time. Because of this, when the contract is initialized, an **owner** account ID is set. Only the owner can approve a new set of **measurements**. -The `shade-agent-cli` handles the deployment of the agent contract and automatically approves the measurements of your agent. +The **Shade Agent CLI** handles the deployment of the agent contract and automatically approves the measurements of your agent. :::tip Upgradeability can be designed for the specific use case. Common upgrade methods include approving a new set of measurements through DAO voting or implementing a grace period or cool down, allowing users to withdraw funds if they're uncomfortable with the incoming measurements for the new agent. @@ -79,28 +75,28 @@ Upgradeability can be designed for the specific use case. Common upgrade methods #### Approve PPIDs -Similar to how measurements are approved, the owner also approves a set of `PPIDs` to ensure that only agents running on specific machines can register. +Similar to how measurements are approved, the owner also approves a set of **PPIDs** to ensure that only agents running on specific machines can register. #### Register Agent The `register_agent` function verifies that the agent is running in a TEE, is executing the expected code (as defined by the approved measurements), and is running on a certain machine (as defined by the approved PPIDs). Upon successful verification, the agent's account ID becomes registered and gains access to agent-gated functions. -The `shade-agent-api` makes it easy to register; just use the `register` method. +The **Shade Agent API** makes it easy to register; just use the `agent.register()` method. #### Request Signature -The `request_signature` function serves as the gateway to access the Shade Agent's multichain accounts and sign transactions. It employs `method access control` so that only registered agents can use this function. +The `request_signature` function serves as the gateway to access the Shade Agent's multichain accounts and sign transactions. It employs **method access control** so that only registered agents can use this function. :::tip Developers should not sign transactions from the agents themselves (except for functions on the agent contract), as these accounts will be lost if the agent goes down. The magic of Shade Agents is that the multichain accounts are tied to the agent contract, which are persistent and accessible by any instance of a valid agent. ::: -The request signature function accepts three arguments: +The `request_signature` function accepts three arguments: - The transaction `payload` - a hash of the transaction to be signed. -- The `derivation path` - a string that modifies the address on the target chain being used. Shade Agents can access a near-unlimited number of accounts, and the account being used can be changed by modifying the path. The same path will always map to the same account for a given agent contract. -- The `key version` - sets the signature scheme required for the transaction. Shade Agents can sign transactions for any blockchain using the `secp256k1` and `ed25519` signature schemes (EVM, Bitcoin, Solana, Sui, XRP, etc.). +- The derivation `path` - a string that modifies the address on the target chain being used. Shade Agents can access a near-unlimited number of accounts, and the account being used can be changed by modifying the path. The same path will always map to the same account for a given agent contract. +- The `key_type` - sets the signature scheme required for the transaction. Shade Agents can sign transactions for any blockchain using the `secp256k1` and `ed25519` signature schemes (EVM, Bitcoin, Solana, Sui, XRP, etc.). -The `shade-agent-api` exposes the `requestSignature` function to sign transactions on behalf of the Shade Agent within your agent. +The **Shade Agent API** exposes the `agent.call()` method to sign transactions on behalf of the Shade Agent within your agent. :::tip `request_signature` is only an example of an agent-gated function. You can implement any function you want on the agent contract. It's recommended to implement [on-chain guardrails](../concepts/terminology.md#on-chain-guardrails) to prevent unauthorized actions even in the case of a compromised TEE. @@ -112,7 +108,7 @@ The `shade-agent-api` exposes the `requestSignature` function to sign transactio The agent is just a backend service that runs inside a TEE instead of a centralized server. You can run the agent on an internal cron job, respond to actions, or it can expose API routes that can be called. -Agents are written in TypeScript/JavaScript using the `shade-agent-api` and agent contracts are written in Rust. +Agents are written in TypeScript/JavaScript using the **Shade Agent API**, and agent contracts are written in Rust. --- diff --git a/docs/ai/shade-agents/getting-started/quickstart/components.md b/docs/ai/shade-agents/getting-started/quickstart/components.md index c026acc4017..3878c6b95cf 100644 --- a/docs/ai/shade-agents/getting-started/quickstart/components.md +++ b/docs/ai/shade-agents/getting-started/quickstart/components.md @@ -10,74 +10,118 @@ import { SigsSupport } from '@site/src/components/sigsSupport'; In this section, we'll explore the main components of the [quickstart template](https://github.com/NearDeFi/shade-agent-template) to understand how to develop a Shade Agent. We'll also look at how to modify the template to build an agent for your use case. - --- ## Template Structure -The template we're using is a simple Shade Agent built with Hono and written in TypeScript that acts as a verifiable ETH price oracle. It takes prices from two different APIs, takes the average, and then pushes the price to an Ethereum contract. The template also comes with a frontend to make it easier to interact with the Shade Agent. +The template we're using is a simple Shade Agent built with Hono and written in **TypeScript** that acts as a verifiable ETH price oracle. It takes prices from two different APIs, takes the average, and then pushes the price to an Ethereum contract. + +The agent has three main files: +1) [**index.ts**](https://github.com/NearDeFi/shade-agent-template/blob/main/src/index.ts) - This is the entry point that sets up the **Shade Agent Client**, **registers** the agent and defines the routes for the agent. We'll review this file in more detail in the next section. +2) [**transaction**](https://github.com/NearDeFi/shade-agent-template/blob/main/src/routes/transaction.ts) - This is where the core logic of the agent is defined. When this API is called, the agent will build a transaction payload and request a signature from the agent contract. We'll look deeper into this API route later on this page. +3) [**agentInfo**](https://github.com/NearDeFi/shade-agent-template/blob/2.0/src/routes/agentInfo.ts) - This API simply fetches the agent's NEAR account ID and its balance by using the `agent.accountId()` and `agent.balance()` methods from the `shade-agent-js` library. +4) [**ethAccount**](https://github.com/NearDeFi/shade-agent-template/blob/main/src/routes/ethAccount.ts) - This API returns the **Ethereum Sepolia account** that the Shade Agent uses to update the price of Ethereum in the Sepolia contract. This API is used so the user knows which account to fund for gas. + +The repo also contains an **agent contract**. We won't review the agent contract as it's the same as the reference implementation [featured here](../../reference/agent-contract.md), but we encourage you to review the reference implementation after this section. + +--- + +## Registering the Agent + +First, in the [index.ts](https://github.com/NearDeFi/shade-agent-template/blob/2.0/src/index.ts) file, the **Shade Agent Client** is **initialized**. + +The client is initialized with the following arguments: +- `networkId` is set to `testnet` since the agent contract was deployed to testnet. +- `agentContractId` is set to the agent contract ID and is fetched from the environment variables. +- `sponsor` is set to the sponsor account details from the environment variables. It is used later to fund the agent. +- `derivationPath` is set to the sponsor's private key from the environment variables. For local deployment, this derives a deterministic account ID for the agent, making testing easier (for TEE deployment, this does nothing as ignored). The derivation path needs to be random and private; a private key fulfils this criterion well. + + -The project has three different APIs: -1) [**agentAccount**](https://github.com/NearDeFi/shade-agent-template/blob/main/src/routes/agentAccount.ts) - This API simply fetches the agent's NEAR account ID and its balance by using the `agentAccountId` and `agent("getBalance")` functions from the `shade-agent-js` library. -2) [**ethAccount**](https://github.com/NearDeFi/shade-agent-template/blob/main/src/routes/ethAccount.ts) - This API returns the `Ethereum Sepolia account` that the Shade Agent uses to update the price of Ethereum in the Sepolia contract. This API is used so the user knows which account to fund for gas. -3) [**transaction**](https://github.com/NearDeFi/shade-agent-template/blob/main/src/routes/transaction.ts) - This is where the core logic of the agent is defined. When this API is called, the agent will build and sign a transaction. We'll look deeper into this API route in the next part. +Next, the agent is **funded** with 0.3 NEAR via the `sponsor` account using the `agent.fund()` method. This is done to ensure the agent has enough NEAR to pay for gas when sending transactions. + + + +After this, the agent **registers** itself with the agent contract. To make it easier for local deployment, a loop is started that checks if the agent is whitelisted; if not, it will wait for 10 seconds and try again until it's whitelisted, at which point the agent will register. + + + +Since registrations expire (every 7 days by default), an interval is set to **re-register** the agent every 6 days. + + + +The agent is now registered and ready to sign transactions. --- ## Signing Transactions -In the [transaction API Route](https://github.com/NearDeFi/shade-agent-template/blob/main/src/routes/transaction.ts), the `requestSignature` function from the `shade-agent-js` library is used to sign a transaction. +In the [transaction API Route](https://github.com/NearDeFi/shade-agent-template/blob/main/src/routes/transaction.ts), the `agent.call()` method from the `shade-agent-js` library is used to call a function on the agent contract. -In this example, we're signing a transaction to call an Ethereum contract to update the stored price of ETH. First, we retrieve the price of ETH (in this example, the function queries two different APIs and calculates the average). +In this example, the agent is calling the `request_signature` function on the agent contract. This function takes a transaction payload for nearly any blockchain and requests a signature via [Chain Signatures](../../../../chain-abstraction/chain-signatures/implementation.md). Here, we're signing a transaction to call an Ethereum contract to update the stored price of ETH. First, we retrieve the price of ETH (in this example, the function queries two different APIs and calculates the average). - -Next, we build the `transaction payload` to be signed. To do this, we're using the `chainsig.js` library. +Next, we build the **transaction payload** to be signed. To do this, we're using the `chainsig.js` library. Using this library, we: -1. `Derive the Ethereum address` that will be sending the transaction. This function takes the agent contract account ID since this is the predecessor account that is calling the Chain Signatures [MPC contract](https://github.com/Near-One/mpc/tree/main/libs/chain-signatures/contract), and a path. The path can be whatever string you like, different paths will derive different addresses. +1. **Derive the Ethereum address** that will be sending the transaction. This function takes the agent contract account ID since this is the predecessor account that is calling the Chain Signatures [MPC contract](https://github.com/Near-One/mpc/tree/main/libs/chain-signatures/contract), and a path. The path can be whatever string you like; different paths will derive different addresses. 2. Create the `data`. This is what action we're performing, in this case, a function call to update the price in the contract. -3. `Build the transaction and the transaction payload` by inputting the derived address, the target Ethereum smart contract, and the data. +3. **Build the transaction and the transaction payload** by inputting the derived address, the target Ethereum smart contract, and the data. - + -Once we have the payload (also known as the hash), we can call the `requestSignature` function to sign the transaction. We specify the `keyType` as `Ecdsa` as we're signing for a blockchain that uses the `secp256k1` signature scheme. +Once we have the payload (also known as the hash), we can call the `request_signature` function on the agent contract to sign the transaction. We specify the `keyType` as `Ecdsa` as we're signing for a blockchain that uses the **secp256k1** signature scheme. - + -The result is the `signature`. +The result is the **signature**. We then attach the signature to the Ethereum transaction and broadcast it to the target network. - + --- -## Using Different Chains +## Modifying This Template + +### Using Different Chains -We set up a chain adapter for Ethereum Sepolia in the [Ethereum.ts](https://github.com/NearDeFi/shade-agent-template/blob/main/src/utils/ethereum.ts) file using the `chainsig.js` library. This library allows us to easily construct transaction payloads to be signed by the agent. +We set up a **chain adapter** for Ethereum Sepolia in the [Ethereum.ts](https://github.com/NearDeFi/shade-agent-template/blob/main/src/utils/ethereum.ts) file using the `chainsig.js` library. This library allows us to easily construct transaction payloads to be signed by the agent. - -You can set up chain adapters for a variety of chains, including EVM, Bitcoin, NEAR, Solana, SUI, XRP, Cosmos, and more to allow your agent to interact with multiple different chains. You can see a full list of the chains currently supported [here](https://github.com/NearDeFi/chainsig.js/tree/main?tab=readme-ov-file#supported-chains), but feel free to contribute any chain that is not yet supported. +You can set up chain adapters for a variety of chains, including NEAR, EVM, Bitcoin, Solana, SUI, XRP, and Cosmos, to allow your agent to interact with multiple different chains. You can see a full list of the chains currently supported [here](https://github.com/NearDeFi/chainsig.js/tree/main?tab=readme-ov-file#supported-chains), but feel free to contribute any chain that is not yet supported. + +Implementation details differ slightly from chain to chain; as such, we recommend you review our [chain signature docs](../../../../chain-abstraction/chain-signatures/implementation.md). Note that step 3 of requesting a signature is different; we use the `agent.call()` method from `shade-agent-js` instead. + +If you are using a chain that uses the **ed25519** signature scheme (NEAR, Solana, SUI, Aptos, etc.), you should specify the `keyType` as `Eddsa` when calling `request_signature`. -Implementation details differ slightly from chain to chain; as such, we recommend you review our [chain signature docs](../../../../chain-abstraction/chain-signatures/implementation.md). Note that step 3 of requesting a signature is different; we use the `requestSignature` function from `shade-agent-js` instead. +### Implementing Guardrails -If you are using a chain that uses the `ed25519` signature scheme (NEAR, Solana, SUI, Aptos, etc.), you should specify the `keyType` as `Eddsa` when calling `requestSignature`. +As you move into production, it's recommended to implement on-chain guardrails in your agent contract to prevent malicious actions even if the TEE is compromised. You can read more about guardrails [here](../../concepts/terminology.md#on-chain-guardrails). --- ## Next Steps -Now that you've explored the basics of Shade Agents, we recommend diving deeper into the [framework overview](../../concepts/framework-overview.md) to understand the core concepts needed for building production-ready Shade Agents. +Now that you've explored the basics of Shade Agents, we recommend diving deeper into the [framework overview](../../concepts/framework-overview.md) to understand the core components for building production-ready Shade Agents. \ No newline at end of file diff --git a/docs/ai/shade-agents/getting-started/quickstart/deploying.md b/docs/ai/shade-agents/getting-started/quickstart/deploying.md index 64f7b5aee11..3e2d8aac3e5 100644 --- a/docs/ai/shade-agents/getting-started/quickstart/deploying.md +++ b/docs/ai/shade-agents/getting-started/quickstart/deploying.md @@ -5,24 +5,20 @@ sidebar_label: Deploying an Agent description: "Learn how to quickly deploy your first Shade Agent." --- -:::warning -The Shade Agent Framework is experimental and contains known critical vulnerabilities. - -It must not be used in production or on mainnet and is intended solely for testing and non-critical use on testnet. - -No representations or warranties are made regarding security, correctness, or fitness for any purpose. Use of this software is entirely at your own risk. - -A production-ready version of the framework is currently in development. -::: - import { TryDemo } from '@site/src/components/TryDemo'; import { SigsSupport } from '@site/src/components/sigsSupport'; import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; -In this section, we'll walk you through deploying a Shade Agent. The Shade Agent Framework abstracts the complexities of creating a agent by removing TEE specific code and handling the deployment of the agent contract under hood. +:::warning +The Shade Agent Framework has not yet undergone a formal audit. -The [template](https://github.com/NearDeFi/shade-agent-template) we're using is a simple Shade Agent built with Hono and written in TypeScript that acts as a verifiable ETH price oracle. It fetches the price of Eth from two different APIs, takes the average, and then pushes the price to an Ethereum contract. +No representations or warranties are made regarding security, correctness, or fitness for any purpose. Use of this software is entirely at your own risk. +::: + +In this section, we'll walk you through **deploying** a Shade Agent. + +The [template](https://github.com/NearDeFi/shade-agent-template) we're using is a simple Shade Agent built with Hono and written in **TypeScript** that acts as a verifiable ETH price oracle. It fetches the price of Eth from two different APIs, takes the average, and then pushes the price to an Ethereum contract. What is a Phala Cloud -Phala Cloud is a cloud service that supports hosting applications in a TEE. It makes it easy to run an agent in TEE. +Phala Cloud is a cloud service that supports hosting applications in TEEs. It makes it easy to run an agent in TEE. --- -## Set up +## Set Up -- First, `clone` the [template](https://github.com/NearDeFi/shade-agent-template). +- First, **clone** the [template](https://github.com/NearDeFi/shade-agent-template): ```bash git clone https://github.com/NearDeFi/shade-agent-template cd shade-agent-template ``` -- Rename the `.env.development.local.example` file name to `.env.development.local` and configure your environment variables. +- Set up **NEAR** and **Phala** credentials in the CLI: + + ```bash + shade auth set all testnet create-new + ``` + +- Set a unique `agent_contract.contract_id` (e.g. example-contract-123.testnet) and fill in your `build_docker_image.tag` (e.g. pivortex/my-first-agent) in the `deployment.yaml` file. + +- Create a `.env` file and configure your environment variables. + +```env +AGENT_CONTRACT_ID= Set this to the agent contract ID you set in the deployment.yaml file +SPONSOR_ACCOUNT_ID= Set this to the NEAR account ID generated by the CLI +SPONSOR_PRIVATE_KEY= Set this to the private key generated by the CLI +``` - Start up Docker: @@ -111,7 +108,7 @@ Phala Cloud is a cloud service that supports hosting applications in a TEE. It m -- Install dependencies +- Install dependencies: ```bash npm i @@ -121,17 +118,17 @@ Phala Cloud is a cloud service that supports hosting applications in a TEE. It m ## Local Development -- Make sure the `NEXT_PUBLIC_contractId` prefix is set to `ac-proxy.` followed by your NEAR accountId. +- Make sure `environment` is set to `local` in the `deployment.yaml` file. - In one terminal, run the Shade Agent CLI: ```bash - shade-agent-cli + shade deploy ``` - The CLI on Linux may prompt you to enter your `sudo password`. + On Linux, the CLI may prompt you to enter your **sudo password**. -- In another terminal, start your app: +- Then, start your app: ```bash npm run dev @@ -139,47 +136,55 @@ Phala Cloud is a cloud service that supports hosting applications in a TEE. It m Your app will start on http://localhost:3000 +- Lastly, you need to **whitelist** the agent in the agent contract (only needed for local development). In another terminal, run: + + ```bash + shade whitelist + ``` + + Enter the agent account ID displayed when starting the app. + --- ## TEE Deployment -- Change the `NEXT_PUBLIC_contractId` prefix to `ac-sandbox.` followed by your NEAR accountId. +- Change the `environment` to `TEE` in the `deployment.yaml` file. - Run the Shade Agent CLI ```bash - shade-agent-cli + shade deploy ``` - The CLI on Linux may prompt you to enter your `sudo password`. + The CLI on Linux may prompt you to enter your **sudo password**. - The last `URL` the CLI outputs is the URL of your app. If your application is not working, head over to your App on the Phala Dashboard and review the logs. +The CLI will output the URL of your app. - After deploying to Phala Cloud, monitor your deployments and delete unused ones to avoid unnecessary costs. You can manage your deployments from the[dashboard](https://cloud.phala.network/dashboard). +After deploying to Phala Cloud, monitor your deployments and delete unused ones to avoid unnecessary costs. You can manage your deployments from the[dashboard](https://cloud.phala.network/dashboard). --- ## Interacting with the Agent -You can interact with your agent via the APIs directly or via a lightweight frontend contained in this repo. +You can interact with your agent via the APIs directly or via the frontend contained in this repo. ### Direct For Phala deployments, swap localhost:3000 for your deployment URL. -- Get the Agent account ID and its balance: +- Get information about the agent: ``` - http://localhost:3000/api/agent-account + http://localhost:3000/api/agent-info ``` - Get the derived Ethereum Sepolia price pusher account ID and its balance (you will need to fund this account): ``` - http://localhost:3000/api/eth-account + http://localhost:3000/api/eth-info ``` -- Send a transaction through the agent to update the price of Eth: +- Request the agent to update the price of Eth: ``` http://localhost:3000/api/transaction @@ -195,7 +200,9 @@ npm i npm run dev ``` -To use the frontend with your Phala deployment change the `API_URL` to Phala URL in your [config.js](https://github.com/NearDeFi/shade-agent-template/blob/main/frontend/src/config.js) file. +To use the frontend with your Phala deployment, change the `API_URL` to the Phala URL in your [config.js](https://github.com/NearDeFi/shade-agent-template/blob/main/frontend/src/config.js) file. + +In the frontend, you can review the approved **measurements** and **PPID** in the contract and details of the registered agents. --- diff --git a/docs/ai/shade-agents/reference/agent-contract.md b/docs/ai/shade-agents/reference/agent-contract.md index 0b0f2c5f790..08a70575526 100644 --- a/docs/ai/shade-agents/reference/agent-contract.md +++ b/docs/ai/shade-agents/reference/agent-contract.md @@ -9,17 +9,17 @@ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; import { Github } from "@site/src/components/UI/Codetabs"; -The agent contract is the on-chain component of the Shade Agent Framework. It handles agent registration, measurement and PPID approval, and enforces that only valid agents can call specific methods. +The **agent contract** is the on-chain component of the Shade Agent Framework. It handles agent registration, measurement, and PPID approval, and enforces that only valid agents can call specific methods. -**suggested:** On this page you'll walk through the key components of the reference agent contract and how to implement your own agent-gated functions. You may need to change other parts of the contract depending on your use case. The full source lives in the [shade-agent-template](https://github.com/NearDeFi/shade-agent-template/tree/2.0/agent-contract) repo. +On this page, you'll walk through the key components of the reference agent contract and how to implement your own **agent-gated functions**. You may need to change other parts of the contract depending on your use case. The full source lives in the [shade-agent-template](https://github.com/NearDeFi/shade-agent-template/tree/2.0/agent-contract) repo. --- ## Flow High-level flow: -- Owner deploys and initializes the contract. -- Owner approves measurements and PPIDs. +- The owner deploys and initializes the contract. +- The owner approves measurements and PPIDs. - Each agent calls `register_agent` with a valid attestation. - Valid agents can then call agent-gated methods. @@ -27,14 +27,13 @@ High-level flow: ## Initialization - The `new` method initializes the contract and takes four arguments (the CLI can initialize the contract with defaults): -- **requires_tee**: Whether the contract runs in local or TEE mode. This switches the behavior of the contract so you can move easily between local and TEE deployments. -- **attestation_expiration_time_ms**: How long a registration stays valid for after an agent registers. -- **owner_id**: The account ID allowed to call owner-only methods. The owner should usually be a multisig. -- **mpc_contract_id**: The Chain Signatures MPC contract that the agent contract will call for multichain signing. +- **`requires_tee`**: Whether the contract runs in local or TEE mode. This switches the behavior of the contract so you can move easily between local and TEE deployments. +- **`attestation_expiration_time_ms`**: How long a registration stays valid for after an agent registers. +- **`owner_id`**: The account ID allowed to call owner-only methods. The owner should usually be a multisig. +- **`mpc_contract_id`**: The Chain Signatures MPC contract that the agent contract will call for multichain signing. -On initialization, the rest of the contract state is left empty. +On initialization, the rest of the contract state is set to empty. -The attestation’s report data must contain the NEAR account ID of the agent. This binds the attestation to the same TEE where the agent’s key was created to prevent replay of valid attestations. Report data is passed as bytes. +The attestation’s **report data** must contain the NEAR account ID of the agent. This binds the attestation to the same TEE where the agent’s key was created to prevent replay of valid attestations. Report data is passed as **bytes**. -#### Local mode +#### Local Mode In local mode (`requires_tee = false`), the method approves the agent if the caller is whitelisted and the mock measurements and PPID are approved in the contract. No real attestation is verified. @@ -164,7 +163,7 @@ In local mode (`requires_tee = false`), the method approves the agent if the cal --- -## Require valid agent +## Require Valid Agent You can restrict methods so only valid agents can call them using the helper `require_valid_agent`. An agent that registered earlier may no longer be valid. To gate a method: call `require_valid_agent`, and if it returns `Some(promise)`, execute the promise. @@ -240,9 +239,9 @@ The promise calls `fail_on_invalid_agent`, which panics in the next block. Panic --- -## Your logic +## Your Functions -The template includes an example `request_signature` function. It allows a valid agent to request a signature for a transaction payload from the MPC contract, so you can sign transactions for most chains. You can learn more about singing transactions for different chains in the [chain signatures documentation](../../../chain-abstraction/chain-signatures/implementation). +The template includes an example `request_signature` function. It allows a **valid agent** to request a signature for a transaction payload from the MPC contract, so you can sign transactions for most chains. You can learn more about singing transactions for different chains in the [chain signatures documentation](../../../chain-abstraction/chain-signatures/implementation). -You should implement your own agent-gated functions in this `your_functions.rs` file, following the same pattern: call `require_valid_agent`, then run your logic. +You should implement your own **agent-gated functions** in this `your_functions.rs` file, following the same pattern: call `require_valid_agent`, then run your logic. :::tip On chain guardrails -A key part of the Shade Agent Framework is the ability to implement on-chain guardrails. This gives protection against unauthorized actions - even if the TEE is compromised. It's strongly recommended that you build actions within the agent contract rather than in the agent itself, for example, using the [omni-transaction-rs](https://github.com/Omni-rs/omni-transaction-rs) library. +A key part of the Shade Agent Framework is the ability to implement **on-chain guardrails**. This gives protection against unauthorized actions - even if the TEE is compromised. It's strongly recommended that you build actions within the agent contract rather than in the agent itself, for example, using the [omni-transaction-rs](https://github.com/Omni-rs/omni-transaction-rs) library. ::: --- -## Building the contract +## Building the Contract -Usually, you build and deploy with the Shade Agent CLI: `shade deploy`. To build the contract manually, use the following command: +Usually, you build and deploy with the **Shade Agent CLI**: `shade deploy`. To build the contract manually, use the following command: @@ -285,7 +284,7 @@ Usually, you build and deploy with the Shade Agent CLI: `shade deploy`. To build docker run --rm -v "$(pwd)":/workspace pivortex/near-builder@sha256:cdffded38c6cff93a046171269268f99d517237fac800f58e5ad1bcd8d6e2418 cargo near build non-reproducible-wasm --no-abi ``` - If you would like to build the image yourself you can use [this Dockerfile](https://github.com/NearDeFi/shade-agent-framework/blob/main/contract-builder/Dockerfile). + If you would like to build the image yourself, you can use [this Dockerfile](https://github.com/NearDeFi/shade-agent-framework/blob/main/contract-builder/Dockerfile). @@ -297,6 +296,6 @@ The `--no-abi` flag is used to build the contract without an ABI. This is requir --- -## Calling methods +## Calling Methods -The Shade Agent CLI calls the main contract methods when you run `shade deploy`, but it does not cover every method. For methods the CLI doesn’t support, use the [NEAR CLI](../../../tools/cli) or create scripts using the [NEAR API](../../../tools/near-api). \ No newline at end of file +The **Shade Agent CLI** calls the main contract methods when you run `shade deploy`, but it does not cover every method. For methods the CLI doesn’t support, use the [NEAR CLI](../../../tools/cli) or create scripts using the [NEAR API](../../../tools/near-api). \ No newline at end of file diff --git a/docs/ai/shade-agents/reference/api.md b/docs/ai/shade-agents/reference/api.md index 433ce3e164b..72212828bb5 100644 --- a/docs/ai/shade-agents/reference/api.md +++ b/docs/ai/shade-agents/reference/api.md @@ -7,7 +7,7 @@ description: "Use the Shade Agent API (TypeScript/JavaScript) to connect your ag ## API Overview -`shade-agent-js` is a `TypeScript/JavaScript` library that connects your agent to the Shade Agent Framework. It hides TEE complexity and simplifies calls to the agent contract. The same API works locally and inside a TEE; its behavior differs slightly by environment, but the interface stays the same. +**Shade Agent API** is a **TypeScript/JavaScript** library that connects your agent to the Shade Agent Framework. It abstracts TEE complexity and simplifies calls to the agent contract. The same API works locally and inside a TEE; its behavior differs slightly by environment, but the interface stays the same. --- @@ -19,7 +19,7 @@ npm install @neardefi/shade-agent-js --- -## Initializing the client +## Initializing the Client Sets up the client with the desired configuration. @@ -45,16 +45,16 @@ All arguments are optional. Omitting some makes certain methods unavailable. | Argument | Description | |----------|-------------| -| **networkId** | The NEAR network: `mainnet` or `testnet` (defaults to testnet). | -| **agentContractId** | The account ID of your agent contract that your agent will interact with. | -| **sponsor** | The account details of a sponsor account to fund the agent. | -| **rpc** | A [near-api-js provider](https://near.github.io/near-api-js/modules/providers.html) object used by the client (defaults to a basic RPC provider based on the network). | -| **numKeys** | The number of key pairs the agent has (1–100, defaults to 1). More keys increase transaction throughput; the client rotates through them when signing transactions. | -| **derivationPath** | A string used to derive deterministic agent account IDs when running locally. Lets you avoid re-whitelisting and re-funding the agent on each run. Use a unique secret (e.g. a private key). If two agents share the same derivation path, they get the same account ID and could control contracts they are not authorized for. | +| `networkId` | The NEAR network: `mainnet` or `testnet` (defaults to testnet). | +| `agentContractId` | The account ID of your agent contract that your agent will interact with. | +| `sponsor` | The account details of a sponsor account to fund the agent. | +| `rpc` | A [near-api-js provider](https://near.github.io/near-api-js/modules/providers.html) object used by the client (defaults to a basic RPC provider based on the network). | +| `numKeys` | The number of key pairs the agent has (1–100, defaults to 1). More keys increase transaction throughput; the client rotates through them when signing transactions. | +| `derivationPath` | A string used to derive deterministic agent account IDs when running locally. Lets you avoid re-whitelisting and re-funding the agent on each run. Use a unique secret (e.g. a private key). If two agents share the same derivation path, they get the same account ID and could control contracts they are not authorized for. | --- -## Agent account ID +## Agent Account ID Returns the ephemeral NEAR account ID of the agent. @@ -64,9 +64,9 @@ const accountId = agent.accountId(); --- -## Agent balance +## Agent Balance -Returns the NEAR balance of the agent's account in human-readable units (e.g. 1 = one NEAR). If the account does not exist, returns 0. +Returns the NEAR balance of the agent's account in human-readable units (e.g. 1 = one NEAR). If the account does not exist, it returns 0. ```ts const balance = await agent.balance(); @@ -74,7 +74,7 @@ const balance = await agent.balance(); --- -## Fund agent +## Fund Agent Transfers NEAR from the configured sponsor account to the agent's account. @@ -82,11 +82,11 @@ Transfers NEAR from the configured sponsor account to the agent's account. await agent.fund(0.3); // 0.3 NEAR ``` -Requires sponsor in config. +Requires `sponsor` in config. --- -## Check whitelist +## Check Whitelist Checks whether the agent's account is whitelisted for local mode. @@ -98,11 +98,11 @@ const whitelisted = await agent.isWhitelisted(); - TEE: Always returns `null`. - Local: Returns `true` if the agent is whitelisted, `false` otherwise. -Requires agentContractId in config. +Requires `agentContractId` in config. --- -## Register agent +## Register Agent Registers the agent's account in the agent contract. Returns `true` on success, throws on failure. @@ -114,13 +114,13 @@ await agent.register(); - TEE: Registers with a real attestation. - Local: Registers with a mock attestation. -Requires agentContractId in config. +Requires `agentContractId` in config. --- -## Call agent contract +## Call Agent Contract -Calls a change function on the agent contract (uses gas, can change state). Returns the call result or throws. +Calls a **change function** on the agent contract (uses gas, can change state). Returns the call result or throws. ```ts const result = await agent.call({ @@ -131,13 +131,13 @@ const result = await agent.call({ }); ``` -Requires agentContractId in config. +Requires `agentContractId` in config. --- -## View agent contract +## View Agent Contract -Calls a view function on the agent contract (no gas, read-only). Returns the call result or throws. +Calls a **view function** on the agent contract (no gas, read-only). Returns the call result or throws. ```ts const result = await agent.view({ @@ -146,11 +146,11 @@ const result = await agent.view({ }); ``` -Requires agentContractId in config. +Requires `agentContractId` in config. --- -## Get attestation +## Get Attestation Returns the attestation in the format the agent contract expects. @@ -164,7 +164,7 @@ const attestation = await agent.getAttestation(); --- -## Get private keys +## Get Private Keys Returns the agent's ephemeral private keys. Useful for when wanting to use other NEAR tooling (e.g. near-api-js) or for other operations like encrypting messages. @@ -180,7 +180,7 @@ const keys = agent.getPrivateKeys({ acknowledgeRisk: true }); ## Utilities -### Sanitize +### sanitize Aims to redact private keys from strings, objects, or Errors. Use before logging. diff --git a/docs/ai/shade-agents/reference/cli.md b/docs/ai/shade-agents/reference/cli.md index 09051320592..6fd2fa02a0a 100644 --- a/docs/ai/shade-agents/reference/cli.md +++ b/docs/ai/shade-agents/reference/cli.md @@ -5,7 +5,7 @@ sidebar_label: Shade Agent CLI description: "Use the Shade Agent CLI to deploy your Shade Agent." --- -The Shade Agent CLI makes it easy to deploy a Shade Agent. Including building and deploying your agent contract, building and publishing your agent's Docker image, and deploying the agent to Phala Cloud. The CLI revolves around a `deployment.yaml` file that configures how your Shade Agent will be deployed. +The **Shade Agent CLI** makes it easy to deploy a Shade Agent. It includes building and deploying your agent contract, building and publishing your agent's Docker image, and deploying the agent to Phala Cloud. The CLI revolves around a `deployment.yaml` file that configures how your Shade Agent will be deployed. --- @@ -21,37 +21,37 @@ npm install -g @neardefi/shade-agent-cli ### Deploy -Deploys your Shade Agent with the configuration as defined by the deployment.yaml file. +Deploys your Shade Agent with the configuration as defined by the `deployment.yaml` file. ```bash shade deploy ``` -Must be executed in the same directory as your deployment.yaml file. +Must be executed in the same directory as your `deployment.yaml` file. ### Plan -Generates a preview of how your Shade Agent will be deployed as defined by the deployment.yaml file. +Generates a preview of how your Shade Agent will be deployed as defined by the `deployment.yaml` file. ```bash shade plan ``` -Must be executed in the same directory as your deployment.yaml file. +Must be executed in the same directory as your `deployment.yaml` file. ### Whitelist -Whitelists a specified agent's account ID in the agent contract as defined by the deployment.yaml file. This is only relevant for local mode. +Whitelists a specified agent's account ID in the agent contract as defined by the `deployment.yaml` file. This is only relevant for local mode. ```bash shade whitelist ``` -Must be executed in the same directory as your deployment.yaml file. +Must be executed in the same directory as your `deployment.yaml` file. ### Auth -Configure NEAR and Phala credentials required for deploying your Shade Agent. Must be run before using the `deploy` or `whitelist` commands. +Configure **NEAR** and **Phala** credentials required for deploying your Shade Agent. Must be run before using the `deploy` or `whitelist` commands. ```bash shade auth @@ -60,11 +60,11 @@ shade auth --- -## deployment.yaml reference +## deployment.yaml Reference CLI configurations are read from a single `deployment.yaml` file in the project root. The following sections describe what each key configures. -### Top-level keys +### Top-Level Keys | Key | Required | Description | |-----|----------|-------------| @@ -74,7 +74,7 @@ CLI configurations are read from a single `deployment.yaml` file in the project | **agent_contract** | Yes | Agent contract configuration. See [agent_contract](#agent_contract) for more details. | | **approve_measurements** | No | If enabled, sets allowed measurements in the agent contract. | | **approve_ppids** | No | If enabled, sets allowed PPIDs in the agent contract.| -| **build_docker_image** | No (TEE only) | If enabled and environment is TEE, builds a new Docker image for your agent, publishes it and updates the Docker Compose with the new image. | +| **build_docker_image** | No (TEE only) | If enabled and environment is TEE, builds a new Docker image for your agent, publishes it, and updates the Docker Compose with the new image. | | **deploy_to_phala** | No (TEE only) | If enabled and environment is TEE, deploys the Docker Compose to Phala Cloud. | | **whitelist_agent_for_local** | No | Config for the `shade whitelist` command to whitelist an agent's account ID whilst in local mode (not used by the shade deploy command). | | **os** | No | Override OS for tooling: `mac` or `linux`. If omitted, the CLI auto-detects from the current platform. | @@ -114,7 +114,7 @@ CLI configurations are read from a single `deployment.yaml` file in the project Placeholders in args: - `` — Resolves to `true` or `false` depending on `environment`. -- `<7_DAYS>` — Resolves to 7 days in milliseconds (`604800000`). +- `<7_DAYS>` — Resolves to 7 days in milliseconds (604800000). - `` — Resolves to the NEAR account ID from `shade auth`. - `` — Resolves to the default MPC contract for the selected `network` (testnet/mainnet). @@ -144,7 +144,7 @@ Placeholders in args: - `` — Resolves to a list of all PPIDs of devices on Phala Cloud for TEE and a mock PPID for local. -### build_docker_image (TEE only) +### build_docker_image (TEE Only) | Key | Required | Description | |-----|----------|-------------| @@ -153,7 +153,7 @@ Placeholders in args: | **cache** | Yes | Boolean; whether to use caching in the build process. | | **dockerfile_path** | Yes | Path to the Dockerfile to use for the build process (e.g. `./Dockerfile`). | -### deploy_to_phala (TEE only) +### deploy_to_phala (TEE Only) | Key | Required | Description | |-----|----------|-------------| @@ -212,6 +212,6 @@ Currently, the CLI only supports measurement calculation and Phala Cloud deploym -## Example deployment.yaml configurations +## Example deployment.yaml Configurations You can view a list of [example deployment.yaml configurations here](https://github.com/NearDeFi/shade-agent-framework/tree/main/shade-agent-cli/example-deployment-files). \ No newline at end of file diff --git a/docs/ai/shade-agents/tutorials/ai-dao/dao-agent-contract.md b/docs/ai/shade-agents/tutorials/ai-dao/dao-agent-contract.md index 25bcb448088..f4e9a8dfc14 100644 --- a/docs/ai/shade-agents/tutorials/ai-dao/dao-agent-contract.md +++ b/docs/ai/shade-agents/tutorials/ai-dao/dao-agent-contract.md @@ -210,6 +210,6 @@ The contract exposes [view functions](https://github.com/NearDeFi/verifiable-ai- --- -## Next steps +## Next Steps Now that you understand the DAO agent contract implementation, continue to the [agent page](./dao-agent.md) to learn about the verifiable agent that queries the contract for pending requests and casts a vote using an LLM. \ No newline at end of file diff --git a/docs/ai/shade-agents/tutorials/ai-dao/deploying.md b/docs/ai/shade-agents/tutorials/ai-dao/deploying.md index a1d552586f6..b7ab0780148 100644 --- a/docs/ai/shade-agents/tutorials/ai-dao/deploying.md +++ b/docs/ai/shade-agents/tutorials/ai-dao/deploying.md @@ -6,13 +6,11 @@ description: "Learn how to deploy the Verifiable AI DAO Shade Agent which includ --- :::warning -The Shade Agent Framework is experimental and contains known critical vulnerabilities. - -It must not be used in production or on mainnet and is intended solely for testing and non-critical use on testnet. +The Verifiable AI DAO tutorial uses an old version of the Shade Agent Framework, which contains known critical vulnerabilities and has a different architecture. No representations or warranties are made regarding security, correctness, or fitness for any purpose. Use of this software is entirely at your own risk. -A production-ready version of the framework is currently in development. +The tutorial will be updated to use the latest version of the Shade Agent Framework in the future. ::: import Tabs from '@theme/Tabs'; diff --git a/docs/ai/shade-agents/tutorials/ai-dao/overview.md b/docs/ai/shade-agents/tutorials/ai-dao/overview.md index dd8c1b50fb7..30d4024ac61 100644 --- a/docs/ai/shade-agents/tutorials/ai-dao/overview.md +++ b/docs/ai/shade-agents/tutorials/ai-dao/overview.md @@ -7,12 +7,15 @@ description: "A brief overview of the Verifiable AI DAO tutorial built using the import { TryDemo } from '@site/src/components/TryDemo'; -In this tutorial, you'll explore how to build a `fully verifiable AI DAO` using the Shade Agent Framework. The Verifiable AI DAO is a DAO smart contract that uses a Shade Agent with a verifiable LLM to vote on governance proposals according to its predefined manifesto, to create transparent, AI-driven governance that is decentralized and auditable from end-to-end. +:::warning +The Verifiable AI DAO tutorial uses an old version of the Shade Agent Framework, which contains known critical vulnerabilities and has a different architecture. + +No representations or warranties are made regarding security, correctness, or fitness for any purpose. Use of this software is entirely at your own risk. - +The tutorial will be updated to use the latest version of the Shade Agent Framework in the future. +::: + +In this tutorial, you'll explore how to build a `fully verifiable AI DAO` using the Shade Agent Framework. The Verifiable AI DAO is a DAO smart contract that uses a Shade Agent with a verifiable LLM to vote on governance proposals according to its predefined manifesto, to create transparent, AI-driven governance that is decentralized and auditable from end-to-end. This tutorial also serves as a `template` for building `yield and resume-based Shade Agents`. This is a smart contract that, when called, halts its execution for the verified agent to complete some logic and resume the transaction when it has a result, enabled by NEAR's asynchronous design. This pattern allows the agent and LLM become a part of the contract, enabling smart contracts with extended capabilities of a backend server that can make API calls and use LLM inference. This is especially useful when making cross-contract calls to smart contracts that use yield and resume, allowing you to receive the result in the callback - for example, an on-demand oracle. @@ -27,7 +30,7 @@ This tutorial demonstrates how key components of the Shade Agent Framework work --- -## Required knowledge +## Required Knowledge To understand this tutorial, you should have familiarity with these concepts: - [Shade Agents](../../getting-started/introduction.md) diff --git a/docs/ai/shade-agents/tutorials/tutorials-overview.md b/docs/ai/shade-agents/tutorials/tutorials-overview.md index 28a33056a74..8c042ee5862 100644 --- a/docs/ai/shade-agents/tutorials/tutorials-overview.md +++ b/docs/ai/shade-agents/tutorials/tutorials-overview.md @@ -41,11 +41,6 @@ The Quickstart provides a basic template for building your first multichain Shad Explore the [Verifiable AI DAO docs](./ai-dao/overview.md) - - ### Summary The Verifiable AI DAO is a DAO smart contract that uses a Shade Agent with a verifiable LLM to vote on governance proposals according to its predefined manifesto, ensuring transparent and auditable AI-driven governance decisions. diff --git a/website/sidebars.js b/website/sidebars.js index d1481e0af43..733be958c2f 100644 --- a/website/sidebars.js +++ b/website/sidebars.js @@ -210,6 +210,7 @@ const sidebar = { "Concepts": [ "ai/shade-agents/concepts/framework-overview", "ai/shade-agents/concepts/what-can-you-build", + "ai/shade-agents/concepts/ai-inference", "ai/shade-agents/concepts/terminology", "ai/shade-agents/concepts/security", ] diff --git a/website/src/components/sigsSupport.js b/website/src/components/sigsSupport.js index 31c68804691..32ba4d56112 100644 --- a/website/src/components/sigsSupport.js +++ b/website/src/components/sigsSupport.js @@ -34,7 +34,7 @@ export function SigsSupport() {
| From 814c570bd23db6f0790328c0a53e71867d9dc8e1 Mon Sep 17 00:00:00 2001 From: PiVortex Date: Tue, 24 Feb 2026 09:31:31 -0800 Subject: [PATCH 08/12] add article --- blog/2026-02-23.md | 127 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 127 insertions(+) create mode 100644 blog/2026-02-23.md diff --git a/blog/2026-02-23.md b/blog/2026-02-23.md new file mode 100644 index 00000000000..c55013bc1eb --- /dev/null +++ b/blog/2026-02-23.md @@ -0,0 +1,127 @@ +--- +title: Shade Agent Framework 2.0 +authors: [pivortex] +slug: shade-agent-framework-2.0 +tags: [updates, ai, shade-agents] +hide_table_of_contents: true +--- + +The biggest update to the Shade Agent Framework has been released since launch. It aims to enable more production-ready builds and a more flexible developer experience and it comes with significant architectural, and breaking changes. + +:::danger Upgrade immediately +The previous version of the Shade Agent Framework has **known critical vulnerabilities**. You should upgrade your agent to 2.0 as soon as possible. +::: + + + +## A Shift in Mental Model + +Shade Agent 2.0 is not a small iteration. It reflects a different way of building and deploying Shade Agents. + +**Previously**, the framework leaned on global, abstract agent contracts and a separate API service. That made early development straightforward but made production use harder: you had less control over contract behavior, deployment was split across env vars and flags, and the API lived in its own Docker image. + +**In Shade Agent Framework 2.0**, the **Shade Agent API** is a single TypeScript library that runs **inside your agent’s codebase** instead of a separate service. The **agent contract** is included in your repo so you can change and extend it for your use case. The **CLI** is built around one config file and built-in credential management, so deploy and whitelist flows are predictable and easier to script. + +The result is a framework that’s easier to reason about, easier to customize, and better suited to production. Below is a summary of the main changes for the API, CLI, and agent contract, with links to the docs so you can get started. + +--- + +## Shade Agent API + +The Shade Agent API no longer offers multi-language support. It has been consolidated into a single **TypeScript/JavaScript** library (`@neardefi/shade-agent-js`) that runs within your agent’s codebase instead of a separate Docker image. + +### How the API Has Changed + +Previously, the API was a separate Docker image (and HTTP service); you called standalone functions that talked to that service. In 2.0, you create a client in your code and use it for everything. Registration and funding now explicit methods instead of automatic on boot. + +**Before (1.x):** No client—you installed the package and called functions that hit the API internally (or HTTP in other languages): + +```ts +import { agentAccountId, agent, agentCall, agentView } from '@neardefi/shade-agent-js'; +// API assumed to be running (Docker / localhost:3140); env vars for config +``` + +**After (2.0):** One client, created once with your config: + +```ts +import { ShadeClient } from "@neardefi/shade-agent-js"; + +const agent = await ShadeClient.create({ + networkId: "testnet", + agentContractId: process.env.AGENT_CONTRACT_ID, + sponsor: { accountId: process.env.SPONSOR_ACCOUNT_ID, privateKey: process.env.SPONSOR_PRIVATE_KEY }, + rpc: provider, +}); +// Then: await agent.register(), await agent.fund(0.3), etc. +``` + +**Account ID:** Same idea, different shape, you now use the client instance and get the value directly (no response object). + +```ts +// Before: const res = await agentAccountId(); const accountId = res.accountId +const accountId = agent.accountId(); +``` + +**Balance:** Balance is now a method on the client and returns human-readable NEAR (e.g. `1` = one NEAR), not yoctoNEAR. + +```ts +// Before: const res = await agent("getBalance"); const balance = res.balance // yoctoNEAR +const balance = await agent.balance(); // human-readable, e.g. 0.3 +``` + +**Call and view:** Call and view have stayed the same but are accessible via the client instance instead of a standalone function. + +```ts +// Before: agentCall({ methodName, args, gas }) / agentView({ methodName, args }) +const result = await agent.call({ + methodName: "example_call_function", + args: { arg1: "value1", arg2: "value2" }, + gas: BigInt("300000000000000"), + deposit: "0", +}); +const viewResult = await agent.view({ + methodName: "example_view_function", + args: { arg1: "value1" }, +}); +``` + +**Request signature:** The old API had a dedicated `requestSignature({ path, payload, keyType })` helper. In 2.0, this has been deprecated, now if you want to call a function of the contract called `request_signature`, call it like any other function: + +```ts +// Before: requestSignature({ path, payload, keyType }) +const result = await agent.call({ + methodName: "request_signature", + args: { path, payload, key_type }, + deposit: "1", +}); +``` + +New methods include `agent.register()`, `agent.fund()`, `agent.isWhitelisted()`, and `agent.getAttestation()` for explicit control over registration, funding, and attestation; see the API reference for details. + +To learn how to install, configure, and use the API, see the **[Shade Agent API reference](/docs/docs/ai/shade-agents/reference/api)**. + +--- + +## Shade Agent CLI + +The Shade Agent CLI has had a **total revamp**. Instead of being configured with a mix of environment variables and flags, it now centers on a **single `deployment.yaml` file**, with built-in credential management and command routing, taking inspiration from the NEAR CLI. + +You run `shade auth` to configure NEAR and Phala credentials, then use the commands `shade deploy` to deploy your Shade Agent, `shade plan` to preview the deployment, and `shade whitelist` to whitelist an agent's account ID. The `deployment.yaml` file drives contract deployment (including from source or WASM), measurement and PPID approval, Docker image build and publish, and deployment to Phala Cloud, so all deployment options live in one place. + +To learn how to install the CLI, use each command, and configure `deployment.yaml`, see the **[Shade Agent CLI reference](/docs/docs/ai/shade-agents/reference/cli)**. + +--- + +## Agent Contract + +Previously, the framework used **global agent contracts** that were abstract and easy to start with, but made production development and customization difficult. In 2.0, by default, a reference agent contract is included in the `shade-agent-template` repo, so you can edit and extend it to your needs (e.g. custom agent-gated functions, guardrails, and initialization). + +The reference agent contract also now uses a more robust external library for attestation verification (the [shade-attestation crate](https://github.com/NearDeFi/shade-agent-framework/tree/main/shade-attestation)). Instead of approving the codehash of a single Docker image, the contract now requires you to approve a set of measurements for more in-depth verification and a list of PPIDs that set the physical hardware the agent can run on. Local mode now requires you to whitelist the account ID of the agent you want to run locally, blocking any other account ID from controlling the contract for more consistent behavior when testing. + +To walk through the contract flow, initialization, attestation verification, and how to add your own agent-gated functions, see the **[Agent Contract reference](/docs/docs/ai/shade-agents/reference/agent-contract)**. + +--- + +## Next Steps + +Start your migration by **cloning the template** in the [quickstart](/docs/docs/ai/shade-agents/getting-started/quickstart/deploying) to explore the new setup. From f0abd89d2e182cbbb8f2f8b0efba6b777c67b069 Mon Sep 17 00:00:00 2001 From: PiVortex Date: Tue, 24 Feb 2026 10:06:50 -0800 Subject: [PATCH 09/12] attempt fix broken links --- blog/2026-02-23.md | 8 ++++---- docs/ai/shade-agents/reference/agent-contract.md | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/blog/2026-02-23.md b/blog/2026-02-23.md index c55013bc1eb..ffaaf336051 100644 --- a/blog/2026-02-23.md +++ b/blog/2026-02-23.md @@ -98,7 +98,7 @@ const result = await agent.call({ New methods include `agent.register()`, `agent.fund()`, `agent.isWhitelisted()`, and `agent.getAttestation()` for explicit control over registration, funding, and attestation; see the API reference for details. -To learn how to install, configure, and use the API, see the **[Shade Agent API reference](/docs/docs/ai/shade-agents/reference/api)**. +To learn how to install, configure, and use the API, see the **[Shade Agent API reference](/ai/shade-agents/reference/api)**. --- @@ -108,7 +108,7 @@ The Shade Agent CLI has had a **total revamp**. Instead of being configured with You run `shade auth` to configure NEAR and Phala credentials, then use the commands `shade deploy` to deploy your Shade Agent, `shade plan` to preview the deployment, and `shade whitelist` to whitelist an agent's account ID. The `deployment.yaml` file drives contract deployment (including from source or WASM), measurement and PPID approval, Docker image build and publish, and deployment to Phala Cloud, so all deployment options live in one place. -To learn how to install the CLI, use each command, and configure `deployment.yaml`, see the **[Shade Agent CLI reference](/docs/docs/ai/shade-agents/reference/cli)**. +To learn how to install the CLI, use each command, and configure `deployment.yaml`, see the **[Shade Agent CLI reference](/ai/shade-agents/reference/cli)**. --- @@ -118,10 +118,10 @@ Previously, the framework used **global agent contracts** that were abstract and The reference agent contract also now uses a more robust external library for attestation verification (the [shade-attestation crate](https://github.com/NearDeFi/shade-agent-framework/tree/main/shade-attestation)). Instead of approving the codehash of a single Docker image, the contract now requires you to approve a set of measurements for more in-depth verification and a list of PPIDs that set the physical hardware the agent can run on. Local mode now requires you to whitelist the account ID of the agent you want to run locally, blocking any other account ID from controlling the contract for more consistent behavior when testing. -To walk through the contract flow, initialization, attestation verification, and how to add your own agent-gated functions, see the **[Agent Contract reference](/docs/docs/ai/shade-agents/reference/agent-contract)**. +To walk through the contract flow, initialization, attestation verification, and how to add your own agent-gated functions, see the **[Agent Contract reference](/ai/shade-agents/reference/agent-contract)**. --- ## Next Steps -Start your migration by **cloning the template** in the [quickstart](/docs/docs/ai/shade-agents/getting-started/quickstart/deploying) to explore the new setup. +Start your migration by **cloning the template** in the [quickstart](/ai/shade-agents/getting-started/quickstart/deploying) to explore the new setup. diff --git a/docs/ai/shade-agents/reference/agent-contract.md b/docs/ai/shade-agents/reference/agent-contract.md index 08a70575526..08aa988c285 100644 --- a/docs/ai/shade-agents/reference/agent-contract.md +++ b/docs/ai/shade-agents/reference/agent-contract.md @@ -298,4 +298,4 @@ The `--no-abi` flag is used to build the contract without an ABI. This is requir ## Calling Methods -The **Shade Agent CLI** calls the main contract methods when you run `shade deploy`, but it does not cover every method. For methods the CLI doesn’t support, use the [NEAR CLI](../../../tools/cli) or create scripts using the [NEAR API](../../../tools/near-api). \ No newline at end of file +The **Shade Agent CLI** calls the main contract methods when you run `shade deploy`, but it does not cover every method. For methods the CLI doesn’t support, use the [NEAR CLI](../../../../tools/near-cli) or create scripts using the [NEAR API](../../../../tools/near-api). \ No newline at end of file From cb0b9a6b78ffdc17c8a4571cfbe538f24fe6983a Mon Sep 17 00:00:00 2001 From: PiVortex Date: Tue, 24 Feb 2026 10:25:08 -0800 Subject: [PATCH 10/12] fix broken link --- docs/ai/shade-agents/concepts/terminology.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/ai/shade-agents/concepts/terminology.md b/docs/ai/shade-agents/concepts/terminology.md index bc494474b1f..968b24494ef 100644 --- a/docs/ai/shade-agents/concepts/terminology.md +++ b/docs/ai/shade-agents/concepts/terminology.md @@ -17,7 +17,7 @@ It includes the **Shade Agent API**, the **Shade Agent CLI**, and an **agent con ### Shade Agent -A **Shade Agent** is an application built using the Shade Agent Framework. See the [what can you build section](../getting-started/introduction.md#what-can-you-build) for some examples. +A **Shade Agent** is an application built using the Shade Agent Framework. See [What can you build?](./what-can-you-build.md) for some examples. ### Agent From 29edc1abc6ce83fcc3b5b1457db3d0f7d7e0c20c Mon Sep 17 00:00:00 2001 From: Guille Date: Fri, 27 Feb 2026 13:54:41 +0100 Subject: [PATCH 11/12] Apply suggestions from code review --- blog/2026-02-23.md | 8 ++++---- .../shade-agents/getting-started/quickstart/components.md | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/blog/2026-02-23.md b/blog/2026-02-23.md index ffaaf336051..bd3a340387c 100644 --- a/blog/2026-02-23.md +++ b/blog/2026-02-23.md @@ -6,7 +6,7 @@ tags: [updates, ai, shade-agents] hide_table_of_contents: true --- -The biggest update to the Shade Agent Framework has been released since launch. It aims to enable more production-ready builds and a more flexible developer experience and it comes with significant architectural, and breaking changes. +The biggest update to the Shade Agent Framework has been released since launch. It aims to enable more production-ready builds, a more flexible developer experience, and it comes with significant architectural changes. :::danger Upgrade immediately The previous version of the Shade Agent Framework has **known critical vulnerabilities**. You should upgrade your agent to 2.0 as soon as possible. @@ -18,9 +18,9 @@ The previous version of the Shade Agent Framework has **known critical vulnerabi Shade Agent 2.0 is not a small iteration. It reflects a different way of building and deploying Shade Agents. -**Previously**, the framework leaned on global, abstract agent contracts and a separate API service. That made early development straightforward but made production use harder: you had less control over contract behavior, deployment was split across env vars and flags, and the API lived in its own Docker image. +**Previously**, the framework leaned on global, abstract agent contracts and a separate API service. That made early development straightforward but production use harder: you had less control over contract behavior, deployment was split across env vars and flags, and the API lived in its own Docker image. -**In Shade Agent Framework 2.0**, the **Shade Agent API** is a single TypeScript library that runs **inside your agent’s codebase** instead of a separate service. The **agent contract** is included in your repo so you can change and extend it for your use case. The **CLI** is built around one config file and built-in credential management, so deploy and whitelist flows are predictable and easier to script. +**In Shade Agent Framework 2.0**, the **Shade Agent API** is a single TypeScript library that runs **inside your agent’s codebase** instead of a separate service. The **agent contract** is included in your repo so you can change and extend it for your use case. The **CLI** is built around a single config file and has built-in credential management, making deploy and whitelist flows are predictable and easier to script. The result is a framework that’s easier to reason about, easier to customize, and better suited to production. Below is a summary of the main changes for the API, CLI, and agent contract, with links to the docs so you can get started. @@ -104,7 +104,7 @@ To learn how to install, configure, and use the API, see the **[Shade Agent API ## Shade Agent CLI -The Shade Agent CLI has had a **total revamp**. Instead of being configured with a mix of environment variables and flags, it now centers on a **single `deployment.yaml` file**, with built-in credential management and command routing, taking inspiration from the NEAR CLI. +The Shade Agent CLI had a **total revamp**. Instead of being configured with a mix of environment variables and flags, it now centers on a **single `deployment.yaml` file**, with built-in credential management and command routing, taking inspiration from the NEAR CLI. You run `shade auth` to configure NEAR and Phala credentials, then use the commands `shade deploy` to deploy your Shade Agent, `shade plan` to preview the deployment, and `shade whitelist` to whitelist an agent's account ID. The `deployment.yaml` file drives contract deployment (including from source or WASM), measurement and PPID approval, Docker image build and publish, and deployment to Phala Cloud, so all deployment options live in one place. diff --git a/docs/ai/shade-agents/getting-started/quickstart/components.md b/docs/ai/shade-agents/getting-started/quickstart/components.md index 3878c6b95cf..f7ea0466331 100644 --- a/docs/ai/shade-agents/getting-started/quickstart/components.md +++ b/docs/ai/shade-agents/getting-started/quickstart/components.md @@ -34,7 +34,7 @@ The client is initialized with the following arguments: - `networkId` is set to `testnet` since the agent contract was deployed to testnet. - `agentContractId` is set to the agent contract ID and is fetched from the environment variables. - `sponsor` is set to the sponsor account details from the environment variables. It is used later to fund the agent. -- `derivationPath` is set to the sponsor's private key from the environment variables. For local deployment, this derives a deterministic account ID for the agent, making testing easier (for TEE deployment, this does nothing as ignored). The derivation path needs to be random and private; a private key fulfils this criterion well. +- `derivationPath` is set to the sponsor's private key from the environment variables. For local deployment, this derives a deterministic account ID for the agent, making testing easier (for TEE deployment, this does nothing as ignored). The derivation path needs to be random and private; a private key fulfills this criterion well. Date: Mon, 2 Mar 2026 12:44:57 -0700 Subject: [PATCH 12/12] remove hosted example and move quickstart snippets to main --- .../getting-started/quickstart/components.md | 32 +++++++++---------- .../getting-started/quickstart/deploying.md | 7 +--- .../tutorials/tutorials-overview.md | 5 --- 3 files changed, 17 insertions(+), 27 deletions(-) diff --git a/docs/ai/shade-agents/getting-started/quickstart/components.md b/docs/ai/shade-agents/getting-started/quickstart/components.md index f7ea0466331..b82847b8621 100644 --- a/docs/ai/shade-agents/getting-started/quickstart/components.md +++ b/docs/ai/shade-agents/getting-started/quickstart/components.md @@ -17,10 +17,10 @@ In this section, we'll explore the main components of the [quickstart template]( The template we're using is a simple Shade Agent built with Hono and written in **TypeScript** that acts as a verifiable ETH price oracle. It takes prices from two different APIs, takes the average, and then pushes the price to an Ethereum contract. The agent has three main files: -1) [**index.ts**](https://github.com/NearDeFi/shade-agent-template/blob/main/src/index.ts) - This is the entry point that sets up the **Shade Agent Client**, **registers** the agent and defines the routes for the agent. We'll review this file in more detail in the next section. -2) [**transaction**](https://github.com/NearDeFi/shade-agent-template/blob/main/src/routes/transaction.ts) - This is where the core logic of the agent is defined. When this API is called, the agent will build a transaction payload and request a signature from the agent contract. We'll look deeper into this API route later on this page. -3) [**agentInfo**](https://github.com/NearDeFi/shade-agent-template/blob/2.0/src/routes/agentInfo.ts) - This API simply fetches the agent's NEAR account ID and its balance by using the `agent.accountId()` and `agent.balance()` methods from the `shade-agent-js` library. -4) [**ethAccount**](https://github.com/NearDeFi/shade-agent-template/blob/main/src/routes/ethAccount.ts) - This API returns the **Ethereum Sepolia account** that the Shade Agent uses to update the price of Ethereum in the Sepolia contract. This API is used so the user knows which account to fund for gas. +1) [**index.ts**](https://github.com/NearDeFi/shade-agent-template/tree/main/src/index.ts) - This is the entry point that sets up the **Shade Agent Client**, **registers** the agent and defines the routes for the agent. We'll review this file in more detail in the next section. +2) [**transaction**](https://github.com/NearDeFi/shade-agent-template/tree/main/src/routes/transaction.ts) - This is where the core logic of the agent is defined. When this API is called, the agent will build a transaction payload and request a signature from the agent contract. We'll look deeper into this API route later on this page. +3) [**agentInfo**](https://github.com/NearDeFi/shade-agent-template/tree/main/src/routes/agentInfo.ts) - This API simply fetches the agent's NEAR account ID and its balance by using the `agent.accountId()` and `agent.balance()` methods from the `shade-agent-js` library. +4) [**ethAccount**](https://github.com/NearDeFi/shade-agent-template/tree/main/src/routes/ethAccount.ts) - This API returns the **Ethereum Sepolia account** that the Shade Agent uses to update the price of Ethereum in the Sepolia contract. This API is used so the user knows which account to fund for gas. The repo also contains an **agent contract**. We won't review the agent contract as it's the same as the reference implementation [featured here](../../reference/agent-contract.md), but we encourage you to review the reference implementation after this section. @@ -28,7 +28,7 @@ The repo also contains an **agent contract**. We won't review the agent contract ## Registering the Agent -First, in the [index.ts](https://github.com/NearDeFi/shade-agent-template/blob/2.0/src/index.ts) file, the **Shade Agent Client** is **initialized**. +First, in the [index.ts](https://github.com/NearDeFi/shade-agent-template/tree/main/src/index.ts) file, the **Shade Agent Client** is **initialized**. The client is initialized with the following arguments: - `networkId` is set to `testnet` since the agent contract was deployed to testnet. @@ -37,25 +37,25 @@ The client is initialized with the following arguments: - `derivationPath` is set to the sponsor's private key from the environment variables. For local deployment, this derives a deterministic account ID for the agent, making testing easier (for TEE deployment, this does nothing as ignored). The derivation path needs to be random and private; a private key fulfills this criterion well. Next, the agent is **funded** with 0.3 NEAR via the `sponsor` account using the `agent.fund()` method. This is done to ensure the agent has enough NEAR to pay for gas when sending transactions. After this, the agent **registers** itself with the agent contract. To make it easier for local deployment, a loop is started that checks if the agent is whitelisted; if not, it will wait for 10 seconds and try again until it's whitelisted, at which point the agent will register. Since registrations expire (every 7 days by default), an interval is set to **re-register** the agent every 6 days. The agent is now registered and ready to sign transactions. @@ -64,12 +64,12 @@ The agent is now registered and ready to sign transactions. ## Signing Transactions -In the [transaction API Route](https://github.com/NearDeFi/shade-agent-template/blob/main/src/routes/transaction.ts), the `agent.call()` method from the `shade-agent-js` library is used to call a function on the agent contract. +In the [transaction API Route](https://github.com/NearDeFi/shade-agent-template/tree/main/src/routes/transaction.ts), the `agent.call()` method from the `shade-agent-js` library is used to call a function on the agent contract. In this example, the agent is calling the `request_signature` function on the agent contract. This function takes a transaction payload for nearly any blockchain and requests a signature via [Chain Signatures](../../../../chain-abstraction/chain-signatures/implementation.md). Here, we're signing a transaction to call an Ethereum contract to update the stored price of ETH. First, we retrieve the price of ETH (in this example, the function queries two different APIs and calculates the average). Next, we build the **transaction payload** to be signed. To do this, we're using the `chainsig.js` library. @@ -79,13 +79,13 @@ Using this library, we: 3. **Build the transaction and the transaction payload** by inputting the derived address, the target Ethereum smart contract, and the data. Once we have the payload (also known as the hash), we can call the `request_signature` function on the agent contract to sign the transaction. We specify the `keyType` as `Ecdsa` as we're signing for a blockchain that uses the **secp256k1** signature scheme. The result is the **signature**. @@ -93,7 +93,7 @@ The result is the **signature**. We then attach the signature to the Ethereum transaction and broadcast it to the target network. --- @@ -102,10 +102,10 @@ We then attach the signature to the Ethereum transaction and broadcast it to the ### Using Different Chains -We set up a **chain adapter** for Ethereum Sepolia in the [Ethereum.ts](https://github.com/NearDeFi/shade-agent-template/blob/main/src/utils/ethereum.ts) file using the `chainsig.js` library. This library allows us to easily construct transaction payloads to be signed by the agent. +We set up a **chain adapter** for Ethereum Sepolia in the [Ethereum.ts](https://github.com/NearDeFi/shade-agent-template/tree/main/src/utils/ethereum.ts) file using the `chainsig.js` library. This library allows us to easily construct transaction payloads to be signed by the agent. You can set up chain adapters for a variety of chains, including NEAR, EVM, Bitcoin, Solana, SUI, XRP, and Cosmos, to allow your agent to interact with multiple different chains. You can see a full list of the chains currently supported [here](https://github.com/NearDeFi/chainsig.js/tree/main?tab=readme-ov-file#supported-chains), but feel free to contribute any chain that is not yet supported. diff --git a/docs/ai/shade-agents/getting-started/quickstart/deploying.md b/docs/ai/shade-agents/getting-started/quickstart/deploying.md index 3e2d8aac3e5..34f708d95dc 100644 --- a/docs/ai/shade-agents/getting-started/quickstart/deploying.md +++ b/docs/ai/shade-agents/getting-started/quickstart/deploying.md @@ -20,11 +20,6 @@ In this section, we'll walk you through **deploying** a Shade Agent. The [template](https://github.com/NearDeFi/shade-agent-template) we're using is a simple Shade Agent built with Hono and written in **TypeScript** that acts as a verifiable ETH price oracle. It fetches the price of Eth from two different APIs, takes the average, and then pushes the price to an Ethereum contract. - - We'll cover two deployment scenarios: 1. **Local Development**: Running the agent locally for rapid testing and development. 2. **TEE Deployment**: Running the agent in a real Trusted Execution Environment (TEE). @@ -200,7 +195,7 @@ npm i npm run dev ``` -To use the frontend with your Phala deployment, change the `API_URL` to the Phala URL in your [config.js](https://github.com/NearDeFi/shade-agent-template/blob/main/frontend/src/config.js) file. +To use the frontend with your Phala deployment, change the `API_URL` to the Phala URL in your [config.js](https://github.com/NearDeFi/shade-agent-template/tree/main/frontend/src/config.js) file. In the frontend, you can review the approved **measurements** and **PPID** in the contract and details of the registered agents. diff --git a/docs/ai/shade-agents/tutorials/tutorials-overview.md b/docs/ai/shade-agents/tutorials/tutorials-overview.md index 8c042ee5862..23f78b42262 100644 --- a/docs/ai/shade-agents/tutorials/tutorials-overview.md +++ b/docs/ai/shade-agents/tutorials/tutorials-overview.md @@ -15,11 +15,6 @@ This section provides tutorials and templates to help you build Shade Agents fas Explore the [Quickstart docs](../getting-started/quickstart/deploying.md) - - ### Summary The Quickstart features a verifiable Oracle secured by the Shade Agent Framework that pushes the price of ETH to a smart contract on Ethereum.