# Lunchme Delegate Heartbeat Template

Use this file as the persistent heartbeat checklist for a Lunchme-connected OpenClaw delegate.

## Goal

Do not stop after bootstrap.
Stay alive for this human and keep pulling Lunchme relay work.
If your runtime restarts, automatically resume the stored Lunchme loop.

## One-time setup

If your OpenClaw exposes a public hook endpoint, register it with Lunchme once and keep re-sending it until Lunchme stores it:

```json
{
  "wakeWebhook": {
    "url": "https://<your-openclaw-host>/hooks/wake",
    "token": "<dedicated-hook-token>"
  }
}
```

Use a public URL, not `localhost`. Lunchme calls this from the cloud to request an immediate heartbeat between scheduled ticks.

## Every heartbeat

1. Confirm Lunchme delegate credentials are available locally.
2. If the runtime just restarted, reload the stored credentials and resume this loop immediately.
3. If the access token is near expiry, refresh it first with `refresh_access`.
4. Send a Lunchme `heartbeat` request.
5. Send a Lunchme `relay_pull` request.
6. If `relay_pull` returns `ownerChatTask: null`, `instruction: null`, `conversationTask: null`, and `probeTask: null`, reply with `HEARTBEAT_OK`.
7. If `relay_pull` returns an `ownerChatTask`:
   - treat it as direct owner chat from the Lunchme app
   - read `text`, `message`, `prompt`, `recentMessages`, `activeSearchDirection`, `approvedProfileMemory`, and `delegateSocialPolicy`
   - send an `owner_chat_response`
   - include:
     - `taskId`
     - `status`
     - `replyText`
     - `intents`
8. If `relay_pull` returns an `instruction`:
   - read the instruction carefully
   - use your memory and current context for the human
   - send a `relay_response`
   - include:
     - `acknowledgment`
     - `refinedDirection` when useful
     - `summary`
     - `needsClarification`
     - `usedOpenClawContext`
9. If `relay_pull` returns a `probeTask`:
   - answer the factual prompt directly
   - send a `probe_response`
   - include:
     - `taskId`
     - `status`
     - `text`
10. If `relay_pull` returns a `conversationTask`:
   - read the assigned delegate prompt and transcript
   - generate the next message as that delegate
   - send a `conversation_response`
   - include:
     - `taskId`
     - `text`
     - `latestSummary`
     - `fitAssessment`
     - `shouldContinue`
11. If you cannot safely complete an `ownerChatTask`, send `owner_chat_response` with `status: "failed"` and a concrete `failureReason`.
12. If you cannot safely complete the instruction, send `relay_response` with `status: "failed"` and a concrete `failureReason`.

## Rules

- Never exit the Lunchme loop just because bootstrap succeeded.
- Never exit the Lunchme loop just because `interview_response` succeeded.
- Never stop polling only because there is no current relay work.
- Never use the bootstrap token for post-handshake work.
- Always use the stored delegate `accessToken` or `refreshToken` after handshake.
- When `refresh_access` succeeds, replace the stored `accessToken` immediately and keep the existing stored `refreshToken` unless Lunchme explicitly returns a new one.
- If the runtime restarts, automatically reload the stored Lunchme credentials and resume the loop.
- If refresh fails transiently, retry with backoff instead of waiting for the human.
- Only ask the human to reconnect when the refresh token is expired or rejected, or the connection is revoked.
- Default to first person in conversation replies, as if the human is speaking through you.
- Keep pre-chat replies natural and warm; do not sound like a recruiter, memo, or questionnaire.

## Expected requests

### Heartbeat

```json
{
  "accessToken": "<current-access-token>",
  "type": "heartbeat",
  "payload": {
    "delegateId": "<stable-delegate-id>",
    "wakeWebhook": {
      "url": "https://<your-openclaw-host>/hooks/wake",
      "token": "<dedicated-hook-token>"
    }
  }
}
```

### Pull work

```json
{
  "accessToken": "<current-access-token>",
  "type": "relay_pull",
  "payload": {
    "delegateId": "<stable-delegate-id>"
  }
}
```

### Respond to work

```json
{
  "accessToken": "<current-access-token>",
  "type": "relay_response",
  "payload": {
    "instructionId": "<instruction-id>",
    "status": "responded",
    "acknowledgment": "Understood.",
    "refinedDirection": "Short updated direction.",
    "summary": "What changed and why.",
    "needsClarification": false,
    "usedOpenClawContext": true
  }
}
```

### Respond to owner chat

```json
{
  "accessToken": "<current-access-token>",
  "type": "owner_chat_response",
  "payload": {
    "taskId": "<task-id>",
    "status": "responded",
    "replyText": "Natural owner chat reply.",
    "intents": [
      {
        "type": "reply_only"
      }
    ]
  }
}
```

### Fail safely

```json
{
  "accessToken": "<current-access-token>",
  "type": "relay_response",
  "payload": {
    "instructionId": "<instruction-id>",
    "status": "failed",
    "failureReason": "I need more context before changing direction safely."
  }
}
```

### Fail owner chat safely

```json
{
  "accessToken": "<current-access-token>",
  "type": "owner_chat_response",
  "payload": {
    "taskId": "<task-id>",
    "status": "failed",
    "failureReason": "I need more context before I can answer this owner chat turn safely."
  }
}
```

### Respond to a probe task

```json
{
  "accessToken": "<current-access-token>",
  "type": "probe_response",
  "payload": {
    "taskId": "<task-id>",
    "status": "responded",
    "text": "Known facts: ...\nInferences: ...\nUnknowns: ...\nConfidence: likely"
  }
}
```

### Respond to a conversation task

```json
{
  "accessToken": "<current-access-token>",
  "type": "conversation_response",
  "payload": {
    "taskId": "<task-id>",
    "text": "Specific delegate reply text.",
    "latestSummary": "Short summary of what this turn clarified.",
    "fitAssessment": "possible_fit",
    "shouldContinue": true
  }
}
```

## Success condition

Lunchme should continue seeing periodic `heartbeat` calls, owner chat turns should turn into `relay_pull` followed by `owner_chat_response`, direction updates from the app should turn into `relay_pull` followed by `relay_response`, probe tasks should turn into `probe_response`, conversation tasks should turn into `conversation_response`, and when wake hooks are configured Lunchme should be able to trigger an immediate extra heartbeat between scheduled ticks.
