For the complete documentation index, see llms.txt. This page is also available as Markdown.

Agent access

A human owns the lab and never hands over a key: the agent gets its own wallet, the human grants it Contributor, the agent issues its own token.

The most common real-world shape: a researcher created their Lab in the Labs app with an email address β€” no wallet, no code β€” and now wants an agent contributing to it. The agent gets its own identity rather than borrowing the human's; the human grants it a role; the agent authenticates itself from then on.

Before you start: you need the two prerequisites β€” a mol_ consumer credential and a funded Base Sepolia wallet β€” plus the shared setup block, which defines the config constants and the graphql() / assertOk() helpers every snippet below uses. The complete script at the end of this page carries all of it inline and runs standalone. Unfamiliar with a term used here? See the Glossary.

Who does what:

#
Actor
Action

1

Agent

Generate a wallet and report its address

2

Human

Add that address to the lab as Contributor, flagged as an agent, with an expiry

3

Agent

Self-issue a service token by signing the sign-in message

4

Agent

Upload files; the human sees the result in the app

The human never hands over a private key, a token, or their session. Revoking the agent is one onchain revoke, and it does not touch anything else.

Three addresses are in play here β€” the human's owner wallet, the agent's own wallet, and the Lab's own OCL account β€” and they are not interchangeable. If you are unsure which goes in which field, read the three wallets, side by side first.

Step 1: The agent reports its address

With the plugin: run wallet_address. With viem:

import { privateKeyToAccount, generatePrivateKey } from "viem/accounts";

// Generate once, store it as the agent's own secret β€” never the human's key.
const agentPrivateKey = process.env.AGENT_PRIVATE_KEY ?? generatePrivateKey();
const agentAccount = privateKeyToAccount(agentPrivateKey);
console.log("Agent wallet address:", agentAccount.address);

Give that address to the lab owner. The agent needs no gas for this tutorial β€” it never sends a transaction, only signs a message. (Persist agentPrivateKey if you generated it, or the next run is a different agent with no role.)

Step 2: The human grants Contributor

In the Labs app, the lab owner adds the agent's address to the lab's members and grants it the Contributor role, setting:

  • isAgent = true β€” informational metadata that marks the member as an agent identity in the members list and UI. It does not change authorisation.

  • an expiry β€” typically the agent's session lifetime. When it lapses the agent loses access until it is re-granted; a permanent grant is possible but not the default you want for an agent.

Members can be invited by wallet address, ENS name or email, and the app sponsors the gas for the grant. Under the hood this is one onchain call on the AccessResolver, which the owner (or an existing Contributor, for Viewer grants) can also make directly:

Only the Owner may grant Contributor. Contributors can grant Viewer, but not Contributor. Full capability matrix: Roles & Permissions.

Why Contributor and not Viewer: a Viewer can decrypt and read but cannot write. Uploading files needs Contributor.

Both parties can confirm the grant landed with a public query β€” no authentication beyond the consumer credential:

Expect role: "CONTRIBUTOR". isAgent simply echoes the flag the owner set β€” false there changes nothing about what the agent may do, so do not treat it as a failed grant. expiry is unix seconds as a decimal string, or null for a permanent grant. Expired grants are excluded from this list entirely, so a missing entry after a while means the grant lapsed.

Step 3: The agent self-issues a service token

Identical to Step 1 of Create a lab and upload a public file, signed by the agent's wallet. Fetch the message and redeem it in one go β€” it embeds a single-use nonce valid for 10 minutes, so an agent that waits for the human's role grant between fetching and signing will hit UNAUTHENTICATED / reason: NONCE_EXPIRED. Poll for the grant first (Step 2), then sign in:

Issuance is not gated on holding a role β€” any wallet can mint a token for itself. The role is what makes the token useful: authorisation is resolved per request from the token's wallet against the lab you name. So a token issued before the grant lands keeps working once it does; you do not need to re-issue it.

Step 4: The agent uploads

From here the agent is an ordinary caller. Run Step 4 of Create a lab and upload a public file with changeBy: agentAccount.address, or Upload an encrypted file for a confidential file β€” the hasRole branch of the team conditions is exactly what lets the agent decrypt too.

Writes by a Contributor service token are gated per mutation, matching the Privy user path: initiateCreateOrUpdateFile, finishCreateOrUpdateFile, deleteDataRoomFile, updateFileMetadata and moveEntry all accept Contributor. A few surfaces remain Owner-only and an agent Contributor cannot reach them: updateLabNftMetadata, generateLabImageUploadUrl and the legal-agreement mutations.

Step 5: Verify from both sides

The agent verifies as in Step 5 of Create a lab and upload a public file β€” the file is in dataRoom.files with createdBy set to the agent's address:

The human verifies in the app: the file appears in the lab's data room, attributed to the agent's address, which the members list shows flagged as an agent.

Revoking the agent

One onchain call, and the agent's writes stop:

Or let the grant's expiry lapse. Independently, the agent's token can be killed with revokeServiceToken(tokenId) β€” a token can only revoke or extend its own record, so one agent cannot interfere with another's.

Complete script

The agent's half of the flow, standalone: report the wallet address, wait for the human's grant to appear, self-issue a token, upload, verify. Steps 1 and 2 involve a human, so the script polls for the role rather than assuming it.

Run it with the agent's own key and the oclId of the human's lab β€” the agent never sees the owner's key.

Usage:


Next

The role model in full

Let the agent run the whole workflow as tool calls

Need help?

Ask the team on Discord. Reporting an API error? Include the requestId from the failing response so we can trace it.

Ask on Discord

Page wrong, unclear or missing something? Let us know with Was this helpful? on this page.

Last updated

Was this helpful?