From 675c1fa4aff8c969a156e84d2cf349ffe4b1aa38 Mon Sep 17 00:00:00 2001 From: anupras-mohapatra-arm Date: Fri, 7 Aug 2026 17:27:05 -0500 Subject: [PATCH 01/12] first pass openclaw --- .../openclaw_continuum/1_architecture.md | 26 ++-- .../openclaw_continuum/2_dgx_deploy.md | 115 +++++++++--------- .../openclaw_continuum/3_household_memory.md | 38 +++--- .../openclaw_continuum/4_workflows.md | 42 ++++--- .../openclaw_continuum/5_cpu_only.md | 89 +++++++++----- .../openclaw_continuum/6_summary.md | 60 --------- .../openclaw_continuum/_index.md | 4 +- 7 files changed, 178 insertions(+), 196 deletions(-) delete mode 100644 content/learning-paths/laptops-and-desktops/openclaw_continuum/6_summary.md diff --git a/content/learning-paths/laptops-and-desktops/openclaw_continuum/1_architecture.md b/content/learning-paths/laptops-and-desktops/openclaw_continuum/1_architecture.md index 13ffb4c3c8..dbf2fd129d 100644 --- a/content/learning-paths/laptops-and-desktops/openclaw_continuum/1_architecture.md +++ b/content/learning-paths/laptops-and-desktops/openclaw_continuum/1_architecture.md @@ -1,24 +1,24 @@ --- -title: Understand the Architecture and Local Data Boundaries +title: Understand the architecture and local data boundaries weight: 2 ### FIXED, DO NOT MODIFY layout: learningpathall --- -## Transition from Inference to an Assistant +## Transition from inference to an assistant Running a local LLM gives you private text generation, but not a complete assistant. You still need an interface for questions, saved information, document searches, and reminders. -In this Learning Path, you will deploy [OpenClaw Arm Continuum](https://github.com/odincodeshen/openclaw-arm-continuum) and use it from Telegram. You will save a household note, query a local document, search the web, and schedule a notification. Inference, embeddings, documents, vector memory, and task state remain on hardware you control. +In this Learning Path, you'll deploy [OpenClaw Arm Continuum](https://github.com/odincodeshen/openclaw-arm-continuum) and use it from Telegram. You'll save a household note, query a local document, search the web, and schedule a notification. Inference, embeddings, documents, vector memory, and task state remain on hardware that you control. -Telegram is the messaging interface for this tutorial. The runtime can support another platform through a gateway that translates its messages and events. +Telegram is the messaging interface. The runtime can support another platform through a gateway that translates its messages and events. -OpenClaw provides the foundation for the assistant. The reference runtime connects it to Telegram, local generation through vLLM or llama.cpp, Ollama embeddings, Qdrant memory, browser search, and scheduled tasks. It routes each request to the relevant local service or tool. +OpenClaw provides the foundation for the assistant. The reference runtime connects it to Telegram, local generation through vLLM or `llama.cpp`, Ollama embeddings, Qdrant memory, browser search, and scheduled tasks. It routes each request to the relevant local service or tool. ## Understand the data boundary -Local-first does not mean that every byte stays offline. Telegram and web search use external services, while the core AI data remains under your control. +Local-first doesn't mean that every byte stays offline. Telegram and web search use external services, while the core AI data remains under your control. | Data or operation | Location | External interaction | |---|---|---| @@ -30,13 +30,13 @@ Local-first does not mean that every byte stays offline. Telegram and web search | External data lookup | Local skill | Public data service selected by the skill | | Browser search | Local Playwright worker | Search engine and selected public pages | -The runtime does not use a public cloud LLM API. Telegram transports bot messages, and browser searches send requests to external websites. +The runtime doesn't use a public cloud LLM API. Telegram transports bot messages, and browser searches send requests to external websites. {{% notice Note %}} -This Learning Path uses synthetic or public data. Do not enter real personal, household, or organizational information. If the host already contains personal runtime data, set the environment variables in the next chapter. +Don't enter real personal, household, or organizational information. Instead, use synthetic or public data. If the host already contains personal runtime data, set the environment variables in the next section. {{% /notice %}} -## Trace the Application Request Path +## Trace the application request path The architecture shows how Telegram requests reach local services and persistent data: @@ -53,6 +53,10 @@ Cron schedule Slash commands follow fixed routes. For example, `/search` always selects browser search, while a plain-language weather question selects the weather skill. +{{% notice Note %}} +The runtime uses a text-first architecture, fixed skill routes, and one local LLM endpoint. `AgentRegistry` and `TaskDispatcher` keep command behavior predictable. This Learning Path doesn't cover multi-model routing, multi-agent handoffs, or hardware benchmarking. +{{% /notice %}} + ## Understand the shared API contract across Arm platforms The same workflow uses an inference engine suited to each platform: @@ -60,7 +64,7 @@ The same workflow uses an inference engine suited to each platform: | Platform | Inference engine | |---|---| | NVIDIA DGX Spark | vLLM server | -| Radxa Orion O6 | llama.cpp server | +| Radxa Orion O6 | `llama.cpp` server | Both expose an OpenAI-compatible chat-completions API, so only the configured endpoint and model name change. @@ -68,4 +72,4 @@ Both expose an OpenAI-compatible chat-completions API, so only the configured en You now understand the runtime components, data boundary, and shared inference API. -Next, you will deploy the baseline runtime on NVIDIA DGX Spark. +Next, you'll deploy the baseline runtime on NVIDIA DGX Spark. diff --git a/content/learning-paths/laptops-and-desktops/openclaw_continuum/2_dgx_deploy.md b/content/learning-paths/laptops-and-desktops/openclaw_continuum/2_dgx_deploy.md index 1381718f59..0d6fce0aea 100644 --- a/content/learning-paths/laptops-and-desktops/openclaw_continuum/2_dgx_deploy.md +++ b/content/learning-paths/laptops-and-desktops/openclaw_continuum/2_dgx_deploy.md @@ -1,14 +1,12 @@ --- -title: Deploy an OpenClaw-based Reference Runtime with vLLM on DGX Spark +title: Deploy an OpenClaw-based reference runtime with vLLM on DGX Spark weight: 3 ### FIXED, DO NOT MODIFY layout: learningpathall --- -## Prepare the DGX Spark Host Environment - -DGX Spark needs Docker Engine, the Docker Compose plugin, the NVIDIA driver, and NVIDIA Container Toolkit for this section. The repository supplies the runtime and vLLM container, but you will install Ollama and Qdrant separately. +## Prepare the DGX Spark host environment Confirm that the Arm CPU and NVIDIA GPU are visible: @@ -24,7 +22,7 @@ aarch64 ``` {{% notice Note %}} -This Learning Path uses Docker Engine and Docker Compose to run its services. If Docker is not installed on your DGX Spark, follow the [Install Docker Engine](https://learn.arm.com/install-guides/docker/docker-engine/) guide before continuing. +You'll use Docker Engine and Docker Compose to run services on your DGX Spark. For Docker installation steps, see the [Install Docker Engine](https://learn.arm.com/install-guides/docker/docker-engine/). {{% /notice %}} Confirm Docker GPU access: @@ -33,11 +31,13 @@ Confirm Docker GPU access: docker run --rm --gpus all ubuntu nvidia-smi ``` -You do not need to install the vLLM Python package or start a vLLM server directly on the DGX Spark host. The project's `compose.yaml` pulls a container image that already includes vLLM and starts the local inference server for you. The NVIDIA driver and NVIDIA Container Toolkit are still required so that this container can access the GPU. +You don't need to install the vLLM Python package or start a vLLM server directly on the DGX Spark host. The project's `compose.yaml` pulls a container image that already includes vLLM and starts the local inference server for you. + +You do need to install the NVIDIA driver and NVIDIA Container Toolkit so that this container can access the GPU. -## Configure Ollama for Local Embeddings +## Configure Ollama for local embeddings -Unlike vLLM, Ollama is not included as a service in the project's `compose.yaml`. Install and run Ollama separately on the DGX Spark host before starting the reference runtime. +Unlike vLLM, Ollama isn't included as a service in the project's `compose.yaml`. Install and run Ollama separately on the DGX Spark host before starting the reference runtime. Install Ollama using the [official Linux installer](https://docs.ollama.com/linux): @@ -45,7 +45,7 @@ Install Ollama using the [official Linux installer](https://docs.ollama.com/linu curl -fsSL https://ollama.com/install.sh | sh ``` -The project containers connect to Ollama through the Docker host gateway. Create a systemd override that configures Ollama to listen on the host interfaces: +The project containers connect to Ollama through the Docker host gateway. Create a `systemd` override that configures Ollama to listen on the host interfaces: ```bash sudo install -d -m 0755 /etc/systemd/system/ollama.service.d @@ -75,7 +75,7 @@ sudo systemctl enable --now ollama sudo systemctl restart ollama ``` -Pull the embedding model used by this Learning Path: +Pull the embedding model that you'll use: ```bash ollama pull nomic-embed-text @@ -87,7 +87,7 @@ Confirm that Ollama lists the model: curl http://127.0.0.1:11434/api/tags ``` -The response should include these fields: +The output is similar to: ```output { @@ -100,7 +100,7 @@ The response should include these fields: } ``` -## Start Qdrant for Persistent Vector Storage +## Start Qdrant for persistent vector storage Create a Docker volume so that vector data remains available when the Qdrant container is replaced: @@ -132,7 +132,7 @@ Confirm that the Qdrant API responds: curl http://127.0.0.1:6333/collections ``` -Before the reference runtime creates its collections, the response is similar to: +The output is similar to: ```output { @@ -141,15 +141,15 @@ Before the reference runtime creates its collections, the response is similar to } ``` -The empty list is expected. The runtime creates collections when you save or ingest content. +The empty list is expected at this stage before the reference runtime creates its collections. The runtime creates collections when you save or ingest content. {{% notice Warning %}} The project containers need access to Ollama and Qdrant. Restrict ports `11434`, `6333`, and `6334` to the host and its Docker networks. {{% /notice %}} -## Clone the Reference Repository +## Clone the reference repository -Clone the repository and check out the release used by this Learning Path: +Clone the repository and check out the release that you'll use: ```bash git clone https://github.com/odincodeshen/openclaw-arm-continuum.git @@ -161,7 +161,7 @@ The tag fixes the tutorial source version. Unversioned container images and mode ## Configure the Telegram bot environment variables -You need a Telegram account, a bot token, and the numeric chat ID for the account that will use the bot. Create a Telegram account if you do not already have one. You can use the Telegram desktop, mobile, or web client for the following steps. +You need a Telegram account, a bot token, and the numeric chat ID for the account that will use the bot. Create a Telegram account if you don't already have one. You can use the Telegram desktop, mobile, or web client for the following steps. To create a bot and obtain its token: @@ -173,9 +173,9 @@ To create a bot and obtain its token: ``` 3. Follow BotFather's prompts to name the bot and choose a username. -4. Copy the HTTP API token that BotFather returns. You will add it to the `.env` file later. +4. Copy the HTTP API token that BotFather returns. You'll add it to the `.env` file later. -See the official [Telegram Bot tutorial](https://core.telegram.org/bots/tutorial) for more information about creating and managing bots. +For more information about creating and managing bots, see the official [Telegram Bot tutorial](https://core.telegram.org/bots/tutorial). Next, obtain the chat ID for your Telegram account: @@ -186,29 +186,28 @@ Next, obtain the chat ID for your Telegram account: curl "https://api.telegram.org/bot/getUpdates" ``` -The output is similar to: + The output is similar to: -```output -{ - "ok": true, - "result": [ + ```output { - "update_id": (...), - "message": { - (...) - }, - "chat": { - (...) - }, - "date": (...), - "text": "Hello" - } + "ok": true, + "result": [ + { + "update_id": (...), + "message": { + (...) + }, + "chat": { + (...) + }, + "date": (...), + "text": "Hello" + } + ] } - ] -} -``` + ``` -Copy the `message.chat.id` value. You will use this value for `` in the `.env` file. If the `result` array is empty, send another message to the bot and run the command again. +Copy the `message.chat.id` value. You'll use this value for `` in the `.env` file. If the `result` array is empty, send another message to the bot and run the command again. Copy the DGX Spark environment template: @@ -235,16 +234,18 @@ OPENCLAW_CRON_CHAT_IDS= OPENCLAW_GATEWAY_TOKEN= ``` -Set `OPENCLAW_CRON_TIMEZONE` to your local [IANA timezone](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones). Scheduled jobs use UTC when this setting is omitted: +Set `OPENCLAW_CRON_TIMEZONE` to your local [IANA timezone](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones). For example, use `Europe/London`, `America/New_York`, or `Asia/Singapore`: ```text OPENCLAW_CRON_TIMEZONE= ``` -For example, use `Europe/London`, `America/New_York`, or `Asia/Singapore`. Weather questions in this Learning Path name their location explicitly, so you do not need to configure `OPENCLAW_DEFAULT_WEATHER_LOCATION`. +Scheduled jobs use UTC when this setting is omitted. + +You'll name the location explicitly when asking weather-related, so you don't need to configure `OPENCLAW_DEFAULT_WEATHER_LOCATION`. {{% notice Note %}} -Do not share your Telegram bot token or chat ID with anyone, and do not include them in screenshots, logs, or public repositories. +Don't share your Telegram bot token or chat ID with anyone, and don't include them in screenshots, logs, or public repositories. {{% /notice %}} Only allowlisted chat IDs can send commands to this runtime. @@ -256,10 +257,10 @@ personal_tracker_memory personal_knowledge_base ``` -You do not need to add collection settings to `.env` for this default path. Use only the synthetic data provided in the exercises. +You don't need to add collection settings to `.env` for this default path. Use only the synthetic data provided in the exercises. {{% notice Note %}} -If this host already contains personal runtime data, or if you are preparing a public demonstration, add the following optional settings to `.env` to isolate the tutorial data: +If this host already contains personal runtime data, or if you're preparing a public demonstration, add the following optional settings to `.env` to isolate the tutorial data: ```text OPENCLAW_TRACKER_COLLECTION=demo_tracker_memory @@ -270,14 +271,14 @@ OPENCLAW_RUNTIME_LABEL=DGX Spark Demo If you choose this option, replace the `personal_*` collection names in later verification commands with the corresponding `demo_*` names. {{% /notice %}} -The DGX model used in this Learning Path is text-first. Disable experimental vision routing: +The DGX model that you'll use is text-first. Disable experimental vision routing: ```text OPENCLAW_VISION_ENABLED=false ``` -## Initialize and Start the Runtime Stack +## Initialize and start the runtime stack The Gateway runs as user ID `1000` inside its container and needs write access to its persistent state directory. Prepare the directory before starting the stack: @@ -293,7 +294,7 @@ Start the complete DGX Spark stack: docker compose --env-file .env -f compose.yaml up -d ``` -The first start takes longer than subsequent starts because vLLM downloads the approximately 30 GiB Qwen model before loading it. The download time depends on your network connection and can make the initial startup longer. Subsequent starts use the cached model. A running container does not mean that its API is ready. +The first start takes longer than subsequent starts because vLLM downloads the approximately 30 GiB Qwen model before loading it. The download time depends on your network connection and can make the initial startup longer. Subsequent starts use the cached model. A running container doesn't mean that its API is ready. Check service status and API readiness: @@ -336,20 +337,20 @@ curl -I http://127.0.0.1:18789/ An HTTP `200` response confirms that the Gateway dashboard is reachable. -## Run the First Telegram Test +## Run the first Telegram test Creating the bot with BotFather registers its name and username in Telegram. The `openclaw-telegram` container uses the token in `.env` to connect the Telegram bot to the local Gateway and AI services on DGX Spark. -Find the bot in Telegram by searching for the username that you chose in BotFather. You can also replace `` in `https://t.me/` with that username and open the URL. Select **Start** to open a chat. The bot does not start a chat with you or automatically appear in your chat list. +Find the bot in Telegram by searching for the username that you chose in BotFather. You can also replace `` in `https://t.me/` with that username and open the URL. Select **Start** to open a chat. The bot doesn't start a chat with you or automatically appear in your chat list. -Messages then follow this path: +Messages then follow the following path: ```text Telegram client -> Telegram Bot API -> openclaw-telegram container on DGX Spark -> local Gateway and AI services -> openclaw-telegram container -> Telegram client ``` -After the containers are running and you have started the Telegram chat, send: +After the containers are running and you've started the Telegram chat, send: ```text /help @@ -369,7 +370,7 @@ Watch the Telegram and vLLM logs while the request is processed: docker logs --tail 10 openclaw-telegram ``` -The output should look similar to: +The output is similar to: ```output 2026-07-17T15:38:47+00:00 [telegram] chat_id= text_chars=69 @@ -387,9 +388,9 @@ The recent log should include a successful local completion request similar to: (APIServer pid=1) INFO: 172.18.0.7:48686 - "POST /v1/chat/completions HTTP/1.1" 200 OK ``` -The request appearing in the local logs confirms the runtime path. The model's text alone is not evidence that inference was local. +The request appearing in the local logs confirms the runtime path. The model's text alone isn't evidence that inference was local. -## Execute Test Suites +## Execute test suites Run the repository tests from the host: @@ -406,10 +407,10 @@ Ran 121 tests in 4.256s OK (skipped=5) ``` -The count and time can change. `OK` confirms that the software behavior tests passed; these are not hardware benchmarks. +The count and time can change. `OK` confirms that the software behavior tests passed. These aren't hardware benchmarks. -## What you've learned and what's next +## What you've accomplished and what's next -You have deployed the personal reference runtime on NVIDIA DGX Spark, connected it to your Telegram bot, verified the local vLLM endpoint, and checked the runtime tests. +You've now deployed the personal reference runtime on NVIDIA DGX Spark, connected it to your Telegram bot, verified the local vLLM endpoint, and checked the runtime tests. -Next, you will use the deployment as a local-first household assistant and confirm that memory is stored in local Qdrant collections. +Next, you'll use the deployment as a local-first household assistant and confirm that memory is stored in local Qdrant collections. diff --git a/content/learning-paths/laptops-and-desktops/openclaw_continuum/3_household_memory.md b/content/learning-paths/laptops-and-desktops/openclaw_continuum/3_household_memory.md index 9628acad7a..61de36572c 100644 --- a/content/learning-paths/laptops-and-desktops/openclaw_continuum/3_household_memory.md +++ b/content/learning-paths/laptops-and-desktops/openclaw_continuum/3_household_memory.md @@ -1,28 +1,30 @@ --- -title: Validate Memory Persistence and Routing with Telegram and Qdrant +title: Validate memory persistence and routing with Telegram and Qdrant weight: 4 ### FIXED, DO NOT MODIFY layout: learningpathall --- -## Define the Household Test Scenario +## Define the household test scenario -In this section, you will create a shared household assistant to test local memory. You will save and retrieve a synthetic maintenance reminder without sending it to a public cloud LLM. +You'll create a shared household assistant to test local memory. You'll save and retrieve a synthetic maintenance reminder without sending it to a public cloud LLM. Telegram transports the messages. Ollama, Qdrant, and the local LLM process them on your host. -This tutorial treats household data as shared. It does not implement separate access control for each family member. +{{% notice Note %}} +Household data is treated as shared data. You won't implement separate access control for each family member. +{{% /notice %}} -## Store and Query Local Memory +## Store and query local memory -Send this command to the Telegram bot: +Send the following command to the Telegram bot: ```text /mem #home The boiler should be inspected every October. ``` -The runtime stores the reminder through this path: +The runtime stores the reminder through the following path: ```text Telegram / Mem command @@ -42,7 +44,7 @@ The response should mention October. ![Telegram conversation showing the boiler reminder saved with the mem command and retrieved with the rag memory query#center](openclaw_telegram_2.jpg "Saving and retrieving a household memory in Telegram") -The retrieval request follows this local path: +The retrieval request follows the following local path: ```text Telegram question @@ -53,7 +55,7 @@ Telegram question -> Telegram answer ``` -## Verify Qdrant Vector Collections +## Verify Qdrant vector collections Confirm that the personal memory collection exists: @@ -85,7 +87,7 @@ The relevant fields are similar to: The point count depends on existing data. A `green` status with `optimizer_status` set to `ok` confirms collection health. The vector size of `768` matches `nomic-embed-text`. -The collection metadata does not prove that the boiler reminder was stored. Query the point payload directly to verify the synthetic record: +The collection metadata doesn't prove that the boiler reminder was stored. Query the point payload directly to verify the synthetic record: ```bash curl -sS -X POST \ @@ -110,7 +112,7 @@ curl -sS -X POST \ Look for the boiler reminder in the returned payload. The filter finds it even when the personal collection contains other records. This verifies the stored data directly instead of relying on the assistant's response. -## Inspect Active Agents and Task Execution +## Inspect active agents and task execution Send the following command to the Telegram bot: @@ -120,7 +122,7 @@ Send the following command to the Telegram bot: The response lists the thin agents registered by the reference runtime, including memory, RAG, browser search, weather, and chat routes. -To inspect recent tasks, send this command to the Telegram bot: +To inspect recent tasks, send the following command to the Telegram bot: ```text /tasks last 5 @@ -128,7 +130,7 @@ To inspect recent tasks, send this command to the Telegram bot: Task history shows which agent handled the request, its status, and its runtime. All routes use the configured LLM endpoint. -## Test External Skill Integration +## Test external skill integration Send a weather question in plain language: @@ -136,12 +138,10 @@ Send a weather question in plain language: Cambridge weather tomorrow ``` -The runtime sends this question to the weather skill. Do not add `/search`, which selects the general browser worker instead. +The runtime sends this question to the weather skill. Don't add `/search`, which selects the general browser worker instead. This request contacts the public [wttr.in](https://wttr.in/) weather service, but generation still uses the local model. -## Check your work - Your household assistant should now: 1. Save and retrieve the synthetic boiler reminder from Telegram. @@ -149,6 +149,8 @@ Your household assistant should now: 3. Show the selected agent in `/agents` and `/tasks last 5`. 4. Return weather data through the external weather skill. -## What you've learned and what's next +## What you've accomplished and what's next + +You've now saved and retrieved a synthetic household memory, verified it in Qdrant, and inspected both local and external request paths. -You saved and retrieved a synthetic household memory, verified it in Qdrant, and inspected both local and external request paths. Next, you will add document RAG, browser search, and a proactive cron reminder. + Next, you'll add document RAG, browser search, and a proactive cron reminder. diff --git a/content/learning-paths/laptops-and-desktops/openclaw_continuum/4_workflows.md b/content/learning-paths/laptops-and-desktops/openclaw_continuum/4_workflows.md index b2c9bd9215..cc69d60618 100644 --- a/content/learning-paths/laptops-and-desktops/openclaw_continuum/4_workflows.md +++ b/content/learning-paths/laptops-and-desktops/openclaw_continuum/4_workflows.md @@ -1,17 +1,17 @@ --- -title: Validate Document RAG, Web Search, and Proactive Tasks +title: Validate document RAG, web search, and proactive tasks weight: 5 ### FIXED, DO NOT MODIFY layout: learningpathall --- -## Ingest and Query Document RAG +## Ingest and query document RAG Create a small text file on the device where you use Telegram. {{% notice Note %}} -Telegram uploads files from the device running the client, not from DGX Spark unless Telegram runs there. Common locations are `Downloads`, `Documents`, or `Desktop` on a computer and `Downloads` in the Files app on a phone or tablet. +Telegram uploads files from the device running the client, not from DGX Spark, unless Telegram runs there. Common locations are `Downloads`, `Documents`, or `Desktop` on a computer, and `Downloads` in the Files app on a phone or tablet. {{% /notice %}} @@ -25,13 +25,13 @@ Clean the heating filter on the first Saturday of every third month. Keep the service reference number with the maintenance record. ``` -Save the file as `household-maintenance.txt`, then upload it to your bot with this caption: +Save the file as `household-maintenance.txt`, then upload it to your bot with the following caption: ```text /knowledge ``` -The document follows this path: +The document follows the following path: ```text File on the Telegram client device @@ -57,7 +57,7 @@ In Telegram, ask a question using the returned filename. Replace ` When should the heating filter be cleaned? ``` -The filename limits retrieval to this upload, so existing records do not affect the result. A general `/rag` query without a filename searches all configured memory and knowledge collections. The screenshot shows this general query, but use the filename-specific command for this test. +The filename limits retrieval to this upload, so existing records don't affect the result. A general `/rag` query without a filename searches all configured memory and knowledge collections. The screenshot shows a general query, but use the filename-specific command for this test. ![Telegram conversation showing household-maintenance.txt uploaded with the knowledge caption, saved to personal_knowledge_base, and retrieved with a general rag question#center](openclaw_telegram_3.jpg "Uploading and querying a household document in Telegram") @@ -88,9 +88,9 @@ curl -sS -X POST \ The payload should contain chunks from `household-maintenance.txt`, confirming that Qdrant stored and indexed the upload. -## Execute Deterministic Web Search +## Execute deterministic web search -Use the browser agent for current public information. Send this command to the bot: +Use the browser agent for current public information. Send the following command to the bot: ```text /search Arm Learning Paths local AI development @@ -117,7 +117,7 @@ docker logs --tail 20 openclaw-browser-scraper Look for a successful `POST /scrape` request. The Telegram response should cite the retrieved sources and include the path to the saved web Markdown file. -Finally, send this command in Telegram: +Finally, send the following command in Telegram: ```text /tasks last 5 @@ -125,15 +125,17 @@ Finally, send this command in Telegram: Confirm that the search task reports `browser_search_agent`. -## Schedule Proactive Cron Tasks +## Schedule proactive cron tasks -Choose a time a few minutes in the future, using `OPENCLAW_CRON_TIMEZONE`. Create a daily reminder: +Choose a time a few minutes in the future, using `OPENCLAW_CRON_TIMEZONE`. + +Create a daily reminder, replacing `21:15` with your test time: ```text /cron add daily 21:15 Heating check :: Remind the household to review the heating maintenance notes. ``` -Replace `21:15` with your test time. Then list the job in Telegram: +Then, list the job in Telegram: ```text /cron list @@ -143,7 +145,7 @@ The bot returns a job ID, and `/cron list` shows the schedule as `[on]`. ![Telegram conversation showing a daily Heating check cron job created, listed as enabled, and triggered at the configured time#center](openclaw_telegram_4.jpg "Creating and triggering a scheduled reminder in Telegram") -Creating the job does not run it immediately. At the configured time, the bot sends the Heating check message. +Creating the job doesn't run it immediately. At the configured time, the bot sends the Heating check message. After the configured time, verify that the cron worker delivered the scheduled job: @@ -161,9 +163,9 @@ To test without waiting, copy the job ID from `/cron list` and send: The result should be delivered as a Telegram push message. -## Inspect Cron From the Gateway Dashboard +## Inspect cron from the gateway dashboard -The Gateway dashboard listens on localhost. If you are working directly on the DGX Spark desktop, open: +The Gateway dashboard listens on localhost. If you're working directly on the DGX Spark desktop, open: ```text http://127.0.0.1:18789/ @@ -182,15 +184,15 @@ Then open `http://127.0.0.1:18789/` locally and enter the `OPENCLAW_GATEWAY_TOKE Confirm that the dashboard and Telegram show the same cron job and run history. {{% notice Warning %}} -Keep the Gateway and its admin RPC endpoint behind localhost, an SSH tunnel, or a trusted private network. Do not expose the dashboard directly to the public internet. +Keep the Gateway and its admin RPC endpoint behind localhost, an SSH tunnel, or a trusted private network. Don't expose the dashboard directly to the public internet. {{% /notice %}} -## Check your work - -You have now validated three runtime paths. Document questions use the RAG skill, Qdrant, and the local LLM. Current public queries use the browser-search agent and Playwright. Proactive reminders run through the cron worker and arrive as Telegram messages. +You've now validated three runtime paths. Document questions use the RAG skill, Qdrant, and the local LLM. Current public queries use the browser-search agent and Playwright. Proactive reminders run through the cron worker and arrive as Telegram messages. The LLM is one replaceable part of the application. The local memory, tools, schedules, and interaction paths remain available around it. ## What you've learned and what's next -You validated document RAG, explicit browser search, and a proactive reminder for the household assistant. Next, you will move the same workflows to a CPU-only Armv9 system. +You've now validated document RAG, explicit browser search, and a proactive reminder for the household assistant. + +You can optionally extend the same workflow to a CPU-only Armv9 system. For more information, see [(Optional) Port the app to a CPU-only Armv9 system](/learning-paths/laptops-and-desktops/openclaw_continuum/5_cpu_only/). You've moved beyond a local-model demo and built a self-managed OpenClaw-based runtime that you can adapt to different Arm compute configurations. diff --git a/content/learning-paths/laptops-and-desktops/openclaw_continuum/5_cpu_only.md b/content/learning-paths/laptops-and-desktops/openclaw_continuum/5_cpu_only.md index 183ba25975..773db52bc6 100644 --- a/content/learning-paths/laptops-and-desktops/openclaw_continuum/5_cpu_only.md +++ b/content/learning-paths/laptops-and-desktops/openclaw_continuum/5_cpu_only.md @@ -1,27 +1,27 @@ --- -title: (Optional) Port the App to a CPU-Only Armv9 System +title: (Optional) Port the app to a CPU-only Armv9 system weight: 6 ### FIXED, DO NOT MODIFY layout: learningpathall --- -## Overview of Cross-Platform Portability +## Cross-platform portability -As an optional step, you will now move the runtime from NVIDIA DGX Spark to a CIX-based Radxa Orion O6 running Debian 12. llama.cpp provides local generation on the Armv9 CPU. +You can optionally move the runtime from NVIDIA DGX Spark to a CIX-based Radxa Orion O6 running Debian 12. `llama.cpp` provides local generation on the Armv9 CPU. The Telegram interface, local memory and RAG, browser search, scheduled workflows, and deterministic routing remain unchanged. Only the local generation backend changes: | Platform | Local generation backend | Runtime API contract | |---|---|---| | NVIDIA DGX Spark | vLLM | OpenAI-compatible API | -| Radxa Orion O6 | llama.cpp | OpenAI-compatible API | +| Radxa Orion O6 | `llama.cpp` | OpenAI-compatible API | {{% notice Note %}} -These backends match the environments used in this Learning Path and [Run ERNIE-4.5 Mixture of Experts model on Armv9 with llama.cpp](/learning-paths/cross-platform/ernie_moe_v9/). You can use another local backend with a compatible OpenAI chat-completions API. +These backends match the environments used in this Learning Path and the [Run ERNIE-4.5 Mixture of Experts model on Armv9 with `llama.cpp`](/learning-paths/cross-platform/ernie_moe_v9/) Learning Path. You can use another local backend with a compatible OpenAI chat-completions API. {{% /notice %}} -## Verify System Requirements on Armv9 Host +## Verify system requirements on Armv9 host On Orion O6, confirm the operating system, architecture, CPU features, memory, and disk capacity: @@ -37,7 +37,7 @@ Confirm that the host reports `aarch64` and has enough available memory and stor ## Prepare llama.cpp and the ERNIE model -Follow [Set up llama.cpp on an Armv9 development board](/learning-paths/cross-platform/ernie_moe_v9/2_llamacpp_installation/). Install the dependencies, compile llama.cpp, download the ERNIE-4.5 Thinking Q4 GGUF model, and run its basic inference test. +Follow the steps in [Set up `llama.cpp` on an Armv9 development board](/learning-paths/cross-platform/ernie_moe_v9/2_llamacpp_installation/). Install the dependencies, compile `llama.cpp`, download the ERNIE-4.5 Thinking Q4 GGUF model, and run its basic inference test. The following commands use these installation paths: @@ -46,7 +46,7 @@ $HOME/llama.cpp/build/bin/llama-server $HOME/models/ernie-4.5/ERNIE-4.5-21B-A3B-Thinking-Q4_0.gguf ``` -## Deploy llama.cpp OpenAI-Compatible Server +## Deploy llama.cpp OpenAI-compatible server Start the server on the host: @@ -81,9 +81,9 @@ curl -sS http://127.0.0.1:8080/v1/chat/completions \ }' ``` -Do not continue until this local endpoint generates a valid response. +Don't continue until this local endpoint generates a valid response. -Press `Ctrl+C` in the server shell after the smoke test. Create a user systemd service so that llama.cpp starts automatically and restarts after a failure: +Press `Ctrl+C` in the server shell after the smoke test. Create a user `systemd` service so that `llama.cpp` starts automatically and restarts after a failure: ```bash mkdir -p $HOME/.config/systemd/user @@ -120,7 +120,7 @@ Confirm that the managed endpoint responds: curl http://127.0.0.1:8080/v1/models ``` -## Provision Supporting Local Services +## Provision supporting local services Install Ollama on the Orion O6 host: @@ -147,13 +147,13 @@ Check whether the Qdrant container already exists: docker ps -a --filter name=openclaw-qdrant ``` -If it already exists, start it: +If the container already exists, start it: ```bash docker start openclaw-qdrant ``` -Otherwise, create persistent storage and start Qdrant. Bind its ports to localhost: +Otherwise, create persistent storage and start Qdrant. Bind its ports to `localhost`: ```bash docker volume create openclaw-qdrant-data @@ -173,7 +173,7 @@ Confirm that the local API responds: curl http://127.0.0.1:6333/collections ``` -## Configure the CPU-Only Runtime Environment +## Configure the CPU-only runtime environment Clone the same release on Orion O6: @@ -185,7 +185,7 @@ git checkout v1.2 cp .env.arm-cpu-only.example .env ``` -Create a separate bot for this runtime with the [Telegram Bot tutorial](https://core.telegram.org/bots/tutorial). Do not reuse the DGX Spark bot token because two polling runtimes can compete for its updates. Have each account send a message to the new bot, then repeat the `getUpdates` process from the DGX Spark setup to obtain each `message.chat.id` value. +Create a separate bot for this runtime with the [Telegram Bot tutorial](https://core.telegram.org/bots/tutorial). Don't reuse the DGX Spark bot token because two polling runtimes can compete for its updates. Have each account send a message to the new bot, then repeat the `getUpdates` process from the DGX Spark setup to obtain each `message.chat.id` value. Generate a new Gateway token: @@ -215,9 +215,9 @@ OPENCLAW_TRACKER_COLLECTION=personal_tracker_memory OPENCLAW_KNOWLEDGE_COLLECTION=personal_knowledge_base ``` -The `VLLM` variable name is retained for compatibility, but it can point to llama.cpp. +The `VLLM` variable name is retained for compatibility, but it can point to `llama.cpp`. -Using the same collection names keeps the configuration consistent, but it does not copy Qdrant data from DGX Spark. Each host keeps its own data. +Using the same collection names keeps the configuration consistent, but it doesn't copy Qdrant data from DGX Spark. Each host keeps its own data. Keep the CPU-only context small and disable unused voice transcription: @@ -229,7 +229,7 @@ OPENCLAW_WEB_CONTEXT_CHARS=1800 OPENCLAW_WHISPER_ENABLED=false ``` -## Launch the CPU-Only Application Stack +## Launch the CPU-only application stack Start the full tutorial stack: @@ -258,14 +258,14 @@ docker exec openclaw-browser-scraper python -c "import socket; print(socket.geth ``` {{% notice Note %}} -If this command cannot resolve the hostname, inspect the Orion host DNS configuration with `cat /etc/resolv.conf`. Then update `OPENCLAW_DNS_SERVER_1` and `OPENCLAW_DNS_SERVER_2` in `.env` with DNS servers that are reachable from your network, restart the stack, and run the check again. +If this command can't resolve the hostname, inspect the Orion host DNS configuration with `cat /etc/resolv.conf`. Then update `OPENCLAW_DNS_SERVER_1` and `OPENCLAW_DNS_SERVER_2` in `.env` with DNS servers that are reachable from your network, restart the stack, and run the check again. {{% /notice %}} -## Validate Shared Workflows on CPU +## Validate shared workflows on CPU -Test the CPU-only deployment with a simple budget assistant shared by two household members. +Test the CPU-only deployment with a budget assistant shared by two household members. -Create a file named `budget.txt` on the device where you use Telegram: +Create a file named `budget.txt` on the device that you use Telegram on: ```text Shared household weekly budget: £120. @@ -284,26 +284,59 @@ After both entries are saved, either member can ask: /rag Based on the shared budget and the saved budget entries, how much remains? ``` -Replace `` with the filename returned when you uploaded `budget.txt`. +Replace `` with the filename that was returned when you uploaded `budget.txt`. The response should report that £55 remains. Both members use the same local collection, without separate per-member access controls. -The response alone does not prove which inference backend generated it. Inspect the Telegram runtime log: +The response alone doesn't prove which inference backend generated it. Inspect the Telegram runtime log: ```bash docker logs --tail 20 openclaw-telegram ``` -Look for the memory write handled by `memory_agent` and the completed retrieval request handled by `rag_agent`. Then inspect the llama.cpp service log: +Look for the memory write handled by `memory_agent` and the completed retrieval request handled by `rag_agent`. Then, inspect the `llama.cpp` service log: ```bash journalctl --user -u openclaw-llama.service -n 30 --no-pager ``` -Look for a successful request to `/v1/chat/completions`. The Telegram response and both log entries confirm that the OpenClaw-based workflow is now using llama.cpp for local generation on the Armv9 CPU. +Look for a successful request to `/v1/chat/completions`. The Telegram response and both log entries confirm that the OpenClaw-based workflow is now using `llama.cpp` for local generation on the Armv9 CPU. + +## Compare Arm deployment architectures + +You've now built a local-first household assistant with memory, document RAG, browser search, and scheduled notifications. You ran the assistant with vLLM on NVIDIA DGX Spark, then moved it to `llama.cpp` on Radxa Orion O6. + +The following comparison shows what stayed the same across the two Arm-based implementations and what changed with the local generation backend: + +| Layer | NVIDIA DGX Spark | Radxa Orion O6 | +|---|---|---| +| Reference runtime services | Same services | Same services | +| User interface | Telegram | Telegram | +| Skills | Memory, RAG, search, weather, cron | Same skills | +| Vector memory | Qdrant | Qdrant | +| Embeddings | Ollama | Ollama | +| Generation API | OpenAI-compatible | OpenAI-compatible | +| Generation engine | vLLM | `llama.cpp` | +| Inference compute | Arm CPU + NVIDIA GPU | Arm CPU | + +Each platform uses model and context settings suited to its compute while preserving the same application contract. + +## Review data privacy boundaries + +The runtime keeps inference requests, generated context, Qdrant collections, uploaded files, cron history, OpenClaw tasks, and Gateway state under your control. + +Telegram still transports messages and uploads. Weather and browser searches contact public services, while setup downloads models and containers from external registries. + +For sensitive deployments, review network exposure, Telegram suitability, host access, backups, model provenance, and the contents of every enabled tool. ## What you've learned and what's next -You have moved the OpenClaw-based runtime from DGX Spark to a CPU-only Armv9 system by replacing the inference endpoint rather than rewriting the application. +You've now moved the OpenClaw-based runtime from DGX Spark to a CPU-only Armv9 system by replacing the inference endpoint. + +The same endpoint-driven design can support additional deployment shapes: + +- An always-on CPU-only Arm server with a compact local model +- An Arm edge gateway connected to a trusted private-LAN inference server +- A heterogeneous Arm AI workstation hosting larger local models -Next, you will review the software portability result and identify the current implementation boundaries. +Each deployment changes the compute and trust boundary. It shouldn't silently change where personal data is stored or which external services are contacted. diff --git a/content/learning-paths/laptops-and-desktops/openclaw_continuum/6_summary.md b/content/learning-paths/laptops-and-desktops/openclaw_continuum/6_summary.md deleted file mode 100644 index 7a1617d55a..0000000000 --- a/content/learning-paths/laptops-and-desktops/openclaw_continuum/6_summary.md +++ /dev/null @@ -1,60 +0,0 @@ ---- -title: Review the Deployment Across Arm Platforms -weight: 7 - -### FIXED, DO NOT MODIFY -layout: learningpathall ---- - -## Compare Arm Deployment Architectures - -You built a local-first household assistant with memory, document RAG, browser search, and scheduled notifications. You ran it with vLLM on NVIDIA DGX Spark, then moved it to llama.cpp on Radxa Orion O6. - -The following comparison shows what stayed the same across the two Arm-based implementations and what changed with the local generation backend: - -| Layer | NVIDIA DGX Spark | Radxa Orion O6 | -|---|---|---| -| Reference runtime services | Same services | Same services | -| User interface | Telegram | Telegram | -| Skills | Memory, RAG, search, weather, cron | Same skills | -| Vector memory | Qdrant | Qdrant | -| Embeddings | Ollama | Ollama | -| Generation API | OpenAI-compatible | OpenAI-compatible | -| Generation engine | vLLM | llama.cpp | -| Inference compute | Arm CPU + NVIDIA GPU | Arm CPU | - -Each platform uses model and context settings suited to its compute while preserving the same application contract. - -## Review Data Privacy Boundaries - -The runtime keeps inference requests, generated context, Qdrant collections, uploaded files, cron history, OpenClaw tasks, and Gateway state under your control. - -Telegram still transports messages and uploads. Weather and browser searches contact public services, while setup downloads models and containers from external registries. - -For sensitive deployments, you should review network exposure, Telegram suitability, host access, backups, model provenance, and the contents of every enabled tool. - -## Identify Current System Scope - -This Learning Path uses a text-first architecture, fixed skill routes, and one local LLM endpoint. It does not cover multi-model routing, multi-agent handoffs, or hardware benchmarking. The AgentRegistry and TaskDispatcher keep command behavior predictable within this scope. - -## Explore Other Arm Deployment Topologies - -The same endpoint-driven design can support additional deployment shapes: - -- An always-on CPU-only Arm server with a compact local model -- An Arm edge gateway connected to a trusted private-LAN inference server -- A heterogeneous Arm AI workstation hosting larger local models - -Each deployment changes the compute and trust boundary. It should not silently change where personal data is stored or which external services are contacted. - -## Key Takeaways and Next Steps - -You can now: - -- Explain the local and external data boundaries of the reference runtime -- Deploy an operational OpenClaw-based runtime with local vLLM inference on DGX Spark -- Use Telegram memory, RAG, browser search, cron, and Gateway workflows -- Verify local persistence through Qdrant and runtime logs -- Move the same application workflow to llama.cpp on a CPU-only Armv9 platform - -You have moved beyond a local-model demo and built a self-managed OpenClaw-based runtime that can adapt to two different Arm compute configurations. diff --git a/content/learning-paths/laptops-and-desktops/openclaw_continuum/_index.md b/content/learning-paths/laptops-and-desktops/openclaw_continuum/_index.md index 1d14ba4e99..628e8ff0df 100644 --- a/content/learning-paths/laptops-and-desktops/openclaw_continuum/_index.md +++ b/content/learning-paths/laptops-and-desktops/openclaw_continuum/_index.md @@ -1,5 +1,5 @@ --- -title: Extend OpenClaw for a Local-First AI Assistant Across Arm Platforms +title: Extend OpenClaw for a local-first AI assistant across Arm platforms draft: true cascade: @@ -9,7 +9,7 @@ description: Extend OpenClaw with local memory, document RAG, browser search, de minutes_to_complete: 120 -who_is_this_for: This is an advanced topic for developers who want to extend OpenClaw into a customizable local-first assistant with persistent memory, document RAG, explicit browser search, deterministic routing, and proactive scheduling. You will deploy the reference runtime on NVIDIA DGX Spark with vLLM, then move the same workflows to a CPU-only Armv9 system with llama.cpp. +who_is_this_for: This is an advanced topic for developers who want to extend OpenClaw into a customizable local-first assistant with persistent memory, document RAG, explicit browser search, deterministic routing, and proactive scheduling. You'll deploy the reference runtime on NVIDIA DGX Spark with vLLM, then move the same workflows to a CPU-only Armv9 system with llama.cpp. learning_objectives: - Explain the local and external data boundaries of an OpenClaw-based runtime From 893d776c376e432a5d5734e29c53948bf22bf357 Mon Sep 17 00:00:00 2001 From: anupras-mohapatra-arm Date: Fri, 7 Aug 2026 17:33:07 -0500 Subject: [PATCH 02/12] bullet list update --- .../openclaw_continuum/5_cpu_only.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/content/learning-paths/laptops-and-desktops/openclaw_continuum/5_cpu_only.md b/content/learning-paths/laptops-and-desktops/openclaw_continuum/5_cpu_only.md index 773db52bc6..be603447ff 100644 --- a/content/learning-paths/laptops-and-desktops/openclaw_continuum/5_cpu_only.md +++ b/content/learning-paths/laptops-and-desktops/openclaw_continuum/5_cpu_only.md @@ -323,7 +323,15 @@ Each platform uses model and context settings suited to its compute while preser ## Review data privacy boundaries -The runtime keeps inference requests, generated context, Qdrant collections, uploaded files, cron history, OpenClaw tasks, and Gateway state under your control. +The runtime keeps the following under your control: + +- Inference requests +- Generated context +- Qdrant collections +- Uploaded files +- Cron history +- OpenClaw tasks +- Gateway state Telegram still transports messages and uploads. Weather and browser searches contact public services, while setup downloads models and containers from external registries. From 95589615978bdc9f27f5708166847bec5b924bfe Mon Sep 17 00:00:00 2001 From: anupras-mohapatra-arm Date: Fri, 7 Aug 2026 18:44:22 -0500 Subject: [PATCH 03/12] edits --- .../laptops-and-desktops/openclaw_continuum/5_cpu_only.md | 2 +- .../laptops-and-desktops/openclaw_continuum/_index.md | 6 +----- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/content/learning-paths/laptops-and-desktops/openclaw_continuum/5_cpu_only.md b/content/learning-paths/laptops-and-desktops/openclaw_continuum/5_cpu_only.md index be603447ff..712e242342 100644 --- a/content/learning-paths/laptops-and-desktops/openclaw_continuum/5_cpu_only.md +++ b/content/learning-paths/laptops-and-desktops/openclaw_continuum/5_cpu_only.md @@ -337,7 +337,7 @@ Telegram still transports messages and uploads. Weather and browser searches con For sensitive deployments, review network exposure, Telegram suitability, host access, backups, model provenance, and the contents of every enabled tool. -## What you've learned and what's next +## What you've accomplished You've now moved the OpenClaw-based runtime from DGX Spark to a CPU-only Armv9 system by replacing the inference endpoint. diff --git a/content/learning-paths/laptops-and-desktops/openclaw_continuum/_index.md b/content/learning-paths/laptops-and-desktops/openclaw_continuum/_index.md index 628e8ff0df..bd7310bccf 100644 --- a/content/learning-paths/laptops-and-desktops/openclaw_continuum/_index.md +++ b/content/learning-paths/laptops-and-desktops/openclaw_continuum/_index.md @@ -1,15 +1,11 @@ --- title: Extend OpenClaw for a local-first AI assistant across Arm platforms -draft: true -cascade: - draft: true - description: Extend OpenClaw with local memory, document RAG, browser search, deterministic routing, and proactive scheduling, then move the same local-first runtime from NVIDIA DGX Spark with vLLM to a CPU-only Armv9 system with llama.cpp. minutes_to_complete: 120 -who_is_this_for: This is an advanced topic for developers who want to extend OpenClaw into a customizable local-first assistant with persistent memory, document RAG, explicit browser search, deterministic routing, and proactive scheduling. You'll deploy the reference runtime on NVIDIA DGX Spark with vLLM, then move the same workflows to a CPU-only Armv9 system with llama.cpp. +who_is_this_for: This is an advanced topic for developers who want to extend OpenClaw into a customizable local-first assistant with persistent memory, document RAG, explicit browser search, deterministic routing, and proactive scheduling. learning_objectives: - Explain the local and external data boundaries of an OpenClaw-based runtime From d6ac96a0529b66ee9727bb28a576c28677cad3a3 Mon Sep 17 00:00:00 2001 From: anupras-mohapatra-arm Date: Mon, 10 Aug 2026 11:05:31 -0500 Subject: [PATCH 04/12] adding summary/faqs --- .../openclaw_continuum/1_architecture.md | 3 +- .../openclaw_continuum/2_dgx_deploy.md | 263 +------------ .../openclaw_continuum/3_household_memory.md | 156 -------- .../openclaw_continuum/4_workflows.md | 198 ---------- .../openclaw_continuum/5_cpu_only.md | 350 ------------------ .../openclaw_continuum/_index.md | 53 ++- 6 files changed, 60 insertions(+), 963 deletions(-) delete mode 100644 content/learning-paths/laptops-and-desktops/openclaw_continuum/3_household_memory.md delete mode 100644 content/learning-paths/laptops-and-desktops/openclaw_continuum/4_workflows.md delete mode 100644 content/learning-paths/laptops-and-desktops/openclaw_continuum/5_cpu_only.md diff --git a/content/learning-paths/laptops-and-desktops/openclaw_continuum/1_architecture.md b/content/learning-paths/laptops-and-desktops/openclaw_continuum/1_architecture.md index dbf2fd129d..743c8fd08a 100644 --- a/content/learning-paths/laptops-and-desktops/openclaw_continuum/1_architecture.md +++ b/content/learning-paths/laptops-and-desktops/openclaw_continuum/1_architecture.md @@ -1,5 +1,6 @@ --- title: Understand the architecture and local data boundaries +description: Map OpenClaw Arm Continuum's Telegram request flow, local data boundaries, and shared inference API across NVIDIA DGX Spark and CPU-only Arm systems. weight: 2 ### FIXED, DO NOT MODIFY @@ -54,7 +55,7 @@ Cron schedule Slash commands follow fixed routes. For example, `/search` always selects browser search, while a plain-language weather question selects the weather skill. {{% notice Note %}} -The runtime uses a text-first architecture, fixed skill routes, and one local LLM endpoint. `AgentRegistry` and `TaskDispatcher` keep command behavior predictable. This Learning Path doesn't cover multi-model routing, multi-agent handoffs, or hardware benchmarking. +The runtime uses a text-first architecture, fixed skill routes, and one local LLM endpoint. This Learning Path doesn't cover multi-model routing, multi-agent handoffs, or hardware benchmarking. {{% /notice %}} ## Understand the shared API contract across Arm platforms diff --git a/content/learning-paths/laptops-and-desktops/openclaw_continuum/2_dgx_deploy.md b/content/learning-paths/laptops-and-desktops/openclaw_continuum/2_dgx_deploy.md index 0d6fce0aea..7b6b50b3a5 100644 --- a/content/learning-paths/laptops-and-desktops/openclaw_continuum/2_dgx_deploy.md +++ b/content/learning-paths/laptops-and-desktops/openclaw_continuum/2_dgx_deploy.md @@ -1,5 +1,6 @@ --- -title: Deploy an OpenClaw-based reference runtime with vLLM on DGX Spark +title: Prepare the DGX Spark host and local services +description: Prepare an NVIDIA DGX Spark host with Docker, Ollama embeddings, Qdrant vector storage, and the pinned OpenClaw Arm Continuum repository. weight: 3 ### FIXED, DO NOT MODIFY @@ -31,9 +32,9 @@ Confirm Docker GPU access: docker run --rm --gpus all ubuntu nvidia-smi ``` -You don't need to install the vLLM Python package or start a vLLM server directly on the DGX Spark host. The project's `compose.yaml` pulls a container image that already includes vLLM and starts the local inference server for you. +You don't need to install the vLLM Python package or start a vLLM server directly on the DGX Spark host. The project's `compose.yaml` pulls a container image that already includes vLLM and starts the local inference server for you. -You do need to install the NVIDIA driver and NVIDIA Container Toolkit so that this container can access the GPU. +You need to install the NVIDIA driver and NVIDIA Container Toolkit so that this container can access the GPU. ## Configure Ollama for local embeddings @@ -67,7 +68,7 @@ The output should include the override: Environment="OLLAMA_HOST=0.0.0.0:11434" ``` -Reload systemd and restart Ollama: +Reload `systemd` and restart Ollama: ```bash sudo systemctl daemon-reload @@ -159,258 +160,8 @@ git checkout v1.2 The tag fixes the tutorial source version. Unversioned container images and model artifacts can still change when downloaded. -## Configure the Telegram bot environment variables - -You need a Telegram account, a bot token, and the numeric chat ID for the account that will use the bot. Create a Telegram account if you don't already have one. You can use the Telegram desktop, mobile, or web client for the following steps. - -To create a bot and obtain its token: - -1. Open Telegram and start a chat with **BotFather**. -2. Send the following command: - - ```text - /newbot - ``` - -3. Follow BotFather's prompts to name the bot and choose a username. -4. Copy the HTTP API token that BotFather returns. You'll add it to the `.env` file later. - -For more information about creating and managing bots, see the official [Telegram Bot tutorial](https://core.telegram.org/bots/tutorial). - -Next, obtain the chat ID for your Telegram account: - -1. Open a chat with the bot that you created and send a test message, such as `Hello`. This creates an update that the Telegram Bot API can return. -2. Open a terminal on your local machine and query the updates. Replace `` with the HTTP API token from BotFather: - - ```bash - curl "https://api.telegram.org/bot/getUpdates" - ``` - - The output is similar to: - - ```output - { - "ok": true, - "result": [ - { - "update_id": (...), - "message": { - (...) - }, - "chat": { - (...) - }, - "date": (...), - "text": "Hello" - } - ] - } - ``` - -Copy the `message.chat.id` value. You'll use this value for `` in the `.env` file. If the `result` array is empty, send another message to the bot and run the command again. - -Copy the DGX Spark environment template: - -```bash -cp .env.example .env -``` - -Keep `.env` in the `openclaw-arm-continuum` repository root, alongside `.env.example`. The deployment command reads it from this location. - - -Then, generate a Gateway token: - -```bash -openssl rand -hex 32 -``` - - -Edit `.env` and set the four private values: - -```text -OPENCLAW_TELEGRAM_BOT_TOKEN= -OPENCLAW_TELEGRAM_ALLOWED_CHAT_IDS= -OPENCLAW_CRON_CHAT_IDS= -OPENCLAW_GATEWAY_TOKEN= -``` - -Set `OPENCLAW_CRON_TIMEZONE` to your local [IANA timezone](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones). For example, use `Europe/London`, `America/New_York`, or `Asia/Singapore`: - -```text -OPENCLAW_CRON_TIMEZONE= -``` - -Scheduled jobs use UTC when this setting is omitted. - -You'll name the location explicitly when asking weather-related, so you don't need to configure `OPENCLAW_DEFAULT_WEATHER_LOCATION`. - -{{% notice Note %}} -Don't share your Telegram bot token or chat ID with anyone, and don't include them in screenshots, logs, or public repositories. -{{% /notice %}} - -Only allowlisted chat IDs can send commands to this runtime. - -The main tutorial flow uses the default personal collections: - -```text -personal_tracker_memory -personal_knowledge_base -``` - -You don't need to add collection settings to `.env` for this default path. Use only the synthetic data provided in the exercises. - -{{% notice Note %}} -If this host already contains personal runtime data, or if you're preparing a public demonstration, add the following optional settings to `.env` to isolate the tutorial data: - -```text -OPENCLAW_TRACKER_COLLECTION=demo_tracker_memory -OPENCLAW_KNOWLEDGE_COLLECTION=demo_knowledge_base -OPENCLAW_RUNTIME_LABEL=DGX Spark Demo -``` - -If you choose this option, replace the `personal_*` collection names in later verification commands with the corresponding `demo_*` names. -{{% /notice %}} - -The DGX model that you'll use is text-first. Disable experimental vision routing: - -```text -OPENCLAW_VISION_ENABLED=false -``` - - -## Initialize and start the runtime stack - -The Gateway runs as user ID `1000` inside its container and needs write access to its persistent state directory. Prepare the directory before starting the stack: - -```bash -mkdir -p gateway-data/state -sudo chown -R 1000:1000 gateway-data -sudo chmod -R u+rwX gateway-data -``` - -Start the complete DGX Spark stack: - -```bash -docker compose --env-file .env -f compose.yaml up -d -``` - -The first start takes longer than subsequent starts because vLLM downloads the approximately 30 GiB Qwen model before loading it. The download time depends on your network connection and can make the initial startup longer. Subsequent starts use the cached model. A running container doesn't mean that its API is ready. - -Check service status and API readiness: - -```bash -docker compose --env-file .env -f compose.yaml ps -a -docker logs --tail 80 openclaw-vllm -docker logs --tail 80 openclaw-gateway -docker logs --tail 80 openclaw-telegram -docker logs --tail 80 openclaw-cron -``` - -Follow the vLLM log during the first startup: - -```bash -docker logs -f openclaw-vllm -``` - -Wait for `Application startup complete`. Press `Ctrl+C` to leave the log view without stopping the container. - -Confirm that the model API is ready: - -```bash -curl http://127.0.0.1:8000/v1/models -``` - -Verify that a project container can reach both host services through the Docker host gateway: - -```bash -docker exec openclaw-telegram python -c "import urllib.request; print(urllib.request.urlopen('http://host.docker.internal:11434/api/tags').status)" -docker exec openclaw-telegram python -c "import urllib.request; print(urllib.request.urlopen('http://host.docker.internal:6333/collections').status)" -``` - -Both commands should print HTTP status `200`. - -Confirm the local Gateway dashboard endpoint: - -```bash -curl -I http://127.0.0.1:18789/ -``` - -An HTTP `200` response confirms that the Gateway dashboard is reachable. - -## Run the first Telegram test - -Creating the bot with BotFather registers its name and username in Telegram. The `openclaw-telegram` container uses the token in `.env` to connect the Telegram bot to the local Gateway and AI services on DGX Spark. - -Find the bot in Telegram by searching for the username that you chose in BotFather. You can also replace `` in `https://t.me/` with that username and open the URL. Select **Start** to open a chat. The bot doesn't start a chat with you or automatically appear in your chat list. - -Messages then follow the following path: - -```text -Telegram client -> Telegram Bot API -> openclaw-telegram container on DGX Spark - -> local Gateway and AI services -> openclaw-telegram container -> Telegram client -``` - -After the containers are running and you've started the Telegram chat, send: - -```text -/help -``` - -The bot should return the OpenClaw command card. Next, send a short general message: - -```text -Explain one benefit of running an AI assistant locally in one sentence. -``` - -Watch the Telegram and vLLM logs while the request is processed: - -![Telegram conversation showing the tutorial prompt and a response from the local reasoning model#center](openclaw_telegram_1.jpg "Telegram response from the local reference runtime") - -```bash -docker logs --tail 10 openclaw-telegram -``` - -The output is similar to: - -```output -2026-07-17T15:38:47+00:00 [telegram] chat_id= text_chars=69 -2026-07-17T15:38:47+00:00 [runtime] start chat_id= active=1 -2026-07-17T15:38:51+00:00 [runtime] done chat_id= task_id= agent=chat_agent duration_ms=4153 answer_chars=180 -``` - -```bash -docker logs --tail 10 openclaw-vllm -``` - -The recent log should include a successful local completion request similar to: - -```output -(APIServer pid=1) INFO: 172.18.0.7:48686 - "POST /v1/chat/completions HTTP/1.1" 200 OK -``` - -The request appearing in the local logs confirms the runtime path. The model's text alone isn't evidence that inference was local. - -## Execute test suites - -Run the repository tests from the host: - -```bash -OPENCLAW_OLLAMA_BASE_URL=http://127.0.0.1:11434 \ -OPENCLAW_QDRANT_BASE_URL=http://127.0.0.1:6333 \ -PYTHONPATH=app python3 -m unittest discover -s tests -``` - -The final lines are similar to: - -```output -Ran 121 tests in 4.256s -OK (skipped=5) -``` - -The count and time can change. `OK` confirms that the software behavior tests passed. These aren't hardware benchmarks. - ## What you've accomplished and what's next -You've now deployed the personal reference runtime on NVIDIA DGX Spark, connected it to your Telegram bot, verified the local vLLM endpoint, and checked the runtime tests. +You've prepared the DGX Spark host, configured local embeddings, started Qdrant, and checked out the reference repository. -Next, you'll use the deployment as a local-first household assistant and confirm that memory is stored in local Qdrant collections. +Next, you'll configure the Telegram bot and start the OpenClaw runtime. diff --git a/content/learning-paths/laptops-and-desktops/openclaw_continuum/3_household_memory.md b/content/learning-paths/laptops-and-desktops/openclaw_continuum/3_household_memory.md deleted file mode 100644 index 61de36572c..0000000000 --- a/content/learning-paths/laptops-and-desktops/openclaw_continuum/3_household_memory.md +++ /dev/null @@ -1,156 +0,0 @@ ---- -title: Validate memory persistence and routing with Telegram and Qdrant -weight: 4 - -### FIXED, DO NOT MODIFY -layout: learningpathall ---- - -## Define the household test scenario - -You'll create a shared household assistant to test local memory. You'll save and retrieve a synthetic maintenance reminder without sending it to a public cloud LLM. - -Telegram transports the messages. Ollama, Qdrant, and the local LLM process them on your host. - -{{% notice Note %}} -Household data is treated as shared data. You won't implement separate access control for each family member. -{{% /notice %}} - -## Store and query local memory - -Send the following command to the Telegram bot: - -```text -/mem #home The boiler should be inspected every October. -``` - -The runtime stores the reminder through the following path: - -```text -Telegram / Mem command - -> Memory skill - -> Ollama embedding - -> Qdrant collection: personal_tracker_memory -``` - -Wait for the confirmation, then retrieve the memory: - -```text -/rag memory: When should the boiler be inspected? -``` - -The response should mention October. - -![Telegram conversation showing the boiler reminder saved with the mem command and retrieved with the rag memory query#center](openclaw_telegram_2.jpg "Saving and retrieving a household memory in Telegram") - - -The retrieval request follows the following local path: - -```text -Telegram question - -> Ollama query embedding - -> Qdrant similarity search - -> Retrieved context - -> Local vLLM response - -> Telegram answer -``` - -## Verify Qdrant vector collections - -Confirm that the personal memory collection exists: - -```bash -curl http://127.0.0.1:6333/collections/personal_tracker_memory -``` - -The relevant fields are similar to: - -```output -{ - "result": { - "status": "green", - "optimizer_status": "ok", - "points_count": 102, - "config": { - "params": { - "vectors": { - "size": 768, - "distance": "Cosine" - }, - "on_disk_payload": true - } - } - }, - "status": "ok" -} -``` - -The point count depends on existing data. A `green` status with `optimizer_status` set to `ok` confirms collection health. The vector size of `768` matches `nomic-embed-text`. - -The collection metadata doesn't prove that the boiler reminder was stored. Query the point payload directly to verify the synthetic record: - -```bash -curl -sS -X POST \ - http://127.0.0.1:6333/collections/personal_tracker_memory/points/scroll \ - -H 'Content-Type: application/json' \ - -d '{ - "filter": { - "must": [ - { - "key": "text", - "match": { - "value": "#home The boiler should be inspected every October." - } - } - ] - }, - "limit": 5, - "with_payload": true, - "with_vector": false - }' -``` - -Look for the boiler reminder in the returned payload. The filter finds it even when the personal collection contains other records. This verifies the stored data directly instead of relying on the assistant's response. - -## Inspect active agents and task execution - -Send the following command to the Telegram bot: - -```text -/agents -``` - -The response lists the thin agents registered by the reference runtime, including memory, RAG, browser search, weather, and chat routes. - -To inspect recent tasks, send the following command to the Telegram bot: - -```text -/tasks last 5 -``` - -Task history shows which agent handled the request, its status, and its runtime. All routes use the configured LLM endpoint. - -## Test external skill integration - -Send a weather question in plain language: - -```text -Cambridge weather tomorrow -``` - -The runtime sends this question to the weather skill. Don't add `/search`, which selects the general browser worker instead. - -This request contacts the public [wttr.in](https://wttr.in/) weather service, but generation still uses the local model. - -Your household assistant should now: - -1. Save and retrieve the synthetic boiler reminder from Telegram. -2. Store the reminder in `personal_tracker_memory`. -3. Show the selected agent in `/agents` and `/tasks last 5`. -4. Return weather data through the external weather skill. - -## What you've accomplished and what's next - -You've now saved and retrieved a synthetic household memory, verified it in Qdrant, and inspected both local and external request paths. - - Next, you'll add document RAG, browser search, and a proactive cron reminder. diff --git a/content/learning-paths/laptops-and-desktops/openclaw_continuum/4_workflows.md b/content/learning-paths/laptops-and-desktops/openclaw_continuum/4_workflows.md deleted file mode 100644 index cc69d60618..0000000000 --- a/content/learning-paths/laptops-and-desktops/openclaw_continuum/4_workflows.md +++ /dev/null @@ -1,198 +0,0 @@ ---- -title: Validate document RAG, web search, and proactive tasks -weight: 5 - -### FIXED, DO NOT MODIFY -layout: learningpathall ---- - -## Ingest and query document RAG - -Create a small text file on the device where you use Telegram. - -{{% notice Note %}} -Telegram uploads files from the device running the client, not from DGX Spark, unless Telegram runs there. Common locations are `Downloads`, `Documents`, or `Desktop` on a computer, and `Downloads` in the Files app on a phone or tablet. -{{% /notice %}} - - -Use the following synthetic tutorial content: - -```text -Household heating maintenance notes - -Inspect the boiler every October. -Clean the heating filter on the first Saturday of every third month. -Keep the service reference number with the maintenance record. -``` - -Save the file as `household-maintenance.txt`, then upload it to your bot with the following caption: - -```text -/knowledge -``` - -The document follows the following path: - -```text -File on the Telegram client device - -> Telegram bot upload - -> DGX Spark workspace/inbox/knowledge/telegram - -> Memory watcher and Ollama embeddings - -> Qdrant collection: personal_knowledge_base -``` - -The `/knowledge` caption explicitly routes the file to document indexing. The runtime stores it under `workspace/inbox/knowledge/telegram/`, creates embeddings, and writes the chunks to `personal_knowledge_base`. - -The bot reports the stored filename with a timestamp prefix, similar to `20260717-180500-household-maintenance.txt`. Copy the filename from the response. - -Indexing runs in the background. Wait a few seconds, then check the memory watcher: - -```bash -docker logs --tail 30 openclaw-memory-watcher -``` - -In Telegram, ask a question using the returned filename. Replace `` with the filename reported by the bot: - -```text -/rag When should the heating filter be cleaned? -``` - -The filename limits retrieval to this upload, so existing records don't affect the result. A general `/rag` query without a filename searches all configured memory and knowledge collections. The screenshot shows a general query, but use the filename-specific command for this test. - -![Telegram conversation showing household-maintenance.txt uploaded with the knowledge caption, saved to personal_knowledge_base, and retrieved with a general rag question#center](openclaw_telegram_3.jpg "Uploading and querying a household document in Telegram") - -The answer should mention the first Saturday of every third month. - -To verify the stored document directly in Qdrant, filter the collection by the returned filename: - -```bash -curl -sS -X POST \ - http://127.0.0.1:6333/collections/personal_knowledge_base/points/scroll \ - -H 'Content-Type: application/json' \ - -d '{ - "filter": { - "must": [ - { - "key": "file_name", - "match": { - "value": "" - } - } - ] - }, - "limit": 5, - "with_payload": true, - "with_vector": false - }' -``` - -The payload should contain chunks from `household-maintenance.txt`, confirming that Qdrant stored and indexed the upload. - -## Execute deterministic web search - -Use the browser agent for current public information. Send the following command to the bot: - -```text -/search Arm Learning Paths local AI development -``` - -The explicit `/search` prefix selects the browser-search route deterministically: - -```text -Telegram /search command - -> Browser-search agent - -> Local Playwright worker - -> Public search engine and selected pages - -> Local vLLM summary - -> Telegram answer -``` - -The query and page requests leave the local network. Playwright saves the retrieved content under `workspace/inbox/tracker/web/`, and local vLLM generates the answer. - -Confirm that the browser worker handled the request: - -```bash -docker logs --tail 20 openclaw-browser-scraper -``` - -Look for a successful `POST /scrape` request. The Telegram response should cite the retrieved sources and include the path to the saved web Markdown file. - -Finally, send the following command in Telegram: - -```text -/tasks last 5 -``` - -Confirm that the search task reports `browser_search_agent`. - -## Schedule proactive cron tasks - -Choose a time a few minutes in the future, using `OPENCLAW_CRON_TIMEZONE`. - -Create a daily reminder, replacing `21:15` with your test time: - -```text -/cron add daily 21:15 Heating check :: Remind the household to review the heating maintenance notes. -``` - -Then, list the job in Telegram: - -```text -/cron list -``` - -The bot returns a job ID, and `/cron list` shows the schedule as `[on]`. - -![Telegram conversation showing a daily Heating check cron job created, listed as enabled, and triggered at the configured time#center](openclaw_telegram_4.jpg "Creating and triggering a scheduled reminder in Telegram") - -Creating the job doesn't run it immediately. At the configured time, the bot sends the Heating check message. - -After the configured time, verify that the cron worker delivered the scheduled job: - -```bash -docker logs --tail 30 openclaw-cron -``` - -Look for a line containing `[cron] dynamic job sent`, the job ID, and the path to the locally saved cron report. - -To test without waiting, copy the job ID from `/cron list` and send: - -```text -/cron run -``` - -The result should be delivered as a Telegram push message. - -## Inspect cron from the gateway dashboard - -The Gateway dashboard listens on localhost. If you're working directly on the DGX Spark desktop, open: - -```text -http://127.0.0.1:18789/ -``` - -If DGX Spark is remote, create an SSH tunnel from your laptop: - -```bash -ssh -L 18789:127.0.0.1:18789 @ -``` - -Replace `` with your DGX Spark user name and `` with its host name or IP address. - -Then open `http://127.0.0.1:18789/` locally and enter the `OPENCLAW_GATEWAY_TOKEN` stored in the private `.env` file. - -Confirm that the dashboard and Telegram show the same cron job and run history. - -{{% notice Warning %}} -Keep the Gateway and its admin RPC endpoint behind localhost, an SSH tunnel, or a trusted private network. Don't expose the dashboard directly to the public internet. -{{% /notice %}} - -You've now validated three runtime paths. Document questions use the RAG skill, Qdrant, and the local LLM. Current public queries use the browser-search agent and Playwright. Proactive reminders run through the cron worker and arrive as Telegram messages. - -The LLM is one replaceable part of the application. The local memory, tools, schedules, and interaction paths remain available around it. - -## What you've learned and what's next - -You've now validated document RAG, explicit browser search, and a proactive reminder for the household assistant. - -You can optionally extend the same workflow to a CPU-only Armv9 system. For more information, see [(Optional) Port the app to a CPU-only Armv9 system](/learning-paths/laptops-and-desktops/openclaw_continuum/5_cpu_only/). You've moved beyond a local-model demo and built a self-managed OpenClaw-based runtime that you can adapt to different Arm compute configurations. diff --git a/content/learning-paths/laptops-and-desktops/openclaw_continuum/5_cpu_only.md b/content/learning-paths/laptops-and-desktops/openclaw_continuum/5_cpu_only.md deleted file mode 100644 index 712e242342..0000000000 --- a/content/learning-paths/laptops-and-desktops/openclaw_continuum/5_cpu_only.md +++ /dev/null @@ -1,350 +0,0 @@ ---- -title: (Optional) Port the app to a CPU-only Armv9 system -weight: 6 - -### FIXED, DO NOT MODIFY -layout: learningpathall ---- - -## Cross-platform portability - -You can optionally move the runtime from NVIDIA DGX Spark to a CIX-based Radxa Orion O6 running Debian 12. `llama.cpp` provides local generation on the Armv9 CPU. - -The Telegram interface, local memory and RAG, browser search, scheduled workflows, and deterministic routing remain unchanged. Only the local generation backend changes: - -| Platform | Local generation backend | Runtime API contract | -|---|---|---| -| NVIDIA DGX Spark | vLLM | OpenAI-compatible API | -| Radxa Orion O6 | `llama.cpp` | OpenAI-compatible API | - -{{% notice Note %}} -These backends match the environments used in this Learning Path and the [Run ERNIE-4.5 Mixture of Experts model on Armv9 with `llama.cpp`](/learning-paths/cross-platform/ernie_moe_v9/) Learning Path. You can use another local backend with a compatible OpenAI chat-completions API. -{{% /notice %}} - -## Verify system requirements on Armv9 host - -On Orion O6, confirm the operating system, architecture, CPU features, memory, and disk capacity: - -```bash -uname -a -cat /etc/os-release -lscpu -free -h -df -h / -``` - -Confirm that the host reports `aarch64` and has enough available memory and storage for the selected GGUF model and containers. - -## Prepare llama.cpp and the ERNIE model - -Follow the steps in [Set up `llama.cpp` on an Armv9 development board](/learning-paths/cross-platform/ernie_moe_v9/2_llamacpp_installation/). Install the dependencies, compile `llama.cpp`, download the ERNIE-4.5 Thinking Q4 GGUF model, and run its basic inference test. - -The following commands use these installation paths: - -```text -$HOME/llama.cpp/build/bin/llama-server -$HOME/models/ernie-4.5/ERNIE-4.5-21B-A3B-Thinking-Q4_0.gguf -``` - -## Deploy llama.cpp OpenAI-compatible server - -Start the server on the host: - -```bash -cd $HOME/llama.cpp - -./build/bin/llama-server \ - --jinja \ - -m $HOME/models/ernie-4.5/ERNIE-4.5-21B-A3B-Thinking-Q4_0.gguf \ - -c 2048 \ - -t 12 \ - --host 127.0.0.1 \ - --port 8080 -``` - -From another shell, inspect the model endpoint: - -```bash -curl http://127.0.0.1:8080/v1/models -``` - -Send a short completion request: - -```bash -curl -sS http://127.0.0.1:8080/v1/chat/completions \ - -H 'Content-Type: application/json' \ - -d '{ - "model": "ernie-o6", - "messages": [{"role":"user","content":"Reply with one sentence about local AI on Arm."}], - "max_tokens": 80, - "temperature": 0.2 - }' -``` - -Don't continue until this local endpoint generates a valid response. - -Press `Ctrl+C` in the server shell after the smoke test. Create a user `systemd` service so that `llama.cpp` starts automatically and restarts after a failure: - -```bash -mkdir -p $HOME/.config/systemd/user - -tee $HOME/.config/systemd/user/openclaw-llama.service > /dev/null <<'EOF' -[Unit] -Description=llama.cpp server for the OpenClaw-based runtime -Wants=network-online.target -After=network-online.target - -[Service] -Type=simple -ExecStart=%h/llama.cpp/build/bin/llama-server --jinja -m %h/models/ernie-4.5/ERNIE-4.5-21B-A3B-Thinking-Q4_0.gguf -c 2048 -t 12 --host 127.0.0.1 --port 8080 -Restart=on-failure -RestartSec=5 - -[Install] -WantedBy=default.target -EOF -``` - -Enable the service and allow it to remain active when you log out: - -```bash -systemctl --user daemon-reload -systemctl --user enable --now openclaw-llama.service -sudo loginctl enable-linger $USER -systemctl --user status openclaw-llama.service --no-pager -``` - -Confirm that the managed endpoint responds: - -```bash -curl http://127.0.0.1:8080/v1/models -``` - -## Provision supporting local services - -Install Ollama on the Orion O6 host: - -```bash -curl -fsSL https://ollama.com/install.sh | sh -sudo systemctl enable --now ollama -``` - -The CPU-only compose file uses host networking, so its containers can reach Ollama through `127.0.0.1:11434`. Pull the embedding model: - -```bash -ollama pull nomic-embed-text -``` - -Confirm that Ollama responds and lists `nomic-embed-text`: - -```bash -curl http://127.0.0.1:11434/api/tags -``` - -Check whether the Qdrant container already exists: - -```bash -docker ps -a --filter name=openclaw-qdrant -``` - -If the container already exists, start it: - -```bash -docker start openclaw-qdrant -``` - -Otherwise, create persistent storage and start Qdrant. Bind its ports to `localhost`: - -```bash -docker volume create openclaw-qdrant-data - -docker run -d \ - --name openclaw-qdrant \ - --restart unless-stopped \ - -p 127.0.0.1:6333:6333 \ - -p 127.0.0.1:6334:6334 \ - -v openclaw-qdrant-data:/qdrant/storage \ - qdrant/qdrant:latest -``` - -Confirm that the local API responds: - -```bash -curl http://127.0.0.1:6333/collections -``` - -## Configure the CPU-only runtime environment - -Clone the same release on Orion O6: - -```bash -cd $HOME -git clone https://github.com/odincodeshen/openclaw-arm-continuum.git -cd openclaw-arm-continuum -git checkout v1.2 -cp .env.arm-cpu-only.example .env -``` - -Create a separate bot for this runtime with the [Telegram Bot tutorial](https://core.telegram.org/bots/tutorial). Don't reuse the DGX Spark bot token because two polling runtimes can compete for its updates. Have each account send a message to the new bot, then repeat the `getUpdates` process from the DGX Spark setup to obtain each `message.chat.id` value. - -Generate a new Gateway token: - -```bash -openssl rand -hex 32 -``` - -Set the new bot and private tokens in `.env`: - -```text -OPENCLAW_TELEGRAM_BOT_TOKEN= -OPENCLAW_TELEGRAM_ALLOWED_CHAT_IDS=, -OPENCLAW_CRON_CHAT_IDS=, -OPENCLAW_GATEWAY_TOKEN= -OPENCLAW_CRON_TIMEZONE= -``` - -Separate multiple chat IDs with commas. Use the same IANA timezone format as before; scheduled jobs use UTC if you omit it. - -Confirm the inference settings: - -```text -OPENCLAW_VLLM_BASE_URL=http://127.0.0.1:8080/v1 -OPENCLAW_VLLM_MODEL=ernie-o6 -OPENCLAW_VISION_ENABLED=false -OPENCLAW_TRACKER_COLLECTION=personal_tracker_memory -OPENCLAW_KNOWLEDGE_COLLECTION=personal_knowledge_base -``` - -The `VLLM` variable name is retained for compatibility, but it can point to `llama.cpp`. - -Using the same collection names keeps the configuration consistent, but it doesn't copy Qdrant data from DGX Spark. Each host keeps its own data. - -Keep the CPU-only context small and disable unused voice transcription: - -```text -OPENCLAW_MAX_TOKENS=128 -OPENCLAW_RETRIEVAL_LIMIT=3 -OPENCLAW_SCRAPER_LIMIT=2 -OPENCLAW_WEB_CONTEXT_CHARS=1800 -OPENCLAW_WHISPER_ENABLED=false -``` - -## Launch the CPU-only application stack - -Start the full tutorial stack: - -```bash -docker compose \ - --env-file .env \ - -f compose.arm-cpu-only.yaml \ - --profile web \ - --profile gateway \ - up -d -``` - -Check the services: - -```bash -docker compose --env-file .env -f compose.arm-cpu-only.yaml ps -docker logs --tail 80 openclaw-telegram -docker logs --tail 80 openclaw-memory-watcher -docker logs --tail 80 openclaw-cron -``` - -Confirm that the browser worker can resolve a public hostname: - -```bash -docker exec openclaw-browser-scraper python -c "import socket; print(socket.gethostbyname('duckduckgo.com'))" -``` - -{{% notice Note %}} -If this command can't resolve the hostname, inspect the Orion host DNS configuration with `cat /etc/resolv.conf`. Then update `OPENCLAW_DNS_SERVER_1` and `OPENCLAW_DNS_SERVER_2` in `.env` with DNS servers that are reachable from your network, restart the stack, and run the check again. -{{% /notice %}} - -## Validate shared workflows on CPU - -Test the CPU-only deployment with a budget assistant shared by two household members. - -Create a file named `budget.txt` on the device that you use Telegram on: - -```text -Shared household weekly budget: £120. -``` - -Upload the file with the `/knowledge` caption and copy the filename returned by the bot. Each allowlisted household member can then add a synthetic expense from their own chat: - -```text -/mem #budget Groceries: £45. -/mem #budget Household supplies: £20. -``` - -After both entries are saved, either member can ask: - -```text -/rag Based on the shared budget and the saved budget entries, how much remains? -``` - -Replace `` with the filename that was returned when you uploaded `budget.txt`. - -The response should report that £55 remains. Both members use the same local collection, without separate per-member access controls. - -The response alone doesn't prove which inference backend generated it. Inspect the Telegram runtime log: - -```bash -docker logs --tail 20 openclaw-telegram -``` - -Look for the memory write handled by `memory_agent` and the completed retrieval request handled by `rag_agent`. Then, inspect the `llama.cpp` service log: - -```bash -journalctl --user -u openclaw-llama.service -n 30 --no-pager -``` - -Look for a successful request to `/v1/chat/completions`. The Telegram response and both log entries confirm that the OpenClaw-based workflow is now using `llama.cpp` for local generation on the Armv9 CPU. - -## Compare Arm deployment architectures - -You've now built a local-first household assistant with memory, document RAG, browser search, and scheduled notifications. You ran the assistant with vLLM on NVIDIA DGX Spark, then moved it to `llama.cpp` on Radxa Orion O6. - -The following comparison shows what stayed the same across the two Arm-based implementations and what changed with the local generation backend: - -| Layer | NVIDIA DGX Spark | Radxa Orion O6 | -|---|---|---| -| Reference runtime services | Same services | Same services | -| User interface | Telegram | Telegram | -| Skills | Memory, RAG, search, weather, cron | Same skills | -| Vector memory | Qdrant | Qdrant | -| Embeddings | Ollama | Ollama | -| Generation API | OpenAI-compatible | OpenAI-compatible | -| Generation engine | vLLM | `llama.cpp` | -| Inference compute | Arm CPU + NVIDIA GPU | Arm CPU | - -Each platform uses model and context settings suited to its compute while preserving the same application contract. - -## Review data privacy boundaries - -The runtime keeps the following under your control: - -- Inference requests -- Generated context -- Qdrant collections -- Uploaded files -- Cron history -- OpenClaw tasks -- Gateway state - -Telegram still transports messages and uploads. Weather and browser searches contact public services, while setup downloads models and containers from external registries. - -For sensitive deployments, review network exposure, Telegram suitability, host access, backups, model provenance, and the contents of every enabled tool. - -## What you've accomplished - -You've now moved the OpenClaw-based runtime from DGX Spark to a CPU-only Armv9 system by replacing the inference endpoint. - -The same endpoint-driven design can support additional deployment shapes: - -- An always-on CPU-only Arm server with a compact local model -- An Arm edge gateway connected to a trusted private-LAN inference server -- A heterogeneous Arm AI workstation hosting larger local models - -Each deployment changes the compute and trust boundary. It shouldn't silently change where personal data is stored or which external services are contacted. diff --git a/content/learning-paths/laptops-and-desktops/openclaw_continuum/_index.md b/content/learning-paths/laptops-and-desktops/openclaw_continuum/_index.md index bd7310bccf..afae5e27f7 100644 --- a/content/learning-paths/laptops-and-desktops/openclaw_continuum/_index.md +++ b/content/learning-paths/laptops-and-desktops/openclaw_continuum/_index.md @@ -11,7 +11,7 @@ learning_objectives: - Explain the local and external data boundaries of an OpenClaw-based runtime - Deploy and validate the reference runtime with local vLLM inference on NVIDIA DGX Spark - Verify persistent memory, document RAG, explicit browser search, deterministic routing, and proactive scheduling with Telegram and Qdrant - - Move the same application workflows to a CPU-only Armv9 system through an OpenAI-compatible llama.cpp endpoint + - (Optional) Move the same application workflows to a CPU-only Armv9 system through an OpenAI-compatible llama.cpp endpoint prerequisites: - An NVIDIA DGX Spark system with NVIDIA drivers, Docker and NVIDIA Container Toolkit @@ -20,10 +20,59 @@ prerequisites: - Familiarity with Linux, Docker Compose, and command-line tools - (Optional) A Radxa Orion O6 or comparable CPU-only Armv9 system running Debian 12, Docker, and at least 30 GB of memory +# START generated_summary_faq +generated_summary_faq: + template_version: summary-faq-v3 + generated_at: '2026-08-10T15:59:32Z' + generator: ai + ai_assisted: true + ai_review_required: true + model: gpt-5 + prompt_template: summary-faq-v3 + source_hash: 8160160b7c59c2294a7666d9748b9f1f0115219431558ed7b378d6d3421d86e8 + summary_generated_at: '2026-08-10T15:59:32Z' + summary_source_hash: 8160160b7c59c2294a7666d9748b9f1f0115219431558ed7b378d6d3421d86e8 + faq_generated_at: '2026-08-10T15:59:32Z' + faq_source_hash: 8160160b7c59c2294a7666d9748b9f1f0115219431558ed7b378d6d3421d86e8 + summary: >- + You'll extend OpenClaw into a local-first assistant that runs across Arm platforms with local + inference and explicit external-data boundaries. First, you'll prepare a DGX Spark with Docker, Ollama, Qdrant, and vLLM. Then, you'll validate memory and + document RAG, browser search, weather, routing, and scheduled notifications. You can optionally + move the same workflows to a CPU-only Armv9 system with an OpenAI-compatible llama.cpp endpoint. + faqs: + - question: What should I check on the DGX Spark host before starting the containers? + answer: >- + Run `uname -m` and confirm the architecture is `aarch64`. Use `nvidia-smi` to verify GPU + visibility, then run `docker run --rm --gpus all ubuntu nvidia-smi` to confirm GPU access from + containers. + - question: How do I get the Telegram bot token and chat ID for the runtime configuration? + answer: >- + Start a chat with **BotFather**, send `/newbot`, and copy the HTTP API token it returns. Send a + test message to your new bot, call `curl "https://api.telegram.org/bot/getUpdates"`, + and copy `message.chat.id`. Set both values in `.env` before starting the services. + - question: How do I know that local memory persistence is working? + answer: >- + Send `/mem #home The boiler should be inspected every October.` in Telegram, then ask + `/rag memory: When should the boiler be inspected?`. You should see October in the response. Confirm + the record directly in the `personal_tracker_memory` Qdrant collection with the documented + payload query. + - question: Where do I upload documents for RAG, and how can I confirm ingestion? + answer: >- + Create the file on the device running your Telegram client and upload it with the `/knowledge` + caption. Copy the returned filename, wait for indexing, and ask `/rag ` a + question about the file. Check the `personal_knowledge_base` Qdrant payload for that filename + to confirm ingestion. + - question: How do I verify that proactive scheduling is active? + answer: >- + Create a job with `/cron add`, confirm it's enabled with `/cron list`, and wait for the + configured time. Check Telegram for the notification and inspect `docker logs --tail 30 openclaw-cron` + for the `[cron] dynamic job sent` entry. You can use `/cron run ` to test + the job without waiting. +# END generated_summary_faq author: Odin Shen -generate_summary_faq: true +generate_summary_faq: false rerun_summary: false rerun_faqs: false From 01287ddc6ac7603250b3839d9a99cd09478c3857 Mon Sep 17 00:00:00 2001 From: anupras-mohapatra-arm Date: Mon, 10 Aug 2026 11:06:07 -0500 Subject: [PATCH 05/12] splitting page 2 into two and renaming other files --- .../3_dgx_runtime_deploy.md | 268 +++++++++++++ .../openclaw_continuum/4_household_memory.md | 157 ++++++++ .../openclaw_continuum/5_workflows.md | 199 ++++++++++ .../openclaw_continuum/6_cpu_only.md | 351 ++++++++++++++++++ 4 files changed, 975 insertions(+) create mode 100644 content/learning-paths/laptops-and-desktops/openclaw_continuum/3_dgx_runtime_deploy.md create mode 100644 content/learning-paths/laptops-and-desktops/openclaw_continuum/4_household_memory.md create mode 100644 content/learning-paths/laptops-and-desktops/openclaw_continuum/5_workflows.md create mode 100644 content/learning-paths/laptops-and-desktops/openclaw_continuum/6_cpu_only.md diff --git a/content/learning-paths/laptops-and-desktops/openclaw_continuum/3_dgx_runtime_deploy.md b/content/learning-paths/laptops-and-desktops/openclaw_continuum/3_dgx_runtime_deploy.md new file mode 100644 index 0000000000..63afa1821b --- /dev/null +++ b/content/learning-paths/laptops-and-desktops/openclaw_continuum/3_dgx_runtime_deploy.md @@ -0,0 +1,268 @@ +--- +title: Configure and start the OpenClaw runtime on DGX Spark +description: Configure Telegram credentials and environment variables, start the OpenClaw runtime with vLLM on DGX Spark, and verify its services and test suite. +weight: 4 + +### FIXED, DO NOT MODIFY +layout: learningpathall +--- + +## Configure the Telegram bot environment variables + +With the host and local services ready, configure the Telegram bot. + +You need a Telegram account, a bot token, and the numeric chat ID for the account that will use the bot. Create a Telegram account if you don't already have one. You can use the Telegram desktop, mobile, or web client for the following steps. + +To create a bot and obtain its token: + +1. Open Telegram and start a chat with **BotFather**. +2. Send the following command: + + ```text + /newbot + ``` + +3. Follow BotFather's prompts to name the bot and choose a username. +4. Copy the HTTP API token that BotFather returns. You'll add it to the `.env` file later. + +For more information about creating and managing bots, see the official [Telegram Bot tutorial](https://core.telegram.org/bots/tutorial). + +Next, obtain the chat ID for your Telegram account: + +1. Open a chat with the bot that you created and send a test message, such as `Hello`. This creates an update that the Telegram Bot API can return. +2. Open a terminal on your local machine and query the updates. Replace `` with the HTTP API token from BotFather: + + ```bash + curl "https://api.telegram.org/bot/getUpdates" + ``` + + The output is similar to: + + ```output + { + "ok": true, + "result": [ + { + "update_id": (...), + "message": { + (...) + }, + "chat": { + (...) + }, + "date": (...), + "text": "Hello" + } + ] + } + ``` + + Copy the `message.chat.id` value. You'll use this value for `` in the `.env` file. If the `result` array is empty, send another message to the bot and run the command again. + +Copy the DGX Spark environment template: + +```bash +cp .env.example .env +``` + +Keep `.env` in the `openclaw-arm-continuum` repository root, alongside `.env.example`. The deployment command reads it from this location. + + +Then, generate a Gateway token: + +```bash +openssl rand -hex 32 +``` + + +Edit `.env` and set the four private values: + +```text +OPENCLAW_TELEGRAM_BOT_TOKEN= +OPENCLAW_TELEGRAM_ALLOWED_CHAT_IDS= +OPENCLAW_CRON_CHAT_IDS= +OPENCLAW_GATEWAY_TOKEN= +``` + +Set `OPENCLAW_CRON_TIMEZONE` to your local [IANA timezone](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones). For example, use `Europe/London`, `America/New_York`, or `Asia/Singapore`: + +```text +OPENCLAW_CRON_TIMEZONE= +``` + +Scheduled jobs use UTC when this setting is omitted. + +You'll name the location explicitly when asking weather-related, so you don't need to configure `OPENCLAW_DEFAULT_WEATHER_LOCATION`. + +{{% notice Note %}} +Don't share your Telegram bot token or chat ID with anyone, and don't include them in screenshots, logs, or public repositories. +{{% /notice %}} + +Only allowlisted chat IDs can send commands to this runtime. + +The main tutorial flow uses the default personal collections: + +```text +personal_tracker_memory +personal_knowledge_base +``` + +You don't need to add collection settings to `.env` for this default path. Use only the synthetic data provided in the exercises. + +{{% notice Note %}} +If this host already contains personal runtime data, or if you're preparing a public demonstration, add the following optional settings to `.env` to isolate the tutorial data: + +```text +OPENCLAW_TRACKER_COLLECTION=demo_tracker_memory +OPENCLAW_KNOWLEDGE_COLLECTION=demo_knowledge_base +OPENCLAW_RUNTIME_LABEL=DGX Spark Demo +``` + +If you choose this option, replace the `personal_*` collection names in later verification commands with the corresponding `demo_*` names. +{{% /notice %}} + +The DGX model that you'll use is text-first. Disable experimental vision routing: + +```text +OPENCLAW_VISION_ENABLED=false +``` + + +## Initialize and start the runtime stack + +The Gateway runs as user ID `1000` inside its container and needs write access to its persistent state directory. Prepare the directory before starting the stack: + +```bash +mkdir -p gateway-data/state +sudo chown -R 1000:1000 gateway-data +sudo chmod -R u+rwX gateway-data +``` + +Start the complete DGX Spark stack: + +```bash +docker compose --env-file .env -f compose.yaml up -d +``` + +The first start takes longer than subsequent starts because vLLM downloads the approximately 30 GiB Qwen model before loading it. The download time depends on your network connection and can make the initial startup longer. Subsequent starts use the cached model. A running container doesn't mean that its API is ready. + +Check service status and API readiness: + +```bash +docker compose --env-file .env -f compose.yaml ps -a +docker logs --tail 80 openclaw-vllm +docker logs --tail 80 openclaw-gateway +docker logs --tail 80 openclaw-telegram +docker logs --tail 80 openclaw-cron +``` + +Follow the vLLM log during the first startup: + +```bash +docker logs -f openclaw-vllm +``` + +Wait for `Application startup complete`. Press `Ctrl+C` to leave the log view without stopping the container. + +Confirm that the model API is ready: + +```bash +curl http://127.0.0.1:8000/v1/models +``` + +Verify that a project container can reach both host services through the Docker host gateway: + +```bash +docker exec openclaw-telegram python -c "import urllib.request; print(urllib.request.urlopen('http://host.docker.internal:11434/api/tags').status)" +docker exec openclaw-telegram python -c "import urllib.request; print(urllib.request.urlopen('http://host.docker.internal:6333/collections').status)" +``` + +Both commands should print HTTP status `200`. + +Confirm the local Gateway dashboard endpoint: + +```bash +curl -I http://127.0.0.1:18789/ +``` + +An HTTP `200` response confirms that the Gateway dashboard is reachable. + +## Run the first Telegram test + +Creating the bot with BotFather registers its name and username in Telegram. The `openclaw-telegram` container uses the token in `.env` to connect the Telegram bot to the local Gateway and AI services on DGX Spark. + +Find the bot in Telegram by searching for the username that you chose in BotFather. You can also replace `` in `https://t.me/` with that username and open the URL. Select **Start** to open a chat. The bot doesn't start a chat with you or automatically appear in your chat list. + +Messages use the following path: + +```text +Telegram client -> Telegram Bot API -> openclaw-telegram container on DGX Spark + -> local Gateway and AI services -> openclaw-telegram container -> Telegram client +``` + +After the containers are running and you've started the Telegram chat, send: + +```text +/help +``` + +The bot should return the OpenClaw command card. Next, send a short general message: + +```text +Explain one benefit of running an AI assistant locally in one sentence. +``` + +![Telegram conversation showing the tutorial prompt and a response from the local reasoning model#center](openclaw_telegram_1.jpg "Telegram response from the local reference runtime") + +Watch the Telegram logs while the request is processed: + +```bash +docker logs --tail 10 openclaw-telegram +``` + +The output is similar to: + +```output +2026-07-17T15:38:47+00:00 [telegram] chat_id= text_chars=69 +2026-07-17T15:38:47+00:00 [runtime] start chat_id= active=1 +2026-07-17T15:38:51+00:00 [runtime] done chat_id= task_id= agent=chat_agent duration_ms=4153 answer_chars=180 +``` + +Watch the Telegram logs while the request is processed: + +```bash +docker logs --tail 10 openclaw-vllm +``` + +The recent log should include a successful local completion request similar to: + +```output +(APIServer pid=1) INFO: 172.18.0.7:48686 - "POST /v1/chat/completions HTTP/1.1" 200 OK +``` + +The request appearing in the local logs confirms the runtime path. The model's text alone isn't evidence that inference was local. + +## Execute test suites + +Run the repository tests from the host: + +```bash +OPENCLAW_OLLAMA_BASE_URL=http://127.0.0.1:11434 \ +OPENCLAW_QDRANT_BASE_URL=http://127.0.0.1:6333 \ +PYTHONPATH=app python3 -m unittest discover -s tests +``` + +The final lines are similar to: + +```output +Ran 121 tests in 4.256s +OK (skipped=5) +``` + +The count and time can change. `OK` confirms that the software behavior tests passed. These aren't hardware benchmarks. + +## What you've accomplished and what's next + +You've now deployed the personal reference runtime on NVIDIA DGX Spark, connected it to your Telegram bot, verified the local vLLM endpoint, and checked the runtime tests. + +Next, you'll use the deployment as a local-first household assistant and confirm that memory is stored in local Qdrant collections. diff --git a/content/learning-paths/laptops-and-desktops/openclaw_continuum/4_household_memory.md b/content/learning-paths/laptops-and-desktops/openclaw_continuum/4_household_memory.md new file mode 100644 index 0000000000..fcbb487e96 --- /dev/null +++ b/content/learning-paths/laptops-and-desktops/openclaw_continuum/4_household_memory.md @@ -0,0 +1,157 @@ +--- +title: Validate memory persistence and routing with Telegram and Qdrant +description: Store and retrieve synthetic household data through Telegram, verify its Qdrant persistence, and inspect OpenClaw agent routing and external weather requests. +weight: 5 + +### FIXED, DO NOT MODIFY +layout: learningpathall +--- + +## Define the household test scenario + +You'll create a shared household assistant to test local memory. You'll save and retrieve a synthetic maintenance reminder without sending it to a public cloud LLM. + +Telegram transports the messages. Ollama, Qdrant, and the local LLM process them on your host. + +{{% notice Note %}} +Household data is treated as shared data. You won't implement separate access control for each family member. +{{% /notice %}} + +## Store and query local memory + +Send the following command to the Telegram bot: + +```text +/mem #home The boiler should be inspected every October. +``` + +The runtime stores the reminder through the following path: + +```text +Telegram / Mem command + -> Memory skill + -> Ollama embedding + -> Qdrant collection: personal_tracker_memory +``` + +Wait for the confirmation, then retrieve the memory: + +```text +/rag memory: When should the boiler be inspected? +``` + +The response should mention October. + +![Telegram conversation showing the boiler reminder saved with the mem command and retrieved with the rag memory query#center](openclaw_telegram_2.jpg "Saving and retrieving a household memory in Telegram") + + +The retrieval request follows the following local path: + +```text +Telegram question + -> Ollama query embedding + -> Qdrant similarity search + -> Retrieved context + -> Local vLLM response + -> Telegram answer +``` + +## Verify Qdrant vector collections + +Confirm that the personal memory collection exists: + +```bash +curl http://127.0.0.1:6333/collections/personal_tracker_memory +``` + +The relevant fields are similar to: + +```output +{ + "result": { + "status": "green", + "optimizer_status": "ok", + "points_count": 102, + "config": { + "params": { + "vectors": { + "size": 768, + "distance": "Cosine" + }, + "on_disk_payload": true + } + } + }, + "status": "ok" +} +``` + +The point count depends on existing data. A `green` status with `optimizer_status` set to `ok` confirms collection health. The vector size of `768` matches `nomic-embed-text`. + +The collection metadata doesn't prove that the boiler reminder was stored. Query the point payload directly to verify the synthetic record: + +```bash +curl -sS -X POST \ + http://127.0.0.1:6333/collections/personal_tracker_memory/points/scroll \ + -H 'Content-Type: application/json' \ + -d '{ + "filter": { + "must": [ + { + "key": "text", + "match": { + "value": "#home The boiler should be inspected every October." + } + } + ] + }, + "limit": 5, + "with_payload": true, + "with_vector": false + }' +``` + +Look for the boiler reminder in the returned payload. The filter finds it even when the personal collection contains other records. This verifies the stored data directly instead of relying on the assistant's response. + +## Inspect active agents and task execution + +Send the following command to the Telegram bot: + +```text +/agents +``` + +The response lists the thin agents registered by the reference runtime, including memory, RAG, browser search, weather, and chat routes. + +To inspect recent tasks, send the following command to the Telegram bot: + +```text +/tasks last 5 +``` + +Task history shows which agent handled the request, its status, and its runtime. All routes use the configured LLM endpoint. + +## Test external skill integration + +Send a weather question in plain language: + +```text +Cambridge weather tomorrow +``` + +The runtime sends this question to the weather skill. Don't add `/search`, which selects the general browser worker instead. + +This request contacts the public [wttr.in](https://wttr.in/) weather service, but generation still uses the local model. + +Your household assistant should now: + +1. Save and retrieve the synthetic boiler reminder from Telegram. +2. Store the reminder in `personal_tracker_memory`. +3. Show the selected agent in `/agents` and `/tasks last 5`. +4. Return weather data through the external weather skill. + +## What you've accomplished and what's next + +You've now saved and retrieved a synthetic household memory, verified it in Qdrant, and inspected both local and external request paths. + +Next, you'll add document RAG, browser search, and a proactive cron reminder. diff --git a/content/learning-paths/laptops-and-desktops/openclaw_continuum/5_workflows.md b/content/learning-paths/laptops-and-desktops/openclaw_continuum/5_workflows.md new file mode 100644 index 0000000000..905ff210c4 --- /dev/null +++ b/content/learning-paths/laptops-and-desktops/openclaw_continuum/5_workflows.md @@ -0,0 +1,199 @@ +--- +title: Validate document RAG, web search, and proactive tasks +description: Run document RAG, deterministic browser search, and proactive Telegram cron workflows with OpenClaw, then verify local storage and runtime behavior. +weight: 6 + +### FIXED, DO NOT MODIFY +layout: learningpathall +--- + +## Ingest and query document RAG + +Create a small text file on the device where you use Telegram. + +{{% notice Note %}} +Telegram uploads files from the device running the client, not from DGX Spark, unless Telegram runs there. Common locations are `Downloads`, `Documents`, or `Desktop` on a computer, and `Downloads` in the Files app on a phone or tablet. +{{% /notice %}} + + +Use the following synthetic tutorial content: + +```text +Household heating maintenance notes + +Inspect the boiler every October. +Clean the heating filter on the first Saturday of every third month. +Keep the service reference number with the maintenance record. +``` + +Save the file as `household-maintenance.txt`, then upload it to your bot with the following caption: + +```text +/knowledge +``` + +The document follows the following path: + +```text +File on the Telegram client device + -> Telegram bot upload + -> DGX Spark workspace/inbox/knowledge/telegram + -> Memory watcher and Ollama embeddings + -> Qdrant collection: personal_knowledge_base +``` + +The `/knowledge` caption explicitly routes the file to document indexing. The runtime stores it under `workspace/inbox/knowledge/telegram/`, creates embeddings, and writes the chunks to `personal_knowledge_base`. + +The bot reports the stored filename with a timestamp prefix, similar to `20260717-180500-household-maintenance.txt`. Copy the filename from the response. + +Indexing runs in the background. Wait a few seconds, then check the memory watcher: + +```bash +docker logs --tail 30 openclaw-memory-watcher +``` + +In Telegram, ask a question using the returned filename. Replace `` with the filename reported by the bot: + +```text +/rag When should the heating filter be cleaned? +``` + +The filename limits retrieval to this upload, so existing records don't affect the result. A general `/rag` query without a filename searches all configured memory and knowledge collections. The screenshot shows a general query, but use the filename-specific command for this test. + +![Telegram conversation showing household-maintenance.txt uploaded with the knowledge caption, saved to personal_knowledge_base, and retrieved with a general rag question#center](openclaw_telegram_3.jpg "Uploading and querying a household document in Telegram") + +The answer should mention the first Saturday of every third month. + +To verify the stored document directly in Qdrant, filter the collection by the returned filename: + +```bash +curl -sS -X POST \ + http://127.0.0.1:6333/collections/personal_knowledge_base/points/scroll \ + -H 'Content-Type: application/json' \ + -d '{ + "filter": { + "must": [ + { + "key": "file_name", + "match": { + "value": "" + } + } + ] + }, + "limit": 5, + "with_payload": true, + "with_vector": false + }' +``` + +The payload should contain chunks from `household-maintenance.txt`, confirming that Qdrant stored and indexed the upload. + +## Execute deterministic web search + +Use the browser agent for current public information. Send the following command to the bot: + +```text +/search Arm Learning Paths local AI development +``` + +The explicit `/search` prefix selects the browser-search route deterministically: + +```text +Telegram /search command + -> Browser-search agent + -> Local Playwright worker + -> Public search engine and selected pages + -> Local vLLM summary + -> Telegram answer +``` + +The query and page requests leave the local network. Playwright saves the retrieved content under `workspace/inbox/tracker/web/`, and local vLLM generates the answer. + +Confirm that the browser worker handled the request: + +```bash +docker logs --tail 20 openclaw-browser-scraper +``` + +Look for a successful `POST /scrape` request. The Telegram response should cite the retrieved sources and include the path to the saved web Markdown file. + +Finally, send the following command in Telegram: + +```text +/tasks last 5 +``` + +Confirm that the search task reports `browser_search_agent`. + +## Schedule proactive cron tasks + +Choose a time a few minutes in the future, using `OPENCLAW_CRON_TIMEZONE`. + +Create a daily reminder, replacing `21:15` with your test time: + +```text +/cron add daily 21:15 Heating check :: Remind the household to review the heating maintenance notes. +``` + +Then, list the job in Telegram: + +```text +/cron list +``` + +The bot returns a job ID, and `/cron list` shows the schedule as `[on]`. + +![Telegram conversation showing a daily Heating check cron job created, listed as enabled, and triggered at the configured time#center](openclaw_telegram_4.jpg "Creating and triggering a scheduled reminder in Telegram") + +Creating the job doesn't run it immediately. At the configured time, the bot sends the Heating check message. + +After the configured time, verify that the cron worker delivered the scheduled job: + +```bash +docker logs --tail 30 openclaw-cron +``` + +Look for a line containing `[cron] dynamic job sent`, the job ID, and the path to the locally saved cron report. + +To test without waiting, copy the job ID from `/cron list` and send: + +```text +/cron run +``` + +The result should be delivered as a Telegram push message. + +## Inspect cron from the gateway dashboard + +The Gateway dashboard listens on localhost. If you're working directly on the DGX Spark desktop, open: + +```text +http://127.0.0.1:18789/ +``` + +If DGX Spark is remote, create an SSH tunnel from your laptop: + +```bash +ssh -L 18789:127.0.0.1:18789 @ +``` + +Replace `` with your DGX Spark user name and `` with its host name or IP address. + +Then open `http://127.0.0.1:18789/` locally and enter the `OPENCLAW_GATEWAY_TOKEN` stored in the private `.env` file. + +Confirm that the dashboard and Telegram show the same cron job and run history. + +{{% notice Warning %}} +Keep the Gateway and its admin RPC endpoint behind localhost, an SSH tunnel, or a trusted private network. Don't expose the dashboard directly to the public internet. +{{% /notice %}} + +You've now validated three runtime paths. Document questions use the RAG skill, Qdrant, and the local LLM. Current public queries use the browser-search agent and Playwright. Proactive reminders run through the cron worker and arrive as Telegram messages. + +The LLM is one replaceable part of the application. The local memory, tools, schedules, and interaction paths remain available around it. + +## What you've learned and what's next + +You've now validated document RAG, explicit browser search, and a proactive reminder for the household assistant. + +You can optionally extend the same workflow to a CPU-only Armv9 system. For more information, see [(Optional) Port the app to a CPU-only Armv9 system](/learning-paths/laptops-and-desktops/openclaw_continuum/6_cpu_only/). You've moved beyond a local-model demo and built a self-managed OpenClaw-based runtime that you can adapt to different Arm compute configurations. diff --git a/content/learning-paths/laptops-and-desktops/openclaw_continuum/6_cpu_only.md b/content/learning-paths/laptops-and-desktops/openclaw_continuum/6_cpu_only.md new file mode 100644 index 0000000000..f2df9ee4db --- /dev/null +++ b/content/learning-paths/laptops-and-desktops/openclaw_continuum/6_cpu_only.md @@ -0,0 +1,351 @@ +--- +title: (Optional) Port the app to a CPU-only Armv9 system +description: Port the OpenClaw workflow from NVIDIA DGX Spark to a CPU-only Armv9 system with llama.cpp, then validate shared services, routing, and data boundaries. +weight: 7 + +### FIXED, DO NOT MODIFY +layout: learningpathall +--- + +## Cross-platform portability + +You can optionally move the runtime from NVIDIA DGX Spark to a CIX-based Radxa Orion O6 running Debian 12. `llama.cpp` provides local generation on the Armv9 CPU. + +The Telegram interface, local memory and RAG, browser search, scheduled workflows, and deterministic routing remain unchanged. Only the local generation backend changes: + +| Platform | Local generation backend | Runtime API contract | +|---|---|---| +| NVIDIA DGX Spark | vLLM | OpenAI-compatible API | +| Radxa Orion O6 | `llama.cpp` | OpenAI-compatible API | + +{{% notice Note %}} +These backends match the environments used in this Learning Path and in the [Run ERNIE-4.5 Mixture of Experts model on Armv9 with `llama.cpp`](/learning-paths/cross-platform/ernie_moe_v9/) Learning Path. You can use another local backend with a compatible OpenAI chat-completions API. +{{% /notice %}} + +## Verify system requirements on Armv9 host + +On Orion O6, confirm the operating system, architecture, CPU features, memory, and disk capacity: + +```bash +uname -a +cat /etc/os-release +lscpu +free -h +df -h / +``` + +Confirm that the host reports `aarch64` and has enough available memory and storage for the selected GGUF model and containers. + +## Prepare llama.cpp and the ERNIE model + +To set up `llama.cpp` and the ERNIE model, see [Set up `llama.cpp` on an Armv9 development board](/learning-paths/cross-platform/ernie_moe_v9/2_llamacpp_installation/). Install the dependencies, compile `llama.cpp`, download the ERNIE-4.5 Thinking Q4 GGUF model, and run its basic inference test. + +The following commands use these installation paths: + +```text +$HOME/llama.cpp/build/bin/llama-server +$HOME/models/ernie-4.5/ERNIE-4.5-21B-A3B-Thinking-Q4_0.gguf +``` + +## Deploy llama.cpp OpenAI-compatible server + +Start the server on the host: + +```bash +cd $HOME/llama.cpp + +./build/bin/llama-server \ + --jinja \ + -m $HOME/models/ernie-4.5/ERNIE-4.5-21B-A3B-Thinking-Q4_0.gguf \ + -c 2048 \ + -t 12 \ + --host 127.0.0.1 \ + --port 8080 +``` + +From another shell, inspect the model endpoint: + +```bash +curl http://127.0.0.1:8080/v1/models +``` + +Send a short completion request: + +```bash +curl -sS http://127.0.0.1:8080/v1/chat/completions \ + -H 'Content-Type: application/json' \ + -d '{ + "model": "ernie-o6", + "messages": [{"role":"user","content":"Reply with one sentence about local AI on Arm."}], + "max_tokens": 80, + "temperature": 0.2 + }' +``` + +Don't continue until this local endpoint generates a valid response. + +Press `Ctrl+C` in the server shell after the smoke test. Create a user `systemd` service so that `llama.cpp` starts automatically and restarts after a failure: + +```bash +mkdir -p $HOME/.config/systemd/user + +tee $HOME/.config/systemd/user/openclaw-llama.service > /dev/null <<'EOF' +[Unit] +Description=llama.cpp server for the OpenClaw-based runtime +Wants=network-online.target +After=network-online.target + +[Service] +Type=simple +ExecStart=%h/llama.cpp/build/bin/llama-server --jinja -m %h/models/ernie-4.5/ERNIE-4.5-21B-A3B-Thinking-Q4_0.gguf -c 2048 -t 12 --host 127.0.0.1 --port 8080 +Restart=on-failure +RestartSec=5 + +[Install] +WantedBy=default.target +EOF +``` + +Enable the service and allow it to remain active when you log out: + +```bash +systemctl --user daemon-reload +systemctl --user enable --now openclaw-llama.service +sudo loginctl enable-linger $USER +systemctl --user status openclaw-llama.service --no-pager +``` + +Confirm that the managed endpoint responds: + +```bash +curl http://127.0.0.1:8080/v1/models +``` + +## Provision supporting local services + +Install Ollama on the Orion O6 host: + +```bash +curl -fsSL https://ollama.com/install.sh | sh +sudo systemctl enable --now ollama +``` + +The CPU-only compose file uses host networking, so its containers can reach Ollama through `127.0.0.1:11434`. Pull the embedding model: + +```bash +ollama pull nomic-embed-text +``` + +Confirm that Ollama responds and lists `nomic-embed-text`: + +```bash +curl http://127.0.0.1:11434/api/tags +``` + +Check whether the Qdrant container already exists: + +```bash +docker ps -a --filter name=openclaw-qdrant +``` + +If the container already exists, start it: + +```bash +docker start openclaw-qdrant +``` + +Otherwise, create persistent storage and start Qdrant. Bind its ports to `localhost`: + +```bash +docker volume create openclaw-qdrant-data + +docker run -d \ + --name openclaw-qdrant \ + --restart unless-stopped \ + -p 127.0.0.1:6333:6333 \ + -p 127.0.0.1:6334:6334 \ + -v openclaw-qdrant-data:/qdrant/storage \ + qdrant/qdrant:latest +``` + +Confirm that the local API responds: + +```bash +curl http://127.0.0.1:6333/collections +``` + +## Configure the CPU-only runtime environment + +Clone the same release on Orion O6: + +```bash +cd $HOME +git clone https://github.com/odincodeshen/openclaw-arm-continuum.git +cd openclaw-arm-continuum +git checkout v1.2 +cp .env.arm-cpu-only.example .env +``` + +Create a separate bot for this runtime with the [Telegram Bot tutorial](https://core.telegram.org/bots/tutorial). Don't reuse the DGX Spark bot token because two polling runtimes can compete for its updates. Have each account send a message to the new bot, then repeat the `getUpdates` process from the DGX Spark setup to obtain each `message.chat.id` value. + +Generate a new Gateway token: + +```bash +openssl rand -hex 32 +``` + +Set the new bot and private tokens in `.env`: + +```text +OPENCLAW_TELEGRAM_BOT_TOKEN= +OPENCLAW_TELEGRAM_ALLOWED_CHAT_IDS=, +OPENCLAW_CRON_CHAT_IDS=, +OPENCLAW_GATEWAY_TOKEN= +OPENCLAW_CRON_TIMEZONE= +``` + +Separate multiple chat IDs with commas. Use the same IANA timezone format as before; scheduled jobs use UTC if you omit it. + +Confirm the inference settings: + +```text +OPENCLAW_VLLM_BASE_URL=http://127.0.0.1:8080/v1 +OPENCLAW_VLLM_MODEL=ernie-o6 +OPENCLAW_VISION_ENABLED=false +OPENCLAW_TRACKER_COLLECTION=personal_tracker_memory +OPENCLAW_KNOWLEDGE_COLLECTION=personal_knowledge_base +``` + +The `VLLM` variable name is retained for compatibility, but it can point to `llama.cpp`. + +Using the same collection names keeps the configuration consistent, but it doesn't copy Qdrant data from DGX Spark. Each host keeps its own data. + +Keep the CPU-only context small and disable unused voice transcription: + +```text +OPENCLAW_MAX_TOKENS=128 +OPENCLAW_RETRIEVAL_LIMIT=3 +OPENCLAW_SCRAPER_LIMIT=2 +OPENCLAW_WEB_CONTEXT_CHARS=1800 +OPENCLAW_WHISPER_ENABLED=false +``` + +## Launch the CPU-only application stack + +Start the full tutorial stack: + +```bash +docker compose \ + --env-file .env \ + -f compose.arm-cpu-only.yaml \ + --profile web \ + --profile gateway \ + up -d +``` + +Check the services: + +```bash +docker compose --env-file .env -f compose.arm-cpu-only.yaml ps +docker logs --tail 80 openclaw-telegram +docker logs --tail 80 openclaw-memory-watcher +docker logs --tail 80 openclaw-cron +``` + +Confirm that the browser worker can resolve a public hostname: + +```bash +docker exec openclaw-browser-scraper python -c "import socket; print(socket.gethostbyname('duckduckgo.com'))" +``` + +{{% notice Note %}} +If this command can't resolve the hostname, inspect the Orion host DNS configuration with `cat /etc/resolv.conf`. Then update `OPENCLAW_DNS_SERVER_1` and `OPENCLAW_DNS_SERVER_2` in `.env` with DNS servers that are reachable from your network, restart the stack, and run the check again. +{{% /notice %}} + +## Validate shared workflows on CPU + +Test the CPU-only deployment with a budget assistant shared by two household members. + +Create a file named `budget.txt` on the device that you use Telegram on: + +```text +Shared household weekly budget: £120. +``` + +Upload the file with the `/knowledge` caption and copy the filename returned by the bot. Each allowlisted household member can then add a synthetic expense from their own chat: + +```text +/mem #budget Groceries: £45. +/mem #budget Household supplies: £20. +``` + +After both entries are saved, either member can ask: + +```text +/rag Based on the shared budget and the saved budget entries, how much remains? +``` + +Replace `` with the filename that was returned when you uploaded `budget.txt`. + +The response should report that £55 remains. Both members use the same local collection, without separate per-member access controls. + +The response alone doesn't prove which inference backend generated it. Inspect the Telegram runtime log: + +```bash +docker logs --tail 20 openclaw-telegram +``` + +Look for the memory write handled by `memory_agent` and the completed retrieval request handled by `rag_agent`. Then, inspect the `llama.cpp` service log: + +```bash +journalctl --user -u openclaw-llama.service -n 30 --no-pager +``` + +Look for a successful request to `/v1/chat/completions`. The Telegram response and both log entries confirm that the OpenClaw-based workflow is now using `llama.cpp` for local generation on the Armv9 CPU. + +## Compare Arm deployment architectures + +You've now built a local-first household assistant with memory, document RAG, browser search, and scheduled notifications. You ran the assistant with vLLM on NVIDIA DGX Spark, then moved it to `llama.cpp` on Radxa Orion O6. + +The following comparison shows what stayed the same across the two Arm-based implementations and what changed with the local generation backend: + +| Layer | NVIDIA DGX Spark | Radxa Orion O6 | +|---|---|---| +| Reference runtime services | Same services | Same services | +| User interface | Telegram | Telegram | +| Skills | Memory, RAG, search, weather, cron | Same skills | +| Vector memory | Qdrant | Qdrant | +| Embeddings | Ollama | Ollama | +| Generation API | OpenAI-compatible | OpenAI-compatible | +| Generation engine | vLLM | `llama.cpp` | +| Inference compute | Arm CPU + NVIDIA GPU | Arm CPU | + +Each platform uses model and context settings suited to its compute while preserving the same application contract. + +## Review data privacy boundaries + +The runtime keeps the following under your control: + +- Inference requests +- Generated context +- Qdrant collections +- Uploaded files +- Cron history +- OpenClaw tasks +- Gateway state + +Telegram still transports messages and uploads. Weather and browser searches contact public services, while setup downloads models and containers from external registries. + +For sensitive deployments, review network exposure, Telegram suitability, host access, backups, model provenance, and the contents of every enabled tool. + +## What you've accomplished + +You've now moved the OpenClaw-based runtime from DGX Spark to a CPU-only Armv9 system by replacing the inference endpoint. + +The same endpoint-driven design can support additional deployment shapes: + +- An always-on CPU-only Arm server with a compact local model +- An Arm edge gateway connected to a trusted private-LAN inference server +- A heterogeneous Arm AI workstation hosting larger local models + +Each deployment changes the compute and trust boundary. It shouldn't silently change where personal data is stored or which external services are contacted. From d70590c578f589d7038e9059941413c01b7e47c0 Mon Sep 17 00:00:00 2001 From: anupras-mohapatra-arm Date: Mon, 10 Aug 2026 11:20:52 -0500 Subject: [PATCH 06/12] updates --- .../laptops-and-desktops/openclaw_continuum/2_dgx_deploy.md | 6 +++--- .../openclaw_continuum/3_dgx_runtime_deploy.md | 2 +- .../laptops-and-desktops/openclaw_continuum/5_workflows.md | 4 +++- .../laptops-and-desktops/openclaw_continuum/6_cpu_only.md | 2 +- 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/content/learning-paths/laptops-and-desktops/openclaw_continuum/2_dgx_deploy.md b/content/learning-paths/laptops-and-desktops/openclaw_continuum/2_dgx_deploy.md index 7b6b50b3a5..82838a2014 100644 --- a/content/learning-paths/laptops-and-desktops/openclaw_continuum/2_dgx_deploy.md +++ b/content/learning-paths/laptops-and-desktops/openclaw_continuum/2_dgx_deploy.md @@ -23,7 +23,7 @@ aarch64 ``` {{% notice Note %}} -You'll use Docker Engine and Docker Compose to run services on your DGX Spark. For Docker installation steps, see the [Install Docker Engine](https://learn.arm.com/install-guides/docker/docker-engine/). +You'll use Docker Engine and Docker Compose to run services on your DGX Spark. For Docker installation steps, see the [Docker Engine install guide](https://learn.arm.com/install-guides/docker/docker-engine/). {{% /notice %}} Confirm Docker GPU access: @@ -32,9 +32,9 @@ Confirm Docker GPU access: docker run --rm --gpus all ubuntu nvidia-smi ``` -You don't need to install the vLLM Python package or start a vLLM server directly on the DGX Spark host. The project's `compose.yaml` pulls a container image that already includes vLLM and starts the local inference server for you. +Install the NVIDIA driver and NVIDIA Container Toolkit so that this container can access the GPU. -You need to install the NVIDIA driver and NVIDIA Container Toolkit so that this container can access the GPU. +You don't need to install the vLLM Python package or start a vLLM server directly on the DGX Spark host. The project's `compose.yaml` pulls a container image that already includes vLLM and starts the local inference server for you. ## Configure Ollama for local embeddings diff --git a/content/learning-paths/laptops-and-desktops/openclaw_continuum/3_dgx_runtime_deploy.md b/content/learning-paths/laptops-and-desktops/openclaw_continuum/3_dgx_runtime_deploy.md index 63afa1821b..632df78bae 100644 --- a/content/learning-paths/laptops-and-desktops/openclaw_continuum/3_dgx_runtime_deploy.md +++ b/content/learning-paths/laptops-and-desktops/openclaw_continuum/3_dgx_runtime_deploy.md @@ -29,7 +29,7 @@ For more information about creating and managing bots, see the official [Telegra Next, obtain the chat ID for your Telegram account: -1. Open a chat with the bot that you created and send a test message, such as `Hello`. This creates an update that the Telegram Bot API can return. +1. Open a chat with the bot that you created and send a test message, such as `Hello`. The message creates an update that the Telegram Bot API can return. 2. Open a terminal on your local machine and query the updates. Replace `` with the HTTP API token from BotFather: ```bash diff --git a/content/learning-paths/laptops-and-desktops/openclaw_continuum/5_workflows.md b/content/learning-paths/laptops-and-desktops/openclaw_continuum/5_workflows.md index 905ff210c4..b5d6f5082e 100644 --- a/content/learning-paths/laptops-and-desktops/openclaw_continuum/5_workflows.md +++ b/content/learning-paths/laptops-and-desktops/openclaw_continuum/5_workflows.md @@ -196,4 +196,6 @@ The LLM is one replaceable part of the application. The local memory, tools, sch You've now validated document RAG, explicit browser search, and a proactive reminder for the household assistant. -You can optionally extend the same workflow to a CPU-only Armv9 system. For more information, see [(Optional) Port the app to a CPU-only Armv9 system](/learning-paths/laptops-and-desktops/openclaw_continuum/6_cpu_only/). You've moved beyond a local-model demo and built a self-managed OpenClaw-based runtime that you can adapt to different Arm compute configurations. +You can optionally extend the same workflow to a CPU-only Armv9 system. For more information, see [(Optional) Port the app to a CPU-only Armv9 system](/learning-paths/laptops-and-desktops/openclaw_continuum/6_cpu_only/). + +You've moved beyond a local-model demo and built a self-managed OpenClaw-based runtime that you can adapt to different Arm compute configurations. diff --git a/content/learning-paths/laptops-and-desktops/openclaw_continuum/6_cpu_only.md b/content/learning-paths/laptops-and-desktops/openclaw_continuum/6_cpu_only.md index f2df9ee4db..f3a3d9a8fe 100644 --- a/content/learning-paths/laptops-and-desktops/openclaw_continuum/6_cpu_only.md +++ b/content/learning-paths/laptops-and-desktops/openclaw_continuum/6_cpu_only.md @@ -47,7 +47,7 @@ $HOME/llama.cpp/build/bin/llama-server $HOME/models/ernie-4.5/ERNIE-4.5-21B-A3B-Thinking-Q4_0.gguf ``` -## Deploy llama.cpp OpenAI-compatible server +## Deploy a llama.cpp OpenAI-compatible server Start the server on the host: From 5885e69b85544d5e0ae32418da040880eb16a9c1 Mon Sep 17 00:00:00 2001 From: anupras-mohapatra-arm Date: Mon, 10 Aug 2026 11:30:20 -0500 Subject: [PATCH 07/12] nit --- .../openclaw_continuum/4_household_memory.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/learning-paths/laptops-and-desktops/openclaw_continuum/4_household_memory.md b/content/learning-paths/laptops-and-desktops/openclaw_continuum/4_household_memory.md index fcbb487e96..4fe6ce8ea9 100644 --- a/content/learning-paths/laptops-and-desktops/openclaw_continuum/4_household_memory.md +++ b/content/learning-paths/laptops-and-desktops/openclaw_continuum/4_household_memory.md @@ -45,7 +45,7 @@ The response should mention October. ![Telegram conversation showing the boiler reminder saved with the mem command and retrieved with the rag memory query#center](openclaw_telegram_2.jpg "Saving and retrieving a household memory in Telegram") -The retrieval request follows the following local path: +The retrieval request uses the following local path: ```text Telegram question From a6d05b0b8d1165b90c704ef66718755864d195bd Mon Sep 17 00:00:00 2001 From: anupras-mohapatra-arm Date: Mon, 10 Aug 2026 11:32:35 -0500 Subject: [PATCH 08/12] nit --- .../laptops-and-desktops/openclaw_continuum/5_workflows.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/learning-paths/laptops-and-desktops/openclaw_continuum/5_workflows.md b/content/learning-paths/laptops-and-desktops/openclaw_continuum/5_workflows.md index b5d6f5082e..de5090719c 100644 --- a/content/learning-paths/laptops-and-desktops/openclaw_continuum/5_workflows.md +++ b/content/learning-paths/laptops-and-desktops/openclaw_continuum/5_workflows.md @@ -32,7 +32,7 @@ Save the file as `household-maintenance.txt`, then upload it to your bot with th /knowledge ``` -The document follows the following path: +The document uses the following path: ```text File on the Telegram client device From 441fb2ff18396541246ef1990f6d1dcdf003c156 Mon Sep 17 00:00:00 2001 From: anupras-mohapatra-arm Date: Mon, 10 Aug 2026 11:38:32 -0500 Subject: [PATCH 09/12] nit --- .../laptops-and-desktops/openclaw_continuum/_index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/learning-paths/laptops-and-desktops/openclaw_continuum/_index.md b/content/learning-paths/laptops-and-desktops/openclaw_continuum/_index.md index afae5e27f7..d6f90a52e1 100644 --- a/content/learning-paths/laptops-and-desktops/openclaw_continuum/_index.md +++ b/content/learning-paths/laptops-and-desktops/openclaw_continuum/_index.md @@ -11,7 +11,7 @@ learning_objectives: - Explain the local and external data boundaries of an OpenClaw-based runtime - Deploy and validate the reference runtime with local vLLM inference on NVIDIA DGX Spark - Verify persistent memory, document RAG, explicit browser search, deterministic routing, and proactive scheduling with Telegram and Qdrant - - (Optional) Move the same application workflows to a CPU-only Armv9 system through an OpenAI-compatible llama.cpp endpoint + - Optionally move the same application workflows to a CPU-only Armv9 system through an OpenAI-compatible llama.cpp endpoint prerequisites: - An NVIDIA DGX Spark system with NVIDIA drivers, Docker and NVIDIA Container Toolkit From fd90bd03ed70657cd95de7c13f5df2be1439c928 Mon Sep 17 00:00:00 2001 From: anupras-mohapatra-arm Date: Mon, 10 Aug 2026 11:40:01 -0500 Subject: [PATCH 10/12] grammar --- .../laptops-and-desktops/openclaw_continuum/_index.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/content/learning-paths/laptops-and-desktops/openclaw_continuum/_index.md b/content/learning-paths/laptops-and-desktops/openclaw_continuum/_index.md index d6f90a52e1..9a26d52552 100644 --- a/content/learning-paths/laptops-and-desktops/openclaw_continuum/_index.md +++ b/content/learning-paths/laptops-and-desktops/openclaw_continuum/_index.md @@ -8,10 +8,10 @@ minutes_to_complete: 120 who_is_this_for: This is an advanced topic for developers who want to extend OpenClaw into a customizable local-first assistant with persistent memory, document RAG, explicit browser search, deterministic routing, and proactive scheduling. learning_objectives: - - Explain the local and external data boundaries of an OpenClaw-based runtime - - Deploy and validate the reference runtime with local vLLM inference on NVIDIA DGX Spark - - Verify persistent memory, document RAG, explicit browser search, deterministic routing, and proactive scheduling with Telegram and Qdrant - - Optionally move the same application workflows to a CPU-only Armv9 system through an OpenAI-compatible llama.cpp endpoint + - Explain the local and external data boundaries of an OpenClaw-based runtime. + - Deploy and validate the reference runtime with local vLLM inference on NVIDIA DGX Spark. + - Verify persistent memory, document RAG, explicit browser search, deterministic routing, and proactive scheduling with Telegram and Qdrant. + - Optionally move the same application workflows to a CPU-only Armv9 system through an OpenAI-compatible llama.cpp endpoint. prerequisites: - An NVIDIA DGX Spark system with NVIDIA drivers, Docker and NVIDIA Container Toolkit From 6775764694b5eaa4c6950c5f49a735aa21ad94e5 Mon Sep 17 00:00:00 2001 From: anupras-mohapatra-arm Date: Mon, 10 Aug 2026 12:12:47 -0500 Subject: [PATCH 11/12] edits --- .../openclaw_continuum/1_architecture.md | 4 ++-- .../openclaw_continuum/3_dgx_runtime_deploy.md | 4 ++-- .../openclaw_continuum/4_household_memory.md | 2 +- .../openclaw_continuum/5_workflows.md | 9 ++++++--- .../openclaw_continuum/6_cpu_only.md | 2 +- 5 files changed, 12 insertions(+), 9 deletions(-) diff --git a/content/learning-paths/laptops-and-desktops/openclaw_continuum/1_architecture.md b/content/learning-paths/laptops-and-desktops/openclaw_continuum/1_architecture.md index 743c8fd08a..6744a47c58 100644 --- a/content/learning-paths/laptops-and-desktops/openclaw_continuum/1_architecture.md +++ b/content/learning-paths/laptops-and-desktops/openclaw_continuum/1_architecture.md @@ -34,7 +34,7 @@ Local-first doesn't mean that every byte stays offline. Telegram and web search The runtime doesn't use a public cloud LLM API. Telegram transports bot messages, and browser searches send requests to external websites. {{% notice Note %}} -Don't enter real personal, household, or organizational information. Instead, use synthetic or public data. If the host already contains personal runtime data, set the environment variables in the next section. +Don't enter real personal, household, or organizational information. Instead, use synthetic or public data. If the host already contains personal runtime data, set environment variables by following the instructions in [Configure and start the OpenClaw runtime on DGX Spark](/learning-paths/laptops-and-desktops/openclaw_continuum/3_dgx_runtime_deploy/). {{% /notice %}} ## Trace the application request path @@ -73,4 +73,4 @@ Both expose an OpenAI-compatible chat-completions API, so only the configured en You now understand the runtime components, data boundary, and shared inference API. -Next, you'll deploy the baseline runtime on NVIDIA DGX Spark. +Next, you'll prepare the NVIDIA DGX Spark and configure Ollama and Qdrant. diff --git a/content/learning-paths/laptops-and-desktops/openclaw_continuum/3_dgx_runtime_deploy.md b/content/learning-paths/laptops-and-desktops/openclaw_continuum/3_dgx_runtime_deploy.md index 632df78bae..f2e43b5f44 100644 --- a/content/learning-paths/laptops-and-desktops/openclaw_continuum/3_dgx_runtime_deploy.md +++ b/content/learning-paths/laptops-and-desktops/openclaw_continuum/3_dgx_runtime_deploy.md @@ -15,7 +15,7 @@ You need a Telegram account, a bot token, and the numeric chat ID for the accoun To create a bot and obtain its token: -1. Open Telegram and start a chat with **BotFather**. +1. Open Telegram and start a chat with BotFather. 2. Send the following command: ```text @@ -92,7 +92,7 @@ OPENCLAW_CRON_TIMEZONE= Scheduled jobs use UTC when this setting is omitted. -You'll name the location explicitly when asking weather-related, so you don't need to configure `OPENCLAW_DEFAULT_WEATHER_LOCATION`. +You'll name the location explicitly when asking weather-related questions, so you don't need to configure `OPENCLAW_DEFAULT_WEATHER_LOCATION`. {{% notice Note %}} Don't share your Telegram bot token or chat ID with anyone, and don't include them in screenshots, logs, or public repositories. diff --git a/content/learning-paths/laptops-and-desktops/openclaw_continuum/4_household_memory.md b/content/learning-paths/laptops-and-desktops/openclaw_continuum/4_household_memory.md index 4fe6ce8ea9..774f5c15d5 100644 --- a/content/learning-paths/laptops-and-desktops/openclaw_continuum/4_household_memory.md +++ b/content/learning-paths/laptops-and-desktops/openclaw_continuum/4_household_memory.md @@ -40,7 +40,7 @@ Wait for the confirmation, then retrieve the memory: /rag memory: When should the boiler be inspected? ``` -The response should mention October. +The response should mention October: ![Telegram conversation showing the boiler reminder saved with the mem command and retrieved with the rag memory query#center](openclaw_telegram_2.jpg "Saving and retrieving a household memory in Telegram") diff --git a/content/learning-paths/laptops-and-desktops/openclaw_continuum/5_workflows.md b/content/learning-paths/laptops-and-desktops/openclaw_continuum/5_workflows.md index de5090719c..6b7186823e 100644 --- a/content/learning-paths/laptops-and-desktops/openclaw_continuum/5_workflows.md +++ b/content/learning-paths/laptops-and-desktops/openclaw_continuum/5_workflows.md @@ -58,11 +58,14 @@ In Telegram, ask a question using the returned filename. Replace ` When should the heating filter be cleaned? ``` -The filename limits retrieval to this upload, so existing records don't affect the result. A general `/rag` query without a filename searches all configured memory and knowledge collections. The screenshot shows a general query, but use the filename-specific command for this test. +The filename limits retrieval to this upload, so existing records don't affect the result. A general `/rag` query without a filename searches all configured memory and knowledge collections. + +The following screenshot shows a general query: ![Telegram conversation showing household-maintenance.txt uploaded with the knowledge caption, saved to personal_knowledge_base, and retrieved with a general rag question#center](openclaw_telegram_3.jpg "Uploading and querying a household document in Telegram") -The answer should mention the first Saturday of every third month. + +Use the command with the filename for this test. The answer should mention the first Saturday of every third month. To verify the stored document directly in Qdrant, filter the collection by the returned filename: @@ -142,7 +145,7 @@ Then, list the job in Telegram: /cron list ``` -The bot returns a job ID, and `/cron list` shows the schedule as `[on]`. +The bot returns a job ID, and `/cron list` shows the schedule as `[on]`: ![Telegram conversation showing a daily Heating check cron job created, listed as enabled, and triggered at the configured time#center](openclaw_telegram_4.jpg "Creating and triggering a scheduled reminder in Telegram") diff --git a/content/learning-paths/laptops-and-desktops/openclaw_continuum/6_cpu_only.md b/content/learning-paths/laptops-and-desktops/openclaw_continuum/6_cpu_only.md index f3a3d9a8fe..df5ac76773 100644 --- a/content/learning-paths/laptops-and-desktops/openclaw_continuum/6_cpu_only.md +++ b/content/learning-paths/laptops-and-desktops/openclaw_continuum/6_cpu_only.md @@ -121,7 +121,7 @@ Confirm that the managed endpoint responds: curl http://127.0.0.1:8080/v1/models ``` -## Provision supporting local services +## Provision Ollama and Qdrant Install Ollama on the Orion O6 host: From 94c15e2e938bae4c0cf3e307bb89e3fa1310429e Mon Sep 17 00:00:00 2001 From: anupras-mohapatra-arm Date: Mon, 10 Aug 2026 12:18:26 -0500 Subject: [PATCH 12/12] adding a note --- .../openclaw_continuum/3_dgx_runtime_deploy.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/content/learning-paths/laptops-and-desktops/openclaw_continuum/3_dgx_runtime_deploy.md b/content/learning-paths/laptops-and-desktops/openclaw_continuum/3_dgx_runtime_deploy.md index f2e43b5f44..5e0d3517aa 100644 --- a/content/learning-paths/laptops-and-desktops/openclaw_continuum/3_dgx_runtime_deploy.md +++ b/content/learning-paths/laptops-and-desktops/openclaw_continuum/3_dgx_runtime_deploy.md @@ -144,7 +144,9 @@ Start the complete DGX Spark stack: docker compose --env-file .env -f compose.yaml up -d ``` +{{% notice Note %}} The first start takes longer than subsequent starts because vLLM downloads the approximately 30 GiB Qwen model before loading it. The download time depends on your network connection and can make the initial startup longer. Subsequent starts use the cached model. A running container doesn't mean that its API is ready. +{{% /notice %}} Check service status and API readiness: