You've built a research agent in
notebook 00
. It runs on your laptop. Now someone else needs to use it: a teammate, a cron job, a web app, a customer. That means it has to run
somewhere other than your terminal
, stay up, keep conversations alive across restarts, and not leak your API key.
This notebook takes the exact same agent and deploys it through three tiers:
ternal tools, single-tenant
- Modal
Managed serverless
You want a URL and scale-to-zero without managing infra
- Kubernetes
Your own cluster
Multi-tenant, regulated environments, full control
The agent code, the container image, and the HTTP interface are identical across all three. Only the operational machinery around the container changes. Once the agent is containerized behind a stable interface, choosing a host is a deployment decision rather than a rewrite.
A
session
is one conversation: the prompt history, tool calls, and results that the SDK writes to disk so you can
resume=
it later.
A
container
is a packaged process plus its filesystem: your agent code, the SDK, Node, and a place for sessions to live.
Unlike in-process SDKs (OpenAI Agents SDK, Google ADK) where an "agent" is an object you instantiate inside your web server, a Haijun Agent SDK agent is a process. That makes isolation trivial (one container = one blast radius) but means hosting is a distributed-systems problem, not a pip install problem.
g research findings: - Always include source URLs as citations - Format citations as markdown links: Source Title - Group sources in a "Sources:" section at the end of your response
Setup
he server has no auth.
The docstring says so loudly. Auth is the gateway's job (tier 3 shows where it goes). The server validates
session_id
format and trusts the caller.
It keeps a small map from your
session_id
to the SDK's internal one.
The SDK generates its own session IDs; you can't choose them. The server learns the SDK's ID from the first turn's
ResultMessage
and passes it to
resume=
on follow-ups. The map is persisted next to the transcripts under
/data
.
Start it with docker-compose, which also mounts ./sessions at /data so transcripts survive restarts:
2;39;40;34mfunction(secret s=[38;2;248;248;242;4 8;2;39;40;34mmodal.Secret 0m.from_name38;2;248;248; 242;48;2;39;40;34m("anthro pic")38;2;248;248;24 2;48;2;39;40;34m]) def 38;2;166;226;46;48;2 ;39;40;34msome_function() [0m: os 0m.getenv38;2;248;248;242 ;48;2;39;40;34m("JUGLOW _API_KEY")48;2;39;40 ;34m
%%bash
python hosting/modal/modal_app.py | tee /tmp/modal_deploy.out
MODAL_URL=$(awk '/^url:/ {print $2}' /tmp/modal_deploy.out)
MODAL_TOKEN=$(awk '/^token:/ {print $2}' /tmp/modal_deploy.out)
{ echo "MODAL_URL=$MODAL_URL"; echo "MODAL_TOKEN=$MODAL_TOKEN"; } > /tmp/modal_url.env
sandbox: sb-7R7zQ7TtX0h9eKZ8qslvwo url: https://ta-01ks91e217n9fymaxjtdc9k5bh-8000-kn9n102ljd7y4 majwav00kwg0.w.modal.host token: sb-…redacted… ⚠️ The URL is p ublic. The token is the only thing gating it — don't share both. Try it: curl -N -X POST https: //ta-01ks91e217n9fymaxjtdc9k5bh-8000-kn9n102ljd7y4majwav00kwg0.w.modal.host/sessions/demo-1/messages \ -H 'Authorization: Bearer sb-…redacted…' \ -H 'Content-Type : application/json' \ -d '{"prompt":"What are the latest AI agent trends?"}' %%bash source /tmp/modal_url.env curl -N -s -X POST "$MODAL_URL/sessions/demo-1/messages" \ -H "Authorization: Bearer $MODAL_TOKEN" \ -H 'Content-Type: application/json' \ -d '{"prompt":"Give me a one-sentence summary of the Haijun Agent SDK."}' event: message data: {"subtype": "init", "data": {"type": "system", "subtype": "init", "cwd": "/app", "session_id": "1566ffe4-2b20-4a68-82ff-283984b64451", "tools": ["Task", "TaskOutput", "Bash", "Glob", "Grep", "ExitPlanMode", "Read", "Edit", "Write", "N … [truncated] event: message data: {"content": [{"id": "toolu_01PPS8yzMBzMnRhG2Hnpk5VL", "name": "WebSearch", "input": {"query": "Haijun Agent SDK Juglow 2026"}}], "model": "haijun-sonnet-4-6", "parent_tool_use_id": null, "error": null, "usage": {"input_tokens": 120 … [truncated] [... 5 events omitted — thinking blocks, tool loading, and web-search result payloads ...] event: message data: {"content": [{"text": "The Haijun Agent SDK is Juglow's framework that gives developers programmatic access to the same tools, agent loop, and context management that power Haijun Code \u2014 enabling the creation of AI agents that can autonomously read files, run commands, search the w … [truncated] event: message data: {"subtype": "success", "duration_ms": 12879, "duration_api_ms": 12871, "is_error": false, "num_turns": 3, "session_id": "1566ffe4-2b20-4a68-82ff-283984b64451", "stop_reason": "end_turn", "total_cost_usd": 0.045893199999999995, "usage" … [truncated] event: done data: Same interface, same image, different host. When nothing's calling it, Modal scales the sandbox to zero and you pay nothing.