jevascript
esc

    Type to search · ↑↓ to move · ↵ to open

    Get started

    Scenarios

    Lead qualification

    Your ideal customer profile lives in one place, as prose the revenue team can edit. Every lead is judged against it in one request.

    Source: examples/launch/02-lead-qualification.ts

    The problem#

    An inbound form arrives with a company, a role and a free-text message. Someone has to decide whether an account executive calls today, a solutions engineer follows up, or the lead gets a self-serve email. The criteria change every quarter and they belong to sales, not engineering.

    The schema#

    The ideal customer profile and the disqualifiers are context. Changing them is a config edit, not a deploy.

    qualify.ts
    import { boolean, defineSchema, enumOf, object, score } from "jevascript"
    
    export const qualify = defineSchema({
      name: "lead-qualification",
      version: "3",
    
      instructions: `
        Qualify an inbound lead for Northwind, a B2B payments API sold to engineering
        teams. Judge the lead only on what the form and enrichment actually say.
        Absence of evidence is not evidence of a poor fit — score it low, not negative.
      `,
    
      context: {
        idealCustomer: `
          Series A to Series C software companies, 50-500 employees, processing
          payments as a core part of their product rather than to collect their own
          subscription fees. Marketplaces and vertical SaaS are the strongest fits.
        `,
        disqualifiers: `
          Agencies and consultancies reselling to clients. Companies in regulated
          lending. Students and personal projects.
        `,
        competitors: ["Stripe Connect", "Adyen for Platforms", "Moov"],
      },
    
      output: object({
        icpFit: score(0, 100, "This company matches the ideal customer profile."),
        buyingIntent: score(0, 100, "This person is actively evaluating a solution right now."),
        technicalDepth: score(0, 100, "The writer understands the technical problem they describe."),
        switching: boolean({
          describe: "The lead is moving away from a named competitor.",
          falseWhen: "Merely mentioning a competitor as a reference point.",
        }),
        disqualified: boolean({
          describe: "This lead matches one of the disqualifiers.",
          trueWhen: "An agency, a reseller, regulated lending, a student, or a personal project.",
        }),
        segment: enumOf(
          {
            marketplace: "Connects buyers and sellers and needs to split or route funds",
            vertical_saas: "Software for one industry that embeds payments for its customers",
            platform: "Lets other businesses build on top of them and pay out to them",
            internal: "Only wants to collect payment for their own product",
            unclear: "Not enough information to tell",
          },
          "What kind of business is this",
        ),
      }),
    })

    Note the unclear option. A choice always picks something; giving it an honest "not enough information" option is how you keep it from guessing.

    The decision#

    Routing is arithmetic on values you can explain to a sales leader:

    route.ts
    const q = await qualify({ company, employees, funding, role, message })
    
    const priority = q.icpFit * 0.5 + q.buyingIntent * 0.35 + q.technicalDepth * 0.15
    
    const route = q.disqualified
      ? "nurture — disqualified"
      : priority > 70
        ? "book AE call today"
        : priority > 45
          ? "solutions engineer follow-up"
          : "self-serve onboarding email"

    The weights are a line of code. Changing them is a pull request with a diff, and a test can pin the routing for a known lead.

    Why three scores instead of one#

    "How good is this lead?" would give one opaque number. Three independent propositions give three numbers you can weigh, log, and chart separately. When the sales team asks why a lead was routed somewhere, the answer is icpFit 82, intent 40, not "the model said so".

    What to test#

    • A marketplace on Series B, switching from a competitor → book AE call today and switching === true.
    • An agency asking for a reseller programme → disqualified === true, routed to nurture regardless of the scores.
    • Change a weight → a snapshot test on route for a fixed set of stubbed answers catches the effect.