agentleFS
0gfoundation0gfoundation/0g-agent-skills/skills/agentic-id/interact-agent/SKILL.md

interact-agent

Skill15 starsChanged 57 days agoMITView on GitHub

- Category: agentic-id - SDK: @0gfoundation/0g-agenticid-sdk ^0.1.6, viem ^2.21.0 - Activation Triggers: "call an agent", "chat with an agent", "talk to my agent", "agent endpoints", "agent services", "agent logs" Call a deployed AgenticID agent: discover what it exposes, chat with it as its owner, invoke its signed /api/* services, and read its logs. The SDK resolves the agent's URL from chain, so an agentId is enough. This layer uses viem, not ethers. The repo-wide ethers rule does not apply to…

  • Reads credentials
  • Sends data out

The file

We split this skill into the rules it gives an agent

7 rules. About 0 are common, 0 are distinctive, and 7 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈0

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 7

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Very specific:

    Call a deployed AgenticID agent: discover what it exposes, chat with it as its owner, invoke its signed /api/* services, and read its logs.

    line 12
  2. Very specific:

    Only /api/* services carry X-Agent-Proof.

    line 26
  3. Very specific:

    Call it: fetchWithProof() for services, chat() for chat routes

    line 42
  4. Very specific:

    Use fetchWithProof() on /api/* services when you intend to leave feedback afterwards

    line 48
  5. Very specific:

    Check agent.chat and agent.logs exist before calling them.

    line 49
  6. Very specific:

    Read agent.services / agent.routes rather than guessing paths

    line 51
  7. Very specific:

    Use connect() when you explicitly want a public handle with no token attached

    line 52

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Interact with a Running AgenticID Agent

Metadata

  • Category: agentic-id
  • SDK: @0gfoundation/0g-agenticid-sdk ^0.1.6, viem ^2.21.0
  • Activation Triggers: "call an agent", "chat with an agent", "talk to my agent", "agent endpoints", "agent services", "agent logs"

Purpose

Call a deployed AgenticID agent: discover what it exposes, chat with it as its owner, invoke its signed /api/* services, and read its logs. The SDK resolves the agent's URL from chain, so an agentId is enough.

This layer uses viem, not ethers. The repo-wide ethers rule does not apply to agentic-id skills.

Two kinds of surface, and the difference matters

SurfaceShapeSigned with a serve-proof?Who can call it
services/api/*yesanyone (attributable)
routesframework prefixes, e.g. /v1/noowner-authenticated

Only /api/* services carry X-Agent-Proof. Chat and UI routes deliberately do not: signing an owner-authenticated channel would let an owner manufacture their own reputation. If you need a proof to leave feedback, call a service, not chat.

Prerequisites

  • Node.js >= 20
  • @0gfoundation/0g-agenticid-sdk and viem installed
  • An agent in phase running
  • A wallet only for owner-scoped calls (chat, chatStream, logs); public calls need none

Quick Workflow

  1. Build the client; pass account only if you need owner-scoped calls
  2. client(agentId) to get a handle, or connect(agentId) to force a public one
  3. Inspect agent.services and agent.routes to see what exists
  4. Call it: fetchWithProof() for services, chat() for chat routes

Core Rules

ALWAYS

  • Use fetchWithProof() on /api/* services when you intend to leave feedback afterwards
  • Check agent.chat and agent.logs exist before calling them; they are present only with an owner key and a declared route
  • Read agent.services / agent.routes rather than guessing paths
  • Use connect() when you explicitly want a public handle with no token attached
  • Remember model on chat() is the framework's selector, not an LLM name; the LLM is fixed at deploy time

NEVER

  • Expect a serve-proof from a chat or UI route; proof comes back null
  • Assume chat is available on a handle built without an owner key
  • Hardcode the agent URL when an agentId will resolve it
  • Pass an LLM model name to chat()'s model option
  • Hardcode a private key

Code Examples

Discover what an agent exposes

sayHi() needs only the URL and no wallet.

import { AgenticID } from '@0gfoundation/0g-agenticid-sdk';
import 'dotenv/config';

async function discover(agentId: bigint) {
  const ag = await AgenticID.fromAttestor('https://agenticid.0g.ai');

  // connect() is the explicit PUBLIC handle: never attaches a token.
  const agent = await ag.agent.connect(agentId);

  console.log('signed services (attributable, /api/*):');
  for (const s of agent.services) {
    console.log(`  ${s.method} ${s.path}  ${s.description ?? ''}`);
  }

  console.log('framework routes (chat/UI, unsigned):');
  for (const r of agent.routes) {
    console.log(`  ${r.prefix}  kind=${r.kind ?? '?'} auth=${r.auth ?? 'none'} signed=${r.signed}`);
  }

  return { services: agent.services, routes: agent.routes };
}

Or straight from a URL, without touching chain:

async function greet(agentUrl: string) {
  const ag = await AgenticID.fromAttestor('https://agenticid.0g.ai');
  const { hello, verification } = await ag.agent.sayHi(agentUrl);
  console.log(hello.agent, hello.owner, hello.message);
  console.log('verification:', JSON.stringify(verification));
  return hello;
}

Call a signed service and keep the proof

This is the call that produces a redeemable serve-proof.

async function summarize(agentId: bigint, text: string) {
  const ag = await AgenticID.fromAttestor('https://agenticid.0g.ai');
  const agent = await ag.agent.connect(agentId);

  const { response, proof } = await agent.fetchWithProof('/api/summarize', {
    method: 'POST',
    headers: { 'content-type': 'application/json' },
    body: JSON.stringify({ q: text }),
  });

  const body = await response.json();

  // proof is null when the route is not a signed /api/* service.
  if (proof) {
    console.log(`proof for agent ${proof.agentId}, redeemable by ${proof.submitter}`);
  }

  return { body, proof };
}

Chat as the owner

chat and chatStream appear on the handle only when the client holds the owner key and the agent declares a chat route.

async function chat(agentId: bigint, message: string) {
  const ag = await AgenticID.fromAttestor('https://agenticid.0g.ai', {
    account: process.env.PRIVATE_KEY as `0x${string}`,
  });

  const agent = await ag.agent.client(agentId);

  if (!agent.chat) {
    console.log('no chat route, or this handle is not the owner');
    return null;
  }

  // `model` selects the FRAMEWORK, not an LLM. openclaw wants "openclaw".
  const { choices } = await agent.chat([{ role: 'user', content: message }], {
    model: 'openclaw',
  });

  return choices[0]?.message?.content;
}

Streaming yields content deltas:

async function streamChat(agentId: bigint, message: string) {
  const ag = await AgenticID.fromAttestor('https://agenticid.0g.ai', {
    account: process.env.PRIVATE_KEY as `0x${string}`,
  });

  const agent = await ag.agent.client(agentId);
  if (!agent.chatStream) return;

  for await (const delta of agent.chatStream([{ role: 'user', content: message }], {
    model: 'openclaw',
  })) {
    process.stdout.write(delta);
  }
}

Plain fetch, and owner-only logs

async function inspect(agentId: bigint) {
  const ag = await AgenticID.fromAttestor('https://agenticid.0g.ai', {
    account: process.env.PRIVATE_KEY as `0x${string}`,
  });

  const agent = await ag.agent.client(agentId);

  // fetch() attaches the bearer token when the route asks for auth.
  const models = await agent.fetch('/v1/models');
  console.log(await models.json());

  // logs() is owner-only, so it may be absent.
  if (agent.logs) {
    console.log(await agent.logs({ tail: 200 }));
  }
}

Choosing a handle

async function handles(agentId: bigint) {
  const ag = await AgenticID.fromAttestor('https://agenticid.0g.ai', {
    account: process.env.PRIVATE_KEY as `0x${string}`,
  });

  // client(): owner ops present when the key matches; accepts an id OR a url
  const auto = await ag.agent.client(agentId);

  // authenticate(): mint the owner token up front; fails without a wallet
  const owner = await ag.agent.authenticate(agentId);

  // connect(): explicitly public, never attaches a token
  const publicHandle = await ag.agent.connect(agentId);

  return { auto, owner, publicHandle };
}

Anti-Patterns

// BAD: expecting a proof from a chat route — chat is deliberately unsigned
const agent = await ag.agent.client(agentId);
const { proof } = await agent.fetchWithProof('/v1/chat/completions', { method: 'POST' });
// proof === null; call an /api/* service instead

// BAD: calling chat() without checking it exists
await agent.chat!([{ role: 'user', content: 'hi' }]); // undefined on a public handle

// BAD: passing an LLM name as the framework selector
await agent.chat(msgs, { model: 'claude-opus-5' }); // the LLM is fixed at deploy

// BAD: hardcoding the URL when the id resolves it
await fetch('https://8080-abc.art.0g.ai/api/summarize', { method: 'POST' });

// BAD: guessing paths instead of reading the manifest
await agent.fetch('/api/summarise'); // check agent.services for the real spelling

Common Errors & Fixes

ErrorCauseFix
proof is nullRoute is not a signed /api/* serviceCall a service from agent.services
agent.chat is undefinedPublic handle, or no chat route declaredBuild with account; check agent.routes
agent.logs is undefinedNot the ownerOwner key required
404 on a path you expectedPath guessed rather than readEnumerate agent.services / agent.routes
Agent unreachablePhase is not runningstart(sealId, …), then waitForRunning()
Chat rejects the modelPassed an LLM name, not the framework'sUse the framework selector, e.g. "openclaw"

Related Skills

  • Agent Reputation — redeem the proof this skill captures
  • Manage Agent — get an agent into running
  • Deploy Agent — mint and provision
  • Agent Accounts — keep the runtime funded

References

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.