Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
116 changes: 42 additions & 74 deletions src/components/BrowseTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ interface Props {

export default function BrowseTab({ skills }: Props) {
const [activeCategory, setActiveCategory] = useState("All");
const [searchQuery, setSearchQuery] = useState("");
const [copied, setCopied] = useState(false);
const [origin, setOrigin] = useState("");
useEffect(() => { setOrigin(window.location.origin); }, []);

Expand All @@ -19,13 +19,13 @@ export default function BrowseTab({ skills }: Props) {
[skills]
);
const filtered = useMemo(() => {
const query = searchQuery.toLowerCase();
return skills.filter((s) => {
const matchCat = activeCategory === "All" || s.category === activeCategory;
const matchSearch = s.title.toLowerCase().includes(query) || s.description.toLowerCase().includes(query);
return matchCat && matchSearch;
return activeCategory === "All" || s.category === activeCategory;
});
}, [searchQuery, activeCategory, skills]);
}, [activeCategory, skills]);

const siteOrigin = origin || "https://skills.internetcomputer.org";
const prompt = `Fetch ${siteOrigin}/llms.txt and follow its instructions when building on ICP`;

return (
<>
Expand All @@ -36,53 +36,44 @@ export default function BrowseTab({ skills }: Props) {
lineHeight: 1.1, margin: "0 0 16px 0",
letterSpacing: "-2px", color: "var(--text-primary)",
}}>
ICP skills for agents that write code
ICP skills for agents that write code.
</h1>
<p style={{
fontSize: "15px", color: "var(--text-tertiary)", maxWidth: "560px",
lineHeight: 1.6, margin: 0, fontFamily: SANS_FONT,
lineHeight: 1.6, margin: "0 0 20px 0", fontFamily: SANS_FONT,
}}>
Build using sovereign software on an onchain open cloud that's tamperproof,
unstoppable, and can process digital assets and payments
</p>
</div>

{/* Search */}
<div style={{
display: "flex", gap: "12px", marginBottom: "24px",
flexWrap: "wrap", alignItems: "center",
}}>
<div style={{ position: "relative", flex: "1 1 300px" }}>
<span style={{
position: "absolute", left: "14px", top: "50%", transform: "translateY(-50%)",
color: "var(--text-faint)", fontSize: "14px",
}}>{"\u2315"}</span>
<input
type="text"
placeholder="Search skills..."
aria-label="Search skills"
value={searchQuery}
onInput={(e) => setSearchQuery((e.target as HTMLInputElement).value)}
style={{
width: "100%", padding: "12px 16px 12px 38px",
background: "var(--bg-input)",
border: "1px solid var(--border-strong)",
borderRadius: "8px", color: "var(--text-body)",
fontSize: "15px", outline: "none",
fontFamily: "inherit", boxSizing: "border-box",
}}
/>
</div>
<div className="endpoint-hint" style={{
padding: "10px 16px",
background: "var(--bg-card)",
border: "1px solid var(--border-default)",
borderRadius: "8px", fontSize: "13px", color: "var(--text-secondary)",
whiteSpace: "nowrap",
display: "flex", alignItems: "center", gap: "8px",
}}>
<code style={{ fontSize: "13px", color: "var(--text-secondary)" }}>npx skills add dfinity/icskills</code>
<CopyButton text="npx skills add dfinity/icskills" />
<div style={{ display: "flex", gap: "10px", alignItems: "center", flexWrap: "wrap" }}>
<button onClick={() => {
navigator.clipboard.writeText(prompt).catch(() => {});
setCopied(true);
setTimeout(() => setCopied(false), 3000);
}} className="copy-prompt-btn" style={{
display: "flex", alignItems: "center", gap: "8px",
padding: "10px 20px", borderRadius: "8px",
background: copied ? "rgba(var(--green-rgb),0.1)" : "var(--bg-input)",
border: `1px solid ${copied ? "rgba(var(--green-rgb),0.2)" : "var(--border-strong)"}`,
color: copied ? "var(--green)" : "var(--text-primary)",
cursor: "pointer", fontSize: "14px", fontWeight: 600,
fontFamily: SANS_FONT,
transition: "all 0.15s ease",
}}>
{copied ? (
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12" /></svg>
) : (
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2" /><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1" /></svg>
)}
<span style={{ display: "grid" }}>
<span style={{ gridArea: "1/1", visibility: copied ? "visible" : "hidden" }}>Now paste into your agent</span>
<span style={{ gridArea: "1/1", visibility: copied ? "hidden" : "visible" }}>Give your agent ICP skills</span>
</span>
</button>
<a href="/get-started/" style={{
fontSize: "14px", color: "var(--text-muted)",
textDecoration: "none", fontFamily: SANS_FONT,
}}>Get Started →</a>
</div>
</div>

Expand Down Expand Up @@ -111,7 +102,6 @@ export default function BrowseTab({ skills }: Props) {
gap: "16px",
}}>
{filtered.map((skill) => {
const installCmd = `npx skills add dfinity/icskills --skill ${skill.name}`;
return (
<div
key={skill.name}
Expand All @@ -128,6 +118,7 @@ export default function BrowseTab({ skills }: Props) {
cursor: "pointer",
color: "inherit",
display: "block",
overflow: "hidden",
}}
>
<div style={{ display: "flex", alignItems: "center", gap: "10px", marginBottom: "12px" }}>
Expand Down Expand Up @@ -187,39 +178,16 @@ export default function BrowseTab({ skills }: Props) {
<p style={{
fontSize: "14px", color: "var(--text-dim)", lineHeight: 1.6,
margin: "0 0 16px 0", fontFamily: SANS_FONT,
overflow: "hidden",
display: "-webkit-box",
WebkitLineClamp: 3,
WebkitBoxOrient: "vertical",
}}>{skill.description}</p>

<div style={{ fontSize: "12px", color: "var(--text-muted)" }}>
updated {skill.lastUpdated}
</div>

<div
className="card-agent-url"
onClick={(e) => e.stopPropagation()}
style={{
marginTop: "12px", paddingTop: "12px",
borderTop: "1px solid var(--border-subtle)",
display: "flex", alignItems: "center", gap: "8px",
cursor: "default",
}}>
<div style={{
fontSize: "11px", color: "var(--text-muted)", whiteSpace: "nowrap", flexShrink: 0,
}}>
install:
</div>
<code style={{
flex: 1, padding: "6px 10px",
background: "var(--bg-code)",
border: "1px solid var(--border-subtle)",
borderRadius: "4px", fontSize: "11px", color: "var(--text-tertiary)",
whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis",
minWidth: 0,
}}>
<span className="install-cmd-full">{installCmd}</span>
<span className="install-cmd-short" style={{ display: "none" }}>--skill {skill.name}</span>
</code>
<CopyButton text={installCmd} />
</div>
</div>
);
})}
Expand Down
140 changes: 114 additions & 26 deletions src/components/GetStartedTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,21 @@ export default function GetStartedTab() {
const [origin, setOrigin] = useState("");
useEffect(() => { setOrigin(window.location.origin); }, []);
const endpoints = getEndpoints(origin);
const siteOrigin = origin || "https://skills.internetcomputer.org";
const prompt = `Fetch ${siteOrigin}/llms.txt and follow its instructions when building on ICP`;
const agentsMd = `# AI Agent Instructions

Tested implementation patterns for ICP development are available as agent skills.
Before writing any ICP code, fetch the skills index and remember each skill's name and description:
${siteOrigin}/.well-known/skills/index.json

When a task matches a skill's description, fetch its content on-demand from:
${siteOrigin}/.well-known/skills/{name}/SKILL.md

Skills contain correct dependency versions, configuration formats, and common pitfalls that prevent build failures.
Always prefer skill guidance over general documentation when both cover the same topic.`;
return (
<div style={{ maxWidth: "860px" }}>
<div>
<div style={{ marginBottom: "48px" }}>
<h2 style={{
fontSize: "clamp(28px, 5vw, 48px)", fontWeight: 800, color: "var(--text-primary)",
Expand All @@ -42,22 +55,21 @@ export default function GetStartedTab() {
fontSize: "15px", color: "var(--text-tertiary)", margin: 0, maxWidth: "560px",
fontFamily: SANS_FONT, lineHeight: 1.6,
}}>
Install directly into your agent, or fetch individual skills via HTTP. No auth, no keys.
Give your coding agent ICP skills. No auth, no keys, no setup.
</p>
</div>

{/* Install section */}
{/* Quick start: paste prompt */}
<div style={{ marginBottom: "48px" }}>
<div style={{
fontSize: "11px", fontWeight: 700, color: "var(--text-faint)",
letterSpacing: "2px", textTransform: "uppercase", marginBottom: "16px",
}}>Install into your agent</div>
}}>Try it now</div>

<div style={{
border: "1px solid var(--border-default)",
borderRadius: "10px",
overflow: "hidden",
marginBottom: "8px",
}}>
<div style={{
padding: "14px 20px",
Expand All @@ -67,26 +79,102 @@ export default function GetStartedTab() {
}}>
<div style={{ flex: 1, minWidth: 0 }}>
<div style={{ fontSize: "14px", fontWeight: 700, color: "var(--text-primary)", marginBottom: "2px" }}>
All skills (interactive)
Paste into your agent
</div>
<div className="endpoint-desc" style={{ fontSize: "13px", color: "var(--text-muted)", fontFamily: SANS_FONT }}>
Pick which skills to install. Auto-detects your agent (Claude Code, Cursor, Copilot, and more).
Works in any agent session. Your agent fetches the skills index and pulls matching skills on demand.
</div>
</div>
</div>
<div style={{
padding: "10px 20px",
padding: "14px 20px",
background: "var(--bg-code)",
display: "flex", alignItems: "center", gap: "8px",
}}>
<code style={{
flex: 1, fontSize: "12px", color: "var(--text-secondary)",
whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis",
flex: 1, fontSize: "13px", color: "var(--text-secondary)",
lineHeight: 1.5,
minWidth: 0,
}}>npx skills add dfinity/icskills</code>
<CopyButton text="npx skills add dfinity/icskills" />
overflowWrap: "break-word",
}}>{prompt}</code>
<CopyButton text={prompt} />
</div>
</div>
</div>

{/* Persistent: AGENTS.md */}
<div style={{ marginBottom: "48px" }}>
<div style={{
fontSize: "11px", fontWeight: 700, color: "var(--text-faint)",
letterSpacing: "2px", textTransform: "uppercase", marginBottom: "16px",
}}>Set it and forget it</div>

<div style={{
border: "1px solid var(--border-default)",
borderRadius: "10px",
overflow: "hidden",
}}>
<div style={{
padding: "14px 20px",
background: "var(--bg-card-subtle)",
display: "flex", alignItems: "center", gap: "12px",
flexWrap: "wrap",
}}>
<div style={{ flex: 1, minWidth: 0 }}>
<div style={{ fontSize: "14px", fontWeight: 700, color: "var(--text-primary)", marginBottom: "2px" }}>
Add AGENTS.md to your repo
</div>
<div className="endpoint-desc" style={{ fontSize: "13px", color: "var(--text-muted)", fontFamily: SANS_FONT }}>
Commit once, every agent session auto-discovers ICP skills. Works with Claude Code, Cursor, Copilot, and others.
</div>
</div>
<div style={{ display: "flex", gap: "6px", flexShrink: 0 }}>
<CopyButton text={agentsMd} />
<a href="/AGENTS.md" download="AGENTS.md"
title="Download AGENTS.md"
style={{
display: "flex", alignItems: "center", justifyContent: "center",
width: "26px", height: "26px", borderRadius: "4px",
background: "var(--bg-card)",
border: "1px solid var(--border-default)",
color: "var(--text-muted)",
cursor: "pointer",
textDecoration: "none",
flexShrink: 0,
}}>
<svg width="14" height="14" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
<path d="M8 2v8M4.5 7.5 8 11l3.5-3.5M2.5 13.5h11" />
</svg>
</a>
</div>
</div>
<div style={{
padding: "14px 20px",
background: "var(--bg-code)",
}}>
<code style={{
fontSize: "13px", color: "var(--text-secondary)",
lineHeight: 1.5,
whiteSpace: "pre-wrap",
overflowWrap: "break-word",
}}>{agentsMd}</code>
</div>
</div>
<p style={{
fontSize: "13px", color: "var(--text-muted)", margin: "12px 0 0 0",
fontFamily: SANS_FONT, lineHeight: 1.6,
}}>
For Claude Code, also add a <code style={{ fontSize: "12px", color: "var(--text-tertiary)" }}>CLAUDE.md</code> that
reads: <code style={{ fontSize: "12px", color: "var(--text-tertiary)" }}>Read and follow the instructions in AGENTS.md.</code>
</p>
</div>

{/* CLI install */}
<div style={{ marginBottom: "48px" }}>
<div style={{
fontSize: "11px", fontWeight: 700, color: "var(--text-faint)",
letterSpacing: "2px", textTransform: "uppercase", marginBottom: "16px",
}}>Use the CLI</div>

<div style={{
border: "1px solid var(--border-default)",
Expand All @@ -102,24 +190,24 @@ export default function GetStartedTab() {
}}>
<div style={{ flex: 1, minWidth: 0 }}>
<div style={{ fontSize: "14px", fontWeight: 700, color: "var(--text-primary)", marginBottom: "2px" }}>
Single skill
All skills
</div>
<div className="endpoint-desc" style={{ fontSize: "13px", color: "var(--text-muted)", fontFamily: SANS_FONT }}>
Install one skill by name. Includes any reference files.
Auto-detects your agents (Claude Code, Cursor, Copilot, and more) and writes the skills into their rules files.
</div>
</div>
</div>
<div style={{
padding: "10px 20px",
padding: "14px 20px",
background: "var(--bg-code)",
display: "flex", alignItems: "center", gap: "8px",
}}>
<code style={{
flex: 1, fontSize: "12px", color: "var(--text-secondary)",
whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis",
flex: 1, fontSize: "13px", color: "var(--text-secondary)",
minWidth: 0,
}}>npx skills add dfinity/icskills --skill ckbtc</code>
<CopyButton text="npx skills add dfinity/icskills --skill ckbtc" />
overflowWrap: "break-word",
}}>npx skills add dfinity/icskills</code>
<CopyButton text="npx skills add dfinity/icskills" />
</div>
</div>

Expand All @@ -136,24 +224,24 @@ export default function GetStartedTab() {
}}>
<div style={{ flex: 1, minWidth: 0 }}>
<div style={{ fontSize: "14px", fontWeight: 700, color: "var(--text-primary)", marginBottom: "2px" }}>
All skills (no prompts)
Single skill
</div>
<div className="endpoint-desc" style={{ fontSize: "13px", color: "var(--text-muted)", fontFamily: SANS_FONT }}>
Install everything into all detected agents. No interactive prompts.
Install one skill by name. Includes any reference files.
</div>
</div>
</div>
<div style={{
padding: "10px 20px",
padding: "14px 20px",
background: "var(--bg-code)",
display: "flex", alignItems: "center", gap: "8px",
}}>
<code style={{
flex: 1, fontSize: "12px", color: "var(--text-secondary)",
whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis",
flex: 1, fontSize: "13px", color: "var(--text-secondary)",
minWidth: 0,
}}>npx skills add dfinity/icskills --all</code>
<CopyButton text="npx skills add dfinity/icskills --all" />
overflowWrap: "break-word",
}}>npx skills add dfinity/icskills --skill ckbtc</code>
<CopyButton text="npx skills add dfinity/icskills --skill ckbtc" />
</div>
</div>
</div>
Expand Down
Loading
Loading