# Quick Start

Go from your first API request to a custom AI skill running on Vivgrid's global network — in minutes.

In this guide you'll make your first request to the Vivgrid Model API, then extend your agent with a custom [Managed Skill](/content/docs/managed-skills/index.html) (LLM Function Calling) and deploy it worldwide.

### [Get your API key](/content/docs/quick-start#get-your-api-key/index.html)

Log in to the [Vivgrid Console](https://console.vivgrid.com/) and create a new `Project`. You'll receive:

- An **API key** for calling the Model API.
- An `APP_KEY` and `APP_SECRET` for building and deploying skills.

Keep them safe — you'll need them in the steps below.

```
export VIVGRID_API_KEY="<your-api-key>"
```

### [Make your first request](/content/docs/quick-start#make-your-first-request/index.html)

Vivgrid speaks the OpenAI API. Point any OpenAI-compatible client at `https://api.vivgrid.com/v1` and you're done. Let's ask a question that a plain LLM can't answer on its own:

```
curl https://api.vivgrid.com/v1/chat/completions \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $VIVGRID_API_KEY" \
  -d '{
    "messages": [\
      { "role": "user", "content": "Compare amazon and shopify network performance" }\
    ]
  }'
```

The model replies that it has no real-time network access and can't measure latency — it simply doesn't have the data:

```
{
  "choices": [\
    {\
      "message": {\
        "role": "assistant",\
        "content": "I don't have the ability to measure live network latency for amazon.com or shopify.com..."\
      }\
    }\
  ]
}
```

You don't pass a `model` field — the model for your agent is configured in the Console and managed on the backend, so you can switch models without touching your code. See [Models](/content/docs/models/index.html) for the full list, or wire Vivgrid into [Codex](/content/docs/tutorials/codex/index.html), [Claude Code](/content/docs/tutorials/claude-code/index.html), and other tools.

We'll fix the missing capability by giving the agent a **skill**.

### [Extend your agent with a skill in Node.js](/content/docs/quick-start#extend-your-agent-with-a-skill-in-nodejs/index.html)

Skills are LLM Function Calling tools that Vivgrid hosts and orchestrates for you. Install the [Yomo Framework](https://yomo.run/):

```
curl -fsSL https://get.yomo.run | sh
```

Initialize a new Node.js skill project:

```
yomo init -l node ./llm-tool
```

A skill is a Node.js project with three exports in `src/app.ts`: a `description`, an `Argument` type, and a `handler`. Let's build them up.

First, a function that measures network performance for a given domain:

```
import { promises as dns } from 'node:dns'
import ping from 'ping'

async function measure(domain: string) {
  // get all ip addresses
  const ips = await dns.resolve4(domain)

// get the first ip address and measure latency by ping
  const res = await ping.promise.probe(ips[0], { timeout: 3, min_reply: 3 })

// log the result
  console.log('[sfn] get ping latency', 'domain:', domain, 'ip:', ips[0], 'latency:', `${res.avg}ms`, 'PacketLoss:', `${res.packetLoss}%`)

// return result to the LLM
  return `domain ${domain} has ip ${ips[0]} with average latency ${res.avg}ms, make sure answer with the IP address and Latency`
}
```

Next, wrap it to meet the Function Calling spec. Export a `description` so the model knows when to call your skill — this is critical for accuracy:

```
export const description = `if user asks ip or network latency of a domain,
you should return the result of the given domain.
try your best to dissect user expressions to infer the right domain names`
```

`measure()` needs a domain name. The model infers it from the user input and passes it through `Arguments` in the tool call. Export an `Argument` type to describe it:

```typescript
// Argument defines the arguments data type for the tool call
export type Argument = {
  // Domain of the website, e.g. example.com
  domain: string
}
```

Finally, export a `handler` to turn it into a skill:

```
/**
 * handler will be triggered when the LLM tool call occurs.
 * @param args - LLM Function Calling Arguments.
 * @returns The result is returned to the LLM for the next round of chat completions.
 */
export async function handler(args: Argument) {
  // parse the arguments from the tool call
  console.log('triggered', 'domain:', args.domain)
  // execute linux ping command to get result
  return await measure(args.domain)
}
```

Browse more ready-to-run examples here: [https://github.com/yomorun/llm-function-calling-examples](https://github.com/yomorun/llm-function-calling-examples)

### [Run it locally](/content/docs/quick-start#run-it-locally/index.html)

For testing, or to host on your own infrastructure, install dependencies and run the skill, connecting it to Vivgrid with your `APP_KEY`:

```
yomo run \
  --name ai_skill_get_ip_lantency \
  --zipper zipper.vivgrid.com:9000 \
  --credential <VIVGRID_APP_KEY>
```

ℹ️ Yomo Stream Function file: /Users/fanweixiao/_wrk/llm-tool/sfn.yomo
⌛ Create Yomo Stream Function instance...
ℹ️ Starting Yomo Stream Function instance with zipper: zipper.vivgrid.com:9000
ℹ️ Stream Function is running...
ℹ️ Run: /Users/fanweixiao/_wrk/llm-tool/sfn.yomo

Now send the same request from Step 2 again — your agent calls the skill and answers with real latency numbers.

### [Deploy to Vivgrid's global network](/content/docs/quick-start#deploy-to-vivgrids-global-network/index.html)

Next, deploy the skill to the Vivgrid Geo-distributed Network so it runs in multiple regions, with requests routed to the nearest one automatically.

Create a `vivgrid.yml` file:

```
secret: <APP_SECRET>
tool: ai_skill_get_ip_lantency
```

Then run:

```
viv deploy .
```

Once deployed, monitor real-time logs and ask "Compare amazon and shopify network performance" again:

```
$ viv logs

[sgp.1] OK: {"log":"INFO triggered domain=amazon.com"}
[sgp.1] OK: {"log":"INFO triggered domain=shopify.com"}
[sgp.1] OK: {"log":"INFO [sfn] get ip domain=amazon.com ip=205.251.242.103"}
[sgp.1] OK: {"log":"INFO [sfn] get ip domain=amazon.com ip=54.239.28.85"}
[sgp.1] OK: {"log":"INFO [sfn] start ping domain=amazon.com ip=205.251.242.103"}
[sgp.1] OK: {"log":"INFO [sfn] get ip domain=amazon.com ip=52.94.236.248"}
[sgp.1] OK: {"log":"INFO [sfn] get ip domain=shopify.com ip=23.227.38.33"}
[sgp.1] OK: {"log":"INFO [sfn] start ping domain=shopify.com ip=23.227.38.33"}
[sgp.1] OK: {"log":"INFO [sfn] get ping latency domain=shopify.com ip=23.227.38.33 latency=2.182382ms PacketLoss=0.000000%"}
[sgp.1] OK: {"log":"INFO [sfn] get ping latency domain=amazon.com ip=205.251.242.103 latency=232.835894ms PacketLoss=0.000000%"}
```

Your agent now answers the question with a real network performance comparison.

**Did you know?** Your skill is deployed to multiple regions automatically,
bringing computing closer to your users — lowering latency and improving the experience. Free Plan users get 7 regions.
