diff --git a/agents/base2/base2.ts b/agents/base2/base2.ts index 31b22bac09..a9b6abdd03 100644 --- a/agents/base2/base2.ts +++ b/agents/base2/base2.ts @@ -166,7 +166,7 @@ ${ - **Be careful with terminal commands:** Be careful about instructing subagents to run terminal commands that could be destructive or have effects that are hard to undo (e.g. git push, git commit, running any scripts -- especially ones that could alter production environments (!), installing packages globally, etc). Don't run any of these effectful commands unless the user explicitly asks you to. - **Do what the user asks:** If the user asks you to do something, even running a risky terminal command, do it. - **Don't use set_output:** The set_output tool is for spawned subagents to report results. Don't use it yourself. -- **Discover and install skills:** Skills are reusable, self-contained instructions for accomplishing a task. Beyond the skills already listed for the \`skill\` tool, you can find and install community skills from the command line: \`npx skills find \` to search, \`npx skills add --list\` to preview a repo's skills, and \`npx skills add --skill --yes\` to install one into \`.agents/skills/\`. After installing, load it by name with the \`skill\` tool. These community skills are not vetted, so confirm with the user which skill(s) to install before running \`npx skills add\`.${ +- **Discover and install skills:** Skills are reusable, self-contained instructions for accomplishing a task. Pre-loaded skills are already in your system prompt (see "# Pre-loaded Skills" above) — you do NOT need to call the \`skill\` tool to load them. To install new community skills, use the \`/skills install [--skill ]\` slash command, or run \`npx skills add --skill --yes\` from the terminal. Use \`/skills list\` to see available skills. These community skills are not vetted, so confirm with the user which skill(s) to install before running \`npx skills add\`. Note: Newly installed skills won't appear until the next session — tell the user to restart or start a new chat to pick them up.${ ENABLE_COMPOSIO_TOOLS ? ` - **External apps:** When Composio tools are available and the user asks to work with connected apps or services like Gmail, Google Calendar, GitHub, Slack, Linear, or Notion, use them to search for the right app tools, help the user connect their account (use the render_ui tool to show a button if the user needs to click a link), and execute the requested action.` diff --git a/cli/src/commands/command-registry.ts b/cli/src/commands/command-registry.ts index db2461529c..9a230bf047 100644 --- a/cli/src/commands/command-registry.ts +++ b/cli/src/commands/command-registry.ts @@ -25,7 +25,12 @@ import { AGENT_MODES, END_SESSION_MESSAGE, IS_FREEBUFF } from '../utils/constant import { exitCliCleanly } from '../utils/exit-cleanly' import { getSystemMessage, getUserMessage } from '../utils/message-history' import { capturePendingAttachments } from '../utils/pending-attachments' -import { getSkillByName } from '../utils/skill-registry' +import { + getSkillByName, + getLoadedSkills, + initializeSkillRegistry, +} from '../utils/skill-registry' +import { execSync } from 'child_process' import type { MultilineInputHandle } from '../components/multiline-input' import type { InputValue, PendingAttachment } from '../types/store' @@ -615,6 +620,115 @@ const ALL_COMMANDS: CommandDefinition[] = [ }) }, }), + // /skills install [--skill ] — install a skill from a GitHub repo + defineCommandWithArgs({ + name: 'skills', + aliases: [], + handler: async (params, args) => { + const trimmedArgs = args.trim() + params.saveToHistory(params.inputValue.trim()) + clearInput(params) + + // Parse subcommand + const parts = trimmedArgs.split(/\s+/) + const subcommand = parts[0]?.toLowerCase() + + if (subcommand === 'list') { + const skills = getLoadedSkills() + const skillNames = Object.keys(skills) + if (skillNames.length === 0) { + params.setMessages((prev) => [ + ...prev, + getSystemMessage( + 'No skills installed.\n\nInstall skills with: /skills install [--skill ]\nOr from the terminal: npx skills add --skill --yes', + ), + ]) + } else { + const list = skillNames + .map( + (name) => + ` • ${name}: ${skills[name].description.slice(0, 80)}`, + ) + .join('\n') + params.setMessages((prev) => [ + ...prev, + getSystemMessage( + `Installed skills (${skillNames.length}):\n${list}\n\nSkills are automatically available to the agent. Install more with: /skills install [--skill ]`, + ), + ]) + } + return + } + + if (subcommand === 'install') { + const repo = parts[1] + if (!repo) { + params.setMessages((prev) => [ + ...prev, + getSystemMessage( + 'Usage: /skills install [--skill ]\n\nExample: /skills install anthropics/skills --skill git-release', + ), + ]) + return + } + + // Parse --skill flag + const skillFlagIdx = parts.indexOf('--skill') + const skillName = + skillFlagIdx !== -1 ? parts[skillFlagIdx + 1] : undefined + const extraArgs = skillFlagIdx !== -1 ? parts.slice(skillFlagIdx + 2) : [] + + const installCmd = [ + 'npx', + 'skills', + 'add', + repo, + ...(skillName ? ['--skill', skillName] : []), + '--yes', + ...extraArgs, + ].join(' ') + + params.setMessages((prev) => [ + ...prev, + getSystemMessage(`Installing skill from ${repo}...`), + ]) + + try { + const output = execSync(installCmd, { + encoding: 'utf8', + stdio: 'pipe', + timeout: 60_000, + }) + // Refresh the skill registry so newly installed skills are picked up + await initializeSkillRegistry() + params.setMessages((prev) => [ + ...prev, + getSystemMessage( + `${output.trim()}\n\nSkill installed to .agents/skills/. It will be available in your next session (use /new to start a fresh chat).`, + ), + ]) + } catch (error) { + const errMsg = + error instanceof Error ? error.message : String(error) + params.setMessages((prev) => [ + ...prev, + getSystemMessage( + `Failed to install skill: ${errMsg}\n\nMake sure you have npx available and the repo exists.`, + ), + ]) + } + return + } + + // Unknown subcommand — show help + params.setMessages((prev) => [ + ...prev, + getSystemMessage( + 'Skills commands:\n /skills list — show installed skills\n /skills install [--skill ] — install a skill from GitHub\n\nExample: /skills install anthropics/skills --skill git-release', + ), + ]) + }, + }), ] export const COMMAND_REGISTRY: CommandDefinition[] = IS_FREEBUFF diff --git a/cli/src/data/slash-commands.ts b/cli/src/data/slash-commands.ts index b1eccce5bf..fcf01554b5 100644 --- a/cli/src/data/slash-commands.ts +++ b/cli/src/data/slash-commands.ts @@ -180,6 +180,12 @@ const ALL_SLASH_COMMANDS: SlashCommand[] = [ // label: 'publish', // description: 'Publish agents to the agent store', // }, + { + id: 'skills', + label: 'skills', + description: 'Install or list automatically-loaded skills', + aliases: [], + }, { id: 'theme:toggle', label: 'theme:toggle', diff --git a/packages/agent-runtime/src/run-agent-step.ts b/packages/agent-runtime/src/run-agent-step.ts index 536c1cd495..ac0d8279c9 100644 --- a/packages/agent-runtime/src/run-agent-step.ts +++ b/packages/agent-runtime/src/run-agent-step.ts @@ -838,6 +838,27 @@ export async function loopAgentSteps( system = systemPrompt ?? '' } + // Inject loaded skills into the system prompt so they are always + // available without needing the agent to call the `skill` tool. + // Skills are installed via `/skills install` or `npx skills add`. + if (!agentTemplate.inheritParentSystemPrompt || !parentSystemPrompt) { + const skills = fileContext.skills ?? {} + const skillEntries = Object.values(skills) + if (skillEntries.length > 0) { + const skillsInstructions = skillEntries + .map( + (skill) => { + // Strip YAML frontmatter from the skill content so the model + // only sees the actual instructions, not metadata noise. + const body = skill.content.replace(/^---[\s\S]*?---\n*/, '').trim() + return `## Skill: ${skill.name}\n\n${body}` + }, + ) + .join('\n\n---\n\n') + system += `\n\n# Pre-loaded Skills\n\nThe following skills are pre-loaded and always available. You do NOT need to use the \`skill\` tool to load them — their full instructions are already part of your context. Use \`/skills install [--skill ]\` to install more, or \`/skills list\` to see available skills.\n\n---\n\n${skillsInstructions}` + } + } + // Build agent tools (agents as direct tool calls) for non-inherited tools const agentTools = useParentTools ? {}