AidaHL Coding Lab

AidaHL is the text language for Agent Hierarchy chips (.ahl). One class is one chip. Stack: Board > SoC > IC > Module / Agent. Language 1.4.

AI Hierarchy is the visual Hierarchy Builder canvas on the desktop. Circuit City is a separate product surface. The three are not the same thing.

Free / logged-out: this page is teach and practice only. There is no compile in the browser. Upgrade to Pro or Team — or sign in if you already have a plan.

Signed in — Free: Save/Compile is Pro/Team. This page does not compile or grade your AidaHL. Upgrade at /pricing.

Pro/Team: Save/Compile on aidaide.app goes through GET /api/ahl/entitlement and POST /api/ahl/compile (401 / 403 / 200). That is a gate, not a compiler body and not the desktop Hierarchy Builder. Lab Check/grade stays desktop teach text.

Windows ships 1.0.0-rc15 today. Coming in RC16 — not available to download yet.

The academy map is 25 labs / 7 tracks, in order start-here → first-chip → layers → control → ship-it → packages → runtime. Capstone: Night Watch (capstone / ship-it). This page teaches and practises. Site Save/Compile is a Pro/Team entitlement gate — not a compiler body, not Lab Check/grade, and not a working in-browser grader.

Academy map

Start here start-here First chip first-chip Layers layers Control control Ship it ship-it Packages packages Runtime runtime

Featured starters — Hello IC → hierarchy (SoC) → retry path:

Hello, chip hello-chip Two ICs, one SoC two-ics-one-soc Retry until retry-until Capstone: Night Watch capstone
TrackLab idTitleGuide
start-herefirst-wireA wireCh. 1 — Quick start
start-herefirst-objectAn objectCh. 2 — Make an object
start-herewire-it-inWire it inCh. 5 — wire(src, dst) -- two parameters
start-herefirst-promptGive it a voiceCh. 3 — Set parameters
first-chiphello-chipHello, chipCh. 1 — Quick start
first-chipname-the-castName the castCh. 2 — Make an object
first-chipdial-it-inDial it inCh. 3 — Set parameters
first-chipfail-laneThe fail laneCh. 8 — Built-in modules
layersfan-out-fan-inFan out, fan inCh. 5 — wire(src, dst) -- two parameters
layerstwo-ics-one-socTwo ICs, one SoCCh. 6 — Wire layers
layersboard-padsPads on a BoardCh. 6 — Wire layers
layerstemplatesOne class, many chipsCh. 12 — Inheritance and templates
controlgate-itGate itCh. 15 — Control -- when, else, retry, loop, each
controlretry-untilRetry untilCh. 15 — Control -- when, else, retry, loop, each
controleach-itemOne pass per itemCh. 15 — Control -- when, else, retry, loop, each
controlvalues-and-fnValues and functionsCh. 9 — Values and expressions
ship-itwrite-the-testWrite the testCh. 19 — Test blocks
ship-itcapstoneCapstone: Night WatchCh. 25 — Full walkthrough
packagesfile-importImport a fileCh. 13 — Imports
packagesinherit-overrideInherit and overrideCh. 12 — Inheritance and templates
packagescanvas-layoutPlace it on the canvasCh. 14 — Operations -- run, ask, feed, pos, size
runtimesoc-gateGate a whole laneCh. 15 — Control -- when, else, retry, loop, each
runtimejson-conditionsRead the payloadCh. 16 — Runtime conditions
runtimepayload-pinShip the work, not the reviewCh. 8 — Built-in modules
runtimeloop-untilRefine until doneCh. 15 — Control -- when, else, retry, loop, each

Start here

start-here — One line at a time: a wire, an object, a prompt.

A wire

id first-wire track start-here 20 XP · ~2 min Guide: Ch. 1 — Quick start

A chip is a box with pins. Text comes in on an in pin and leaves on an out pin. This chip has both pins already; it only needs one wire between them. Type this one line where the TODO is: wire(ticket, report);

Starter .ahl + TODO — fill the TODO lines. This page does not compile or grade.

# A wire
# Pins are already here. Add the one wire between them.

class Pass : IC {
    in  ticket : text
    out report : text

    # TODO 1: wire(ticket, report);
}

TODO — what you type:

  1. wire(ticket, report);

Desktop Check / grade intent (teach text only — this page does not grade; in-browser Check is open / awaiting Wes):

  • kind=class — a chip class is present
  • kind=wire — ticket feeds report: wire(ticket, report);

Full Check/run = desktop Hierarchy Builder / aidahl academy.

Read: Ch. 1 — Quick start

An object

id first-object track start-here 20 XP · ~2 min Guide: Ch. 2 — Make an object

An object is an agent that lives inside the chip. You make one by giving it a name and saying which model runs it. Type this one line where the TODO is: var scribe = Scribe(Agent.claude-sonnet); scribe is the name you will wire later.

Starter .ahl + TODO — fill the TODO lines. This page does not compile or grade.

# An object
# Declare the agent. Wires already wait for the name scribe.

class Pass : IC {
    in  ticket : text
    out report : text

    # TODO 1: var scribe = Scribe(Agent.claude-sonnet);
    wire(ticket, scribe);
    wire(scribe, report);
}

TODO — what you type:

  1. var scribe = Scribe(Agent.claude-sonnet);

Desktop Check / grade intent (teach text only — this page does not grade; in-browser Check is open / awaiting Wes):

  • kind=class — a chip class is present
  • kind=object — name scribe (var scribe = Scribe(Agent.claude-sonnet);)
  • kind=wire — ticket → scribe → report

Full Check/run = desktop Hierarchy Builder / aidahl academy.

Read: Ch. 2 — Make an object

Wire it in

id wire-it-in track start-here 20 XP · ~3 min Guide: Ch. 5 — wire(src, dst) -- two parameters

Now put scribe on the path. The direct wire becomes two wires: one into the object, one out of it. Replace the TODO lines with: wire(ticket, scribe); wire(scribe, report); Text arriving at ticket now goes to scribe, and scribe's answer leaves on report.

Starter .ahl + TODO — fill the TODO lines. This page does not compile or grade.

# Wire it in
# scribe exists. Put it on the path.

class Pass : IC {
    in  ticket : text
    out report : text
    var scribe = Scribe(Agent.claude-sonnet);

    # TODO 1: wire(ticket, scribe);
    # TODO 2: wire(scribe, report);
}

TODO — what you type:

  1. wire(ticket, scribe);
  2. wire(scribe, report);

Desktop Check / grade intent (teach text only — this page does not grade; in-browser Check is open / awaiting Wes):

  • kind=class — a chip class is present
  • kind=wire — ticket → scribe
  • kind=wire — scribe → report

Full Check/run = desktop Hierarchy Builder / aidahl academy.

Read: Ch. 5 — wire(src, dst) -- two parameters

Give it a voice

id first-prompt track start-here 20 XP · ~2 min Guide: Ch. 3 — Set parameters

After an object exists, a dot sets any of its parameters. The one that matters most is the prompt: what the agent is told it is. Type this where the TODO is: scribe.prompt = "Answer in one short sentence."; The dot works the same for model, temperature, and every other field.

Starter .ahl + TODO — fill the TODO lines. This page does not compile or grade.

# Give it a voice
# scribe exists and is already on the path. Set its prompt.

class Pass : IC {
    in  ticket : text
    out report : text
    var scribe = Scribe(Agent.claude-sonnet);

    # TODO 1: scribe.prompt = "Answer in one short sentence.";
    wire(ticket, scribe);
    wire(scribe, report);
}

TODO — what you type:

  1. scribe.prompt = "Answer in one short sentence.";

Desktop Check / grade intent (teach text only — this page does not grade; in-browser Check is open / awaiting Wes):

  • kind=class — a chip class is present
  • kind=field — scribe.prompt is set
  • kind=wire — ticket → scribe → report

Full Check/run = desktop Hierarchy Builder / aidahl academy.

Read: Ch. 3 — Set parameters

First chip

first-chip — Objects, parameters, pins and wires -- one IC at a time.

Name the cast

id name-the-cast track first-chip 50 XP · ~6 min Guide: Ch. 2 — Make an object

An object's constructor name is a label; its parameters decide what it is. Agent.X picks the model or portal agent, Persona.Y the persona. A chain of two agents is the smallest real team.

Starter .ahl + TODO — fill the TODO lines. This page does not compile or grade.

# Name the cast
# Two labelled agents, then a chain.

class ReviewLane : IC {
    in  ticket : text
    out report : text

    # TODO 1: var craig = Craig(Agent.claude-sonnet, Persona.ChiefArchitect);
    # TODO 2: var brian = Brian(Agent.claude-haiku, Persona.TechLead);
    # TODO 3: craig.prompt = "Review the PR. List every defect.";  brian.prompt = "Fix what the review found.";
    # TODO 4: wire ticket -> craig -> brian -> report;
}

TODO — what you type:

  1. var craig = Craig(Agent.claude-sonnet, Persona.ChiefArchitect);
  2. var brian = Brian(Agent.claude-haiku, Persona.TechLead);
  3. craig.prompt = "Review the PR. List every defect."; brian.prompt = "Fix what the review found.";
  4. wire ticket -> craig -> brian -> report;

Desktop Check / grade intent (teach text only — this page does not grade; in-browser Check is open / awaiting Wes):

  • kind=class — ReviewLane IC
  • kind=object — craig and brian
  • kind=field — both prompts
  • kind=wire — ticket → craig → brian → report

Full Check/run = desktop Hierarchy Builder / aidahl academy.

Read: Ch. 2 — Make an object

Dial it in

id dial-it-in track first-chip 50 XP · ~6 min Guide: Ch. 3 — Set parameters

After you construct an object, the dot is every parameter of it, and a port can be labelled or kept in a variable. Set craig up precisely: craig.name, craig.temperature, craig.max_tokens, a port label, then a hop alias into the wire.

Starter .ahl + TODO — fill the TODO lines. This page does not compile or grade.

# Dial it in
# Tune craig after construction.

class ReviewLane : IC {
    in  ticket : text
    out report : text
    var craig = Craig(Agent.claude-sonnet, Persona.ChiefArchitect);
    craig.prompt = "Review the PR.";

    # TODO 1: craig.name = "Craig";
    # TODO 2: craig.temperature = 0.2;
    # TODO 3: craig.max_tokens = 1500;
    # TODO 4: craig.port.in1.label = "ticket";
    # TODO 5: draftIn = craig.port.in1;  wire(ticket, draftIn);
    wire(craig, report);
}

TODO — what you type:

  1. craig.name = "Craig";
  2. craig.temperature = 0.2;
  3. craig.max_tokens = 1500;
  4. craig.port.in1.label = "ticket";
  5. draftIn = craig.port.in1; wire(ticket, draftIn);

Desktop Check / grade intent (teach text only — this page does not grade; in-browser Check is open / awaiting Wes):

  • kind=class, object craig
  • kind=field — name, temperature, max_tokens
  • kind=port_label — craig.port.in1.label
  • kind=wire — hop alias into craig, then craig → report

Full Check/run = desktop Hierarchy Builder / aidahl academy.

Read: Ch. 3 — Set parameters

The fail lane

id fail-lane track first-chip 50 XP · ~7 min Guide: Ch. 8 — Built-in modules

A Validator is an LLM judge: the first line of its answer, PASS or FAIL, picks the lane. What it was given ships down the passed lane to the out pin; on FAIL it goes to the failed port, which you wire to a fail pin so the parent can see the reject.

Starter .ahl + TODO — fill the TODO lines. This page does not compile or grade.

# The fail lane
# PASS ships to report. FAIL reaches the parent on reject.

class Intake : IC {
    in  ticket : text
    out report : text
    # TODO 1: fail reject : text

    var craig = Craig(Agent.claude-sonnet, Persona.ChiefArchitect);
    craig.prompt = "Write the brief. Name an owner and a date.";
    # TODO 2: var check = Validator();
    # TODO 3: check.criteria = ["names an owner", "names a date"];

    wire(ticket, craig);
    # TODO 4: wire(craig, check);
    # TODO 5: wire(check, report);
    # TODO 6: wire(check.port.fail, reject);
}

TODO — what you type:

  1. fail reject : text
  2. var check = Validator();
  3. check.criteria = ["names an owner", "names a date"];
  4. wire(craig, check);
  5. wire(check, report);
  6. wire(check.port.fail, reject);

Desktop Check / grade intent (teach text only — this page does not grade; in-browser Check is open / awaiting Wes):

  • kind=class, pins including fail reject
  • kind=object — Validator named check
  • kind=field — check.criteria
  • kind=wire — craig → check → report, and check.port.fail → reject

Full Check/run = desktop Hierarchy Builder / aidahl academy.

Read: Ch. 8 — Built-in modules

Layers

layers — Fan-out, ICs on a SoC, SoCs on a Board, templates.

Fan out, fan in

id fan-out-fan-in track layers 50 XP · ~6 min Guide: Ch. 5 — wire(src, dst) -- two parameters

A [list] in a wire is sugar for every pair: one source to many destinations fans out, many sources to one destination fan in, landing on in_2, in_3, ... A Merger joins what arrives.

Starter .ahl + TODO — fill the TODO lines. This page does not compile or grade.

# Fan out, fan in
# One start, two readers, one Merger.

class Scan : IC {
    in  start : text
    out done : text
    var scout = Scout(Agent.claude-sonnet, Persona.ProductStrategist);
    var analyst = Analyst(Agent.claude-haiku, Persona.ChiefArchitect);
    scout.prompt = "What is the opportunity?";
    analyst.prompt = "What is the risk?";

    # TODO 1: var join = Merger();
    # TODO 2: wire(start, [scout, analyst]);
    # TODO 3: wire([scout, analyst], join);
    # TODO 4: wire(join, done);
}

TODO — what you type:

  1. var join = Merger();
  2. wire(start, [scout, analyst]);
  3. wire([scout, analyst], join);
  4. wire(join, done);

Desktop Check / grade intent (teach text only — this page does not grade; in-browser Check is open / awaiting Wes):

  • kind=class, object join (Merger)
  • kind=wire — start fans out to scout and analyst
  • kind=wire — both fan in to join, then join → done

Full Check/run = desktop Hierarchy Builder / aidahl academy.

Read: Ch. 5 — wire(src, dst) -- two parameters

Pads on a Board

id board-pads track layers 50 XP · ~6 min Guide: Ch. 6 — Wire layers

A Board holds SoCs. Its pins are pads: user text in, circuit results out. A Board file usually imports its SoC packages; here the SoC class is in the same file, which also works.

Starter .ahl + TODO — fill the TODO lines. This page does not compile or grade.

# Pads on a Board
# A SoC already exists. Wrap it in a Board.

class Team : SoC {
    in  kick : text
    out done : text
    var lane = LaneA();
    wire(kick, lane);
    wire(lane, done);
}

class LaneA : IC {
    in  start : text
    out done : text
    var craig = Craig(Agent.claude-sonnet, Persona.ChiefArchitect);
    wire(start, craig);
    wire(craig, done);
}

# TODO 1: class Shop : Board {
#           in  kick : text
#           out done : text
#           var codeSoC = Team();
#           wire(kick, codeSoC);
#           wire(codeSoC, done);
#         }

TODO — what you type:

  1. class Shop : Board { ... }

Desktop Check / grade intent (teach text only — this page does not grade; in-browser Check is open / awaiting Wes):

  • kind=class — Team (soc) and Shop (board)
  • kind=children — Shop places Team
  • kind=pins / pad — Board pads kick and done

Full Check/run = desktop Hierarchy Builder / aidahl academy.

Read: Ch. 6 — Wire layers

One class, many chips

id templates track layers 50 XP · ~8 min Guide: Ch. 12 — Inheritance and templates

A class with parameters is a template. Every use on a SoC compiles its own chip with the arguments bound as constants over the whole body, so one Lane class can be a quick lane and a deep lane.

Starter .ahl + TODO — fill the TODO lines. This page does not compile or grade.

# One class, many chips
# A template Lane, then two uses on a SoC.

class Lane(persona = Persona.TechLead, depth = 1) : IC {
    in  start : text
    out done : text

    # TODO 1: var reviewer = Reviewer(Agent.claude-sonnet, persona);
    # TODO 2: reviewer.prompt = "Review at depth ${depth}.";
    # TODO 3: if (depth > 1) { reviewer.max_tokens = depth * 1000; }
    # TODO 4: wire(start, reviewer);  wire(reviewer, done);
}

class Desk : SoC {
    in  kick : text
    out done : text
    # TODO 5: var quick = Lane();
    # TODO 6: var deep = Lane(Persona.ChiefArchitect, 2);
    # TODO 7: wire kick -> quick -> deep -> done;
}

TODO — what you type:

  1. var reviewer = Reviewer(Agent.claude-sonnet, persona);
  2. reviewer.prompt = "Review at depth ${depth}.";
  3. if (depth > 1) { reviewer.max_tokens = depth * 1000; }
  4. wire(start, reviewer); wire(reviewer, done);
  5. var quick = Lane();
  6. var deep = Lane(Persona.ChiefArchitect, 2);
  7. wire kick -> quick -> deep -> done;

Desktop Check / grade intent (teach text only — this page does not grade; in-browser Check is open / awaiting Wes):

  • kind=class — Lane template + Desk SoC
  • kind=children / child_doc / child_field — quick and deep specializations
  • kind=soc_wire — kick → quick → deep → done

Full Check/run = desktop Hierarchy Builder / aidahl academy.

Read: Ch. 12 — Inheritance and templates

Control

control — when / else, retry until, each, and compile-time values.

Gate it

id gate-it track control 50 XP · ~7 min Guide: Ch. 15 — Control -- when, else, retry, loop, each

when(cond) on an object mints a Conditional on its inbound wire: the true leg reaches the object, the false leg goes to the object the else block names. The condition reads input, the text on the wire: craig.when(input.contains("ship")) { ... } else { fixer.run(...); }

Starter .ahl + TODO — fill the TODO lines. This page does not compile or grade.

# Gate it
# when / else picks a lane from the text on the wire.

class Gate : IC {
    in  ticket : text
    out shipped : text
    out fixed : text
    var craig = Craig(Agent.claude-sonnet, Persona.ChiefArchitect);
    var fixer = Fixer(Agent.claude-haiku, Persona.TechLead);
    craig.prompt = "Decide if this ships.";
    fixer.prompt = "Fix it first.";

    # TODO 1: craig.when(input.contains("ship")) { craig.run("ship it"); }
    #           else { fixer.run("fix it first"); }
    wire(ticket, craig);
    wire(craig, shipped);
    # TODO 2: wire(fixer, fixed);
}

TODO — what you type:

  1. craig.when(input.contains("ship")) { craig.run("ship it"); }
  2. wire(fixer, fixed);

Desktop Check / grade intent (teach text only — this page does not grade; in-browser Check is open / awaiting Wes):

  • kind=class
  • kind=control — when on craig
  • kind=control_field — condition / else target
  • kind=wire — true lane to shipped, fixer to fixed

Full Check/run = desktop Hierarchy Builder / aidahl academy.

Read: Ch. 15 — Control -- when, else, retry, loop, each

One pass per item

id each-item track control 50 XP · ~6 min Guide: Ch. 15 — Control -- when, else, retry, loop, each

each(list) mints a For-Each chip on the inbound wire. The payload is split into items -- a JSON list, or one per line -- the object runs once per item with the block's instruction, and the answers are joined with newlines.

Starter .ahl + TODO — fill the TODO lines. This page does not compile or grade.

# One pass per item
# Split the payload; one pass per item.

class Batch : IC {
    in  items : text
    out done : text
    var reviewer = Reviewer(Agent.claude-sonnet, Persona.TechLead);
    reviewer.prompt = "Answer for one ticket only.";

    # TODO 1: reviewer.each(items) { reviewer.run("Review this one ticket."); }
    wire(items, reviewer);
    wire(reviewer, done);
}

TODO — what you type:

  1. reviewer.each(items) { reviewer.run("Review this one ticket."); }

Desktop Check / grade intent (teach text only — this page does not grade; in-browser Check is open / awaiting Wes):

  • kind=class
  • kind=control, op=each
  • kind=control_field — run instruction per item
  • kind=wire — items → reviewer → done

Full Check/run = desktop Hierarchy Builder / aidahl academy.

Read: Ch. 15 — Control -- when, else, retry, loop, each

Values and functions

id values-and-fn track control 50 XP · ~7 min Guide: Ch. 9 — Values and expressions

Everything right of = is evaluated at Save and baked into the chip: let constants, maps, functions, and ${} templates inside strings. fn and if decide what goes into the chip; nothing about them reaches the runtime.

Starter .ahl + TODO — fill the TODO lines. This page does not compile or grade.

# Values and functions
# Bake lets, a fn, and ${} at Save.

class ReviewLane : IC {
    in  ticket : text
    out report : text
    var craig = Craig(Agent.claude-sonnet, Persona.ChiefArchitect);

    # TODO 1: let WHO = "Craig";
    # TODO 2: let LIMITS = { fast: 400, deep: 4000 };
    # TODO 3: fn brief(who) { return "You are " + who + ". Review the PR."; }
    # TODO 4: craig.prompt = brief(WHO);
    # TODO 5: craig.max_tokens = LIMITS.deep;
    # TODO 6: craig.style = "Under ${LIMITS.fast} words.";
    wire(ticket, craig);
    wire(craig, report);
}

TODO — what you type:

  1. let WHO = "Craig";
  2. let LIMITS = { fast: 400, deep: 4000 };
  3. fn brief(who) { return "You are " + who + ". Review the PR."; }
  4. craig.prompt = brief(WHO);
  5. craig.max_tokens = LIMITS.deep;
  6. craig.style = "Under ${LIMITS.fast} words.";

Desktop Check / grade intent (teach text only — this page does not grade; in-browser Check is open / awaiting Wes):

  • kind=class
  • kind=field — prompt from brief(WHO), max_tokens from LIMITS.deep, style template

Full Check/run = desktop Hierarchy Builder / aidahl academy.

Read: Ch. 9 — Values and expressions

Ship it

ship-it — Test blocks, then a capstone team with a fail lane.

Write the test

id write-the-test track ship-it 50 XP · ~8 min Guide: Ch. 19 — Test blocks

A test block runs a chip on the engine with canned answers and no model. Script each object, feed an in pin, then expect what the out pins hold. The chip is given; the test is yours to write.

Starter .ahl + TODO — fill the TODO lines. This page does not compile or grade.

# Write the test
# The chip is given. The tests are yours.

class Intake : IC {
    in  ticket : text
    out report : text
    fail reject : text
    var writer = Writer(Agent.claude-sonnet, Persona.ProductStrategist);
    var check = Validator();
    check.criteria = ["names an owner"];
    wire(ticket, writer);
    wire(writer, check);
    wire(check, report);
    wire(check.port.fail, reject);
}

# TODO 1 (yours): test "a clear ticket passes" for Intake {
#     writer = "BRIEF: add a login page";
#     check = "PASS";
#     feed(ticket, "add a login page");
#     expect(report, contains("login"));
#     expect(reject, empty());
# }
# TODO 2 (yours): test "a vague ticket is rejected" for Intake {
#     writer = "???";
#     check = "FAIL: vague";
#     feed(ticket, "???");
#     expect(report, empty());
#     expect(reject, contains("vague"));
# }

TODO — what you type:

  1. test "a clear ticket passes" for Intake { writer = "..."; check = "PASS"; ... }
  2. test "a vague ticket is rejected" for Intake { ... check = "FAIL: vague"; ... }

Desktop Check / grade intent (teach text only — this page does not grade; in-browser Check is open / awaiting Wes):

  • kind=class — Intake
  • kind=tests — a test block is present
  • kind=test_named — both named tests

Full Check/run = desktop Hierarchy Builder / aidahl academy.

Read: Ch. 19 — Test blocks

Capstone: Night Watch

id capstone track ship-it 100 XP · ~15 min Guide: Ch. 25 — Full walkthrough
Capstone · Night Watch

Everything at once. NightWatch turns a ticket into a checked architecture: writer briefs it, architect designs it and retries until the design has markdown headings, a Validator judges it, PASS ships to report and FAIL to reject, then you write a test.

Starter .ahl + TODO — fill the TODO lines. This page does not compile or grade.

# Capstone: Night Watch
# Writer briefs, architect retries headings, Validator judges.

class NightWatch : IC {
    in  ticket : text
    out report : text
    # TODO 1: fail reject : text

    # TODO 2: var writer = Writer(Agent.claude-sonnet, Persona.ProductStrategist);
    # TODO 3: var architect = Architect(Agent.claude-sonnet, Persona.ChiefArchitect);
    # TODO 4: var check = Validator();  check.criteria = ["names the components", "names the risks"];

    writer.prompt = "Turn the ticket into a short brief.";
    architect.prompt = "Turn the brief into an architecture.";
    architect.retry(2, until = input.contains("##")) {
        architect.run("Use markdown headings.");
    }

    # TODO 5: wire ticket -> writer -> architect -> check;
    wire(check, report);
    wire(check.port.fail, reject);
}

# TODO 6 (yours): test "a ticket becomes a checked architecture" for NightWatch {
#     writer = "BRIEF: add a login page";
#     architect = "## Components: login form, session store";
#     check = "PASS";
#     feed(ticket, "add a login page");
#     expect(report, contains("Components"));
#     expect(reject, empty());
# }

TODO — what you type:

  1. fail reject : text
  2. var writer = Writer(Agent.claude-sonnet, Persona.ProductStrategist);
  3. var architect = Architect(Agent.claude-sonnet, Persona.ChiefArchitect);
  4. var check = Validator(); check.criteria = ["names the components", "names the risks"];
  5. wire ticket -> writer -> architect -> check;
  6. test "a ticket becomes a checked architecture" for NightWatch { ... }

Desktop Check / grade intent (teach text only — this page does not grade; in-browser Check is open / awaiting Wes):

  • kind=class NightWatch, pins including fail
  • kind=object — writer, architect, check
  • kind=field — prompts / criteria
  • kind=control — architect.retry until headings
  • kind=wire — ticket → writer → architect → check → report / reject
  • kind=tests — student test block

Full Check/run = desktop Hierarchy Builder / aidahl academy.

Read: Ch. 25 — Full walkthrough

Packages

packages — Files that import files, inheritance, and the canvas in the source.

Import a file

id file-import track packages 50 XP · ~6 min Guide: Ch. 13 — Imports

A team does not have to live in one file. from "path.ahl" import Class reads another source file, relative to this one, compiles everything in it first, and binds the named classes as constructors.

Starter .ahl + TODO — fill the TODO lines. This page does not compile or grade.

# Import a file
# Companion file lanes/scout.ahl defines ScoutLane.
# This file places it. Do not re-declare ScoutLane here.

# TODO 1: from "lanes/scout.ahl" import ScoutLane

class Desk : Board {
    in  ticket : text
    out brief : text
    # TODO 2: var scout = ScoutLane();
    # TODO 3: wire(ticket, scout);  wire(scout, brief);
}

TODO — what you type:

  1. from "lanes/scout.ahl" import ScoutLane
  2. var scout = ScoutLane();
  3. wire(ticket, scout); wire(scout, brief);

Desktop Check / grade intent (teach text only — this page does not grade; in-browser Check is open / awaiting Wes):

  • kind=class — Desk places the imported chip
  • kind=children / pad — scout on the Board
  • kind=source_lacks — this file does not re-declare ScoutLane

Full Check/run = desktop Hierarchy Builder / aidahl academy.

Read: Ch. 13 — Imports

Inherit and override

id inherit-override track packages 50 XP · ~6 min Guide: Ch. 12 — Inheritance and templates

A class can extend another class of the same tier. The base body applies first, then the child's: assignments and wires add on, and a later line wins, so a child can retune one object without repeating the lane.

Starter .ahl + TODO — fill the TODO lines. This page does not compile or grade.

# Inherit and override
# Retune one object. Do not rewrite the lane.

class ReviewLane : IC {
    in  start : text
    out done : text
    var reviewer = Reviewer(Agent.claude-sonnet, Persona.TechLead);
    reviewer.prompt = "Review the change.";
    wire(start, reviewer);
    wire(reviewer, done);
}

# TODO 1: class FastReview : ReviewLane {
#           model = "claude-haiku"
#           reviewer.prompt = "One paragraph only.";
#         }

TODO — what you type:

  1. class FastReview : ReviewLane { ... }

Desktop Check / grade intent (teach text only — this page does not grade; in-browser Check is open / awaiting Wes):

  • kind=class — ReviewLane and FastReview
  • kind=object / field — reviewer prompt override, model on the child
  • kind=wire — inherited start → reviewer → done

Full Check/run = desktop Hierarchy Builder / aidahl academy.

Read: Ch. 12 — Inheritance and templates

Place it on the canvas

id canvas-layout track packages 50 XP · ~5 min Guide: Ch. 14 — Operations -- run, ask, feed, pos, size

Source and canvas are the same chip, so the source can say where things sit. pos(x, y) and size(w, h) write canvas geometry, and a port label is what the pin says on the canvas. Open-as-AidaHL writes them back.

Starter .ahl + TODO — fill the TODO lines. This page does not compile or grade.

# Place it on the canvas
# Geometry lives in the source.

class Studio : IC {
    in  ticket : text
    out report : text
    var writer = Writer(Agent.claude-sonnet, Persona.ProductStrategist);
    var reviewer = Reviewer(Agent.claude-haiku, Persona.TechLead);
    wire(ticket, writer);
    wire(writer, reviewer);
    wire(reviewer, report);

    # TODO 1: writer.pos(280, 120);
    # TODO 2: writer.size(160, 80);
    # TODO 3: writer.port.in1.label = "ticket";
    # TODO 4: reviewer.pos(560, 120);
}

TODO — what you type:

  1. writer.pos(280, 120);
  2. writer.size(160, 80);
  3. writer.port.in1.label = "ticket";
  4. reviewer.pos(560, 120);

Desktop Check / grade intent (teach text only — this page does not grade; in-browser Check is open / awaiting Wes):

  • kind=class
  • kind=pos / size — writer geometry
  • kind=port_label — ticket on writer.in1
  • kind=pos — reviewer
  • kind=wire — ticket → writer → reviewer → report

Full Check/run = desktop Hierarchy Builder / aidahl academy.

Read: Ch. 14 — Operations -- run, ask, feed, pos, size

Runtime

runtime — Gates on whole lanes, JSON payloads, the payload port, loops that stop.

Gate a whole lane

id soc-gate track runtime 50 XP · ~6 min Guide: Ch. 15 — Control -- when, else, retry, loop, each

Control operations work on a SoC too: when() on a child chip mints a gate in front of the whole lane, and the parent still never names the agents inside it. var lane = WorkLane(); lane.when("ready");

Starter .ahl + TODO — fill the TODO lines. This page does not compile or grade.

# Gate a whole lane
# WorkLane is given. Gate the whole child, not its agents.

class WorkLane : IC {
    in  start : text
    out done : text
    var worker = Worker(Agent.claude-sonnet, Persona.TechLead);
    wire(start, worker);
    wire(worker, done);
}

class Desk : SoC {
    in  kick : text
    out done : text
    var lane = WorkLane();
    # TODO 1: lane.when("ready");
    wire(kick, lane);
    wire(lane, done);
}

TODO — what you type:

  1. lane.when("ready");

Desktop Check / grade intent (teach text only — this page does not grade; in-browser Check is open / awaiting Wes):

  • kind=class — WorkLane + Desk
  • kind=children — lane
  • kind=control / control_field — when("ready") on the child chip

Full Check/run = desktop Hierarchy Builder / aidahl academy.

Read: Ch. 15 — Control -- when, else, retry, loop, each

Read the payload

id json-conditions track runtime 50 XP · ~6 min Guide: Ch. 16 — Runtime conditions

When the text on the wire is a JSON object, a condition can read its fields: input.score, input.status, input.result.score. Name the owner itself in the else block and it runs either way, told different things.

Starter .ahl + TODO — fill the TODO lines. This page does not compile or grade.

# Read the payload
# Branch on a JSON field. Same object, two instructions.

class ScoreGate : IC {
    in  ticket : text
    out done : text
    var wes = Wes(Agent.claude-sonnet, Persona.ChiefArchitect);
    wes.prompt = "Read the score.";

    # TODO 1: wes.when(input.score >= 8) { wes.run("ship it"); }
    #           else { wes.run("explain why not"); }
    wire(ticket, wes);
    wire(wes, done);
}

TODO — what you type:

  1. wes.when(input.score >= 8) { wes.run("ship it"); }

Desktop Check / grade intent (teach text only — this page does not grade; in-browser Check is open / awaiting Wes):

  • kind=class
  • kind=control — when on wes
  • kind=control_field — input.score >= 8, ship / explain instructions

Full Check/run = desktop Hierarchy Builder / aidahl academy.

Read: Ch. 16 — Runtime conditions

Ship the work, not the review

id payload-pin track runtime 50 XP · ~7 min Guide: Ch. 8 — Built-in modules

A Validator judges what arrives on in, but what it forwards on passed is whatever is wired to its payload port. Wire the build there and a PASS ships the build, not the review that approved it.

Starter .ahl + TODO — fill the TODO lines. This page does not compile or grade.

# Ship the work, not the review
# Judge the review; forward the build.

class Ship : IC {
    in  ticket : text
    out report : text
    fail reject : text
    var builder = Builder(Agent.claude-sonnet, Persona.TechLead);
    var reviewer = Reviewer(Agent.claude-haiku, Persona.TechLead);
    var check = Validator();
    check.criteria = ["names an owner"];
    wire(ticket, builder);
    wire(builder, reviewer);
    wire(reviewer, check);
    # TODO 1: wire(builder, check.port.payload);
    wire(check, report);
    wire(check.port.fail, reject);
}

TODO — what you type:

  1. wire(builder, check.port.payload);

Desktop Check / grade intent (teach text only — this page does not grade; in-browser Check is open / awaiting Wes):

  • kind=class
  • kind=wire — reviewer → check (judged), builder → check.port.payload (shipped)
  • kind=wire — check → report, check.port.fail → reject

Full Check/run = desktop Hierarchy Builder / aidahl academy.

Read: Ch. 8 — Built-in modules

Refine until done

id loop-until track runtime 50 XP · ~6 min Guide: Ch. 15 — Control -- when, else, retry, loop, each

loop(n, until = cond) runs an object up to n passes, feeding each pass the previous answer, and stops early when the answer satisfies until. The last answer goes downstream.

Starter .ahl + TODO — fill the TODO lines. This page does not compile or grade.

# Refine until done
# Each pass sees the previous answer.

class Refine : IC {
    in  draft : text
    out done : text
    var writer = Writer(Agent.claude-sonnet, Persona.ProductStrategist);
    writer.prompt = "Refine the draft. End with DONE when finished.";

    # TODO 1: writer.loop(3, until = input.contains("DONE")) { writer.run("refine"); }
    wire(draft, writer);
    wire(writer, done);
}

TODO — what you type:

  1. writer.loop(3, until = input.contains("DONE")) { writer.run("refine"); }

Desktop Check / grade intent (teach text only — this page does not grade; in-browser Check is open / awaiting Wes):

  • kind=class
  • kind=control, op=loop
  • kind=control_field — n=3, until=DONE, run refine

Full Check/run = desktop Hierarchy Builder / aidahl academy.

Read: Ch. 15 — Control -- when, else, retry, loop, each

Upgrade to Pro/Team for the Save/Compile gate

Free / logged-out: teach and practice only — no compile. Upgrade to Pro or Team for the Save/Compile gate. Coming in RC16 — not available to download yet. Windows 1.0.0-rc15 today.

Sign Up Free — Download

AidaHL Guide · Pro / Team pricing · AI Hierarchy canvas · Community · Marketplace