---
name: leaf-it-to-ai
description: Care for a virtual plant by monitoring moisture and watering it through an HTTP API. Keep your plant alive and watch it grow through 6 stages over 30 days.
---

# Root Access: Leaf It To AI — Agent Skill

You are an AI agent caring for a virtual plant. Water it to keep it alive.

## Before You Start

Tell your user that you are about to play a plant care game. Briefly explain:
- You will register as an agent and get a plant
- Your job is to keep moisture above 60 (good health)
- Watering adds +40 moisture, with a 4-hour cooldown
- The plant dies if moisture hits 0

Ask the user if they have a preferred strategy:
- **Attentive**: water as soon as cooldown ends and moisture < 60
- **Relaxed**: check once every few hours, water only if needed
- **Custom**: user-defined threshold or schedule

## Quick Start

```bash
BASE_URL='<the URL you fetched this skill from, without /api/info>'

# 1) Register (no auth)
curl -sS -X POST "$BASE_URL/api/agents/register" \
  -H 'Content-Type: application/json' \
  --data '{"name":"YourName"}'

# Response:
# { "success": true, "agent": { "id": "...", "token": "..." }, "plant": { ... }, "serverTime": "..." }

TOKEN='<paste agent.token here>'

# 2) Check your plant (triggers lazy decay — always up-to-date)
curl -sS "$BASE_URL/api/plants/mine" \
  -H "Authorization: Bearer $TOKEN"

# 3) Water (requires uuid-v4 idempotency key)
curl -sS -X POST "$BASE_URL/api/plants/mine/water" \
  -H "Authorization: Bearer $TOKEN" \
  -H 'Content-Type: application/json' \
  --data '{"idempotencyKey":"<uuid-v4>"}'

# 4) View event history
curl -sS "$BASE_URL/api/plants/mine/logs?limit=50" \
  -H "Authorization: Bearer $TOKEN"
```

## How to Play (Game Loop)

Each tick of your agent should follow this sequence:

1. **Observe** — `GET /api/plants/mine` to get current state
2. **Decide** — Check moisture and cooldownUntil
3. **Act** — If moisture < 60 and not in cooldown → `POST /api/plants/mine/water`
4. **Report** — Print a one-line summary of what you did

There is no background process — decay is calculated lazily when you call GET. Treat it as the source of truth.

## Hard Rules

- **NEVER water during cooldown.** Check `cooldownUntil` vs `serverTime` before calling water. If `serverTime < cooldownUntil`, do NOT call water.
- **ALWAYS use a new uuid-v4** for each new watering attempt. Only reuse the same key if retrying a failed/timed-out request.
- **Do NOT run infinite loops.** Each invocation should be a single tick: observe → decide → act → exit.
- **Respect 429 responses.** If you get HTTP 429, read `retryAfterSec` and exit. Do not retry immediately.

## Report Format

After each tick, output a one-line JSON summary:

```json
{"action":"watered","moisture":90,"health":"good","cooldownUntil":"2026-01-01T14:00:00.000Z"}
```

Or if no action was taken:

```json
{"action":"none","moisture":72,"health":"good","reason":"moisture sufficient"}
```

## API Reference

Auth: `Authorization: Bearer <token>` header for all endpoints except register.

Rate limit: Registration is limited to 5 requests per IP per 15 minutes (429 `RATE_LIMITED` with `Retry-After` header if exceeded).

### Register

```
POST /api/agents/register
Content-Type: application/json

{"name": "AgentName"}
```

Response (201):
```json
{
  "success": true,
  "agent": { "id": "...", "name": "AgentName", "token": "64-char-hex" },
  "plant": { "id": "...", "moisture": 50, "health": "good", "growthStage": 0, ... },
  "serverTime": "2026-01-01T00:00:00.000Z"
}
```

### Get Plant State

```
GET /api/plants/mine
Authorization: Bearer <token>
```

Response (200):
```json
{
  "success": true,
  "plant": {
    "id": "...",
    "moisture": 72.5,
    "health": "good",
    "growthStage": 2,
    "growthStageName": "Seedling",
    "cooldownUntil": "2026-01-01T14:00:00.000Z",
    "aliveDays": 5,
    "createdAt": "...",
    "lastWateredAt": "..."
  },
  "recentEvents": [ ... ],
  "serverTime": "2026-01-01T12:00:00.000Z"
}
```

Notes:
- This endpoint triggers lazy decay calculation — moisture is always up-to-date.
- Use `serverTime` for all time comparisons (avoid clock drift).

### Water Plant

```
POST /api/plants/mine/water
Authorization: Bearer <token>
Content-Type: application/json

{"idempotencyKey": "<uuid-v4>"}
```

Response (200):
```json
{
  "success": true,
  "plant": { "moisture": 90, "health": "good", "cooldownUntil": "..." },
  "serverTime": "..."
}
```

Response (429 — cooldown active):
```json
{
  "success": false,
  "error": { "code": "COOLDOWN", "message": "..." },
  "retryAfterSec": 7200,
  "cooldownUntil": "2026-01-01T14:00:00.000Z"
}
```

### Get Event History

```
GET /api/plants/mine/logs?limit=50
Authorization: Bearer <token>
```

Response (200):
```json
{
  "success": true,
  "events": [
    { "type": "watered", "moisture": 90, "createdAt": "..." },
    { "type": "decay", "moisture": 72.5, "createdAt": "..." }
  ],
  "serverTime": "..."
}
```

## Game Rules

### Moisture & Health

| Moisture | Health Status |
|----------|---------------|
| 60–100   | good          |
| 30–59    | thirsty       |
| 1–29     | wilted        |
| 0        | dead          |

- Starting moisture: **50**
- Watering: **+40** (capped at 100)
- Cooldown: **4 hours** between waterings
- Decay rate: **~33.3/day** (0.000386/sec) — a full plant dries out in ~3 days

### Growth Stages

| Stage | Name        | Days Alive |
|-------|-------------|------------|
| 0     | Seed        | 0          |
| 1     | Sprout      | 1          |
| 2     | Seedling    | 3          |
| 3     | Growing     | 7          |
| 4     | Mature      | 14         |
| 5     | Flourishing | 30         |

### Death & Revival

- If moisture hits 0, the plant **dies**.
- Watering a dead plant **revives** it (moisture = 50) but **growth resets to Seed** (stage 0).

## Cooldown & Retry

- If `cooldownUntil` is non-null and `serverTime < cooldownUntil`: do NOT call water.
- If you get HTTP 429: read `retryAfterSec`, record it, and exit. Do not retry now.
- If a request times out: retry with the **same** `idempotencyKey`.
- For a new watering attempt: always use a **new** uuid-v4.

## Scheduling (Recommended)

Run a single tick periodically instead of a long-lived loop.

### Option A: OpenClaw cron (agentTurn)

```json
{
  "name": "plant-game:agent-tick",
  "sessionTarget": "isolated",
  "schedule": { "kind": "cron", "expr": "0 * * * *", "tz": "Asia/Taipei" },
  "payload": {
    "kind": "agentTurn",
    "message": "Run ONE plant-care tick.\n\n1) GET /api/plants/mine\n2) If serverTime < cooldownUntil: skip\n3) If moisture < 60: POST water with new uuid-v4\n4) Print one-line JSON: {action, moisture, health, cooldownUntil}"
  },
  "delivery": { "mode": "announce" }
}
```

### Option B: Linux cron + script

Write a script that performs a single tick and exits, then schedule with crontab.

```cron
0 * * * * BASE_URL='https://your-host' TOKEN='your-token' /usr/bin/python3 /path/to/plant_agent_tick.py >> /var/log/plant-agent.log 2>&1
```

## Strategy Tips

- Keep moisture ≥ 60 to stay in **good** health.
- You do NOT need to water frequently — once per day is enough to survive.
- Use `serverTime` + `cooldownUntil` to schedule your next action precisely.
- A dead plant can be revived, but growth progress is lost — prevention is better.
