⌂ Home
Gemini CLI: Terminal AI Agent Foundations
Gemini CLI Track
⏰ 35-45 min Module 3 of 18 📺 Windows-first
🔮
Gemini CLI Track — M02: GEMINI.md & Configuration Configure Gemini CLI for the TaskFlow project using GEMINI.md — the file that turns a generic AI tool into a project-aware assistant that already knows your codebase, standards, and patterns.

GEMINI.md & Configuration

In M01 you learned how to give Gemini context with @-mentions. That's great for one-off questions. But what about things that are always true about your project? GEMINI.md is how you encode that permanent context.

What GEMINI.md Does

Analogy First

Every new employee at a company gets an onboarding document: here's what we build, here's our tech stack, here's the coding style we use, here's what you should never do in production. Without it, they'd spend their first month asking basic questions and making avoidable mistakes. The pain is that this knowledge exists but isn't written down — so it only transfers in conversations. GEMINI.md is that onboarding document for Gemini CLI. Write it once, and every session starts with Gemini already knowing your project at the level of a developer who read the onboarding guide.

Technical Definition

GEMINI.md is a Markdown file that Gemini CLI automatically reads at the start of every session when it exists in the current working directory (or any parent directory up to the home directory). It is not a config file with a fixed schema — it is free-form Markdown that you write in natural language. Gemini treats its contents as system-level context: facts about the project, rules for how to respond, and instructions that override default behavior.

Loading order: Gemini CLI finds the nearest GEMINI.md by walking up from the current directory. If you have ~/GEMINI.md and ~/projects/taskflow/GEMINI.md, and you're in the taskflow directory, Gemini loads both — the project file takes precedence where there are conflicts.

Gemini CLI — session startup
PS>cd sample-project\taskflow
PS>gemini
✦ Found GEMINI.md in current directory
✦ Loading project context... (1,247 tokens)
✓ Context loaded: TaskFlow API — FastAPI + SQLite
✦ Gemini 2.5 FlashReady. I know about TaskFlow — ask me anything.
>What are the valid priority values for a task?
Based on the GEMINI.md context: low, medium, or high (stored as strings).
The default in models.py is "medium".
Press ▶ to see GEMINI.md auto-loading
What Just Happened?

Gemini CLI found GEMINI.md in the current directory, read it, and was able to answer "what are the valid priority values?" without any @-mention — because that information was in the context file. This is the key insight: GEMINI.md is always-on context that you write once and never repeat.

Reading the TaskFlow GEMINI.md

TaskFlow already has a GEMINI.md at sample-project/taskflow/GEMINI.md. Let's walk through every section and understand why it's written the way it is.

WHAT: Section 1 — Project Overview. Gives Gemini the essential "what and how" in three lines: what it does, how to run it, where the docs are. WHY: The first thing Gemini needs to know is the project's purpose and entry point. This prevents it from suggesting wrong server commands.
# TaskFlow — Gemini CLI Context

## Project Overview
TaskFlow is a REST API for managing personal tasks. Built with FastAPI + SQLite.
Run it with: uvicorn main:app --reload
Docs at: http://localhost:8000/docs
WHAT: Section 2 — Key Files. Maps each filename to its role. WHY: Without this, Gemini has to infer which file does what from names alone. With it, Gemini knows immediately that auth.py contains JWT helpers and database.py contains the session dependency — so it gives accurate cross-file advice without needing @-mentions.
## Key Files
- main.py — FastAPI app, middleware, router registration
- models.py — SQLAlchemy models: User, Task, Tag (many-to-many via task_tags)
- schemas.py — Pydantic v2 schemas for request/response validation
- auth.py — JWT authentication: hash_password, verify_password, get_current_user
- database.py — SQLAlchemy engine, SessionLocal, get_db() dependency
- routers/users.py — POST /users/register, POST /users/login
- routers/tasks.py — CRUD for /tasks/ (requires auth)
- routers/tags.py — CRUD for /tags/ (requires auth)
WHAT: Section 3 — API Endpoints. A complete endpoint table in a format Gemini can easily parse. WHY: When you ask "is there an endpoint for X?", Gemini checks this table first before guessing. Structured tables are faster for the model to scan than prose descriptions.
## API Endpoints
POST   /users/register      Create account {email, username, password}
POST   /users/login         Get JWT token (form: username, password)
GET    /tasks/              List tasks (query: completed, priority, tag)
POST   /tasks/              Create task {title, description, priority, due_date, tag_ids}
GET    /tasks/{id}          Get single task
PATCH  /tasks/{id}          Update task fields
DELETE /tasks/{id}          Delete task
GET    /tags/               List all tags
POST   /tags/               Create tag {name, color}
DELETE /tags/{id}           Delete tag
GET    /health              Health check
WHAT: Section 4 — Authentication. Explains auth in one line. WHY: The most common mistake Gemini makes without this is suggesting wrong auth patterns. "Bearer <token>" vs cookie vs API key — this tells Gemini exactly how TaskFlow works.
## Authentication
All /tasks/ and /tags/ routes require: Authorization: Bearer <token>
Get a token from POST /users/login with form-encoded username+password.
WHAT: Section 5 — Development Commands. The exact commands to install, run, test, and verify the API. WHY: Gemini can suggest running commands. With this section, it suggests the correct commands for this project rather than generic FastAPI commands that might differ.
## Development Commands
# Install dependencies
pip install -r requirements.txt

# Start server (auto-reload on file changes)
uvicorn main:app --reload

# Run tests
pytest tests/ -v

# Quick API test (after starting server)
curl http://localhost:8000/health
What Just Happened?

You just read the five sections of TaskFlow's GEMINI.md and understood why each one is there. Notice the pattern: each section answers a different question Gemini might ask itself when reasoning about your project. Project Overview = "what is this?" Key Files = "where does what live?" Endpoints = "what does it expose?" Auth = "how are requests secured?" Commands = "how is it run?" Together they give Gemini a complete mental model of TaskFlow before you've typed a single prompt.

Model Selection

Technical Definition

Gemini CLI can use different Gemini modelsDifferent versions of the Gemini language model with different capabilities, speeds, and costs. Flash is optimized for speed and cost efficiency. Pro is optimized for reasoning quality and complex tasks. You select the model in GEMINI.md or at runtime. depending on your task. You set the default model in GEMINI.md using the model: field, or override it per-session with the --model flag. The two main options are Gemini 2.5 Flash (fast, cheap, good for most tasks) and Gemini 2.5 Pro (smarter, better at complex reasoning, higher cost).

⚡ Gemini 2.5 Flash

Speed~1-3s response
Context1M tokens
Cost (API)$0.075/1M in
Best forRoutine questions, code gen, file reads, CI tasks
Use Flash for 90% of your TaskFlow work: explaining code, generating tests, reformatting responses.

✨ Gemini 2.5 Pro

Speed~5-15s response
Context2M tokens
Cost (API)$1.25/1M in
Best forArchitecture decisions, complex refactors, security reviews
Use Pro when you need deeper reasoning: "What would break if I changed the auth model?" or "Design the caching layer."
WHAT: Set a default model in GEMINI.md and override per-session. WHY: Most TaskFlow work is Flash-level. Reserve Pro for architectural questions that require deeper reasoning. GOTCHA: On the free tier, both Flash and Pro are available — but Pro may have lower rate limits.
GEMINI.md — model selection
# TaskFlow — Gemini CLI Context

## Configuration
model: gemini-2.5-flash      # Default for routine tasks
# Uncomment for architecture reviews:
# model: gemini-2.5-pro
powershell — override model per-session
# Use Flash for routine tasks (faster)
gemini --model gemini-2.5-flash "@routers/tasks.py Add input validation to priority field"

# Use Pro for complex architecture questions
gemini --model gemini-2.5-pro "@models.py @schemas.py @routers/ Design a caching strategy for the task list endpoint"
bash
gemini --model gemini-2.5-flash "@routers/tasks.py Add input validation to priority field"
gemini --model gemini-2.5-pro "@models.py @schemas.py @routers/ Design a caching strategy for the task list endpoint"

System Instructions

Analogy First

Every software team has unwritten rules: "we use type hints everywhere", "never commit directly to main", "tests are mandatory for new endpoints". New developers learn these rules the hard way — through code review comments and "that's not how we do it here" feedback. The pain is that these rules exist only in the heads of senior developers and come out as reactive corrections. System instructions in GEMINI.md are the proactive version: you write the rules once, and Gemini follows them from the first response — without waiting to be corrected.

Technical Definition

System instructions in GEMINI.md are sections that tell Gemini how to behave, not just what the project is. Use a ## Instructions or ## Coding Standards section with bullet points or imperative sentences. Instructions override Gemini's default behavior for this project. Common uses: enforce style guides, specify what libraries to use or avoid, require certain patterns (like always adding type hints), and define "never do X" rules for safety.

WHAT: Add a coding standards section to GEMINI.md. WHY: These instructions shape every code suggestion Gemini makes for TaskFlow. Without them, Gemini might use Python 3.9 syntax, Pydantic v1 patterns, or raw dict manipulation instead of ORM style. GOTCHA: Keep instructions specific and actionable. "Write good code" is useless. "Use SQLAlchemy 2.0 session.get() instead of session.query()" is actionable.
GEMINI.md — adding system instructions
## Coding Standards

### Always Do
- Use Python 3.12 type hints on all function parameters and return types
- Use Pydantic v2 style: model_config dict, model_dump() not .dict(), model_validate() not .from_orm()
- Use SQLAlchemy 2.0 ORM style: session.get() for single lookups, session.execute(select()) for queries
- Add try/except with specific exception types, never bare except
- Put new tests in tests/ directory following the conftest.py fixtures pattern

### Never Do
- Never use raw SQL strings — always use SQLAlchemy ORM or Core expressions
- Never commit SECRET_KEY, DATABASE_URL, or any credentials to the codebase
- Never add a new dependency without also adding it to requirements.txt
- Never change the response schema of an existing endpoint without a migration plan
Gemini CLI — system instructions in action
>@routers/tasks.py Add an endpoint to get all overdue tasks
✦ Reading tasks.py, checking coding standards...
Adding to routers/tasks.py (following your SQLAlchemy 2.0 + type hints standards):
 
@router.get("/overdue", response_model=List[schemas.Task])
def list_overdue_tasks(
db: Session = Depends(get_db),
current_user: models.User = Depends(get_current_user),
) -> List[models.Task]: # <-- type hint from your standards
now = datetime.utcnow()
return db.query(models.Task).filter(...).all()
Press ▶ to see instructions applied

Token Caching

Technical Definition

Token caching (also called context cachingA Gemini API feature that stores a snapshot of a large context window. Subsequent requests that use the same cached context are cheaper and faster because the model doesn't re-process the same input tokens.) means that once Gemini has processed the content of your GEMINI.md and any @-mentioned files, it can reuse that processed representation for subsequent requests in the same session. The first request in a session pays the full token cost to process the context. Subsequent requests that use the same context prefix are cheaper and faster.

Practical implication for GEMINI.md: Content you put in GEMINI.md is cached once per session. Content you @-mention in individual prompts is processed fresh each time. This means GEMINI.md is the most cost-efficient place to put large, stable context that applies to all your questions.

What Belongs Where

Put in GEMINI.md (cached)

  • Project overview and purpose
  • Technology stack and versions
  • File roles and key file list
  • API endpoint table
  • Auth pattern description
  • Coding standards / "always/never" rules
  • Development commands

Use @-mention (per-prompt)

  • Specific file contents for targeted questions
  • Files you're actively modifying
  • Error messages or stack traces
  • Test output that needs analysis
  • Snippets from files that change often
  • Large files only needed for one question

Global vs Project Config

Configuration Priority (highest to lowest)

1 Command-line flags gemini --model gemini-2.5-pro — overrides everything for that invocation
2 Project GEMINI.md ./GEMINI.md — project-specific context and instructions, loaded when in that directory
3 Parent GEMINI.md files Walked up to the home directory — useful for monorepos with shared context
4 Global config (~/.gemini/config.yaml) Your personal defaults — default model, output format, API key, proxy settings
WHAT: The global config file sets defaults for all projects on your machine. WHY: If you always want Flash as the default model and want to save your API key in one place, put it here. GOTCHA: On Windows the path is %USERPROFILE%\.gemini\config.yaml (same as ~\.gemini\config.yaml in PowerShell).
powershell — create/edit global config
# Create the .gemini directory if it doesn't exist
New-Item -ItemType Directory -Force -Path "$env:USERPROFILE\.gemini"

# Edit the global config
notepad "$env:USERPROFILE\.gemini\config.yaml"
~\.gemini\config.yaml — global defaults
# ~/.gemini/config.yaml — applies to all projects
model: gemini-2.5-flash        # default model for all sessions
theme: dark                    # terminal color theme
auto_accept_edits: false       # always confirm file changes
sandbox: false                 # set true to restrict shell tool
bash
mkdir -p ~/.gemini
cat > ~/.gemini/config.yaml << 'EOF'
model: gemini-2.5-flash
theme: dark
auto_accept_edits: false
EOF

Three Starter Templates

Use these templates as starting points when creating GEMINI.md for new projects. Each is annotated to explain why each section is included.

WHAT: Template for FastAPI/Flask/Express REST API projects (like TaskFlow). WHY: API projects need endpoint documentation and auth pattern documentation above all else.
GEMINI.md — REST API template
# [Project Name] — Gemini CLI Context

## Project Overview
[One sentence: what this API does and who uses it]
Run: [exact start command]
API docs: [URL]

## Tech Stack
- Language/runtime: Python 3.12 / Node.js 20
- Framework: FastAPI 0.111 / Express 4
- Database: [name + ORM/driver]
- Auth: [JWT / OAuth2 / API key — describe the pattern]
- Tests: [pytest / jest — test directory]

## Key Files
- [filename] — [one-sentence role]
(list 5-10 most important files)

## API Endpoints
[table: METHOD /path — description — auth required: yes/no]

## Coding Standards
- [Language version rules: type hints, async/await patterns]
- [ORM style: what patterns to use/avoid]
- [Error handling: specific exception types, HTTP status codes]
- [Testing: required for new endpoints? where do tests go?]

## Development Commands
[copy-paste ready commands for: install, run, test, lint]

## Common Gemini CLI Tasks for This Project
- "[example prompt that's especially useful]"
(3-5 examples)
WHAT: Template for monorepos with multiple packages/services. WHY: Monorepos need explicit package ownership and cross-package rules to prevent Gemini from suggesting solutions that break other packages.
GEMINI.md — monorepo template
# [Monorepo Name] — Gemini CLI Context

## Repository Structure
[Brief description of what this monorepo contains]

## Packages / Services
- packages/[name] — [what it does, language, entry point]
- services/[name] — [what it does, how it's deployed]
(list all significant packages)

## Shared Infrastructure
- packages/shared/ — [shared types, utilities, constants]
- infra/ — [IaC: Terraform/Pulumi/CDK]
- [CI config location]

## Cross-Package Rules
- Shared types must be defined in packages/shared — never duplicated
- Breaking changes to shared types require updating all consumers
- Service-to-service calls use [gRPC / REST / message queue] — not direct imports

## Per-Package Standards
### packages/api (Node.js)
- TypeScript strict mode, zod for validation
### packages/worker (Python)
- Type hints required, mypy in CI

## Common Gemini CLI Tasks
- "@packages/api/src/ @packages/shared/ Check if this new type is consistent"
- "@services/auth/ Trace the complete login flow across services"
WHAT: Template for data engineering projects: ETL pipelines, dbt projects, Spark jobs. WHY: Data projects need schema documentation and idempotency rules that don't apply to web APIs.
GEMINI.md — data pipeline template
# [Pipeline Name] — Gemini CLI Context

## Pipeline Overview
[What data flows in, what comes out, what it's used for]
Orchestration: [Airflow / Prefect / cron]
Schedule: [how often it runs]

## Data Flow
[Source A] → [transform] → [Stage B] → [transform] → [Sink C]

## Key Datasets / Tables
- [table/dataset name] — [schema summary, row count, refresh cadence]
(list 5-10 key data assets)

## Data Quality Rules
- All pipelines must be idempotent (safe to re-run)
- Null handling: [your policy — drop, fill, error?]
- Schema changes: [process — migration required? backward compat?]
- Date/time: [all timestamps UTC? timezone handling?]

## Critical Never-Dos
- Never modify source tables directly — always write to staging first
- Never DELETE production data without a backup checkpoint
- Never commit database credentials — use [secret manager name]

## Development Commands
[commands for: install, run locally, test, validate data quality]
Bridge: From Templates to Your Own GEMINI.md

The TaskFlow GEMINI.md you've been reading all module is the REST API template filled in for a real project. In the lab below, you'll add a custom system instructions section to it and observe how Gemini's behavior changes. After the lab, you can use these templates for any future project — just swap the project-specific details and keep the structure.

Lab: Customize TaskFlow's GEMINI.md

You'll add four custom instructions to TaskFlow's GEMINI.md and observe how each one changes Gemini CLI's output on identical prompts. All commands run from inside sample-project/taskflow/.

Baseline: generate a new endpoint without custom instructions

First, run this command on the original TaskFlow GEMINI.md (before your changes). Note what style the code uses.

powershell
gemini "@routers/tasks.py Add an endpoint: GET /tasks/stats that returns total task count, completed count, and count by priority"
🔎
Observe: Does the generated code have type hints? Does it use Pydantic for the response schema? Does it follow the existing auth pattern? Save your observations for comparison in Step 3.

Add custom instructions to GEMINI.md

Open sample-project/taskflow/GEMINI.md and add this section at the end:

powershell — open GEMINI.md for editing
notepad GEMINI.md   # or: code GEMINI.md  (VS Code)
bash
code GEMINI.md   # or: nano GEMINI.md

Add this section to the bottom of GEMINI.md:

## Common Gemini CLI Tasks for This Project
(existing content above)
 
## Coding Standards (Custom)
 
### Always Do
- Use Python 3.12 type hints on ALL function parameters and return types
- Always create a Pydantic response schema for new endpoints (never return raw dicts)
- Prefer SQLAlchemy 2.0 ORM style: avoid legacy session.query() where possible
- Tests go in tests/ directory, follow the conftest.py fixture pattern
 
### Never Do
- Never use bare except: — always catch specific exception types
- Never add an import that isn't already in requirements.txt without noting it
- Never return sensitive fields (hashed_password) in any response schema

Re-run the same prompt and compare

powershell
# Exact same prompt as Step 1
gemini "@routers/tasks.py Add an endpoint: GET /tasks/stats that returns total task count, completed count, and count by priority"
Expected changes from Step 1: The new code should have type hints on all parameters and return type, a new Pydantic schema like class TaskStats(BaseModel) instead of a raw dict return, specific exception types if error handling was added, and no import of libraries not in requirements.txt.

Test the "never return sensitive fields" rule

powershell
gemini "@routers/users.py Add a GET /users/me endpoint that returns the current user's profile"
Expected: Gemini should use the existing schemas.User schema (which already excludes hashed_password) and NOT return the user object directly. If it adds a new schema, hashed_password should not appear in it. This demonstrates that your "never return sensitive fields" instruction is being followed.

Knowledge Check

1. You run gemini inside sample-project/taskflow/. TaskFlow has a GEMINI.md file. What happens?

Nothing — you must @mention GEMINI.md explicitly for it to be loaded
GEMINI.md is automatically read and its content is used as session context
GEMINI.md replaces your prompt — you cannot ask questions in that session
GEMINI.md is only loaded when you use headless mode with -p

2. When should you use Gemini 2.5 Pro instead of Flash for a TaskFlow question?

Any time you're reading more than 3 files
Always — Pro is strictly better than Flash
For complex architecture decisions and deep reasoning tasks (not routine code gen)
Only when asking about security vulnerabilities

3. You add "Never use raw SQL strings — always use SQLAlchemy ORM" to GEMINI.md's Coding Standards section. What effect does this have?

Gemini CLI enforces this at runtime and refuses to write raw SQL
Gemini includes this as a system instruction and follows it when generating code for this project
It adds a linting rule that scans your codebase for violations
Nothing — GEMINI.md only supports the listed section headings, not custom sections

4. What is the highest-priority configuration source in Gemini CLI?

~/.gemini/config.yaml (global config)
Project GEMINI.md
Command-line flags (e.g., --model, --no-interactive)
Environment variables (e.g., GEMINI_API_KEY)

5. Which type of content is most cost-efficient to put in GEMINI.md vs using @-mentions per prompt?

Large files you only need for one question
Error messages and stack traces
Stable project context that applies to every question (stack, auth pattern, endpoint list)
Files you're actively editing

Quiz Complete!

Ready for M03: Skill.md — Teaching Gemini Your Project's Patterns →