A model call should stay local until three clocks agree. Latency, secrets, and offline need are those clocks. A free server wins only inside that narrow overlap.
The laptop is a workshop with the lights already on. The network is a ferry with a posted schedule. You board when the cargo is clean and the crossing fits the deadline.
Habit is a bad dispatcher for this choice. A fast demo last week does not price today's hop. A free seat does not make a secret safe to move.
The latency clock
Latency is the first clock on the desk. Interactive completion dies when the pause outlasts the thought. Batch work can spend more time and still stay useful.
Write the budget before you choose a host. A completion loop might allow four hundred milliseconds. A nightly rename can allow several seconds of delay.
Measure the hop with a probe you control. Keep the median of five runs from the same network. Discard a blog number that names a different city and hour.
# Proposed probe. Point it at a host you operate or trust.
for i in 1 2 3 4 5; do
curl -o /dev/null -s -w '%{time_total}\n' https://example.invalid/health
done
Sort those five totals and take the middle value. That middle value is your median round trip. Compare it with the budget you wrote down first.
If the median already consumes the budget, the server cannot win. Local execution or a plain deferral is the honest result. Do not average away a failure with a lucky first sample.
Cold start is a separate reading on the same clock. The first call often pays a load cost later calls skip. Warm the process once, then record the five interactive samples.
Use the warm median for a loop that stays open. Use the cold reading when each task starts a fresh process. Mixing those two numbers produces a policy that lies.
The secret clock
Secrets are the second clock on the same desk. A prompt can carry keys, rows, and unreleased diffs. Those fields do not become harmless because a server invoice is zero.
Scan the payload before any client opens a socket. A keyword hit is a hard stay on the laptop. A clean scan only allows the other clocks to continue.
SENSITIVE = ("api_key", "authorization", "password", "private_key", "ssn")
def secret_boundary(text: str) -> bool:
lowered = text.lower()
return any(token in lowered for token in SENSITIVE)
This scan is a gate, not a proof of safety. It misses novel field names and encoded blobs. A person still owns the last look at regulated text.
Treat source trees as secret until a review says otherwise. A private monorepo can leak through a stack trace alone. Strip traces before you even run the keyword gate.
The offline clock
Offline work is the third clock on the desk. Planes, incident bridges, and sealed build rooms do not retry politely.
The job must finish while the network is down. A server route has already failed that job.
Write the offline flag before you open a client. A missing flag is not a recorded false. It is an unknown, and unknowns should defer the call.
task:
name: rename-internal-helper
latency_budget_ms: 400
offline_required: true
contains_secrets: false
payload_bytes: 12000
Payload size belongs beside the offline flag you stored. A small rename may fit a local model easily. A multi-file context can blow past laptop memory and still be secret-free.
Where a free server wins
A free server wins a small set of jobs. The payload has no secrets, and the offline flag is false. Measured round trip fits the budget, and the laptop cannot finish.
Cost is a vote, not the chair of the meeting. A zero invoice removes one objection from the table. It does not erase a secret or a missed deadline.
MonkeyCode enters here as one host that can take the server side. Disclosure: This article was prepared as part of MonkeyCode's product outreach. The operator states that free model access and a free server option exist.
The operator also presents the project as open source. This draft claims no model names, quotas, hardware, or offer duration. Pin nothing until the docs you open still match the task.
Check the project docs on the day you run the probe. Availability moves, and a copied figure goes stale quickly. The clocks still outrank any offer you find there.
Rerun the route
Decide local_can_finish with a time box, not with a feeling. Give the local runner the same budget you gave the network. A timeout is evidence, and a success is evidence too.
# Proposed local time box. Exit 124 means the box was missed.
timeout 2s python3 -m local_runner --dry-run < task.json
echo "exit:$?"
Exit zero can set local_can_finish to true for that task shape. Exit 124 can set it to false for that same shape. Neither exit is a quality score for the model text.
The function below is a proposed policy module. It was not executed against a live host for this draft. Replace the timing field with your probe before you trust a label.
from dataclasses import dataclass
@dataclass
class Task:
latency_budget_ms: int
offline_required: bool
contains_secrets: bool
local_can_finish: bool
measured_rtt_ms: int | None
def route(task: Task) -> str:
if task.offline_required or task.contains_secrets:
return "local"
if task.measured_rtt_ms is None:
return "defer"
if task.measured_rtt_ms > task.latency_budget_ms:
return "local"
if not task.local_can_finish:
return "free_server"
return "either_local_preferred"
Read the labels as policy, not as a vendor score. local means the bytes stay on the machine that created them. free_server means the clocks passed and the laptop cannot finish.
defer means you refused to invent a round trip. either_local_preferred means the server is fast enough, yet the laptop can still finish. Prefer local in that tie, because movement still has a cost.
Save the function as route_task.py before you run the driver. The driver imports that file from the working directory. A missing import is a setup error, not a policy result.
Pass fields in dataclass order, or switch to keywords. A swapped boolean silently changes the route you meant.
python3 - <<'PY'
from route_task import Task, route
open_job = Task(800, False, False, False, 180)
secret_job = Task(800, False, True, False, 180)
print(route(open_job))
print(route(secret_job))
PY
Expect free_server on the first line of output. Expect local on the second line of output. If either line drifts, fix the policy before you fix the network.
| RTT vs budget | Offline | Secrets | Laptop finishes | Route |
|---|---|---|---|---|
| inside | no | no | no | free server |
| inside | no | no | yes | local preferred |
| missing | no | no | no | defer |
| any | yes | any | any | local |
| any | any | yes | any | local |
The table is a policy, not a measurement of any vendor. Fill the round-trip cell from a probe you ran today. Do not paste a foreign median and call it current evidence.
Order the checks so the cheap refusal happens first. Offline and secrets return local before any socket opens. The probe runs only after those two gates pass.
That order saves time, and it also saves mistakes. A latency script that uploads a sample prompt has already lost. Probe a health path, never a real task body.
What this will not do
Limitations sit in the gaps the labels cannot name. A keyword list misses secrets buried in minified bundles. A median hides a slow tail that ruins a live demo.
A free server can be limited, blocked, or withdrawn without notice. A local model can be too weak for the refactor you need. None of those facts appear inside the returned label.
Region and identity add two more gaps to the method. A health check from home is not a check from a build agent. A shared free server may log metadata even when you send no secrets.
Skip this route when regulated data lacks a written review. Skip it when the only prompt copy is live production traffic. Skip it as a hiding place for where source code went.
The method sorts ordinary developer tasks, and it does nothing more. It is not a control for a certified security boundary. Do not stretch it into a compliance certificate.
Keep a local log of the decision, not of the prompt text. Store the route, the budget, the median, and the clock time. Review that file when a task felt slow or unsafe.
You want a boring pattern over a week of real edits. Most edits stay local, and the server shows up rarely. It shows up for secret-free jobs the laptop cannot finish.
If the server column is still an open question, read the current MonkeyCode docs. Confirm free model access and the free server option yourself. Send a byte only after the three clocks still agree.
Top comments (0)