# Phase 1: Platform mental model

Understand how the Viam cloud, agent, and server fit together, and configure your first resource, the arm.
> Source: https://docs.viam.com/tutorials/pick-and-place/platform-mental-model/


This phase introduces you to Viam machine management and gives you the mental map you need before the rest of the workshop: what happens when you make an API call, why config changes appear instantly on the robot, and how Python code on your laptop talks to hardware across the room. You will configure your first resource as you go.

## Three questions to consider

By the end of this phase you should be able to answer the following questions. Keep them in mind as you read, and check yourself against them again at the end.

1. What are the three layers of a Viam machine, and which one does your Python code actually talk to?
2. What is the difference between a component and a service?
3. Why does adding the arm component to the machine trigger a module download?

You will not write any code in this phase, but you will configure your first resource, the arm, so the concepts below have something real to point at. Open your own machine in the Viam app and follow along.

## The three layers

<!-- ASSET P0 diagram-three-layers (DIAGRAM): cloud app (source of truth) -> viam-server pulls config; viam-agent supervises; SDK arrow to viam-server. See plans/2026-07-02-pick-and-place-shot-list.md -->

```text
Viam cloud app
  └─ machine configuration  (the source of truth)
           │
           │  viam-server pulls config
           ▼
The robot's computer
  ├─ viam-agent    supervises viam-server (installs, updates, restarts)
  └─ viam-server   runs components and services, exposes the control API
           ▲
           │  control API calls
           │
Your Python script (on your laptop)
```

A Viam machine is made of three layers that each do one job:

- **The Viam cloud app** is the source of truth for configuration. When you add a component, change an attribute, or wire up a service, you are editing a JSON document stored in the cloud. The app never controls your robot directly; it describes what should run. Later, when you click **Grab** on the gripper card or jog the arm from the **Control** tab, that action does not go through this config path either: the app's browser page sends the control call straight to `viam-server`, the same as the Python scripts you write later, so the cloud app still is not in the loop for control, only the Control tab's UI is.
- **viam-agent** is a service that runs on the computer controlling the arm. viam-agent manages `viam-server`: it installs, updates, and keeps `viam-server` running, restarts the server if it crashes, and provides the initial bootstrap credentials viam-server needs to reach the cloud. Think of viam-agent as the process supervisor, not as the source of your resource config, and not as something you interact with directly during this workshop.
- **viam-server** pulls the machine resource configuration from the cloud app, starts every component and service that configuration describes, and exposes the components and services over an API. This is the layer that handles the modules that drive the arm, reads the camera, and runs the vision pipeline.

Open your machine's overview page in the Viam app now and find the status indicator that shows the machine is live. That indicator reflects viam-agent keeping viam-server running and connected to the cloud app, the handoff between all three layers happening continuously in the background.

## How your SDK connects

When a Python script imports the Viam SDK and connects to your machine, the connection goes to `viam-server`, not to the cloud app. The cloud app helps your script locate the machine and authenticate, but once the connection is established, every control API call goes directly to `viam-server` on the robot: moving the arm, reading the camera, calling the vision service. You will write exactly this kind of script later in the workshop.

This matters because it explains why your script keeps working even if your laptop briefly loses its connection to the internet at large but keeps a path to the robot: the cloud app is not in the request path for control, only for discovery and configuration delivery.

Open the **Connect** tab on your machine's page in the Viam app and look at the code sample it generates. It contains your machine's address and an API key + ID pair, the main things any script needs to authenticate and reach `viam-server`.

## Configuration is the source of truth

Whatever you set in the app's **Configure** tab is what the machine runs. When you save an edit, the app updates the config document, and `viam-server` picks up the new config and applies it, typically within seconds, without a restart for most changes.

This is why the workshop asks you to make changes in the app rather than by editing a file on the robot directly. The app's Configure tab is the only place you need to look to know what a machine will do.

Open the **Configure** tab now and find the JSON view toggle near the top of the panel. Switching to JSON shows you the exact document that `viam-server` receives. Your machine has no resources configured yet, so the document is nearly empty; it fills in as you add resources.

<!-- ASSET P1 configure-json-toggle (UI+): Configure tab JSON view toggle highlighted, near-empty {} config document -->






    
    
    
<picture>

  
  
<source srcset="/tutorials/pick-and-place/configure-json-toggle_hu_f493fef25060e11d.webp" type="image/webp" width="1200" height="795">
<img src="/tutorials/pick-and-place/configure-json-toggle.png" width="1200" height="795" alt="The Configure tab with the JSON view toggle highlighted, showing a near-empty config document for the pick-and-place-main machine." class="" id="" style="" loading="lazy">
  

</picture>




## Configure your first resource

Everything a Viam machine does, hardware and software alike, is modeled as a **resource**. Each resource has a name you choose (like `arm-1`), an API that describes what kind of thing it is (an arm, a camera, a vision service), and a model that identifies the specific implementation. The fastest way to understand a resource is to configure one, so add the arm now.

On the **Configure** tab, click the **+** icon and select **Blocks**. Search for `xArm6`, select the `ufactory/xArm6` result, **Add to machine**, and name the component `arm-1`.

<!-- ASSET P0 configure-add-component (UI+): add-component dialog, "xArm6" searched, viam:ufactory:xArm6 result highlighted. See plans/2026-07-02-pick-and-place-shot-list.md -->






    
    
    
<picture>

  
  
<source srcset="/tutorials/pick-and-place/configure-add-component_hu_c60a602bcf195da4.webp" type="image/webp" width="1200" height="866">
<img src="/tutorials/pick-and-place/configure-add-component.png" width="1200" height="866" alt="The add-component dialog with xArm6 searched and the ufactory/xArm6 result selected." class="" id="" style="" loading="lazy">
  

</picture>




Set the following attributes:

```json
{
  "host": "192.168.x.x",
  "speed_degs_per_sec": 30
}
```

`host` is the only required attribute; it is the IP address listed on the arm's control box. Setting `speed_degs_per_sec` to `30` keeps the arm moving slowly enough to stay safe while you work near it.

<!-- ASSET P2 arm-controller-host (PHOTO): the xArm controller box with its IP address label -->






    
    
    
<picture>

  
  
<source srcset="/tutorials/pick-and-place/arm-controller-host_hu_d707e758761c84f.webp" type="image/webp" width="1200" height="984">
<img src="/tutorials/pick-and-place/arm-controller-host.jpeg" width="1200" height="984" alt="The xArm controller box; the IP address to use for the host attribute is printed on a label." class="" id="" style="" loading="lazy">
  

</picture>




Save the config, then open the **Logs** tab and watch what happens: a log line for a module download, then one for the module starting, then `arm-1` coming online, usually well under a minute. You just set the module system in motion; the [Builtin resources and modules](#builtin-resources-and-modules) section below explains what you saw.

<!-- ASSET P0 logs-xarm-module-start (UI+): Logs showing the viam:ufactory module download + start (the module-download moment) -->






    
    
    
<picture>

  
  
<source srcset="/tutorials/pick-and-place/logs-xarm-module-start_hu_25c8d81607d44287.webp" type="image/webp" width="1200" height="430">
<img src="/tutorials/pick-and-place/logs-xarm-module-start.png" width="1200" height="430" alt="The Logs tab showing the viam:ufactory module downloading and starting." class="" id="" style="" loading="lazy">
  

</picture>




Back on the **Configure** tab, look at the `arm-1` card. Next to the name, it shows the model as `ufactory/xArm6`, the family and model name, with `from ufactory` marking the module it came from. That is the short form. The model's full name is a **triplet**, `namespace:family:name`, which you can see written out as `viam:ufactory:xArm6` if you switch to the JSON view. The triplet tells `viam-server` exactly which code to run for this resource: who published it (`namespace`, here `viam`), the family of models it belongs to (`family`, here `ufactory`), and the specific model name (`name`, here `xArm6`).

<!-- ASSET P1 configure-arm1-triplet (UI+): arm-1 card showing the ufactory/xArm6 model label and "from ufactory", plus the full viam:ufactory:xArm6 triplet in the JSON model field -->






    
    
    
<picture>

  
  
<source srcset="/tutorials/pick-and-place/configure-arm1-triplet_hu_e9718ca879066f3d.webp" type="image/webp" width="1200" height="605">
<img src="/tutorials/pick-and-place/configure-arm1-triplet.png" width="1200" height="605" alt="The arm-1 resource card showing its ufactory/xArm6 model and from ufactory module label." class="" id="" style="" loading="lazy">
  

</picture>




You will configure the gripper and camera the same way in the next phase. Each is a resource too, with its own name, API, and model, even though one drives a gripper and the other reads a depth camera.

## Components and services

Resources split into two kinds:

- **Components** represent physical hardware. `arm-1` is a component, and so are the `gripper-1` and `cam-1` you add in Phase 2: each one wraps a piece of hardware and exposes a standard API for it (an arm API with move commands, a camera API that returns images, and so on).
- **Services** represent software tasks or capabilities. A motion service plans collision-free paths for an arm. Later, you configure a `shape-detector` vision service that gets images from `cam-1` and finds blocks by shape, and a 3D segmenter vision service that takes those detections and turns them into point cloud objects with 3D positions used for planning arm motions. Neither service is a physical thing; each one composes other resources into a new capability.

The difference shows up in what each API does: a component's API maps onto its hardware, so an arm moves to a pose and a camera returns an image, while a service's API exposes a capability, so the motion service plans a path and a vision service returns detections. Keep that split in mind: for the rest of the workshop, "component" means a piece of hardware you can point at or visualize, and "service" means a behavior built on top of one or more of those components.

## Builtin resources and modules

Some resources are **builtin**: `viam-server` (also called the RDK, the robot development kit) ships with support for common APIs and a handful of default models out of the box. Most of the interesting functionality on a real machine, though, comes from **modules**: packages that `viam-server` downloads and runs to add support for a specific model.

The `ufactory/xArm6` arm you just added comes from a module. That is what the Logs activity was when you saved it: `viam-server` recognized it does not have `ufactory/xArm6` model built in, so it downloaded the module that provides it from the Viam registry and started it. Every other module-provided resource you add follows the same pattern.

You can read this straight off the triplet seen in the JSON view of the machine configuration. `arm-1`'s namespace is `viam`, a third-party namespace, which is why it arrived as a module. A namespace of `rdk` would mean the model ships inside `viam-server` itself and needs no download; any other namespace, like `viam` or `erh`, means the model comes from a module.

## The resource dependency graph

Resources rarely stand alone. Many need another resource configured and running before they can start, and `viam-server` works out that order for you. The graph below shows the dependencies you build up across this workshop:

<!-- ASSET P0 diagram-dependency-graph (DIAGRAM): cam-1 -> shape-detector -> vision-segment; arm-1 -> gripper-1 + five pose switches; motion service -->

```text
arm-1 (arm)
  ├─→ gripper-1 (gripper)
  └─→ home / approach / grasp / travel / place  (pose switches)

cam-1 (camera)
  └─→ shape-detector (vision)
        └─→ vision-segment (vision)

motion  (builtin service, no configuration)

"A → B" means B depends on A: A must be online before B starts.
```

Resources can depend on each other. A dependency means one resource needs another to be configured and running before it can start, because it relies on that resource to do its job. A gripper attaches to an arm, so `gripper-1`'s config points at `arm-1`. A vision service reads from a camera, so it depends on `cam-1`. `viam-server` reads these dependencies returned by resources when validating their configuration and builds a dependency graph, then starts resources in an order that respects it: a resource cannot start until everything it depends on has started.

Open the **Logs** tab and look at the startup sequence the next time the machine restarts. The order resources come online in the log follows the dependency graph, not the order they appear in the config file.

> **Check yourself:**
> 
> 
> Before moving to Phase 2, make sure you can answer the three questions from the top of this page: name the three layers of a Viam machine and which one your code talks to, what separates a component from a service, and why adding the arm triggers a module download. If any answer feels shaky, re-skim the relevant section above.
> 

<nav class="workshop-nav" aria-label="Workshop phase navigation"><p class="workshop-progress">Phase 1 of 6</p><div class="workshop-nav-links"><a class="workshop-nav-prev" href="/tutorials/pick-and-place/">&larr; Previous</a><a class="workshop-nav-next" href="/tutorials/pick-and-place/configure-resources/">Next &rarr;</a></div>
</nav>


