Terminal Coding Agent with Azure AI
Deploy a GPT-4o-mini model on Azure and use it as a terminal coding agent.
Introduction
30 Second Summary
AI coding assistants are changing how developers work. Most require paid subscriptions or tie you to a specific code editor.
In this project, you will deploy a GPT-4o-mini model to Azure and connect it to the OpenAI Codex CLI. This gives you an AI coding agent that can write, debug, and refactor code directly from your terminal.
What You'll Build
A terminal-based AI coding agent powered by a GPT-4o-mini model hosted in Azure AI Foundry, configured through the OpenAI Codex CLI.
By the end of this project, you'll have:
- A deployed gpt-4o-mini model instance running in Azure AI Foundry.
- A configured ~/.codex/config.toml connecting Codex CLI to your Azure endpoint.
- A small Python project created and refactored entirely through your terminal coding agent.
- Secret Mission: Configure a second model deployment and set up a Codex profile to switch between models depending on task complexity.
Are there any prerequisites?
You need an active Azure for Students subscription with remaining credit and Azure CLI installed on your machine.
You'll also need Node.js 18 or higher, which Step 1 covers if you don't have it yet.
Set Up Your Azure AI Foundry Resource
To build a terminal coding agent, you first need a model running in the cloud that the agent can talk to. Azure AI Foundry lets you deploy models like gpt-4o-mini to your own endpoint, giving you full control over billing and access.
In this step, you will provision an Azure OpenAI resource using the Azure CLI, deploy the gpt-4o-mini model, and retrieve the credentials your coding agent needs to connect.
In this step, get ready to:
- Create an Azure AI Services resource in the cloud.
- Deploy the gpt-4o-mini model to your resource.
- Retrieve your endpoint URL and API key.
Create an Azure OpenAI resource via Azure CLI
Azure requires a resource group to organize cloud resources. You will create a new resource group and then provision an Azure OpenAI resource inside it.
- Create a resource group in the East US 2 region by running this command:
az group create --name codex-rg --location eastus2
- Create your Azure OpenAI resource by running this command:
az cognitiveservices account create \
--name my-codex-resource \
--resource-group codex-rg \
--location eastus2 \
--kind OpenAI \
--sku S0 \
--custom-domain my-codex-resource \
--yes
What does this command do?
This provisions an Azure OpenAI resource named my-codex-resource in the East US 2 region.
- The --kind OpenAI flag tells Azure this resource will host OpenAI models.
- The --sku S0 sets the Standard pricing tier (pay-per-token).
- The --custom-domain flag gives your resource a unique URL like https://my-codex-resource.openai.azure.com/.
- Wait for the command to complete. You should see a JSON response with "provisioningState": "Succeeded" in the output.
Seeing RequestDisallowedByAzure?
Some Azure for Students subscriptions are policy-blocked from creating Azure OpenAI resources. If you see this error, you may need to open a support request through the Azure portal or upgrade to a Pay-As-You-Go subscription (your student credits still apply).
Help me resolve this error
Deploy the gpt-4o-mini model
With your resource created, you can now deploy a model to it. The gpt-4o-mini model is a fast, capable coding model available on Azure for Students at 1K tokens per minute.
- Deploy the gpt-4o-mini model to your resource by running this command:
az cognitiveservices account deployment create \
--name my-codex-resource \
--resource-group codex-rg \
--deployment-name gpt-4o-mini \
--model-name gpt-4o-mini \
--model-version "2024-07-18" \
--model-format OpenAI \
--sku-capacity 1 \
--sku-name GlobalStandard
What does this command do?
This creates a model deployment named gpt-4o-mini inside your Azure OpenAI resource.
- The --sku-name GlobalStandard sets the deployment type to pay-per-token. Idle deployments do not incur charges.
- The --sku-capacity 1 sets the minimum token capacity for your deployment.
- The --model-format OpenAI specifies this is an OpenAI-format model (as opposed to Microsoft or third-party).
- Wait for the command to finish. You should see a JSON response confirming the deployment was created successfully.
Deployment failing?
If you see a quota error, your Azure for Students tier may not have capacity in East US 2 for GlobalStandard deployments. Try reducing --sku-capacity to 1 (as shown above) or check that your subscription has remaining credit.
Help me fix this deployment error
Retrieve your endpoint and API key
Your coding agent needs two pieces of information to connect: the endpoint URL and an API key. You will retrieve both from your newly created resource.
- Get your resource's endpoint URL by running:
az cognitiveservices account show \
--name my-codex-resource \
--resource-group codex-rg \
--query "properties.endpoint" \
--output tsv
- You should see an endpoint like https://my-codex-resource.openai.azure.com/ printed to your terminal. Copy this value and save it somewhere (like a text file or sticky note).
- Get your API key by running:
az cognitiveservices account keys list \
--name my-codex-resource \
--resource-group codex-rg \
--query "key1" \
--output tsv
- Copy the API key that is printed to your terminal. Save it alongside your endpoint URL.
Why two values?
The endpoint tells your coding agent WHERE to send requests (your specific Azure resource). The API key proves you have permission to use it.
In the next step, you will put both into a configuration file so Codex CLI can find them automatically.
Not seeing an endpoint or key?
Make sure the resource name my-codex-resource and resource group codex-rg match exactly what you used in the create commands. Names are case-sensitive.
Help me troubleshoot this
Your Azure AI Foundry resource is live and your model is deployed. Next up, you will install the Codex CLI and point it at your Azure endpoint so you can start coding with AI directly in your terminal.
Install and Configure Codex CLI
In the previous step, you deployed a gpt-4o-mini model to Azure AI Foundry and retrieved your endpoint URL and API key.
Now you need a way to actually use that model as a coding assistant in your terminal. That's where OpenAI Codex CLI comes in. It's a terminal-based coding agent that can read your files, suggest changes, and even run commands on your behalf. In this step, you'll install it and point it at your Azure endpoint.
In this step, get ready to:
- Install Node.js and OpenAI Codex CLI.
- Create a configuration file that connects Codex to your Azure endpoint.
- Set your API key and test that Codex responds.
Install Node.js and Codex CLI
Codex CLI is distributed as an npm package, which means it requires Node.js to be installed on your machine. The minimum version is 18.
- Check if Node.js is already installed by running this command in your terminal:
node --version
✔️ I see version 18 or higher
You're all set. Any version number starting with v18, v20, v22, v24, or higher means Node.js is ready for Codex CLI.
ⓧ I see a version lower than 18
You have an older version of Node.js that won't work with Codex CLI. You need to upgrade to version 18 or higher.
- Visit nodejs.org/en/download and download the LTS installer for your operating system.
- Run the installer and follow the prompts to complete the upgrade.
- Close and reopen your terminal, then run node --version again to confirm you see v18 or higher.
Using a version manager?
If you use nvm or another Node version manager, you can install the latest LTS with nvm install --lts and activate it with nvm use --lts.
ⓧ Command not found
Node.js is not installed on your machine. You need to install it before continuing.
- Visit nodejs.org/en/download and download the LTS installer for your operating system.
- Run the installer and follow the prompts.
- Close and reopen your terminal so the new node command is available on your PATH.
- Confirm the install by running node --version. You should see v18 or higher.
- Install Codex CLI globally by running this command:
npm install -g @openai/codex
What does this command do?
The -g flag installs the package globally, making the codex command available from any directory in your terminal. The @openai/codex package is the official OpenAI Codex CLI agent.
- Verify the installation by running:
codex --version
You should see a version number printed (such as 0.133.0 or similar). This confirms Codex CLI is installed and working.
Seeing a permission error?
If you see an EACCES error on macOS or Linux, your npm global directory may be owned by root. Do not use sudo to fix this. Instead, configure npm to use a user-owned directory:
mkdir -p ~/.npm-global
npm config set prefix ~/.npm-global
Then add ~/.npm-global/bin to your PATH in your shell profile (~/.zshrc or ~/.bashrc), restart your terminal, and re-run the install command.
Help me fix this npm permission error.
Create config.toml for Azure
Codex CLI needs to know where your model lives and how to authenticate. You'll configure this in a TOML configuration file that tells Codex to use your Azure endpoint instead of the default OpenAI API.
- Create the Codex configuration directory by running:
mkdir -p ~/.codex
- Create the configuration file by running:
cat > ~/.codex/config.toml << 'EOF'
model = "gpt-4o-mini"
model_provider = "azure"
[model_providers.azure]
name = "Azure OpenAI"
base_url = "https://[[RESOURCE_NAME="your-resource-name"]].openai.azure.com/openai/v1"
env_key = "AZURE_OPENAI_API_KEY"
wire_api = "responses"
EOF
What do these settings mean?
The model field tells Codex which deployment to use. The model_provider field routes requests through the Azure adapter instead of the default OpenAI endpoint.
Inside the [model_providers.azure] section, base_url points to your Azure resource's Responses API. The env_key tells Codex which environment variable holds your API key. The wire_api field specifies the API format to use.
Finding your resource name
Your resource name is the first part of your endpoint URL. If your endpoint is https://my-codex-resource.openai.azure.com/, then your resource name is my-codex-resource. Replace the placeholder in the base_url with your actual resource name from Step 1.
- Verify the file was created by running:
cat ~/.codex/config.toml
You should see the configuration content you just wrote, with your resource name in the base_url field.
File looks empty or missing?
Make sure you copied the entire cat command including the EOF on the last line. The heredoc syntax requires EOF to appear alone on its own line to close the file. Try running the command again.
Help me create my config.toml file.
✔️ Awesome, I've got everything!
Great. Make sure the base_url contains your actual resource name from Step 1 (not the placeholder text).
ⓧ I'd like to double check the full code
Your ~/.codex/config.toml should look like this (with your resource name substituted):
model = "gpt-4o-mini"
model_provider = "azure"
[model_providers.azure]
name = "Azure OpenAI"
base_url = "https://your-resource-name.openai.azure.com/openai/v1"
env_key = "AZURE_OPENAI_API_KEY"
wire_api = "responses"
Set your API key environment variable
Your config.toml references an environment variable called AZURE_OPENAI_API_KEY. You need to set this variable with the actual API key you retrieved in Step 1.
- Export your API key for the current terminal session by running:
export AZURE_OPENAI_API_KEY=your-api-key-here
Where do I find my API key?
This is the key you retrieved at the end of Step 1 using az cognitiveservices account keys list. Paste the key1 value in place of your-api-key-here.
- Add the export to your shell profile so it persists across terminal sessions.
macOS
- Add the export line to your ~/.zshrc by running:
echo 'export AZURE_OPENAI_API_KEY=your-api-key-here' >> ~/.zshrc
Windows
Codex CLI on Windows runs through WSL2, so you're using a Linux shell.
- Add the export line to your ~/.bashrc by running:
echo 'export AZURE_OPENAI_API_KEY=your-api-key-here' >> ~/.bashrc
Why add it to a shell profile?
The export command only sets the variable for your current terminal session. Adding it to your shell profile (~/.zshrc or ~/.bashrc) means the variable is automatically set every time you open a new terminal.
- Test the connection by launching Codex in interactive mode:
codex
Codex will start an interactive session. Type a simple prompt like "What is 2 plus 2?" and press Enter.
You should see a response from the model. This confirms that Codex CLI can connect to your Azure-hosted gpt-4o-mini deployment.
Seeing an authentication error?
Double check that your AZURE_OPENAI_API_KEY is set correctly by running echo $AZURE_OPENAI_API_KEY in your terminal. You should see your key printed.
Also verify that the base_url in your ~/.codex/config.toml matches your actual Azure resource endpoint. A typo in the resource name will cause authentication to fail.
Help me fix this Codex authentication error.
Your coding agent is live and connected to Azure. Next up, you'll put it to work on a real coding project to see what it can do.
Use Your Coding Agent on a Real Project
Your coding agent is configured, connected to Azure, and ready to work. Now it is time to put it to the test on real code.
In this step, you will create a Python script with intentional bugs, then use Codex CLI to find and fix them, add error handling, and generate unit tests. This is the same workflow professional developers use with terminal coding agents every day.
In this step, get ready to:
- Create a Python project with intentional bugs and missing features.
- Use Codex to debug and refactor the code.
- Generate a new test file with Codex and verify it passes.
Create a starter project with intentional bugs
Before Codex can fix code, it needs code to work on. You will create a simple Python script that parses numbers, calculates averages, and finds maximums.
- Move to your Desktop by running this command:
cd ~/Desktop
- Create your project folder and move into it by running these commands:
mkdir codex-project
cd codex-project
- Create the buggy starter script by running this command:
cat > buggy_app_starter.py << 'EOF'
import sys
def calculate_average(numbers):
total = sum(numbers)
return total / len(numbers)
def find_maximum(numbers):
max_val = numbers[0]
for num in numbers:
if num > max_val:
max_val = num
return max_val
def parse_numbers(input_string):
parts = input_string.split(",")
numbers = []
for part in parts:
numbers.append(float(part))
return numbers
def main():
input_string = sys.argv[1]
numbers = parse_numbers(input_string)
avg = calculate_average(numbers)
max_val = find_maximum(numbers)
print(f"Numbers: {numbers}")
print(f"Average: {avg}")
print(f"Maximum: {max_val}")
if __name__ == "__main__":
main()
EOF
What does this script do?
This script takes comma-separated numbers as a command-line argument and prints their average and maximum.
The bugs are intentional. calculate_average crashes on an empty list (division by zero). parse_numbers crashes on non-numeric input. The script has no argument validation, so running it without arguments throws an IndexError.
- Verify the file was created by running:
ls
You should see buggy_app_starter.py in the output.
- Try running the script with valid input to confirm it works:
python3 buggy_app_starter.py 10,20,30,40,50
You should see the numbers, their average, and the maximum printed.
- Now try running it without any arguments to see one of the bugs:
python3 buggy_app_starter.py
The script crashes with an IndexError because there is no argument validation. This is one of the bugs Codex will fix.
- Copy the starter file to buggy_app.py so you keep the original and give Codex a working copy:
cp buggy_app_starter.py buggy_app.py
Seeing 'python3: command not found'?
Try using python instead of python3 depending on your system. On Windows (via WSL2), Python is often available as python3 but some setups use python.
help me troubleshoot Python not being found in my terminal
Debug and refactor with Codex
Now you will see the power of a terminal coding agent. Instead of manually hunting for bugs, you will ask Codex to read the file, identify issues, and fix them for you.
- Make sure you are inside the codex-project folder, then launch Codex with a debugging prompt by running:
codex "Review buggy_app.py, find all bugs and edge cases, add error handling, add docstrings, and fix the code. Save the fixed version to buggy_app.py"
What happens when you run this?
Codex opens an interactive session with your prompt pre-loaded. It reads buggy_app.py, analyzes the code, identifies bugs, and proposes fixes.
By default, Codex runs in suggest mode. It will show you each proposed change and ask for approval before applying it. Select Yes (or press y) to approve each change until it completes the task.
- When Codex shows its proposed changes, review them and approve each one by pressing y.
- Once Codex finishes, verify the fixed script handles edge cases by running:
python3 buggy_app.py 10,20,30,40,50
You should see formatted output like Average: 30.00 and Maximum: 50.0.
- Test the error handling by running the script without arguments:
python3 buggy_app.py
Instead of crashing, you should now see a helpful usage message.
- Test with invalid input to confirm the parsing is robust:
python3 buggy_app.py "10,abc,30"
You should see a warning about the invalid value and the valid numbers still processed correctly.
What did Codex fix?
Codex should have addressed these issues in the original code:
- Added empty list handling in calculate_average to prevent division by zero.
- Added empty list handling in find_maximum and fixed the iteration to skip the first element (since it is already assigned to max_val).
- Added try/except in parse_numbers for non-numeric input.
- Added CLI argument validation in main with a usage message.
- Added docstrings to each function.
Codex did not fix all the bugs?
AI output can vary between runs. If Codex missed some fixes, you can run another prompt asking it to address specific issues. For example, run codex again and type a follow-up like "add empty list handling to calculate_average and find_maximum in buggy_app.py".
help me get Codex to fix the remaining bugs in my Python script
Generate new code with Codex
Codex can do more than fix bugs. It can generate entirely new files for your project. You will ask it to create a unit test file that validates all the functions in your fixed script.
- Install pytest so the generated tests can run:
pip install pytest
- Ask Codex to generate a test file by running:
codex "Write a comprehensive pytest test file called test_buggy_app.py that tests calculate_average, find_maximum, and parse_numbers from buggy_app.py. Include tests for normal cases, edge cases like empty lists, and invalid input."
What is Codex doing here?
Codex reads your buggy_app.py to understand the function signatures and behavior. It then generates a complete test file with multiple test cases covering normal inputs, edge cases, and error conditions.
This is a workflow professional developers use constantly. Writing tests by hand is tedious, but an AI agent can generate a solid first draft in seconds.
- When Codex shows the proposed file creation, approve it by pressing y.
- Once Codex finishes, run the tests to verify they pass:
pytest test_buggy_app.py -v
You should see all tests passing with green output. The -v flag shows each individual test name and its result.
Tests failing?
If some tests fail, Codex may have generated tests that do not match what it fixed in buggy_app.py. Run codex again and ask it to "fix the failing tests in test_buggy_app.py to match the current implementation of buggy_app.py".
help me fix failing pytest tests that Codex generated for my project
- Confirm all three project files exist by running:
ls
You should see buggy_app_starter.py, buggy_app.py, and test_buggy_app.py listed.
✔️ Awesome, I've got everything!
Great. Make sure all your tests pass with pytest before moving on.
ⓧ I'd like to double check the full code
Here is what your buggy_app_starter.py should look like (the original untouched version):
import sys
def calculate_average(numbers):
total = sum(numbers)
return total / len(numbers)
def find_maximum(numbers):
max_val = numbers[0]
for num in numbers:
if num > max_val:
max_val = num
return max_val
def parse_numbers(input_string):
parts = input_string.split(",")
numbers = []
for part in parts:
numbers.append(float(part))
return numbers
def main():
input_string = sys.argv[1]
numbers = parse_numbers(input_string)
avg = calculate_average(numbers)
max_val = find_maximum(numbers)
print(f"Numbers: {numbers}")
print(f"Average: {avg}")
print(f"Maximum: {max_val}")
if __name__ == "__main__":
main()
Here is what your fixed buggy_app.py should look like after Codex refactors it:
import sys
def calculate_average(numbers):
"""Calculate the average of a list of numbers."""
if not numbers:
return 0
total = sum(numbers)
return total / len(numbers)
def find_maximum(numbers):
"""Find the maximum value in a list."""
if not numbers:
raise ValueError("Cannot find maximum of empty list")
max_val = numbers[0]
for num in numbers[1:]:
if num > max_val:
max_val = num
return max_val
def parse_numbers(input_string):
"""Parse a comma-separated string into a list of numbers."""
if not input_string or not input_string.strip():
return []
parts = input_string.split(",")
numbers = []
for part in parts:
stripped = part.strip()
if stripped:
try:
numbers.append(float(stripped))
except ValueError:
print(f"Warning: '{stripped}' is not a valid number, skipping.")
return numbers
def main():
if len(sys.argv) < 2:
print("Usage: python buggy_app.py <comma-separated-numbers>")
print("Example: python buggy_app.py 10,20,30,40,50")
sys.exit(1)
input_string = sys.argv[1]
numbers = parse_numbers(input_string)
if not numbers:
print("No valid numbers provided.")
sys.exit(1)
avg = calculate_average(numbers)
max_val = find_maximum(numbers)
print(f"Numbers: {numbers}")
print(f"Average: {avg:.2f}")
print(f"Maximum: {max_val}")
if __name__ == "__main__":
main()
Here is what test_buggy_app.py should look like:
import pytest
from buggy_app import calculate_average, find_maximum, parse_numbers
def test_calculate_average_normal():
assert calculate_average([10, 20, 30]) == 20.0
def test_calculate_average_empty():
assert calculate_average([]) == 0
def test_calculate_average_single():
assert calculate_average([5]) == 5.0
def test_find_maximum_normal():
assert find_maximum([10, 50, 30]) == 50
def test_find_maximum_negative():
assert find_maximum([-5, -1, -10]) == -1
def test_find_maximum_empty():
with pytest.raises(ValueError):
find_maximum([])
def test_parse_numbers_normal():
assert parse_numbers("10,20,30") == [10.0, 20.0, 30.0]
def test_parse_numbers_with_spaces():
assert parse_numbers("10, 20, 30") == [10.0, 20.0, 30.0]
def test_parse_numbers_empty():
assert parse_numbers("") == []
def test_parse_numbers_invalid():
result = parse_numbers("10,abc,30")
assert result == [10.0, 30.0]
AI output varies
Your Codex-generated code may not match these examples word-for-word. The important thing is that the behavior is the same: edge cases are handled, invalid input does not crash the script, and all tests pass.
Secret mission
Deploy a Second Model and Create Codex Profiles for Task Routing
What if you could use a faster, cheaper model for simple tasks and save the heavy-hitter for complex reasoning? In this secret mission, you'll deploy gpt-4.1-nano as a second model in your Azure resource and configure Codex profiles to switch between models based on task complexity.
Clean Up Your Resources
Clean Up Your Resources
Decide whether to keep your resources running, pause them to come back later, or delete them entirely. This project uses pay-per-token billing with GlobalStandard deployments, so idle deployments do not incur charges. You only pay for tokens you actually process, and those come from your $100 Azure for Students credit.
Resources you used:
- Azure AI Services resource (my-codex-resource) in East US 2 with model deployments (gpt-4o-mini, gpt-4.1-nano).
- Codex CLI installed globally via npm (@openai/codex).
- Codex CLI configuration directory (~/.codex/).
- Local project files (buggy_app.py, buggy_app_starter.py, test_buggy_app.py).
- AZURE_OPENAI_API_KEY environment variable in your shell profile.
Keep everything running
No action needed. Choose this if you are still actively building or experimenting with your coding agent.
- Your model deployments stay active. Idle deployments do not cost anything. You only pay for tokens processed during active use.
- Codex CLI remains installed and ready to use from any terminal session.
- Your AZURE_OPENAI_API_KEY stays in your shell profile for future sessions.
Pause - I'll come back to this later
Since your Azure deployments use serverless pay-per-token billing, there is no compute to pause. Idle deployments do not incur charges.
- No action needed on Azure. Your deployments sit idle at zero cost until you use them again.
- Your Codex CLI and config.toml will be ready when you return.
Delete - I don't want to use this again
Remove all project resources and start fresh. Follow each step below to fully clean up.
- Delete the Azure AI Services resource (this removes both model deployments) by running:
az cognitiveservices account delete --name my-codex-resource --resource-group [[RESOURCE_GROUP="your resource group name"]]
- Uninstall Codex CLI globally by running:
npm uninstall -g @openai/codex
- Remove the Codex CLI configuration directory by running:
rm -rf ~/.codex
- Remove the AZURE_OPENAI_API_KEY export line from your shell profile. Open ~/.zshrc (macOS) or ~/.bashrc (Linux) and delete the line that contains export AZURE_OPENAI_API_KEY.
- Remove your local project files by running:
rm -rf ~/Desktop/codex-project
- Confirm the Azure resource is gone by running:
az cognitiveservices account list -o table
You should no longer see my-codex-resource in the output.
Nice Work!
Nice Work!
You just deployed your own AI-powered terminal coding agent. You now have a fully functional setup that lets you write, debug, and refactor code from the command line, all backed by a model running on your own Azure infrastructure.
Here's what you learned:
- Deployed a gpt-4o-mini model to Azure AI Foundry and retrieved your endpoint and API key for authentication.
- Installed and configured OpenAI Codex CLI to connect to your Azure-hosted model using config.toml.
- Used your coding agent to find bugs, add error handling, refactor code, and generate a test suite directly from the terminal.
- Created multiple model profiles for task-appropriate routing between gpt-4o-mini and gpt-4.1-nano.
Ready to quiz yourself?