Skip to content

Commit bcaffb4

Browse files
author
Alex Godoroja
committed
catalogue: io.pilot.agentphone v0.3.0
AgentPhone — a real US/CA phone number for agents (voice, SMS/iMessage, conversations) over REST. Managed app: the Pilot broker holds the master key and meters each user against a $5 budget. 4 signed platform bundles on prod R2; catalogue.json re-signed (verifies against the embedded catalogtrust key). Rebased on latest main + re-signed after an intervening catalogue update.
1 parent 64e6f33 commit bcaffb4

3 files changed

Lines changed: 311 additions & 1 deletion

File tree

Lines changed: 278 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,278 @@
1+
{
2+
"schema_version": 1,
3+
"id": "io.pilot.agentphone",
4+
"display_name": "AgentPhone",
5+
"tagline": "A real phone number for your agent — voice calls, SMS/iMessage, and conversations over REST",
6+
"description_md": "# AgentPhone — a real phone number for your AI agent\n\nAgentPhone gives your agent its **own real US/Canada phone number**: place and receive **voice calls**, send and receive **SMS \u0026 iMessage**, and hold threaded **conversations** with real people — all over plain REST. This is the managed Pilot front door: you bring **nothing** (no signup, no API key). Pilot holds one AgentPhone master key behind the broker and gives **each Pilot user a $5 budget**; calls and texts debit against it, and once it's spent the paid endpoints return `402 Payment Required` (reads stay free).\n\n## What you can do\n\n- **Call people.** `agentphone.place_call` with a `systemPrompt` runs an autonomous voice call — the phone rings in ~1–2s and the AI holds the conversation. Book a reservation, chase a shipment, return a missed call, or call another agent.\n- **Text people.** `agentphone.send_message` delivers over **iMessage** when both sides support it (unlocking threaded replies, tapback reactions, send effects, typing indicators, group chats) and transparently falls back to **SMS/MMS** otherwise — same call either way.\n- **Answer \u0026 follow up.** Poll `agentphone.list_number_messages` / `agentphone.list_conversation_messages` for inbound texts and `agentphone.get_call` for call transcripts — **no websockets required**.\n- **Manage your setup.** Buy/release numbers, create and tune agents (voice, model tier, system prompt, ambience), keep an address book of contacts, and attach numbers to agents.\n\n## How it works (no signup step)\n\nBecause this is the **managed** app, the AgentPhone account already exists behind the Pilot broker — you skip the `/v0/agent/sign-up` + `/v0/agent/verify` flow entirely. Just call the `/v1` methods below; the broker authenticates you as your Pilot identity, injects the master key, meters your spend, and forwards to `https://api.agentphone.ai`.\n\n**Async, poll-based (no streaming):**\n1. `agentphone.place_call` → returns a call `id` immediately; the call runs in the background.\n2. Poll `agentphone.get_call` every few seconds until `status` is `completed` or `failed`, then read `transcripts[]` (or `agentphone.get_transcript`).\n3. For inbound SMS, poll `agentphone.list_number_messages` with the `after` cursor and filter `direction == \"inbound\"`.\n\n## Critical gotchas (read once)\n\n- **You cannot call 911**, N11 numbers, or crisis lines — they're blocked. If your human has an emergency, tell them to dial directly.\n- **Released numbers are gone forever** — no refund for the unused month. Confirm before `agentphone.release_number`.\n- **Always use E.164**: `+14155551234` ✓ — never `(415) 555-1234` or `415-555-1234`. Assume `+1` for a bare US number and confirm if it matters.\n- **Inbound calls need hosted mode OR a webhook.** Create agents with `voiceMode: \"hosted\"` explicitly (the backend defaults to `webhook`, which fails inbound if no webhook is set).\n- **iMessage-only features** (reactions, send effects, typing, backgrounds, contact cards) are silently ignored on SMS — check the response `channel`.\n- **Don't spam.** Unsolicited bulk calls/texts are illegal and get the account suspended.\n\n## Cost \u0026 the $5 budget\n\nReads are free. Spending operations debit your per-user $5 Pilot budget: buying a number (**$3.00/mo**), placing a call (**per-minute**), and sending a text (**~$0.01–0.02**). When a call would overdraw, the broker returns `402` before anything is charged, and every response carries your remaining balance in the `X-Pilot-Credits-Remaining` header (micro-dollars).\n\nEvery method's parameters, kind, and latency class are discoverable at runtime via `agentphone.help`.\n",
7+
"vendor": {
8+
"name": "AgentPhone",
9+
"url": "https://agentphone.ai",
10+
"contact": "founders@agentphone.to",
11+
"publisher_pubkey": "ed25519:mvVzYABubZwOTzWWQA/TDbRLYkKzmD/x6k/w0nz+zHc="
12+
},
13+
"homepage": "https://agentphone.ai",
14+
"source_url": "https://github.com/AgentPhone-AI/skills",
15+
"license": "Apache-2.0",
16+
"categories": [
17+
"communication",
18+
"phone",
19+
"voice",
20+
"messaging"
21+
],
22+
"keywords": [
23+
"phone",
24+
"sms",
25+
"imessage",
26+
"voice",
27+
"calls",
28+
"telephony",
29+
"conversations",
30+
"agent"
31+
],
32+
"size": {
33+
"bundle_bytes": 5130424,
34+
"installed_bytes": 9363452
35+
},
36+
"compat": {
37+
"min_pilot_version": "1.10.0",
38+
"runtimes": [
39+
"go"
40+
]
41+
},
42+
"methods": [
43+
{
44+
"name": "agentphone.usage",
45+
"summary": "Account status: plan, phone-number hold limit (used/limit/remaining), and message/call/webhook stats. Call this first to orient in a session. Read-only; no charge."
46+
},
47+
{
48+
"name": "agentphone.usage_daily",
49+
"summary": "Daily usage breakdown for the last N days (max 365). Read-only."
50+
},
51+
{
52+
"name": "agentphone.usage_monthly",
53+
"summary": "Monthly usage aggregation. Read-only."
54+
},
55+
{
56+
"name": "agentphone.usage_by_number",
57+
"summary": "Usage broken down per phone number. Read-only."
58+
},
59+
{
60+
"name": "agentphone.usage_by_agent",
61+
"summary": "Usage broken down per agent over a period. Read-only."
62+
},
63+
{
64+
"name": "agentphone.list_voices",
65+
"summary": "List available text-to-speech voices (voice_id, voice_name, provider, gender, accent, preview_audio_url) across ElevenLabs, Cartesia, OpenAI, and platform voices. gender/accent/preview may be null — do not crash on missing fields. Use voice_id when creating/updating an agent. Read-only."
66+
},
67+
{
68+
"name": "agentphone.list_agents",
69+
"summary": "List your agents (phone personas: name, voiceMode, model tier, system prompt, attached numbers). You get one starter agent on account setup — ALWAYS list before creating another. Read-only."
70+
},
71+
{
72+
"name": "agentphone.create_agent",
73+
"summary": "Create an agent (phone persona). For AI-driven use pass voiceMode:\"hosted\" explicitly (the backend defaults to \"webhook\", which needs a configured webhook or inbound calls fail). systemPrompt is required for hosted. Pick a voice from agentphone.list_voices. Free (no telephony spend)."
74+
},
75+
{
76+
"name": "agentphone.get_agent",
77+
"summary": "Get one agent's full config and its attached numbers. Read-only."
78+
},
79+
{
80+
"name": "agentphone.update_agent",
81+
"summary": "Update an agent — only the fields you send change. Any create field is updatable (systemPrompt, voice, modelTier, …). Free."
82+
},
83+
{
84+
"name": "agentphone.delete_agent",
85+
"summary": "Delete an agent. Irreversible — clears the agent's references on its numbers/conversations/calls (those are NOT deleted). Confirm with your human first. Free."
86+
},
87+
{
88+
"name": "agentphone.attach_number",
89+
"summary": "Attach an existing number to an agent so the agent can call/text from it. Free."
90+
},
91+
{
92+
"name": "agentphone.detach_number",
93+
"summary": "Detach a number from an agent (the number is kept, just unassigned). Free."
94+
},
95+
{
96+
"name": "agentphone.list_agent_conversations",
97+
"summary": "List an agent's conversation threads, newest activity first (data[], hasMore, total). Read-only."
98+
},
99+
{
100+
"name": "agentphone.list_agent_calls",
101+
"summary": "List an agent's calls (data[], hasMore, total). Read-only."
102+
},
103+
{
104+
"name": "agentphone.list_numbers",
105+
"summary": "List your active phone numbers (id, phoneNumber, country, status, agentId). Read-only."
106+
},
107+
{
108+
"name": "agentphone.buy_number",
109+
"summary": "Provision a new US/CA phone number. COSTS $3.00 from your $5 Pilot budget (402 if it would overdraw). The provisioned number is saved to this host's ~/.pilot/.agentphone so you can recall it later with agentphone.mynumber — no need to store it yourself. Optionally attach to an agent and request an area code."
110+
},
111+
{
112+
"name": "agentphone.get_number",
113+
"summary": "Get one phone number by id (any status, including released). Read-only."
114+
},
115+
{
116+
"name": "agentphone.release_number",
117+
"summary": "Release (delete) a number. IRREVERSIBLE — the number returns to the carrier pool; no refund for the unused month. Confirm with your human first. Free to call."
118+
},
119+
{
120+
"name": "agentphone.list_number_messages",
121+
"summary": "List messages on a number (inbound + outbound), newest first, cursor-paginated. THE non-websocket way to detect SMS replies: poll with the `after` cursor and filter direction==\"inbound\". Read-only."
122+
},
123+
{
124+
"name": "agentphone.list_number_calls",
125+
"summary": "List calls on a number. Read-only."
126+
},
127+
{
128+
"name": "agentphone.get_contact_card",
129+
"summary": "Get the iMessage contact card shown on a number (firstName, lastName, displayName, hasAvatar). iMessage only. Read-only."
130+
},
131+
{
132+
"name": "agentphone.set_contact_card",
133+
"summary": "Create/replace the iMessage contact card on a number (name + avatar shown to recipients). iMessage only. Free."
134+
},
135+
{
136+
"name": "agentphone.delete_contact_card",
137+
"summary": "Remove the iMessage contact card from a number. Free."
138+
},
139+
{
140+
"name": "agentphone.send_message",
141+
"summary": "Send an SMS/iMessage. COSTS MONEY (~$0.01–0.02, debited from your $5 budget → 402 if over). Auto-delivers over iMessage when both sides support it, else SMS/MMS — the response `channel` (sms|mms|imessage) tells you how it went. E.164 for `to_number` (or a group id grp_… for an iMessage group). iMessage-only extras (send_style, reply_to_message_id) are silently ignored on SMS."
142+
},
143+
{
144+
"name": "agentphone.react",
145+
"summary": "Send a tapback reaction to a message. iMessage ONLY — returns 400 on SMS. Free."
146+
},
147+
{
148+
"name": "agentphone.list_calls",
149+
"summary": "List calls for the account (filter by status/direction). Read-only."
150+
},
151+
{
152+
"name": "agentphone.place_call",
153+
"summary": "Place an OUTBOUND voice call. COSTS MONEY (per-minute, ~$0.05+, debited from your $5 budget → 402 if over). With `systemPrompt` the AI runs the call autonomously (recommended); without it, each turn is POSTed to the agent's webhook. Returns a call id IMMEDIATELY (async) — the phone rings in a second or two. Then POLL agentphone.get_call every few seconds until status is completed/failed to read the transcript. Cannot call 911 / N11 / crisis lines (blocked)."
154+
},
155+
{
156+
"name": "agentphone.get_call",
157+
"summary": "Get a call and its embedded transcripts[]. THE poll target for a call outcome (no websockets): call every few seconds until status is completed or failed (in-progress means partial/empty transcript). Also carries durationSeconds, startedAt, endedAt. Read-only."
158+
},
159+
{
160+
"name": "agentphone.end_call",
161+
"summary": "Terminate an in-progress call. status/endedAt settle shortly after via the provider — keep polling agentphone.get_call until terminal. Free."
162+
},
163+
{
164+
"name": "agentphone.get_transcript",
165+
"summary": "Get the full ordered transcript of a call as plain JSON (user utterance + agent response per turn). This is the REST/polling alternative to the SSE live-transcript stream — the adapter never uses the stream. Read-only."
166+
},
167+
{
168+
"name": "agentphone.list_conversations",
169+
"summary": "List conversation threads (one per external contact or iMessage group), sorted by lastMessageAt desc (data[], hasMore, total). Read-only."
170+
},
171+
{
172+
"name": "agentphone.get_conversation",
173+
"summary": "Get one conversation with its recent messages (participant, isGroup, group roster, messageCount, metadata). Read-only."
174+
},
175+
{
176+
"name": "agentphone.update_conversation",
177+
"summary": "Update a conversation's `metadata` (attach custom AI context/state to the thread). Free."
178+
},
179+
{
180+
"name": "agentphone.list_conversation_messages",
181+
"summary": "List a conversation's messages, cursor-paginated (data[], hasMore). Poll with `after` to catch new inbound replies in a thread. Read-only."
182+
},
183+
{
184+
"name": "agentphone.typing",
185+
"summary": "Show a typing indicator before you reply. iMessage only, best-effort, auto-expires (no stop call). Free."
186+
},
187+
{
188+
"name": "agentphone.set_background",
189+
"summary": "Set a chat background image for a conversation. iMessage only. Free."
190+
},
191+
{
192+
"name": "agentphone.clear_background",
193+
"summary": "Clear a conversation's chat background. iMessage only. Free."
194+
},
195+
{
196+
"name": "agentphone.list_contacts",
197+
"summary": "List saved contacts (data[], hasMore, total); `search` filters by name/phone. Read-only."
198+
},
199+
{
200+
"name": "agentphone.create_contact",
201+
"summary": "Save a contact so you can look them up by name later. phoneNumber is normalized to E.164; returns 409 if the phone already exists. Free."
202+
},
203+
{
204+
"name": "agentphone.get_contact",
205+
"summary": "Get one contact by id. Read-only."
206+
},
207+
{
208+
"name": "agentphone.update_contact",
209+
"summary": "Update a contact — only the fields you send change (phone is re-normalized; 409 on conflict). Free."
210+
},
211+
{
212+
"name": "agentphone.delete_contact",
213+
"summary": "Delete a contact. Confirm with your human first. Free."
214+
},
215+
{
216+
"name": "agentphone.get_webhook",
217+
"summary": "Get the account-level webhook config. Read-only. (Polling is the default event model for this adapter; webhooks are optional.)"
218+
},
219+
{
220+
"name": "agentphone.set_webhook",
221+
"summary": "Set the account-level webhook URL (returns a signing `secret`; a new one each call). NOTE: on the shared Pilot AgentPhone account this is a GLOBAL setting — prefer per-agent webhooks or polling. Free."
222+
},
223+
{
224+
"name": "agentphone.delete_webhook",
225+
"summary": "Remove the account-level webhook. Global on the shared account — use with care. Free."
226+
},
227+
{
228+
"name": "agentphone.list_webhook_deliveries",
229+
"summary": "List recent webhook delivery attempts (items[], total). Read-only."
230+
},
231+
{
232+
"name": "agentphone.webhook_delivery_stats",
233+
"summary": "Aggregated webhook delivery stats over the last N hours (success/failed/pending, byEventType, byHour). Read-only."
234+
},
235+
{
236+
"name": "agentphone.test_webhook",
237+
"summary": "Send a synthetic test event to verify your endpoint is reachable and verifying signatures. Free."
238+
},
239+
{
240+
"name": "agentphone.get_agent_webhook",
241+
"summary": "Get an agent-specific webhook (overrides the account default for that agent). Read-only."
242+
},
243+
{
244+
"name": "agentphone.set_agent_webhook",
245+
"summary": "Set an agent-specific webhook URL (overrides the account default for THIS agent only — safer than the account-level webhook on a shared account). Free."
246+
},
247+
{
248+
"name": "agentphone.delete_agent_webhook",
249+
"summary": "Delete an agent-specific webhook (the agent falls back to the account default). Free."
250+
},
251+
{
252+
"name": "agentphone.mynumber",
253+
"summary": "Recall the phone number(s) THIS daemon provisioned (local, no backend call, free). Reads ~/.pilot/.agentphone, populated automatically by agentphone.buy_number. Returns {entries:[{id,phoneNumber,status,agentId,...}]} — empty if this host hasn't provisioned one yet. Use it to find 'my number' without listing the shared account."
254+
},
255+
{
256+
"name": "agentphone.help",
257+
"summary": "Discovery: every method with params, kind, and latency class."
258+
}
259+
],
260+
"changelog": [
261+
{
262+
"version": "0.3.0",
263+
"notes": [
264+
"Released v0.3.0"
265+
]
266+
}
267+
],
268+
"links": [
269+
{
270+
"label": "Source",
271+
"url": "https://github.com/AgentPhone-AI/skills"
272+
},
273+
{
274+
"label": "Website",
275+
"url": "https://agentphone.ai"
276+
}
277+
]
278+
}

catalogue/catalogue.json

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -500,6 +500,38 @@
500500
}
501501
},
502502
"publisher": "ed25519:Lmf0vzz0CNPu94pbqsbD/ueSuOaKsGc0xU/DoL+Yu7c="
503+
},
504+
{
505+
"id": "io.pilot.agentphone",
506+
"version": "0.3.0",
507+
"description": "Give your AI agent a real US/Canada phone number: place and receive voice calls, send and receive SMS/iMessage, and hold threaded conversations — all over REST, metered per user against a $5 budget.",
508+
"display_name": "AgentPhone",
509+
"vendor": "AgentPhone",
510+
"license": "Apache-2.0",
511+
"source_url": "https://github.com/AgentPhone-AI/skills",
512+
"bundle_url": "https://pub-f09f9a4ea848491198d48e329ba030e3.r2.dev/bundles/io.pilot.agentphone/0.3.0/io.pilot.agentphone-0.3.0-linux-amd64.tar.gz",
513+
"bundle_sha256": "7b7792c7df26be0a1f8bf516b46d4629a31a975fbc4b7586555688cb735471a0",
514+
"bundles": {
515+
"darwin/amd64": {
516+
"bundle_url": "https://pub-f09f9a4ea848491198d48e329ba030e3.r2.dev/bundles/io.pilot.agentphone/0.3.0/io.pilot.agentphone-0.3.0-darwin-amd64.tar.gz",
517+
"bundle_sha256": "155c5413edd960932d9d70421e7f80d8f6a5f35f492d723e98f3d02a52e9c53d"
518+
},
519+
"darwin/arm64": {
520+
"bundle_url": "https://pub-f09f9a4ea848491198d48e329ba030e3.r2.dev/bundles/io.pilot.agentphone/0.3.0/io.pilot.agentphone-0.3.0-darwin-arm64.tar.gz",
521+
"bundle_sha256": "93e4a0c334d45de63c7d96befed9af8a1aa7fb841f54a4d137ec679331a32f6a"
522+
},
523+
"linux/amd64": {
524+
"bundle_url": "https://pub-f09f9a4ea848491198d48e329ba030e3.r2.dev/bundles/io.pilot.agentphone/0.3.0/io.pilot.agentphone-0.3.0-linux-amd64.tar.gz",
525+
"bundle_sha256": "7b7792c7df26be0a1f8bf516b46d4629a31a975fbc4b7586555688cb735471a0"
526+
},
527+
"linux/arm64": {
528+
"bundle_url": "https://pub-f09f9a4ea848491198d48e329ba030e3.r2.dev/bundles/io.pilot.agentphone/0.3.0/io.pilot.agentphone-0.3.0-linux-arm64.tar.gz",
529+
"bundle_sha256": "c40b977bd0e1b28d770911c97bb0bfe342bd6ebe1a375c583e4c440c6836ff78"
530+
}
531+
},
532+
"metadata_url": "https://raw.githubusercontent.com/pilot-protocol/pilotprotocol/main/catalogue/apps/io.pilot.agentphone/metadata.json",
533+
"metadata_sha256": "9099d15e6008aaf0506c4dc91607644b201a866f78f5db2343f85413de7a6ee1",
534+
"publisher": "ed25519:mvVzYABubZwOTzWWQA/TDbRLYkKzmD/x6k/w0nz+zHc="
503535
}
504536
]
505537
}

catalogue/catalogue.json.sig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
3DeVcBPvNNP7146Rx6m5jkrwFpDx/SB+avfZ1bQ6YuWNZL+FDRVi55HAie2Vz59l2wxgkL+MQAyZ61GM/BGMBA==
1+
JSE0qc5am6jEvuxcidIfsN6uuYZIYaYK3Zgnxszzk/cxmQB9rXE2Zaq0BQg8lESqGtB+CWDICHsRj6mSTBdrAQ==

0 commit comments

Comments
 (0)