Agent guide¶
Machine-oriented repository facts and constraints.
Source-of-truth order¶
- Current
src/azure_jobs/source. - Generated
aj --helpand subcommand help. - Contract/regression tests under
tests/. pyproject.tomland workflows.- Documentation.
When they disagree, follow code/tests and update docs. Never infer availability from old examples or roadmap text.
Runtime facts¶
- Entry point:
azure_jobs.client.cli:main. - Python: 3.10+.
- Azure execution: daemon only; no in-process mode.
- Transport: HTTP over private UDS; API
/v2; schema/openapi.json. - Project scope:
X-AJ-Rootis absoluteAJ_HOME. - Client performs no Azure token acquisition, discovery command, or submission.
- Public SDK:
from azure_jobs import connect. - Services: native
aml/sing,volcano, compatibilityamlt. - Remote HTTP/TCP: not implemented.
Hard invariants¶
Layers¶
shared imports neither client nor server
sdk imports neither client nor server
client never imports server or Azure clients
server never imports client
Azure clients exist only under server
Rich/Textual exist only under client
Guard: tests/test_api_architecture.py.
Daemon¶
- No
AJ_NO_DAEMONor alternative client. - Daemon failure is actionable, never bypassed.
- Public transport does not replay requests automatically.
- Ambiguous mutations require reconciliation before caller retry.
.azure_jobs/daemon/journals may contain full queuedJobSpec.env_vars; template sync must always treat that directory as local-only.
Guard: tests/test_api_daemon_only.py.
JobSpec and backends¶
backend_spec = typed backend Opts
extra = verbatim template _extra
template = source Template for amlt rendering
shared/job/build.pynever branches on service.- Description hooks register in
shared/spec.py. - Execution functions register in
server/submit/. _extrais stripped before amlt.- Do not add strategy-specific top-level
JobSpecfields.
Guard: tests/test_backend_registry.py.
API¶
- SDK and FastAPI intentionally use direct path strings.
- Add every SDK operation to
tests/test_openapi_contract.py. - Submit/watch progress uses SSE.
- Logs use HTTP Range.
- Typed errors survive the wire.
X-AJ-Rootscopes state; UDS permissions authenticate locally.
Scripts and errors¶
- New injected script around 15+ lines: standalone resource.
- New parameterized resources use the owning
_scripts.load_script; placeholders are literal{KEY}. Existing Volcano preamble/blobfuse loaders are legacy exceptions. - Force-install pod dependencies or fail loudly.
- Broad catch calls
log.exception. - User error includes type/message and
AJ_DEBUG=1guidance. - Subprocess failure includes command, status, stdout, and stderr.
File map¶
| Change | Primary location |
|---|---|
| CLI tree/commands | client/cli/__init__.py, client/cli/ |
| Agent Skill lifecycle | client/skill_manager.py, skills/azure-jobs/ |
| Rich/JSON output | client/ui/ |
| SDK namespaces | sdk/account.py, sdk/workspace.py, sdk/logs.py |
| UDS/SSE | sdk/_transport.py |
| HTTP routes | server/app.py |
| contexts/queue/watch | server/context.py, server/queue.py, server/watch.py |
| wire adapters | server/resources.py |
| Azure HTTP | server/az_client/arm/, server/az_client/ml/ |
| template engine | shared/template/ |
| JobSpec build | shared/job/ |
| backend hooks/options | shared/spec.py, shared/opts/ |
| native submit/archive | server/submit/azureml/, server/submit/archive.py |
| Volcano | server/submit/volcano/ |
| amlt | server/submit/amlt.py, shared/job/render.py |
| TUI | client/tui/ |
Change recipes¶
New daemon capability¶
shared wire type if needed
→ server resource method
→ FastAPI route
→ SDK namespace direct path
→ OpenAPI CALLS inventory
→ CLI/TUI presentation
Never import server code from SDK/client.
New backend¶
typed Opts + from_template/load
→ register_spec(build/load/normalize)
→ daemon implementation
→ register_backend
→ backend/registry tests
Never add a service branch to shared build or client entry points.
New template field¶
backend behavior → typed backend Opts
opaque aj feature → _extra.<consumer>
amlt compatibility → raw template/render overlay
Consumer schemas do not belong in shared/job/build.py.
New Volcano uploader¶
Implement CodeUploader.prepare, keep its parser/scripts beside it, add one
literal pick_uploader branch, and test uploader plus entry flow. Keep literal
dispatch while strategy count is small.
New TUI workflow¶
Add command metadata, controller I/O, store transition, typed event, and view port. Worker threads cannot mutate bound stores directly.
Backend facts¶
Native AML/Sing:
- archive current working directory with built-in and user ignores;
- generated
aj_runner.shoverrides a matching project path; - project
.ssh/takes precedence; otherwise an optional home whitelist is added unlessAJ_SHIP_SSH=0; - deterministic tar/gzip; SHA-256 addresses one Blob at
LocalUpload/<hash>/code.tar.gz; - Azure ML downloads the archive and a content-addressed bootstrap
uri_file; - node verifies SHA-256 and extracts once through
AJ_IDlock/ready state; - process runs
bash aj_runner.sh; - no Code Asset and no per-file native upload.
Sing auto-selection:
- missing/empty
target.nameis allowed forservice: sing; - target subscription/resource group are optional VC filters;
- GPU SKUs use exact GPU count; CPU SKUs use ordered CPU size tier;
- exact accelerator/per-GPU memory when specified;
- current user and tier quota must cover capacity;
- ranking: tier, per-VC NVIDIA preference when accelerator is omitted, NVLink, remaining quota, stable coordinates;
- explicit VC uses the same matching/tier fallback.
Volcano:
kubectl-exec/PVC and Blob archive are the two upload strategies;- uploader dispatch is literal, not a registry;
- pod binaries are installed or submission fails;
- CPU-only means no GPU/RDMA unless explicit.
Verification matrix¶
| Area | Minimum tests |
|---|---|
| templates/JobSpec | test_merge_confs.py, test_read_conf.py, test_submit.py |
| backend hooks | test_backend_registry.py |
| SDK/API | test_sdk.py, test_openapi_contract.py, test_api_contract.py |
| transport | test_api_transport.py, test_api_daemon_only.py |
| native archive | test_server_submit_archive.py, test_server_azureml_bootstrap_payload.py |
| Sing | test_sing_auto_selection.py, test_sku.py, test_quota.py |
| Volcano | test_volcano_uploaders.py, test_volcano_storage.py |
| CLI JSON | test_json_audit.py plus relevant CLI test |
| Agent Skill | test_skill_manager.py, test_cli_skill.py, test_skill_assets.py |
| TUI | test_tui_architecture.py plus relevant feature test |
| docs | uv run mkdocs build --strict |
Full suite:
Coverage threshold: 95% combined line/branch.
Prohibited shortcuts¶
- In-process fallback or client-side Azure execution.
- Shared route builder that hides SDK/OpenAPI drift.
- Service branch in
shared/job/build.py. - Backend typed config in
extra;_extraparsing in shared build. - Native Azure ML Code Asset or per-file upload.
- Large inline pod scripts or assumed pod binaries.
- Flattened errors, swallowed subprocess output, or automatic mutation replay.
- TCP exposure without authentication, authorization, artifact upload, isolation, filtered SSE, explicit identity, and idempotency.
- Documentation of unimplemented behavior.