Hello World
This tutorial walks you through a minimal Hello World application, covering the complete lifecycle of an NE503 container application: write application β build ARM64 image β upload and deploy β start β verify in Web Console β view logs β clean up. Once you master this minimal closed loop, you can rapidly iterate on any AI application.
Hello World does not depend on the AI SDK β it simply prints a counter in a loop, making it ideal for verifying that the development environment and deployment pipeline are working end to end.
1. Prerequisitesβ
| Condition | Verification |
|---|---|
| NE503 device is online and running | Visit http://<device-ip>:8080 in a browser; the Web login page should appear |
| Docker is installed on the development machine | Run docker --version in a terminal; version >= 20.10 |
| Development machine can ping the device | curl -o /dev/null -w "%{http_code}" http://<device-ip>:8080 returns 200 |
| Know the device login credentials | Web Console default is admin / password (change after first login) |
The NE503 device is ARM64 architecture. If your development machine is Apple Silicon (M-series), it is also ARM64, so you can build natively at full speed. On an x86 machine, Docker buildx will automatically use QEMU emulation β slightly slower but fully functional.
2. Application Structureβ
The Hello World application consists of three files (full source in the repository at apps/hello-world/):
hello-world/
βββ app.py # Application main logic
βββ app.yaml # Application manifest (resources / permissions / configuration)
βββ Dockerfile # Container build definition
app.py -- Pure Python, prints a counter in a loop and responds to SIGTERM for graceful shutdown (the platform sends SIGTERM when stopping an application):
import os, time, signal
class HelloWorldApp:
def __init__(self):
self.running = True
self.app_id = os.environ.get("APP_ID", "hello_world") # platform injects
self.counter = 0
signal.signal(signal.SIGTERM, self._signal_handler)
def _signal_handler(self, signum, frame):
self.running = False
def run(self):
while self.running:
self.counter += 1
print(f"[{time.strftime('%Y-%m-%d %H:%M:%S')}] #{self.counter:06d} - Hello World from AIPC!")
time.sleep(1)
if __name__ == "__main__":
HelloWorldApp().run()
app.yaml -- Application manifest, declaring the image, resource limits, and startup policy (Hello World does not require any permissions):
apiVersion: v1
kind: Application
metadata:
id: hello-world
name: Hello World
version: 1.0.0
description: A simple hello world application that prints continuously
spec:
image: aipc/hello-world:1.0.0 # must match the tag from docker build -t
resources:
cpu: "10%"
memory: "32Mi"
autostart: false
restart_policy: on-failure
restart_max_retries: 3
Dockerfile -- Based on python:3.11-alpine, lightweight:
FROM python:3.11-alpine3.19
WORKDIR /app
COPY app.py /app/app.py
ENV PYTHONUNBUFFERED=1
ENV APP_ID=hello_world
CMD ["python3", "/app/app.py"]
3. Building the Imageβ
Build the ARM64 image in the application directory, export it as a tar, then package it into a .aipc installation package:
cd apps/hello-world
# 1. Build ARM64 image (--load imports into local Docker)
docker buildx build --platform linux/arm64 --load -t aipc/hello-world:1.0.0 .
# 2. Export image as tar
docker save aipc/hello-world:1.0.0 -o image.tar
# 3. Package into .aipc (zip of app.yaml + image.tar)
zip hello-world.aipc app.yaml image.tar
Build artifacts (actual):
| Artifact | Size |
|---|---|
| Docker image | 26.5 MB (113 MB disk usage) |
image.tar | 25 MB |
hello-world.aipc | 25 MB |
The
.aipcfile is simply a zip archive ofapp.yaml+image.tar, convenient for storage and distribution. Deployment to the device uses the two files inside it (image.tarandapp.yaml, see the next section); the.aipcitself is not uploaded via the API.
On macOS + Docker Desktop, apk add may occasionally report Failed to create ...: I/O error. This is a known intermittent issue with buildx -- simply run the build command again and it should succeed.
4. Deploying to the Deviceβ
After building, you have two files: app.yaml (application manifest) and image.tar (container image). Three deployment options are provided below β the Web Console is recommended (graphical UI, no SSH required).
All three options require the two separate files app.yaml and image.tar. After following the manual steps in Β§3, both files are in the app directory. If you used the repo's apps/<app>/build.sh (which deletes the intermediate image.tar after packaging .aipc), unzip it first: unzip -o <app>.aipc.
4.1 Upload via the Web Console (Recommended)β
Done entirely in the browser, no SSH login required.
-
Open the Web Console at
http://<device-ip>:8080in a browser and log in with the default credentialsadmin/password. -
Click App Management in the left sidebar to reach the app list. In the top-right corner there is an Import card β click it.
-
The Application Setup Wizard dialog opens. In the first step, Source, pick the third option, Upload Package β this accepts both the
app.yamlmanifest and the image file. -
Under App Manifest (app.yaml) click Choose File and select your local
app.yaml; under Container Image selectimage.tar.

- Click the Install button in the bottom-right corner. The wizard runs the remaining steps automatically (parse manifest β import image β register app), usually within 10β15 seconds. Back in the app list, Hello World appears (initially in Stopped state β you start it in the next section).
4.2 Deploy via aipc-cli (Alternative)β
If you have already SSH'd into the device, install in one command with the platform's built-in aipc-cli. First copy app.yaml and image.tar to the device:
scp app.yaml image.tar root@<device-ip>:/tmp/
ssh root@<device-ip>
Then on the device run:
aipc-cli app install app.yaml image.tar
4.3 Deploy via HTTP API (Alternative)β
For scripting / CI automation. This is the same installation as above broken into explicit HTTP calls: two-step upload + async install β upload the image and manifest separately, then trigger a background install task and poll for progress.
curl -F 'app=@xxx.aipc' /api/v1/apps (uploading the whole .aipc at once) no longer works (the endpoint returns a JSON parse error). Use the two-step flow below.
Login to Obtain a Tokenβ
curl -X POST http://<device-ip>:8080/api/login \
-H "Content-Type: application/json" \
-d '{"username":"admin","password":"password"}'
Response (note the token value includes the Bearer prefix):
{"code":0,"data":{"token":"Bearer aipc-secure-token-secret","username":"admin"}}
All subsequent API calls must include the Authorization: <the entire token string from above> header.
Upload Image and Manifestβ
# Upload image (field name is file)
curl -X POST http://<device-ip>:8080/api/v1/apps/upload-image \
-H "Authorization: Bearer <token>" \
-F "file=@image.tar"
# β {"data":{"path":"/opt/aipc/images/1781509627_image.tar", "image":"aipc/hello-world:1.0.0", ...}}
# Upload manifest
curl -X POST http://<device-ip>:8080/api/v1/apps/upload-manifest \
-H "Authorization: Bearer <token>" \
-F "file=@app.yaml"
# β {"data":{"path":"/opt/aipc/apps/manifests/hello-world/app.yaml", ...}}
Trigger Installation and Poll Progressβ
# Trigger async install (JSON body, passing both paths from above)
curl -X POST http://<device-ip>:8080/api/v1/apps/install-package \
-H "Authorization: Bearer <token>" -H "Content-Type: application/json" \
-d '{"manifest_path":"/opt/aipc/apps/manifests/hello-world/app.yaml",
"image_path":"/opt/aipc/images/1781509627_image.tar","force":true}'
# β {"data":{"task_id":"0f26285a"}}
# Poll installation progress (until phase=complete)
curl http://<device-ip>:8080/api/v1/apps/install-progress/<task_id> \
-H "Authorization: Bearer <token>"
Progress evolution: phase:"pulling" percent:10 "Importing local image..." β phase:"complete" percent:100 "Installation complete", typically finishing in 10-15 seconds.
5. Start and Verifyβ
5.1 Start the Applicationβ
After deployment the app is in the Stopped state β you need to start it once manually. Pick either of the two options below.
Option 1: Start via the Web Console (recommended)
Go to App Management, find the Hello World card (status shown as Stopped), and click the Start button on the card. Normally within a few seconds the status badge switches from Stopped to Running.
Option 2: Start via the HTTP API
curl -X POST http://<device-ip>:8080/api/v1/apps/hello-world/start \
-H "Authorization: Bearer <token>"
The first time you start an image, the platform needs to load it into the container runtime, which may exceed the 10-second API timeout, returning code:6002 DeadlineExceeded. This is not an error β just call the start endpoint once more (or click Start again on the Web UI) and it will succeed.
5.2 Verify in the Web Console (simulating a user's perspective)β
After deployment, log into the Web Console at http://<device-ip>:8080 with a browser and verify the application is running normally from a real user's point of view.

Log in with the default credentials admin / password to reach the Dashboard. The top of the homepage shows device status (uptime, temperature, CPU/NPU/memory/storage usage), and the Applications section in the middle shows currently running applications:

Navigate to Applications in the left sidebar -- you should see Hello World in Running status with real-time CPU and memory usage:

Click on Hello World to open the detail view, showing the application ID, version, install/start time, uptime, and Stop / Restart / Uninstall action buttons -- this confirms the application is fully managed by the platform:

5.3 View Runtime Logsβ
Application logs can also be retrieved via the API (returned in NDJSON format, one JSON object per line):
curl "http://<device-ip>:8080/api/v1/apps/hello-world/logs?max_lines=10" \
-H "Authorization: Bearer <token>"
{"timestamp":1781509897838838800,"level":"info","message":"[2026-06-15 07:51:23] #000011 - Hello World from AIPC!"}
{"timestamp":1781509897838892960,"level":"info","message":"[2026-06-15 07:51:24] #000012 - Hello World from AIPC!"}
{"timestamp":1781509897838901400,"level":"info","message":"[2026-06-15 07:51:25] #000013 - Hello World from AIPC!"}
The counter increments every second, confirming the application is running stably.
6. Stop and Clean Upβ
After verification, stop and uninstall the application:
# Stop
curl -X POST http://<device-ip>:8080/api/v1/apps/hello-world/stop -H "Authorization: Bearer <token>"
# β {"data":{"message":"App stopped successfully"}}
# Uninstall
curl -X DELETE http://<device-ip>:8080/api/v1/apps/hello-world -H "Authorization: Bearer <token>"
# β {"data":{"message":"App uninstalled successfully"}}
7. Summaryβ
Congratulations, you have completed the full closed loop for an NE503 container application:
- Write -- the
app.py+app.yaml+Dockerfiletrifecta - Build --
docker buildx build --platform linux/arm64βdocker saveβzip .aipc - Deploy -- Web Console upload (recommended) / aipc-cli / HTTP two-step upload β pick one
- Verify -- confirm Running status in Web Console + check logs to confirm output
- Clean up -- stop + uninstall
Next, in the Person Detection Application Tutorial, you will use the same flow to deploy a real AI inference application, learning how to use the SDK, discover models and video streams, and process detection results.
If you encounter errors during application deployment or startup, refer to Application Troubleshooting.