Skip to main content

Build a personal agent

This guide separates the working SDK surface from the remaining roadmap.

Available now: discover and validate a company​

  1. Accept a company domain—not an arbitrary metadata URL—from the task.
  2. Call the discovery client.
  3. Choose only an interface and extension your runtime supports.
  4. Keep the returned issuer and endpoints attached to that verified company.
from personal_agent_protocol import DiscoveryClient

async with DiscoveryClient() as client:
company = await client.discover("example.com")
print(company.document.organization.name)
print(company.oauth_metadata.token_endpoint)

Do not send credentials during discovery. Python rejects private, loopback, link-local, and otherwise non-public resolved addresses by default. Server-side TypeScript callers should contribute a DNS-aware URL safety policy.

Available now: start or renew a signed-out session​

Resolve one pairwise identifier for each tenant, internal user, and exact verified company issuer. The store creates a random value atomically and returns the same mapping across restarts.

from personal_agent_protocol import (
build_session_assertion_claims,
resolve_pairwise_user_id,
)

user_id = await resolve_pairwise_user_id(
reactor,
tenant_id="application-42",
local_user_id="local-user-42",
company_issuer=company.oauth_metadata.issuer,
)
claims = build_session_assertion_claims(
client_id="https://agent.example/agent.json",
pairwise_user_id=user_id,
token_endpoint="https://auth.example.com/oauth/token",
)

Python provides SqlitePairwiseUserIdStore for local file-backed deployments. Distributed hosts contribute a transactional implementation through pap.pairwiseUserIdStore; TypeScript exposes the same Reactor contract.

The lower-level result is unsigned. SessionClient uses Reactor signer and DPoP-proof contributions to create fresh proofs and send the real token request. Those host services must keep private keys outside model context and tool arguments. See Signed-out sessions for the complete implemented boundary.

Lifecycle status​

The lifecycle, in Python and TypeScript:

  1. Implemented: start or renew a signed-out session;
  2. Implemented: sign in with Direct, Device, or Mediated Sign-In;
  3. Implemented: narrow scopes or a resource when refreshing with the Account Token;
  4. Implemented: browse with a Browser Session or open a conversation; planned: OpenAPI and MCP helpers;
  5. Implemented: confirm exact operation revisions for consequential actions;
  6. Implemented: revoke account access when the user signs out.

Hosts still provide the protected stores, keys, and user interface each step relies on. Track readiness on Protocol status.