Start Jamming LLM Agent Guide
Start Jamming (https://www.startjamming.com) is the website for Grass, a bluegrass jam companion. Its public data includes a canonical Songbook, chord charts, lyrics, demo videos, learning videos, curated collections, and custom songs that their authors have chosen to share.
This guide documents the supported public read surfaces. Other /api/...
routes used by the Grass app may require authentication and are not part of
the public agent contract.
Contact
Questions about usage, integration, traffic patterns, or high-volume access:
Elijah Mayfield elijah@treeforts.org
Agent identification
Append for=agent to every /api/songs/* request made by an LLM agent.
For example:
https://www.startjamming.com/api/songs/index?for=agent
Known agent clients that omit this parameter receive a 400 response linking back to this guide. The parameter also gives agent responses canonical URLs and removes fields that are not reliable enough for agents to surface.
The public Learn and custom-song endpoints documented below do not currently
have an agent-specific response mode, so for=agent is not required there.
Canonical Songbook endpoints
These endpoints require no API key or authentication.
| URL | Use it for | ETag |
|---|---|---|
GET /api/songs/search?for=agent&q=... |
Ranked lookup by exact or partial title, misspelling, song ID, or lyric fragment. limit may be 1 through 20 and defaults to 8. |
Yes for normal searches |
GET /api/songs/index?for=agent |
Catalog discovery. Returns no chord sections, but currently includes metadata, lyrics, demo URLs, canonical id, human url, and full-song api_url. |
Yes |
GET /api/songs/<id>/full?for=agent |
One canonical song with legacy song fields plus a normalized arrangement. Add key=G, key=Bb, and so on to transpose the arrangement. |
Yes, per song |
GET /api/songs/catalog?for=agent |
Every canonical song in one response. Use only for a deliberate bulk mirror. | Yes, catalog-wide |
GET /api/songs/collections?for=agent |
Live curated collection definitions and their ordered song IDs. | Yes |
GET /api/songs/<id>/data?for=agent |
Full song data, normalized arrangement, and bundles, which are collection memberships for that song. |
Yes, catalog-wide |
GET /api/songs/<id>/content?for=agent |
Optional editorial sections: about_section, structure_section, jam_section, and is_jambuster. Returns has_content: false when none exists. |
No |
GET /api/songs/<id>/pdf?for=agent&key=A |
Printable PDF, optionally transposed with key. This returns application/pdf, not JSON. |
No |
GET /api/songs/<id>/backing-track?for=agent&key=A&tempo=100 |
Generated MP3 backing track. Optional bass, guitar, and mandolin booleans default to true; tempo must be 60 through 200. |
No |
Legacy routes such as GET /api/songs, GET /api/songs/<id>, and
GET /api/songs/title/<title> remain available for older clients but should
not be used for new integrations. Their response and caching behavior are
less consistent than the endpoints above.
Recommended discovery flow
- If the user gives a title or lyric fragment and you do not know the
canonical song ID, call
GET /api/songs/search?for=agent&q=<user text>. - An exact normalized title returns a top-level song object with
"match_type": "title_exact". A partial or fuzzy query returns aresultsarray sorted by descending score. - Use
scoreandmatch_typeas confidence signals. Ask a short clarification question when multiple results are close. - Follow the returned
api_urlwhen you need the normalized arrangement or the latest complete representation. Do not reconstruct identifiers when the API has already supplied the URL. - For repeated use, cache
/api/songs/index?for=agentwith its ETag. Revalidate withIf-None-Match; an unchanged resource returns 304.
Identifiers and links
id,canonical_id, andslugare the canonical public, hyphenated identifier used in human song URLs, such asclinch-mountain-backstep.song_idis the older internal underscore identifier, such asclinch_mountain_backstep. It remains accepted for compatibility.api_urlis the safest URL for the full JSON representation.urlis the canonical human-readable page to show users.
Prefer id, api_url, and url exactly as returned.
Index response
The index is an object keyed by internal song_id. Each value carries the
canonical public identifiers and links:
{
"sitting_on_top_of_the_world": {
"id": "sitting-on-top-of-the-world",
"canonical_id": "sitting-on-top-of-the-world",
"song_id": "sitting_on_top_of_the_world",
"slug": "sitting-on-top-of-the-world",
"url": "https://www.startjamming.com/song/sitting-on-top-of-the-world",
"api_url": "https://www.startjamming.com/api/songs/sitting-on-top-of-the-world/full?for=agent",
"title": "Sitting On Top Of The World",
"key": "G",
"type": "vocal",
"has_lyrics": true,
"demo": ["https://www.youtube.com/watch?v=..."],
"featured_demo": [],
"updated_at": "2026-06-05T12:00:00"
}
}
The index omits chord sections and normalized arrangements, but lyrics and
demo arrays may be present. Do not assume it is metadata-only. Fetch the
returned api_url before presenting a chord chart.
Search responses
Exact normalized title match:
{
"query": "Sitting on top of the world",
"normalized_query": "sitting on top of the world",
"match_type": "title_exact",
"score": 1.0,
"id": "sitting-on-top-of-the-world",
"canonical_id": "sitting-on-top-of-the-world",
"song_id": "sitting_on_top_of_the_world",
"slug": "sitting-on-top-of-the-world",
"url": "https://www.startjamming.com/song/sitting-on-top-of-the-world",
"api_url": "https://www.startjamming.com/api/songs/sitting-on-top-of-the-world/full?for=agent",
"title": "Sitting On Top Of The World",
"key": "G",
"type": "vocal",
"sections": []
}
Partial or fuzzy match:
{
"query": "Sitting on top of the world",
"normalized_query": "sitting on top of the world",
"results": [
{
"id": "sitting-on-top-of-the-world",
"canonical_id": "sitting-on-top-of-the-world",
"song_id": "sitting_on_top_of_the_world",
"slug": "sitting-on-top-of-the-world",
"title": "Sitting On Top Of The World",
"url": "https://www.startjamming.com/song/sitting-on-top-of-the-world",
"api_url": "https://www.startjamming.com/api/songs/sitting-on-top-of-the-world/full?for=agent",
"score": 0.94,
"match_type": "title_contains",
"matched_text": "Sitting On Top Of The World",
"key": "G",
"type": "vocal",
"has_lyrics": true
}
]
}
A lyric match may also include matching_lyrics_line.
Full song response
A /full response contains both legacy source fields and the preferred
normalized arrangement:
{
"id": "clinch-mountain-backstep",
"song_id": "clinch_mountain_backstep",
"title": "Clinch Mountain Backstep",
"key": "Am",
"type": "fiddle",
"artist": "Ralph Stanley",
"tempo": 120,
"signature": "4/4",
"sections": [
{
"name": "A",
"repeats": 2,
"standard_chords": ["Am / / /"]
}
],
"lyrics": "Verse 1...\n\n<chorus>Chorus...</chorus>",
"demo": ["https://www.youtube.com/watch?v=..."],
"featured_demo": [],
"arrangement": {
"song_id": "clinch_mountain_backstep",
"title": "Clinch Mountain Backstep",
"original_key": "Am",
"target_key": "Am",
"signature": "4/4",
"default_beats_per_measure": 4,
"sections": [
{
"name": "A",
"repeats": 2,
"measures": [
{
"index": 0,
"source": "Am / / /",
"beats": ["Am", "Am", "Am", "Am"],
"display": "Am / / /",
"beat_count": 4,
"has_rest": false
}
]
}
],
"backing_track_progression": ["Am / / /", "Am / / /"],
"unique_chords": ["Am"]
}
}
Agent-mode responses intentionally omit license. Do not infer licensing
from its absence and do not copy that field from non-agent responses.
Other fields:
keyis a string or, for some multi-arrangement songs, a list.typeis a catalog classification. Current values are primarilyvocalandfiddle; integrations should tolerate new values.artist,tempo, anddescriptionare optional.signatureis optional. Missing,common, or4/4means four beats;waltzor3/4means three beats.lyricsis a string or an array of strings.lyrics_alternateslabels array-valued lyrics by index.demoandfeatured_demoare arrays of YouTube URLs.alternatesandalternate_sectionspreserve legacy alternate arrangements.
Normalized arrangement
Prefer arrangement for chord rendering, playback, and transposition. It is
the server-side normalized interpretation of older section formats.
original_keyis the source key.target_keyis the requested key, or the original key whenkeywas not supplied.sectionsis always an ordered array.- Each section has
name,repeats, and orderedmeasures. - Each measure has expanded
beats, a compactdisplaystring, and its originalsourcenotation. - A rest is represented by
nullinbeats. backing_track_progressionexpands section repeats into playback order.unique_chordslists the transposed chords used by the arrangement.
To transpose, call the API again with a target key:
/api/songs/clinch-mountain-backstep/full?for=agent&key=G
Only the normalized arrangement is transposed. Legacy top-level key,
sections, and standard_chords remain in their source form.
Legacy chord notation
Within standard_chords, each string is one measure and tokens are separated
by spaces:
- A chord such as
G,Am,D7,F#m, orBbstarts that chord. /repeats the active chord for that beat.—or-is a rest.
The legacy chords field may use a different representation and may be
empty. New integrations should use arrangement.sections[].measures[].
Raw sections is usually an ordered array of
{name, repeats, standard_chords} objects. Multi-arrangement songs may use
older nested shapes in sections and alternate_sections; this is another
reason to prefer arrangement for the default arrangement.
Lyrics convention
lyrics is either one string or an array paired by index with
lyrics_alternates. Chorus blocks may be wrapped in
<chorus>...</chorus>. Treat those tags as semantic markers, remove them
from display text, and label the enclosed block as a chorus when useful.
Preserve verse and chorus spacing. Do not claim that lyric blocks map to specific chord sections unless the data explicitly provides that mapping.
Song collections
GET /api/songs/collections?for=agent returns:
{
"collections": {
"fundamental_fiddles": {
"display": "Fundamental Fiddle Tunes",
"type": "essential",
"description": "...",
"songs": ["song_id_one", "song_id_two"],
"featured": true,
"sort_order": 0
}
}
}
Collection songs values are internal underscore IDs. Resolve them through
the Songbook index and use the returned canonical URLs.
The bundles array on /api/songs/<id>/data is the reverse lookup: each
entry describes a collection containing that song. It is not a list of demo
videos.
Learning catalog
The Learn catalog is public JSON and requires no authentication:
| URL | Contents |
|---|---|
GET /api/learning/catalog-v2/first-party |
Songs with both a primary Grass lesson and a primary Grass jam-along. |
GET /api/learning/catalog-v2/third-party |
Songs with no primary lesson or jam-along and at least one active bonus lesson or bonus jam-along. |
GET /api/learning/catalog-v2 |
Legacy compatibility view. New integrations should use the two explicit endpoints above. |
Each response has schema_version, channels, topics, videos, and
jam_alongs. A jam-along entry can contain lesson_video, jam_video,
bonus_lesson_videos, and bonus_jam_videos.
Lesson videos may include instrument, instrument_override, and
channel_instrument. Effective instrument already applies a video-specific
override before the channel default. Current instrument labels include
fiddle, banjo, guitar, mandolin, bass, dobro, harmonica,
dance, and voice.
The Learn endpoints use server-side static snapshots that refresh after
catalog edits. Each response carries an ETag; revalidate with
If-None-Match and accept 304.
Shareable custom songs
GET /api/custom-songs/<id-or-slug>/public returns a user-authored custom
song when its owner has made it public or unlisted. Private or missing songs
return 404. This endpoint requires no authentication and does not currently
return an ETag.
Custom songs are user-generated, not canonical Songbook entries. Preserve
the returned creator attribution and do not present them as universal
Songbook content. The human page is
https://www.startjamming.com/custom-songs/<slug>.
Presentation guidance
- For chord charts, use the normalized arrangement and print one section at a time with its repeat count and measure displays.
- For lyrics, remove chorus tags while preserving verse and chorus spacing.
- Use demo videos from the returned song only.
- Link back to the returned canonical human
urlafter answering. - Use the returned identifiers and URLs instead of transforming them.
Caching and etiquette
- Honor ETags from Songbook search, index, full-song, catalog, collections,
and data responses, and from the Learn catalogs. Send
If-None-Matchon later requests and accept 304. - Do not assume ETag support on custom-song, editorial-content, PDF, or backing-track routes.
- Use
/api/songs/catalog?for=agentfor a bulk mirror instead of fetching hundreds of individual songs. Use/indexplus/fullfor interactive lookups. - Always identify agent traffic on
/api/songs/*withfor=agent. - Email elijah@treeforts.org before sustained high-volume use.