From 2e275e1af23320a4c1e26d439ea8f159f2e1b935 Mon Sep 17 00:00:00 2001 From: Alex Godoroja Date: Sat, 29 Aug 2026 17:06:38 -0700 Subject: [PATCH 1/2] =?UTF-8?q?app-store:=20add=20General=20Legal=20?= =?UTF-8?q?=E2=80=94=20attorney=20contract=20review=20+=20Delaware=20forma?= =?UTF-8?q?tion?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds io.pilot.generallegal to the app store: a licensed US law firm's contract review API plus Delaware company formation, in one namespace. - app record from the app-store metadata API snapshot (19 methods) - category: work (Work & Research) — real-world work with human hands on it - pinned first in New & Updated - vendor icon from general.legal, plus the 96/240 webp variants Also carries per-method pricing through to the store page. The metadata already had a `gated` field, but gated means "your plan does not include this"; these methods work and charge you. Conflating the two misleads in both directions, so methods now carry a separate `billable` string and the app page renders a distinct `paid` badge with the price. Five methods spend money and say so: formation_start_llc, formation_start_c_corp, deal_open, document_upload, thread_post. The plain twin's sha is re-stamped rather than regenerated: regen-plain needs GEMINI_API_KEY, and the only source change is one id added to the freshPinned array, which the plain page (static prose, no app data) cannot render. Re-run regen-plain if you'd rather it be regenerated. --- public/appicons/io.pilot.generallegal.png | Bin 0 -> 5103 bytes .../optimized/io.pilot.generallegal-240.webp | Bin 0 -> 1754 bytes .../optimized/io.pilot.generallegal-96.webp | Bin 0 -> 916 bytes scripts/gen-apps.mjs | 4 +- src/data/app-metadata.json | 903 ++++++--- src/data/apps.ts | 1723 ++++++++++++----- src/pages/app-store.astro | 2 +- src/pages/apps/[id].astro | 2 + src/pages/plain/app-store.astro | 2 +- src/styles/appstore.css | 6 + 10 files changed, 1873 insertions(+), 769 deletions(-) create mode 100644 public/appicons/io.pilot.generallegal.png create mode 100644 public/appicons/optimized/io.pilot.generallegal-240.webp create mode 100644 public/appicons/optimized/io.pilot.generallegal-96.webp diff --git a/public/appicons/io.pilot.generallegal.png b/public/appicons/io.pilot.generallegal.png new file mode 100644 index 0000000000000000000000000000000000000000..590aa14caa42f79ab99117a6498911d5edba5090 GIT binary patch literal 5103 zcmXw7byQT}_nl#2$dRt0h7wV_hLTVk1f-=wM23>?7`jVBqy%9A$sr{KMg%EoNlB3w z0ZGa4`>fyk{qbVmckVfNz4!J$d*3)+ZB-ZvoCE{{!PM21^nfewzk>)0ob?u*2|*wV zkh+qhfgkvHK5-CihP5vg8Ji_AP1Gc>Sv{p!O*d86jELpVefTtGHs0WeNxZ{{U}AFh z-)XVj;U(q9-!nM{$m7QaFR+2)r3@*OKzBSb_ijC1^KqIX5R$oMcS zy{pX3$IY~#5|KY`0hbOZ5|sxX8o2fdJH($ zi_FRyA&1$%Y`6p)(siLxXJdwk8!>nGYT;8H%4U^_l{J33#ys=B^anBpyPJz$y01FK zUt-7NTKu*}p8R|-6m~=}U~`^5DrB?coZ4KE;m8LQja8d{tg}`pYdeO=QuF9U+(vZZwbj!U-N?~FLunZ>Dq6&u_bW#Jb#O0j~*C){KT>J}ZRGICdb zvUjy}BbIMlw9{MElvYx9Lv1IHLphaXRxy?SR8d)|dxH$<`od~?izf`_doYJug~^s! z9=EGsyq}QH86g-R<+_KBdQilN?P!fWAGxv0+e=A|#fw6ec@HH57I4BAZFoqmv4k@i z0da|27@pgYo}IsRdc_so#pe6xz#r`HZqL4T+opBAyMZvxIk$$jxUKcy0>97jo*R9=L!Wd7fSo1eN476UIdT z9BgtDi%ST@k9F^2|8h9KMO@ha2`aIkQIUxRJ-s;k3ga_x#%tRBsLgoSX~vt= z$GwT~x~%>6ZNnzk8b!7v;TV-|c!=1Ls(ls&D-}YsaC+A>P>ImF1O?d6#=5uh`UGFH zB)^lbz9mW!c<0etW2G{Z2yy4Kx7xd)BYjhYBP^C1e|zV~O-#VN#jejK-dLXzO;c2< zq?*j4`s+0VeoUmJFIU9Mcqb{`-%II>y`?$pm%=cKTbCqS;Un^`+S_nZ+d~g#sQ_kP z-Vc$p2EATTwb~K>y`Jo5`>ukADd}Y)<7fDdFV;LR()hF;0yWzbG{0??4fP1|^FK87 z>_9ewzi}Jhoja&D1|j7TTyw0{RhBdb1HqL zg9?Z;VJz4~BlV4O4v0ws^-uCVkBY(-lsgGxjC<+`6 z8_1T(`O3C3J9@I|{sKt<<#69=t#27=+_GsHDCq*}zhS=mfdmOkI-BhD6x2nwU(4S_ zI(6L^{o2Co&diVn!3EM9uUBy?L~yG2zSyF=NTnG51rR=31y)+OmK$)fO|BDb!kk21 z=BI0J`#jp?s)sjH&@{OqIJz*(n4T}$lo$?r7QIjc{0;agqKl0$n99>-!rpgu>!>Cl z;#zzZPK^mH_e(LWW2?ms6tZ}%ENweEt~VY`HCDI!6ceNU`wWfL&M^l+~4qbkMx1-|w5rqw;+oR7y) zY=Y(k*`x!Ci#ac^t*e@wD&7m{ccZnoL_wInx7*;Dl7W^{d$d?<^_bA7Z;rlju;heN@2;FTj87+#odQk$%!v}UyAur$JUNSy1o`jdN1 z_PMEejS>A?g^%{Idf-`+>buVloAl^9>eAganyrf0o~9qQA9zjK|1e%g82o?){yUqf zo!--)-}M3|yXyKwC{i;r447rT@F(qKiao7EKdo&?@HT90Kc5?mV+@WNN~cEnsD{dc zrJG+Z%$tS&qI|e_i1z7<&X)I2`pa)a0-3FQZGG$(9ZYz~=6lP4U(-{~@2)Fha{Ixt z%0sq?i%Zv%?tjHX{+%$7ShSS0X^fv|83}r+J=Tha3BPBj2qb4HZK#|agK$3P3CpH3 zvvuBdi3Wg+C`NEi*RAnj#R9}HU@XZWO}#)#LDN;$Z1a9+N@mL-0XRfwpA~VpXJaob zztQQ8laiK+&{ma9)I)sor9RV&&7<+`?5;ei%H@)xG93@8#CMIkNj;IX*}+kxE!rj{ zAV%=PODAgGe$X^sd;>BX=<^IU=9L@(EaQoKZQzdqtwCm7V@L@gSUK{iP!c;JB%&*y zJFU-?aUzny=H}+dhv@qmf}{c)FLXa;GpRX!ncm{5G9iJ`+&7`nmt%=~;#7>aS?3VA zYmem(k+Rofj_8gekz1{B{5BKCwDR`qU!8 z%Pk+b0+>VLisCgl5BBq;Yd!i|C% z?MeK5(U;P0|6~d~#o7 zuPpK8Ax45Qmp?Kq0|ZM-3pyR|E0Gz?LEpE-S!$Yc=ooqGGf;RL!30knyX zax{U>+z3=4-o{8anl-=Uq&ldz9`kf3>gT;bf1qc!%Bx0=u|_0jjWpwoG=dwYqU;il zJij-VDLqR=DjF_*cA<%P7%N1%n|o$c#Sd>Yr7wGFp#AwW^cBXzlmJ`X4qP$L)(b%Q z2~HmMhGwK!K$;tRhf#rz^~Mz@tPz(d-Smg!CU80Go)*(g4WM&YTSc#DA{7?rnQ=;1%;L7Ep0WoNX8&Vfb)JaeuMti+T=^ z|2cVNSt9svTieeQV=Kk}O9)m^#@#~97rqqKF#;hz#NVVsJmGk$Ga=4+c%xuZEbISQ z5*f?fc((&=-bCAFc;rh#&l0vy+I{@|(p0=6XM;hEa9+LPUiE>XVQsvkVpyBXt}$Pv z>f}d2a8du_#7pZ3g{qz#EPe7Tifs2;FQxWzHjQ|Z)}Y&EX+gtl9;@Sc`;}`^MjCZD zX=&{A+c@dwO69QAu`pUqbHbnv-GnX?!8MG^McjRb?BQVxMMq{PG&!9;e~R%SXqol< zMfBtW=4Q@W;@W<#YM@BXyhCZG5w-SF0a7%O5laIttdy|0mPWWwQ7MhQO~ko&-m|Jn z)XJ00Vy3ufT-qr2*Gg%YYp+B~WBI|DA%@vt8>T|;5$9vKI2O8HKfW<+Joo+AD2X@|qOFA3~iIyR;P~2VuH=@m30_{N15?ln}^wFW` z+Izq}DLugLk#ggp6!Gtv=$`<%H3hp`-2;a~DRPj=5qvLzRaqdnFAecZ#X;Baa{}0D z1q^ieEsUDI)H5EK!Pi@5vlQnT_pp24plHD>rdubrVOBkMN*|f(j@NVY5(~y zul)t$SDiN%oxR1?j7h-*>(6A9!F%E;9d%AQue1F~;^&VQ^0V%yFcqB*NldbS20nR6 zsodVf!{O&5DV8EO;xUI~Zkb4QpfEB> z#F4>X`;KxE9sz3(myQ=R*j6h>S{T4|q3hjPPGAG{&8tUMBtsI^Fz7MxKkkZsMRQ|w)d^WS^pv?9N2>&5S} z?$hnS3Iaj0|Jw@~#Mr`hM?eAs0uKAzVg8~#g^4~Wef6EYBspT)@<*bLE^}G~l}Z|n zXlNJ9sil=xzL05q{g*Z9z|Ufj`HswO>OOQMdy+_kX0tzFL0CtGe12UrNFP`g)L_%Oj(qjXBUNZb$dB|U%(+=TmD>YT{O2)*YZ0Fn5iTzh z^zTE)Qm|X}c@g1wY4TQbb0+Sxb6lzNp>o#)a+6;}$=Y(>3_FrN(*k6Uv&8rEQx1T~ zru&l1axJ3mhB8Sw6>=`T9b*ojQF~XrNaSKoCXjqlU`M0c@P6!o!}mhVi`nxIVq!5@ z12!*L)zR=&_J^y`!gq6D`BQKS$M?ACS6BNB<32nud1zy zUb<^{h^~-b1>=2JMCmT02}@-H!`&cb)CBqYVjp=3!#?hG3CL2cLR-B4Ay+9RLBjX~ zmQ=MJZVu@Q;W@)Fh!(o?-08{0eXjMvUV=ZAqUb-$=H z$;CePYwm`n=H(@ls|1JR3ayT?72%E1qIMWT4~ zn0g@DpazfXN`>m7Jg{4Ldn=ibi2-h)|6vpY60YiVc`HcP4UB-)m9>>>9$AO~59ozf A3jhEB literal 0 HcmV?d00001 diff --git a/public/appicons/optimized/io.pilot.generallegal-240.webp b/public/appicons/optimized/io.pilot.generallegal-240.webp new file mode 100644 index 0000000000000000000000000000000000000000..489b4e7e3639ec71b1ef51bc8c8a770de84bc977 GIT binary patch literal 1754 zcmV<01||7YNk&G}1^@t8MM6+kP&gpQ1^@t1FaVtaD)0dC06sAoibEnHp%)oU03ZVd zv$uRNq=A|SV9K5gVOMsC%yEd@`_HQSU+O>gUdR8p^ilTxBENBeAK>NSzrVlXeFguC z|8xAO{Ho;R03VHiMgMPX`ec4WewY8R?i2jW`tSTc$DWNO#0`!V1DXW^gPTGbJvpEJ z#*OX>fFyoM{E_)0z{)>I@31PrdYbI<^Pc(;B!FHp!|rU;9O?n)e*x)^Gt--RgXIUv zMi3iEY0%i;GJphEH!vpsM5(J2fhPV59H_wnqE+vbK%}Q76(?o>7XC~pv8l2VmocW=3cnz+wq zq5Ys7YkfTY=U)ONJwG&+K&JwsRwhFGe28%Vz{OWQQU@byNq`j?lE9=#oyIdl zfMGQ2T8FZ$Tqx%_E|C^VEtxUzxv2`MR-+y?)IaVZyxCj1b#qxgh;>iqU4o;%dynH9 z6pq1Pyt5KcS&tYQVrm1QO*HOEJDtBMY=uo(rvCUTyW^sRzdhve2JQ)UHs#QD3|0X5 zkbb2$ea9)=fmg(4oh&OtKt?I$P9+A8O%XE2S z%ae0a&hZNYp>@rt?*l(ZX?y2W-L#lT5CJmccSkkD`#8e^ILB~&s9I7-rXAV zH3S4sG9XwaI*33#LTP|PHMB>X#G>+gwi+&alFmODS6~ET){HE#Shl@j1u22UV4G?- zAn)*riv4anZ79tczx2B|P?$;gG(9!1F(c4Jt@(}?tIp4#8HU2!GTSq1IjQAh8M&rl zcU~5y__&^$SL60xbT{|`K!4ek#*eiZ>=c#*RglSzBSOGr`(G?>iuJO%ce{-eNa(;b zpVmzxqK>nI+mEmuvIvS(4Of0aN%+PDi&X)MvZvgNB0@v&>--Mw8XsLaE3o8E?nQJj z2^=9^GEe~e*&5ZX>F#(pt%Vshl;a6c{0z+EA_*(fqO|KC0!$C{hwRmWehJk-55JGP zC(g&?c`QWn8a8uPimK41MCLKj*e>?1o_$gF zuKn$-zh-P_@GiaQ-}IpYiN@^YSojsb;pc|m5gL=O?s0$Smwp1b)RV!p(?f1ViY)IV z!>oiRwltA6=yO)T41TYu!QeN2%E@E%1iicO7j45=_!Zf-=mVJw-Z@1U<62FVp- zY@P58vtH}@ShBe7my2b<%|0J}??aZ%yY}k;cJ^O0EGkRKzrwJ|(rQ{u7D~#D?%UM# z#t~de?GKB20;C|*&Yn*a5uXx{L@o`k-26es-N$g(mmhmHp5kN^SP{&sWH-`-WQp5~Lxg_4UR+ujk-+2>M{naL?+AEH|tav3oiz@iZFxZ9q2 z9=ASUW#uwz7t7$XWWXw(Z>|gERG&c(kUblIY|y?pXn!M5S>~>Q)n~f1_g~%7*S2%j zN>xZ?POgVp7uQ3U-uXa*gG?obRhnQb;k6GwhMc*5@kDEFsk~}u9FPjMjk!xRi*t2E zxZIve$%_n|!qJEd6VVcBAkY;&(DGKm6wm&jb{=1u-X1zd85yIuom7hZXer-6VrkQ7 zl+_zbuw2*(rTyHSfuMCad32IEH}oL+>2jyVJ|w{jLeii>gh;^p_6j4c|IncZ96!0y z1sAx-ZQ2AbbgL1UM8N^NG?1+H;B47frEC;*fZ*8=$%AF`TDN&@L|X`MbQj2C9i$*d zm=VElTrB&R`da{XZ-5EjK?o5bZfV5l2usVfaf>RP`v?=sgghd000000BrhfyZ`_I literal 0 HcmV?d00001 diff --git a/public/appicons/optimized/io.pilot.generallegal-96.webp b/public/appicons/optimized/io.pilot.generallegal-96.webp new file mode 100644 index 0000000000000000000000000000000000000000..54f03efb6a59dc9dde9189233d26d5028143bb86 GIT binary patch literal 916 zcmV;F18e+JNk&GD0{{S5MM6+kP&gof0{{R}6abw8DqsL$06sAih(e+vAsdQx03ZVd zvxT`>oVo}v_*Z^@|5JP?pbfTs|L*_}tvseD$$m>XfAwFf4 z0>fP0S+=+Rv(Jy}v|S6$bxO@6i*>bs(>4CPK0v-n|KIhW=?oJQ=EwgowPh&RbJ& zH^vQP|9^#lH9)IG%8kdSZ}m665}na+Ghc{r_9U-;7FG^rbZq&-nPXtTQDH9|lD#wY ztu(Ody;?nkATJq}{lHzGssv8Y{}AGTbkF)^w|uR^iimBScr_Xs$QZ4>nNgduLki^@ zzGM7P-6rhnT5CPIgn@`!7%GPm5jS zD&y-{a6Jb$XPF9yLn5HdhTkYO`(_Og64^d+)e^=K_p_`V7T^=0a-h#$2+6Fy;f?Zc zZ#yE}IZnp7vEvZ%6wV|cZ9xCtpQr$PeC&Q-raW#T^$!k#d@AC>v6P+>O6BrV37hU? z|NPKhp?2xQav1FASdsHh5vSGNeyU?eMeRs0M)z0GL-%NNaIJpK;?!5|6LD+9W(adI zZ|0x!LO(V@yFPs0$(V%-FQ{UbsT+X;Cqo#@+@?0002Nf5~?M literal 0 HcmV?d00001 diff --git a/scripts/gen-apps.mjs b/scripts/gen-apps.mjs index eed42f88..d683b6f2 100644 --- a/scripts/gen-apps.mjs +++ b/scripts/gen-apps.mjs @@ -144,7 +144,7 @@ function toApp(app) { homepage: emptyToNull(app.homepage), methods: (app.methods || []).map((method) => ({ name: method.name, summary: emptyToNull(method.summary), - example: emptyToNull(method.example), gated: emptyToNull(method.gated), + example: emptyToNull(method.example), gated: emptyToNull(method.gated), billable: emptyToNull(method.billable), })), changelog: (app.changelog || []).map((release) => ({ version: release.version, date: emptyToNull(release.date), notes: release.notes || [], @@ -200,7 +200,7 @@ const FEATURED = (document.featured_order || []).filter((id) => apps.some((app) const source = fetched ? API : `${path.basename(SNAPSHOT)} (offline)`; const banner = `// AUTO-GENERATED by scripts/gen-apps.mjs from the app-store metadata API\n// (${source}) — the same document the Alpha management console reads.\n// Do not edit by hand, and do not edit the records here: change an app in\n// pilot-protocol/app-template under appstore-meta/data/apps/ and redeploy.\n// No ratings or install counts — those are not published by the catalogue.\n`; const body = `${banner} -export interface AppMethod { name: string; summary: string | null; example: string | null; gated: string | null; } +export interface AppMethod { name: string; summary: string | null; example: string | null; gated: string | null; billable: string | null; } export interface AppLimit { label: string; value: string; } export interface AppChangelog { version: string; date?: string | null; notes: string[]; } export interface AppBundle { platform: string; bytes: number | null; } diff --git a/src/data/app-metadata.json b/src/data/app-metadata.json index f5fc8683..6f201ee0 100644 --- a/src/data/app-metadata.json +++ b/src/data/app-metadata.json @@ -23,7 +23,7 @@ { "id": "infra", "name": "Infrastructure", - "blurb": "Containers, microVMs, and deploys — the compute layer for agents.", + "blurb": "Containers, microVMs, and deploys \u2014 the compute layer for agents.", "hue": 30 }, { @@ -41,13 +41,13 @@ { "id": "work", "name": "Work & Research", - "blurb": "Put real-world work in motion and get real answers back — human hands on a task, and pricing research with your own customers.", + "blurb": "Put real-world work in motion and get real answers back \u2014 human hands on a task, and pricing research with your own customers.", "hue": 45 }, { "id": "comms", "name": "Communications", - "blurb": "Give an agent its own phone number or email inbox — voice, SMS/iMessage, email, and threaded conversations.", + "blurb": "Give an agent its own phone number or email inbox \u2014 voice, SMS/iMessage, email, and threaded conversations.", "hue": 315 } ], @@ -57,6 +57,7 @@ "io.pilot.docker" ], "app_order": [ + "io.pilot.generallegal", "io.pilot.dial", "io.pilot.deadsimple", "io.pilot.kinetic", @@ -86,12 +87,322 @@ "io.pilot.tldr" ], "apps": [ + { + "id": "io.pilot.generallegal", + "name": "General Legal", + "tagline": "Attorney-backed contract review and Delaware company formation \u2014 flat-fee legal work from a licensed US law firm", + "description": "General Legal is a Y Combinator-backed law firm. This app puts a licensed\nattorney and a Delaware filing desk behind your agent \u2014 contract review and\ncompany formation, in one namespace.\n\n**A General Legal account is required for both halves.** Sign up at\nhttps://portal.general.legal/signup. The two halves then authenticate\ndifferently; both are covered below.\n\n### Contract review \u2014 bring your own API key\n\n1. Sign up at https://portal.general.legal/signup\n2. Open the account menu and choose **API keys**\n (https://portal.general.legal/api-keys)\n3. Create a key and copy it \u2014 the full value is shown **once**\n4. Import it into the app:\n\n```\nprintf '{\"GENERAL_LEGAL_API_KEY\":\"glk_YOUR_KEY\"}' > ~/.pilot/apps/io.pilot.generallegal/secrets.json\nchmod 600 ~/.pilot/apps/io.pilot.generallegal/secrets.json\npilotctl appstore restart io.pilot.generallegal\n```\n\nThe restart matters: the key is read at startup. Verify with\n`pilotctl appstore call io.pilot.generallegal generallegal.deals_list '{}'`.\nThe key stays on your machine, is never sent to the formation service, and\nscopes you to your own General Legal organization.\n\n### Company formation \u2014 nothing to import\n\nFormation needs the same General Legal account but **no key and no secret**\non your side. Call `generallegal.formation_options` and it works. The founder\npays at the link the app returns \u2014 use the same email as your account so the\nfiling lands in it.\n\n### What it costs\n\nContract review is flat-fee, with no hourly billing and no minimums. The fee\ncovers every turn through signature, including negotiation with the\ncounterparty.\n\n| Work | Price |\n| --- | --- |\n| Contract, 3 pages or fewer | $250 |\n| Contract, 3-50 pages | $500 |\n| Contract, 50+ pages | $10 per page |\n| Drafting from scratch | $2,000 |\n| Delaware LLC | $190 instant / $210 standard / $260 next-day / $310 same-day |\n| Delaware C-corp | $218 standard / $268 next-day / $318 same-day |\n\n### What the app does\n\n**Company formation** \u2014 `formation_options` (free), `formation_start_llc`\n(**paid**), `formation_start_c_corp` (**paid**), `formation_status`,\n`formation_update`, `formation_documents` (free).\n\n**Contract review** \u2014 `deal_open` (**paid**), `document_upload` (**paid**),\n`thread_post` (**paid**, covered by the matter's flat fee), plus\n`deals_list`, `deal_get`, `thread_get`, `contracts_list`, `contract_get`,\n`version_download_link` (free) and `upload_begin`, `upload_chunk`,\n`upload_abort` (free \u2014 a document is staged in chunks because a single call\ncannot carry a file).\n\n### What costs money\n\nFive methods spend real money and will not warn you first:\n`formation_start_llc`, `formation_start_c_corp`, `deal_open`,\n`document_upload` and `thread_post`. Every other method is free.\n`generallegal.help` lists them under `billable_methods` with the price.", + "categories": [ + "work" + ], + "primary_category": "work", + "keywords": [ + "legal", + "contracts", + "attorney", + "review", + "nda", + "redline", + "incorporation", + "delaware", + "llc", + "c-corp" + ], + "version": "0.1.0", + "vendor": "General Legal", + "vendor_url": "https://general.legal", + "license": "Apache-2.0", + "source_url": "https://github.com/pilot-protocol/generallegal-app", + "homepage": "https://general.legal", + "methods": [ + { + "name": "generallegal.formation_options", + "summary": "Itemised pricing for every Delaware entity type and filing speed. Needs a General Legal account; no key or secret to import.", + "example": "", + "gated": "", + "billable": "" + }, + { + "name": "generallegal.formation_start_llc", + "summary": "File a sole-member Delaware LLC and get back a payment link plus a formation_id. Needs a General Legal account; no key or secret to import. 'instant' hands over a pre-formed shelf company; the other speeds file under a name you choose.", + "example": "", + "gated": "", + "billable": "Paid \u2014 files a real Delaware LLC. $190 instant / $210 standard / $260 next-day / $310 same-day, paid by the founder at the returned link." + }, + { + "name": "generallegal.formation_start_c_corp", + "summary": "File a Delaware C-corp and get back a payment link plus a formation_id. Needs a General Legal account; no key or secret to import. The founder acts as sole incorporator.", + "example": "", + "gated": "", + "billable": "Paid \u2014 files a real Delaware C-corp. $218 standard / $268 next-day / $318 same-day, paid by the founder at the returned link." + }, + { + "name": "generallegal.formation_status", + "summary": "Poll a filing's progress. Needs a General Legal account; no key or secret to import. Repeat after poll_after_seconds while it keeps coming back.", + "example": "", + "gated": "", + "billable": "" + }, + { + "name": "generallegal.formation_update", + "summary": "Change the company name before the documents are generated. Needs a General Legal account; no key or secret to import. Late changes are rejected.", + "example": "", + "gated": "", + "billable": "" + }, + { + "name": "generallegal.formation_documents", + "summary": "Short-lived links to a completed formation's documents. Needs a General Legal account; no key or secret to import.", + "example": "", + "gated": "", + "billable": "" + }, + { + "name": "generallegal.deals_list", + "summary": "List your matters, paginated, with an optional status filter. Free.", + "example": "", + "gated": "", + "billable": "" + }, + { + "name": "generallegal.deal_open", + "summary": "Open a matter from a written request. It reaches a real attorney.", + "example": "", + "gated": "", + "billable": "Paid \u2014 flat fee per contract: $250 (3 pages or fewer), $500 (3\u201350 pages), $10/page (50+), $2,000 to draft from scratch. Covers every turn through signature." + }, + { + "name": "generallegal.deal_get", + "summary": "One matter with its documents and released versions. Free.", + "example": "", + "gated": "", + "billable": "" + }, + { + "name": "generallegal.thread_get", + "summary": "Read the lawyer-client thread on a matter. Free.", + "example": "", + "gated": "", + "billable": "" + }, + { + "name": "generallegal.thread_post", + "summary": "Reply to the attorney on a matter's thread.", + "example": "", + "gated": "", + "billable": "Paid \u2014 covered by the matter's flat fee; General Legal does not bill hourly, so a reply adds no separate charge. Free when target is \"ai\"." + }, + { + "name": "generallegal.contracts_list", + "summary": "List your documents. Free.", + "example": "", + "gated": "", + "billable": "" + }, + { + "name": "generallegal.contract_get", + "summary": "One document with its released versions; the version ids feed downloads. Free.", + "example": "", + "gated": "", + "billable": "" + }, + { + "name": "generallegal.document_upload", + "summary": "Upload a DOCX, PDF, PNG, JPEG or Markdown document for AI + attorney review, up to 20 MiB. Stage the bytes with upload_begin/upload_chunk first.", + "example": "", + "gated": "", + "billable": "Paid \u2014 priced per contract by length: $250 (3 pages or fewer), $500 (3\u201350 pages), $10/page (50+). Flat fee, covering every turn through signature." + }, + { + "name": "generallegal.version_download_link", + "summary": "Issue a short-lived (~15 min) direct download URL for a released version. Free.", + "example": "", + "gated": "", + "billable": "" + }, + { + "name": "generallegal.upload_begin", + "summary": "Start a staged upload and get a blob_id. Free \u2014 a document cannot cross in one call, so declare it here first.", + "example": "", + "gated": "", + "billable": "" + }, + { + "name": "generallegal.upload_chunk", + "summary": "Append the next chunk of a staged upload, at most 512 KiB of raw bytes per call. Free.", + "example": "", + "gated": "", + "billable": "" + }, + { + "name": "generallegal.upload_abort", + "summary": "Discard a staged upload and its bytes. Free.", + "example": "", + "gated": "", + "billable": "" + }, + { + "name": "generallegal.help", + "summary": "Every method with its parameters, duration class, and which calls cost money. Free, local, no backend call.", + "example": "", + "gated": "", + "billable": "" + } + ], + "changelog": [ + { + "version": "0.1.0", + "date": "2026-08-29", + "notes": [ + "Contract review: matters, lawyer thread, document upload and released-version downloads.", + "Delaware company formation: pricing, LLC and C-corp filing, status and documents \u2014 no API key required.", + "Bring your own General Legal API key for contract review; it never reaches the formation service." + ] + } + ], + "grants": [ + "fs.read:$APP/config.json", + "fs.read:$APP/secrets.json", + "fs.read:$APP/blobs", + "fs.write:$APP/blobs", + "net.dial:api.general.legal", + "net.dial:incorp-mcp.general.legal", + "audit.log:*" + ], + "limits": [ + { + "label": "Contract review", + "value": "$250 / $500 / $10 per page \u2014 flat fee" + }, + { + "label": "Delaware LLC", + "value": "$190\u2013$310 depending on speed" + }, + { + "label": "Delaware C-corp", + "value": "$218\u2013$318 depending on speed" + }, + { + "label": "New matters", + "value": "25 / day per organization" + } + ], + "bundles": [ + { + "platform": "darwin-arm64", + "bytes": 0 + }, + { + "platform": "darwin-amd64", + "bytes": 0 + }, + { + "platform": "linux-arm64", + "bytes": 0 + }, + { + "platform": "linux-amd64", + "bytes": 0 + } + ], + "installed_bytes": 0, + "depends": [], + "protection": "shareable", + "featured": false, + "in_catalogue": true, + "icon": { + "mode": "image", + "img": "/appicons/io.pilot.generallegal.png", + "file": "", + "fit": "cover", + "pos": "center", + "color": "#0e1a2b", + "ink": false, + "hue": 45, + "mark": null + }, + "min_pilot_version": "", + "runtimes": [ + "go" + ], + "published_at": "2026-08-29", + "updated_at": "2026-08-29", + "product_demo": { + "skill": "io.pilot.generallegal", + "title": "Full usage demo", + "metered": false, + "when_to_use": "When a contract needs a licensed attorney to review, redline or draft it, or when an agent needs its own Delaware company. A General Legal account is required for both.", + "quickstart": { + "goal": "Price a Delaware company \u2014 works on a fresh install, no account, no key", + "command": "pilotctl appstore call io.pilot.generallegal generallegal.formation_options '{\"entity_type\":\"llc\"}'", + "expect": "{\"options\":[{\"filing_speed\":\"instant\",\"total_cents\":19000},{\"filing_speed\":\"standard\",\"total_cents\":21000}]}", + "note": "Free. Formation needs a General Legal account but no key or secret on your side. Contract review needs an API key imported - see the examples." + }, + "examples": [ + { + "title": "Form a Delaware company \u2014 no API key needed", + "goal": "Price it, file it, hand the founder a payment link", + "command": "pilotctl appstore call io.pilot.generallegal generallegal.formation_start_llc '{\"filing_speed\":\"standard\",\"company_name\":\"NewCo LLC\",\"founder\":{\"full_name\":\"Ada Lovelace\",\"email\":\"ada@example.com\"},\"principal_address\":{\"street\":\"1 Main St\",\"city\":\"Dover\",\"state\":\"DE\",\"postal_code\":\"19901\"},\"ai_agent_description\":\"Procurement agent\",\"authority_limits\":\"No commitments above $5,000 without sign-off\",\"contract_threshold\":\"$5,000\"}'", + "expect": "{\"formation_id\":\"f-...\",\"payment_url\":\"https://...\",\"status\":\"awaiting_payment\"}", + "note": "BILLABLE - files a real company. $190 instant / $210 standard / $260 next-day / $310 same-day, paid by the founder at the returned link. Needs a General Legal account; nothing to import. formation_id is shown once." + }, + { + "title": "Track the filing and collect the paperwork", + "goal": "Poll to completion, then pull the documents", + "command": "pilotctl appstore call io.pilot.generallegal generallegal.formation_status '{\"formation_id\":\"f-...\"}'", + "expect": "{\"status\":\"filed\",\"poll_after_seconds\":30} then {\"status\":\"complete\"}", + "note": "Free. Repeat only after poll_after_seconds. When complete, generallegal.formation_documents returns short-lived links." + }, + { + "title": "Bring your own key, then confirm it works", + "goal": "Authenticate as your own General Legal organization", + "command": "pilotctl appstore call io.pilot.generallegal generallegal.deals_list '{\"page\":1,\"page_size\":5}'", + "expect": "{\"items\":[...],\"total\":n} once the key is in place; 401 until then", + "note": "Sign up at https://portal.general.legal/signup, then account menu -> API keys (shown once). Import: printf '{\"GENERAL_LEGAL_API_KEY\":\"glk_YOUR_KEY\"}' > ~/.pilot/apps/io.pilot.generallegal/secrets.json && chmod 600 ~/.pilot/apps/io.pilot.generallegal/secrets.json && pilotctl appstore restart io.pilot.generallegal" + }, + { + "title": "Ask an attorney to review a contract", + "goal": "Open a matter a real lawyer picks up", + "command": "pilotctl appstore call io.pilot.generallegal generallegal.deal_open '{\"initial_request\":\"Please review this mutual NDA. We are the disclosing party; flag anything unusual in the confidentiality term.\",\"deal_name\":\"Acme mutual NDA\"}'", + "expect": "{\"deal_id\":\"d-9f3...\",\"status\":\"open\"}", + "note": "BILLABLE - flat fee per contract: $250 (<=3 pages), $500 (3-50), $10/page (50+), $2,000 to draft. Covers every turn through signature. Keep the deal_id." + }, + { + "title": "Stage the document, then send it", + "goal": "Push the bytes in chunks (a file cannot cross in one message), then upload", + "command": "pilotctl appstore call io.pilot.generallegal generallegal.upload_begin '{\"file_name\":\"nda.docx\",\"content_type\":\"application/vnd.openxmlformats-officedocument.wordprocessingml.document\",\"total_bytes\":3145728,\"sha256\":\"\"}'", + "expect": "{\"blob_id\":\"a1b2...\",\"max_chunk_bytes\":524288,\"next_seq\":0}", + "note": "Then generallegal.upload_chunk with seq 0,1,2... and base64 of at most max_chunk_bytes raw bytes. The last returns complete:true. Finally generallegal.document_upload with the blob_id and deal_id (BILLABLE)." + }, + { + "title": "Collect the released redline", + "goal": "Get a downloadable link to counsel's version", + "command": "pilotctl appstore call io.pilot.generallegal generallegal.version_download_link '{\"version_id\":\"v-07...\"}'", + "expect": "{\"file_name\":\"nda-redline.docx\",\"download_url\":\"https://...\",\"download_token_expires_at\":\"...\"}", + "note": "Free. The URL needs no auth and expires in ~15 minutes - fetch it yourself. Find version ids via generallegal.deal_get or generallegal.contract_get." + } + ], + "gotchas": [ + "A General Legal account is required for both halves. Sign up at portal.general.legal/signup.", + "Contract review needs an API key imported: account menu -> API keys, write it to $APP/secrets.json, then restart the app - the key is read at startup.", + "Company formation needs no key or secret on your side; the service handles its own authentication. Just call formation_options.", + "Five methods spend money: deal_open and document_upload are flat-fee per contract ($250/$500/$10-per-page/$2,000); formation_start_llc and formation_start_c_corp file a real company ($190-$318); thread_post is covered by the matter's fee.", + "A document cannot ride in one call. Use upload_begin then upload_chunk (<=512 KiB raw each) and pass the blob_id. A blob is single-use and dropped once sent.", + "Matters reach a real attorney and formations file a real company. Neither is a sandbox - confirm before calling a billable method." + ], + "next": [ + "generallegal.formation_options to price a company, or generallegal.deals_list to see the matters your key can reach.", + "generallegal.help lists every method and marks exactly which ones cost money." + ] + }, + "summary": "General Legal is a Y Combinator-backed law firm. This app puts a licensed attorney and a Delaware filing desk behind your agent \u2014 contract review and company formation, in one namespace. A General Legal account is required for both halves. Sign up at https://portal.general.legal/signup. The two halves then authenticate differently; both are covered below. Contract review \u2014 bring your own API key 1. Sign up at" + }, { "id": "io.pilot.dial", "name": "Dial", - "tagline": "A complete phone identity for your agent — voice calls, SMS and iMessage on a real US number, provisioned in one call", - "description": "Dial gives your agent its own real phone number: place and receive AI voice calls, send and receive SMS and iMessage, and wait on inbound events without polling. Bring your Dial API key at install time and every method authenticates as your own account. The account is yours, works outside Pilot too, and starts with $5 of credit and no credit card. No key yet? dial.signup emails a 6-digit code and dial.verify exchanges it for one. What you can do - Call people. dial.place_call runs an autonomous AI voice call from your number: book a table, chase a delivery, return a missed call. Pass transferTo and it waits out hold music and IVR menus, then cold-transfers to your human the moment a real person answers — never to a recording. Poll dial.get_call for the transcript, or block on dial.wait_for_event. - Give the call your tools. Connect a Context MCP and your MCP server tools become available to the voice agent DURING the call, so it can look something up or take an action mid-conversation. Dial runs the OAuth 2.1 flow and keeps the token fresh in the background. - Text people. dial.send_message delivers over iMessage when the recipient supports it and falls back to SMS otherwise, same call either way. Show a typing indicator first with dial.typing. - Wait, do not poll. dial.wait_for_event blocks until an inbound reply, a 2FA code, or a finished call shows up. A 408 means try again, not an error. - Own the identity. Set each number inbound behavior, voice and language, and on iMessage numbers the display name and avatar recipients see in Messages. Cost Reads are free. $3/month per number. US SMS $0.02 per segment. Managed voice $0.22/min all-in; self-hosted voice $0.13/min if you bring your own LLM over a WebSocket. Your $5 signup credit covers the first usage and spend pauses at $0 rather than surprising you. Good to know A brand-new account is on the free tier until it is topped up, which caps calls at 5 minutes and 2 concurrent calls. Both lift permanently on the first top-up. Emergency and crisis numbers are blocked. Always pass numbers in E.164, e.g. +14155551234. Every method, its parameters and latency class are discoverable at runtime via dial.help.", - "summary": "Dial gives your agent its own real phone number: place and receive AI voice calls, send and receive SMS and iMessage, and wait on inbound events without polling. Bring your Dial API key at install time and every method authenticates as your own account. The account is yours, works outside Pilot too, and starts with $5 of credit and no credit card. No key yet? dial.signup emails a 6-digit code and dial.verify…", + "tagline": "A complete phone identity for your agent \u2014 voice calls, SMS and iMessage on a real US number, provisioned in one call", + "description": "Dial gives your agent its own real phone number: place and receive AI voice calls, send and receive SMS and iMessage, and wait on inbound events without polling. Bring your Dial API key at install time and every method authenticates as your own account. The account is yours, works outside Pilot too, and starts with $5 of credit and no credit card. No key yet? dial.signup emails a 6-digit code and dial.verify exchanges it for one. What you can do - Call people. dial.place_call runs an autonomous AI voice call from your number: book a table, chase a delivery, return a missed call. Pass transferTo and it waits out hold music and IVR menus, then cold-transfers to your human the moment a real person answers \u2014 never to a recording. Poll dial.get_call for the transcript, or block on dial.wait_for_event. - Give the call your tools. Connect a Context MCP and your MCP server tools become available to the voice agent DURING the call, so it can look something up or take an action mid-conversation. Dial runs the OAuth 2.1 flow and keeps the token fresh in the background. - Text people. dial.send_message delivers over iMessage when the recipient supports it and falls back to SMS otherwise, same call either way. Show a typing indicator first with dial.typing. - Wait, do not poll. dial.wait_for_event blocks until an inbound reply, a 2FA code, or a finished call shows up. A 408 means try again, not an error. - Own the identity. Set each number inbound behavior, voice and language, and on iMessage numbers the display name and avatar recipients see in Messages. Cost Reads are free. $3/month per number. US SMS $0.02 per segment. Managed voice $0.22/min all-in; self-hosted voice $0.13/min if you bring your own LLM over a WebSocket. Your $5 signup credit covers the first usage and spend pauses at $0 rather than surprising you. Good to know A brand-new account is on the free tier until it is topped up, which caps calls at 5 minutes and 2 concurrent calls. Both lift permanently on the first top-up. Emergency and crisis numbers are blocked. Always pass numbers in E.164, e.g. +14155551234. Every method, its parameters and latency class are discoverable at runtime via dial.help.", + "summary": "Dial gives your agent its own real phone number: place and receive AI voice calls, send and receive SMS and iMessage, and wait on inbound events without polling. Bring your Dial API key at install time and every method authenticates as your own account. The account is yours, works outside Pilot too, and starts with $5 of credit and no credit card. No key yet? dial.signup emails a 6-digit code and dial.verify\u2026", "categories": [ "comms" ], @@ -310,7 +621,7 @@ "command": "pilotctl appstore call io.pilot.dial dial.buy_number '{\"areaCode\":\"415\",\"explicitProgrammaticConsent\":\"yes\"}'", "expect": "{\"id\":\"num_...\",\"phoneNumber\":\"+14155550123\"}", "cost": "$3.00/month", - "note": "Spends money, so it requires an explicit consent attestation — confirm with your human first. Then dial.send_message delivers over iMessage when the recipient supports it, else SMS." + "note": "Spends money, so it requires an explicit consent attestation \u2014 confirm with your human first. Then dial.send_message delivers over iMessage when the recipient supports it, else SMS." }, { "title": "Place a call and let it wait out the IVR", @@ -318,7 +629,7 @@ "command": "pilotctl appstore call io.pilot.dial dial.place_call '{\"to\":\"+14155550199\",\"fromNumber\":\"+14155550123\",\"outboundInstruction\":\"Ask if they take reservations for 4 at 8pm Friday\",\"transferTo\":\"+14155550100\"}'", "expect": "{\"id\":\"call_...\",\"status\":\"queued\"}", "cost": "$0.22/min", - "note": "transferTo hands the live call to your human the moment a real person answers — never to a recording. Poll dial.get_call for the transcript." + "note": "transferTo hands the live call to your human the moment a real person answers \u2014 never to a recording. Poll dial.get_call for the transcript." }, { "title": "Block until the reply arrives, instead of polling", @@ -355,12 +666,12 @@ "note": "$0.13/min self-hosted if you bring your own LLM" } ], - "worked_total": "$3.44 — one number for a month ($3.00), one 2-minute call ($0.44), reads free. Inside the $5 signup credit.", + "worked_total": "$3.44 \u2014 one number for a month ($3.00), one 2-minute call ($0.44), reads free. Inside the $5 signup credit.", "check_balance": "" }, "gotchas": [ "Reads are free; buying a number, texting and calling cost money. Check dial.status first.", - "dial.buy_number needs an explicit consent attestation because it spends — confirm with your human.", + "dial.buy_number needs an explicit consent attestation because it spends \u2014 confirm with your human.", "A new account is capped at 5-minute calls and 2 concurrent until the first top-up.", "Always pass numbers in E.164, e.g. +14155551234. Emergency and crisis numbers are blocked.", "Prefer dial.wait_for_event over polling; a 408 means retry, not failure." @@ -374,8 +685,8 @@ "id": "io.pilot.deadsimple", "name": "Dead Simple Email", "tagline": "An email identity your agent provisions for itself, then uses to send, receive, and read its own signup codes", - "description": "Dead Simple Email gives an agent a real, deliverable email identity — not a sandbox — and it can get one entirely on its own. A single call to `deadsimple.signup` returns an account, an API key and a live inbox. No dashboard, no verification email, no human in the loop.\n\n**The method agents reach for most is `deadsimple.get_verification_code`.** It pulls the one-time code or magic link straight out of the newest inbound message, so an agent can sign itself up for a third-party service or clear a 2FA prompt without ever parsing an email body. Filter by sender and by timestamp so a stale code is never returned. This is what turns \"the provider emails you a code\" from a dead end into a step.\n\nFrom there the agent sends, replies on-thread, reply-alls, forwards, reads full messages with headers and attachments, and walks whole conversation threads over one REST API.\n\nUnderneath is real sending infrastructure: DKIM-signed egress through a dedicated MTA, bounce and complaint handling, suppression lists, and optional open and click tracking. Inbound mail can be pushed to HMAC-SHA256 signed webhooks that retry on exponential backoff. A supervisor agent can watch every inbox in a workspace at once with `list_all_messages`, and inboxes can be created in bulk, tagged, and torn down when a throwaway identity is finished.\n\n**Tiers.** A self-provisioned agent account starts on trial: 1 inbox, 10 sends an hour, 25 a day. Calling `deadsimple.claim` with an email a human controls, then `deadsimple.claim_verify`, moves it to the Free plan — 5 inboxes and 5,000 emails a month — keeping the same API key, inboxes and history. Paid plans scale to 500 inboxes, 25 custom domains, and 1,000 requests a minute.\n\n**Edge cases.** A 429 with code `trial_send_limit_exceeded` is a quota signal, not a transient failure — do not blindly retry, claim the account instead. Pagination is cursor-based. Spam is excluded from `list_messages` unless `include_spam` is true. Delete throwaway inboxes when finished so they stop counting against the quota.", - "summary": "Dead Simple Email gives an agent a real, deliverable email identity — not a sandbox — and it can get one entirely on its own. A single call to deadsimple.signup returns an account, an API key and a live inbox. No dashboard, no verification email, no human in the loop. The method agents reach for most is deadsimple.get_verification_code. It pulls the one-time code or magic link straight out of the newest inbound…", + "description": "Dead Simple Email gives an agent a real, deliverable email identity \u2014 not a sandbox \u2014 and it can get one entirely on its own. A single call to `deadsimple.signup` returns an account, an API key and a live inbox. No dashboard, no verification email, no human in the loop.\n\n**The method agents reach for most is `deadsimple.get_verification_code`.** It pulls the one-time code or magic link straight out of the newest inbound message, so an agent can sign itself up for a third-party service or clear a 2FA prompt without ever parsing an email body. Filter by sender and by timestamp so a stale code is never returned. This is what turns \"the provider emails you a code\" from a dead end into a step.\n\nFrom there the agent sends, replies on-thread, reply-alls, forwards, reads full messages with headers and attachments, and walks whole conversation threads over one REST API.\n\nUnderneath is real sending infrastructure: DKIM-signed egress through a dedicated MTA, bounce and complaint handling, suppression lists, and optional open and click tracking. Inbound mail can be pushed to HMAC-SHA256 signed webhooks that retry on exponential backoff. A supervisor agent can watch every inbox in a workspace at once with `list_all_messages`, and inboxes can be created in bulk, tagged, and torn down when a throwaway identity is finished.\n\n**Tiers.** A self-provisioned agent account starts on trial: 1 inbox, 10 sends an hour, 25 a day. Calling `deadsimple.claim` with an email a human controls, then `deadsimple.claim_verify`, moves it to the Free plan \u2014 5 inboxes and 5,000 emails a month \u2014 keeping the same API key, inboxes and history. Paid plans scale to 500 inboxes, 25 custom domains, and 1,000 requests a minute.\n\n**Edge cases.** A 429 with code `trial_send_limit_exceeded` is a quota signal, not a transient failure \u2014 do not blindly retry, claim the account instead. Pagination is cursor-based. Spam is excluded from `list_messages` unless `include_spam` is true. Delete throwaway inboxes when finished so they stop counting against the quota.", + "summary": "Dead Simple Email gives an agent a real, deliverable email identity \u2014 not a sandbox \u2014 and it can get one entirely on its own. A single call to deadsimple.signup returns an account, an API key and a live inbox. No dashboard, no verification email, no human in the loop. The method agents reach for most is deadsimple.get_verification_code. It pulls the one-time code or magic link straight out of the newest inbound\u2026", "categories": [ "comms" ], @@ -401,7 +712,7 @@ "methods": [ { "name": "deadsimple.signup", - "summary": "START HERE if you have no key. Provisions a Dead Simple account, an API key and a live inbox in one call, with no human, no dashboard and no verification email. Returns {account_id, api_key, inbox}. Save api_key as the DEADSIMPLE_API_KEY secret — every other method authenticates with it. Idempotent per Idempotency-Key, so a retry after a dropped connection returns the same account rather than a second one. The account starts on the trial tier: 1 inbox, 10 sends an hour, 25 a day.", + "summary": "START HERE if you have no key. Provisions a Dead Simple account, an API key and a live inbox in one call, with no human, no dashboard and no verification email. Returns {account_id, api_key, inbox}. Save api_key as the DEADSIMPLE_API_KEY secret \u2014 every other method authenticates with it. Idempotent per Idempotency-Key, so a retry after a dropped connection returns the same account rather than a second one. The account starts on the trial tier: 1 inbox, 10 sends an hour, 25 a day.", "example": "", "gated": "" }, @@ -419,7 +730,7 @@ }, { "name": "deadsimple.create_inbox", - "summary": "Create a real, deliverable email inbox in one call. Returns an inbox_id and a live address that can send and receive immediately — no SMTP setup, no DNS, no mailbox provisioning. Use this when you already have a key and want an additional identity.", + "summary": "Create a real, deliverable email inbox in one call. Returns an inbox_id and a live address that can send and receive immediately \u2014 no SMTP setup, no DNS, no mailbox provisioning. Use this when you already have a key and want an additional identity.", "example": "", "gated": "" }, @@ -467,7 +778,7 @@ }, { "name": "deadsimple.reply", - "summary": "Reply to the sender of a message. Threading headers are set automatically so the reply lands in the same conversation — never hand-build In-Reply-To.", + "summary": "Reply to the sender of a message. Threading headers are set automatically so the reply lands in the same conversation \u2014 never hand-build In-Reply-To.", "example": "", "gated": "" }, @@ -491,7 +802,7 @@ }, { "name": "deadsimple.get_thread", - "summary": "Get a full conversation thread with every message in order — the context an agent needs before replying.", + "summary": "Get a full conversation thread with every message in order \u2014 the context an agent needs before replying.", "example": "", "gated": "" }, @@ -503,7 +814,7 @@ }, { "name": "deadsimple.list_all_messages", - "summary": "List messages across every inbox this key can see, newest first. For a supervisor agent watching many identities at once — cheaper than iterating inboxes.", + "summary": "List messages across every inbox this key can see, newest first. For a supervisor agent watching many identities at once \u2014 cheaper than iterating inboxes.", "example": "", "gated": "" }, @@ -581,7 +892,7 @@ "command": "pilotctl appstore call io.pilot.deadsimple deadsimple.signup '{\"label\":\"my-agent\"}'", "expect": "{\"data\":{\"account_id\":\"...\",\"api_key\":\"dse_...\",\"inbox\":{\"inbox_id\":\"...\",\"email\":\"...@box1.deadsimple.email\"},\"plan\":{\"plan\":\"trial\",\"inbox_limit\":1,\"sends_per_hour\":10}}}", "cost": "", - "note": "Everything is under data. Save data.api_key as DEADSIMPLE_API_KEY — it is shown once. Already have a key? Skip this and call create_inbox." + "note": "Everything is under data. Save data.api_key as DEADSIMPLE_API_KEY \u2014 it is shown once. Already have a key? Skip this and call create_inbox." }, "examples": [ { @@ -613,7 +924,7 @@ "gotchas": [ "Every response is wrapped: the payload is under data, with meta.request_id beside it.", "Call signup only when you have no key. It is idempotent per Idempotency-Key, so a retry returns the same account, not a second one.", - "Trial is 1 inbox, 10 sends/hour, 25/day. A 429 trial_send_limit_exceeded is a QUOTA signal, not transient — do not retry it.", + "Trial is 1 inbox, 10 sends/hour, 25/day. A 429 trial_send_limit_exceeded is a QUOTA signal, not transient \u2014 do not retry it.", "Lift the caps with claim then claim_verify. Your key, inboxes and history survive.", "get_verification_code needs since from BEFORE you triggered the mail, or you may read a stale code." ], @@ -627,7 +938,7 @@ "name": "Kinetic Pricing", "tagline": "Decide what to charge, using answers from your own customers rather than a guess", "description": "Kinetic Pricing runs real pricing research end to end: choose the method that fits the decision, draft and preview the survey, send a link to your own customers, and read results computed by an analysis engine rather than asserted by a model.\n\n**Pick the right method or the answer is worthless.** `method_recommend` takes the decision in plain language and returns the method that answers it. Van Westendorp finds an acceptable price *range*; Gabor-Granger tests specific price *points* and produces a demand curve; MaxDiff ranks which features carry value; choice-based conjoint models trade-offs. Asking the wrong one produces a confident, useless number.\n\n**Everything up to launch is free.** Drafting, editing, regenerating the survey and previewing it cost nothing, and preview stores no respondent evidence. Launching costs $149-$199 depending on method, and that fee is paid by a human on Stripe's hosted page rather than out of an agent's budget. `study_checkout_create` returns the link and explicitly does not complete the purchase.\n\n**You supply the respondents.** Kinetic has no panel. `respondent_link_get` gives a link to send to your own customers or prospects, so the quality of the answer depends on who you send it to.\n\n**The numbers are computed, not narrated.** `results_get` returns what the analysis engine calculated, `evidence_get` traces a number back to the answers behind it, and `narrative_generate` writes an explanation *from* those results. Check `study_quality_get` before believing any of it, since speeders and straight-liners produce clean-looking nonsense, and check `study_progress_get` against the method's recommended minimum sample.\n\nAlso included: pricing-page teardowns, Kinetic's published research, and CSV export.", - "summary": "Kinetic Pricing runs real pricing research end to end: choose the method that fits the decision, draft and preview the survey, send a link to your own customers, and read results computed by an analysis engine rather than asserted by a model. Pick the right method or the answer is worthless. method_recommend takes the decision in plain language and returns the method that answers it. Van Westendorp finds an…", + "summary": "Kinetic Pricing runs real pricing research end to end: choose the method that fits the decision, draft and preview the survey, send a link to your own customers, and read results computed by an analysis engine rather than asserted by a model. Pick the right method or the answer is worthless. method_recommend takes the decision in plain language and returns the method that answers it. Van Westendorp finds an\u2026", "categories": [ "work" ], @@ -663,7 +974,7 @@ }, { "name": "kinetic.study_create", - "summary": "START HERE once you know the decision. Creates a draft study. You do NOT pick the method: Kinetic derives the methodology from decision_type (first_time and new_tier map to Van Westendorp today) and returns it on the study along with price_cents. Free — a draft costs nothing and is not launched. Returns {id, methodology, status:\"draft\", price_cents}.", + "summary": "START HERE once you know the decision. Creates a draft study. You do NOT pick the method: Kinetic derives the methodology from decision_type (first_time and new_tier map to Van Westendorp today) and returns it on the study along with price_cents. Free \u2014 a draft costs nothing and is not launched. Returns {id, methodology, status:\"draft\", price_cents}.", "example": "", "gated": "" }, @@ -930,7 +1241,7 @@ "Everything except launching is free. The $149-$199 fee is paid by a human on Stripe, not your budget.", "Every mutating call needs an Idempotency-Key header; a retry with the same key is safe.", "study_checkout_create returns a link and does NOT pay. Hand the URL to your human and stop.", - "Preview before launch — once live, questions are fixed.", + "Preview before launch \u2014 once live, questions are fixed.", "You supply the respondents; Kinetic has no panel.", "Check study_quality_get and progress before trusting a result." ], @@ -944,8 +1255,8 @@ "id": "io.pilot.rentahuman", "name": "Rent A Human", "tagline": "Hire a real person for a physical-world task, in plain language, and talk to ops until it is done", - "description": "Rent A Human gives an agent hands in the physical world. Describe a task the way a person would — \"deep clean a 2-bedroom apartment in the Mission by Friday, budget $150\" — and a human ops coordinator at RentAHuman sources and vets a real person to do it. Everything after that happens on a message thread your agent polls.\n\n**This is the Partner API, not the marketplace.** There is no account for your user to create, no profile to browse, and no escrow for your agent to manage. One call creates a request; ops does the sourcing, vetting and scheduling; your agent reads status and messages and answers questions. When work is priced, a payment link comes back for your agent to relay.\n\n**Your agent is the only channel.** RentAHuman never contacts your end customer. Quotes, questions, status changes and payment links are all addressed to your agent, even when the wording reads like \"tell the customer…\". You decide whether, when and how to relay each one. Nothing reaches your customer unless your agent sends it.\n\n**The loop.** `create_request` returns a `requestId`. Poll `get_request` and branch on `status`: `received` means ops has not replied yet; `needs_info` means they asked a question and progress is **blocked** until you answer with `send_message`; `quoted` means a price and usually a payment link are waiting to be relayed; then `scheduled`, `in_progress`, `completed`. `list_requests` shows everything in flight.\n\n**Edge cases.** `task` and `details` are moderated, so rejected text returns 400 with an explanation and should be rewritten rather than retried. `requesterPhoneNumber` must be E.164 and is customer PII. `budgetUsd` is the budget before fees. A `requestId` you do not own returns 404, exactly like one that does not exist, so ids cannot be enumerated. `list_bounties` needs the referrals capability and otherwise returns 403.", - "summary": "Rent A Human gives an agent hands in the physical world. Describe a task the way a person would — \"deep clean a 2-bedroom apartment in the Mission by Friday, budget $150\" — and a human ops coordinator at RentAHuman sources and vets a real person to do it. Everything after that happens on a message thread your agent polls. This is the Partner API, not the marketplace. There is no account for your user to create, no…", + "description": "Rent A Human gives an agent hands in the physical world. Describe a task the way a person would \u2014 \"deep clean a 2-bedroom apartment in the Mission by Friday, budget $150\" \u2014 and a human ops coordinator at RentAHuman sources and vets a real person to do it. Everything after that happens on a message thread your agent polls.\n\n**This is the Partner API, not the marketplace.** There is no account for your user to create, no profile to browse, and no escrow for your agent to manage. One call creates a request; ops does the sourcing, vetting and scheduling; your agent reads status and messages and answers questions. When work is priced, a payment link comes back for your agent to relay.\n\n**Your agent is the only channel.** RentAHuman never contacts your end customer. Quotes, questions, status changes and payment links are all addressed to your agent, even when the wording reads like \"tell the customer\u2026\". You decide whether, when and how to relay each one. Nothing reaches your customer unless your agent sends it.\n\n**The loop.** `create_request` returns a `requestId`. Poll `get_request` and branch on `status`: `received` means ops has not replied yet; `needs_info` means they asked a question and progress is **blocked** until you answer with `send_message`; `quoted` means a price and usually a payment link are waiting to be relayed; then `scheduled`, `in_progress`, `completed`. `list_requests` shows everything in flight.\n\n**Edge cases.** `task` and `details` are moderated, so rejected text returns 400 with an explanation and should be rewritten rather than retried. `requesterPhoneNumber` must be E.164 and is customer PII. `budgetUsd` is the budget before fees. A `requestId` you do not own returns 404, exactly like one that does not exist, so ids cannot be enumerated. `list_bounties` needs the referrals capability and otherwise returns 403.", + "summary": "Rent A Human gives an agent hands in the physical world. Describe a task the way a person would \u2014 \"deep clean a 2-bedroom apartment in the Mission by Friday, budget $150\" \u2014 and a human ops coordinator at RentAHuman sources and vets a real person to do it. Everything after that happens on a message thread your agent polls. This is the Partner API, not the marketplace. There is no account for your user to create, no\u2026", "categories": [ "work" ], @@ -970,25 +1281,25 @@ "methods": [ { "name": "rentahuman.create_request", - "summary": "START HERE. Ask for a human to do something in the physical world, in plain language. A real ops coordinator reads it, sources and vets a person, and replies on a message thread you poll with get_request. Returns {requestId, status:\"received\", request}. Keep the requestId — every other method hangs off it. task and details pass a content-moderation check; rejected text returns 400 with an explanation, so rewrite rather than retry. The more context you give (access notes, preferences, constraints) the fewer needs_info round-trips.", + "summary": "START HERE. Ask for a human to do something in the physical world, in plain language. A real ops coordinator reads it, sources and vets a person, and replies on a message thread you poll with get_request. Returns {requestId, status:\"received\", request}. Keep the requestId \u2014 every other method hangs off it. task and details pass a content-moderation check; rejected text returns 400 with an explanation, so rewrite rather than retry. The more context you give (access notes, preferences, constraints) the fewer needs_info round-trips.", "example": "", "gated": "" }, { "name": "rentahuman.get_request", - "summary": "Read one request: its current status and the full message thread with the ops coordinator. THIS IS THE POLL TARGET after create_request. Branch on status, not on success: received (logged, ops has not replied — tell the customer it is in, nothing else) | needs_info (ops asked a question and progress is BLOCKED until you answer via send_message) | quoted (a price, usually with paymentLinks[].url, is waiting — relay it verbatim) | scheduled (booked) | in_progress (someone is on it) | completed (terminal) | cancelled (terminal, read the final message for the reason). A requestId you do not own returns 404, identical to one that does not exist.", + "summary": "Read one request: its current status and the full message thread with the ops coordinator. THIS IS THE POLL TARGET after create_request. Branch on status, not on success: received (logged, ops has not replied \u2014 tell the customer it is in, nothing else) | needs_info (ops asked a question and progress is BLOCKED until you answer via send_message) | quoted (a price, usually with paymentLinks[].url, is waiting \u2014 relay it verbatim) | scheduled (booked) | in_progress (someone is on it) | completed (terminal) | cancelled (terminal, read the final message for the reason). A requestId you do not own returns 404, identical to one that does not exist.", "example": "", "gated": "" }, { "name": "rentahuman.send_message", - "summary": "Send a follow-up message to the ops coordinator on a request — answer their question, or relay your customer's decision. This is the way out of a needs_info status. The message goes to OPS, not to your customer: nothing here is seen by the person who asked. Max 5,000 characters, moderated.", + "summary": "Send a follow-up message to the ops coordinator on a request \u2014 answer their question, or relay your customer's decision. This is the way out of a needs_info status. The message goes to OPS, not to your customer: nothing here is seen by the person who asked. Max 5,000 characters, moderated.", "example": "", "gated": "" }, { "name": "rentahuman.list_requests", - "summary": "List your requests, newest first, so an agent can see everything in flight at once. Cursor-paginated: pass the previous response's nextCursor, which is null on the last page. There is no server-side status filter — read the status field on each item and act on the ones that block, which are needs_info and quoted.", + "summary": "List your requests, newest first, so an agent can see everything in flight at once. Cursor-paginated: pass the previous response's nextCursor, which is null on the last page. There is no server-side status filter \u2014 read the status field on each item and act on the ones that block, which are needs_info and quoted.", "example": "", "gated": "" }, @@ -1058,7 +1369,7 @@ "product_demo": { "skill": "io.pilot.rentahuman", "title": "Full usage demo", - "when_to_use": "When a task needs hands in the physical world — a clean, a pickup, an errand, an on-site check — and your agent needs a real person to do it and report back.", + "when_to_use": "When a task needs hands in the physical world \u2014 a clean, a pickup, an errand, an on-site check \u2014 and your agent needs a real person to do it and report back.", "metered": false, "quickstart": { "title": "", @@ -1066,7 +1377,7 @@ "command": "pilotctl appstore call io.pilot.rentahuman rentahuman.create_request '{\"task\":\"Deep clean a 2-bedroom apartment\",\"externalChatId\":\"thread-9f2a41c7\",\"requesterPhoneNumber\":\"+14155550100\",\"budgetUsd\":150,\"location\":\"Mission District, San Francisco, CA\"}'", "expect": "{\"success\":true,\"requestId\":\"8FQxJ0N2VvR5aYc31TZk\",\"status\":\"received\",\"request\":{...}}", "cost": "", - "note": "A human ops coordinator picks this up and sources a vetted person. Keep the requestId — everything else hangs off it." + "note": "A human ops coordinator picks this up and sources a vetted person. Keep the requestId \u2014 everything else hangs off it." }, "examples": [ { @@ -1091,14 +1402,14 @@ "command": "pilotctl appstore call io.pilot.rentahuman rentahuman.list_requests '{\"limit\":20}'", "expect": "{\"success\":true,\"requests\":[{\"requestId\":\"...\",\"status\":\"quoted\"}],\"nextCursor\":null}", "cost": "", - "note": "Newest first, cursor-paginated. No server-side status filter — read status per item." + "note": "Newest first, cursor-paginated. No server-side status filter \u2014 read status per item." } ], "cost": null, "gotchas": [ "Nothing reaches your customer unless YOU send it. Ops replies, quotes and payment links are all addressed to your agent.", "Branch on status, not success. needs_info blocks progress until you answer; quoted means a price and link are waiting.", - "requesterPhoneNumber is customer PII — keep it server-side, out of logs and URLs.", + "requesterPhoneNumber is customer PII \u2014 keep it server-side, out of logs and URLs.", "task and details are moderated. A 400 means rewrite, not retry.", "budgetUsd is before fees (1-100000). Always pass dueBy if the customer gave a deadline." ], @@ -1111,8 +1422,8 @@ "id": "io.pilot.upfile", "name": "Upfile", "tagline": "Upload a file, get a permanent URL. One call to sign up, one to upload", - "description": "Upfile turns a file on the host into a URL an agent can hand to a human or another service. There is no dashboard and no browser step anywhere in the loop: `upfile.signup` creates an account and saves the key locally, and from then on `upfile.upload` returns a live, permanent link.\n\n**Everything returns JSON.** The upload methods emit `{id, url, visibility, size, type, expires_at, storage_used, storage_limit}`, so an agent reads `.url` rather than scraping console output.\n\n**Three shapes of link.** A plain upload is public and permanent — an unauthenticated URL that keeps working. `upload_private` puts it behind authentication. `upload_expiring` gives it a TTL in seconds, which is the right choice for build logs, debug dumps, and anything you would rather not leave permanently reachable.\n\n**Housekeeping.** `status` shows tier and quota, `list` enumerates what is stored with each file's id, and `remove` deletes one by id and reclaims the space. The free tier is 1GB total across all files.\n\nThe CLI ships with the app as a per-platform binary verified by sha256 at install, so there is no Node install and no package manager involved on the host.", - "summary": "Upfile turns a file on the host into a URL an agent can hand to a human or another service. There is no dashboard and no browser step anywhere in the loop: upfile.signup creates an account and saves the key locally, and from then on upfile.upload returns a live, permanent link. Everything returns JSON. The upload methods emit {id, url, visibility, size, type, expires_at, storage_used, storage_limit}, so an agent…", + "description": "Upfile turns a file on the host into a URL an agent can hand to a human or another service. There is no dashboard and no browser step anywhere in the loop: `upfile.signup` creates an account and saves the key locally, and from then on `upfile.upload` returns a live, permanent link.\n\n**Everything returns JSON.** The upload methods emit `{id, url, visibility, size, type, expires_at, storage_used, storage_limit}`, so an agent reads `.url` rather than scraping console output.\n\n**Three shapes of link.** A plain upload is public and permanent \u2014 an unauthenticated URL that keeps working. `upload_private` puts it behind authentication. `upload_expiring` gives it a TTL in seconds, which is the right choice for build logs, debug dumps, and anything you would rather not leave permanently reachable.\n\n**Housekeeping.** `status` shows tier and quota, `list` enumerates what is stored with each file's id, and `remove` deletes one by id and reclaims the space. The free tier is 1GB total across all files.\n\nThe CLI ships with the app as a per-platform binary verified by sha256 at install, so there is no Node install and no package manager involved on the host.", + "summary": "Upfile turns a file on the host into a URL an agent can hand to a human or another service. There is no dashboard and no browser step anywhere in the loop: upfile.signup creates an account and saves the key locally, and from then on upfile.upload returns a live, permanent link. Everything returns JSON. The upload methods emit {id, url, visibility, size, type, expires_at, storage_used, storage_limit}, so an agent\u2026", "categories": [ "infra" ], @@ -1255,7 +1566,7 @@ "product_demo": { "skill": "io.pilot.upfile", "title": "Full usage demo", - "when_to_use": "When your agent has produced a file — a render, a report, a screenshot, a log — and needs a URL it can paste somewhere a human or another service will open.", + "when_to_use": "When your agent has produced a file \u2014 a render, a report, a screenshot, a log \u2014 and needs a URL it can paste somewhere a human or another service will open.", "metered": false, "quickstart": { "title": "", @@ -1294,7 +1605,7 @@ "cost": null, "gotchas": [ "Run upfile.signup once per host if there is no key. Everything else fails with No API key until you do.", - "Read .url from the JSON — the human-readable output is not stable.", + "Read .url from the JSON \u2014 the human-readable output is not stable.", "A plain upload is a permanent, unauthenticated URL. Use upload_private or upload_expiring for anything sensitive.", "expiry is in SECONDS, not minutes. 3600 is an hour.", "Free tier is 1GB total, not per file. Use upfile.remove to reclaim space." @@ -1307,9 +1618,9 @@ { "id": "io.pilot.primitive", "name": "Primitive", - "tagline": "Email for AI agents — provision a managed inbox in one call, then send, receive, reply, and search real email over one REST API", - "description": "# Primitive — email for AI agents\n\n[Primitive](https://www.primitive.dev) gives an agent a real, working email identity with **no SMTP credentials, no DNS, and no human in the loop**. `primitive.signup` provisions a free account plus a managed `*.primitive.email` inbox in **one call** (no email, no code). The adapter caches the API key locally under `~/.pilot` and **injects it on every subsequent call automatically** — the agent never sees, stores, or passes it. Call signup once; everything else authenticates as you.\n\n## What you can do on the free plan\n- **Send** outbound mail, **reply** on-thread, and **batch-send**, with attachments and idempotency keys.\n- **Receive** at your managed inbox: list, get, search, download raw MIME + attachments, and follow conversations. Long-poll for new mail with `?since=&wait=30`.\n- **Filter** inbound mail, register **webhook endpoints**, and read **inbox readiness**.\n- **Primitive Memories** — durable JSON key-value state across turns, retries, and inbound messages.\n\n## Auth model\nOne step: `primitive.signup`. It mints a `prim_` API key + a provisioned inbox, caches both locally, and the key is injected on every call thereafter. **Idempotent** — a host that already has a key keeps it. Any method called before signup **soft-fails with exact activation instructions** instead of erroring.\n\n## Requires an upgrade\nFour families are marked in `primitive.help` under a free-plan disclaimer: **Functions** (hosted JavaScript on inbound mail), **Wake** schedules, **x402** USDC payments over email (invite-only), and **custom Domains**. They ship implemented and callable, and return a plan/entitlement error until the account is upgraded at [primitive.dev](https://www.primitive.dev).", - "summary": "Primitive gives an agent a real, working email identity with no SMTP credentials, no DNS, and no human in the loop. primitive.signup provisions a free account plus a managed *.primitive.email inbox in one call (no email, no code). The adapter caches the API key locally under ~/.pilot and injects it on every subsequent call automatically — the agent never sees, stores, or passes it. Call signup once; everything else…", + "tagline": "Email for AI agents \u2014 provision a managed inbox in one call, then send, receive, reply, and search real email over one REST API", + "description": "# Primitive \u2014 email for AI agents\n\n[Primitive](https://www.primitive.dev) gives an agent a real, working email identity with **no SMTP credentials, no DNS, and no human in the loop**. `primitive.signup` provisions a free account plus a managed `*.primitive.email` inbox in **one call** (no email, no code). The adapter caches the API key locally under `~/.pilot` and **injects it on every subsequent call automatically** \u2014 the agent never sees, stores, or passes it. Call signup once; everything else authenticates as you.\n\n## What you can do on the free plan\n- **Send** outbound mail, **reply** on-thread, and **batch-send**, with attachments and idempotency keys.\n- **Receive** at your managed inbox: list, get, search, download raw MIME + attachments, and follow conversations. Long-poll for new mail with `?since=&wait=30`.\n- **Filter** inbound mail, register **webhook endpoints**, and read **inbox readiness**.\n- **Primitive Memories** \u2014 durable JSON key-value state across turns, retries, and inbound messages.\n\n## Auth model\nOne step: `primitive.signup`. It mints a `prim_` API key + a provisioned inbox, caches both locally, and the key is injected on every call thereafter. **Idempotent** \u2014 a host that already has a key keeps it. Any method called before signup **soft-fails with exact activation instructions** instead of erroring.\n\n## Requires an upgrade\nFour families are marked in `primitive.help` under a free-plan disclaimer: **Functions** (hosted JavaScript on inbound mail), **Wake** schedules, **x402** USDC payments over email (invite-only), and **custom Domains**. They ship implemented and callable, and return a plan/entitlement error until the account is upgraded at [primitive.dev](https://www.primitive.dev).", + "summary": "Primitive gives an agent a real, working email identity with no SMTP credentials, no DNS, and no human in the loop. primitive.signup provisions a free account plus a managed *.primitive.email inbox in one call (no email, no code). The adapter caches the API key locally under ~/.pilot and injects it on every subsequent call automatically \u2014 the agent never sees, stores, or passes it. Call signup once; everything else\u2026", "categories": [ "comms" ], @@ -1333,7 +1644,7 @@ "methods": [ { "name": "primitive.signup", - "summary": "Provision your own Primitive account and a managed *.primitive.email inbox in ONE call — no email, no code, no human step", + "summary": "Provision your own Primitive account and a managed *.primitive.email inbox in ONE call \u2014 no email, no code, no human step", "example": "{}", "gated": "" }, @@ -1377,7 +1688,7 @@ "name": "primitive.add_domain", "summary": "Claim a new domain", "example": "{\"domain\": \"\", \"confirmed\": true, \"outbound\": true}", - "gated": "requires a custom domain whose DNS you control — the managed *.primitive.email inbox needs no domain setup" + "gated": "requires a custom domain whose DNS you control \u2014 the managed *.primitive.email inbox needs no domain setup" }, { "name": "primitive.update_domain", @@ -1527,103 +1838,103 @@ "name": "primitive.list_wake_schedules", "summary": "List wake schedules", "example": "{}", - "gated": "requires a plan/entitlement upgrade — Wake scheduling is not on the free agent plan" + "gated": "requires a plan/entitlement upgrade \u2014 Wake scheduling is not on the free agent plan" }, { "name": "primitive.create_wake_schedule", "summary": "Create a wake schedule", "example": "{\"from_address\": \"\", \"target_address\": \"\", \"command\": \"\", \"cron_expr\": \"\", \"args\": {\"...\": \"...\"}, \"timezone\": \"\", \"note\": \"\"}", - "gated": "requires a plan/entitlement upgrade — Wake scheduling is not on the free agent plan" + "gated": "requires a plan/entitlement upgrade \u2014 Wake scheduling is not on the free agent plan" }, { "name": "primitive.get_wake_schedule", "summary": "Get a wake schedule", "example": "{\"id\": \"\"}", - "gated": "requires a plan/entitlement upgrade — Wake scheduling is not on the free agent plan" + "gated": "requires a plan/entitlement upgrade \u2014 Wake scheduling is not on the free agent plan" }, { "name": "primitive.update_wake_schedule", "summary": "Update a wake schedule", "example": "{\"id\": \"\", \"enabled\": true, \"command\": \"\", \"args\": {\"...\": \"...\"}, \"cron_expr\": \"\", \"timezone\": \"\", \"from_address\": \"\"}", - "gated": "requires a plan/entitlement upgrade — Wake scheduling is not on the free agent plan" + "gated": "requires a plan/entitlement upgrade \u2014 Wake scheduling is not on the free agent plan" }, { "name": "primitive.delete_wake_schedule", "summary": "Delete a wake schedule", "example": "{\"id\": \"\"}", - "gated": "requires a plan/entitlement upgrade — Wake scheduling is not on the free agent plan" + "gated": "requires a plan/entitlement upgrade \u2014 Wake scheduling is not on the free agent plan" }, { "name": "primitive.run_wake_schedule", "summary": "Run a wake schedule now", "example": "{\"id\": \"\"}", - "gated": "requires a plan/entitlement upgrade — Wake scheduling is not on the free agent plan" + "gated": "requires a plan/entitlement upgrade \u2014 Wake scheduling is not on the free agent plan" }, { "name": "primitive.list_wake_authorizations", "summary": "List wake authorizations", "example": "{\"recipient_endpoint_id\": \"\"}", - "gated": "requires a plan/entitlement upgrade — Wake scheduling is not on the free agent plan" + "gated": "requires a plan/entitlement upgrade \u2014 Wake scheduling is not on the free agent plan" }, { "name": "primitive.create_wake_authorization", "summary": "Create a wake authorization", "example": "{\"recipient_endpoint_id\": \"\", \"allowed_sender_domain\": \"\", \"allowed_sender_address\": \"\", \"allowed_commands\": [\"...\"], \"note\": \"\"}", - "gated": "requires a plan/entitlement upgrade — Wake scheduling is not on the free agent plan" + "gated": "requires a plan/entitlement upgrade \u2014 Wake scheduling is not on the free agent plan" }, { "name": "primitive.update_wake_authorization", "summary": "Update a wake authorization", "example": "{\"id\": \"\", \"enabled\": true}", - "gated": "requires a plan/entitlement upgrade — Wake scheduling is not on the free agent plan" + "gated": "requires a plan/entitlement upgrade \u2014 Wake scheduling is not on the free agent plan" }, { "name": "primitive.delete_wake_authorization", "summary": "Delete a wake authorization", "example": "{\"id\": \"\"}", - "gated": "requires a plan/entitlement upgrade — Wake scheduling is not on the free agent plan" + "gated": "requires a plan/entitlement upgrade \u2014 Wake scheduling is not on the free agent plan" }, { "name": "primitive.list_wake_dispatches", "summary": "List recent wake dispatches", "example": "{\"limit\": 20}", - "gated": "requires a plan/entitlement upgrade — Wake scheduling is not on the free agent plan" + "gated": "requires a plan/entitlement upgrade \u2014 Wake scheduling is not on the free agent plan" }, { "name": "primitive.list_routes", "summary": "List recipient routes", "example": "{}", - "gated": "requires the recipient-routing feature — disabled on the free agent plan (the managed inbox routes to storage automatically)" + "gated": "requires the recipient-routing feature \u2014 disabled on the free agent plan (the managed inbox routes to storage automatically)" }, { "name": "primitive.create_route", "summary": "Create a recipient route", "example": "{\"match_type\": \"to\", \"pattern\": \"*@example.com\", \"endpoint_id\": \"\", \"function_id\": \"\", \"domain_id\": \"\", \"priority\": 0, \"enabled\": true}", - "gated": "requires the recipient-routing feature — disabled on the free agent plan (the managed inbox routes to storage automatically)" + "gated": "requires the recipient-routing feature \u2014 disabled on the free agent plan (the managed inbox routes to storage automatically)" }, { "name": "primitive.reorder_routes", "summary": "Reorder recipient routes", "example": "{\"updates\": [\"...\"]}", - "gated": "requires the recipient-routing feature — disabled on the free agent plan (the managed inbox routes to storage automatically)" + "gated": "requires the recipient-routing feature \u2014 disabled on the free agent plan (the managed inbox routes to storage automatically)" }, { "name": "primitive.simulate_route", "summary": "Simulate routing for a recipient", "example": "{\"recipient\": \"someone@example.com\", \"event_type\": \"\"}", - "gated": "requires the recipient-routing feature — disabled on the free agent plan (the managed inbox routes to storage automatically)" + "gated": "requires the recipient-routing feature \u2014 disabled on the free agent plan (the managed inbox routes to storage automatically)" }, { "name": "primitive.update_route", "summary": "Update a recipient route", "example": "{\"id\": \"\", \"match_type\": \"to\", \"pattern\": \"*@example.com\", \"endpoint_id\": \"\", \"domain_id\": \"\", \"priority\": 0, \"enabled\": true}", - "gated": "requires the recipient-routing feature — disabled on the free agent plan (the managed inbox routes to storage automatically)" + "gated": "requires the recipient-routing feature \u2014 disabled on the free agent plan (the managed inbox routes to storage automatically)" }, { "name": "primitive.delete_route", "summary": "Delete a recipient route", "example": "{\"id\": \"\"}", - "gated": "requires the recipient-routing feature — disabled on the free agent plan (the managed inbox routes to storage automatically)" + "gated": "requires the recipient-routing feature \u2014 disabled on the free agent plan (the managed inbox routes to storage automatically)" }, { "name": "primitive.list_deliveries", @@ -1653,7 +1964,7 @@ "name": "primitive.semantic_search", "summary": "Semantic search across received and sent mail", "example": "{\"query\": \"search terms\", \"mode\": \"\", \"corpus\": [\"...\"], \"search_in\": [\"...\"], \"exclude\": [\"...\"], \"date_from\": \"\", \"date_to\": \"\"}", - "gated": "requires the Pro plan — semantic search over mail is not on the free agent plan" + "gated": "requires the Pro plan \u2014 semantic search over mail is not on the free agent plan" }, { "name": "primitive.list_sent_emails", @@ -1677,121 +1988,121 @@ "name": "primitive.list_functions", "summary": "List functions", "example": "{}", - "gated": "requires the developer plan — confirm an email at primitive.dev to upgrade; hosted Functions are not on the free agent plan" + "gated": "requires the developer plan \u2014 confirm an email at primitive.dev to upgrade; hosted Functions are not on the free agent plan" }, { "name": "primitive.create_function", "summary": "Deploy a function", "example": "{\"name\": \"\", \"code\": \"\", \"sourceMap\": \"\", \"files\": {\"...\": \"...\"}}", - "gated": "requires the developer plan — confirm an email at primitive.dev to upgrade; hosted Functions are not on the free agent plan" + "gated": "requires the developer plan \u2014 confirm an email at primitive.dev to upgrade; hosted Functions are not on the free agent plan" }, { "name": "primitive.get_function", "summary": "Get a function", "example": "{\"id\": \"\"}", - "gated": "requires the developer plan — confirm an email at primitive.dev to upgrade; hosted Functions are not on the free agent plan" + "gated": "requires the developer plan \u2014 confirm an email at primitive.dev to upgrade; hosted Functions are not on the free agent plan" }, { "name": "primitive.update_function", "summary": "Update and redeploy a function", "example": "{\"id\": \"\", \"code\": \"\", \"sourceMap\": \"\", \"files\": {\"...\": \"...\"}}", - "gated": "requires the developer plan — confirm an email at primitive.dev to upgrade; hosted Functions are not on the free agent plan" + "gated": "requires the developer plan \u2014 confirm an email at primitive.dev to upgrade; hosted Functions are not on the free agent plan" }, { "name": "primitive.delete_function", "summary": "Delete a function", "example": "{\"id\": \"\"}", - "gated": "requires the developer plan — confirm an email at primitive.dev to upgrade; hosted Functions are not on the free agent plan" + "gated": "requires the developer plan \u2014 confirm an email at primitive.dev to upgrade; hosted Functions are not on the free agent plan" }, { "name": "primitive.test_function", "summary": "Send a test invocation", "example": "{\"id\": \"\", \"local_part\": \"\"}", - "gated": "requires the developer plan — confirm an email at primitive.dev to upgrade; hosted Functions are not on the free agent plan" + "gated": "requires the developer plan \u2014 confirm an email at primitive.dev to upgrade; hosted Functions are not on the free agent plan" }, { "name": "primitive.get_function_test_run_trace", "summary": "Get a function test run trace", "example": "{\"id\": \"\", \"run_id\": \"\"}", - "gated": "requires the developer plan — confirm an email at primitive.dev to upgrade; hosted Functions are not on the free agent plan" + "gated": "requires the developer plan \u2014 confirm an email at primitive.dev to upgrade; hosted Functions are not on the free agent plan" }, { "name": "primitive.get_org_routing_topology", "summary": "Get the org's function routing topology", "example": "{}", - "gated": "requires the developer plan — confirm an email at primitive.dev to upgrade; hosted Functions are not on the free agent plan" + "gated": "requires the developer plan \u2014 confirm an email at primitive.dev to upgrade; hosted Functions are not on the free agent plan" }, { "name": "primitive.get_function_routing", "summary": "Get a function's current route binding", "example": "{\"id\": \"\"}", - "gated": "requires the developer plan — confirm an email at primitive.dev to upgrade; hosted Functions are not on the free agent plan" + "gated": "requires the developer plan \u2014 confirm an email at primitive.dev to upgrade; hosted Functions are not on the free agent plan" }, { "name": "primitive.set_function_route", "summary": "Bind a route to a function", "example": "{\"id\": \"\", \"target\": {\"...\": \"...\"}, \"takeover\": true}", - "gated": "requires the developer plan — confirm an email at primitive.dev to upgrade; hosted Functions are not on the free agent plan" + "gated": "requires the developer plan \u2014 confirm an email at primitive.dev to upgrade; hosted Functions are not on the free agent plan" }, { "name": "primitive.unset_function_route", "summary": "Unbind any route from a function", "example": "{\"id\": \"\"}", - "gated": "requires the developer plan — confirm an email at primitive.dev to upgrade; hosted Functions are not on the free agent plan" + "gated": "requires the developer plan \u2014 confirm an email at primitive.dev to upgrade; hosted Functions are not on the free agent plan" }, { "name": "primitive.list_function_secrets", "summary": "List a function's secrets", "example": "{\"id\": \"\"}", - "gated": "requires the developer plan — confirm an email at primitive.dev to upgrade; hosted Functions are not on the free agent plan" + "gated": "requires the developer plan \u2014 confirm an email at primitive.dev to upgrade; hosted Functions are not on the free agent plan" }, { "name": "primitive.create_function_secret", "summary": "Create or update a secret", "example": "{\"id\": \"\", \"key\": \"namespace/key\", \"value\": {\"any\": \"json\"}}", - "gated": "requires the developer plan — confirm an email at primitive.dev to upgrade; hosted Functions are not on the free agent plan" + "gated": "requires the developer plan \u2014 confirm an email at primitive.dev to upgrade; hosted Functions are not on the free agent plan" }, { "name": "primitive.set_function_secret", "summary": "Set a secret by key", "example": "{\"id\": \"\", \"key\": \"namespace/key\", \"value\": {\"any\": \"json\"}}", - "gated": "requires the developer plan — confirm an email at primitive.dev to upgrade; hosted Functions are not on the free agent plan" + "gated": "requires the developer plan \u2014 confirm an email at primitive.dev to upgrade; hosted Functions are not on the free agent plan" }, { "name": "primitive.delete_function_secret", "summary": "Delete a secret", "example": "{\"id\": \"\", \"key\": \"namespace/key\"}", - "gated": "requires the developer plan — confirm an email at primitive.dev to upgrade; hosted Functions are not on the free agent plan" + "gated": "requires the developer plan \u2014 confirm an email at primitive.dev to upgrade; hosted Functions are not on the free agent plan" }, { "name": "primitive.list_org_secrets", "summary": "List org-level (global) secrets", "example": "{}", - "gated": "requires the developer plan — confirm an email at primitive.dev to upgrade; hosted Functions are not on the free agent plan" + "gated": "requires the developer plan \u2014 confirm an email at primitive.dev to upgrade; hosted Functions are not on the free agent plan" }, { "name": "primitive.create_org_secret", "summary": "Create or update an org secret", "example": "{\"key\": \"namespace/key\", \"value\": {\"any\": \"json\"}}", - "gated": "requires the developer plan — confirm an email at primitive.dev to upgrade; hosted Functions are not on the free agent plan" + "gated": "requires the developer plan \u2014 confirm an email at primitive.dev to upgrade; hosted Functions are not on the free agent plan" }, { "name": "primitive.set_org_secret", "summary": "Set an org secret by key", "example": "{\"key\": \"namespace/key\", \"value\": {\"any\": \"json\"}}", - "gated": "requires the developer plan — confirm an email at primitive.dev to upgrade; hosted Functions are not on the free agent plan" + "gated": "requires the developer plan \u2014 confirm an email at primitive.dev to upgrade; hosted Functions are not on the free agent plan" }, { "name": "primitive.delete_org_secret", "summary": "Delete an org secret", "example": "{\"key\": \"namespace/key\"}", - "gated": "requires the developer plan — confirm an email at primitive.dev to upgrade; hosted Functions are not on the free agent plan" + "gated": "requires the developer plan \u2014 confirm an email at primitive.dev to upgrade; hosted Functions are not on the free agent plan" }, { "name": "primitive.list_function_logs", "summary": "List a function's execution logs", "example": "{\"id\": \"\", \"limit\": 20, \"cursor\": \"\"}", - "gated": "requires the developer plan — confirm an email at primitive.dev to upgrade; hosted Functions are not on the free agent plan" + "gated": "requires the developer plan \u2014 confirm an email at primitive.dev to upgrade; hosted Functions are not on the free agent plan" }, { "name": "primitive.set_memory", @@ -1965,13 +2276,13 @@ "name": "primitive.install_template", "summary": "Install a function template", "example": "{\"id\": \"\", \"address\": \"someone@example.com\", \"domain\": \"\", \"variables\": {\"...\": \"...\"}, \"secrets\": {\"...\": \"...\"}}", - "gated": "requires the developer plan — installs a template as a hosted Function" + "gated": "requires the developer plan \u2014 installs a template as a hosted Function" }, { "name": "primitive.get_template_install", "summary": "Get template install status", "example": "{\"id\": \"\"}", - "gated": "requires the developer plan — tracks a hosted Function install" + "gated": "requires the developer plan \u2014 tracks a hosted Function install" }, { "name": "primitive.send_mail_batch", @@ -1981,7 +2292,7 @@ }, { "name": "primitive.ask", - "summary": "Ask about Primitive — NLWeb query (no authentication)", + "summary": "Ask about Primitive \u2014 NLWeb query (no authentication)", "example": "{\"q\": \"search terms\", \"prefer\": {\"...\": \"...\"}}", "gated": "" }, @@ -1997,7 +2308,7 @@ "version": "1.0.0", "date": "", "notes": [ - "Initial release — Primitive's email API for agents over one byo HTTPS app: 110 methods + primitive.help.", + "Initial release \u2014 Primitive's email API for agents over one byo HTTPS app: 110 methods + primitive.help.", "Emailless one-call signup (primitive.signup): mints a prim_ API key + a managed *.primitive.email inbox with no email or code; the key is cached locally and injected on every call automatically.", "Full email lifecycle on the free plan: send/reply/batch, inbound list/get/search/raw/attachments/conversations, threads, filters, webhook endpoints, and durable Memories.", "Functions, Wake schedules, x402 payments, and custom domains are implemented and marked gated until the account is upgraded." @@ -2014,7 +2325,7 @@ "limits": [ { "label": "Outbound send", - "value": "10 / hour · 50 / day (free 'agent' plan)" + "value": "10 / hour \u00b7 50 / day (free 'agent' plan)" }, { "label": "API requests", @@ -2030,7 +2341,7 @@ }, { "label": "Account creation", - "value": "rate-limited per IP (429 after several new accounts/day) — signup is idempotent, so reuse the cached key" + "value": "rate-limited per IP (429 after several new accounts/day) \u2014 signup is idempotent, so reuse the cached key" }, { "label": "Recipient scope", @@ -2082,9 +2393,9 @@ { "id": "io.pilot.agentphone", "name": "AgentPhone", - "tagline": "A real phone number for your agent — voice calls, SMS/iMessage, and conversations over REST", - "description": "# 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 & 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 & 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## First run: `agentphone.setup` (no signup, no agent)\n\nBecause this is the **managed** app there is no signup — but there is also **no agent or number**: the AgentPhone account is shared behind the broker and every Pilot user starts empty. So the first thing to do is call **`agentphone.setup`** once. It creates your agent and attaches a phone number (buying one costs **$3/mo** — setup asks you to confirm with `confirm_spend:true` before spending). After that, `agentphone.send_message` / `agentphone.place_call` work from the `agent_id` it returned. `agentphone.status` tells you at any time whether you're ready. 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## Your data is yours (per-user isolation)\n\nEven though every Pilot user shares one AgentPhone account, the broker isolates you completely: **you only ever see and act on your own agents, numbers, messages, calls, conversations, and contacts** — never another user's, whatever the method. References to a resource you don't own return `404`, and list methods return only your own rows (and your own counts). **Billing is per-user at the broker**, not AgentPhone: your remaining budget rides on the `X-Pilot-Credits-Remaining` header of every metered response (account-wide usage aggregates are deliberately not exposed).\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 & 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", - "summary": "AgentPhone gives your agent its own real US/Canada phone number: place and receive voice calls, send and receive SMS & 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…", + "tagline": "A real phone number for your agent \u2014 voice calls, SMS/iMessage, and conversations over REST", + "description": "# AgentPhone \u2014 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 & iMessage**, and hold threaded **conversations** with real people \u2014 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 \u2014 the phone rings in ~1\u20132s 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 \u2014 same call either way.\n- **Answer & follow up.** Poll `agentphone.list_number_messages` / `agentphone.list_conversation_messages` for inbound texts and `agentphone.get_call` for call transcripts \u2014 **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## First run: `agentphone.setup` (no signup, no agent)\n\nBecause this is the **managed** app there is no signup \u2014 but there is also **no agent or number**: the AgentPhone account is shared behind the broker and every Pilot user starts empty. So the first thing to do is call **`agentphone.setup`** once. It creates your agent and attaches a phone number (buying one costs **$3/mo** \u2014 setup asks you to confirm with `confirm_spend:true` before spending). After that, `agentphone.send_message` / `agentphone.place_call` work from the `agent_id` it returned. `agentphone.status` tells you at any time whether you're ready. 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## Your data is yours (per-user isolation)\n\nEven though every Pilot user shares one AgentPhone account, the broker isolates you completely: **you only ever see and act on your own agents, numbers, messages, calls, conversations, and contacts** \u2014 never another user's, whatever the method. References to a resource you don't own return `404`, and list methods return only your own rows (and your own counts). **Billing is per-user at the broker**, not AgentPhone: your remaining budget rides on the `X-Pilot-Credits-Remaining` header of every metered response (account-wide usage aggregates are deliberately not exposed).\n\n**Async, poll-based (no streaming):**\n1. `agentphone.place_call` \u2192 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 \u2014 they're blocked. If your human has an emergency, tell them to dial directly.\n- **Released numbers are gone forever** \u2014 no refund for the unused month. Confirm before `agentphone.release_number`.\n- **Always use E.164**: `+14155551234` \u2713 \u2014 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 \u2014 check the response `channel`.\n- **Don't spam.** Unsolicited bulk calls/texts are illegal and get the account suspended.\n\n## Cost & 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\u20130.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", + "summary": "AgentPhone gives your agent its own real US/Canada phone number: place and receive voice calls, send and receive SMS & iMessage, and hold threaded conversations with real people \u2014 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\u2026", "categories": [ "comms" ], @@ -2138,13 +2449,13 @@ }, { "name": "agentphone.list_voices", - "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.", + "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 \u2014 do not crash on missing fields. Use voice_id when creating/updating an agent. Read-only.", "example": "", "gated": "" }, { "name": "agentphone.list_agents", - "summary": "List the agents you own. Managed model: you start with NONE — run agentphone.setup first. You only ever see your own agents, never other users'.", + "summary": "List the agents you own. Managed model: you start with NONE \u2014 run agentphone.setup first. You only ever see your own agents, never other users'.", "example": "", "gated": "" }, @@ -2162,13 +2473,13 @@ }, { "name": "agentphone.update_agent", - "summary": "Update an agent — only the fields you send change. Any create field is updatable (systemPrompt, voice, modelTier, …). Free.", + "summary": "Update an agent \u2014 only the fields you send change. Any create field is updatable (systemPrompt, voice, modelTier, \u2026). Free.", "example": "", "gated": "" }, { "name": "agentphone.delete_agent", - "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.", + "summary": "Delete an agent. Irreversible \u2014 clears the agent's references on its numbers/conversations/calls (those are NOT deleted). Confirm with your human first. Free.", "example": "", "gated": "" }, @@ -2204,7 +2515,7 @@ }, { "name": "agentphone.buy_number", - "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.", + "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 \u2014 no need to store it yourself. Optionally attach to an agent and request an area code.", "example": "", "gated": "" }, @@ -2216,7 +2527,7 @@ }, { "name": "agentphone.release_number", - "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.", + "summary": "Release (delete) a number. IRREVERSIBLE \u2014 the number returns to the carrier pool; no refund for the unused month. Confirm with your human first. Free to call.", "example": "", "gated": "" }, @@ -2252,13 +2563,13 @@ }, { "name": "agentphone.send_message", - "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.", + "summary": "Send an SMS/iMessage. COSTS MONEY (~$0.01\u20130.02, debited from your $5 budget \u2192 402 if over). Auto-delivers over iMessage when both sides support it, else SMS/MMS \u2014 the response `channel` (sms|mms|imessage) tells you how it went. E.164 for `to_number` (or a group id grp_\u2026 for an iMessage group). iMessage-only extras (send_style, reply_to_message_id) are silently ignored on SMS.", "example": "", "gated": "" }, { "name": "agentphone.react", - "summary": "Send a tapback reaction to a message. iMessage ONLY — returns 400 on SMS. Free.", + "summary": "Send a tapback reaction to a message. iMessage ONLY \u2014 returns 400 on SMS. Free.", "example": "", "gated": "" }, @@ -2270,7 +2581,7 @@ }, { "name": "agentphone.place_call", - "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).", + "summary": "Place an OUTBOUND voice call. COSTS MONEY (per-minute, ~$0.05+, debited from your $5 budget \u2192 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) \u2014 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).", "example": "", "gated": "" }, @@ -2282,13 +2593,13 @@ }, { "name": "agentphone.end_call", - "summary": "Terminate an in-progress call. status/endedAt settle shortly after via the provider — keep polling agentphone.get_call until terminal. Free.", + "summary": "Terminate an in-progress call. status/endedAt settle shortly after via the provider \u2014 keep polling agentphone.get_call until terminal. Free.", "example": "", "gated": "" }, { "name": "agentphone.get_transcript", - "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.", + "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 \u2014 the adapter never uses the stream. Read-only.", "example": "", "gated": "" }, @@ -2354,7 +2665,7 @@ }, { "name": "agentphone.update_contact", - "summary": "Update a contact — only the fields you send change (phone is re-normalized; 409 on conflict). Free.", + "summary": "Update a contact \u2014 only the fields you send change (phone is re-normalized; 409 on conflict). Free.", "example": "", "gated": "" }, @@ -2372,13 +2683,13 @@ }, { "name": "agentphone.set_webhook", - "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.", + "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 \u2014 prefer per-agent webhooks or polling. Free.", "example": "", "gated": "" }, { "name": "agentphone.delete_webhook", - "summary": "Remove the account-level webhook. Global on the shared account — use with care. Free.", + "summary": "Remove the account-level webhook. Global on the shared account \u2014 use with care. Free.", "example": "", "gated": "" }, @@ -2408,7 +2719,7 @@ }, { "name": "agentphone.set_agent_webhook", - "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.", + "summary": "Set an agent-specific webhook URL (overrides the account default for THIS agent only \u2014 safer than the account-level webhook on a shared account). Free.", "example": "", "gated": "" }, @@ -2420,7 +2731,7 @@ }, { "name": "agentphone.mynumber", - "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.", + "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,...}]} \u2014 empty if this host hasn't provisioned one yet. Use it to find 'my number' without listing the shared account.", "example": "", "gated": "" } @@ -2430,7 +2741,7 @@ "version": "0.3.1", "date": "", "notes": [ - "Add agentphone.setup / agentphone.status: one-call onboarding for the managed model (no signup, no agent) — creates your agent and attaches a number; send_message/place_call point you to setup on a cold start.", + "Add agentphone.setup / agentphone.status: one-call onboarding for the managed model (no signup, no agent) \u2014 creates your agent and attaches a number; send_message/place_call point you to setup on a cold start.", "Per-user isolation: drop /v1/usage/daily and /v1/usage/monthly (shared-account aggregates that leaked other users' activity). Per-user budget is the broker ledger (X-Pilot-Credits-Remaining)." ] }, @@ -2438,7 +2749,7 @@ "version": "0.3.0", "date": "", "notes": [ - "Managed Pilot front door — no signup, no API key: the broker holds one master key and gives each user a $5 budget (402 on overdraw; reads free).", + "Managed Pilot front door \u2014 no signup, no API key: the broker holds one master key and gives each user a $5 budget (402 on overdraw; reads free).", "Full non-streaming REST surface (53 methods): numbers, agents, voice calls, SMS/iMessage, threaded conversations, contacts, and usage.", "Local recall: agentphone.buy_number captures the number to ~/.pilot/.agentphone; agentphone.mynumber reads it back with no backend call." ] @@ -2496,11 +2807,11 @@ "product_demo": { "skill": "io.pilot.agentphone", "title": "Full usage demo", - "when_to_use": "When your agent needs to place a real phone call or send an SMS/iMessage to a person — bookings, reminders, follow-ups, chasing a shipment or a missed call.", + "when_to_use": "When your agent needs to place a real phone call or send an SMS/iMessage to a person \u2014 bookings, reminders, follow-ups, chasing a shipment or a missed call.", "metered": true, "quickstart": { "title": "", - "goal": "Orient — check your account and $5 budget (free read)", + "goal": "Orient \u2014 check your account and $5 budget (free read)", "command": "pilotctl appstore call io.pilot.agentphone agentphone.usage '{}'", "expect": "{\"plan\":\"managed\",\"numbers\":{\"used\":0,\"limit\":1},\"stats\":{...}}", "cost": "$0.00 (read)", @@ -2532,7 +2843,7 @@ "note": "" }, { - "title": "Send a text (iMessage → SMS fallback)", + "title": "Send a text (iMessage \u2192 SMS fallback)", "goal": "", "command": "pilotctl appstore call io.pilot.agentphone agentphone.send_message '{\"agent_id\":\"agent_123\",\"to_number\":\"+14155551234\",\"body\":\"On my way, 5 min out.\"}'", "expect": "{\"id\":\"msg_...\",\"channel\":\"imessage\"}", @@ -2570,12 +2881,12 @@ "check_balance": "pilotctl appstore call io.pilot.agentphone agentphone.usage '{}'" }, "gotchas": [ - "Always use E.164 numbers (+14155551234) — never (415) 555-1234.", - "You cannot dial 911, N11, or crisis lines — they are blocked.", - "402 Payment Required means your $5.00 budget is spent — reads still work.", - "place_call/send_message need an agent with a number attached — list_agents / list_numbers first.", + "Always use E.164 numbers (+14155551234) \u2014 never (415) 555-1234.", + "You cannot dial 911, N11, or crisis lines \u2014 they are blocked.", + "402 Payment Required means your $5.00 budget is spent \u2014 reads still work.", + "place_call/send_message need an agent with a number attached \u2014 list_agents / list_numbers first.", "Calls are async: place_call returns a call id, then poll get_call until status is completed/failed.", - "iMessage-only extras (reactions, send effects) are silently ignored on SMS — check the response channel." + "iMessage-only extras (reactions, send effects) are silently ignored on SMS \u2014 check the response channel." ], "next": [ "io.pilot.agentphone agentphone.help '{}'" @@ -2585,9 +2896,9 @@ { "id": "io.pilot.postgres", "name": "PostgreSQL", - "tagline": "Run and query PostgreSQL from an agent — local server lifecycle + psql, any libpq target", - "description": "# PostgreSQL (psql + local server) — native CLI for agents\n\nThis app installs the official **PostgreSQL 17.5.0** toolchain on the host and fronts it as typed methods. The bundle is a relocatable build of PostgreSQL 17.5.0 (from conda-forge, compiled from the upstream PostgreSQL sources) carrying the **complete client + server suite**: `psql`, `initdb`, `pg_ctl`, `postgres`, `createdb`, `dropdb`, `pg_isready`, `pg_dump`, `pg_restore`, `pg_dumpall`, `vacuumdb`, `pg_basebackup`. Every binary is sha-pinned and staged at install; a tiny `pg` dispatcher in the bundle routes each method to the right tool.\n\n## Two ways to use it\n\n**A) Talk to an existing PostgreSQL server.** Point the query methods at any reachable server with a libpq `uri` (or `PG*` env) — no local server needed:\n- `postgres.query` / `postgres.query_csv` — run SQL, get an aligned table or CSV.\n- `postgres.command` — backslash introspection (`\\dt`, `\\d table`, `\\du`, `\\l`, …).\n- `postgres.list` — list databases. `postgres.version` / `postgres.psql_help` — client version and full `--help`.\n\n**B) Run a database locally on this machine.** The app can provision and manage its own cluster — useful for an agent that needs a throwaway or embedded Postgres:\n\n1. **Configure (one-time):** `postgres.initdb` `{ \"datadir\": \"/path/to/pgdata\" }` — creates the cluster (superuser `postgres`, local `trust` auth).\n2. **Start:** `postgres.start` `{ \"datadir\": \"/path/to/pgdata\", \"port\": \"5599\" }` — boots the server on `127.0.0.1:5599` (+ a Unix socket in the datadir), waits until ready, logs to `/postgres.log`.\n3. **Create a database:** `postgres.createdb` `{ \"port\": \"5599\", \"dbname\": \"appdb\" }`.\n4. **Use it:** `postgres.query` with `uri = \"host=127.0.0.1 port=5599 user=postgres dbname=appdb\"`.\n5. **Health / teardown:** `postgres.ready` `{ \"port\": \"5599\" }`, `postgres.status` `{ \"datadir\": \"...\" }`, `postgres.stop` `{ \"datadir\": \"...\" }`.\n\n## Configuration\n\nPostgreSQL is configuration-rich; the knobs this app exposes:\n\n- **`datadir`** — where the cluster lives. Pick a writable absolute path (e.g. `$HOME/.pilot/pgdata` or a tmp dir). One cluster can hold many databases.\n- **`port`** — TCP port for the local server (default convention `5599`). The server also listens on a Unix socket inside `datadir`.\n- **Auth** — local clusters are initialized with `trust` (no password) for convenience; for any networked use, set a password (`postgres.exec` → `psql ... -c \"ALTER ROLE postgres PASSWORD '...'\"`) and supply it via the `uri` or `PGPASSWORD`.\n- **Non-root for the server** — `postgres.initdb`/`postgres.start` run the PostgreSQL **server**, which refuses to run as the OS `root` user (a PostgreSQL safety rule). On a normal host the pilot daemon runs as your user, so this just works; only fully-root environments (e.g. some containers) need a non-root user. The query methods against a remote server are unaffected and run anywhere.\n- **`uri`** — a full libpq connection string, either `postgresql://user:secret@host:5432/dbname?sslmode=require` or `host=... port=... dbname=... user=... sslmode=...`.\n- **`PG*` env** — `PGHOST`, `PGPORT`, `PGUSER`, `PGPASSWORD`, `PGDATABASE`, `PGSSLMODE`, `PGOPTIONS`, `PGCONNECT_TIMEOUT`, `PGAPPNAME`, `PGCLIENTENCODING` are passed through to the child, so `postgres.exec` can connect with no inline credentials.\n- **Anything else** — full `postgresql.conf`/server flags are reachable via `postgres.exec` (e.g. `pg_ctl ... -o \"-c shared_buffers=256MB\"`), and per-session settings via SQL `SET`.\n\n## Good to know\n\n- Output returns verbatim where it is already clean; on a non-zero exit (SQL error, server down) the reply is `{stdout, stderr, exit}` so the caller sees everything the tool produced.\n- Runs on **macOS and Linux** (arm64 + amd64); binaries are fetched from the Pilot artifact registry and sha-pinned on install. Free and open source under the **PostgreSQL License**.\n- `postgres.help` lists every method with its latency class; this is the self-describing discovery contract.\n\n## `psql --help`\n```\npsql is the PostgreSQL interactive terminal.\n\nUsage:\n psql [OPTION]... [DBNAME [USERNAME]]\n\nGeneral options:\n -c, --command=COMMAND run only single command (SQL or internal) and exit\n -d, --dbname=DBNAME database name to connect to\n -f, --file=FILENAME execute commands from file, then exit\n -l, --list list available databases, then exit\n -v, --set=, --variable=NAME=VALUE\n set psql variable NAME to VALUE\n (e.g., -v ON_ERROR_STOP=1)\n -V, --version output version information, then exit\n -X, --no-psqlrc do not read startup file (~/.psqlrc)\n -1 (\"one\"), --single-transaction\n execute as a single transaction (if non-interactive)\n -?, --help[=options] show this help, then exit\n --help=commands list backslash commands, then exit\n --help=variables list special variables, then exit\n\nInput and output options:\n -a, --echo-all echo all input from script\n -b, --echo-errors echo failed commands\n -e, --echo-queries echo commands sent to server\n -E, --echo-hidden display queries that internal commands generate\n -L, --log-file=FILENAME send session log to file\n -n, --no-readline disable enhanced command line editing (readline)\n -o, --output=FILENAME send query results to file (or |pipe)\n -q, --quiet run quietly (no messages, only query output)\n -s, --single-step single-step mode (confirm each query)\n -S, --single-line single-line mode (end of line terminates SQL command)\n\nOutput format options:\n -A, --no-align unaligned table output mode\n --csv CSV (Comma-Separated Values) table output mode\n -F, --field-separator=STRING\n field separator for unaligned output (default: \"|\")\n -H, --html HTML table output mode\n -P, --pset=VAR[=ARG] set printing option VAR to ARG (see \\pset command)\n -R, --record-separator=STRING\n record separator for unaligned output (default: newline)\n -t, --tuples-only print rows only\n -T, --table-attr=TEXT set HTML table tag attributes (e.g., width, border)\n -x, --expanded turn on expanded table output\n -z, --field-separator-zero\n set field separator for unaligned output to zero byte\n -0, --record-separator-zero\n set record separator for unaligned output to zero byte\n\nConnection options:\n -h, --host=HOSTNAME database server host or socket directory\n -p, --port=PORT database server port\n -U, --username=USERNAME database user name\n -w, --no-password never prompt for password\n -W, --password force password prompt (should happen automatically)\n\nFor more information, type \"\\?\" (for internal commands) or \"\\help\" (for SQL\ncommands) from within psql, or consult the psql section in the PostgreSQL\ndocumentation.\n\nReport bugs to .\nPostgreSQL home page: \n```\n", - "summary": "This app installs the official PostgreSQL 17.5.0 toolchain on the host and fronts it as typed methods. The bundle is a relocatable build of PostgreSQL 17.5.0 (from conda-forge, compiled from the upstream PostgreSQL sources) carrying the complete client + server suite: psql, initdb, pg_ctl, postgres, createdb, dropdb, pg_isready, pg_dump, pg_restore, pg_dumpall, vacuumdb, pg_basebackup. Every binary is sha-pinned…", + "tagline": "Run and query PostgreSQL from an agent \u2014 local server lifecycle + psql, any libpq target", + "description": "# PostgreSQL (psql + local server) \u2014 native CLI for agents\n\nThis app installs the official **PostgreSQL 17.5.0** toolchain on the host and fronts it as typed methods. The bundle is a relocatable build of PostgreSQL 17.5.0 (from conda-forge, compiled from the upstream PostgreSQL sources) carrying the **complete client + server suite**: `psql`, `initdb`, `pg_ctl`, `postgres`, `createdb`, `dropdb`, `pg_isready`, `pg_dump`, `pg_restore`, `pg_dumpall`, `vacuumdb`, `pg_basebackup`. Every binary is sha-pinned and staged at install; a tiny `pg` dispatcher in the bundle routes each method to the right tool.\n\n## Two ways to use it\n\n**A) Talk to an existing PostgreSQL server.** Point the query methods at any reachable server with a libpq `uri` (or `PG*` env) \u2014 no local server needed:\n- `postgres.query` / `postgres.query_csv` \u2014 run SQL, get an aligned table or CSV.\n- `postgres.command` \u2014 backslash introspection (`\\dt`, `\\d table`, `\\du`, `\\l`, \u2026).\n- `postgres.list` \u2014 list databases. `postgres.version` / `postgres.psql_help` \u2014 client version and full `--help`.\n\n**B) Run a database locally on this machine.** The app can provision and manage its own cluster \u2014 useful for an agent that needs a throwaway or embedded Postgres:\n\n1. **Configure (one-time):** `postgres.initdb` `{ \"datadir\": \"/path/to/pgdata\" }` \u2014 creates the cluster (superuser `postgres`, local `trust` auth).\n2. **Start:** `postgres.start` `{ \"datadir\": \"/path/to/pgdata\", \"port\": \"5599\" }` \u2014 boots the server on `127.0.0.1:5599` (+ a Unix socket in the datadir), waits until ready, logs to `/postgres.log`.\n3. **Create a database:** `postgres.createdb` `{ \"port\": \"5599\", \"dbname\": \"appdb\" }`.\n4. **Use it:** `postgres.query` with `uri = \"host=127.0.0.1 port=5599 user=postgres dbname=appdb\"`.\n5. **Health / teardown:** `postgres.ready` `{ \"port\": \"5599\" }`, `postgres.status` `{ \"datadir\": \"...\" }`, `postgres.stop` `{ \"datadir\": \"...\" }`.\n\n## Configuration\n\nPostgreSQL is configuration-rich; the knobs this app exposes:\n\n- **`datadir`** \u2014 where the cluster lives. Pick a writable absolute path (e.g. `$HOME/.pilot/pgdata` or a tmp dir). One cluster can hold many databases.\n- **`port`** \u2014 TCP port for the local server (default convention `5599`). The server also listens on a Unix socket inside `datadir`.\n- **Auth** \u2014 local clusters are initialized with `trust` (no password) for convenience; for any networked use, set a password (`postgres.exec` \u2192 `psql ... -c \"ALTER ROLE postgres PASSWORD '...'\"`) and supply it via the `uri` or `PGPASSWORD`.\n- **Non-root for the server** \u2014 `postgres.initdb`/`postgres.start` run the PostgreSQL **server**, which refuses to run as the OS `root` user (a PostgreSQL safety rule). On a normal host the pilot daemon runs as your user, so this just works; only fully-root environments (e.g. some containers) need a non-root user. The query methods against a remote server are unaffected and run anywhere.\n- **`uri`** \u2014 a full libpq connection string, either `postgresql://user:secret@host:5432/dbname?sslmode=require` or `host=... port=... dbname=... user=... sslmode=...`.\n- **`PG*` env** \u2014 `PGHOST`, `PGPORT`, `PGUSER`, `PGPASSWORD`, `PGDATABASE`, `PGSSLMODE`, `PGOPTIONS`, `PGCONNECT_TIMEOUT`, `PGAPPNAME`, `PGCLIENTENCODING` are passed through to the child, so `postgres.exec` can connect with no inline credentials.\n- **Anything else** \u2014 full `postgresql.conf`/server flags are reachable via `postgres.exec` (e.g. `pg_ctl ... -o \"-c shared_buffers=256MB\"`), and per-session settings via SQL `SET`.\n\n## Good to know\n\n- Output returns verbatim where it is already clean; on a non-zero exit (SQL error, server down) the reply is `{stdout, stderr, exit}` so the caller sees everything the tool produced.\n- Runs on **macOS and Linux** (arm64 + amd64); binaries are fetched from the Pilot artifact registry and sha-pinned on install. Free and open source under the **PostgreSQL License**.\n- `postgres.help` lists every method with its latency class; this is the self-describing discovery contract.\n\n## `psql --help`\n```\npsql is the PostgreSQL interactive terminal.\n\nUsage:\n psql [OPTION]... [DBNAME [USERNAME]]\n\nGeneral options:\n -c, --command=COMMAND run only single command (SQL or internal) and exit\n -d, --dbname=DBNAME database name to connect to\n -f, --file=FILENAME execute commands from file, then exit\n -l, --list list available databases, then exit\n -v, --set=, --variable=NAME=VALUE\n set psql variable NAME to VALUE\n (e.g., -v ON_ERROR_STOP=1)\n -V, --version output version information, then exit\n -X, --no-psqlrc do not read startup file (~/.psqlrc)\n -1 (\"one\"), --single-transaction\n execute as a single transaction (if non-interactive)\n -?, --help[=options] show this help, then exit\n --help=commands list backslash commands, then exit\n --help=variables list special variables, then exit\n\nInput and output options:\n -a, --echo-all echo all input from script\n -b, --echo-errors echo failed commands\n -e, --echo-queries echo commands sent to server\n -E, --echo-hidden display queries that internal commands generate\n -L, --log-file=FILENAME send session log to file\n -n, --no-readline disable enhanced command line editing (readline)\n -o, --output=FILENAME send query results to file (or |pipe)\n -q, --quiet run quietly (no messages, only query output)\n -s, --single-step single-step mode (confirm each query)\n -S, --single-line single-line mode (end of line terminates SQL command)\n\nOutput format options:\n -A, --no-align unaligned table output mode\n --csv CSV (Comma-Separated Values) table output mode\n -F, --field-separator=STRING\n field separator for unaligned output (default: \"|\")\n -H, --html HTML table output mode\n -P, --pset=VAR[=ARG] set printing option VAR to ARG (see \\pset command)\n -R, --record-separator=STRING\n record separator for unaligned output (default: newline)\n -t, --tuples-only print rows only\n -T, --table-attr=TEXT set HTML table tag attributes (e.g., width, border)\n -x, --expanded turn on expanded table output\n -z, --field-separator-zero\n set field separator for unaligned output to zero byte\n -0, --record-separator-zero\n set record separator for unaligned output to zero byte\n\nConnection options:\n -h, --host=HOSTNAME database server host or socket directory\n -p, --port=PORT database server port\n -U, --username=USERNAME database user name\n -w, --no-password never prompt for password\n -W, --password force password prompt (should happen automatically)\n\nFor more information, type \"\\?\" (for internal commands) or \"\\help\" (for SQL\ncommands) from within psql, or consult the psql section in the PostgreSQL\ndocumentation.\n\nReport bugs to .\nPostgreSQL home page: \n```\n", + "summary": "This app installs the official PostgreSQL 17.5.0 toolchain on the host and fronts it as typed methods. The bundle is a relocatable build of PostgreSQL 17.5.0 (from conda-forge, compiled from the upstream PostgreSQL sources) carrying the complete client + server suite: psql, initdb, pg_ctl, postgres, createdb, dropdb, pg_isready, pg_dump, pg_restore, pg_dumpall, vacuumdb, pg_basebackup. Every binary is sha-pinned\u2026", "categories": [ "data" ], @@ -2614,7 +2925,7 @@ "methods": [ { "name": "postgres.initdb", - "summary": "Create (configure) a brand-new PostgreSQL data directory / cluster on this host — the one-time setup before a local server can start. Initializes `datadir` with superuser `postgres` and `trust` local auth (no password for local connections). Run once per cluster; `start` then brings it up. This is `initdb -D -U postgres -A trust --encoding=UTF8`.", + "summary": "Create (configure) a brand-new PostgreSQL data directory / cluster on this host \u2014 the one-time setup before a local server can start. Initializes `datadir` with superuser `postgres` and `trust` local auth (no password for local connections). Run once per cluster; `start` then brings it up. This is `initdb -D -U postgres -A trust --encoding=UTF8`.", "example": "", "gated": "" }, @@ -2656,7 +2967,7 @@ }, { "name": "postgres.query_csv", - "summary": "Same as postgres.query but returns the result set as CSV (header + rows) — the right shape when an agent needs to parse output. This is `psql -d --csv -c `. ON_ERROR_STOP=1 is set.", + "summary": "Same as postgres.query but returns the result set as CSV (header + rows) \u2014 the right shape when an agent needs to parse output. This is `psql -d --csv -c `. ON_ERROR_STOP=1 is set.", "example": "", "gated": "" }, @@ -2668,13 +2979,13 @@ }, { "name": "postgres.list", - "summary": "List the databases on the server (owner, encoding, collation, access privileges) as an aligned table — a quick connectivity + inventory check. This is `psql -d -l`.", + "summary": "List the databases on the server (owner, encoding, collation, access privileges) as an aligned table \u2014 a quick connectivity + inventory check. This is `psql -d -l`.", "example": "", "gated": "" }, { "name": "postgres.exec", - "summary": "Run any PostgreSQL client/server tool shipped in this bundle with a verbatim argv — the full surface beyond the curated methods. Payload is {\"args\":[, ...]} where the first element is the tool name (psql, initdb, pg_ctl, createdb, dropdb, pg_isready, pg_dump, pg_restore, pg_dumpall, vacuumdb, pg_basebackup, postgres) and the rest are its flags; optional {\"stdin\":\"...\"} is piped to the tool. Examples: {\"args\":[\"psql\",\"-d\",\"postgresql://127.0.0.1:5599/postgres\",\"-A\",\"-t\",\"-c\",\"select 1\"]}; {\"args\":[\"pg_dump\",\"-h\",\"127.0.0.1\",\"-p\",\"5599\",\"-U\",\"postgres\",\"mydb\"]}; {\"args\":[\"psql\",\"-d\",\"\"],\"stdin\":\"select 1;\\nselect 2;\"}. Connection can also come from PG* env vars passed through to the child.", + "summary": "Run any PostgreSQL client/server tool shipped in this bundle with a verbatim argv \u2014 the full surface beyond the curated methods. Payload is {\"args\":[, ...]} where the first element is the tool name (psql, initdb, pg_ctl, createdb, dropdb, pg_isready, pg_dump, pg_restore, pg_dumpall, vacuumdb, pg_basebackup, postgres) and the rest are its flags; optional {\"stdin\":\"...\"} is piped to the tool. Examples: {\"args\":[\"psql\",\"-d\",\"postgresql://127.0.0.1:5599/postgres\",\"-A\",\"-t\",\"-c\",\"select 1\"]}; {\"args\":[\"pg_dump\",\"-h\",\"127.0.0.1\",\"-p\",\"5599\",\"-U\",\"postgres\",\"mydb\"]}; {\"args\":[\"psql\",\"-d\",\"\"],\"stdin\":\"select 1;\\nselect 2;\"}. Connection can also come from PG* env vars passed through to the child.", "example": "", "gated": "" }, @@ -2748,7 +3059,7 @@ "product_demo": { "skill": "io.pilot.postgres", "title": "Full usage demo", - "when_to_use": "When you need a full PostgreSQL server RDBMS — rich SQL, extensions, concurrent clients over a libpq connection — rather than an in-process file db; requires a one-time initdb + start.", + "when_to_use": "When you need a full PostgreSQL server RDBMS \u2014 rich SQL, extensions, concurrent clients over a libpq connection \u2014 rather than an in-process file db; requires a one-time initdb + start.", "metered": false, "quickstart": { "title": "", @@ -2815,9 +3126,9 @@ { "id": "io.pilot.duckdb", "name": "DuckDB", - "tagline": "Run DuckDB from an agent — in-process analytical SQL over files, no server, no provisioning", - "description": "# DuckDB — in-process analytical SQL, native CLI for agents\n\nThis app installs the official **DuckDB 1.5.4** command-line shell on the host and fronts it as typed\nmethods. The bundle is the upstream DuckDB CLI binary (sha-pinned per OS/arch, fetched from the Pilot\nartifact registry at install) plus a tiny wrapper that serves a clean, complete `--help`.\n\nDuckDB is an **in-process** OLAP database — \"SQLite for analytics.\" There is **no server, no daemon, no\nport, no auth, and nothing to provision**: an agent opens an in-memory database (`:memory:`) or a single\n`.duckdb` file like any other file. That posture is exactly right for an autonomous agent working in its\nown sandbox with no cloud account.\n\n## Why an agent wants this\n\n- **Zero provisioning.** No `initdb`, no server lifecycle, no credentials, no \"is the daemon up?\" state.\n Run SQL against `:memory:` or a file and you're done.\n- **Query files in place — the killer feature.** Point SQL straight at CSV, Parquet, or JSON on disk with\n no load step: `SELECT region, sum(amount) FROM '/data/*.parquet' GROUP BY region`. The file *is* the table.\n- **Fast analytics on a laptop.** A columnar, vectorized engine: aggregations and joins over millions of\n rows run quickly in a single process, in the agent's own context.\n- **Agent-friendly output.** Get results as an aligned table, **CSV**, **JSON**, or **Markdown** — pick the\n shape that parses cleanly or drops straight into a report.\n- **Full SQL.** Window functions, CTEs, nested types (lists/structs/maps), `COPY` to/from Parquet/CSV, and\n a rich function library.\n- **Self-contained + offline.** One binary, no dependencies; the core CSV/Parquet/JSON readers are built in,\n so the common cases need no network and no extensions.\n\n## Methods\n\n- `duckdb.query` — run SQL, get an aligned `box` table (default). In-memory or against a file.\n- `duckdb.query_csv` / `duckdb.query_json` / `duckdb.query_markdown` — same, as CSV / JSON / Markdown.\n- `duckdb.file` — execute a `.sql` script file (migrations, ETL, multi-statement setup).\n- `duckdb.tables` — list every table and view (`SHOW ALL TABLES`).\n- `duckdb.schema` — print the `CREATE` DDL for the database (`.schema`).\n- `duckdb.exec` — run the CLI with a verbatim argv (+ optional stdin) for any flag, output mode, or\n dot-command the curated methods don't cover (`.mode`, `.import`, `.export`, `.read`, `-init`, …).\n- `duckdb.cli_help` — the complete CLI help: every option **and** every dot-command, as clean text.\n- `duckdb.version` — the delivered DuckDB version. `duckdb.help` — the self-describing method list.\n\n## How to use it\n\n1. **Quick analysis (no setup):** `duckdb.query` `{ \"database\": \":memory:\", \"sql\": \"SELECT count(*) FROM '/data/events.parquet'\" }`.\n2. **Persistent database:** point `database` at a file path (`/work/app.duckdb`); it's created on first use and\n persists. The same file holds many tables/schemas.\n3. **Parse the output:** use `duckdb.query_json` (array of row objects) or `duckdb.query_csv`.\n4. **Anything else:** `duckdb.exec` `{ \"args\": [\":memory:\", \"-cmd\", \".import /data/in.csv t\", \"-c\", \"SELECT count(*) FROM t\"] }`.\n\n## Configuration\n\n- **`database`** — `:memory:` (ephemeral, no provisioning) or an absolute path to a `.duckdb`/`.db` file\n (created on first use, persists, holds many tables). Independent of this, the SQL can read/write CSV,\n Parquet, and JSON files anywhere on disk.\n- **Output mode** — choose the method (`query` box / `query_csv` / `query_json` / `query_markdown`), or any\n other mode via `duckdb.exec` (`-line`, `-html`, `-ascii`, `-jsonlines`, …).\n- **Extensions** — Parquet/CSV/JSON readers are built in. Network-backed extensions (e.g. `httpfs` for S3/HTTP\n Parquet) are loadable via `duckdb.exec` (`INSTALL httpfs; LOAD httpfs;`) where the host allows egress; the\n local-only path needs neither.\n- **Read-only** — open a database without write access via `duckdb.exec` (`-readonly`).\n\n## Good to know\n\n- Output returns verbatim where it's already clean; on a non-zero exit (SQL error) the reply is\n `{stdout, stderr, exit}` so the caller sees everything the CLI produced.\n- Runs on **macOS and Linux** (arm64 + amd64); the binary is fetched from the Pilot artifact registry and\n sha-pinned on install. Free and open source under the **MIT License**.\n- `duckdb.help` lists every method with its latency class — the self-describing discovery contract.\n\n## DuckDB CLI help (`duckdb.cli_help`)\n```\nDuckDB CLI — command-line options and meta-commands\n===================================================\n\nDuckDB is an in-process analytical SQL database (think \"SQLite for analytics\").\nThe CLI runs SQL against an in-memory database (use ':memory:') or a database\nfile, and can query CSV, Parquet, and JSON files directly with no import step,\ne.g. SELECT * FROM 'data/*.parquet' WHERE ... — the file IS the table.\n\nUSAGE: duckdb [OPTIONS] [DATABASE_FILE] [SQL]\n\nDATABASE_FILE is a DuckDB database; it is created if it does not exist.\nUse ':memory:' for an ephemeral in-memory database.\n\n------------------------------------------------------------------------------\nCOMMAND-LINE OPTIONS (duckdb -help)\n------------------------------------------------------------------------------\n\nOPTIONS:\n -ascii set output mode to 'ascii'\n -bail stop after hitting an error\n -batch force batch I/O'\n -box set output mode to 'box'\n -column set output mode to 'column'\n -cmd COMMAND run \"COMMAND\" before reading stdin\n -csv set output mode to 'csv'\n -c COMMAND run \"COMMAND\" and exit\n -dark-mode use dark mode colors\n -echo print commands before execution\n -f FILENAME read/process named file and exit\n -init FILENAME read/process named file\n -header turn headers on\n -h show help message\n -help show help message\n -html set output mode to HTML\n -interactive force interactive I/O\n -json set output mode to 'json'\n -jsonlines set output mode to 'jsonlines'\n -light-mode use light mode colors\n -line set output mode to 'line'\n -list set output mode to 'list'\n -markdown set output mode to 'markdown'\n -newline SEP set output row separator. Default: '\\n'\n -no-init skip processing the init file\n -no-stdin exit after processing options instead of reading stdin\n -noheader turn headers off\n -nullvalue TEXT set text string for NULL values. Default 'NULL'\n -quote set output mode to 'quote'\n -readonly open the database read-only\n -s COMMAND run \"COMMAND\" and exit\n -safe enable safe-mode\n -separator SEP set output column separator. Default: '|'\n -storage-version VER database storage compatibility version to use. Default: 'v0.10.0'\n -table set output mode to 'table'\n -ui launches a web interface using the ui extension (configurable with .ui_command)\n -unredacted allow printing unredacted secrets\n -unsigned allow loading of unsigned extensions\n -version show DuckDB version\n\n------------------------------------------------------------------------------\nDOT-COMMANDS (meta-commands; usable inside the shell or via -cmd \"...\")\n------------------------------------------------------------------------------\n.bail on|off Stop after hitting an error. Default OFF\n.binary on|off Turn binary output on or off. Default OFF\n.cd DIRECTORY Change the working directory to DIRECTORY\n.changes on|off Show number of rows changed by SQL\n.columns Column-wise rendering of query results\n.decimal_sep SEP Sets the decimal separator used when rendering numbers. Only for duckbox mode.\n.databases List names and files of attached databases\n.dump ?TABLE? Render database content as SQL\n.display_colors [bold|underline] Display all terminal colors and their names\n.echo on|off Turn command echo on or off\n.edit Opens an external text editor to edit a query.\n.excel Display the output of next command in spreadsheet\n.exit ?CODE? Exit this program with return-code CODE\n.headers on|off Turn display of headers on or off\n.help ?-all? ?PATTERN? Show help text for PATTERN\n.highlight on|off Toggle syntax highlighting in the shell on/off\n.highlight_colors OPTIONS Configure highlighting colors\n.highlight_errors on|off Turn highlighting of errors on or off\n.highlight_mode mixed|dark|light Toggle the highlight mode to dark or light mode\n.highlight_results on|off Turn highlighting of results on or off\n.import FILE TABLE Import data from FILE into TABLE\n.indexes ?TABLE? Show names of indexes\n.last Render the last result without truncating\n.large_number_rendering MODE Toggle readable rendering of large numbers (duckbox only)\n.log FILE|off Turn logging on or off. FILE can be stderr/stdout\n.maxrows COUNT Sets the maximum number of rows for display (default: 40). Only for duckbox mode.\n.maxwidth COUNT Sets the maximum width in characters. 0 defaults to terminal width. Only for duckbox mode.\n.mode MODE ?TABLE? Set output mode\n.multiline Sets the render mode to multi-line\n.nullvalue STRING Use STRING in place of NULL values\n.open ?OPTIONS? ?FILE? Close existing database and reopen FILE\n.once ?FILE? Output for the next SQL command only to FILE\n.output ?FILE? Send output to FILE or stdout if FILE is omitted\n.pager OPTIONS Control pager usage for output\n.print STRING... Print literal STRING\n.progress_bar OPTIONS Configure the progress bar display\n.prompt MAIN CONTINUE Replace the standard prompts\n.quit Exit this program\n.read FILE Read input from FILE\n.read_line_version linenoise|fallback Sets the library used for processing interactive input\n.render_completion on|off Toggle displaying of completion prompts in the shell on/off\n.render_errors on|off Toggle rendering of errors in the shell on/off\n.rows Row-wise rendering of query results (default)\n.safe_mode Enable safe-mode\n.separator COL ?ROW? Change the column and row separators\n.schema ?PATTERN? Show the CREATE statements matching PATTERN\n.shell CMD ARGS... Run CMD ARGS... in a system shell\n.show Show the current values for various settings\n.singleline Sets the render mode to single-line\n.startup_text none|version|all Start-up text to display. Set this as the first line in .duckdbrc\n.system CMD ARGS... Run CMD ARGS... in a system shell\n.tables ?TABLE? List names of tables matching LIKE pattern TABLE\n.thousand_sep SEP Sets the thousand separator used when rendering numbers. Only for duckbox mode.\n.timer on|off Turn SQL timer on or off\n.ui_command [command] Set the UI command\n.version Show the version\n.width NUM1 NUM2 ... Set minimum column widths for columnar output\n\nRun .help --all for extended information\nRun .help shortcuts for keyboard shortcuts\n```\n", - "summary": "This app installs the official DuckDB 1.5.4 command-line shell on the host and fronts it as typed methods. The bundle is the upstream DuckDB CLI binary (sha-pinned per OS/arch, fetched from the Pilot artifact registry at install) plus a tiny wrapper that serves a clean, complete --help. DuckDB is an in-process OLAP database — \"SQLite for analytics.\" There is no server, no daemon, no port, no auth, and nothing to…", + "tagline": "Run DuckDB from an agent \u2014 in-process analytical SQL over files, no server, no provisioning", + "description": "# DuckDB \u2014 in-process analytical SQL, native CLI for agents\n\nThis app installs the official **DuckDB 1.5.4** command-line shell on the host and fronts it as typed\nmethods. The bundle is the upstream DuckDB CLI binary (sha-pinned per OS/arch, fetched from the Pilot\nartifact registry at install) plus a tiny wrapper that serves a clean, complete `--help`.\n\nDuckDB is an **in-process** OLAP database \u2014 \"SQLite for analytics.\" There is **no server, no daemon, no\nport, no auth, and nothing to provision**: an agent opens an in-memory database (`:memory:`) or a single\n`.duckdb` file like any other file. That posture is exactly right for an autonomous agent working in its\nown sandbox with no cloud account.\n\n## Why an agent wants this\n\n- **Zero provisioning.** No `initdb`, no server lifecycle, no credentials, no \"is the daemon up?\" state.\n Run SQL against `:memory:` or a file and you're done.\n- **Query files in place \u2014 the killer feature.** Point SQL straight at CSV, Parquet, or JSON on disk with\n no load step: `SELECT region, sum(amount) FROM '/data/*.parquet' GROUP BY region`. The file *is* the table.\n- **Fast analytics on a laptop.** A columnar, vectorized engine: aggregations and joins over millions of\n rows run quickly in a single process, in the agent's own context.\n- **Agent-friendly output.** Get results as an aligned table, **CSV**, **JSON**, or **Markdown** \u2014 pick the\n shape that parses cleanly or drops straight into a report.\n- **Full SQL.** Window functions, CTEs, nested types (lists/structs/maps), `COPY` to/from Parquet/CSV, and\n a rich function library.\n- **Self-contained + offline.** One binary, no dependencies; the core CSV/Parquet/JSON readers are built in,\n so the common cases need no network and no extensions.\n\n## Methods\n\n- `duckdb.query` \u2014 run SQL, get an aligned `box` table (default). In-memory or against a file.\n- `duckdb.query_csv` / `duckdb.query_json` / `duckdb.query_markdown` \u2014 same, as CSV / JSON / Markdown.\n- `duckdb.file` \u2014 execute a `.sql` script file (migrations, ETL, multi-statement setup).\n- `duckdb.tables` \u2014 list every table and view (`SHOW ALL TABLES`).\n- `duckdb.schema` \u2014 print the `CREATE` DDL for the database (`.schema`).\n- `duckdb.exec` \u2014 run the CLI with a verbatim argv (+ optional stdin) for any flag, output mode, or\n dot-command the curated methods don't cover (`.mode`, `.import`, `.export`, `.read`, `-init`, \u2026).\n- `duckdb.cli_help` \u2014 the complete CLI help: every option **and** every dot-command, as clean text.\n- `duckdb.version` \u2014 the delivered DuckDB version. `duckdb.help` \u2014 the self-describing method list.\n\n## How to use it\n\n1. **Quick analysis (no setup):** `duckdb.query` `{ \"database\": \":memory:\", \"sql\": \"SELECT count(*) FROM '/data/events.parquet'\" }`.\n2. **Persistent database:** point `database` at a file path (`/work/app.duckdb`); it's created on first use and\n persists. The same file holds many tables/schemas.\n3. **Parse the output:** use `duckdb.query_json` (array of row objects) or `duckdb.query_csv`.\n4. **Anything else:** `duckdb.exec` `{ \"args\": [\":memory:\", \"-cmd\", \".import /data/in.csv t\", \"-c\", \"SELECT count(*) FROM t\"] }`.\n\n## Configuration\n\n- **`database`** \u2014 `:memory:` (ephemeral, no provisioning) or an absolute path to a `.duckdb`/`.db` file\n (created on first use, persists, holds many tables). Independent of this, the SQL can read/write CSV,\n Parquet, and JSON files anywhere on disk.\n- **Output mode** \u2014 choose the method (`query` box / `query_csv` / `query_json` / `query_markdown`), or any\n other mode via `duckdb.exec` (`-line`, `-html`, `-ascii`, `-jsonlines`, \u2026).\n- **Extensions** \u2014 Parquet/CSV/JSON readers are built in. Network-backed extensions (e.g. `httpfs` for S3/HTTP\n Parquet) are loadable via `duckdb.exec` (`INSTALL httpfs; LOAD httpfs;`) where the host allows egress; the\n local-only path needs neither.\n- **Read-only** \u2014 open a database without write access via `duckdb.exec` (`-readonly`).\n\n## Good to know\n\n- Output returns verbatim where it's already clean; on a non-zero exit (SQL error) the reply is\n `{stdout, stderr, exit}` so the caller sees everything the CLI produced.\n- Runs on **macOS and Linux** (arm64 + amd64); the binary is fetched from the Pilot artifact registry and\n sha-pinned on install. Free and open source under the **MIT License**.\n- `duckdb.help` lists every method with its latency class \u2014 the self-describing discovery contract.\n\n## DuckDB CLI help (`duckdb.cli_help`)\n```\nDuckDB CLI \u2014 command-line options and meta-commands\n===================================================\n\nDuckDB is an in-process analytical SQL database (think \"SQLite for analytics\").\nThe CLI runs SQL against an in-memory database (use ':memory:') or a database\nfile, and can query CSV, Parquet, and JSON files directly with no import step,\ne.g. SELECT * FROM 'data/*.parquet' WHERE ... \u2014 the file IS the table.\n\nUSAGE: duckdb [OPTIONS] [DATABASE_FILE] [SQL]\n\nDATABASE_FILE is a DuckDB database; it is created if it does not exist.\nUse ':memory:' for an ephemeral in-memory database.\n\n------------------------------------------------------------------------------\nCOMMAND-LINE OPTIONS (duckdb -help)\n------------------------------------------------------------------------------\n\nOPTIONS:\n -ascii set output mode to 'ascii'\n -bail stop after hitting an error\n -batch force batch I/O'\n -box set output mode to 'box'\n -column set output mode to 'column'\n -cmd COMMAND run \"COMMAND\" before reading stdin\n -csv set output mode to 'csv'\n -c COMMAND run \"COMMAND\" and exit\n -dark-mode use dark mode colors\n -echo print commands before execution\n -f FILENAME read/process named file and exit\n -init FILENAME read/process named file\n -header turn headers on\n -h show help message\n -help show help message\n -html set output mode to HTML\n -interactive force interactive I/O\n -json set output mode to 'json'\n -jsonlines set output mode to 'jsonlines'\n -light-mode use light mode colors\n -line set output mode to 'line'\n -list set output mode to 'list'\n -markdown set output mode to 'markdown'\n -newline SEP set output row separator. Default: '\\n'\n -no-init skip processing the init file\n -no-stdin exit after processing options instead of reading stdin\n -noheader turn headers off\n -nullvalue TEXT set text string for NULL values. Default 'NULL'\n -quote set output mode to 'quote'\n -readonly open the database read-only\n -s COMMAND run \"COMMAND\" and exit\n -safe enable safe-mode\n -separator SEP set output column separator. Default: '|'\n -storage-version VER database storage compatibility version to use. Default: 'v0.10.0'\n -table set output mode to 'table'\n -ui launches a web interface using the ui extension (configurable with .ui_command)\n -unredacted allow printing unredacted secrets\n -unsigned allow loading of unsigned extensions\n -version show DuckDB version\n\n------------------------------------------------------------------------------\nDOT-COMMANDS (meta-commands; usable inside the shell or via -cmd \"...\")\n------------------------------------------------------------------------------\n.bail on|off Stop after hitting an error. Default OFF\n.binary on|off Turn binary output on or off. Default OFF\n.cd DIRECTORY Change the working directory to DIRECTORY\n.changes on|off Show number of rows changed by SQL\n.columns Column-wise rendering of query results\n.decimal_sep SEP Sets the decimal separator used when rendering numbers. Only for duckbox mode.\n.databases List names and files of attached databases\n.dump ?TABLE? Render database content as SQL\n.display_colors [bold|underline] Display all terminal colors and their names\n.echo on|off Turn command echo on or off\n.edit Opens an external text editor to edit a query.\n.excel Display the output of next command in spreadsheet\n.exit ?CODE? Exit this program with return-code CODE\n.headers on|off Turn display of headers on or off\n.help ?-all? ?PATTERN? Show help text for PATTERN\n.highlight on|off Toggle syntax highlighting in the shell on/off\n.highlight_colors OPTIONS Configure highlighting colors\n.highlight_errors on|off Turn highlighting of errors on or off\n.highlight_mode mixed|dark|light Toggle the highlight mode to dark or light mode\n.highlight_results on|off Turn highlighting of results on or off\n.import FILE TABLE Import data from FILE into TABLE\n.indexes ?TABLE? Show names of indexes\n.last Render the last result without truncating\n.large_number_rendering MODE Toggle readable rendering of large numbers (duckbox only)\n.log FILE|off Turn logging on or off. FILE can be stderr/stdout\n.maxrows COUNT Sets the maximum number of rows for display (default: 40). Only for duckbox mode.\n.maxwidth COUNT Sets the maximum width in characters. 0 defaults to terminal width. Only for duckbox mode.\n.mode MODE ?TABLE? Set output mode\n.multiline Sets the render mode to multi-line\n.nullvalue STRING Use STRING in place of NULL values\n.open ?OPTIONS? ?FILE? Close existing database and reopen FILE\n.once ?FILE? Output for the next SQL command only to FILE\n.output ?FILE? Send output to FILE or stdout if FILE is omitted\n.pager OPTIONS Control pager usage for output\n.print STRING... Print literal STRING\n.progress_bar OPTIONS Configure the progress bar display\n.prompt MAIN CONTINUE Replace the standard prompts\n.quit Exit this program\n.read FILE Read input from FILE\n.read_line_version linenoise|fallback Sets the library used for processing interactive input\n.render_completion on|off Toggle displaying of completion prompts in the shell on/off\n.render_errors on|off Toggle rendering of errors in the shell on/off\n.rows Row-wise rendering of query results (default)\n.safe_mode Enable safe-mode\n.separator COL ?ROW? Change the column and row separators\n.schema ?PATTERN? Show the CREATE statements matching PATTERN\n.shell CMD ARGS... Run CMD ARGS... in a system shell\n.show Show the current values for various settings\n.singleline Sets the render mode to single-line\n.startup_text none|version|all Start-up text to display. Set this as the first line in .duckdbrc\n.system CMD ARGS... Run CMD ARGS... in a system shell\n.tables ?TABLE? List names of tables matching LIKE pattern TABLE\n.thousand_sep SEP Sets the thousand separator used when rendering numbers. Only for duckbox mode.\n.timer on|off Turn SQL timer on or off\n.ui_command [command] Set the UI command\n.version Show the version\n.width NUM1 NUM2 ... Set minimum column widths for columnar output\n\nRun .help --all for extended information\nRun .help shortcuts for keyboard shortcuts\n```\n", + "summary": "This app installs the official DuckDB 1.5.4 command-line shell on the host and fronts it as typed methods. The bundle is the upstream DuckDB CLI binary (sha-pinned per OS/arch, fetched from the Pilot artifact registry at install) plus a tiny wrapper that serves a clean, complete --help. DuckDB is an in-process OLAP database \u2014 \"SQLite for analytics.\" There is no server, no daemon, no port, no auth, and nothing to\u2026", "categories": [ "data" ], @@ -2845,55 +3156,55 @@ "methods": [ { "name": "duckdb.query", - "summary": "Run a SQL statement (or `;`-separated batch) and return an aligned `box` table — the default, human-readable shape. Works in-memory (`database=\":memory:\"`) or against a DuckDB file, and can query CSV/Parquet/JSON files in place, e.g. `SELECT region, sum(amount) FROM '/data/*.parquet' GROUP BY region`. This is `duckdb -box -c `.", + "summary": "Run a SQL statement (or `;`-separated batch) and return an aligned `box` table \u2014 the default, human-readable shape. Works in-memory (`database=\":memory:\"`) or against a DuckDB file, and can query CSV/Parquet/JSON files in place, e.g. `SELECT region, sum(amount) FROM '/data/*.parquet' GROUP BY region`. This is `duckdb -box -c `.", "example": "", "gated": "" }, { "name": "duckdb.query_csv", - "summary": "Same as duckdb.query but returns the result set as CSV (header + rows) — the right shape when an agent needs to parse the output. This is `duckdb -csv -c `.", + "summary": "Same as duckdb.query but returns the result set as CSV (header + rows) \u2014 the right shape when an agent needs to parse the output. This is `duckdb -csv -c `.", "example": "", "gated": "" }, { "name": "duckdb.query_json", - "summary": "Run SQL and return the result set as a JSON array of row objects — the most directly machine-parseable output. This is `duckdb -json -c `.", + "summary": "Run SQL and return the result set as a JSON array of row objects \u2014 the most directly machine-parseable output. This is `duckdb -json -c `.", "example": "", "gated": "" }, { "name": "duckdb.query_markdown", - "summary": "Run SQL and return the result set as a GitHub-flavored Markdown table — handy when the output is going straight into a report or PR comment. This is `duckdb -markdown -c `.", + "summary": "Run SQL and return the result set as a GitHub-flavored Markdown table \u2014 handy when the output is going straight into a report or PR comment. This is `duckdb -markdown -c `.", "example": "", "gated": "" }, { "name": "duckdb.file", - "summary": "Execute a `.sql` script file against the database and exit — for multi-statement setups, migrations, or ETL scripts the agent has written to disk. This is `duckdb -f `.", + "summary": "Execute a `.sql` script file against the database and exit \u2014 for multi-statement setups, migrations, or ETL scripts the agent has written to disk. This is `duckdb -f `.", "example": "", "gated": "" }, { "name": "duckdb.tables", - "summary": "List every table and view across all attached databases/schemas (name, database, schema, column list) as a `box` table — a quick inventory of what a DuckDB file holds. This is `duckdb -box -c \"SHOW ALL TABLES\"`.", + "summary": "List every table and view across all attached databases/schemas (name, database, schema, column list) as a `box` table \u2014 a quick inventory of what a DuckDB file holds. This is `duckdb -box -c \"SHOW ALL TABLES\"`.", "example": "", "gated": "" }, { "name": "duckdb.schema", - "summary": "Print the `CREATE` statements for every table, view, and index in the database — the DDL, via DuckDB's `.schema` meta-command. This is `duckdb -no-stdin -cmd \".schema\"`.", + "summary": "Print the `CREATE` statements for every table, view, and index in the database \u2014 the DDL, via DuckDB's `.schema` meta-command. This is `duckdb -no-stdin -cmd \".schema\"`.", "example": "", "gated": "" }, { "name": "duckdb.exec", - "summary": "Run the DuckDB CLI with a verbatim argv — the full surface beyond the curated methods. Payload is {\"args\":[...]} (the args passed straight to `duckdb`) plus optional {\"stdin\":\"...\"} piped to the process. Use it for any flag or meta-command the curated methods don't cover: a different output mode (`-line`, `-html`, `-ascii`), reading a script with `-init`, a `.mode`/`.import`/`.read` dot-command via `-cmd`, or a multi-statement session over stdin. Examples: {\"args\":[\":memory:\",\"-line\",\"-c\",\"SELECT 1\"]}; {\"args\":[\"/data/app.duckdb\",\"-csv\",\"-cmd\",\".import /data/in.csv t\",\"-c\",\"SELECT count(*) FROM t\"]}; {\"args\":[\":memory:\"],\"stdin\":\"CREATE TABLE t(x int);\\nINSERT INTO t VALUES (1),(2);\\nSELECT sum(x) FROM t;\"}.", + "summary": "Run the DuckDB CLI with a verbatim argv \u2014 the full surface beyond the curated methods. Payload is {\"args\":[...]} (the args passed straight to `duckdb`) plus optional {\"stdin\":\"...\"} piped to the process. Use it for any flag or meta-command the curated methods don't cover: a different output mode (`-line`, `-html`, `-ascii`), reading a script with `-init`, a `.mode`/`.import`/`.read` dot-command via `-cmd`, or a multi-statement session over stdin. Examples: {\"args\":[\":memory:\",\"-line\",\"-c\",\"SELECT 1\"]}; {\"args\":[\"/data/app.duckdb\",\"-csv\",\"-cmd\",\".import /data/in.csv t\",\"-c\",\"SELECT count(*) FROM t\"]}; {\"args\":[\":memory:\"],\"stdin\":\"CREATE TABLE t(x int);\\nINSERT INTO t VALUES (1),(2);\\nSELECT sum(x) FROM t;\"}.", "example": "", "gated": "" }, { "name": "duckdb.cli_help", - "summary": "Return the complete DuckDB CLI help — every command-line option AND every dot-command (`.mode`, `.tables`, `.schema`, `.read`, `.import`, `.export`, `.timer`, …) — captured verbatim from the delivered binary and rendered as clean, color-free text. The full reference for what duckdb.query / duckdb.exec accept.", + "summary": "Return the complete DuckDB CLI help \u2014 every command-line option AND every dot-command (`.mode`, `.tables`, `.schema`, `.read`, `.import`, `.export`, `.timer`, \u2026) \u2014 captured verbatim from the delivered binary and rendered as clean, color-free text. The full reference for what duckdb.query / duckdb.exec accept.", "example": "", "gated": "" }, @@ -2967,11 +3278,11 @@ "product_demo": { "skill": "io.pilot.duckdb", "title": "Full usage demo", - "when_to_use": "When you need an in-process OLAP/SQL engine to query CSV, Parquet or JSON files and crunch analytics locally with zero server — not for concurrent writes or a long-lived shared database.", + "when_to_use": "When you need an in-process OLAP/SQL engine to query CSV, Parquet or JSON files and crunch analytics locally with zero server \u2014 not for concurrent writes or a long-lived shared database.", "metered": false, "quickstart": { "title": "", - "goal": "Run your first query (no provisioning — in-memory)", + "goal": "Run your first query (no provisioning \u2014 in-memory)", "command": "pilotctl appstore call io.pilot.duckdb duckdb.query '{\"database\":\":memory:\",\"sql\":\"SELECT 42 AS answer\"}'", "expect": "an aligned box table with one column `answer` and value 42", "cost": "", @@ -2979,7 +3290,7 @@ }, "examples": [ { - "title": "Aggregate a CSV file in place — no import step", + "title": "Aggregate a CSV file in place \u2014 no import step", "goal": "Group and count straight over a file on disk", "command": "pilotctl appstore call io.pilot.duckdb duckdb.query_json '{\"database\":\":memory:\",\"sql\":\"SELECT country, count(*) AS n FROM read_csv_auto('/data/users.csv') GROUP BY 1 ORDER BY n DESC\"}'", "expect": "JSON array of row objects, e.g. [{\"country\":\"US\",\"n\":120},{\"country\":\"DE\",\"n\":44}]", @@ -3014,7 +3325,7 @@ "cost": null, "gotchas": [ "File paths (read_csv_auto, read_parquet, .duckdb files) resolve inside the app sandbox, not your shell CWD.", - "`database` is required on every query — use \":memory:\" for throwaway work or an absolute .duckdb path to persist.", + "`database` is required on every query \u2014 use \":memory:\" for throwaway work or an absolute .duckdb path to persist.", ":memory: databases vanish when the call returns; nothing is saved.", "Single-writer engine: great for analytics, not for many concurrent writers." ], @@ -3026,9 +3337,9 @@ { "id": "io.pilot.sqlite", "name": "SQLite", - "tagline": "Run SQLite from an agent — zero-server, single-file transactional SQL, no provisioning", - "description": "# SQLite — zero-server transactional SQL, native CLI for agents\n\nThis app installs the official **SQLite 3.45.2** command-line shell (`sqlite3`) on the host and fronts it\nas typed methods. The bundle is the upstream sqlite3 CLI binary (sha-pinned per OS/arch, fetched from the\nPilot artifact registry at install) plus a tiny wrapper that serves a clean, complete `--help`.\n\nSQLite is a **zero-server, single-file, transactional (OLTP)** SQL engine — the most widely deployed\ndatabase in the world. There is **no server, no daemon, no port, no auth, and nothing to provision**: an\nagent opens an in-memory database (`:memory:`) or a single `.db` file like any other file. It is the\ndurable, on-disk complement to **DuckDB's in-memory analytics** ([io.pilot.duckdb](https://pilotprotocol.network)) —\nreal transactional SQL and durable agent memory, locally, with no cloud account.\n\n## Why an agent wants this\n\n- **Zero provisioning.** No server lifecycle, no credentials, no \"is the daemon up?\" state. Open `:memory:`\n or a file and run SQL.\n- **Durable, transactional storage — the killer feature.** A single `.db` file *is* the database: ACID\n transactions, real constraints, indexes, triggers, and full-text search, all persisted to one file the\n agent can copy, back up, or hand off. The right home for durable agent memory and structured state.\n- **Universal + rock-solid.** SQLite is public-domain, exhaustively tested, and backward-compatible — the\n format your data will still open in decades from now.\n- **Agent-friendly output.** `sqlite.query` returns rows as **JSON**; other shapes (CSV, table, Markdown,\n line, HTML) are one `sqlite.exec` away.\n- **Full SQL.** Window functions, CTEs, JSON1, generated columns, upserts, FTS5, and a rich function library.\n- **Self-contained + offline.** One binary, no dependencies, no network.\n\n## Methods\n\n- `sqlite.query` — run SQL, get rows back as a **JSON** array. In-memory or against a file.\n- `sqlite.script` — run a multi-statement SQL script (DDL + DML + a trailing SELECT) in one call.\n- `sqlite.schema` — print the `CREATE` DDL for every object in the database (`.schema`).\n- `sqlite.tables` — list the tables in the database (`.tables`).\n- `sqlite.exec` — run the CLI with a verbatim argv (+ optional stdin) for any flag, output mode, or\n dot-command the curated methods don't cover (`.dump`, `.import`, `.backup`, `.clone`, `.read`, `-csv`, …).\n- `sqlite.cli_help` — the complete CLI help: every option **and** every dot-command, as clean text.\n- `sqlite.version` — the delivered SQLite version. `sqlite.help` — the self-describing method list.\n\n## How to use it\n\n1. **Quick query (no setup):** `sqlite.query` `{ \"database\": \":memory:\", \"sql\": \"SELECT 42 AS answer\" }`.\n2. **Persistent database:** point `database` at a file path (`/work/app.db`); it's created on first use and\n persists. The same file holds many tables, indexes, and views.\n3. **Set up a schema:** `sqlite.script` `{ \"database\": \"/work/app.db\", \"sql\": \"CREATE TABLE notes(id INTEGER PRIMARY KEY, body TEXT); INSERT INTO notes(body) VALUES ('hello');\" }`.\n4. **Anything else:** `sqlite.exec` `{ \"args\": [\"/work/app.db\", \"-cmd\", \".mode csv\", \"-cmd\", \".import /data/in.csv t\", \"SELECT count(*) FROM t\"] }`.\n\n## Configuration\n\n- **`database`** — `:memory:` (ephemeral, no provisioning) or an absolute path to a `.db`/`.sqlite` file\n (created on first use, persists, holds many tables).\n- **Output mode** — `sqlite.query` returns JSON; choose any other mode via `sqlite.exec` (`-csv`, `-table`,\n `-markdown`, `-line`, `-html`, `-box`, `-ascii`).\n- **Read-only** — open a database without write access via `sqlite.exec` (`-readonly`).\n\n## Good to know\n\n- On a non-zero exit (SQL error) the reply is `{stdout, stderr, exit}` so the caller sees everything the\n CLI produced.\n- Runs on **macOS and Linux** (arm64 + amd64); the binary is fetched from the Pilot artifact registry and\n sha-pinned on install. SQLite is in the **public domain** (the \"blessing\" license).\n- `sqlite.help` lists every method with its latency class — the self-describing discovery contract.\n\n## SQLite CLI help (`sqlite.cli_help`)\n```\nSQLite CLI (sqlite3) — command-line options and meta-commands\n=============================================================\n\nSQLite is a zero-server, single-file, transactional SQL database engine.\nThe sqlite3 CLI runs SQL against a database file (created if it does not\nexist) or an in-memory database (use ':memory:' or omit the filename).\n\nUSAGE: sqlite3 [OPTIONS] [FILENAME] [SQL]\n\nFILENAME is an SQLite database file; ':memory:' is an ephemeral in-memory DB.\nA trailing SQL string is executed (may contain multiple ;-separated statements).\n\n------------------------------------------------------------------------------\nCOMMAND-LINE OPTIONS (sqlite3 -help)\n------------------------------------------------------------------------------\n -- treat no subsequent arguments as options\n -append append the database to the end of the file\n -ascii set output mode to 'ascii'\n -bail stop after hitting an error\n -batch force batch I/O\n -box set output mode to 'box'\n -column set output mode to 'column'\n -cmd COMMAND run \"COMMAND\" before reading stdin\n -csv set output mode to 'csv'\n -deserialize open the database using sqlite3_deserialize()\n -echo print inputs before execution\n -init FILENAME read/process named file\n -[no]header turn headers on or off\n -help show this message\n -html set output mode to HTML\n -interactive force interactive I/O\n -json set output mode to 'json'\n -line set output mode to 'line'\n -list set output mode to 'list'\n -lookaside SIZE N use N entries of SZ bytes for lookaside memory\n -markdown set output mode to 'markdown'\n -maxsize N maximum size for a --deserialize database\n -memtrace trace all memory allocations and deallocations\n -mmap N default mmap size set to N\n -newline SEP set output row separator. Default: '\\n'\n -nofollow refuse to open symbolic links to database files\n -nonce STRING set the safe-mode escape nonce\n -nullvalue TEXT set text string for NULL values. Default ''\n -pagecache SIZE N use N slots of SZ bytes each for page cache memory\n -pcachetrace trace all page cache operations\n -quote set output mode to 'quote'\n -readonly open the database read-only\n -safe enable safe-mode\n -separator SEP set output column separator. Default: '|'\n -stats print memory stats before each finalize\n -table set output mode to 'table'\n -tabs set output mode to 'tabs'\n -unsafe-testing allow unsafe commands and modes for testing\n -version show SQLite version\n -vfs NAME use NAME as the default VFS\n\n------------------------------------------------------------------------------\nDOT-COMMANDS (meta-commands; usable inside the shell or via -cmd \"...\")\n------------------------------------------------------------------------------\n.auth ON|OFF Show authorizer callbacks\n.backup ?DB? FILE Backup DB (default \"main\") to FILE\n.bail on|off Stop after hitting an error. Default OFF\n.cd DIRECTORY Change the working directory to DIRECTORY\n.changes on|off Show number of rows changed by SQL\n.check GLOB Fail if output since .testcase does not match\n.clone NEWDB Clone data into NEWDB from the existing database\n.connection [close] [#] Open or close an auxiliary database connection\n.databases List names and files of attached databases\n.dbconfig ?op? ?val? List or change sqlite3_db_config() options\n.dump ?OBJECTS? Render database content as SQL\n.echo on|off Turn command echo on or off\n.eqp on|off|full|... Enable or disable automatic EXPLAIN QUERY PLAN\n.excel Display the output of next command in spreadsheet\n.exit ?CODE? Exit this program with return-code CODE\n.expert EXPERIMENTAL. Suggest indexes for queries\n.explain ?on|off|auto? Change the EXPLAIN formatting mode. Default: auto\n.filectrl CMD ... Run various sqlite3_file_control() operations\n.fullschema ?--indent? Show schema and the content of sqlite_stat tables\n.headers on|off Turn display of headers on or off\n.help ?-all? ?PATTERN? Show help text for PATTERN\n.import FILE TABLE Import data from FILE into TABLE\n.indexes ?TABLE? Show names of indexes\n.limit ?LIMIT? ?VAL? Display or change the value of an SQLITE_LIMIT\n.lint OPTIONS Report potential schema issues.\n.load FILE ?ENTRY? Load an extension library\n.log FILE|on|off Turn logging on or off. FILE can be stderr/stdout\n.mode MODE ?OPTIONS? Set output mode\n.nonce STRING Suspend safe mode for one command if nonce matches\n.nullvalue STRING Use STRING in place of NULL values\n.once ?OPTIONS? ?FILE? Output for the next SQL command only to FILE\n.open ?OPTIONS? ?FILE? Close existing database and reopen FILE\n.output ?FILE? Send output to FILE or stdout if FILE is omitted\n.parameter CMD ... Manage SQL parameter bindings\n.print STRING... Print literal STRING\n.progress N Invoke progress handler after every N opcodes\n.prompt MAIN CONTINUE Replace the standard prompts\n.quit Stop interpreting input stream, exit if primary.\n.read FILE Read input from FILE or command output\n.restore ?DB? FILE Restore content of DB (default \"main\") from FILE\n.save ?OPTIONS? FILE Write database to FILE (an alias for .backup ...)\n.scanstats on|off|est Turn sqlite3_stmt_scanstatus() metrics on or off\n.schema ?PATTERN? Show the CREATE statements matching PATTERN\n.separator COL ?ROW? Change the column and row separators\n.sha3sum ... Compute a SHA3 hash of database content\n.shell CMD ARGS... Run CMD ARGS... in a system shell\n.show Show the current values for various settings\n.stats ?ARG? Show stats or turn stats on or off\n.system CMD ARGS... Run CMD ARGS... in a system shell\n.tables ?TABLE? List names of tables matching LIKE pattern TABLE\n.timeout MS Try opening locked tables for MS milliseconds\n.timer on|off Turn SQL timer on or off\n.trace ?OPTIONS? Output each SQL statement as it is run\n.version Show source, library and compiler versions\n.vfsinfo ?AUX? Information about the top-level VFS\n.vfslist List all available VFSes\n.vfsname ?AUX? Print the name of the VFS stack\n.width NUM1 NUM2 ... Set minimum column widths for columnar output\n\n```\n", - "summary": "This app installs the official SQLite 3.45.2 command-line shell (sqlite3) on the host and fronts it as typed methods. The bundle is the upstream sqlite3 CLI binary (sha-pinned per OS/arch, fetched from the Pilot artifact registry at install) plus a tiny wrapper that serves a clean, complete --help. SQLite is a zero-server, single-file, transactional (OLTP) SQL engine — the most widely deployed database in the…", + "tagline": "Run SQLite from an agent \u2014 zero-server, single-file transactional SQL, no provisioning", + "description": "# SQLite \u2014 zero-server transactional SQL, native CLI for agents\n\nThis app installs the official **SQLite 3.45.2** command-line shell (`sqlite3`) on the host and fronts it\nas typed methods. The bundle is the upstream sqlite3 CLI binary (sha-pinned per OS/arch, fetched from the\nPilot artifact registry at install) plus a tiny wrapper that serves a clean, complete `--help`.\n\nSQLite is a **zero-server, single-file, transactional (OLTP)** SQL engine \u2014 the most widely deployed\ndatabase in the world. There is **no server, no daemon, no port, no auth, and nothing to provision**: an\nagent opens an in-memory database (`:memory:`) or a single `.db` file like any other file. It is the\ndurable, on-disk complement to **DuckDB's in-memory analytics** ([io.pilot.duckdb](https://pilotprotocol.network)) \u2014\nreal transactional SQL and durable agent memory, locally, with no cloud account.\n\n## Why an agent wants this\n\n- **Zero provisioning.** No server lifecycle, no credentials, no \"is the daemon up?\" state. Open `:memory:`\n or a file and run SQL.\n- **Durable, transactional storage \u2014 the killer feature.** A single `.db` file *is* the database: ACID\n transactions, real constraints, indexes, triggers, and full-text search, all persisted to one file the\n agent can copy, back up, or hand off. The right home for durable agent memory and structured state.\n- **Universal + rock-solid.** SQLite is public-domain, exhaustively tested, and backward-compatible \u2014 the\n format your data will still open in decades from now.\n- **Agent-friendly output.** `sqlite.query` returns rows as **JSON**; other shapes (CSV, table, Markdown,\n line, HTML) are one `sqlite.exec` away.\n- **Full SQL.** Window functions, CTEs, JSON1, generated columns, upserts, FTS5, and a rich function library.\n- **Self-contained + offline.** One binary, no dependencies, no network.\n\n## Methods\n\n- `sqlite.query` \u2014 run SQL, get rows back as a **JSON** array. In-memory or against a file.\n- `sqlite.script` \u2014 run a multi-statement SQL script (DDL + DML + a trailing SELECT) in one call.\n- `sqlite.schema` \u2014 print the `CREATE` DDL for every object in the database (`.schema`).\n- `sqlite.tables` \u2014 list the tables in the database (`.tables`).\n- `sqlite.exec` \u2014 run the CLI with a verbatim argv (+ optional stdin) for any flag, output mode, or\n dot-command the curated methods don't cover (`.dump`, `.import`, `.backup`, `.clone`, `.read`, `-csv`, \u2026).\n- `sqlite.cli_help` \u2014 the complete CLI help: every option **and** every dot-command, as clean text.\n- `sqlite.version` \u2014 the delivered SQLite version. `sqlite.help` \u2014 the self-describing method list.\n\n## How to use it\n\n1. **Quick query (no setup):** `sqlite.query` `{ \"database\": \":memory:\", \"sql\": \"SELECT 42 AS answer\" }`.\n2. **Persistent database:** point `database` at a file path (`/work/app.db`); it's created on first use and\n persists. The same file holds many tables, indexes, and views.\n3. **Set up a schema:** `sqlite.script` `{ \"database\": \"/work/app.db\", \"sql\": \"CREATE TABLE notes(id INTEGER PRIMARY KEY, body TEXT); INSERT INTO notes(body) VALUES ('hello');\" }`.\n4. **Anything else:** `sqlite.exec` `{ \"args\": [\"/work/app.db\", \"-cmd\", \".mode csv\", \"-cmd\", \".import /data/in.csv t\", \"SELECT count(*) FROM t\"] }`.\n\n## Configuration\n\n- **`database`** \u2014 `:memory:` (ephemeral, no provisioning) or an absolute path to a `.db`/`.sqlite` file\n (created on first use, persists, holds many tables).\n- **Output mode** \u2014 `sqlite.query` returns JSON; choose any other mode via `sqlite.exec` (`-csv`, `-table`,\n `-markdown`, `-line`, `-html`, `-box`, `-ascii`).\n- **Read-only** \u2014 open a database without write access via `sqlite.exec` (`-readonly`).\n\n## Good to know\n\n- On a non-zero exit (SQL error) the reply is `{stdout, stderr, exit}` so the caller sees everything the\n CLI produced.\n- Runs on **macOS and Linux** (arm64 + amd64); the binary is fetched from the Pilot artifact registry and\n sha-pinned on install. SQLite is in the **public domain** (the \"blessing\" license).\n- `sqlite.help` lists every method with its latency class \u2014 the self-describing discovery contract.\n\n## SQLite CLI help (`sqlite.cli_help`)\n```\nSQLite CLI (sqlite3) \u2014 command-line options and meta-commands\n=============================================================\n\nSQLite is a zero-server, single-file, transactional SQL database engine.\nThe sqlite3 CLI runs SQL against a database file (created if it does not\nexist) or an in-memory database (use ':memory:' or omit the filename).\n\nUSAGE: sqlite3 [OPTIONS] [FILENAME] [SQL]\n\nFILENAME is an SQLite database file; ':memory:' is an ephemeral in-memory DB.\nA trailing SQL string is executed (may contain multiple ;-separated statements).\n\n------------------------------------------------------------------------------\nCOMMAND-LINE OPTIONS (sqlite3 -help)\n------------------------------------------------------------------------------\n -- treat no subsequent arguments as options\n -append append the database to the end of the file\n -ascii set output mode to 'ascii'\n -bail stop after hitting an error\n -batch force batch I/O\n -box set output mode to 'box'\n -column set output mode to 'column'\n -cmd COMMAND run \"COMMAND\" before reading stdin\n -csv set output mode to 'csv'\n -deserialize open the database using sqlite3_deserialize()\n -echo print inputs before execution\n -init FILENAME read/process named file\n -[no]header turn headers on or off\n -help show this message\n -html set output mode to HTML\n -interactive force interactive I/O\n -json set output mode to 'json'\n -line set output mode to 'line'\n -list set output mode to 'list'\n -lookaside SIZE N use N entries of SZ bytes for lookaside memory\n -markdown set output mode to 'markdown'\n -maxsize N maximum size for a --deserialize database\n -memtrace trace all memory allocations and deallocations\n -mmap N default mmap size set to N\n -newline SEP set output row separator. Default: '\\n'\n -nofollow refuse to open symbolic links to database files\n -nonce STRING set the safe-mode escape nonce\n -nullvalue TEXT set text string for NULL values. Default ''\n -pagecache SIZE N use N slots of SZ bytes each for page cache memory\n -pcachetrace trace all page cache operations\n -quote set output mode to 'quote'\n -readonly open the database read-only\n -safe enable safe-mode\n -separator SEP set output column separator. Default: '|'\n -stats print memory stats before each finalize\n -table set output mode to 'table'\n -tabs set output mode to 'tabs'\n -unsafe-testing allow unsafe commands and modes for testing\n -version show SQLite version\n -vfs NAME use NAME as the default VFS\n\n------------------------------------------------------------------------------\nDOT-COMMANDS (meta-commands; usable inside the shell or via -cmd \"...\")\n------------------------------------------------------------------------------\n.auth ON|OFF Show authorizer callbacks\n.backup ?DB? FILE Backup DB (default \"main\") to FILE\n.bail on|off Stop after hitting an error. Default OFF\n.cd DIRECTORY Change the working directory to DIRECTORY\n.changes on|off Show number of rows changed by SQL\n.check GLOB Fail if output since .testcase does not match\n.clone NEWDB Clone data into NEWDB from the existing database\n.connection [close] [#] Open or close an auxiliary database connection\n.databases List names and files of attached databases\n.dbconfig ?op? ?val? List or change sqlite3_db_config() options\n.dump ?OBJECTS? Render database content as SQL\n.echo on|off Turn command echo on or off\n.eqp on|off|full|... Enable or disable automatic EXPLAIN QUERY PLAN\n.excel Display the output of next command in spreadsheet\n.exit ?CODE? Exit this program with return-code CODE\n.expert EXPERIMENTAL. Suggest indexes for queries\n.explain ?on|off|auto? Change the EXPLAIN formatting mode. Default: auto\n.filectrl CMD ... Run various sqlite3_file_control() operations\n.fullschema ?--indent? Show schema and the content of sqlite_stat tables\n.headers on|off Turn display of headers on or off\n.help ?-all? ?PATTERN? Show help text for PATTERN\n.import FILE TABLE Import data from FILE into TABLE\n.indexes ?TABLE? Show names of indexes\n.limit ?LIMIT? ?VAL? Display or change the value of an SQLITE_LIMIT\n.lint OPTIONS Report potential schema issues.\n.load FILE ?ENTRY? Load an extension library\n.log FILE|on|off Turn logging on or off. FILE can be stderr/stdout\n.mode MODE ?OPTIONS? Set output mode\n.nonce STRING Suspend safe mode for one command if nonce matches\n.nullvalue STRING Use STRING in place of NULL values\n.once ?OPTIONS? ?FILE? Output for the next SQL command only to FILE\n.open ?OPTIONS? ?FILE? Close existing database and reopen FILE\n.output ?FILE? Send output to FILE or stdout if FILE is omitted\n.parameter CMD ... Manage SQL parameter bindings\n.print STRING... Print literal STRING\n.progress N Invoke progress handler after every N opcodes\n.prompt MAIN CONTINUE Replace the standard prompts\n.quit Stop interpreting input stream, exit if primary.\n.read FILE Read input from FILE or command output\n.restore ?DB? FILE Restore content of DB (default \"main\") from FILE\n.save ?OPTIONS? FILE Write database to FILE (an alias for .backup ...)\n.scanstats on|off|est Turn sqlite3_stmt_scanstatus() metrics on or off\n.schema ?PATTERN? Show the CREATE statements matching PATTERN\n.separator COL ?ROW? Change the column and row separators\n.sha3sum ... Compute a SHA3 hash of database content\n.shell CMD ARGS... Run CMD ARGS... in a system shell\n.show Show the current values for various settings\n.stats ?ARG? Show stats or turn stats on or off\n.system CMD ARGS... Run CMD ARGS... in a system shell\n.tables ?TABLE? List names of tables matching LIKE pattern TABLE\n.timeout MS Try opening locked tables for MS milliseconds\n.timer on|off Turn SQL timer on or off\n.trace ?OPTIONS? Output each SQL statement as it is run\n.version Show source, library and compiler versions\n.vfsinfo ?AUX? Information about the top-level VFS\n.vfslist List all available VFSes\n.vfsname ?AUX? Print the name of the VFS stack\n.width NUM1 NUM2 ... Set minimum column widths for columnar output\n\n```\n", + "summary": "This app installs the official SQLite 3.45.2 command-line shell (sqlite3) on the host and fronts it as typed methods. The bundle is the upstream sqlite3 CLI binary (sha-pinned per OS/arch, fetched from the Pilot artifact registry at install) plus a tiny wrapper that serves a clean, complete --help. SQLite is a zero-server, single-file, transactional (OLTP) SQL engine \u2014 the most widely deployed database in the\u2026", "categories": [ "data" ], @@ -3052,7 +3363,7 @@ "methods": [ { "name": "sqlite.query", - "summary": "Run a SQL statement (or `;`-separated batch) against a database file (or `:memory:`) and return the rows as a JSON array of row objects — the most directly machine-parseable output. This is `sqlite3 -json `.", + "summary": "Run a SQL statement (or `;`-separated batch) against a database file (or `:memory:`) and return the rows as a JSON array of row objects \u2014 the most directly machine-parseable output. This is `sqlite3 -json `.", "example": "", "gated": "" }, @@ -3064,37 +3375,37 @@ }, { "name": "sqlite.schema", - "summary": "Print the `CREATE` statements (DDL) for every table, index, view, and trigger in the database — via SQLite's `.schema` meta-command. This is `sqlite3 .schema`.", + "summary": "Print the `CREATE` statements (DDL) for every table, index, view, and trigger in the database \u2014 via SQLite's `.schema` meta-command. This is `sqlite3 .schema`.", "example": "", "gated": "" }, { "name": "sqlite.tables", - "summary": "List the names of the tables (and views) in the database — via SQLite's `.tables` meta-command. This is `sqlite3 .tables`.", + "summary": "List the names of the tables (and views) in the database \u2014 via SQLite's `.tables` meta-command. This is `sqlite3 .tables`.", "example": "", "gated": "" }, { "name": "sqlite.exec", - "summary": "Run the sqlite3 CLI with a verbatim argv — the full surface beyond the curated methods. Payload is {\"args\":[...]} (the args passed straight to `sqlite3`) plus optional {\"stdin\":\"...\"} piped to the process. Use it for any flag, output mode, or dot-command the curated methods don't cover: a different output mode (`-csv`, `-table`, `-markdown`, `-line`, `-html`, `-box`), `.dump`/`.import`/`.backup`/`.clone`/`.read` via `-cmd`, or a multi-statement session piped over stdin. Examples: {\"args\":[\":memory:\",\"-csv\",\"SELECT 1 AS a, 2 AS b\"]}; {\"args\":[\"/data/app.db\",\"-cmd\",\".mode csv\",\"-cmd\",\".import /data/in.csv t\",\"SELECT count(*) FROM t\"]}; {\"args\":[\"/data/app.db\"],\"stdin\":\"CREATE TABLE t(x);\\nINSERT INTO t VALUES (1),(2);\\nSELECT sum(x) FROM t;\"}.", + "summary": "Run the sqlite3 CLI with a verbatim argv \u2014 the full surface beyond the curated methods. Payload is {\"args\":[...]} (the args passed straight to `sqlite3`) plus optional {\"stdin\":\"...\"} piped to the process. Use it for any flag, output mode, or dot-command the curated methods don't cover: a different output mode (`-csv`, `-table`, `-markdown`, `-line`, `-html`, `-box`), `.dump`/`.import`/`.backup`/`.clone`/`.read` via `-cmd`, or a multi-statement session piped over stdin. Examples: {\"args\":[\":memory:\",\"-csv\",\"SELECT 1 AS a, 2 AS b\"]}; {\"args\":[\"/data/app.db\",\"-cmd\",\".mode csv\",\"-cmd\",\".import /data/in.csv t\",\"SELECT count(*) FROM t\"]}; {\"args\":[\"/data/app.db\"],\"stdin\":\"CREATE TABLE t(x);\\nINSERT INTO t VALUES (1),(2);\\nSELECT sum(x) FROM t;\"}.", "example": "", "gated": "" }, { "name": "sqlite.cli_help", - "summary": "Return the complete sqlite3 CLI help — every command-line option AND every dot-command (`.dump`, `.import`, `.backup`, `.clone`, `.mode`, `.schema`, `.tables`, `.read`, …) — captured verbatim from the delivered binary and rendered as clean, color-free text. The full reference for what sqlite.query / sqlite.exec accept.", + "summary": "Return the complete sqlite3 CLI help \u2014 every command-line option AND every dot-command (`.dump`, `.import`, `.backup`, `.clone`, `.mode`, `.schema`, `.tables`, `.read`, \u2026) \u2014 captured verbatim from the delivered binary and rendered as clean, color-free text. The full reference for what sqlite.query / sqlite.exec accept.", "example": "", "gated": "" }, { "name": "sqlite.version", - "summary": "Print the delivered SQLite version, e.g. \"3.45.2 2024-03-12 …\". Needs no database. This is `sqlite3 -version`.", + "summary": "Print the delivered SQLite version, e.g. \"3.45.2 2024-03-12 \u2026\". Needs no database. This is `sqlite3 -version`.", "example": "", "gated": "" }, { "name": "sqlite.help", - "summary": "Discovery: every method with its params, kind, and latency class — the self-describing contract.", + "summary": "Discovery: every method with its params, kind, and latency class \u2014 the self-describing contract.", "example": "", "gated": "" } @@ -3156,7 +3467,7 @@ "product_demo": { "skill": "io.pilot.sqlite", "title": "Full usage demo", - "when_to_use": "When you need a zero-config embedded relational database in a single file (or :memory:) for local structured data with SQL — not a networked server and not high-concurrency writes.", + "when_to_use": "When you need a zero-config embedded relational database in a single file (or :memory:) for local structured data with SQL \u2014 not a networked server and not high-concurrency writes.", "metered": false, "quickstart": { "title": "", @@ -3203,7 +3514,7 @@ "cost": null, "gotchas": [ "Database file paths resolve inside the app sandbox, not your shell CWD.", - ":memory: is ephemeral — it vanishes when the call returns; use an absolute .db path to persist.", + ":memory: is ephemeral \u2014 it vanishes when the call returns; use an absolute .db path to persist.", "A file `database` is created automatically if it does not exist.", "sqlite.query returns rows as JSON objects keyed by column name." ], @@ -3215,9 +3526,9 @@ { "id": "io.pilot.mysql", "name": "MySQL", - "tagline": "Run a real MySQL server from an agent — full client/server SQL, no cloud account, no provisioning", - "description": "# MySQL — the world's most popular open-source SQL database, native CLI for agents\n\nThis app installs the official **MySQL 9.7.1** server (`mysqld`) **and** client tools (`mysql`,\n`mysqladmin`, `mysqldump`, `mysqlshow`) on the host and fronts them as typed methods. The bundle is the\nupstream MySQL suite (sha-pinned per OS/arch, fetched from the Pilot artifact registry at install) plus a\ntiny `mysqlctl` dispatcher that makes the server relocatable — it finds its plugins and error messages\nwherever the bundle is staged.\n\nMySQL is a **real client/server RDBMS** — the database behind a huge share of the web. Unlike a hosted\nMySQL, there is **no cloud account, no credentials to provision, and no network egress**: the agent runs\n`mysql.initialize` once to lay down a data directory, `mysql.start` to bring up a server on\n`127.0.0.1:`, and then creates databases and runs SQL — all locally, in its own sandbox. It is the\ntransactional, server-grade complement to the embedded `io.pilot.sqlite` and the analytics-focused\n`io.pilot.duckdb`, and a sibling to `io.pilot.postgres`.\n\n## Why an agent wants this\n\n- **A full local MySQL, zero provisioning.** No RDS, no `docker run`, no credentials. `initialize` →\n `start` → `createdb` → `query`, all on `127.0.0.1`.\n- **Real server semantics.** Transactions, InnoDB, foreign keys, triggers, stored routines, JSON columns,\n window functions, full-text indexes — the actual MySQL engine, not an emulation.\n- **The MySQL dialect + wire protocol.** Test and run exactly what your production MySQL will see: same SQL,\n same `mysqldump` format, same client tools.\n- **Durable + portable.** The data directory is a real MySQL instance the agent can stop, restart, back up\n with `mysql.dump`, or hand off.\n- **Agent-friendly output.** `mysql.query` returns an aligned table; `mysql.query_tsv` returns tab-separated\n values for clean parsing.\n\n## Methods\n\n- `mysql.initialize` — create a new data directory (system tables + insecure `root`). Run once.\n- `mysql.start` / `mysql.stop` — bring a server on `127.0.0.1:` up (detached) / down (clean shutdown).\n- `mysql.ping` — is the server accepting connections?\n- `mysql.createdb` — create a database.\n- `mysql.query` — run SQL, get an aligned table. `mysql.query_tsv` — same, as TSV.\n- `mysql.databases` / `mysql.tables` — list databases / tables.\n- `mysql.dump` — mysqldump a database to portable SQL.\n- `mysql.exec` — run any bundled tool with a verbatim argv (+ optional stdin) for anything the curated\n methods don't cover (`--vertical`, `mysqlshow`, `SOURCE script.sql`, a different output mode, …).\n- `mysql.mysql_help` — the full `mysql` client help. `mysql.version` — the delivered version.\n `mysql.help` — the self-describing method list.\n\n## How to use it (typical flow)\n\n1. **Initialize once:** `mysql.initialize` `{ \"datadir\": \"/work/mysql-data\" }`.\n2. **Start the server:** `mysql.start` `{ \"datadir\": \"/work/mysql-data\", \"port\": \"13306\" }` (then `mysql.ping`).\n3. **Create a database:** `mysql.createdb` `{ \"port\": \"13306\", \"dbname\": \"app\" }`.\n4. **Run SQL:** `mysql.query` `{ \"port\": \"13306\", \"database\": \"app\", \"sql\": \"CREATE TABLE t(id INT PRIMARY KEY, v TEXT); INSERT INTO t VALUES (1,'hi'); SELECT * FROM t;\" }`.\n5. **Back up / stop:** `mysql.dump` `{ \"port\": \"13306\", \"database\": \"app\" }`, then `mysql.stop` `{ \"port\": \"13306\" }`.\n\n## Configuration & connection\n\n- **Connection** is always local: `127.0.0.1:`, user `root`. After `initialize` the root password is\n empty; set one with `mysql.exec` (`ALTER USER 'root'@'localhost' IDENTIFIED BY '…'`) and pass it to later\n calls via the **`MYSQL_PWD`** environment variable (opted into `env_passthrough`).\n- **Data directory** — each `datadir` is an independent MySQL instance; run several on different ports.\n- **X protocol** is disabled (`--mysqlx=OFF`) for a lean local footprint; the classic protocol is on.\n- **Anything else** — `mysql.exec` gives you the raw tools: `--vertical`/`--html`/`--xml` output, `mysqlshow`,\n `SOURCE` a script over stdin, or `mysqld`/`mysqladmin` flags the curated methods don't expose.\n\n## Good to know\n\n- On a non-zero exit (SQL error) the reply is `{stdout, stderr, exit}` so the caller sees everything the\n tool produced.\n- Runs on **macOS and Linux** (arm64 + amd64); binaries come from the Pilot artifact registry, sha-pinned on\n install. The server must not run as OS root — the Pilot daemon runs unprivileged, which is exactly right.\n- MySQL Community Server is **GPL-2.0** licensed. `mysql.help` lists every method with its latency class.\n\n## MySQL client help (`mysql.mysql_help`)\n```\n/tmp/mysql-reloc/mysql-9.7.1-darwin-arm64/bin/mysql Ver 9.7.1 for macos15.7 on arm64 (conda-forge)\nCopyright (c) 2000, 2026, Oracle and/or its affiliates.\n\nOracle is a registered trademark of Oracle Corporation and/or its\naffiliates. Other names may be trademarks of their respective\nowners.\n\nUsage: /tmp/mysql-reloc/mysql-9.7.1-darwin-arm64/bin/mysql [OPTIONS] [database]\n -?, --help Display this help and exit.\n -I, --help Synonym for -?\n --auto-rehash Enable automatic rehashing. One doesn't need to use\n 'rehash' to get table and field completion, but startup\n and reconnecting may take a longer time. Disable with\n --disable-auto-rehash.\n (Defaults to on; use --skip-auto-rehash to disable.)\n -A, --no-auto-rehash \n No automatic rehashing. One has to use 'rehash' to get\n table and field completion. This gives a quicker start of\n mysql and disables rehashing on reconnect.\n --auto-vertical-output \n Automatically switch to vertical output mode if the\n result is wider than the terminal width.\n -B, --batch Don't use history file. Disable interactive behavior.\n (Enables --silent.)\n --bind-address=name IP address to bind to.\n --binary-as-hex Print binary data as hex. Enabled by default for\n interactive terminals.\n --character-sets-dir=name \n Directory for character set files.\n --column-type-info Display column type information.\n --commands Enable or disable processing of local mysql commands.\n -c, --comments Preserve comments. Send comments to the server. The\n default is --comments (keep comments), disable with\n --skip-comments.\n (Defaults to on; use --skip-comments to disable.)\n -C, --compress Use compression in server/client protocol.\n -#, --debug[=#] This is a non-debug version. Catch this and exit.\n --debug-check This is a non-debug version. Catch this and exit.\n -T, --debug-info This is a non-debug version. Catch this and exit.\n -D, --database=name Database to use.\n --default-character-set=name \n Set the default character set.\n --delimiter=name Delimiter to be used.\n --enable-cleartext-plugin \n Enable/disable the clear text authentication plugin.\n -e, --execute=name Execute command and quit. (Disables --force and history\n file.)\n -E, --vertical Print the output of a query (rows) vertically.\n -f, --force Continue even if we get an SQL error.\n --histignore=name A colon-separated list of patterns to keep statements\n from getting logged into syslog and mysql history.\n -G, --named-commands \n Enable named commands. Named commands mean this program's\n internal commands; see mysql> help . When enabled, the\n named commands can be used from any line of the query,\n otherwise only from the first line, before an enter.\n Disable with --disable-named-commands. This option is\n disabled by default.\n -i, --ignore-spaces Ignore space after function names.\n --init-command=name Single SQL Command to execute when connecting to MySQL\n```\n", - "summary": "This app installs the official MySQL 9.7.1 server (mysqld) and client tools (mysql, mysqladmin, mysqldump, mysqlshow) on the host and fronts them as typed methods. The bundle is the upstream MySQL suite (sha-pinned per OS/arch, fetched from the Pilot artifact registry at install) plus a tiny mysqlctl dispatcher that makes the server relocatable — it finds its plugins and error messages wherever the bundle is…", + "tagline": "Run a real MySQL server from an agent \u2014 full client/server SQL, no cloud account, no provisioning", + "description": "# MySQL \u2014 the world's most popular open-source SQL database, native CLI for agents\n\nThis app installs the official **MySQL 9.7.1** server (`mysqld`) **and** client tools (`mysql`,\n`mysqladmin`, `mysqldump`, `mysqlshow`) on the host and fronts them as typed methods. The bundle is the\nupstream MySQL suite (sha-pinned per OS/arch, fetched from the Pilot artifact registry at install) plus a\ntiny `mysqlctl` dispatcher that makes the server relocatable \u2014 it finds its plugins and error messages\nwherever the bundle is staged.\n\nMySQL is a **real client/server RDBMS** \u2014 the database behind a huge share of the web. Unlike a hosted\nMySQL, there is **no cloud account, no credentials to provision, and no network egress**: the agent runs\n`mysql.initialize` once to lay down a data directory, `mysql.start` to bring up a server on\n`127.0.0.1:`, and then creates databases and runs SQL \u2014 all locally, in its own sandbox. It is the\ntransactional, server-grade complement to the embedded `io.pilot.sqlite` and the analytics-focused\n`io.pilot.duckdb`, and a sibling to `io.pilot.postgres`.\n\n## Why an agent wants this\n\n- **A full local MySQL, zero provisioning.** No RDS, no `docker run`, no credentials. `initialize` \u2192\n `start` \u2192 `createdb` \u2192 `query`, all on `127.0.0.1`.\n- **Real server semantics.** Transactions, InnoDB, foreign keys, triggers, stored routines, JSON columns,\n window functions, full-text indexes \u2014 the actual MySQL engine, not an emulation.\n- **The MySQL dialect + wire protocol.** Test and run exactly what your production MySQL will see: same SQL,\n same `mysqldump` format, same client tools.\n- **Durable + portable.** The data directory is a real MySQL instance the agent can stop, restart, back up\n with `mysql.dump`, or hand off.\n- **Agent-friendly output.** `mysql.query` returns an aligned table; `mysql.query_tsv` returns tab-separated\n values for clean parsing.\n\n## Methods\n\n- `mysql.initialize` \u2014 create a new data directory (system tables + insecure `root`). Run once.\n- `mysql.start` / `mysql.stop` \u2014 bring a server on `127.0.0.1:` up (detached) / down (clean shutdown).\n- `mysql.ping` \u2014 is the server accepting connections?\n- `mysql.createdb` \u2014 create a database.\n- `mysql.query` \u2014 run SQL, get an aligned table. `mysql.query_tsv` \u2014 same, as TSV.\n- `mysql.databases` / `mysql.tables` \u2014 list databases / tables.\n- `mysql.dump` \u2014 mysqldump a database to portable SQL.\n- `mysql.exec` \u2014 run any bundled tool with a verbatim argv (+ optional stdin) for anything the curated\n methods don't cover (`--vertical`, `mysqlshow`, `SOURCE script.sql`, a different output mode, \u2026).\n- `mysql.mysql_help` \u2014 the full `mysql` client help. `mysql.version` \u2014 the delivered version.\n `mysql.help` \u2014 the self-describing method list.\n\n## How to use it (typical flow)\n\n1. **Initialize once:** `mysql.initialize` `{ \"datadir\": \"/work/mysql-data\" }`.\n2. **Start the server:** `mysql.start` `{ \"datadir\": \"/work/mysql-data\", \"port\": \"13306\" }` (then `mysql.ping`).\n3. **Create a database:** `mysql.createdb` `{ \"port\": \"13306\", \"dbname\": \"app\" }`.\n4. **Run SQL:** `mysql.query` `{ \"port\": \"13306\", \"database\": \"app\", \"sql\": \"CREATE TABLE t(id INT PRIMARY KEY, v TEXT); INSERT INTO t VALUES (1,'hi'); SELECT * FROM t;\" }`.\n5. **Back up / stop:** `mysql.dump` `{ \"port\": \"13306\", \"database\": \"app\" }`, then `mysql.stop` `{ \"port\": \"13306\" }`.\n\n## Configuration & connection\n\n- **Connection** is always local: `127.0.0.1:`, user `root`. After `initialize` the root password is\n empty; set one with `mysql.exec` (`ALTER USER 'root'@'localhost' IDENTIFIED BY '\u2026'`) and pass it to later\n calls via the **`MYSQL_PWD`** environment variable (opted into `env_passthrough`).\n- **Data directory** \u2014 each `datadir` is an independent MySQL instance; run several on different ports.\n- **X protocol** is disabled (`--mysqlx=OFF`) for a lean local footprint; the classic protocol is on.\n- **Anything else** \u2014 `mysql.exec` gives you the raw tools: `--vertical`/`--html`/`--xml` output, `mysqlshow`,\n `SOURCE` a script over stdin, or `mysqld`/`mysqladmin` flags the curated methods don't expose.\n\n## Good to know\n\n- On a non-zero exit (SQL error) the reply is `{stdout, stderr, exit}` so the caller sees everything the\n tool produced.\n- Runs on **macOS and Linux** (arm64 + amd64); binaries come from the Pilot artifact registry, sha-pinned on\n install. The server must not run as OS root \u2014 the Pilot daemon runs unprivileged, which is exactly right.\n- MySQL Community Server is **GPL-2.0** licensed. `mysql.help` lists every method with its latency class.\n\n## MySQL client help (`mysql.mysql_help`)\n```\n/tmp/mysql-reloc/mysql-9.7.1-darwin-arm64/bin/mysql Ver 9.7.1 for macos15.7 on arm64 (conda-forge)\nCopyright (c) 2000, 2026, Oracle and/or its affiliates.\n\nOracle is a registered trademark of Oracle Corporation and/or its\naffiliates. Other names may be trademarks of their respective\nowners.\n\nUsage: /tmp/mysql-reloc/mysql-9.7.1-darwin-arm64/bin/mysql [OPTIONS] [database]\n -?, --help Display this help and exit.\n -I, --help Synonym for -?\n --auto-rehash Enable automatic rehashing. One doesn't need to use\n 'rehash' to get table and field completion, but startup\n and reconnecting may take a longer time. Disable with\n --disable-auto-rehash.\n (Defaults to on; use --skip-auto-rehash to disable.)\n -A, --no-auto-rehash \n No automatic rehashing. One has to use 'rehash' to get\n table and field completion. This gives a quicker start of\n mysql and disables rehashing on reconnect.\n --auto-vertical-output \n Automatically switch to vertical output mode if the\n result is wider than the terminal width.\n -B, --batch Don't use history file. Disable interactive behavior.\n (Enables --silent.)\n --bind-address=name IP address to bind to.\n --binary-as-hex Print binary data as hex. Enabled by default for\n interactive terminals.\n --character-sets-dir=name \n Directory for character set files.\n --column-type-info Display column type information.\n --commands Enable or disable processing of local mysql commands.\n -c, --comments Preserve comments. Send comments to the server. The\n default is --comments (keep comments), disable with\n --skip-comments.\n (Defaults to on; use --skip-comments to disable.)\n -C, --compress Use compression in server/client protocol.\n -#, --debug[=#] This is a non-debug version. Catch this and exit.\n --debug-check This is a non-debug version. Catch this and exit.\n -T, --debug-info This is a non-debug version. Catch this and exit.\n -D, --database=name Database to use.\n --default-character-set=name \n Set the default character set.\n --delimiter=name Delimiter to be used.\n --enable-cleartext-plugin \n Enable/disable the clear text authentication plugin.\n -e, --execute=name Execute command and quit. (Disables --force and history\n file.)\n -E, --vertical Print the output of a query (rows) vertically.\n -f, --force Continue even if we get an SQL error.\n --histignore=name A colon-separated list of patterns to keep statements\n from getting logged into syslog and mysql history.\n -G, --named-commands \n Enable named commands. Named commands mean this program's\n internal commands; see mysql> help . When enabled, the\n named commands can be used from any line of the query,\n otherwise only from the first line, before an enter.\n Disable with --disable-named-commands. This option is\n disabled by default.\n -i, --ignore-spaces Ignore space after function names.\n --init-command=name Single SQL Command to execute when connecting to MySQL\n```\n", + "summary": "This app installs the official MySQL 9.7.1 server (mysqld) and client tools (mysql, mysqladmin, mysqldump, mysqlshow) on the host and fronts them as typed methods. The bundle is the upstream MySQL suite (sha-pinned per OS/arch, fetched from the Pilot artifact registry at install) plus a tiny mysqlctl dispatcher that makes the server relocatable \u2014 it finds its plugins and error messages wherever the bundle is\u2026", "categories": [ "data" ], @@ -3243,7 +3554,7 @@ "methods": [ { "name": "mysql.initialize", - "summary": "Initialize a new MySQL data directory (system tables + an insecure `root@localhost` with an empty password) — the one-time setup before the first start. This is `mysqld --initialize-insecure --datadir=`. The bundle's basedir/plugin-dir/error-messages are wired in automatically.", + "summary": "Initialize a new MySQL data directory (system tables + an insecure `root@localhost` with an empty password) \u2014 the one-time setup before the first start. This is `mysqld --initialize-insecure --datadir=`. The bundle's basedir/plugin-dir/error-messages are wired in automatically.", "example": "", "gated": "" }, @@ -3273,13 +3584,13 @@ }, { "name": "mysql.query", - "summary": "Run SQL against a database and return an aligned ASCII table — the default, human-readable shape. May contain multiple `;`-separated statements. This is `mysql -h 127.0.0.1 -P -u root -D --table -e `.", + "summary": "Run SQL against a database and return an aligned ASCII table \u2014 the default, human-readable shape. May contain multiple `;`-separated statements. This is `mysql -h 127.0.0.1 -P -u root -D --table -e `.", "example": "", "gated": "" }, { "name": "mysql.query_tsv", - "summary": "Same as mysql.query but returns tab-separated values (header + rows) via `--batch` — the machine-parseable shape. This is `mysql -h 127.0.0.1 -P -u root -D --batch -e `.", + "summary": "Same as mysql.query but returns tab-separated values (header + rows) via `--batch` \u2014 the machine-parseable shape. This is `mysql -h 127.0.0.1 -P -u root -D --batch -e `.", "example": "", "gated": "" }, @@ -3297,31 +3608,31 @@ }, { "name": "mysql.dump", - "summary": "Dump a database as SQL (schema + data) with mysqldump — a portable logical backup the agent can save or replay. This is `mysqldump -h 127.0.0.1 -P -u root --no-tablespaces `.", + "summary": "Dump a database as SQL (schema + data) with mysqldump \u2014 a portable logical backup the agent can save or replay. This is `mysqldump -h 127.0.0.1 -P -u root --no-tablespaces `.", "example": "", "gated": "" }, { "name": "mysql.exec", - "summary": "Run any bundled MySQL tool with a verbatim argv — the full surface beyond the curated methods. Payload is {\"args\":[tool, ...]} where tool is one of `mysql`, `mysqld`, `mysqladmin`, `mysqldump`, `mysqlshow`, plus optional {\"stdin\":\"...\"} piped to the process. Examples: {\"args\":[\"mysql\",\"--protocol=TCP\",\"-h\",\"127.0.0.1\",\"-P\",\"13306\",\"-u\",\"root\",\"-D\",\"app\",\"--vertical\",\"-e\",\"SELECT * FROM t\\\\G\"]}; {\"args\":[\"mysqlshow\",\"--protocol=TCP\",\"-h\",\"127.0.0.1\",\"-P\",\"13306\",\"-u\",\"root\",\"app\"]}; {\"args\":[\"mysql\",\"--protocol=TCP\",\"-h\",\"127.0.0.1\",\"-P\",\"13306\",\"-u\",\"root\",\"-D\",\"app\"],\"stdin\":\"SOURCE /work/schema.sql;\"}.", + "summary": "Run any bundled MySQL tool with a verbatim argv \u2014 the full surface beyond the curated methods. Payload is {\"args\":[tool, ...]} where tool is one of `mysql`, `mysqld`, `mysqladmin`, `mysqldump`, `mysqlshow`, plus optional {\"stdin\":\"...\"} piped to the process. Examples: {\"args\":[\"mysql\",\"--protocol=TCP\",\"-h\",\"127.0.0.1\",\"-P\",\"13306\",\"-u\",\"root\",\"-D\",\"app\",\"--vertical\",\"-e\",\"SELECT * FROM t\\\\G\"]}; {\"args\":[\"mysqlshow\",\"--protocol=TCP\",\"-h\",\"127.0.0.1\",\"-P\",\"13306\",\"-u\",\"root\",\"app\"]}; {\"args\":[\"mysql\",\"--protocol=TCP\",\"-h\",\"127.0.0.1\",\"-P\",\"13306\",\"-u\",\"root\",\"-D\",\"app\"],\"stdin\":\"SOURCE /work/schema.sql;\"}.", "example": "", "gated": "" }, { "name": "mysql.mysql_help", - "summary": "Return the full `mysql` client help — every command-line option — captured from the delivered binary. The reference for what mysql.query / mysql.exec accept.", + "summary": "Return the full `mysql` client help \u2014 every command-line option \u2014 captured from the delivered binary. The reference for what mysql.query / mysql.exec accept.", "example": "", "gated": "" }, { "name": "mysql.version", - "summary": "Print the delivered MySQL version, e.g. \"mysql Ver 9.7.1 for … (conda-forge)\". This is `mysql --version`.", + "summary": "Print the delivered MySQL version, e.g. \"mysql Ver 9.7.1 for \u2026 (conda-forge)\". This is `mysql --version`.", "example": "", "gated": "" }, { "name": "mysql.help", - "summary": "Discovery: every method with its params, kind, and latency class — the self-describing contract.", + "summary": "Discovery: every method with its params, kind, and latency class \u2014 the self-describing contract.", "example": "", "gated": "" } @@ -3383,7 +3694,7 @@ "product_demo": { "skill": "io.pilot.mysql", "title": "Full usage demo", - "when_to_use": "When you need a full MySQL server RDBMS — multiple databases, concurrent clients, a wire protocol on a TCP port — rather than an in-process file db; requires a one-time initialize + start.", + "when_to_use": "When you need a full MySQL server RDBMS \u2014 multiple databases, concurrent clients, a wire protocol on a TCP port \u2014 rather than an in-process file db; requires a one-time initialize + start.", "metered": false, "quickstart": { "title": "", @@ -3450,9 +3761,9 @@ { "id": "io.pilot.redis", "name": "Redis", - "tagline": "Run Redis from an agent — start a local in-memory store and run any command with redis-cli", - "description": "# Redis (server + redis-cli) — native CLI for agents\n\nThis app installs the official **Redis 8.6.2** server and client on the host and fronts them as\ntyped methods. The bundle is a relocatable build of Redis 8.6.2 (from conda-forge, AGPL-3.0)\ncarrying `redis-server`, `redis-cli`, `redis-benchmark`, `redis-check-rdb`, `redis-check-aof`, and\n`redis-sentinel`; every binary is sha-pinned and staged at install, and a tiny `redis` dispatcher routes\neach method to the right tool. Binaries are fetched from the Pilot artifact registry on **macOS and Linux**\n(arm64 + amd64).\n\nRedis is an **in-memory data-structure store** — strings, hashes, lists, sets, sorted sets, streams, plus\npub/sub and transactions. There is no cluster to provision: an agent starts a throwaway local server and\nuses it as a cache, a fast key-value DB, or a coordination/queue primitive.\n\n## Run a Redis locally — the usual flow\n\n1. **Start:** `redis.start` `{ \"port\": \"6399\", \"dir\": \"/tmp\" }` — boots a daemonized server on\n `127.0.0.1:6399`, with pidfile/logfile/RDB under `dir`.\n2. **Health:** `redis.ping` `{ \"port\": \"6399\" }` → `PONG`.\n3. **Use it:** `redis.set` / `redis.get`, `redis.info`, `redis.dbsize`, or **any** command via\n `redis.exec` `{ \"args\": [\"redis-cli\",\"-p\",\"6399\",\"ZADD\",\"board\",\"100\",\"alice\"] }`.\n4. **Stop:** `redis.stop` `{ \"port\": \"6399\" }`.\n\n## Methods\n\n- `redis.start` / `redis.stop` — local server lifecycle (daemonized; per-port pidfile/logfile).\n- `redis.ping` — liveness (PONG). `redis.info` — full server INFO. `redis.dbsize` — key count.\n- `redis.set` / `redis.get` — string get/set convenience.\n- `redis.exec` — run any tool with a verbatim argv (+ optional stdin) — every Redis command, pipelined\n batches, benchmarks, RDB/AOF checks, sentinel.\n- `redis.cli_help` — the complete `redis-cli --help`. `redis.version` — the delivered version.\n `redis.help` — the self-describing method list.\n\n## Configuration\n\n- **`port`** — TCP port for the local server (convention `6399`). Bound to `127.0.0.1`.\n- **`dir`** — an existing writable directory for the pidfile, logfile, and RDB snapshot; pass `/tmp` for a\n throwaway server, or a path you control for persistence (the RDB lives at `/dump.rdb`).\n- **Persistence** — `redis.stop` does `SHUTDOWN NOSAVE`; run `redis.exec` with `SAVE`/`BGSAVE` first if you\n need the dataset on disk. Any redis.conf directive is reachable as a `--flag` via\n `redis.exec` (`redis-server --port ... --maxmemory 256mb --maxmemory-policy allkeys-lru ...`).\n- **Auth** — local servers are open by default; set `--requirepass` (via `redis.exec` on start) and pass the\n password through the `REDISCLI_AUTH` env var (forwarded to the child) or `-a` on `redis.exec`.\n\n## Good to know\n\n- Output returns verbatim where it is already clean; on a non-zero exit the reply is `{stdout, stderr, exit}`.\n- Free and open source under the **AGPL-3.0** license (Redis 8.x). Repackaged unmodified from conda-forge.\n\n## redis-cli / redis-server help\n```\nRedis CLI help — redis-cli and redis-server\n===========================================\n\nRedis is an in-memory data-structure store (cache, database, message broker).\nThis app fronts the Redis server + redis-cli as agent methods: start a local\nserver, then SET/GET/PING/INFO or run any command via redis.exec.\n\n------------------------------------------------------------------------------\nredis-cli --help\n------------------------------------------------------------------------------\nredis-cli 8.6.2\n\nUsage: redis-cli [OPTIONS] [cmd [arg [arg ...]]]\n -h Server hostname (default: 127.0.0.1).\n -p Server port (default: 6379).\n -t Server connection timeout in seconds (decimals allowed).\n Default timeout is 0, meaning no limit, depending on the OS.\n -s Server socket (overrides hostname and port).\n -a Password to use when connecting to the server.\n You can also use the REDISCLI_AUTH environment\n variable to pass this password more safely\n (if both are used, this argument takes precedence).\n --user Used to send ACL style 'AUTH username pass'. Needs -a.\n --pass Alias of -a for consistency with the new --user option.\n --askpass Force user to input password with mask from STDIN.\n If this argument is used, '-a' and REDISCLI_AUTH\n environment variable will be ignored.\n -u Server URI on format redis://user:password@host:port/dbnum\n User, password and dbnum are optional. For authentication\n without a username, use username 'default'. For TLS, use\n the scheme 'rediss'.\n -r Execute specified command N times.\n -i When -r is used, waits seconds per command.\n It is possible to specify sub-second times like -i 0.1.\n This interval is also used in --scan and --stat per cycle.\n and in --bigkeys, --memkeys, --keystats, and --hotkeys per 100 cycles.\n -n Database number.\n --name Set the client name.\n -2 Start session in RESP2 protocol mode.\n -3 Start session in RESP3 protocol mode.\n -x Read last argument from STDIN (see example below).\n -X Read argument from STDIN (see example below).\n -d Delimiter between response bulks for raw formatting (default: \\n).\n -D Delimiter between responses for raw formatting (default: \\n).\n -c Enable cluster mode (follow -ASK and -MOVED redirections).\n -e Return exit error code when command execution fails.\n -4 Prefer IPv4 over IPv6 on DNS lookup.\n -6 Prefer IPv6 over IPv4 on DNS lookup.\n --tls Establish a secure TLS connection.\n --sni Server name indication for TLS.\n --cacert CA Certificate file to verify with.\n --cacertdir Directory where trusted CA certificates are stored.\n If neither cacert nor cacertdir are specified, the default\n system-wide trusted root certs configuration will apply.\n --insecure Allow insecure TLS connection by skipping cert validation.\n --cert Client certificate to authenticate with.\n --key Private key file to authenticate with.\n --tls-ciphers Sets the list of preferred ciphers (TLSv1.2 and below)\n in order of preference from highest to lowest separated by colon (\":\").\n See the ciphers(1ssl) manpage for more information about the syntax of this string.\n --tls-ciphersuites Sets the list of preferred ciphersuites (TLSv1.3)\n in order of preference from highest to lowest separated by colon (\":\").\n See the ciphers(1ssl) manpage for more information about the syntax of this string,\n and specifically for TLSv1.3 ciphersuites.\n --raw Use raw formatting for replies (default when STDOUT is\n not a tty).\n --no-raw Force formatted output even when STDOUT is not a tty.\n --quoted-input Force input to be handled as quoted strings.\n --csv Output in CSV format.\n --json Output in JSON format (default RESP3, use -2 if you want to use with RESP2).\n --quoted-json Same as --json, but produce ASCII-safe quoted strings, not Unicode.\n --show-pushes Whether to print RESP3 PUSH messages. Enabled by default when\n STDOUT is a tty but can be overridden with --show-pushes no.\n --stat Print rolling stats about server: mem, clients, ...\n --latency Enter a special mode continuously sampling latency.\n If you use this mode in an interactive session it runs\n forever displaying real-time stats. Otherwise if --raw or\n --csv is specified, or if you redirect the output to a non\n TTY, it samples the latency for 1 second (you can use\n -i to change the interval), then produces a single output\n and exits.\n --latency-history Like --latency but tracking latency changes over time.\n Default time interval is 15 sec. Change it using -i.\n --latency-dist Shows latency as a spectrum, requires xterm 256 colors.\n Default time interval is 1 sec. Change it using -i.\n --vset-recall Enable VSIM recall test mode for the specified key\n (that must be a vector set). Random vectors are created\n mixing components from other elements. A VSIM is then\n executed and checked against ground truth.\n --vset-recall-count How many top elements to fetch per query.\n --vset-recall-ef HSNW EF (search effort) to use. Default 500.\n --vset-recall-ele Number of elements used to compose query vectors\n Default 1.\n --lru-test Simulate a cache workload with an 80-20 distribution.\n --replica Simulate a replica showing commands received from the master.\n --rdb Transfer an RDB dump from remote server to local file.\n Use filename of \"-\" to write to stdout.\n --functions-rdb Like --rdb but only get the functions (not the keys)\n when getting the RDB dump file.\n --pipe Transfer raw Redis protocol from stdin to server.\n --pipe-timeout In --pipe mode, abort with error if after sending all data.\n no reply is received within seconds.\n Default timeout: 30. Use 0 to wait forever.\n --bigkeys Sample Redis keys looking for keys with many elements (complexity).\n --memkeys Sample Redis keys looking for keys consuming a lot of memory.\n --memkeys-samples Sample Redis keys looking for keys consuming a lot of memory.\n And define number of key elements to sample\n --keystats Sample Redis keys looking for keys memory size and length (combine bigkeys and memkeys).\n --keystats-samples Sample Redis keys looking for keys memory size and length.\n And define number of key elements to sample (only for memory usage).\n --cursor Start the scan at the cursor (usually after a Ctrl-C).\n Optionally used with --keystats and --keystats-samples.\n --top To display top key sizes (default: 10).\n Optionally used with --keystats and --keystats-samples.\n --hotkeys Sample Redis keys looking for hot keys.\n only works when maxmemory-policy is *lfu.\n --scan List all keys using the SCAN command.\n --pattern Keys pattern when using the --scan, --bigkeys, --memkeys,\n --keystats or --hotkeys options (default: *).\n --count Count option when using the --scan, --bigkeys, --memkeys,\n --keystats or --hotkeys (default: 10).\n --quoted-pattern Same as --pattern, but the specified string can be\n quoted, in order to pass an otherwise non binary-safe string.\n --intrinsic-latency Run a test to measure intrinsic system latency.\n The test will run for the specified amount of seconds.\n --eval Send an EVAL command using the Lua script at .\n --ldb Used with --eval enable the Redis Lua debugger.\n --ldb-sync-mode Like --ldb but uses the synchronous Lua debugger, in\n this mode the server is blocked and script changes are\n not rolled back from the server memory.\n --cluster [args...] [opts...]\n Cluster Manager command and arguments (see below).\n --verbose Verbose mode.\n --no-auth-warning Don't show warning message when using password on command\n line interface.\n --help Output this help and exit.\n --version Output version and exit.\n\nCluster Manager Commands:\n Use --cluster help to list all available cluster manager commands.\n\nExamples:\n redis-cli -u redis://default:PASSWORD@localhost:6379/0\n cat /etc/passwd | redis-cli -x set mypasswd\n redis-cli -D \"\" --raw dump key > key.dump && redis-cli -X dump_tag restore key2 0 dump_tag replace < key.dump\n redis-cli -r 100 lpush mylist x\n redis-cli -r 100 -i 1 info | grep used_memory_human:\n redis-cli --quoted-input set '\"null-\\x00-separated\"' value\n redis-cli --eval myscript.lua key1 key2 , arg1 arg2 arg3\n redis-cli --scan --pattern '*:12345*'\n redis-cli --scan --pattern '*:12345*' --count 100\n\n (Note: when using --eval the comma separates KEYS[] from ARGV[] items)\n\nWhen no command is given, redis-cli starts in interactive mode.\nType \"help\" in interactive mode for information on available commands\nand settings.\n\n\n------------------------------------------------------------------------------\nredis-server --help\n------------------------------------------------------------------------------\nUsage: ./redis-server [/path/to/redis.conf] [options] [-]\n ./redis-server - (read config from stdin)\n ./redis-server -v or --version\n ./redis-server -h or --help\n ./redis-server --test-memory \n ./redis-server --check-system\n\nExamples:\n ./redis-server (run the server with default conf)\n echo 'maxmemory 128mb' | ./redis-server -\n ./redis-server /etc/redis/6379.conf\n ./redis-server --port 7777\n ./redis-server --port 7777 --replicaof 127.0.0.1 8888\n ./redis-server /etc/myredis.conf --loglevel verbose -\n ./redis-server /etc/myredis.conf --loglevel verbose\n\nSentinel mode:\n ./redis-server /etc/sentinel.conf --sentinel\n```\n", - "summary": "This app installs the official Redis 8.6.2 server and client on the host and fronts them as typed methods. The bundle is a relocatable build of Redis 8.6.2 (from conda-forge, AGPL-3.0) carrying redis-server, redis-cli, redis-benchmark, redis-check-rdb, redis-check-aof, and redis-sentinel; every binary is sha-pinned and staged at install, and a tiny redis dispatcher routes each method to the right tool. Binaries are…", + "tagline": "Run Redis from an agent \u2014 start a local in-memory store and run any command with redis-cli", + "description": "# Redis (server + redis-cli) \u2014 native CLI for agents\n\nThis app installs the official **Redis 8.6.2** server and client on the host and fronts them as\ntyped methods. The bundle is a relocatable build of Redis 8.6.2 (from conda-forge, AGPL-3.0)\ncarrying `redis-server`, `redis-cli`, `redis-benchmark`, `redis-check-rdb`, `redis-check-aof`, and\n`redis-sentinel`; every binary is sha-pinned and staged at install, and a tiny `redis` dispatcher routes\neach method to the right tool. Binaries are fetched from the Pilot artifact registry on **macOS and Linux**\n(arm64 + amd64).\n\nRedis is an **in-memory data-structure store** \u2014 strings, hashes, lists, sets, sorted sets, streams, plus\npub/sub and transactions. There is no cluster to provision: an agent starts a throwaway local server and\nuses it as a cache, a fast key-value DB, or a coordination/queue primitive.\n\n## Run a Redis locally \u2014 the usual flow\n\n1. **Start:** `redis.start` `{ \"port\": \"6399\", \"dir\": \"/tmp\" }` \u2014 boots a daemonized server on\n `127.0.0.1:6399`, with pidfile/logfile/RDB under `dir`.\n2. **Health:** `redis.ping` `{ \"port\": \"6399\" }` \u2192 `PONG`.\n3. **Use it:** `redis.set` / `redis.get`, `redis.info`, `redis.dbsize`, or **any** command via\n `redis.exec` `{ \"args\": [\"redis-cli\",\"-p\",\"6399\",\"ZADD\",\"board\",\"100\",\"alice\"] }`.\n4. **Stop:** `redis.stop` `{ \"port\": \"6399\" }`.\n\n## Methods\n\n- `redis.start` / `redis.stop` \u2014 local server lifecycle (daemonized; per-port pidfile/logfile).\n- `redis.ping` \u2014 liveness (PONG). `redis.info` \u2014 full server INFO. `redis.dbsize` \u2014 key count.\n- `redis.set` / `redis.get` \u2014 string get/set convenience.\n- `redis.exec` \u2014 run any tool with a verbatim argv (+ optional stdin) \u2014 every Redis command, pipelined\n batches, benchmarks, RDB/AOF checks, sentinel.\n- `redis.cli_help` \u2014 the complete `redis-cli --help`. `redis.version` \u2014 the delivered version.\n `redis.help` \u2014 the self-describing method list.\n\n## Configuration\n\n- **`port`** \u2014 TCP port for the local server (convention `6399`). Bound to `127.0.0.1`.\n- **`dir`** \u2014 an existing writable directory for the pidfile, logfile, and RDB snapshot; pass `/tmp` for a\n throwaway server, or a path you control for persistence (the RDB lives at `/dump.rdb`).\n- **Persistence** \u2014 `redis.stop` does `SHUTDOWN NOSAVE`; run `redis.exec` with `SAVE`/`BGSAVE` first if you\n need the dataset on disk. Any redis.conf directive is reachable as a `--flag` via\n `redis.exec` (`redis-server --port ... --maxmemory 256mb --maxmemory-policy allkeys-lru ...`).\n- **Auth** \u2014 local servers are open by default; set `--requirepass` (via `redis.exec` on start) and pass the\n password through the `REDISCLI_AUTH` env var (forwarded to the child) or `-a` on `redis.exec`.\n\n## Good to know\n\n- Output returns verbatim where it is already clean; on a non-zero exit the reply is `{stdout, stderr, exit}`.\n- Free and open source under the **AGPL-3.0** license (Redis 8.x). Repackaged unmodified from conda-forge.\n\n## redis-cli / redis-server help\n```\nRedis CLI help \u2014 redis-cli and redis-server\n===========================================\n\nRedis is an in-memory data-structure store (cache, database, message broker).\nThis app fronts the Redis server + redis-cli as agent methods: start a local\nserver, then SET/GET/PING/INFO or run any command via redis.exec.\n\n------------------------------------------------------------------------------\nredis-cli --help\n------------------------------------------------------------------------------\nredis-cli 8.6.2\n\nUsage: redis-cli [OPTIONS] [cmd [arg [arg ...]]]\n -h Server hostname (default: 127.0.0.1).\n -p Server port (default: 6379).\n -t Server connection timeout in seconds (decimals allowed).\n Default timeout is 0, meaning no limit, depending on the OS.\n -s Server socket (overrides hostname and port).\n -a Password to use when connecting to the server.\n You can also use the REDISCLI_AUTH environment\n variable to pass this password more safely\n (if both are used, this argument takes precedence).\n --user Used to send ACL style 'AUTH username pass'. Needs -a.\n --pass Alias of -a for consistency with the new --user option.\n --askpass Force user to input password with mask from STDIN.\n If this argument is used, '-a' and REDISCLI_AUTH\n environment variable will be ignored.\n -u Server URI on format redis://user:password@host:port/dbnum\n User, password and dbnum are optional. For authentication\n without a username, use username 'default'. For TLS, use\n the scheme 'rediss'.\n -r Execute specified command N times.\n -i When -r is used, waits seconds per command.\n It is possible to specify sub-second times like -i 0.1.\n This interval is also used in --scan and --stat per cycle.\n and in --bigkeys, --memkeys, --keystats, and --hotkeys per 100 cycles.\n -n Database number.\n --name Set the client name.\n -2 Start session in RESP2 protocol mode.\n -3 Start session in RESP3 protocol mode.\n -x Read last argument from STDIN (see example below).\n -X Read argument from STDIN (see example below).\n -d Delimiter between response bulks for raw formatting (default: \\n).\n -D Delimiter between responses for raw formatting (default: \\n).\n -c Enable cluster mode (follow -ASK and -MOVED redirections).\n -e Return exit error code when command execution fails.\n -4 Prefer IPv4 over IPv6 on DNS lookup.\n -6 Prefer IPv6 over IPv4 on DNS lookup.\n --tls Establish a secure TLS connection.\n --sni Server name indication for TLS.\n --cacert CA Certificate file to verify with.\n --cacertdir Directory where trusted CA certificates are stored.\n If neither cacert nor cacertdir are specified, the default\n system-wide trusted root certs configuration will apply.\n --insecure Allow insecure TLS connection by skipping cert validation.\n --cert Client certificate to authenticate with.\n --key Private key file to authenticate with.\n --tls-ciphers Sets the list of preferred ciphers (TLSv1.2 and below)\n in order of preference from highest to lowest separated by colon (\":\").\n See the ciphers(1ssl) manpage for more information about the syntax of this string.\n --tls-ciphersuites Sets the list of preferred ciphersuites (TLSv1.3)\n in order of preference from highest to lowest separated by colon (\":\").\n See the ciphers(1ssl) manpage for more information about the syntax of this string,\n and specifically for TLSv1.3 ciphersuites.\n --raw Use raw formatting for replies (default when STDOUT is\n not a tty).\n --no-raw Force formatted output even when STDOUT is not a tty.\n --quoted-input Force input to be handled as quoted strings.\n --csv Output in CSV format.\n --json Output in JSON format (default RESP3, use -2 if you want to use with RESP2).\n --quoted-json Same as --json, but produce ASCII-safe quoted strings, not Unicode.\n --show-pushes Whether to print RESP3 PUSH messages. Enabled by default when\n STDOUT is a tty but can be overridden with --show-pushes no.\n --stat Print rolling stats about server: mem, clients, ...\n --latency Enter a special mode continuously sampling latency.\n If you use this mode in an interactive session it runs\n forever displaying real-time stats. Otherwise if --raw or\n --csv is specified, or if you redirect the output to a non\n TTY, it samples the latency for 1 second (you can use\n -i to change the interval), then produces a single output\n and exits.\n --latency-history Like --latency but tracking latency changes over time.\n Default time interval is 15 sec. Change it using -i.\n --latency-dist Shows latency as a spectrum, requires xterm 256 colors.\n Default time interval is 1 sec. Change it using -i.\n --vset-recall Enable VSIM recall test mode for the specified key\n (that must be a vector set). Random vectors are created\n mixing components from other elements. A VSIM is then\n executed and checked against ground truth.\n --vset-recall-count How many top elements to fetch per query.\n --vset-recall-ef HSNW EF (search effort) to use. Default 500.\n --vset-recall-ele Number of elements used to compose query vectors\n Default 1.\n --lru-test Simulate a cache workload with an 80-20 distribution.\n --replica Simulate a replica showing commands received from the master.\n --rdb Transfer an RDB dump from remote server to local file.\n Use filename of \"-\" to write to stdout.\n --functions-rdb Like --rdb but only get the functions (not the keys)\n when getting the RDB dump file.\n --pipe Transfer raw Redis protocol from stdin to server.\n --pipe-timeout In --pipe mode, abort with error if after sending all data.\n no reply is received within seconds.\n Default timeout: 30. Use 0 to wait forever.\n --bigkeys Sample Redis keys looking for keys with many elements (complexity).\n --memkeys Sample Redis keys looking for keys consuming a lot of memory.\n --memkeys-samples Sample Redis keys looking for keys consuming a lot of memory.\n And define number of key elements to sample\n --keystats Sample Redis keys looking for keys memory size and length (combine bigkeys and memkeys).\n --keystats-samples Sample Redis keys looking for keys memory size and length.\n And define number of key elements to sample (only for memory usage).\n --cursor Start the scan at the cursor (usually after a Ctrl-C).\n Optionally used with --keystats and --keystats-samples.\n --top To display top key sizes (default: 10).\n Optionally used with --keystats and --keystats-samples.\n --hotkeys Sample Redis keys looking for hot keys.\n only works when maxmemory-policy is *lfu.\n --scan List all keys using the SCAN command.\n --pattern Keys pattern when using the --scan, --bigkeys, --memkeys,\n --keystats or --hotkeys options (default: *).\n --count Count option when using the --scan, --bigkeys, --memkeys,\n --keystats or --hotkeys (default: 10).\n --quoted-pattern Same as --pattern, but the specified string can be\n quoted, in order to pass an otherwise non binary-safe string.\n --intrinsic-latency Run a test to measure intrinsic system latency.\n The test will run for the specified amount of seconds.\n --eval Send an EVAL command using the Lua script at .\n --ldb Used with --eval enable the Redis Lua debugger.\n --ldb-sync-mode Like --ldb but uses the synchronous Lua debugger, in\n this mode the server is blocked and script changes are\n not rolled back from the server memory.\n --cluster [args...] [opts...]\n Cluster Manager command and arguments (see below).\n --verbose Verbose mode.\n --no-auth-warning Don't show warning message when using password on command\n line interface.\n --help Output this help and exit.\n --version Output version and exit.\n\nCluster Manager Commands:\n Use --cluster help to list all available cluster manager commands.\n\nExamples:\n redis-cli -u redis://default:PASSWORD@localhost:6379/0\n cat /etc/passwd | redis-cli -x set mypasswd\n redis-cli -D \"\" --raw dump key > key.dump && redis-cli -X dump_tag restore key2 0 dump_tag replace < key.dump\n redis-cli -r 100 lpush mylist x\n redis-cli -r 100 -i 1 info | grep used_memory_human:\n redis-cli --quoted-input set '\"null-\\x00-separated\"' value\n redis-cli --eval myscript.lua key1 key2 , arg1 arg2 arg3\n redis-cli --scan --pattern '*:12345*'\n redis-cli --scan --pattern '*:12345*' --count 100\n\n (Note: when using --eval the comma separates KEYS[] from ARGV[] items)\n\nWhen no command is given, redis-cli starts in interactive mode.\nType \"help\" in interactive mode for information on available commands\nand settings.\n\n\n------------------------------------------------------------------------------\nredis-server --help\n------------------------------------------------------------------------------\nUsage: ./redis-server [/path/to/redis.conf] [options] [-]\n ./redis-server - (read config from stdin)\n ./redis-server -v or --version\n ./redis-server -h or --help\n ./redis-server --test-memory \n ./redis-server --check-system\n\nExamples:\n ./redis-server (run the server with default conf)\n echo 'maxmemory 128mb' | ./redis-server -\n ./redis-server /etc/redis/6379.conf\n ./redis-server --port 7777\n ./redis-server --port 7777 --replicaof 127.0.0.1 8888\n ./redis-server /etc/myredis.conf --loglevel verbose -\n ./redis-server /etc/myredis.conf --loglevel verbose\n\nSentinel mode:\n ./redis-server /etc/sentinel.conf --sentinel\n```\n", + "summary": "This app installs the official Redis 8.6.2 server and client on the host and fronts them as typed methods. The bundle is a relocatable build of Redis 8.6.2 (from conda-forge, AGPL-3.0) carrying redis-server, redis-cli, redis-benchmark, redis-check-rdb, redis-check-aof, and redis-sentinel; every binary is sha-pinned and staged at install, and a tiny redis dispatcher routes each method to the right tool. Binaries are\u2026", "categories": [ "data" ], @@ -3484,7 +3795,7 @@ }, { "name": "redis.stop", - "summary": "Stop the local server on 127.0.0.1:`port` (no final save — use redis.exec with SAVE/BGSAVE first if you need to persist). This is `redis-cli -p SHUTDOWN NOSAVE`.", + "summary": "Stop the local server on 127.0.0.1:`port` (no final save \u2014 use redis.exec with SAVE/BGSAVE first if you need to persist). This is `redis-cli -p SHUTDOWN NOSAVE`.", "example": "", "gated": "" }, @@ -3508,7 +3819,7 @@ }, { "name": "redis.info", - "summary": "Return the server's INFO (version, memory, clients, persistence, stats, replication, keyspace) as plain text — a full health/inventory snapshot. This is `redis-cli -p INFO`.", + "summary": "Return the server's INFO (version, memory, clients, persistence, stats, replication, keyspace) as plain text \u2014 a full health/inventory snapshot. This is `redis-cli -p INFO`.", "example": "", "gated": "" }, @@ -3520,13 +3831,13 @@ }, { "name": "redis.exec", - "summary": "Run any bundled Redis tool with a verbatim argv — the full surface beyond the curated methods. Payload is {\"args\":[, ...]} where the first element is the tool (redis-cli, redis-server, redis-benchmark, redis-check-rdb, redis-check-aof, redis-sentinel) and the rest are its args; optional {\"stdin\":\"...\"} is piped to it. This is how you run ANY Redis command: {\"args\":[\"redis-cli\",\"-p\",\"6399\",\"LPUSH\",\"mylist\",\"a\",\"b\",\"c\"]}, {\"args\":[\"redis-cli\",\"-p\",\"6399\",\"-n\",\"1\",\"HSET\",\"h\",\"f\",\"v\"]}, a pipelined script via stdin {\"args\":[\"redis-cli\",\"-p\",\"6399\"],\"stdin\":\"SET a 1\\nINCR a\\nGET a\"}, or a benchmark {\"args\":[\"redis-benchmark\",\"-p\",\"6399\",\"-n\",\"1000\",\"-q\"]}. The REDISCLI_AUTH env var is passed through for password auth.", + "summary": "Run any bundled Redis tool with a verbatim argv \u2014 the full surface beyond the curated methods. Payload is {\"args\":[, ...]} where the first element is the tool (redis-cli, redis-server, redis-benchmark, redis-check-rdb, redis-check-aof, redis-sentinel) and the rest are its args; optional {\"stdin\":\"...\"} is piped to it. This is how you run ANY Redis command: {\"args\":[\"redis-cli\",\"-p\",\"6399\",\"LPUSH\",\"mylist\",\"a\",\"b\",\"c\"]}, {\"args\":[\"redis-cli\",\"-p\",\"6399\",\"-n\",\"1\",\"HSET\",\"h\",\"f\",\"v\"]}, a pipelined script via stdin {\"args\":[\"redis-cli\",\"-p\",\"6399\"],\"stdin\":\"SET a 1\\nINCR a\\nGET a\"}, or a benchmark {\"args\":[\"redis-benchmark\",\"-p\",\"6399\",\"-n\",\"1000\",\"-q\"]}. The REDISCLI_AUTH env var is passed through for password auth.", "example": "", "gated": "" }, { "name": "redis.cli_help", - "summary": "Return the complete `redis-cli --help` (every option of the Redis command-line client) straight from the delivered binary — the reference for what redis.exec accepts. This is `redis-cli --help`.", + "summary": "Return the complete `redis-cli --help` (every option of the Redis command-line client) straight from the delivered binary \u2014 the reference for what redis.exec accepts. This is `redis-cli --help`.", "example": "", "gated": "" }, @@ -3600,7 +3911,7 @@ "product_demo": { "skill": "io.pilot.redis", "title": "Full usage demo", - "when_to_use": "When you need a fast in-memory key/value store for caching, counters, session state, queues or ephemeral shared data — not for relational queries or durable structured storage.", + "when_to_use": "When you need a fast in-memory key/value store for caching, counters, session state, queues or ephemeral shared data \u2014 not for relational queries or durable structured storage.", "metered": false, "quickstart": { "title": "", @@ -3639,7 +3950,7 @@ "title": "Set a TTL via the raw CLI", "goal": "Expire a cache entry after 60s using redis.exec", "command": "pilotctl appstore call io.pilot.redis redis.exec '{\"args\":[\"redis-cli\",\"-p\",\"6399\",\"EXPIRE\",\"session:42\",\"60\"]}'", - "expect": "(integer) 1 — the key will auto-delete after 60 seconds", + "expect": "(integer) 1 \u2014 the key will auto-delete after 60 seconds", "cost": "", "note": "" }, @@ -3654,7 +3965,7 @@ ], "cost": null, "gotchas": [ - "You must redis.start a server before ping/set/get/dbsize — only redis.version works with no server.", + "You must redis.start a server before ping/set/get/dbsize \u2014 only redis.version works with no server.", "port is a string (\"6399\"), and each server needs its own port + writable dir.", "redis.stop does no final save; use redis.exec with SAVE first if you need the RDB persisted.", "redis.set/get handle plain strings; for lists, hashes, EXPIRE etc. drop to redis.exec with a verbatim argv." @@ -3897,9 +4208,9 @@ "check_balance": "" }, "gotchas": [ - "Quota is 50 REQUESTS per Pilot user, not a dollar budget — every enrichment/discovery call spends 1.", + "Quota is 50 REQUESTS per Pilot user, not a dollar budget \u2014 every enrichment/discovery call spends 1.", "402 Payment Required means your 50 free requests are used up.", - "Every returned field is source-backed — inspect the sources[] before trusting a value.", + "Every returned field is source-backed \u2014 inspect the sources[] before trusting a value.", "deep_search is async: it returns a task_id and results are retrieved separately.", "Provide as many seed details as you have (name + company, email, domain) for higher-confidence hits." ], @@ -3912,8 +4223,8 @@ "id": "io.pilot.cosift", "name": "Cosift", "tagline": "Grounded web search, retrieval, and research for agents", - "description": "Cosift is the Pilot app-store front door for the cosift search/answer/research API. It gives an agent keyword + semantic search, document retrieval, and LLM-grounded answers and multi-step research over a crawled web corpus — returned as clean structured JSON.\n\nEvery method is discoverable at runtime via cosift.help, which reports each method's parameters and a latency class (fast / med / slow) so a caller can pick the cheapest method that fits.", - "summary": "Cosift is the Pilot app-store front door for the cosift search/answer/research API. It gives an agent keyword + semantic search, document retrieval, and LLM-grounded answers and multi-step research over a crawled web corpus — returned as clean structured JSON. Every method is discoverable at runtime via cosift.help, which reports each method's parameters and a latency class (fast / med / slow) so a caller can pick…", + "description": "Cosift is the Pilot app-store front door for the cosift search/answer/research API. It gives an agent keyword + semantic search, document retrieval, and LLM-grounded answers and multi-step research over a crawled web corpus \u2014 returned as clean structured JSON.\n\nEvery method is discoverable at runtime via cosift.help, which reports each method's parameters and a latency class (fast / med / slow) so a caller can pick the cheapest method that fits.", + "summary": "Cosift is the Pilot app-store front door for the cosift search/answer/research API. It gives an agent keyword + semantic search, document retrieval, and LLM-grounded answers and multi-step research over a crawled web corpus \u2014 returned as clean structured JSON. Every method is discoverable at runtime via cosift.help, which reports each method's parameters and a latency class (fast / med / slow) so a caller can pick\u2026", "categories": [ "ai" ], @@ -4045,8 +4356,8 @@ "id": "io.telepat.ideon-free", "name": "Ideon (Free)", "tagline": "Free long-form article generation for agents", - "description": "Free article generation for agents: ideon-free.generate(idea) returns a jobId; ideon-free.poll(jobId) returns the finished markdown article. A thin adapter over Ideon's ideon_write — no payment.", - "summary": "Free article generation for agents: ideon-free.generate(idea) returns a jobId; ideon-free.poll(jobId) returns the finished markdown article. A thin adapter over Ideon's ideon_write — no payment.", + "description": "Free article generation for agents: ideon-free.generate(idea) returns a jobId; ideon-free.poll(jobId) returns the finished markdown article. A thin adapter over Ideon's ideon_write \u2014 no payment.", + "summary": "Free article generation for agents: ideon-free.generate(idea) returns a jobId; ideon-free.poll(jobId) returns the finished markdown article. A thin adapter over Ideon's ideon_write \u2014 no payment.", "categories": [ "ai" ], @@ -4088,7 +4399,7 @@ "version": "0.3.1", "date": "", "notes": [ - "Thin adapter over Ideon ideon_write — no payment" + "Thin adapter over Ideon ideon_write \u2014 no payment" ] } ], @@ -4140,7 +4451,7 @@ "product_demo": { "skill": "io.telepat.ideon-free", "title": "Full usage demo", - "when_to_use": "When you need a finished long-form Markdown article generated from a one-line idea — kick off generation, then poll for the completed title, slug, and body. Free, no payment.", + "when_to_use": "When you need a finished long-form Markdown article generated from a one-line idea \u2014 kick off generation, then poll for the completed title, slug, and body. Free, no payment.", "metered": false, "quickstart": { "title": "", @@ -4178,10 +4489,10 @@ ], "cost": null, "gotchas": [ - "Generation is async: generate returns a jobId immediately; poll it until status is \"done\" (~60–90s for a real run).", + "Generation is async: generate returns a jobId immediately; poll it until status is \"done\" (~60\u201390s for a real run).", "poll returns status \"pending\" until ready, then the finished Markdown in the article field.", "An unknown or expired jobId polls back status \"error\".", - "Free — a thin adapter over Ideon's ideon_write (backend ideon-mcp.telepat.io), rate-limited to 30 calls/min." + "Free \u2014 a thin adapter over Ideon's ideon_write (backend ideon-mcp.telepat.io), rate-limited to 30 calls/min." ], "next": [ "io.telepat.ideon-free ideon-free.help '{}'" @@ -4191,9 +4502,9 @@ { "id": "io.pilot.plainweb", "name": "Plainweb", - "tagline": "Any web page as clean Markdown — no HTML, no JS, one call", - "description": "Plainweb is a Pilot-owned URL→Markdown service: give it any web page and get back clean, accurate Markdown — no HTML, no JavaScript, just plain text structured as Markdown.\n\nWhat an agent gets:\n- **One call** — `plainweb.fetch(url)` fetches the page and returns it as Markdown (GFM tables, fenced code with language, task lists). The target URL goes straight in the path.\n- **Accurate extraction** — a cost-aware static→headless-Chrome fetch ladder (most pages never launch Chrome), go-readability primary (preserves code blocks and tables) with go-trafilatura fallback, converted via html-to-markdown v2.\n- **Scheme-less OK** — bare hosts like `example.com` are sanitized to `https://`.\n\nGood to know:\n- **Free to call — no API key required.** Public endpoints are available to every caller.\n- **Rate limit:** anonymous callers get **1000 requests/second** (burst 2000); a master key only elevates a caller past that limit.\n- The reply is `text/markdown`, returned by the adapter as `{ \"content_type\", \"content\" }` (the Markdown is in `content`).\n- In-house Pilot Protocol tool, deployed on Cloud Run.", - "summary": "Plainweb is a Pilot-owned URL→Markdown service: give it any web page and get back clean, accurate Markdown — no HTML, no JavaScript, just plain text structured as Markdown. What an agent gets: - One call — plainweb.fetch(url) fetches the page and returns it as Markdown (GFM tables, fenced code with language, task lists). The target URL goes straight in the path. - Accurate extraction — a cost-aware…", + "tagline": "Any web page as clean Markdown \u2014 no HTML, no JS, one call", + "description": "Plainweb is a Pilot-owned URL\u2192Markdown service: give it any web page and get back clean, accurate Markdown \u2014 no HTML, no JavaScript, just plain text structured as Markdown.\n\nWhat an agent gets:\n- **One call** \u2014 `plainweb.fetch(url)` fetches the page and returns it as Markdown (GFM tables, fenced code with language, task lists). The target URL goes straight in the path.\n- **Accurate extraction** \u2014 a cost-aware static\u2192headless-Chrome fetch ladder (most pages never launch Chrome), go-readability primary (preserves code blocks and tables) with go-trafilatura fallback, converted via html-to-markdown v2.\n- **Scheme-less OK** \u2014 bare hosts like `example.com` are sanitized to `https://`.\n\nGood to know:\n- **Free to call \u2014 no API key required.** Public endpoints are available to every caller.\n- **Rate limit:** anonymous callers get **1000 requests/second** (burst 2000); a master key only elevates a caller past that limit.\n- The reply is `text/markdown`, returned by the adapter as `{ \"content_type\", \"content\" }` (the Markdown is in `content`).\n- In-house Pilot Protocol tool, deployed on Cloud Run.", + "summary": "Plainweb is a Pilot-owned URL\u2192Markdown service: give it any web page and get back clean, accurate Markdown \u2014 no HTML, no JavaScript, just plain text structured as Markdown. What an agent gets: - One call \u2014 plainweb.fetch(url) fetches the page and returns it as Markdown (GFM tables, fenced code with language, task lists). The target URL goes straight in the path. - Accurate extraction \u2014 a cost-aware\u2026", "categories": [ "web" ], @@ -4219,7 +4530,7 @@ "methods": [ { "name": "plainweb.fetch", - "summary": "Fetch any web page and return it as clean Markdown — no HTML, no JavaScript. Pass the full target URL as `url`; it is placed verbatim in the request path (GET /). Scheme-less hosts (e.g. example.com) are sanitized to https://. The reply is `{\"content_type\":\"text/markdown; charset=utf-8\",\"content\":\"\"}`. Open and free — no API key needed.", + "summary": "Fetch any web page and return it as clean Markdown \u2014 no HTML, no JavaScript. Pass the full target URL as `url`; it is placed verbatim in the request path (GET /). Scheme-less hosts (e.g. example.com) are sanitized to https://. The reply is `{\"content_type\":\"text/markdown; charset=utf-8\",\"content\":\"\"}`. Open and free \u2014 no API key needed.", "example": "", "gated": "" }, @@ -4288,7 +4599,7 @@ "product_demo": { "skill": "io.pilot.plainweb", "title": "Full usage demo", - "when_to_use": "When you need to read a public web page as clean Markdown (no HTML, no JS) in one call — for summarizing, extracting, or feeding article content to a model.", + "when_to_use": "When you need to read a public web page as clean Markdown (no HTML, no JS) in one call \u2014 for summarizing, extracting, or feeding article content to a model.", "metered": false, "quickstart": { "title": "", @@ -4329,7 +4640,7 @@ "The target URL goes verbatim into the request path (GET /); pass it as the url param.", "Scheme-less hosts (e.g. example.com) are sanitized to https://.", "The Markdown body is in the content field of the reply, not the top level.", - "Free and open — no API key required." + "Free and open \u2014 no API key required." ], "next": [ "io.pilot.plainweb plainweb.help '{}'" @@ -4339,9 +4650,9 @@ { "id": "io.pilot.otto", "name": "Otto", - "tagline": "Drive real Chrome tabs from an agent — extract, automate, screenshot, no headless farm", - "description": "Otto is secure remote browser automation. A controller CLI sends commands over an authenticated WebSocket to a relay daemon, which routes them to a Chrome extension running on live tabs. Code drives the browser deterministically; the agent decides what to do, not how to click.\n\nWhat an agent gets:\n- **Content extraction** — `otto.extract` / `otto.extract.format` turn a URL into clean markdown, distilled/clean/raw HTML, or text through a real tab.\n- **Site commands** — `otto.test` runs registered actions on real sessions (Reddit/LinkedIn `getPosts`, Hacker News `getFrontPage`, Google `getSearchResults`, …); `otto.commands` lists what a node exposes.\n- **Page & tab control** — `otto.screenshot` (viewport or full page) and `otto.cmd` for low-level primitives (tab open/navigate/query, DOM extract).\n- **Status & diagnostics** — `otto.status` (relay + connected nodes), `otto.client.status`, `otto.authcode`, `otto.extension.info`, `otto.logs`/`otto.logs.status`, `otto.agent.status` — all JSON.\n- **Full CLI surface** — `otto.exec` runs any verbatim otto argv.\n\nGood to know:\n- Returns JSON wherever the CLI offers it; discover the live surface at runtime with `otto.help` — every method, its parameters, and its latency class (fast / med / slow).\n- Real browser tabs, not a headless farm — no Docker, Puppeteer farm, or cloud-browser rental.\n- Prerequisite stack on the host: a running relay (`otto start`), Chrome with the Otto extension loaded and paired as a node, and a logged-in controller. Until that is up, page commands return a structured error (`{stdout,stderr,exit}`); `otto.status` is the right preflight.\n- Runs on macOS and Linux (arm64 + amd64); the otto CLI is staged as a self-contained binary and sha-pinned on install. Free and open source (MIT) — no payment, no per-call limit.", - "summary": "Otto is secure remote browser automation. A controller CLI sends commands over an authenticated WebSocket to a relay daemon, which routes them to a Chrome extension running on live tabs. Code drives the browser deterministically; the agent decides what to do, not how to click. What an agent gets: - Content extraction — otto.extract / otto.extract.format turn a URL into clean markdown, distilled/clean/raw HTML, or…", + "tagline": "Drive real Chrome tabs from an agent \u2014 extract, automate, screenshot, no headless farm", + "description": "Otto is secure remote browser automation. A controller CLI sends commands over an authenticated WebSocket to a relay daemon, which routes them to a Chrome extension running on live tabs. Code drives the browser deterministically; the agent decides what to do, not how to click.\n\nWhat an agent gets:\n- **Content extraction** \u2014 `otto.extract` / `otto.extract.format` turn a URL into clean markdown, distilled/clean/raw HTML, or text through a real tab.\n- **Site commands** \u2014 `otto.test` runs registered actions on real sessions (Reddit/LinkedIn `getPosts`, Hacker News `getFrontPage`, Google `getSearchResults`, \u2026); `otto.commands` lists what a node exposes.\n- **Page & tab control** \u2014 `otto.screenshot` (viewport or full page) and `otto.cmd` for low-level primitives (tab open/navigate/query, DOM extract).\n- **Status & diagnostics** \u2014 `otto.status` (relay + connected nodes), `otto.client.status`, `otto.authcode`, `otto.extension.info`, `otto.logs`/`otto.logs.status`, `otto.agent.status` \u2014 all JSON.\n- **Full CLI surface** \u2014 `otto.exec` runs any verbatim otto argv.\n\nGood to know:\n- Returns JSON wherever the CLI offers it; discover the live surface at runtime with `otto.help` \u2014 every method, its parameters, and its latency class (fast / med / slow).\n- Real browser tabs, not a headless farm \u2014 no Docker, Puppeteer farm, or cloud-browser rental.\n- Prerequisite stack on the host: a running relay (`otto start`), Chrome with the Otto extension loaded and paired as a node, and a logged-in controller. Until that is up, page commands return a structured error (`{stdout,stderr,exit}`); `otto.status` is the right preflight.\n- Runs on macOS and Linux (arm64 + amd64); the otto CLI is staged as a self-contained binary and sha-pinned on install. Free and open source (MIT) \u2014 no payment, no per-call limit.", + "summary": "Otto is secure remote browser automation. A controller CLI sends commands over an authenticated WebSocket to a relay daemon, which routes them to a Chrome extension running on live tabs. Code drives the browser deterministically; the agent decides what to do, not how to click. What an agent gets: - Content extraction \u2014 otto.extract / otto.extract.format turn a URL into clean markdown, distilled/clean/raw HTML, or\u2026", "categories": [ "web" ], @@ -4369,13 +4680,13 @@ "methods": [ { "name": "otto.exec", - "summary": "Run any otto subcommand. Payload is {\"args\":[...]} — the verbatim otto argv. Use this for the full CLI surface beyond the curated methods (config, client register/login/remove, pair, listener unsubscribe, extension update, agent install, site-filtered `commands list --site`, filtered `logs list`, etc.). Add \"--json\" where the command supports it. Example args: [\"commands\",\"list\",\"--site\",\"reddit.com\",\"--json\"]. Note: interactive/streaming subcommands (setup, settings, logs follow, listener subscribe-network, test with stream/wait flags, mcp serve, start --attached) are not suitable over one-shot IPC.", + "summary": "Run any otto subcommand. Payload is {\"args\":[...]} \u2014 the verbatim otto argv. Use this for the full CLI surface beyond the curated methods (config, client register/login/remove, pair, listener unsubscribe, extension update, agent install, site-filtered `commands list --site`, filtered `logs list`, etc.). Add \"--json\" where the command supports it. Example args: [\"commands\",\"list\",\"--site\",\"reddit.com\",\"--json\"]. Note: interactive/streaming subcommands (setup, settings, logs follow, listener subscribe-network, test with stream/wait flags, mcp serve, start --attached) are not suitable over one-shot IPC.", "example": "", "gated": "" }, { "name": "otto.status", - "summary": "Relay daemon status as JSON: running pid, port, uptime, log path, and the list of currently connected browser node IDs. The right preflight before any page command — an empty node list means no Chrome extension node is paired/online.", + "summary": "Relay daemon status as JSON: running pid, port, uptime, log path, and the list of currently connected browser node IDs. The right preflight before any page command \u2014 an empty node list means no Chrome extension node is paired/online.", "example": "", "gated": "" }, @@ -4447,7 +4758,7 @@ }, { "name": "otto.agent.status", - "summary": "Which agent frameworks (claude, codex, cursor, vscode, …) currently have the Otto MCP server registered, as JSON.", + "summary": "Which agent frameworks (claude, codex, cursor, vscode, \u2026) currently have the Otto MCP server registered, as JSON.", "example": "", "gated": "" }, @@ -4512,15 +4823,15 @@ "product_demo": { "skill": "io.pilot.otto", "title": "Full usage demo", - "when_to_use": "When you need to drive a real Chrome tab from an agent — extract a page as markdown/HTML, run site commands (Reddit/LinkedIn/HN/Google), or screenshot — via a paired browser extension, not a headless farm.", + "when_to_use": "When you need to drive a real Chrome tab from an agent \u2014 extract a page as markdown/HTML, run site commands (Reddit/LinkedIn/HN/Google), or screenshot \u2014 via a paired browser extension, not a headless farm.", "metered": false, "quickstart": { "title": "", - "goal": "Preflight — check the relay and connected browser nodes", + "goal": "Preflight \u2014 check the relay and connected browser nodes", "command": "pilotctl appstore call io.pilot.otto otto.status '{}'", "expect": "{\"stdout\":\"{\\\"pid\\\":...,\\\"nodes\\\":[\\\"node-1\\\"]}\",\"exit\":0}", "cost": "", - "note": "An empty nodes list means no Chrome extension node is paired/online — page commands will fail until one is." + "note": "An empty nodes list means no Chrome extension node is paired/online \u2014 page commands will fail until one is." }, "examples": [ { @@ -4566,11 +4877,11 @@ ], "cost": null, "gotchas": [ - "Preflight with otto.status — an empty nodes list means no Chrome extension node is paired/online and page commands will fail.", + "Preflight with otto.status \u2014 an empty nodes list means no Chrome extension node is paired/online and page commands will fail.", "Requires the host stack up: a running relay (otto start), Chrome with the Otto extension loaded + paired, and a logged-in controller.", - "otto.test payload is a JSON object STRING (use {} for none), e.g. \"{\\\"limit\\\":10}\" — not a bare object.", - "Page commands (extract, screenshot, test) are slow — each opens a real tab, acts, then closes it.", - "Free and open source (MIT) — no payment, no per-call limit." + "otto.test payload is a JSON object STRING (use {} for none), e.g. \"{\\\"limit\\\":10}\" \u2014 not a bare object.", + "Page commands (extract, screenshot, test) are slow \u2014 each opens a real tab, acts, then closes it.", + "Free and open source (MIT) \u2014 no payment, no per-call limit." ], "next": [ "io.pilot.otto otto.help '{}'" @@ -4580,9 +4891,9 @@ { "id": "io.pilot.smol", "name": "Smol Machines", - "tagline": "Fast, hardware-isolated microVMs — local and cloud", - "description": "Smol Machines — fast, hardware-isolated Linux microVMs for agents, now local AND cloud. Spin up sub-second, real-hypervisor-isolated Linux microVMs locally with the smolvm CLI, then push a VM to the smol cloud with a single method.\n\nLocal (free, offline): run untrusted or AI-generated code safely (networking off by default), a real Linux shell, ephemeral or persistent VMs, portable .smolmachine artifacts, GPU/Vulkan.\n\nCloud (per-user, metered): smol.push sends a local VM (or an OCI image) to the smol cloud; Pilot provisions your own cloud key automatically on install — no account, no API key. Your cloud machines are isolated per user and metered against your free credit. The master key never leaves Pilot's broker.", - "summary": "Smol Machines — fast, hardware-isolated Linux microVMs for agents, now local AND cloud. Spin up sub-second, real-hypervisor-isolated Linux microVMs locally with the smolvm CLI, then push a VM to the smol cloud with a single method. Local (free, offline): run untrusted or AI-generated code safely (networking off by default), a real Linux shell, ephemeral or persistent VMs, portable .smolmachine artifacts…", + "tagline": "Fast, hardware-isolated microVMs \u2014 local and cloud", + "description": "Smol Machines \u2014 fast, hardware-isolated Linux microVMs for agents, now local AND cloud. Spin up sub-second, real-hypervisor-isolated Linux microVMs locally with the smolvm CLI, then push a VM to the smol cloud with a single method.\n\nLocal (free, offline): run untrusted or AI-generated code safely (networking off by default), a real Linux shell, ephemeral or persistent VMs, portable .smolmachine artifacts, GPU/Vulkan.\n\nCloud (per-user, metered): smol.push sends a local VM (or an OCI image) to the smol cloud; Pilot provisions your own cloud key automatically on install \u2014 no account, no API key. Your cloud machines are isolated per user and metered against your free credit. The master key never leaves Pilot's broker.", + "summary": "Smol Machines \u2014 fast, hardware-isolated Linux microVMs for agents, now local AND cloud. Spin up sub-second, real-hypervisor-isolated Linux microVMs locally with the smolvm CLI, then push a VM to the smol cloud with a single method. Local (free, offline): run untrusted or AI-generated code safely (networking off by default), a real Linux shell, ephemeral or persistent VMs, portable .smolmachine artifacts\u2026", "categories": [ "infra" ], @@ -4605,7 +4916,7 @@ "methods": [ { "name": "smol.exec", - "summary": "Run ANY smolvm subcommand in a fast, hardware-isolated Linux microVM LOCALLY. Payload is {\"args\":[...]} (verbatim smolvm argv) with optional {\"stdin\":\"...\"}. This one method exposes the whole smolvm CLI — for the complete agent reference call smol.exec {\"args\":[\"--help\"]}, and for any subcommand call smol.exec {\"args\":[\"\",\"--help\"]}.\n\nCOMMAND SURFACE:\n• machine run — create an EPHEMERAL VM, run one command, tear down (nothing persists). e.g. [\"machine\",\"run\",\"--net\",\"--image\",\"alpine\",\"--\",\"sh\",\"-c\",\"echo hi\"].\n• machine create | start | stop | delete — lifecycle of a PERSISTENT named VM (--name, default \"default\").\n• machine exec — run a command in a persistent VM; FILESYSTEM CHANGES PERSIST across sessions (package installs stick). e.g. [\"machine\",\"exec\",\"--name\",\"myvm\",\"--\",\"apk\",\"add\",\"python3\"].\n• machine status | ls | images | monitor — read-only introspection (do NOT stop a running VM).\n• machine cp — copy files host↔VM (HOST:GUEST). machine update — change mounts/ports/env/cpu/memory on a STOPPED VM. machine prune — reclaim layers (prune --all needs the VM stopped).\n• pack create -o — build a portable, self-contained .smolmachine executable; pack run — run one. machine create --from .smolmachine for fast start.\n• serve start --listen — HTTP API server (POST/GET /api/v1/machines…); serve openapi — the spec.\n• config — manage registries + defaults.\n\nKEY FLAGS: --net (networking is OFF by default), --image , -v HOST:GUEST[:ro] (mount; -v host:/workspace replaces the default workspace), -p HOST:GUEST (port), --gpu, --ssh-agent (forward host SSH agent; keys never enter the VM), --secret-env GUEST=HOST / --secret-file GUEST=/abs / -s Smolfile (inject secrets by reference), --from , --cpus, --memory.\n\nDEFAULTS: network off; cpus 4; memory 8192 MiB; storage 20 GiB; name \"default\". Elastic memory/CPU via virtio balloon.\n\nNOT SUPPORTED OVER IPC: interactive sessions (-it / machine shell) and long-running serve (no attached TTY).", + "summary": "Run ANY smolvm subcommand in a fast, hardware-isolated Linux microVM LOCALLY. Payload is {\"args\":[...]} (verbatim smolvm argv) with optional {\"stdin\":\"...\"}. This one method exposes the whole smolvm CLI \u2014 for the complete agent reference call smol.exec {\"args\":[\"--help\"]}, and for any subcommand call smol.exec {\"args\":[\"\",\"--help\"]}.\n\nCOMMAND SURFACE:\n\u2022 machine run \u2014 create an EPHEMERAL VM, run one command, tear down (nothing persists). e.g. [\"machine\",\"run\",\"--net\",\"--image\",\"alpine\",\"--\",\"sh\",\"-c\",\"echo hi\"].\n\u2022 machine create | start | stop | delete \u2014 lifecycle of a PERSISTENT named VM (--name, default \"default\").\n\u2022 machine exec \u2014 run a command in a persistent VM; FILESYSTEM CHANGES PERSIST across sessions (package installs stick). e.g. [\"machine\",\"exec\",\"--name\",\"myvm\",\"--\",\"apk\",\"add\",\"python3\"].\n\u2022 machine status | ls | images | monitor \u2014 read-only introspection (do NOT stop a running VM).\n\u2022 machine cp \u2014 copy files host\u2194VM (HOST:GUEST). machine update \u2014 change mounts/ports/env/cpu/memory on a STOPPED VM. machine prune \u2014 reclaim layers (prune --all needs the VM stopped).\n\u2022 pack create -o \u2014 build a portable, self-contained .smolmachine executable; pack run \u2014 run one. machine create --from .smolmachine for fast start.\n\u2022 serve start --listen \u2014 HTTP API server (POST/GET /api/v1/machines\u2026); serve openapi \u2014 the spec.\n\u2022 config \u2014 manage registries + defaults.\n\nKEY FLAGS: --net (networking is OFF by default), --image , -v HOST:GUEST[:ro] (mount; -v host:/workspace replaces the default workspace), -p HOST:GUEST (port), --gpu, --ssh-agent (forward host SSH agent; keys never enter the VM), --secret-env GUEST=HOST / --secret-file GUEST=/abs / -s Smolfile (inject secrets by reference), --from , --cpus, --memory.\n\nDEFAULTS: network off; cpus 4; memory 8192 MiB; storage 20 GiB; name \"default\". Elastic memory/CPU via virtio balloon.\n\nNOT SUPPORTED OVER IPC: interactive sessions (-it / machine shell) and long-running serve (no attached TTY).", "example": "", "gated": "" }, @@ -4617,7 +4928,7 @@ }, { "name": "smol.provision", - "summary": "Provision (or fetch) this Pilot user's proprietary smol cloud key and free credit balance. Runs automatically on install and on smol.help — you rarely call it directly. The key is bound to your Pilot identity, stored only in your app's private secrets, and used to push and isolate your cloud VMs. Returns {key, credits}.", + "summary": "Provision (or fetch) this Pilot user's proprietary smol cloud key and free credit balance. Runs automatically on install and on smol.help \u2014 you rarely call it directly. The key is bound to your Pilot identity, stored only in your app's private secrets, and used to push and isolate your cloud VMs. Returns {key, credits}.", "example": "", "gated": "" }, @@ -4635,19 +4946,19 @@ }, { "name": "smol.list", - "summary": "List YOUR smol cloud machines (only yours — the broker filters by owner). Free (no credit). Returns an array of machines.", + "summary": "List YOUR smol cloud machines (only yours \u2014 the broker filters by owner). Free (no credit). Returns an array of machines.", "example": "", "gated": "" }, { "name": "smol.key", - "summary": "Get your current smol cloud key (the per-user credential bound to your Pilot identity). Idempotent — safe to call anytime. The key is also cached in your app's private secrets. Returns {key, credits}.", + "summary": "Get your current smol cloud key (the per-user credential bound to your Pilot identity). Idempotent \u2014 safe to call anytime. The key is also cached in your app's private secrets. Returns {key, credits}.", "example": "", "gated": "" }, { "name": "smol.rotate", - "summary": "Rotate your smol cloud key if it leaked. Your OLD key stops working immediately and a NEW key is issued — your credit and cloud machines are NOT affected (only the key changes). Returns {key, credits, rotated}.", + "summary": "Rotate your smol cloud key if it leaked. Your OLD key stops working immediately and a NEW key is issued \u2014 your credit and cloud machines are NOT affected (only the key changes). Returns {key, credits, rotated}.", "example": "", "gated": "" }, @@ -4723,7 +5034,7 @@ "product_demo": { "skill": "io.pilot.smol", "title": "Full usage demo", - "when_to_use": "When you need to run untrusted or AI-generated code in a throwaway, hardware-isolated Linux microVM — locally for free, or pushed to the cloud when it needs to keep running.", + "when_to_use": "When you need to run untrusted or AI-generated code in a throwaway, hardware-isolated Linux microVM \u2014 locally for free, or pushed to the cloud when it needs to keep running.", "metered": true, "quickstart": { "title": "", @@ -4736,7 +5047,7 @@ "examples": [ { "title": "Run code in an ephemeral local microVM (free)", - "goal": "Boot alpine, run one command, tear down — nothing persists", + "goal": "Boot alpine, run one command, tear down \u2014 nothing persists", "command": "pilotctl appstore call io.pilot.smol smol.exec '{\"args\":[\"machine\",\"run\",\"--image\",\"alpine\",\"--\",\"sh\",\"-c\",\"echo hi\"]}'", "expect": "{\"stdout\":\"hi\\n\",\"exit_code\":0}", "cost": "$0.00 (local)", @@ -4755,7 +5066,7 @@ "goal": "Runs as you, metered by real CPU/memory/disk usage", "command": "pilotctl appstore call io.pilot.smol smol.push '{\"image\":\"alpine:3.20\",\"net\":true}'", "expect": "{\"machine\":{\"id\":\"m_...\",\"status\":\"running\",\"name\":\"...\"}}", - "cost": "≈$0.01 for a 30s 1-vCPU run", + "cost": "\u2248$0.01 for a 30s 1-vCPU run", "note": "Compute is time-based: billed per second from the rate card until you stop it or credit runs out." }, { @@ -4775,12 +5086,12 @@ { "op": "smol.exec / smol.version / smol.help", "price": "$0.00", - "note": "local methods run on your machine — free" + "note": "local methods run on your machine \u2014 free" }, { "op": "smol.provision / key / rotate / balance / list", "price": "$0.00", - "note": "cloud account reads — free" + "note": "cloud account reads \u2014 free" }, { "op": "smol.push (CPU)", @@ -4803,16 +5114,16 @@ "note": "outbound network transfer" } ], - "worked_total": "Local runs are free; the one cloud push here is ≈$0.01 for a short 1-vCPU run — well under your $5.00. The broker stops your VMs when credit runs out.", + "worked_total": "Local runs are free; the one cloud push here is \u2248$0.01 for a short 1-vCPU run \u2014 well under your $5.00. The broker stops your VMs when credit runs out.", "check_balance": "pilotctl appstore call io.pilot.smol smol.balance '{}'" }, "gotchas": [ "Local methods (smol.exec/version/help) are always free; only cloud smol.push spends credit.", - "Networking is OFF by default — pass {\"net\":true} for outbound internet, locally and in the cloud.", + "Networking is OFF by default \u2014 pass {\"net\":true} for outbound internet, locally and in the cloud.", "smol.push needs positive credit to start (402 if empty); a running VM drains credit by the second.", - "When your credit runs out the broker STOPS your running cloud VMs — check smol.balance.", + "When your credit runs out the broker STOPS your running cloud VMs \u2014 check smol.balance.", "Interactive sessions (-it / machine shell) and long-running serve are NOT supported over IPC.", - "Cloud machines are isolated per user — smol.list shows only yours." + "Cloud machines are isolated per user \u2014 smol.list shows only yours." ], "next": [ "io.pilot.smol smol.help '{}'" @@ -4823,8 +5134,8 @@ "id": "io.pilot.miren", "name": "Miren", "tagline": "Operate the Miren PaaS from an agent: deploy apps, run the server, and debug them", - "description": "Miren is a deployment platform for small teams. This app is the app-store front door for the `miren` CLI, letting an agent drive a Miren PaaS over IPC.\n\nWhat an agent gets:\n- **Deploy lifecycle** — `miren.deploy` (non-interactive build + deploy), `miren.deploy.analyze` (detect the stack/services without building), and `miren.rollback`.\n- **Inspect apps** — `miren.apps`, `miren.app` (status), `miren.app.history`, and `miren.logs` (JSON).\n- **Server & diagnostics** — `miren.server.install`/`miren.server.status`, `miren.doctor`, `miren.whoami`, and `miren.debug.connection`/`miren.debug.advertise`.\n- **Full CLI surface** — `miren.exec` runs any verbatim `miren` argv (addon, auth, env, route, cluster, disk, sandbox, and more).\n\nGood to know:\n- Structured JSON is returned wherever the CLI offers it (e.g. pass `--json`).\n- Discover the live surface at runtime with `miren.help` — every method, its parameters, and its latency class (fast / med / slow).\n- Server-side commands need a configured cluster; without one, calls return a structured error (`{stdout,stderr,exit}`) telling the agent what to do next.\n- Runs on macOS and Linux (arm64 + amd64); the miren CLI is staged and sha-pinned on install.", - "summary": "Miren is a deployment platform for small teams. This app is the app-store front door for the miren CLI, letting an agent drive a Miren PaaS over IPC. What an agent gets: - Deploy lifecycle — miren.deploy (non-interactive build + deploy), miren.deploy.analyze (detect the stack/services without building), and miren.rollback. - Inspect apps — miren.apps, miren.app (status), miren.app.history, and miren.logs (JSON).…", + "description": "Miren is a deployment platform for small teams. This app is the app-store front door for the `miren` CLI, letting an agent drive a Miren PaaS over IPC.\n\nWhat an agent gets:\n- **Deploy lifecycle** \u2014 `miren.deploy` (non-interactive build + deploy), `miren.deploy.analyze` (detect the stack/services without building), and `miren.rollback`.\n- **Inspect apps** \u2014 `miren.apps`, `miren.app` (status), `miren.app.history`, and `miren.logs` (JSON).\n- **Server & diagnostics** \u2014 `miren.server.install`/`miren.server.status`, `miren.doctor`, `miren.whoami`, and `miren.debug.connection`/`miren.debug.advertise`.\n- **Full CLI surface** \u2014 `miren.exec` runs any verbatim `miren` argv (addon, auth, env, route, cluster, disk, sandbox, and more).\n\nGood to know:\n- Structured JSON is returned wherever the CLI offers it (e.g. pass `--json`).\n- Discover the live surface at runtime with `miren.help` \u2014 every method, its parameters, and its latency class (fast / med / slow).\n- Server-side commands need a configured cluster; without one, calls return a structured error (`{stdout,stderr,exit}`) telling the agent what to do next.\n- Runs on macOS and Linux (arm64 + amd64); the miren CLI is staged and sha-pinned on install.", + "summary": "Miren is a deployment platform for small teams. This app is the app-store front door for the miren CLI, letting an agent drive a Miren PaaS over IPC. What an agent gets: - Deploy lifecycle \u2014 miren.deploy (non-interactive build + deploy), miren.deploy.analyze (detect the stack/services without building), and miren.rollback. - Inspect apps \u2014 miren.apps, miren.app (status), miren.app.history, and miren.logs (JSON).\u2026", "categories": [ "infra" ], @@ -4850,7 +5161,7 @@ "methods": [ { "name": "miren.exec", - "summary": "Run any miren subcommand. Payload is {\"args\":[...]} — the verbatim miren argv. Use this for the full CLI surface beyond the curated methods below (addon, auth, env, route, cluster, disk, sandbox, etc.). Run `miren help` or `miren --help` for the surface. Example args: [\"app\",\"list\",\"--json\"]. Note: interactive subcommands (e.g. `app run`, `login`) and long-running ones (e.g. `server start`) are not suitable over IPC.", + "summary": "Run any miren subcommand. Payload is {\"args\":[...]} \u2014 the verbatim miren argv. Use this for the full CLI surface beyond the curated methods below (addon, auth, env, route, cluster, disk, sandbox, etc.). Run `miren help` or `miren --help` for the surface. Example args: [\"app\",\"list\",\"--json\"]. Note: interactive subcommands (e.g. `app run`, `login`) and long-running ones (e.g. `server start`) are not suitable over IPC.", "example": "", "gated": "" }, @@ -4944,7 +5255,7 @@ "version": "0.1.0", "date": "", "notes": [ - "Operate the Miren PaaS from an agent: deploy and roll back apps; inspect status, logs, and history; run the server; and diagnose connectivity — plus a passthrough exec for any miren subcommand." + "Operate the Miren PaaS from an agent: deploy and roll back apps; inspect status, logs, and history; run the server; and diagnose connectivity \u2014 plus a passthrough exec for any miren subcommand." ] } ], @@ -4993,7 +5304,7 @@ "product_demo": { "skill": "io.pilot.miren", "title": "Full usage demo", - "when_to_use": "When you need to operate a Miren PaaS from an agent — deploy or roll back apps and inspect their status, history, and logs — over IPC.", + "when_to_use": "When you need to operate a Miren PaaS from an agent \u2014 deploy or roll back apps and inspect their status, history, and logs \u2014 over IPC.", "metered": false, "quickstart": { "title": "", @@ -5047,9 +5358,9 @@ ], "cost": null, "gotchas": [ - "Server-side commands need a configured cluster; without one they return a structured {stdout,stderr,exit} error explaining the next step — not a crash.", + "Server-side commands need a configured cluster; without one they return a structured {stdout,stderr,exit} error explaining the next step \u2014 not a crash.", "miren.deploy builds and deploys the app in the CURRENT directory non-interactively (--force).", - "Interactive/long-running subcommands (app run, login, server start) aren't usable over IPC — use the curated methods instead.", + "Interactive/long-running subcommands (app run, login, server start) aren't usable over IPC \u2014 use the curated methods instead.", "Pass --json inside miren.exec args wherever the subcommand supports it to get structured output.", "server install / server status are Linux-only." ], @@ -5061,9 +5372,9 @@ { "id": "io.pilot.docker", "name": "Docker", - "tagline": "Run Docker from an agent — a local Docker Engine + CLI on Linux, real containers", - "description": "# Docker (Engine + CLI) — native CLI for agents (Linux)\n\nThis app installs the official **Docker 29.6.1** static distribution on a Linux host and fronts it as typed\nmethods. The bundle carries the full **Docker Engine** — `dockerd`, `containerd`, `runc`, `containerd-shim-runc-v2`,\n`docker-proxy`, `docker-init`, `ctr` — plus the `docker` CLI, each sha-pinned and staged at install. A small\n`dockerctl` wrapper manages the engine lifecycle and fronts the CLI.\n\n## Linux only\n\nDocker containers require Linux kernel features (namespaces, cgroups, overlayfs) — there is **no native macOS\n`dockerd`** (Docker Desktop runs the engine inside a hidden Linux VM). This app therefore targets **Linux (amd64 +\narm64)**. `docker.engine_start` runs a real daemon and requires **root** (the pilot host must run as root, e.g. in a\ncontainer or VM). To use Docker against an existing daemon instead, set `DOCKER_HOST` and skip `engine_start`.\n\n## The usual flow\n\n1. **Start the engine:** `docker.engine_start` `{}` — boots `dockerd` on a private socket under `DOCKER_DIR`\n (default `/tmp/pilot-docker`), waits until the API is ready.\n2. **Pull + run:** `docker.pull` `{ \"image\": \"hello-world\" }`, then `docker.run` `{ \"image\": \"hello-world\" }`.\n3. **Inspect:** `docker.ps`, `docker.images`, `docker.logs`, `docker.info`.\n4. **Anything else:** `docker.exec` `{ \"args\": [\"run\",\"-d\",\"-p\",\"8080:80\",\"nginx\"] }` — any docker command with any flags.\n5. **Stop:** `docker.engine_stop`.\n\n## Methods\n\n- `docker.engine_start` / `docker.engine_stop` — local Docker Engine lifecycle (root).\n- `docker.version`, `docker.info` — client/server versions and system info.\n- `docker.ps`, `docker.images`, `docker.logs` — inspect containers/images/logs.\n- `docker.pull` / `docker.run` — pull an image / run a container (`--rm`).\n- `docker.exec` — the docker CLI with a verbatim argv (+ optional stdin): run with any flags, `build`, `exec`,\n networks, volumes, compose plugins, etc.\n- `docker.cli_help` — the full `docker --help`. `docker.help` — the self-describing method list.\n\n## Configuration\n\n- **`DOCKER_DIR`** (env) — where dockerd keeps its socket, data-root, exec-root, pidfile, and log\n (default `/tmp/pilot-docker`).\n- **`DOCKER_HOST`** (env) — point the CLI at an existing/remote daemon instead of the bundled one\n (`tcp://host:2375` or `unix:///path`); when set, skip `docker.engine_start`.\n- **Root** — `dockerd` needs root and kernel container support. Works on a Linux host/VM/privileged container where\n the pilot daemon runs as root; not on a restricted, capability-stripped sandbox.\n- **Storage driver** — defaults to `overlay2`; pass an alternative via `docker.exec`\n (`{\"args\":[\"engine-start\",\"--storage-driver\",\"vfs\"]}`) on filesystems where overlay2 is unavailable.\n\n## Good to know\n\n- Free and open source (Apache-2.0). Binaries are the official Docker static release, repackaged unmodified.\n- Output returns verbatim; on a non-zero exit the reply is `{stdout, stderr, exit}`.\n\n## docker --help\n```\nDocker CLI — commands and options\n=================================\n\nDocker runs applications in containers. This app delivers the Docker Engine\n(dockerd + containerd + runc) and the docker CLI. Start a local engine with\n'engine-start', then use any docker command.\n\nUsage: docker [OPTIONS] COMMAND\n\nA self-sufficient runtime for containers\n\nCommon Commands:\n run Create and run a new container from an image\n exec Execute a command in a running container\n ps List containers\n build Build an image from a Dockerfile\n pull Download an image from a registry\n push Upload an image to a registry\n images List images\n login Authenticate to a registry\n logout Log out from a registry\n search Search Docker Hub for images\n version Show the Docker version information\n info Display system-wide information\n\nManagement Commands:\n builder Manage builds\n compose* Docker Compose\n container Manage containers\n context Manage contexts\n image Manage images\n manifest Manage Docker image manifests and manifest lists\n network Manage networks\n plugin Manage plugins\n system Manage Docker\n volume Manage volumes\n\nSwarm Commands:\n swarm Manage Swarm\n\nCommands:\n attach Attach local standard input, output, and error streams to a running container\n commit Create a new image from a container's changes\n cp Copy files/folders between a container and the local filesystem\n create Create a new container\n diff Inspect changes to files or directories on a container's filesystem\n events Get real time events from the server\n export Export a container's filesystem as a tar archive\n history Show the history of an image\n import Import the contents from a tarball to create a filesystem image\n inspect Return low-level information on Docker objects\n kill Kill one or more running containers\n load Load an image from a tar archive or STDIN\n logs Fetch the logs of a container\n pause Pause all processes within one or more containers\n port List port mappings or a specific mapping for the container\n rename Rename a container\n restart Restart one or more containers\n rm Remove one or more containers\n rmi Remove one or more images\n save Save one or more images to a tar archive (streamed to STDOUT by default)\n start Start one or more stopped containers\n stats Display a live stream of container(s) resource usage statistics\n stop Stop one or more running containers\n tag Create a tag TARGET_IMAGE that refers to SOURCE_IMAGE\n top Display the running processes of a container\n unpause Unpause all processes within one or more containers\n update Update configuration of one or more containers\n wait Block until one or more containers stop, then print their exit codes\n\nGlobal Options:\n --config string Location of client config files (default\n \"/Users/alexgodo/.docker\")\n -c, --context string Name of the context to use to connect to the\n daemon (overrides DOCKER_HOST env var and\n default context set with \"docker context use\")\n -D, --debug Enable debug mode\n -H, --host string Daemon socket to connect to\n -l, --log-level string Set the logging level (\"debug\", \"info\",\n \"warn\", \"error\", \"fatal\") (default \"info\")\n --tls Use TLS; implied by --tlsverify\n --tlscacert string Trust certs signed only by this CA (default\n \"/Users/alexgodo/.docker/ca.pem\")\n --tlscert string Path to TLS certificate file (default\n \"/Users/alexgodo/.docker/cert.pem\")\n --tlskey string Path to TLS key file (default\n \"/Users/alexgodo/.docker/key.pem\")\n --tlsverify Use TLS and verify the remote\n -v, --version Print version information and quit\n\nRun 'docker COMMAND --help' for more information on a command.\n\nFor more help on how to use Docker, head to https://docs.docker.com/go/guides/\n```\n", - "summary": "This app installs the official Docker 29.6.1 static distribution on a Linux host and fronts it as typed methods. The bundle carries the full Docker Engine — dockerd, containerd, runc, containerd-shim-runc-v2, docker-proxy, docker-init, ctr — plus the docker CLI, each sha-pinned and staged at install. A small dockerctl wrapper manages the engine lifecycle and fronts the CLI. Linux only Docker containers require…", + "tagline": "Run Docker from an agent \u2014 a local Docker Engine + CLI on Linux, real containers", + "description": "# Docker (Engine + CLI) \u2014 native CLI for agents (Linux)\n\nThis app installs the official **Docker 29.6.1** static distribution on a Linux host and fronts it as typed\nmethods. The bundle carries the full **Docker Engine** \u2014 `dockerd`, `containerd`, `runc`, `containerd-shim-runc-v2`,\n`docker-proxy`, `docker-init`, `ctr` \u2014 plus the `docker` CLI, each sha-pinned and staged at install. A small\n`dockerctl` wrapper manages the engine lifecycle and fronts the CLI.\n\n## Linux only\n\nDocker containers require Linux kernel features (namespaces, cgroups, overlayfs) \u2014 there is **no native macOS\n`dockerd`** (Docker Desktop runs the engine inside a hidden Linux VM). This app therefore targets **Linux (amd64 +\narm64)**. `docker.engine_start` runs a real daemon and requires **root** (the pilot host must run as root, e.g. in a\ncontainer or VM). To use Docker against an existing daemon instead, set `DOCKER_HOST` and skip `engine_start`.\n\n## The usual flow\n\n1. **Start the engine:** `docker.engine_start` `{}` \u2014 boots `dockerd` on a private socket under `DOCKER_DIR`\n (default `/tmp/pilot-docker`), waits until the API is ready.\n2. **Pull + run:** `docker.pull` `{ \"image\": \"hello-world\" }`, then `docker.run` `{ \"image\": \"hello-world\" }`.\n3. **Inspect:** `docker.ps`, `docker.images`, `docker.logs`, `docker.info`.\n4. **Anything else:** `docker.exec` `{ \"args\": [\"run\",\"-d\",\"-p\",\"8080:80\",\"nginx\"] }` \u2014 any docker command with any flags.\n5. **Stop:** `docker.engine_stop`.\n\n## Methods\n\n- `docker.engine_start` / `docker.engine_stop` \u2014 local Docker Engine lifecycle (root).\n- `docker.version`, `docker.info` \u2014 client/server versions and system info.\n- `docker.ps`, `docker.images`, `docker.logs` \u2014 inspect containers/images/logs.\n- `docker.pull` / `docker.run` \u2014 pull an image / run a container (`--rm`).\n- `docker.exec` \u2014 the docker CLI with a verbatim argv (+ optional stdin): run with any flags, `build`, `exec`,\n networks, volumes, compose plugins, etc.\n- `docker.cli_help` \u2014 the full `docker --help`. `docker.help` \u2014 the self-describing method list.\n\n## Configuration\n\n- **`DOCKER_DIR`** (env) \u2014 where dockerd keeps its socket, data-root, exec-root, pidfile, and log\n (default `/tmp/pilot-docker`).\n- **`DOCKER_HOST`** (env) \u2014 point the CLI at an existing/remote daemon instead of the bundled one\n (`tcp://host:2375` or `unix:///path`); when set, skip `docker.engine_start`.\n- **Root** \u2014 `dockerd` needs root and kernel container support. Works on a Linux host/VM/privileged container where\n the pilot daemon runs as root; not on a restricted, capability-stripped sandbox.\n- **Storage driver** \u2014 defaults to `overlay2`; pass an alternative via `docker.exec`\n (`{\"args\":[\"engine-start\",\"--storage-driver\",\"vfs\"]}`) on filesystems where overlay2 is unavailable.\n\n## Good to know\n\n- Free and open source (Apache-2.0). Binaries are the official Docker static release, repackaged unmodified.\n- Output returns verbatim; on a non-zero exit the reply is `{stdout, stderr, exit}`.\n\n## docker --help\n```\nDocker CLI \u2014 commands and options\n=================================\n\nDocker runs applications in containers. This app delivers the Docker Engine\n(dockerd + containerd + runc) and the docker CLI. Start a local engine with\n'engine-start', then use any docker command.\n\nUsage: docker [OPTIONS] COMMAND\n\nA self-sufficient runtime for containers\n\nCommon Commands:\n run Create and run a new container from an image\n exec Execute a command in a running container\n ps List containers\n build Build an image from a Dockerfile\n pull Download an image from a registry\n push Upload an image to a registry\n images List images\n login Authenticate to a registry\n logout Log out from a registry\n search Search Docker Hub for images\n version Show the Docker version information\n info Display system-wide information\n\nManagement Commands:\n builder Manage builds\n compose* Docker Compose\n container Manage containers\n context Manage contexts\n image Manage images\n manifest Manage Docker image manifests and manifest lists\n network Manage networks\n plugin Manage plugins\n system Manage Docker\n volume Manage volumes\n\nSwarm Commands:\n swarm Manage Swarm\n\nCommands:\n attach Attach local standard input, output, and error streams to a running container\n commit Create a new image from a container's changes\n cp Copy files/folders between a container and the local filesystem\n create Create a new container\n diff Inspect changes to files or directories on a container's filesystem\n events Get real time events from the server\n export Export a container's filesystem as a tar archive\n history Show the history of an image\n import Import the contents from a tarball to create a filesystem image\n inspect Return low-level information on Docker objects\n kill Kill one or more running containers\n load Load an image from a tar archive or STDIN\n logs Fetch the logs of a container\n pause Pause all processes within one or more containers\n port List port mappings or a specific mapping for the container\n rename Rename a container\n restart Restart one or more containers\n rm Remove one or more containers\n rmi Remove one or more images\n save Save one or more images to a tar archive (streamed to STDOUT by default)\n start Start one or more stopped containers\n stats Display a live stream of container(s) resource usage statistics\n stop Stop one or more running containers\n tag Create a tag TARGET_IMAGE that refers to SOURCE_IMAGE\n top Display the running processes of a container\n unpause Unpause all processes within one or more containers\n update Update configuration of one or more containers\n wait Block until one or more containers stop, then print their exit codes\n\nGlobal Options:\n --config string Location of client config files (default\n \"/Users/alexgodo/.docker\")\n -c, --context string Name of the context to use to connect to the\n daemon (overrides DOCKER_HOST env var and\n default context set with \"docker context use\")\n -D, --debug Enable debug mode\n -H, --host string Daemon socket to connect to\n -l, --log-level string Set the logging level (\"debug\", \"info\",\n \"warn\", \"error\", \"fatal\") (default \"info\")\n --tls Use TLS; implied by --tlsverify\n --tlscacert string Trust certs signed only by this CA (default\n \"/Users/alexgodo/.docker/ca.pem\")\n --tlscert string Path to TLS certificate file (default\n \"/Users/alexgodo/.docker/cert.pem\")\n --tlskey string Path to TLS key file (default\n \"/Users/alexgodo/.docker/key.pem\")\n --tlsverify Use TLS and verify the remote\n -v, --version Print version information and quit\n\nRun 'docker COMMAND --help' for more information on a command.\n\nFor more help on how to use Docker, head to https://docs.docker.com/go/guides/\n```\n", + "summary": "This app installs the official Docker 29.6.1 static distribution on a Linux host and fronts it as typed methods. The bundle carries the full Docker Engine \u2014 dockerd, containerd, runc, containerd-shim-runc-v2, docker-proxy, docker-init, ctr \u2014 plus the docker CLI, each sha-pinned and staged at install. A small dockerctl wrapper manages the engine lifecycle and fronts the CLI. Linux only Docker containers require\u2026", "categories": [ "infra" ], @@ -5143,7 +5454,7 @@ }, { "name": "docker.exec", - "summary": "Run the docker CLI with a verbatim argv — the full surface beyond the curated methods. Payload is {\"args\":[...]} passed straight to `docker` (+ optional {\"stdin\":\"...\"}). This is how you run a container with any flags, build an image, exec into a container, manage networks/volumes/compose, etc. Examples: {\"args\":[\"run\",\"-d\",\"--name\",\"web\",\"-p\",\"8080:80\",\"nginx\"]}; {\"args\":[\"run\",\"--rm\",\"alpine\",\"sh\",\"-c\",\"echo hi\"]}; {\"args\":[\"build\",\"-t\",\"myapp\",\"/work\"]}; {\"args\":[\"exec\",\"web\",\"nginx\",\"-v\"]}. The wrapper's own verbs `engine-start`/`engine-stop` also work here.", + "summary": "Run the docker CLI with a verbatim argv \u2014 the full surface beyond the curated methods. Payload is {\"args\":[...]} passed straight to `docker` (+ optional {\"stdin\":\"...\"}). This is how you run a container with any flags, build an image, exec into a container, manage networks/volumes/compose, etc. Examples: {\"args\":[\"run\",\"-d\",\"--name\",\"web\",\"-p\",\"8080:80\",\"nginx\"]}; {\"args\":[\"run\",\"--rm\",\"alpine\",\"sh\",\"-c\",\"echo hi\"]}; {\"args\":[\"build\",\"-t\",\"myapp\",\"/work\"]}; {\"args\":[\"exec\",\"web\",\"nginx\",\"-v\"]}. The wrapper's own verbs `engine-start`/`engine-stop` also work here.", "example": "", "gated": "" }, @@ -5209,7 +5520,7 @@ "product_demo": { "skill": "io.pilot.docker", "title": "Full usage demo", - "when_to_use": "When you need to run real OCI containers on a Linux host — pull images and run/build/exec containers via a local Docker Engine — without Docker Desktop.", + "when_to_use": "When you need to run real OCI containers on a Linux host \u2014 pull images and run/build/exec containers via a local Docker Engine \u2014 without Docker Desktop.", "metered": false, "quickstart": { "title": "", @@ -5264,7 +5575,7 @@ "cost": null, "gotchas": [ "LINUX-ONLY: there is no native macOS dockerd (Docker Desktop hides a Linux VM), so this app cannot start an engine on macOS.", - "docker.engine_start needs root — dockerd manages namespaces/cgroups; run on a Linux host/VM/privileged container.", + "docker.engine_start needs root \u2014 dockerd manages namespaces/cgroups; run on a Linux host/VM/privileged container.", "Call docker.engine_start once before other methods, or set DOCKER_HOST to target an existing daemon and skip it.", "docker.run uses --rm and the image's default command; for flags, ports, detached, or build/exec use docker.exec.", "On a non-zero exit the reply is {stdout, stderr, exit}." @@ -5277,9 +5588,9 @@ { "id": "io.pilot.aegis", "name": "AEGIS", - "tagline": "Runtime firewall for AI agents — blocks prompt injection before your agent reads it", - "description": "AEGIS is a runtime firewall for AI agents. It inspects untrusted content reaching your agent — inbox messages, tool results, web fetches, MCP responses, skill files — and blocks prompt injection, jailbreaks, and impersonation before the agent ever sees it. Genuine status messages pass straight through.\n\nTwo layers: L1 Aho-Corasick pattern matching (pure Rust, microseconds, ~120 known attack families with homoglyph and leetspeak normalization) and L2 a local Qwen3-1.7B judge via llama.cpp — fully offline, no network. On a held-out labeled set it scores 90% recall, 95% precision, 92% F1. An 880 KB binary with an HMAC-chained audit log.", - "summary": "AEGIS is a runtime firewall for AI agents. It inspects untrusted content reaching your agent — inbox messages, tool results, web fetches, MCP responses, skill files — and blocks prompt injection, jailbreaks, and impersonation before the agent ever sees it. Genuine status messages pass straight through. Two layers: L1 Aho-Corasick pattern matching (pure Rust, microseconds, ~120 known attack families with homoglyph…", + "tagline": "Runtime firewall for AI agents \u2014 blocks prompt injection before your agent reads it", + "description": "AEGIS is a runtime firewall for AI agents. It inspects untrusted content reaching your agent \u2014 inbox messages, tool results, web fetches, MCP responses, skill files \u2014 and blocks prompt injection, jailbreaks, and impersonation before the agent ever sees it. Genuine status messages pass straight through.\n\nTwo layers: L1 Aho-Corasick pattern matching (pure Rust, microseconds, ~120 known attack families with homoglyph and leetspeak normalization) and L2 a local Qwen3-1.7B judge via llama.cpp \u2014 fully offline, no network. On a held-out labeled set it scores 90% recall, 95% precision, 92% F1. An 880 KB binary with an HMAC-chained audit log.", + "summary": "AEGIS is a runtime firewall for AI agents. It inspects untrusted content reaching your agent \u2014 inbox messages, tool results, web fetches, MCP responses, skill files \u2014 and blocks prompt injection, jailbreaks, and impersonation before the agent ever sees it. Genuine status messages pass straight through. Two layers: L1 Aho-Corasick pattern matching (pure Rust, microseconds, ~120 known attack families with homoglyph\u2026", "categories": [ "security" ], @@ -5332,7 +5643,7 @@ }, { "name": "aegis.exec", - "summary": "Run any AEGIS subcommand verbatim — including the scan-cmd / scan-result blocking gates (allow 0 / block 2) via stdin.", + "summary": "Run any AEGIS subcommand verbatim \u2014 including the scan-cmd / scan-result blocking gates (allow 0 / block 2) via stdin.", "example": "", "gated": "" }, @@ -5349,7 +5660,7 @@ "date": "", "notes": [ "Runtime firewall: L1 Aho-Corasick patterns + L2 local Qwen3-1.7B judge", - "Fully offline — no network", + "Fully offline \u2014 no network", "HMAC-chained audit log; 90% recall / 95% precision on the held-out set" ] } @@ -5399,7 +5710,7 @@ "product_demo": { "skill": "io.pilot.aegis", "title": "Full usage demo", - "when_to_use": "When your agent is about to act on untrusted content — inbox messages, tool results, web fetches, skill/memory files — scan it for prompt injection or jailbreaks first and read the verdict before proceeding.", + "when_to_use": "When your agent is about to act on untrusted content \u2014 inbox messages, tool results, web fetches, skill/memory files \u2014 scan it for prompt injection or jailbreaks first and read the verdict before proceeding.", "metered": false, "quickstart": { "title": "", @@ -5446,9 +5757,9 @@ "cost": null, "gotchas": [ "Fully offline: L1 Aho-Corasick patterns need no network; the L2 judge model (~1.8 GB) is optional.", - "aegis.scan takes a filesystem path, not raw text — write the content to a file first, then scan it.", + "aegis.scan takes a filesystem path, not raw text \u2014 write the content to a file first, then scan it.", "scan-cmd (via aegis.exec) is the blocking gate: exit 0 = allow, 2 = block; scan-result warns without blocking.", - "Verdicts append to an HMAC-chained audit log at ~/.aegis/audit.jsonl — read it with aegis.status." + "Verdicts append to an HMAC-chained audit log at ~/.aegis/audit.jsonl \u2014 read it with aegis.status." ], "next": [ "io.pilot.aegis aegis.help '{}'" @@ -5459,8 +5770,8 @@ "id": "io.pilot.slipstream", "name": "Slipstream", "tagline": "Polymarket smart-money leaderboard, signals, and tape", - "description": "# Slipstream — market intelligence for agents\n\nSlipstream gives an agent a focused, read-oriented view of Polymarket activity through nine discoverable Pilot methods. It brings leaderboards, market signals, transaction tape, market records, wallet context, skilled participants, opportunities, service statistics, and method help into the same request-and-response interface used by other Pilot apps.\n\n## What an agent can inspect\n\n- `slipstream.leaderboard` surfaces ranked market participants.\n- `slipstream.signals` and `slipstream.opportunities` expose the service's derived market-intelligence views.\n- `slipstream.tape` provides the activity stream, while `slipstream.markets` provides market context.\n- `slipstream.wallet` and `slipstream.skilled` support participant-level research.\n- `slipstream.stats` describes service-level statistics, and `slipstream.help` is the runtime discovery entry point.\n\nThe API responses are Ed25519-signed so a caller can verify their origin before using the result downstream. As published in the current catalog, Slipstream exposes research and monitoring methods; it does **not** list an order-placement or trade-execution method. That boundary matters for operators: an agent can use the app as one input to an analysis workflow, but execution policy, spending authority, human approval, and independent verification remain outside this app.\n\nFor production use, inspect `slipstream.help` at runtime before relying on a field or parameter, retain the signed response with the surrounding decision record, and treat market signals as time-sensitive evidence rather than guaranteed outcomes.", - "summary": "Slipstream gives an agent a focused, read-oriented view of Polymarket activity through nine discoverable Pilot methods. It brings leaderboards, market signals, transaction tape, market records, wallet context, skilled participants, opportunities, service statistics, and method help into the same request-and-response interface used by other Pilot apps. What an agent can inspect - slipstream.leaderboard surfaces…", + "description": "# Slipstream \u2014 market intelligence for agents\n\nSlipstream gives an agent a focused, read-oriented view of Polymarket activity through nine discoverable Pilot methods. It brings leaderboards, market signals, transaction tape, market records, wallet context, skilled participants, opportunities, service statistics, and method help into the same request-and-response interface used by other Pilot apps.\n\n## What an agent can inspect\n\n- `slipstream.leaderboard` surfaces ranked market participants.\n- `slipstream.signals` and `slipstream.opportunities` expose the service's derived market-intelligence views.\n- `slipstream.tape` provides the activity stream, while `slipstream.markets` provides market context.\n- `slipstream.wallet` and `slipstream.skilled` support participant-level research.\n- `slipstream.stats` describes service-level statistics, and `slipstream.help` is the runtime discovery entry point.\n\nThe API responses are Ed25519-signed so a caller can verify their origin before using the result downstream. As published in the current catalog, Slipstream exposes research and monitoring methods; it does **not** list an order-placement or trade-execution method. That boundary matters for operators: an agent can use the app as one input to an analysis workflow, but execution policy, spending authority, human approval, and independent verification remain outside this app.\n\nFor production use, inspect `slipstream.help` at runtime before relying on a field or parameter, retain the signed response with the surrounding decision record, and treat market signals as time-sensitive evidence rather than guaranteed outcomes.", + "summary": "Slipstream gives an agent a focused, read-oriented view of Polymarket activity through nine discoverable Pilot methods. It brings leaderboards, market signals, transaction tape, market records, wallet context, skilled participants, opportunities, service statistics, and method help into the same request-and-response interface used by other Pilot apps. What an agent can inspect - slipstream.leaderboard surfaces\u2026", "categories": [ "finance" ], @@ -5585,8 +5896,8 @@ "id": "io.pilot.wallet", "name": "Wallet", "tagline": "On-overlay USDC payments across Base, Ethereum, and Polygon", - "description": "The Pilot reference wallet brings x402 + EIP-3009 USDC payments to the overlay, with spend caps the supervisor enforces. One secp256k1 address works across all three USDC mainnets (Base, Ethereum, Polygon); per-chain RPC is configurable via PILOT_EVM_RPC_.\n\nInstalling this app lets other apps and agents settle payments without leaving the network. Spend caps declared in the manifest are reviewed at install time and enforced on every signing operation — see `pilotctl appstore caps io.pilot.wallet`.", - "summary": "The Pilot reference wallet brings x402 + EIP-3009 USDC payments to the overlay, with spend caps the supervisor enforces. One secp256k1 address works across all three USDC mainnets (Base, Ethereum, Polygon); per-chain RPC is configurable via PILOT_EVM_RPC_. Installing this app lets other apps and agents settle payments without leaving the network. Spend caps declared in the manifest are reviewed at install…", + "description": "The Pilot reference wallet brings x402 + EIP-3009 USDC payments to the overlay, with spend caps the supervisor enforces. One secp256k1 address works across all three USDC mainnets (Base, Ethereum, Polygon); per-chain RPC is configurable via PILOT_EVM_RPC_.\n\nInstalling this app lets other apps and agents settle payments without leaving the network. Spend caps declared in the manifest are reviewed at install time and enforced on every signing operation \u2014 see `pilotctl appstore caps io.pilot.wallet`.", + "summary": "The Pilot reference wallet brings x402 + EIP-3009 USDC payments to the overlay, with spend caps the supervisor enforces. One secp256k1 address works across all three USDC mainnets (Base, Ethereum, Polygon); per-chain RPC is configurable via PILOT_EVM_RPC_. Installing this app lets other apps and agents settle payments without leaving the network. Spend caps declared in the manifest are reviewed at install\u2026", "categories": [ "finance" ], @@ -5770,7 +6081,7 @@ "name": "Bowmark", "tagline": "Live data from real websites: prices, stock, fares and quotes, including what only appears after you operate the page", "description": "Bowmark gives agents a **typed function library for the live web**, and runs the script they write against it on the real sites. `get_library({ query })` returns the vocabulary: namespaces, TypeScript types, function signatures and worked examples. `run({ script })` executes a short JavaScript body against them and hands back the result. Ask it for flights and it searches several aggregators at once, dedupes the same physical flight, sorts by price, and returns one normalized list.\n\n**The data it reaches is the kind an index cannot hold.** A fare that only exists after the site's own live poll completes. A price that appears once dates are entered. Stock for one postcode. A quote behind a form. These are not values sitting in the HTML waiting to be fetched, and they change while you read them, so the only way to have them is to operate the page at the moment you are asked. Bowmark does that and hands back structured JSON. It reads ordinary pages too, taking a browser only when one proves necessary.\n\nIt's plain request/response REST: no websockets, no async jobs, and no browser on your side. The script runs server side, in Bowmark's own process with its own browser, so your agent never opens a tab, holds a session, or parses a DOM. A capability like `bowmark.flights.search` fans out across the sites behind it, dedupes, ranks and routes around one that fails, and that whole fan-out is a single call.\n\n**Methods.** `bowmark.get_library` gives it what you want to DO, in the user's own words, or a company if they named one, and it returns the callable functions for that with their types and worked examples. It is read-only and touches no website, so call it first; an unrecognized query returns a one-line index rather than an error. `bowmark.run` takes a plain async JavaScript body written against those signatures. `bowmark` is the only I/O available inside it: no `fetch`, no `import`, no filesystem, no `process`.\n\n**What it covers today.** Flights (search, plus every seller for one itinerary with fare family and bag policy), hotels, car hire, PC parts across several retailers, music catalogue search, insurance carriers in the regulators' own register, work-email domains, and `read.page` / `read.pages` for any page as markdown, text or HTML. Individual sites are callable directly at `bowmark.providers.*` when you want one specific site rather than the fan-out.\n\n**Syntax & edge cases.** Check `status` before `ok`. `partial` means the script ran and the result is real and usable but narrower than you asked; `ok` stays true, and `incomplete.summary` names what never answered. `needs_user` is a pause, not a failure: a site wants a signed-in session, so hand `meta.handoff.url` to the user, wait, then re-send the identical script. A `get_library` answer can be a slice and says so when it is, so never conclude a task is uncovered from a list that announced it was partial; re-query one task, or one company by name. Prefer a capability over `bowmark.providers.*` unless you want one specific site. Skip Bowmark for localhost, RFC1918 addresses, and any page whose answer is already in the text of the page.", - "summary": "Bowmark gives agents a typed function library for the live web, and runs the script they write against it on the real sites. get_library({ query }) returns the vocabulary: namespaces, TypeScript types, function signatures and worked examples. run({ script }) executes a short JavaScript body against them and hands back the result. Ask it for flights and it searches several aggregators at once, dedupes the same…", + "summary": "Bowmark gives agents a typed function library for the live web, and runs the script they write against it on the real sites. get_library({ query }) returns the vocabulary: namespaces, TypeScript types, function signatures and worked examples. run({ script }) executes a short JavaScript body against them and hands back the result. Ask it for flights and it searches several aggregators at once, dedupes the same\u2026", "categories": [ "web" ], @@ -5830,8 +6141,8 @@ "version": "0.1.0", "date": "", "notes": [ - "Initial release — REST adapter over the Bowmark API: bowmark.ask (/v1/ask) and bowmark.report_outcome (/v1/outcomes).", - "Free to use — no signup or API key; your agent runs the returned cheatsheet in its own browser." + "Initial release \u2014 REST adapter over the Bowmark API: bowmark.ask (/v1/ask) and bowmark.report_outcome (/v1/outcomes).", + "Free to use \u2014 no signup or API key; your agent runs the returned cheatsheet in its own browser." ] } ], @@ -5936,9 +6247,9 @@ { "id": "io.pilot.orthogonal", "name": "Orthogonal", - "tagline": "One key, 851 paid APIs — described in English, metered per user", - "description": "# Orthogonal — a catalog of paid tools and APIs, for your agent\n\nOrthogonal is an **API marketplace / meta-API**: a single key fronts **58 third-party APIs across 851 endpoints** — lead & contact enrichment, work-email and phone finding, web & social scraping, AI web search, company / people / jobs data, weather, voice/phone, email inboxes, and more. You never sign up for the underlying providers and you never juggle their keys — you describe what you need, and pay Orthogonal per call. This Pilot app wraps Orthogonal's control plane behind the managed-key broker, so **your agent gets one metered, keyless surface** and a **per-user $5 budget**.\n\n## The workflow: discover → price → execute\n\n1. **Discover — `orthogonal.search`** (the natural-language router ★). Describe the task in plain English, e.g. *\"find the work email and phone for a person given their name and company\"*, and get back the ranked APIs and endpoints that can do it, grouped by API with a relevance score. This is the \"which API do I need?\" endpoint — you don't have to know the catalog.\n2. **Price — `orthogonal.details`.** Pass an `{api, path}` and get the full request schema (every path/query/body param, with types and required flags) **and the exact price in dollars**. This is the authoritative price source — search and list return `null` prices.\n3. **Execute — `orthogonal.run`.** Call `{api, path, body?, query?}` and Orthogonal dispatches to the provider, returns the provider's data, and reports the exact `priceCents` charged. This is the **only call that costs money**.\n\n`orthogonal.integrate` and `orthogonal.list` round out discovery (code snippets and full-catalog browse), and `orthogonal.balance` shows YOUR remaining per-user budget — all free.\n\n## What you can do (representative)\n\n- **Contact & lead enrichment** — apollo, contactout, company-enrich, peopledatalabs, coresignal, aviato, crustdata, ocean-io, influencers-club.\n- **Work-email & phone finding** — tomba, icypeas, contactout, company-enrich, hunter.\n- **Web & AI search** — serper, linkup, tavily, exa/perplexity.\n- **Web & social scraping** — olostep, serper-scrape, scrapecreators (107 endpoints), scrapegraphai, fiber (92 endpoints).\n- **Company / firmographic / jobs data** — predictleads, fantastic-jobs, openfunnel, edges, context-dev, brand-dev.\n- **Weather, voice/phone, email inboxes** — precip, agentphone, agentmail.\n\nRun `orthogonal.search` (or `orthogonal.list`) for the live, complete set.\n\n## Pricing — how you're billed (true to real usage)\n\n- **Only `orthogonal.run` costs money.** Every discovery, pricing, and account call is **free**.\n- Each run is billed the **target endpoint's real price**, debited from your **$5 per-user budget** in micro-dollars. The `priceCents` in the run response is the exact amount charged (real cents); `X-Pilot-Credits-Remaining` on every response is your remaining budget in micro-dollars ($5 = 5000000).\n- Prices span **$0.001 – $3.50**. Distribution across the 851 endpoints: **11 free, ~612 fixed-price, 104 \"dynamic\"** (priced only after the call). Common tiers: Basic $0.001–0.01, Standard $0.01–0.10, Premium $0.10–1.00. Cheap endpoints to start with: serper ($0.002), olostep / tomba / linkup ($0.01).\n- For a **known** cost up front, call `orthogonal.details` first. For **\"dynamic\"** endpoints the price is only knowable from the run response — so metering is done on the actual charged amount, and a single call may spend the last of your budget; after that, `orthogonal.run` returns **402** (the free discovery calls keep working).\n\n## Per-user budget & fair use\n\nEach Pilot user is seeded **$5 of credit** on first use, metered by the broker against their signed pilot identity. When the budget is exhausted, billable runs return 402. To keep the shared master account fair, the broker also enforces a **per-IP identity cap**: a small number of distinct pilot identities may claim a fresh $5 from any one network, so a depleted user can't farm new budgets by minting new identities. The Orthogonal account itself is the ultimate backstop — if it runs dry, runs return 402 until it's topped up.\n\n## Good to know\n\n- **Auth is fully managed.** The `orth_live_` master key lives only in the broker; the installed adapter is keyless and signs each request with your pilot identity. Nothing to configure.\n- **You only ever see your own budget.** The provider account is shared (no per-user sub-accounts on Orthogonal), so the broker deliberately does **not** expose the account-wide balance/usage/ledger. `orthogonal.balance` is answered by the broker from its own per-user ledger — you get your personal remaining budget (also on the `X-Pilot-Credits-Remaining` header), never the pooled account total.\n- Errors surface verbatim: 402 insufficient credit, 404 unknown api/path, 5xx upstream provider error, 429 rate-limited (back off).\n- `orthogonal.help` is the self-describing discovery contract: it lists every method with params, cost note, and latency class.\n\n## Endpoint pricing (grouped by price)\n\nDistribution across Orthogonal's priced endpoints (604 of the 851). Only `orthogonal.run` bills — the price shown is charged per successful call and debited from your $5 budget.\n\n- `█░░░░░░░░░░░░░░░░░░░░░░░` **Free ($0)** — 11 endpoints\n- `███████░░░░░░░░░░░░░░░░░` **$0.001–0.01** — 85 endpoints\n- `████████████████████████` **$0.01–0.05** — 280 endpoints\n- `█████░░░░░░░░░░░░░░░░░░░` **$0.05–0.20** — 64 endpoints\n- `████░░░░░░░░░░░░░░░░░░░░` **$0.20–1.00** — 51 endpoints\n- `█░░░░░░░░░░░░░░░░░░░░░░░` **$1.00–3.50** — 9 endpoints\n- `█████████░░░░░░░░░░░░░░░` **Dynamic (priced after the call)** — 104 endpoints\n\nMost calls are cheap: the single most common price is **$0.02** (123 endpoints), then **$0.04**, **$0.01**, and **$0.03**. A $5 budget covers hundreds of typical calls.", - "summary": "Orthogonal is an API marketplace / meta-API: a single key fronts 58 third-party APIs across 851 endpoints — lead & contact enrichment, work-email and phone finding, web & social scraping, AI web search, company / people / jobs data, weather, voice/phone, email inboxes, and more. You never sign up for the underlying providers and you never juggle their keys — you describe what you need, and pay Orthogonal per call.…", + "tagline": "One key, 851 paid APIs \u2014 described in English, metered per user", + "description": "# Orthogonal \u2014 a catalog of paid tools and APIs, for your agent\n\nOrthogonal is an **API marketplace / meta-API**: a single key fronts **58 third-party APIs across 851 endpoints** \u2014 lead & contact enrichment, work-email and phone finding, web & social scraping, AI web search, company / people / jobs data, weather, voice/phone, email inboxes, and more. You never sign up for the underlying providers and you never juggle their keys \u2014 you describe what you need, and pay Orthogonal per call. This Pilot app wraps Orthogonal's control plane behind the managed-key broker, so **your agent gets one metered, keyless surface** and a **per-user $5 budget**.\n\n## The workflow: discover \u2192 price \u2192 execute\n\n1. **Discover \u2014 `orthogonal.search`** (the natural-language router \u2605). Describe the task in plain English, e.g. *\"find the work email and phone for a person given their name and company\"*, and get back the ranked APIs and endpoints that can do it, grouped by API with a relevance score. This is the \"which API do I need?\" endpoint \u2014 you don't have to know the catalog.\n2. **Price \u2014 `orthogonal.details`.** Pass an `{api, path}` and get the full request schema (every path/query/body param, with types and required flags) **and the exact price in dollars**. This is the authoritative price source \u2014 search and list return `null` prices.\n3. **Execute \u2014 `orthogonal.run`.** Call `{api, path, body?, query?}` and Orthogonal dispatches to the provider, returns the provider's data, and reports the exact `priceCents` charged. This is the **only call that costs money**.\n\n`orthogonal.integrate` and `orthogonal.list` round out discovery (code snippets and full-catalog browse), and `orthogonal.balance` shows YOUR remaining per-user budget \u2014 all free.\n\n## What you can do (representative)\n\n- **Contact & lead enrichment** \u2014 apollo, contactout, company-enrich, peopledatalabs, coresignal, aviato, crustdata, ocean-io, influencers-club.\n- **Work-email & phone finding** \u2014 tomba, icypeas, contactout, company-enrich, hunter.\n- **Web & AI search** \u2014 serper, linkup, tavily, exa/perplexity.\n- **Web & social scraping** \u2014 olostep, serper-scrape, scrapecreators (107 endpoints), scrapegraphai, fiber (92 endpoints).\n- **Company / firmographic / jobs data** \u2014 predictleads, fantastic-jobs, openfunnel, edges, context-dev, brand-dev.\n- **Weather, voice/phone, email inboxes** \u2014 precip, agentphone, agentmail.\n\nRun `orthogonal.search` (or `orthogonal.list`) for the live, complete set.\n\n## Pricing \u2014 how you're billed (true to real usage)\n\n- **Only `orthogonal.run` costs money.** Every discovery, pricing, and account call is **free**.\n- Each run is billed the **target endpoint's real price**, debited from your **$5 per-user budget** in micro-dollars. The `priceCents` in the run response is the exact amount charged (real cents); `X-Pilot-Credits-Remaining` on every response is your remaining budget in micro-dollars ($5 = 5000000).\n- Prices span **$0.001 \u2013 $3.50**. Distribution across the 851 endpoints: **11 free, ~612 fixed-price, 104 \"dynamic\"** (priced only after the call). Common tiers: Basic $0.001\u20130.01, Standard $0.01\u20130.10, Premium $0.10\u20131.00. Cheap endpoints to start with: serper ($0.002), olostep / tomba / linkup ($0.01).\n- For a **known** cost up front, call `orthogonal.details` first. For **\"dynamic\"** endpoints the price is only knowable from the run response \u2014 so metering is done on the actual charged amount, and a single call may spend the last of your budget; after that, `orthogonal.run` returns **402** (the free discovery calls keep working).\n\n## Per-user budget & fair use\n\nEach Pilot user is seeded **$5 of credit** on first use, metered by the broker against their signed pilot identity. When the budget is exhausted, billable runs return 402. To keep the shared master account fair, the broker also enforces a **per-IP identity cap**: a small number of distinct pilot identities may claim a fresh $5 from any one network, so a depleted user can't farm new budgets by minting new identities. The Orthogonal account itself is the ultimate backstop \u2014 if it runs dry, runs return 402 until it's topped up.\n\n## Good to know\n\n- **Auth is fully managed.** The `orth_live_` master key lives only in the broker; the installed adapter is keyless and signs each request with your pilot identity. Nothing to configure.\n- **You only ever see your own budget.** The provider account is shared (no per-user sub-accounts on Orthogonal), so the broker deliberately does **not** expose the account-wide balance/usage/ledger. `orthogonal.balance` is answered by the broker from its own per-user ledger \u2014 you get your personal remaining budget (also on the `X-Pilot-Credits-Remaining` header), never the pooled account total.\n- Errors surface verbatim: 402 insufficient credit, 404 unknown api/path, 5xx upstream provider error, 429 rate-limited (back off).\n- `orthogonal.help` is the self-describing discovery contract: it lists every method with params, cost note, and latency class.\n\n## Endpoint pricing (grouped by price)\n\nDistribution across Orthogonal's priced endpoints (604 of the 851). Only `orthogonal.run` bills \u2014 the price shown is charged per successful call and debited from your $5 budget.\n\n- `\u2588\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591` **Free ($0)** \u2014 11 endpoints\n- `\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591` **$0.001\u20130.01** \u2014 85 endpoints\n- `\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588` **$0.01\u20130.05** \u2014 280 endpoints\n- `\u2588\u2588\u2588\u2588\u2588\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591` **$0.05\u20130.20** \u2014 64 endpoints\n- `\u2588\u2588\u2588\u2588\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591` **$0.20\u20131.00** \u2014 51 endpoints\n- `\u2588\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591` **$1.00\u20133.50** \u2014 9 endpoints\n- `\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591` **Dynamic (priced after the call)** \u2014 104 endpoints\n\nMost calls are cheap: the single most common price is **$0.02** (123 endpoints), then **$0.04**, **$0.01**, and **$0.03**. A $5 budget covers hundreds of typical calls.", + "summary": "Orthogonal is an API marketplace / meta-API: a single key fronts 58 third-party APIs across 851 endpoints \u2014 lead & contact enrichment, work-email and phone finding, web & social scraping, AI web search, company / people / jobs data, weather, voice/phone, email inboxes, and more. You never sign up for the underlying providers and you never juggle their keys \u2014 you describe what you need, and pay Orthogonal per call.\u2026", "categories": [ "data" ], @@ -5965,37 +6276,37 @@ "methods": [ { "name": "orthogonal.search", - "summary": "★ Natural-language API router. Describe a task in plain English (prompt) and get back the ranked Orthogonal APIs + endpoints that can do it — grouped by API, each with slug, path, method and a 0–1 relevance score. FREE. Start here when you don't know which of the 851 endpoints to use, then price it with orthogonal.details and execute with orthogonal.run.", + "summary": "\u2605 Natural-language API router. Describe a task in plain English (prompt) and get back the ranked Orthogonal APIs + endpoints that can do it \u2014 grouped by API, each with slug, path, method and a 0\u20131 relevance score. FREE. Start here when you don't know which of the 851 endpoints to use, then price it with orthogonal.details and execute with orthogonal.run.", "example": "", "gated": "" }, { "name": "orthogonal.details", - "summary": "Full request schema (path/query/body params with types + required flags) AND the exact price in dollars for one endpoint. FREE. Call this before orthogonal.run to know the cost — it is the authoritative price source (prices are null in search/list). Price may be the string 'dynamic' for endpoints priced only after the call.", + "summary": "Full request schema (path/query/body params with types + required flags) AND the exact price in dollars for one endpoint. FREE. Call this before orthogonal.run to know the cost \u2014 it is the authoritative price source (prices are null in search/list). Price may be the string 'dynamic' for endpoints priced only after the call.", "example": "", "gated": "" }, { "name": "orthogonal.integrate", - "summary": "Ready-to-paste code snippets for one endpoint. FREE. format ∈ orth-sdk (default) | run-api | curl | x402-fetch | x402-python | all.", + "summary": "Ready-to-paste code snippets for one endpoint. FREE. format \u2208 orth-sdk (default) | run-api | curl | x402-fetch | x402-python | all.", "example": "", "gated": "" }, { "name": "orthogonal.list", - "summary": "Browse the whole catalog — 58 APIs / 851 endpoints with descriptions and param schemas, paginated by limit/offset. FREE. Prices are null here; use orthogonal.details for the price of a specific endpoint.", + "summary": "Browse the whole catalog \u2014 58 APIs / 851 endpoints with descriptions and param schemas, paginated by limit/offset. FREE. Prices are null here; use orthogonal.details for the price of a specific endpoint.", "example": "", "gated": "" }, { "name": "orthogonal.run", - "summary": "★ Execute any of the 851 provider endpoints via a JSON payload {api, path, body?, query?} (the HTTP method is chosen automatically; body is the provider request body, query is its query-string params). THIS IS THE ONLY CALL THAT COSTS MONEY: you are billed the target endpoint's real price and it is debited from your $5 Pilot budget. The response returns priceCents (cents actually charged) alongside the provider data, and X-Pilot-Credits-Remaining shows your budget. Once your $5 is spent, run returns 402 while the free discovery calls keep working. Prices range $0.001–$3.50; 104 endpoints are 'dynamic' (priced only from the response) — check orthogonal.details first when you need the cost up front.", + "summary": "\u2605 Execute any of the 851 provider endpoints via a JSON payload {api, path, body?, query?} (the HTTP method is chosen automatically; body is the provider request body, query is its query-string params). THIS IS THE ONLY CALL THAT COSTS MONEY: you are billed the target endpoint's real price and it is debited from your $5 Pilot budget. The response returns priceCents (cents actually charged) alongside the provider data, and X-Pilot-Credits-Remaining shows your budget. Once your $5 is spent, run returns 402 while the free discovery calls keep working. Prices range $0.001\u2013$3.50; 104 endpoints are 'dynamic' (priced only from the response) \u2014 check orthogonal.details first when you need the cost up front.", "example": "", "gated": "" }, { "name": "orthogonal.balance", - "summary": "YOUR remaining per-user budget on this app — returned by the broker from its own ledger as '$X.XX' plus credits_remaining (micro-USD; $5 = 5000000) and credits_seed. FREE, read-only, no upstream call. This is your personal budget, seeded at $5 on first use and debited by your own runs; the shared provider account's balance is never exposed. The same figure is on the X-Pilot-Credits-Remaining header of every response.", + "summary": "YOUR remaining per-user budget on this app \u2014 returned by the broker from its own ledger as '$X.XX' plus credits_remaining (micro-USD; $5 = 5000000) and credits_seed. FREE, read-only, no upstream call. This is your personal budget, seeded at $5 on first use and debited by your own runs; the shared provider account's balance is never exposed. The same figure is on the X-Pilot-Credits-Remaining header of every response.", "example": "", "gated": "" }, @@ -6018,7 +6329,7 @@ "version": "0.1.0", "date": "", "notes": [ - "Initial release — managed meta-API wrapper over Orthogonal (58 APIs / 851 endpoints), per-user $5 budget, NL router." + "Initial release \u2014 managed meta-API wrapper over Orthogonal (58 APIs / 851 endpoints), per-user $5 budget, NL router." ] } ], @@ -6091,7 +6402,7 @@ "goal": "Dispatch to the provider; billed the real per-call price", "command": "pilotctl appstore call io.pilot.orthogonal orthogonal.run '{\"api\":\"tomba\",\"path\":\"/email-finder\",\"query\":{\"full_name\":\"Ada Lovelace\",\"domain\":\"acme.com\"}}'", "expect": "{\"data\":{\"email\":\"ada@acme.com\"},\"priceCents\":1}", - "cost": "dynamic — see cost.operations", + "cost": "dynamic \u2014 see cost.operations", "note": "priceCents in the response is the exact amount charged; X-Pilot-Credits-Remaining is your remaining budget." }, { @@ -6099,7 +6410,7 @@ "goal": "", "command": "pilotctl appstore call io.pilot.orthogonal orthogonal.run '{\"api\":\"serper\",\"path\":\"/search\",\"body\":{\"q\":\"latest AI safety papers\"}}'", "expect": "{\"data\":{\"organic\":[...]},\"priceCents\":0.2}", - "cost": "dynamic — see cost.operations", + "cost": "dynamic \u2014 see cost.operations", "note": "" }, { @@ -6112,41 +6423,41 @@ } ], "cost": { - "unit": "micro-USD (1000000 = $1.00); dynamic — each run priced by the target endpoint", + "unit": "micro-USD (1000000 = $1.00); dynamic \u2014 each run priced by the target endpoint", "free_budget": "$5.00 per Pilot user", "hard_cap_usd": 5, "operations": [ { "op": "orthogonal.run", "price": "dynamic", - "note": "billed the target endpoint's real price; response priceCents (¢) × 10000 = micro-USD debited. Range $0.001–$3.50; 104 endpoints are 'dynamic' (priced only from the response)." + "note": "billed the target endpoint's real price; response priceCents (\u00a2) \u00d7 10000 = micro-USD debited. Range $0.001\u2013$3.50; 104 endpoints are 'dynamic' (priced only from the response)." }, { "op": "orthogonal.search", "price": "$0.00", - "note": "natural-language API router — free" + "note": "natural-language API router \u2014 free" }, { "op": "orthogonal.details / integrate / list", "price": "$0.00", - "note": "discovery, pricing and code-snippet reads — free" + "note": "discovery, pricing and code-snippet reads \u2014 free" }, { "op": "orthogonal.balance", "price": "$0.00", - "note": "your per-user remaining budget — free" + "note": "your per-user remaining budget \u2014 free" } ], - "worked_total": "Discovery/pricing/balance are free; each /v1/run debits its response priceCents from your $5.00 budget (the demo's two runs total ≈$0.012). At $0 the run call returns 402 while free reads keep working.", + "worked_total": "Discovery/pricing/balance are free; each /v1/run debits its response priceCents from your $5.00 budget (the demo's two runs total \u2248$0.012). At $0 the run call returns 402 while free reads keep working.", "check_balance": "pilotctl appstore call io.pilot.orthogonal orthogonal.balance '{}'" }, "gotchas": [ - "Only orthogonal.run costs money — search, details, integrate, list and balance are all free.", - "Prices are null in search/list; orthogonal.details is the authoritative price source — call it first.", - "104 endpoints are 'dynamic' (priced only from the run response) — a single run can spend the last of your budget.", + "Only orthogonal.run costs money \u2014 search, details, integrate, list and balance are all free.", + "Prices are null in search/list; orthogonal.details is the authoritative price source \u2014 call it first.", + "104 endpoints are 'dynamic' (priced only from the run response) \u2014 a single run can spend the last of your budget.", "402 Payment Required means your $5.00 is spent; free discovery calls keep working.", "Per-IP identity cap (5): you can't farm fresh $5 budgets by minting new pilot identities.", - "run takes {api, path, body?, query?} — body is the provider request body, query its query-string params." + "run takes {api, path, body?, query?} \u2014 body is the provider request body, query its query-string params." ], "next": [ "io.pilot.orthogonal orthogonal.help '{}'" @@ -6156,9 +6467,9 @@ { "id": "io.pilot.didit", "name": "Didit", - "tagline": "One API for identity and fraud — KYC, liveness, face match, AML, and more, with a no-broker key you mint in one call", - "description": "**Didit is one API for identity and fraud** — KYC/ID verification, liveness, face match, AML screening, proof of address, database validation, and email/phone OTP, wrapped as a single Pilot app. It fronts Didit's full platform: **hosted verification sessions**, reusable **workflows**, **users**, **billing**, **blocklists**, **questionnaires**, and **webhooks** — 40 methods in all.\n\n## Your own key, minted in one call — no email, no code\n\nThe hard part of using an identity provider is usually onboarding: signing up, confirming an email code, and wiring the key. This app removes all of it. **`didit.signup` takes no arguments** and returns a working key:\n\n- It signs a keyless request (your Pilot identity) to Pilot's Didit broker. The broker provisions a mailbox on Pilot infrastructure, registers a Didit account, reads Didit's one-time email code **server-side**, verifies it, and hands back your account's `api_key`.\n- The adapter caches `{email, api_key}` to `$APP/secrets.json`. From then on **every other method sends your key as `x-api-key` automatically** — you never see an inbox, a code, or the key unless you ask (`didit.account`).\n- **Idempotent:** the broker mints at most one Didit account per Pilot identity, so a repeat call — or a fresh install on another machine — returns the *same* account. The account is entirely **yours**: verifications bill to **your** Didit balance (top up with `didit.billing_topup`), and Pilot adds no markup. Each account includes Didit's **500 free full-KYC checks/month**; account creation, management, sessions CRUD, users, billing, blocklists, questionnaires and webhooks are all **free** — you pay only per verification you run.\n\n## The fast path\n\n1. `didit.signup {}` → your key is cached (one call, ~5s, no email).\n2. `didit.create_workflow` `{workflow_label:\"KYC\", features:[{feature:\"OCR\"},{feature:\"LIVENESS\"},{feature:\"FACE_MATCH\"}]}` → get `uuid`.\n3. `didit.create_session` `{workflow_id, vendor_data:\"user-123\"}` → send the user to the returned `url`.\n4. `didit.get_decision` `{session_id}` (or a webhook) → read the Approved/Declined result and extracted data.\n\n`didit.account` returns your provisioned email + key any time.\n\n## What each area does\n\n- **Sessions** — hosted flows where the user completes verification at a Didit URL, so you never handle document images: `create_session`, `get_decision`, `list_sessions`, `update_session_status` (approve/decline/resubmit), `delete_session`, `batch_delete_sessions`, `share_session` / `import_session` (B2B KYC reuse), `list_reviews`, `create_review`.\n- **Workflows** — templates built from an ordered `features` array (`OCR`, `LIVENESS`, `FACE_MATCH`, `AML`, `PROOF_OF_ADDRESS`, `PHONE_VERIFICATION`, `EMAIL_VERIFICATION`, `DATABASE_VALIDATION`, `IP_ANALYSIS`, `AGE_ESTIMATION`, `NFC`, `QUESTIONNAIRE`, `KYB_*`), each with an optional per-feature `config`: `create_workflow`, `list_workflows`, `get_workflow`, `update_workflow`, `delete_workflow`.\n- **Standalone checks (JSON, no session)** — `aml` (sanctions/PEP/adverse-media, $0.20), `database_validation` (gov sources, from $0.05).\n- **Contact** — `email_send`/`email_check` ($0.03) and `phone_send`/`phone_check` (from $0.03) OTP verification.\n- **Billing** — `billing_balance`, `billing_topup` (Stripe checkout URL).\n- **Governance** — `blocklist_*` (auto-flag repeat faces/docs/phones/emails), `questionnaire_*` (custom forms), `users_*` (people grouped by your `vendor_data`), `get_webhook`/`update_webhook` (set + rotate the HMAC secret programmatically).\n\n## Pricing\n\nPay-per-check on **your** Didit balance — no Pilot markup. See the full rate card in `didit.help`. Highlights: full KYC bundle **$0.33/check** (first **500/month free**), ID verification $0.15, passive liveness $0.10, face match $0.05, **face search free**, AML $0.20, PoA $0.20, email/phone from $0.03. Image-upload APIs (direct ID scan, liveness, face match, face search, age estimation, PoA) run through the **hosted session** flow rather than as direct methods.\n\n## Notes\n\n- The adapter dials exactly two hosts: Pilot's broker (`broker.pilotprotocol.network`) for the one-call `didit.signup`, and Didit (`verification.didit.me`) for every operational call with your cached key. It holds no shared secret; the broker signs you in, then steps out of the data path.\n- Plain request/response REST — no websockets, no async jobs. Rate limits: ~600 session-creates/min, 300/min per other method; the account OTP register is 5/IP/hour.\n- Errors surface verbatim: `401` (run `didit.signup` first), `403` (top up credits), `429` (back off).\n", - "summary": "Didit is one API for identity and fraud — KYC/ID verification, liveness, face match, AML screening, proof of address, database validation, and email/phone OTP, wrapped as a single Pilot app. It fronts Didit's full platform: hosted verification sessions, reusable workflows, users, billing, blocklists, questionnaires, and webhooks — 40 methods in all. Your own key, minted in one call — no email, no code The hard part…", + "tagline": "One API for identity and fraud \u2014 KYC, liveness, face match, AML, and more, with a no-broker key you mint in one call", + "description": "**Didit is one API for identity and fraud** \u2014 KYC/ID verification, liveness, face match, AML screening, proof of address, database validation, and email/phone OTP, wrapped as a single Pilot app. It fronts Didit's full platform: **hosted verification sessions**, reusable **workflows**, **users**, **billing**, **blocklists**, **questionnaires**, and **webhooks** \u2014 40 methods in all.\n\n## Your own key, minted in one call \u2014 no email, no code\n\nThe hard part of using an identity provider is usually onboarding: signing up, confirming an email code, and wiring the key. This app removes all of it. **`didit.signup` takes no arguments** and returns a working key:\n\n- It signs a keyless request (your Pilot identity) to Pilot's Didit broker. The broker provisions a mailbox on Pilot infrastructure, registers a Didit account, reads Didit's one-time email code **server-side**, verifies it, and hands back your account's `api_key`.\n- The adapter caches `{email, api_key}` to `$APP/secrets.json`. From then on **every other method sends your key as `x-api-key` automatically** \u2014 you never see an inbox, a code, or the key unless you ask (`didit.account`).\n- **Idempotent:** the broker mints at most one Didit account per Pilot identity, so a repeat call \u2014 or a fresh install on another machine \u2014 returns the *same* account. The account is entirely **yours**: verifications bill to **your** Didit balance (top up with `didit.billing_topup`), and Pilot adds no markup. Each account includes Didit's **500 free full-KYC checks/month**; account creation, management, sessions CRUD, users, billing, blocklists, questionnaires and webhooks are all **free** \u2014 you pay only per verification you run.\n\n## The fast path\n\n1. `didit.signup {}` \u2192 your key is cached (one call, ~5s, no email).\n2. `didit.create_workflow` `{workflow_label:\"KYC\", features:[{feature:\"OCR\"},{feature:\"LIVENESS\"},{feature:\"FACE_MATCH\"}]}` \u2192 get `uuid`.\n3. `didit.create_session` `{workflow_id, vendor_data:\"user-123\"}` \u2192 send the user to the returned `url`.\n4. `didit.get_decision` `{session_id}` (or a webhook) \u2192 read the Approved/Declined result and extracted data.\n\n`didit.account` returns your provisioned email + key any time.\n\n## What each area does\n\n- **Sessions** \u2014 hosted flows where the user completes verification at a Didit URL, so you never handle document images: `create_session`, `get_decision`, `list_sessions`, `update_session_status` (approve/decline/resubmit), `delete_session`, `batch_delete_sessions`, `share_session` / `import_session` (B2B KYC reuse), `list_reviews`, `create_review`.\n- **Workflows** \u2014 templates built from an ordered `features` array (`OCR`, `LIVENESS`, `FACE_MATCH`, `AML`, `PROOF_OF_ADDRESS`, `PHONE_VERIFICATION`, `EMAIL_VERIFICATION`, `DATABASE_VALIDATION`, `IP_ANALYSIS`, `AGE_ESTIMATION`, `NFC`, `QUESTIONNAIRE`, `KYB_*`), each with an optional per-feature `config`: `create_workflow`, `list_workflows`, `get_workflow`, `update_workflow`, `delete_workflow`.\n- **Standalone checks (JSON, no session)** \u2014 `aml` (sanctions/PEP/adverse-media, $0.20), `database_validation` (gov sources, from $0.05).\n- **Contact** \u2014 `email_send`/`email_check` ($0.03) and `phone_send`/`phone_check` (from $0.03) OTP verification.\n- **Billing** \u2014 `billing_balance`, `billing_topup` (Stripe checkout URL).\n- **Governance** \u2014 `blocklist_*` (auto-flag repeat faces/docs/phones/emails), `questionnaire_*` (custom forms), `users_*` (people grouped by your `vendor_data`), `get_webhook`/`update_webhook` (set + rotate the HMAC secret programmatically).\n\n## Pricing\n\nPay-per-check on **your** Didit balance \u2014 no Pilot markup. See the full rate card in `didit.help`. Highlights: full KYC bundle **$0.33/check** (first **500/month free**), ID verification $0.15, passive liveness $0.10, face match $0.05, **face search free**, AML $0.20, PoA $0.20, email/phone from $0.03. Image-upload APIs (direct ID scan, liveness, face match, face search, age estimation, PoA) run through the **hosted session** flow rather than as direct methods.\n\n## Notes\n\n- The adapter dials exactly two hosts: Pilot's broker (`broker.pilotprotocol.network`) for the one-call `didit.signup`, and Didit (`verification.didit.me`) for every operational call with your cached key. It holds no shared secret; the broker signs you in, then steps out of the data path.\n- Plain request/response REST \u2014 no websockets, no async jobs. Rate limits: ~600 session-creates/min, 300/min per other method; the account OTP register is 5/IP/hour.\n- Errors surface verbatim: `401` (run `didit.signup` first), `403` (top up credits), `429` (back off).\n", + "summary": "Didit is one API for identity and fraud \u2014 KYC/ID verification, liveness, face match, AML screening, proof of address, database validation, and email/phone OTP, wrapped as a single Pilot app. It fronts Didit's full platform: hosted verification sessions, reusable workflows, users, billing, blocklists, questionnaires, and webhooks \u2014 40 methods in all. Your own key, minted in one call \u2014 no email, no code The hard part\u2026", "categories": [ "security" ], @@ -6189,13 +6500,13 @@ "methods": [ { "name": "didit.signup", - "summary": "Get your own Didit API key in ONE call — no email, no code, no human step. This signs a keyless request to Pilot's Didit broker, which provisions a mailbox on Pilot infrastructure, registers a Didit account, reads the emailed one-time code server-side, verifies it, and returns your account's api_key. The adapter caches {email, api_key} to $APP/secrets.json, and from then on EVERY other didit.* method authenticates automatically (x-api-key) — you never handle the key or an inbox. Idempotent: the broker mints at most one account per Pilot identity, so a repeat call (or a fresh install) returns the SAME account. Run this ONCE before any other method. FREE — account creation costs nothing; you pay only per verification you run, and each account includes Didit's 500 free full-KYC checks/month. The account (email + key) is retrievable any time via didit.account. Takes no arguments.", + "summary": "Get your own Didit API key in ONE call \u2014 no email, no code, no human step. This signs a keyless request to Pilot's Didit broker, which provisions a mailbox on Pilot infrastructure, registers a Didit account, reads the emailed one-time code server-side, verifies it, and returns your account's api_key. The adapter caches {email, api_key} to $APP/secrets.json, and from then on EVERY other didit.* method authenticates automatically (x-api-key) \u2014 you never handle the key or an inbox. Idempotent: the broker mints at most one account per Pilot identity, so a repeat call (or a fresh install) returns the SAME account. Run this ONCE before any other method. FREE \u2014 account creation costs nothing; you pay only per verification you run, and each account includes Didit's 500 free full-KYC checks/month. The account (email + key) is retrievable any time via didit.account. Takes no arguments.", "example": "", "gated": "" }, { "name": "didit.account", - "summary": "Retrieve your cached Didit account — the email the broker provisioned for you and your api_key — plus a signed_up flag. Local, instant, FREE (reads $APP/secrets.json; no backend call). Use it to confirm you're signed up or to read your key. If signed_up is false, call didit.signup first.", + "summary": "Retrieve your cached Didit account \u2014 the email the broker provisioned for you and your api_key \u2014 plus a signed_up flag. Local, instant, FREE (reads $APP/secrets.json; no backend call). Use it to confirm you're signed up or to read your key. If signed_up is false, call didit.signup first.", "example": "", "gated": "" }, @@ -6207,13 +6518,13 @@ }, { "name": "didit.billing_topup", - "summary": "Add credit to your Didit balance. FREE call — returns a Stripe checkout URL (checkout_session_url) to present to the user; the charge happens on Stripe, not through Pilot.", + "summary": "Add credit to your Didit balance. FREE call \u2014 returns a Stripe checkout URL (checkout_session_url) to present to the user; the charge happens on Stripe, not through Pilot.", "example": "", "gated": "" }, { "name": "didit.create_workflow", - "summary": "Create a verification workflow — the reusable template that defines which checks a hosted session runs, in order. FREE to create; you're billed per feature only when a session actually runs it. Returns {uuid} — pass it as workflow_id to didit.create_session. The v3 API takes a `features` ARRAY (in the order users complete them); each item is {feature, config?} where feature is one of OCR, NFC, LIVENESS, FACE_MATCH, PROOF_OF_ADDRESS, QUESTIONNAIRE, DOCUMENT_AI, PHONE_VERIFICATION, EMAIL_VERIFICATION, DATABASE_VALIDATION, AML, IP_ANALYSIS, AGE_ESTIMATION, KYB_REGISTRY, KYB_DOCUMENTS, KYB_KEY_PEOPLE. Example: [{\"feature\":\"OCR\"},{\"feature\":\"LIVENESS\",\"config\":{\"face_liveness_method\":\"PASSIVE\"}},{\"feature\":\"FACE_MATCH\"}]. The API uses a strict field whitelist — any undeclared key (e.g. workflow_type) is a 400. Max 50 workflows per account.", + "summary": "Create a verification workflow \u2014 the reusable template that defines which checks a hosted session runs, in order. FREE to create; you're billed per feature only when a session actually runs it. Returns {uuid} \u2014 pass it as workflow_id to didit.create_session. The v3 API takes a `features` ARRAY (in the order users complete them); each item is {feature, config?} where feature is one of OCR, NFC, LIVENESS, FACE_MATCH, PROOF_OF_ADDRESS, QUESTIONNAIRE, DOCUMENT_AI, PHONE_VERIFICATION, EMAIL_VERIFICATION, DATABASE_VALIDATION, AML, IP_ANALYSIS, AGE_ESTIMATION, KYB_REGISTRY, KYB_DOCUMENTS, KYB_KEY_PEOPLE. Example: [{\"feature\":\"OCR\"},{\"feature\":\"LIVENESS\",\"config\":{\"face_liveness_method\":\"PASSIVE\"}},{\"feature\":\"FACE_MATCH\"}]. The API uses a strict field whitelist \u2014 any undeclared key (e.g. workflow_type) is a 400. Max 50 workflows per account.", "example": "", "gated": "" }, @@ -6231,7 +6542,7 @@ }, { "name": "didit.update_workflow", - "summary": "Update a workflow (partial — send only the fields to change; same field set as create_workflow, e.g. a replacement `features` array, workflow_label, status, is_default). FREE.", + "summary": "Update a workflow (partial \u2014 send only the fields to change; same field set as create_workflow, e.g. a replacement `features` array, workflow_label, status, is_default). FREE.", "example": "", "gated": "" }, @@ -6243,13 +6554,13 @@ }, { "name": "didit.create_session", - "summary": "Start a hosted verification session for a user and get a URL to send them to. This is Didit's recommended path for ID/liveness/face-match/AML/PoA/etc. — the user completes everything at the hosted URL, so you never handle document images yourself. COST is the sum of the features the workflow enables (e.g. a full KYC bundle ≈ $0.33/check; 500 full-KYC checks/month are free), charged to your Didit balance when the session runs. Returns {session_id, session_token, url, status}. Poll didit.get_decision or set a webhook for the result. Nested objects (contact_details, expected_details) are passed as JSON objects.", + "summary": "Start a hosted verification session for a user and get a URL to send them to. This is Didit's recommended path for ID/liveness/face-match/AML/PoA/etc. \u2014 the user completes everything at the hosted URL, so you never handle document images yourself. COST is the sum of the features the workflow enables (e.g. a full KYC bundle \u2248 $0.33/check; 500 full-KYC checks/month are free), charged to your Didit balance when the session runs. Returns {session_id, session_token, url, status}. Poll didit.get_decision or set a webhook for the result. Nested objects (contact_details, expected_details) are passed as JSON objects.", "example": "", "gated": "" }, { "name": "didit.get_decision", - "summary": "Get the full decision and extracted data for a session — status plus id_verifications, liveness_checks, face_matches, aml_screenings, phone/email verifications, poa_verifications, database_validations, ip_analyses, and reviews. FREE (reading results). Image URLs in the response expire after 60 minutes. Statuses: Not Started | In Progress | In Review | Approved | Declined | Abandoned | Expired | Resubmitted.", + "summary": "Get the full decision and extracted data for a session \u2014 status plus id_verifications, liveness_checks, face_matches, aml_screenings, phone/email verifications, poa_verifications, database_validations, ip_analyses, and reviews. FREE (reading results). Image URLs in the response expire after 60 minutes. Statuses: Not Started | In Progress | In Review | Approved | Declined | Abandoned | Expired | Resubmitted.", "example": "", "gated": "" }, @@ -6261,7 +6572,7 @@ }, { "name": "didit.update_session_status", - "summary": "Manually override a session's status (approve/decline/resubmit) — the programmatic-review action. FREE. For Resubmitted, pass nodes_to_resubmit; the session must be Declined, In Review, or Abandoned.", + "summary": "Manually override a session's status (approve/decline/resubmit) \u2014 the programmatic-review action. FREE. For Resubmitted, pass nodes_to_resubmit; the session must be Declined, In Review, or Abandoned.", "example": "", "gated": "" }, @@ -6417,7 +6728,7 @@ }, { "name": "didit.update_webhook", - "summary": "Set/rotate your webhook config programmatically — no console needed. FREE.", + "summary": "Set/rotate your webhook config programmatically \u2014 no console needed. FREE.", "example": "", "gated": "" }, @@ -6433,9 +6744,9 @@ "version": "1.0.0", "date": "", "notes": [ - "Initial release — the full Didit identity platform over one byo HTTPS app: 39 methods + didit.help.", + "Initial release \u2014 the full Didit identity platform over one byo HTTPS app: 39 methods + didit.help.", "One-call broker signup: didit.signup {} mints and caches a per-user Didit API key with no email and no code (Pilot's broker runs the signup and reads the OTP server-side); didit.account retrieves it; ops stay direct to Didit.", - "KYC/ID, liveness, face match, AML, proof-of-address, database validation, email/phone OTP, hosted sessions, workflows, billing, blocklist, questionnaires, users, webhooks — per-endpoint pricing in didit.help." + "KYC/ID, liveness, face match, AML, proof-of-address, database validation, email/phone OTP, hosted sessions, workflows, billing, blocklist, questionnaires, users, webhooks \u2014 per-endpoint pricing in didit.help." ] } ], @@ -6546,10 +6857,10 @@ ], "cost": null, "gotchas": [ - "Run didit.signup once before anything else — every other method authenticates with the key it caches; a 401 means you skipped it.", - "Verification calls bill to YOUR own Didit account/balance (the key signup minted), not to Pilot — top up with didit.billing_topup (min $50); 500 full-KYC checks/month are free.", + "Run didit.signup once before anything else \u2014 every other method authenticates with the key it caches; a 401 means you skipped it.", + "Verification calls bill to YOUR own Didit account/balance (the key signup minted), not to Pilot \u2014 top up with didit.billing_topup (min $50); 500 full-KYC checks/month are free.", "signup is idempotent per Pilot identity: a repeat call (or a fresh install) returns the SAME account, not a new one.", - "create_workflow takes a features ARRAY in completion order and uses a strict field whitelist — any undeclared key (e.g. workflow_type) is a 400.", + "create_workflow takes a features ARRAY in completion order and uses a strict field whitelist \u2014 any undeclared key (e.g. workflow_type) is a 400.", "Image-upload checks (ID scan, liveness, face match, PoA) run only via the hosted create_session flow, not as direct methods." ], "next": [ @@ -6560,9 +6871,9 @@ { "id": "io.pilot.tldr", "name": "tldr", - "tagline": "Simplified man pages for ~7,350+ CLIs — instant, example-first command recall for agents", - "description": "# tldr — simplified man pages for almost every CLI, native for agents\n\nThis app installs the official **tldr-pages** client **tlrc v1.13.1** on the host and fronts it as typed\nmethods. tldr is *\"simplified, community-driven man pages\"* — concise, **example-first** cheat-sheets for\n**~7,350+ command-line tools**, the practical opposite of a dense `man` page. Instead of scrolling a manual,\nan agent asks `tldr docker` and gets the handful of commands it actually needs, each with a one-line\ndescription. The bundle is the upstream tlrc binary (sha-pinned per OS/arch, fetched from the Pilot artifact\nregistry at install) plus a tiny wrapper that serves a complete, color-free command-palette reference.\n\n**Open source, and every command is tested.** The tlrc client is **MIT**; the pages are written by the\ntldr-pages community and licensed **CC-BY-4.0**. The full page catalog (~3 MiB) auto-downloads on first use\nand then works offline.\n\n## Why an agent wants this\n\n- **Recall any CLI instantly.** `tldr ` returns the 5–10 invocations that matter — no manual to parse,\n no web search. The dictionary of man pages, for the whole toolbox an agent builds and deploys with.\n- **Discover tools by task.** `tldr.search ` does first-class full-text search across the catalog\n (\"compress\", \"screenshot\", \"certificate\"); `tldr.list` prints the whole directory of documented commands.\n- **Machine-parseable.** `tldr.raw` returns raw Markdown so an agent can lift the exact example lines\n programmatically; `tldr.get` returns clean rendered text for humans-in-the-loop.\n- **Self-contained + offline.** One static binary, no dependencies; after the first fetch, lookups need no\n network. Runs on macOS and Linux (arm64 + amd64).\n- **The complete palette.** Every flag is reachable — platform overrides, languages, list/search, render a\n local page — via curated methods plus a verbatim-argv `tldr.exec` passthrough.\n\n## What it documents (a taste — all verbatim from real tldr pages)\n\n**Version control & GitHub**\n- `git` — Clone a repository: `git clone https://example.com/repo.git` · View status: `git status`\n- `gh` — Clone a repo: `gh repo clone owner/repository` · List open issues: `gh issue list`\n\n**Containers, orchestration & IaC**\n- `docker` — List all containers: `docker ps -a` · Run a named container: `docker run --name name image`\n- `kubectl` — Wide resource listing: `kubectl get pods -o wide` · Everything: `kubectl get all`\n- `terraform` — Initialize: `terraform init` · Format config: `terraform fmt`\n- `ansible` — Ping a host group: `ansible group -m ping` · Gather facts: `ansible group -m setup`\n- `helm` — Create a chart: `helm create chart_name` · Add a repo: `helm repo add repository_name`\n\n**Cloud**\n- `aws` — Configure SSO: `aws configure sso` · Who am I: `aws sts get-caller-identity`\n- `ssh` — Connect: `ssh username@remote_host` · With an identity key: `ssh username@remote_host -i key`\n\n**Languages & package managers**\n- `npm` — Install deps: `npm install` · A pinned version: `npm install package@version`\n- `cargo` — Install a crate: `cargo install crate_name` · List installed: `cargo install --list`\n- `go` — Run a file: `go run file.go` · Build a binary: `go build -o executable file.go`\n\n**Data & text**\n- `jq` — Pretty-print JSON: `jq '.' file.json`\n- `sed` — Replace text: `command | sed 's/apple/mango/g'` · First line: `command | sed -n '1p'`\n- `awk` — Print a column: `awk '{print $5}' file` · Last field, comma-separated: `awk -F ',' '{print $NF}' file`\n- `grep` — Recursive search: `grep -rI \"pattern\" path/to/dir`\n- `psql` — Connect: `psql -h host -p port -U username database`\n\n**Networking, files & archives**\n- `curl` — GET a URL: `curl https://example.com` · Save to a file: `curl -O https://example.com/file.zip`\n- `rsync` — Archive-mode copy: `rsync -a path/to/source path/to/destination`\n- `tar` — Create a gzipped archive: `tar czf target.tar.gz file1 file2`\n- `find` — By extension: `find path/to/dir -name '*.ext'`\n- `openssl` — Self-signed cert: `openssl req -new -x509 -key private.key -out certificate.crt -days 365`\n- `ffmpeg` — Extract audio: `ffmpeg -i video.mp4 -vn sound.mp3`\n\n**System & services (Linux)**\n- `systemctl` — Failed units: `systemctl --failed` · Manage a service: `systemctl start|stop|status unit`\n- `journalctl` — Follow a unit's logs: `journalctl -u unit -f`\n\n…and ~7,300 more, across `common`, `linux`, `osx`, `windows`, `android`, and `sunos`.\n\n## Methods\n\n- `tldr.get` — a command's cheat-sheet as clean text.\n- `tldr.raw` — a page as raw Markdown (machine-parseable).\n- `tldr.search` — full-text search across the whole catalog for a keyword.\n- `tldr.list` — the directory of every documented command for this platform.\n- `tldr.info` — cache path / age / languages / page count.\n- `tldr.update` — refresh the local page cache.\n- `tldr.render` — render a local tldr-format `.md` page.\n- `tldr.exec` — run the client with a verbatim argv (any flag: `--platform`, `-L`, `--list-all`, …) + optional stdin.\n- `tldr.cli_help` — the complete command-palette reference as clean text.\n- `tldr.version` — the delivered client + spec version. `tldr.help` — the self-describing method list.\n\n## How to use it\n\n1. **Recall a tool (no setup):** `tldr.get` `{ \"command\": \"tar\" }` → the tar cheat-sheet. First call auto-downloads the cache.\n2. **Multi-word page:** `tldr.get` `{ \"command\": \"git-commit\" }` (hyphen-joined) or `tldr.exec` `{ \"args\": [\"git\",\"commit\"] }`.\n3. **Find a tool by task:** `tldr.search` `{ \"keyword\": \"compress\" }` → every page mentioning compression.\n4. **Browse the catalog:** `tldr.list` → all documented commands for this platform.\n5. **Anything else:** `tldr.exec` `{ \"args\": [\"--platform\",\"linux\",\"systemctl\"] }` to force a platform.\n\n## Good to know\n\n- The page cache (~3 MiB, ~7,350+ pages) auto-downloads on first use and refreshes when stale; progress goes\n to stderr so method output on stdout stays clean. Use `tldr.update` to refresh, `--offline` (via `tldr.exec`)\n to pin the current cache.\n- On a non-zero exit the reply is `{stdout, stderr, exit}` so the caller sees everything the CLI produced.\n- Runs on **macOS and Linux** (arm64 + amd64); the binary is fetched from the Pilot artifact registry and\n sha-pinned on install. Client license **MIT** (tlrc); pages content **CC-BY-4.0**, © tldr-pages contributors.\n- `tldr.help` lists every method with its latency class — the self-describing discovery contract.\n\n## tldr command palette (`tldr.cli_help`)\n```\ntldr — simplified, community-driven man pages (io.pilot.tldr)\n================================================================================\nPowered by tlrc v1.13.1, the official tldr-pages client (tldr client spec v2.3).\ntldr gives you concise, example-first help for ~7,350+ command-line tools — a\npractical cheat-sheet for almost every CLI an agent uses to build, deploy, and\noperate software. Open source: the tlrc client is MIT; the pages are authored by\nthe tldr-pages community and licensed CC-BY-4.0. Every command below is tested.\n\nUSAGE\n--------------------------------------------------------------------------------\n tldr [OPTIONS] [PAGE]...\n\n PAGE The command to look up, e.g. `tar`, `docker`, `kubectl`.\n Multi-word pages: join with a hyphen -> `git-commit`,\n `docker-compose`, `gh-repo` (or pass the words as separate\n arguments via the passthrough method: [\"git\",\"commit\"]).\n\nOPERATIONS (choose at most one per invocation)\n--------------------------------------------------------------------------------\n Show the tldr page for a command (rendered).\n -u, --update Update the local page cache (downloads only the\n languages that changed). Needs network.\n -l, --list List every page for the current platform (plus\n the cross-platform `common` set) — a directory of\n all documented tools, one name per line.\n -a, --list-all List every page across ALL platforms.\n -s, --search Search page CONTENTS for a keyword and print each\n match as `language platform page`. First-class\n full-text search across the whole catalog.\n --list-platforms List the available platforms.\n --list-languages List the installed languages.\n -i, --info Show cache info: path, age, installed languages,\n and total page count.\n -r, --render Render a local tldr page file (`.md`) — preview a\n page you are authoring or one you fetched.\n --clean-cache Interactively delete the cache directory contents.\n --gen-config Print the default config (TOML) to stdout.\n --config-path Print the default config path (creates the dir).\n -v, --version Print the client + spec version.\n -h, --help Print this complete command-palette reference.\n\nMODIFIERS (change how an operation behaves)\n--------------------------------------------------------------------------------\n -p, --platform Force a platform instead of the host's.\n Values: linux, osx (macOS), windows, android,\n sunos, common. Default: the OS you are on.\n -L, --language Force a language (repeatable), e.g. `-L es`,\n `-L fr`, `-L ja`. Default: config, else $LANG.\n --short-options Prefer short option forms in placeholders (-s).\n --long-options Prefer long option forms in placeholders (--long).\n --edit Show a GitHub \"edit this page\" link for the page.\n -o, --offline Never touch the network, even if the cache is\n stale (use the pages already downloaded).\n -c, --compact Strip empty lines from the output.\n --no-compact Keep empty lines (overrides --compact).\n -R, --raw Print the page as raw Markdown (no rendering) —\n the most machine-parseable form.\n --no-raw Render instead of raw (overrides --raw).\n -q, --quiet Suppress status/progress messages and warnings.\n --verbose Print debug info (repeatable).\n --color Color output: auto (default), always, never.\n --config Use an alternative config file path.\n\nPLATFORM VALUES\n--------------------------------------------------------------------------------\n common Cross-platform tools (the largest bucket: git, docker, curl, jq, ...)\n linux Linux-specific pages (systemctl, journalctl, apt, ip, ...)\n osx macOS-specific pages (brew, pbcopy, launchctl, ...)\n windows Windows-specific pages (choco, taskkill, ...)\n android Android tool pages (adb, pm, ...)\n sunos illumos / SunOS pages\n\nCACHE & OFFLINE\n--------------------------------------------------------------------------------\n The page cache auto-downloads on first use (a ~3 MiB archive of ~7,350+ pages)\n and thereafter refreshes automatically when it goes stale. After the first\n fetch, lookups (`get`, `raw`, `search`, `list`, `info`, `render`) are fully\n local and offline. Progress messages are written to stderr, so method output\n on stdout stays clean. Use --offline to pin the current cache and --update to\n refresh on demand. Cache path: `tldr --info`.\n\nEXAMPLES\n--------------------------------------------------------------------------------\n tldr tar # show the tar cheat-sheet\n tldr git-commit # multi-word page (hyphen-joined)\n tldr --raw docker # raw Markdown for docker\n tldr --search compress # find every page mentioning \"compress\"\n tldr --list # directory of all tools for this platform\n tldr --list-all # every page across all platforms\n tldr --platform linux systemctl # force the linux page\n tldr --update # refresh the cache\n tldr --info # cache path / age / page count\n\nLICENSING\n--------------------------------------------------------------------------------\n Client (tlrc): MIT — https://github.com/tldr-pages/tlrc\n Pages content: CC-BY-4.0, (c) tldr-pages contributors —\n https://github.com/tldr-pages/tldr\n Project home: https://tldr.sh\n\n```\n", - "summary": "This app installs the official tldr-pages client tlrc v1.13.1 on the host and fronts it as typed methods. tldr is \"simplified, community-driven man pages\" — concise, example-first cheat-sheets for ~7,350+ command-line tools, the practical opposite of a dense man page. Instead of scrolling a manual, an agent asks tldr docker and gets the handful of commands it actually needs, each with a one-line description. The…", + "tagline": "Simplified man pages for ~7,350+ CLIs \u2014 instant, example-first command recall for agents", + "description": "# tldr \u2014 simplified man pages for almost every CLI, native for agents\n\nThis app installs the official **tldr-pages** client **tlrc v1.13.1** on the host and fronts it as typed\nmethods. tldr is *\"simplified, community-driven man pages\"* \u2014 concise, **example-first** cheat-sheets for\n**~7,350+ command-line tools**, the practical opposite of a dense `man` page. Instead of scrolling a manual,\nan agent asks `tldr docker` and gets the handful of commands it actually needs, each with a one-line\ndescription. The bundle is the upstream tlrc binary (sha-pinned per OS/arch, fetched from the Pilot artifact\nregistry at install) plus a tiny wrapper that serves a complete, color-free command-palette reference.\n\n**Open source, and every command is tested.** The tlrc client is **MIT**; the pages are written by the\ntldr-pages community and licensed **CC-BY-4.0**. The full page catalog (~3 MiB) auto-downloads on first use\nand then works offline.\n\n## Why an agent wants this\n\n- **Recall any CLI instantly.** `tldr ` returns the 5\u201310 invocations that matter \u2014 no manual to parse,\n no web search. The dictionary of man pages, for the whole toolbox an agent builds and deploys with.\n- **Discover tools by task.** `tldr.search ` does first-class full-text search across the catalog\n (\"compress\", \"screenshot\", \"certificate\"); `tldr.list` prints the whole directory of documented commands.\n- **Machine-parseable.** `tldr.raw` returns raw Markdown so an agent can lift the exact example lines\n programmatically; `tldr.get` returns clean rendered text for humans-in-the-loop.\n- **Self-contained + offline.** One static binary, no dependencies; after the first fetch, lookups need no\n network. Runs on macOS and Linux (arm64 + amd64).\n- **The complete palette.** Every flag is reachable \u2014 platform overrides, languages, list/search, render a\n local page \u2014 via curated methods plus a verbatim-argv `tldr.exec` passthrough.\n\n## What it documents (a taste \u2014 all verbatim from real tldr pages)\n\n**Version control & GitHub**\n- `git` \u2014 Clone a repository: `git clone https://example.com/repo.git` \u00b7 View status: `git status`\n- `gh` \u2014 Clone a repo: `gh repo clone owner/repository` \u00b7 List open issues: `gh issue list`\n\n**Containers, orchestration & IaC**\n- `docker` \u2014 List all containers: `docker ps -a` \u00b7 Run a named container: `docker run --name name image`\n- `kubectl` \u2014 Wide resource listing: `kubectl get pods -o wide` \u00b7 Everything: `kubectl get all`\n- `terraform` \u2014 Initialize: `terraform init` \u00b7 Format config: `terraform fmt`\n- `ansible` \u2014 Ping a host group: `ansible group -m ping` \u00b7 Gather facts: `ansible group -m setup`\n- `helm` \u2014 Create a chart: `helm create chart_name` \u00b7 Add a repo: `helm repo add repository_name`\n\n**Cloud**\n- `aws` \u2014 Configure SSO: `aws configure sso` \u00b7 Who am I: `aws sts get-caller-identity`\n- `ssh` \u2014 Connect: `ssh username@remote_host` \u00b7 With an identity key: `ssh username@remote_host -i key`\n\n**Languages & package managers**\n- `npm` \u2014 Install deps: `npm install` \u00b7 A pinned version: `npm install package@version`\n- `cargo` \u2014 Install a crate: `cargo install crate_name` \u00b7 List installed: `cargo install --list`\n- `go` \u2014 Run a file: `go run file.go` \u00b7 Build a binary: `go build -o executable file.go`\n\n**Data & text**\n- `jq` \u2014 Pretty-print JSON: `jq '.' file.json`\n- `sed` \u2014 Replace text: `command | sed 's/apple/mango/g'` \u00b7 First line: `command | sed -n '1p'`\n- `awk` \u2014 Print a column: `awk '{print $5}' file` \u00b7 Last field, comma-separated: `awk -F ',' '{print $NF}' file`\n- `grep` \u2014 Recursive search: `grep -rI \"pattern\" path/to/dir`\n- `psql` \u2014 Connect: `psql -h host -p port -U username database`\n\n**Networking, files & archives**\n- `curl` \u2014 GET a URL: `curl https://example.com` \u00b7 Save to a file: `curl -O https://example.com/file.zip`\n- `rsync` \u2014 Archive-mode copy: `rsync -a path/to/source path/to/destination`\n- `tar` \u2014 Create a gzipped archive: `tar czf target.tar.gz file1 file2`\n- `find` \u2014 By extension: `find path/to/dir -name '*.ext'`\n- `openssl` \u2014 Self-signed cert: `openssl req -new -x509 -key private.key -out certificate.crt -days 365`\n- `ffmpeg` \u2014 Extract audio: `ffmpeg -i video.mp4 -vn sound.mp3`\n\n**System & services (Linux)**\n- `systemctl` \u2014 Failed units: `systemctl --failed` \u00b7 Manage a service: `systemctl start|stop|status unit`\n- `journalctl` \u2014 Follow a unit's logs: `journalctl -u unit -f`\n\n\u2026and ~7,300 more, across `common`, `linux`, `osx`, `windows`, `android`, and `sunos`.\n\n## Methods\n\n- `tldr.get` \u2014 a command's cheat-sheet as clean text.\n- `tldr.raw` \u2014 a page as raw Markdown (machine-parseable).\n- `tldr.search` \u2014 full-text search across the whole catalog for a keyword.\n- `tldr.list` \u2014 the directory of every documented command for this platform.\n- `tldr.info` \u2014 cache path / age / languages / page count.\n- `tldr.update` \u2014 refresh the local page cache.\n- `tldr.render` \u2014 render a local tldr-format `.md` page.\n- `tldr.exec` \u2014 run the client with a verbatim argv (any flag: `--platform`, `-L`, `--list-all`, \u2026) + optional stdin.\n- `tldr.cli_help` \u2014 the complete command-palette reference as clean text.\n- `tldr.version` \u2014 the delivered client + spec version. `tldr.help` \u2014 the self-describing method list.\n\n## How to use it\n\n1. **Recall a tool (no setup):** `tldr.get` `{ \"command\": \"tar\" }` \u2192 the tar cheat-sheet. First call auto-downloads the cache.\n2. **Multi-word page:** `tldr.get` `{ \"command\": \"git-commit\" }` (hyphen-joined) or `tldr.exec` `{ \"args\": [\"git\",\"commit\"] }`.\n3. **Find a tool by task:** `tldr.search` `{ \"keyword\": \"compress\" }` \u2192 every page mentioning compression.\n4. **Browse the catalog:** `tldr.list` \u2192 all documented commands for this platform.\n5. **Anything else:** `tldr.exec` `{ \"args\": [\"--platform\",\"linux\",\"systemctl\"] }` to force a platform.\n\n## Good to know\n\n- The page cache (~3 MiB, ~7,350+ pages) auto-downloads on first use and refreshes when stale; progress goes\n to stderr so method output on stdout stays clean. Use `tldr.update` to refresh, `--offline` (via `tldr.exec`)\n to pin the current cache.\n- On a non-zero exit the reply is `{stdout, stderr, exit}` so the caller sees everything the CLI produced.\n- Runs on **macOS and Linux** (arm64 + amd64); the binary is fetched from the Pilot artifact registry and\n sha-pinned on install. Client license **MIT** (tlrc); pages content **CC-BY-4.0**, \u00a9 tldr-pages contributors.\n- `tldr.help` lists every method with its latency class \u2014 the self-describing discovery contract.\n\n## tldr command palette (`tldr.cli_help`)\n```\ntldr \u2014 simplified, community-driven man pages (io.pilot.tldr)\n================================================================================\nPowered by tlrc v1.13.1, the official tldr-pages client (tldr client spec v2.3).\ntldr gives you concise, example-first help for ~7,350+ command-line tools \u2014 a\npractical cheat-sheet for almost every CLI an agent uses to build, deploy, and\noperate software. Open source: the tlrc client is MIT; the pages are authored by\nthe tldr-pages community and licensed CC-BY-4.0. Every command below is tested.\n\nUSAGE\n--------------------------------------------------------------------------------\n tldr [OPTIONS] [PAGE]...\n\n PAGE The command to look up, e.g. `tar`, `docker`, `kubectl`.\n Multi-word pages: join with a hyphen -> `git-commit`,\n `docker-compose`, `gh-repo` (or pass the words as separate\n arguments via the passthrough method: [\"git\",\"commit\"]).\n\nOPERATIONS (choose at most one per invocation)\n--------------------------------------------------------------------------------\n Show the tldr page for a command (rendered).\n -u, --update Update the local page cache (downloads only the\n languages that changed). Needs network.\n -l, --list List every page for the current platform (plus\n the cross-platform `common` set) \u2014 a directory of\n all documented tools, one name per line.\n -a, --list-all List every page across ALL platforms.\n -s, --search Search page CONTENTS for a keyword and print each\n match as `language platform page`. First-class\n full-text search across the whole catalog.\n --list-platforms List the available platforms.\n --list-languages List the installed languages.\n -i, --info Show cache info: path, age, installed languages,\n and total page count.\n -r, --render Render a local tldr page file (`.md`) \u2014 preview a\n page you are authoring or one you fetched.\n --clean-cache Interactively delete the cache directory contents.\n --gen-config Print the default config (TOML) to stdout.\n --config-path Print the default config path (creates the dir).\n -v, --version Print the client + spec version.\n -h, --help Print this complete command-palette reference.\n\nMODIFIERS (change how an operation behaves)\n--------------------------------------------------------------------------------\n -p, --platform Force a platform instead of the host's.\n Values: linux, osx (macOS), windows, android,\n sunos, common. Default: the OS you are on.\n -L, --language Force a language (repeatable), e.g. `-L es`,\n `-L fr`, `-L ja`. Default: config, else $LANG.\n --short-options Prefer short option forms in placeholders (-s).\n --long-options Prefer long option forms in placeholders (--long).\n --edit Show a GitHub \"edit this page\" link for the page.\n -o, --offline Never touch the network, even if the cache is\n stale (use the pages already downloaded).\n -c, --compact Strip empty lines from the output.\n --no-compact Keep empty lines (overrides --compact).\n -R, --raw Print the page as raw Markdown (no rendering) \u2014\n the most machine-parseable form.\n --no-raw Render instead of raw (overrides --raw).\n -q, --quiet Suppress status/progress messages and warnings.\n --verbose Print debug info (repeatable).\n --color Color output: auto (default), always, never.\n --config Use an alternative config file path.\n\nPLATFORM VALUES\n--------------------------------------------------------------------------------\n common Cross-platform tools (the largest bucket: git, docker, curl, jq, ...)\n linux Linux-specific pages (systemctl, journalctl, apt, ip, ...)\n osx macOS-specific pages (brew, pbcopy, launchctl, ...)\n windows Windows-specific pages (choco, taskkill, ...)\n android Android tool pages (adb, pm, ...)\n sunos illumos / SunOS pages\n\nCACHE & OFFLINE\n--------------------------------------------------------------------------------\n The page cache auto-downloads on first use (a ~3 MiB archive of ~7,350+ pages)\n and thereafter refreshes automatically when it goes stale. After the first\n fetch, lookups (`get`, `raw`, `search`, `list`, `info`, `render`) are fully\n local and offline. Progress messages are written to stderr, so method output\n on stdout stays clean. Use --offline to pin the current cache and --update to\n refresh on demand. Cache path: `tldr --info`.\n\nEXAMPLES\n--------------------------------------------------------------------------------\n tldr tar # show the tar cheat-sheet\n tldr git-commit # multi-word page (hyphen-joined)\n tldr --raw docker # raw Markdown for docker\n tldr --search compress # find every page mentioning \"compress\"\n tldr --list # directory of all tools for this platform\n tldr --list-all # every page across all platforms\n tldr --platform linux systemctl # force the linux page\n tldr --update # refresh the cache\n tldr --info # cache path / age / page count\n\nLICENSING\n--------------------------------------------------------------------------------\n Client (tlrc): MIT \u2014 https://github.com/tldr-pages/tlrc\n Pages content: CC-BY-4.0, (c) tldr-pages contributors \u2014\n https://github.com/tldr-pages/tldr\n Project home: https://tldr.sh\n\n```\n", + "summary": "This app installs the official tldr-pages client tlrc v1.13.1 on the host and fronts it as typed methods. tldr is \"simplified, community-driven man pages\" \u2014 concise, example-first cheat-sheets for ~7,350+ command-line tools, the practical opposite of a dense man page. Instead of scrolling a manual, an agent asks tldr docker and gets the handful of commands it actually needs, each with a one-line description. The\u2026", "categories": [ "infra" ], @@ -6595,19 +6906,19 @@ }, { "name": "tldr.raw", - "summary": "Return a page as raw Markdown (unrendered) — the most machine-parseable form, ideal for an agent that wants to extract the example commands programmatically. This is `tldr --quiet --raw `.", + "summary": "Return a page as raw Markdown (unrendered) \u2014 the most machine-parseable form, ideal for an agent that wants to extract the example commands programmatically. This is `tldr --quiet --raw `.", "example": "", "gated": "" }, { "name": "tldr.search", - "summary": "Full-text search across the entire tldr catalog for a keyword and return each matching page as `language platform page`. First-class content search — find the right tool when you only know the task (\"compress\", \"screenshot\", \"json\"). This is `tldr --quiet --search `.", + "summary": "Full-text search across the entire tldr catalog for a keyword and return each matching page as `language platform page`. First-class content search \u2014 find the right tool when you only know the task (\"compress\", \"screenshot\", \"json\"). This is `tldr --quiet --search `.", "example": "", "gated": "" }, { "name": "tldr.list", - "summary": "List every documented command for the current platform plus the cross-platform `common` set — a directory of all tools tldr covers, one name per line. Pair with tldr.search to explore the catalog. This is `tldr --quiet --list`. (Use tldr.exec with [\"--list-all\"] for every platform.)", + "summary": "List every documented command for the current platform plus the cross-platform `common` set \u2014 a directory of all tools tldr covers, one name per line. Pair with tldr.search to explore the catalog. This is `tldr --quiet --list`. (Use tldr.exec with [\"--list-all\"] for every platform.)", "example": "", "gated": "" }, @@ -6625,19 +6936,19 @@ }, { "name": "tldr.render", - "summary": "Render a local tldr page file (a `.md` in tldr format) as clean text — preview a page you are authoring or one written elsewhere. This is `tldr --quiet --color never --render `.", + "summary": "Render a local tldr page file (a `.md` in tldr format) as clean text \u2014 preview a page you are authoring or one written elsewhere. This is `tldr --quiet --color never --render `.", "example": "", "gated": "" }, { "name": "tldr.exec", - "summary": "Run the tldr client with a verbatim argv — the full surface beyond the curated methods. Payload is {\"args\":[...]} forwarded straight to `tldr`, plus optional {\"stdin\":\"...\"}. Use it for any flag or combination the curated methods don't cover: `--platform linux systemctl` to force a platform, `--list-all`/`--list-platforms`/`--list-languages`, `-L es` for another language, `--short-options`/`--long-options`, `--edit`, `--offline`, `--gen-config`, or a multi-word page as separate args. Examples: {\"args\":[\"--platform\",\"linux\",\"systemctl\"]}; {\"args\":[\"--list-all\"]}; {\"args\":[\"git\",\"commit\"]}; {\"args\":[\"-L\",\"es\",\"tar\"]}.", + "summary": "Run the tldr client with a verbatim argv \u2014 the full surface beyond the curated methods. Payload is {\"args\":[...]} forwarded straight to `tldr`, plus optional {\"stdin\":\"...\"}. Use it for any flag or combination the curated methods don't cover: `--platform linux systemctl` to force a platform, `--list-all`/`--list-platforms`/`--list-languages`, `-L es` for another language, `--short-options`/`--long-options`, `--edit`, `--offline`, `--gen-config`, or a multi-word page as separate args. Examples: {\"args\":[\"--platform\",\"linux\",\"systemctl\"]}; {\"args\":[\"--list-all\"]}; {\"args\":[\"git\",\"commit\"]}; {\"args\":[\"-L\",\"es\",\"tar\"]}.", "example": "", "gated": "" }, { "name": "tldr.cli_help", - "summary": "Return the complete tldr command-palette reference — every operation and modifier flag, its values and defaults, the platform list, cache/offline behavior, search & directory usage, worked examples, and licensing — as clean, color-free text. The full contract for what tldr.get / tldr.exec accept. This is `tldr --help`.", + "summary": "Return the complete tldr command-palette reference \u2014 every operation and modifier flag, its values and defaults, the platform list, cache/offline behavior, search & directory usage, worked examples, and licensing \u2014 as clean, color-free text. The full contract for what tldr.get / tldr.exec accept. This is `tldr --help`.", "example": "", "gated": "" }, @@ -6702,7 +7013,7 @@ "product_demo": { "skill": "io.pilot.tldr", "title": "Full usage demo", - "when_to_use": "When you need to recall exactly how to invoke a CLI — get a command's example-first cheat-sheet, or find the right tool by task — instead of parsing a man page or web searching.", + "when_to_use": "When you need to recall exactly how to invoke a CLI \u2014 get a command's example-first cheat-sheet, or find the right tool by task \u2014 instead of parsing a man page or web searching.", "metered": false, "quickstart": { "title": "", @@ -6768,4 +7079,4 @@ } ], "fetched_from": "https://appstore-meta.pilotprotocol.network/v1/appstore/metadata" -} +} \ No newline at end of file diff --git a/src/data/apps.ts b/src/data/apps.ts index d47218c4..8fe18a68 100644 --- a/src/data/apps.ts +++ b/src/data/apps.ts @@ -1,10 +1,10 @@ // AUTO-GENERATED by scripts/gen-apps.mjs from the app-store metadata API -// (https://appstore-meta.pilotprotocol.network/v1/appstore/metadata) — the same document the Alpha management console reads. +// (app-metadata.json (offline)) — the same document the Alpha management console reads. // Do not edit by hand, and do not edit the records here: change an app in // pilot-protocol/app-template under appstore-meta/data/apps/ and redeploy. // No ratings or install counts — those are not published by the catalogue. -export interface AppMethod { name: string; summary: string | null; example: string | null; gated: string | null; } +export interface AppMethod { name: string; summary: string | null; example: string | null; gated: string | null; billable: string | null; } export interface AppLimit { label: string; value: string; } export interface AppChangelog { version: string; date?: string | null; notes: string[]; } export interface AppBundle { platform: string; bytes: number | null; } @@ -86,6 +86,324 @@ export const categories: Category[] = [ ]; export const apps: App[] = [ + { + "id": "io.pilot.generallegal", + "name": "General Legal", + "tagline": "Attorney-backed contract review and Delaware company formation — flat-fee legal work from a licensed US law firm", + "description": "General Legal is a Y Combinator-backed law firm. This app puts a licensed\nattorney and a Delaware filing desk behind your agent — contract review and\ncompany formation, in one namespace.\n\n**A General Legal account is required for both halves.** Sign up at\nhttps://portal.general.legal/signup. The two halves then authenticate\ndifferently; both are covered below.\n\n### Contract review — bring your own API key\n\n1. Sign up at https://portal.general.legal/signup\n2. Open the account menu and choose **API keys**\n (https://portal.general.legal/api-keys)\n3. Create a key and copy it — the full value is shown **once**\n4. Import it into the app:\n\n```\nprintf '{\"GENERAL_LEGAL_API_KEY\":\"glk_YOUR_KEY\"}' > ~/.pilot/apps/io.pilot.generallegal/secrets.json\nchmod 600 ~/.pilot/apps/io.pilot.generallegal/secrets.json\npilotctl appstore restart io.pilot.generallegal\n```\n\nThe restart matters: the key is read at startup. Verify with\n`pilotctl appstore call io.pilot.generallegal generallegal.deals_list '{}'`.\nThe key stays on your machine, is never sent to the formation service, and\nscopes you to your own General Legal organization.\n\n### Company formation — nothing to import\n\nFormation needs the same General Legal account but **no key and no secret**\non your side. Call `generallegal.formation_options` and it works. The founder\npays at the link the app returns — use the same email as your account so the\nfiling lands in it.\n\n### What it costs\n\nContract review is flat-fee, with no hourly billing and no minimums. The fee\ncovers every turn through signature, including negotiation with the\ncounterparty.\n\n| Work | Price |\n| --- | --- |\n| Contract, 3 pages or fewer | $250 |\n| Contract, 3-50 pages | $500 |\n| Contract, 50+ pages | $10 per page |\n| Drafting from scratch | $2,000 |\n| Delaware LLC | $190 instant / $210 standard / $260 next-day / $310 same-day |\n| Delaware C-corp | $218 standard / $268 next-day / $318 same-day |\n\n### What the app does\n\n**Company formation** — `formation_options` (free), `formation_start_llc`\n(**paid**), `formation_start_c_corp` (**paid**), `formation_status`,\n`formation_update`, `formation_documents` (free).\n\n**Contract review** — `deal_open` (**paid**), `document_upload` (**paid**),\n`thread_post` (**paid**, covered by the matter's flat fee), plus\n`deals_list`, `deal_get`, `thread_get`, `contracts_list`, `contract_get`,\n`version_download_link` (free) and `upload_begin`, `upload_chunk`,\n`upload_abort` (free — a document is staged in chunks because a single call\ncannot carry a file).\n\n### What costs money\n\nFive methods spend real money and will not warn you first:\n`formation_start_llc`, `formation_start_c_corp`, `deal_open`,\n`document_upload` and `thread_post`. Every other method is free.\n`generallegal.help` lists them under `billable_methods` with the price.", + "categories": [ + "work" + ], + "primaryCategory": "work", + "keywords": [ + "legal", + "contracts", + "attorney", + "review", + "nda", + "redline", + "incorporation", + "delaware", + "llc", + "c-corp" + ], + "version": "0.1.0", + "vendor": "General Legal", + "vendorUrl": "https://general.legal", + "license": "Apache-2.0", + "sourceUrl": "https://github.com/pilot-protocol/generallegal-app", + "homepage": "https://general.legal", + "methods": [ + { + "name": "generallegal.formation_options", + "summary": "Itemised pricing for every Delaware entity type and filing speed. Needs a General Legal account; no key or secret to import.", + "example": null, + "gated": null, + "billable": null + }, + { + "name": "generallegal.formation_start_llc", + "summary": "File a sole-member Delaware LLC and get back a payment link plus a formation_id. Needs a General Legal account; no key or secret to import. 'instant' hands over a pre-formed shelf company; the other speeds file under a name you choose.", + "example": null, + "gated": null, + "billable": "Paid — files a real Delaware LLC. $190 instant / $210 standard / $260 next-day / $310 same-day, paid by the founder at the returned link." + }, + { + "name": "generallegal.formation_start_c_corp", + "summary": "File a Delaware C-corp and get back a payment link plus a formation_id. Needs a General Legal account; no key or secret to import. The founder acts as sole incorporator.", + "example": null, + "gated": null, + "billable": "Paid — files a real Delaware C-corp. $218 standard / $268 next-day / $318 same-day, paid by the founder at the returned link." + }, + { + "name": "generallegal.formation_status", + "summary": "Poll a filing's progress. Needs a General Legal account; no key or secret to import. Repeat after poll_after_seconds while it keeps coming back.", + "example": null, + "gated": null, + "billable": null + }, + { + "name": "generallegal.formation_update", + "summary": "Change the company name before the documents are generated. Needs a General Legal account; no key or secret to import. Late changes are rejected.", + "example": null, + "gated": null, + "billable": null + }, + { + "name": "generallegal.formation_documents", + "summary": "Short-lived links to a completed formation's documents. Needs a General Legal account; no key or secret to import.", + "example": null, + "gated": null, + "billable": null + }, + { + "name": "generallegal.deals_list", + "summary": "List your matters, paginated, with an optional status filter. Free.", + "example": null, + "gated": null, + "billable": null + }, + { + "name": "generallegal.deal_open", + "summary": "Open a matter from a written request. It reaches a real attorney.", + "example": null, + "gated": null, + "billable": "Paid — flat fee per contract: $250 (3 pages or fewer), $500 (3–50 pages), $10/page (50+), $2,000 to draft from scratch. Covers every turn through signature." + }, + { + "name": "generallegal.deal_get", + "summary": "One matter with its documents and released versions. Free.", + "example": null, + "gated": null, + "billable": null + }, + { + "name": "generallegal.thread_get", + "summary": "Read the lawyer-client thread on a matter. Free.", + "example": null, + "gated": null, + "billable": null + }, + { + "name": "generallegal.thread_post", + "summary": "Reply to the attorney on a matter's thread.", + "example": null, + "gated": null, + "billable": "Paid — covered by the matter's flat fee; General Legal does not bill hourly, so a reply adds no separate charge. Free when target is \"ai\"." + }, + { + "name": "generallegal.contracts_list", + "summary": "List your documents. Free.", + "example": null, + "gated": null, + "billable": null + }, + { + "name": "generallegal.contract_get", + "summary": "One document with its released versions; the version ids feed downloads. Free.", + "example": null, + "gated": null, + "billable": null + }, + { + "name": "generallegal.document_upload", + "summary": "Upload a DOCX, PDF, PNG, JPEG or Markdown document for AI + attorney review, up to 20 MiB. Stage the bytes with upload_begin/upload_chunk first.", + "example": null, + "gated": null, + "billable": "Paid — priced per contract by length: $250 (3 pages or fewer), $500 (3–50 pages), $10/page (50+). Flat fee, covering every turn through signature." + }, + { + "name": "generallegal.version_download_link", + "summary": "Issue a short-lived (~15 min) direct download URL for a released version. Free.", + "example": null, + "gated": null, + "billable": null + }, + { + "name": "generallegal.upload_begin", + "summary": "Start a staged upload and get a blob_id. Free — a document cannot cross in one call, so declare it here first.", + "example": null, + "gated": null, + "billable": null + }, + { + "name": "generallegal.upload_chunk", + "summary": "Append the next chunk of a staged upload, at most 512 KiB of raw bytes per call. Free.", + "example": null, + "gated": null, + "billable": null + }, + { + "name": "generallegal.upload_abort", + "summary": "Discard a staged upload and its bytes. Free.", + "example": null, + "gated": null, + "billable": null + }, + { + "name": "generallegal.help", + "summary": "Every method with its parameters, duration class, and which calls cost money. Free, local, no backend call.", + "example": null, + "gated": null, + "billable": null + } + ], + "changelog": [ + { + "version": "0.1.0", + "date": "2026-08-29", + "notes": [ + "Contract review: matters, lawyer thread, document upload and released-version downloads.", + "Delaware company formation: pricing, LLC and C-corp filing, status and documents — no API key required.", + "Bring your own General Legal API key for contract review; it never reaches the formation service." + ] + } + ], + "grants": [ + "fs.read:$APP/config.json", + "fs.read:$APP/secrets.json", + "fs.read:$APP/blobs", + "fs.write:$APP/blobs", + "net.dial:api.general.legal", + "net.dial:incorp-mcp.general.legal", + "audit.log:*" + ], + "bundles": [ + { + "platform": "darwin-arm64", + "bytes": null + }, + { + "platform": "darwin-amd64", + "bytes": null + }, + { + "platform": "linux-arm64", + "bytes": null + }, + { + "platform": "linux-amd64", + "bytes": null + } + ], + "installedBytes": null, + "depends": [], + "protection": "shareable", + "featured": false, + "real": true, + "inCatalogue": true, + "icon": { + "mode": "image", + "img": "/appicons/io.pilot.generallegal.png", + "fit": "cover", + "pos": "center", + "color": "#0e1a2b", + "ink": false, + "file": null, + "hue": 45 + }, + "minPilotVersion": "1.0.0", + "runtimes": [ + "go" + ], + "publishedAt": "2026-08-29", + "updatedAt": "2026-08-29", + "productDemo": { + "skill": "io.pilot.generallegal", + "title": "Full usage demo", + "when_to_use": "When a contract needs a licensed attorney to review, redline or draft it, or when an agent needs its own Delaware company. A General Legal account is required for both.", + "metered": false, + "quickstart": { + "title": null, + "goal": "Price a Delaware company — works on a fresh install, no account, no key", + "command": "pilotctl appstore call io.pilot.generallegal generallegal.formation_options '{\"entity_type\":\"llc\"}'", + "expect": "{\"options\":[{\"filing_speed\":\"instant\",\"total_cents\":19000},{\"filing_speed\":\"standard\",\"total_cents\":21000}]}", + "cost": null, + "note": "Free. Formation needs a General Legal account but no key or secret on your side. Contract review needs an API key imported - see the examples." + }, + "examples": [ + { + "title": "Form a Delaware company — no API key needed", + "goal": "Price it, file it, hand the founder a payment link", + "command": "pilotctl appstore call io.pilot.generallegal generallegal.formation_start_llc '{\"filing_speed\":\"standard\",\"company_name\":\"NewCo LLC\",\"founder\":{\"full_name\":\"Ada Lovelace\",\"email\":\"ada@example.com\"},\"principal_address\":{\"street\":\"1 Main St\",\"city\":\"Dover\",\"state\":\"DE\",\"postal_code\":\"19901\"},\"ai_agent_description\":\"Procurement agent\",\"authority_limits\":\"No commitments above $5,000 without sign-off\",\"contract_threshold\":\"$5,000\"}'", + "expect": "{\"formation_id\":\"f-...\",\"payment_url\":\"https://...\",\"status\":\"awaiting_payment\"}", + "cost": null, + "note": "BILLABLE - files a real company. $190 instant / $210 standard / $260 next-day / $310 same-day, paid by the founder at the returned link. Needs a General Legal account; nothing to import. formation_id is shown once." + }, + { + "title": "Track the filing and collect the paperwork", + "goal": "Poll to completion, then pull the documents", + "command": "pilotctl appstore call io.pilot.generallegal generallegal.formation_status '{\"formation_id\":\"f-...\"}'", + "expect": "{\"status\":\"filed\",\"poll_after_seconds\":30} then {\"status\":\"complete\"}", + "cost": null, + "note": "Free. Repeat only after poll_after_seconds. When complete, generallegal.formation_documents returns short-lived links." + }, + { + "title": "Bring your own key, then confirm it works", + "goal": "Authenticate as your own General Legal organization", + "command": "pilotctl appstore call io.pilot.generallegal generallegal.deals_list '{\"page\":1,\"page_size\":5}'", + "expect": "{\"items\":[...],\"total\":n} once the key is in place; 401 until then", + "cost": null, + "note": "Sign up at https://portal.general.legal/signup, then account menu -> API keys (shown once). Import: printf '{\"GENERAL_LEGAL_API_KEY\":\"glk_YOUR_KEY\"}' > ~/.pilot/apps/io.pilot.generallegal/secrets.json && chmod 600 ~/.pilot/apps/io.pilot.generallegal/secrets.json && pilotctl appstore restart io.pilot.generallegal" + }, + { + "title": "Ask an attorney to review a contract", + "goal": "Open a matter a real lawyer picks up", + "command": "pilotctl appstore call io.pilot.generallegal generallegal.deal_open '{\"initial_request\":\"Please review this mutual NDA. We are the disclosing party; flag anything unusual in the confidentiality term.\",\"deal_name\":\"Acme mutual NDA\"}'", + "expect": "{\"deal_id\":\"d-9f3...\",\"status\":\"open\"}", + "cost": null, + "note": "BILLABLE - flat fee per contract: $250 (<=3 pages), $500 (3-50), $10/page (50+), $2,000 to draft. Covers every turn through signature. Keep the deal_id." + }, + { + "title": "Stage the document, then send it", + "goal": "Push the bytes in chunks (a file cannot cross in one message), then upload", + "command": "pilotctl appstore call io.pilot.generallegal generallegal.upload_begin '{\"file_name\":\"nda.docx\",\"content_type\":\"application/vnd.openxmlformats-officedocument.wordprocessingml.document\",\"total_bytes\":3145728,\"sha256\":\"\"}'", + "expect": "{\"blob_id\":\"a1b2...\",\"max_chunk_bytes\":524288,\"next_seq\":0}", + "cost": null, + "note": "Then generallegal.upload_chunk with seq 0,1,2... and base64 of at most max_chunk_bytes raw bytes. The last returns complete:true. Finally generallegal.document_upload with the blob_id and deal_id (BILLABLE)." + }, + { + "title": "Collect the released redline", + "goal": "Get a downloadable link to counsel's version", + "command": "pilotctl appstore call io.pilot.generallegal generallegal.version_download_link '{\"version_id\":\"v-07...\"}'", + "expect": "{\"file_name\":\"nda-redline.docx\",\"download_url\":\"https://...\",\"download_token_expires_at\":\"...\"}", + "cost": null, + "note": "Free. The URL needs no auth and expires in ~15 minutes - fetch it yourself. Find version ids via generallegal.deal_get or generallegal.contract_get." + } + ], + "cost": null, + "gotchas": [ + "A General Legal account is required for both halves. Sign up at portal.general.legal/signup.", + "Contract review needs an API key imported: account menu -> API keys, write it to $APP/secrets.json, then restart the app - the key is read at startup.", + "Company formation needs no key or secret on your side; the service handles its own authentication. Just call formation_options.", + "Five methods spend money: deal_open and document_upload are flat-fee per contract ($250/$500/$10-per-page/$2,000); formation_start_llc and formation_start_c_corp file a real company ($190-$318); thread_post is covered by the matter's fee.", + "A document cannot ride in one call. Use upload_begin then upload_chunk (<=512 KiB raw each) and pass the blob_id. A blob is single-use and dropped once sent.", + "Matters reach a real attorney and formations file a real company. Neither is a sandbox - confirm before calling a billable method." + ], + "next": [ + "generallegal.formation_options to price a company, or generallegal.deals_list to see the matters your key can reach.", + "generallegal.help lists every method and marks exactly which ones cost money." + ] + }, + "limits": [ + { + "label": "Contract review", + "value": "$250 / $500 / $10 per page — flat fee" + }, + { + "label": "Delaware LLC", + "value": "$190–$310 depending on speed" + }, + { + "label": "Delaware C-corp", + "value": "$218–$318 depending on speed" + }, + { + "label": "New matters", + "value": "25 / day per organization" + } + ] + }, { "id": "io.pilot.dial", "name": "Dial", @@ -116,121 +434,141 @@ export const apps: App[] = [ "name": "dial.status", "summary": "Your account: credit balance, plan, and the limits currently in force (max call duration, max concurrent calls). Free. Call this first to orient.", "example": null, - "gated": null + "gated": null, + "billable": null }, { "name": "dial.usage", "summary": "Activity analytics: message and call counts, voice minutes, per-day series, and busiest numbers. Free.", "example": null, - "gated": null + "gated": null, + "billable": null }, { "name": "dial.signup", "summary": "Start creating a Dial account. Emails a 6-digit code and returns a verificationId; pass both to dial.verify to finish. Only needed if you do not already have an API key.", "example": null, - "gated": null + "gated": null, + "billable": null }, { "name": "dial.verify", "summary": "Finish signup by exchanging the emailed code for an API key. The new account starts with $5 of credit and no card on file.", "example": null, - "gated": null + "gated": null, + "billable": null }, { "name": "dial.list_numbers", "summary": "Your phone numbers, with capabilities, setup status, and per-number inbound configuration. Free.", "example": null, - "gated": null + "gated": null, + "billable": null }, { "name": "dial.buy_number", "summary": "Provision a new US phone number. COSTS $3/month. Requires an explicit consent attestation because it spends money on behalf of the account holder, so confirm with your human first.", "example": null, - "gated": null + "gated": null, + "billable": null }, { "name": "dial.get_number", "summary": "One phone number by id. Free.", "example": null, - "gated": null + "gated": null, + "billable": null }, { "name": "dial.set_number", "summary": "Update a number: nickname, inbound behavior, voice, language, call ceiling, and (iMessage numbers only) the display name and avatar recipients see. Only the fields you send change. Free.", "example": null, - "gated": null + "gated": null, + "billable": null }, { "name": "dial.release_number", "summary": "Release a number. IRREVERSIBLE: the number is gone and the unused month is not refunded. Confirm with your human first.", "example": null, - "gated": null + "gated": null, + "billable": null }, { "name": "dial.send_message", "summary": "Send a text. Delivers over iMessage when the recipient supports it, otherwise SMS, same call either way. COSTS MONEY (US SMS $0.02 per segment). Pass exactly one of fromNumber or fromNumberId.", "example": null, - "gated": null + "gated": null, + "billable": null }, { "name": "dial.list_messages", "summary": "Your messages, inbound and outbound, newest first (up to the 100 most recent). Free. Poll this for replies, or prefer dial.wait_for_event to block until one arrives.", "example": null, - "gated": null + "gated": null, + "billable": null }, { "name": "dial.typing", "summary": "Show or clear a typing indicator before you reply. iMessage numbers display it; SMS numbers ignore it, so it is always safe to call. Sending a message clears it automatically. Free.", "example": null, - "gated": null + "gated": null, + "billable": null }, { "name": "dial.place_call", "summary": "Place an outbound AI voice call. Returns a call id immediately; the call runs in the background. COSTS MONEY per minute. Pass transferTo to have the agent wait out hold queues and IVR menus and hand the live call to a human when a real person answers. Poll dial.get_call, or block on dial.wait_for_event with call.ended.", "example": null, - "gated": null + "gated": null, + "billable": null }, { "name": "dial.get_call", "summary": "One call with its status and transcript once available. THE poll target after dial.place_call. Free.", "example": null, - "gated": null + "gated": null, + "billable": null }, { "name": "dial.list_calls", "summary": "Your calls, newest first (up to the 100 most recent), inbound and outbound. Free.", "example": null, - "gated": null + "gated": null, + "billable": null }, { "name": "dial.end_call", "summary": "Hang up a call that is still in progress. Free.", "example": null, - "gated": null + "gated": null, + "billable": null }, { "name": "dial.wait_for_event", "summary": "Block until a matching event arrives instead of polling. Use it for an inbound reply or a 2FA code (message.received) or a finished call (call.ended, call.transcribed). A 408 means the wait timed out: try again, it is not an error. Free.", "example": null, - "gated": null + "gated": null, + "billable": null }, { "name": "dial.list_context_mcps", "summary": "The MCP servers connected to your voice agent. Secrets and tokens are masked. Free.", "example": null, - "gated": null + "gated": null, + "billable": null }, { "name": "dial.add_context_mcp", "summary": "Connect an MCP server so its tools are available to your AI voice agent DURING calls, to look something up or take an action mid-conversation. Works unattended for servers needing no auth or a static header. An OAuth server instead returns an authorizationUrl and stays pending until a human grants consent in a browser. Free.", "example": null, - "gated": null + "gated": null, + "billable": null }, { "name": "dial.remove_context_mcp", "summary": "Disconnect an MCP server from your voice agent. Its tools stop being offered on future calls. Free.", "example": null, - "gated": null + "gated": null, + "billable": null } ], "changelog": [ @@ -401,115 +739,134 @@ export const apps: App[] = [ "name": "deadsimple.signup", "summary": "START HERE if you have no key. Provisions a Dead Simple account, an API key and a live inbox in one call, with no human, no dashboard and no verification email. Returns {account_id, api_key, inbox}. Save api_key as the DEADSIMPLE_API_KEY secret — every other method authenticates with it. Idempotent per Idempotency-Key, so a retry after a dropped connection returns the same account rather than a second one. The account starts on the trial tier: 1 inbox, 10 sends an hour, 25 a day.", "example": null, - "gated": null + "gated": null, + "billable": null }, { "name": "deadsimple.claim", "summary": "Start lifting the trial caps by attaching an email address a human controls. Sends a 6-digit code to that address; pass it to deadsimple.claim_verify to finish. Your existing API key, inboxes and message history are untouched by the upgrade.", "example": null, - "gated": null + "gated": null, + "billable": null }, { "name": "deadsimple.claim_verify", "summary": "Confirm the code from deadsimple.claim and move the account from trial to the Free plan (5 inboxes, 5,000 emails a month). The same API key keeps working.", "example": null, - "gated": null + "gated": null, + "billable": null }, { "name": "deadsimple.create_inbox", "summary": "Create a real, deliverable email inbox in one call. Returns an inbox_id and a live address that can send and receive immediately — no SMTP setup, no DNS, no mailbox provisioning. Use this when you already have a key and want an additional identity.", "example": null, - "gated": null + "gated": null, + "billable": null }, { "name": "deadsimple.list_inboxes", "summary": "List the inboxes this key can see, newest first. Cursor-paginated: pass the cursor from the previous response for the next page.", "example": null, - "gated": null + "gated": null, + "billable": null }, { "name": "deadsimple.get_inbox", "summary": "Fetch one inbox: its address, display name, tags, status, and counters.", "example": null, - "gated": null + "gated": null, + "billable": null }, { "name": "deadsimple.delete_inbox", "summary": "Permanently delete an inbox and its stored messages. IRREVERSIBLE. Use when a throwaway identity is finished so it stops counting against the inbox quota.", "example": null, - "gated": null + "gated": null, + "billable": null }, { "name": "deadsimple.send_email", "summary": "Send an email from one of your inboxes. Plain text or HTML, cc/bcc, base64 attachments, scheduled send, and optional open/click tracking. Real DKIM-signed egress, not a test harness. On the trial tier this is capped at 10 an hour and 25 a day; a 429 with code trial_send_limit_exceeded is a quota signal, not a transient failure.", "example": null, - "gated": null + "gated": null, + "billable": null }, { "name": "deadsimple.get_verification_code", "summary": "THE method agents reach for. Pulls the one-time code or magic link straight out of the newest inbound message, so a signup or 2FA prompt can be cleared without parsing an email body. Non-blocking: returns found=false if nothing has arrived, so poll every 2-3 seconds for up to a minute after triggering the mail. Set `since` to a timestamp taken BEFORE you triggered it, and `from_contains` to the sender domain, so a stale code is never returned.", "example": null, - "gated": null + "gated": null, + "billable": null }, { "name": "deadsimple.list_messages", "summary": "List messages in an inbox, newest first, with sender, subject, snippet, and labels. Spam is excluded unless include_spam is true. Cursor-paginated.", "example": null, - "gated": null + "gated": null, + "billable": null }, { "name": "deadsimple.get_message", "summary": "Get one message in full: headers, plain-text and HTML bodies, and attachment metadata.", "example": null, - "gated": null + "gated": null, + "billable": null }, { "name": "deadsimple.reply", "summary": "Reply to the sender of a message. Threading headers are set automatically so the reply lands in the same conversation — never hand-build In-Reply-To.", "example": null, - "gated": null + "gated": null, + "billable": null }, { "name": "deadsimple.reply_all", "summary": "Reply to the sender and every other recipient of a message, with threading headers set automatically.", "example": null, - "gated": null + "gated": null, + "billable": null }, { "name": "deadsimple.forward", "summary": "Forward a message, with its attachments, to new recipients.", "example": null, - "gated": null + "gated": null, + "billable": null }, { "name": "deadsimple.list_threads", "summary": "List conversation threads in an inbox, each with its latest message, so an agent can track ongoing exchanges instead of loose messages.", "example": null, - "gated": null + "gated": null, + "billable": null }, { "name": "deadsimple.get_thread", "summary": "Get a full conversation thread with every message in order — the context an agent needs before replying.", "example": null, - "gated": null + "gated": null, + "billable": null }, { "name": "deadsimple.get_attachment", "summary": "Get a time-limited signed download URL for an attachment. The link expires in one hour.", "example": null, - "gated": null + "gated": null, + "billable": null }, { "name": "deadsimple.list_all_messages", "summary": "List messages across every inbox this key can see, newest first. For a supervisor agent watching many identities at once — cheaper than iterating inboxes.", "example": null, - "gated": null + "gated": null, + "billable": null }, { "name": "deadsimple.create_webhook", "summary": "Register an HMAC-SHA256 signed webhook for inbound mail, bounces, and complaints, so long-running work does not have to poll list_messages in a loop. Deliveries retry on exponential backoff and every attempt is logged.", "example": null, - "gated": null + "gated": null, + "billable": null } ], "changelog": [ @@ -650,163 +1007,190 @@ export const apps: App[] = [ "name": "kinetic.method_list", "summary": "List the pricing-research methods available, with each one's server-owned launch price in cents, methodology version, and sample-size guidance. Van Westendorp finds an acceptable price RANGE, Gabor-Granger tests exact price POINTS, MaxDiff ranks feature value, choice-based conjoint models trade-offs. Free, and the right first call when you do not yet know which study to run.", "example": null, - "gated": null + "gated": null, + "billable": null }, { "name": "kinetic.method_recommend", "summary": "Describe the pricing decision in plain language and get back the method that fits it, with reasoning. Free. Use this instead of guessing between Van Westendorp and Gabor-Granger: they answer different questions, and the wrong one produces a confident, useless number.", "example": null, - "gated": null + "gated": null, + "billable": null }, { "name": "kinetic.study_create", "summary": "START HERE once you know the decision. Creates a draft study. You do NOT pick the method: Kinetic derives the methodology from decision_type (first_time and new_tier map to Van Westendorp today) and returns it on the study along with price_cents. Free — a draft costs nothing and is not launched. Returns {id, methodology, status:\"draft\", price_cents}.", "example": null, - "gated": null + "gated": null, + "billable": null }, { "name": "kinetic.study_prefill", "summary": "Generate a draft study filled in from a description of your product and audience, so you edit a sensible starting point rather than an empty form. Free.", "example": null, - "gated": null + "gated": null, + "billable": null }, { "name": "kinetic.study_get", "summary": "Read one study: its configuration, state, and position in the lifecycle. Free.", "example": null, - "gated": null + "gated": null, + "billable": null }, { "name": "kinetic.study_list", "summary": "List your studies with their states. Free.", "example": null, - "gated": null + "gated": null, + "billable": null }, { "name": "kinetic.study_update", "summary": "Edit a draft study: name, prices, features, audience and question configuration. Only the fields you send change. Free, and only valid before launch.", "example": null, - "gated": null + "gated": null, + "billable": null }, { "name": "kinetic.study_duplicate", "summary": "Copy an existing study into a new draft, to run the same design against a different audience or set of prices. Free.", "example": null, - "gated": null + "gated": null, + "billable": null }, { "name": "kinetic.survey_regenerate", "summary": "Regenerate the respondent-facing survey from the study's current configuration after editing it. Free.", "example": null, - "gated": null + "gated": null, + "billable": null }, { "name": "kinetic.survey_preview", "summary": "Read the survey exactly as a respondent will see it, WITHOUT storing any respondent evidence. Free. Always preview before launching: once a study is live the questions are fixed, and a bad question wastes the whole sample.", "example": null, - "gated": null + "gated": null, + "billable": null }, { "name": "kinetic.study_launch", "summary": "Take a draft live so it can collect responses. COSTS MONEY: the launch price comes from kinetic.method_list (currently $149-$199 by method) and must be paid first via kinetic.study_checkout_create. Confirm with your human before calling. Once live the questions are fixed.", "example": null, - "gated": null + "gated": null, + "billable": null }, { "name": "kinetic.respondent_link_get", "summary": "Get the link to send to your customers or prospects. THEY are the respondents: Kinetic supplies no panel, so the quality of the answer depends on who you send this to. Free.", "example": null, - "gated": null + "gated": null, + "billable": null }, { "name": "kinetic.study_progress_get", "summary": "How many responses have arrived against the recommended sample size. Free. Poll after launch; results are only meaningful once you clear the method's recommended minimum.", "example": null, - "gated": null + "gated": null, + "billable": null }, { "name": "kinetic.study_quality_get", "summary": "Response-quality signals: speeders, straight-liners, and other patterns meaning a response should not be trusted. Free. Check this before believing the results.", "example": null, - "gated": null + "gated": null, + "billable": null }, { "name": "kinetic.study_close", "summary": "Stop collecting responses and finalize the study so results can be computed. Free.", "example": null, - "gated": null + "gated": null, + "billable": null }, { "name": "kinetic.results_get", "summary": "The deterministic results: numbers Kinetic's analysis engine computed from the responses, not a model's opinion of them. Free. This is the output you act on.", "example": null, - "gated": null + "gated": null, + "billable": null }, { "name": "kinetic.evidence_get", "summary": "The structured respondent evidence behind the results, so a number can be traced to the answers that produced it. Free.", "example": null, - "gated": null + "gated": null, + "billable": null }, { "name": "kinetic.narrative_generate", "summary": "Generate a written explanation of the results. The narrative is written FROM the deterministic results, so it explains the computed numbers rather than inventing them. Free.", "example": null, - "gated": null + "gated": null, + "billable": null }, { "name": "kinetic.narrative_get", "summary": "Read a previously generated narrative. Free.", "example": null, - "gated": null + "gated": null, + "billable": null }, { "name": "kinetic.results_export_csv", "summary": "Export results and responses as CSV for analysis elsewhere. Free.", "example": null, - "gated": null + "gated": null, + "billable": null }, { "name": "kinetic.offer_list", "summary": "List what is purchasable and what it costs: one-time study prices and Kinetic Pro plans. Free, and the honest place to check a price before committing to a spend.", "example": null, - "gated": null + "gated": null, + "billable": null }, { "name": "kinetic.study_checkout_create", "summary": "Start payment for a draft study. Returns {checkout_url, study_id, amount_cents} and does NOT complete the purchase. A human must open checkout_url and pay on Stripe's hosted page; hand them the link and stop. Once paid, kinetic.study_launch will work. Confirm the amount with your human first.", "example": null, - "gated": null + "gated": null, + "billable": null }, { "name": "kinetic.teardown_create", "summary": "Run a teardown of a public pricing page and get a structured read of how it is constructed. Free.", "example": null, - "gated": null + "gated": null, + "billable": null }, { "name": "kinetic.teardown_get", "summary": "Read a completed teardown. Free.", "example": null, - "gated": null + "gated": null, + "billable": null }, { "name": "kinetic.research_list", "summary": "Browse Kinetic's published pricing research. Free.", "example": null, - "gated": null + "gated": null, + "billable": null }, { "name": "kinetic.research_get", "summary": "Read one published research piece. Free.", "example": null, - "gated": null + "gated": null, + "billable": null }, { "name": "kinetic.task_get", "summary": "Poll a long-running task (prefill, teardown, export) for completion. Free.", "example": null, - "gated": null + "gated": null, + "billable": null } ], "changelog": [ @@ -968,31 +1352,36 @@ export const apps: App[] = [ "name": "rentahuman.create_request", "summary": "START HERE. Ask for a human to do something in the physical world, in plain language. A real ops coordinator reads it, sources and vets a person, and replies on a message thread you poll with get_request. Returns {requestId, status:\"received\", request}. Keep the requestId — every other method hangs off it. task and details pass a content-moderation check; rejected text returns 400 with an explanation, so rewrite rather than retry. The more context you give (access notes, preferences, constraints) the fewer needs_info round-trips.", "example": null, - "gated": null + "gated": null, + "billable": null }, { "name": "rentahuman.get_request", "summary": "Read one request: its current status and the full message thread with the ops coordinator. THIS IS THE POLL TARGET after create_request. Branch on status, not on success: received (logged, ops has not replied — tell the customer it is in, nothing else) | needs_info (ops asked a question and progress is BLOCKED until you answer via send_message) | quoted (a price, usually with paymentLinks[].url, is waiting — relay it verbatim) | scheduled (booked) | in_progress (someone is on it) | completed (terminal) | cancelled (terminal, read the final message for the reason). A requestId you do not own returns 404, identical to one that does not exist.", "example": null, - "gated": null + "gated": null, + "billable": null }, { "name": "rentahuman.send_message", "summary": "Send a follow-up message to the ops coordinator on a request — answer their question, or relay your customer's decision. This is the way out of a needs_info status. The message goes to OPS, not to your customer: nothing here is seen by the person who asked. Max 5,000 characters, moderated.", "example": null, - "gated": null + "gated": null, + "billable": null }, { "name": "rentahuman.list_requests", "summary": "List your requests, newest first, so an agent can see everything in flight at once. Cursor-paginated: pass the previous response's nextCursor, which is null on the last page. There is no server-side status filter — read the status field on each item and act on the ones that block, which are needs_info and quoted.", "example": null, - "gated": null + "gated": null, + "billable": null }, { "name": "rentahuman.list_bounties", "summary": "List open marketplace bounties, each with a tracked referral URL, for agents that want to surface paid real-world work rather than commission it. Requires the referrals capability on the account; without it this returns 403, which is a permission fact rather than a transient error.", "example": null, - "gated": null + "gated": null, + "billable": null } ], "changelog": [ @@ -1133,61 +1522,71 @@ export const apps: App[] = [ "name": "upfile.signup", "summary": "START HERE if this host has no API key. Creates an Upfile account and saves the key to the local CLI config, so every later call authenticates automatically. No browser, no dashboard, no verification step. The account starts on the free tier: 1GB of storage. Everything else fails with No API key until this has been run.", "example": null, - "gated": null + "gated": null, + "billable": null }, { "name": "upfile.upload", "summary": "Upload a file from this host and get back a permanent, immediately-live URL. Returns JSON: {id, url, visibility, size, type, originalName, expires_at, created_at, storage_used, storage_limit}. Read .url. Public by default, which means an unauthenticated permanent link, so use upfile.upload_private or upfile.upload_expiring for anything you would not want to stay reachable.", "example": null, - "gated": null + "gated": null, + "billable": null }, { "name": "upfile.upload_private", "summary": "Upload a file as private, so the returned URL requires authentication rather than being open to anyone holding the link. Same JSON shape as upfile.upload, with visibility private.", "example": null, - "gated": null + "gated": null, + "billable": null }, { "name": "upfile.upload_expiring", "summary": "Upload a file with a time-to-live, so the link stops working on its own. Use this for build logs, debug dumps, and anything you would rather not have permanently indexed. Same JSON shape as upfile.upload, with expires_at set.", "example": null, - "gated": null + "gated": null, + "billable": null }, { "name": "upfile.status", "summary": "Show the account tier and how much of the storage quota is used, e.g. Tier: free Storage: 0.01GB / 1GB. Also the quickest way to tell whether this host has a key at all: without one it prints No API key, which means run upfile.signup first.", "example": null, - "gated": null + "gated": null, + "billable": null }, { "name": "upfile.list", "summary": "List the files stored on this account as JSON, newest first, with each file's id and URL. The ids are what upfile.remove takes.", "example": null, - "gated": null + "gated": null, + "billable": null }, { "name": "upfile.remove", "summary": "Delete one stored file by its id, reclaiming its space against the quota. IRREVERSIBLE: the URL stops resolving immediately.", "example": null, - "gated": null + "gated": null, + "billable": null }, { "name": "upfile.version", "summary": "Print the Upfile CLI version bundled with this app.", "example": null, - "gated": null + "gated": null, + "billable": null }, { "name": "upfile.cli_help", "summary": "The Upfile CLI's own full help text, listing every subcommand and flag including any not curated as a named method here.", "example": null, - "gated": null + "gated": null, + "billable": null }, { "name": "upfile.run", "summary": "Escape hatch: run the Upfile CLI with an arbitrary argv array, for anything the named methods do not cover such as config set/get, upgrade, or stdin uploads. Payload is {args:[...]}. Prefer the named methods when one fits, because they return JSON.", "example": null, - "gated": null + "gated": null, + "billable": null } ], "changelog": [ @@ -1329,661 +1728,771 @@ export const apps: App[] = [ "name": "primitive.signup", "summary": "Provision your own Primitive account and a managed *.primitive.email inbox in ONE call — no email, no code, no human step", "example": "{}", - "gated": null + "gated": null, + "billable": null }, { "name": "primitive.get_account", "summary": "Get account info", "example": "{}", - "gated": null + "gated": null, + "billable": null }, { "name": "primitive.update_account", "summary": "Update account settings", "example": "{\"spam_threshold\": 10, \"discard_content_on_webhook_confirmed\": true}", - "gated": null + "gated": null, + "billable": null }, { "name": "primitive.get_storage_stats", "summary": "Get storage usage", "example": "{}", - "gated": null + "gated": null, + "billable": null }, { "name": "primitive.get_webhook_secret", "summary": "Get webhook signing secret", "example": "{}", - "gated": null + "gated": null, + "billable": null }, { "name": "primitive.rotate_webhook_secret", "summary": "Rotate webhook signing secret", "example": "{}", - "gated": null + "gated": null, + "billable": null }, { "name": "primitive.list_domains", "summary": "List all domains", "example": "{}", - "gated": null + "gated": null, + "billable": null }, { "name": "primitive.add_domain", "summary": "Claim a new domain", "example": "{\"domain\": \"\", \"confirmed\": true, \"outbound\": true}", - "gated": "requires a custom domain whose DNS you control — the managed *.primitive.email inbox needs no domain setup" + "gated": "requires a custom domain whose DNS you control — the managed *.primitive.email inbox needs no domain setup", + "billable": null }, { "name": "primitive.update_domain", "summary": "Update domain settings", "example": "{\"id\": \"\", \"is_active\": true, \"spam_threshold\": 10}", - "gated": null + "gated": null, + "billable": null }, { "name": "primitive.delete_domain", "summary": "Delete a domain", "example": "{\"id\": \"\"}", - "gated": null + "gated": null, + "billable": null }, { "name": "primitive.verify_domain", "summary": "Verify domain ownership", "example": "{\"id\": \"\"}", - "gated": "requires a custom domain whose DNS you control" + "gated": "requires a custom domain whose DNS you control", + "billable": null }, { "name": "primitive.download_domain_zone_file", "summary": "Download domain DNS zone file", "example": "{\"id\": \"\", \"outbound_only\": true}", - "gated": "requires a custom domain whose DNS you control" + "gated": "requires a custom domain whose DNS you control", + "billable": null }, { "name": "primitive.get_inbox_status", "summary": "Get inbound inbox readiness", "example": "{}", - "gated": null + "gated": null, + "billable": null }, { "name": "primitive.list_emails", "summary": "List inbound emails", "example": "{\"cursor\": \"\", \"limit\": 20, \"domain_id\": \"\", \"status\": \"\", \"search\": \"search terms\", \"date_from\": \"\", \"date_to\": \"\"}", - "gated": null + "gated": null, + "billable": null }, { "name": "primitive.search_emails", "summary": "Search inbound emails", "example": "{\"q\": \"search terms\", \"from\": \"you@your-inbox.primitive.email\", \"to\": \"someone@example.com\", \"subject\": \"Subject line\", \"body\": \"\", \"domain_id\": \"\", \"reply_to_sent_email_id\": \"\"}", - "gated": null + "gated": null, + "billable": null }, { "name": "primitive.get_email", "summary": "Get inbound email by id", "example": "{\"id\": \"\"}", - "gated": null + "gated": null, + "billable": null }, { "name": "primitive.delete_email", "summary": "Delete an email", "example": "{\"id\": \"\"}", - "gated": null + "gated": null, + "billable": null }, { "name": "primitive.download_raw_email", "summary": "Download raw email", "example": "{\"id\": \"\", \"token\": \"\"}", - "gated": null + "gated": null, + "billable": null }, { "name": "primitive.download_attachments", "summary": "Download email attachments", "example": "{\"id\": \"\", \"token\": \"\"}", - "gated": null + "gated": null, + "billable": null }, { "name": "primitive.reply_to_email", "summary": "Reply to an inbound email", "example": "{\"id\": \"\", \"body_text\": \"Plain-text body\", \"body_html\": \"

HTML body

\", \"from\": \"you@your-inbox.primitive.email\", \"wait\": 30, \"attachments\": [\"...\"]}", - "gated": null + "gated": null, + "billable": null }, { "name": "primitive.replay_email_webhooks", "summary": "Replay email webhooks", "example": "{\"id\": \"\"}", - "gated": null + "gated": null, + "billable": null }, { "name": "primitive.discard_email_content", "summary": "Discard email content", "example": "{\"id\": \"\"}", - "gated": null + "gated": null, + "billable": null }, { "name": "primitive.get_conversation", "summary": "Get the conversation an email belongs to", "example": "{\"id\": \"\"}", - "gated": null + "gated": null, + "billable": null }, { "name": "primitive.list_endpoints", "summary": "List webhook endpoints", "example": "{}", - "gated": null + "gated": null, + "billable": null }, { "name": "primitive.create_endpoint", "summary": "Create a webhook endpoint", "example": "{\"kind\": \"http\", \"url\": \"https://example.com/webhook\", \"function_id\": \"\", \"enabled\": true, \"domain_id\": \"\", \"rules\": {\"...\": \"...\"}, \"is_route_target\": true}", - "gated": null + "gated": null, + "billable": null }, { "name": "primitive.update_endpoint", "summary": "Update a webhook endpoint", "example": "{\"id\": \"\", \"url\": \"https://example.com/webhook\", \"enabled\": true, \"domain_id\": \"\", \"rules\": {\"...\": \"...\"}}", - "gated": null + "gated": null, + "billable": null }, { "name": "primitive.delete_endpoint", "summary": "Delete a webhook endpoint", "example": "{\"id\": \"\"}", - "gated": null + "gated": null, + "billable": null }, { "name": "primitive.test_endpoint", "summary": "Send a test webhook", "example": "{\"id\": \"\"}", - "gated": null + "gated": null, + "billable": null }, { "name": "primitive.list_filters", "summary": "List filter rules", "example": "{}", - "gated": null + "gated": null, + "billable": null }, { "name": "primitive.create_filter", "summary": "Create a filter rule", "example": "{\"type\": \"whitelist\", \"pattern\": \"*@example.com\", \"domain_id\": \"\"}", - "gated": null + "gated": null, + "billable": null }, { "name": "primitive.update_filter", "summary": "Update a filter rule", "example": "{\"id\": \"\", \"enabled\": true}", - "gated": null + "gated": null, + "billable": null }, { "name": "primitive.delete_filter", "summary": "Delete a filter rule", "example": "{\"id\": \"\"}", - "gated": null + "gated": null, + "billable": null }, { "name": "primitive.list_wake_schedules", "summary": "List wake schedules", "example": "{}", - "gated": "requires a plan/entitlement upgrade — Wake scheduling is not on the free agent plan" + "gated": "requires a plan/entitlement upgrade — Wake scheduling is not on the free agent plan", + "billable": null }, { "name": "primitive.create_wake_schedule", "summary": "Create a wake schedule", "example": "{\"from_address\": \"\", \"target_address\": \"\", \"command\": \"\", \"cron_expr\": \"\", \"args\": {\"...\": \"...\"}, \"timezone\": \"\", \"note\": \"\"}", - "gated": "requires a plan/entitlement upgrade — Wake scheduling is not on the free agent plan" + "gated": "requires a plan/entitlement upgrade — Wake scheduling is not on the free agent plan", + "billable": null }, { "name": "primitive.get_wake_schedule", "summary": "Get a wake schedule", "example": "{\"id\": \"\"}", - "gated": "requires a plan/entitlement upgrade — Wake scheduling is not on the free agent plan" + "gated": "requires a plan/entitlement upgrade — Wake scheduling is not on the free agent plan", + "billable": null }, { "name": "primitive.update_wake_schedule", "summary": "Update a wake schedule", "example": "{\"id\": \"\", \"enabled\": true, \"command\": \"\", \"args\": {\"...\": \"...\"}, \"cron_expr\": \"\", \"timezone\": \"\", \"from_address\": \"\"}", - "gated": "requires a plan/entitlement upgrade — Wake scheduling is not on the free agent plan" + "gated": "requires a plan/entitlement upgrade — Wake scheduling is not on the free agent plan", + "billable": null }, { "name": "primitive.delete_wake_schedule", "summary": "Delete a wake schedule", "example": "{\"id\": \"\"}", - "gated": "requires a plan/entitlement upgrade — Wake scheduling is not on the free agent plan" + "gated": "requires a plan/entitlement upgrade — Wake scheduling is not on the free agent plan", + "billable": null }, { "name": "primitive.run_wake_schedule", "summary": "Run a wake schedule now", "example": "{\"id\": \"\"}", - "gated": "requires a plan/entitlement upgrade — Wake scheduling is not on the free agent plan" + "gated": "requires a plan/entitlement upgrade — Wake scheduling is not on the free agent plan", + "billable": null }, { "name": "primitive.list_wake_authorizations", "summary": "List wake authorizations", "example": "{\"recipient_endpoint_id\": \"\"}", - "gated": "requires a plan/entitlement upgrade — Wake scheduling is not on the free agent plan" + "gated": "requires a plan/entitlement upgrade — Wake scheduling is not on the free agent plan", + "billable": null }, { "name": "primitive.create_wake_authorization", "summary": "Create a wake authorization", "example": "{\"recipient_endpoint_id\": \"\", \"allowed_sender_domain\": \"\", \"allowed_sender_address\": \"\", \"allowed_commands\": [\"...\"], \"note\": \"\"}", - "gated": "requires a plan/entitlement upgrade — Wake scheduling is not on the free agent plan" + "gated": "requires a plan/entitlement upgrade — Wake scheduling is not on the free agent plan", + "billable": null }, { "name": "primitive.update_wake_authorization", "summary": "Update a wake authorization", "example": "{\"id\": \"\", \"enabled\": true}", - "gated": "requires a plan/entitlement upgrade — Wake scheduling is not on the free agent plan" + "gated": "requires a plan/entitlement upgrade — Wake scheduling is not on the free agent plan", + "billable": null }, { "name": "primitive.delete_wake_authorization", "summary": "Delete a wake authorization", "example": "{\"id\": \"\"}", - "gated": "requires a plan/entitlement upgrade — Wake scheduling is not on the free agent plan" + "gated": "requires a plan/entitlement upgrade — Wake scheduling is not on the free agent plan", + "billable": null }, { "name": "primitive.list_wake_dispatches", "summary": "List recent wake dispatches", "example": "{\"limit\": 20}", - "gated": "requires a plan/entitlement upgrade — Wake scheduling is not on the free agent plan" + "gated": "requires a plan/entitlement upgrade — Wake scheduling is not on the free agent plan", + "billable": null }, { "name": "primitive.list_routes", "summary": "List recipient routes", "example": "{}", - "gated": "requires the recipient-routing feature — disabled on the free agent plan (the managed inbox routes to storage automatically)" + "gated": "requires the recipient-routing feature — disabled on the free agent plan (the managed inbox routes to storage automatically)", + "billable": null }, { "name": "primitive.create_route", "summary": "Create a recipient route", "example": "{\"match_type\": \"to\", \"pattern\": \"*@example.com\", \"endpoint_id\": \"\", \"function_id\": \"\", \"domain_id\": \"\", \"priority\": 0, \"enabled\": true}", - "gated": "requires the recipient-routing feature — disabled on the free agent plan (the managed inbox routes to storage automatically)" + "gated": "requires the recipient-routing feature — disabled on the free agent plan (the managed inbox routes to storage automatically)", + "billable": null }, { "name": "primitive.reorder_routes", "summary": "Reorder recipient routes", "example": "{\"updates\": [\"...\"]}", - "gated": "requires the recipient-routing feature — disabled on the free agent plan (the managed inbox routes to storage automatically)" + "gated": "requires the recipient-routing feature — disabled on the free agent plan (the managed inbox routes to storage automatically)", + "billable": null }, { "name": "primitive.simulate_route", "summary": "Simulate routing for a recipient", "example": "{\"recipient\": \"someone@example.com\", \"event_type\": \"\"}", - "gated": "requires the recipient-routing feature — disabled on the free agent plan (the managed inbox routes to storage automatically)" + "gated": "requires the recipient-routing feature — disabled on the free agent plan (the managed inbox routes to storage automatically)", + "billable": null }, { "name": "primitive.update_route", "summary": "Update a recipient route", "example": "{\"id\": \"\", \"match_type\": \"to\", \"pattern\": \"*@example.com\", \"endpoint_id\": \"\", \"domain_id\": \"\", \"priority\": 0, \"enabled\": true}", - "gated": "requires the recipient-routing feature — disabled on the free agent plan (the managed inbox routes to storage automatically)" + "gated": "requires the recipient-routing feature — disabled on the free agent plan (the managed inbox routes to storage automatically)", + "billable": null }, { "name": "primitive.delete_route", "summary": "Delete a recipient route", "example": "{\"id\": \"\"}", - "gated": "requires the recipient-routing feature — disabled on the free agent plan (the managed inbox routes to storage automatically)" + "gated": "requires the recipient-routing feature — disabled on the free agent plan (the managed inbox routes to storage automatically)", + "billable": null }, { "name": "primitive.list_deliveries", "summary": "List webhook deliveries", "example": "{\"cursor\": \"\", \"limit\": 20, \"email_id\": \"\", \"status\": \"\", \"date_from\": \"\", \"date_to\": \"\"}", - "gated": null + "gated": null, + "billable": null }, { "name": "primitive.replay_delivery", "summary": "Replay a webhook delivery", "example": "{\"id\": \"\"}", - "gated": null + "gated": null, + "billable": null }, { "name": "primitive.get_send_permissions", "summary": "List send-permission rules", "example": "{}", - "gated": null + "gated": null, + "billable": null }, { "name": "primitive.send_email", "summary": "Send outbound email", "example": "{\"from\": \"you@your-inbox.primitive.email\", \"to\": \"someone@example.com\", \"subject\": \"Subject line\", \"body_text\": \"Plain-text body\", \"body_html\": \"

HTML body

\", \"in_reply_to\": \"\", \"references\": [\"...\"]}", - "gated": null + "gated": null, + "billable": null }, { "name": "primitive.semantic_search", "summary": "Semantic search across received and sent mail", "example": "{\"query\": \"search terms\", \"mode\": \"\", \"corpus\": [\"...\"], \"search_in\": [\"...\"], \"exclude\": [\"...\"], \"date_from\": \"\", \"date_to\": \"\"}", - "gated": "requires the Pro plan — semantic search over mail is not on the free agent plan" + "gated": "requires the Pro plan — semantic search over mail is not on the free agent plan", + "billable": null }, { "name": "primitive.list_sent_emails", "summary": "List outbound sent emails", "example": "{\"cursor\": \"\", \"limit\": 20, \"status\": \"\", \"request_id\": \"\", \"idempotency_key\": \"\", \"date_from\": \"\", \"date_to\": \"\"}", - "gated": null + "gated": null, + "billable": null }, { "name": "primitive.get_sent_email", "summary": "Get a sent email by id", "example": "{\"id\": \"\"}", - "gated": null + "gated": null, + "billable": null }, { "name": "primitive.get_thread", "summary": "Get a conversation thread by id", "example": "{\"id\": \"\"}", - "gated": null + "gated": null, + "billable": null }, { "name": "primitive.list_functions", "summary": "List functions", "example": "{}", - "gated": "requires the developer plan — confirm an email at primitive.dev to upgrade; hosted Functions are not on the free agent plan" + "gated": "requires the developer plan — confirm an email at primitive.dev to upgrade; hosted Functions are not on the free agent plan", + "billable": null }, { "name": "primitive.create_function", "summary": "Deploy a function", "example": "{\"name\": \"\", \"code\": \"\", \"sourceMap\": \"\", \"files\": {\"...\": \"...\"}}", - "gated": "requires the developer plan — confirm an email at primitive.dev to upgrade; hosted Functions are not on the free agent plan" + "gated": "requires the developer plan — confirm an email at primitive.dev to upgrade; hosted Functions are not on the free agent plan", + "billable": null }, { "name": "primitive.get_function", "summary": "Get a function", "example": "{\"id\": \"\"}", - "gated": "requires the developer plan — confirm an email at primitive.dev to upgrade; hosted Functions are not on the free agent plan" + "gated": "requires the developer plan — confirm an email at primitive.dev to upgrade; hosted Functions are not on the free agent plan", + "billable": null }, { "name": "primitive.update_function", "summary": "Update and redeploy a function", "example": "{\"id\": \"\", \"code\": \"\", \"sourceMap\": \"\", \"files\": {\"...\": \"...\"}}", - "gated": "requires the developer plan — confirm an email at primitive.dev to upgrade; hosted Functions are not on the free agent plan" + "gated": "requires the developer plan — confirm an email at primitive.dev to upgrade; hosted Functions are not on the free agent plan", + "billable": null }, { "name": "primitive.delete_function", "summary": "Delete a function", "example": "{\"id\": \"\"}", - "gated": "requires the developer plan — confirm an email at primitive.dev to upgrade; hosted Functions are not on the free agent plan" + "gated": "requires the developer plan — confirm an email at primitive.dev to upgrade; hosted Functions are not on the free agent plan", + "billable": null }, { "name": "primitive.test_function", "summary": "Send a test invocation", "example": "{\"id\": \"\", \"local_part\": \"\"}", - "gated": "requires the developer plan — confirm an email at primitive.dev to upgrade; hosted Functions are not on the free agent plan" + "gated": "requires the developer plan — confirm an email at primitive.dev to upgrade; hosted Functions are not on the free agent plan", + "billable": null }, { "name": "primitive.get_function_test_run_trace", "summary": "Get a function test run trace", "example": "{\"id\": \"\", \"run_id\": \"\"}", - "gated": "requires the developer plan — confirm an email at primitive.dev to upgrade; hosted Functions are not on the free agent plan" + "gated": "requires the developer plan — confirm an email at primitive.dev to upgrade; hosted Functions are not on the free agent plan", + "billable": null }, { "name": "primitive.get_org_routing_topology", "summary": "Get the org's function routing topology", "example": "{}", - "gated": "requires the developer plan — confirm an email at primitive.dev to upgrade; hosted Functions are not on the free agent plan" + "gated": "requires the developer plan — confirm an email at primitive.dev to upgrade; hosted Functions are not on the free agent plan", + "billable": null }, { "name": "primitive.get_function_routing", "summary": "Get a function's current route binding", "example": "{\"id\": \"\"}", - "gated": "requires the developer plan — confirm an email at primitive.dev to upgrade; hosted Functions are not on the free agent plan" + "gated": "requires the developer plan — confirm an email at primitive.dev to upgrade; hosted Functions are not on the free agent plan", + "billable": null }, { "name": "primitive.set_function_route", "summary": "Bind a route to a function", "example": "{\"id\": \"\", \"target\": {\"...\": \"...\"}, \"takeover\": true}", - "gated": "requires the developer plan — confirm an email at primitive.dev to upgrade; hosted Functions are not on the free agent plan" + "gated": "requires the developer plan — confirm an email at primitive.dev to upgrade; hosted Functions are not on the free agent plan", + "billable": null }, { "name": "primitive.unset_function_route", "summary": "Unbind any route from a function", "example": "{\"id\": \"\"}", - "gated": "requires the developer plan — confirm an email at primitive.dev to upgrade; hosted Functions are not on the free agent plan" + "gated": "requires the developer plan — confirm an email at primitive.dev to upgrade; hosted Functions are not on the free agent plan", + "billable": null }, { "name": "primitive.list_function_secrets", "summary": "List a function's secrets", "example": "{\"id\": \"\"}", - "gated": "requires the developer plan — confirm an email at primitive.dev to upgrade; hosted Functions are not on the free agent plan" + "gated": "requires the developer plan — confirm an email at primitive.dev to upgrade; hosted Functions are not on the free agent plan", + "billable": null }, { "name": "primitive.create_function_secret", "summary": "Create or update a secret", "example": "{\"id\": \"\", \"key\": \"namespace/key\", \"value\": {\"any\": \"json\"}}", - "gated": "requires the developer plan — confirm an email at primitive.dev to upgrade; hosted Functions are not on the free agent plan" + "gated": "requires the developer plan — confirm an email at primitive.dev to upgrade; hosted Functions are not on the free agent plan", + "billable": null }, { "name": "primitive.set_function_secret", "summary": "Set a secret by key", "example": "{\"id\": \"\", \"key\": \"namespace/key\", \"value\": {\"any\": \"json\"}}", - "gated": "requires the developer plan — confirm an email at primitive.dev to upgrade; hosted Functions are not on the free agent plan" + "gated": "requires the developer plan — confirm an email at primitive.dev to upgrade; hosted Functions are not on the free agent plan", + "billable": null }, { "name": "primitive.delete_function_secret", "summary": "Delete a secret", "example": "{\"id\": \"\", \"key\": \"namespace/key\"}", - "gated": "requires the developer plan — confirm an email at primitive.dev to upgrade; hosted Functions are not on the free agent plan" + "gated": "requires the developer plan — confirm an email at primitive.dev to upgrade; hosted Functions are not on the free agent plan", + "billable": null }, { "name": "primitive.list_org_secrets", "summary": "List org-level (global) secrets", "example": "{}", - "gated": "requires the developer plan — confirm an email at primitive.dev to upgrade; hosted Functions are not on the free agent plan" + "gated": "requires the developer plan — confirm an email at primitive.dev to upgrade; hosted Functions are not on the free agent plan", + "billable": null }, { "name": "primitive.create_org_secret", "summary": "Create or update an org secret", "example": "{\"key\": \"namespace/key\", \"value\": {\"any\": \"json\"}}", - "gated": "requires the developer plan — confirm an email at primitive.dev to upgrade; hosted Functions are not on the free agent plan" + "gated": "requires the developer plan — confirm an email at primitive.dev to upgrade; hosted Functions are not on the free agent plan", + "billable": null }, { "name": "primitive.set_org_secret", "summary": "Set an org secret by key", "example": "{\"key\": \"namespace/key\", \"value\": {\"any\": \"json\"}}", - "gated": "requires the developer plan — confirm an email at primitive.dev to upgrade; hosted Functions are not on the free agent plan" + "gated": "requires the developer plan — confirm an email at primitive.dev to upgrade; hosted Functions are not on the free agent plan", + "billable": null }, { "name": "primitive.delete_org_secret", "summary": "Delete an org secret", "example": "{\"key\": \"namespace/key\"}", - "gated": "requires the developer plan — confirm an email at primitive.dev to upgrade; hosted Functions are not on the free agent plan" + "gated": "requires the developer plan — confirm an email at primitive.dev to upgrade; hosted Functions are not on the free agent plan", + "billable": null }, { "name": "primitive.list_function_logs", "summary": "List a function's execution logs", "example": "{\"id\": \"\", \"limit\": 20, \"cursor\": \"\"}", - "gated": "requires the developer plan — confirm an email at primitive.dev to upgrade; hosted Functions are not on the free agent plan" + "gated": "requires the developer plan — confirm an email at primitive.dev to upgrade; hosted Functions are not on the free agent plan", + "billable": null }, { "name": "primitive.set_memory", "summary": "Set a memory", "example": "{\"key\": \"namespace/key\", \"value\": {\"any\": \"json\"}, \"scope\": {\"...\": \"...\"}, \"ttl_seconds\": 10, \"expires_at\": \"\", \"clear_ttl\": true, \"if_absent\": true}", - "gated": null + "gated": null, + "billable": null }, { "name": "primitive.get_memory", "summary": "Get a memory", "example": "{\"key\": \"namespace/key\", \"scope_type\": \"\", \"scope_id\": \"\"}", - "gated": null + "gated": null, + "billable": null }, { "name": "primitive.delete_memory", "summary": "Delete a memory", "example": "{\"key\": \"namespace/key\", \"scope_type\": \"\", \"scope_id\": \"\", \"if_version\": \"\"}", - "gated": null + "gated": null, + "billable": null }, { "name": "primitive.search_memories", "summary": "Search memories", "example": "{\"prefix\": \"search terms\", \"cursor\": \"\", \"limit\": 20, \"include_value\": \"\", \"updated_after\": \"\", \"updated_before\": \"\", \"scope_type\": \"\"}", - "gated": null + "gated": null, + "billable": null }, { "name": "primitive.register_payout_address", "summary": "Register a payout address", "example": "{\"address\": \"someone@example.com\", \"network\": \"\", \"signature\": \"\", \"issued_at\": \"\", \"label\": \"