DEV Community

Riley Zhang
Riley Zhang

Posted on

Cut the Scope First: A Weekend Side Project With One Endpoint and One Smoke Test

Friday, 9:40 pm. Three side-project ideas. One Sunday deadline.

By Saturday noon I had killed two of them. That decision is the whole article.

Most weekend projects die from scope, not from code. That is the boring truth.

Why "just add an agent loop" ruins the weekend

A loop needs state, retries, and a stop condition. That is a week of work.

You have two days. So I keep one rule: one job, one endpoint, one smoke test.

Everything below is a build log for a helper that reads stdin and prints stdout. It is small on purpose.

1. Write the job in one sentence

If you cannot say the job in one sentence, you do not have a project yet.

Bad: "An AI assistant that helps me organize my notes."

Good: "Read a raw meeting transcript on stdin, print five action items on stdout."

The second version has a falsifier. You can fail it in ten seconds. Ambition does not ship; a falsifier does.

Write that sentence in a notes file. Do not open an editor yet.

2. Score every feature, then cut

List every feature you want. Then score each one honestly.

Anything above 30 minutes of debug risk gets cut on pass one. You can add it next weekend.

Candidate Build (min) Debug risk Cut? Reason
stdin/stdout CLI 20 low no this is the demo
one retry with backoff 25 medium no networks fail
plain text log to disk 10 low no you will need it
web UI 120 high yes stdout is enough
agent loop 180 high yes no stop condition
accounts and auth 90 high yes one user: you

The table is the real artifact here. Rebuild it for your own idea. Print it and tape it next to the monitor.

Then say the painful part out loud: "This weekend, the demo is a terminal command." Nobody is watching anyway.

3. Prove the endpoint before you build anything

Do not write application code until a single HTTP call returns real output.

This is the step people skip. They build a UI first, then discover the request shape is wrong.

Save this as smoke.sh. It is a template, not a finished tool.

#!/usr/bin/env bash
# smoke.sh - template. Fill variables from the docs you were given.
set -euo pipefail

: "${BASE_URL:?export BASE_URL from your dashboard}"
: "${API_KEY:?export API_KEY from your dashboard}"
: "${MODEL:?export MODEL from your documentation}"

# Never guess this path. Copy it from the docs you were given.
PATH_SUFFIX="${PATH_SUFFIX:-/v1/chat/completions}"
BUDGET_SECONDS="${BUDGET_SECONDS:-20}"

payload() {
  cat <<JSON
{"model":"${MODEL}","messages":[{"role":"user","content":"Reply with one word: ok"}],"max_tokens":8}
JSON
}

run_once() {
  curl --silent --show-error \
    --max-time "${BUDGET_SECONDS}" \
    --write-out '\n%{http_code} %{time_total}\n' \
    --header "Authorization: Bearer ${API_KEY}" \
    --header 'Content-Type: application/json' \
    --data "$(payload)" \
    "${BASE_URL}${PATH_SUFFIX}"
}

out="$(run_once)"
code="$(printf '%s' "$out" | tail -n1 | awk '{print $1}')"
secs="$(printf '%s' "$out" | tail -n1 | awk '{print $2}')"
body="$(printf '%s' "$out" | sed '$d' | sed '$d')"

printf 'http=%s time=%ss\n' "$code" "$secs"
[ "$code" = "200" ] || { echo "FAIL: non-200. Body:"; echo "$body"; exit 1; }

# Adjust this field name to your provider's response shape.
printf '%s' "$body" | grep -q '"content"' || { echo "FAIL: no content field"; exit 1; }
echo "PASS in ${secs}s"
Enter fullscreen mode Exit fullscreen mode

Run it with three exported variables. Read the failure text, not just the status code.

export BASE_URL='https://...'   # from your dashboard
export API_KEY='...'            # from your dashboard
export MODEL='...'              # from the docs you were given
chmod +x smoke.sh && ./smoke.sh
Enter fullscreen mode Exit fullscreen mode

The script asserts three things: a 200, a non-empty content field, and a time budget. Each assertion maps to one class of weekend bug.

4. Measure the spread, not one lucky call

One fast call proves nothing. Shared capacity is shared.

for i in 1 2 3 4 5; do ./smoke.sh | tail -n1; done
Enter fullscreen mode Exit fullscreen mode

Record five numbers. Drop the first one, that is your cold start. The rest is your real budget.

Now set your timeout from the spread, not from your hopes. I have never regretted measuring this before writing UI code.

5. Ship the smallest surface that survives a reboot

My helper is one script and one long-running process. That is the entire deployment.

If your free server is a Linux box you can SSH into, a systemd unit is the smallest durable thing.

[Unit]
Description=weekend helper
After=network-online.target

[Service]
EnvironmentFile=/home/me/.helper.env
ExecStart=/home/me/helper/run.sh
Restart=on-failure
StandardOutput=journal
StandardError=journal

[Install]
WantedBy=multi-user.target
Enter fullscreen mode Exit fullscreen mode

Enable it, then watch the logs:

sudo systemctl enable --now weekend-helper
journalctl -u weekend-helper -f
Enter fullscreen mode Exit fullscreen mode

If your server is not a Linux box, use whatever supervisor it exposes. The rule is the same. One process, restart on failure, logs to stdout.

6. Where free access actually changed my plan

Two decisions simply disappeared from this weekend's list.

First, billing. Free model access deleted the "add a payment method, add usage caps, add a quota screen" branch. That branch is not hard, but it costs an afternoon.

Second, the deploy target. A free server option deleted the provider comparison. I stopped reading pricing pages and started writing the smoke test.

Disclosure: This article was prepared as part of MonkeyCode's product outreach.

I am deliberately not publishing latency or throughput numbers for it. I do not have a reproducible benchmark, and shared capacity varies by hour and region. Run the loop in step 4 and trust your own measurements instead.

7. What I skipped on purpose

  • Web UI. The terminal demo is enough for one user.
  • A database. Append JSON lines to a file instead.
  • Multi-step retries. One retry with backoff covers most transient failures.
  • Model switching. Two models means two behaviors to debug.
  • Test suite beyond smoke.sh. One assertion beats zero, and five would be theater.

Each skip has a trigger. Add the feature when a real user asks for it, not before.

8. Limits you should assume

  • Free capacity is shared. Expect variance you did not cause.
  • There is no SLA here. Accept a broken demo, or build a fallback path.
  • Do not send client, health, or personal data to a service you have not reviewed yourself.
  • Free access can change. Keep an exit plan: isolate the call in one function so you can swap it.
  • Model output is unverified text. Validate it before it touches anything real.

9. Who should not use this workflow

Skip this approach if you need contractual uptime, pinned model versions for audits, or data residency guarantees. Skip it if your "weekend" is really a product launch with a date.

This is a build log for a disposable helper. Treat it that way.

Takeaways

One job. One endpoint. One smoke test. One process.

Cut the table until Sunday feels boring. A boring Sunday ships.

If you try it, run smoke.sh before you write the app. Tell me which assertion caught your first bug.

Top comments (0)