Scala on Go — and the feedback loop an AI coding agent actually wants.

GALA for AI — the compiler is the agent’s feedback loop

A coding agent is only as fast as its feedback signal. It works in discrete generate → check → fix turns, and the quality of “check” decides how many turns it burns to reach correct code. GALA’s compiler turns whole classes of bugs into an instant, precise, deterministic error at the exact edit site — no test harness, no lucky code-path coverage, no runtime surprise.

This is not a claim that GALA writes better code. It’s a claim about loop economics: where the error surfaces, how precise it is, and whether the agent has to run the program to discover it.

GALA for AI — the compiler is the agent's feedback loop: a loosely-checked language forces a slow runtime-discovery loop, while GALA fails fast at compile time with an exact error.


Why this matters for agents specifically

Human developers tolerate a loose feedback loop because they hold context in their heads. An agent doesn’t — every turn that requires running code costs more than a turn that only requires compiling it.

  Loosely-checked language GALA (compile-time fast-fail)
Where the bug shows runtime, only on an exercised path build time, always
To even reach it write and run a test harness just gala build
Precision stack trace at the symptom file:line at the root edit + what’s missing
Determinism flaky / path-dependent same input → same error
Escapes to prod yes, if untested no — it will not compile

Fewer turns per fix, and no “did my test actually cover that path?” gamble. The compiler is a free, exhaustive reviewer the agent can call on every turn.


The demo: extend a closed set

The single most common refactor an agent performs is extending a closed set — “add a Crypto payment method.” Here a sealed type is matched on in three places. The agent adds the variant and forgets the match sites — the realistic mistake.

GALA — compiler hands you a worklist

sealed type Payment {
    case Card(Last4 string)
    case Cash()
    case Bank(Iban string)
    case Crypto(Chain string)  // agent added
}

// three match sites now incomplete
func label(p Payment) string = ...
func fee(p Payment) float64  = ...
func requiresName(p Payment) bool = ...

Go — compiles clean, ships the bug

type Payment interface{ isPayment() }
type Card struct{ Last4 string }
type Cash struct{}
type Bank struct{ Iban string }
type Crypto struct{ Chain string } // added

func label(p Payment) string {
    switch v := p.(type) {
    case Card: return "card ****" + v.Last4
    case Cash: return "cash"
    case Bank: return "bank " + v.Iban
    }
    return "" // Crypto silently lands here
}

Run each build. GALA fails, and names the exact site and the missing variant — one precise task per build, until green:

$ gala run main.gala
[GALA-E0002] line 13:4 non-exhaustive match: missing cases: Crypto
  (hint: add the missing variant cases, or add a `case _ => ...` default)

# fix label(), rebuild → line 20:4 (fee)
# fix fee(),   rebuild → line 27:4 (requiresName)
# fix all three         → compiles, runs

Go compiles the same mistake with no error and no warning, and label(Crypto{"eth"}) returns "" at runtime — forever, unless a test happens to pass a Crypto value through label and assert the result. The agent would have to predict the exact bug in advance. Dynamically-typed languages are worse: the mistake hides until that line executes in production.

(The transcript above is real output from GALA — the compiler stops at the first incomplete site, so each build is a deterministic step toward green.)


Which features feed the loop

Exhaustiveness is the flagship, but the same runtime → compile-time shift runs through the language. Each one is another class of bug the agent is told about for free, instead of having to discover by running code:

Every one converts a “write a test and hope” turn into a “read the compiler” turn.


Honest limits


Try it