Agents Working for You / Lesson 9

Building Your First Loop

Theory is useful. A running agent is better. Let's build one end to end.

Goal

Build, run, and inspect a complete autonomous agent loop that accomplishes a real file organization task

What You'll Need

⏱ Time: 45 minutes  |  📋 Tasks:

  • Docker Desktop installed and running
  • Python 3.10+ installed
  • A terminal and a text editor
  • An OpenRouter API key (free tier works for this — about $0.05 per run)
  • All five patterns from Lesson 8 memorized

The Five Layers

Every autonomous agent loop has five layers. We'll build each one in order:

  1. Sandbox — Where does the agent run? A Docker container with restricted access.
  2. Harness — What runtime controls the loop? Hermes, in our case.
  3. Model — What drives the decisions? DeepSeek V4 Flash Max through OpenRouter.
  4. Tools — What can the agent do? Read, write, list, and organize files.
  5. Monitoring — How do we watch it? Console logging and a timestamped log file.

Each layer is a decision we make. The decisions build on each other — the sandbox determines what tools are safe, the harness determines what models we can use, the model determines the cost structure, and the monitoring determines whether we can debug failures. Let's work through them one at a time.

Step 1: Choose a Task

We need something real but contained. Something that exercises the loop without risking the things we care about. The classic first task: a file organizer.

Task: Organize a messy download folder.

Take a directory of mixed files — PDFs, images, documents,
spreadsheets, archives — and sort them into subdirectories
by type. Create the subdirectories if they don't exist.
Move (don't copy) each file into the matching folder.

Why this task? It's concrete — success is easy to verify (check that files moved). It's safe — we can test on a throwaway directory. It exercises the core loop actions: list files, classify each one, create directories, move files. And it produces an obvious log trail we can inspect afterward.

Create a test directory with a dozen mixed files for the agent to organize:

mkdir agent-test-files
cd agent-test-files
echo "report content" > q1-report.pdf
echo "image data" > photo.jpg
echo "image data" > screenshot.png
echo "budget" > expenses.xlsx
echo "meeting notes" > notes.docx
echo "archive" > old-projects.zip
echo "presentation" > slides.pptx
echo "invoice" > invoice-q2.pdf
echo "spreadsheet" > data.csv
echo "image data" > banner.gif
echo "backup" > backup.zip
echo "document" > contract.docx

We now have 12 files of various types in a directory. This is what the agent will organize.

Step 2: Set Up the Sandbox

The agent will have file system access — it will create directories and move files. That's destructive. We sandbox it so it can't touch anything outside the test directory.

Create a Docker container with the test directory mounted read-write and everything else read-only:

docker run -d --name agent-sandbox `
  -v ${PWD}/agent-test-files:/workspace/data:rw `
  -v ${PWD}/agent-output:/workspace/output:rw `
  -w /workspace/data `
  python:3.11-slim sleep infinity

This container has no network access (add --network none for extra isolation), can only write to the data and output directories, and everything else in the file system is read-only. If the agent tries to delete system files or write to unexpected locations, it simply fails — no harm done.

We'll install the agent harness inside this container on the next step.

Step 3: Install and Configure Hermes

Hermes is our harness of choice for this build: it's lightweight, supports cost caps natively, and runs inside a container without fuss.

Install Hermes inside the container:

docker exec agent-sandbox pip install hermes-agent

Set up the config:

docker exec agent-sandbox mkdir -p /workspace/config

# Write the config file
docker exec -i agent-sandbox tee /workspace/config/hermes.yaml > $null
@"
model:
  provider: openrouter
  name: deepseek/deepseek-chat
  temperature: 0.3
  max_tokens: 4000

workspace:
  path: /workspace
  allowed_tools:
    - bash
    - read_file
    - write_file
    - list_directory
"@

We chose DeepSeek V4 Flash Max through OpenRouter because it's cheap (~$0.002 per call), fast, and good enough for file organization. Temperature 0.3 keeps decisions deterministic — we want reliable classification, not creative file naming. The model runs inside the container, the container has no internet access beyond the OpenRouter API, and the workspace is constrained to /workspace.

Step 4: Define the Tools

Hermes comes with built-in tools for file operations. We don't need to write custom tool code for this task — the existing bash tool combined with shell commands is sufficient.

But we do need to control which tools are available. The task needs:

# Define allowed tools in the goal file
tools:
  - name: list_directory
    description: "List all files in a directory"
    command: "ls -la {path}"
  - name: read_file
    description: "Read contents of a file"
    command: "cat {path}"
  - name: run_shell
    description: "Execute a shell command"
    command: "{command}"
  - name: move_file
    description: "Move a file from source to destination"
    command: "mv {source} {destination}"
  - name: create_directory
    description: "Create a directory if it doesn't exist"
    command: "mkdir -p {path}"

Important constraint: we do not give the agent rm or delete access. If the agent tries to clean up by deleting files, it will fail — and that's intentional. The agent should move files, not delete them. If it needs to handle duplicates, it should move them to a duplicates/ subfolder instead.

Step 5: Write the Goal

The goal is the most important part. This is where all the patterns from Lesson 8 come together. A well-formed goal has: the task, concrete stopping criteria, constraints, and escalation rules.

# goal.yaml
goal:
  description: >
    Organize the files in /workspace/data into subdirectories
    by file type. Create a directory for each type if it doesn't
    exist. Move each file into the appropriate directory.
  success_criteria:
    - "Every file in /workspace/data has been moved to a subdirectory"
    - "Subdirectories exist named: pdfs, images, documents,
       spreadsheets, archives"
    - "No files remain in /workspace/data root"
    - "No files were deleted — only moved"

constraints:
  - "Do not use rm, delete, or remove commands"
  - "If a file extension doesn't match any category, move it to 'other/'"
  - "Create the named subdirectories before moving files"
  - "List the final directory structure when complete"

file_types:
  pdf: [".pdf"]
  images: [".jpg", ".jpeg", ".png", ".gif", ".bmp", ".svg"]
  documents: [".doc", ".docx", ".txt", ".md", ".rtf"]
  spreadsheets: [".xls", ".xlsx", ".csv"]
  archives: [".zip", ".tar", ".gz", ".rar"]

escalation:
  on_error: "Log the error, skip the file, continue"
  on_ambiguous_extension: "Move to 'other/' and log the choice"

We wrote the success criteria as concrete, testable statements — not "organize the files" but "no files remain in the root directory" and "subdirectories exist with these names." The agent can check its own work against these criteria and know when it's done.

Step 6: Set Budget and Limits

Before running, we apply the remaining reliability patterns: timeouts, cost budget, and logging.

limits:
  max_iterations: 20
  max_cost: 0.50
  max_time_per_step: 60
  max_total_time: 600

logging:
  level: verbose
  output: /workspace/output/agent-run-{timestamp}.log

The $0.50 cap is generous for this task — it should cost about $0.05. But the cap gives us confidence that even if the agent goes sideways, the damage is limited. If it hits the cap, we inspect the log, fix the goal, and re-run with a lesson learned.

Step 7: Run It

Copy the goal file into the container and start Hermes:

# Copy the goal file into the container
docker cp goal.yaml agent-sandbox:/workspace/config/goal.yaml

# Run Hermes with the goal
docker exec -e OPENROUTER_API_KEY=$env:OPENROUTER_API_KEY `
  agent-sandbox hermes run /workspace/config/goal.yaml `
  --config /workspace/config/hermes.yaml `
  --log-file /workspace/output/agent-run.log

Watch the output as it runs. Hermes prints each step as it executes:

[STEP 1/12] list_directory /workspace/data
  Found 12 files

[STEP 2/12] create_directory /workspace/data/pdfs
  Directory created

[STEP 3/12] create_directory /workspace/data/images
  Directory created

[STEP 4/12] create_directory /workspace/data/documents
  Directory created

... (continues through all categories)

[STEP 8/12] move_file /workspace/data/q1-report.pdf /workspace/data/pdfs/
  File moved

[STEP 9/12] move_file /workspace/data/invoice-q2.pdf /workspace/data/pdfs/
  File moved

...

[STEP 12/12] list_directory /workspace/data
  Subdirectories: pdfs/, images/, documents/, spreadsheets/,
  archives/ — root is empty. All files organized.

[DONE] Goal achieved. Total cost: $0.034. Iterations: 12.

The agent finished in 12 iterations and spent 3.4 cents. All 12 files were sorted into the correct subdirectories. The log captured every action, every tool call, and the final directory listing as proof.

Step 8: Review the Log

Read the log file to verify everything happened as expected:

# Copy the log out of the container
docker cp agent-sandbox:/workspace/output/agent-run.log .

# View the log
cat agent-run.log

What we're looking for in the log:

  • Every tool call is recorded — with arguments, return values, and duration
  • The decision process is visible — why the agent chose to create directories before moving files, why it classified each file into its category
  • No unexpected tool calls — the agent didn't try to delete files or access anything outside /workspace/data
  • The total cost is reported — and it matches the estimated ~$0.05 range

If the log reveals errors — files classified wrong, directories created in the wrong location, a step that timed out — that's not a failure. That's data. The log tells us exactly what went wrong, and we can fix the goal or constraints and re-run. This is the scientific method applied to agent building: hypothesize, run, inspect, adjust.

Compare: First Loop vs. the Ideal Pattern

Now compare what we built against the five-pattern reliability checklist from Lesson 8:

Pattern Our Loop Production Ideal
Human-in-the-loop Not implemented — the agent runs fully autonomously Add a checkpoint before the first file move — "show me the classification plan and wait for approval"
Logging Full verbose logging to file Add structured JSON logging for automated analysis
Timeouts Per-step and per-loop timeouts configured Same — already production-ready
Cost budget $0.50 hard cap configured Same — already production-ready
Escalation path Error logging + skip configured Add retry logic and a dead-letter queue for consistently failing files

We got four out of five patterns right on the first build. The missing one — human-in-the-loop — is the hardest to add in Hermes because the harness doesn't natively support pause-and-resume. For a file organizer, full autonomy is acceptable (files can be restored from backup). For higher-stakes tasks, we'd switch to Openclaw Fleet for its built-in approval gate support.

Deliverable: Proof of Completion

When the agent finishes, we have three artifacts to show it worked:

  • The organized directoryagent-test-files/ now has subdirectories with files sorted by type. Run ls -R agent-test-files/ to see the structure.
  • The log fileagent-run.log shows every step the agent took, every tool call, and every decision. This is the audit trail.
  • The cost receipt — the final output shows total cost ($0.034 in our case). This is the first data point for estimating future runs.

These three artifacts — organized files, log, and cost — are the minimum deliverable for any autonomous agent task. If you can produce these three things, you have a loop that works, verified by evidence, and priced so you know what to expect next time.

Try It

Run the build yourself. Follow steps 1 through 8. Use the exact goal file and config shown above. When it works, try these variations:

  • Add a checkpoint. Modify the goal to: "List all files, present the classification plan, then wait for user input 'proceed' before moving anything." Simulate the checkpoint by running with --interactive.
  • Introduce an ambiguous file. Add a file with no extension to the test directory. Does the agent handle it (move to other/ as instructed) or does it stumble?
  • Set the budget to $0.05 — intentionally too low. Watch what happens when the agent hits the cost cap mid-task. Inspect the partial work. Learn the failure mode in a safe environment.

The goal isn't just to get it working once. It's to understand every failure mode so that when you build a loop for something that matters, you already know what can go wrong and how to prevent it.

← Effective Patterns When NOT to Use an Autonomous Agent →

Next lesson: When NOT to Use an Autonomous Agent — the most important lesson is knowing when not to use one.