Skills
Install once.
The agent wires the rest.
FinalApproval ships as Claude Code skills. Install them and your agent learns how to create channels, submit approvals, and wire the branches your app should take when a human approves or denies.
> /plugin marketplace add pmccurley87/final-approval-skills ✓ marketplace added > /plugin install finalapproval@final-approval-skills ✓ skill installed > add a human-in-the-loop gate before the publishPost() call ● Writing src/approval.ts — onDecision(approved|denied) ● Writing src/webhook.ts — HMAC verifier + POST /webhook ● Calling create-channel skill ✓ channel: content-publishing ✓ api key: fa_7b2a… saved to .env ✓ webhook: https://app.example.com/webhook Ready. Your agent now pauses for approval before publishPost().
One command
Install the marketplace, install the skill. Done.
Two lines in Claude Code and the skills are installed. Your agent can now create an approval channel on your workspace, wire the webhook to your app, and generate the handler code you need.
- Works with Claude Code today, other agent runtimes next
- Or drop the skill markdown into any agent framework by hand
- Open-source on GitHub — fork it, edit it, ship your own
/plugin marketplace add pmccurley87/final-approval-skills /plugin install finalapproval@final-approval-skills
Submit an approval
create-approval skill — the gate point.
When your agent hits a line in its own code that needs a human, it calls the skill with a title, an HTML body, and a structured data payload. The skill handles the HTTP, the auth, and the webhook wiring.
- Title, body (HTML for humans), data (JSON for your handler)
- Optional custom action buttons per call
- Returns an approval id your code can poll or await
const { id } = await fa.submit({
channel: "content",
title: "Publish blog post",
body: renderHTML({ post }), // rich HTML
data: { post_id: post.id }, // JSON for your handler
actions: [
{ id: "publish", label: "Approve & publish" },
{ id: "draft", label: "Save as draft" },
],
});
const decision = await fa.awaitDecision(id);
if (decision.status === "approved") publishPost(post);Wire the branches
The skill also writes your handler.
The skill doesn't stop at the submit call. It writes the onDecision(approved) and onDecision(denied) branches into your codebase, so when the webhook lands your app already knows what to do.
- Writes a verifier for the HMAC signature
- Scaffolds an onDecision function with both branches
- Connects it to your existing handler or creates a new route
export async function onDecision(evt: ApprovalEvent) {
if (evt.status === "approved") {
await publishPost(evt.data.post_id);
return;
}
// denied
await logDenial(evt.denial_reason);
}Your agent already knows how to do this.
Install the skills. Ask your agent to add a human-in-the-loop gate. Watch it wire itself.