Agentic Workflows
▶ Open a JupyterHub terminal — opens JupyterLab in the training workspace directory on jh-training.nrp-nautilus.io; use a Terminal for the opencode steps below.
In Part 2 you used NRP's managed LLM from Python. Now you'll point an agentic coding CLI at the same managed endpoint and have it write a small program from scratch. The CLI we use is opencode, a terminal UI similar in spirit to Claude Code or Cursor's CLI — it plans, edits files, runs tools, and iterates. The key teaching point is portability: anything that speaks an OpenAI-compatible base URL works against NRP, so the agentic workflow you already use locally runs unchanged against NRP's managed inference.
Run all commands from a JupyterHub terminal. Command blocks are formatted for copy/paste into that terminal.
Schedule
| Topic | Outcome |
|---|---|
| Setup | Install opencode and point it at the NRP managed LLM. |
| Build a chess game | Drive opencode through a small but real coding task. |
| Discussion and Q&A | Implementation strategies for under-resourced classrooms. |
Setup
Install opencode into the JupyterHub session. The installer drops the binary in ~/.opencode/bin/ — no sudo needed.
curl -fsSL https://opencode.ai/install | bash
export PATH="$HOME/.opencode/bin:$PATH"
opencode --versionWrite an opencode config that uses the NRP managed LLM via the already exported OPENAI_API_KEY:
mkdir -p ~/.config/opencode
cat > ~/.config/opencode/opencode.json <<'JSON'
{
"$schema": "https://opencode.ai/config.json",
"provider": {
"nrp": {
"npm": "@ai-sdk/openai-compatible",
"name": "NRP LLM",
"options": {
"baseURL": "https://ellm.nrp-nautilus.io/v1",
"apiKey": "{env:OPENAI_API_KEY}"
},
"models": {
"minimax-m2": { "name": "MiniMax M2" },
"gpt-oss": { "name": "GPT-OSS" },
"qwen3": { "name": "Qwen3 397B" },
"gemma-small-e4b": { "name": "Gemma 3n E4B" }
}
}
},
"model": "nrp/gpt-oss"
}
JSONgpt-oss is the default model here because it tends to do well on code; you can switch in-session with Ctrl+P → Switch models.
Build a chess game
Create a clean project directory and launch the agent:
mkdir -p ~/chess && cd ~/chess
opencodeInside the opencode TUI, press / to open the prompt and paste:
Write a single-file Python program chess_game.py that lets two humans play
chess in the terminal. Use the python-chess library. Render the board after
every move using board.unicode(). Accept moves in SAN (e.g., "e4", "Nf3").
When the game ends, print the result. Add a top-of-file docstring. After
writing the file, add a requirements.txt pinning python-chess to 1.999, and
tell me the exact commands to install and play.opencode plans, writes chess_game.py and requirements.txt, and prints the run instructions. Install and play:
pip install -r requirements.txt
python chess_game.py⚠️ Don't name the file
chess.py— it shadows thepython-chesspackage.import chessthen re-imports your script andchess.Board()raisesAttributeError. Models sometimes pickchess.pyanyway because the prompt says "chess game"; if that happens, rename it. Models have also been known to invent versions likepython-chess==1.10.0that do not exist on PyPI — the actual current pin ispython-chess==1.999. The prompt above pre-pins to avoid the round-trip.
Try a few moves: e4, e5, Nf3, Nc6, Bb5, a6, Bxc6, dxc6. Press Ctrl+C to quit.
Switch models inside opencode with Ctrl+P → Switch models. Try the same prompt against qwen3 (the largest context window) or minimax-m2 (strong general-purpose reasoning) — same agent, same prompt, different inference backend.
Discussion and Q&A
Key teaching points:
- Any agentic coding tool that supports an OpenAI-compatible base URL —
opencode, Crush, Continue, Cursor's custom-provider field, Claude Code viaANTHROPIC_BASE_URL— works against NRP. You bring the workflow you already use; NRP supplies the inference. - Agents work in a controlled directory or workspace, not against production systems. The user still reviews diffs and decides what to commit.
- Persistent workspaces (Coder, an SSH dev host, or even a checked-out repo on a long-lived JupyterHub session) make it possible to pause and resume agentic work across class sessions.
- Managed LLMs are the lowest-friction classroom path — students don't buy separate model access, and there's no token-handoff theater.
Practical classroom strategies:
- Pre-create namespaces, quotas, secrets, and any needed resource exceptions before class.
- Use a prepared JupyterHub image with
kubectl,helm, common Python packages, and LLM environment variables already configured (this is what the training JupyterHub does). - Reserve accelerator-heavy workflows for short, time-boxed demos.
- Give each student a unique username convention for pod and workspace names.
- Include cleanup commands in every activity.
- Prefer reviewable repository workflows over untracked generated files.
Reference: client configs.