From 335fddeb7abc0a894252878dfa6cfe4dbc337d91 Mon Sep 17 00:00:00 2001 From: Ben Sabic Date: Tue, 28 Jul 2026 12:25:21 +1000 Subject: [PATCH] feat(docs): add Sanity, Typefully, and GitHub agent templates Mirror the authored surface of three vercel-labs templates into the gallery, pinned to the revision each was copied from. Each entry uses the template's own setup prompt. Fix the file browser's category order along the way: names missing from the list rendered last, so instructions.ts, sandbox.ts, schedules, and the design template's sandbox folder were stranded below lib. Standalone files now lead, folders follow, and every template renders the same sequence. Signed-off-by: Ben Sabic --- .../[lang]/templates/[slug]/file-viewer.tsx | 14 + .../[lang]/templates/integration-icons.tsx | 16 +- apps/docs/lib/integrations/logos.tsx | 12 + apps/docs/lib/templates/data.ts | 49 + apps/docs/lib/templates/sources.ts | 4782 +++++++++++++++++ 5 files changed, 4872 insertions(+), 1 deletion(-) diff --git a/apps/docs/app/[lang]/templates/[slug]/file-viewer.tsx b/apps/docs/app/[lang]/templates/[slug]/file-viewer.tsx index e98c8cf98..3f30ab94f 100644 --- a/apps/docs/app/[lang]/templates/[slug]/file-viewer.tsx +++ b/apps/docs/app/[lang]/templates/[slug]/file-viewer.tsx @@ -2,7 +2,9 @@ import { BotIcon, + BoxIcon, BracesIcon, + CalendarClockIcon, ChevronRightIcon, FileTextIcon, type LucideIcon, @@ -32,8 +34,12 @@ interface CategoryStyle { const categoryStyles: Record = { "agent.ts": { icon: SettingsIcon }, "instructions.md": { icon: FileTextIcon }, + "instructions.ts": { icon: FileTextIcon }, + "sandbox.ts": { icon: BoxIcon }, + sandbox: { icon: BoxIcon }, channels: { icon: MessageSquareIcon }, connections: { icon: PlugIcon }, + schedules: { icon: CalendarClockIcon }, skills: { icon: FileTextIcon }, tools: { icon: WrenchIcon }, subagents: { icon: BotIcon }, @@ -41,11 +47,19 @@ const categoryStyles: Record = { }; const defaultStyle: CategoryStyle = { icon: FileTextIcon }; + +// Keys absent from this list render last in encounter order, so every top-level +// name a template can author belongs here. Standalone files lead, folders follow; +// `sandbox` appears twice because templates author it as either a file or a folder. const categoryOrder = [ "agent.ts", "instructions.md", + "instructions.ts", + "sandbox.ts", + "sandbox", "channels", "connections", + "schedules", "skills", "tools", "subagents", diff --git a/apps/docs/app/[lang]/templates/integration-icons.tsx b/apps/docs/app/[lang]/templates/integration-icons.tsx index 034448267..1e2b6582e 100644 --- a/apps/docs/app/[lang]/templates/integration-icons.tsx +++ b/apps/docs/app/[lang]/templates/integration-icons.tsx @@ -1,15 +1,29 @@ import { BracesIcon } from "lucide-react"; import type { ComponentType, SVGProps } from "react"; -import { linearLogo, notionLogo, sentryLogo, slackLogo, webLogo } from "@/lib/integrations/logos"; +import { + githubLogo, + linearLogo, + notionLogo, + resendLogo, + sanityLogo, + sentryLogo, + slackLogo, + typefullyLogo, + webLogo, +} from "@/lib/integrations/logos"; import type { TemplateIntegration } from "@/lib/templates/data"; type IconComponent = ComponentType>; export const integrationIcons: Record = { + GitHub: githubLogo, "HTTP API": BracesIcon, Linear: linearLogo, Notion: notionLogo, + Resend: resendLogo, + Sanity: sanityLogo, Sentry: sentryLogo, Slack: slackLogo, + Typefully: typefullyLogo, "Web chat": webLogo, }; diff --git a/apps/docs/lib/integrations/logos.tsx b/apps/docs/lib/integrations/logos.tsx index 6c2697219..f767dd686 100644 --- a/apps/docs/lib/integrations/logos.tsx +++ b/apps/docs/lib/integrations/logos.tsx @@ -21,6 +21,7 @@ import { SiPosthog, SiPostman, SiRazorpay, + SiSanity, SiSentry, SiSimilarweb, SiStripe, @@ -230,6 +231,8 @@ export const postmanLogo = (props: LogoProps) => ; +export const sanityLogo = (props: LogoProps) => ; + export const sentryLogo = (props: LogoProps) => ; export const similarwebLogo = (props: LogoProps) => ; @@ -240,6 +243,15 @@ export const supabaseLogo = (props: LogoProps) => ; +export const typefullyLogo = (props: LogoProps) => ( + + + +); + export const todoistLogo = (props: LogoProps) => ; export const webflowLogo = (props: LogoProps) => ; diff --git a/apps/docs/lib/templates/data.ts b/apps/docs/lib/templates/data.ts index e6161bfec..9c4a4377a 100644 --- a/apps/docs/lib/templates/data.ts +++ b/apps/docs/lib/templates/data.ts @@ -2,11 +2,15 @@ export type TemplateCategory = "Chat" | "Collaboration" | "Example"; import { templateSourceFiles } from "./sources"; export type TemplateIntegration = + | "GitHub" | "HTTP API" | "Linear" | "Notion" + | "Resend" + | "Sanity" | "Sentry" | "Slack" + | "Typefully" | "Web chat"; export type TemplateSource = "GitHub" | "Vercel Templates"; @@ -76,6 +80,51 @@ export const templateEntries: TemplateEntry[] = [ source: "Vercel Templates", files: templateSourceFiles["eve-slack-agent"], }, + { + slug: "kody", + title: "GitHub", + setupPrompt: + "I want to build a GitHub maintainer agent with the eve framework, using the Kody template. Read the setup instructions at https://agent-resources.dev/kody-eve-template.md and follow them. They will cover deploying the template, building with eve, how everything works overall, and more.", + description: + "Kody, a personal GitHub maintainer agent: emails you a weekly digest of open issues, acts on your replies, summarizes new pull requests, and works the issues you delegate in Linear.", + sourceHref: "https://github.com/vercel-labs/kody-eve-template/tree/main", + sourceRevision: "8427e3c7e88a6a449dd7c79c601619ac37cf18e1", + category: "Collaboration", + model: "anthropic/claude-fable-5", + integrations: ["GitHub", "Linear", "Resend"], + source: "Vercel Templates", + files: templateSourceFiles.kody, + }, + { + slug: "sanity-copilot", + title: "Sanity", + setupPrompt: + "I want to build a Slack agent with the eve framework, using the Sanity copilot template. Read the setup instructions at https://agent-resources.dev/sanity-copilot-eve-template.md and follow them. They will cover deploying the template, building with eve, how everything works overall, and more.", + description: + "A Slack copilot for your Sanity project: query and edit content with GROQ, shape schemas, manage releases, and draft long-form pieces into Notion.", + sourceHref: "https://github.com/vercel-labs/sanity-copilot-eve-template/tree/main", + sourceRevision: "f076b80e2bb3a2ccae3dc1cfe4886d5ac88c338b", + category: "Collaboration", + model: "anthropic/claude-sonnet-5", + integrations: ["Slack", "Sanity", "Notion"], + source: "Vercel Templates", + files: templateSourceFiles["sanity-copilot"], + }, + { + slug: "typefully", + title: "Typefully", + setupPrompt: + "I want to build a Slack agent with the eve framework, using the Typefully social media agent template. Read the setup instructions at https://agent-resources.dev/typefully-eve-template.md and follow them. They will cover deploying the template, building with eve, how everything works overall, and more.", + description: + "A Slack agent that runs your social presence through Typefully: draft posts and threads for X, LinkedIn, Threads, Bluesky, and Mastodon, manage the publishing queue, and get a weekly analytics digest.", + sourceHref: "https://github.com/vercel-labs/typefully-eve-template/tree/main", + sourceRevision: "3627b2282a9ebfa1badd987f2b3a0c337219575f", + category: "Collaboration", + model: "anthropic/claude-sonnet-5", + integrations: ["Slack", "Typefully", "Notion"], + source: "Vercel Templates", + files: templateSourceFiles.typefully, + }, { slug: "weather-agent-fixture", title: "Weather", diff --git a/apps/docs/lib/templates/sources.ts b/apps/docs/lib/templates/sources.ts index 85018d1e5..c9d8bd31e 100644 --- a/apps/docs/lib/templates/sources.ts +++ b/apps/docs/lib/templates/sources.ts @@ -458,6 +458,4788 @@ export default defineTool({ return { city, condition: "Sunny", temperatureF: 72 }; }, }); +`, + ), + ], + kody: [ + file( + "agent/agent.ts", + "typescript", + `import { defineAgent } from "eve"; + +/** + * Root agent runtime configuration. + * + * @remarks + * Sets the model and the session budget for Kody, the GitHub maintainer agent; the rest of the + * agent's surface (channels, connections, tools, skills, subagents) is discovered from the + * filesystem under \`agent/\`. Conversation history is compacted once it reaches 75% of the context + * window, and the per-session output token limit caps runaway sessions. \`@vercel/connect\` is + * externalized from the build as a temporary workaround until eve handles transitive Connect + * imports from \`@github-tools/sdk\` without configuration. + */ +export default defineAgent({ + build: { externalDependencies: ["@vercel/connect"] }, + compaction: { thresholdPercent: 0.75 }, + limits: { + maxOutputTokensPerSession: 20_000, + }, + model: "anthropic/claude-fable-5", +}); +`, + ), + file( + "agent/channels/eve.ts", + "typescript", + `import { type AuthFn, localDev, vercelOidc } from "eve/channels/auth"; +import { eveChannel } from "eve/channels/eve"; + +const localDevAuth = localDev(); + +/** + * Dev-only: present a trusted local session as an authenticated user. + * + * @remarks + * The user-preference tools key their storage on a \`principalType: "user"\` session. In + * production the channels supply one; the eve dev TUI authenticates with \`localDev()\`, + * whose \`local-dev\` principal is not a user, so user-scoped tool calls fail with + * \`principal_required\`. This shim defers the trust decision to \`localDev()\` — returning \`null\` + * for anything it would reject, so it never affects production — and only upgrades the resolved + * principal to a user. Drop it if you don't exercise user-scoped tools from the dev TUI. + */ +const localDevUser: AuthFn = async (request) => { + const local = await localDevAuth(request); + return local ? { ...local, principalType: "user" } : null; +}; + +export default eveChannel({ auth: [localDevUser, vercelOidc()] }); +`, + ), + file( + "agent/channels/github.ts", + "typescript", + `import { connectGitHubCredentials } from "@vercel/connect/eve"; +import { + defaultGitHubAuth, + type GitHubComment, + githubChannel, +} from "eve/channels/github"; + +const BOT_NAME = "Kody"; + +/** + * Matches an \`@Kody\` mention on a word boundary, the same pattern the + * channel's built-in comment gate uses. Kept in sync with {@link BOT_NAME}. + */ +const MENTION_PATTERN = /@kody(?=$|[^A-Za-z0-9_-])/iu; + +/** + * Commenter roles allowed to start a session by mentioning the agent. + * + * @remarks + * GitHub's \`author_association\` on the comment payload. Anything outside this + * set (CONTRIBUTOR, FIRST_TIME_CONTRIBUTOR, NONE, MANNEQUIN) is a user the + * repo hasn't trusted with write access, so their mentions are acknowledged + * without dispatching. + */ +const TRUSTED_ASSOCIATIONS = new Set(["COLLABORATOR", "MEMBER", "OWNER"]); + +/** + * Replicates the channel's built-in ignore rules: eve's own marker comments, + * bot authors, and the agent's own \`kody[bot]\` login. + */ +const isIgnoredComment = (comment: GitHubComment): boolean => { + if (comment.body.includes("