Remote models should not see traffic until three permits clear. Latency, secrets, and link state each get a veto. A free server becomes useful only after all three permits pass.
Teams often grant the hop first and invent permits later. That order leaks tokens and then adds latency to the apology. The cheaper path is a local default with a measured exception.
Picture a workshop with a locked loading dock. Work happens at the bench until the crate is ready. The dock opens only when the bench is too small. The crate must be clean and the road must exist. Opening the dock because the bench looks old loses crates.
On-device agents and in-browser agents revived this dock problem. The useful part is not another hosted demo. The useful part is that the wire remains a choice. Treat that choice as a permit system, not a preference.
Permits need numbers rather than taste or vendor slides. Taste does not survive a thermal throttle or a leaked env file. The rest of this note is a method you can run today. It stays useful even if every hosted name is deleted.
Permit A: the clock
Your silicon sets a floor for local decode speed. The network adds handshake time, queue time, and return time. If the added time exceeds one editor breath, the loop starves.
Call an editor breath the gap between two considered keystrokes. Developers protect that gap without writing a performance spec. They simply stop feeding the tool any rich context.
Do not debate laptops versus clouds in the abstract. Time a local stub on the repository you actually edit. Time a TLS handshake to a harmless public host. Compare those two clocks before any prompt leaves disk.
Handshake time is only the cover charge for a hop. Shared queues can still ruin a free remote decode. Re-run the hop during work hours, not at midnight.
The script later in this article prints both clocks. It is an assay, not a claim about your GPU. Swap the stub for your local runner and keep the rest.
Permit B: the secret surface
A remote completion stores a copy of whatever you packed. Stack traces, internal URLs, and env fragments travel together. Local inference keeps that blob under the same user id.
Filename checks are blunt and still worth running first. If env files or private keys sit in the tree, fail closed. Expand the name set until it matches your actual shop.
Adjacent secrets still count against the remote hop. A context builder that walks every file will vacuum fixtures. Narrow the glob until a dry run shows ticket-safe source.
Redaction is not the main artifact in this note. The permit stays binary at the loading dock. A dirty glob means the model stays on disk. A clean glob means you may consider the clock next.
You can preflight secret names with git before the assay.
git ls-files | grep -E '(^|/)\.env$|(^|/)id_rsa$|(^|/)credentials\.json$' || true
Empty output is not a security proof. It is only permit B in its cheapest form. Anything printed here keeps the model on disk.
Permit C: the link
Offline is not an edge case for people who ship from trains. A loop that dies without packets is a fair-weather tool. Local weights turn a dead network card into a planned mode.
Offline also deletes a pile of auth failure modes. There is no refresh token and no SSO interstitial. The laptop remains the only principal in the loop.
When the link returns, you still hold the transcript on disk. You can export a bounded job after the other permits pass. You cannot unsay a prompt that already crossed the card.
When a free server wins
Local-first is not a vow to suffer on a hot laptop. Fans roar when context outgrows quiet thermal limits. Some reviews need a second model you refuse to store.
Those are dock-opening events, not a new default home. The crate must be clean before it rolls to the dock. The road must exist, and the bench must be too small. Then a remote hop can carry one bounded job.
MonkeyCode fits that narrow dock role for measurement. Disclosure: This article was prepared as part of MonkeyCode's product outreach. The project is open source and offers free model access. It also offers a free server option for that measured hop. Use those options after the three permits pass, not before.
Free still crosses a trust boundary you do not control. Free does not mean private, resident, or fast under load. Free means you can measure a hop without a billing loop.
A free server wins when local stub time is long. It also needs a small handshake, a clean glob, and a live link. It loses when any permit fails, including policy. It also loses when you need a written service agreement.
Do not park a home directory on a complimentary box. Send a redacted batch and bring the answer back. Keep weights and secrets on the bench after the hop.
The assay
Save this file as permits.py at a repository root. Run it with Python 3 from that same root. It prints clocks, secret hits, and a single verdict. Treat the stub as a placeholder you must replace.
#!/usr/bin/env python3
"""Labeled assay: local stub vs TLS hop vs secret filenames.
This is a method template, not a benchmark. Replace time_local_stub()
with your on-disk runner before you trust HOP_MAY_WIN.
"""
from __future__ import annotations
import ssl
import socket
import sys
import time
from pathlib import Path
SECRET_NAMES = {".env", ".env.local", "id_rsa", "credentials.json"}
SKIP_DIRS = {".git", "node_modules", "dist", ".venv", "__pycache__"}
def time_local_stub(prompt: str, rounds: int = 80) -> float:
t0 = time.perf_counter()
text = prompt
acc = 0
for _ in range(rounds):
acc += hash(text) & 0xFFFF
text = text[::-1]
# The acc sink stops a too-eager optimizer.
if acc < 0:
raise RuntimeError("unreachable")
return time.perf_counter() - t0
def time_tls_hop(host: str, port: int = 443, timeout: float = 5.0) -> float:
ctx = ssl.create_default_context()
t0 = time.perf_counter()
with socket.create_connection((host, port), timeout=timeout) as raw:
with ctx.wrap_socket(raw, server_hostname=host) as sock:
sock.do_handshake()
return time.perf_counter() - t0
def secret_hits(root: Path) -> list[str]:
hits: list[str] = []
for path in root.rglob("*"):
if not path.is_file():
continue
if any(part in SKIP_DIRS for part in path.parts):
continue
if path.name in SECRET_NAMES:
hits.append(str(path))
return hits
def decide(local_s: float, hop_s: float | None, hits: list[str]) -> str:
if hits:
return "HOLD_LOCAL_SECRETS"
if hop_s is None:
return "HOLD_LOCAL_LINK"
if hop_s > max(local_s * 3.0, 0.25):
return "HOLD_LOCAL_CLOCK"
if local_s > 2.0 and hop_s < 0.08:
return "HOP_MAY_WIN"
return "HOLD_LOCAL_DEFAULT"
def main() -> None:
root = Path(".").resolve()
host = sys.argv[1] if len(sys.argv) > 1 else "example.com"
readme = root / "README.md"
prompt = readme.read_text(encoding="utf-8", errors="ignore")[:4000] if readme.exists() else "local-first assay"
local_s = time_local_stub(prompt)
try:
hop_s: float | None = time_tls_hop(host)
except OSError:
hop_s = None
hits = secret_hits(root)
verdict = decide(local_s, hop_s, hits)
hop_out = f"{hop_s:.4f}" if hop_s is not None else "unreachable"
print(f"local_stub_s={local_s:.4f}")
print(f"tls_hop_s={hop_out}")
print(f"secret_files={len(hits)}")
print(f"verdict={verdict}")
if __name__ == "__main__":
main()
Run the assay with a plain interpreter command.
python3 permits.py
Pass a host if you need a different handshake target.
python3 permits.py example.com
The printer should emit four lines similar to this shape. The numbers below are format samples, not measured claims.
local_stub_s=0.0412
tls_hop_s=0.1866
secret_files=2
verdict=HOLD_LOCAL_SECRETS
Replace the stub with a call to your on-disk runner. Keep the secret scan and the decide function under policy. Commit the assay next to the context builder to prevent drift.
Read HOP_MAY_WIN as permission to measure one redacted batch. It is not permission to stream keystrokes. It is not permission to upload the working tree.
Limitations
The hash loop is not inference on real weights. It only proves the wiring of the permit method. A real local model may be slower than the hop.
Handshake time ignores application queues after TLS completes. A free shared server can stall after the handshake succeeds. Measure one throwaway completion that contains no secrets.
Filename filters miss keys embedded in source and docs. Add a content scan if that risk is in scope. This article does not ship that extra scanner.
The method ignores data residency and contractual limits. A fast clean hop can still violate org policy. Stop at policy, not at the verdict string alone.
Thermal state changes across an ordinary heavy workday. Morning numbers can lie after a long compile. Run the assay under your normal editor and build load.
Who should skip this
Skip this permit system if an approved private endpoint exists. Skip it if laptops may not store model weights at all. Skip it if you cannot redact a prompt before any hop.
Regulated shops with logging duties may need the wire. A local default would fight an audit trail duty. Follow the duty and keep this assay off the critical path.
People who cannot yet run a local model should wait. The stub is not a substitute for a working runner. Get disk inference working, then time it against the hop.
Close
Grant remote models three independent permits, then one bounded hop. Clock, secrets, and link each vote, and any veto sticks. A free server is a dock, never a second workshop.
Top comments (0)