One sandbox, one phone, one humanoid.
Every mega-prompt in this repo uses the same pattern, because it's the only pattern that works when the participant has only a phone: the Lovable sandbox runs a tiny Python script that exercises the Adamo SDK once at build time, writes a JSON proof into public/, and the phone app fetches that proof at runtime. The key never leaves the sandbox. The robot performance happens later at the showcase, off-device.
Why the sandbox and not a server function?
The Adamo SDK is Python, Rust, and C — there is no JS SDK, and Cloudflare Workers can't import adamo. The Lovable sandbox is the only place inside a mobile session where the SDK can actually run. Anything you need Adamo to prove, prove it in a script at build time and ship the result as static JSON.
Run the sandbox smoke test
# In the Lovable sandbox (the agent runs this at build time — you don't touch a terminal) python -m pip install --no-cache-dir adamo python scripts/adamo_smoke.py # ADAMO_API_KEY is in the sandbox env # writes public/adamo-smoke.json — the proof the phone app renders
The full script lives at /adamo-bridge.py (kept for the operator's laptop at the showcase — participants never run it themselves).
1. The sandbox script
Every mega-prompt tells the agent to write this script and run it once. It's the only file that imports adamo.
# scripts/adamo_smoke.py — sandbox-only. Never imported from .ts/.tsx.
import adamo, os, json, time, threading
from pathlib import Path
s = adamo.connect(api_key=os.environ["ADAMO_API_KEY"])
k = f"lovable/smoke/{int(time.time()*1000)}"
got, seen = threading.Event(), {}
def on(sample):
seen["v"] = json.loads(bytes(sample.payload).decode())
got.set()
sub = s.subscribe(k, callback=on) # kwarg-only!
time.sleep(0.2)
t0 = time.time()
s.put(k, json.dumps({"ping": t0}).encode())
got.wait(3.0)
rt = int((time.time() - t0) * 1000)
Path("public/adamo-smoke.json").write_text(json.dumps({
"ok": True, "roundtrip_ms": rt, "echo": seen.get("v"),
"alive": sorted(str(t) for t in (s.live_tokens("**/alive") or [])),
}, indent=2))
2. The phone renders the proof
// src/components/adamo-proof.tsx — the phone renders this. No SDK, no key.
import { useEffect, useState } from "react";
export function AdamoProof() {
const [p, setP] = useState<any>(null);
useEffect(() => { fetch("/adamo-smoke.json").then(r => r.json()).then(setP); }, []);
if (!p) return null;
return <div>Sandbox verified · {p.roundtrip_ms}ms roundtrip · {p.alive?.length ?? 0} live</div>;
}Hackathon rules of thumb (phone edition)
- · One mega-prompt = one build message. You have five credits and a phone. Ship the artifact, not the architecture.
- ·
ADAMO_API_KEYbelongs in Lovable secrets and stays in the sandbox process. Never inimport.meta.env, never in a server fn. - · Design mobile-first: 44px+ tap targets, thumb-reachable primary action, no drag-only interactions.
- ·
session.subscribe(key, callback=fn)— the callback is kwarg-only. Positional callbacks fail with a cryptic takes 2 positional arguments but 3 were given. - · Discovery uses
session.live_tokens("**/alive").session.alive(token)DECLARES a liveliness token; it is not a discovery call. - · Add "Built during the Physical AI & Creative Robotics Hackathon — StreetKode Fam · Indian Krump Festival 14" to your footer.