RUL-037 — Every agent writes Python only as files through the guarded tools; enforced on every channel, never promised

Ruling

Mohamed, 2026-10-17, after the orchestrator explained that the Bash write hook's /tmp/claude- scratch escape was why its probes lived in /tmp, verbatim:

  1. "THE HOOK IS DESIGNED SO YOU WOULD USE THE TOOLS TO WRITE PYTHON FILES AND GO THROUGH THE CHEKS NOT WORK AROUND THEM USING THE BASH"
  2. "THE SAME RULES MUST APPLY TO THE AGENTS AND SUBAGENTS AND MUST ALSO BE A RULE THAT IS PERMANENT SO YOUR PROMISE IS MEANINGLES"

What this rules:

Evidence

Measured 2026-10-17 on session 18108376 (the components refactor orchestrator):

Enforcement

Judgment-only at recording time (2026-10-17 18:24 EDT). This is a recorded gap, not the intended end state. Each mechanism below replaces this line with its gate entry when it lands, and the ruling is complete only when all four are in force.

Mechanism (owed, RUL-014)

  1. Claude main session and subagents. Extend the source of plugins/orchestrata/hooks/intercept_bash.py on master (the installed plugin 1.5.0 is a copy of it) to refuse inline interpreter programs. Hooks are user-level (RUL-035), so subagents are covered, but this is verified by observation: a subagent's python -c call must be refused.
  2. Dispatched opencode workers: one rule set, two adapters. An opencode tool.execute.before plugin, loaded by the headless config, passes each bash, edit and write call to the orchestrata plugin's own PreToolUse hooks through the same JSON contract Claude Code uses.
    • Workers then obey exactly the hooks the main session obeys: the same rules, one implementation.
    • Add an opencode formatter entry for .py, so worker writes are formatted.
    • The plugin never commits and never uses --no-verify.
  3. Brief authoring. dispatch.py run refuses a brief whose checks block contains an inline program. Checks are one-line calls to committed checker files.
  4. Other executors (Hermes, Kimi, pi-task). Each one gets the equivalent guard, verified in its real channel, or is barred from code work.

Build routing (Mohamed, 2026-10-17, verbatim: "AGREE WITH THIS"). Until M2 is in force, every brief that changes Python goes to the sonnet executor, which runs under the Claude hooks. DeepSeek and Qwen get no Python work.

Verification

For each mechanism, run it in the real channel and observe:

scripts/rulings_lint.py checks each declared gate entry once it replaces the judgment line.