vibe_ship
Announce your shipped project to the community board and update your profile with a description, URL, and tags. Fulfill requests or credit inspirations.
Instructions
Announce something you just shipped to the community board and update your profile.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| what | Yes | What you shipped (brief description) | |
| url | No | URL to your ship (deployed site, repo, demo) | |
| inspired_by | No | Handle of person who inspired this (@alice) | |
| for_request | No | Request ID this fulfills (if building for someone) | |
| tags | No | Tags for discovery (e.g., ["ai", "mcp", "tools"]) |
Implementation Reference
- tools/ship.js:48-128 (handler)The main handler function for vibe_ship. It validates args, builds rich content with metadata (URL, inspired_by, for_request), POSTs to /api/board, and returns a formatted display with a shareable tweet.
async function handler(args) { const initCheck = requireInit(); if (initCheck) return initCheck; if (!args.what) { return { error: 'Please tell us what you shipped: ship "Built a new feature"' }; } const myHandle = config.getHandle(); const apiUrl = config.getApiUrl(); try { // Build rich content with metadata let content = args.what; const metaParts = []; if (args.url) { metaParts.push(`š ${args.url}`); } if (args.inspired_by) { const inspiree = args.inspired_by.replace('@', '').toLowerCase(); metaParts.push(`⨠inspired by @${inspiree}`); } if (args.for_request) { metaParts.push(`š fulfills ${args.for_request}`); } if (metaParts.length > 0) { content += '\n' + metaParts.join(' | '); } // Build tags with attribution const tags = args.tags || []; if (args.inspired_by) { tags.push(`inspired:${args.inspired_by.replace('@', '')}`); } if (args.for_request) { tags.push(`fulfills:${args.for_request}`); } // Post to board const response = await fetch(`${apiUrl}/api/board`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ author: myHandle, content, category: 'shipped', tags }) }); const data = await response.json(); if (!data.success) { return { display: `ā ļø Failed to announce ship: ${data.error}` }; } let display = `š shipped\n\n${args.what}`; if (args.url) { display += `\n${args.url}`; } if (args.inspired_by) { display += `\n_via @${args.inspired_by.replace('@', '')}_`; } // Generate share-ready tweet const tweetParts = [`Just shipped: ${args.what} š`]; if (args.url) tweetParts.push(args.url); tweetParts.push('#vibecoding'); const tweet = tweetParts.join(' '); display += `\n\n---\nš **Share it:**\n\`${tweet}\``; return { display }; } catch (error) { return { display: `## Ship Error\n\n${error.message}` }; } } - tools/ship.js:16-46 (schema)The tool definition/schema for vibe_ship, defining the name, description, and inputSchema with properties: what (required), url, inspired_by, for_request, and tags.
const definition = { name: 'vibe_ship', description: 'Announce something you just shipped to the community board and update your profile.', inputSchema: { type: 'object', properties: { what: { type: 'string', description: 'What you shipped (brief description)' }, url: { type: 'string', description: 'URL to your ship (deployed site, repo, demo)' }, inspired_by: { type: 'string', description: 'Handle of person who inspired this (@alice)' }, for_request: { type: 'string', description: 'Request ID this fulfills (if building for someone)' }, tags: { type: 'array', items: { type: 'string' }, description: 'Tags for discovery (e.g., ["ai", "mcp", "tools"])' } }, required: ['what'] } }; - index.js:165-175 (registration)Registration of vibe_ship in the tools map: requiring './tools/ship' and mapping it to the 'vibe_ship' key.
const tools = { vibe_start: require('./tools/start'), vibe_init: require('./tools/init'), vibe_who: require('./tools/who'), vibe_dm: require('./tools/dm'), vibe_inbox: require('./tools/inbox'), vibe_status: require('./tools/status'), vibe_ship: require('./tools/ship'), vibe_discover: require('./tools/discover'), vibe_help: require('./tools/help'), }; - index.js:35-38 (registration)Safety annotations for vibe_ship: readOnlyHint=false, destructiveHint=false, idempotentHint=false, openWorldHint=true.
vibe_ship: { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: true }, vibe_discover: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true }, vibe_help: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false }, }; - index.js:271-277 (registration)vibe_ship is listed as a state-changing tool that triggers list_changed notifications after execution.
const stateChangingTools = [ 'vibe_dm', 'vibe_status', 'vibe_ship' ]; if (stateChangingTools.includes(params.name)) { // Debounced notification (prevents spam) global.vibeNotifier?.emitChange(params.name); }