On this page
The codegen room agents writing code๏
๐ต Expert ยท Lesson 07
THE CODEGEN ROOM - where an agent writes code that becomes part of a running world, and the gate it has to get through first. This is the only room kind where the caller supplies EXECUTABLE SOURCE, so it is the only one that has to answer "may I" before "did it work".
THE DEFAULT POSTURE IS DENY, AND THE DENYLIST IS THE THREAT MODEL WRITTEN DOWN. A codegen room with no widening projection ships with imports OFF entirely and thirteen builtins refused by name:
import breakpoint compile dir eval exec getattr globals input locals setattr delattr vars
Read that list as a document rather than a setting. Every entry is a door OUT of the namespace contract: eval/exec/compile execute text the gate never saw, __import__ bypasses the import rules, getattr/setattr/vars/dir reach attributes by computed name, and globals/locals hand back the environment itself. Somebody enumerated the ways out and wrote them down where you can read them.
A REFUSAL IS A VALUE, AND IT NAMES THE OFFENDER. validate_codegen returns a payload, not an exception and not a bare boolean: {"accepted": bool, "frame_name": str, "reason": str, "validation_issues": (str, ...)} Rejected source comes back as accepted: False with a message that names the specific thing - "Builtin 'eval' is not allowed in this codegen mode" - because a bare False would force you to re-run validation with different instrumentation just to learn why.
THE CHAIN IS ORDERED AND IT SHORT-CIRCUITS. Syntax is checked first (a parse failure never reaches a gate), then seven strategies run in a fixed sequence and the FIRST refusal returns immediately:
ast_structure -> import_policy -> builtin_policy -> name_resolution -> attribute_access -> reflection_policy -> recursive_control
So validation_issues is normally ONE issue: the first gate that objected, not an audit of everything wrong. Fix it and re-ask - the next answer may well name a different gate. And the order is observable, which is why it is worth knowing rather than guessing: eval('1 + 1') is refused by builtin_policy, which sits BEFORE name_resolution, so you get the builtin message rather than an unresolved-name one.
READ recursive_control TWICE. It is last in the chain and it exists because generated code that generates code is how a bounded system stops being bounded. Someone thought about an agent escaping its sandbox by writing a smaller one inside it.
VALIDATION RUNS BEFORE THE ENVIRONMENT EXISTS, AND THAT ORDERING IS THE POINT. The gates read the AST, not a live namespace. The execution environment has not been built when they run - and building it to find out whether building it was allowed "would be exactly the escape the gate exists to prevent". That is why validate_codegen is a separate verb rather than a flag on execute: you can learn a boundary without approaching it.
AND MELDER DOES NOT CLAIM THIS IS A PROOF. In its own words, the checks reject OBVIOUS violations, because "static analysis of Python cannot be exhaustive, so the validation chain is defence in depth alongside the namespace denylists and the ACL posture, not a proof of safety on its own". Three layers, named, with the honest limit stated. A system that claimed a guarantee here would be lying, and the willingness to write that down is worth more than the claim.
THE ROOM OVERRIDES A THIRD PROPERTY. Advanced 11 found static and capability each swap TWO - command_system (what you may DO) and frame_viewer (what you may SEE). CodegenRiftSpace adds codegen_system: what you may MAKE. Do / see / make, each by handing over a different class rather than guarding a shared one.
Before you run๏
Use the Expert guide for prerequisite concepts. Run from a checkout with Melder installed and Python 3.14 free-threading selected. The collection download includes the level's local helper modules.
Run the saved script๏
python UX_and_AIX_experiences/04_expert/07_the_codegen_room_agents_writing_code.py
py -3.14t UX_and_AIX_experiences/04_expert/07_the_codegen_room_agents_writing_code.py
Public surface๏
validate_codegen driven against accepted source, a denied import and a denied builtin; the validation payload shape; RiftSpace.space_kind / command_system / frame_viewer / codegen_system; list_supported_command_methods
Code๏
1"""
2TIER: expert (07)
3GOAL: THE CODEGEN ROOM - where an agent writes code that becomes part of
4 a running world, and the gate it has to get through first. This is
5 the only room kind where the caller supplies EXECUTABLE SOURCE, so
6 it is the only one that has to answer "may I" before "did it work".
7
8 THE DEFAULT POSTURE IS DENY, AND THE DENYLIST IS THE THREAT MODEL
9 WRITTEN DOWN. A codegen room with no widening projection ships with
10 imports OFF entirely and thirteen builtins refused by name:
11
12 __import__ breakpoint compile dir eval exec getattr
13 globals input locals setattr delattr vars
14
15 Read that list as a document rather than a setting. Every entry is a
16 door OUT of the namespace contract: `eval`/`exec`/`compile` execute
17 text the gate never saw, `__import__` bypasses the import rules,
18 `getattr`/`setattr`/`vars`/`dir` reach attributes by computed name,
19 and `globals`/`locals` hand back the environment itself. Somebody
20 enumerated the ways out and wrote them down where you can read them.
21
22 A REFUSAL IS A VALUE, AND IT NAMES THE OFFENDER.
23 `validate_codegen` returns a payload, not an exception and not a
24 bare boolean:
25 {"accepted": bool, "frame_name": str, "reason": str,
26 "validation_issues": (str, ...)}
27 Rejected source comes back as `accepted: False` with a message that
28 names the specific thing - "Builtin 'eval' is not allowed in this
29 codegen mode" - because a bare False would force you to re-run
30 validation with different instrumentation just to learn why.
31
32 THE CHAIN IS ORDERED AND IT SHORT-CIRCUITS. Syntax is checked first
33 (a parse failure never reaches a gate), then seven strategies run in
34 a fixed sequence and the FIRST refusal returns immediately:
35
36 ast_structure -> import_policy -> builtin_policy ->
37 name_resolution -> attribute_access -> reflection_policy ->
38 recursive_control
39
40 So `validation_issues` is normally ONE issue: the first gate that
41 objected, not an audit of everything wrong. Fix it and re-ask - the
42 next answer may well name a different gate. And the order is
43 observable, which is why it is worth knowing rather than guessing:
44 `eval('1 + 1')` is refused by builtin_policy, which sits BEFORE
45 name_resolution, so you get the builtin message rather than an
46 unresolved-name one.
47
48 READ `recursive_control` TWICE. It is last in the chain and it
49 exists because generated code that generates code is how a bounded
50 system stops being bounded. Someone thought about an agent escaping
51 its sandbox by writing a smaller one inside it.
52
53 VALIDATION RUNS BEFORE THE ENVIRONMENT EXISTS, AND THAT ORDERING IS
54 THE POINT. The gates read the AST, not a live namespace. The
55 execution environment has not been built when they run - and
56 building it to find out whether building it was allowed "would be
57 exactly the escape the gate exists to prevent". That is why
58 `validate_codegen` is a separate verb rather than a flag on execute:
59 you can learn a boundary without approaching it.
60
61 AND MELDER DOES NOT CLAIM THIS IS A PROOF. In its own words, the
62 checks reject OBVIOUS violations, because "static analysis of Python
63 cannot be exhaustive, so the validation chain is defence in depth
64 alongside the namespace denylists and the ACL posture, not a proof
65 of safety on its own". Three layers, named, with the honest limit
66 stated. A system that claimed a guarantee here would be lying, and
67 the willingness to write that down is worth more than the claim.
68
69 THE ROOM OVERRIDES A THIRD PROPERTY. Advanced 11 found static and
70 capability each swap TWO - `command_system` (what you may DO) and
71 `frame_viewer` (what you may SEE). CodegenRiftSpace adds
72 `codegen_system`: what you may MAKE. Do / see / make, each by
73 handing over a different class rather than guarding a shared one.
74SURFACE EXERCISED: validate_codegen driven against accepted source, a
75 denied import and a denied builtin; the validation
76 payload shape; RiftSpace.space_kind / command_system /
77 frame_viewer / codegen_system;
78 list_supported_command_methods
79VERIFY: rewritten 2026-08-05 to DRIVE the validator instead of listing
80 gate names; not yet re-run.
81"""
82import melder as md
83
84
85FRAME = "gate-world"
86
87SAFE = "result = 2 + 2\n"
88IMPORTING = "import socket\nresult = socket\n"
89EVALUATING = "result = eval('1 + 1')\n"
90
91# The shipped deny list for a room with no widening projection. Named
92# here so the lesson can CHECK the refusals against it rather than assert
93# a number it typed.
94DENIED_BUILTINS = (
95 "__import__", "breakpoint", "compile", "dir", "eval", "exec",
96 "getattr", "globals", "input", "locals", "setattr", "delattr", "vars",
97)
98
99
100def main() -> None:
101 spellbook_configuration = (
102 md.SpellbookConfiguration(FRAME).with_defaults().finalize()
103 )
104 book = md.Spellbook(aetheric_frame=FRAME,
105 configuration=spellbook_configuration)
106 book.configure_aether_frame(
107 system_state="dynamic",
108 disposal=None,
109 disposal_method_names=None,
110 rift_enabled=True,
111 ai_native=True,
112 )
113 # An empty conjured frame is a real frame - `conjure` realizes it and
114 # publishes it to the Nexus, and spells are cargo rather than a
115 # precondition (expert 33).
116 book.conjure(name="gate-root")
117
118 nexus = md.Nexus()
119 system_configuration = nexus.create_configuration()
120 system_configuration.with_rift_creation_enabled(True)
121 system_configuration.with_allowed_target_frame_names([FRAME])
122 nexus.activate(system_configuration)
123 rift_configuration = nexus.create_rift_configuration()
124 rift_configuration.with_space_type("codegen")
125 rift = nexus.create_rift(configuration=rift_configuration,
126 rift_name="workshop")
127 rift.mark_active()
128 rift.create_frame_link(FRAME)
129
130 room = rift.space
131 commands = room.command_system
132
133 # DO / SEE / MAKE - three properties, three classes, one room kind.
134 assert room.space_kind == "codegen"
135 print("room kind:", room.space_kind, "->", type(room).__name__)
136 print(" command_system:", type(commands).__name__, "(what you may DO)")
137 print(" frame_viewer :", type(room.frame_viewer).__name__,
138 "(what you may SEE)")
139 assert hasattr(room, "codegen_system"), "the codegen room adds a third"
140 print(" codegen_system:", type(room.codegen_system).__name__,
141 "(what you may MAKE)")
142
143 # ACCEPTED SOURCE. The payload is a verdict, not a boolean.
144 print()
145 print("ASKING PERMISSION, WITHOUT RUNNING ANYTHING:")
146 accepted = commands.validate_codegen(SAFE, frame_name=FRAME)
147 assert isinstance(accepted, dict), accepted
148 assert accepted["accepted"] is True, accepted
149 assert accepted["frame_name"] == FRAME
150 print(" validate(result = 2 + 2) -> accepted:", accepted["accepted"],
151 "| reason:", accepted.get("reason"))
152
153 # A DENIED IMPORT. The shipped posture has imports OFF entirely, so
154 # the refusal is about the STATEMENT, not about `socket` specifically.
155 denied_import = commands.validate_codegen(IMPORTING, frame_name=FRAME)
156 assert denied_import["accepted"] is False, denied_import
157 import_issues = denied_import.get("validation_issues", ())
158 assert import_issues, denied_import
159 print()
160 print(" validate(import socket) -> accepted:",
161 denied_import["accepted"])
162 print(" reason :", denied_import.get("reason"))
163 print(" issue :", import_issues[0])
164 print(" imports are OFF in the shipped posture, so the refusal is")
165 print(" about the STATEMENT rather than about `socket` - there is")
166 print(" no allow-list to fail yet. A widening ACL projection is")
167 print(" what turns them on, and it is NOT reachable from the")
168 print(" public surface today (see expert 34, withdrawn)")
169
170 # A DENIED BUILTIN. This one DOES name the offender, because the
171 # denylist is per-name.
172 denied_builtin = commands.validate_codegen(EVALUATING, frame_name=FRAME)
173 assert denied_builtin["accepted"] is False, denied_builtin
174 builtin_issues = denied_builtin.get("validation_issues", ())
175 assert builtin_issues, denied_builtin
176 assert "eval" in builtin_issues[0], builtin_issues
177 print()
178 print(" validate(eval('1 + 1')) -> accepted:",
179 denied_builtin["accepted"])
180 print(" issue :", builtin_issues[0])
181 print(" it NAMES the builtin. A bare False would make you re-run")
182 print(" validation with different instrumentation to learn why")
183
184 # ONE ISSUE, NOT AN AUDIT. The chain returns on the FIRST refusal, so
185 # a rejected payload carries the first gate's objection and stops.
186 assert len(builtin_issues) == 1, builtin_issues
187 print(" and exactly ONE issue came back - the chain short-circuits,")
188 print(" so this is the first gate that objected, not a list of")
189 print(" everything wrong. Fix it and ask again; the next answer")
190 print(" may name a different gate.")
191
192 # NOTHING RAN. Three verdicts, zero execution - which is the whole
193 # reason validate is its own verb.
194 print()
195 print("three verdicts so far and NOTHING has executed. The gates read")
196 print("the AST; the namespace does not exist yet. Building it to find")
197 print("out whether building it was permitted would be exactly the")
198 print("escape the gate exists to prevent.")
199
200 # THE DENYLIST AS A DOCUMENT.
201 print()
202 print("the shipped builtin denylist -", len(DENIED_BUILTINS), "names:")
203 print(" ", " ".join(DENIED_BUILTINS[:7]))
204 print(" ", " ".join(DENIED_BUILTINS[7:]))
205 print(" every one is a door OUT of the namespace contract:")
206 print(" eval / exec / compile run text the gate never saw")
207 print(" __import__ bypasses the import rules")
208 print(" getattr / setattr /")
209 print(" vars / dir reach attributes by computed name")
210 print(" globals / locals hand back the environment itself")
211
212 # MALFORMED REQUEST IS A DIFFERENT FAILURE FROM DISALLOWED CODE.
213 for bad_code, bad_frame in (("", FRAME), (SAFE, "")):
214 try:
215 commands.validate_codegen(bad_code, frame_name=bad_frame)
216 raise AssertionError("expected ValueError on an empty argument")
217 except ValueError:
218 pass
219 print()
220 print("empty code or empty frame_name RAISE ValueError - a malformed")
221 print("REQUEST is a different failure from disallowed CODE, and they")
222 print("are not spelled the same way")
223
224 # The room enumerates its own authority (the AIX door from advanced 11).
225 supported = commands.list_supported_command_methods()
226 assert isinstance(supported, tuple)
227 assert "validate_codegen" in supported
228 print()
229 print("the room reports", len(supported), "command methods it will answer")
230
231 print()
232 print("validate is a SEPARATE verb - learn a boundary without")
233 print("approaching it. And melder does not call this a proof: the")
234 print("checks reject OBVIOUS violations, and the honest claim is")
235 print("defence in depth across gates, namespace denylists and the ACL")
236 print("posture. A system promising a guarantee here would be lying.")
237
238
239if __name__ == "__main__":
240 main()
Check the outcome๏
The script contains its own assertions or demonstrated refusal paths. Run it to evaluate those checks against your installed version. The code above is taken directly from the saved file; no run output is invented here.