Skip to content
Level 5 · Agentic EngineerProjectCapstone · page 6 of 790 minSXMN 16 GB
90Minutes
4Tools
3Sources
All fourTracks
Tools used on this page4

Capstone 5: The Agentic Workstation

Validated on: written from the documentation cited above and from Parts 24 to 27; not yet validated on hardware on any track. The agents, the sandbox and the evaluation suite were each built in those parts; this project assembles them and asks for the evidence.

By the end of this project you will have a workstation on which two different kinds of agent do real work using models your own service serves, inside a boundary you have tested by trying to cross it, rebuildable from a script you have actually run, with suite numbers from enough repeats that you can defend a comparison.

The reason this is a capstone deliverable rather than a configuration exercise is the sandbox. An agent is a loop in which a model decides the next step, and the steps are real: files change, commands run, network requests go out. Everything in Parts 24 to 26 about permissions, prompt injection and human-in-the-loop becomes concrete the moment a model you fine-tuned yourself is deciding what to do with your source tree.

The workstation is a client of the service you built in Capstone 2, not a replacement for it. Drawing the boundary is the point of the picture.

The workstation, and the line the sandbox draws

  • clientYouapprove the steps that need approving; read the trajectories afterwards
  • agentAgent A, supervisedthe one you watch: an editor or terminal agent on a task you care about
  • agentAgent B, unattendedthe one that runs a bounded task alone, inside the sandbox
  • workerSandboxnon-root, read-only root filesystem, one writable project directory, no credentials
  • workerMCP serversthe tools; each with a stated permission and a stated blast radius
  • routerGatewayfrom Capstone 2: one key per agent, its own limits and its own budget
  • workerModelsthe coding model, the small router model, and your improved model from Capstone 4
  • storageProject directorythe only thing the agents can write, and it is under version control
Two links carry the whole security argument: the sandbox reaches the gateway and nothing else on the network, and it writes the project directory and nothing else on the disk. Everything in the boundary test is an attempt to find a third link that should not be there.

Every track needs the service from Capstone 2 with a working gateway key per application, the agent configurations from Part 25, the sandbox from its sandbox lab, the suite and the repeat rule from Part 26’s evaluation lesson, and about ninety minutes. The 16 GB floor is because a workstation runs at least two models at once: the one the agent drives and the small one that routes or classifies.

Track S — NVIDIA DGX Spark

All of it applies, and with a large unified memory you can keep the coding model and a small model resident together, which removes the model switch from the critical path of an agent loop. Record the memory both agents occupy while working, because it is a number your Capstone 1 plan probably did not include.

Track X — AMD Ryzen AI Max+ 395

All of it applies. Container-based sandboxing is available on this track and Part 25’s lab covers the hardening step for it. The thing to watch is that an agent loop is many short requests rather than one long one, so the model switch, if you rely on one, is exercised far more often here than during chat use.

Track M — Apple siliconPartial

Container support on macOS runs inside a virtual machine, which changes what the boundary checks are testing; Part 25's lab gives the dedicated-user alternative.

Both paths are open: a container, with the caveat that on this platform it runs inside a virtual machine, or a dedicated user account as Part 25’s lab describes. Whichever you choose, say in the checklist which mechanism enforced each boundary, because “the container refused it” and “file permissions refused it” are different claims with different failure modes.

Track N — NVIDIA desktop or laptop

All of it applies. On this track the constraint is usually device memory, so the two resident models may not both fit and the model switch becomes part of the agent’s latency. Measure that: the time an agent spends waiting for a model to load is time your suite numbers will attribute to the agent.

Working directory and terminal roles

Prepare the course execution workspace once before this procedure. It includes this part's scripts, data and shared Python helpers. In the client or training terminal, select this directory:

RunnableAll tracks

select this part’s execution directory
export LABS_ROOT="${LABS_ROOT:-$HOME/llm-course/labs}"
export LAB_DIR="$LABS_ROOT/capstone"
cd "$LAB_DIR"
pwd
test -f "workstation-checklist.md"

Expected result: pwd ends in capstone and the file check returns successfully. If it does not, finish workspace preparation before continuing. Activate the environment in the requirements for your track. Bare script and data filenames below are relative to this directory; paths to earlier experiments must point at the artefacts you actually retained.

Keep each foreground server in a separate terminal and send requests from this terminal. Reapply lesson-specific environment variables in each new shell. Stop at the first failed checkpoint and retain its output; the execution guide explains how to distinguish missing files, endpoint failures and capacity problems.

Fragment — not complete on its own

workstation-checklist.md
# Agentic workstation checklist — <the workstation you are building>
<!--
Purpose: the deliverable of Capstone 5. Two agents driven by local models, the tools they
reach through MCP servers, a sandbox whose test passes by failing, a setup script
that rebuilds the whole thing, and the evaluation suite's numbers over enough
repeats to mean something.
Platform: all
Minimum memory: 16 GB; the agent-driving models in this course start around there and the
workstation runs at least two models at once
Assumes: the gateway from Part 9's project, the agent loop and MCP work of Part 24, the
coding-agent configurations and the sandbox lab of Part 25, the multi-agent
patterns and evaluation suite of Part 26, and the improved model from Capstone 4
if it is good enough for one of the roles.
The rule: nothing here is a plan. Every row names what you ran and what it printed, and
the sandbox section is only complete when every boundary attempt was refused and the
control check still succeeded. Delete every comment block, including this one.
No key, address or hostname belongs in this file.
-->
**Author:** <you> · **Date:** <YYYY-MM-DD> · **Track:** <S/X/M/N> ·
**Machines:** <which machine hosts the agents, which serves the models>
---
## 1. Agents and models per role
| Role | Agent | Model | Served by | Context configured | Why this pairing | Evidence |
| --- | --- | --- | --- | --- | --- | --- |
| <e.g. the one you supervise closely> | <agent> | <id or your improved model> | <gateway alias> | <n tokens> | <one sentence> | <a measurement or an observed failure> |
| <e.g. the one that runs a small task unattended> | | | | | | |
| <router or classifier, if you have one> | | | | | | |
**Two agents at minimum, and they must be different in kind:** <say what the difference is
in one sentence: a terminal agent and an editor agent, an interactive one and a batch one,
one you watch and one you do not.>
**Memory while both are running:** <GB observed, against <GB> available, at <the moment
you measured it: both idle, one working, both working>.>
**What happens when both want a model at once:** <the gateway queues, the swap unloads one,
or they use different models. Say which, and how you found out.>
## 2. MCP servers and tools
| Server | Transport | What it can read | What it can change | Reaches the network? | Why the agent needs it |
| --- | --- | --- | --- | --- | --- |
| <name> | <stdio or HTTP> | <paths, data> | <nothing, these paths, these commands> | <no / these hosts> | <one sentence> |
**Tool descriptions are untrusted input.** <Name where each server came from, and say what
you did about the ones you did not write: read the source, pinned a version, ran it inside
the sandbox, or all three.>
**The lethal combination, checked:** <does any single agent hold private data, read
untrusted content and have a way to send data out? If yes, say which of the three you
removed and how. If the answer is no by construction, say what the construction is.>
**What would happen if a tool's output were hostile:** <one paragraph, naming the agent
that would act on it and what would stop it.>
## 3. The sandbox and its test
| Field | Value |
| --- | --- |
| Mechanism | <container runtime, dedicated user, virtual machine> |
| Runs as | <a non-root user id> |
| Root filesystem | <read-only or not, and why> |
| What is writable | <the project directory only, or the list> |
| Network | <what it can reach; the gateway should be on the list and little else> |
| Credentials visible inside | <none; and how you confirmed it> |
| Rebuilt from | <the file that defines it> |
| Boundary check | What was attempted | Result | Pass condition |
| --- | --- | --- | --- |
| Home directory not mounted | <read something outside the project> | | refused |
| Container control socket absent | <list containers from inside> | | refused |
| Runs as a non-root user | <print the user id> | | not root |
| Root filesystem read-only | <write outside the project> | | refused |
| Project directory writable | <write a file in the project> | | succeeds |
| Planted secret unreadable | <read a file you planted outside> | | refused |
| Environment clean | <print the environment> | | no credential in it |
| Outbound network blocked | <fetch something on the internet> | | refused |
| **Control: the gateway is reachable** | <one completion through the gateway> | | **succeeds** |
<The control row is what stops you celebrating a box so isolated that no agent can work in
it. Part 25's boundary test is built the same way, and a run where every boundary was
refused and the control failed is a failed test, not a strict one.>
**Date the whole test last passed:** <YYYY-MM-DD> · **Anything that did not pass:**
<what, and what you changed.>
## 4. The setup script
| Field | Value |
| --- | --- |
| Script | <name> |
| What it builds | <the sandbox image, the agent configuration files, the gateway aliases, the MCP server list> |
| What it deliberately does not do | <download models, write secrets, start anything destructive> |
| Where secrets come from | <the environment, an untracked file, a prompt; never the script> |
| Run from clean on | <YYYY-MM-DD, on which machine> |
| What it did not cover, found by running it | <the manual steps that remained> |
| Time it took | <minutes> |
<The test of the script is a fresh run, not a reading. The list of things it did not cover
is the most useful output of that run and it belongs above rather than in your memory.>
## 5. Evaluation suite results
| Configuration | Agent | Model | Repeats | Success rate | Mean steps | Mean tokens | Mean seconds | Spread across repeats |
| --- | --- | --- | --- | --- | --- | --- | --- | --- |
| <baseline: the stock model> | | | <3> | | | | | |
| <the improved model from Capstone 4> | | | <3> | | | | | |
| <a second agent or a smaller model> | | | <3> | | | | | |
**Task set and version:** <file and version> · **Tasks:** <n> · **Date:** <YYYY-MM-DD>
**Comparisons you are prepared to defend:** <name them, with the spread. Part 26's rule is
three repeats as the minimum for comparing two configurations, and with a suite of this
size a difference of one or two tasks is inside the noise.>
**One failing trajectory, read:** <which task, at which step it went wrong, and what the
agent did instead. One paragraph, and it teaches more than the whole table.>
**Cost, if you computed it:** <tokens per task and the cost per million tokens from the
Part 23 model, or "not computed".>
## 6. What is not done, and what you would not trust it with
<Every gap above, one line each. Then the sentence that matters: what would you not let
this workstation do unattended, and what would have to be true before you would?>

Download workstation-checklist.md131 lines

RunnableAll tracks

start from the checklist
cp workstation-checklist.md workstation.md

As in Capstone 2, every row names what you ran and what it printed. The difference here is that one whole section passes by failing, and that section is the one to read before you build anything.

2. Two agents, of different kinds, with a reason for each model

Section titled “2. Two agents, of different kinds, with a reason for each model”

Section 1. Two agents at minimum and they must differ in kind, not merely in name: one you watch and one that runs a bounded task alone, or a terminal agent and an editor agent, or an interactive one and a batch one. Say in one sentence what the difference is.

For each, the model, the gateway name it reaches, the configured context, and the reason for the pairing with the evidence behind it. “A measurement or an observed failure” is the standard: Part 25’s lab compared several agents on one task and Part 26’s suite gives success rates, and either is evidence. A preference is not.

This is where your improved model from Capstone 4 gets its trial. If it is good enough for one of these roles, use it and record the comparison. If it is not, record that too: a fine-tune that improved a format and cannot drive a tool loop is a specific, useful finding and it belongs in the report.

Then the row people forget: what happens when both agents want a model at once. The gateway queues, the switch unloads one, or they use different models. Find out which, rather than assuming, and write down the memory both agents occupy while working.

3. The tools, and what each one is allowed to touch

Section titled “3. The tools, and what each one is allowed to touch”

Section 2, one row per server: what it can read, what it can change, whether it reaches the network, and why the agent needs it.

The Model Context Protocol’s specification is explicit about the trust position here, and it is worth reading rather than paraphrasing. Its key principles are that users must explicitly consent to and understand data access and operations; that tools represent arbitrary code execution and must be treated with appropriate caution; that descriptions of tool behaviour, including annotations, should be considered untrusted unless they come from a trusted server; and that hosts must obtain explicit consent before invoking a tool. The specification also notes that the protocol itself cannot enforce any of this, which puts it in your configuration rather than in the wire format.

Two consequences for your checklist. First, name where each server came from and what you did about the ones you did not write: read the source, pinned a version, ran it inside the sandbox, or all three. Second, fill in the row about the dangerous combination that Part 26’s project is built around: does any single agent hold private data, read content it did not author, and have a way to send data outwards? If the answer is yes, say which of the three you removed. If it is no by construction, say what the construction is.

4. Build the sandbox, then try to break out of it

Section titled “4. Build the sandbox, then try to break out of it”

Section 3, and this is the deliverable’s centre.

Docker’s own security documentation describes what a container gives you: kernel namespaces so that processes cannot see or affect processes outside, control groups so that one container cannot starve the machine, and it is direct about the daemon being the sharp edge, stating that only trusted users should be allowed to control it. It also states that exposing the daemon’s API over plain HTTP is not permitted and causes the daemon to fail at startup. On the Apple track, where containers run inside a virtual machine, or if you use a dedicated user account instead, the mechanisms differ and the checklist should say which one enforced each boundary.

Then run the boundary test from Part 25’s lab and record every line. Nine checks: eight boundaries you try to cross and one control.

Check What you attempt A pass is
Home directory not mounted Read a file outside the project refused
Container control socket absent List containers from inside refused
Runs as a non-root user Print the user identifier not root
Root filesystem read-only Write outside the project refused
Project directory writable Write a file in the project succeeds
Planted secret unreadable Read a credential file you placed outside on purpose refused
Environment clean Print the environment no credential in it
Outbound network blocked Fetch something on the public internet refused
Control: gateway reachable One completion through the gateway succeeds

Plant the secret yourself, in a file outside the project, so that the check tests something real rather than the absence of anything to find. Then record the date the whole test last passed and anything that did not.

5. Give each agent its own key, with its own limits

Section titled “5. Give each agent its own key, with its own limits”

The gateway from Capstone 2 already supports this and the agents are the reason it matters. An agent loop is the most likely thing in your household to send a thousand requests by accident, and LiteLLM’s virtual key documentation covers the properties that turn that into a refusal rather than an outage: a spending budget per key, requests-per-minute and tokens-per-minute limits, an expiry, and rotation.

One key per agent, not one key for “the agents”. When one of them misbehaves you want to revoke exactly it, and you want the usage log to say which one did it.

6. Write the setup script, then run it from clean

Section titled “6. Write the setup script, then run it from clean”

Section 4. The script builds the sandbox image, writes the agent configuration files, adds the gateway names, and lists the MCP servers. It does not download models, does not write secrets, and does not do anything destructive without asking.

Then run it on a machine or in a directory where none of it exists yet, and time it. The list of things it did not cover is the most valuable output of that run, and it exists in your memory for about a day, so write it into the checklist immediately.

7. Run the evaluation suite, three repeats

Section titled “7. Run the evaluation suite, three repeats”

Section 5. Part 26’s suite gives four numbers per configuration: success rate, steps, tokens and seconds. Run each configuration you want to compare three times at minimum, and report the spread.

The rule is worth restating because it is the one most often broken here. One repeat tells you whether the thing runs at all. Three is the minimum for comparing two configurations. More than that is for a decision you are not going to revisit. With a suite of a dozen or two tasks, a difference of one or two tasks is comfortably inside the noise, and if you only have time for two runs, spend both on the same configuration and learn your noise floor instead.

Compare at least two configurations: the stock model against your improved model from Capstone 4, or your two agents on the same tasks, or a smaller model against a larger one. Say in the checklist which comparisons you are prepared to defend and which you are not.

Then read one failing trajectory properly. Which task, at which step it went wrong, and what the agent did instead. One paragraph, and it will teach you more than the whole table.

Section 6. Every gap, one line each, and then the sentence that matters: what would you not let this workstation do unattended, and what would have to be true before you would?

That sentence is the honest end point of Level 5. The course’s position throughout has been that an agent is a loop, that the loop runs real commands, and that the interesting engineering is in the boundaries rather than in the prompt.

List every tool available to each agent and the resources it may access. Verify the sandbox directly with synthetic denied reads, prohibited network access and absent administrative sockets before running a model. Then test a permitted code task and a denied action through the agent itself.

Use separate client credentials and record their gateway limits. Keep the starting repository, task prompt and trusted tests outside the disposable edit area. For each trial, retain the diff, independent test output, trajectory, token usage, elapsed time and manual interventions. Confirm the agent did not change the success test to make its own result pass.

Rebuild from the setup script in a fresh environment and repeat the boundary and task checks. This detects hidden global configuration and dependencies on earlier sessions. Document cancellation, credential rotation and recovery from an unavailable model. State which tasks remain unsuitable for unattended execution and why. The workstation is complete when its useful effects and denied effects are both demonstrated under the written operating procedure, with enough evidence for a reviewer to assess the actual code and permissions rather than relying on the agent’s self-report.

  • workstation.md has a status and evidence for every row.
  • Two agents are configured, they differ in kind, and each has a model with a stated reason and evidence behind it.
  • Each MCP server has a row stating what it can read, what it can change and whether it reaches the network.
  • The row about private data, untrusted content and an outward channel is answered.
  • All eight boundary checks were attempted and refused, and the control check succeeded, on a recorded date.
  • A secret you planted outside the project was unreadable from inside.
  • Each agent has its own gateway key with a limit on it, and a request past the limit is refused.
  • The setup script has been run from clean, timed, and the list of what it did not cover is written down.
  • The suite was run at least three times per configuration, with the spread reported, on at least two configurations.
  • One failing trajectory is described in a paragraph.
  • The memory both agents occupy while working is recorded, against the Capstone 1 budget.

A workstation you use, and a checklist in which the security claims are things you tried rather than things you configured. The shape below is what the suite table commits to.

Pending validationThe agent comparison this project produces — the shape, to be filled in with your own
ConfigurationAgentModelRepeatsSuccess rateMean stepsMean tokensSpread
Baselinethe agent you watchthe stock coding model3pendingpendingpendingpending
Improved modelthe same agentyour model from Capstone 43pendingpendingpendingpending
Second agentthe unattended oneas configured3pendingpendingpendingpending
Smaller modeleither agentthe small model from your plan3pendingpendingpendingpending

the machine hosting the agents, and the machine serving the models if they differ · the engine behind the gateway name each agent used as recorded in your run records · as listed per row, the file each gateway name resolves to · 32,768 tokens of context · 2026-09-09

Three repeats is the minimum for comparing any two rows. With a suite of a dozen or two tasks, a difference of one or two tasks is inside the noise, and the spread column is what tells you which comparisons you can defend.

Two workstations count as finished. One is a single machine running the service and the agents together, where the interference between them is itself a measurement worth having. The other separates them, and the agents reach the service over the house network through the same authenticated front door as everything else. The checklist is the same in both cases, and so is the boundary test.

The agent cannot reach the model. Check the control row of the boundary test first: if the sandbox has no route to the gateway, everything else will look like a model problem. The control check exists precisely to make this five seconds of diagnosis instead of an hour.

The boundary test passes completely and the agent cannot do anything. The control check failed, or you have blocked the project directory as well as everything else. A sandbox is a shape, not an absence.

The agent loops, burning tokens. The rate limit on its key turns this into a refusal rather than an outage, which is why each agent has its own. Then look at the trajectory: repeated identical tool calls usually mean the tool returned something the model could not use, and the fix is in the tool’s output rather than in the prompt.

Tool calls fail constantly on your improved model. Part 25’s material on which models can drive an agent is the reference. A fine-tune that narrowed a model to a format can make it worse at producing tool calls, which is exactly the kind of regression Capstone 4’s section 7 asks about; if you find it here, go back and add it there.

Suite numbers move a lot between runs. That is the finding, and it is why three repeats is the minimum. Report the mean and the range, and if the ranges of two configurations overlap, say that they are indistinguishable on this suite rather than picking the higher mean.

The setup script works for you and not on a clean machine. That is the script working as a test. Whatever it depended on that you had already is the thing to add, and the list in the checklist is where it goes.

Stop the unattended agent, revoke any temporary key you made, and delete the planted secret file so that it does not become a real one. Remove the sandbox container if you are not keeping it running, but keep the file that defines it, because it is the artefact.

Keep the trajectories: Capstone 6 quotes one, and Part 27’s work on improving a model from your own agent trajectories starts from exactly this material. Note in the checklist what is still running.

  • The sandbox is the deliverable, not the agents. Agents are configuration; the boundary is engineering, and it is the part that has to be tested by trying to cross it.
  • A boundary test needs a control. Eight refusals prove nothing without one success, and the failure this catches is a box nothing can work in.
  • Tool descriptions are untrusted input. The protocol’s own specification says so, and it also says the protocol cannot enforce any of it, which puts the burden in your configuration.
  • One key per agent is what makes revocation and attribution possible. A runaway loop becomes a refusal and the usage log says which agent did it.
  • A setup script is tested by running it somewhere it has never run. What it did not cover is the useful output.
  • Three repeats or no comparison. With a small suite, one or two tasks of difference is noise, and the spread column is what says which comparisons you can defend.

Record in the notebook: the boundary test result with its date, the memory both agents occupied while working, the suite runs with their spreads, which comparisons you would defend, and one paragraph on the failing trajectory you read.

Check your understanding

Question 1. Your boundary test refuses all eight attempts and the control check also fails. What have you built?
Show the answer and why

Answer: A box no agent can work in, which is a failed test rather than a strict one

The control exists to stop exactly this celebration. A sandbox is a shape: the agent must be unable to reach your home directory, your credentials and the wider network, and must still be able to reach the gateway and write the project directory. Eight refusals with no success is isolation, not a workstation.

Question 2. The Model Context Protocol specification says tool descriptions and annotations should be treated how?
Show the answer and why

Answer: As untrusted, unless obtained from a trusted server, because tools represent arbitrary code execution

The specification lists this under tool safety, alongside the requirement that hosts obtain explicit user consent before invoking a tool. It also notes that the protocol cannot enforce these principles at the wire level, which is why the useful question in your checklist is what would happen if a server output were hostile.

Question 3. Why does each agent get its own gateway key rather than sharing one? Select all that apply.
Show the answer and why

Answer: So that one misbehaving agent can be revoked without breaking the others, So that the usage log says which agent generated the traffic, So that limits and budgets can differ between a supervised agent and an unattended one

Revocation, attribution and differentiated limits are the three practical reasons, and an agent loop is the most likely thing in a household to generate a thousand requests by accident. Nothing in the protocol requires it; it is an operational choice that Capstone 2 already made possible.

Question 4. You have time for two suite runs. What is the best use of them?
Show the answer and why

Answer: Two runs of the same configuration, to learn the noise floor

Part 26 gives this advice directly. One run each produces a comparison you cannot defend, because with a small task suite a difference of one or two tasks sits inside the run-to-run variation. Two runs of one configuration at least tells you how large that variation is, which is what makes any later comparison meaningful.

Question 5. True or false: your fine-tuned model from Capstone 4 should be used for the agent roles because it is your own model.
Show the answer and why

Answer: False

It should be tried and measured. A fine-tune that narrowed a model to a format can be worse at producing tool calls than the model it came from, which is precisely the sort of regression Capstone 4 asks you to look for. Whichever way it comes out, the comparison belongs in both documents.

Sources for this lesson

3 verified · checked 2026-09-09

  1. 01Model Context Protocol — Specification (2025-06-18)§ Security and Trust and Safety; key principlesmodelcontextprotocol.io/specification/2025-06-182026-09-09
  2. 02Docker — Docker security§ Kernel namespaces; control groups; daemon attack surfacedocs.docker.com/engine/security2026-09-09
  3. 03LiteLLM — Virtual Keys§ Budgets; rate limits; key expirydocs.litellm.ai/docs/proxy/virtual_keys2026-09-09

Every technical claim on this page was checked against the official documentation of the tool, vendor or model publisher on the date shown, at the version pinned for the course. Where the course disagrees with folklore, the source is how you can tell which one to trust.