name: quickstart description: Start one NVIDIA Content Agents REST service locally with Docker Compose. Use when the user asks for /quickstart, local POC setup, or single-service Material, Physics, and Texture startup. version: "0.1.0" author: NVIDIA Content Agents tags: - content-agents - quickstart - docker - local-deploy tools: - Shell - Docker - curl - Filesystem compatibility: Requires Docker daemon, Docker Compose v2.24+, curl, and repo-root .env provider credentials.
Content Agents Quickstart
When to Use
- Use when the user asks for
/quickstartor help starting a local Content Agents proof of concept. - Use when the user wants exactly one Material, Physics, or Texture REST service from this repository's compose files.
- Use when the user needs a safe preflight, startup, health-check, and follow-up-command handoff for a local service.
Scope
This skill starts one local Content Agents REST service from the repo root. It is a thin wrapper over the existing per-agent Docker Compose files; do not create a new compose stack for this workflow. Material Agent is the recommended first POC.
- Start one target at a time:
material,physics, ortexture. - Use
deploy-collectionwhen the user wants to run Material, Physics, and Texture together or configure shared dependency endpoints. - Use the service-specific deploy skills for local NIM sidecars, image-gen sidecars, embedding sidecars, multi-GPU layouts, or deliberate port changes.
Limitations
- Keep secrets out of chat. Tell the user to edit
.env; never ask them to paste API keys. - Always use the repo-root
.envfile and keep--env-file .envin compose commands. - Stop before startup when
.envwas just created or is missing. The user must edit provider credentials before any compose command starts services. - Do not create a new compose stack for this workflow.
- Do not hold the Shell tool in long build or warm-up loops. Start detached, run only a short bounded health pass, and return clear follow-up commands when the service is still building or warming.
Instructions
- Infer the target from the user request, or ask for
material,physics, ortexturewhen unclear. - Check prerequisites and create
.envfrom.env_exampleonly when the template exists. - Run the preflight commands and stop before startup when Docker, Compose,
.env, required GPU/toolkit checks, or running-container conflicts are not resolved. - Start only after conflicts are resolved by stopping the owning stack or by restarting the selected target. If the user keeps an overlapping stack running, skip startup for the new target.
- Start the selected compose stack with the matching prefix from the target table. Use a background handoff for first builds or any shell tool with a short timeout budget.
- Run one short bounded health pass, including OVRTX for Material or Physics.
- Return the service URL, docs URL, startup state, health result, and exact follow-up commands from the output format.
Prerequisites
- Docker daemon reachable.
- Docker Compose v2.24+.
- Repo-root
.envwith the provider key for the selected backend. The default public backend usually needsNVIDIA_API_KEY. - Material and Physics require an RTX-capable NVIDIA render GPU plus NVIDIA Container Toolkit because their compose files start OVRTX.
- Recommended render-GPU capacity: Material is a 48 GB-class target and Physics is a 16 GB-class target. Smaller RTX GPUs, including 24 GB or 32 GB cards, may still be valid for small-scene POCs; warn the user and ask before proceeding rather than blocking solely on VRAM.
- A100, H100, H200, and V100 are model-serving GPUs, not render-GPU targets for this quickstart. Texture can run CPU-only with hosted backends.
If .env is missing, create it only when the template exists:
if [ -f .env ]; then
echo "ENV_FILE=present"
elif [ -f .env_example ]; then
cp .env_example .env
echo "ENV_FILE=created; edit .env with one provider key before starting"
else
echo "ENV_FILE=missing; create .env manually with provider keys"
fi
Treat ENV_FILE=created and ENV_FILE=missing as hard stops. Tell the user to
edit the repo-root .env, then rerun this quickstart after credentials are in
place.
Preflight
Run this from the repo root and parse the KEY=VALUE lines:
if command -v docker >/dev/null 2>&1 && docker info >/dev/null 2>&1; then
echo "DOCKER=ok"
else
echo "DOCKER=missing_or_unreachable"
fi
if docker compose version >/dev/null 2>&1; then
compose_version="$(docker compose version --short 2>/dev/null)"
compose_version="${compose_version#v}"
compose_major="${compose_version%%.*}"
compose_rest="${compose_version#*.}"
compose_minor="${compose_rest%%.*}"
if ! [ "$compose_major" -eq "$compose_major" ] 2>/dev/null || ! [ "$compose_minor" -eq "$compose_minor" ] 2>/dev/null; then
echo "COMPOSE=unparseable (${compose_version}; need 2.24+)"
elif [ "$compose_major" -gt 2 ] 2>/dev/null || { [ "$compose_major" -eq 2 ] 2>/dev/null && [ "$compose_minor" -ge 24 ] 2>/dev/null; }; then
echo "COMPOSE=ok (${compose_version})"
else
echo "COMPOSE=too_old (${compose_version}; need 2.24+)"
fi
elif command -v docker-compose >/dev/null 2>&1; then
echo "COMPOSE=legacy_v1"
else
echo "COMPOSE=missing"
fi
if nvidia-smi >/dev/null 2>&1; then
gpu_mem_mib="$(nvidia-smi --query-gpu=memory.total --format=csv,noheader,nounits 2>/dev/null | awk 'BEGIN { max = 0 } $1 + 0 > max { max = $1 + 0 } END { if (max > 0) printf "%.0f", max }')"
gpu_names="$(nvidia-smi --query-gpu=name --format=csv,noheader 2>/dev/null | paste -sd '|' -)"
echo "GPU=yes"
echo "GPU_VRAM_MIB_MAX=${gpu_mem_mib:-unknown}"
echo "GPU_NAMES=${gpu_names:-unknown}"
if docker info --format '{{json .Runtimes}}' 2>/dev/null | grep -q '"nvidia"'; then
echo "CONTAINER_TOOLKIT=ok"
elif command -v nvidia-container-cli >/dev/null 2>&1 || command -v nvidia-container-runtime >/dev/null 2>&1; then
echo "CONTAINER_TOOLKIT=installed_not_registered"
else
echo "CONTAINER_TOOLKIT=missing"
fi
else
echo "GPU=no"
echo "GPU_VRAM_MIB_MAX=0"
echo "GPU_NAMES=none"
echo "CONTAINER_TOOLKIT=skipped"
fi
echo "RUNNING_CONTAINERS=$(docker ps --format '{{.Names}}' 2>/dev/null | grep -E '^(material-agent-service|physics-agent-service|texture-agent-service|ovrtx-rendering-api|physics-ovrtx-rendering-api|ovrtx_rendering_api-ovrtx-rendering-api-1|vlm-nim|llm-nim|image-gen-nim)$' | paste -sd ',' -)"
Stop before startup when Docker or Compose is not ready. For Material or
Physics, also stop when there is no NVIDIA GPU, the NVIDIA Container Toolkit is
missing or not registered, or GPU_NAMES contains A100, H100, H200, or V100.
If VRAM is unknown or below the recommended capacity, warn the user and ask
whether to continue with a small-scene POC.
If RUNNING_CONTAINERS is non-empty, ask whether to stop the owning stack or
restart the selected target. Ports overlap across the per-agent compose files;
do not start a new target while overlapping containers continue to bind those
ports. If the user chooses to leave the existing stack running, skip startup and
report the existing-stack state.
Target Table
| Target | Prefix | Base URL | Health | Docs |
|---|---|---|---|---|
| Material | docker compose --env-file .env -f apps/material_agent_service/docker-compose.yml |
http://localhost:8000 |
http://localhost:8000/health |
http://localhost:8000/docs |
| Physics | docker compose --env-file .env -f apps/physics_agent_service/docker-compose.yml |
http://localhost:8000 |
http://localhost:8000/health |
http://localhost:8000/docs |
| Texture | docker compose --env-file .env -f apps/texture_agent_service/docker-compose.yml |
http://localhost:8001 |
http://localhost:8001/health |
http://localhost:8001/docs |
Infer the target from the user request. If unclear, ask:
Which agent should I start: material (recommended), physics, or texture?
Start
Show a concise summary, then start the selected prefix.
Use the foreground form only when the images are already built or the Shell tool timeout is known to be long enough for the first build:
<PREFIX> up -d --build
For first builds or short Shell tool timeouts, hand off the compose build in the
background and return immediately. Store transient logs under logs/quickstart
because that path is already ignored by git.
STARTUP_ROOT="logs/quickstart/<target>"
STARTUP_DIR="$STARTUP_ROOT/$(date +%Y%m%d-%H%M%S)"
STARTUP_LOG="$STARTUP_DIR/compose.log"
STARTUP_PID="$STARTUP_DIR/compose.pid"
STARTUP_LATEST="$STARTUP_ROOT/latest"
mkdir -p "$STARTUP_DIR" || { echo "STARTUP=blocked; cannot create $STARTUP_DIR"; exit 1; }
printf '%s\n' "$STARTUP_DIR" > "$STARTUP_LATEST" || { echo "STARTUP=blocked; cannot write $STARTUP_LATEST"; exit 1; }
nohup sh -c '<PREFIX> up -d --build' > "$STARTUP_LOG" 2>&1 &
pid="$!"
printf '%s\n' "$pid" > "$STARTUP_PID" || { echo "STARTUP=blocked; cannot write $STARTUP_PID"; exit 1; }
disown "$pid" 2>/dev/null || true
echo "STARTUP=background pid=$pid log=$STARTUP_LOG"
First build can take around 10 minutes. Material and Physics can take several more minutes while OVRTX warms up. Do not wait through that whole period inside one Shell tool call.
Check
Run a short bounded check. If a background build is still running, report
STARTUP=building and return the log command instead of blocking.
<PREFIX> ps
STARTUP_ROOT="logs/quickstart/<target>"
STARTUP_LATEST="$STARTUP_ROOT/latest"
STARTUP_DIR="$(cat "$STARTUP_LATEST" 2>/dev/null || true)"
if [ -z "$STARTUP_DIR" ] || [ ! -d "$STARTUP_DIR" ]; then
STARTUP_DIR="$(find "$STARTUP_ROOT" -mindepth 1 -maxdepth 1 -type d 2>/dev/null | sort | tail -n 1)"
fi
STARTUP_LOG="${STARTUP_DIR:+$STARTUP_DIR/compose.log}"
# STARTUP_PID is the PID-file path; pid below is the running process ID.
STARTUP_PID="${STARTUP_DIR:+$STARTUP_DIR/compose.pid}"
if [ -n "$STARTUP_PID" ] && [ -f "$STARTUP_PID" ]; then
pid="$(cat "$STARTUP_PID" 2>/dev/null || true)"
if [ -n "$pid" ] && kill -0 "$pid" 2>/dev/null; then
echo "STARTUP=building pid=$pid log=$STARTUP_LOG"
echo "LOG_COMMAND=tail -f $STARTUP_LOG"
exit 0
fi
fi
healthy=no
for i in 1 2 3 4 5 6; do
if curl -fsS --max-time 5 <HEALTH_URL>; then
healthy=yes
break
fi
sleep 10
done
if [ "$healthy" = yes ]; then
echo "SERVICE_HEALTH=healthy"
else
echo "SERVICE_HEALTH=starting_or_unhealthy"
if [ -s "$STARTUP_LOG" ]; then
echo "STARTUP_LOG=$STARTUP_LOG"
tail -n 80 "$STARTUP_LOG"
fi
<PREFIX> logs --no-color --tail=80 || true
fi
For Material or Physics, also run a bounded OVRTX check. If it is not healthy
yet, report it as warming unless logs show a clear error. OVRTX and Texture both
use port 8001; if Texture owns that port, report a port conflict instead of
counting http://localhost:8001/health as healthy for OVRTX.
ovrtx=warming
ovrtx_body=""
for i in 1 2 3 4 5 6; do
ovrtx_body="$(curl -fsS --max-time 5 http://localhost:8001/health 2>/dev/null || true)"
if printf '%s\n' "$ovrtx_body" | grep -Eq '"gpu_initialized"[[:space:]]*:[[:space:]]*true'; then
ovrtx=healthy
break
fi
sleep 10
done
echo "OVRTX_HEALTH=$ovrtx"
if [ "$ovrtx" != healthy ] && [ -n "$ovrtx_body" ]; then
echo "OVRTX_HEALTH_BODY=$ovrtx_body"
fi
Output Format
Report a concise summary with:
- Selected target and compose prefix.
- Service URL and docs URL.
- Startup state:
blocked,not_started,background_building,warming,healthy, orunhealthy. - Health result, including OVRTX health for Material or Physics.
- Any blocker found during preflight, including
.envcreation or unresolved port conflicts. - Log file path or log command when startup is still building or warming.
Then return these follow-up commands:
<PREFIX> logs -f
<PREFIX> ps
<PREFIX> down
<PREFIX> down -v
When stopping a stack that was already running, use the compose file that owns the running container. If ownership is ambiguous, inspect:
docker inspect --format '{{ index .Config.Labels "com.docker.compose.project.config_files" }}' <container-name>
Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
DOCKER=missing_or_unreachable |
Docker is not installed, not running, or not reachable by the current user. | Stop and ask the user to start Docker or fix daemon access before retrying. |
COMPOSE=too_old or COMPOSE=legacy_v1 |
Docker Compose is older than v2.24 or only legacy docker-compose is installed. |
Ask the user to install Docker Compose v2.24+ and rerun preflight. |
ENV_FILE=created or ENV_FILE=missing |
The repo-root .env still needs provider credentials. |
Stop startup, tell the user to edit .env, then rerun this skill. |
| Material or Physics reports no GPU/toolkit | The selected target needs the local render stack from Prerequisites. | Stop startup and explain that Texture can run CPU-only with hosted backends. |
| Material or Physics reports low or unknown VRAM | Small-scene POCs may work, but the target is below recommended capacity. | Warn the user and ask before continuing; do not block solely on VRAM. |
| Service health stays unhealthy after the short check | The service is still building, warming, or a dependency is misconfigured. | Report the current state and show <PREFIX> ps, curl -fsS <HEALTH_URL>, and <PREFIX> logs --no-color --tail=80. |
| OVRTX is not immediately healthy | OVRTX can warm up after the service process starts. | Report OVRTX_HEALTH=warming and provide the logs command unless logs show a clear failure. |
| Texture is running while checking Material or Physics OVRTX | Texture and OVRTX both use port 8001. | Report the port owner conflict instead of counting http://localhost:8001/health as OVRTX healthy. |
| Ports conflict with another stack | The per-agent compose files share ports. | Stop or restart the owning stack before starting the new target; if the user leaves it running, skip startup. |