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.
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:
wire(ticket, report);
Desktop Check / grade intent (teach text only — this page does not grade; in-browser Check is open / awaiting Wes):
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:
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.
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:
wire(ticket, scribe);
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.
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:
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.
A chip is a class. Pins are its public edge; objects live inside; wires carry text from one to the next. This first lab wires one agent between an in pin and an out pin. in ticket : text — the pin text arrives on; out report : text — the pin the answer leaves on.
Starter .ahl + TODO — fill the TODO lines. This page does not compile or grade.
# Hello, chip
# One agent between an in pin and an out pin.
class HelloLane : IC {
in ticket : text
out report : text
# TODO 1: var scribe = Scribe(Agent.claude-sonnet);
# TODO 2: wire(ticket, scribe);
# TODO 3: wire(scribe, report);
}
TODO — what you type:
var scribe = Scribe(Agent.claude-sonnet);
wire(ticket, scribe);
wire(scribe, report);
Desktop Check / grade intent (teach text only — this page does not grade; in-browser Check is open / awaiting Wes):
kind=class, name=HelloLane, tier=ic
kind=pins, cls=HelloLane
kind=object, name=scribe — var scribe = Scribe(Agent.claude-sonnet);
kind=wire, src=ticket, dst=scribe
kind=wire, src=scribe, dst=report
Full Check/run = desktop Hierarchy Builder / aidahl academy.
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:
var craig = Craig(Agent.claude-sonnet, Persona.ChiefArchitect);
var brian = Brian(Agent.claude-haiku, Persona.TechLead);
craig.prompt = "Review the PR. List every defect."; brian.prompt = "Fix what the review found.";
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.
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:
craig.name = "Craig";
craig.temperature = 0.2;
craig.max_tokens = 1500;
craig.port.in1.label = "ticket";
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.
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:
fail reject : text
var check = Validator();
check.criteria = ["names an owner", "names a date"];
wire(craig, check);
wire(check, report);
wire(check.port.fail, reject);
Desktop Check / grade intent (teach text only — this page does not grade; in-browser Check is open / awaiting Wes):
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:
var join = Merger();
wire(start, [scout, analyst]);
wire([scout, analyst], join);
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.
An IC holds agents. A SoC holds ICs and wires between them -- it never names the agents inside a child; it wires the child's pins. Two lanes become a team.
Starter .ahl + TODO — fill the TODO lines. This page does not compile or grade.
# Two ICs, one SoC
# Two lanes, then a SoC that wires them.
class LaneA : IC {
in start : text
out done : text
var craig = Craig(Agent.claude-sonnet, Persona.ChiefArchitect);
craig.prompt = "Draft the design.";
wire(start, craig);
wire(craig, done);
}
class LaneB : IC {
in start : text
out done : text
var brian = Brian(Agent.claude-haiku, Persona.TechLead);
brian.prompt = "Review the design.";
wire(start, brian);
wire(brian, done);
}
# TODO 1: class Team : SoC {
# in kick : text
# out done : text
# var intake = LaneA();
# var review = LaneB();
# wire(kick, intake);
# wire(intake, review);
# wire(review, done);
# }
TODO — what you type:
class Team : SoC { ... }
Desktop Check / grade intent (teach text only — this page does not grade; in-browser Check is open / awaiting Wes):
kind=class — LaneA and LaneB (ic), Team (soc)
kind=children — var intake = LaneA(); var review = LaneB();
kind=pins on Team
kind=soc_wire — intake → review (the SoC wires chips, not agents)
kind=pad — kick → intake, review → done
Full Check/run = desktop Hierarchy Builder / aidahl academy.
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:
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.
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:
var reviewer = Reviewer(Agent.claude-sonnet, persona);
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);
}
retry(n, until = cond) mints a Retry Loop on the object's outbound wire. While the answer fails the condition and attempts remain, the object is asked again with the original task, "[Retry k/n]" and the block's instruction, plus its previous answer. Then final continues.
Starter .ahl + TODO — fill the TODO lines. This page does not compile or grade.
# Retry until
# Ask again until the answer has markdown headings.
class Design : IC {
in draft : text
out done : text
var arch = Arch(Agent.claude-sonnet, Persona.ChiefArchitect);
arch.prompt = "Turn the draft into an architecture.";
# TODO 1: arch.retry(2, until = input.contains("##")) { arch.run("Use markdown headings."); }
wire(draft, arch);
wire(arch, done);
}
TODO — what you type:
arch.retry(2, until = input.contains("##")) { arch.run("Use markdown headings."); }
Desktop Check / grade intent (teach text only — this page does not grade; in-browser Check is open / awaiting Wes):
kind=class, name=Design, tier=ic
kind=control, op=retry — arch.retry(2, until = ...)
kind=control_field — n=2, until=input.contains("##"), run instruction
kind=wire — arch → done
Full Check/run = desktop Hierarchy Builder / aidahl academy.
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:
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.
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:
let WHO = "Craig";
let LIMITS = { fast: 400, deep: 4000 };
fn brief(who) { return "You are " + who + ". Review the PR."; }
craig.prompt = brief(WHO);
craig.max_tokens = LIMITS.deep;
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.
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:
test "a clear ticket passes" for Intake { writer = "..."; check = "PASS"; ... }
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.
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:
fail reject : text
var writer = Writer(Agent.claude-sonnet, Persona.ProductStrategist);
var architect = Architect(Agent.claude-sonnet, Persona.ChiefArchitect);
var check = Validator(); check.criteria = ["names the components", "names the risks"];
wire ticket -> writer -> architect -> check;
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):
packages — Files that import files, inheritance, and the canvas in the source.
Import a file
id file-importtrack packages50 XP · ~6 minGuide: 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:
from "lanes/scout.ahl" import ScoutLane
var scout = ScoutLane();
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.
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:
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.
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:
writer.pos(280, 120);
writer.size(160, 80);
writer.port.in1.label = "ticket";
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.
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:
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.
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);
}
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:
wire(builder, check.port.payload);
Desktop Check / grade intent (teach text only — this page does not grade; in-browser Check is open / awaiting Wes):
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:
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.
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.