Docs

Build With Tee Agent

Deploy contracts, run a Phala Cloud TDX oracle, mint ERC-8004 compatible agents with ERC-7857 private data, then validate and move them without exposing encrypted skills.

Contract Addresses

AgentRegistryTee Agent · ERC-7857
0x83eF896Fc482EdDf5ff812bd6b20f552e352BDF7
Reputation RegistryGlobal · ERC-8004
0x8004B663056A597Dffe9eCcC1965A193B7388713
TeeVerifierTee Agent · ERC-7857 + ERC-8004
0xa46fD4879c3bD188d9dd7E9d61bc801731cBdc9f
Identity RegistryGlobal · ERC-8004
0x8004A818BFB912233c491871b3d84c89A494BD9e
ValidationRegistryTee Agent · ERC-8004
0xc57fA5321F7fc2bD60bb889527AF0a26D9d2Af93

Feedback Verification

Verify feedback with its URI

Feedback rows can be checked against the on-chain validation registry by sending the `feedbackURI` to the dashboard verifier. The verifier decodes the ERC-8004 feedback JSON, reads the validation response, and confirms it came from the configured TEE verifier.

await fetch("/api/verify", {
  method: "POST",
  headers: { "content-type": "application/json" },
  body: JSON.stringify({ feedbackURI }),
});
ERC-8004

Official agent identity

Deploy an ERC-8004 agent on the official registries, publish the teeOracle service on IPFS, and stay compatible with 8004scan.io.

ValidationRegistry

TEE-backed reputation

Use a shared Validation Module with a TEE verifier/oracle to turn DCAP-backed results into Sybil-resistant feedback for the Reputation Module.

ERC-7857 · TEE

Encrypted private skills

Encrypt agent data such as skills, prompts, and models so only your oracle can decode it, uploaded to 0G Storage, with secure re-encryption during ownership transfer.

MCP

Operate agents from AI clients

`@tee-agent/mcp` exposes stdio and Streamable HTTP tools for creating metadata, minting, running oracles, requesting validation, submitting feedback, and verifying feedback. Write-oriented tools return calldata for the caller to submit with their own wallet.

{
  "mcpServers": {
    "tee-agent": {
      "command": "node",
      "args": ["apps/mcp/dist/index.js"]
    }
  }
}
npm run mcp:start:http

POST /mcp
GET /health

8004scan, With Validation, Proof And Private Skills

Start with official ERC-8004 discovery, run private encrypted skills through a Phala CVM oracle endpoint, verify TDX quotes, then turn validated runs into Sybil-resistant reputation.

ERC-8004ERC-7857Phala CVMAutomata DCAP

WebApp / User

1

Deploy CVM + mint agent

Deploy the Phala CVM oracle first, then mint an official ERC-8004 agent with the printed HTTPS endpoint published as its teeOracle service.

Phala endpointERC-8004
2

Run your oracle and verify proof

Apps call the oracle endpoint for owner-signed runs, then pass the returned proof bundle to /verify when they need off-chain proof.

/run/verify
3

Request validation

The app writes a ValidationRequest that points at TeeVerifier and references the run payload, output, score, quote, and request hash.

ValidationRequestTeeVerifier
4

Transfer ownership

When the agent is sold or transferred, the new owner chooses an oracle endpoint and signs the re-encryption flow.

TransferNew owner

Phala CVM / Oracle

1

Bring your handler

Copy an oracle example, replace the handler with your app logic, and deploy it as a Phala Cloud CVM with the repo scripts.

Custom handlerPhala CVM
2

Run inside Intel TDX

The oracle checks ownership, decrypts ERC-7857 data only inside the TEE, runs code or model inference, and returns the result with a TDX quote.

Intel TDXTEE quote
3

Validate with AI

For validation, the oracle can rerun inference with another model at temperature 0 and compare the original result, score, and reasoning.

/validatetemperature 0
4

Re-wrap keys in TEE

The current oracle re-wraps ERC-7857 content keys to the new oracle key inside the TEE without exposing plaintext.

Re-encryptionTEE

Blockchain

1

Publish identity + endpoint

AgentRegistry mints ERC-7857 encrypted skills, links the official ERC-8004 identity, and publishes metadata on IPFS. Encoded hash on 0G Storage.

ERC-78578004scan
2

Verify TEE proof

TeeVerifier and Automata DCAP verify Intel TDX quotes before trusting oracle registration, validation proofs, or transfer proofs.

TeeVerifierAutomata DCAP
3

Feed reputation

Validated runs can feed ERC-8004 reputation with TEE proof, reducing Sybil-prone self-reporting from arbitrary wallets.

ReputationSybil-resistant
4

Move identity + data

The ERC-7857 NFT and linked ERC-8004 identity move together, while encrypted data remains anchored on-chain.

ERC-7857ERC-8004

Bring Your Own Oracle Handler

Copy one of the oracle examples under apps/oracle/src/examples, replace the handler with your app logic, then deploy it with npm run oracle:deploy. The printed Phala HTTPS endpoint is the URL published as the ERC-8004 teeOracle service and called by /run, /verify, /validate, and re-encryption flows.

Custom handler

Hardware Trust Boundary

The endpoint is for discovery and execution; the trust root is the TDX quote. Oracle registration binds reportData to the TEE-derived key, and validation quotes bind the agent id, request hash, and score before on-chain verification.

RTMR0 identifies the measured CVM hardware/firmware setup, RTMR1 the Linux kernel, RTMR2 kernel parameters plus initrd/rootfs, and RTMR3 the dstack app compose and runtime events. Matching RTMRs prove a run and verification came from the same measured environment.

On-chain DCAP

Build On Top

Deploy one Phala CVM oracle, point ERC-8004 `teeOracle` services at it, then use the SDK from any app or backend. Remote oracle trust is enforced on-chain through Automata DCAP verification of Intel TDX quotes.

@tee-agent/oracle@tee-agent/agent

Launch An Agent

Deploy the contracts and oracle, then mint the agent with ERC-721 metadata, ERC-8004 services, and ERC-7857 private data.

1

Deploy

Deploy contracts and one Phala CVM oracle through the repo scripts. oracle:deploy prints the HTTPS endpoint to use as teeOracle.

Automata DCAP
copy-ready snippet
# Deploy contracts and write deployments.json
npm run deploy:arbitrumSepolia --workspace=contracts
npm run setup-env --workspace=contracts

# Copy an example oracle or create your own handler
cp apps/oracle/src/examples/prediction-market.ts \
  apps/oracle/src/prod/my-oracle.ts

# Fill root .env and apps/oracle/.env, then deploy it
npm run oracle:image
npm run oracle:deploy -- src/prod/my-oracle.ts

# oracle:deploy prints the HTTPS teeOracle endpoint
2

Handler

Copy an oracle example or create your own handler; /run receives the owner-signed payload and decrypted private blobs.

Oracle
copy-ready snippet
const handler = {
  async run(payload, ctx) {
    const skill = ctx.blobs[0];
    const config = ctx.blobs[1];
    return {
      answer: await runModel({
        prompt: skill,
        input: payload.question,
        config,
      }),
    };
  },
};

await startOracle({ handler, deployments });
3

Mint

Prepare metadata, ERC-8004 services, and ERC-7857 encrypted data, then call AgentRegistry.

ERC-7857 + 8004
copy-ready snippet
const network = getNetworkConfig("arbitrumSepolia");

const deployment = deployments[String(network.chainId)];
const contracts = deployment.contracts;
const config = {
  chain: network.chain,
  registryAddress: contracts.agentRegistry,
  teeVerifierAddress: contracts.teeVerifier,
  validationRegistryAddress: contracts.validationRegistry,
  identityRegistryAddress: network.identityRegistryAddress,
  reputationRegistryAddress: network.reputationRegistryAddress,
  rpcUrl,
  pinataJwt,
  privateKey,
  zeroGRpcUrl,
  zeroGIndexerUrl,
} satisfies AgentConfig;

const prepared = await prepareMint(config, {
  name: "Prediction Agent",
  description: "Runs inside my Phala CVM.",
  imageUrl,
  ownerAddress,
  services: [{ name: "teeOracle", endpoint: oracleUrl }],
  privateEntries: [{ name: "skill", data: systemPrompt }],
});

await walletClient.writeContract({
  address: prepared.contractAddress,
  abi: AGENT_REGISTRY_ABI,
  functionName: "mint",
  args: [
    ownerAddress,
    prepared.publicMetadataUri, // ERC-721 metadata
    prepared.agentMetadataUri,  // ERC-8004 services
    prepared.intelligentData,   // ERC-7857 private data
  ],
});

Use And Transfer

Run the oracle, verify TDX quotes, respond to validation requests, and transfer the encrypted agent safely.

4

Run then Verify

Call the teeOracle /run endpoint with an owner signature, then verify the returned TDX proof bundle through /verify.

/run
copy-ready snippet
const payload = {
  question: "Will ETH close above $4,000 on May 30, 2026?",
  url:
    "https://api.coingecko.com/api/v3/coins/ethereum/market_chart/range?vs_currency=usd&from=1780099200&to=1780185600",
};
const deadline = Math.floor(Date.now() / 1000) + 300;
const typedData = buildRunTypedData({
  oracleAddress,
  chainId: network.chainId,
  agentId,
  payload,
  deadline,
});

const signature = await walletClient.signTypedData({
  account: ownerAddress,
  ...typedData,
});

const run = await fetch(`${oracleUrl}/run`, {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    agentId: agentId.toString(),
    registryAddress: contracts.agentRegistry,
    payload,
    signature,
    deadline,
  }),
}).then((res) => res.json());

const verified = await fetch(`${oracleUrl}/verify`, {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ proof: run.proof }),
}).then((res) => res.json());
5

Validate

Write a ValidationRequest, then let the owner worker call /validate so the oracle submits the TEE-backed response.

/validate
copy-ready snippet
const requestURI = toDataUri({
  ...
});
const validation = prepareValidation(config, {
  agentId: erc8004AgentId,
  validatorAddress: contracts.teeVerifier,
  requestURI,
});

await walletClient.writeContract({
  address: contracts.validationRegistry,
  abi: VALIDATION_REGISTRY_ABI,
  functionName: "validationRequest",
  args: [
    validation.validatorAddress,
    BigInt(validation.agentId),
    validation.requestURI,
    validation.requestHash,
  ],
});

// Worker watches ValidationRequest events, signs as PRIVATE_KEY,
// then calls the agent teeOracle. The oracle submits validationResponse.
await fetch(`${oracleUrl}/validate`, {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify(validateRequest),
});
6

Transfer

Create an offer, let the recipient accept, then submit the combined transfer transaction.

Transfer
copy-ready snippet
const offer = await createTransferOffer(config, transferParams);
const toSign = getTransferAccessPayloadsToSign(offer);
const signatures = await wallet.signMessages(toSign);
const acceptance = buildTransferAcceptance(offer, signatures);
await walletClient.writeContract(buildTransferTxArgs(acceptance));