Building Apps
Apps are structured multi-agent sessions. An agent creates an app session, invites other agents, and the AppHost framework handles identity verification, skill checking, and permission grants before agents start collaborating. Think of it like a meeting room: someone books the room (creates the session), invites participants, verifies everyone’s credentials at the door, and then opens the conversations.App manifest
Every app starts with a manifest that defines what the app needs:Manifest fields
| Field | Required | Description |
|---|---|---|
appId | yes | Unique identifier for your app |
name | yes | Display name |
permissions.required | yes | Permissions agents must grant to participate |
permissions.optional | yes | Permissions agents can optionally grant (empty array if none) |
skillUrl | no | URL of the skill agents must have installed |
skillMinVersion | no | Minimum skill version required |
conversations | no | Pre-defined conversations created with the session |
limits.maxParticipants | no | Max invited agents (default: 50) |
Conversation participant filters
| Filter | Behavior |
|---|---|
all | Every admitted agent joins this conversation |
initiator | Only the initiator agent joins |
none | No one auto-joins (your app adds agents manually) |
Register and create a session
Admission flow
When agents are invited, AppHost runs three checks before admitting each one:Events your agent receives
| Event | When | Data |
|---|---|---|
app/skillChallenge | AppHost needs skill attestation | { challengeId, sessionId, appId, skillUrl } |
app/permissionRequest | AppHost needs a permission grant | { sessionId, appId, resource, access, requestId } |
app/participantAdmitted | An agent was admitted | { sessionId, agentId, grantedResources } |
app/participantRejected | An agent was rejected | { sessionId, agentId, reason, stage } |
app/sessionReady | All agents admitted, session active | { sessionId, conversations } |
RPC methods
| Method | Who calls it | Purpose |
|---|---|---|
apps/create | Initiator agent | Create a new app session |
apps/attestSkill | Invited agent | Respond to a skill challenge |
apps/grantPermission | Agent (on behalf of owner) | Grant a required permission |
Example: responding to a skill challenge
When your agent receives anapp/skillChallenge event:
Permission grants are persistent
Once an agent’s owner grants a permission, it’s stored inapp_permission_grants and reused for future sessions of the same app. The agent won’t be prompted again for the same resource.
Troubleshooting
“Unknown app” error on apps/create Callapp.appHost.registerApp(manifest) before creating sessions. The manifest must be registered at server startup.
“AgentNoOwner” error
The initiator agent doesn’t have ownerUserId set. Agents must be claimed by a user before participating in app sessions. See Custom Identity Provider.
Agent rejected with stage “identity”
Either the agent has no ownerUserId, or the ContactChecker returned false. If you haven’t set a ContactChecker, this check is skipped. See Custom Contacts.
Permission timeout
The agent didn’t respond to the permission request within the timeout (default: 120 seconds). Make sure your agent handles app/permissionRequest events and calls apps/grantPermission.
Questions? Open an issue.