Skip to main content
Glama
qualify-lead.v1.ts5.6 kB
/** * Qualify Lead v1 Prompt * * Resolve lead, scan 2-3 web sources, return BANT/CHAMP summary with evidence, * propose next actions. */ import { z } from 'zod'; import { PromptV1Definition, PromptMessage, PromptArgument } from './types.js'; import { DryRunArg } from './types.js'; import { WEB_RESEARCH_LIMITS } from './constants.js'; /** * Argument schema for qualify_lead.v1 */ export const QualifyLeadArgs = z.object({ target: z .string() .min(3) .describe('Attio Person/Company/Deal URL or ID, or "search:<text>"'), icp_preset: z .string() .optional() .describe("Optional ICP preset (e.g., 'SaaS mid-market NA')"), framework: z .enum(['bant', 'champ']) .optional() .default('bant') .describe('Qualification framework'), format: z .enum(['json', 'table']) .optional() .default('json') .describe('Output format'), verbosity: z .enum(['brief', 'normal']) .optional() .default('brief') .describe('Response detail level'), dry_run: DryRunArg, limit_web: z .number() .int() .min(1) .max(WEB_RESEARCH_LIMITS.maxLimitWeb) .optional() .default(WEB_RESEARCH_LIMITS.defaultLimitWeb) .describe( `Max pages to fetch (default ${WEB_RESEARCH_LIMITS.defaultLimitWeb}, max ${WEB_RESEARCH_LIMITS.maxLimitWeb})` ), }); export type QualifyLeadArgsType = z.infer<typeof QualifyLeadArgs>; /** * Argument definitions for registration */ export const qualifyLeadArguments: PromptArgument[] = [ { name: 'target', description: 'Attio URL, ID, or "search:<text>"', required: true, schema: z.string().min(3), }, { name: 'icp_preset', description: "Optional ICP preset (e.g., 'SaaS mid-market NA')", required: false, schema: z.string(), }, { name: 'framework', description: 'bant | champ (default bant)', required: false, schema: z.enum(['bant', 'champ']), default: 'bant', }, { name: 'format', description: 'json | table (default json)', required: false, schema: z.enum(['json', 'table']), default: 'json', }, { name: 'verbosity', description: 'brief | normal (default brief)', required: false, schema: z.enum(['brief', 'normal']), default: 'brief', }, { name: 'dry_run', description: "Only propose, don't execute (default false)", required: false, schema: z.boolean(), default: false, }, { name: 'limit_web', description: `Max pages (default ${WEB_RESEARCH_LIMITS.defaultLimitWeb}, max ${WEB_RESEARCH_LIMITS.maxLimitWeb})`, required: false, schema: z.number().int().min(1).max(WEB_RESEARCH_LIMITS.maxLimitWeb), default: WEB_RESEARCH_LIMITS.defaultLimitWeb, }, ]; /** * Build prompt messages for qualifying lead */ export function buildQualifyLeadMessages( args: Record<string, unknown> ): PromptMessage[] { const validated = QualifyLeadArgs.parse(args); const icpContext = validated.icp_preset ? `ICP context: "${validated.icp_preset}" affects scoring thresholds.` : ''; const instructions = `Goal: produce a compact lead-qualification summary with evidence, then optionally update fields and create a next-action task. ${icpContext} Steps: 1) Resolve \`target\`: If starts with \`search:\`, call \`records_query\` to find one Person/Company (prefer exact domain/email + title+company). If multiple, list up to 5 for disambiguation and STOP. 2) Build a tiny web plan (token-light): At most ${validated.limit_web} pages total. Prioritize: company homepage (domain), LinkedIn company page, product/pricing page. Call \`web.search\` only if domain is unknown; otherwise skip search. Call \`web.fetch\` and extract readable text only (strip nav/boilerplate). Truncate each page to the first ~${WEB_RESEARCH_LIMITS.maxWordsPerPage} words. 3) Extract key facts for ${validated.framework.toUpperCase()}: - Firmographic: industry, employee bucket, region; ICP match - Problem fit: product category/keywords - Budget: pricing tier mentions - Authority: likely buyer role(s) - Timing/Priority: hiring/funding/news in last 12 months 4) Output (${validated.format}): - If json: return ONLY a JSON object with fields: lead, framework, fit, score, summary (≤80w), evidence (≤${WEB_RESEARCH_LIMITS.maxEvidence}), fields_to_update, recommended_next_step (≤20w) - If table: return a 2-column table Verbosity=${validated.verbosity} → no preamble 5) Propose actions: Suggest a single \`records.update\` and optionally \`tasks.create\`. ${validated.dry_run ? 'Output proposed tool call(s) as JSON only.' : 'Ask for approval before any write.'} Constraints: Pages ≤ ${validated.limit_web}, each ≤ ~${WEB_RESEARCH_LIMITS.maxWordsPerPage} words; evidence max ${WEB_RESEARCH_LIMITS.maxEvidence}. Keep answers short and structured; no raw dumps; JSON under ~120 lines. MORE_AVAILABLE: true when results exceed limits.`; return [ { role: 'user', content: { type: 'text', text: instructions, }, }, ]; } /** * Complete prompt definition */ export const qualifyLeadPrompt: PromptV1Definition = { metadata: { name: 'qualify_lead.v1', title: 'Qualify a lead (light web research)', description: 'Resolve a lead, scan 2-3 web sources, return a BANT/CHAMP summary with evidence, and propose next actions.', category: 'analysis', version: 'v1', }, arguments: qualifyLeadArguments, buildMessages: buildQualifyLeadMessages, tokenBudget: 400, // Per spec (with defaults) }; export default qualifyLeadPrompt;

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/kesslerio/attio-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server