Skip to main content

Jupyter kernel for the Gallowglass programming language (PLAN target).

Project description

Gallowglass

An LLM-first programming language targeting the PLAN virtual machine.

What is Gallowglass?

Gallowglass is a statically typed functional programming language designed with two equally weighted goals:

  1. LLMs can write it correctly. High local constraint at every token, effects visible in every signature, canonical naming enforced by the compiler, no implicit state.
  2. LLMs can reason about it accurately. Pure by default, explicit effects, contracts stated from mathematical specifications, Glass IR makes compiler decisions visible.

It compiles to PLAN --- a minimal graph-reduction VM with four constructors (Pin, Law, App, Nat) and five opcodes. All types are erased at compile time; type errors are purely a compile-time concern.

Quick taste

-- Algebraic types
type Result a b =
  | Ok  a
  | Err b

-- Effects are always visible in type signatures
let read_file : Path -> {IO, Exn IOError | r} Bytes

-- Handlers discharge effects locally
handle computation {
  | return x  -> x
  | raise e k -> default_value
}

-- Typeclasses
class Eq a {
  let eq : a -> a -> Bool
  let neq : a -> a -> Bool
  let neq = \ xx yy -> not (eq xx yy)
}

-- Where clauses and operator sections
let hypotenuse = \ aa bb ->
  result
  where { sq_a = aa * aa ; sq_b = bb * bb ; result = sq_a + sq_b }

let incremented = map (+ 1) my_list

Naming is compiler-enforced: snake_case for values, PascalCase for types, single lowercase letters for type variables. Unicode operators (->, \) are normalized to canonical forms (-> to \u2192, \ to \u03bb) at the lexer.

Project structure

gallowglass/
  SPEC.md                -- Full language specification
  ROADMAP.md             -- Delivery plan and forward work
  DECISIONS.md           -- Design rationale for non-obvious choices

  spec/                  -- Component specifications
  bootstrap/             -- Python bootstrap compiler (lexer -> parser -> scope -> typecheck -> codegen -> emit)
  prelude/src/Core/      -- Core prelude in Gallowglass (8 modules, 112 definitions)
  compiler/src/          -- Self-hosting compiler in Gallowglass
  tests/                 -- Test suite (bootstrap, prelude, compiler)
  doc/                   -- Language guide, phrasebook, and references
  tutorials/             -- Notebook-based walkthroughs for the Jupyter kernel

Build and test

# Run all tests
python3 -m pytest tests/

# Run bootstrap compiler tests only
python3 -m pytest tests/bootstrap/

# Compile a Gallowglass file
python3 -c "
from bootstrap.lexer import lex; from bootstrap.parser import parse
from bootstrap.scope import resolve; from bootstrap.codegen import compile_program
from bootstrap.emit_seed import emit
import sys
src = open(sys.argv[1]).read()
prog = parse(lex(src, sys.argv[1]), sys.argv[1])
resolved, _ = resolve(prog, 'Module', {}, sys.argv[1])
compiled = compile_program(resolved, 'Module')
sys.stdout.buffer.write(emit(compiled, 'Module.main'))
" input.gls > output.seed

Skipped tests are planvm-gated (the legacy xocore VM, no longer a deployment target) or deep-recursion stress tests that exceed Python's stack. Run python3 -m pytest tests/ -q for current pass/skip totals.

Interactive use

Jupyter kernel

A Jupyter kernel evaluates Gallowglass cells in-process via the Python BPLAN harness — declarations accumulate across cells, expressions render as cell results.

Install the kernelspec once per Python environment:

python3 -m bootstrap.jupyter_kernel install

This registers a gallowglass kernel with Jupyter (under ~/Library/Jupyter/kernels/gallowglass/ on macOS, ~/.local/share/jupyter/kernels/gallowglass/ on Linux). Then launch a notebook:

jupyter lab    # or `jupyter notebook`

and choose Gallowglass from the kernel selector.

A typical session:

-- Cell 1: declaration — renders as `twice : Nat → Nat`
let twice : Nat → Nat = λ n → n + n

-- Cell 2: expression — renders as `42`
twice 21

-- Cell 3: text — renders as `"hello"` (quoted)
"hello"

-- Cell 4: more declarations
use Core.Pair unqualified { Pair, MkPair }
use Core.List unqualified { List, Cons, Nil }

-- Cell 5: compound value — renders as `Cons (MkPair 1 10) (Cons (MkPair 2 20) Nil)`
Cons (MkPair 1 10) (Cons (MkPair 2 20) Nil)

-- Cell 6: pattern match — renders as `8`
let snd_plus_one : Pair Nat Nat → Nat
  = λ p → match p { | MkPair _ b → b + 1 }
snd_plus_one (MkPair 3 7)

Cell output is type-driven. Declaration cells (let, type, use) display a one-line summary per declaration so the user can see what was just added to the notebook (twice : Nat → Nat). Expression cells render the result value:

  • Primitives (Nat, Bool, Text) render in their canonical literal forms — 42, True, "hello".
  • Constructors (user-defined types, Pair, Option, List, Result) render with their constructor names recovered from the compile-time con_info table — MkPair 3 7, Cons 1 (Cons 2 Nil), Some 42. Field types are derived by matching each constructor's scheme against the cell's instantiated type and applying the substitution.
  • Functions render as <λ : Nat → Nat>, surfacing the type rather than the underlying law structure.

Output is emitted as both text/plain and text/html — JupyterLab and notebooks render the colourised HTML form (constructor names in bold blue, types in muted italic, numbers in cyan, strings in green, keywords in orange italic). Terminals and JSON exports fall back to the plain text rendering, which carries the same content without colour.

If the cell isn't an expression at all, it's parsed as one or more top-level declarations and accumulated into the notebook's module. A failing cell does not corrupt the accumulated state — the next cell still sees whatever the last successful cell defined.

The kernel runs entirely in Python and does not require Reaver or Nix.

To uninstall the kernel:

jupyter kernelspec remove gallowglass

Tutorials

Notebook-based walkthroughs live under tutorials/. Lesson 1 covers declarations, types, algebraic types, and pattern matching:

jupyter lab tutorials/01-hello-gallowglass.ipynb

Each lesson is regenerable from its sibling _build_lesson_NN.py script, which captures real kernel output so the committed notebooks stay in sync with the renderer. See tutorials/README.md for authoring details.

LLM-context reference

doc/phrasebook.md is a dense, LLM-shaped reference of canonical Gallowglass patterns, common pitfalls (the type-variable / binding- name lex distinction, let-in vs decl-let, class-method dispatch boundaries), and current bootstrap limitations. Designed to be included verbatim in an LLM's context window.

MCP server

For LLM-driven workflows, an MCP (Model Context Protocol) server exposes six tools over stdio:

Tool Purpose
compile_snippet Compile a source snippet, return IR and pin table
infer_type Infer the type of a name or expression
explain_effect_row Explain an effect row in prose
render_fragment Render a Glass IR fragment by FQ name
lookup_fragment Look up Glass IR for a specific name
get_context Bundle Glass IR for multiple names within a token budget
python3 -m bootstrap.mcp_server

The server loads the Core prelude once at startup and threads it as priors into every per-call snippet build. See bootstrap/mcp_server.py for the protocol shape.

Running under Reaver

tools/run_reaver.py compiles a .gls file via the Python bootstrap and hands the result to Reaver's plan-assembler CLI. Requires vendor/reaver/ (run tools/vendor.sh) and nix or cabal on PATH.

Discover what a file exports (load-only — no --fn):

python3 tools/run_reaver.py demos/csv_table.gls CsvTable
# OK — all bindings loaded.  'CsvTable' exports:
#   list_nth
#   max_nat
#   table_get_field
#   col_max
#   row0  row1  row2
#   table
#   row_count_result
#   col_count_result
#   top_score_result
#   get_field_result

Inspect a pure value (--trace embeds a (Trace ...) call; Reaver evaluates and prints):

python3 tools/run_reaver.py demos/csv_table.gls CsvTable --fn top_score_result --trace
# 95

Run an I/O entry point (stdin/stdout wired through, for programs using Reaver.RPLAN.input/output):

echo 'let xx = 42' | \
    python3 tools/run_reaver.py compiler/src/Compiler.gls Compiler \
        --fn main_reaver --no-prelude

The --no-prelude flag skips loading the Core prelude — use it for self-contained files (like Compiler.gls) that define their own primitives via external mod. Omit it for files that use Core.Nat, use Core.List, etc.

Via make:

make reaver-run SRC=demos/csv_table.gls MOD=CsvTable
make reaver-run SRC=demos/csv_table.gls MOD=CsvTable FN=top_score_result REAVER_ARGS=--trace

Design principles

  • Contracts derive tests. Tests do not become contracts. A contract is valuable if it could be written by someone who only had the mathematical specification.
  • Effects are always locally visible in type signatures. Nothing is hidden.
  • Pure by default. Effect annotation is explicit, not implicit.
  • Structural truth over convenient fictions. The type system never lies.
  • Representation has audience. Show is for users. Debug is for developers. Serialize is for machines. Never conflate them.

Status

The bootstrap compiler, core prelude, and self-hosting compiler are in place. The language is usable for writing programs that compile to PLAN.

What works:

  • Full surface syntax: let bindings, lambdas, pattern matching (with exhaustiveness checking), algebraic types, records, type aliases, list syntax
  • Effect system: algebraic effects with CPS handlers, shallow (once) handlers, do-notation
  • Typeclasses: single-parameter classes, superclass constraints, default methods, constrained instances, dictionary-passing codegen
  • Module system: use imports, export lists, pin-based module loading (BLAKE3-256 content addressing)
  • Glass IR: type-annotated intermediate representation with round-trip verification
  • Self-hosting: compiler written in Gallowglass processes its own source and produces correct Plan Assembler output

Forward work — including deriving, contract solver tiers, nested list patterns, the Rust VM, the debugger, and the jet optimizer — is tracked in ROADMAP.md.

License

See repository for license terms.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

gallowglass_kernel-0.1.0.tar.gz (184.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

gallowglass_kernel-0.1.0-py3-none-any.whl (196.5 kB view details)

Uploaded Python 3

File details

Details for the file gallowglass_kernel-0.1.0.tar.gz.

File metadata

  • Download URL: gallowglass_kernel-0.1.0.tar.gz
  • Upload date:
  • Size: 184.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.7

File hashes

Hashes for gallowglass_kernel-0.1.0.tar.gz
Algorithm Hash digest
SHA256 05326ee52224d9d91f8de8d8e2092075dbdcd880f4cd68ef3e42b756d33f3735
MD5 d16a3f064cac091e054e0dd373eba06f
BLAKE2b-256 a166f1654e5cb05c041010de46a667fbdc55a5f83d21f9e4ab3055d9825769be

See more details on using hashes here.

File details

Details for the file gallowglass_kernel-0.1.0-py3-none-any.whl.

File metadata

File hashes

Hashes for gallowglass_kernel-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 679c1b503ada6d8ddd784e70106d0fb0334168e992e42094c07870eca3a7a80d
MD5 5d20f5944518e45252255dfe23eabb24
BLAKE2b-256 1e8c033d2eb95999e002af18dcd47872f40101dfcff4d846e35d70e3b0995d83

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page