Direct Code Deployment Reference
Use this reference only when the user explicitly requested direct code deployment.
This reference covers only direct-code deployment from deploy.md Step 3. After deployment completes, proceed directly back to deploy.md Step 7: Test the Agent.
Direct-code deployment uses local project files plus the Foundry REST API for upload and version operations. Azure MCP discovery and context lookup are optional context, not a prerequisite when project endpoint, model deployment, and agent name are already resolved. For the code upload itself, follow the REST endpoints below instead of the Docker/ACR agent_update path.
Task 1: Preflight
Resolve the project endpoint from project context, .env, azd env get-values, or the user. The endpoint must look like:
https://<account>.services.ai.azure.com/api/projects/<project>Every direct-code REST call must use:
Foundry-Features: CodeAgents=V1Preview,HostedAgents=V1PreviewThis includes create/update/create-version, version polling, version listing, code download, and delete calls.
Get the token for this resource. Do not use the Cognitive Services token resource for direct-code REST calls:
https://ai.azure.comDirect-code REST caller prerequisite: the signed-in user or service principal must have Azure AI User or a higher role on the Foundry project.
Global direct-code limits:
- Agent name: at most 63 characters, alphanumeric and hyphens only.
- Multipart upload zip: at most 250 MB.
- CPU/memory: use conservative defaults such as
0.5CPU and1Giwhen the project does not specify resources.
Task 2: Detect Runtime and Entry Point
Scan only the selected agent root.
| Project Type | Detection | Runtime | Entry point |
|---|---|---|---|
| Python | main.py plus requirements.txt | python_3_13 or python_3_14 | ["python", "main.py"] |
| C#/.NET | exactly one *.csproj or user-selected project file | dotnet_8, dotnet_9, or dotnet_10 | ["dotnet", "<AssemblyName>.dll"] |
For Python, prefer a supported runtime explicitly declared in agent.yaml/agent.manifest.yaml or provided by the user. If none is declared, use python_3_13. Do not use python_3_11 or python_3_12 for this preview path; if a manifest declares either one, warn and choose python_3_13 unless the user selects another supported runtime.
For .NET, derive the runtime from the project TargetFramework:
| TargetFramework | Runtime |
|---|---|
net8.0 | dotnet_8 |
net9.0 | dotnet_9 |
net10.0 | dotnet_10 |
If the target framework is missing or does not map to a supported runtime, ask instead of guessing.
For .NET, derive <AssemblyName> from <AssemblyName> in the .csproj when present; otherwise use the .csproj file stem. Never use ["dotnet", "run", ...] for direct code deployment. The runtime environment has the .NET runtime, not the SDK, and dotnet run fails with No .NET SDKs were found.
Task 3: Collect Direct-Code Configuration
Ask only for values not already resolved:
projectEndpointagentName- preferagent.yamloragent.manifest.yamlname, then folder name- model deployment environment variable, usually
AZURE_AI_MODEL_DEPLOYMENT_NAME - CPU and memory - prefer
agent.yamlresources, otherwise use conservative defaults (0.5CPU,1Gimemory) - protocol/version - prefer
agent.yamlprotocols, otherwiseresponses1.0.0
Do not put FOUNDRY_PROJECT_ENDPOINT in environment_variables; the platform injects it for hosted agents. Include only custom variables that the agent code reads at runtime, such as AZURE_AI_MODEL_DEPLOYMENT_NAME.
Dependency Packaging Mode
Use remote dependency packaging by default (dependency_resolution: "remote_build" in metadata.json). In this mode, upload source files plus dependency manifests such as requirements.txt or .csproj; Foundry installs dependencies during the remote build.
Use bundled local dependencies only when the user explicitly asks for it. In bundled mode, package Linux-compatible dependencies that match the selected runtime.
For remote packaging, keep the user's dependency files unchanged. Do not slim, pin, or remove packages just to make deployment smoother. If the service fails while installing dependencies, report the exact error and ask before changing dependencies.
Task 4: Create metadata.json
Create the parent directory and write .foundry/direct-code/metadata.json. Do not write metadata.json before the parent directory exists.
Use the user's platform or language tooling. For example, Python works consistently across common shells:
from pathlib import Path
metadata = Path(".foundry/direct-code/metadata.json")
metadata.parent.mkdir(parents=True, exist_ok=True)
# Build the JSON object, then write it to metadata.Example Python metadata:
{
"description": "Direct code deployment hosted agent",
"definition": {
"kind": "hosted",
"protocol_versions": [
{
"protocol": "responses",
"version": "1.0.0"
}
],
"cpu": "0.5",
"memory": "1Gi",
"environment_variables": {
"AZURE_AI_MODEL_DEPLOYMENT_NAME": "<model-deployment>"
},
"code_configuration": {
"runtime": "python_3_13",
"entry_point": ["python", "main.py"],
"dependency_resolution": "remote_build"
}
}
}Example C#/.NET metadata:
{
"description": "Direct code deployment C# hosted agent",
"definition": {
"kind": "hosted",
"protocol_versions": [
{
"protocol": "responses",
"version": "1.0.0"
}
],
"cpu": "0.5",
"memory": "1Gi",
"environment_variables": {
"AZURE_AI_MODEL_DEPLOYMENT_NAME": "<model-deployment>"
},
"code_configuration": {
"runtime": "dotnet_10",
"entry_point": ["dotnet", "<AssemblyName>.dll"],
"dependency_resolution": "remote_build"
}
}
}Task 5: Create a Flat Code Zip
The zip must be flat at the root. Do not include a top-level wrapper folder such as my-agent/. The entry point path in metadata.json must resolve from the zip root.
Before upload, inspect the archive entries and verify the required files are at the zip root. A wrapper folder, raw wheel files, Windows binaries, or a published output nested under publish/ will usually fail at version build or session startup.
Exclude local/development artifacts:
.env
.foundry/
.git/
.vscode/
.venv/
__pycache__/
bin/
obj/
Dockerfile
.dockerignore
docker-compose.yml
Properties/launchSettings.jsonRemote Packaging (Default)
The examples below use Python's zipfile module so they work across common shells and operating systems. Use equivalent platform zip tooling if Python is unavailable.
Python remote-packaging zip should include main.py, requirements.txt, and any imported local source modules/packages needed by the entry point. Do not include packages/; the service installs dependencies from requirements.txt.
from pathlib import Path
from zipfile import ZipFile, ZIP_DEFLATED
zip_path = Path(".foundry/direct-code/agent-code.zip")
zip_path.parent.mkdir(parents=True, exist_ok=True)
files = ["main.py", "requirements.txt"]
with ZipFile(zip_path, "w", ZIP_DEFLATED) as zf:
for name in files:
path = Path(name)
if path.exists():
zf.write(path, name)C#/.NET remote-packaging zip should include the project file, source files, and appsettings files. Do not include bin/, obj/, .env, Docker assets, or local launch settings. The .csproj TargetFramework must match the selected dotnet_* runtime.
from pathlib import Path
from zipfile import ZipFile, ZIP_DEFLATED
zip_path = Path(".foundry/direct-code/agent-code.zip")
zip_path.parent.mkdir(parents=True, exist_ok=True)
files = ["StorytellerAgent.csproj", "Program.cs", "appsettings.json", "appsettings.Development.json"]
with ZipFile(zip_path, "w", ZIP_DEFLATED) as zf:
for name in files:
path = Path(name)
if path.exists():
zf.write(path, name)Bundled Local Dependencies (Only When Requested)
Bundled Python zip should include main.py, requirements.txt, and a packages/ directory containing extracted Linux-compatible modules. Do not include raw .whl files, Windows .pyd/.dll binaries, or packages built without the target Linux platform flags.
python -m pip install -r requirements.txt --target packages --platform manylinux2014_x86_64 --python-version 3.13 --implementation cp --only-binary=:all:Match --python-version to the selected python_* runtime and avoid Windows binaries.
Bundled .NET zip is the output of dotnet publish -c Release -r linux-x64 --self-contained false, rooted directly at the publish output. It should contain <AssemblyName>.dll, <AssemblyName>.runtimeconfig.json, and the rest of the publish output at the zip root, not inside a publish/ wrapper folder.
dotnet publish -c Release -r linux-x64 --self-contained false -o publishThen create the zip from the publish output:
from pathlib import Path
from zipfile import ZipFile, ZIP_DEFLATED
root = Path("publish")
zip_path = Path(".foundry/direct-code/agent-code.zip")
zip_path.parent.mkdir(parents=True, exist_ok=True)
with ZipFile(zip_path, "w", ZIP_DEFLATED) as zf:
for path in root.rglob("*"):
if path.is_file():
zf.write(path, path.relative_to(root).as_posix())Task 6: Upload Code and Create or Update the Agent
Use the user's current platform and shell syntax. The examples below use literal placeholders and can be translated to any shell or HTTP client. Always keep ?api-version=... in the final request URL.
Resolve these values:
<project-endpoint><agent-name><metadata-json>- usually.foundry/direct-code/metadata.json<code-zip>- usually.foundry/direct-code/agent-code.zip<access-token>- fromaz account get-access-token --resource https://ai.azure.com --query accessToken -o tsv<code-sha256>- SHA-256 of the zip file
Calculate the zip SHA-256 with any platform tool. Python example:
import hashlib
from pathlib import Path
with Path(".foundry/direct-code/agent-code.zip").open("rb") as f:
print(hashlib.sha256(f.read()).hexdigest())Use <project-endpoint> as the base URL. Append paths directly to that project endpoint; do not strip /api/projects/<project> from it.
Direct-code deployment uses these REST operations:
| Purpose | Method and endpoint | When to use |
|---|---|---|
| Check whether the agent exists | GET <project-endpoint>/agents/<agent-name>?api-version=2025-11-15-preview | Run first. 404 means create the agent; 200 means deploy a new version by default |
| Create a new agent | POST <project-endpoint>/agents?api-version=2025-11-15-preview | Use only when the existence check returned 404 |
| Create a new version for an existing agent | POST <project-endpoint>/agents/<agent-name>/versions?api-version=2025-11-15-preview | Default path when the agent already exists |
| Update an existing agent in place | POST <project-endpoint>/agents/<agent-name>?api-version=2025-11-15-preview | Use only when the user explicitly asks for an in-place update |
If any GET/POST returns Missing required query parameter: api-version, the request URL was malformed. Fix the URL construction and retry the same REST call before continuing; do not interpret that response as "agent exists", "agent missing", or a version/build problem.
All write requests use multipart/form-data with:
metadata: the JSON metadata file, content typeapplication/jsoncode: the flat zip file, content typeapplication/zip, withfilename=<agent-name>.zipx-ms-code-zip-sha256: SHA-256 of the zip file
Create-agent request shape:
POST <project-endpoint>/agents?api-version=2025-11-15-preview
Authorization: Bearer <access-token>
Accept: application/json
Foundry-Features: CodeAgents=V1Preview,HostedAgents=V1Preview
x-ms-agent-name: <agent-name>
x-ms-code-zip-sha256: <code-sha256>
Content-Type: multipart/form-data
metadata=<metadata-json file>; type=application/json
code=<code-zip file>; type=application/zip; filename=<agent-name>.zipCreate-version request shape:
POST <project-endpoint>/agents/<agent-name>/versions?api-version=2025-11-15-preview
Authorization: Bearer <access-token>
Accept: application/json
Foundry-Features: CodeAgents=V1Preview,HostedAgents=V1Preview
x-ms-code-zip-sha256: <code-sha256>
Content-Type: multipart/form-data
metadata=<metadata-json file>; type=application/json
code=<code-zip file>; type=application/zip; filename=<agent-name>.zipDo not send x-ms-agent-name on POST /agents/<agent-name>/versions or POST /agents/<agent-name>. Send it only on POST /agents because the agent name is not in that route.
Update agent and create version are idempotent on zip SHA-256 plus agent definition. If both are unchanged from the latest version, the service can return the existing version instead of creating a duplicate. To force a new version, change the zip contents or definition.
Other useful REST operations:
| Purpose | Method and endpoint | Notes |
|---|---|---|
| List versions | GET <project-endpoint>/agents/<agent-name>/versions?api-version=2025-11-15-preview | Use when the write response does not clearly return a version |
| Download code | GET <project-endpoint>/agents/<agent-name>/code:download?api-version=2025-11-15-preview | Add agent_version=<n> when downloading a specific version; compare the x-ms-code-zip-sha256 response header with the local SHA |
| Delete agent | DELETE <project-endpoint>/agents/<agent-name>?api-version=2025-11-15-preview | Deletes the agent and all versions; pull logs before deletion if needed |
Task 7: Poll Version Status
Use the version from the create/version response. If the response does not clearly include it, list versions and pick the newest version returned for the agent.
GET <project-endpoint>/agents/<agent-name>/versions/<version>?api-version=2025-11-15-preview
Authorization: Bearer <access-token>
Foundry-Features: CodeAgents=V1Preview,HostedAgents=V1PreviewLoop until the version status is no longer creating.
active-> proceed directly back to deploy.md Step 7: Test the Agent.failed-> read the error from the version object. There is no runtime session yet, so:logstreamwill not help.