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
7 changes: 7 additions & 0 deletions COPY.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,20 @@ These exact strings. Do not paraphrase them per page.
| Home caption | Try any skill before you install it. Your agent can search for its own. | guidance only: the homepage caption under the H1. It assumes the reader knows what a Skill is, so it names only what sets skilld apart. "Search for its own" is the skilld Skill behind the promo label. The homepage OG card uses it as its description |
| Home claims line | Open-source CLI, no telemetry Β· A skills.sh alternative | guidance only: the homepage claims line under the search. The second item links to `/vs/skills-sh`, and the promo label closes the line |
| Promo label | Teach your agent skilld | guidance only: the last item of the homepage claims line. It opens a popover with `npx skilld install skilld --global` |
| Promo panel note | No terminal? Paste this into your agent. | guidance only: the promo popover, under the install command and over the setup prompt |
| Setup prompt | Read https://skilld.dev/agent.md and follow it to set up skilld for me. | guidance only: `agentSetupPrompt()` in `shared/agent-setup.ts` builds it for the promo popover and the homepage Agents section. `/agent.md` serves the steps it points at |
| Hero Agent logos | The seven `AGENT_LOGOS` icons, then `+12` | guidance only: the quiet row under the homepage claims line. Links `#agents`. Its label names each Agent. 12 is `AGENT_TARGETS` minus `AGENT_LOGOS` |
| Step 01: find | Find Β· Stay hyped. A curated registry, plus what devs talk about on X and Bluesky. | guidance only: the first step of the homepage lifecycle band. The step name comes first, then the pitch line, then the description. Links `/skills/trending`. The braille spark motif pairs with the pitch line |
| Step 02: run | Run Β· No more skill bloat. Your Agent reads the Skill now. Nothing lands on disk. | guidance only: a homepage lifecycle step. Links `/cli#run`. It carries the band's one rose dot, because run is the default. The run chip motif pairs with the pitch line |
| Step 03: install | Install or fork Β· One install writes to 19 Agents, pinned to a commit and checked before files land. Fork for an editable copy. | guidance only: a homepage lifecycle step. Links `/cli#install`. 19 is `AGENT_TARGETS` in the CLI's `crates/skilld-core/src/target.rs`. If that count changes, change this string |
| Step 04: update | Keep current Β· Keep updated. Watch repos and get a digest when their Skills change, or run `npx skilld outdated`. | guidance only: a homepage lifecycle step. Links `/cli#update`. The page prints the command through `skillOutdatedCmd`. The change grid motif pairs with the pitch line |
| Step 05: make | Make Β· Guides and three authoring Skills to write and review your own. | guidance only: a homepage lifecycle step. Links `/make-skill`. The three are `generate-package-skill`, `generate-project-skill` and `review-skill` |
| Step 06: build | Build on Β· Built to be built on. CLI, API, SDK, MCP and the Claude Code plugin. | guidance only: a homepage lifecycle step. Links `/developers` |
| Home section: trending | Trending skills this week. | guidance only: the homepage trending section heading |
| Home section: agents | Works with your agent. Β· The CLI installs into 19 Agents. ChatGPT, Claude, and other MCP apps search the registry from the chat. | guidance only: the homepage Agents section heading and line. 19 is `AGENT_TARGETS.length` |
| Agents way: prompt | Paste into any agent Β· Your agent reads the setup steps and picks the path that fits it. | guidance only: the first way in the homepage Agents section, over the setup prompt |
| Agents way: terminal | From a terminal Β· Teaches your agent to search and run Skills in every project. | guidance only: the second way, over `npx skilld install skilld --global` |
| Agents way: MCP | In ChatGPT, Claude, and other MCP apps Β· Add the server once. Then ask the chat to find a Skill. | guidance only: the third way, over the MCP server URL. Its link, "Setup steps for each app", opens `/developers?setup=mcp` |
| Home section: changes | Keep up with skill changes. | guidance only: the homepage section heading for watching and the digest |
| Home section: authoring | Write a skill for your project. | guidance only: the homepage section heading for making a Skill |
| Nav: developers | Developers | guidance only: the header menu trigger, and the group label in the mobile menu. The menu holds the four items below |
Expand Down
52 changes: 52 additions & 0 deletions app/components/CopyText.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<script setup lang="ts">
/**
* One line of text to copy, such as a prompt or a URL, with a copy button.
* Commands use `CommandChip` instead, which records the copy.
*/
const { text, label } = defineProps<{
text: string
/** What the button copies, read by screen readers. */
label: string
}>()

const { copy, copied } = useClipboard({ copiedDuring: 2000, legacy: true })
const copyError = ref('')
const textRef = ref<HTMLElement>()

async function copyText(): Promise<void> {
copyError.value = ''
await copy(text).catch((error) => {
console.warn('[copy-text] Copy failed:', error)
copyError.value = 'Could not copy. Select the text and copy it manually.'
const selection = window.getSelection()
if (textRef.value && selection)
selection.selectAllChildren(textRef.value)
})
}
</script>

<template>
<div class="min-w-0">
<div class="flex items-start gap-2">
<code
ref="textRef"
class="min-w-0 flex-1 rounded-lg border border-default bg-muted px-3 py-2.5 font-mono text-xs leading-relaxed text-default [overflow-wrap:anywhere] whitespace-pre-wrap"
>{{ text }}</code>
<UButton
type="button"
:icon="copied ? 'i-lucide-check' : 'i-lucide-copy'"
color="neutral"
variant="outline"
class="min-h-11 min-w-11 shrink-0 justify-center"
:aria-label="`Copy ${label}`"
@click="copyText"
/>
</div>
<p class="sr-only" aria-live="polite">
{{ copied ? `Copied the ${label}.` : '' }}
</p>
<p v-if="copyError" role="alert" class="mt-2 text-sm text-error">
{{ copyError }}
</p>
</div>
</template>
144 changes: 144 additions & 0 deletions app/components/HomeAgents.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
<script setup lang="ts">
import { agentSetupPrompt, REGISTRY_MCP_URL } from '#shared/agent-setup'
import { AGENT_REACH, MORE_AGENT_COUNT } from '~/utils/agent-reach'
import { AGENT_TARGETS } from '~/utils/agents'

/**
* Every way into skilld, by what the Agent can do: read a pasted prompt, run
* a terminal command, or speak MCP. The tiles show which Agents those paths
* reach, so a visitor finds their own tool before they read a command.
*/
const setupPrompt = agentSetupPrompt()
</script>

<template>
<section id="agents" class="home-wm" aria-labelledby="agents-heading">
<!-- The mask fades the word to the right, so it stays short like Week and Work. -->
<span class="home-watermark" aria-hidden="true">Any</span>
<div class="home-agents mx-auto max-w-6xl px-4 py-12 sm:px-6 md:py-16">
<div class="min-w-0">
<h2 id="agents-heading" class="home-h2 text-balance">
Works with <span class="home-ink">your agent</span>.
</h2>
<p class="mt-4 max-w-xl text-base leading-relaxed text-muted text-pretty">
The CLI installs into {{ AGENT_TARGETS.length }} Agents. ChatGPT, Claude, and other MCP apps search the registry from the chat.
</p>
<ul class="home-agents__tiles mt-8 list-none p-0" aria-label="Agents skilld works with">
<li v-for="agent in AGENT_REACH" :key="agent.id">
<NuxtLink :to="agent.to" class="home-agents__tile" :aria-label="`${agent.label}, ${agent.via}`">
<UIcon :name="agent.icon" class="size-5 shrink-0 text-default" aria-hidden="true" />
<span class="min-w-0 truncate text-sm font-medium text-default">{{ agent.label }}</span>
<!-- Hidden on phones, where two tiles share a row and the name needs the room. -->
<span class="data-label ml-auto hidden shrink-0 sm:inline" aria-hidden="true">{{ agent.via }}</span>
</NuxtLink>
</li>
<li>
<NuxtLink to="/cli#install" class="home-agents__tile home-agents__tile--more">
<span class="text-sm text-muted">+{{ MORE_AGENT_COUNT }} more Agents</span>
<UIcon name="i-lucide-arrow-right" class="ml-auto size-4 shrink-0 text-muted" aria-hidden="true" />
</NuxtLink>
</li>
</ul>
</div>

<ol class="home-agents__ways list-none p-0" aria-label="Ways to set up skilld">
<li class="home-agents__way">
<h3 class="text-sm font-semibold text-highlighted">
Paste into any agent
</h3>
<p class="mt-1 text-sm leading-relaxed text-muted">
Your agent reads the setup steps and picks the path that fits it.
</p>
<CopyText class="mt-3" :text="setupPrompt" label="setup prompt" />
</li>
<li class="home-agents__way">
<h3 class="text-sm font-semibold text-highlighted">
From a terminal
</h3>
<p class="mt-1 text-sm leading-relaxed text-muted">
Teaches your agent to search and run Skills in every project.
</p>
<SkilldInstallChip class="mt-3" surface="home-agents" />
</li>
<li class="home-agents__way">
<h3 class="text-sm font-semibold text-highlighted">
In ChatGPT, Claude, and other MCP apps
</h3>
<p class="mt-1 text-sm leading-relaxed text-muted">
Add the server once. Then ask the chat to find a Skill.
</p>
<CopyText class="mt-3" :text="REGISTRY_MCP_URL" label="MCP server URL" />
<NuxtLink
to="/developers?setup=mcp"
class="mt-2 inline-flex min-h-11 items-center gap-1 text-sm text-default underline underline-offset-4 hover:text-primary"
>
Setup steps for each app
<UIcon name="i-lucide-arrow-right" class="size-3.5 shrink-0" aria-hidden="true" />
</NuxtLink>
</li>
</ol>
</div>
</section>
</template>

<style scoped>
.home-agents {
display: grid;
gap: 2.5rem;
}

@media (min-width: 64rem) {
.home-agents {
grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
gap: 4rem;
align-items: start;
}
}

.home-agents__tiles {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 0.5rem;
}

.home-agents__tile {
display: flex;
align-items: center;
gap: 0.75rem;
min-height: 2.75rem;
padding: 0.625rem 0.75rem;
border: 1px solid var(--ui-border);
border-radius: var(--ui-radius);
background: var(--ui-bg);
transition: border-color 150ms ease;
}

.home-agents__tile:hover,
.home-agents__tile:focus-visible {
border-color: var(--ui-border-accented);
}

.home-agents__tile--more {
border-style: dashed;
}

.home-agents__ways {
border: 1px solid var(--ui-border);
border-radius: var(--ui-radius);
background: var(--ui-bg);
}

.home-agents__way {
padding: 1rem;
}

.home-agents__way + .home-agents__way {
border-top: 1px solid var(--ui-border);
}

@media (prefers-reduced-motion: reduce) {
.home-agents__tile {
transition: none;
}
}
</style>
40 changes: 39 additions & 1 deletion app/pages/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,15 @@
import type { RecentPublishesResponse } from '~~/server/api/feed/recent-publishes.get'
import type { RecentUpdateCard, RecentUpdatesResponse } from '~~/server/api/feed/recent-updates.get'
import type { TrendingFeedResponse } from '~~/server/api/feed/trending.get'
import { agentSetupPrompt } from '#shared/agent-setup'
import { WRITING_COMPARISON_LINK } from '#shared/comparison-navigation'
import { avatarProxyUrl, githubAvatarProxyUrl } from '#shared/image-proxy'
import OutcomeClusterGrid from '../components/OutcomeClusterGrid.vue'
import { AGENT_LOGOS } from '../utils/agent-logos'
import { MORE_AGENT_COUNT } from '../utils/agent-reach'

const setupPrompt = agentSetupPrompt()
const heroAgentsLabel = `Works with ${AGENT_LOGOS.map(agent => agent.label).join(', ')}, and ${MORE_AGENT_COUNT} more Agents`

const title = 'Agent skills for you and your agent Β· skilld'
const description = 'Try any agent skill before you install it, and let your agent search for its own. Open-source CLI, no telemetry. A skills.sh alternative.'
Expand Down Expand Up @@ -229,13 +235,23 @@ function recentRepoDescription(item: RecentRepoUpdate): string {
<UIcon name="i-lucide-chevron-down" class="size-3 shrink-0" aria-hidden="true" />
</button>
<template #content>
<div class="p-2">
<div class="home-hero__promo-panel space-y-3 p-3">
<SkilldInstallChip surface="home-hero-promo" />
<p class="text-xs leading-relaxed text-muted">
No terminal? Paste this into your agent.
</p>
<CopyText :text="setupPrompt" label="setup prompt" />
</div>
</template>
</UPopover>
</li>
</ul>

<!-- Quiet proof under the claims line. The section it links to names each Agent and the way in. -->
<NuxtLink to="#agents" class="home-hero__agents mx-auto mt-5" :aria-label="heroAgentsLabel">
<UIcon v-for="agent in AGENT_LOGOS" :key="agent.id" :name="agent.icon" class="size-4 shrink-0" aria-hidden="true" />
<span class="data-label" aria-hidden="true">+{{ MORE_AGENT_COUNT }}</span>
</NuxtLink>
</div>
</section>

Expand Down Expand Up @@ -319,6 +335,8 @@ function recentRepoDescription(item: RecentRepoUpdate): string {
</div>
</section>

<HomeAgents />

<section
id="outcomes"
class="home-wm editorial-band home-outcomes-band"
Expand Down Expand Up @@ -802,6 +820,26 @@ function recentRepoDescription(item: RecentRepoUpdate): string {
}
}

.home-hero__agents {
display: flex;
width: fit-content;
align-items: center;
gap: 0.75rem;
min-height: 2.75rem;
padding-inline: 0.5rem;
color: var(--ui-text-dimmed);
transition: color 150ms ease;
}

.home-hero__agents:hover,
.home-hero__agents:focus-visible {
color: var(--ui-text-muted);
}

.home-hero__promo-panel {
width: min(22rem, calc(100vw - 2rem));
}

.home-hero__promo {
display: inline-flex;
align-items: center;
Expand Down
25 changes: 25 additions & 0 deletions app/utils/agent-reach.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { AGENT_LOGOS } from './agent-logos'
import { AGENT_TARGETS } from './agents'

/**
* Where skilld reaches an Agent, for the homepage. The CLI Agents link their
* `/agents/<id>` page. Claude and ChatGPT have no terminal, so they link the
* MCP setup steps; the Skill page also gives them a ZIP to upload.
*/
export interface AgentReach {
id: string
label: string
icon: string
to: string
/** How skilld reaches it. */
via: 'CLI' | 'MCP'
}

export const AGENT_REACH: readonly AgentReach[] = [
...AGENT_LOGOS.map(agent => ({ ...agent, to: `/agents/${agent.id}`, via: 'CLI' as const })),
{ id: 'claude', label: 'Claude', icon: 'i-simple-icons-claude', to: '/developers?setup=mcp&app=claude', via: 'MCP' },
{ id: 'chatgpt', label: 'ChatGPT', icon: 'i-simple-icons-openai', to: '/developers?setup=mcp&app=chatgpt', via: 'MCP' },
]

/** The CLI targets without a logo here. `/cli#install` lists every one. */
export const MORE_AGENT_COUNT = AGENT_TARGETS.length - AGENT_LOGOS.length
2 changes: 1 addition & 1 deletion layers/marketing/app/pages/developers.vue
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<script setup lang="ts">
import { REGISTRY_MCP_URL } from '#shared/agent-setup'
import ApiTokenSetup from '../components/_ApiTokenSetup.vue'
import SetupSnippet from '../components/_SetupSnippet.vue'
import {
Expand All @@ -9,7 +10,6 @@ import {
cursorInstallUrl,
mcpApps,
mcpAppSchema,
REGISTRY_MCP_URL,
setupModes,
setupModeSchema,
setupSnippets,
Expand Down
4 changes: 1 addition & 3 deletions layers/marketing/app/utils/developer-setup.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import { z } from 'zod'
import { REGISTRY_MCP_URL } from '#shared/agent-setup'
import { accountCmds, skilldSelfInstallCmd } from '#shared/skill-commands'

/** The discovery MCP server. `nuxt.config.ts` mounts it at `mcp.route`. */
export const REGISTRY_MCP_URL = 'https://skilld.dev/api/mcp'

/** The key every app's config files the server under. */
const SERVER_NAME = 'skilld'

Expand Down
14 changes: 14 additions & 0 deletions server/middleware/agent-md.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { AGENT_SETUP_PATH, agentSetupMarkdown } from '#shared/agent-setup'

// Setup steps for an Agent, linked from the homepage prompt. A middleware, not
// a route: nuxt-ai-ready answers every explicit `.md` path from its own
// middleware, and a project middleware runs before it. The file is for
// Agents, not search, so it answers noindex and stays out of the sitemap.
export default defineEventHandler((event) => {
if (event.path !== AGENT_SETUP_PATH)
return
setHeader(event, 'Content-Type', 'text/markdown; charset=utf-8')
setHeader(event, 'X-Robots-Tag', 'noindex')
setHeader(event, 'Cache-Control', 'public, max-age=3600, s-maxage=86400')
return agentSetupMarkdown()
})
Loading