Lesson 1: The map
Sections
Reading settings
No voice for this language in this browser.
More voices
Code and English terms
Off: the page’s voice reads everything, with no pause between two voices.
No voice for this language in this browser.
More voices
More voices: Microsoft Edge has natural online voices, and Windows (Settings › Time & language › Speech), macOS and Android install others.
“GA’s AI” is not one component. It is a pipeline that computes a vector for every chord shape a guitar can play and stores them in a file, and a web host that answers chat messages, sometimes with that file, sometimes with plain C# code, sometimes with a language model. This lesson draws both, then opens the chatbot host and lists what it really registers, so that the next three lessons each zoom into one box of the map.
All GA links point to commit a826864.
Running the code
Section titled “Running the code”The course program lives in code/ga-ai. The first run clones the parts of GA it needs into code/ga-ai/.ga, builds everything and compares every lesson with its expected output:
bash code/ga-ai/check.shOn Windows, run it from Git Bash; the commands are the same on the three systems. The clone is blobless and sparse: fetch-ga.sh checks out 17 project folders, about 11 MB of source, and never touches a clone of GA you may already have. On the CI runners, a whole run, clone and build included, takes 1.5 minutes on Linux and 3 on Windows. Then each lesson runs on its own:
dotnet run --project code/ga-ai/GaAi -c Release -- l1Five layers
Section titled “Five layers”GA’s CLAUDE.md describes a strict bottom-up model of five layers, and a rule: AI code goes in layer 4, orchestration in layer 5, never lower.
| Layer | Projects | What the AI side uses from it |
|---|---|---|
| 1. Core | GA.Core, GA.Domain.Core |
notes, pitch classes, the fretboard, set classes: the music theory course reads these |
| 2. Domain | GA.Business.Core, GA.Business.Config |
the records a voicing analysis fills |
| 3. Analysis | voicing generation and analysis (in GA.Domain.Services at this commit) |
VoicingGenerator, VoicingAnalyzer |
| 4. AI/ML | GA.Business.ML |
the OPTIC-K schema, the embedding generator, the index reader and search, the agents and intents |
| 5. Orchestration | GA.Business.Core.Orchestration |
ProductionOrchestrator, the skills plugin, the warm-up services |
The layer 3 projects CLAUDE.md names, GA.Business.Core.Harmony and GA.Business.Core.Fretboard, are not the ones that hold the voicing code at this commit: VoicingGenerator and VoicingAnalyzer are in Common/GA.Domain.Services. The apps sit above the five layers: the chatbot host is Apps/GaChatbot.Api, and the tool that writes the index is a demo project, Demos/Music Theory/FretboardVoicingsCLI.
Two pipelines
Section titled “Two pipelines”The diagram shows the two halves. The first group is work done once, offline: every playable chord shape becomes a vector, and the vectors go into one file. The second group is work done for each chat message.
flowchart TB subgraph Offline["Offline: build the index"] Gen["VoicingGenerator<br/>every playable shape"] --> Ana["VoicingAnalyzer<br/>chord name, notes, features"] Ana --> Doc["VoicingDocumentFactory<br/>one document per shape"] Doc --> Emb["MusicalEmbeddingGenerator<br/>240 numbers: OPTIC-K"] Emb --> Wri["OptickIndexWriter<br/>keeps 124 numbers"] Wri --> File[("optick.index")] end subgraph Online["Online: answer a chat message"] User(["POST /api/chatbot/chat"]) --> App["OrchestratedChatApplicationService"] App --> Orch["ProductionOrchestrator"] Orch --> Hooks["hooks"] Hooks --> Guards["deterministic guards<br/>voicing, algebra"] Guards --> Intents["SemanticIntentRouter<br/>36 intents"] Intents --> Agents["SemanticRouter<br/>6 agents"] Guards -. "voicing agent" .-> Search["OptickSearchStrategy"] Search --> File Intents -. "embeddings" .-> Ollama[["Ollama"]] Agents -. "embeddings, text" .-> Ollama endLesson 2 opens the embedding box, lesson 3 the index and its search, lesson 4 the orchestrator. Two remarks already:
- The same schema is used on both sides. A search query is turned into a vector with the same partitions and weights as the stored shapes, so that a dot product between them means something. If the two drift apart, the index file’s header carries a hash of the layout, and the reader refuses a file written with another one (lesson 3).
- The model server is optional for some paths and required for others. GA talks to Ollama, a local server for open-weight models, through Microsoft.Extensions.AI:
IEmbeddingGeneratorfor embeddings,IChatClientfor text. Lesson 4 shows which questions survive without it.
The sibling repositories
Section titled “The sibling repositories”GA’s CLAUDE.md names three repositories that exchange files with it:
- ix, machine learning algorithms in Rust, “produces
state/voicings/optick.indexconsumed by GA’s RAG layer”, and trains sparse autoencoders on it. In GA’s code, though, the file is written by the C#OptickIndexWriterofFretboardVoicingsCLI: GA’s ownoptic-k-rebuildskill builds the index with that CLI, then runs ix’s diagnostics on it. Whether ix can also write the file is to verify. The IX course reads ix’s code at another commit. - Demerzel, governance: its pipelines run the reviews GA’s contracts describe, and it generates the Streeling modules on this site.
- TARS, in F#, is described as a “cross-model theory validator”. Nothing in this course calls it.
What the chatbot host registers
Section titled “What the chatbot host registers”The canonical chatbot host is GaChatbot.Api: GA’s chat surfaces document says so since 2026-05-13, and says it serves the public demo at demos.guitaralchemist.com/chatbot/. The host has three modes. AddMinimalChatbotApi reads Chatbot:Mode, direct by default: direct sends every message to the model, routed uses a lightweight router, and full (or orchestrated) registers the whole orchestration stack. The course uses full.
Rather than read the registrations, the program starts the host and asks its container. WebApplicationFactory<TEntryPoint> is the class ASP.NET Core integration tests use: it runs an app’s Program inside the test process, with an in-memory server, and lets the caller override settings and services. The course’s ChatHost.cs is a console program’s version of it:
builder.UseSetting("Chatbot:Mode", "full");builder.UseSetting("Chatbot:PathBase", "");builder.UseSetting("Ollama:BaseUrl", DeadOllama);builder.UseSetting("Ollama:Endpoint", DeadOllama);builder.UseSetting("VoicingSearch:OpticIndexPath", Lesson3.IndexPath);builder.UseSetting("IX:External:Enabled", "false");DeadOllama is http://127.0.0.1:9, a port nothing listens on, so every model call fails at once, as on a CI runner. The index is a small one lesson 3 builds. The chat memory, which GA stores in ~/.ga by default, is redirected to files next to the program, so a run never reads or changes the author’s. Then Lesson1.cs resolves a few services:
== Orchestrator and application serviceIHarmonicChatOrchestrator ProductionOrchestratorIChatApplicationService (host) OrchestratedChatApplicationService36 intents
Section titled “36 intents”An intent, here, is a C# object that can answer one kind of question, with a list of example prompts. The semantic intent router compares a message with those examples (lesson 4). The host registers 36:
== Intents the semantic router chooses from (36)id examples first exampleskill.chordinfo 32 What is a C major chord?skill.scaleinfo 24 What notes are in C major?skill.modes 37 What are the modes of the major scaleskill.interval 13 What is the interval between C and G?skill.fretspan 0 (none)skill.chordsubstitution 12 Tritone substitution for G7skill.beginnerchords 7 Show me some easy beginner chordsskill.progressionmood 15 How do I make this progression sound darker?skill.circleoffifths 10 Explain the circle of fifthsskill.practiceroutine 9 give me a 20 minute practice routineskill.genreessentials 8 essential chords for blues guitarskill.whatcanyoudo 14 what can you doskill.transpose 13 transpose this progression down a half stepskill.commontones 9 What notes do Cmaj7 and Am7 share?skill.diatonicchords 20 Give me the diatonic chords in C majorskill.relativekey 12 What is the relative minor of G majorskill.theorycomparison 7 What is the difference between major and minorskill.settheoryequivalence 5 Are pitch classes 0,1,4 and 0,1,6 equivalent under inversionskill.capo 10 What shape do I play in E with capo 4skill.voiceleading 10 voice leading from C to Fskill.alternatetunings 12 what is DADGAD tuningskill.intervalclassvector 10 what is the interval-class vector of Cmaj7skill.grothendieckdelta 10 how harmonically far is Am from D7skill.icvneighbors 10 which chords are most similar to Dm7skill.icvshortestpath 10 shortest harmonic path from Cmaj7 to G7skill.grothendieckparse 10 parse C ⊗ Gskill.chordvoicings 12 voicings for Cmaj7skill.improvisation 17 what scale can I use to solo over Cmaj7?skill.outsidenotes 10 why does F sound outside over Cmaj7skill.keyidentification 7 What key is C Am F G in?skill.progressioncompletion 5 What chord comes next after C G Am?skill.rememberthis 7 remember that I prefer drop-2 voicings for jazz compingalgebra 13 Are 0146 and 0137 z-related?tab.optimize 5 Make this progression smoother to playtab.analyze 4 Analyse this tabvoicing 11 Show me Drop 2 voicings of Cmaj732 of them wrap a skill, a class implementing IOrchestratorSkill that GaPlugin registers three times over: as itself, as IOrchestratorSkill, and wrapped in an OrchestratorSkillIntent. One of them, skill.fretspan, has no example, and the router skips intents without examples: it can never be chosen by similarity.
6 agents and 4 hooks
Section titled “6 agents and 4 hooks”An agent, in GA’s code, is a class that answers with a language model, possibly calling tools. Messages no intent claims go to one of six:
== Agents behind the LLM path (6)tab TabAgenttheory TheoryAgenttechnique TechniqueAgentcomposer ComposerAgentcritic CriticAgentvoicing VoicingAgent
== Hooks, in the order they run (4)PromptSanitizationHookMemoryHookMemoryWriteHookObservabilityHookA hook runs at fixed points of every request: when it arrives, before and after a skill, when the response leaves. It’s the same idea as the hooks of the agentic coding course, on the other side: there, code around an agent you use; here, code around the agents GA runs.
The last line of the lesson ties the two pipelines together:
== The embedding every voicing getsOPTIC-K-v1.8, 240 dims in 11 partitions, 124 of them searchedWhat the chatbot is meant to become
Section titled “What the chatbot is meant to become”GA’s chatbot roadmap states its North Star in one sentence: the chatbot is “the conversational front end to the Guitar Alchemist domain”, in which “each user query is routed by intent, answered by the domain, formatted by the skill, and shaped by the LLM only at the prose layer”. The model writes sentences; the facts come from GA’s typed music theory.
Issue #623, opened on 2026-08-01 and marked P0, turns that into a user-visible goal: a guitarist gives a chord progression and a tuning, and gets the key and chord functions, scale and arpeggio choices, playable voicings with little hand movement between them, and an explanation of the trade-offs. Issue #589 names the risk it answers: “free-form LLM text asserting music-theory claims nothing validates”, and proposes that the model only fill a JSON structure that the theory engine checks.
Where things stand, as far as this course can tell on 2026-09-14:
| Status | What | Evidence |
|---|---|---|
| Works, verified here | OPTIC-K vectors, the index writer and reader, search by chord symbol, the algebra and voicing paths of the chatbot, the skills called directly | lessons 2 to 4, run in CI without a model |
| Works with a model, not verified here | routing by embeddings, the six agents, prose answers | needs Ollama; not run by this course (to verify) |
| Known problems, open | the CONTEXT partition carries nothing (#616); wrong advice on borrowed chords (#567); “E-flat major” read as E major (#554); keys of cadences (#614) | GA’s issues, open on 2026-09-14 |
| Planned | the progression-to-voicing coach (#623); validated structured output (#589) | proposed, open |
| Research | latent world models and planning over OPTIC-K (#605, #610, #611, #606, #607) | spikes, open |
The lessons add to the “known problems” row: the course found more than a dozen differences between GA’s code and its documents, listed in the journal.
Exercises
Section titled “Exercises”- Without running anything, which path answers “Are 0146 and 0137 z-related?”: an intent, an agent, or something before both? Look at the list of intents above and at the diagram.
- The host is started with
Chatbot:Modeleft at its default. WhichIChatApplicationServicedoes it resolve, and what happens to every message? - Why does the course program redirect
MemoryStoreandChatTranscriptStoreinstead of letting GA use its defaults?
Solutions
- Something before both:
ProductionOrchestratorruns a deterministic algebra check before any intent routing (lines 359-373). The prompt contains “z-related”, one of the classifier’s keywords. Thealgebraintent exists too, with this very prompt as its first example, but the fast path answers before the router is asked. Lesson 4 shows the response:routingMethod ix-algebra. DirectChatApplicationService: the default mode isdirect(line 22), and in that mode every message goes straight to the chat model with a system prompt. With the model unreachable, every message fails.- Because the defaults are files in the user’s home directory,
~/.ga: a test that writes a chat turn would change the author’s real memory, and a test that reads it would depend on it. Pointing both stores at a fresh folder makes the run repeatable and harmless.ConfigureTestServicesregisters the replacements after the app’s own registrations, so they win.
Key takeaways
Section titled “Key takeaways”- GA’s AI is two pipelines sharing one schema: offline, chord shapes become 240-number OPTIC-K vectors stored in an index; online, a chat message goes through hooks, deterministic guards, 36 intents and 6 agents.
- AI code lives in
GA.Business.ML(layer 4), orchestration inGA.Business.Core.Orchestration(layer 5); the chatbot host isGaChatbot.Api, and the index writer is a CLI inDemos. WebApplicationFactorylets a plain console program start a real ASP.NET Core host, override its settings and services, and read its container: the most reliable map of what is registered.- The North Star is a chatbot where the domain answers and the model only phrases; the planned coach slice and structured output are steps towards it, and several known problems stand in the way.
Sources
Section titled “Sources”- GuitarAlchemist/ga at
a826864:CLAUDE.md,docs/architecture/chat-surfaces.md,docs/plans/2026-05-07-chatbot-roadmap.md,Apps/GaChatbot.Api/Extensions/ServiceCollectionExtensions.cs,Common/GA.Business.Core.Orchestration/Plugins/GaPlugin.cs,Common/GA.Business.Core.Orchestration/Services/ProductionOrchestrator.cs. - GA issues #554, #567, #589, #605, #606, #607, #610, #611, #614, #616, #623, read on 2026-09-14.
- Microsoft Learn: Integration tests in ASP.NET Core, Microsoft.Extensions.AI libraries.
- Ollama.