<!--
hoody-cron Subskill (http)
Auto-generated by Hoody Skills Generator
Generated: 2026-06-20T00:37:49.137Z
Model: mimo-v2.5-pro
Mode: http


Tokens: 5574

DO NOT EDIT MANUALLY - Changes will be overwritten on next generation
-->

# hoody-cron.md

## Overview

### What It Does

**hoody-cron** is a managed cron job scheduling service for Hoody Kit containers. It provides:

- **Per-user cron entries** — create, read, update, and delete scheduled commands with standard cron expressions.
- **Bulk crontab management** — upload and retrieve an entire crontab file for a user.
- **Enable/disable control** — toggle individual entries without deleting them.
- **Auto-expiration** — entries can be configured to expire automatically after a set time.
- **Health monitoring** — a `/health` endpoint for service liveness checks.

### When to Use It

Use hoody-cron when your application needs to run recurring tasks inside a Hoody container — database backups, cache purges, report generation, periodic data syncs, or any time-triggered workload. Each user namespace gets isolated cron entries, making multi-tenant scheduling straightforward.

### How It Fits Into Hoody Philosophy

hoody-cron follows the Hoody Kit model: it runs as a container service with automatic domain routing, zero DNS configuration, and built-in authentication. Your project, container, and service IDs compose the URL — no external dependencies needed. The service manages scheduling so your application code focuses on business logic.

---

## Common Workflows

### 1. Check Service Health

Verify the cron service is running before performing operations.

```
curl -s \
  "https://{projectId}-{containerId}-cron-{serviceId}.{node}.containers.hoody.com/health"
```

Expected response (status `200`):

```
{
  "status": "ok"
}
```

If this returns an error or timeout, the container may need restarting. Refer to the core SKILL.md for container lifecycle management.

---

### 2. Create a Single Cron Entry

Schedule a command for a specific user with a cron expression.

```
curl -s -X POST \
  "https://{projectId}-{containerId}-cron-{serviceId}.{node}.containers.hoody.com/users/alice/entries" \
  -H "Content-Type: application/json" \
  -d '{
    "command": "/usr/bin/backup.sh --incremental",
    "schedule": "0 2 * * *"
  }'
```

This schedules the backup script to run daily at 02:00 for user `alice`. The response includes the created entry with its assigned `id`.

Expected response (status `201`):

```
{
  "id": "entry-abc123",
  "command": "/usr/bin/backup.sh --incremental",
  "schedule": "0 2 * * *",
  "enabled": true,
  "user": "alice"
}
```

**Verify creation** by retrieving the entry:

```
curl -s \
  "https://{projectId}-{containerId}-cron-{serviceId}.{node}.containers.hoody.com/users/alice/entries/entry-abc123"
```

---

### 3. List All Entries for a User

```
curl -s \
  "https://{projectId}-{containerId}-cron-{serviceId}.{node}.containers.hoody.com/users/alice/entries"
```

Expected response (status `200`):

```
{
  "entries": [
    {
      "id": "entry-abc123",
      "command": "/usr/bin/backup.sh --incremental",
      "schedule": "0 2 * * *",
      "enabled": true,
      "user": "alice"
    },
    {
      "id": "entry-def456",
      "command": "/usr/bin/cleanup.sh --tmp",
      "schedule": "*/30 * * * *",
      "enabled": true,
      "user": "alice"
    }
  ]
}
```

---

### 4. Update a Cron Entry

Disable an entry by patching its `enabled` field, or change its schedule and command.

```
curl -s -X PATCH \
  "https://{projectId}-{containerId}-cron-{serviceId}.{node}.containers.hoody.com/users/alice/entries/entry-abc123" \
  -H "Content-Type: application/json" \
  -d '{
    "enabled": false
  }'
```

Expected response (status `200`):

```
{
  "id": "entry-abc123",
  "command": "/usr/bin/backup.sh --incremental",
  "schedule": "0 2 * * *",
  "enabled": false,
  "user": "alice"
}
```

To change the schedule instead:

```
curl -s -X PATCH \
  "https://{projectId}-{containerId}-cron-{serviceId}.{node}.containers.hoody.com/users/alice/entries/entry-abc123" \
  -H "Content-Type: application/json" \
  -d '{
    "schedule": "0 3 * * 0",
    "enabled": true
  }'
```

This reschedules the entry to Sundays at 03:00 and re-enables it.

---

### 5. Delete a Cron Entry

```
curl -s -X DELETE \
  "https://{projectId}-{containerId}-cron-{serviceId}.{node}.containers.hoody.com/users/alice/entries/entry-abc123"
```

Expected response (status `200` or `204`):

Verify deletion by attempting to retrieve the entry — it should return `404`.

```
curl -s \
  "https://{projectId}-{containerId}-cron-{serviceId}.{node}.containers.hoody.com/users/alice/entries/entry-abc123"
```

---

### 6. Retrieve a User's Full Crontab

Get the assembled crontab string for a user (all active entries combined).

```
curl -s \
  "https://{projectId}-{containerId}-cron-{serviceId}.{node}.containers.hoody.com/users/alice/crontab"
```

---

### 7. Replace a User's Full Crontab

Bulk-set an entire crontab for a user, replacing all existing entries.

```
curl -s -X PUT \
  "https://{projectId}-{containerId}-cron-{serviceId}.{node}.containers.hoody.com/users/alice/crontab" \
  -H "Content-Type: application/json" \
  -d '{
    "crontab": "0 2 * * * /usr/bin/backup.sh --incremental\n*/15 * * * * /usr/bin/sync.sh --partial\n0 0 1 * * /usr/bin/report.sh --monthly"
  }'
```

This replaces alice's entire schedule with three entries.

---

### 8. List All Crontabs (Admin View)

Retrieve crontabs for every user in the service.

```
curl -s \
  "https://{projectId}-{containerId}-cron-{serviceId}.{node}.containers.hoody.com/crontab"
```

---

## Advanced Operations

### Multi-Step: Set Up a New User's Schedule

Provision a complete cron schedule for a new user with verification between steps.

**Step 1 — Health check:**

```
curl -s \
  "https://{projectId}-{containerId}-cron-{serviceId}.{node}.containers.hoody.com/health"
```

Confirm status `200` before proceeding.

**Step 2 — Create entries one by one (allows individual IDs for later management):**

```
curl -s -X POST \
  "https://{projectId}-{containerId}-cron-{serviceId}.{node}.containers.hoody.com/users/bob/entries" \
  -H "Content-Type: application/json" \
  -d '{
    "command": "/usr/bin/cleanup.sh --temp",
    "schedule": "0 */6 * * *"
  }'
```

Save the returned `id` for future reference.

**Step 3 — Add a second entry:**

```
curl -s -X POST \
  "https://{projectId}-{containerId}-cron-{serviceId}.{node}.containers.hoody.com/users/bob/entries" \
  -H "Content-Type: application/json" \
  -d '{
    "command": "/usr/bin/healthcheck.sh --alert",
    "schedule": "*/5 * * * *"
  }'
```

**Step 4 — Verify the complete schedule:**

```
curl -s \
  "https://{projectId}-{containerId}-cron-{serviceId}.{node}.containers.hoody.com/users/bob/entries"
```

Confirm both entries appear with `enabled: true`.

---

### Error Recovery: Entry Not Found After Timeout

If an entry creation times out or the response is lost, the entry may have been created. Re-list entries before retrying to avoid duplicates:

```
curl -s \
  "https://{projectId}-{containerId}-cron-{serviceId}.{node}.containers.hoody.com/users/alice/entries"
```

Check whether the intended command and schedule already exist. If not found, safely retry the POST. If found, save the `id` and patch as needed.

---

### Bulk Migration: Switch Crontab Format

When migrating from bulk crontab management to individual entries, first retrieve the current crontab:

```
curl -s \
  "https://{projectId}-{containerId}-cron-{serviceId}.{node}.containers.hoody.com/users/alice/crontab"
```

Parse each line and create individual entries via `POST /users/alice/entries`. Once all entries are created and verified, individual management (enable/disable, update schedule) becomes possible per entry.

---

### Performance Considerations

- **One user at a time** — all entry operations are scoped to a single user namespace. Parallel requests for different users are safe; sequential requests for the same user are recommended.
- **Health checks** — call `/health` before batch operations to avoid wasting request budget on a downed service.
- **Bulk vs. granular** — use `PUT /users/{user}/crontab` for initial provisioning of many entries; use `POST /users/{user}/entries` for adding entries incrementally during runtime.
- **`max-time 600`** — all curl examples include a 600-second timeout. Reduce this for health checks and simple reads; keep it high for PUT/POST operations with large crontabs.

---

## Quick Reference

### Base URL

```
https://{projectId}-{containerId}-cron-{serviceId}.{node}.containers.hoody.com
```

Replace all `{...}` components with your actual values. Do NOT add `/api/v1` or any other prefix.

### Core Endpoints

| Method | Path | Purpose |
|--------|------|---------|
| `GET` | `/health` | Service liveness check |
| `GET` | `/users/{user}/entries` | List all entries for a user |
| `POST` | `/users/{user}/entries` | Create a new entry (`command`, `schedule` required) |
| `GET` | `/users/{user}/entries/{id}` | Retrieve a single entry |
| `PATCH` | `/users/{user}/entries/{id}` | Update entry fields (schedule, command, enabled) |
| `DELETE` | `/users/{user}/entries/{id}` | Remove an entry |
| `GET` | `/users/{user}/crontab` | Get assembled crontab string |
| `PUT` | `/users/{user}/crontab` | Replace full crontab (`crontab` string required) |
| `GET` | `/crontab` | List all user crontabs (admin) |

### Required Fields by Operation

- **POST /users/{user}/entries** → `command` (string), `schedule` (string)
- **PUT /users/{user}/crontab** → `crontab` (string)
- **PATCH /users/{user}/entries/{id}** → no strictly required fields; send any subset of updatable fields

### Common Response Codes

| Code | Meaning |
|------|---------|
| `200` | Success (read, update, delete) |
| `201` | Created (POST entry) |
| `404` | User or entry not found |
| `422` | Invalid schedule expression or missing required field |