> ## Documentation Index
> Fetch the complete documentation index at: https://docs.generalrobotics.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Your first skill

> Write a program against your live robot, then deploy it — all from the grid shell

A **skill** is a plain Python program that drives your robot through GRID's
APIs. You develop it against a *live* robot in a generated notebook, save it
as a script, and deploy it from the shell. No environment setup — the CLI
provisions the Python environment for you.

## 1. Open a dev session

```text theme={null}
GRID # session start robot
```

Pick your robot, then choose **Create a new skill**. The CLI opens a VS Code
workspace with a generated notebook whose first cell already holds the live
connection:

```python theme={null}
from grid_nexus_client import connect

robot = connect("my-go2")
print(f"Connected: {robot}")
```

## 2. Explore, then act

See every method your robot exposes:

```python theme={null}
for name in robot.session.methods_info():
    print(f"  {name}")
```

Then drive it — state, motion, camera, and Cortex calls all work from the
notebook:

```python theme={null}
robot.getState()
robot.standUp()
robot.moveByVelocity((0.1, 0.0, 0.0), (0.0, 0.0, 0.0))
```

<Warning>
  Motion cells move the robot physically. Make sure it has clearance, and run
  `robot.shutdown()` when you're done — it releases the session cleanly.
</Warning>

## 3. Save it as a skill

When the notebook logic works, turn it into a **program**: a function
decorated with `@program()` that takes the robot (and a Cortex client, if it
calls models) plus your own parameters. `while tick(hz=...)` is the control
loop — the body runs at that rate, decisions live in small `@func` helpers,
and the program ends by `break`ing on a condition. This skill spins in place
until the camera sees the prompt, then stops:

```python theme={null}
import argparse
import os

from grid_nexus_client import connect, resolve_grid_profile
from grid_nexus_program import Cortex, Robot, func, program, tick
from grid_types import Velocity


@func
def found(detections) -> bool:
    """True once OWLv2 sees the prompt with reasonable confidence."""
    scores = detections.get("scores", [])
    if hasattr(scores, "tolist"):
        scores = scores.tolist()
    if not isinstance(scores, list):
        scores = [scores] if scores is not None else []
    return len(scores) > 0 and max(scores) > 0.3


@program()
def find_object(robot: Robot, cortex: Cortex, prompt: str):
    robot.standUp()
    while tick(hz=2):
        image = robot.getImage("front")
        detections = cortex.run("owlv2", image_input=image, prompt=prompt)
        if found(detections):
            robot.stop()
            break
        robot.moveByVelocity(Velocity(0.0, 0.0, 0.0), Velocity(0.0, 0.0, 0.4))


def main(argv=None):
    parser = argparse.ArgumentParser(description="Spin until the camera sees the prompt")
    parser.add_argument("--prompt", type=str, default="water bottle")
    args = parser.parse_args(argv)

    robot_id = os.environ.get("GRID_ROBOT_ID", "")
    if not robot_id:
        raise ValueError("GRID_ROBOT_ID must name the robot to connect to")

    cortex = Cortex(base_url=resolve_grid_profile().cortex_base_url)
    robot = connect(robot_id, program=find_object)
    try:
        find_object(robot, cortex, prompt=args.prompt)
    finally:
        robot.shutdown()
        cortex.close()


if __name__ == "__main__":
    main()
```

`connect(robot_id, program=find_object)` opens the connection in
**deployment mode** — the platform stages your program, streams its camera
and state topics, and shows the run live in the session monitor. (A bare
`connect(robot_id)` is the direct mode you used in the notebook; deployments
always pass `program=`.) The deploy runner supplies `GRID_ROBOT_ID` and your
Cortex API key through the environment.

## 4. Deploy it

```text theme={null}
GRID # session start robot
```

This time choose **Deploy an existing skill** and pick your script. The CLI:

* provisions the workflow Python environment (GRID's client packages install
  from a private index with credentials fetched from your cluster — **don't**
  `pip install` them by hand),
* prompts for your script's arguments,
* exports `GRID_ROBOT_ID` and your Cortex API key, then runs the script
  against the robot you selected, streaming logs live. Press
  <kbd>Esc</kbd> to cancel a run.

## Where next

* The full Cortex model catalog for perception in your skills:
  [AI models](/models/overview)
* Calling models from Python: [grid-cortex-client](/python-api/grid-cortex-client/overview)
* Every shell command: [CLI reference](/cli/reference)


## Related topics

- [Your first session](/get-started/first-session.md)
- [Get started](/get-started/installation.md)
- [The Intelligence Grid for Physical AI](/introduction.md)
- [GRID Cortex Client](/models/cortex.md)
- [Common FAQs](/faq/common-faqs.md)
