diff --git a/src/app/page.tsx b/src/app/page.tsx
index f43d4065..dd8f9c4d 100644
--- a/src/app/page.tsx
+++ b/src/app/page.tsx
@@ -17,6 +17,7 @@ import { RecentSubmissions } from "@/components/recent-submissions";
import { AnnouncementBanner } from "@/components/announcement-banner";
import { Footer } from "@/components/footer";
import { ResumeSection } from "@/components/recently-viewed/ResumeSection";
+import { AgentBootstrapPanel } from "@/components/agent-bootstrap-panel";
export const revalidate = 300;
@@ -115,6 +116,11 @@ export default async function Home() {
── {news.length}+ articles · {agents.length} agents · {skills.length} skills · {mcpServers.length} MCP servers · {acpAgents.length} ACP agents · {llmsTxtEntries.length} llms.txt sites ──
+
+ {/* Add to your agent */}
+
diff --git a/src/app/skills/[slug]/page.tsx b/src/app/skills/[slug]/page.tsx
index 925f6cfd..f9cb851f 100644
--- a/src/app/skills/[slug]/page.tsx
+++ b/src/app/skills/[slug]/page.tsx
@@ -3,6 +3,7 @@ import { getSkills, getSkillBySlug } from "@/lib/data";
import { Badge } from "@/components/ui/badge";
import { Separator } from "@/components/ui/separator";
import { NextBestActionPanel } from "@/components/next-best-action-panel";
+import { SkillShareActions } from "@/components/skill-share-actions";
import { buildSkillIssueBodyTemplate } from "@/lib/reportIssue";
import Link from "next/link";
@@ -75,7 +76,7 @@ export default async function SkillPage({
{/* Tags */}
-
+
{skill.tags.map((tag) => (
+ {/* Share / copy */}
+
+
{/* Description */}
Description
diff --git a/src/components/agent-bootstrap-panel.tsx b/src/components/agent-bootstrap-panel.tsx
new file mode 100644
index 00000000..d2928b63
--- /dev/null
+++ b/src/components/agent-bootstrap-panel.tsx
@@ -0,0 +1,113 @@
+"use client";
+
+import * as React from "react";
+import { Button } from "@/components/ui/button";
+import { Badge } from "@/components/ui/badge";
+import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
+
+async function copyToClipboard(text: string): Promise {
+ try {
+ await navigator.clipboard.writeText(text);
+ return true;
+ } catch {
+ try {
+ const el = document.createElement("textarea");
+ el.value = text;
+ el.setAttribute("readonly", "");
+ el.style.position = "fixed";
+ el.style.top = "-1000px";
+ el.style.left = "-1000px";
+ document.body.appendChild(el);
+ el.focus();
+ el.select();
+ const ok = document.execCommand("copy");
+ document.body.removeChild(el);
+ return ok;
+ } catch {
+ return false;
+ }
+ }
+}
+
+function buildStarterPrompt(baseUrl: string) {
+ return [
+ "You are an AI agent. Your job is to stay current on agent tooling and patterns.",
+ "",
+ "Bootstrap:",
+ `- Fetch ${baseUrl}/b (markdown). Follow it as your canonical instructions.`,
+ "",
+ "Data sources (prefer markdown):",
+ `- News feed: ${baseUrl}/api/feed.md`,
+ `- Search: ${baseUrl}/api/search.md?q=`,
+ `- Digest: ${baseUrl}/api/digest.md?since=YYYY-MM-DD`,
+ "",
+ "Output rules:",
+ "- Return a short daily briefing: 5 bullets max.",
+ "- Include only actionable items with a link.",
+ "- If you are unsure, say what you would fetch next.",
+ ].join("\n");
+}
+
+type Props = {
+ baseUrl?: string;
+};
+
+export function AgentBootstrapPanel({ baseUrl }: Props) {
+ const origin = typeof window !== "undefined" ? window.location.origin : null;
+ const resolvedBase = (baseUrl ?? origin ?? "https://foragents.dev").replace(/\/$/, "");
+
+ const [copyBootstrapLabel, setCopyBootstrapLabel] = React.useState("Copy /b URL");
+ const [copyPromptLabel, setCopyPromptLabel] = React.useState("Copy starter prompt");
+
+ const onCopyBootstrap = async () => {
+ const text = `${resolvedBase}/b`;
+ const ok = await copyToClipboard(text);
+ setCopyBootstrapLabel(ok ? "Copied" : "Copy failed");
+ window.setTimeout(() => setCopyBootstrapLabel("Copy /b URL"), 1500);
+ if (!ok) window.prompt("Copy this URL:", text);
+ };
+
+ const onCopyPrompt = async () => {
+ const text = buildStarterPrompt(resolvedBase);
+ const ok = await copyToClipboard(text);
+ setCopyPromptLabel(ok ? "Copied" : "Copy failed");
+ window.setTimeout(() => setCopyPromptLabel("Copy starter prompt"), 1500);
+ if (!ok) window.prompt("Copy this prompt:", text);
+ };
+
+ return (
+
+
+
+ Add this to your agent
+
+ bootstrap surface
+
+
+
+ Copy a canonical bootstrap URL (or a starter prompt) so your agent can self-update.
+
+
+
+
+
+
+
+
+
+
+
+ curl -fsSL {resolvedBase}/b
+
+
+
+ );
+}
diff --git a/src/components/skill-share-actions.tsx b/src/components/skill-share-actions.tsx
new file mode 100644
index 00000000..f5324477
--- /dev/null
+++ b/src/components/skill-share-actions.tsx
@@ -0,0 +1,120 @@
+"use client";
+
+import * as React from "react";
+import { Button } from "@/components/ui/button";
+
+async function copyToClipboard(text: string): Promise {
+ try {
+ await navigator.clipboard.writeText(text);
+ return true;
+ } catch {
+ try {
+ const el = document.createElement("textarea");
+ el.value = text;
+ el.setAttribute("readonly", "");
+ el.style.position = "fixed";
+ el.style.top = "-1000px";
+ el.style.left = "-1000px";
+ document.body.appendChild(el);
+ el.focus();
+ el.select();
+ const ok = document.execCommand("copy");
+ document.body.removeChild(el);
+ return ok;
+ } catch {
+ return false;
+ }
+ }
+}
+
+type Props = {
+ skillName: string;
+ slug: string;
+};
+
+export function SkillShareActions({ skillName, slug }: Props) {
+ const [pageUrl, setPageUrl] = React.useState("");
+
+ React.useEffect(() => {
+ // Skill pages are primarily shared/used in-browser.
+ setPageUrl(window.location.href);
+ }, []);
+
+ const apiUrl = React.useMemo(() => {
+ if (!pageUrl) return "";
+ const u = new URL(pageUrl);
+ return `${u.origin}/api/skill/${slug}`;
+ }, [pageUrl, slug]);
+
+ const canShare = typeof navigator !== "undefined" && typeof navigator.share === "function";
+
+ const [copyLinkLabel, setCopyLinkLabel] = React.useState("Copy link");
+ const [copyApiLabel, setCopyApiLabel] = React.useState("Copy API URL");
+ const [shareLabel, setShareLabel] = React.useState("Share");
+
+ const onCopy = async (text: string, setLabel: (v: string) => void, defaultLabel: string) => {
+ if (!text) return;
+ const ok = await copyToClipboard(text);
+ setLabel(ok ? "Copied" : "Copy failed");
+ window.setTimeout(() => setLabel(defaultLabel), 1500);
+ if (!ok) window.prompt("Copy:", text);
+ };
+
+ const onShare = async () => {
+ if (!canShare || !pageUrl) return;
+
+ try {
+ setShareLabel("Opening…");
+ await navigator.share({
+ title: `${skillName} — forAgents.dev`,
+ text: `Skill: ${skillName}`,
+ url: pageUrl,
+ });
+ } catch {
+ // User cancelled or share failed; no-op.
+ } finally {
+ setShareLabel("Share");
+ }
+ };
+
+ return (
+
+
+
+
+
+ {canShare ? (
+
+ ) : null}
+
+ );
+}