Agent take-homes are usually graded on the transcript, and the transcript is the easiest artifact to fake. The operational layer underneath it — deadlines, retries, secret handling, observable state — is where a candidate reveals whether they have shipped anything that ran unattended. This packet turns that layer into a 90-minute exercise with a public rubric, a runnable reference implementation, and a failure taxonomy collected from review notes.

Why the plumbing deserves the grade

Portfolios full of agent demos have made polished conversations cheap, because anyone can paste a convincing exchange into a README. Reviewers cannot verify the setup behind that screenshot, and they rarely have time to reproduce it. Operational hygiene is different: a health endpoint, a wall-clock deadline, a capped retry loop, and logs that name the failure mode are checkable in about ten minutes.

Free-tier infrastructure is the right substrate for that check because it makes scarcity visible instead of theoretical. The candidate works against free model access and a free server option rather than a funded cloud account, so decisions about timeouts, retries, and token spend produce consequences the reviewer can actually observe. The exercise therefore grades judgment under constraint rather than access to budget.

The prompt handed to the candidate

The text below is copy-paste ready; adapt the names and keep the constraints intact, since the constraints are the grading surface.

Build a small HTTP service that forwards one prompt to a hosted model and returns the generated text. Constraints:

  1. The repository must boot from a clean clone with one documented command once environment variables are supplied.
  2. No credential may appear in git history, log output, or error responses.
  3. Every upstream call must carry a wall-clock deadline, and the request as a whole must carry a budget.
  4. The service must expose a health endpoint reporting uptime and tokens consumed since start.
  5. A 429 from the provider must be retried with backoff and a capped attempt count, never surfaced as a crash.
  6. Ship a README with a limitations section that states what breaks at 100 concurrent users.
  7. Timebox is 90 minutes; a smaller working service beats a larger broken one.

Deliverables are the repository, the README, and two log excerpts: one successful run and one deliberately forced failure. The second log is the important one, because a candidate who cannot produce a clean failure transcript has probably never watched their own service break.

The rubric

Criterion Points
Boots from a clean clone with one documented command 15
Secrets absent from repo, logs, and error payloads 15
Deadline enforced per call and per request 15
429 handling with backoff and capped attempts 15
/health reports uptime and token spend 10
Structured logs name the failure mode 10
README states limitations and the 100-user boundary 10
Honest failure demo: real error, not fabricated output 10

A score of 70 or more usually predicts that the candidate can own a service on-call; a score below 40 with a beautiful demo predicts the opposite.

Reference solution: about seventy lines, zero dependencies

The implementation targets Node 20 or newer and uses only the standard library, so the reviewer can run it without trusting a lockfile. Note that the retry decision lives in one place, and that token accounting reads the provider's own usage field rather than estimating.

// server.mjs — minimal agent endpoint for the take-home. import { createServer } from "node:http"; const BASE_URL = process.env.MODEL_BASE_URL; const API_KEY = process.env.MODEL_API_KEY; const MODEL = process.env.MODEL_NAME; const PORT = Number(process.env.PORT ?? 8080); const BUDGET_MS = Number(process.env.REQUEST_BUDGET_MS ?? 20000); const MAX_ATTEMPTS = Number(process.env.MAX_ATTEMPTS ?? 3); if (!BASE_URL || !API_KEY || !MODEL) { console.error("missing MODEL_BASE_URL, MODEL_API_KEY or MODEL_NAME"); process.exit(1); } let tokensSpent = 0; const startedAt = Date.now(); const log = (entry) => console.log(JSON.stringify({ ts: new Date().toISOString(), ...entry })); const json = (res, status, payload) => { res.writeHead(status, { "content-type": "application/json" }); res.end(JSON.stringify(payload)); }; async function readJson(req) { const chunks = []; for await (const chunk of req) chunks.push(chunk); try { return JSON.parse(Buffer.concat(chunks).toString("utf8")); } catch { return null; } } async function callModel(prompt, signal) { const res = await fetch(`${BASE_URL}/chat/completions`, { method: "POST", headers: { "content-type": "application/json", authorization: `Bearer ${API_KEY}`, }, body: JSON.stringify({ model: MODEL, max_tokens: 256, messages: [{ role: "user", content: prompt }], }), signal, }); if (res.status === 429) { throw Object.assign(new Error("rate_limited"), { retryable: true }); } if (!res.ok) throw new Error(`upstream_${res.status}`); const data = await res.json(); tokensSpent += data.usage?.total_tokens ?? 0; return data.choices?.[0]?.message?.content ?? ""; } const server = createServer(async (req, res) => { if (req.method === "GET" && req.url === "/health") { return json(res, 200, { ok: true, uptimeMs: Date.now() - startedAt, tokensSpent, }); } if (req.method === "POST" && req.url === "/run") { const body = await readJson(req); if (!body?.prompt) return json(res, 400, { error: "prompt_required" }); const deadline = Date.now() + BUDGET_MS; for (let attempt = 1; attempt <= MAX_ATTEMPTS; attempt += 1) { if (Date.now() >= deadline) { return json(res, 504, { error: "budget_exhausted", attempt }); } try { const text = await callModel( body.prompt, AbortSignal.timeout(deadline - Date.now()), ); return json(res, 200, { text, attempt, tokensSpent }); } catch (err) { log({ event: "attempt_failed", attempt, message: String(err.message) }); if (!err.retryable || attempt === MAX_ATTEMPTS) { return json(res, 502, { error: err.message, attempt }); } await new Promise((r) => setTimeout(r, 500 * 2 ** (attempt - 1))); } } } return json(res, 404, { error: "not_found" }); }); server.listen(PORT, () => log({ event: "listening", port: PORT })); 

Verification commands

Two curls cover the happy path and the observability claim; both belong in the README verbatim.

MODEL_BASE_URL="$BASE" MODEL_API_KEY="$KEY" MODEL_NAME="$MODEL" node server.mjs & curl -s localhost:8080/health # {"ok":true,"uptimeMs":812,"tokensSpent":0} curl -s -X POST localhost:8080/run \ -H 'content-type: application/json' \ -d '{"prompt":"summarize the request budget in one sentence"}' # {"text":"...","attempt":1,"tokensSpent":41} 

Forcing the failure path

A twelve-line stub that rate-limits the first two calls turns the retry and budget branches into something a reviewer can watch. Point MODEL_BASE_URL at http://localhost:9099/v1 and run the request again.

// stub-429.mjs — mimics a provider that rate-limits the first two calls. import { createServer } from "node:http"; let hits = 0; createServer((req, res) => { hits += 1; if (hits <= 2) { res.writeHead(429, { "retry-after": "1" }); return res.end(); } res.writeHead(200, { "content-type": "application/json" }); res.end( JSON.stringify({ choices: [{ message: { content: "stub ok" } }], usage: { total_tokens: 7 }, }), ); }).listen(9099, () => console.log("stub on 9099")); 

The interesting assertions are that the third attempt succeeds, that the process survives, and that /health shows seven tokens rather than an estimate.

Common failure modes and what each reveals

  • Committed .env or a key in the README. The candidate has not worked in a shared repository, and the score for that row is zero regardless of the demo.
  • Unbounded retry on any error. A for loop without an attempt cap reproduces provider outages locally; reviewers see a hang instead of a diagnosis.
  • No deadline on the outbound call. The default fetch timeout is effectively infinite, so one stalled connection pins the request forever.
  • Retrying a 400. Treating every non-200 as transient wastes budget and hides a prompt bug that will never resolve itself.
  • A mock that answers when the key is missing. Silent fallbacks are the most damaging failure, because the transcript looks real while nothing was called.
  • Token accounting by character count. Guessed spend diverges from billing and undermines every downstream budget decision.
  • /health returning a constant. A hardcoded {"ok":true} proves the endpoint exists and nothing else.
  • Limitations section that says "none". Every free-tier demo has a boundary; refusing to name it is the clearest signal in the packet.

Where free model access and a free server fit

Disclosure: This article was prepared as part of MonkeyCode's product outreach. The exercise uses MonkeyCode's free model access and free server option as the substrate for candidates who do not want to fund a cloud account for an interview. Those availability claims are operator-supplied; confirm the current terms, limits, and any duration on the project site before assigning the task, because free-tier offers change and this packet should never be graded against stale numbers.

The product participates in the workflow at two points only: the candidate points MODEL_BASE_URL and the credentials at the free model endpoint, and the service runs on the free server so the reviewer can call it over the network instead of on localhost. Neither point changes the rubric, and a candidate using any other provider with the same shape would score identically.

This approach is a poor fit for teams that need production latency numbers, regulated data handling, or a permanent demo environment for customers. It is also unsuitable when the interview goal is judging model output quality, since a free tier invites variance the rubric deliberately ignores.

Adapting the packet

Keep the timebox at 90 minutes and grade the two transcripts before reading any code, because the failure transcript predicts behavior under incident far better than a tidy repository does. If the role involves multi-step agents, add one row worth ten points for idempotency and reduce the README row to match. If the role is frontend, swap the HTTP service for a streaming UI that must show a degraded state when the provider rate-limits.

Readers who want to try the task themselves can start with the free model access and free server, run the two curls above, and then break their own service on purpose.