Starter repo for AI 372: Agentic Systems Engineering, Patterns & Controls.
Building or extending this course? Read
COURSE_DESIGN_CONTRACT.mdfirst — it is the single source of truth for the architecture, branch convention, and per-module spec.
It contains a real, working content-moderation agent — a perceive-decide-act
loop over a live SQLite comments table, with a runtime brain that decides
what to do with each flagged comment. In the starter its safety controls are
switched off, so it acts on its own authority and even obeys a prompt
injection. Across Modules 2–5 you cage it — without changing the brain — and
prove the cage holds by querying the database directly.
Everything is local and deterministic: no live LLM calls by default, no real systems, no credentials. The brain has a free offline mock (default) and an optional live-Claude backend for demos.
The model proposes the next step. The controller permits or blocks it. A prompt describes intent; the state machine, allowlist, permission policy, approval gates, stop signals, and tests are what make a boundary hold.
pip install -e . # or: pip install pytest pyyaml
python -m pytest # ~13 passed, ~14 failed (the red ones are your work)
python demo/run_demo.py # watch the UNBOUNDED agent moderate
python demo/verify_boundaries.py # prove, from the DB, what it did (breaches now)
test_agent_is_agent.py proves this is an agent (decisions are observation-driven;
the action target is chosen at runtime). The red tests and verify_boundaries.py
breaches are the "before" picture; both go green as you build the controls.
Control flow is produced at runtime by the brain reading observations: different comments yield different actions, and the injection in comment #5 makes the agent re-target a different comment at runtime. It pursues a goal (clear the flagged queue), perceives a live environment, acts through tools, and loops.
Every Module 2–5 activity has two tiers. The worksheet designs a control (a reviewable artifact — everyone does this). The code activity implements the same control, turns its red tests green, and makes the agent measurably more bounded. The worksheet is the spec for the code. Module 1 is worksheet-only (pattern selection + meet the agent; no code).
The spine ships working and is never an exercise: the environment
(env/), the loop (agent/controller.py), the brain (brain/), and the state
machine. The controls are what you build, one per module, each snapping into
the loop:
| Module | Control (where it acts in the loop) | Key files |
|---|---|---|
| 1 | Pattern + boundaries (decision only) | docs/agent-blueprint.md, agent/controller.py (read) |
| 2 | Tool contracts + allowlist — the action boundary | tools/registry.py, tools/validators.py, tools/contracts/*.yaml |
| 3 | Permissions, tiers, approval gates — the authority boundary | permissions/permission_engine.py, approval/*.py |
| 4 | Threat model + detectors — the perceive/decide risk layer | safety/*_detector.py, evals/*.jsonl |
| 5 | Stop signals + traces + capstone — safety & evidence | safety/stop_signals.py, observability/execution_trace.py, demo/ |
exercises/ one handout per module (start with module-1-pattern-selection.md)
solutions/ pointers to git solution branches (solution/module-N)
demo/ run_demo.py, verify_boundaries.py, approve.py
docs/ artifact templates you fill in + ADRs (adr/)
src/ai372/ env, brain, agent(loop+state machine), tools, permissions, approval, safety, observability, config
tests/ green = it's an agent + spine works; red = your control work (TODO-tagged)
evals/ adversarial + boundary fixtures
AI 270 decided bounded autonomy was warranted; AI 370 designed the architecture; AI 372 makes the agent obey the boundaries — in code, and provably.