Skip to content

Agent examples

Each example on this page is a complete custom agent you can copy: a chat page in your browser, a notebook server, and Claude Code working on tasks in the background. Your first agent shows the simplest one.

A chat app in the browser

These steps run a Streamlit chat page in the container, which you open in your Mac browser:

  1. Make a project and add the libraries:
cd ~/src
uv init --package --python 3.13 chat-desk
cd chat-desk
uv add streamlit openai
  1. Write app.py in the project folder:
import os

import streamlit as st
from openai import OpenAI

client = OpenAI()
model = os.environ["GMLX_MODEL"]

st.title("Chat desk")
if "messages" not in st.session_state:
    st.session_state.messages = []
for message in st.session_state.messages:
    st.chat_message(message["role"]).write(message["content"])
if prompt := st.chat_input("Ask the local model"):
    st.session_state.messages.append({"role": "user", "content": prompt})
    st.chat_message("user").write(prompt)
    stream = client.chat.completions.create(
        model=model, messages=st.session_state.messages, stream=True)
    reply = st.chat_message("assistant").write_stream(stream)
    st.session_state.messages.append({"role": "assistant", "content": reply})
  1. Add the agent to your gmlx config file:
launch:
  agents:
    chat-desk:
      runtime: python
      command: [streamlit, run, app.py, --server.address, "127.0.0.1",
                --server.port, "8501", --server.headless, "true"]
      web_port: 8501
  1. Launch it from the project folder:
gmlx launch chat-desk --model qwen3.8-27b-ud-q6@instruct --detach

launch opens the page once Streamlit answers. End the session with gmlx launch chat-desk --stop. --server.headless true stops Streamlit from asking for an email address on its first start. Use an @instruct model, because the page shows nothing while a thinking model thinks.

A notebook server

These steps run JupyterLab in the container, with notebooks that call the model:

  1. Make a project with JupyterLab and the OpenAI library:
cd ~/src
uv init --package --python 3.13 lab
cd lab
uv add jupyterlab openai
  1. Make a token for the page with openssl rand -hex 16, and add the agent to your gmlx config file with it:
launch:
  agents:
    lab:
      runtime: python
      command: [jupyter, lab, --ip, "127.0.0.1", --port, "8888",
                --no-browser, --allow-root]
      web_port: 8888
      env: [JUPYTER_TOKEN=<your token>]
  1. Launch it from the project folder with gmlx launch lab --detach, open the address that launch prints, and sign in with the token.

  2. In a notebook, call the model:

import os

from openai import OpenAI

reply = OpenAI().chat.completions.create(
    model=os.environ["GMLX_MODEL"],
    messages=[{"role": "user", "content": "Name three uses of a local model."}])
print(reply.choices[0].message.content)
  1. End the session with gmlx launch lab --stop from the project folder.

Notebooks are saved in the project folder. Keep the token secret: any program on the Mac can open the page, and a notebook runs any code in the container. Jupyter needs --allow-root because the container runs as root.

Coding agents in the background

These steps give Claude Code one task at a time in the background, each in its own git worktree. You read and merge the branches it commits.

  1. Make the folder ~/containers/claude-bg with a one-line Containerfile:
FROM gmlx.invalid/launch-claude-code:base
  1. Add the agent to your gmlx config file:
launch:
  agents:
    fixer:
      build: ~/containers/claude-bg
      api: anthropic
      command: [claude, -p, --dangerously-skip-permissions]
      env: [IS_SANDBOX=1, DISABLE_AUTOUPDATER=1]
  1. Make a worktree for the task, and start the agent in it with the task after --:
cd ~/src/app
git worktree add ../app-mul -b add-mul
cd ../app-mul
gmlx launch fixer --detach -- "Add a mul function to calc.py, then commit it."
  1. Follow the sessions with gmlx launch --list, which names each one's output file.

  2. When the session has ended, read the branch, merge it, and clean up:

cd ~/src/app
git diff main add-mul
git merge add-mul
(cd ../app-mul && gmlx launch fixer --remove-home)
git worktree remove ../app-mul

-p runs the task after --, and the session ends when Claude Code finishes. launch sets IS_SANDBOX=1 and DISABLE_AUTOUPDATER=1 only for the built-in claude-code client, so the agent sets both in env. Each worktree is a separate project, so several tasks can run at once. The agent commits with your git name, because the session shares the repository's git folder.

Run --remove-home before you remove the worktree, because launch finds the private home by the folder. Read each branch before you merge it, since it can change files that the Mac runs. For a repository you do not trust, follow A session for code you do not trust.