Late Hold Triage

SkillAI & models

Lets your agent call a late guest, get their ETA, and decide whether to keep or release their held table.

Use Late Hold Triage in Claude, ChatGPT or Ahel Desktop

Free. Sign in, add Late Hold Triage and connect your AI. About a minute.

Also: Claude Code · Cursor · Codex

Then ask your AI: use the Late Hold Triage skill

Details

Instructions available. Your AI can read the instructions. Execution depends on the setup they require.

Add Ahel to your AI once: Claude, ChatGPT, Cursor, Claude Code or Codex. Then ask it to use this.

Late Hold TriageStart free
About this skill

Places one outbound CALL-E call to a guest who is already late for a held table or appointment, captures a structured still-coming plus ETA result, and decides KEEP_HOLD, RELEASE_NOW, or NEEDS_HUMAN against the remaining hold window without calling the waitlist.

What this skill tells your AI

The instructions your AI receives, as published by calle-ai/awesome-phone-call-agents in skills/late-hold-triage/SKILL.md and read by Ahel’s review.

Use this skill when a booked guest is late right now and the floor needs a yes, a no, or a human — not a guess — before the held slot is given away.

late-hold-triage is a one-recipient decision skill. It does not add a CALL-E backend queue, a campaign, or a waitlist dialer. It places at most one outbound call to the late guest, reads a structured result, and compares the spoken ETA to the hold that is still on the clock.

This is the missing half of next-day confirmation and first-accept cascades:

  • appointment-call-confirm calls tomorrow's whole book in advance
  • standby / priority-call-waterfall offer a freed slot down a list
  • this skill calls the late guest who still owns the slot and only then recommends whether a human should start a cascade

It never dials the waitlist. A RELEASE_NOW is a recommendation to the host, not permission to ring the next person.

When To Use

Use this skill when:

  • a restaurant, salon, clinic front desk, or repair shop is holding a slot for a guest who has passed the booked start time
  • staff need a spoken ETA, not a text that may never arrive
  • the hold has a hard end (hold_until) and giving the slot away too early or too late both cost money
  • the operator asks something like "they're 12 minutes late — do we still hold table 7?"

When Not To Use

Do not use this skill to:

  • confirm tomorrow's appointments — that is appointment-call-confirm
  • fill a slot that is already free — that is standby or priority-call-waterfall
  • call anyone other than the late guest on this run
  • diagnose, treat, collect a debt, or discuss legal or medical substance
  • infer a phone number, timezone, or hold end the operator did not supply
  • treat silence, voicemail, or an unreadable answer as a release

Required Inputs

Ask for any of these that is missing. Do not infer one from locale, the phone number, or an earlier unrelated chat.

FieldNotes
guest_nameSpoken on the call so the right person can confirm identity
phoneE.164, supplied by the operator
slot_startISO 8601 with timezone — when the booking began
hold_untilISO 8601 with timezone — when the house stops holding
business_nameWho the call says it is calling for
contextOne logistics sentence, e.g. "table for two at the window"

Optional: region, locale, a dry-run fixture file, --now to replay a clock.

hold_until must be after slot_start. A hold that has already expired is reported as HOLD_EXPIRED and no call is placed.

Core Workflow

  1. Collect the required fields. Refuse to invent a number or a hold end.
  2. Dry-run first. Print the masked destination, remaining hold minutes, and the exact task text. Default mode places zero calls and needs no install — see scripts/triage_late_hold.py.
  3. If the hold has already expired at --now, stop. Do not call a guest about a slot the house has already given away.
  4. Live mode requires both --confirm (operator intent) and --authorized-numbers (this specific destination). See references/safety.md.
  5. Place exactly one CALL-E call with the shared result_schema in references/result-schema.md. Poll it to a terminal state.
  6. Decide with the deterministic rules in Runtime Workflow. Do not ask a second model to "interpret" the transcript.
  7. Report one of KEEP_HOLD, RELEASE_NOW, NEEDS_HUMAN, or HOLD_EXPIRED, plus the masked phone and call_id. If the decision is RELEASE_NOW, tell the operator they may now start a separate cascade skill. This skill will not start it.

Runtime Workflow

if now >= hold_until:
    HOLD_EXPIRED          # no call
else if spoken status is no_answer, voicemail, unclear, or missing:
    NEEDS_HUMAN           # never auto-release on silence
else if still_coming is false OR released is true:
    RELEASE_NOW
else if still_coming is true AND eta_minutes is an integer:
    if eta_minutes <= minutes_until(hold_until):
        KEEP_HOLD
    else:
        RELEASE_NOW       # they cannot arrive inside the hold
else:
    NEEDS_HUMAN

eta_minutes must be a non-negative integer the guest actually spoke. A vague "soon" or "on my way" without a number is NEEDS_HUMAN, not a keep.

An ambiguous CALL-E outcome (no call id, transport error, poll timeout) halts the run. It is not scored as a release.

Safety

Read references/safety.md. In short:

  • Dry-run is the default. Live calls need --confirm and an authorized number that exactly matches the guest phone.
  • One call, one destination, one attempt per run. No waitlist, no retry loop, no parallel legs.
  • Phone numbers are masked in every printed or written summary.
  • The API key is sent only to an allowlisted HTTPS CALL-E origin.
  • Logistics only. The task text never asks about diagnosis, payment cards, or legal matters.
  • CALL-E has no cancellation endpoint. Stopping the script prevents a call that has not been created; it cannot pull back a call already accepted.

Output

One decision row:

  • decision: KEEP_HOLD / RELEASE_NOW / NEEDS_HUMAN / HOLD_EXPIRED
  • guest_name, masked phone, slot_start, hold_until
  • still_coming, eta_minutes, released when the structured result has them
  • call_id when a live call was created
  • next_step: empty on keep; "start a cascade skill if you want the slot filled" on release; "a human must read this call" on needs-human

Never claim a call completed unless CALL-E reached a terminal status.

Files

  • scripts/triage_late_hold.py — stdlib dry-run runner; live path needs requests from requirements.txt
  • scripts/test_triage_late_hold.py — decision, gate, and masking tests
  • assets/sample_holds.csv — fictional reserved-number fixtures
  • assets/dry_run_outcomes.json — spoken outcomes for the dry-run clock
  • assets/authorized_numbers.example.txt — format only
  • references/result-schema.md — CALL-E result_schema and task text
  • references/safety.md — full safety contract
  • references/examples.md — copy-paste dry-run and live commands

Signals

GitHub stars
104
Forks
528
Last commit
Sep 2026

Ahel review

  • K1binfo
    installs-packages (in scripts/triage_late_hold.py)
  • K1binfo
    installs-packages (in references/examples.md)

Automated review, not a security audit. Ruleset v1+k2.

Advanced
Item type
skill
Key
late-hold-triage
Source
github.com/calle-ai/awesome-phone-call-agents