Repository navigation
Adding tools and capabilities to Gemini CLI Sandbox
This is the perfect next question. You've created a useful tool, and now you want to integrate it into your permanent workflow so it's always available.
The Gemini CLI is designed for exactly this kind of customization. You can persist tools by placing them in a specific configuration directory.
Here is the complete guide on how to do this.
The Gemini CLI is built on a framework called axtools. This framework looks for custom tools and configurations in a special directory in your user's home folder. By placing your Python tool file there, the CLI will automatically load it every time you start a sandbox session.
The directory is: ~/.config/axtools/
Inside this directory, there are two important subdirectories:
-
tools/: Any Python (.py) file you place here will be loaded as a custom tool. -
prompts/: Any text (.txt) file you place here can be loaded as a reusable prompt.
Let's make your fetch_github_issue tool a permanent part of your Gemini CLI.
Open your terminal on Manjaro and run the following command. The -p flag ensures that it creates the parent directories if they don't exist and doesn't complain if they already do.
mkdir -p ~/.config/axtools/toolsNow, create a new Python file inside that directory. Let's call it github_tools.py. You can use your favorite text editor, like nano, vim, or VS Code.
nano ~/.config/axtools/tools/github_tools.pyCopy and paste the following code into the github_tools.py file. Note that we've moved the import statements to the top of the file, which is standard practice for Python modules.
# ~/.config/axtools/tools/github_tools.py
import requests
import json
from google.generativeai.notebook import tool
@tool
def fetch_github_issue(
owner: str,
repo: str,
issue_number: int
):
"""
Fetches the details of a specific issue from a GitHub repository.
Args:
owner: The owner of the repository (e.g., 'Digital-Assistant').
repo: The name of the repository (e.g., 'Digital-Assistant-Server').
issue_number: The number of the issue to fetch.
"""
url = f"https://api.github.com/repos/{owner}/{repo}/issues/{issue_number}"
headers = {
"Accept": "application/vnd.github.v3+json"
}
try:
response = requests.get(url, headers=headers)
response.raise_for_status() # Raise an exception for bad status codes (4xx or 5xx)
issue_data = response.json()
# Return a summary of the issue
return json.dumps({
"title": issue_data.get("title"),
"author": issue_data.get("user", {}).get("login"),
"state": issue_data.get("state"),
"labels": [label.get("name") for label in issue_data.get("labels", [])],
"body_preview": issue_data.get("body", "")[:200] + "..."
}, indent=2)
except requests.exceptions.HTTPError as e:
return f"Error: Could not fetch issue. Status code: {e.response.status_code}. Message: {e.response.text}"
except Exception as e:
return f"An unexpected error occurred: {e}"Save the file and exit the editor (in nano, that's Ctrl+X, then Y, then Enter).
Now, the magic happens. Close your current Gemini CLI session if you have one open. Start a new one with the sandbox enabled.
gemini --sandbox
```Inside the new session, you can verify that your tool was loaded by using the built-in `//tools` command:
//tools
The output should now list your custom tool:
Tools available in the current session:
- fetch_github_issue(owner: str, repo: str, issue_number: int)
#### **Step 5: Use Your Persisted Tool**
You can now use the tool directly in any new sandbox session without ever having to paste its code again.
Get the details for issue #41 in the Digital-Assistant/Digital-Assistant-Server repo.
The Gemini model will find your persisted `fetch_github_issue` tool, understand how to use it, and execute it to get your answer.
---
### **Critical Next Step: Managing Dependencies**
Your tool has a dependency: the `requests` library. By default, the sandbox might not have this library installed. You need to tell the Gemini CLI to install it.
You do this by editing the main configuration file.
1. **Open the config file:**
```bash
nano ~/.config/axtools/config.toml
```
2. **Add the `pip_packages` section:** If the file is empty or doesn't have this section, add the following lines. This tells the sandbox to automatically `pip install requests` every time it starts.
```toml
[sandbox]
# A list of pip packages to install in the sandbox environment.
pip_packages = [
"requests"
]
```
3. **Save the file.**
Now your setup is complete and robust. Every time you start `gemini --sandbox`, it will have a clean environment with `requests` installed and your `fetch_github_issue` tool ready to go.
***
***
***
This is a brilliant and insightful question. You have correctly deduced that giving the agent access to the full `gh` CLI would be far more powerful than a single-purpose Python function.
The answer is nuanced but leads to a much more capable solution:
* **Can you point Gemini directly to your installed `gh` binary?** No. The sandbox is a security feature. It's an isolated environment that, by design, **cannot see or execute programs on your host operating system (Manjaro)**. This prevents the AI from running arbitrary, potentially harmful commands.
* **Can you give the Gemini sandbox the *functionality* of `gh`?** Yes, absolutely! You do this by creating a new Python tool that acts as a "wrapper." This tool, running *inside* the sandbox, will use Python's `subprocess` module to call the `gh` command.
And to your second question:
* **Does `gh` have fetch functionality?** Yes. Its `gh issue view` command is the direct equivalent of what we built, and it's even more powerful.
This is a superior approach. Let's build it.
---
### **The Superior Method: A Python Tool that Wraps the `gh` CLI**
By creating a tool that calls `gh`, you gain several massive advantages:
1. **Authentication is Automatic:** The `gh` command automatically uses your authenticated session. This means the tool will work seamlessly with **private repositories**, which our `requests`-based tool would not.
2. **Power & Flexibility:** The `gh` command can return structured JSON output for almost any piece of data on GitHub.
3. **Extensibility:** It's easy to add new functions to our tool that call other `gh` commands (e.g., `gh issue edit`, `gh issue comment`).
#### **Step 1: The New `gh`-Powered Python Tool**
We will create a new, more powerful tool. You should **replace** the old `fetch_github_issue` function in your `github_tools.py` file with this new one.
**File: `~/.config/axtools/tools/github_tools.py` (Updated)**
```python
import subprocess
import json
from google.generativeai.notebook import tool
@tool
def get_github_issue_details(
issue_url: str = "",
owner: str = "",
repo: str = "",
issue_number: int = 0
):
"""
Fetches the details of a specific issue from a GitHub repository using the 'gh' CLI.
You can provide either a full issue URL or the owner, repo, and issue_number separately.
Args:
issue_url: The full URL of the GitHub issue (e.g., 'https://github.com/owner/repo/issues/41').
owner: The owner of the repository (e.g., 'Digital-Assistant').
repo: The name of the repository (e.g., 'Digital-Assistant-Server').
issue_number: The number of the issue to fetch.
"""
# The 'gh' command needs to be installed inside the sandbox environment.
# We will handle its installation in the config.toml file.
# Determine the issue to view, preferring the URL if provided
if issue_url:
target_issue = issue_url
elif owner and repo and issue_number:
target_issue = str(issue_number)
else:
return "Error: You must provide either an issue_url or all of owner, repo, and issue_number."
# Construct the gh command
# We ask for specific fields in JSON format for a clean, predictable output.
cmd = [
"gh", "issue", "view", target_issue,
"--json", "title,body,state,author,labels,url"
]
# If owner/repo are provided, add the --repo flag for context
if owner and repo:
cmd.extend(["--repo", f"{owner}/{repo}"])
try:
# Execute the command from within the sandbox
result = subprocess.run(cmd, check=True, capture_output=True, text=True)
# The output from gh is a JSON string, so we parse it and return
return json.dumps(json.loads(result.stdout), indent=2)
except FileNotFoundError:
return "Error: The 'gh' command is not available in the sandbox. Please check the config.toml configuration."
except subprocess.CalledProcessError as e:
# This will capture errors from gh, like "issue not found"
return f"Error: The 'gh' command failed. Stderr: {e.stderr}"
except Exception as e:
return f"An unexpected error occurred: {e}"
This is the most critical step. Just like we had to pip install requests, we now need to tell the sandbox to install the gh binary. The Gemini sandbox is based on Debian Linux, so we can use apt-get.
-
Open your
config.tomlfile:nano ~/.config/axtools/config.toml -
Modify the file to look like this: We remove
requestsand add a new section forapt_packages.# ~/.config/axtools/config.toml [sandbox] # A list of pip packages to install in the sandbox environment. # We don't need 'requests' anymore. pip_packages = [] # A list of apt packages to install in the sandbox environment. apt_packages = [ "github-cli" ] ```3. **Save the file.**
Now, every time you start gemini --sandbox, it will perform a silent apt-get update && apt-get install -y github-cli inside its secure environment.
The gh running inside the sandbox is a different installation from your Manjaro one. It needs to be authenticated. The sandbox provides a secure way to pass secrets to it.
-
Get your GitHub Token: You need a Personal Access Token (PAT) with
repoandprojectscopes. You can generate a new one if needed. -
Add the Secret to the Config: Open the
config.tomlfile again.nano ~/.config/axtools/config.toml -
Add the
[secrets]section: This securely exposes the token as an environment variable only within the sandbox.# ~/.config/axtools/config.toml [sandbox] pip_packages = [] apt_packages = [ "github-cli" ] [secrets] # The key is the name of the environment variable inside the sandbox. # The value is the name of the secret as stored by the axtools framework. # GH_TOKEN is the standard environment variable that the gh CLI looks for. GH_TOKEN = "github" ```4. **Set the Secret:** Now, run this command in your regular terminal (not the Gemini prompt). It will securely store your token under the name "github". ```bash gemini secret set github ``` It will prompt you to paste your Personal Access Token.
Your setup is now complete and vastly more powerful.
-
Start a new sandbox session:
gemini --sandbox -
The sandbox will start, install
gh, and securely inject yourGH_TOKEN. -
The CLI will load your new
get_github_issue_detailstool from yourgithub_tools.pyfile. -
You can now make a request:
>>> Get the details for issue #41 from the Digital-Assistant/Digital-Assistant-Server repo.or
>>> Fetch the issue at https://github.com/Digital-Assistant/Digital-Assistant-Server/issues/41
The agent will now use your powerful, authenticated gh-based tool to get the answer. You have successfully given your AI agent access to the rich functionality of the GitHub CLI in a secure and controlled way.