Automation Tutorial
Learn how to build powerful automation workflows that leverage Gemini CLI's AI capabilities.
One of the most transformative ways to use Gemini CLI is to move beyond interactive sessions and embed AI reasoning directly into your development workflows. By piping files through Gemini CLI in shell scripts, scheduling those scripts with cron, and wiring them into CI/CD pipelines like GitHub Actions, you can add a layer of AI-powered analysis, review, and generation to every commit, pull request, or nightly build — without any manual steps. This tutorial walks through real, production-ready script patterns for each of those scenarios, explains how batch mode works, and covers the pitfalls that catch most people when they first try to automate Gemini CLI.
Running Gemini CLI Non-Interactively
Before building complex scripts, understand the two input patterns Gemini CLI supports in non-interactive mode. Both suppress the interactive prompt and return output directly to stdout, making them composable with standard Unix tools.
Pattern 1 — Piping a prompt
# Prompt comes from stdin via echo
echo "Summarize the key points of this topic" | gemini
Use this pattern when you want to generate text from a static prompt without reading a file.
Pattern 2 — File input redirection
# File contents are sent as context along with the prompt
gemini "Review this code for security issues" < src/auth.js
gemini "Generate JSDoc comments" < utils.js > utils-documented.js
Use output redirection (>) to save the result to a file instead of printing to the terminal.
Shell Script Examples
These scripts are production-ready starting points. Adapt the prompts and file patterns to your project's conventions.
Code Review Automation
This script compares the last commit to HEAD and asks Gemini CLI to review each changed file. It skips binary files and saves each review to a reviews/directory, preserving the original filename for easy reference.
#!/bin/bash
set -euo pipefail
# auto-review.sh — AI code review for recent changes
REVIEW_DIR="reviews/$(date +%Y%m%d)"
mkdir -p "$REVIEW_DIR"
git diff --name-only HEAD~1 HEAD | while read -r file; do
# Skip binary and non-existent files
[[ -f "$file" ]] || continue
file "$file" | grep -q text || continue
echo "Reviewing: $file"
OUTFILE="$REVIEW_DIR/$(basename "$file").review"
gemini "Review this code for correctness, security issues, and style violations." < "$file" > "$OUTFILE"
sleep 1 # Respect rate limits
done
echo "Reviews saved to $REVIEW_DIR"
Make executable with chmod +x auto-review.sh then run with ./auto-review.sh.
Documentation Generation
This script scans your src/ directory for JavaScript files and generates Markdown documentation for each one. It mirrors the source tree structure under docs/ so documentation is easy to navigate.
#!/bin/bash
set -euo pipefail
# generate-docs.sh — AI-powered documentation generation
SRC_DIR="${1:-src}"
DOCS_DIR="docs"
find "$SRC_DIR" -name "*.js" -o -name "*.ts" | while read -r file; do
# Mirror source tree in docs/
rel_path="${file#$SRC_DIR/}"
doc_file="$DOCS_DIR/${rel_path%.*}.md"
mkdir -p "$(dirname "$doc_file")"
echo "Documenting: $file -> $doc_file"
gemini "Generate comprehensive Markdown documentation including: purpose, parameters, return values, and usage examples." < "$file" > "$doc_file"
sleep 1
done
Keep documentation up-to-date automatically by wiring this script to a pre-commit hook or a nightly CI job.
Test Generation
Bootstrapping a test suite for legacy code is one of the most time-consuming tasks in software development. This script automates the first pass by generating unit test files for each source file.
#!/bin/bash
set -euo pipefail
# generate-tests.sh — generate unit test scaffolding
TEST_DIR="tests"
mkdir -p "$TEST_DIR"
for file in src/*.js; do
base="$(basename "$file" .js)"
out="$TEST_DIR/${base}.test.js"
if [[ -f "$out" ]]; then
echo "Skipping $file — test file already exists"
continue
fi
echo "Generating tests for: $file"
gemini "Write Jest unit tests for every exported function. Include happy-path, edge-case, and error-path tests." < "$file" > "$out"
sleep 1
done
Always review generated tests before committing. Gemini CLI generates solid scaffolding, but tests benefit from a human sanity check before being merged.
Scheduling with Cron
Cron is the standard Unix job scheduler. It lets you run any script on a fixed schedule — perfect for nightly code health reports, weekly changelog summaries, or daily documentation rebuilds.
Cron syntax quick reference
# ┌───────────── minute (0-59)
# │ ┌───────────── hour (0-23)
# │ │ ┌───────────── day of month (1-31)
# │ │ │ ┌───────────── month (1-12)
# │ │ │ │ ┌───────────── day of week (0=Sun)
# │ │ │ │ │
* * * * * command
Adding a daily documentation job
Open your crontab with crontab -e and add the following lines. Use absolute paths — cron runs with a minimal environment and does not inherit your shell's PATH or exported variables.
# Run doc generation every day at 9 AM
0 9 * * * GOOGLE_AI_API_KEY=AIzaXXX /home/user/scripts/generate-docs.sh >> /home/user/logs/docs.log 2>&1
# Run code review every weekday at 6 PM
0 18 * * 1-5 GOOGLE_AI_API_KEY=AIzaXXX /home/user/scripts/auto-review.sh >> /home/user/logs/review.log 2>&1
Store the API key in a restricted file (chmod 600 ~/.env.gemini) and source it in your script rather than embedding it directly in the crontab, which is world-readable by default on some systems.
GitHub Actions Integration
GitHub Actions workflows give you full control over when and how Gemini CLI runs in your repository's CI pipeline. Store your API key as a GitHub secret and reference it as an environment variable inside the workflow.
Step 1 — Add the API key secret
Go to your repository on GitHub, navigate to Settings > Secrets and variables > Actions, and click New repository secret. Name it GOOGLE_AI_API_KEY and paste your key as the value.
Step 2 — Create the workflow file
Save this file to .github/workflows/ai-review.yml in your repository.
name: AI Code Analysis
on:
pull_request:
branches: [main, develop]
push:
branches: [main]
jobs:
ai_review:
runs-on: ubuntu-latest
env:
GOOGLE_AI_API_KEY: ${{ secrets.GOOGLE_AI_API_KEY }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 2 # needed for git diff
- uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install Gemini CLI
run: npm install -g @google/gemini-cli
- name: AI Code Review
run: |
git diff --name-only HEAD~1 HEAD -- '*.js' '*.ts' | while read f; do
[ -f "$f" ] && gemini "Review for bugs and security issues" < "$f" >> review.md
sleep 1
done
- name: Upload Review Artifact
uses: actions/upload-artifact@v4
with:
name: ai-review
path: review.md
Batch changelog generation on release
name: Generate Changelog
on:
release:
types: [created]
jobs:
changelog:
runs-on: ubuntu-latest
env:
GOOGLE_AI_API_KEY: ${{ secrets.GOOGLE_AI_API_KEY }}
steps:
- uses: actions/checkout@v4
with: {fetch-depth: 0}
- run: npm install -g @google/gemini-cli
- name: Draft changelog
run: |
git log --oneline $(git describe --tags --abbrev=0 HEAD~1)..HEAD > commits.txt
gemini "Generate a user-friendly CHANGELOG entry from these commits" < commits.txt > CHANGELOG_DRAFT.md
Batch Processing Mode
When processing large numbers of files, a few patterns help you stay within rate limits and keep scripts maintainable and debuggable.
Rate-limit-aware batch loop
#!/bin/bash
# Process files in batches of 5 with a pause between batches
count=0
for file in src/**/*.js; do
gemini "Add JSDoc to all functions" < "$file" > "docs/$(basename "$file").md"
count=$((count + 1))
if (( count % 5 == 0 )); then
echo "Processed $count files, pausing 10s..."
sleep 10
fi
done
Resume-safe processing with a processed list
For long-running batch jobs, track which files have already been processed so the script can be interrupted and restarted without re-processing completed files.
PROCESSED=".processed_files"
touch "$PROCESSED"
for file in src/*.js; do
grep -qxF "$file" "$PROCESSED" && continue # skip if already done
gemini "Summarize this module" < "$file" > "summaries/$(basename "$file").txt"
echo "$file" >> "$PROCESSED"
sleep 1
done
Frequently Asked Questions
How do I handle errors in automation scripts gracefully?
Add set -euo pipefail at the top of your bash scripts so any command failure immediately stops the script with a clear exit code. Wrap individual gemini calls in if-blocks or use the || operator to log failures without aborting the whole batch: gemini "..." < "$file" > out.md || echo "Failed on $file" >> errors.log.
How do I run Gemini CLI in a Docker container for CI?
Use the official Node.js Docker image as your base. Add RUN npm install -g @google/gemini-cli to your Dockerfile. Pass the API key at runtime via an environment variable: docker run -e GOOGLE_AI_API_KEY=AIzaXXX my-image ./review.sh. Never bake the API key into the Docker image.
Can I use Gemini CLI with GitLab CI or Azure DevOps?
Yes. The patterns are identical — install Gemini CLI with npm, expose the API key as a CI/CD secret variable, and run your shell scripts as pipeline steps. In GitLab CI, use the variables block with GOOGLE_AI_API_KEY: $GOOGLE_AI_API_KEY. In Azure DevOps, use a pipeline variable group and reference it with $(GOOGLE_AI_API_KEY).