An app can contain specialists: agents that take whole tasks in its field and report back. The app publishes them in its manifest, Caroline starts and follows them, the owner is asked when an agent needs a decision, and A2A lets outside systems call them too.
Declaring an agent
Agents are an array in the same manifest. The manifest is the approval: what an agent declares is what it may do, and nobody clicks anything.
An agent in a manifest (example)| Field | Meaning |
|---|---|
description | Required. One line telling Caroline what the agent is for |
skills | At least one: name, description, input (same types as tools; a trailing ? marks an optional parameter), output (text or json), long, confirm |
host | Where the agent answers. Exactly one of: {"service","endpoint"} (an endpoint of the app's service that allows the agent caller), {"mcp": id}, {"page": true} (the app's page over /appws), or {"a2a": card-url, "key": name} for a remote A2A agent |
permissions | System access beyond the app's own data: files.read, files.write, net.status, net.manage, settings.read, settings.write, notifications.read, notifications.post, sound, vibration, message_box, apps.open. Absent means none |
camerlengo | The owner's Camerlengo commands the agent may call through the shell, charged to the owner's wallet. Absent means none |
a2a | expose, confirm, tags; see below |
How an agent solves a task is its own business. The format has no model field, so an agent may be a script, a service calling an AI model or a remote system.
Tasks and their life
The broker in the shell keeps a registry built from manifests and runs every agent call as a task.
- Questions to the owner. An agent can ask with a set of choices. Caroline relays the question and the answer. An unanswered question fails the task after 600 seconds.
- The journal records each task, and totals of calls and spend are kept per agent.
- Caroline's
agentsgroup:agent_list,agent_start,agent_status,agent_answer,agent_cancel. - Apps' pages may not command agents. Settings shows the list read-only.
Calling the owner's cloud
An agent that needs the owner's cloud service (speech recognition, mail, other AI commands) never holds credentials. It calls the shell, which adds the owner's session and key, runs only the commands the manifest lists, and journals the call: agent, command, outcome, cost. Parameters and results are never written to the journal.
Errors come back as a kind with a status: network 503, auth 401, balance 402, config 500, service 502. A command that isn't in the manifest answers 403.
A2A: open an agent to the outside
"a2a": {"expose": true} publishes the agent over the open A2A 1.0 protocol. The shell serves an Agent Card and JSON-RPC (SendMessage, SendStreamingMessage, SubscribeToTask, GetTask, CancelTask, ListTasks) on its A2A listener.
- Naming the skill. An agent with one skill needs no name: the text goes to its string parameter, as above. With several skills, send a data part,
{"data": {"skill": "plan_week", "input": {"focus": "the launch"}}}. - Results. A
textskill returns its text as an artifact; ajsonskill returns a data part. A skill markedlongis waited for unless the call asks to return at once. - Give clients the address with the closing slash. A client that resolves the card path as a URL otherwise drops the last segment.
- Skills marked
confirmare not offered outside unlessa2a.confirmis true. An agent whose every skill is markedconfirmcan't be exposed without it. - No port, key or address is ever written in a manifest.
A2A: use someone else's agent
A remote A2A agent can be installed like a local one. Its card gives the skills, and Caroline commands it like any other agent.
key is the name of a key kept in the device's key file, never the key itself. A remote agent has no camerlengo and no permissions, and can't be exposed again. What Caroline gives such an agent leaves the device, so she treats it like any outside party.
