TL;DR — This article is going to be jam-packed with useful information, tips, tricks and hacks for setting up an agentic development in the Google ecosystem.
This one isn’t really about the FinOps!
Welcome back, friends!
In the first part, I described the purpose of the FinSavant FinOps solution, the motivation for creating it, its overall architecture and tech stack, and how it works.
In this part, we’ll use FinSavant as a case study in how to set up a development environment for the purposes of building such an ADK-based agentic solution. Even if you’re not particularly interested in FinSavant itself, I hope you’ll find a bunch of useful information and tips here that will help you build your own agentic solutions more effectively and quickly.
We’ll cover:
GEMINI.md
(or if you prefer, AGENTS.md
)Makefile
Sound good? Let’s get cracking!
Let’s see where we are in this series.
These days, my favourite coding environment for any significant project is Antigravity IDE. This is Google’s agent-first integrated development environment. You get a look-and-feel that’s familiar to VS Code users, but powered with autonomous, context-aware agents that can plan, execute, verify, and work in parallel.
You can get it here.
By the way, Antigravity IDE is just one member of the Antigravity (aka Agy) suite.
I’ve covered these before, but here’s a quick reminder of the four Agy solutions in the suite:
google.antigravity
we can programmatically leverage Antigravity’s capabilities.Here’s the rough outline of the project structure we’ll be creating. We won’t be building all of this structure here; nor does this represent the final state of the project. But it gives you an idea of where we’re heading. (I’ll explain the *
in a minute!)
smart-gcp-finops/
├── agent/ # ADK agent package
│ ├── finops_agent/ # Root agent
│ ├── .env # Agent specific environment vars
│ ├── Dockerfile # For deploying agent to Agent Runtime
│ └── pyproject.toml # Agent runtime dependencies
* ├── bff/ # Backend-for-Frontend (API)
* ├── deployment/ # Infrastructure & CI/CD (Terraform IaC)
* │ ├── terraform/ # Centralised IaC for Prod & Staging
│ └── README.md # Deployment documentation
* ├── docs/ # Project documentation
* │ ├── images/ # Diagrams and architectural visual assets
│ ├── DESIGN.md # Visual identity, components, and UI design
│ ├── architecture-and-walkthrough.md # Solution blueprints, ADRs, and component data flows
│ └── testing.md # Testing strategy and verification instructions
* ├── frontend/ # React UI frontend
* ├── notebooks/ # Jupyter notebooks for prototyping and evaluation
* ├── scripts/ # Environment setup and other utility scripts
│ └── setup-env.sh # Configure local environment including Google auth / ADC
* ├── tests/ # Unit and integration test suites
* │ ├── eval/ # Agent evaluation
* │ ├── unit/ # Unit tests
* │ └── integration/ # Integration tests
* ├── .agents/ # Workspace customizations root
│ └── mcp_config.json # E.g. MCP servers
* ├── .github/ # GitHub Actions workflows and CI/CD
* ├── .env # Root environment vars (dev setup, unified container, GitHub, etc)
├── .envrc # Automatically launch when entering this directory
* ├── .gitignore # Exclude from git
* ├── Makefile # Centralised developer convenience commands
* ├── GEMINI.md # Development agent context & guidelines
* ├── LICENSE # Standard open-source license file
* ├── pyproject.toml # Root project configuration / dependencies
* ├── README.md # Developer documentation homepage
└── TODO.md # TODO list
If you wanted to build such a structure from scratch, here’s a cool thing to try…
my-cool-project
/grill-me Using this folder tree as a template,
create the required folder structure in this workspace for my new Python
project. Only create folders and files that are marked as '*'.
For required files, provide initial starter-for-10 content.
<< paste the tree structure here >>
Why /grill-me
? This is a built-in Agy command that causes the agent to ask questions to remove ambiguity. If you were to give the agent a slightly vague prompt without this prefix, then the agent might make some guesses about what you want. But with /grill-me
, the agent will still make educated guesses, but it will also ask you questions to clarify your intent.
The prompt above is a good example of where this is useful. You’ll notice that my project tree has a LICENSE.md
file, which is a standard component to include in open-source projects. But my prompt doesn't specify which license to use. So when you use /grill-me
, the agent will offer sensible license choices based on your project and context, and ask you to confirm.
This video demonstrates Agy scaffolding the entire project from scratch, in response to the prompt above:
Give it a go!
I like to describe skills as units of knowledge that agents load on-demand, when they need to do a particular task. I’ve previously written articles on the subject of my favourite skills, where to find them, and how to install them. I recommend you check out this one. You might want to go ahead and install all of my favourites!
But for now, let’s add a few skills that will definitely be useful for our current project. I recommend installing them globally, so they’ll be available to all of your development projects.
npx skills add https://github.com/vercel-labs/skills -y -g --skill find-skills
npx skills add https://github.com/derailed-dash/dazbo-agent-skills -y -g
npx skills add https://github.com/google/skills -y -g
npx skills add https://github.com/google-gemini/gemini-skills/ -y -g
npx skills add https://github.com/shubhamsaboo/awesome-llm-apps/awesome-agent-skills -y -g --skill technical-writer
We’re also going to install the Google Agents CLI and its associated skills, but we’ll get to that later.
GEMINI.md
- Context for Your Coding Agent
The
GEMINI.md
file (or AGENTS.md
if you prefer) is how you define your project's rules and context. It's where you tell the Agy Agent:
When we create GEMINI.md
in the root of a project then the file is scoped only to that project. (This project-specific context gets appended to any global GEMINI.md
you have defined.) When you launch any Antigravity tool from this workspace - such as Agy 2.0, Agy IDE, or Agy CLI - the Agent will automatically read this context.
Let me show you what my GEMINI.md
looked like, when starting out with FinSavant:
## Project Goals
To create an agentic FinOps solution for GCP that:
- Uses ADK for agent orchestration.
- Is able to examine billing and cost data in BigQuery, based on billing
exports.
- Is able to understand Google Cloud infrastructure and services across
multiple Google projects associated with a billing account.
- Considers projects associated with a particular Google Cloud organisation,
associated with a billing account.
- Leverages Google Developer Knowledge API MCP for grounding:
Google APIs, Google Cloud infrastructure, Google Cloud best practices.
- Is able to detect cost anomalies and inefficiencies, and trends.
- Is able to understand all deployed infra and services, and historical
configuration changes, leveraging Google Cloud Asset Inventory
- Is able to invoke Google Cloud Assist for immediate logs investigation,
RCA and recommendations.
- Is able to combine all of the above to provide actionable insights and
recommendations to users.
- Provides a UI for users, which includes:
- Dashboard of cost trends, billing data and anomalies
- Cost forecasting
- Cost analysis
- Anomaly detection
- Recommendations
- Cost optimisation suggestions
- A natural language chat interface
- The UI should be based on React. Use skills you have available to leverage
React best practices.
- Leverage Google Stitch to design the UI, and use the Stitch MCP server to
pull in the design, in order to convert to React.
- The UI is connected to the agent via FastAPI.
- The UI and API will be hosted in a single Cloud Run service. The service
will be secured using IAP, using direct Cloud Run integration - no
Load Balancer.
- The Agent will be deployed to Agent Runtime in Gemini Enterprise Agent
Platform.
## Tool Use: Skills, Gemini Enterprise Agent Platform, Agent Runtime and ADK
Be sure to use all **agents** skills, **Gemini Enterprise Agent Platform**
skills, and **ADK** skills you have available for developing ADK agents and
best practices, and use **adk-docs-mcp** for latest ADK documentation.
You will have additional skills available to you, but always check if the
following can help with a particular task.
### ADK & agents-cli Lifecycle Skills
- `google-agents-cli-workflow`: Entrypoint for building ADK agents (scaffold,
build, evaluate, deploy, publish, observe).
[skipping for brevity]
### Gemini Enterprise Agent Platform APIs
- `gemini-api`: Gemini Enterprise Agent Platform, Google Cloud, and
Agent Platform enterprise usage with the Google Gen AI SDK.
[skipping for brevity]
### Agent Platform Engine & Model Management
- `agent-platform-deploy`: Deploying models and tuned weights to Agent
Platform endpoints.
[skipping for brevity]
## Key Internal Documentation
- README.md - Project README; the developer's front door
- TODO.md - High level plan for the project
- architecture-and-walkthrough.md - The main architecture, including design
decisions
- DESIGN.md - Where we will capture the UI design
- testing.md - Where we will document test strategy, summary of tests,
testing instructions, any manual testing processes
- docs/blog.md - A blog post document we will build along the way
- /deployment/README.md - Deployment and CI/CD documentation
## Essential Reading
You should read and leverage these resources for guidance and best practices,
in addition to the skills and MCP servers you have available for knowledge.
| Resource | Description and Relevance |
| -------- | ------------------------- |
| https://docs.cloud.google.com/bigquery/docs/use-bigquery-mcp?utm_campaign=DEVECO_GDEMembers&utm_source=deveco | Use the BigQuery MCP server |
| https://adk.dev/integrations/bigquery/?utm_campaign=DEVECO_GDEMembers&utm_source=deveco | BigQuery tool for ADK |
| https://docs.cloud.google.com/gemini-enterprise-agent-platform?utm_campaign=DEVECO_GDEMembers&utm_source=deveco | Gemini Enterprise Agent Platform Overview |
| https://adk.dev/deploy/agent-runtime?utm_campaign=DEVECO_GDEMembers&utm_source=deveco | ADK with Agent Runtime |
[skipping for brevity]
## Other Notes
- "Vertex AI" no longer exists as a product; the replacement is Gemini
Enterprise Agent Platform.
- "Vertex AI Agent Engine" is no more; the replacement is "Agent Runtime",
which is a part of the Gemini Enterprise Agent Platform.
- But APIs and Google internal resource names may still refer to legacy names,
e.g. `reasoningEngine` rather than Agent Runtime. Always use the new names
when creating documentation, but be mindful that we may need to use old
names in API calls and certain resource definitions.
## Blog
I want to build a multi-part blog series, which I'll post on Medium and Dev.to.
### Documenting As We Go
As we go, document steps taken, experience and findings in docs/blog.md.
Later, I will build a Medium blog from this content. During this "as we go"
phase, the blog.md does not need to be a collection of notes, code snippets, and observations. It should:
- Include all the key steps we did, in the order we did them.
[skipping for brevity]
If you’re following along and you’ve just created your context file, give Agy a restart now, so it picks this up.
I’m a big fan of having a consistent set of high-quality, continuously maintained documentation. I even have my own agent skill — maintaining-core-documentation
- to automate much of this for me. Check out my previous blog on this subject: Documentation as Context: A Skill to Automate Your Blueprints for the Agentic Era.
If you previously ran the npx skills add https://github.com/derailed-dash/dazbo-agent-skills -y -g
command from above, then you already have this skill installed.
With this in place, you could issue this prompt to bootstrap a set of documentation for a brand-new project:
Use maintaining-core-documentation to bootstrap my project documentation.
Check out this video to see the skill doing its magic!
As you evolve your project, this skill will automatically maintain your documentation.
I’ve previously written about some of my favourite MCP servers. There are only a couple that we’ll need for this project:
Note that we won’t be using either of these in the FinSavant agent itself. These are purely to help us during development.
Let’s try out the BigQuery MCP server first. In your workspace’s .agents/mcp_config.json
file, we configure the Remote BigQuery MCP server like this:
{
"mcpServers": {
"bigquery-mcp-server": {
"serverUrl": "https://bigquery.googleapis.com/mcp",
"authProviderType": "google_credentials",
"oauth": {
"scopes": [
"https://www.googleapis.com/auth/bigquery"
]
},
"headers": {
"x-goog-user-project": "your-gcp-billing-project"
}
}
}
}
A few things to note about this:
your-gcp-billing-project
with the Google project where your billing data export lives.bigquery.googleapis.com
) is enabled on that project.google_credentials
to authenticate, your local developer account (active in gcloud auth
) must be authorised on Google Cloud. You need the roles/bigquery.dataViewer
and roles/bigquery.jobUser
roles on the project hosting the billing dataset.roles/mcp.toolUser
role, in order to use this managed MCP server to query the BigQuery database.And now, when you open the workspace in Antigravity IDE, it will load this configuration automatically. Your coding agent will be able to query schemas, inspect tables, and try out SQL queries in order to assist you when you actually create the FinSavant agent code.
Let’s test it!
First, I issue this prompt to the Agy agent:
What billing tables do I have? Explain their key functions.
You can see the agent immediately finds the MCP server and asks for permission to invoke its tools. After I grant permission, I get this response:
Nice! You can see how helpful this is going to be.
The easiest way to scaffold a new ADK agent is to make use of Google Agents CLI. The Agents CLI is actually a bundle, containing:
You install the bundle using this one-time command:
uvx google-agents-cli setup
If you already have it installed, then you can upgrade like this:
uv tool upgrade google-agents-cli
(It’s worth doing this occasionally — this CLI is evolving quickly!)
With this installed, we could create our top level agent
folder that contains a root agent called finops_agent
by running this command:
agents-cli scaffold create agent \
--agent adk \
--prototype \
--agent-directory finops_agent
You’ll end up with the following inside of your workspace folder:
agent/
├── finops_agent/ # Your agent code
│ ├── __init__.py # Registers the app (exports `app`)
│ ├── agent.py # Agent definition — instructions, model, tools
│ └── app_utils/ # Utilities (telemetry, converters)
│ ├── __init__.py
│ ├── telemetry.py # OpenTelemetry setup for Cloud Trace
│ ├── typing.py # Request/response Pydantic models
│ └── gcs.py # GCS utility functions
│
├── tests/
│ ├── eval/ # Evaluation test cases
│ │ ├── datasets/
│ │ │ └── basic-dataset.json # Default eval cases
│ │ └── eval_config.yaml # Evaluation metrics configuration
│ ├── integration/
│ │ └── test_agent.py # Integration test (runs agent end-to-end)
│ └── unit/
│ └── test_dummy.py # Placeholder for unit tests
│
├── .env # Environment variables (project ID, location)
├── .env.example # Example environment variables
├── .gitignore # Git ignore file
├── pyproject.toml # Project config and dependencies
├── agents-cli-manifest.yaml # Configuration for agents-cli
├── Dockerfile # Dockerfile for the agent runtime
└── GEMINI.md # Guidance file for coding agents
But since we now have the skills installed, there’s an easier way to accomplish this, that doesn’t require you to check the CLI documentation…
Please bootstrap a new ADK agent project. The agent top-level project should
be named `agent`, and it should contain a root `agent-directory` called
`finops_agent`, NOT the default of `app`. This means `pyproject.toml` and
other config files will live under `agent/`, and all Python source files
(like `agent.py` and `fast_api_app.py`) will live inside
`agent/finops_agent/`.
Sure, this prompt is quite detailed, but I’m after a very specific folder structure.
Let’s see a live demo…
As you can see from the demo, we can now use agents-cli
to check if our newly scaffolded agent is working.
For example, by issuing a single test prompt on the command line:
cd agent
agents-cli run "Hello! Who are you?"
Or, we could run up the extremely powerful and useful ADK Web interface, using this handy shortcut:
agents-cli playground
Concluding thought about Agents-CLI
: if you know your way around the CLI, you can use it directly. It'll be faster and use fewer tokens. But when you're doing lots of agent related activities like boostrapping, adding CI/CD, deploying and evaluating, you'll probably find that natural language conversations are going to save you a lot of time and pain.
In a “monorepo” project setup like FinSavant, you quickly end up managing a lot of moving parts: building frontend assets, compiling Python environments, building and running multiple Docker images, executing test suites, and deploying resources to various target environments.
Rather than forcing yourself (or your team) to remember a massive list of commands and flags, wrapping them in a Makefile
is a big win.
But what actually is a Makefile
? At its core, it is a configuration file used by the classic make
build automation tool. These days it has evolved into a lightweight, standardised task runner. It allows us to define short aliases (known as "targets") for complex shell commands, documenting project workflows in a single, standard file that is easy for both humans and agents to discover.
Earlier, during the demonstration of bootstrapping the project, the agent actually created an initial Makefile
for us. If you followed along, you'll now have a Makefile
that looks something like this:
.PHONY: install lint format lint-fix test
install:
@command -v uv >/dev/null 2>&1 || { echo "uv is not installed. Installing uv..."; curl -LsSf https://astral.sh/uv/0.11.16/install.sh | sh; source $HOME/.local/bin/env; }
uv sync
lint:
uvx codespell@latest -s
uvx ruff@latest check .
lint-fix:
uvx codespell@latest -w
uvx ruff@latest check --fix .
test:
uv run pytest tests/
Now you can run any of these make
targets, like this:
make install
With this in place, we can build on it in future articles as we develop the FinSavant solution.
These days, whenever I’m working on a project that makes use of Google services, I always create a helper setup-env
script to configure my environment for me.
This script:
.env
directly into the current shell session.--noauth
flag), it runs gcloud auth login --update-adc
to authenticate the user and configure Google Application Default Credentials (ADC).gcloud
defaults for the target project and billing quota project settings.uv sync
to ensure all standard, development, and notebook dependencies are installed in the local environment..venv
) so the user is immediately ready to run code.You can find a copy of this scripts/setup-env.sh
in my GitHub repository. Because it uses standard environment variables defined in your .env
, you can use it in any of your Google projects!
You run it from the project root directory like this:
source scripts/setup-env.sh
direnv
and .envrc
If you haven’t come across this before, I think you’re going to like it!
Manually sourcing the setup-env.sh
script every time I open a terminal in the project directory is a bit of a chore. To automate this, we can use direnv
— an extension for your shell that automatically runs custom scripts and loads / unloads environment variables depending on your current directory.
By placing a .envrc
file at the root of the project, direnv
automatically executes it whenever you cd
into the directory.
Here is what our .envrc
looks like:
if [ ! -d ".venv" ]; then
uv venv
fi
if gcloud auth print-access-token --quiet > /dev/null 2>&1; then
echo "gcloud token is valid, skipping authentication."
source scripts/setup-env.sh --noauth
else
echo "gcloud token is not valid, re-authenticating."
source scripts/setup-env.sh
fi
This configuration does a few smart things:
uv venv
if it doesn't already exist.gcloud auth print-access-token
silently to check if our Google Cloud session is active.--noauth
flag, avoiding repetitive and annoying browser login prompts. If the session has expired, it triggers the full setup script to re-authenticate.There are a couple of one-off steps we have to do to get direnv
up and running:
direnv
. On Debian/Ubuntu systems, this is sudo apt install direnv
.direnv
. Run direnv allow
in the terminal, in the project folder where we've placed our .envrc
file.Now, when we enter our project folder, the script runs automatically, like this:
Pretty neat, right?
Okay, we’re done with the environment setup. We’ve:
/grill-me
agents-cli
and its skillsMakefile
for standardising common development, testing and deployment tasksscripts/setup-env.sh
script for setting up our Google Cloud environmentdirenv
and a .envrc
file to automate the setup process, every time we open a terminal in this directoryIn the next part, we’ll look at the actual code for our FinSavant agents and tools!
See you there!