Intelligent agents in practice: a runnable PEAS design lab
From definition to testable behaviour
An agent receives observations and selects actions. PEAS makes its task explicit: Performance measure, Environment, Actuators and Sensors.
For builders
A small JavaScript lab for people learning to turn an AI-system brief into reviewable code and tests.
What runs
A deterministic rule policy in a synthetic environment. No model, credentials, network or external actions.
What it proves
Only the specified simulation cases—not production security, general intelligence or readiness for client work.

This tutorial is for early-career builders who can run JavaScript and want concrete design-and-test evidence. You do not need a paid AI account. If you are a business owner deciding what to commission, use the agent-or-simpler-workflow guide instead.
You will run the original observation/action loop, inspect its failure cases and reproduce a completed freshness change. The comparison separates what a policy proposes from what its environment permits. All examples are synthetic; copying the supplied lab does not establish your own delivery experience.
1. Specify the task with PEAS
UC Berkeley’s agent-design notes explain rational agents in terms of expected outcomes and define PEAS as a description of the task environment. Rationality is relative to the performance measure and available information, not consciousness, certainty or universal competence.
Our original teaching scenario prepares an internal draft for a fictional maintenance request. It is deliberately small enough to inspect completely. The rule policy is not claimed to be optimal, learned or a modern autonomous LLM product.
| PEAS element | Lab specification | What changes in code |
|---|---|---|
| Performance | One draft only for a permitted, complete request with a successful lookup; otherwise refuse or escalate within the step limit | Assertions on status, drafts and trace length—not a “looks intelligent” score |
| Environment | One synthetic request, a simulated lookup and an in-memory draft list | Input fixture and isolated state per run |
| Actuators | lookup, draft, refuse, escalate | Action allowlist and readiness checks; no send or delete implementation |
| Sensors | Location-present flag, request-permitted flag and latest lookup status | Frozen observation; the policy does not see the future lookup result |
The environment has a hidden lookup outcome until the lookup runs. The policy cannot simply inspect the test’s answer beforehand. This makes the observation boundary visible without pretending that the three possible lookup results represent real-world complexity.
2. Save and run the actual lab
Save all seven files in the same folder. Review the code before execution. It uses Node’s built-in modules and needs no package installation:
- agent.mjs — original policy and simulation
- agent.test.mjs — nine baseline tests
- freshness.mjs — freshness guard and comparison
- freshness.test.mjs — twelve extension tests
- recorded-review.json — executed comparison and source hashes
- CHANGE-REVIEW.md — completed review and handover
- README.md — instructions and limits
With Node.js 22 or later available, open a terminal in that folder:
node agent.mjs
node --test agent.test.mjs freshness.test.mjs
node freshness.mjs --reviewThe normal baseline run prints status: drafted, one draft marked needs-human-review and the trace below. The nine baseline and twelve extension tests should pass: 21 total. The review command deliberately exits with code 2 and REVIEW_REQUIRED; section 4 explains why. No real message, booking or payment is performed.
| Step | Observed lookup | Selected action | Environment result |
|---|---|---|---|
| 1 | not-run | lookup | ok |
| 2 | ok | draft | draft-created; run stops for human review |
This is an execution trace from the supplied deterministic fixture, not a model’s hidden reasoning. externalActions: 0 is zero because this program has no external-action tools, not because an independent security monitor has certified it.
3. Change the environment and inspect failure
Create an exercise file beside the downloaded module. This example simulates an unavailable tool:
import { simulate } from "./agent.mjs";
console.log(simulate({
id: "exercise-1", hasLocation: true,
lookupResult: "unavailable", requestedAction: "prepare-draft"
}));| Change | Expected result | Boundary demonstrated |
|---|---|---|
| hasLocation: false | escalated, no draft | Missing required information is not invented |
| lookupResult: unavailable or conflict | lookup followed by escalation | Failed or contradictory evidence does not permit a draft |
| requestedAction: send; policy returns draft | refused, no draft | The simulator enforces the request boundary even when the policy does not |
| Policy always selects lookup; maxSteps: 3 | step-limit after three actions | Repeated allowed actions terminate |
| failWrite: true | draft-write-failed; empty draft list | Only the simulated in-memory change is rolled back |
| Policy selects draft before lookup | draft-precondition-failed | A selected action still needs valid prerequisites |
Inspect expected status and the absence of an unintended draft, not only the error message. A test that checks merely whether the function returns can pass while the behaviour is wrong.
4. Use an AI coding tool without outsourcing the acceptance criteria
This teaching asset was drafted with AI coding assistance and checked with the supplied automated tests. That is not independent human review or a client deployment. For your extension, keep a record of the coding tool/model, date, request, proposed diff, rejected suggestions and actual test output.
Read this simulator and its tests. Propose one new failure fixture within the current synthetic schema. Explain which PEAS boundary it exercises. Add a failing test before proposing a fix. Do not remove the action allowlist, readiness checks or existing assertions. Do not add network calls or credentials.
Inspect the proposed change before running it. If the coding tool changes the expected result simply to make the test pass, reject that change unless the task specification itself was intentionally revised and documented. Keep the baseline as a comparison and explain why the new implementation is better.
Completed extension: the new task permits a draft only when a successful lookup has a known record age between 0 and 60,000 milliseconds inclusive. Unknown, future-dated and older records require escalation. This 60-second limit is our teaching assumption, not a production recommendation. Both timestamps are supplied synthetic integers, not readings from a real clock.
The original simulator receives its original four fields; it has no timestamp schema. The new wrapper adds recordedAtMs and checkedAtMs, exposing age/status only after lookup succeeds. It keeps the same rule policy and enforces freshness at the action boundary. This is a changed task requirement and environment permission—not a learned or smarter policy, or proof that the baseline violated its older specification.
| Visible fixture | New requirement | Original simulator | Guarded simulator |
|---|---|---|---|
| Age zero | drafted | drafted | drafted |
| Exactly 60,000 ms old | drafted | drafted | drafted |
| 60,001 ms old | escalated | drafted — fails new requirement | escalated |
| Unknown record time | escalated | drafted — fails new requirement | escalated |
| Future record time | escalated | drafted — fails new requirement | escalated |
| Unavailable lookup | escalated | escalated | escalated |
| Missing location | escalated | escalated | escalated |
The executed record shows 4/7 matching cases for the original simulator and 7/7 for the guarded version. All seven fixtures were visible while authoring; none is an independent held-out benchmark. Tests that reproduce these results are not permission to deploy.
| Step | Visible freshness / age | Proposed action | Enforced action / reason |
|---|---|---|---|
| 1 | unobserved / not observed | lookup | lookup / no freshness override |
| 2 | stale / 60001 ms | draft | escalate / freshness-stale |
Notice the second step still records a proposed draft. The guard changes execution to escalate; it must not erase the policy’s proposal. The downloadable JSON preserves every case and source hashes. The completed CHANGE-REVIEW.md records rationale, actual results, AI assistance, limits and recipient instructions. Its decision remains REVIEW_REQUIRED: independent technical and recipient review have not occurred.
5. State what this lab does not test
The simulation does not implement real authentication, persistent duplicate prevention, concurrency, process isolation, live tool timeouts, crash recovery or prompt-injection defence. The policy is trusted synchronous local code: an infinite loop inside it can hang the process despite the step limit. Never run untrusted generated code on the assumption that this harness contains it.
No language model learns here. Tool feedback changes the next action in one run; nothing persists between runs and no model parameters change. Adding an asynchronous LLM or a live tool requires a separate design for timeouts, access, cost, data handling and recovery—not simply replacing the policy function and claiming the same tests prove safety.
For further architecture context, Anthropic distinguishes predefined workflows from model-directed agents. That distinction prevents this simple rule policy from being presented as evidence of an LLM’s planning ability.
The rollback test restores an array after an injected failure. It does not undo an email or payment. A real deployment must describe irreversible consequences and test the actual system boundary.
The freshness extension fixes both fixture clocks for the whole run. It does not test clock trust or skew, elapsed time during a real tool call, record changes between checking and acting, or concurrent writes. Frozen observations constrain the intended interface, not trusted code sharing the same process. Removing the guard would restore the three freshness failures, not provide a safe real-world rollback.
6. Turn the exercise into honest delivery evidence
Before sharing your work, include the PEAS table, instructions, baseline output, one failure you added, the reviewed diff, test results and known limits. Ask another person to run it from those instructions; record what failed or needed explanation. Do not label that verification complete until it happens.
If you already have broader delivery evidence, show MLAI Studio what you shipped, how you used AI coding tools and how you tested the boundaries. This lab alone is not proof of client readiness. Applications are considered for scoped paid work; selection, available projects and portfolio publication rights are not guaranteed. Current intake asks about contracting in Australia; confirm eligibility before assuming a New Zealand pathway.
A practical next step with MLAI
Show how you review what you build
Have delivery evidence beyond this teaching lab? Share a permitted AI-assisted build, your own contribution, test results and limitations with MLAI Studio to be considered for scoped paid projects. Selection and matching are not guaranteed.
Apply with your build evidenceStill learning? Choose an appropriate MLAI event and bring a specific test question. For a complementary evidence exercise, see the agent-trace lab and its provenance limits.
Primary sources checked 10 September 2026. The lab is an original synthetic teaching example, not Berkeley- or Anthropic-endorsed software. The Anthropic source supplies an architectural distinction, not a current tool recommendation. These tests establish only the cases described above.
Frequently Asked Questions
Does an intelligent agent have to use an LLM?
What does PEAS stand for?
Is the lab learning from its results?
Does rollback undo real actions?
Disclaimer: This article provides general information and is not legal or technical advice. For official guidelines on the safe and responsible use of AI, please refer to the Australian Government’s Guidance for AI Adoption →
A practical next step with MLAI
Show how you review what you build
Have delivery evidence beyond this teaching lab? Share a permitted AI-assisted build, your own contribution, test results and limitations with MLAI Studio to be considered for scoped paid projects. Selection and matching are not guaranteed.
Apply with your build evidence