AlbyCliSkill.tsx raw
1 import { BotIcon, CopyIcon, ShieldCheckIcon, WalletIcon } from "lucide-react";
2 import React from "react";
3 import { toast } from "sonner";
4 import { AppDetailConnectedApps } from "src/components/connections/AppDetailConnectedApps";
5 import { AppStoreDetailHeader } from "src/components/connections/AppStoreDetailHeader";
6 import { appStoreApps } from "src/components/connections/SuggestedAppData";
7 import {
8 Accordion,
9 AccordionContent,
10 AccordionItem,
11 AccordionTrigger,
12 } from "src/components/ui/accordion";
13 import { Button } from "src/components/ui/button";
14 import {
15 Card,
16 CardContent,
17 CardHeader,
18 CardTitle,
19 } from "src/components/ui/card";
20 import { LoadingButton } from "src/components/ui/custom/loading-button";
21 import {
22 DEFAULT_APP_BUDGET_RENEWAL,
23 DEFAULT_APP_BUDGET_SATS,
24 } from "src/constants";
25 import { copyToClipboard } from "src/lib/clipboard";
26 import { createApp } from "src/requests/createApp";
27 import { handleRequestError } from "src/utils/handleRequestError";
28
29 const skillInstallCommand = "npx skills add getAlby/payments-skill";
30 const skillInstallPrompt =
31 "Run `npx -y skills add getAlby/payments-skill -y` to install the Alby bitcoin payments skill";
32 const verifyPrompt = "What's your wallet balance?";
33
34 export function AlbyCliSkill() {
35 const [isLoading, setLoading] = React.useState(false);
36 const [connectionSecret, setConnectionSecret] = React.useState("");
37
38 const appStoreApp = appStoreApps.find((app) => app.id === "alby-cli-skill");
39 if (!appStoreApp) {
40 return null;
41 }
42
43 const handleSubmit = async (event: React.FormEvent<HTMLFormElement>) => {
44 event.preventDefault();
45 setLoading(true);
46
47 try {
48 const createAppResponse = await createApp({
49 name: appStoreApp.title,
50 scopes: [
51 "get_info",
52 "get_balance",
53 "list_transactions",
54 "lookup_invoice",
55 "make_invoice",
56 "notifications",
57 "pay_invoice",
58 "sign_message",
59 ],
60 maxAmountSat: DEFAULT_APP_BUDGET_SATS,
61 budgetRenewal: DEFAULT_APP_BUDGET_RENEWAL,
62 metadata: {
63 app_store_app_id: "alby-cli-skill",
64 },
65 });
66
67 setConnectionSecret(createAppResponse.pairingUri);
68 toast("Alby CLI Skill connection created");
69 } catch (error) {
70 handleRequestError("Failed to create connection", error);
71 } finally {
72 setLoading(false);
73 }
74 };
75
76 return (
77 <div className="grid gap-5">
78 <AppStoreDetailHeader appStoreApp={appStoreApp} contentRight={null} />
79
80 {connectionSecret ? (
81 <div className="max-w-3xl flex flex-col gap-5">
82 <p className="text-muted-foreground">
83 Follow these steps to install and use Alby CLI Skill with your AI
84 agent.
85 </p>
86
87 <Accordion type="single" collapsible>
88 <AccordionItem value="install">
89 <AccordionTrigger>
90 Install with one command (Claude Code, Goose etc)
91 </AccordionTrigger>
92 <AccordionContent>
93 <ul className="list-decimal list-inside space-y-2 text-muted-foreground">
94 <li>
95 Install the Alby CLI skill:
96 <div className="my-4 flex items-center gap-4">
97 <div className="font-mono text-foreground text-sm break-all bg-muted p-2 rounded">
98 {skillInstallCommand}
99 </div>
100 <Button
101 size="sm"
102 onClick={() => copyToClipboard(skillInstallCommand)}
103 >
104 <CopyIcon />
105 Copy Command
106 </Button>
107 </div>
108 </li>
109 <li>
110 Save your wallet connection secret at
111 <code className="ml-1 text-foreground">
112 ~/.alby-cli/connection-secret.key
113 </code>
114 .
115 </li>
116 </ul>
117
118 <div className="mt-4 flex flex-col gap-2">
119 <div className="text-sm text-muted-foreground">
120 Connection secret
121 </div>
122 <div className="flex items-center gap-2">
123 <Button
124 size="sm"
125 onClick={() => copyToClipboard(connectionSecret)}
126 >
127 <CopyIcon />
128 Copy Connection secret
129 </Button>
130 </div>
131 </div>
132 </AccordionContent>
133 </AccordionItem>
134
135 <AccordionItem value="openclaw">
136 <AccordionTrigger>OpenClaw setup</AccordionTrigger>
137 <AccordionContent>
138 <ul className="list-decimal list-inside space-y-2 text-muted-foreground">
139 <li>
140 Tell your agent to install this skill as a custom skill:
141 <div className="my-4 flex items-center gap-4">
142 <div className="font-mono text-foreground text-sm break-all bg-muted p-2 rounded">
143 {skillInstallPrompt}
144 </div>
145 <Button
146 size="sm"
147 onClick={() => copyToClipboard(skillInstallPrompt)}
148 >
149 <CopyIcon />
150 Copy Prompt
151 </Button>
152 </div>
153 </li>
154 <li>
155 Save your wallet connection secret at
156 <code className="ml-1 text-foreground">
157 ~/.alby-cli/connection-secret.key
158 </code>
159 .
160 </li>
161 </ul>
162
163 <div className="mt-4 flex flex-col gap-2">
164 <div className="text-sm text-muted-foreground">
165 Connection secret
166 </div>
167 <div className="flex items-center gap-2">
168 <Button
169 size="sm"
170 onClick={() => copyToClipboard(connectionSecret)}
171 >
172 <CopyIcon />
173 Copy Connection secret
174 </Button>
175 </div>
176 </div>
177 </AccordionContent>
178 </AccordionItem>
179
180 <AccordionItem value="verify">
181 <AccordionTrigger>Verify it works</AccordionTrigger>
182 <AccordionContent>
183 <p className="text-muted-foreground">
184 Ask your agent this question:
185 </p>
186 <div className="mt-2 flex items-center gap-2">
187 <div className="font-mono text-foreground text-sm break-all bg-muted p-2 rounded">
188 {verifyPrompt}
189 </div>
190 <Button
191 size="sm"
192 onClick={() => copyToClipboard(verifyPrompt)}
193 >
194 <CopyIcon />
195 Copy prompt
196 </Button>
197 </div>
198 </AccordionContent>
199 </AccordionItem>
200 </Accordion>
201 </div>
202 ) : (
203 <>
204 <Card className="max-w-lg">
205 <CardHeader>
206 <CardTitle className="text-2xl">About the App</CardTitle>
207 </CardHeader>
208 <CardContent className="flex flex-col gap-5">
209 <p className="text-muted-foreground">
210 Alby CLI Skill is built for AI agents that need to use Alby CLI
211 more effectively. It connects your Alby Hub to skill-enabled
212 agents so they can use Bitcoin payments inside autonomous
213 workflows.
214 </p>
215
216 <ul className="text-muted-foreground pl-4 flex flex-col gap-3">
217 <li>
218 <WalletIcon className="size-4 inline" /> Give your AI agent a
219 programmable Lightning wallet to check balances, create
220 invoices, and send payments from prompts.
221 </li>
222 <li>
223 <BotIcon className="size-4 inline" /> Enable agentic payment
224 workflows in OpenClaw with wallet context for multi-step
225 tasks.
226 </li>
227 <li>
228 <ShieldCheckIcon className="size-4 inline" /> Use scoped NWC
229 permissions with budgets so you can grant access safely and
230 stay in control of spending.
231 </li>
232 </ul>
233
234 <form
235 onSubmit={handleSubmit}
236 className="flex flex-col items-start gap-5 max-w-lg"
237 >
238 <LoadingButton loading={isLoading} type="submit">
239 Create Connection
240 </LoadingButton>
241 </form>
242 </CardContent>
243 </Card>
244 <AppDetailConnectedApps appStoreApp={appStoreApp} showTitle />
245 </>
246 )}
247 </div>
248 );
249 }
250