jevrecipes

Recipe catalog / next-chord

Pick the next chord

Which candidate chord best continues progression, given any key and style supplied?

A generation loop has a chord progression so far, application code has enumerated a few chords it could play next, and you want a musical judgment of which continuation a listener in the stated style would expect or enjoy.

Explore this recipe interactively ยท Source and implementation guide

Use next-chord in TypeScript

Install with npm install jev-recipes. Requires Node.js 22.9 or newer and ES modules. Set TYPESAFE_API_KEY in your server environment for live calls, which send input to TypeSafe and use API quota. See the installation guide.

import { nextChord } from 'jev-recipes/next-chord';

const result = await nextChord({
  "progression": "C - Am - F - G",
  "key": "C major",
  "style": "pop ballad, end of the first verse",
  "candidates": [
    {
      "id": "c",
      "text": "C (return to the tonic)"
    },
    {
      "id": "am",
      "text": "Am (deceptive move to the submediant)"
    }
  ],
  "minConfidence": 0.8
});
console.log(result);

Input contract

FieldTypeNeeded
progressionstringRequired
candidatesarrayRequired
keystringOptional
stylestringOptional
minConfidencenumberOptional
Full input and result schemas
{
  "input": {
    "$schema": "https://json-schema.org/draft/2020-12/schema",
    "type": "object",
    "properties": {
      "progression": {
        "type": "string"
      },
      "candidates": {
        "minItems": 1,
        "maxItems": 50,
        "type": "array",
        "items": {
          "type": "object",
          "properties": {
            "id": {
              "type": "string"
            },
            "text": {
              "type": "string"
            }
          },
          "required": [
            "id",
            "text"
          ]
        }
      },
      "key": {
        "type": "string"
      },
      "style": {
        "type": "string"
      },
      "minConfidence": {
        "type": "number",
        "minimum": 0,
        "maximum": 1
      }
    },
    "required": [
      "progression",
      "candidates"
    ]
  },
  "result": {
    "$schema": "https://json-schema.org/draft/2020-12/schema",
    "type": "object",
    "properties": {
      "model": {
        "type": "string"
      },
      "usage": {
        "type": "object",
        "properties": {
          "input_tokens": {
            "type": "integer",
            "minimum": 0,
            "maximum": 9007199254740991
          },
          "output_tokens": {
            "type": "integer",
            "minimum": 0,
            "maximum": 9007199254740991
          }
        },
        "required": [
          "input_tokens",
          "output_tokens"
        ],
        "additionalProperties": false
      },
      "status": {
        "type": "string",
        "enum": [
          "ready",
          "review"
        ]
      },
      "verdict": {
        "type": "string",
        "enum": [
          "matched",
          "none",
          "ambiguous"
        ]
      },
      "selection": {
        "type": [
          "string",
          "null"
        ]
      },
      "suggestedSelection": {
        "type": [
          "string",
          "null"
        ]
      },
      "confidence": {
        "type": "number",
        "minimum": 0,
        "maximum": 1
      },
      "probabilities": {
        "type": "object",
        "properties": {
          "candidates": {
            "type": "object",
            "propertyNames": {
              "type": "string"
            },
            "additionalProperties": {
              "type": "number",
              "minimum": 0,
              "maximum": 1
            }
          },
          "none": {
            "type": "number",
            "minimum": 0,
            "maximum": 1
          },
          "ambiguous": {
            "type": "number",
            "minimum": 0,
            "maximum": 1
          }
        },
        "required": [
          "candidates",
          "none",
          "ambiguous"
        ],
        "additionalProperties": false
      }
    },
    "required": [
      "model",
      "usage",
      "status",
      "verdict",
      "selection",
      "suggestedSelection",
      "confidence",
      "probabilities"
    ],
    "additionalProperties": false
  }
}

Saved example result

This hand-authored response demonstrates the contract. It is not a model accuracy measurement. Run it without an API key: npx jev-recipes demo next-chord.

{
  "model": "demo-fixture",
  "usage": {
    "input_tokens": 0,
    "output_tokens": 0
  },
  "status": "ready",
  "verdict": "matched",
  "selection": "c",
  "suggestedSelection": "c",
  "confidence": 0.88,
  "probabilities": {
    "candidates": {
      "c": 0.88,
      "am": 0.08
    },
    "none": 0.02,
    "ambiguous": 0.02
  }
}

Evaluation evidence

Fixture only

No verified live accuracy measurement is available. Evaluate representative cases before using this decision in your workflow.

Use the evaluation guide to measure this decision on your own labeled cases.

Limitations

Related recipes