How to Teach Gemini CLI to Write Python Scripts with Inline Dependencies
In a previous post, I
shared how Gemini CLI wrote a portable, single-file Python script that I could
immediately run. I didn't have to run pip install
or create a virtual
environment, even though it used various Python dependencies.
This was not a coincidence; I learned how to write single-file executable Python scripts with inline dependencies through a blog post by Simon Willison on one-shot Python tools, and I taught Gemini CLI to always write scripts in that way.
Let's review how this works and how you, too, can teach Gemini to write scripts in the same convenient way.
The Anatomy of an Executable Python Script with Inline Dependencies
First, here's the script that Gemini generated:
#!/usr/bin/env -S uv run
# /// script
# requires-python = ">=3.12"
# dependencies = [
# "fitparse==1.2.0",
# "matplotlib==3.8.2",
# "numpy==1.26.4"
# ]
# ///
import fitparse
import os
import sys
import matplotlib.pyplot as plt
import numpy as np
# ... rest of the script ...
The script starts with a special shebang line to execute the script with uv run
, and
includes an inline script metadata block with the Python dependencies.
The uv run
Shebang
The first line of the script is a shebang (#!
):
#!/usr/bin/env -S uv run
Let's break down each part:
-
#!
: This is the shebang (or hashbang). It's a special character sequence at the very beginning of a script that tells the operating system which program to use to run the script's contents. -
/usr/bin/env
: This is a standard utility that executes a command, respecting the$PATH
shell variable. Usingenv
instead of a direct path (for example,#!/usr/bin/uv
) makes the script more portable. It doesn't matter ifuv
is installed in/usr/bin/uv
or/home/user/.local/bin/uv
;env
finds it. -
-S
: It's the split-string option and it makes theenv
command executeuv
with the argumentrun
, instead of trying to find a non-existent program named"uv run"
. -
uv run
: A subcommand ofuv
that executes a Python script. In case you're not familiar withuv
, it's a super fast Python package and project manager. Read more about it at the uv documentation site.
The Inline Script Metadata Block
The second key part is the /// script
block, which is a standardized way to
embed a script's dependencies and Python version requirements directly within
the .py
file itself. This makes the script portable and easy to run without
needing a separate requirements.txt
or pyproject.toml
file. You can read
more about it in the Python Packaging User
Guide.
-
# /// script
: This header indicates the start of the embedded metadata block. -
# requires-python = ">=3.12"
: This line specifies that the script needs Python version 3.12 or newer to run correctly. -
# dependencies = [...]
: This is a list of the external libraries the script depends on, along with their specific versions.
When you run this script using a compatible tool (such as uv
), the
tool first reads this block, automatically creates a temporary virtual
environment, installs the specified dependencies, and then executes the script
within that environment.
How to Teach Gemini This Convention
The key to making Gemini CLI produce scripts like this in every session is to
give it a clear, explicit instruction and save it to its global instructional
memory in ~/.gemini/GEMINI.md
in your home directory. You only need to do
this once.
While you can can edit GEMINI.md
manually, you can also add instructions to
the using the Save Memory tool. I used the /memory add
slash command, like
here:
/memory add When writing single-file Python scripts,
I should use a `uv` shebang (`#!/usr/bin/env -S uv run`) and
include a `# /// script` block to define the Python version
and in-line dependencies (e.g., `requires-python = ">=3.12"`,
`dependencies = []`), and make the file
executable.
You can copy this snippet and run it in any gemini
session. Gemini CLI then
adds the memory to ~/.gemini/GEMINI.md
, and from that point on, whenever you
ask it to write a one-off Python script, it follows this convention.
After adding the instruction, you can run /memory show
to view the entire
instructional memory, loaded from the various GEMINI.md
files.
How GEMINI.md
Files Work
Instructional memory is stored in files named GEMINI.md
, which Gemini CLI
loads from two distinct locations:
- Global: A global
GEMINI.md
file at~/.gemini/GEMINI.md
in your home directory. Instructions here apply to all sessions. - Project: All
GEMINI.md
files found within your project's hierarchy. Gemini CLI starts from your current directory and searches up to the.git
root and down through all subfolders. If no.git
root is present, the upward search stops at your home directory.
Summary
Here's what this post covered:
- Writing executable, single-file Python scripts by using a
uv run
shebang line and adding an inline script metadata block with its dependencies. - Using the
/memory add
command to add a clear instruction to the instructional memory of Gemini CLI. This allows you to customize Gemini CLI's behavior to fit your workflow.
* * *
More on: Gemini CLI: Google's coding agent for the terminal →